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 "a0paper", "a1paper", "a2paper", "a3paper", "a4paper", "a5paper",
76 "a6paper", "b0paper", "b1paper", "b2paper","b3paper", "b4paper",
77 "b5paper", "b6paper", "c0paper", "c1paper", "c2paper", "c3paper",
78 "c4paper", "c5paper", "c6paper", "b0j", "b1j", "b2j", "b3j", "b4j", "b5j",
83 static char const * const string_orientation[] = {
84 "portrait", "landscape", ""
88 static char const * const string_footnotekinds[] = {
89 "footnote", "margin", "fig", "tab", "alg", "wide-fig", "wide-tab", ""
93 static char const * const tex_graphics[] = {
94 "default", "dvialw", "dvilaser", "dvipdf", "dvipdfm", "dvipdfmx",
95 "dvips", "dvipsone", "dvitops", "dviwin", "dviwindo", "dvi2ps", "emtex",
96 "ln", "oztex", "pctexhp", "pctexps", "pctexwin", "pctex32", "pdftex",
97 "psprint", "pubps", "tcidvi", "textures", "truetex", "vtex", "xdvi",
108 // Paragraph separation
109 typedef Translator<string, BufferParams::ParagraphSeparation> ParSepTranslator;
112 ParSepTranslator const init_parseptranslator()
114 ParSepTranslator translator
115 (string_paragraph_separation[0], BufferParams::ParagraphIndentSeparation);
116 translator.addPair(string_paragraph_separation[1], BufferParams::ParagraphSkipSeparation);
121 ParSepTranslator const & parseptranslator()
123 static ParSepTranslator translator = init_parseptranslator();
129 typedef Translator<string, InsetQuotes::QuoteLanguage> QuotesLangTranslator;
132 QuotesLangTranslator const init_quoteslangtranslator()
134 QuotesLangTranslator translator
135 (string_quotes_language[0], InsetQuotes::EnglishQuotes);
136 translator.addPair(string_quotes_language[1], InsetQuotes::SwedishQuotes);
137 translator.addPair(string_quotes_language[2], InsetQuotes::GermanQuotes);
138 translator.addPair(string_quotes_language[3], InsetQuotes::PolishQuotes);
139 translator.addPair(string_quotes_language[4], InsetQuotes::FrenchQuotes);
140 translator.addPair(string_quotes_language[5], InsetQuotes::DanishQuotes);
145 QuotesLangTranslator const & quoteslangtranslator()
147 static QuotesLangTranslator translator = init_quoteslangtranslator();
153 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
156 static PaperSizeTranslator initPaperSizeTranslator()
158 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
159 translator.addPair(string_papersize[1], PAPER_CUSTOM);
160 translator.addPair(string_papersize[2], PAPER_USLETTER);
161 translator.addPair(string_papersize[3], PAPER_USLEGAL);
162 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
163 translator.addPair(string_papersize[5], PAPER_A0);
164 translator.addPair(string_papersize[6], PAPER_A1);
165 translator.addPair(string_papersize[7], PAPER_A2);
166 translator.addPair(string_papersize[8], PAPER_A3);
167 translator.addPair(string_papersize[9], PAPER_A4);
168 translator.addPair(string_papersize[10], PAPER_A5);
169 translator.addPair(string_papersize[11], PAPER_A6);
170 translator.addPair(string_papersize[12], PAPER_B0);
171 translator.addPair(string_papersize[13], PAPER_B1);
172 translator.addPair(string_papersize[14], PAPER_B2);
173 translator.addPair(string_papersize[15], PAPER_B3);
174 translator.addPair(string_papersize[16], PAPER_B4);
175 translator.addPair(string_papersize[17], PAPER_B5);
176 translator.addPair(string_papersize[18], PAPER_B6);
177 translator.addPair(string_papersize[19], PAPER_C0);
178 translator.addPair(string_papersize[20], PAPER_C1);
179 translator.addPair(string_papersize[21], PAPER_C2);
180 translator.addPair(string_papersize[22], PAPER_C3);
181 translator.addPair(string_papersize[23], PAPER_C4);
182 translator.addPair(string_papersize[24], PAPER_C5);
183 translator.addPair(string_papersize[25], PAPER_C6);
184 translator.addPair(string_papersize[26], PAPER_JISB0);
185 translator.addPair(string_papersize[27], PAPER_JISB1);
186 translator.addPair(string_papersize[28], PAPER_JISB2);
187 translator.addPair(string_papersize[29], PAPER_JISB3);
188 translator.addPair(string_papersize[30], PAPER_JISB4);
189 translator.addPair(string_papersize[31], PAPER_JISB5);
190 translator.addPair(string_papersize[32], PAPER_JISB6);
195 PaperSizeTranslator const & papersizetranslator()
197 static PaperSizeTranslator translator = initPaperSizeTranslator();
203 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
206 PaperOrientationTranslator const init_paperorientationtranslator()
208 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
209 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
214 PaperOrientationTranslator const & paperorientationtranslator()
216 static PaperOrientationTranslator translator = init_paperorientationtranslator();
222 typedef Translator<int, PageSides> SidesTranslator;
225 SidesTranslator const init_sidestranslator()
227 SidesTranslator translator(1, OneSide);
228 translator.addPair(2, TwoSides);
233 SidesTranslator const & sidestranslator()
235 static SidesTranslator translator = init_sidestranslator();
241 typedef Translator<int, BufferParams::Package> PackageTranslator;
244 PackageTranslator const init_packagetranslator()
246 PackageTranslator translator(0, BufferParams::package_off);
247 translator.addPair(1, BufferParams::package_auto);
248 translator.addPair(2, BufferParams::package_on);
253 PackageTranslator const & packagetranslator()
255 static PackageTranslator translator = init_packagetranslator();
261 typedef Translator<string, CiteEngine> CiteEngineTranslator;
264 CiteEngineTranslator const init_citeenginetranslator()
266 CiteEngineTranslator translator("basic", ENGINE_BASIC);
267 translator.addPair("natbib_numerical", ENGINE_NATBIB_NUMERICAL);
268 translator.addPair("natbib_authoryear", ENGINE_NATBIB_AUTHORYEAR);
269 translator.addPair("jurabib", ENGINE_JURABIB);
274 CiteEngineTranslator const & citeenginetranslator()
276 static CiteEngineTranslator translator = init_citeenginetranslator();
282 typedef Translator<string, Spacing::Space> SpaceTranslator;
285 SpaceTranslator const init_spacetranslator()
287 SpaceTranslator translator("default", Spacing::Default);
288 translator.addPair("single", Spacing::Single);
289 translator.addPair("onehalf", Spacing::Onehalf);
290 translator.addPair("double", Spacing::Double);
291 translator.addPair("other", Spacing::Other);
296 SpaceTranslator const & spacetranslator()
298 static SpaceTranslator translator = init_spacetranslator();
305 class BufferParams::Impl
310 AuthorList authorlist;
311 BranchList branchlist;
312 Bullet temp_bullets[4];
313 Bullet user_defined_bullets[4];
314 IndicesList indiceslist;
316 /** This is the amount of space used for paragraph_separation "skip",
317 * and for detached paragraphs in "indented" documents.
321 PDFOptions pdfoptions;
322 LayoutFileIndex baseClass_;
326 BufferParams::Impl::Impl()
327 : defskip(VSpace::MEDSKIP), baseClass_(string(""))
329 // set initial author
331 authorlist.record(Author(from_utf8(lyxrc.user_name), from_utf8(lyxrc.user_email)));
336 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
340 return new BufferParams::Impl(*ptr);
344 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
350 BufferParams::BufferParams()
353 setBaseClass(defaultBaseclass());
355 paragraph_separation = ParagraphIndentSeparation;
356 quotes_language = InsetQuotes::EnglishQuotes;
357 fontsize = "default";
360 papersize = PAPER_DEFAULT;
361 orientation = ORIENTATION_PORTRAIT;
362 use_geometry = false;
363 use_amsmath = package_auto;
364 use_esint = package_auto;
365 use_mhchem = package_auto;
366 cite_engine_ = ENGINE_BASIC;
367 use_bibtopic = false;
369 trackChanges = false;
370 outputChanges = false;
371 use_default_options = true;
372 maintain_unincluded_children = false;
375 language = default_language;
377 fontsRoman = "default";
378 fontsSans = "default";
379 fontsTypewriter = "default";
380 fontsDefaultFamily = "default";
384 fontsSansScale = 100;
385 fontsTypewriterScale = 100;
387 graphicsDriver = "default";
388 defaultOutputFormat = "default";
389 bibtex_command = "default";
390 index_command = "default";
393 listings_params = string();
394 pagestyle = "default";
395 suppress_date = false;
396 // no color is the default (white)
397 backgroundcolor = lyx::rgbFromHexName("#ffffff");
398 isbackgroundcolor = false;
399 // no color is the default (black)
400 fontcolor = lyx::rgbFromHexName("#000000");
402 // light gray is the default font color for greyed-out notes
403 notefontcolor = lyx::rgbFromHexName("#cccccc");
404 boxbgcolor = lyx::rgbFromHexName("#ff0000");
405 compressed = lyxrc.save_compressed;
406 for (int iter = 0; iter < 4; ++iter) {
407 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
408 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
411 indiceslist().addDefault(B_("Index"));
412 html_be_strict = false;
413 html_math_output = MathML;
414 html_math_img_scale = 1.0;
420 docstring BufferParams::B_(string const & l10n) const
422 LASSERT(language, /**/);
423 return getMessages(language->code()).get(l10n);
427 AuthorList & BufferParams::authors()
429 return pimpl_->authorlist;
433 AuthorList const & BufferParams::authors() const
435 return pimpl_->authorlist;
439 BranchList & BufferParams::branchlist()
441 return pimpl_->branchlist;
445 BranchList const & BufferParams::branchlist() const
447 return pimpl_->branchlist;
451 IndicesList & BufferParams::indiceslist()
453 return pimpl_->indiceslist;
457 IndicesList const & BufferParams::indiceslist() const
459 return pimpl_->indiceslist;
463 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
465 LASSERT(index < 4, /**/);
466 return pimpl_->temp_bullets[index];
470 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
472 LASSERT(index < 4, /**/);
473 return pimpl_->temp_bullets[index];
477 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
479 LASSERT(index < 4, /**/);
480 return pimpl_->user_defined_bullets[index];
484 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
486 LASSERT(index < 4, /**/);
487 return pimpl_->user_defined_bullets[index];
491 Spacing & BufferParams::spacing()
493 return pimpl_->spacing;
497 Spacing const & BufferParams::spacing() const
499 return pimpl_->spacing;
503 PDFOptions & BufferParams::pdfoptions()
505 return pimpl_->pdfoptions;
509 PDFOptions const & BufferParams::pdfoptions() const
511 return pimpl_->pdfoptions;
515 HSpace const & BufferParams::getIndentation() const
517 return pimpl_->indentation;
521 void BufferParams::setIndentation(HSpace const & indent)
523 pimpl_->indentation = indent;
527 VSpace const & BufferParams::getDefSkip() const
529 return pimpl_->defskip;
533 void BufferParams::setDefSkip(VSpace const & vs)
535 pimpl_->defskip = vs;
539 string BufferParams::readToken(Lexer & lex, string const & token,
540 FileName const & filepath)
542 if (token == "\\textclass") {
544 string const classname = lex.getString();
545 // if there exists a local layout file, ignore the system one
546 // NOTE: in this case, the textclass (.cls file) is assumed to be available.
548 LayoutFileList & bcl = LayoutFileList::get();
549 if (tcp.empty() && !filepath.empty())
550 tcp = bcl.addLocalLayout(classname, filepath.absFileName());
554 setBaseClass(classname);
555 // We assume that a tex class exists for local or unknown layouts so this warning
556 // will only be given for system layouts.
557 if (!baseClass()->isTeXClassAvailable()) {
559 translateIfPossible(from_utf8(baseClass()->description()));
560 docstring const msg =
561 bformat(_("The selected document class\n"
563 "requires external files that are not available.\n"
564 "The document class can still be used, but LyX\n"
565 "will not be able to produce output until the\n"
566 "following prerequisites are installed:\n"
568 "See section 3.1.2.2 of the User's Guide for\n"
569 "more information."),
570 desc, from_utf8(baseClass()->prerequisites()));
571 frontend::Alert::warning(_("Document class not available"),
574 } else if (token == "\\begin_preamble") {
576 } else if (token == "\\begin_local_layout") {
577 readLocalLayout(lex);
578 } else if (token == "\\begin_modules") {
580 } else if (token == "\\begin_removed_modules") {
581 readRemovedModules(lex);
582 } else if (token == "\\begin_includeonly") {
583 readIncludeonly(lex);
584 } else if (token == "\\maintain_unincluded_children") {
585 lex >> maintain_unincluded_children;
586 } else if (token == "\\options") {
588 options = lex.getString();
589 } else if (token == "\\use_default_options") {
590 lex >> use_default_options;
591 } else if (token == "\\master") {
593 master = lex.getString();
594 } else if (token == "\\suppress_date") {
595 lex >> suppress_date;
596 } else if (token == "\\language") {
598 } else if (token == "\\inputencoding") {
600 } else if (token == "\\graphics") {
601 readGraphicsDriver(lex);
602 } else if (token == "\\default_output_format") {
603 lex >> defaultOutputFormat;
604 } else if (token == "\\bibtex_command") {
606 bibtex_command = lex.getString();
607 } else if (token == "\\index_command") {
609 index_command = lex.getString();
610 } else if (token == "\\fontencoding") {
612 fontenc = lex.getString();
613 } else if (token == "\\font_roman") {
615 fontsRoman = lex.getString();
616 } else if (token == "\\font_sans") {
618 fontsSans = lex.getString();
619 } else if (token == "\\font_typewriter") {
621 fontsTypewriter = lex.getString();
622 } else if (token == "\\font_default_family") {
623 lex >> fontsDefaultFamily;
624 } else if (token == "\\use_xetex") {
626 } else if (token == "\\font_sc") {
628 } else if (token == "\\font_osf") {
630 } else if (token == "\\font_sf_scale") {
631 lex >> fontsSansScale;
632 } else if (token == "\\font_tt_scale") {
633 lex >> fontsTypewriterScale;
634 } else if (token == "\\font_cjk") {
636 } else if (token == "\\paragraph_separation") {
639 paragraph_separation = parseptranslator().find(parsep);
640 } else if (token == "\\paragraph_indentation") {
642 string indentation = lex.getString();
643 pimpl_->indentation = HSpace(indentation);
644 } else if (token == "\\defskip") {
646 string defskip = lex.getString();
647 if (defskip == "defskip")
650 pimpl_->defskip = VSpace(defskip);
651 } else if (token == "\\quotes_language") {
654 quotes_language = quoteslangtranslator().find(quotes_lang);
655 } else if (token == "\\papersize") {
658 papersize = papersizetranslator().find(ppsize);
659 } else if (token == "\\use_geometry") {
661 } else if (token == "\\use_amsmath") {
664 use_amsmath = packagetranslator().find(use_ams);
665 } else if (token == "\\use_esint") {
668 use_esint = packagetranslator().find(useesint);
669 } else if (token == "\\use_mhchem") {
672 use_mhchem = packagetranslator().find(usemhchem);
673 } else if (token == "\\cite_engine") {
676 cite_engine_ = citeenginetranslator().find(engine);
677 } else if (token == "\\use_bibtopic") {
679 } else if (token == "\\use_indices") {
681 } else if (token == "\\tracking_changes") {
683 } else if (token == "\\output_changes") {
684 lex >> outputChanges;
685 } else if (token == "\\branch") {
687 docstring branch = lex.getDocString();
688 branchlist().add(branch);
691 string const tok = lex.getString();
692 if (tok == "\\end_branch")
694 Branch * branch_ptr = branchlist().find(branch);
695 if (tok == "\\selected") {
698 branch_ptr->setSelected(lex.getInteger());
700 if (tok == "\\filename_suffix") {
703 branch_ptr->setFileNameSuffix(lex.getInteger());
705 if (tok == "\\color") {
707 string color = lex.getString();
709 branch_ptr->setColor(color);
710 // Update also the Color table:
712 color = lcolor.getX11Name(Color_background);
714 lcolor.setColor(to_utf8(branch), color);
717 } else if (token == "\\index") {
719 docstring index = lex.getDocString();
721 indiceslist().add(index);
724 string const tok = lex.getString();
725 if (tok == "\\end_index")
727 Index * index_ptr = indiceslist().find(index);
728 if (tok == "\\shortcut") {
730 shortcut = lex.getDocString();
732 index_ptr->setShortcut(shortcut);
734 if (tok == "\\color") {
736 string color = lex.getString();
738 index_ptr->setColor(color);
739 // Update also the Color table:
741 color = lcolor.getX11Name(Color_background);
743 if (!shortcut.empty())
744 lcolor.setColor(to_utf8(shortcut), color);
747 } else if (token == "\\author") {
749 istringstream ss(lex.getString());
752 author_map[a.buffer_id()] = pimpl_->authorlist.record(a);
753 } else if (token == "\\paperorientation") {
756 orientation = paperorientationtranslator().find(orient);
757 } else if (token == "\\backgroundcolor") {
759 backgroundcolor = lyx::rgbFromHexName(lex.getString());
760 isbackgroundcolor = true;
761 } else if (token == "\\fontcolor") {
763 fontcolor = lyx::rgbFromHexName(lex.getString());
765 } else if (token == "\\notefontcolor") {
767 string color = lex.getString();
768 notefontcolor = lyx::rgbFromHexName(color);
769 } else if (token == "\\boxbgcolor") {
771 string color = lex.getString();
772 boxbgcolor = lyx::rgbFromHexName(color);
773 } else if (token == "\\paperwidth") {
775 } else if (token == "\\paperheight") {
777 } else if (token == "\\leftmargin") {
779 } else if (token == "\\topmargin") {
781 } else if (token == "\\rightmargin") {
783 } else if (token == "\\bottommargin") {
785 } else if (token == "\\headheight") {
787 } else if (token == "\\headsep") {
789 } else if (token == "\\footskip") {
791 } else if (token == "\\columnsep") {
793 } else if (token == "\\paperfontsize") {
795 } else if (token == "\\papercolumns") {
797 } else if (token == "\\listings_params") {
800 listings_params = InsetListingsParams(par).params();
801 } else if (token == "\\papersides") {
804 sides = sidestranslator().find(psides);
805 } else if (token == "\\paperpagestyle") {
807 } else if (token == "\\bullet") {
809 } else if (token == "\\bulletLaTeX") {
810 readBulletsLaTeX(lex);
811 } else if (token == "\\secnumdepth") {
813 } else if (token == "\\tocdepth") {
815 } else if (token == "\\spacing") {
819 if (nspacing == "other") {
822 spacing().set(spacetranslator().find(nspacing), tmp_val);
823 } else if (token == "\\float_placement") {
824 lex >> float_placement;
826 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
827 string toktmp = pdfoptions().readToken(lex, token);
828 if (!toktmp.empty()) {
829 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
833 } else if (token == "\\html_math_output") {
836 html_math_output = static_cast<MathOutput>(temp);
837 } else if (token == "\\html_be_strict") {
838 lex >> html_be_strict;
839 } else if (token == "\\html_math_img_scale") {
840 lex >> html_math_img_scale;
841 } else if (token == "\\html_latex_start") {
843 html_latex_start = lex.getString();
844 } else if (token == "\\html_latex_end") {
846 html_latex_end = lex.getString();
847 } else if (token == "\\output_sync") {
849 } else if (token == "\\output_sync_macro") {
850 lex >> output_sync_macro;
852 lyxerr << "BufferParams::readToken(): Unknown token: " <<
861 void BufferParams::writeFile(ostream & os) const
863 // The top of the file is written by the buffer.
864 // Prints out the buffer info into the .lyx file given by file
867 os << "\\textclass " << baseClass()->name() << '\n';
870 if (!preamble.empty()) {
871 // remove '\n' from the end of preamble
872 string const tmppreamble = rtrim(preamble, "\n");
873 os << "\\begin_preamble\n"
875 << "\n\\end_preamble\n";
879 if (!options.empty()) {
880 os << "\\options " << options << '\n';
883 // use the class options defined in the layout?
884 os << "\\use_default_options "
885 << convert<string>(use_default_options) << "\n";
887 // the master document
888 if (!master.empty()) {
889 os << "\\master " << master << '\n';
893 if (!removedModules_.empty()) {
894 os << "\\begin_removed_modules" << '\n';
895 list<string>::const_iterator it = removedModules_.begin();
896 list<string>::const_iterator en = removedModules_.end();
897 for (; it != en; it++)
899 os << "\\end_removed_modules" << '\n';
903 if (!layoutModules_.empty()) {
904 os << "\\begin_modules" << '\n';
905 LayoutModuleList::const_iterator it = layoutModules_.begin();
906 LayoutModuleList::const_iterator en = layoutModules_.end();
907 for (; it != en; it++)
909 os << "\\end_modules" << '\n';
913 if (!includedChildren_.empty()) {
914 os << "\\begin_includeonly" << '\n';
915 list<string>::const_iterator it = includedChildren_.begin();
916 list<string>::const_iterator en = includedChildren_.end();
917 for (; it != en; it++)
919 os << "\\end_includeonly" << '\n';
921 os << "\\maintain_unincluded_children "
922 << convert<string>(maintain_unincluded_children) << '\n';
924 // local layout information
925 if (!local_layout.empty()) {
926 // remove '\n' from the end
927 string const tmplocal = rtrim(local_layout, "\n");
928 os << "\\begin_local_layout\n"
930 << "\n\\end_local_layout\n";
933 // then the text parameters
934 if (language != ignore_language)
935 os << "\\language " << language->lang() << '\n';
936 os << "\\inputencoding " << inputenc
937 << "\n\\fontencoding " << fontenc
938 << "\n\\font_roman " << fontsRoman
939 << "\n\\font_sans " << fontsSans
940 << "\n\\font_typewriter " << fontsTypewriter
941 << "\n\\font_default_family " << fontsDefaultFamily
942 << "\n\\use_xetex " << convert<string>(useXetex)
943 << "\n\\font_sc " << convert<string>(fontsSC)
944 << "\n\\font_osf " << convert<string>(fontsOSF)
945 << "\n\\font_sf_scale " << fontsSansScale
946 << "\n\\font_tt_scale " << fontsTypewriterScale
948 if (!fontsCJK.empty()) {
949 os << "\\font_cjk " << fontsCJK << '\n';
951 os << "\n\\graphics " << graphicsDriver << '\n';
952 os << "\\default_output_format " << defaultOutputFormat << '\n';
953 os << "\\output_sync " << output_sync << '\n';
954 if (!output_sync_macro.empty())
955 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
956 os << "\\bibtex_command " << bibtex_command << '\n';
957 os << "\\index_command " << index_command << '\n';
959 if (!float_placement.empty()) {
960 os << "\\float_placement " << float_placement << '\n';
962 os << "\\paperfontsize " << fontsize << '\n';
964 spacing().writeFile(os);
965 pdfoptions().writeFile(os);
967 os << "\\papersize " << string_papersize[papersize]
968 << "\n\\use_geometry " << convert<string>(use_geometry)
969 << "\n\\use_amsmath " << use_amsmath
970 << "\n\\use_esint " << use_esint
971 << "\n\\use_mhchem " << use_mhchem
972 << "\n\\cite_engine " << citeenginetranslator().find(cite_engine_)
973 << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
974 << "\n\\use_indices " << convert<string>(use_indices)
975 << "\n\\paperorientation " << string_orientation[orientation]
976 << "\n\\suppress_date " << convert<string>(suppress_date)
978 if (isbackgroundcolor == true)
979 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
980 if (isfontcolor == true)
981 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
982 if (notefontcolor != lyx::rgbFromHexName("#cccccc"))
983 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
984 if (boxbgcolor != lyx::rgbFromHexName("#ff0000"))
985 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
987 BranchList::const_iterator it = branchlist().begin();
988 BranchList::const_iterator end = branchlist().end();
989 for (; it != end; ++it) {
990 os << "\\branch " << to_utf8(it->branch())
991 << "\n\\selected " << it->isSelected()
992 << "\n\\filename_suffix " << it->hasFileNameSuffix()
993 << "\n\\color " << lyx::X11hexname(it->color())
998 IndicesList::const_iterator iit = indiceslist().begin();
999 IndicesList::const_iterator iend = indiceslist().end();
1000 for (; iit != iend; ++iit) {
1001 os << "\\index " << to_utf8(iit->index())
1002 << "\n\\shortcut " << to_utf8(iit->shortcut())
1003 << "\n\\color " << lyx::X11hexname(iit->color())
1008 if (!paperwidth.empty())
1009 os << "\\paperwidth "
1010 << VSpace(paperwidth).asLyXCommand() << '\n';
1011 if (!paperheight.empty())
1012 os << "\\paperheight "
1013 << VSpace(paperheight).asLyXCommand() << '\n';
1014 if (!leftmargin.empty())
1015 os << "\\leftmargin "
1016 << VSpace(leftmargin).asLyXCommand() << '\n';
1017 if (!topmargin.empty())
1018 os << "\\topmargin "
1019 << VSpace(topmargin).asLyXCommand() << '\n';
1020 if (!rightmargin.empty())
1021 os << "\\rightmargin "
1022 << VSpace(rightmargin).asLyXCommand() << '\n';
1023 if (!bottommargin.empty())
1024 os << "\\bottommargin "
1025 << VSpace(bottommargin).asLyXCommand() << '\n';
1026 if (!headheight.empty())
1027 os << "\\headheight "
1028 << VSpace(headheight).asLyXCommand() << '\n';
1029 if (!headsep.empty())
1031 << VSpace(headsep).asLyXCommand() << '\n';
1032 if (!footskip.empty())
1034 << VSpace(footskip).asLyXCommand() << '\n';
1035 if (!columnsep.empty())
1036 os << "\\columnsep "
1037 << VSpace(columnsep).asLyXCommand() << '\n';
1038 os << "\\secnumdepth " << secnumdepth
1039 << "\n\\tocdepth " << tocdepth
1040 << "\n\\paragraph_separation "
1041 << string_paragraph_separation[paragraph_separation];
1042 if (!paragraph_separation)
1043 os << "\n\\paragraph_indentation " << getIndentation().asLyXCommand();
1045 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1046 os << "\n\\quotes_language "
1047 << string_quotes_language[quotes_language]
1048 << "\n\\papercolumns " << columns
1049 << "\n\\papersides " << sides
1050 << "\n\\paperpagestyle " << pagestyle << '\n';
1051 if (!listings_params.empty())
1052 os << "\\listings_params \"" <<
1053 InsetListingsParams(listings_params).encodedString() << "\"\n";
1054 for (int i = 0; i < 4; ++i) {
1055 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1056 if (user_defined_bullet(i).getFont() != -1) {
1057 os << "\\bullet " << i << " "
1058 << user_defined_bullet(i).getFont() << " "
1059 << user_defined_bullet(i).getCharacter() << " "
1060 << user_defined_bullet(i).getSize() << "\n";
1064 os << "\\bulletLaTeX " << i << " \""
1065 << lyx::to_ascii(user_defined_bullet(i).getText())
1071 os << "\\tracking_changes " << convert<string>(trackChanges) << '\n'
1072 << "\\output_changes " << convert<string>(outputChanges) << '\n'
1073 << "\\html_math_output " << html_math_output << '\n'
1074 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1076 if (html_math_img_scale != 1.0)
1077 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1078 if (!html_latex_start.empty())
1079 os << "\\html_latex_start " << html_latex_start << '\n';
1080 if (!html_latex_end.empty())
1081 os << "\\html_latex_end " << html_latex_end << '\n';
1083 os << pimpl_->authorlist;
1087 void BufferParams::validate(LaTeXFeatures & features) const
1089 features.require(documentClass().requires());
1091 if (outputChanges) {
1092 bool dvipost = LaTeXFeatures::isAvailable("dvipost");
1093 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1094 LaTeXFeatures::isAvailable("xcolor");
1096 switch (features.runparams().flavor) {
1097 case OutputParams::LATEX:
1099 features.require("ct-dvipost");
1100 features.require("dvipost");
1101 } else if (xcolorulem) {
1102 features.require("ct-xcolor-ulem");
1103 features.require("ulem");
1104 features.require("xcolor");
1106 features.require("ct-none");
1109 case OutputParams::PDFLATEX:
1110 case OutputParams::XETEX:
1112 features.require("ct-xcolor-ulem");
1113 features.require("ulem");
1114 features.require("xcolor");
1115 // improves color handling in PDF output
1116 features.require("pdfcolmk");
1118 features.require("ct-none");
1126 // Floats with 'Here definitely' as default setting.
1127 if (float_placement.find('H') != string::npos)
1128 features.require("float");
1130 // AMS Style is at document level
1131 if (use_amsmath == package_on
1132 || documentClass().provides("amsmath"))
1133 features.require("amsmath");
1134 if (use_esint == package_on)
1135 features.require("esint");
1136 if (use_mhchem == package_on)
1137 features.require("mhchem");
1139 // Document-level line spacing
1140 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1141 features.require("setspace");
1143 // the bullet shapes are buffer level not paragraph level
1144 // so they are tested here
1145 for (int i = 0; i < 4; ++i) {
1146 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1148 int const font = user_defined_bullet(i).getFont();
1150 int const c = user_defined_bullet(i).getCharacter();
1156 features.require("latexsym");
1158 } else if (font == 1) {
1159 features.require("amssymb");
1160 } else if (font >= 2 && font <= 5) {
1161 features.require("pifont");
1165 if (pdfoptions().use_hyperref) {
1166 features.require("hyperref");
1167 // due to interferences with babel and hyperref, the color package has to
1168 // be loaded after hyperref when hyperref is used with the colorlinks
1169 // option, see http://www.lyx.org/trac/ticket/5291
1170 if (pdfoptions().colorlinks)
1171 features.require("color");
1175 features.require("xetex");
1177 if (language->lang() == "vietnamese")
1178 features.require("vietnamese");
1179 else if (language->lang() == "japanese")
1180 features.require("japanese");
1184 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
1185 TexRow & texrow, FileName const & filepath) const
1187 os << "\\documentclass";
1189 DocumentClass const & tclass = documentClass();
1191 ostringstream clsoptions; // the document class options.
1193 if (tokenPos(tclass.opt_fontsize(),
1194 '|', fontsize) >= 0) {
1195 // only write if existing in list (and not default)
1196 clsoptions << fontsize << "pt,";
1199 // all paper sizes except of A4, A5, B5 and the US sizes need the
1201 bool nonstandard_papersize = papersize != PAPER_DEFAULT
1202 && papersize != PAPER_USLETTER
1203 && papersize != PAPER_USLEGAL
1204 && papersize != PAPER_USEXECUTIVE
1205 && papersize != PAPER_A4
1206 && papersize != PAPER_A5
1207 && papersize != PAPER_B5;
1209 if (!use_geometry) {
1210 switch (papersize) {
1212 clsoptions << "a4paper,";
1214 case PAPER_USLETTER:
1215 clsoptions << "letterpaper,";
1218 clsoptions << "a5paper,";
1221 clsoptions << "b5paper,";
1223 case PAPER_USEXECUTIVE:
1224 clsoptions << "executivepaper,";
1227 clsoptions << "legalpaper,";
1261 if (sides != tclass.sides()) {
1264 clsoptions << "oneside,";
1267 clsoptions << "twoside,";
1273 if (columns != tclass.columns()) {
1275 clsoptions << "twocolumn,";
1277 clsoptions << "onecolumn,";
1281 && orientation == ORIENTATION_LANDSCAPE)
1282 clsoptions << "landscape,";
1284 // language should be a parameter to \documentclass
1285 if (language->babel() == "hebrew"
1286 && default_language->babel() != "hebrew")
1287 // This seems necessary
1288 features.useLanguage(default_language);
1290 ostringstream language_options;
1291 bool const use_babel = features.useBabel();
1293 language_options << features.getLanguages();
1294 if (!language->babel().empty()) {
1295 if (!language_options.str().empty())
1296 language_options << ',';
1297 language_options << language->babel();
1299 // if Vietnamese is used, babel must directly be loaded
1300 // with language options, not in the class options, see
1301 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1302 size_t viet = language_options.str().find("vietnam");
1303 // viet = string::npos when not found
1304 // the same is for all other languages that are not directly supported by
1305 // babel, but where LaTeX-packages add babel support.
1306 // this is currently the case for Latvian, Lithuanian, Mongolian
1308 size_t latvian = language_options.str().find("latvian");
1309 size_t lithu = language_options.str().find("lithuanian");
1310 size_t mongo = language_options.str().find("mongolian");
1311 size_t turkmen = language_options.str().find("turkmen");
1312 // if Japanese is used, babel must directly be loaded
1313 // with language options, not in the class options, see
1314 // http://www.lyx.org/trac/ticket/4597#c4
1315 size_t japan = language_options.str().find("japanese");
1316 if (lyxrc.language_global_options && !language_options.str().empty()
1317 && viet == string::npos && japan == string::npos
1318 && latvian == string::npos && lithu == string::npos
1319 && mongo == string::npos && turkmen == string::npos)
1320 clsoptions << language_options.str() << ',';
1323 // the predefined options from the layout
1324 if (use_default_options && !tclass.options().empty())
1325 clsoptions << tclass.options() << ',';
1327 // the user-defined options
1328 if (!options.empty()) {
1329 clsoptions << options << ',';
1332 string strOptions(clsoptions.str());
1333 if (!strOptions.empty()) {
1334 strOptions = rtrim(strOptions, ",");
1336 os << '[' << from_utf8(strOptions) << ']';
1339 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1341 // end of \documentclass defs
1344 os << "\\usepackage{fontspec}\n";
1348 // font selection must be done before loading fontenc.sty
1349 string const fonts =
1350 loadFonts(fontsRoman, fontsSans,
1351 fontsTypewriter, fontsSC, fontsOSF,
1352 fontsSansScale, fontsTypewriterScale, useXetex);
1353 if (!fonts.empty()) {
1354 os << from_ascii(fonts);
1357 if (fontsDefaultFamily != "default")
1358 os << "\\renewcommand{\\familydefault}{\\"
1359 << from_ascii(fontsDefaultFamily) << "}\n";
1361 // set font encoding
1362 // for arabic_arabi and farsi we also need to load the LAE and
1364 // XeTeX works without fontenc
1365 if (font_encoding() != "default" && language->lang() != "japanese"
1366 && !useXetex && !tclass.provides("fontenc")) {
1367 size_t fars = language_options.str().find("farsi");
1368 size_t arab = language_options.str().find("arabic");
1369 if (language->lang() == "arabic_arabi"
1370 || language->lang() == "farsi" || fars != string::npos
1371 || arab != string::npos) {
1372 os << "\\usepackage[" << from_ascii(font_encoding())
1373 << ",LFE,LAE]{fontenc}\n";
1376 os << "\\usepackage[" << from_ascii(font_encoding())
1382 // handle inputenc etc.
1383 writeEncodingPreamble(os, features, texrow);
1386 if (!features.runparams().includeall && !includedChildren_.empty()) {
1387 os << "\\includeonly{";
1388 list<string>::const_iterator it = includedChildren_.begin();
1390 for (; it != includedChildren_.end() ; ++it) {
1391 string incfile = *it;
1392 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1393 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1395 if (!features.runparams().nice)
1397 // \includeonly doesn't want an extension
1398 incfile = changeExtension(incfile, string());
1399 incfile = support::latex_path(incfile);
1400 if (!incfile.empty()) {
1403 os << from_utf8(incfile);
1410 if (!listings_params.empty() || features.isRequired("listings")) {
1411 os << "\\usepackage{listings}\n";
1414 if (!listings_params.empty()) {
1416 // do not test validity because listings_params is
1417 // supposed to be valid
1419 InsetListingsParams(listings_params).separatedParams(true);
1420 // we can't support all packages, but we should load the color package
1421 if (par.find("\\color", 0) != string::npos)
1422 features.require("color");
1423 os << from_utf8(par);
1424 // count the number of newlines
1425 for (size_t i = 0; i < par.size(); ++i)
1431 if (!tclass.provides("geometry")
1432 && (use_geometry || nonstandard_papersize)) {
1433 odocstringstream ods;
1434 if (!getGraphicsDriver("geometry").empty())
1435 ods << getGraphicsDriver("geometry");
1436 if (orientation == ORIENTATION_LANDSCAPE)
1437 ods << ",landscape";
1438 switch (papersize) {
1440 if (!paperwidth.empty())
1441 ods << ",paperwidth="
1442 << from_ascii(paperwidth);
1443 if (!paperheight.empty())
1444 ods << ",paperheight="
1445 << from_ascii(paperheight);
1447 case PAPER_USLETTER:
1448 ods << ",letterpaper";
1451 ods << ",legalpaper";
1453 case PAPER_USEXECUTIVE:
1454 ods << ",executivepaper";
1541 // default papersize ie PAPER_DEFAULT
1542 switch (lyxrc.default_papersize) {
1543 case PAPER_DEFAULT: // keep compiler happy
1544 case PAPER_USLETTER:
1545 ods << ",letterpaper";
1548 ods << ",legalpaper";
1550 case PAPER_USEXECUTIVE:
1551 ods << ",executivepaper";
1593 docstring const g_options = trim(ods.str(), ",");
1594 os << "\\usepackage";
1595 if (!g_options.empty())
1596 os << '[' << g_options << ']';
1597 os << "{geometry}\n";
1599 // output this only if use_geometry is true
1601 os << "\\geometry{verbose";
1602 if (!topmargin.empty())
1603 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1604 if (!bottommargin.empty())
1605 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1606 if (!leftmargin.empty())
1607 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1608 if (!rightmargin.empty())
1609 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1610 if (!headheight.empty())
1611 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1612 if (!headsep.empty())
1613 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1614 if (!footskip.empty())
1615 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1616 if (!columnsep.empty())
1617 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1621 } else if (orientation == ORIENTATION_LANDSCAPE
1622 || papersize != PAPER_DEFAULT) {
1623 features.require("papersize");
1626 if (tokenPos(tclass.opt_pagestyle(),
1627 '|', pagestyle) >= 0) {
1628 if (pagestyle == "fancy") {
1629 os << "\\usepackage{fancyhdr}\n";
1632 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1636 // only output when the background color is not default
1637 if (isbackgroundcolor == true) {
1638 // only require color here, the background color will be defined
1639 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1641 features.require("color");
1642 features.require("pagecolor");
1645 // only output when the font color is not default
1646 if (isfontcolor == true) {
1647 // only require color here, the font color will be defined
1648 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1650 features.require("color");
1651 features.require("fontcolor");
1654 // Only if class has a ToC hierarchy
1655 if (tclass.hasTocLevels()) {
1656 if (secnumdepth != tclass.secnumdepth()) {
1657 os << "\\setcounter{secnumdepth}{"
1662 if (tocdepth != tclass.tocdepth()) {
1663 os << "\\setcounter{tocdepth}{"
1670 if (paragraph_separation) {
1671 // when skip separation
1672 switch (getDefSkip().kind()) {
1673 case VSpace::SMALLSKIP:
1674 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1676 case VSpace::MEDSKIP:
1677 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1679 case VSpace::BIGSKIP:
1680 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1682 case VSpace::LENGTH:
1683 os << "\\setlength{\\parskip}{"
1684 << from_utf8(getDefSkip().length().asLatexString())
1687 default: // should never happen // Then delete it.
1688 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1692 os << "\\setlength{\\parindent}{0pt}\n";
1695 // when separation by indentation
1696 // only output something when a width is given
1697 if (getIndentation().asLyXCommand() != "default") {
1698 os << "\\setlength{\\parindent}{"
1699 << from_utf8(getIndentation().asLatexCommand())
1705 // Now insert the LyX specific LaTeX commands...
1706 docstring lyxpreamble;
1709 if (!output_sync_macro.empty())
1710 lyxpreamble += from_utf8(output_sync_macro) +"\n";
1711 else if (features.runparams().flavor == OutputParams::LATEX)
1712 lyxpreamble += "\\usepackage[active]{srcltx}\n";
1713 else if (features.runparams().flavor == OutputParams::PDFLATEX)
1714 lyxpreamble += "\\synctex=-1\n";
1717 // due to interferences with babel and hyperref, the color package has to
1718 // be loaded (when it is not already loaded) before babel when hyperref
1719 // is used with the colorlinks option, see
1720 // http://www.lyx.org/trac/ticket/5291
1721 // we decided therefore to load color always before babel, see
1722 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
1723 lyxpreamble += from_ascii(features.getColorOptions());
1725 // If we use hyperref, jurabib, japanese, or vietnamese, we have to call babel before them.
1727 && (features.isRequired("jurabib")
1728 || features.isRequired("hyperref")
1729 || features.isRequired("vietnamese")
1730 || features.isRequired("japanese") ) ) {
1732 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1733 lyxpreamble += from_utf8(features.getBabelOptions()) + '\n';
1736 // The optional packages;
1737 lyxpreamble += from_ascii(features.getPackages());
1739 // Additional Indices
1740 if (features.isRequired("splitidx")) {
1741 IndicesList::const_iterator iit = indiceslist().begin();
1742 IndicesList::const_iterator iend = indiceslist().end();
1743 for (; iit != iend; ++iit) {
1744 lyxpreamble += "\\newindex[";
1745 lyxpreamble += iit->index();
1746 lyxpreamble += "]{";
1747 lyxpreamble += iit->shortcut();
1748 lyxpreamble += "}\n";
1753 lyxpreamble += from_utf8(spacing().writePreamble(tclass.provides("SetSpace")));
1756 // * Hyperref manual: "Make sure it comes last of your loaded
1757 // packages, to give it a fighting chance of not being over-written,
1758 // since its job is to redefine many LaTeX commands."
1759 // * Email from Heiko Oberdiek: "It is usually better to load babel
1760 // before hyperref. Then hyperref has a chance to detect babel.
1761 // * Has to be loaded before the "LyX specific LaTeX commands" to
1762 // avoid errors with algorithm floats.
1763 // use hyperref explicitly if it is required
1764 if (features.isRequired("hyperref")) {
1765 // pass what we have to stream here, since we need
1766 // to access the stream itself in PDFOptions.
1770 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1772 OutputParams tmp_params = features.runparams();
1773 lines += pdfoptions().writeLaTeX(tmp_params, os,
1774 documentClass().provides("hyperref"));
1775 texrow.newlines(lines);
1776 // set back for the rest
1777 lyxpreamble.clear();
1780 // Will be surrounded by \makeatletter and \makeatother when not empty
1781 docstring atlyxpreamble;
1783 // Some macros LyX will need
1784 docstring tmppreamble(features.getMacros());
1786 if (!tmppreamble.empty())
1787 atlyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1788 "LyX specific LaTeX commands.\n"
1789 + tmppreamble + '\n';
1791 // the text class specific preamble
1792 tmppreamble = features.getTClassPreamble();
1793 if (!tmppreamble.empty())
1794 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1795 "Textclass specific LaTeX commands.\n"
1796 + tmppreamble + '\n';
1798 // suppress date if selected
1799 // use \@ifundefined because we cannot be sure that every document class
1800 // has a \date command
1802 atlyxpreamble += "\\@ifundefined{date}{}{\\date{}}\n";
1804 /* the user-defined preamble */
1805 if (!containsOnly(preamble, " \n\t"))
1807 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1808 "User specified LaTeX commands.\n"
1809 + from_utf8(preamble) + '\n';
1811 // subfig loads internally the LaTeX package "caption". As
1812 // caption is a very popular package, users will load it in
1813 // the preamble. Therefore we must load subfig behind the
1814 // user-defined preamble and check if the caption package was
1815 // loaded or not. For the case that caption is loaded before
1816 // subfig, there is the subfig option "caption=false". This
1817 // option also works when a koma-script class is used and
1818 // koma's own caption commands are used instead of caption. We
1819 // use \PassOptionsToPackage here because the user could have
1820 // already loaded subfig in the preamble.
1821 if (features.isRequired("subfig")) {
1822 atlyxpreamble += "\\@ifundefined{showcaptionsetup}{}{%\n"
1823 " \\PassOptionsToPackage{caption=false}{subfig}}\n"
1824 "\\usepackage{subfig}\n";
1827 // Itemize bullet settings need to be last in case the user
1828 // defines their own bullets that use a package included
1829 // in the user-defined preamble -- ARRae
1830 // Actually it has to be done much later than that
1831 // since some packages like frenchb make modifications
1832 // at \begin{document} time -- JMarc
1833 docstring bullets_def;
1834 for (int i = 0; i < 4; ++i) {
1835 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1836 if (bullets_def.empty())
1837 bullets_def += "\\AtBeginDocument{\n";
1838 bullets_def += " \\def\\labelitemi";
1840 // `i' is one less than the item to modify
1847 bullets_def += "ii";
1853 bullets_def += '{' +
1854 user_defined_bullet(i).getText()
1859 if (!bullets_def.empty())
1860 atlyxpreamble += bullets_def + "}\n\n";
1862 if (!atlyxpreamble.empty())
1863 lyxpreamble += "\n\\makeatletter\n"
1864 + atlyxpreamble + "\\makeatother\n\n";
1866 // We try to load babel late, in case it interferes with other packages.
1867 // Jurabib and Hyperref have to be called after babel, though.
1868 if (use_babel && !features.isRequired("jurabib")
1869 && !features.isRequired("hyperref")
1870 && !features.isRequired("vietnamese")
1871 && !features.isRequired("japanese")) {
1873 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1874 lyxpreamble += from_utf8(features.getBabelOptions()) + '\n';
1877 docstring const i18npreamble = features.getTClassI18nPreamble(use_babel);
1878 if (!i18npreamble.empty())
1879 lyxpreamble += i18npreamble + '\n';
1882 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1883 texrow.newlines(nlines);
1887 // these packages (xunicode, for that matter) need to be loaded at least
1888 // after amsmath, amssymb, esint and the other packages that provide
1891 os << "\\usepackage{xunicode}\n";
1893 os << "\\usepackage{xltxtra}\n";
1900 void BufferParams::useClassDefaults()
1902 DocumentClass const & tclass = documentClass();
1904 sides = tclass.sides();
1905 columns = tclass.columns();
1906 pagestyle = tclass.pagestyle();
1907 use_default_options = true;
1908 // Only if class has a ToC hierarchy
1909 if (tclass.hasTocLevels()) {
1910 secnumdepth = tclass.secnumdepth();
1911 tocdepth = tclass.tocdepth();
1916 bool BufferParams::hasClassDefaults() const
1918 DocumentClass const & tclass = documentClass();
1920 return sides == tclass.sides()
1921 && columns == tclass.columns()
1922 && pagestyle == tclass.pagestyle()
1923 && use_default_options
1924 && secnumdepth == tclass.secnumdepth()
1925 && tocdepth == tclass.tocdepth();
1929 DocumentClass const & BufferParams::documentClass() const
1935 DocumentClass const * BufferParams::documentClassPtr() const {
1940 void BufferParams::setDocumentClass(DocumentClass const * const tc) {
1941 // evil, but this function is evil
1942 doc_class_ = const_cast<DocumentClass *>(tc);
1946 bool BufferParams::setBaseClass(string const & classname)
1948 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
1949 LayoutFileList & bcl = LayoutFileList::get();
1950 if (!bcl.haveClass(classname)) {
1952 bformat(_("The layout file:\n"
1954 "could not be found. A default textclass with default\n"
1955 "layouts will be used. LyX will not be able to produce\n"
1957 from_utf8(classname));
1958 frontend::Alert::error(_("Document class not found"), s);
1959 bcl.addEmptyClass(classname);
1962 bool const success = bcl[classname].load();
1965 bformat(_("Due to some error in it, the layout file:\n"
1967 "could not be loaded. A default textclass with default\n"
1968 "layouts will be used. LyX will not be able to produce\n"
1970 from_utf8(classname));
1971 frontend::Alert::error(_("Could not load class"), s);
1972 bcl.addEmptyClass(classname);
1975 pimpl_->baseClass_ = classname;
1976 layoutModules_.adaptToBaseClass(baseClass(), removedModules_);
1981 LayoutFile const * BufferParams::baseClass() const
1983 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
1984 return &(LayoutFileList::get()[pimpl_->baseClass_]);
1990 LayoutFileIndex const & BufferParams::baseClassID() const
1992 return pimpl_->baseClass_;
1996 void BufferParams::makeDocumentClass()
2001 doc_class_ = &(DocumentClassBundle::get().makeDocumentClass(*baseClass(), layoutModules_));
2003 if (!local_layout.empty()) {
2004 if (!doc_class_->read(local_layout, TextClass::MODULE)) {
2005 docstring const msg = _("Error reading internal layout information");
2006 frontend::Alert::warning(_("Read Error"), msg);
2012 bool BufferParams::moduleCanBeAdded(string const & modName) const
2014 return layoutModules_.moduleCanBeAdded(modName, baseClass());
2018 bool BufferParams::addLayoutModule(string const & modName)
2020 LayoutModuleList::const_iterator it = layoutModules_.begin();
2021 LayoutModuleList::const_iterator end = layoutModules_.end();
2022 for (; it != end; it++)
2025 layoutModules_.push_back(modName);
2030 Font const BufferParams::getFont() const
2032 FontInfo f = documentClass().defaultfont();
2033 if (fontsDefaultFamily == "rmdefault")
2034 f.setFamily(ROMAN_FAMILY);
2035 else if (fontsDefaultFamily == "sfdefault")
2036 f.setFamily(SANS_FAMILY);
2037 else if (fontsDefaultFamily == "ttdefault")
2038 f.setFamily(TYPEWRITER_FAMILY);
2039 return Font(f, language);
2043 void BufferParams::readPreamble(Lexer & lex)
2045 if (lex.getString() != "\\begin_preamble")
2046 lyxerr << "Error (BufferParams::readPreamble):"
2047 "consistency check failed." << endl;
2049 preamble = lex.getLongString("\\end_preamble");
2053 void BufferParams::readLocalLayout(Lexer & lex)
2055 if (lex.getString() != "\\begin_local_layout")
2056 lyxerr << "Error (BufferParams::readLocalLayout):"
2057 "consistency check failed." << endl;
2059 local_layout = lex.getLongString("\\end_local_layout");
2063 void BufferParams::readLanguage(Lexer & lex)
2065 if (!lex.next()) return;
2067 string const tmptok = lex.getString();
2069 // check if tmptok is part of tex_babel in tex-defs.h
2070 language = languages.getLanguage(tmptok);
2072 // Language tmptok was not found
2073 language = default_language;
2074 lyxerr << "Warning: Setting language `"
2075 << tmptok << "' to `" << language->lang()
2081 void BufferParams::readGraphicsDriver(Lexer & lex)
2086 string const tmptok = lex.getString();
2087 // check if tmptok is part of tex_graphics in tex_defs.h
2090 string const test = tex_graphics[n++];
2092 if (test == tmptok) {
2093 graphicsDriver = tmptok;
2098 "Warning: graphics driver `$$Token' not recognized!\n"
2099 " Setting graphics driver to `default'.\n");
2100 graphicsDriver = "default";
2107 void BufferParams::readBullets(Lexer & lex)
2112 int const index = lex.getInteger();
2114 int temp_int = lex.getInteger();
2115 user_defined_bullet(index).setFont(temp_int);
2116 temp_bullet(index).setFont(temp_int);
2118 user_defined_bullet(index).setCharacter(temp_int);
2119 temp_bullet(index).setCharacter(temp_int);
2121 user_defined_bullet(index).setSize(temp_int);
2122 temp_bullet(index).setSize(temp_int);
2126 void BufferParams::readBulletsLaTeX(Lexer & lex)
2128 // The bullet class should be able to read this.
2131 int const index = lex.getInteger();
2133 docstring const temp_str = lex.getDocString();
2135 user_defined_bullet(index).setText(temp_str);
2136 temp_bullet(index).setText(temp_str);
2140 void BufferParams::readModules(Lexer & lex)
2142 if (!lex.eatLine()) {
2143 lyxerr << "Error (BufferParams::readModules):"
2144 "Unexpected end of input." << endl;
2148 string mod = lex.getString();
2149 if (mod == "\\end_modules")
2151 addLayoutModule(mod);
2157 void BufferParams::readRemovedModules(Lexer & lex)
2159 if (!lex.eatLine()) {
2160 lyxerr << "Error (BufferParams::readRemovedModules):"
2161 "Unexpected end of input." << endl;
2165 string mod = lex.getString();
2166 if (mod == "\\end_removed_modules")
2168 removedModules_.push_back(mod);
2171 // now we want to remove any removed modules that were previously
2172 // added. normally, that will be because default modules were added in
2173 // setBaseClass(), which gets called when \textclass is read at the
2174 // start of the read.
2175 list<string>::const_iterator rit = removedModules_.begin();
2176 list<string>::const_iterator const ren = removedModules_.end();
2177 for (; rit != ren; rit++) {
2178 LayoutModuleList::iterator const mit = layoutModules_.begin();
2179 LayoutModuleList::iterator const men = layoutModules_.end();
2180 LayoutModuleList::iterator found = find(mit, men, *rit);
2183 layoutModules_.erase(found);
2188 void BufferParams::readIncludeonly(Lexer & lex)
2190 if (!lex.eatLine()) {
2191 lyxerr << "Error (BufferParams::readIncludeonly):"
2192 "Unexpected end of input." << endl;
2196 string child = lex.getString();
2197 if (child == "\\end_includeonly")
2199 includedChildren_.push_back(child);
2205 string BufferParams::paperSizeName(PapersizePurpose purpose) const
2207 char real_papersize = papersize;
2208 if (real_papersize == PAPER_DEFAULT)
2209 real_papersize = lyxrc.default_papersize;
2211 switch (real_papersize) {
2213 // could be anything, so don't guess
2215 case PAPER_CUSTOM: {
2216 if (purpose == XDVI && !paperwidth.empty() &&
2217 !paperheight.empty()) {
2218 // heightxwidth<unit>
2219 string first = paperwidth;
2220 string second = paperheight;
2221 if (orientation == ORIENTATION_LANDSCAPE)
2224 return first.erase(first.length() - 2)
2230 // dvips and dvipdfm do not know this
2231 if (purpose == DVIPS || purpose == DVIPDFM)
2235 if (purpose == DVIPS || purpose == DVIPDFM)
2239 if (purpose == DVIPS || purpose == DVIPDFM)
2249 if (purpose == DVIPS || purpose == DVIPDFM)
2253 if (purpose == DVIPS || purpose == DVIPDFM)
2257 if (purpose == DVIPS || purpose == DVIPDFM)
2261 if (purpose == DVIPS || purpose == DVIPDFM)
2265 if (purpose == DVIPS || purpose == DVIPDFM)
2269 // dvipdfm does not know this
2270 if (purpose == DVIPDFM)
2274 if (purpose == DVIPDFM)
2278 if (purpose == DVIPS || purpose == DVIPDFM)
2282 if (purpose == DVIPS || purpose == DVIPDFM)
2286 if (purpose == DVIPS || purpose == DVIPDFM)
2290 if (purpose == DVIPS || purpose == DVIPDFM)
2294 if (purpose == DVIPS || purpose == DVIPDFM)
2298 if (purpose == DVIPS || purpose == DVIPDFM)
2302 if (purpose == DVIPS || purpose == DVIPDFM)
2306 if (purpose == DVIPS || purpose == DVIPDFM)
2310 if (purpose == DVIPS || purpose == DVIPDFM)
2314 if (purpose == DVIPS || purpose == DVIPDFM)
2318 if (purpose == DVIPS || purpose == DVIPDFM)
2322 if (purpose == DVIPS || purpose == DVIPDFM)
2326 if (purpose == DVIPS || purpose == DVIPDFM)
2330 if (purpose == DVIPS || purpose == DVIPDFM)
2334 if (purpose == DVIPS || purpose == DVIPDFM)
2337 case PAPER_USEXECUTIVE:
2338 // dvipdfm does not know this
2339 if (purpose == DVIPDFM)
2344 case PAPER_USLETTER:
2346 if (purpose == XDVI)
2353 string const BufferParams::dvips_options() const
2358 && papersize == PAPER_CUSTOM
2359 && !lyxrc.print_paper_dimension_flag.empty()
2360 && !paperwidth.empty()
2361 && !paperheight.empty()) {
2362 // using a custom papersize
2363 result = lyxrc.print_paper_dimension_flag;
2364 result += ' ' + paperwidth;
2365 result += ',' + paperheight;
2367 string const paper_option = paperSizeName(DVIPS);
2368 if (!paper_option.empty() && (paper_option != "letter" ||
2369 orientation != ORIENTATION_LANDSCAPE)) {
2370 // dvips won't accept -t letter -t landscape.
2371 // In all other cases, include the paper size
2373 result = lyxrc.print_paper_flag;
2374 result += ' ' + paper_option;
2377 if (orientation == ORIENTATION_LANDSCAPE &&
2378 papersize != PAPER_CUSTOM)
2379 result += ' ' + lyxrc.print_landscape_flag;
2384 string const BufferParams::font_encoding() const
2386 return (fontenc == "global") ? lyxrc.fontenc : fontenc;
2390 string BufferParams::babelCall(string const & lang_opts) const
2392 string lang_pack = lyxrc.language_package;
2393 if (lang_pack != "\\usepackage{babel}")
2395 // suppress the babel call when there is no babel language defined
2396 // for the document language in the lib/languages file and if no
2397 // other languages are used (lang_opts is then empty)
2398 if (lang_opts.empty())
2400 // If Vietnamese is used, babel must directly be loaded with the
2401 // language options, see
2402 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
2403 size_t viet = lang_opts.find("vietnam");
2404 // viet = string::npos when not found
2405 // the same is for all other languages that are not directly supported by
2406 // babel, but where LaTeX-packages add babel support.
2407 // this is currently the case for Latvian, Lithuanian, Mongolian
2409 size_t latvian = lang_opts.find("latvian");
2410 size_t lithu = lang_opts.find("lithuanian");
2411 size_t mongo = lang_opts.find("mongolian");
2412 size_t turkmen = lang_opts.find("turkmen");
2413 // If Japanese is used, babel must directly be loaded with the
2414 // language options, see
2415 // http://www.lyx.org/trac/ticket/4597#c4
2416 size_t japan = lang_opts.find("japanese");
2417 if (!lyxrc.language_global_options || viet != string::npos
2418 || japan != string::npos || latvian != string::npos
2419 || lithu != string::npos || mongo != string::npos
2420 || turkmen != string::npos)
2421 return "\\usepackage[" + lang_opts + "]{babel}";
2426 docstring BufferParams::getGraphicsDriver(string const & package) const
2430 if (package == "geometry") {
2431 if (graphicsDriver == "dvips"
2432 || graphicsDriver == "dvipdfm"
2433 || graphicsDriver == "pdftex"
2434 || graphicsDriver == "vtex")
2435 result = from_ascii(graphicsDriver);
2436 else if (graphicsDriver == "dvipdfmx")
2437 result = from_ascii("dvipdfm");
2444 void BufferParams::writeEncodingPreamble(odocstream & os,
2445 LaTeXFeatures & features, TexRow & texrow) const
2449 if (inputenc == "auto") {
2450 string const doc_encoding =
2451 language->encoding()->latexName();
2452 Encoding::Package const package =
2453 language->encoding()->package();
2455 // Create a list with all the input encodings used
2457 set<string> encodings =
2458 features.getEncodingSet(doc_encoding);
2460 // If the "japanese" package (i.e. pLaTeX) is used,
2461 // inputenc must be omitted.
2462 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
2463 if (package == Encoding::japanese)
2464 features.require("japanese");
2466 if ((!encodings.empty() || package == Encoding::inputenc)
2467 && !features.isRequired("japanese")) {
2468 os << "\\usepackage[";
2469 set<string>::const_iterator it = encodings.begin();
2470 set<string>::const_iterator const end = encodings.end();
2472 os << from_ascii(*it);
2475 for (; it != end; ++it)
2476 os << ',' << from_ascii(*it);
2477 if (package == Encoding::inputenc) {
2478 if (!encodings.empty())
2480 os << from_ascii(doc_encoding);
2482 os << "]{inputenc}\n";
2485 if (package == Encoding::CJK || features.mustProvide("CJK")) {
2486 if (language->encoding()->name() == "utf8-cjk"
2487 && LaTeXFeatures::isAvailable("CJKutf8"))
2488 os << "\\usepackage{CJKutf8}\n";
2490 os << "\\usepackage{CJK}\n";
2493 } else if (inputenc != "default") {
2494 switch (encoding().package()) {
2495 case Encoding::none:
2496 case Encoding::japanese:
2498 case Encoding::inputenc:
2499 // do not load inputenc if japanese is used
2500 if (features.isRequired("japanese"))
2502 os << "\\usepackage[" << from_ascii(inputenc)
2507 if (encoding().name() == "utf8-cjk"
2508 && LaTeXFeatures::isAvailable("CJKutf8"))
2509 os << "\\usepackage{CJKutf8}\n";
2511 os << "\\usepackage{CJK}\n";
2517 // The encoding "armscii8" (for Armenian) is only available when
2518 // the package "armtex" is loaded.
2519 if (language->encoding()->latexName() == "armscii8"
2520 || inputenc == "armscii8") {
2521 os << "\\usepackage{armtex}\n";
2527 string const BufferParams::parseFontName(string const & name) const
2529 string mangled = name;
2530 size_t const idx = mangled.find('[');
2531 if (idx == string::npos || idx == 0)
2534 return mangled.substr(0, idx - 1);
2538 string const BufferParams::loadFonts(string const & rm,
2539 string const & sf, string const & tt,
2540 bool const & sc, bool const & osf,
2541 int const & sfscale, int const & ttscale,
2542 bool const & xetex) const
2544 /* The LaTeX font world is in a flux. In the PSNFSS font interface,
2545 several packages have been replaced by others, that might not
2546 be installed on every system. We have to take care for that
2547 (see psnfss.pdf). We try to support all psnfss fonts as well
2548 as the fonts that have become de facto standard in the LaTeX
2549 world (e.g. Latin Modern). We do not support obsolete fonts
2550 (like PSLatex). In general, it should be possible to mix any
2551 rm font with any sf or tt font, respectively. (JSpitzm)
2553 -- separate math fonts.
2556 if (rm == "default" && sf == "default" && tt == "default")
2563 if (rm != "default")
2564 os << "\\setmainfont[Mapping=tex-text]{"
2565 << parseFontName(rm) << "}\n";
2566 if (sf != "default") {
2567 string const sans = parseFontName(sf);
2569 os << "\\setsansfont[Scale="
2570 << float(sfscale) / 100
2571 << ",Mapping=tex-text]{"
2574 os << "\\setsansfont[Mapping=tex-text]{"
2577 if (tt != "default") {
2578 string const mono = parseFontName(tt);
2580 os << "\\setmonofont[Scale="
2581 << float(sfscale) / 100
2585 os << "\\setmonofont[Mapping=tex-text]{"
2589 os << "\\defaultfontfeatures{Numbers=OldStyle}\n";
2594 // Computer Modern (must be explicitly selectable -- there might be classes
2595 // that define a different default font!
2597 os << "\\renewcommand{\\rmdefault}{cmr}\n";
2598 // osf for Computer Modern needs eco.sty
2600 os << "\\usepackage{eco}\n";
2602 // Latin Modern Roman
2603 else if (rm == "lmodern")
2604 os << "\\usepackage{lmodern}\n";
2606 else if (rm == "ae") {
2607 // not needed when using OT1 font encoding.
2608 if (font_encoding() != "default")
2609 os << "\\usepackage{ae,aecompl}\n";
2612 else if (rm == "times") {
2613 // try to load the best available package
2614 if (LaTeXFeatures::isAvailable("mathptmx"))
2615 os << "\\usepackage{mathptmx}\n";
2616 else if (LaTeXFeatures::isAvailable("mathptm"))
2617 os << "\\usepackage{mathptm}\n";
2619 os << "\\usepackage{times}\n";
2622 else if (rm == "palatino") {
2623 // try to load the best available package
2624 if (LaTeXFeatures::isAvailable("mathpazo")) {
2625 os << "\\usepackage";
2631 // "osf" includes "sc"!
2635 os << "{mathpazo}\n";
2637 else if (LaTeXFeatures::isAvailable("mathpple"))
2638 os << "\\usepackage{mathpple}\n";
2640 os << "\\usepackage{palatino}\n";
2643 else if (rm == "utopia") {
2644 // fourier supersedes utopia.sty, but does
2645 // not work with OT1 encoding.
2646 if (LaTeXFeatures::isAvailable("fourier")
2647 && font_encoding() != "default") {
2648 os << "\\usepackage";
2659 os << "{fourier}\n";
2662 os << "\\usepackage{utopia}\n";
2664 // Bera (complete fontset)
2665 else if (rm == "bera" && sf == "default" && tt == "default")
2666 os << "\\usepackage{bera}\n";
2668 else if (rm != "default")
2669 os << "\\usepackage" << "{" << rm << "}\n";
2672 // Helvetica, Bera Sans
2673 if (sf == "helvet" || sf == "berasans") {
2675 os << "\\usepackage[scaled=" << float(sfscale) / 100
2676 << "]{" << sf << "}\n";
2678 os << "\\usepackage{" << sf << "}\n";
2681 else if (sf == "avant")
2682 os << "\\usepackage{" << sf << "}\n";
2683 // Computer Modern, Latin Modern, CM Bright
2684 else if (sf != "default")
2685 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
2687 // monospaced/typewriter
2688 // Courier, LuxiMono
2689 if (tt == "luximono" || tt == "beramono") {
2691 os << "\\usepackage[scaled=" << float(ttscale) / 100
2692 << "]{" << tt << "}\n";
2694 os << "\\usepackage{" << tt << "}\n";
2697 else if (tt == "courier" )
2698 os << "\\usepackage{" << tt << "}\n";
2699 // Computer Modern, Latin Modern, CM Bright
2700 else if (tt != "default")
2701 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
2707 Encoding const & BufferParams::encoding() const
2710 return *(encodings.fromLaTeXName("utf8-plain"));
2711 if (inputenc == "auto" || inputenc == "default")
2712 return *language->encoding();
2713 Encoding const * const enc = encodings.fromLaTeXName(inputenc);
2716 LYXERR0("Unknown inputenc value `" << inputenc
2717 << "'. Using `auto' instead.");
2718 return *language->encoding();
2722 CiteEngine BufferParams::citeEngine() const
2724 // FIXME the class should provide the numerical/
2725 // authoryear choice
2726 if (documentClass().provides("natbib")
2727 && cite_engine_ != ENGINE_NATBIB_NUMERICAL)
2728 return ENGINE_NATBIB_AUTHORYEAR;
2729 return cite_engine_;
2733 void BufferParams::setCiteEngine(CiteEngine cite_engine)
2735 cite_engine_ = cite_engine;