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 use_mathdots = package_auto;
367 cite_engine_ = ENGINE_BASIC;
368 use_bibtopic = false;
370 trackChanges = false;
371 outputChanges = false;
372 use_default_options = true;
373 maintain_unincluded_children = false;
376 language = default_language;
378 fontsRoman = "default";
379 fontsSans = "default";
380 fontsTypewriter = "default";
381 fontsDefaultFamily = "default";
385 fontsSansScale = 100;
386 fontsTypewriterScale = 100;
388 graphicsDriver = "default";
389 defaultOutputFormat = "default";
390 bibtex_command = "default";
391 index_command = "default";
394 listings_params = string();
395 pagestyle = "default";
396 suppress_date = false;
397 // no color is the default (white)
398 backgroundcolor = lyx::rgbFromHexName("#ffffff");
399 isbackgroundcolor = false;
400 // no color is the default (black)
401 fontcolor = lyx::rgbFromHexName("#000000");
403 // light gray is the default font color for greyed-out notes
404 notefontcolor = lyx::rgbFromHexName("#cccccc");
405 boxbgcolor = lyx::rgbFromHexName("#ff0000");
406 compressed = lyxrc.save_compressed;
407 for (int iter = 0; iter < 4; ++iter) {
408 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
409 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
412 indiceslist().addDefault(B_("Index"));
413 html_be_strict = false;
414 html_math_output = MathML;
415 html_math_img_scale = 1.0;
422 docstring BufferParams::B_(string const & l10n) const
424 LASSERT(language, /**/);
425 return getMessages(language->code()).get(l10n);
429 AuthorList & BufferParams::authors()
431 return pimpl_->authorlist;
435 AuthorList const & BufferParams::authors() const
437 return pimpl_->authorlist;
441 BranchList & BufferParams::branchlist()
443 return pimpl_->branchlist;
447 BranchList const & BufferParams::branchlist() const
449 return pimpl_->branchlist;
453 IndicesList & BufferParams::indiceslist()
455 return pimpl_->indiceslist;
459 IndicesList const & BufferParams::indiceslist() const
461 return pimpl_->indiceslist;
465 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
467 LASSERT(index < 4, /**/);
468 return pimpl_->temp_bullets[index];
472 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
474 LASSERT(index < 4, /**/);
475 return pimpl_->temp_bullets[index];
479 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
481 LASSERT(index < 4, /**/);
482 return pimpl_->user_defined_bullets[index];
486 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
488 LASSERT(index < 4, /**/);
489 return pimpl_->user_defined_bullets[index];
493 Spacing & BufferParams::spacing()
495 return pimpl_->spacing;
499 Spacing const & BufferParams::spacing() const
501 return pimpl_->spacing;
505 PDFOptions & BufferParams::pdfoptions()
507 return pimpl_->pdfoptions;
511 PDFOptions const & BufferParams::pdfoptions() const
513 return pimpl_->pdfoptions;
517 HSpace const & BufferParams::getIndentation() const
519 return pimpl_->indentation;
523 void BufferParams::setIndentation(HSpace const & indent)
525 pimpl_->indentation = indent;
529 VSpace const & BufferParams::getDefSkip() const
531 return pimpl_->defskip;
535 void BufferParams::setDefSkip(VSpace const & vs)
537 // DEFSKIP will cause an infinite loop
538 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
539 pimpl_->defskip = vs;
543 string BufferParams::readToken(Lexer & lex, string const & token,
544 FileName const & filepath)
546 if (token == "\\textclass") {
548 string const classname = lex.getString();
549 // if there exists a local layout file, ignore the system one
550 // NOTE: in this case, the textclass (.cls file) is assumed to be available.
552 LayoutFileList & bcl = LayoutFileList::get();
553 if (tcp.empty() && !filepath.empty())
554 tcp = bcl.addLocalLayout(classname, filepath.absFileName());
558 setBaseClass(classname);
559 // We assume that a tex class exists for local or unknown layouts so this warning
560 // will only be given for system layouts.
561 if (!baseClass()->isTeXClassAvailable()) {
562 docstring const desc =
563 translateIfPossible(from_utf8(baseClass()->description()));
564 docstring const prereqs = from_utf8(baseClass()->prerequisites());
565 docstring const msg =
566 bformat(_("The selected document class\n"
568 "requires external files that are not available.\n"
569 "The document class can still be used, but the\n"
570 "document cannot be compiled until the following\n"
571 "prerequisites are installed:\n"
573 "See section 3.1.2.2 of the User's Guide for\n"
574 "more information."), desc, prereqs);
575 frontend::Alert::warning(_("Document class not available"),
578 } else if (token == "\\begin_preamble") {
580 } else if (token == "\\begin_local_layout") {
581 readLocalLayout(lex);
582 } else if (token == "\\begin_modules") {
584 } else if (token == "\\begin_removed_modules") {
585 readRemovedModules(lex);
586 } else if (token == "\\begin_includeonly") {
587 readIncludeonly(lex);
588 } else if (token == "\\maintain_unincluded_children") {
589 lex >> maintain_unincluded_children;
590 } else if (token == "\\options") {
592 options = lex.getString();
593 } else if (token == "\\use_default_options") {
594 lex >> use_default_options;
595 } else if (token == "\\master") {
597 master = lex.getString();
598 } else if (token == "\\suppress_date") {
599 lex >> suppress_date;
600 } else if (token == "\\language") {
602 } else if (token == "\\inputencoding") {
604 } else if (token == "\\graphics") {
605 readGraphicsDriver(lex);
606 } else if (token == "\\default_output_format") {
607 lex >> defaultOutputFormat;
608 } else if (token == "\\bibtex_command") {
610 bibtex_command = lex.getString();
611 } else if (token == "\\index_command") {
613 index_command = lex.getString();
614 } else if (token == "\\fontencoding") {
616 fontenc = lex.getString();
617 } else if (token == "\\font_roman") {
619 fontsRoman = lex.getString();
620 } else if (token == "\\font_sans") {
622 fontsSans = lex.getString();
623 } else if (token == "\\font_typewriter") {
625 fontsTypewriter = lex.getString();
626 } else if (token == "\\font_default_family") {
627 lex >> fontsDefaultFamily;
628 } else if (token == "\\use_xetex") {
630 } else if (token == "\\font_sc") {
632 } else if (token == "\\font_osf") {
634 } else if (token == "\\font_sf_scale") {
635 lex >> fontsSansScale;
636 } else if (token == "\\font_tt_scale") {
637 lex >> fontsTypewriterScale;
638 } else if (token == "\\font_cjk") {
640 } else if (token == "\\paragraph_separation") {
643 paragraph_separation = parseptranslator().find(parsep);
644 } else if (token == "\\paragraph_indentation") {
646 string indentation = lex.getString();
647 pimpl_->indentation = HSpace(indentation);
648 } else if (token == "\\defskip") {
650 string const defskip = lex.getString();
651 pimpl_->defskip = VSpace(defskip);
652 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
654 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
655 } else if (token == "\\quotes_language") {
658 quotes_language = quoteslangtranslator().find(quotes_lang);
659 } else if (token == "\\papersize") {
662 papersize = papersizetranslator().find(ppsize);
663 } else if (token == "\\use_geometry") {
665 } else if (token == "\\use_amsmath") {
668 use_amsmath = packagetranslator().find(use_ams);
669 } else if (token == "\\use_esint") {
672 use_esint = packagetranslator().find(useesint);
673 } else if (token == "\\use_mhchem") {
676 use_mhchem = packagetranslator().find(usemhchem);
677 } else if (token == "\\use_mathdots") {
680 use_mathdots = packagetranslator().find(usemathdots);
681 } else if (token == "\\cite_engine") {
684 cite_engine_ = citeenginetranslator().find(engine);
685 } else if (token == "\\use_bibtopic") {
687 } else if (token == "\\use_indices") {
689 } else if (token == "\\tracking_changes") {
691 } else if (token == "\\output_changes") {
692 lex >> outputChanges;
693 } else if (token == "\\branch") {
695 docstring branch = lex.getDocString();
696 branchlist().add(branch);
699 string const tok = lex.getString();
700 if (tok == "\\end_branch")
702 Branch * branch_ptr = branchlist().find(branch);
703 if (tok == "\\selected") {
706 branch_ptr->setSelected(lex.getInteger());
708 if (tok == "\\filename_suffix") {
711 branch_ptr->setFileNameSuffix(lex.getInteger());
713 if (tok == "\\color") {
715 string color = lex.getString();
717 branch_ptr->setColor(color);
718 // Update also the Color table:
720 color = lcolor.getX11Name(Color_background);
722 lcolor.setColor(to_utf8(branch), color);
725 } else if (token == "\\index") {
727 docstring index = lex.getDocString();
729 indiceslist().add(index);
732 string const tok = lex.getString();
733 if (tok == "\\end_index")
735 Index * index_ptr = indiceslist().find(index);
736 if (tok == "\\shortcut") {
738 shortcut = lex.getDocString();
740 index_ptr->setShortcut(shortcut);
742 if (tok == "\\color") {
744 string color = lex.getString();
746 index_ptr->setColor(color);
747 // Update also the Color table:
749 color = lcolor.getX11Name(Color_background);
751 if (!shortcut.empty())
752 lcolor.setColor(to_utf8(shortcut), color);
755 } else if (token == "\\author") {
757 istringstream ss(lex.getString());
760 author_map[a.buffer_id()] = pimpl_->authorlist.record(a);
761 } else if (token == "\\paperorientation") {
764 orientation = paperorientationtranslator().find(orient);
765 } else if (token == "\\backgroundcolor") {
767 backgroundcolor = lyx::rgbFromHexName(lex.getString());
768 isbackgroundcolor = true;
769 } else if (token == "\\fontcolor") {
771 fontcolor = lyx::rgbFromHexName(lex.getString());
773 } else if (token == "\\notefontcolor") {
775 string color = lex.getString();
776 notefontcolor = lyx::rgbFromHexName(color);
777 } else if (token == "\\boxbgcolor") {
779 string color = lex.getString();
780 boxbgcolor = lyx::rgbFromHexName(color);
781 } else if (token == "\\paperwidth") {
783 } else if (token == "\\paperheight") {
785 } else if (token == "\\leftmargin") {
787 } else if (token == "\\topmargin") {
789 } else if (token == "\\rightmargin") {
791 } else if (token == "\\bottommargin") {
793 } else if (token == "\\headheight") {
795 } else if (token == "\\headsep") {
797 } else if (token == "\\footskip") {
799 } else if (token == "\\columnsep") {
801 } else if (token == "\\paperfontsize") {
803 } else if (token == "\\papercolumns") {
805 } else if (token == "\\listings_params") {
808 listings_params = InsetListingsParams(par).params();
809 } else if (token == "\\papersides") {
812 sides = sidestranslator().find(psides);
813 } else if (token == "\\paperpagestyle") {
815 } else if (token == "\\bullet") {
817 } else if (token == "\\bulletLaTeX") {
818 readBulletsLaTeX(lex);
819 } else if (token == "\\secnumdepth") {
821 } else if (token == "\\tocdepth") {
823 } else if (token == "\\spacing") {
827 if (nspacing == "other") {
830 spacing().set(spacetranslator().find(nspacing), tmp_val);
831 } else if (token == "\\float_placement") {
832 lex >> float_placement;
834 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
835 string toktmp = pdfoptions().readToken(lex, token);
836 if (!toktmp.empty()) {
837 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
841 } else if (token == "\\html_math_output") {
844 html_math_output = static_cast<MathOutput>(temp);
845 } else if (token == "\\html_be_strict") {
846 lex >> html_be_strict;
847 } else if (token == "\\html_math_img_scale") {
848 lex >> html_math_img_scale;
849 } else if (token == "\\html_latex_start") {
851 html_latex_start = lex.getString();
852 } else if (token == "\\html_latex_end") {
854 html_latex_end = lex.getString();
855 } else if (token == "\\output_sync") {
857 } else if (token == "\\output_sync_macro") {
858 lex >> output_sync_macro;
859 } else if (token == "\\use_refstyle") {
862 lyxerr << "BufferParams::readToken(): Unknown token: " <<
871 void BufferParams::writeFile(ostream & os) const
873 // The top of the file is written by the buffer.
874 // Prints out the buffer info into the .lyx file given by file
877 os << "\\textclass " << baseClass()->name() << '\n';
880 if (!preamble.empty()) {
881 // remove '\n' from the end of preamble
882 string const tmppreamble = rtrim(preamble, "\n");
883 os << "\\begin_preamble\n"
885 << "\n\\end_preamble\n";
889 if (!options.empty()) {
890 os << "\\options " << options << '\n';
893 // use the class options defined in the layout?
894 os << "\\use_default_options "
895 << convert<string>(use_default_options) << "\n";
897 // the master document
898 if (!master.empty()) {
899 os << "\\master " << master << '\n';
903 if (!removedModules_.empty()) {
904 os << "\\begin_removed_modules" << '\n';
905 list<string>::const_iterator it = removedModules_.begin();
906 list<string>::const_iterator en = removedModules_.end();
907 for (; it != en; it++)
909 os << "\\end_removed_modules" << '\n';
913 if (!layoutModules_.empty()) {
914 os << "\\begin_modules" << '\n';
915 LayoutModuleList::const_iterator it = layoutModules_.begin();
916 LayoutModuleList::const_iterator en = layoutModules_.end();
917 for (; it != en; it++)
919 os << "\\end_modules" << '\n';
923 if (!includedChildren_.empty()) {
924 os << "\\begin_includeonly" << '\n';
925 list<string>::const_iterator it = includedChildren_.begin();
926 list<string>::const_iterator en = includedChildren_.end();
927 for (; it != en; it++)
929 os << "\\end_includeonly" << '\n';
931 os << "\\maintain_unincluded_children "
932 << convert<string>(maintain_unincluded_children) << '\n';
934 // local layout information
935 if (!local_layout.empty()) {
936 // remove '\n' from the end
937 string const tmplocal = rtrim(local_layout, "\n");
938 os << "\\begin_local_layout\n"
940 << "\n\\end_local_layout\n";
943 // then the text parameters
944 if (language != ignore_language)
945 os << "\\language " << language->lang() << '\n';
946 os << "\\inputencoding " << inputenc
947 << "\n\\fontencoding " << fontenc
948 << "\n\\font_roman " << fontsRoman
949 << "\n\\font_sans " << fontsSans
950 << "\n\\font_typewriter " << fontsTypewriter
951 << "\n\\font_default_family " << fontsDefaultFamily
952 << "\n\\use_xetex " << convert<string>(useXetex)
953 << "\n\\font_sc " << convert<string>(fontsSC)
954 << "\n\\font_osf " << convert<string>(fontsOSF)
955 << "\n\\font_sf_scale " << fontsSansScale
956 << "\n\\font_tt_scale " << fontsTypewriterScale
958 if (!fontsCJK.empty()) {
959 os << "\\font_cjk " << fontsCJK << '\n';
961 os << "\n\\graphics " << graphicsDriver << '\n';
962 os << "\\default_output_format " << defaultOutputFormat << '\n';
963 os << "\\output_sync " << output_sync << '\n';
964 if (!output_sync_macro.empty())
965 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
966 os << "\\bibtex_command " << bibtex_command << '\n';
967 os << "\\index_command " << index_command << '\n';
969 if (!float_placement.empty()) {
970 os << "\\float_placement " << float_placement << '\n';
972 os << "\\paperfontsize " << fontsize << '\n';
974 spacing().writeFile(os);
975 pdfoptions().writeFile(os);
977 os << "\\papersize " << string_papersize[papersize]
978 << "\n\\use_geometry " << convert<string>(use_geometry)
979 << "\n\\use_amsmath " << use_amsmath
980 << "\n\\use_esint " << use_esint
981 << "\n\\use_mhchem " << use_mhchem
982 << "\n\\use_mathdots " << use_mathdots
983 << "\n\\cite_engine " << citeenginetranslator().find(cite_engine_)
984 << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
985 << "\n\\use_indices " << convert<string>(use_indices)
986 << "\n\\paperorientation " << string_orientation[orientation]
987 << "\n\\suppress_date " << convert<string>(suppress_date)
988 << "\n\\use_refstyle " << use_refstyle
990 if (isbackgroundcolor == true)
991 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
992 if (isfontcolor == true)
993 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
994 if (notefontcolor != lyx::rgbFromHexName("#cccccc"))
995 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
996 if (boxbgcolor != lyx::rgbFromHexName("#ff0000"))
997 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
999 BranchList::const_iterator it = branchlist().begin();
1000 BranchList::const_iterator end = branchlist().end();
1001 for (; it != end; ++it) {
1002 os << "\\branch " << to_utf8(it->branch())
1003 << "\n\\selected " << it->isSelected()
1004 << "\n\\filename_suffix " << it->hasFileNameSuffix()
1005 << "\n\\color " << lyx::X11hexname(it->color())
1010 IndicesList::const_iterator iit = indiceslist().begin();
1011 IndicesList::const_iterator iend = indiceslist().end();
1012 for (; iit != iend; ++iit) {
1013 os << "\\index " << to_utf8(iit->index())
1014 << "\n\\shortcut " << to_utf8(iit->shortcut())
1015 << "\n\\color " << lyx::X11hexname(iit->color())
1020 if (!paperwidth.empty())
1021 os << "\\paperwidth "
1022 << VSpace(paperwidth).asLyXCommand() << '\n';
1023 if (!paperheight.empty())
1024 os << "\\paperheight "
1025 << VSpace(paperheight).asLyXCommand() << '\n';
1026 if (!leftmargin.empty())
1027 os << "\\leftmargin "
1028 << VSpace(leftmargin).asLyXCommand() << '\n';
1029 if (!topmargin.empty())
1030 os << "\\topmargin "
1031 << VSpace(topmargin).asLyXCommand() << '\n';
1032 if (!rightmargin.empty())
1033 os << "\\rightmargin "
1034 << VSpace(rightmargin).asLyXCommand() << '\n';
1035 if (!bottommargin.empty())
1036 os << "\\bottommargin "
1037 << VSpace(bottommargin).asLyXCommand() << '\n';
1038 if (!headheight.empty())
1039 os << "\\headheight "
1040 << VSpace(headheight).asLyXCommand() << '\n';
1041 if (!headsep.empty())
1043 << VSpace(headsep).asLyXCommand() << '\n';
1044 if (!footskip.empty())
1046 << VSpace(footskip).asLyXCommand() << '\n';
1047 if (!columnsep.empty())
1048 os << "\\columnsep "
1049 << VSpace(columnsep).asLyXCommand() << '\n';
1050 os << "\\secnumdepth " << secnumdepth
1051 << "\n\\tocdepth " << tocdepth
1052 << "\n\\paragraph_separation "
1053 << string_paragraph_separation[paragraph_separation];
1054 if (!paragraph_separation)
1055 os << "\n\\paragraph_indentation " << getIndentation().asLyXCommand();
1057 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1058 os << "\n\\quotes_language "
1059 << string_quotes_language[quotes_language]
1060 << "\n\\papercolumns " << columns
1061 << "\n\\papersides " << sides
1062 << "\n\\paperpagestyle " << pagestyle << '\n';
1063 if (!listings_params.empty())
1064 os << "\\listings_params \"" <<
1065 InsetListingsParams(listings_params).encodedString() << "\"\n";
1066 for (int i = 0; i < 4; ++i) {
1067 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1068 if (user_defined_bullet(i).getFont() != -1) {
1069 os << "\\bullet " << i << " "
1070 << user_defined_bullet(i).getFont() << " "
1071 << user_defined_bullet(i).getCharacter() << " "
1072 << user_defined_bullet(i).getSize() << "\n";
1076 os << "\\bulletLaTeX " << i << " \""
1077 << lyx::to_ascii(user_defined_bullet(i).getText())
1083 os << "\\tracking_changes " << convert<string>(trackChanges) << '\n'
1084 << "\\output_changes " << convert<string>(outputChanges) << '\n'
1085 << "\\html_math_output " << html_math_output << '\n'
1086 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1088 if (html_math_img_scale != 1.0)
1089 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1090 if (!html_latex_start.empty())
1091 os << "\\html_latex_start " << html_latex_start << '\n';
1092 if (!html_latex_end.empty())
1093 os << "\\html_latex_end " << html_latex_end << '\n';
1095 os << pimpl_->authorlist;
1099 void BufferParams::validate(LaTeXFeatures & features) const
1101 features.require(documentClass().requires());
1103 if (outputChanges) {
1104 bool dvipost = LaTeXFeatures::isAvailable("dvipost");
1105 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1106 LaTeXFeatures::isAvailable("xcolor");
1108 switch (features.runparams().flavor) {
1109 case OutputParams::LATEX:
1111 features.require("ct-dvipost");
1112 features.require("dvipost");
1113 } else if (xcolorulem) {
1114 features.require("ct-xcolor-ulem");
1115 features.require("ulem");
1116 features.require("xcolor");
1118 features.require("ct-none");
1121 case OutputParams::PDFLATEX:
1122 case OutputParams::XETEX:
1124 features.require("ct-xcolor-ulem");
1125 features.require("ulem");
1126 features.require("xcolor");
1127 // improves color handling in PDF output
1128 features.require("pdfcolmk");
1130 features.require("ct-none");
1138 // Floats with 'Here definitely' as default setting.
1139 if (float_placement.find('H') != string::npos)
1140 features.require("float");
1142 // AMS Style is at document level
1143 if (use_amsmath == package_on
1144 || documentClass().provides("amsmath"))
1145 features.require("amsmath");
1146 if (use_esint == package_on)
1147 features.require("esint");
1148 if (use_mhchem == package_on)
1149 features.require("mhchem");
1150 if (use_mathdots == package_on)
1151 features.require("mathdots");
1153 // Document-level line spacing
1154 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1155 features.require("setspace");
1157 // the bullet shapes are buffer level not paragraph level
1158 // so they are tested here
1159 for (int i = 0; i < 4; ++i) {
1160 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1162 int const font = user_defined_bullet(i).getFont();
1164 int const c = user_defined_bullet(i).getCharacter();
1170 features.require("latexsym");
1172 } else if (font == 1) {
1173 features.require("amssymb");
1174 } else if (font >= 2 && font <= 5) {
1175 features.require("pifont");
1179 if (pdfoptions().use_hyperref) {
1180 features.require("hyperref");
1181 // due to interferences with babel and hyperref, the color package has to
1182 // be loaded after hyperref when hyperref is used with the colorlinks
1183 // option, see http://www.lyx.org/trac/ticket/5291
1184 if (pdfoptions().colorlinks)
1185 features.require("color");
1189 features.require("xetex");
1191 if (language->lang() == "vietnamese")
1192 features.require("vietnamese");
1193 else if (language->lang() == "japanese")
1194 features.require("japanese");
1198 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
1199 TexRow & texrow, FileName const & filepath) const
1201 os << "\\documentclass";
1203 DocumentClass const & tclass = documentClass();
1205 ostringstream clsoptions; // the document class options.
1207 if (tokenPos(tclass.opt_fontsize(),
1208 '|', fontsize) >= 0) {
1209 // only write if existing in list (and not default)
1210 clsoptions << fontsize << "pt,";
1213 // all paper sizes except of A4, A5, B5 and the US sizes need the
1215 bool nonstandard_papersize = papersize != PAPER_DEFAULT
1216 && papersize != PAPER_USLETTER
1217 && papersize != PAPER_USLEGAL
1218 && papersize != PAPER_USEXECUTIVE
1219 && papersize != PAPER_A4
1220 && papersize != PAPER_A5
1221 && papersize != PAPER_B5;
1223 if (!use_geometry) {
1224 switch (papersize) {
1226 clsoptions << "a4paper,";
1228 case PAPER_USLETTER:
1229 clsoptions << "letterpaper,";
1232 clsoptions << "a5paper,";
1235 clsoptions << "b5paper,";
1237 case PAPER_USEXECUTIVE:
1238 clsoptions << "executivepaper,";
1241 clsoptions << "legalpaper,";
1275 if (sides != tclass.sides()) {
1278 clsoptions << "oneside,";
1281 clsoptions << "twoside,";
1287 if (columns != tclass.columns()) {
1289 clsoptions << "twocolumn,";
1291 clsoptions << "onecolumn,";
1295 && orientation == ORIENTATION_LANDSCAPE)
1296 clsoptions << "landscape,";
1298 // language should be a parameter to \documentclass
1299 if (language->babel() == "hebrew"
1300 && default_language->babel() != "hebrew")
1301 // This seems necessary
1302 features.useLanguage(default_language);
1304 ostringstream language_options;
1305 bool const use_babel = features.useBabel() && !tclass.provides("babel");
1307 language_options << features.getLanguages();
1308 if (!language->babel().empty()) {
1309 if (!language_options.str().empty())
1310 language_options << ',';
1311 language_options << language->babel();
1313 // if Vietnamese is used, babel must directly be loaded
1314 // with language options, not in the class options, see
1315 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1316 size_t viet = language_options.str().find("vietnam");
1317 // viet = string::npos when not found
1318 // the same is for all other languages that are not directly supported by
1319 // babel, but where LaTeX-packages add babel support.
1320 // this is currently the case for Latvian, Lithuanian, Mongolian
1322 size_t latvian = language_options.str().find("latvian");
1323 size_t lithu = language_options.str().find("lithuanian");
1324 size_t mongo = language_options.str().find("mongolian");
1325 size_t turkmen = language_options.str().find("turkmen");
1326 // if Japanese is used, babel must directly be loaded
1327 // with language options, not in the class options, see
1328 // http://www.lyx.org/trac/ticket/4597#c4
1329 size_t japan = language_options.str().find("japanese");
1330 if (lyxrc.language_global_options && !language_options.str().empty()
1331 && viet == string::npos && japan == string::npos
1332 && latvian == string::npos && lithu == string::npos
1333 && mongo == string::npos && turkmen == string::npos)
1334 clsoptions << language_options.str() << ',';
1337 // the predefined options from the layout
1338 if (use_default_options && !tclass.options().empty())
1339 clsoptions << tclass.options() << ',';
1341 // the user-defined options
1342 if (!options.empty()) {
1343 clsoptions << options << ',';
1346 string strOptions(clsoptions.str());
1347 if (!strOptions.empty()) {
1348 strOptions = rtrim(strOptions, ",");
1350 os << '[' << from_utf8(strOptions) << ']';
1353 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1355 // end of \documentclass defs
1358 os << "\\usepackage{fontspec}\n";
1362 // font selection must be done before loading fontenc.sty
1363 string const fonts =
1364 loadFonts(fontsRoman, fontsSans,
1365 fontsTypewriter, fontsSC, fontsOSF,
1366 fontsSansScale, fontsTypewriterScale, useXetex);
1367 if (!fonts.empty()) {
1368 os << from_ascii(fonts);
1371 if (fontsDefaultFamily != "default")
1372 os << "\\renewcommand{\\familydefault}{\\"
1373 << from_ascii(fontsDefaultFamily) << "}\n";
1375 // set font encoding
1376 // for arabic_arabi and farsi we also need to load the LAE and
1378 // XeTeX works without fontenc
1379 if (font_encoding() != "default" && language->lang() != "japanese"
1380 && !useXetex && !tclass.provides("fontenc")) {
1381 size_t fars = language_options.str().find("farsi");
1382 size_t arab = language_options.str().find("arabic");
1383 if (language->lang() == "arabic_arabi"
1384 || language->lang() == "farsi" || fars != string::npos
1385 || arab != string::npos) {
1386 os << "\\usepackage[" << from_ascii(font_encoding())
1387 << ",LFE,LAE]{fontenc}\n";
1390 os << "\\usepackage[" << from_ascii(font_encoding())
1396 // handle inputenc etc.
1397 writeEncodingPreamble(os, features, texrow);
1400 if (!features.runparams().includeall && !includedChildren_.empty()) {
1401 os << "\\includeonly{";
1402 list<string>::const_iterator it = includedChildren_.begin();
1404 for (; it != includedChildren_.end() ; ++it) {
1405 string incfile = *it;
1406 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1407 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1409 if (!features.runparams().nice)
1411 // \includeonly doesn't want an extension
1412 incfile = changeExtension(incfile, string());
1413 incfile = support::latex_path(incfile);
1414 if (!incfile.empty()) {
1417 os << from_utf8(incfile);
1424 if (!listings_params.empty() || features.isRequired("listings")) {
1425 os << "\\usepackage{listings}\n";
1428 if (!listings_params.empty()) {
1430 // do not test validity because listings_params is
1431 // supposed to be valid
1433 InsetListingsParams(listings_params).separatedParams(true);
1434 // we can't support all packages, but we should load the color package
1435 if (par.find("\\color", 0) != string::npos)
1436 features.require("color");
1437 os << from_utf8(par);
1438 // count the number of newlines
1439 for (size_t i = 0; i < par.size(); ++i)
1445 if (!tclass.provides("geometry")
1446 && (use_geometry || nonstandard_papersize)) {
1447 odocstringstream ods;
1448 if (!getGraphicsDriver("geometry").empty())
1449 ods << getGraphicsDriver("geometry");
1450 if (orientation == ORIENTATION_LANDSCAPE)
1451 ods << ",landscape";
1452 switch (papersize) {
1454 if (!paperwidth.empty())
1455 ods << ",paperwidth="
1456 << from_ascii(paperwidth);
1457 if (!paperheight.empty())
1458 ods << ",paperheight="
1459 << from_ascii(paperheight);
1461 case PAPER_USLETTER:
1462 ods << ",letterpaper";
1465 ods << ",legalpaper";
1467 case PAPER_USEXECUTIVE:
1468 ods << ",executivepaper";
1555 // default papersize ie PAPER_DEFAULT
1556 switch (lyxrc.default_papersize) {
1557 case PAPER_DEFAULT: // keep compiler happy
1558 case PAPER_USLETTER:
1559 ods << ",letterpaper";
1562 ods << ",legalpaper";
1564 case PAPER_USEXECUTIVE:
1565 ods << ",executivepaper";
1607 docstring const g_options = trim(ods.str(), ",");
1608 os << "\\usepackage";
1609 if (!g_options.empty())
1610 os << '[' << g_options << ']';
1611 os << "{geometry}\n";
1613 // output this only if use_geometry is true
1615 os << "\\geometry{verbose";
1616 if (!topmargin.empty())
1617 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1618 if (!bottommargin.empty())
1619 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1620 if (!leftmargin.empty())
1621 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1622 if (!rightmargin.empty())
1623 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1624 if (!headheight.empty())
1625 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1626 if (!headsep.empty())
1627 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1628 if (!footskip.empty())
1629 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1630 if (!columnsep.empty())
1631 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1635 } else if (orientation == ORIENTATION_LANDSCAPE
1636 || papersize != PAPER_DEFAULT) {
1637 features.require("papersize");
1640 if (tokenPos(tclass.opt_pagestyle(),
1641 '|', pagestyle) >= 0) {
1642 if (pagestyle == "fancy") {
1643 os << "\\usepackage{fancyhdr}\n";
1646 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1650 // only output when the background color is not default
1651 if (isbackgroundcolor == true) {
1652 // only require color here, the background color will be defined
1653 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1655 features.require("color");
1656 features.require("pagecolor");
1659 // only output when the font color is not default
1660 if (isfontcolor == true) {
1661 // only require color here, the font color will be defined
1662 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1664 features.require("color");
1665 features.require("fontcolor");
1668 // Only if class has a ToC hierarchy
1669 if (tclass.hasTocLevels()) {
1670 if (secnumdepth != tclass.secnumdepth()) {
1671 os << "\\setcounter{secnumdepth}{"
1676 if (tocdepth != tclass.tocdepth()) {
1677 os << "\\setcounter{tocdepth}{"
1684 if (paragraph_separation) {
1685 // when skip separation
1686 switch (getDefSkip().kind()) {
1687 case VSpace::SMALLSKIP:
1688 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1690 case VSpace::MEDSKIP:
1691 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1693 case VSpace::BIGSKIP:
1694 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1696 case VSpace::LENGTH:
1697 os << "\\setlength{\\parskip}{"
1698 << from_utf8(getDefSkip().length().asLatexString())
1701 default: // should never happen // Then delete it.
1702 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1706 os << "\\setlength{\\parindent}{0pt}\n";
1709 // when separation by indentation
1710 // only output something when a width is given
1711 if (getIndentation().asLyXCommand() != "default") {
1712 os << "\\setlength{\\parindent}{"
1713 << from_utf8(getIndentation().asLatexCommand())
1719 // Now insert the LyX specific LaTeX commands...
1720 docstring lyxpreamble;
1723 if (!output_sync_macro.empty())
1724 lyxpreamble += from_utf8(output_sync_macro) +"\n";
1725 else if (features.runparams().flavor == OutputParams::LATEX)
1726 lyxpreamble += "\\usepackage[active]{srcltx}\n";
1727 else if (features.runparams().flavor == OutputParams::PDFLATEX)
1728 lyxpreamble += "\\synctex=-1\n";
1731 // due to interferences with babel and hyperref, the color package has to
1732 // be loaded (when it is not already loaded) before babel when hyperref
1733 // is used with the colorlinks option, see
1734 // http://www.lyx.org/trac/ticket/5291
1735 // we decided therefore to load color always before babel, see
1736 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
1737 lyxpreamble += from_ascii(features.getColorOptions());
1739 // If we use hyperref, jurabib, japanese, or vietnamese, we have to call babel before them.
1741 && (features.isRequired("jurabib")
1742 || features.isRequired("hyperref")
1743 || features.isRequired("vietnamese")
1744 || features.isRequired("japanese") ) ) {
1746 lyxpreamble += from_utf8(features.getBabelPresettings());
1747 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1748 lyxpreamble += from_utf8(features.getBabelPostsettings());
1751 // The optional packages;
1752 lyxpreamble += from_ascii(features.getPackages());
1754 // Additional Indices
1755 if (features.isRequired("splitidx")) {
1756 IndicesList::const_iterator iit = indiceslist().begin();
1757 IndicesList::const_iterator iend = indiceslist().end();
1758 for (; iit != iend; ++iit) {
1759 lyxpreamble += "\\newindex[";
1760 lyxpreamble += iit->index();
1761 lyxpreamble += "]{";
1762 lyxpreamble += iit->shortcut();
1763 lyxpreamble += "}\n";
1768 lyxpreamble += from_utf8(spacing().writePreamble(tclass.provides("SetSpace")));
1771 // * Hyperref manual: "Make sure it comes last of your loaded
1772 // packages, to give it a fighting chance of not being over-written,
1773 // since its job is to redefine many LaTeX commands."
1774 // * Email from Heiko Oberdiek: "It is usually better to load babel
1775 // before hyperref. Then hyperref has a chance to detect babel.
1776 // * Has to be loaded before the "LyX specific LaTeX commands" to
1777 // avoid errors with algorithm floats.
1778 // use hyperref explicitly if it is required
1779 if (features.isRequired("hyperref")) {
1780 // pass what we have to stream here, since we need
1781 // to access the stream itself in PDFOptions.
1785 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1787 OutputParams tmp_params = features.runparams();
1788 lines += pdfoptions().writeLaTeX(tmp_params, os,
1789 documentClass().provides("hyperref"));
1790 texrow.newlines(lines);
1791 // set back for the rest
1792 lyxpreamble.clear();
1793 } else if (features.isRequired("nameref"))
1794 // hyperref loads this automatically
1795 lyxpreamble += "\\usepackage{nameref}\n";
1797 // Will be surrounded by \makeatletter and \makeatother when not empty
1798 docstring atlyxpreamble;
1800 // Some macros LyX will need
1801 docstring tmppreamble(features.getMacros());
1803 if (!tmppreamble.empty())
1804 atlyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1805 "LyX specific LaTeX commands.\n"
1806 + tmppreamble + '\n';
1808 // the text class specific preamble
1809 tmppreamble = features.getTClassPreamble();
1810 if (!tmppreamble.empty())
1811 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1812 "Textclass specific LaTeX commands.\n"
1813 + tmppreamble + '\n';
1815 // suppress date if selected
1816 // use \@ifundefined because we cannot be sure that every document class
1817 // has a \date command
1819 atlyxpreamble += "\\@ifundefined{date}{}{\\date{}}\n";
1821 /* the user-defined preamble */
1822 if (!containsOnly(preamble, " \n\t"))
1824 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1825 "User specified LaTeX commands.\n"
1826 + from_utf8(preamble) + '\n';
1828 // subfig loads internally the LaTeX package "caption". As
1829 // caption is a very popular package, users will load it in
1830 // the preamble. Therefore we must load subfig behind the
1831 // user-defined preamble and check if the caption package was
1832 // loaded or not. For the case that caption is loaded before
1833 // subfig, there is the subfig option "caption=false". This
1834 // option also works when a koma-script class is used and
1835 // koma's own caption commands are used instead of caption. We
1836 // use \PassOptionsToPackage here because the user could have
1837 // already loaded subfig in the preamble.
1838 if (features.isRequired("subfig")) {
1839 atlyxpreamble += "\\@ifundefined{showcaptionsetup}{}{%\n"
1840 " \\PassOptionsToPackage{caption=false}{subfig}}\n"
1841 "\\usepackage{subfig}\n";
1844 // Itemize bullet settings need to be last in case the user
1845 // defines their own bullets that use a package included
1846 // in the user-defined preamble -- ARRae
1847 // Actually it has to be done much later than that
1848 // since some packages like frenchb make modifications
1849 // at \begin{document} time -- JMarc
1850 docstring bullets_def;
1851 for (int i = 0; i < 4; ++i) {
1852 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1853 if (bullets_def.empty())
1854 bullets_def += "\\AtBeginDocument{\n";
1855 bullets_def += " \\def\\labelitemi";
1857 // `i' is one less than the item to modify
1864 bullets_def += "ii";
1870 bullets_def += '{' +
1871 user_defined_bullet(i).getText()
1876 if (!bullets_def.empty())
1877 atlyxpreamble += bullets_def + "}\n\n";
1879 if (!atlyxpreamble.empty())
1880 lyxpreamble += "\n\\makeatletter\n"
1881 + atlyxpreamble + "\\makeatother\n\n";
1883 // We try to load babel late, in case it interferes with other packages.
1884 // Jurabib and Hyperref have to be called after babel, though.
1885 if (use_babel && !features.isRequired("jurabib")
1886 && !features.isRequired("hyperref")
1887 && !features.isRequired("vietnamese")
1888 && !features.isRequired("japanese")) {
1890 lyxpreamble += from_utf8(features.getBabelPresettings());
1891 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1892 lyxpreamble += from_utf8(features.getBabelPostsettings());
1895 docstring const i18npreamble = features.getTClassI18nPreamble(use_babel);
1896 if (!i18npreamble.empty())
1897 lyxpreamble += i18npreamble + '\n';
1900 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1901 texrow.newlines(nlines);
1905 // these packages (xunicode, for that matter) need to be loaded at least
1906 // after amsmath, amssymb, esint and the other packages that provide
1909 os << "\\usepackage{xunicode}\n";
1911 os << "\\usepackage{xltxtra}\n";
1918 void BufferParams::useClassDefaults()
1920 DocumentClass const & tclass = documentClass();
1922 sides = tclass.sides();
1923 columns = tclass.columns();
1924 pagestyle = tclass.pagestyle();
1925 use_default_options = true;
1926 // Only if class has a ToC hierarchy
1927 if (tclass.hasTocLevels()) {
1928 secnumdepth = tclass.secnumdepth();
1929 tocdepth = tclass.tocdepth();
1934 bool BufferParams::hasClassDefaults() const
1936 DocumentClass const & tclass = documentClass();
1938 return sides == tclass.sides()
1939 && columns == tclass.columns()
1940 && pagestyle == tclass.pagestyle()
1941 && use_default_options
1942 && secnumdepth == tclass.secnumdepth()
1943 && tocdepth == tclass.tocdepth();
1947 DocumentClass const & BufferParams::documentClass() const
1953 DocumentClass const * BufferParams::documentClassPtr() const
1959 void BufferParams::setDocumentClass(DocumentClass const * const tc)
1961 // evil, but this function is evil
1962 doc_class_ = const_cast<DocumentClass *>(tc);
1966 bool BufferParams::setBaseClass(string const & classname)
1968 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
1969 LayoutFileList & bcl = LayoutFileList::get();
1970 if (!bcl.haveClass(classname)) {
1972 bformat(_("The layout file:\n"
1974 "could not be found. A default textclass with default\n"
1975 "layouts will be used. LyX will not be able to produce\n"
1977 from_utf8(classname));
1978 frontend::Alert::error(_("Document class not found"), s);
1979 bcl.addEmptyClass(classname);
1982 bool const success = bcl[classname].load();
1985 bformat(_("Due to some error in it, the layout file:\n"
1987 "could not be loaded. A default textclass with default\n"
1988 "layouts will be used. LyX will not be able to produce\n"
1990 from_utf8(classname));
1991 frontend::Alert::error(_("Could not load class"), s);
1992 bcl.addEmptyClass(classname);
1995 pimpl_->baseClass_ = classname;
1996 layoutModules_.adaptToBaseClass(baseClass(), removedModules_);
2001 LayoutFile const * BufferParams::baseClass() const
2003 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2004 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2010 LayoutFileIndex const & BufferParams::baseClassID() const
2012 return pimpl_->baseClass_;
2016 void BufferParams::makeDocumentClass()
2021 doc_class_ = &(DocumentClassBundle::get().makeDocumentClass(*baseClass(), layoutModules_));
2023 if (!local_layout.empty()) {
2024 if (!doc_class_->read(local_layout, TextClass::MODULE)) {
2025 docstring const msg = _("Error reading internal layout information");
2026 frontend::Alert::warning(_("Read Error"), msg);
2032 bool BufferParams::moduleCanBeAdded(string const & modName) const
2034 return layoutModules_.moduleCanBeAdded(modName, baseClass());
2038 bool BufferParams::addLayoutModule(string const & modName)
2040 LayoutModuleList::const_iterator it = layoutModules_.begin();
2041 LayoutModuleList::const_iterator end = layoutModules_.end();
2042 for (; it != end; it++)
2045 layoutModules_.push_back(modName);
2050 Font const BufferParams::getFont() const
2052 FontInfo f = documentClass().defaultfont();
2053 if (fontsDefaultFamily == "rmdefault")
2054 f.setFamily(ROMAN_FAMILY);
2055 else if (fontsDefaultFamily == "sfdefault")
2056 f.setFamily(SANS_FAMILY);
2057 else if (fontsDefaultFamily == "ttdefault")
2058 f.setFamily(TYPEWRITER_FAMILY);
2059 return Font(f, language);
2063 void BufferParams::readPreamble(Lexer & lex)
2065 if (lex.getString() != "\\begin_preamble")
2066 lyxerr << "Error (BufferParams::readPreamble):"
2067 "consistency check failed." << endl;
2069 preamble = lex.getLongString("\\end_preamble");
2073 void BufferParams::readLocalLayout(Lexer & lex)
2075 if (lex.getString() != "\\begin_local_layout")
2076 lyxerr << "Error (BufferParams::readLocalLayout):"
2077 "consistency check failed." << endl;
2079 local_layout = lex.getLongString("\\end_local_layout");
2083 void BufferParams::readLanguage(Lexer & lex)
2085 if (!lex.next()) return;
2087 string const tmptok = lex.getString();
2089 // check if tmptok is part of tex_babel in tex-defs.h
2090 language = languages.getLanguage(tmptok);
2092 // Language tmptok was not found
2093 language = default_language;
2094 lyxerr << "Warning: Setting language `"
2095 << tmptok << "' to `" << language->lang()
2101 void BufferParams::readGraphicsDriver(Lexer & lex)
2106 string const tmptok = lex.getString();
2107 // check if tmptok is part of tex_graphics in tex_defs.h
2110 string const test = tex_graphics[n++];
2112 if (test == tmptok) {
2113 graphicsDriver = tmptok;
2118 "Warning: graphics driver `$$Token' not recognized!\n"
2119 " Setting graphics driver to `default'.\n");
2120 graphicsDriver = "default";
2127 void BufferParams::readBullets(Lexer & lex)
2132 int const index = lex.getInteger();
2134 int temp_int = lex.getInteger();
2135 user_defined_bullet(index).setFont(temp_int);
2136 temp_bullet(index).setFont(temp_int);
2138 user_defined_bullet(index).setCharacter(temp_int);
2139 temp_bullet(index).setCharacter(temp_int);
2141 user_defined_bullet(index).setSize(temp_int);
2142 temp_bullet(index).setSize(temp_int);
2146 void BufferParams::readBulletsLaTeX(Lexer & lex)
2148 // The bullet class should be able to read this.
2151 int const index = lex.getInteger();
2153 docstring const temp_str = lex.getDocString();
2155 user_defined_bullet(index).setText(temp_str);
2156 temp_bullet(index).setText(temp_str);
2160 void BufferParams::readModules(Lexer & lex)
2162 if (!lex.eatLine()) {
2163 lyxerr << "Error (BufferParams::readModules):"
2164 "Unexpected end of input." << endl;
2168 string mod = lex.getString();
2169 if (mod == "\\end_modules")
2171 addLayoutModule(mod);
2177 void BufferParams::readRemovedModules(Lexer & lex)
2179 if (!lex.eatLine()) {
2180 lyxerr << "Error (BufferParams::readRemovedModules):"
2181 "Unexpected end of input." << endl;
2185 string mod = lex.getString();
2186 if (mod == "\\end_removed_modules")
2188 removedModules_.push_back(mod);
2191 // now we want to remove any removed modules that were previously
2192 // added. normally, that will be because default modules were added in
2193 // setBaseClass(), which gets called when \textclass is read at the
2194 // start of the read.
2195 list<string>::const_iterator rit = removedModules_.begin();
2196 list<string>::const_iterator const ren = removedModules_.end();
2197 for (; rit != ren; rit++) {
2198 LayoutModuleList::iterator const mit = layoutModules_.begin();
2199 LayoutModuleList::iterator const men = layoutModules_.end();
2200 LayoutModuleList::iterator found = find(mit, men, *rit);
2203 layoutModules_.erase(found);
2208 void BufferParams::readIncludeonly(Lexer & lex)
2210 if (!lex.eatLine()) {
2211 lyxerr << "Error (BufferParams::readIncludeonly):"
2212 "Unexpected end of input." << endl;
2216 string child = lex.getString();
2217 if (child == "\\end_includeonly")
2219 includedChildren_.push_back(child);
2225 string BufferParams::paperSizeName(PapersizePurpose purpose) const
2227 char real_papersize = papersize;
2228 if (real_papersize == PAPER_DEFAULT)
2229 real_papersize = lyxrc.default_papersize;
2231 switch (real_papersize) {
2233 // could be anything, so don't guess
2235 case PAPER_CUSTOM: {
2236 if (purpose == XDVI && !paperwidth.empty() &&
2237 !paperheight.empty()) {
2238 // heightxwidth<unit>
2239 string first = paperwidth;
2240 string second = paperheight;
2241 if (orientation == ORIENTATION_LANDSCAPE)
2244 return first.erase(first.length() - 2)
2250 // dvips and dvipdfm do not know this
2251 if (purpose == DVIPS || purpose == DVIPDFM)
2255 if (purpose == DVIPS || purpose == DVIPDFM)
2259 if (purpose == DVIPS || purpose == DVIPDFM)
2269 if (purpose == DVIPS || purpose == DVIPDFM)
2273 if (purpose == DVIPS || purpose == DVIPDFM)
2277 if (purpose == DVIPS || purpose == DVIPDFM)
2281 if (purpose == DVIPS || purpose == DVIPDFM)
2285 if (purpose == DVIPS || purpose == DVIPDFM)
2289 // dvipdfm does not know this
2290 if (purpose == DVIPDFM)
2294 if (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)
2338 if (purpose == DVIPS || purpose == DVIPDFM)
2342 if (purpose == DVIPS || purpose == DVIPDFM)
2346 if (purpose == DVIPS || purpose == DVIPDFM)
2350 if (purpose == DVIPS || purpose == DVIPDFM)
2354 if (purpose == DVIPS || purpose == DVIPDFM)
2357 case PAPER_USEXECUTIVE:
2358 // dvipdfm does not know this
2359 if (purpose == DVIPDFM)
2364 case PAPER_USLETTER:
2366 if (purpose == XDVI)
2373 string const BufferParams::dvips_options() const
2378 && papersize == PAPER_CUSTOM
2379 && !lyxrc.print_paper_dimension_flag.empty()
2380 && !paperwidth.empty()
2381 && !paperheight.empty()) {
2382 // using a custom papersize
2383 result = lyxrc.print_paper_dimension_flag;
2384 result += ' ' + paperwidth;
2385 result += ',' + paperheight;
2387 string const paper_option = paperSizeName(DVIPS);
2388 if (!paper_option.empty() && (paper_option != "letter" ||
2389 orientation != ORIENTATION_LANDSCAPE)) {
2390 // dvips won't accept -t letter -t landscape.
2391 // In all other cases, include the paper size
2393 result = lyxrc.print_paper_flag;
2394 result += ' ' + paper_option;
2397 if (orientation == ORIENTATION_LANDSCAPE &&
2398 papersize != PAPER_CUSTOM)
2399 result += ' ' + lyxrc.print_landscape_flag;
2404 string const BufferParams::font_encoding() const
2406 return (fontenc == "global") ? lyxrc.fontenc : fontenc;
2410 string BufferParams::babelCall(string const & lang_opts) const
2412 string lang_pack = lyxrc.language_package;
2413 if (lang_pack != "\\usepackage{babel}")
2415 // suppress the babel call when there is no babel language defined
2416 // for the document language in the lib/languages file and if no
2417 // other languages are used (lang_opts is then empty)
2418 if (lang_opts.empty())
2420 // If Vietnamese is used, babel must directly be loaded with the
2421 // language options, see
2422 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
2423 size_t viet = lang_opts.find("vietnam");
2424 // viet = string::npos when not found
2425 // the same is for all other languages that are not directly supported by
2426 // babel, but where LaTeX-packages add babel support.
2427 // this is currently the case for Latvian, Lithuanian, Mongolian
2429 size_t latvian = lang_opts.find("latvian");
2430 size_t lithu = lang_opts.find("lithuanian");
2431 size_t mongo = lang_opts.find("mongolian");
2432 size_t turkmen = lang_opts.find("turkmen");
2433 // If Japanese is used, babel must directly be loaded with the
2434 // language options, see
2435 // http://www.lyx.org/trac/ticket/4597#c4
2436 size_t japan = lang_opts.find("japanese");
2437 if (!lyxrc.language_global_options || viet != string::npos
2438 || japan != string::npos || latvian != string::npos
2439 || lithu != string::npos || mongo != string::npos
2440 || turkmen != string::npos)
2441 return "\\usepackage[" + lang_opts + "]{babel}";
2446 docstring BufferParams::getGraphicsDriver(string const & package) const
2450 if (package == "geometry") {
2451 if (graphicsDriver == "dvips"
2452 || graphicsDriver == "dvipdfm"
2453 || graphicsDriver == "pdftex"
2454 || graphicsDriver == "vtex")
2455 result = from_ascii(graphicsDriver);
2456 else if (graphicsDriver == "dvipdfmx")
2457 result = from_ascii("dvipdfm");
2464 void BufferParams::writeEncodingPreamble(odocstream & os,
2465 LaTeXFeatures & features, TexRow & texrow) const
2469 if (inputenc == "auto") {
2470 string const doc_encoding =
2471 language->encoding()->latexName();
2472 Encoding::Package const package =
2473 language->encoding()->package();
2475 // Create a list with all the input encodings used
2477 set<string> encodings =
2478 features.getEncodingSet(doc_encoding);
2480 // If the "japanese" package (i.e. pLaTeX) is used,
2481 // inputenc must be omitted.
2482 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
2483 if (package == Encoding::japanese)
2484 features.require("japanese");
2486 if ((!encodings.empty() || package == Encoding::inputenc)
2487 && !features.isRequired("japanese")) {
2488 os << "\\usepackage[";
2489 set<string>::const_iterator it = encodings.begin();
2490 set<string>::const_iterator const end = encodings.end();
2492 os << from_ascii(*it);
2495 for (; it != end; ++it)
2496 os << ',' << from_ascii(*it);
2497 if (package == Encoding::inputenc) {
2498 if (!encodings.empty())
2500 os << from_ascii(doc_encoding);
2502 os << "]{inputenc}\n";
2505 if (package == Encoding::CJK || features.mustProvide("CJK")) {
2506 if (language->encoding()->name() == "utf8-cjk"
2507 && LaTeXFeatures::isAvailable("CJKutf8"))
2508 os << "\\usepackage{CJKutf8}\n";
2510 os << "\\usepackage{CJK}\n";
2513 } else if (inputenc != "default") {
2514 switch (encoding().package()) {
2515 case Encoding::none:
2516 case Encoding::japanese:
2518 case Encoding::inputenc:
2519 // do not load inputenc if japanese is used
2520 if (features.isRequired("japanese"))
2522 os << "\\usepackage[" << from_ascii(inputenc)
2527 if (encoding().name() == "utf8-cjk"
2528 && LaTeXFeatures::isAvailable("CJKutf8"))
2529 os << "\\usepackage{CJKutf8}\n";
2531 os << "\\usepackage{CJK}\n";
2537 // The encoding "armscii8" (for Armenian) is only available when
2538 // the package "armtex" is loaded.
2539 if (language->encoding()->latexName() == "armscii8"
2540 || inputenc == "armscii8") {
2541 os << "\\usepackage{armtex}\n";
2547 string const BufferParams::parseFontName(string const & name) const
2549 string mangled = name;
2550 size_t const idx = mangled.find('[');
2551 if (idx == string::npos || idx == 0)
2554 return mangled.substr(0, idx - 1);
2558 string const BufferParams::loadFonts(string const & rm,
2559 string const & sf, string const & tt,
2560 bool const & sc, bool const & osf,
2561 int const & sfscale, int const & ttscale,
2562 bool const & xetex) const
2564 /* The LaTeX font world is in a flux. In the PSNFSS font interface,
2565 several packages have been replaced by others, that might not
2566 be installed on every system. We have to take care for that
2567 (see psnfss.pdf). We try to support all psnfss fonts as well
2568 as the fonts that have become de facto standard in the LaTeX
2569 world (e.g. Latin Modern). We do not support obsolete fonts
2570 (like PSLatex). In general, it should be possible to mix any
2571 rm font with any sf or tt font, respectively. (JSpitzm)
2573 -- separate math fonts.
2576 if (rm == "default" && sf == "default" && tt == "default")
2583 if (rm != "default")
2584 os << "\\setmainfont[Mapping=tex-text]{"
2585 << parseFontName(rm) << "}\n";
2586 if (sf != "default") {
2587 string const sans = parseFontName(sf);
2589 os << "\\setsansfont[Scale="
2590 << float(sfscale) / 100
2591 << ",Mapping=tex-text]{"
2594 os << "\\setsansfont[Mapping=tex-text]{"
2597 if (tt != "default") {
2598 string const mono = parseFontName(tt);
2600 os << "\\setmonofont[Scale="
2601 << float(sfscale) / 100
2605 os << "\\setmonofont[Mapping=tex-text]{"
2609 os << "\\defaultfontfeatures{Numbers=OldStyle}\n";
2614 // Computer Modern (must be explicitly selectable -- there might be classes
2615 // that define a different default font!
2617 os << "\\renewcommand{\\rmdefault}{cmr}\n";
2618 // osf for Computer Modern needs eco.sty
2620 os << "\\usepackage{eco}\n";
2622 // Latin Modern Roman
2623 else if (rm == "lmodern")
2624 os << "\\usepackage{lmodern}\n";
2626 else if (rm == "ae") {
2627 // not needed when using OT1 font encoding.
2628 if (font_encoding() != "default")
2629 os << "\\usepackage{ae,aecompl}\n";
2632 else if (rm == "times") {
2633 // try to load the best available package
2634 if (LaTeXFeatures::isAvailable("mathptmx"))
2635 os << "\\usepackage{mathptmx}\n";
2636 else if (LaTeXFeatures::isAvailable("mathptm"))
2637 os << "\\usepackage{mathptm}\n";
2639 os << "\\usepackage{times}\n";
2642 else if (rm == "palatino") {
2643 // try to load the best available package
2644 if (LaTeXFeatures::isAvailable("mathpazo")) {
2645 os << "\\usepackage";
2651 // "osf" includes "sc"!
2655 os << "{mathpazo}\n";
2657 else if (LaTeXFeatures::isAvailable("mathpple"))
2658 os << "\\usepackage{mathpple}\n";
2660 os << "\\usepackage{palatino}\n";
2663 else if (rm == "utopia") {
2664 // fourier supersedes utopia.sty, but does
2665 // not work with OT1 encoding.
2666 if (LaTeXFeatures::isAvailable("fourier")
2667 && font_encoding() != "default") {
2668 os << "\\usepackage";
2679 os << "{fourier}\n";
2682 os << "\\usepackage{utopia}\n";
2684 // Bera (complete fontset)
2685 else if (rm == "bera" && sf == "default" && tt == "default")
2686 os << "\\usepackage{bera}\n";
2688 else if (rm != "default")
2689 os << "\\usepackage" << "{" << rm << "}\n";
2692 // Helvetica, Bera Sans
2693 if (sf == "helvet" || sf == "berasans") {
2695 os << "\\usepackage[scaled=" << float(sfscale) / 100
2696 << "]{" << sf << "}\n";
2698 os << "\\usepackage{" << sf << "}\n";
2701 else if (sf == "avant")
2702 os << "\\usepackage{" << sf << "}\n";
2703 // Computer Modern, Latin Modern, CM Bright
2704 else if (sf != "default")
2705 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
2707 // monospaced/typewriter
2708 // Courier, LuxiMono
2709 if (tt == "luximono" || tt == "beramono") {
2711 os << "\\usepackage[scaled=" << float(ttscale) / 100
2712 << "]{" << tt << "}\n";
2714 os << "\\usepackage{" << tt << "}\n";
2717 else if (tt == "courier" )
2718 os << "\\usepackage{" << tt << "}\n";
2719 // Computer Modern, Latin Modern, CM Bright
2720 else if (tt != "default")
2721 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
2727 Encoding const & BufferParams::encoding() const
2730 return *(encodings.fromLaTeXName("utf8-plain"));
2731 if (inputenc == "auto" || inputenc == "default")
2732 return *language->encoding();
2733 Encoding const * const enc = encodings.fromLaTeXName(inputenc);
2736 LYXERR0("Unknown inputenc value `" << inputenc
2737 << "'. Using `auto' instead.");
2738 return *language->encoding();
2742 CiteEngine BufferParams::citeEngine() const
2744 // FIXME the class should provide the numerical/
2745 // authoryear choice
2746 if (documentClass().provides("natbib")
2747 && cite_engine_ != ENGINE_NATBIB_NUMERICAL)
2748 return ENGINE_NATBIB_AUTHORYEAR;
2749 return cite_engine_;
2753 void BufferParams::setCiteEngine(CiteEngine cite_engine)
2755 cite_engine_ = cite_engine;