2 * \file BufferParams.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
10 * \author André Pönitz
11 * \author Martin Vermeer
13 * Full author contact details are available in file CREDITS.
18 #include "BufferParams.h"
21 #include "LayoutFile.h"
22 #include "BranchList.h"
23 #include "buffer_funcs.h"
29 #include "IndicesList.h"
31 #include "LaTeXFeatures.h"
32 #include "ModuleList.h"
36 #include "OutputParams.h"
40 #include "PDFOptions.h"
42 #include "frontends/alert.h"
44 #include "insets/InsetListingsParams.h"
46 #include "support/convert.h"
47 #include "support/debug.h"
48 #include "support/docstream.h"
49 #include "support/FileName.h"
50 #include "support/filetools.h"
51 #include "support/gettext.h"
52 #include "support/Messages.h"
53 #include "support/Translator.h"
54 #include "support/lstrings.h"
60 using namespace lyx::support;
63 static char const * const string_paragraph_separation[] = {
68 static char const * const string_quotes_language[] = {
69 "english", "swedish", "german", "polish", "french", "danish", ""
73 static char const * const string_papersize[] = {
74 "default", "custom", "letterpaper", "legalpaper", "executivepaper",
75 "a3paper", "a4paper", "a5paper", "b3paper", "b4paper", "b5paper", ""
79 static char const * const string_orientation[] = {
80 "portrait", "landscape", ""
84 static char const * const string_footnotekinds[] = {
85 "footnote", "margin", "fig", "tab", "alg", "wide-fig", "wide-tab", ""
89 static char const * const tex_graphics[] = {
90 "default", "dvialw", "dvilaser", "dvipdf", "dvipdfm", "dvipdfmx",
91 "dvips", "dvipsone", "dvitops", "dviwin", "dviwindo", "dvi2ps", "emtex",
92 "ln", "oztex", "pctexhp", "pctexps", "pctexwin", "pctex32", "pdftex",
93 "psprint", "pubps", "tcidvi", "textures", "truetex", "vtex", "xdvi",
104 // Paragraph separation
105 typedef Translator<string, BufferParams::ParagraphSeparation> ParSepTranslator;
108 ParSepTranslator const init_parseptranslator()
110 ParSepTranslator translator
111 (string_paragraph_separation[0], BufferParams::ParagraphIndentSeparation);
112 translator.addPair(string_paragraph_separation[1], BufferParams::ParagraphSkipSeparation);
117 ParSepTranslator const & parseptranslator()
119 static ParSepTranslator translator = init_parseptranslator();
125 typedef Translator<string, InsetQuotes::QuoteLanguage> QuotesLangTranslator;
128 QuotesLangTranslator const init_quoteslangtranslator()
130 QuotesLangTranslator translator
131 (string_quotes_language[0], InsetQuotes::EnglishQuotes);
132 translator.addPair(string_quotes_language[1], InsetQuotes::SwedishQuotes);
133 translator.addPair(string_quotes_language[2], InsetQuotes::GermanQuotes);
134 translator.addPair(string_quotes_language[3], InsetQuotes::PolishQuotes);
135 translator.addPair(string_quotes_language[4], InsetQuotes::FrenchQuotes);
136 translator.addPair(string_quotes_language[5], InsetQuotes::DanishQuotes);
141 QuotesLangTranslator const & quoteslangtranslator()
143 static QuotesLangTranslator translator = init_quoteslangtranslator();
149 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
152 static PaperSizeTranslator initPaperSizeTranslator()
154 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
155 translator.addPair(string_papersize[1], PAPER_CUSTOM);
156 translator.addPair(string_papersize[2], PAPER_USLETTER);
157 translator.addPair(string_papersize[3], PAPER_USLEGAL);
158 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
159 translator.addPair(string_papersize[5], PAPER_A3);
160 translator.addPair(string_papersize[6], PAPER_A4);
161 translator.addPair(string_papersize[7], PAPER_A5);
162 translator.addPair(string_papersize[8], PAPER_B3);
163 translator.addPair(string_papersize[9], PAPER_B4);
164 translator.addPair(string_papersize[10], PAPER_B5);
169 PaperSizeTranslator const & papersizetranslator()
171 static PaperSizeTranslator translator = initPaperSizeTranslator();
177 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
180 PaperOrientationTranslator const init_paperorientationtranslator()
182 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
183 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
188 PaperOrientationTranslator const & paperorientationtranslator()
190 static PaperOrientationTranslator translator = init_paperorientationtranslator();
196 typedef Translator<int, PageSides> SidesTranslator;
199 SidesTranslator const init_sidestranslator()
201 SidesTranslator translator(1, OneSide);
202 translator.addPair(2, TwoSides);
207 SidesTranslator const & sidestranslator()
209 static SidesTranslator translator = init_sidestranslator();
215 typedef Translator<int, BufferParams::Package> PackageTranslator;
218 PackageTranslator const init_packagetranslator()
220 PackageTranslator translator(0, BufferParams::package_off);
221 translator.addPair(1, BufferParams::package_auto);
222 translator.addPair(2, BufferParams::package_on);
227 PackageTranslator const & packagetranslator()
229 static PackageTranslator translator = init_packagetranslator();
235 typedef Translator<string, CiteEngine> CiteEngineTranslator;
238 CiteEngineTranslator const init_citeenginetranslator()
240 CiteEngineTranslator translator("basic", ENGINE_BASIC);
241 translator.addPair("natbib_numerical", ENGINE_NATBIB_NUMERICAL);
242 translator.addPair("natbib_authoryear", ENGINE_NATBIB_AUTHORYEAR);
243 translator.addPair("jurabib", ENGINE_JURABIB);
248 CiteEngineTranslator const & citeenginetranslator()
250 static CiteEngineTranslator translator = init_citeenginetranslator();
256 typedef Translator<string, Spacing::Space> SpaceTranslator;
259 SpaceTranslator const init_spacetranslator()
261 SpaceTranslator translator("default", Spacing::Default);
262 translator.addPair("single", Spacing::Single);
263 translator.addPair("onehalf", Spacing::Onehalf);
264 translator.addPair("double", Spacing::Double);
265 translator.addPair("other", Spacing::Other);
270 SpaceTranslator const & spacetranslator()
272 static SpaceTranslator translator = init_spacetranslator();
279 class BufferParams::Impl
284 AuthorList authorlist;
285 BranchList branchlist;
286 Bullet temp_bullets[4];
287 Bullet user_defined_bullets[4];
288 IndicesList indiceslist;
290 /** This is the amount of space used for paragraph_separation "skip",
291 * and for detached paragraphs in "indented" documents.
295 PDFOptions pdfoptions;
296 LayoutFileIndex baseClass_;
300 BufferParams::Impl::Impl()
301 : defskip(VSpace::MEDSKIP), baseClass_(string(""))
303 // set initial author
305 authorlist.record(Author(from_utf8(lyxrc.user_name), from_utf8(lyxrc.user_email)));
310 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
314 return new BufferParams::Impl(*ptr);
318 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
324 BufferParams::BufferParams()
327 setBaseClass(defaultBaseclass());
329 paragraph_separation = ParagraphIndentSeparation;
330 quotes_language = InsetQuotes::EnglishQuotes;
331 fontsize = "default";
334 papersize = PAPER_DEFAULT;
335 orientation = ORIENTATION_PORTRAIT;
336 use_geometry = false;
337 use_amsmath = package_auto;
338 use_esint = package_auto;
339 use_mhchem = package_auto;
340 cite_engine_ = ENGINE_BASIC;
341 use_bibtopic = false;
343 trackChanges = false;
344 outputChanges = false;
345 use_default_options = true;
346 maintain_unincluded_children = false;
349 language = default_language;
351 fontsRoman = "default";
352 fontsSans = "default";
353 fontsTypewriter = "default";
354 fontsDefaultFamily = "default";
358 fontsSansScale = 100;
359 fontsTypewriterScale = 100;
361 graphicsDriver = "default";
362 defaultOutputFormat = "default";
363 bibtex_command = "default";
364 index_command = "default";
367 listings_params = string();
368 pagestyle = "default";
369 suppress_date = false;
370 // no color is the default (white)
371 backgroundcolor = lyx::rgbFromHexName("#ffffff");
372 isbackgroundcolor = false;
373 // no color is the default (black)
374 fontcolor = lyx::rgbFromHexName("#000000");
376 // light gray is the default font color for greyed-out notes
377 notefontcolor = lyx::rgbFromHexName("#cccccc");
378 boxbgcolor = lyx::rgbFromHexName("#ff0000");
379 compressed = lyxrc.save_compressed;
380 for (int iter = 0; iter < 4; ++iter) {
381 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
382 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
385 indiceslist().addDefault(B_("Index"));
386 html_be_strict = true;
387 html_math_output = MathML;
391 docstring BufferParams::B_(string const & l10n) const
393 LASSERT(language, /**/);
394 return getMessages(language->code()).get(l10n);
398 AuthorList & BufferParams::authors()
400 return pimpl_->authorlist;
404 AuthorList const & BufferParams::authors() const
406 return pimpl_->authorlist;
410 BranchList & BufferParams::branchlist()
412 return pimpl_->branchlist;
416 BranchList const & BufferParams::branchlist() const
418 return pimpl_->branchlist;
422 IndicesList & BufferParams::indiceslist()
424 return pimpl_->indiceslist;
428 IndicesList const & BufferParams::indiceslist() const
430 return pimpl_->indiceslist;
434 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
436 LASSERT(index < 4, /**/);
437 return pimpl_->temp_bullets[index];
441 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
443 LASSERT(index < 4, /**/);
444 return pimpl_->temp_bullets[index];
448 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
450 LASSERT(index < 4, /**/);
451 return pimpl_->user_defined_bullets[index];
455 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
457 LASSERT(index < 4, /**/);
458 return pimpl_->user_defined_bullets[index];
462 Spacing & BufferParams::spacing()
464 return pimpl_->spacing;
468 Spacing const & BufferParams::spacing() const
470 return pimpl_->spacing;
474 PDFOptions & BufferParams::pdfoptions()
476 return pimpl_->pdfoptions;
480 PDFOptions const & BufferParams::pdfoptions() const
482 return pimpl_->pdfoptions;
486 HSpace const & BufferParams::getIndentation() const
488 return pimpl_->indentation;
492 void BufferParams::setIndentation(HSpace const & indent)
494 pimpl_->indentation = indent;
498 VSpace const & BufferParams::getDefSkip() const
500 return pimpl_->defskip;
504 void BufferParams::setDefSkip(VSpace const & vs)
506 pimpl_->defskip = vs;
510 string BufferParams::readToken(Lexer & lex, string const & token,
511 FileName const & filepath)
513 if (token == "\\textclass") {
515 string const classname = lex.getString();
516 // if there exists a local layout file, ignore the system one
517 // NOTE: in this case, the textclass (.cls file) is assumed to be available.
519 LayoutFileList & bcl = LayoutFileList::get();
520 if (tcp.empty() && !filepath.empty())
521 tcp = bcl.addLocalLayout(classname, filepath.absFilename());
525 setBaseClass(classname);
526 // We assume that a tex class exists for local or unknown layouts so this warning
527 // will only be given for system layouts.
528 if (!baseClass()->isTeXClassAvailable()) {
530 translateIfPossible(from_utf8(baseClass()->description()));
531 docstring const msg =
532 bformat(_("The document class requested\n"
534 "requires external files that are not available.\n"
535 "The document class can still be used, but LyX\n"
536 "will not be able to produce output until the\n"
537 "following prerequisites are installed:\n"
539 "See section 3.1.2.2 of the User's Guide for\n"
540 "more information."),
541 desc, from_utf8(baseClass()->prerequisites()));
542 frontend::Alert::warning(_("Document class not available"),
545 } else if (token == "\\begin_preamble") {
547 } else if (token == "\\begin_local_layout") {
548 readLocalLayout(lex);
549 } else if (token == "\\begin_modules") {
551 } else if (token == "\\begin_removed_modules") {
552 readRemovedModules(lex);
553 } else if (token == "\\begin_includeonly") {
554 readIncludeonly(lex);
555 } else if (token == "\\maintain_unincluded_children") {
556 lex >> maintain_unincluded_children;
557 } else if (token == "\\options") {
559 options = lex.getString();
560 } else if (token == "\\use_default_options") {
561 lex >> use_default_options;
562 } else if (token == "\\master") {
564 master = lex.getString();
565 } else if (token == "\\suppress_date") {
566 lex >> suppress_date;
567 } else if (token == "\\language") {
569 } else if (token == "\\inputencoding") {
571 } else if (token == "\\graphics") {
572 readGraphicsDriver(lex);
573 } else if (token == "\\default_output_format") {
574 lex >> defaultOutputFormat;
575 } else if (token == "\\bibtex_command") {
577 bibtex_command = lex.getString();
578 } else if (token == "\\index_command") {
580 index_command = lex.getString();
581 } else if (token == "\\fontencoding") {
583 fontenc = lex.getString();
584 } else if (token == "\\font_roman") {
586 fontsRoman = lex.getString();
587 } else if (token == "\\font_sans") {
589 fontsSans = lex.getString();
590 } else if (token == "\\font_typewriter") {
592 fontsTypewriter = lex.getString();
593 } else if (token == "\\font_default_family") {
594 lex >> fontsDefaultFamily;
595 } else if (token == "\\use_xetex") {
597 } else if (token == "\\font_sc") {
599 } else if (token == "\\font_osf") {
601 } else if (token == "\\font_sf_scale") {
602 lex >> fontsSansScale;
603 } else if (token == "\\font_tt_scale") {
604 lex >> fontsTypewriterScale;
605 } else if (token == "\\font_cjk") {
607 } else if (token == "\\paragraph_separation") {
610 paragraph_separation = parseptranslator().find(parsep);
611 } else if (token == "\\paragraph_indentation") {
613 string indentation = lex.getString();
614 pimpl_->indentation = HSpace(indentation);
615 } else if (token == "\\defskip") {
617 string defskip = lex.getString();
618 if (defskip == "defskip")
621 pimpl_->defskip = VSpace(defskip);
622 } else if (token == "\\quotes_language") {
625 quotes_language = quoteslangtranslator().find(quotes_lang);
626 } else if (token == "\\papersize") {
629 papersize = papersizetranslator().find(ppsize);
630 } else if (token == "\\use_geometry") {
632 } else if (token == "\\use_amsmath") {
635 use_amsmath = packagetranslator().find(use_ams);
636 } else if (token == "\\use_esint") {
639 use_esint = packagetranslator().find(useesint);
640 } else if (token == "\\use_mhchem") {
643 use_mhchem = packagetranslator().find(usemhchem);
644 } else if (token == "\\cite_engine") {
647 cite_engine_ = citeenginetranslator().find(engine);
648 } else if (token == "\\use_bibtopic") {
650 } else if (token == "\\use_indices") {
652 } else if (token == "\\tracking_changes") {
654 } else if (token == "\\output_changes") {
655 lex >> outputChanges;
656 } else if (token == "\\branch") {
658 docstring branch = lex.getDocString();
659 branchlist().add(branch);
662 string const tok = lex.getString();
663 if (tok == "\\end_branch")
665 Branch * branch_ptr = branchlist().find(branch);
666 if (tok == "\\selected") {
669 branch_ptr->setSelected(lex.getInteger());
671 if (tok == "\\filename_suffix") {
674 branch_ptr->setFilenameSuffix(lex.getInteger());
676 if (tok == "\\color") {
678 string color = lex.getString();
680 branch_ptr->setColor(color);
681 // Update also the Color table:
683 color = lcolor.getX11Name(Color_background);
685 lcolor.setColor(to_utf8(branch), color);
688 } else if (token == "\\index") {
690 docstring index = lex.getDocString();
692 indiceslist().add(index);
695 string const tok = lex.getString();
696 if (tok == "\\end_index")
698 Index * index_ptr = indiceslist().find(index);
699 if (tok == "\\shortcut") {
701 shortcut = lex.getDocString();
703 index_ptr->setShortcut(shortcut);
705 if (tok == "\\color") {
707 string color = lex.getString();
709 index_ptr->setColor(color);
710 // Update also the Color table:
712 color = lcolor.getX11Name(Color_background);
714 if (!shortcut.empty())
715 lcolor.setColor(to_utf8(shortcut), color);
718 } else if (token == "\\author") {
720 istringstream ss(lex.getString());
723 author_map[a.buffer_id()] = pimpl_->authorlist.record(a);
724 } else if (token == "\\paperorientation") {
727 orientation = paperorientationtranslator().find(orient);
728 } else if (token == "\\backgroundcolor") {
730 backgroundcolor = lyx::rgbFromHexName(lex.getString());
731 isbackgroundcolor = true;
732 } else if (token == "\\fontcolor") {
734 fontcolor = lyx::rgbFromHexName(lex.getString());
736 } else if (token == "\\notefontcolor") {
738 string color = lex.getString();
739 notefontcolor = lyx::rgbFromHexName(color);
740 // set the font color within LyX
741 // FIXME: the color is correctly set but later overwritten by the default
742 lcolor.setColor(Color_greyedouttext, color);
743 } else if (token == "\\boxbgcolor") {
745 string color = lex.getString();
746 boxbgcolor = lyx::rgbFromHexName(color);
747 // set the font color within LyX
748 // FIXME: the color is correctly set but later overwritten by the default
749 lcolor.setColor(Color_shadedbg, color);
750 } else if (token == "\\paperwidth") {
752 } else if (token == "\\paperheight") {
754 } else if (token == "\\leftmargin") {
756 } else if (token == "\\topmargin") {
758 } else if (token == "\\rightmargin") {
760 } else if (token == "\\bottommargin") {
762 } else if (token == "\\headheight") {
764 } else if (token == "\\headsep") {
766 } else if (token == "\\footskip") {
768 } else if (token == "\\columnsep") {
770 } else if (token == "\\paperfontsize") {
772 } else if (token == "\\papercolumns") {
774 } else if (token == "\\listings_params") {
777 listings_params = InsetListingsParams(par).params();
778 } else if (token == "\\papersides") {
781 sides = sidestranslator().find(psides);
782 } else if (token == "\\paperpagestyle") {
784 } else if (token == "\\bullet") {
786 } else if (token == "\\bulletLaTeX") {
787 readBulletsLaTeX(lex);
788 } else if (token == "\\secnumdepth") {
790 } else if (token == "\\tocdepth") {
792 } else if (token == "\\spacing") {
796 if (nspacing == "other") {
799 spacing().set(spacetranslator().find(nspacing), tmp_val);
800 } else if (token == "\\float_placement") {
801 lex >> float_placement;
803 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
804 string toktmp = pdfoptions().readToken(lex, token);
805 if (!toktmp.empty()) {
806 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
810 } else if (token == "\\html_math_output") {
813 html_math_output = static_cast<MathOutput>(temp);
814 } else if (token == "\\html_be_strict") {
815 lex >> html_be_strict;
817 lyxerr << "BufferParams::readToken(): Unknown token: " <<
826 void BufferParams::writeFile(ostream & os) const
828 // The top of the file is written by the buffer.
829 // Prints out the buffer info into the .lyx file given by file
832 os << "\\textclass " << baseClass()->name() << '\n';
835 if (!preamble.empty()) {
836 // remove '\n' from the end of preamble
837 string const tmppreamble = rtrim(preamble, "\n");
838 os << "\\begin_preamble\n"
840 << "\n\\end_preamble\n";
844 if (!options.empty()) {
845 os << "\\options " << options << '\n';
848 // use the class options defined in the layout?
849 os << "\\use_default_options "
850 << convert<string>(use_default_options) << "\n";
852 // the master document
853 if (!master.empty()) {
854 os << "\\master " << master << '\n';
858 if (!removedModules_.empty()) {
859 os << "\\begin_removed_modules" << '\n';
860 list<string>::const_iterator it = removedModules_.begin();
861 list<string>::const_iterator en = removedModules_.end();
862 for (; it != en; it++)
864 os << "\\end_removed_modules" << '\n';
868 if (!layoutModules_.empty()) {
869 os << "\\begin_modules" << '\n';
870 LayoutModuleList::const_iterator it = layoutModules_.begin();
871 LayoutModuleList::const_iterator en = layoutModules_.end();
872 for (; it != en; it++)
874 os << "\\end_modules" << '\n';
878 if (!includedChildren_.empty()) {
879 os << "\\begin_includeonly" << '\n';
880 list<string>::const_iterator it = includedChildren_.begin();
881 list<string>::const_iterator en = includedChildren_.end();
882 for (; it != en; it++)
884 os << "\\end_includeonly" << '\n';
886 os << "\\maintain_unincluded_children "
887 << convert<string>(maintain_unincluded_children) << '\n';
889 // local layout information
890 if (!local_layout.empty()) {
891 // remove '\n' from the end
892 string const tmplocal = rtrim(local_layout, "\n");
893 os << "\\begin_local_layout\n"
895 << "\n\\end_local_layout\n";
898 // then the text parameters
899 if (language != ignore_language)
900 os << "\\language " << language->lang() << '\n';
901 os << "\\inputencoding " << inputenc
902 << "\n\\fontencoding " << fontenc
903 << "\n\\font_roman " << fontsRoman
904 << "\n\\font_sans " << fontsSans
905 << "\n\\font_typewriter " << fontsTypewriter
906 << "\n\\font_default_family " << fontsDefaultFamily
907 << "\n\\use_xetex " << convert<string>(useXetex)
908 << "\n\\font_sc " << convert<string>(fontsSC)
909 << "\n\\font_osf " << convert<string>(fontsOSF)
910 << "\n\\font_sf_scale " << fontsSansScale
911 << "\n\\font_tt_scale " << fontsTypewriterScale
913 if (!fontsCJK.empty()) {
914 os << "\\font_cjk " << fontsCJK << '\n';
916 os << "\n\\graphics " << graphicsDriver << '\n';
917 os << "\\default_output_format " << defaultOutputFormat << '\n';
918 os << "\\bibtex_command " << bibtex_command << '\n';
919 os << "\\index_command " << index_command << '\n';
921 if (!float_placement.empty()) {
922 os << "\\float_placement " << float_placement << '\n';
924 os << "\\paperfontsize " << fontsize << '\n';
926 spacing().writeFile(os);
927 pdfoptions().writeFile(os);
929 os << "\\papersize " << string_papersize[papersize]
930 << "\n\\use_geometry " << convert<string>(use_geometry)
931 << "\n\\use_amsmath " << use_amsmath
932 << "\n\\use_esint " << use_esint
933 << "\n\\use_mhchem " << use_mhchem
934 << "\n\\cite_engine " << citeenginetranslator().find(cite_engine_)
935 << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
936 << "\n\\use_indices " << convert<string>(use_indices)
937 << "\n\\paperorientation " << string_orientation[orientation]
938 << "\n\\suppress_date " << convert<string>(suppress_date)
940 if (isbackgroundcolor == true)
941 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
942 if (isfontcolor == true)
943 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
944 if (notefontcolor != lyx::rgbFromHexName("#cccccc"))
945 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
946 if (boxbgcolor != lyx::rgbFromHexName("#ff0000"))
947 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
949 BranchList::const_iterator it = branchlist().begin();
950 BranchList::const_iterator end = branchlist().end();
951 for (; it != end; ++it) {
952 os << "\\branch " << to_utf8(it->branch())
953 << "\n\\selected " << it->isSelected()
954 << "\n\\filename_suffix " << it->hasFilenameSuffix()
955 << "\n\\color " << lyx::X11hexname(it->color())
960 IndicesList::const_iterator iit = indiceslist().begin();
961 IndicesList::const_iterator iend = indiceslist().end();
962 for (; iit != iend; ++iit) {
963 os << "\\index " << to_utf8(iit->index())
964 << "\n\\shortcut " << to_utf8(iit->shortcut())
965 << "\n\\color " << lyx::X11hexname(iit->color())
970 if (!paperwidth.empty())
971 os << "\\paperwidth "
972 << VSpace(paperwidth).asLyXCommand() << '\n';
973 if (!paperheight.empty())
974 os << "\\paperheight "
975 << VSpace(paperheight).asLyXCommand() << '\n';
976 if (!leftmargin.empty())
977 os << "\\leftmargin "
978 << VSpace(leftmargin).asLyXCommand() << '\n';
979 if (!topmargin.empty())
981 << VSpace(topmargin).asLyXCommand() << '\n';
982 if (!rightmargin.empty())
983 os << "\\rightmargin "
984 << VSpace(rightmargin).asLyXCommand() << '\n';
985 if (!bottommargin.empty())
986 os << "\\bottommargin "
987 << VSpace(bottommargin).asLyXCommand() << '\n';
988 if (!headheight.empty())
989 os << "\\headheight "
990 << VSpace(headheight).asLyXCommand() << '\n';
991 if (!headsep.empty())
993 << VSpace(headsep).asLyXCommand() << '\n';
994 if (!footskip.empty())
996 << VSpace(footskip).asLyXCommand() << '\n';
997 if (!columnsep.empty())
999 << VSpace(columnsep).asLyXCommand() << '\n';
1000 os << "\\secnumdepth " << secnumdepth
1001 << "\n\\tocdepth " << tocdepth
1002 << "\n\\paragraph_separation "
1003 << string_paragraph_separation[paragraph_separation];
1004 if (!paragraph_separation)
1005 os << "\n\\paragraph_indentation " << getIndentation().asLyXCommand();
1007 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1008 os << "\n\\quotes_language "
1009 << string_quotes_language[quotes_language]
1010 << "\n\\papercolumns " << columns
1011 << "\n\\papersides " << sides
1012 << "\n\\paperpagestyle " << pagestyle << '\n';
1013 if (!listings_params.empty())
1014 os << "\\listings_params \"" <<
1015 InsetListingsParams(listings_params).encodedString() << "\"\n";
1016 for (int i = 0; i < 4; ++i) {
1017 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1018 if (user_defined_bullet(i).getFont() != -1) {
1019 os << "\\bullet " << i << " "
1020 << user_defined_bullet(i).getFont() << " "
1021 << user_defined_bullet(i).getCharacter() << " "
1022 << user_defined_bullet(i).getSize() << "\n";
1026 os << "\\bulletLaTeX " << i << " \""
1027 << lyx::to_ascii(user_defined_bullet(i).getText())
1033 os << "\\tracking_changes " << convert<string>(trackChanges) << "\n"
1034 << "\\output_changes " << convert<string>(outputChanges) << "\n"
1035 << "\\html_math_output " << html_math_output << "\n"
1036 << "\\html_be_strict " << convert<string>(html_be_strict) << "\n";
1038 os << pimpl_->authorlist;
1042 void BufferParams::validate(LaTeXFeatures & features) const
1044 features.require(documentClass().requires());
1046 if (outputChanges) {
1047 bool dvipost = LaTeXFeatures::isAvailable("dvipost");
1048 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1049 LaTeXFeatures::isAvailable("xcolor");
1051 switch (features.runparams().flavor) {
1052 case OutputParams::LATEX:
1054 features.require("ct-dvipost");
1055 features.require("dvipost");
1056 } else if (xcolorulem) {
1057 features.require("ct-xcolor-ulem");
1058 features.require("ulem");
1059 features.require("xcolor");
1061 features.require("ct-none");
1064 case OutputParams::PDFLATEX:
1065 case OutputParams::XETEX:
1067 features.require("ct-xcolor-ulem");
1068 features.require("ulem");
1069 features.require("xcolor");
1070 // improves color handling in PDF output
1071 features.require("pdfcolmk");
1073 features.require("ct-none");
1081 // Floats with 'Here definitely' as default setting.
1082 if (float_placement.find('H') != string::npos)
1083 features.require("float");
1085 // AMS Style is at document level
1086 if (use_amsmath == package_on
1087 || documentClass().provides("amsmath"))
1088 features.require("amsmath");
1089 if (use_esint == package_on)
1090 features.require("esint");
1091 if (use_mhchem == package_on)
1092 features.require("mhchem");
1094 // Document-level line spacing
1095 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1096 features.require("setspace");
1098 // the bullet shapes are buffer level not paragraph level
1099 // so they are tested here
1100 for (int i = 0; i < 4; ++i) {
1101 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1103 int const font = user_defined_bullet(i).getFont();
1105 int const c = user_defined_bullet(i).getCharacter();
1111 features.require("latexsym");
1113 } else if (font == 1) {
1114 features.require("amssymb");
1115 } else if (font >= 2 && font <= 5) {
1116 features.require("pifont");
1120 if (pdfoptions().use_hyperref) {
1121 features.require("hyperref");
1122 // due to interferences with babel and hyperref, the color package has to
1123 // be loaded after hyperref when hyperref is used with the colorlinks
1124 // option, see http://www.lyx.org/trac/ticket/5291
1125 if (pdfoptions().colorlinks)
1126 features.require("color");
1130 features.require("xetex");
1132 if (language->lang() == "vietnamese")
1133 features.require("vietnamese");
1134 else if (language->lang() == "japanese")
1135 features.require("japanese");
1139 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
1140 TexRow & texrow, FileName const & filepath) const
1142 os << "\\documentclass";
1144 DocumentClass const & tclass = documentClass();
1146 ostringstream clsoptions; // the document class options.
1148 if (tokenPos(tclass.opt_fontsize(),
1149 '|', fontsize) >= 0) {
1150 // only write if existing in list (and not default)
1151 clsoptions << fontsize << "pt,";
1154 // custom, A3, B3 and B4 paper sizes need geometry
1155 bool nonstandard_papersize = papersize == PAPER_B3
1156 || papersize == PAPER_B4
1157 || papersize == PAPER_A3
1158 || papersize == PAPER_CUSTOM;
1160 if (!use_geometry) {
1161 switch (papersize) {
1163 clsoptions << "a4paper,";
1165 case PAPER_USLETTER:
1166 clsoptions << "letterpaper,";
1169 clsoptions << "a5paper,";
1172 clsoptions << "b5paper,";
1174 case PAPER_USEXECUTIVE:
1175 clsoptions << "executivepaper,";
1178 clsoptions << "legalpaper,";
1190 if (sides != tclass.sides()) {
1193 clsoptions << "oneside,";
1196 clsoptions << "twoside,";
1202 if (columns != tclass.columns()) {
1204 clsoptions << "twocolumn,";
1206 clsoptions << "onecolumn,";
1210 && orientation == ORIENTATION_LANDSCAPE)
1211 clsoptions << "landscape,";
1213 // language should be a parameter to \documentclass
1214 if (language->babel() == "hebrew"
1215 && default_language->babel() != "hebrew")
1216 // This seems necessary
1217 features.useLanguage(default_language);
1219 ostringstream language_options;
1220 bool const use_babel = features.useBabel();
1222 language_options << features.getLanguages();
1223 if (!language->babel().empty()) {
1224 if (!language_options.str().empty())
1225 language_options << ',';
1226 language_options << language->babel();
1228 // if Vietnamese is used, babel must directly be loaded
1229 // with language options, not in the class options, see
1230 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1231 size_t viet = language_options.str().find("vietnam");
1232 // viet = string::npos when not found
1233 // the same is for all other languages that are not directly supported by
1234 // babel, but where LaTeX-packages add babel support.
1235 // this is currently the case for Latvian, Lithuanian, Mongolian
1237 size_t latvian = language_options.str().find("latvian");
1238 size_t lithu = language_options.str().find("lithuanian");
1239 size_t mongo = language_options.str().find("mongolian");
1240 size_t turkmen = language_options.str().find("turkmen");
1241 // if Japanese is used, babel must directly be loaded
1242 // with language options, not in the class options, see
1243 // http://www.lyx.org/trac/ticket/4597#c4
1244 size_t japan = language_options.str().find("japanese");
1245 if (lyxrc.language_global_options && !language_options.str().empty()
1246 && viet == string::npos && japan == string::npos
1247 && latvian == string::npos && lithu == string::npos
1248 && mongo == string::npos && turkmen == string::npos)
1249 clsoptions << language_options.str() << ',';
1252 // the predefined options from the layout
1253 if (use_default_options && !tclass.options().empty())
1254 clsoptions << tclass.options() << ',';
1256 // the user-defined options
1257 if (!options.empty()) {
1258 clsoptions << options << ',';
1261 string strOptions(clsoptions.str());
1262 if (!strOptions.empty()) {
1263 strOptions = rtrim(strOptions, ",");
1265 os << '[' << from_utf8(strOptions) << ']';
1268 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1270 // end of \documentclass defs
1273 os << "\\usepackage{fontspec}\n";
1277 // font selection must be done before loading fontenc.sty
1278 string const fonts =
1279 loadFonts(fontsRoman, fontsSans,
1280 fontsTypewriter, fontsSC, fontsOSF,
1281 fontsSansScale, fontsTypewriterScale, useXetex);
1282 if (!fonts.empty()) {
1283 os << from_ascii(fonts);
1286 if (fontsDefaultFamily != "default")
1287 os << "\\renewcommand{\\familydefault}{\\"
1288 << from_ascii(fontsDefaultFamily) << "}\n";
1290 // set font encoding
1291 // for arabic_arabi and farsi we also need to load the LAE and
1293 // XeTeX works without fontenc
1294 if (font_encoding() != "default" && language->lang() != "japanese"
1296 if (language->lang() == "arabic_arabi"
1297 || language->lang() == "farsi") {
1298 os << "\\usepackage[" << from_ascii(font_encoding())
1299 << ",LFE,LAE]{fontenc}\n";
1302 os << "\\usepackage[" << from_ascii(font_encoding())
1308 // handle inputenc etc.
1309 writeEncodingPreamble(os, features, texrow);
1312 if (!features.runparams().includeall && !includedChildren_.empty()) {
1313 os << "\\includeonly{";
1314 list<string>::const_iterator it = includedChildren_.begin();
1316 for (; it != includedChildren_.end() ; ++it) {
1317 string incfile = *it;
1318 FileName inc = makeAbsPath(incfile, filepath.absFilename());
1319 string mangled = DocFileName(changeExtension(inc.absFilename(), ".tex")).
1321 if (!features.runparams().nice)
1323 // \includeonly doesn't want an extension
1324 incfile = changeExtension(incfile, string());
1325 incfile = support::latex_path(incfile);
1326 if (!incfile.empty()) {
1329 os << from_utf8(incfile);
1336 if (!listings_params.empty() || features.isRequired("listings")) {
1337 os << "\\usepackage{listings}\n";
1340 if (!listings_params.empty()) {
1342 // do not test validity because listings_params is
1343 // supposed to be valid
1345 InsetListingsParams(listings_params).separatedParams(true);
1346 // we can't support all packages, but we should load the color package
1347 if (par.find("\\color", 0) != string::npos)
1348 features.require("color");
1349 os << from_utf8(par);
1350 // count the number of newlines
1351 for (size_t i = 0; i < par.size(); ++i)
1357 if (!tclass.provides("geometry")
1358 && (use_geometry || nonstandard_papersize)) {
1359 odocstringstream ods;
1360 if (!getGraphicsDriver("geometry").empty())
1361 ods << getGraphicsDriver("geometry");
1362 if (orientation == ORIENTATION_LANDSCAPE)
1363 ods << ",landscape";
1364 switch (papersize) {
1366 if (!paperwidth.empty())
1367 ods << ",paperwidth="
1368 << from_ascii(paperwidth);
1369 if (!paperheight.empty())
1370 ods << ",paperheight="
1371 << from_ascii(paperheight);
1373 case PAPER_USLETTER:
1374 ods << ",letterpaper";
1377 ods << ",legalpaper";
1379 case PAPER_USEXECUTIVE:
1380 ods << ",executivepaper";
1401 // default papersize ie PAPER_DEFAULT
1402 switch (lyxrc.default_papersize) {
1403 case PAPER_DEFAULT: // keep compiler happy
1404 case PAPER_USLETTER:
1405 ods << ",letterpaper";
1408 ods << ",legalpaper";
1410 case PAPER_USEXECUTIVE:
1411 ods << ",executivepaper";
1431 docstring const g_options = trim(ods.str(), ",");
1432 os << "\\usepackage";
1433 if (!g_options.empty())
1434 os << '[' << g_options << ']';
1435 os << "{geometry}\n";
1437 os << "\\geometry{verbose";
1438 if (!topmargin.empty())
1439 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1440 if (!bottommargin.empty())
1441 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1442 if (!leftmargin.empty())
1443 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1444 if (!rightmargin.empty())
1445 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1446 if (!headheight.empty())
1447 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1448 if (!headsep.empty())
1449 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1450 if (!footskip.empty())
1451 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1452 if (!columnsep.empty())
1453 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1456 } else if (orientation == ORIENTATION_LANDSCAPE) {
1457 features.require("papersize");
1460 if (tokenPos(tclass.opt_pagestyle(),
1461 '|', pagestyle) >= 0) {
1462 if (pagestyle == "fancy") {
1463 os << "\\usepackage{fancyhdr}\n";
1466 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1470 // only output when the background color is not default
1471 if (isbackgroundcolor == true) {
1472 // only require color here, the background color will be defined
1473 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1475 features.require("color");
1476 features.require("pagecolor");
1479 // only output when the font color is not default
1480 if (isfontcolor == true) {
1481 // only require color here, the font color will be defined
1482 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1484 features.require("color");
1485 features.require("fontcolor");
1488 // Only if class has a ToC hierarchy
1489 if (tclass.hasTocLevels()) {
1490 if (secnumdepth != tclass.secnumdepth()) {
1491 os << "\\setcounter{secnumdepth}{"
1496 if (tocdepth != tclass.tocdepth()) {
1497 os << "\\setcounter{tocdepth}{"
1504 if (paragraph_separation) {
1505 // when skip separation
1506 switch (getDefSkip().kind()) {
1507 case VSpace::SMALLSKIP:
1508 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1510 case VSpace::MEDSKIP:
1511 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1513 case VSpace::BIGSKIP:
1514 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1516 case VSpace::LENGTH:
1517 os << "\\setlength{\\parskip}{"
1518 << from_utf8(getDefSkip().length().asLatexString())
1521 default: // should never happen // Then delete it.
1522 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1526 os << "\\setlength{\\parindent}{0pt}\n";
1529 // when separation by indentation
1530 // only output something when a width is given
1531 if (getIndentation().asLyXCommand() != "default") {
1532 os << "\\setlength{\\parindent}{"
1533 << from_utf8(getIndentation().asLatexCommand())
1539 // Now insert the LyX specific LaTeX commands...
1540 docstring lyxpreamble;
1542 // due to interferences with babel and hyperref, the color package has to
1543 // be loaded (when it is not already loaded) before babel when hyperref
1544 // is used with the colorlinks option, see
1545 // http://www.lyx.org/trac/ticket/5291
1546 // we decided therefore to load color always before babel, see
1547 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
1548 lyxpreamble += from_ascii(features.getColorOptions());
1550 // If we use hyperref, jurabib, japanese, or vietnamese, we have to call babel before them.
1552 && (features.isRequired("jurabib")
1553 || features.isRequired("hyperref")
1554 || features.isRequired("vietnamese")
1555 || features.isRequired("japanese") ) ) {
1557 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1558 lyxpreamble += from_utf8(features.getBabelOptions()) + '\n';
1561 // The optional packages;
1562 lyxpreamble += from_ascii(features.getPackages());
1564 // Additional Indices
1565 if (features.isRequired("splitidx")) {
1566 IndicesList::const_iterator iit = indiceslist().begin();
1567 IndicesList::const_iterator iend = indiceslist().end();
1568 for (; iit != iend; ++iit) {
1569 lyxpreamble += "\\newindex[";
1570 lyxpreamble += iit->index();
1571 lyxpreamble += "]{";
1572 lyxpreamble += iit->shortcut();
1573 lyxpreamble += "}\n";
1578 lyxpreamble += from_utf8(spacing().writePreamble(tclass.provides("SetSpace")));
1581 // * Hyperref manual: "Make sure it comes last of your loaded
1582 // packages, to give it a fighting chance of not being over-written,
1583 // since its job is to redefine many LaTeX commands."
1584 // * Email from Heiko Oberdiek: "It is usually better to load babel
1585 // before hyperref. Then hyperref has a chance to detect babel.
1586 // * Has to be loaded before the "LyX specific LaTeX commands" to
1587 // avoid errors with algorithm floats.
1588 // use hyperref explicitly if it is required
1589 if (features.isRequired("hyperref")) {
1590 // pass what we have to stream here, since we need
1591 // to access the stream itself in PDFOptions.
1595 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1597 OutputParams tmp_params = features.runparams();
1598 lines += pdfoptions().writeLaTeX(tmp_params, os,
1599 documentClass().provides("hyperref"));
1600 texrow.newlines(lines);
1601 // set back for the rest
1602 lyxpreamble.clear();
1605 // Will be surrounded by \makeatletter and \makeatother when not empty
1606 docstring atlyxpreamble;
1608 // Some macros LyX will need
1609 docstring tmppreamble(features.getMacros());
1611 if (!tmppreamble.empty())
1612 atlyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1613 "LyX specific LaTeX commands.\n"
1614 + tmppreamble + '\n';
1616 // the text class specific preamble
1617 tmppreamble = features.getTClassPreamble();
1618 if (!tmppreamble.empty())
1619 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1620 "Textclass specific LaTeX commands.\n"
1621 + tmppreamble + '\n';
1623 // suppress date if selected
1624 // use \@ifundefined because we cannot be sure that every document class
1625 // has a \date command
1627 atlyxpreamble += "\\@ifundefined{date}{}{\\date{}}\n";
1629 /* the user-defined preamble */
1630 if (!containsOnly(preamble, " \n\t"))
1632 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1633 "User specified LaTeX commands.\n"
1634 + from_utf8(preamble) + '\n';
1636 // subfig loads internally the LaTeX package "caption". As
1637 // caption is a very popular package, users will load it in
1638 // the preamble. Therefore we must load subfig behind the
1639 // user-defined preamble and check if the caption package was
1640 // loaded or not. For the case that caption is loaded before
1641 // subfig, there is the subfig option "caption=false". This
1642 // option also works when a koma-script class is used and
1643 // koma's own caption commands are used instead of caption. We
1644 // use \PassOptionsToPackage here because the user could have
1645 // already loaded subfig in the preamble.
1646 if (features.isRequired("subfig")) {
1647 atlyxpreamble += "\\@ifundefined{showcaptionsetup}{}{%\n"
1648 " \\PassOptionsToPackage{caption=false}{subfig}}\n"
1649 "\\usepackage{subfig}\n";
1652 // Itemize bullet settings need to be last in case the user
1653 // defines their own bullets that use a package included
1654 // in the user-defined preamble -- ARRae
1655 // Actually it has to be done much later than that
1656 // since some packages like frenchb make modifications
1657 // at \begin{document} time -- JMarc
1658 docstring bullets_def;
1659 for (int i = 0; i < 4; ++i) {
1660 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1661 if (bullets_def.empty())
1662 bullets_def += "\\AtBeginDocument{\n";
1663 bullets_def += " \\def\\labelitemi";
1665 // `i' is one less than the item to modify
1672 bullets_def += "ii";
1678 bullets_def += '{' +
1679 user_defined_bullet(i).getText()
1684 if (!bullets_def.empty())
1685 atlyxpreamble += bullets_def + "}\n\n";
1687 if (!atlyxpreamble.empty())
1688 lyxpreamble += "\n\\makeatletter\n"
1689 + atlyxpreamble + "\\makeatother\n\n";
1691 // We try to load babel late, in case it interferes with other packages.
1692 // Jurabib and Hyperref have to be called after babel, though.
1693 if (use_babel && !features.isRequired("jurabib")
1694 && !features.isRequired("hyperref")
1695 && !features.isRequired("vietnamese")
1696 && !features.isRequired("japanese")) {
1698 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1699 lyxpreamble += from_utf8(features.getBabelOptions()) + '\n';
1702 docstring const i18npreamble = features.getTClassI18nPreamble(use_babel);
1703 if (!i18npreamble.empty())
1704 lyxpreamble += i18npreamble + '\n';
1707 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1708 texrow.newlines(nlines);
1712 // these packages (xunicode, for that matter) need to be loaded at least
1713 // after amsmath, amssymb, esint and the other packages that provide
1716 os << "\\usepackage{xunicode}\n";
1718 os << "\\usepackage{xltxtra}\n";
1725 void BufferParams::useClassDefaults()
1727 DocumentClass const & tclass = documentClass();
1729 sides = tclass.sides();
1730 columns = tclass.columns();
1731 pagestyle = tclass.pagestyle();
1732 use_default_options = true;
1733 // Only if class has a ToC hierarchy
1734 if (tclass.hasTocLevels()) {
1735 secnumdepth = tclass.secnumdepth();
1736 tocdepth = tclass.tocdepth();
1741 bool BufferParams::hasClassDefaults() const
1743 DocumentClass const & tclass = documentClass();
1745 return sides == tclass.sides()
1746 && columns == tclass.columns()
1747 && pagestyle == tclass.pagestyle()
1748 && use_default_options
1749 && secnumdepth == tclass.secnumdepth()
1750 && tocdepth == tclass.tocdepth();
1754 DocumentClass const & BufferParams::documentClass() const
1760 DocumentClass const * BufferParams::documentClassPtr() const {
1765 void BufferParams::setDocumentClass(DocumentClass const * const tc) {
1766 // evil, but this function is evil
1767 doc_class_ = const_cast<DocumentClass *>(tc);
1771 bool BufferParams::setBaseClass(string const & classname)
1773 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
1774 LayoutFileList & bcl = LayoutFileList::get();
1775 if (!bcl.haveClass(classname)) {
1777 bformat(_("The layout file:\n"
1779 "could not be found. A default textclass with default\n"
1780 "layouts will be used. LyX will not be able to produce\n"
1782 from_utf8(classname));
1783 frontend::Alert::error(_("Document class not found"), s);
1784 bcl.addEmptyClass(classname);
1787 bool const success = bcl[classname].load();
1790 bformat(_("Due to some error in it, the layout file:\n"
1792 "could not be loaded. A default textclass with default\n"
1793 "layouts will be used. LyX will not be able to produce\n"
1795 from_utf8(classname));
1796 frontend::Alert::error(_("Could not load class"), s);
1797 bcl.addEmptyClass(classname);
1800 pimpl_->baseClass_ = classname;
1801 layoutModules_.adaptToBaseClass(baseClass(), removedModules_);
1806 LayoutFile const * BufferParams::baseClass() const
1808 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
1809 return &(LayoutFileList::get()[pimpl_->baseClass_]);
1815 LayoutFileIndex const & BufferParams::baseClassID() const
1817 return pimpl_->baseClass_;
1821 void BufferParams::makeDocumentClass()
1826 doc_class_ = &(DocumentClassBundle::get().makeDocumentClass(*baseClass(), layoutModules_));
1828 if (!local_layout.empty()) {
1829 if (!doc_class_->read(local_layout, TextClass::MODULE)) {
1830 docstring const msg = _("Error reading internal layout information");
1831 frontend::Alert::warning(_("Read Error"), msg);
1837 bool BufferParams::moduleCanBeAdded(string const & modName) const
1839 return layoutModules_.moduleCanBeAdded(modName, baseClass());
1843 bool BufferParams::addLayoutModule(string const & modName)
1845 LayoutModuleList::const_iterator it = layoutModules_.begin();
1846 LayoutModuleList::const_iterator end = layoutModules_.end();
1847 for (; it != end; it++)
1850 layoutModules_.push_back(modName);
1855 Font const BufferParams::getFont() const
1857 FontInfo f = documentClass().defaultfont();
1858 if (fontsDefaultFamily == "rmdefault")
1859 f.setFamily(ROMAN_FAMILY);
1860 else if (fontsDefaultFamily == "sfdefault")
1861 f.setFamily(SANS_FAMILY);
1862 else if (fontsDefaultFamily == "ttdefault")
1863 f.setFamily(TYPEWRITER_FAMILY);
1864 return Font(f, language);
1868 void BufferParams::readPreamble(Lexer & lex)
1870 if (lex.getString() != "\\begin_preamble")
1871 lyxerr << "Error (BufferParams::readPreamble):"
1872 "consistency check failed." << endl;
1874 preamble = lex.getLongString("\\end_preamble");
1878 void BufferParams::readLocalLayout(Lexer & lex)
1880 if (lex.getString() != "\\begin_local_layout")
1881 lyxerr << "Error (BufferParams::readLocalLayout):"
1882 "consistency check failed." << endl;
1884 local_layout = lex.getLongString("\\end_local_layout");
1888 void BufferParams::readLanguage(Lexer & lex)
1890 if (!lex.next()) return;
1892 string const tmptok = lex.getString();
1894 // check if tmptok is part of tex_babel in tex-defs.h
1895 language = languages.getLanguage(tmptok);
1897 // Language tmptok was not found
1898 language = default_language;
1899 lyxerr << "Warning: Setting language `"
1900 << tmptok << "' to `" << language->lang()
1906 void BufferParams::readGraphicsDriver(Lexer & lex)
1911 string const tmptok = lex.getString();
1912 // check if tmptok is part of tex_graphics in tex_defs.h
1915 string const test = tex_graphics[n++];
1917 if (test == tmptok) {
1918 graphicsDriver = tmptok;
1923 "Warning: graphics driver `$$Token' not recognized!\n"
1924 " Setting graphics driver to `default'.\n");
1925 graphicsDriver = "default";
1932 void BufferParams::readBullets(Lexer & lex)
1937 int const index = lex.getInteger();
1939 int temp_int = lex.getInteger();
1940 user_defined_bullet(index).setFont(temp_int);
1941 temp_bullet(index).setFont(temp_int);
1943 user_defined_bullet(index).setCharacter(temp_int);
1944 temp_bullet(index).setCharacter(temp_int);
1946 user_defined_bullet(index).setSize(temp_int);
1947 temp_bullet(index).setSize(temp_int);
1951 void BufferParams::readBulletsLaTeX(Lexer & lex)
1953 // The bullet class should be able to read this.
1956 int const index = lex.getInteger();
1958 docstring const temp_str = lex.getDocString();
1960 user_defined_bullet(index).setText(temp_str);
1961 temp_bullet(index).setText(temp_str);
1965 void BufferParams::readModules(Lexer & lex)
1967 if (!lex.eatLine()) {
1968 lyxerr << "Error (BufferParams::readModules):"
1969 "Unexpected end of input." << endl;
1973 string mod = lex.getString();
1974 if (mod == "\\end_modules")
1976 addLayoutModule(mod);
1982 void BufferParams::readRemovedModules(Lexer & lex)
1984 if (!lex.eatLine()) {
1985 lyxerr << "Error (BufferParams::readRemovedModules):"
1986 "Unexpected end of input." << endl;
1990 string mod = lex.getString();
1991 if (mod == "\\end_removed_modules")
1993 removedModules_.push_back(mod);
1996 // now we want to remove any removed modules that were previously
1997 // added. normally, that will be because default modules were added in
1998 // setBaseClass(), which gets called when \textclass is read at the
1999 // start of the read.
2000 list<string>::const_iterator rit = removedModules_.begin();
2001 list<string>::const_iterator const ren = removedModules_.end();
2002 for (; rit != ren; rit++) {
2003 LayoutModuleList::iterator const mit = layoutModules_.begin();
2004 LayoutModuleList::iterator const men = layoutModules_.end();
2005 LayoutModuleList::iterator found = find(mit, men, *rit);
2008 layoutModules_.erase(found);
2013 void BufferParams::readIncludeonly(Lexer & lex)
2015 if (!lex.eatLine()) {
2016 lyxerr << "Error (BufferParams::readIncludeonly):"
2017 "Unexpected end of input." << endl;
2021 string child = lex.getString();
2022 if (child == "\\end_includeonly")
2024 includedChildren_.push_back(child);
2030 string BufferParams::paperSizeName(PapersizePurpose purpose) const
2032 char real_papersize = papersize;
2033 if (real_papersize == PAPER_DEFAULT)
2034 real_papersize = lyxrc.default_papersize;
2036 switch (real_papersize) {
2038 // could be anything, so don't guess
2040 case PAPER_CUSTOM: {
2041 if (purpose == XDVI && !paperwidth.empty() &&
2042 !paperheight.empty()) {
2043 // heightxwidth<unit>
2044 string first = paperwidth;
2045 string second = paperheight;
2046 if (orientation == ORIENTATION_LANDSCAPE)
2049 return first.erase(first.length() - 2)
2061 // dvips and dvipdfm do not know this
2062 if (purpose == DVIPS || purpose == DVIPDFM)
2066 // dvipdfm does not know this
2067 if (purpose == DVIPDFM)
2071 // dvipdfm does not know this
2072 if (purpose == DVIPDFM)
2075 case PAPER_USEXECUTIVE:
2076 // dvipdfm does not know this
2077 if (purpose == DVIPDFM)
2082 case PAPER_USLETTER:
2084 if (purpose == XDVI)
2091 string const BufferParams::dvips_options() const
2096 && papersize == PAPER_CUSTOM
2097 && !lyxrc.print_paper_dimension_flag.empty()
2098 && !paperwidth.empty()
2099 && !paperheight.empty()) {
2100 // using a custom papersize
2101 result = lyxrc.print_paper_dimension_flag;
2102 result += ' ' + paperwidth;
2103 result += ',' + paperheight;
2105 string const paper_option = paperSizeName(DVIPS);
2106 if (!paper_option.empty() && (paper_option != "letter" ||
2107 orientation != ORIENTATION_LANDSCAPE)) {
2108 // dvips won't accept -t letter -t landscape.
2109 // In all other cases, include the paper size
2111 result = lyxrc.print_paper_flag;
2112 result += ' ' + paper_option;
2115 if (orientation == ORIENTATION_LANDSCAPE &&
2116 papersize != PAPER_CUSTOM)
2117 result += ' ' + lyxrc.print_landscape_flag;
2122 string const BufferParams::font_encoding() const
2124 return (fontenc == "global") ? lyxrc.fontenc : fontenc;
2128 string BufferParams::babelCall(string const & lang_opts) const
2130 string lang_pack = lyxrc.language_package;
2131 if (lang_pack != "\\usepackage{babel}")
2133 // suppress the babel call when there is no babel language defined
2134 // for the document language in the lib/languages file and if no
2135 // other languages are used (lang_opts is then empty)
2136 if (lang_opts.empty())
2138 // If Vietnamese is used, babel must directly be loaded with the
2139 // language options, see
2140 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
2141 size_t viet = lang_opts.find("vietnam");
2142 // viet = string::npos when not found
2143 // the same is for all other languages that are not directly supported by
2144 // babel, but where LaTeX-packages add babel support.
2145 // this is currently the case for Latvian, Lithuanian, Mongolian
2147 size_t latvian = lang_opts.find("latvian");
2148 size_t lithu = lang_opts.find("lithuanian");
2149 size_t mongo = lang_opts.find("mongolian");
2150 size_t turkmen = lang_opts.find("turkmen");
2151 // If Japanese is used, babel must directly be loaded with the
2152 // language options, see
2153 // http://www.lyx.org/trac/ticket/4597#c4
2154 size_t japan = lang_opts.find("japanese");
2155 if (!lyxrc.language_global_options || viet != string::npos
2156 || japan != string::npos || latvian != string::npos
2157 || lithu != string::npos || mongo != string::npos
2158 || turkmen != string::npos)
2159 return "\\usepackage[" + lang_opts + "]{babel}";
2164 docstring BufferParams::getGraphicsDriver(string const & package) const
2168 if (package == "geometry") {
2169 if (graphicsDriver == "dvips"
2170 || graphicsDriver == "dvipdfm"
2171 || graphicsDriver == "pdftex"
2172 || graphicsDriver == "vtex")
2173 result = from_ascii(graphicsDriver);
2174 else if (graphicsDriver == "dvipdfmx")
2175 result = from_ascii("dvipdfm");
2182 void BufferParams::writeEncodingPreamble(odocstream & os,
2183 LaTeXFeatures & features, TexRow & texrow) const
2187 if (inputenc == "auto") {
2188 string const doc_encoding =
2189 language->encoding()->latexName();
2190 Encoding::Package const package =
2191 language->encoding()->package();
2193 // Create a list with all the input encodings used
2195 set<string> encodings =
2196 features.getEncodingSet(doc_encoding);
2198 // If the "japanese" package (i.e. pLaTeX) is used,
2199 // inputenc must be omitted.
2200 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
2201 if (package == Encoding::japanese)
2202 features.require("japanese");
2204 if ((!encodings.empty() || package == Encoding::inputenc)
2205 && !features.isRequired("japanese")) {
2206 os << "\\usepackage[";
2207 set<string>::const_iterator it = encodings.begin();
2208 set<string>::const_iterator const end = encodings.end();
2210 os << from_ascii(*it);
2213 for (; it != end; ++it)
2214 os << ',' << from_ascii(*it);
2215 if (package == Encoding::inputenc) {
2216 if (!encodings.empty())
2218 os << from_ascii(doc_encoding);
2220 os << "]{inputenc}\n";
2223 if (package == Encoding::CJK || features.mustProvide("CJK")) {
2224 if (language->encoding()->name() == "utf8-cjk"
2225 && LaTeXFeatures::isAvailable("CJKutf8"))
2226 os << "\\usepackage{CJKutf8}\n";
2228 os << "\\usepackage{CJK}\n";
2231 } else if (inputenc != "default") {
2232 switch (encoding().package()) {
2233 case Encoding::none:
2234 case Encoding::japanese:
2236 case Encoding::inputenc:
2237 // do not load inputenc if japanese is used
2238 if (features.isRequired("japanese"))
2240 os << "\\usepackage[" << from_ascii(inputenc)
2245 if (encoding().name() == "utf8-cjk"
2246 && LaTeXFeatures::isAvailable("CJKutf8"))
2247 os << "\\usepackage{CJKutf8}\n";
2249 os << "\\usepackage{CJK}\n";
2255 // The encoding "armscii8" (for Armenian) is only available when
2256 // the package "armtex" is loaded.
2257 if (language->encoding()->latexName() == "armscii8"
2258 || inputenc == "armscii8") {
2259 os << "\\usepackage{armtex}\n";
2265 string const BufferParams::parseFontName(string const & name) const
2267 string mangled = name;
2268 size_t const idx = mangled.find('[');
2269 if (idx == string::npos || idx == 0)
2272 return mangled.substr(0, idx - 1);
2276 string const BufferParams::loadFonts(string const & rm,
2277 string const & sf, string const & tt,
2278 bool const & sc, bool const & osf,
2279 int const & sfscale, int const & ttscale,
2280 bool const & xetex) const
2282 /* The LaTeX font world is in a flux. In the PSNFSS font interface,
2283 several packages have been replaced by others, that might not
2284 be installed on every system. We have to take care for that
2285 (see psnfss.pdf). We try to support all psnfss fonts as well
2286 as the fonts that have become de facto standard in the LaTeX
2287 world (e.g. Latin Modern). We do not support obsolete fonts
2288 (like PSLatex). In general, it should be possible to mix any
2289 rm font with any sf or tt font, respectively. (JSpitzm)
2291 -- separate math fonts.
2294 if (rm == "default" && sf == "default" && tt == "default")
2301 if (rm != "default")
2302 os << "\\setmainfont[Mapping=tex-text]{"
2303 << parseFontName(rm) << "}\n";
2304 if (sf != "default") {
2305 string const sans = parseFontName(sf);
2307 os << "\\setsansfont[Scale="
2308 << float(sfscale) / 100
2309 << ",Mapping=tex-text]{"
2312 os << "\\setsansfont[Mapping=tex-text]{"
2315 if (tt != "default") {
2316 string const mono = parseFontName(tt);
2318 os << "\\setmonofont[Scale="
2319 << float(sfscale) / 100
2323 os << "\\setmonofont[Mapping=tex-text]{"
2327 os << "\\defaultfontfeatures{Numbers=OldStyle}\n";
2332 // Computer Modern (must be explicitly selectable -- there might be classes
2333 // that define a different default font!
2335 os << "\\renewcommand{\\rmdefault}{cmr}\n";
2336 // osf for Computer Modern needs eco.sty
2338 os << "\\usepackage{eco}\n";
2340 // Latin Modern Roman
2341 else if (rm == "lmodern")
2342 os << "\\usepackage{lmodern}\n";
2344 else if (rm == "ae") {
2345 // not needed when using OT1 font encoding.
2346 if (font_encoding() != "default")
2347 os << "\\usepackage{ae,aecompl}\n";
2350 else if (rm == "times") {
2351 // try to load the best available package
2352 if (LaTeXFeatures::isAvailable("mathptmx"))
2353 os << "\\usepackage{mathptmx}\n";
2354 else if (LaTeXFeatures::isAvailable("mathptm"))
2355 os << "\\usepackage{mathptm}\n";
2357 os << "\\usepackage{times}\n";
2360 else if (rm == "palatino") {
2361 // try to load the best available package
2362 if (LaTeXFeatures::isAvailable("mathpazo")) {
2363 os << "\\usepackage";
2369 // "osf" includes "sc"!
2373 os << "{mathpazo}\n";
2375 else if (LaTeXFeatures::isAvailable("mathpple"))
2376 os << "\\usepackage{mathpple}\n";
2378 os << "\\usepackage{palatino}\n";
2381 else if (rm == "utopia") {
2382 // fourier supersedes utopia.sty, but does
2383 // not work with OT1 encoding.
2384 if (LaTeXFeatures::isAvailable("fourier")
2385 && font_encoding() != "default") {
2386 os << "\\usepackage";
2397 os << "{fourier}\n";
2400 os << "\\usepackage{utopia}\n";
2402 // Bera (complete fontset)
2403 else if (rm == "bera" && sf == "default" && tt == "default")
2404 os << "\\usepackage{bera}\n";
2406 else if (rm != "default")
2407 os << "\\usepackage" << "{" << rm << "}\n";
2410 // Helvetica, Bera Sans
2411 if (sf == "helvet" || sf == "berasans") {
2413 os << "\\usepackage[scaled=" << float(sfscale) / 100
2414 << "]{" << sf << "}\n";
2416 os << "\\usepackage{" << sf << "}\n";
2419 else if (sf == "avant")
2420 os << "\\usepackage{" << sf << "}\n";
2421 // Computer Modern, Latin Modern, CM Bright
2422 else if (sf != "default")
2423 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
2425 // monospaced/typewriter
2426 // Courier, LuxiMono
2427 if (tt == "luximono" || tt == "beramono") {
2429 os << "\\usepackage[scaled=" << float(ttscale) / 100
2430 << "]{" << tt << "}\n";
2432 os << "\\usepackage{" << tt << "}\n";
2435 else if (tt == "courier" )
2436 os << "\\usepackage{" << tt << "}\n";
2437 // Computer Modern, Latin Modern, CM Bright
2438 else if (tt != "default")
2439 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
2445 Encoding const & BufferParams::encoding() const
2448 return *(encodings.fromLaTeXName("utf8-plain"));
2449 if (inputenc == "auto" || inputenc == "default")
2450 return *language->encoding();
2451 Encoding const * const enc = encodings.fromLaTeXName(inputenc);
2454 LYXERR0("Unknown inputenc value `" << inputenc
2455 << "'. Using `auto' instead.");
2456 return *language->encoding();
2460 CiteEngine BufferParams::citeEngine() const
2462 // FIXME the class should provide the numerical/
2463 // authoryear choice
2464 if (documentClass().provides("natbib")
2465 && cite_engine_ != ENGINE_NATBIB_NUMERICAL)
2466 return ENGINE_NATBIB_AUTHORYEAR;
2467 return cite_engine_;
2471 void BufferParams::setCiteEngine(CiteEngine cite_engine)
2473 cite_engine_ = cite_engine;