2 * \file BufferParams.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
10 * \author André Pönitz
11 * \author Martin Vermeer
13 * Full author contact details are available in file CREDITS.
18 #include "BufferParams.h"
21 #include "LayoutFile.h"
22 #include "BranchList.h"
23 #include "buffer_funcs.h"
29 #include "IndicesList.h"
31 #include "LaTeXFeatures.h"
32 #include "ModuleList.h"
36 #include "OutputParams.h"
40 #include "PDFOptions.h"
42 #include "frontends/alert.h"
44 #include "insets/InsetListingsParams.h"
46 #include "support/convert.h"
47 #include "support/debug.h"
48 #include "support/docstream.h"
49 #include "support/FileName.h"
50 #include "support/filetools.h"
51 #include "support/gettext.h"
52 #include "support/Messages.h"
53 #include "support/Translator.h"
54 #include "support/lstrings.h"
60 using namespace lyx::support;
63 static char const * const string_paragraph_separation[] = {
68 static char const * const string_quotes_language[] = {
69 "english", "swedish", "german", "polish", "french", "danish", ""
73 static char const * const string_papersize[] = {
74 "default", "custom", "letterpaper", "legalpaper", "executivepaper",
75 "a3paper", "a4paper", "a5paper", "b3paper", "b4paper", "b5paper", ""
79 static char const * const string_orientation[] = {
80 "portrait", "landscape", ""
84 static char const * const string_footnotekinds[] = {
85 "footnote", "margin", "fig", "tab", "alg", "wide-fig", "wide-tab", ""
89 static char const * const tex_graphics[] = {
90 "default", "dvialw", "dvilaser", "dvipdf", "dvipdfm", "dvipdfmx",
91 "dvips", "dvipsone", "dvitops", "dviwin", "dviwindo", "dvi2ps", "emtex",
92 "ln", "oztex", "pctexhp", "pctexps", "pctexwin", "pctex32", "pdftex",
93 "psprint", "pubps", "tcidvi", "textures", "truetex", "vtex", "xdvi",
104 // Paragraph separation
105 typedef Translator<string, BufferParams::ParagraphSeparation> ParSepTranslator;
108 ParSepTranslator const init_parseptranslator()
110 ParSepTranslator translator
111 (string_paragraph_separation[0], BufferParams::ParagraphIndentSeparation);
112 translator.addPair(string_paragraph_separation[1], BufferParams::ParagraphSkipSeparation);
117 ParSepTranslator const & parseptranslator()
119 static ParSepTranslator translator = init_parseptranslator();
125 typedef Translator<string, InsetQuotes::QuoteLanguage> QuotesLangTranslator;
128 QuotesLangTranslator const init_quoteslangtranslator()
130 QuotesLangTranslator translator
131 (string_quotes_language[0], InsetQuotes::EnglishQuotes);
132 translator.addPair(string_quotes_language[1], InsetQuotes::SwedishQuotes);
133 translator.addPair(string_quotes_language[2], InsetQuotes::GermanQuotes);
134 translator.addPair(string_quotes_language[3], InsetQuotes::PolishQuotes);
135 translator.addPair(string_quotes_language[4], InsetQuotes::FrenchQuotes);
136 translator.addPair(string_quotes_language[5], InsetQuotes::DanishQuotes);
141 QuotesLangTranslator const & quoteslangtranslator()
143 static QuotesLangTranslator translator = init_quoteslangtranslator();
149 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
152 static PaperSizeTranslator initPaperSizeTranslator()
154 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
155 translator.addPair(string_papersize[1], PAPER_CUSTOM);
156 translator.addPair(string_papersize[2], PAPER_USLETTER);
157 translator.addPair(string_papersize[3], PAPER_USLEGAL);
158 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
159 translator.addPair(string_papersize[5], PAPER_A3);
160 translator.addPair(string_papersize[6], PAPER_A4);
161 translator.addPair(string_papersize[7], PAPER_A5);
162 translator.addPair(string_papersize[8], PAPER_B3);
163 translator.addPair(string_papersize[9], PAPER_B4);
164 translator.addPair(string_papersize[10], PAPER_B5);
169 PaperSizeTranslator const & papersizetranslator()
171 static PaperSizeTranslator translator = initPaperSizeTranslator();
177 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
180 PaperOrientationTranslator const init_paperorientationtranslator()
182 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
183 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
188 PaperOrientationTranslator const & paperorientationtranslator()
190 static PaperOrientationTranslator translator = init_paperorientationtranslator();
196 typedef Translator<int, PageSides> SidesTranslator;
199 SidesTranslator const init_sidestranslator()
201 SidesTranslator translator(1, OneSide);
202 translator.addPair(2, TwoSides);
207 SidesTranslator const & sidestranslator()
209 static SidesTranslator translator = init_sidestranslator();
215 typedef Translator<int, BufferParams::Package> PackageTranslator;
218 PackageTranslator const init_packagetranslator()
220 PackageTranslator translator(0, BufferParams::package_off);
221 translator.addPair(1, BufferParams::package_auto);
222 translator.addPair(2, BufferParams::package_on);
227 PackageTranslator const & packagetranslator()
229 static PackageTranslator translator = init_packagetranslator();
235 typedef Translator<string, CiteEngine> CiteEngineTranslator;
238 CiteEngineTranslator const init_citeenginetranslator()
240 CiteEngineTranslator translator("basic", ENGINE_BASIC);
241 translator.addPair("natbib_numerical", ENGINE_NATBIB_NUMERICAL);
242 translator.addPair("natbib_authoryear", ENGINE_NATBIB_AUTHORYEAR);
243 translator.addPair("jurabib", ENGINE_JURABIB);
248 CiteEngineTranslator const & citeenginetranslator()
250 static CiteEngineTranslator translator = init_citeenginetranslator();
256 typedef Translator<string, Spacing::Space> SpaceTranslator;
259 SpaceTranslator const init_spacetranslator()
261 SpaceTranslator translator("default", Spacing::Default);
262 translator.addPair("single", Spacing::Single);
263 translator.addPair("onehalf", Spacing::Onehalf);
264 translator.addPair("double", Spacing::Double);
265 translator.addPair("other", Spacing::Other);
270 SpaceTranslator const & spacetranslator()
272 static SpaceTranslator translator = init_spacetranslator();
279 class BufferParams::Impl
284 AuthorList authorlist;
285 BranchList branchlist;
286 Bullet temp_bullets[4];
287 Bullet user_defined_bullets[4];
288 IndicesList indiceslist;
290 /** This is the amount of space used for paragraph_separation "skip",
291 * and for detached paragraphs in "indented" documents.
295 PDFOptions pdfoptions;
296 LayoutFileIndex baseClass_;
300 BufferParams::Impl::Impl()
301 : defskip(VSpace::MEDSKIP), baseClass_(string(""))
303 // set initial author
305 authorlist.record(Author(from_utf8(lyxrc.user_name), from_utf8(lyxrc.user_email)));
310 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
314 return new BufferParams::Impl(*ptr);
318 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
324 BufferParams::BufferParams()
327 setBaseClass(defaultBaseclass());
329 paragraph_separation = ParagraphIndentSeparation;
330 quotes_language = InsetQuotes::EnglishQuotes;
331 fontsize = "default";
334 papersize = PAPER_DEFAULT;
335 orientation = ORIENTATION_PORTRAIT;
336 use_geometry = false;
337 use_amsmath = package_auto;
338 use_esint = package_auto;
339 use_mhchem = package_auto;
340 cite_engine_ = ENGINE_BASIC;
341 use_bibtopic = false;
343 trackChanges = false;
344 outputChanges = false;
345 use_default_options = true;
346 maintain_unincluded_children = false;
349 language = default_language;
351 fontsRoman = "default";
352 fontsSans = "default";
353 fontsTypewriter = "default";
354 fontsDefaultFamily = "default";
358 fontsSansScale = 100;
359 fontsTypewriterScale = 100;
361 graphicsDriver = "default";
362 defaultOutputFormat = "default";
363 bibtex_command = "default";
364 index_command = "default";
367 listings_params = string();
368 pagestyle = "default";
369 suppress_date = false;
370 // white is equal to no background color
371 backgroundcolor = lyx::rgbFromHexName("#ffffff");
372 // light gray is the default font color for greyed-out notes
373 notefontcolor = lyx::rgbFromHexName("#cccccc");
374 compressed = lyxrc.save_compressed;
375 for (int iter = 0; iter < 4; ++iter) {
376 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
377 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
380 indiceslist().addDefault(B_("Index"));
381 html_be_strict = true;
382 html_math_output = MathML;
386 docstring BufferParams::B_(string const & l10n) const
388 LASSERT(language, /**/);
389 return getMessages(language->code()).get(l10n);
393 AuthorList & BufferParams::authors()
395 return pimpl_->authorlist;
399 AuthorList const & BufferParams::authors() const
401 return pimpl_->authorlist;
405 BranchList & BufferParams::branchlist()
407 return pimpl_->branchlist;
411 BranchList const & BufferParams::branchlist() const
413 return pimpl_->branchlist;
417 IndicesList & BufferParams::indiceslist()
419 return pimpl_->indiceslist;
423 IndicesList const & BufferParams::indiceslist() const
425 return pimpl_->indiceslist;
429 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
431 LASSERT(index < 4, /**/);
432 return pimpl_->temp_bullets[index];
436 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
438 LASSERT(index < 4, /**/);
439 return pimpl_->temp_bullets[index];
443 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
445 LASSERT(index < 4, /**/);
446 return pimpl_->user_defined_bullets[index];
450 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
452 LASSERT(index < 4, /**/);
453 return pimpl_->user_defined_bullets[index];
457 Spacing & BufferParams::spacing()
459 return pimpl_->spacing;
463 Spacing const & BufferParams::spacing() const
465 return pimpl_->spacing;
469 PDFOptions & BufferParams::pdfoptions()
471 return pimpl_->pdfoptions;
475 PDFOptions const & BufferParams::pdfoptions() const
477 return pimpl_->pdfoptions;
481 HSpace const & BufferParams::getIndentation() const
483 return pimpl_->indentation;
487 void BufferParams::setIndentation(HSpace const & indent)
489 pimpl_->indentation = indent;
493 VSpace const & BufferParams::getDefSkip() const
495 return pimpl_->defskip;
499 void BufferParams::setDefSkip(VSpace const & vs)
501 pimpl_->defskip = vs;
505 string BufferParams::readToken(Lexer & lex, string const & token,
506 FileName const & filepath)
508 if (token == "\\textclass") {
510 string const classname = lex.getString();
511 // if there exists a local layout file, ignore the system one
512 // NOTE: in this case, the textclass (.cls file) is assumed to be available.
514 LayoutFileList & bcl = LayoutFileList::get();
515 if (tcp.empty() && !filepath.empty())
516 tcp = bcl.addLocalLayout(classname, filepath.absFilename());
520 setBaseClass(classname);
521 // We assume that a tex class exists for local or unknown layouts so this warning
522 // will only be given for system layouts.
523 if (!baseClass()->isTeXClassAvailable()) {
525 translateIfPossible(from_utf8(baseClass()->description()));
526 docstring const msg =
527 bformat(_("The document class requested\n"
529 "requires external files that are not available.\n"
530 "The document class can still be used, but LyX\n"
531 "will not be able to produce output until the\n"
532 "following prerequisites are installed:\n"
534 "See section 3.1.2.2 of the User's Guide for\n"
535 "more information."),
536 desc, from_utf8(baseClass()->prerequisites()));
537 frontend::Alert::warning(_("Document class not available"),
540 } else if (token == "\\begin_preamble") {
542 } else if (token == "\\begin_local_layout") {
543 readLocalLayout(lex);
544 } else if (token == "\\begin_modules") {
546 } else if (token == "\\begin_removed_modules") {
547 readRemovedModules(lex);
548 } else if (token == "\\begin_includeonly") {
549 readIncludeonly(lex);
550 } else if (token == "\\maintain_unincluded_children") {
551 lex >> maintain_unincluded_children;
552 } else if (token == "\\options") {
554 options = lex.getString();
555 } else if (token == "\\use_default_options") {
556 lex >> use_default_options;
557 } else if (token == "\\master") {
559 master = lex.getString();
560 } else if (token == "\\suppress_date") {
561 lex >> suppress_date;
562 } else if (token == "\\language") {
564 } else if (token == "\\inputencoding") {
566 } else if (token == "\\graphics") {
567 readGraphicsDriver(lex);
568 } else if (token == "\\default_output_format") {
569 lex >> defaultOutputFormat;
570 } else if (token == "\\bibtex_command") {
572 bibtex_command = lex.getString();
573 } else if (token == "\\index_command") {
575 index_command = lex.getString();
576 } else if (token == "\\fontencoding") {
578 fontenc = lex.getString();
579 } else if (token == "\\font_roman") {
581 fontsRoman = lex.getString();
582 } else if (token == "\\font_sans") {
584 fontsSans = lex.getString();
585 } else if (token == "\\font_typewriter") {
587 fontsTypewriter = lex.getString();
588 } else if (token == "\\font_default_family") {
589 lex >> fontsDefaultFamily;
590 } else if (token == "\\use_xetex") {
592 } else if (token == "\\font_sc") {
594 } else if (token == "\\font_osf") {
596 } else if (token == "\\font_sf_scale") {
597 lex >> fontsSansScale;
598 } else if (token == "\\font_tt_scale") {
599 lex >> fontsTypewriterScale;
600 } else if (token == "\\font_cjk") {
602 } else if (token == "\\paragraph_separation") {
605 paragraph_separation = parseptranslator().find(parsep);
606 } else if (token == "\\paragraph_indentation") {
608 string indentation = lex.getString();
609 pimpl_->indentation = HSpace(indentation);
610 } else if (token == "\\defskip") {
612 string defskip = lex.getString();
613 if (defskip == "defskip")
616 pimpl_->defskip = VSpace(defskip);
617 } else if (token == "\\quotes_language") {
620 quotes_language = quoteslangtranslator().find(quotes_lang);
621 } else if (token == "\\papersize") {
624 papersize = papersizetranslator().find(ppsize);
625 } else if (token == "\\use_geometry") {
627 } else if (token == "\\use_amsmath") {
630 use_amsmath = packagetranslator().find(use_ams);
631 } else if (token == "\\use_esint") {
634 use_esint = packagetranslator().find(useesint);
635 } else if (token == "\\use_mhchem") {
638 use_mhchem = packagetranslator().find(usemhchem);
639 } else if (token == "\\cite_engine") {
642 cite_engine_ = citeenginetranslator().find(engine);
643 } else if (token == "\\use_bibtopic") {
645 } else if (token == "\\use_indices") {
647 } else if (token == "\\tracking_changes") {
649 } else if (token == "\\output_changes") {
650 lex >> outputChanges;
651 } else if (token == "\\branch") {
653 docstring branch = lex.getDocString();
654 branchlist().add(branch);
657 string const tok = lex.getString();
658 if (tok == "\\end_branch")
660 Branch * branch_ptr = branchlist().find(branch);
661 if (tok == "\\selected") {
664 branch_ptr->setSelected(lex.getInteger());
666 if (tok == "\\filename_suffix") {
669 branch_ptr->setFilenameSuffix(lex.getInteger());
671 if (tok == "\\color") {
673 string color = lex.getString();
675 branch_ptr->setColor(color);
676 // Update also the Color table:
678 color = lcolor.getX11Name(Color_background);
680 lcolor.setColor(to_utf8(branch), color);
683 } else if (token == "\\index") {
685 docstring index = lex.getDocString();
687 indiceslist().add(index);
690 string const tok = lex.getString();
691 if (tok == "\\end_index")
693 Index * index_ptr = indiceslist().find(index);
694 if (tok == "\\shortcut") {
696 shortcut = lex.getDocString();
698 index_ptr->setShortcut(shortcut);
700 if (tok == "\\color") {
702 string color = lex.getString();
704 index_ptr->setColor(color);
705 // Update also the Color table:
707 color = lcolor.getX11Name(Color_background);
709 if (!shortcut.empty())
710 lcolor.setColor(to_utf8(shortcut), color);
713 } else if (token == "\\author") {
715 istringstream ss(lex.getString());
718 author_map[a.buffer_id()] = pimpl_->authorlist.record(a);
719 } else if (token == "\\paperorientation") {
722 orientation = paperorientationtranslator().find(orient);
723 } else if (token == "\\backgroundcolor") {
725 backgroundcolor = lyx::rgbFromHexName(lex.getString());
726 } else if (token == "\\notefontcolor") {
728 string color = lex.getString();
729 notefontcolor = lyx::rgbFromHexName(color);
730 // set the font color within LyX
731 lcolor.setColor(Color_greyedouttext, color);
732 } else if (token == "\\paperwidth") {
734 } else if (token == "\\paperheight") {
736 } else if (token == "\\leftmargin") {
738 } else if (token == "\\topmargin") {
740 } else if (token == "\\rightmargin") {
742 } else if (token == "\\bottommargin") {
744 } else if (token == "\\headheight") {
746 } else if (token == "\\headsep") {
748 } else if (token == "\\footskip") {
750 } else if (token == "\\columnsep") {
752 } else if (token == "\\paperfontsize") {
754 } else if (token == "\\papercolumns") {
756 } else if (token == "\\listings_params") {
759 listings_params = InsetListingsParams(par).params();
760 } else if (token == "\\papersides") {
763 sides = sidestranslator().find(psides);
764 } else if (token == "\\paperpagestyle") {
766 } else if (token == "\\bullet") {
768 } else if (token == "\\bulletLaTeX") {
769 readBulletsLaTeX(lex);
770 } else if (token == "\\secnumdepth") {
772 } else if (token == "\\tocdepth") {
774 } else if (token == "\\spacing") {
778 if (nspacing == "other") {
781 spacing().set(spacetranslator().find(nspacing), tmp_val);
782 } else if (token == "\\float_placement") {
783 lex >> float_placement;
785 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
786 string toktmp = pdfoptions().readToken(lex, token);
787 if (!toktmp.empty()) {
788 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
792 } else if (token == "\\html_math_output") {
795 html_math_output = static_cast<MathOutput>(temp);
796 } else if (token == "\\html_be_strict") {
797 lex >> html_be_strict;
799 lyxerr << "BufferParams::readToken(): Unknown token: " <<
808 void BufferParams::writeFile(ostream & os) const
810 // The top of the file is written by the buffer.
811 // Prints out the buffer info into the .lyx file given by file
814 os << "\\textclass " << baseClass()->name() << '\n';
817 if (!preamble.empty()) {
818 // remove '\n' from the end of preamble
819 string const tmppreamble = rtrim(preamble, "\n");
820 os << "\\begin_preamble\n"
822 << "\n\\end_preamble\n";
826 if (!options.empty()) {
827 os << "\\options " << options << '\n';
830 // use the class options defined in the layout?
831 os << "\\use_default_options "
832 << convert<string>(use_default_options) << "\n";
834 // the master document
835 if (!master.empty()) {
836 os << "\\master " << master << '\n';
840 if (!removedModules_.empty()) {
841 os << "\\begin_removed_modules" << '\n';
842 list<string>::const_iterator it = removedModules_.begin();
843 list<string>::const_iterator en = removedModules_.end();
844 for (; it != en; it++)
846 os << "\\end_removed_modules" << '\n';
850 if (!layoutModules_.empty()) {
851 os << "\\begin_modules" << '\n';
852 LayoutModuleList::const_iterator it = layoutModules_.begin();
853 LayoutModuleList::const_iterator en = layoutModules_.end();
854 for (; it != en; it++)
856 os << "\\end_modules" << '\n';
860 if (!includedChildren_.empty()) {
861 os << "\\begin_includeonly" << '\n';
862 list<string>::const_iterator it = includedChildren_.begin();
863 list<string>::const_iterator en = includedChildren_.end();
864 for (; it != en; it++)
866 os << "\\end_includeonly" << '\n';
868 os << "\\maintain_unincluded_children "
869 << convert<string>(maintain_unincluded_children) << '\n';
871 // local layout information
872 if (!local_layout.empty()) {
873 // remove '\n' from the end
874 string const tmplocal = rtrim(local_layout, "\n");
875 os << "\\begin_local_layout\n"
877 << "\n\\end_local_layout\n";
880 // then the text parameters
881 if (language != ignore_language)
882 os << "\\language " << language->lang() << '\n';
883 os << "\\inputencoding " << inputenc
884 << "\n\\fontencoding " << fontenc
885 << "\n\\font_roman " << fontsRoman
886 << "\n\\font_sans " << fontsSans
887 << "\n\\font_typewriter " << fontsTypewriter
888 << "\n\\font_default_family " << fontsDefaultFamily
889 << "\n\\use_xetex " << convert<string>(useXetex)
890 << "\n\\font_sc " << convert<string>(fontsSC)
891 << "\n\\font_osf " << convert<string>(fontsOSF)
892 << "\n\\font_sf_scale " << fontsSansScale
893 << "\n\\font_tt_scale " << fontsTypewriterScale
895 if (!fontsCJK.empty()) {
896 os << "\\font_cjk " << fontsCJK << '\n';
898 os << "\n\\graphics " << graphicsDriver << '\n';
899 os << "\\default_output_format " << defaultOutputFormat << '\n';
900 os << "\\bibtex_command " << bibtex_command << '\n';
901 os << "\\index_command " << index_command << '\n';
903 if (!float_placement.empty()) {
904 os << "\\float_placement " << float_placement << '\n';
906 os << "\\paperfontsize " << fontsize << '\n';
908 spacing().writeFile(os);
909 pdfoptions().writeFile(os);
911 os << "\\papersize " << string_papersize[papersize]
912 << "\n\\use_geometry " << convert<string>(use_geometry)
913 << "\n\\use_amsmath " << use_amsmath
914 << "\n\\use_esint " << use_esint
915 << "\n\\use_mhchem " << use_mhchem
916 << "\n\\cite_engine " << citeenginetranslator().find(cite_engine_)
917 << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
918 << "\n\\use_indices " << convert<string>(use_indices)
919 << "\n\\paperorientation " << string_orientation[orientation]
920 << "\n\\suppress_date " << convert<string>(suppress_date)
922 if (backgroundcolor != lyx::rgbFromHexName("#ffffff"))
923 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
924 if (notefontcolor != lyx::rgbFromHexName("#cccccc"))
925 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
927 BranchList::const_iterator it = branchlist().begin();
928 BranchList::const_iterator end = branchlist().end();
929 for (; it != end; ++it) {
930 os << "\\branch " << to_utf8(it->branch())
931 << "\n\\selected " << it->isSelected()
932 << "\n\\filename_suffix " << it->hasFilenameSuffix()
933 << "\n\\color " << lyx::X11hexname(it->color())
938 IndicesList::const_iterator iit = indiceslist().begin();
939 IndicesList::const_iterator iend = indiceslist().end();
940 for (; iit != iend; ++iit) {
941 os << "\\index " << to_utf8(iit->index())
942 << "\n\\shortcut " << to_utf8(iit->shortcut())
943 << "\n\\color " << lyx::X11hexname(iit->color())
948 if (!paperwidth.empty())
949 os << "\\paperwidth "
950 << VSpace(paperwidth).asLyXCommand() << '\n';
951 if (!paperheight.empty())
952 os << "\\paperheight "
953 << VSpace(paperheight).asLyXCommand() << '\n';
954 if (!leftmargin.empty())
955 os << "\\leftmargin "
956 << VSpace(leftmargin).asLyXCommand() << '\n';
957 if (!topmargin.empty())
959 << VSpace(topmargin).asLyXCommand() << '\n';
960 if (!rightmargin.empty())
961 os << "\\rightmargin "
962 << VSpace(rightmargin).asLyXCommand() << '\n';
963 if (!bottommargin.empty())
964 os << "\\bottommargin "
965 << VSpace(bottommargin).asLyXCommand() << '\n';
966 if (!headheight.empty())
967 os << "\\headheight "
968 << VSpace(headheight).asLyXCommand() << '\n';
969 if (!headsep.empty())
971 << VSpace(headsep).asLyXCommand() << '\n';
972 if (!footskip.empty())
974 << VSpace(footskip).asLyXCommand() << '\n';
975 if (!columnsep.empty())
977 << VSpace(columnsep).asLyXCommand() << '\n';
978 os << "\\secnumdepth " << secnumdepth
979 << "\n\\tocdepth " << tocdepth
980 << "\n\\paragraph_separation "
981 << string_paragraph_separation[paragraph_separation];
982 if (!paragraph_separation)
983 os << "\n\\paragraph_indentation " << getIndentation().asLyXCommand();
985 os << "\n\\defskip " << getDefSkip().asLyXCommand();
986 os << "\n\\quotes_language "
987 << string_quotes_language[quotes_language]
988 << "\n\\papercolumns " << columns
989 << "\n\\papersides " << sides
990 << "\n\\paperpagestyle " << pagestyle << '\n';
991 if (!listings_params.empty())
992 os << "\\listings_params \"" <<
993 InsetListingsParams(listings_params).encodedString() << "\"\n";
994 for (int i = 0; i < 4; ++i) {
995 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
996 if (user_defined_bullet(i).getFont() != -1) {
997 os << "\\bullet " << i << " "
998 << user_defined_bullet(i).getFont() << " "
999 << user_defined_bullet(i).getCharacter() << " "
1000 << user_defined_bullet(i).getSize() << "\n";
1004 os << "\\bulletLaTeX " << i << " \""
1005 << lyx::to_ascii(user_defined_bullet(i).getText())
1011 os << "\\tracking_changes " << convert<string>(trackChanges) << "\n"
1012 << "\\output_changes " << convert<string>(outputChanges) << "\n"
1013 << "\\html_math_output " << html_math_output << "\n"
1014 << "\\html_be_strict " << convert<string>(html_be_strict) << "\n";
1016 os << pimpl_->authorlist;
1020 void BufferParams::validate(LaTeXFeatures & features) const
1022 features.require(documentClass().requires());
1024 if (outputChanges) {
1025 bool dvipost = LaTeXFeatures::isAvailable("dvipost");
1026 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1027 LaTeXFeatures::isAvailable("xcolor");
1029 switch (features.runparams().flavor) {
1030 case OutputParams::LATEX:
1032 features.require("ct-dvipost");
1033 features.require("dvipost");
1034 } else if (xcolorulem) {
1035 features.require("ct-xcolor-ulem");
1036 features.require("ulem");
1037 features.require("xcolor");
1039 features.require("ct-none");
1042 case OutputParams::PDFLATEX:
1043 case OutputParams::XETEX:
1045 features.require("ct-xcolor-ulem");
1046 features.require("ulem");
1047 features.require("xcolor");
1048 // improves color handling in PDF output
1049 features.require("pdfcolmk");
1051 features.require("ct-none");
1059 // Floats with 'Here definitely' as default setting.
1060 if (float_placement.find('H') != string::npos)
1061 features.require("float");
1063 // AMS Style is at document level
1064 if (use_amsmath == package_on
1065 || documentClass().provides("amsmath"))
1066 features.require("amsmath");
1067 if (use_esint == package_on)
1068 features.require("esint");
1069 if (use_mhchem == package_on)
1070 features.require("mhchem");
1072 // Document-level line spacing
1073 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1074 features.require("setspace");
1076 // the bullet shapes are buffer level not paragraph level
1077 // so they are tested here
1078 for (int i = 0; i < 4; ++i) {
1079 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1081 int const font = user_defined_bullet(i).getFont();
1083 int const c = user_defined_bullet(i).getCharacter();
1089 features.require("latexsym");
1091 } else if (font == 1) {
1092 features.require("amssymb");
1093 } else if (font >= 2 && font <= 5) {
1094 features.require("pifont");
1098 if (pdfoptions().use_hyperref) {
1099 features.require("hyperref");
1100 // due to interferences with babel and hyperref, the color package has to
1101 // be loaded after hyperref when hyperref is used with the colorlinks
1102 // option, see http://www.lyx.org/trac/ticket/5291
1103 if (pdfoptions().colorlinks)
1104 features.require("color");
1108 features.require("xetex");
1110 if (language->lang() == "vietnamese")
1111 features.require("vietnamese");
1112 else if (language->lang() == "japanese")
1113 features.require("japanese");
1117 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
1118 TexRow & texrow, FileName const & filepath) const
1120 os << "\\documentclass";
1122 DocumentClass const & tclass = documentClass();
1124 ostringstream clsoptions; // the document class options.
1126 if (tokenPos(tclass.opt_fontsize(),
1127 '|', fontsize) >= 0) {
1128 // only write if existing in list (and not default)
1129 clsoptions << fontsize << "pt,";
1132 // custom, A3, B3 and B4 paper sizes need geometry
1133 bool nonstandard_papersize = papersize == PAPER_B3
1134 || papersize == PAPER_B4
1135 || papersize == PAPER_A3
1136 || papersize == PAPER_CUSTOM;
1138 if (!use_geometry) {
1139 switch (papersize) {
1141 clsoptions << "a4paper,";
1143 case PAPER_USLETTER:
1144 clsoptions << "letterpaper,";
1147 clsoptions << "a5paper,";
1150 clsoptions << "b5paper,";
1152 case PAPER_USEXECUTIVE:
1153 clsoptions << "executivepaper,";
1156 clsoptions << "legalpaper,";
1168 if (sides != tclass.sides()) {
1171 clsoptions << "oneside,";
1174 clsoptions << "twoside,";
1180 if (columns != tclass.columns()) {
1182 clsoptions << "twocolumn,";
1184 clsoptions << "onecolumn,";
1188 && orientation == ORIENTATION_LANDSCAPE)
1189 clsoptions << "landscape,";
1191 // language should be a parameter to \documentclass
1192 if (language->babel() == "hebrew"
1193 && default_language->babel() != "hebrew")
1194 // This seems necessary
1195 features.useLanguage(default_language);
1197 ostringstream language_options;
1198 bool const use_babel = features.useBabel();
1200 language_options << features.getLanguages();
1201 if (!language->babel().empty()) {
1202 if (!language_options.str().empty())
1203 language_options << ',';
1204 language_options << language->babel();
1206 // if Vietnamese is used, babel must directly be loaded
1207 // with language options, not in the class options, see
1208 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1209 size_t viet = language_options.str().find("vietnam");
1210 // viet = string::npos when not found
1211 // the same is for all other languages that are not directly supported by
1212 // babel, but where LaTeX-packages add babel support.
1213 // this is currently the case for Latvian, Lithuanian, and Mongolian
1214 size_t latvian = language_options.str().find("latvian");
1215 size_t lithu = language_options.str().find("lithuanian");
1216 size_t mongo = language_options.str().find("mongolian");
1217 // if Japanese is used, babel must directly be loaded
1218 // with language options, not in the class options, see
1219 // http://www.lyx.org/trac/ticket/4597#c4
1220 size_t japan = language_options.str().find("japanese");
1221 if (lyxrc.language_global_options && !language_options.str().empty()
1222 && viet == string::npos && japan == string::npos
1223 && latvian == string::npos && lithu == string::npos
1224 && mongo == string::npos)
1225 clsoptions << language_options.str() << ',';
1228 // the predefined options from the layout
1229 if (use_default_options && !tclass.options().empty())
1230 clsoptions << tclass.options() << ',';
1232 // the user-defined options
1233 if (!options.empty()) {
1234 clsoptions << options << ',';
1237 string strOptions(clsoptions.str());
1238 if (!strOptions.empty()) {
1239 strOptions = rtrim(strOptions, ",");
1241 os << '[' << from_utf8(strOptions) << ']';
1244 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1246 // end of \documentclass defs
1249 os << "\\usepackage{fontspec}\n";
1253 // font selection must be done before loading fontenc.sty
1254 string const fonts =
1255 loadFonts(fontsRoman, fontsSans,
1256 fontsTypewriter, fontsSC, fontsOSF,
1257 fontsSansScale, fontsTypewriterScale, useXetex);
1258 if (!fonts.empty()) {
1259 os << from_ascii(fonts);
1262 if (fontsDefaultFamily != "default")
1263 os << "\\renewcommand{\\familydefault}{\\"
1264 << from_ascii(fontsDefaultFamily) << "}\n";
1266 // set font encoding
1267 // for arabic_arabi and farsi we also need to load the LAE and
1269 // XeTeX works without fontenc
1270 if (font_encoding() != "default" && language->lang() != "japanese"
1272 if (language->lang() == "arabic_arabi"
1273 || language->lang() == "farsi") {
1274 os << "\\usepackage[" << from_ascii(font_encoding())
1275 << ",LFE,LAE]{fontenc}\n";
1278 os << "\\usepackage[" << from_ascii(font_encoding())
1284 // handle inputenc etc.
1285 writeEncodingPreamble(os, features, texrow);
1288 if (!features.runparams().includeall && !includedChildren_.empty()) {
1289 os << "\\includeonly{";
1290 list<string>::const_iterator it = includedChildren_.begin();
1292 for (; it != includedChildren_.end() ; ++it) {
1293 string incfile = *it;
1294 FileName inc = makeAbsPath(incfile, filepath.absFilename());
1295 string mangled = DocFileName(changeExtension(inc.absFilename(), ".tex")).
1297 if (!features.runparams().nice)
1299 // \includeonly doesn't want an extension
1300 incfile = changeExtension(incfile, string());
1301 incfile = support::latex_path(incfile);
1302 if (!incfile.empty()) {
1305 os << from_utf8(incfile);
1312 if (!listings_params.empty() || features.isRequired("listings")) {
1313 os << "\\usepackage{listings}\n";
1316 if (!listings_params.empty()) {
1318 // do not test validity because listings_params is
1319 // supposed to be valid
1321 InsetListingsParams(listings_params).separatedParams(true);
1322 // we can't support all packages, but we should load the color package
1323 if (par.find("\\color", 0) != string::npos)
1324 features.require("color");
1325 os << from_utf8(par);
1326 // count the number of newlines
1327 for (size_t i = 0; i < par.size(); ++i)
1333 if (!tclass.provides("geometry")
1334 && (use_geometry || nonstandard_papersize)) {
1335 odocstringstream ods;
1336 if (!getGraphicsDriver("geometry").empty())
1337 ods << getGraphicsDriver("geometry");
1338 if (orientation == ORIENTATION_LANDSCAPE)
1339 ods << ",landscape";
1340 switch (papersize) {
1342 if (!paperwidth.empty())
1343 ods << ",paperwidth="
1344 << from_ascii(paperwidth);
1345 if (!paperheight.empty())
1346 ods << ",paperheight="
1347 << from_ascii(paperheight);
1349 case PAPER_USLETTER:
1350 ods << ",letterpaper";
1353 ods << ",legalpaper";
1355 case PAPER_USEXECUTIVE:
1356 ods << ",executivepaper";
1377 // default papersize ie PAPER_DEFAULT
1378 switch (lyxrc.default_papersize) {
1379 case PAPER_DEFAULT: // keep compiler happy
1380 case PAPER_USLETTER:
1381 ods << ",letterpaper";
1384 ods << ",legalpaper";
1386 case PAPER_USEXECUTIVE:
1387 ods << ",executivepaper";
1407 docstring const g_options = trim(ods.str(), ",");
1408 os << "\\usepackage";
1409 if (!g_options.empty())
1410 os << '[' << g_options << ']';
1411 os << "{geometry}\n";
1413 os << "\\geometry{verbose";
1414 if (!topmargin.empty())
1415 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1416 if (!bottommargin.empty())
1417 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1418 if (!leftmargin.empty())
1419 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1420 if (!rightmargin.empty())
1421 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1422 if (!headheight.empty())
1423 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1424 if (!headsep.empty())
1425 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1426 if (!footskip.empty())
1427 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1428 if (!columnsep.empty())
1429 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1432 } else if (orientation == ORIENTATION_LANDSCAPE) {
1433 features.require("papersize");
1436 if (tokenPos(tclass.opt_pagestyle(),
1437 '|', pagestyle) >= 0) {
1438 if (pagestyle == "fancy") {
1439 os << "\\usepackage{fancyhdr}\n";
1442 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1446 // only output when the background color is not white
1447 if (backgroundcolor != lyx::rgbFromHexName("#ffffff")) {
1448 // only require color here, the background color will be defined
1449 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1451 features.require("color");
1452 features.require("pagecolor");
1455 // Only if class has a ToC hierarchy
1456 if (tclass.hasTocLevels()) {
1457 if (secnumdepth != tclass.secnumdepth()) {
1458 os << "\\setcounter{secnumdepth}{"
1463 if (tocdepth != tclass.tocdepth()) {
1464 os << "\\setcounter{tocdepth}{"
1471 if (paragraph_separation) {
1472 // when skip separation
1473 switch (getDefSkip().kind()) {
1474 case VSpace::SMALLSKIP:
1475 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1477 case VSpace::MEDSKIP:
1478 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1480 case VSpace::BIGSKIP:
1481 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1483 case VSpace::LENGTH:
1484 os << "\\setlength{\\parskip}{"
1485 << from_utf8(getDefSkip().length().asLatexString())
1488 default: // should never happen // Then delete it.
1489 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1493 os << "\\setlength{\\parindent}{0pt}\n";
1496 // when separation by indentation
1497 // only output something when a width is given
1498 if (getIndentation().asLyXCommand() != "default") {
1499 os << "\\setlength{\\parindent}{"
1500 << from_utf8(getIndentation().asLatexCommand())
1506 // Now insert the LyX specific LaTeX commands...
1507 docstring lyxpreamble;
1509 // due to interferences with babel and hyperref, the color package has to
1510 // be loaded (when it is not already loaded) before babel when hyperref
1511 // is used with the colorlinks option, see
1512 // http://www.lyx.org/trac/ticket/5291
1513 // we decided therefore to load color always before babel, see
1514 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
1515 lyxpreamble += from_ascii(features.getColorOptions());
1517 // If we use hyperref, jurabib, japanese, or vietnamese, we have to call babel before them.
1519 && (features.isRequired("jurabib")
1520 || features.isRequired("hyperref")
1521 || features.isRequired("vietnamese")
1522 || features.isRequired("japanese") ) ) {
1524 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1525 lyxpreamble += from_utf8(features.getBabelOptions()) + '\n';
1528 // The optional packages;
1529 lyxpreamble += from_ascii(features.getPackages());
1531 // Additional Indices
1532 if (features.isRequired("splitidx")) {
1533 IndicesList::const_iterator iit = indiceslist().begin();
1534 IndicesList::const_iterator iend = indiceslist().end();
1535 for (; iit != iend; ++iit) {
1536 lyxpreamble += "\\newindex[";
1537 lyxpreamble += iit->index();
1538 lyxpreamble += "]{";
1539 lyxpreamble += iit->shortcut();
1540 lyxpreamble += "}\n";
1545 lyxpreamble += from_utf8(spacing().writePreamble(tclass.provides("SetSpace")));
1548 // * Hyperref manual: "Make sure it comes last of your loaded
1549 // packages, to give it a fighting chance of not being over-written,
1550 // since its job is to redefine many LaTeX commands."
1551 // * Email from Heiko Oberdiek: "It is usually better to load babel
1552 // before hyperref. Then hyperref has a chance to detect babel.
1553 // * Has to be loaded before the "LyX specific LaTeX commands" to
1554 // avoid errors with algorithm floats.
1555 // use hyperref explicitly if it is required
1556 if (features.isRequired("hyperref")) {
1557 // pass what we have to stream here, since we need
1558 // to access the stream itself in PDFOptions.
1562 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1564 OutputParams tmp_params = features.runparams();
1565 lines += pdfoptions().writeLaTeX(tmp_params, os,
1566 documentClass().provides("hyperref"));
1567 texrow.newlines(lines);
1568 // set back for the rest
1569 lyxpreamble.clear();
1572 // Will be surrounded by \makeatletter and \makeatother when not empty
1573 docstring atlyxpreamble;
1575 // Some macros LyX will need
1576 docstring tmppreamble(features.getMacros());
1578 if (!tmppreamble.empty())
1579 atlyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1580 "LyX specific LaTeX commands.\n"
1581 + tmppreamble + '\n';
1583 // the text class specific preamble
1584 tmppreamble = features.getTClassPreamble();
1585 if (!tmppreamble.empty())
1586 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1587 "Textclass specific LaTeX commands.\n"
1588 + tmppreamble + '\n';
1590 // suppress date if selected
1591 // use \@ifundefined because we cannot be sure that every document class
1592 // has a \date command
1594 atlyxpreamble += "\\@ifundefined{date}{}{\\date{}}\n";
1596 /* the user-defined preamble */
1597 if (!containsOnly(preamble, " \n\t"))
1599 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1600 "User specified LaTeX commands.\n"
1601 + from_utf8(preamble) + '\n';
1603 // subfig loads internally the LaTeX package "caption". As
1604 // caption is a very popular package, users will load it in
1605 // the preamble. Therefore we must load subfig behind the
1606 // user-defined preamble and check if the caption package was
1607 // loaded or not. For the case that caption is loaded before
1608 // subfig, there is the subfig option "caption=false". This
1609 // option also works when a koma-script class is used and
1610 // koma's own caption commands are used instead of caption. We
1611 // use \PassOptionsToPackage here because the user could have
1612 // already loaded subfig in the preamble.
1613 if (features.isRequired("subfig")) {
1614 atlyxpreamble += "\\@ifundefined{showcaptionsetup}{}{%\n"
1615 " \\PassOptionsToPackage{caption=false}{subfig}}\n"
1616 "\\usepackage{subfig}\n";
1619 // Itemize bullet settings need to be last in case the user
1620 // defines their own bullets that use a package included
1621 // in the user-defined preamble -- ARRae
1622 // Actually it has to be done much later than that
1623 // since some packages like frenchb make modifications
1624 // at \begin{document} time -- JMarc
1625 docstring bullets_def;
1626 for (int i = 0; i < 4; ++i) {
1627 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1628 if (bullets_def.empty())
1629 bullets_def += "\\AtBeginDocument{\n";
1630 bullets_def += " \\def\\labelitemi";
1632 // `i' is one less than the item to modify
1639 bullets_def += "ii";
1645 bullets_def += '{' +
1646 user_defined_bullet(i).getText()
1651 if (!bullets_def.empty())
1652 atlyxpreamble += bullets_def + "}\n\n";
1654 if (!atlyxpreamble.empty())
1655 lyxpreamble += "\n\\makeatletter\n"
1656 + atlyxpreamble + "\\makeatother\n\n";
1658 // We try to load babel late, in case it interferes with other packages.
1659 // Jurabib and Hyperref have to be called after babel, though.
1660 if (use_babel && !features.isRequired("jurabib")
1661 && !features.isRequired("hyperref")
1662 && !features.isRequired("vietnamese")
1663 && !features.isRequired("japanese")) {
1665 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1666 lyxpreamble += from_utf8(features.getBabelOptions()) + '\n';
1669 docstring const i18npreamble = features.getTClassI18nPreamble(use_babel);
1670 if (!i18npreamble.empty())
1671 lyxpreamble += i18npreamble + '\n';
1674 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1675 texrow.newlines(nlines);
1679 // these packages (xunicode, for that matter) need to be loaded at least
1680 // after amsmath, amssymb, esint and the other packages that provide
1683 os << "\\usepackage{xunicode}\n";
1685 os << "\\usepackage{xltxtra}\n";
1692 void BufferParams::useClassDefaults()
1694 DocumentClass const & tclass = documentClass();
1696 sides = tclass.sides();
1697 columns = tclass.columns();
1698 pagestyle = tclass.pagestyle();
1699 use_default_options = true;
1700 // Only if class has a ToC hierarchy
1701 if (tclass.hasTocLevels()) {
1702 secnumdepth = tclass.secnumdepth();
1703 tocdepth = tclass.tocdepth();
1708 bool BufferParams::hasClassDefaults() const
1710 DocumentClass const & tclass = documentClass();
1712 return sides == tclass.sides()
1713 && columns == tclass.columns()
1714 && pagestyle == tclass.pagestyle()
1715 && use_default_options
1716 && secnumdepth == tclass.secnumdepth()
1717 && tocdepth == tclass.tocdepth();
1721 DocumentClass const & BufferParams::documentClass() const
1727 DocumentClass const * BufferParams::documentClassPtr() const {
1732 void BufferParams::setDocumentClass(DocumentClass const * const tc) {
1733 // evil, but this function is evil
1734 doc_class_ = const_cast<DocumentClass *>(tc);
1738 bool BufferParams::setBaseClass(string const & classname)
1740 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
1741 LayoutFileList & bcl = LayoutFileList::get();
1742 if (!bcl.haveClass(classname)) {
1744 bformat(_("The document class %1$s could not be found. "
1745 "A default textclass with default layouts will be used. "
1746 "LyX might not be able to produce output unless a correct "
1747 "textclass is selected from the document settings dialog."),
1748 from_utf8(classname));
1749 frontend::Alert::error(_("Document class not found"), s);
1750 bcl.addEmptyClass(classname);
1753 bool const success = bcl[classname].load();
1756 bformat(_("The document class %1$s could not be loaded."),
1757 from_utf8(classname));
1758 frontend::Alert::error(_("Could not load class"), s);
1762 pimpl_->baseClass_ = classname;
1763 layoutModules_.adaptToBaseClass(baseClass(), removedModules_);
1768 LayoutFile const * BufferParams::baseClass() const
1770 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
1771 return &(LayoutFileList::get()[pimpl_->baseClass_]);
1777 LayoutFileIndex const & BufferParams::baseClassID() const
1779 return pimpl_->baseClass_;
1783 void BufferParams::makeDocumentClass()
1788 doc_class_ = &(DocumentClassBundle::get().makeDocumentClass(*baseClass(), layoutModules_));
1790 if (!local_layout.empty()) {
1791 if (!doc_class_->read(local_layout, TextClass::MODULE)) {
1792 docstring const msg = _("Error reading internal layout information");
1793 frontend::Alert::warning(_("Read Error"), msg);
1798 bool BufferParams::moduleCanBeAdded(string const & modName) const
1800 return layoutModules_.moduleCanBeAdded(modName, baseClass());
1804 bool BufferParams::addLayoutModule(string const & modName)
1806 LayoutModuleList::const_iterator it = layoutModules_.begin();
1807 LayoutModuleList::const_iterator end = layoutModules_.end();
1808 for (; it != end; it++)
1811 layoutModules_.push_back(modName);
1816 Font const BufferParams::getFont() const
1818 FontInfo f = documentClass().defaultfont();
1819 if (fontsDefaultFamily == "rmdefault")
1820 f.setFamily(ROMAN_FAMILY);
1821 else if (fontsDefaultFamily == "sfdefault")
1822 f.setFamily(SANS_FAMILY);
1823 else if (fontsDefaultFamily == "ttdefault")
1824 f.setFamily(TYPEWRITER_FAMILY);
1825 return Font(f, language);
1829 void BufferParams::readPreamble(Lexer & lex)
1831 if (lex.getString() != "\\begin_preamble")
1832 lyxerr << "Error (BufferParams::readPreamble):"
1833 "consistency check failed." << endl;
1835 preamble = lex.getLongString("\\end_preamble");
1839 void BufferParams::readLocalLayout(Lexer & lex)
1841 if (lex.getString() != "\\begin_local_layout")
1842 lyxerr << "Error (BufferParams::readLocalLayout):"
1843 "consistency check failed." << endl;
1845 local_layout = lex.getLongString("\\end_local_layout");
1849 void BufferParams::readLanguage(Lexer & lex)
1851 if (!lex.next()) return;
1853 string const tmptok = lex.getString();
1855 // check if tmptok is part of tex_babel in tex-defs.h
1856 language = languages.getLanguage(tmptok);
1858 // Language tmptok was not found
1859 language = default_language;
1860 lyxerr << "Warning: Setting language `"
1861 << tmptok << "' to `" << language->lang()
1867 void BufferParams::readGraphicsDriver(Lexer & lex)
1872 string const tmptok = lex.getString();
1873 // check if tmptok is part of tex_graphics in tex_defs.h
1876 string const test = tex_graphics[n++];
1878 if (test == tmptok) {
1879 graphicsDriver = tmptok;
1884 "Warning: graphics driver `$$Token' not recognized!\n"
1885 " Setting graphics driver to `default'.\n");
1886 graphicsDriver = "default";
1893 void BufferParams::readBullets(Lexer & lex)
1898 int const index = lex.getInteger();
1900 int temp_int = lex.getInteger();
1901 user_defined_bullet(index).setFont(temp_int);
1902 temp_bullet(index).setFont(temp_int);
1904 user_defined_bullet(index).setCharacter(temp_int);
1905 temp_bullet(index).setCharacter(temp_int);
1907 user_defined_bullet(index).setSize(temp_int);
1908 temp_bullet(index).setSize(temp_int);
1912 void BufferParams::readBulletsLaTeX(Lexer & lex)
1914 // The bullet class should be able to read this.
1917 int const index = lex.getInteger();
1919 docstring const temp_str = lex.getDocString();
1921 user_defined_bullet(index).setText(temp_str);
1922 temp_bullet(index).setText(temp_str);
1926 void BufferParams::readModules(Lexer & lex)
1928 if (!lex.eatLine()) {
1929 lyxerr << "Error (BufferParams::readModules):"
1930 "Unexpected end of input." << endl;
1934 string mod = lex.getString();
1935 if (mod == "\\end_modules")
1937 addLayoutModule(mod);
1943 void BufferParams::readRemovedModules(Lexer & lex)
1945 if (!lex.eatLine()) {
1946 lyxerr << "Error (BufferParams::readRemovedModules):"
1947 "Unexpected end of input." << endl;
1951 string mod = lex.getString();
1952 if (mod == "\\end_removed_modules")
1954 removedModules_.push_back(mod);
1957 // now we want to remove any removed modules that were previously
1958 // added. normally, that will be because default modules were added in
1959 // setBaseClass(), which gets called when \textclass is read at the
1960 // start of the read.
1961 list<string>::const_iterator rit = removedModules_.begin();
1962 list<string>::const_iterator const ren = removedModules_.end();
1963 for (; rit != ren; rit++) {
1964 LayoutModuleList::iterator const mit = layoutModules_.begin();
1965 LayoutModuleList::iterator const men = layoutModules_.end();
1966 LayoutModuleList::iterator found = find(mit, men, *rit);
1969 layoutModules_.erase(found);
1974 void BufferParams::readIncludeonly(Lexer & lex)
1976 if (!lex.eatLine()) {
1977 lyxerr << "Error (BufferParams::readIncludeonly):"
1978 "Unexpected end of input." << endl;
1982 string child = lex.getString();
1983 if (child == "\\end_includeonly")
1985 includedChildren_.push_back(child);
1991 string BufferParams::paperSizeName(PapersizePurpose purpose) const
1993 char real_papersize = papersize;
1994 if (real_papersize == PAPER_DEFAULT)
1995 real_papersize = lyxrc.default_papersize;
1997 switch (real_papersize) {
1999 // could be anything, so don't guess
2001 case PAPER_CUSTOM: {
2002 if (purpose == XDVI && !paperwidth.empty() &&
2003 !paperheight.empty()) {
2004 // heightxwidth<unit>
2005 string first = paperwidth;
2006 string second = paperheight;
2007 if (orientation == ORIENTATION_LANDSCAPE)
2010 return first.erase(first.length() - 2)
2022 // dvips and dvipdfm do not know this
2023 if (purpose == DVIPS || purpose == DVIPDFM)
2027 // dvipdfm does not know this
2028 if (purpose == DVIPDFM)
2032 // dvipdfm does not know this
2033 if (purpose == DVIPDFM)
2036 case PAPER_USEXECUTIVE:
2037 // dvipdfm does not know this
2038 if (purpose == DVIPDFM)
2043 case PAPER_USLETTER:
2045 if (purpose == XDVI)
2052 string const BufferParams::dvips_options() const
2057 && papersize == PAPER_CUSTOM
2058 && !lyxrc.print_paper_dimension_flag.empty()
2059 && !paperwidth.empty()
2060 && !paperheight.empty()) {
2061 // using a custom papersize
2062 result = lyxrc.print_paper_dimension_flag;
2063 result += ' ' + paperwidth;
2064 result += ',' + paperheight;
2066 string const paper_option = paperSizeName(DVIPS);
2067 if (!paper_option.empty() && (paper_option != "letter" ||
2068 orientation != ORIENTATION_LANDSCAPE)) {
2069 // dvips won't accept -t letter -t landscape.
2070 // In all other cases, include the paper size
2072 result = lyxrc.print_paper_flag;
2073 result += ' ' + paper_option;
2076 if (orientation == ORIENTATION_LANDSCAPE &&
2077 papersize != PAPER_CUSTOM)
2078 result += ' ' + lyxrc.print_landscape_flag;
2083 string const BufferParams::font_encoding() const
2085 return (fontenc == "global") ? lyxrc.fontenc : fontenc;
2089 string BufferParams::babelCall(string const & lang_opts) const
2091 string lang_pack = lyxrc.language_package;
2092 if (lang_pack != "\\usepackage{babel}")
2094 // suppress the babel call when there is no babel language defined
2095 // for the document language in the lib/languages file and if no
2096 // other languages are used (lang_opts is then empty)
2097 if (lang_opts.empty())
2099 // If Vietnamese is used, babel must directly be loaded with the
2100 // language options, see
2101 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
2102 size_t viet = lang_opts.find("vietnam");
2103 // viet = string::npos when not found
2104 // the same is for all other languages that are not directly supported by
2105 // babel, but where LaTeX-packages add babel support.
2106 // this is currently the case for Latvian, Lithuanian, and Mongolian
2107 size_t latvian = lang_opts.find("latvian");
2108 size_t lithu = lang_opts.find("lithuanian");
2109 size_t mongo = lang_opts.find("mongolian");
2110 // If Japanese is used, babel must directly be loaded with the
2111 // language options, see
2112 // http://www.lyx.org/trac/ticket/4597#c4
2113 size_t japan = lang_opts.find("japanese");
2114 if (!lyxrc.language_global_options || viet != string::npos
2115 || japan != string::npos || latvian != string::npos
2116 || lithu != string::npos || mongo != string::npos)
2117 return "\\usepackage[" + lang_opts + "]{babel}";
2122 docstring BufferParams::getGraphicsDriver(string const & package) const
2126 if (package == "geometry") {
2127 if (graphicsDriver == "dvips"
2128 || graphicsDriver == "dvipdfm"
2129 || graphicsDriver == "pdftex"
2130 || graphicsDriver == "vtex")
2131 result = from_ascii(graphicsDriver);
2132 else if (graphicsDriver == "dvipdfmx")
2133 result = from_ascii("dvipdfm");
2140 void BufferParams::writeEncodingPreamble(odocstream & os,
2141 LaTeXFeatures & features, TexRow & texrow) const
2145 if (inputenc == "auto") {
2146 string const doc_encoding =
2147 language->encoding()->latexName();
2148 Encoding::Package const package =
2149 language->encoding()->package();
2151 // Create a list with all the input encodings used
2153 set<string> encodings =
2154 features.getEncodingSet(doc_encoding);
2156 // If the "japanese" package (i.e. pLaTeX) is used,
2157 // inputenc must be omitted.
2158 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
2159 if (package == Encoding::japanese)
2160 features.require("japanese");
2162 if ((!encodings.empty() || package == Encoding::inputenc)
2163 && !features.isRequired("japanese")) {
2164 os << "\\usepackage[";
2165 set<string>::const_iterator it = encodings.begin();
2166 set<string>::const_iterator const end = encodings.end();
2168 os << from_ascii(*it);
2171 for (; it != end; ++it)
2172 os << ',' << from_ascii(*it);
2173 if (package == Encoding::inputenc) {
2174 if (!encodings.empty())
2176 os << from_ascii(doc_encoding);
2178 os << "]{inputenc}\n";
2181 if (package == Encoding::CJK || features.mustProvide("CJK")) {
2182 if (language->encoding()->name() == "utf8-cjk"
2183 && LaTeXFeatures::isAvailable("CJKutf8"))
2184 os << "\\usepackage{CJKutf8}\n";
2186 os << "\\usepackage{CJK}\n";
2189 } else if (inputenc != "default") {
2190 switch (encoding().package()) {
2191 case Encoding::none:
2192 case Encoding::japanese:
2194 case Encoding::inputenc:
2195 // do not load inputenc if japanese is used
2196 if (features.isRequired("japanese"))
2198 os << "\\usepackage[" << from_ascii(inputenc)
2203 if (encoding().name() == "utf8-cjk"
2204 && LaTeXFeatures::isAvailable("CJKutf8"))
2205 os << "\\usepackage{CJKutf8}\n";
2207 os << "\\usepackage{CJK}\n";
2213 // The encoding "armscii8" (for Armenian) is only available when
2214 // the package "armtex" is loaded.
2215 if (language->encoding()->latexName() == "armscii8"
2216 || inputenc == "armscii8") {
2217 os << "\\usepackage{armtex}\n";
2223 string const BufferParams::parseFontName(string const & name) const
2225 string mangled = name;
2226 size_t const idx = mangled.find('[');
2227 if (idx == string::npos || idx == 0)
2230 return mangled.substr(0, idx - 1);
2234 string const BufferParams::loadFonts(string const & rm,
2235 string const & sf, string const & tt,
2236 bool const & sc, bool const & osf,
2237 int const & sfscale, int const & ttscale,
2238 bool const & xetex) const
2240 /* The LaTeX font world is in a flux. In the PSNFSS font interface,
2241 several packages have been replaced by others, that might not
2242 be installed on every system. We have to take care for that
2243 (see psnfss.pdf). We try to support all psnfss fonts as well
2244 as the fonts that have become de facto standard in the LaTeX
2245 world (e.g. Latin Modern). We do not support obsolete fonts
2246 (like PSLatex). In general, it should be possible to mix any
2247 rm font with any sf or tt font, respectively. (JSpitzm)
2249 -- separate math fonts.
2252 if (rm == "default" && sf == "default" && tt == "default")
2259 if (rm != "default")
2260 os << "\\setmainfont[Mapping=tex-text]{"
2261 << parseFontName(rm) << "}\n";
2262 if (sf != "default") {
2263 string const sans = parseFontName(sf);
2265 os << "\\setsansfont[Scale="
2266 << float(sfscale) / 100
2267 << ",Mapping=tex-text]{"
2270 os << "\\setsansfont[Mapping=tex-text]{"
2273 if (tt != "default") {
2274 string const mono = parseFontName(tt);
2276 os << "\\setmonofont[Scale="
2277 << float(sfscale) / 100
2281 os << "\\setmonofont[Mapping=tex-text]{"
2285 os << "\\defaultfontfeatures{Numbers=OldStyle}\n";
2290 // Computer Modern (must be explicitly selectable -- there might be classes
2291 // that define a different default font!
2293 os << "\\renewcommand{\\rmdefault}{cmr}\n";
2294 // osf for Computer Modern needs eco.sty
2296 os << "\\usepackage{eco}\n";
2298 // Latin Modern Roman
2299 else if (rm == "lmodern")
2300 os << "\\usepackage{lmodern}\n";
2302 else if (rm == "ae") {
2303 // not needed when using OT1 font encoding.
2304 if (font_encoding() != "default")
2305 os << "\\usepackage{ae,aecompl}\n";
2308 else if (rm == "times") {
2309 // try to load the best available package
2310 if (LaTeXFeatures::isAvailable("mathptmx"))
2311 os << "\\usepackage{mathptmx}\n";
2312 else if (LaTeXFeatures::isAvailable("mathptm"))
2313 os << "\\usepackage{mathptm}\n";
2315 os << "\\usepackage{times}\n";
2318 else if (rm == "palatino") {
2319 // try to load the best available package
2320 if (LaTeXFeatures::isAvailable("mathpazo")) {
2321 os << "\\usepackage";
2327 // "osf" includes "sc"!
2331 os << "{mathpazo}\n";
2333 else if (LaTeXFeatures::isAvailable("mathpple"))
2334 os << "\\usepackage{mathpple}\n";
2336 os << "\\usepackage{palatino}\n";
2339 else if (rm == "utopia") {
2340 // fourier supersedes utopia.sty, but does
2341 // not work with OT1 encoding.
2342 if (LaTeXFeatures::isAvailable("fourier")
2343 && font_encoding() != "default") {
2344 os << "\\usepackage";
2355 os << "{fourier}\n";
2358 os << "\\usepackage{utopia}\n";
2360 // Bera (complete fontset)
2361 else if (rm == "bera" && sf == "default" && tt == "default")
2362 os << "\\usepackage{bera}\n";
2364 else if (rm != "default")
2365 os << "\\usepackage" << "{" << rm << "}\n";
2368 // Helvetica, Bera Sans
2369 if (sf == "helvet" || sf == "berasans") {
2371 os << "\\usepackage[scaled=" << float(sfscale) / 100
2372 << "]{" << sf << "}\n";
2374 os << "\\usepackage{" << sf << "}\n";
2377 else if (sf == "avant")
2378 os << "\\usepackage{" << sf << "}\n";
2379 // Computer Modern, Latin Modern, CM Bright
2380 else if (sf != "default")
2381 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
2383 // monospaced/typewriter
2384 // Courier, LuxiMono
2385 if (tt == "luximono" || tt == "beramono") {
2387 os << "\\usepackage[scaled=" << float(ttscale) / 100
2388 << "]{" << tt << "}\n";
2390 os << "\\usepackage{" << tt << "}\n";
2393 else if (tt == "courier" )
2394 os << "\\usepackage{" << tt << "}\n";
2395 // Computer Modern, Latin Modern, CM Bright
2396 else if (tt != "default")
2397 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
2403 Encoding const & BufferParams::encoding() const
2406 return *(encodings.fromLaTeXName("utf8-plain"));
2407 if (inputenc == "auto" || inputenc == "default")
2408 return *language->encoding();
2409 Encoding const * const enc = encodings.fromLaTeXName(inputenc);
2412 LYXERR0("Unknown inputenc value `" << inputenc
2413 << "'. Using `auto' instead.");
2414 return *language->encoding();
2418 CiteEngine BufferParams::citeEngine() const
2420 // FIXME the class should provide the numerical/
2421 // authoryear choice
2422 if (documentClass().provides("natbib")
2423 && cite_engine_ != ENGINE_NATBIB_NUMERICAL)
2424 return ENGINE_NATBIB_AUTHORYEAR;
2425 return cite_engine_;
2429 void BufferParams::setCiteEngine(CiteEngine cite_engine)
2431 cite_engine_ = cite_engine;