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 // no color is the default (black)
373 fontcolor = lyx::rgbFromHexName("#000000");
375 // light gray is the default font color for greyed-out notes
376 notefontcolor = lyx::rgbFromHexName("#cccccc");
377 compressed = lyxrc.save_compressed;
378 for (int iter = 0; iter < 4; ++iter) {
379 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
380 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
383 indiceslist().addDefault(B_("Index"));
384 html_be_strict = true;
385 html_math_output = MathML;
389 docstring BufferParams::B_(string const & l10n) const
391 LASSERT(language, /**/);
392 return getMessages(language->code()).get(l10n);
396 AuthorList & BufferParams::authors()
398 return pimpl_->authorlist;
402 AuthorList const & BufferParams::authors() const
404 return pimpl_->authorlist;
408 BranchList & BufferParams::branchlist()
410 return pimpl_->branchlist;
414 BranchList const & BufferParams::branchlist() const
416 return pimpl_->branchlist;
420 IndicesList & BufferParams::indiceslist()
422 return pimpl_->indiceslist;
426 IndicesList const & BufferParams::indiceslist() const
428 return pimpl_->indiceslist;
432 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
434 LASSERT(index < 4, /**/);
435 return pimpl_->temp_bullets[index];
439 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
441 LASSERT(index < 4, /**/);
442 return pimpl_->temp_bullets[index];
446 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
448 LASSERT(index < 4, /**/);
449 return pimpl_->user_defined_bullets[index];
453 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
455 LASSERT(index < 4, /**/);
456 return pimpl_->user_defined_bullets[index];
460 Spacing & BufferParams::spacing()
462 return pimpl_->spacing;
466 Spacing const & BufferParams::spacing() const
468 return pimpl_->spacing;
472 PDFOptions & BufferParams::pdfoptions()
474 return pimpl_->pdfoptions;
478 PDFOptions const & BufferParams::pdfoptions() const
480 return pimpl_->pdfoptions;
484 HSpace const & BufferParams::getIndentation() const
486 return pimpl_->indentation;
490 void BufferParams::setIndentation(HSpace const & indent)
492 pimpl_->indentation = indent;
496 VSpace const & BufferParams::getDefSkip() const
498 return pimpl_->defskip;
502 void BufferParams::setDefSkip(VSpace const & vs)
504 pimpl_->defskip = vs;
508 string BufferParams::readToken(Lexer & lex, string const & token,
509 FileName const & filepath)
511 if (token == "\\textclass") {
513 string const classname = lex.getString();
514 // if there exists a local layout file, ignore the system one
515 // NOTE: in this case, the textclass (.cls file) is assumed to be available.
517 LayoutFileList & bcl = LayoutFileList::get();
518 if (tcp.empty() && !filepath.empty())
519 tcp = bcl.addLocalLayout(classname, filepath.absFilename());
523 setBaseClass(classname);
524 // We assume that a tex class exists for local or unknown layouts so this warning
525 // will only be given for system layouts.
526 if (!baseClass()->isTeXClassAvailable()) {
528 translateIfPossible(from_utf8(baseClass()->description()));
529 docstring const msg =
530 bformat(_("The document class requested\n"
532 "requires external files that are not available.\n"
533 "The document class can still be used, but LyX\n"
534 "will not be able to produce output until the\n"
535 "following prerequisites are installed:\n"
537 "See section 3.1.2.2 of the User's Guide for\n"
538 "more information."),
539 desc, from_utf8(baseClass()->prerequisites()));
540 frontend::Alert::warning(_("Document class not available"),
543 } else if (token == "\\begin_preamble") {
545 } else if (token == "\\begin_local_layout") {
546 readLocalLayout(lex);
547 } else if (token == "\\begin_modules") {
549 } else if (token == "\\begin_removed_modules") {
550 readRemovedModules(lex);
551 } else if (token == "\\begin_includeonly") {
552 readIncludeonly(lex);
553 } else if (token == "\\maintain_unincluded_children") {
554 lex >> maintain_unincluded_children;
555 } else if (token == "\\options") {
557 options = lex.getString();
558 } else if (token == "\\use_default_options") {
559 lex >> use_default_options;
560 } else if (token == "\\master") {
562 master = lex.getString();
563 } else if (token == "\\suppress_date") {
564 lex >> suppress_date;
565 } else if (token == "\\language") {
567 } else if (token == "\\inputencoding") {
569 } else if (token == "\\graphics") {
570 readGraphicsDriver(lex);
571 } else if (token == "\\default_output_format") {
572 lex >> defaultOutputFormat;
573 } else if (token == "\\bibtex_command") {
575 bibtex_command = lex.getString();
576 } else if (token == "\\index_command") {
578 index_command = lex.getString();
579 } else if (token == "\\fontencoding") {
581 fontenc = lex.getString();
582 } else if (token == "\\font_roman") {
584 fontsRoman = lex.getString();
585 } else if (token == "\\font_sans") {
587 fontsSans = lex.getString();
588 } else if (token == "\\font_typewriter") {
590 fontsTypewriter = lex.getString();
591 } else if (token == "\\font_default_family") {
592 lex >> fontsDefaultFamily;
593 } else if (token == "\\use_xetex") {
595 } else if (token == "\\font_sc") {
597 } else if (token == "\\font_osf") {
599 } else if (token == "\\font_sf_scale") {
600 lex >> fontsSansScale;
601 } else if (token == "\\font_tt_scale") {
602 lex >> fontsTypewriterScale;
603 } else if (token == "\\font_cjk") {
605 } else if (token == "\\paragraph_separation") {
608 paragraph_separation = parseptranslator().find(parsep);
609 } else if (token == "\\paragraph_indentation") {
611 string indentation = lex.getString();
612 pimpl_->indentation = HSpace(indentation);
613 } else if (token == "\\defskip") {
615 string defskip = lex.getString();
616 if (defskip == "defskip")
619 pimpl_->defskip = VSpace(defskip);
620 } else if (token == "\\quotes_language") {
623 quotes_language = quoteslangtranslator().find(quotes_lang);
624 } else if (token == "\\papersize") {
627 papersize = papersizetranslator().find(ppsize);
628 } else if (token == "\\use_geometry") {
630 } else if (token == "\\use_amsmath") {
633 use_amsmath = packagetranslator().find(use_ams);
634 } else if (token == "\\use_esint") {
637 use_esint = packagetranslator().find(useesint);
638 } else if (token == "\\use_mhchem") {
641 use_mhchem = packagetranslator().find(usemhchem);
642 } else if (token == "\\cite_engine") {
645 cite_engine_ = citeenginetranslator().find(engine);
646 } else if (token == "\\use_bibtopic") {
648 } else if (token == "\\use_indices") {
650 } else if (token == "\\tracking_changes") {
652 } else if (token == "\\output_changes") {
653 lex >> outputChanges;
654 } else if (token == "\\branch") {
656 docstring branch = lex.getDocString();
657 branchlist().add(branch);
660 string const tok = lex.getString();
661 if (tok == "\\end_branch")
663 Branch * branch_ptr = branchlist().find(branch);
664 if (tok == "\\selected") {
667 branch_ptr->setSelected(lex.getInteger());
669 if (tok == "\\filename_suffix") {
672 branch_ptr->setFilenameSuffix(lex.getInteger());
674 if (tok == "\\color") {
676 string color = lex.getString();
678 branch_ptr->setColor(color);
679 // Update also the Color table:
681 color = lcolor.getX11Name(Color_background);
683 lcolor.setColor(to_utf8(branch), color);
686 } else if (token == "\\index") {
688 docstring index = lex.getDocString();
690 indiceslist().add(index);
693 string const tok = lex.getString();
694 if (tok == "\\end_index")
696 Index * index_ptr = indiceslist().find(index);
697 if (tok == "\\shortcut") {
699 shortcut = lex.getDocString();
701 index_ptr->setShortcut(shortcut);
703 if (tok == "\\color") {
705 string color = lex.getString();
707 index_ptr->setColor(color);
708 // Update also the Color table:
710 color = lcolor.getX11Name(Color_background);
712 if (!shortcut.empty())
713 lcolor.setColor(to_utf8(shortcut), color);
716 } else if (token == "\\author") {
718 istringstream ss(lex.getString());
721 author_map[a.buffer_id()] = pimpl_->authorlist.record(a);
722 } else if (token == "\\paperorientation") {
725 orientation = paperorientationtranslator().find(orient);
726 } else if (token == "\\backgroundcolor") {
728 backgroundcolor = lyx::rgbFromHexName(lex.getString());
729 } else if (token == "\\fontcolor") {
731 fontcolor = lyx::rgbFromHexName(lex.getString());
733 } else if (token == "\\notefontcolor") {
735 string color = lex.getString();
736 notefontcolor = lyx::rgbFromHexName(color);
737 // set the font color within LyX
738 // FIXME: the color is correctly set but later overwritten by the default
739 lcolor.setColor(Color_greyedouttext, color);
740 } else if (token == "\\paperwidth") {
742 } else if (token == "\\paperheight") {
744 } else if (token == "\\leftmargin") {
746 } else if (token == "\\topmargin") {
748 } else if (token == "\\rightmargin") {
750 } else if (token == "\\bottommargin") {
752 } else if (token == "\\headheight") {
754 } else if (token == "\\headsep") {
756 } else if (token == "\\footskip") {
758 } else if (token == "\\columnsep") {
760 } else if (token == "\\paperfontsize") {
762 } else if (token == "\\papercolumns") {
764 } else if (token == "\\listings_params") {
767 listings_params = InsetListingsParams(par).params();
768 } else if (token == "\\papersides") {
771 sides = sidestranslator().find(psides);
772 } else if (token == "\\paperpagestyle") {
774 } else if (token == "\\bullet") {
776 } else if (token == "\\bulletLaTeX") {
777 readBulletsLaTeX(lex);
778 } else if (token == "\\secnumdepth") {
780 } else if (token == "\\tocdepth") {
782 } else if (token == "\\spacing") {
786 if (nspacing == "other") {
789 spacing().set(spacetranslator().find(nspacing), tmp_val);
790 } else if (token == "\\float_placement") {
791 lex >> float_placement;
793 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
794 string toktmp = pdfoptions().readToken(lex, token);
795 if (!toktmp.empty()) {
796 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
800 } else if (token == "\\html_math_output") {
803 html_math_output = static_cast<MathOutput>(temp);
804 } else if (token == "\\html_be_strict") {
805 lex >> html_be_strict;
807 lyxerr << "BufferParams::readToken(): Unknown token: " <<
816 void BufferParams::writeFile(ostream & os) const
818 // The top of the file is written by the buffer.
819 // Prints out the buffer info into the .lyx file given by file
822 os << "\\textclass " << baseClass()->name() << '\n';
825 if (!preamble.empty()) {
826 // remove '\n' from the end of preamble
827 string const tmppreamble = rtrim(preamble, "\n");
828 os << "\\begin_preamble\n"
830 << "\n\\end_preamble\n";
834 if (!options.empty()) {
835 os << "\\options " << options << '\n';
838 // use the class options defined in the layout?
839 os << "\\use_default_options "
840 << convert<string>(use_default_options) << "\n";
842 // the master document
843 if (!master.empty()) {
844 os << "\\master " << master << '\n';
848 if (!removedModules_.empty()) {
849 os << "\\begin_removed_modules" << '\n';
850 list<string>::const_iterator it = removedModules_.begin();
851 list<string>::const_iterator en = removedModules_.end();
852 for (; it != en; it++)
854 os << "\\end_removed_modules" << '\n';
858 if (!layoutModules_.empty()) {
859 os << "\\begin_modules" << '\n';
860 LayoutModuleList::const_iterator it = layoutModules_.begin();
861 LayoutModuleList::const_iterator en = layoutModules_.end();
862 for (; it != en; it++)
864 os << "\\end_modules" << '\n';
868 if (!includedChildren_.empty()) {
869 os << "\\begin_includeonly" << '\n';
870 list<string>::const_iterator it = includedChildren_.begin();
871 list<string>::const_iterator en = includedChildren_.end();
872 for (; it != en; it++)
874 os << "\\end_includeonly" << '\n';
876 os << "\\maintain_unincluded_children "
877 << convert<string>(maintain_unincluded_children) << '\n';
879 // local layout information
880 if (!local_layout.empty()) {
881 // remove '\n' from the end
882 string const tmplocal = rtrim(local_layout, "\n");
883 os << "\\begin_local_layout\n"
885 << "\n\\end_local_layout\n";
888 // then the text parameters
889 if (language != ignore_language)
890 os << "\\language " << language->lang() << '\n';
891 os << "\\inputencoding " << inputenc
892 << "\n\\fontencoding " << fontenc
893 << "\n\\font_roman " << fontsRoman
894 << "\n\\font_sans " << fontsSans
895 << "\n\\font_typewriter " << fontsTypewriter
896 << "\n\\font_default_family " << fontsDefaultFamily
897 << "\n\\use_xetex " << convert<string>(useXetex)
898 << "\n\\font_sc " << convert<string>(fontsSC)
899 << "\n\\font_osf " << convert<string>(fontsOSF)
900 << "\n\\font_sf_scale " << fontsSansScale
901 << "\n\\font_tt_scale " << fontsTypewriterScale
903 if (!fontsCJK.empty()) {
904 os << "\\font_cjk " << fontsCJK << '\n';
906 os << "\n\\graphics " << graphicsDriver << '\n';
907 os << "\\default_output_format " << defaultOutputFormat << '\n';
908 os << "\\bibtex_command " << bibtex_command << '\n';
909 os << "\\index_command " << index_command << '\n';
911 if (!float_placement.empty()) {
912 os << "\\float_placement " << float_placement << '\n';
914 os << "\\paperfontsize " << fontsize << '\n';
916 spacing().writeFile(os);
917 pdfoptions().writeFile(os);
919 os << "\\papersize " << string_papersize[papersize]
920 << "\n\\use_geometry " << convert<string>(use_geometry)
921 << "\n\\use_amsmath " << use_amsmath
922 << "\n\\use_esint " << use_esint
923 << "\n\\use_mhchem " << use_mhchem
924 << "\n\\cite_engine " << citeenginetranslator().find(cite_engine_)
925 << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
926 << "\n\\use_indices " << convert<string>(use_indices)
927 << "\n\\paperorientation " << string_orientation[orientation]
928 << "\n\\suppress_date " << convert<string>(suppress_date)
930 if (backgroundcolor != lyx::rgbFromHexName("#ffffff"))
931 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
932 if (isfontcolor == true)
933 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
934 if (notefontcolor != lyx::rgbFromHexName("#cccccc"))
935 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
937 BranchList::const_iterator it = branchlist().begin();
938 BranchList::const_iterator end = branchlist().end();
939 for (; it != end; ++it) {
940 os << "\\branch " << to_utf8(it->branch())
941 << "\n\\selected " << it->isSelected()
942 << "\n\\filename_suffix " << it->hasFilenameSuffix()
943 << "\n\\color " << lyx::X11hexname(it->color())
948 IndicesList::const_iterator iit = indiceslist().begin();
949 IndicesList::const_iterator iend = indiceslist().end();
950 for (; iit != iend; ++iit) {
951 os << "\\index " << to_utf8(iit->index())
952 << "\n\\shortcut " << to_utf8(iit->shortcut())
953 << "\n\\color " << lyx::X11hexname(iit->color())
958 if (!paperwidth.empty())
959 os << "\\paperwidth "
960 << VSpace(paperwidth).asLyXCommand() << '\n';
961 if (!paperheight.empty())
962 os << "\\paperheight "
963 << VSpace(paperheight).asLyXCommand() << '\n';
964 if (!leftmargin.empty())
965 os << "\\leftmargin "
966 << VSpace(leftmargin).asLyXCommand() << '\n';
967 if (!topmargin.empty())
969 << VSpace(topmargin).asLyXCommand() << '\n';
970 if (!rightmargin.empty())
971 os << "\\rightmargin "
972 << VSpace(rightmargin).asLyXCommand() << '\n';
973 if (!bottommargin.empty())
974 os << "\\bottommargin "
975 << VSpace(bottommargin).asLyXCommand() << '\n';
976 if (!headheight.empty())
977 os << "\\headheight "
978 << VSpace(headheight).asLyXCommand() << '\n';
979 if (!headsep.empty())
981 << VSpace(headsep).asLyXCommand() << '\n';
982 if (!footskip.empty())
984 << VSpace(footskip).asLyXCommand() << '\n';
985 if (!columnsep.empty())
987 << VSpace(columnsep).asLyXCommand() << '\n';
988 os << "\\secnumdepth " << secnumdepth
989 << "\n\\tocdepth " << tocdepth
990 << "\n\\paragraph_separation "
991 << string_paragraph_separation[paragraph_separation];
992 if (!paragraph_separation)
993 os << "\n\\paragraph_indentation " << getIndentation().asLyXCommand();
995 os << "\n\\defskip " << getDefSkip().asLyXCommand();
996 os << "\n\\quotes_language "
997 << string_quotes_language[quotes_language]
998 << "\n\\papercolumns " << columns
999 << "\n\\papersides " << sides
1000 << "\n\\paperpagestyle " << pagestyle << '\n';
1001 if (!listings_params.empty())
1002 os << "\\listings_params \"" <<
1003 InsetListingsParams(listings_params).encodedString() << "\"\n";
1004 for (int i = 0; i < 4; ++i) {
1005 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1006 if (user_defined_bullet(i).getFont() != -1) {
1007 os << "\\bullet " << i << " "
1008 << user_defined_bullet(i).getFont() << " "
1009 << user_defined_bullet(i).getCharacter() << " "
1010 << user_defined_bullet(i).getSize() << "\n";
1014 os << "\\bulletLaTeX " << i << " \""
1015 << lyx::to_ascii(user_defined_bullet(i).getText())
1021 os << "\\tracking_changes " << convert<string>(trackChanges) << "\n"
1022 << "\\output_changes " << convert<string>(outputChanges) << "\n"
1023 << "\\html_math_output " << html_math_output << "\n"
1024 << "\\html_be_strict " << convert<string>(html_be_strict) << "\n";
1026 os << pimpl_->authorlist;
1030 void BufferParams::validate(LaTeXFeatures & features) const
1032 features.require(documentClass().requires());
1034 if (outputChanges) {
1035 bool dvipost = LaTeXFeatures::isAvailable("dvipost");
1036 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1037 LaTeXFeatures::isAvailable("xcolor");
1039 switch (features.runparams().flavor) {
1040 case OutputParams::LATEX:
1042 features.require("ct-dvipost");
1043 features.require("dvipost");
1044 } else if (xcolorulem) {
1045 features.require("ct-xcolor-ulem");
1046 features.require("ulem");
1047 features.require("xcolor");
1049 features.require("ct-none");
1052 case OutputParams::PDFLATEX:
1053 case OutputParams::XETEX:
1055 features.require("ct-xcolor-ulem");
1056 features.require("ulem");
1057 features.require("xcolor");
1058 // improves color handling in PDF output
1059 features.require("pdfcolmk");
1061 features.require("ct-none");
1069 // Floats with 'Here definitely' as default setting.
1070 if (float_placement.find('H') != string::npos)
1071 features.require("float");
1073 // AMS Style is at document level
1074 if (use_amsmath == package_on
1075 || documentClass().provides("amsmath"))
1076 features.require("amsmath");
1077 if (use_esint == package_on)
1078 features.require("esint");
1079 if (use_mhchem == package_on)
1080 features.require("mhchem");
1082 // Document-level line spacing
1083 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1084 features.require("setspace");
1086 // the bullet shapes are buffer level not paragraph level
1087 // so they are tested here
1088 for (int i = 0; i < 4; ++i) {
1089 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1091 int const font = user_defined_bullet(i).getFont();
1093 int const c = user_defined_bullet(i).getCharacter();
1099 features.require("latexsym");
1101 } else if (font == 1) {
1102 features.require("amssymb");
1103 } else if (font >= 2 && font <= 5) {
1104 features.require("pifont");
1108 if (pdfoptions().use_hyperref) {
1109 features.require("hyperref");
1110 // due to interferences with babel and hyperref, the color package has to
1111 // be loaded after hyperref when hyperref is used with the colorlinks
1112 // option, see http://www.lyx.org/trac/ticket/5291
1113 if (pdfoptions().colorlinks)
1114 features.require("color");
1118 features.require("xetex");
1120 if (language->lang() == "vietnamese")
1121 features.require("vietnamese");
1122 else if (language->lang() == "japanese")
1123 features.require("japanese");
1127 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
1128 TexRow & texrow, FileName const & filepath) const
1130 os << "\\documentclass";
1132 DocumentClass const & tclass = documentClass();
1134 ostringstream clsoptions; // the document class options.
1136 if (tokenPos(tclass.opt_fontsize(),
1137 '|', fontsize) >= 0) {
1138 // only write if existing in list (and not default)
1139 clsoptions << fontsize << "pt,";
1142 // custom, A3, B3 and B4 paper sizes need geometry
1143 bool nonstandard_papersize = papersize == PAPER_B3
1144 || papersize == PAPER_B4
1145 || papersize == PAPER_A3
1146 || papersize == PAPER_CUSTOM;
1148 if (!use_geometry) {
1149 switch (papersize) {
1151 clsoptions << "a4paper,";
1153 case PAPER_USLETTER:
1154 clsoptions << "letterpaper,";
1157 clsoptions << "a5paper,";
1160 clsoptions << "b5paper,";
1162 case PAPER_USEXECUTIVE:
1163 clsoptions << "executivepaper,";
1166 clsoptions << "legalpaper,";
1178 if (sides != tclass.sides()) {
1181 clsoptions << "oneside,";
1184 clsoptions << "twoside,";
1190 if (columns != tclass.columns()) {
1192 clsoptions << "twocolumn,";
1194 clsoptions << "onecolumn,";
1198 && orientation == ORIENTATION_LANDSCAPE)
1199 clsoptions << "landscape,";
1201 // language should be a parameter to \documentclass
1202 if (language->babel() == "hebrew"
1203 && default_language->babel() != "hebrew")
1204 // This seems necessary
1205 features.useLanguage(default_language);
1207 ostringstream language_options;
1208 bool const use_babel = features.useBabel();
1210 language_options << features.getLanguages();
1211 if (!language->babel().empty()) {
1212 if (!language_options.str().empty())
1213 language_options << ',';
1214 language_options << language->babel();
1216 // if Vietnamese is used, babel must directly be loaded
1217 // with language options, not in the class options, see
1218 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1219 size_t viet = language_options.str().find("vietnam");
1220 // viet = string::npos when not found
1221 // the same is for all other languages that are not directly supported by
1222 // babel, but where LaTeX-packages add babel support.
1223 // this is currently the case for Latvian, Lithuanian, Mongolian
1225 size_t latvian = language_options.str().find("latvian");
1226 size_t lithu = language_options.str().find("lithuanian");
1227 size_t mongo = language_options.str().find("mongolian");
1228 size_t turkmen = language_options.str().find("turkmen");
1229 // if Japanese is used, babel must directly be loaded
1230 // with language options, not in the class options, see
1231 // http://www.lyx.org/trac/ticket/4597#c4
1232 size_t japan = language_options.str().find("japanese");
1233 if (lyxrc.language_global_options && !language_options.str().empty()
1234 && viet == string::npos && japan == string::npos
1235 && latvian == string::npos && lithu == string::npos
1236 && mongo == string::npos && turkmen == string::npos)
1237 clsoptions << language_options.str() << ',';
1240 // the predefined options from the layout
1241 if (use_default_options && !tclass.options().empty())
1242 clsoptions << tclass.options() << ',';
1244 // the user-defined options
1245 if (!options.empty()) {
1246 clsoptions << options << ',';
1249 string strOptions(clsoptions.str());
1250 if (!strOptions.empty()) {
1251 strOptions = rtrim(strOptions, ",");
1253 os << '[' << from_utf8(strOptions) << ']';
1256 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1258 // end of \documentclass defs
1261 os << "\\usepackage{fontspec}\n";
1265 // font selection must be done before loading fontenc.sty
1266 string const fonts =
1267 loadFonts(fontsRoman, fontsSans,
1268 fontsTypewriter, fontsSC, fontsOSF,
1269 fontsSansScale, fontsTypewriterScale, useXetex);
1270 if (!fonts.empty()) {
1271 os << from_ascii(fonts);
1274 if (fontsDefaultFamily != "default")
1275 os << "\\renewcommand{\\familydefault}{\\"
1276 << from_ascii(fontsDefaultFamily) << "}\n";
1278 // set font encoding
1279 // for arabic_arabi and farsi we also need to load the LAE and
1281 // XeTeX works without fontenc
1282 if (font_encoding() != "default" && language->lang() != "japanese"
1284 if (language->lang() == "arabic_arabi"
1285 || language->lang() == "farsi") {
1286 os << "\\usepackage[" << from_ascii(font_encoding())
1287 << ",LFE,LAE]{fontenc}\n";
1290 os << "\\usepackage[" << from_ascii(font_encoding())
1296 // handle inputenc etc.
1297 writeEncodingPreamble(os, features, texrow);
1300 if (!features.runparams().includeall && !includedChildren_.empty()) {
1301 os << "\\includeonly{";
1302 list<string>::const_iterator it = includedChildren_.begin();
1304 for (; it != includedChildren_.end() ; ++it) {
1305 string incfile = *it;
1306 FileName inc = makeAbsPath(incfile, filepath.absFilename());
1307 string mangled = DocFileName(changeExtension(inc.absFilename(), ".tex")).
1309 if (!features.runparams().nice)
1311 // \includeonly doesn't want an extension
1312 incfile = changeExtension(incfile, string());
1313 incfile = support::latex_path(incfile);
1314 if (!incfile.empty()) {
1317 os << from_utf8(incfile);
1324 if (!listings_params.empty() || features.isRequired("listings")) {
1325 os << "\\usepackage{listings}\n";
1328 if (!listings_params.empty()) {
1330 // do not test validity because listings_params is
1331 // supposed to be valid
1333 InsetListingsParams(listings_params).separatedParams(true);
1334 // we can't support all packages, but we should load the color package
1335 if (par.find("\\color", 0) != string::npos)
1336 features.require("color");
1337 os << from_utf8(par);
1338 // count the number of newlines
1339 for (size_t i = 0; i < par.size(); ++i)
1345 if (!tclass.provides("geometry")
1346 && (use_geometry || nonstandard_papersize)) {
1347 odocstringstream ods;
1348 if (!getGraphicsDriver("geometry").empty())
1349 ods << getGraphicsDriver("geometry");
1350 if (orientation == ORIENTATION_LANDSCAPE)
1351 ods << ",landscape";
1352 switch (papersize) {
1354 if (!paperwidth.empty())
1355 ods << ",paperwidth="
1356 << from_ascii(paperwidth);
1357 if (!paperheight.empty())
1358 ods << ",paperheight="
1359 << from_ascii(paperheight);
1361 case PAPER_USLETTER:
1362 ods << ",letterpaper";
1365 ods << ",legalpaper";
1367 case PAPER_USEXECUTIVE:
1368 ods << ",executivepaper";
1389 // default papersize ie PAPER_DEFAULT
1390 switch (lyxrc.default_papersize) {
1391 case PAPER_DEFAULT: // keep compiler happy
1392 case PAPER_USLETTER:
1393 ods << ",letterpaper";
1396 ods << ",legalpaper";
1398 case PAPER_USEXECUTIVE:
1399 ods << ",executivepaper";
1419 docstring const g_options = trim(ods.str(), ",");
1420 os << "\\usepackage";
1421 if (!g_options.empty())
1422 os << '[' << g_options << ']';
1423 os << "{geometry}\n";
1425 os << "\\geometry{verbose";
1426 if (!topmargin.empty())
1427 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1428 if (!bottommargin.empty())
1429 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1430 if (!leftmargin.empty())
1431 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1432 if (!rightmargin.empty())
1433 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1434 if (!headheight.empty())
1435 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1436 if (!headsep.empty())
1437 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1438 if (!footskip.empty())
1439 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1440 if (!columnsep.empty())
1441 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1444 } else if (orientation == ORIENTATION_LANDSCAPE) {
1445 features.require("papersize");
1448 if (tokenPos(tclass.opt_pagestyle(),
1449 '|', pagestyle) >= 0) {
1450 if (pagestyle == "fancy") {
1451 os << "\\usepackage{fancyhdr}\n";
1454 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1458 // only output when the background color is not white
1459 if (backgroundcolor != lyx::rgbFromHexName("#ffffff")) {
1460 // only require color here, the background color will be defined
1461 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1463 features.require("color");
1464 features.require("pagecolor");
1467 // only output when the font color is not black
1468 if (isfontcolor == true) {
1469 // only require color here, the font color will be defined
1470 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1472 features.require("color");
1473 features.require("fontcolor");
1476 // Only if class has a ToC hierarchy
1477 if (tclass.hasTocLevels()) {
1478 if (secnumdepth != tclass.secnumdepth()) {
1479 os << "\\setcounter{secnumdepth}{"
1484 if (tocdepth != tclass.tocdepth()) {
1485 os << "\\setcounter{tocdepth}{"
1492 if (paragraph_separation) {
1493 // when skip separation
1494 switch (getDefSkip().kind()) {
1495 case VSpace::SMALLSKIP:
1496 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1498 case VSpace::MEDSKIP:
1499 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1501 case VSpace::BIGSKIP:
1502 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1504 case VSpace::LENGTH:
1505 os << "\\setlength{\\parskip}{"
1506 << from_utf8(getDefSkip().length().asLatexString())
1509 default: // should never happen // Then delete it.
1510 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1514 os << "\\setlength{\\parindent}{0pt}\n";
1517 // when separation by indentation
1518 // only output something when a width is given
1519 if (getIndentation().asLyXCommand() != "default") {
1520 os << "\\setlength{\\parindent}{"
1521 << from_utf8(getIndentation().asLatexCommand())
1527 // Now insert the LyX specific LaTeX commands...
1528 docstring lyxpreamble;
1530 // due to interferences with babel and hyperref, the color package has to
1531 // be loaded (when it is not already loaded) before babel when hyperref
1532 // is used with the colorlinks option, see
1533 // http://www.lyx.org/trac/ticket/5291
1534 // we decided therefore to load color always before babel, see
1535 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
1536 lyxpreamble += from_ascii(features.getColorOptions());
1538 // If we use hyperref, jurabib, japanese, or vietnamese, we have to call babel before them.
1540 && (features.isRequired("jurabib")
1541 || features.isRequired("hyperref")
1542 || features.isRequired("vietnamese")
1543 || features.isRequired("japanese") ) ) {
1545 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1546 lyxpreamble += from_utf8(features.getBabelOptions()) + '\n';
1549 // The optional packages;
1550 lyxpreamble += from_ascii(features.getPackages());
1552 // Additional Indices
1553 if (features.isRequired("splitidx")) {
1554 IndicesList::const_iterator iit = indiceslist().begin();
1555 IndicesList::const_iterator iend = indiceslist().end();
1556 for (; iit != iend; ++iit) {
1557 lyxpreamble += "\\newindex[";
1558 lyxpreamble += iit->index();
1559 lyxpreamble += "]{";
1560 lyxpreamble += iit->shortcut();
1561 lyxpreamble += "}\n";
1566 lyxpreamble += from_utf8(spacing().writePreamble(tclass.provides("SetSpace")));
1569 // * Hyperref manual: "Make sure it comes last of your loaded
1570 // packages, to give it a fighting chance of not being over-written,
1571 // since its job is to redefine many LaTeX commands."
1572 // * Email from Heiko Oberdiek: "It is usually better to load babel
1573 // before hyperref. Then hyperref has a chance to detect babel.
1574 // * Has to be loaded before the "LyX specific LaTeX commands" to
1575 // avoid errors with algorithm floats.
1576 // use hyperref explicitly if it is required
1577 if (features.isRequired("hyperref")) {
1578 // pass what we have to stream here, since we need
1579 // to access the stream itself in PDFOptions.
1583 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1585 OutputParams tmp_params = features.runparams();
1586 lines += pdfoptions().writeLaTeX(tmp_params, os,
1587 documentClass().provides("hyperref"));
1588 texrow.newlines(lines);
1589 // set back for the rest
1590 lyxpreamble.clear();
1593 // Will be surrounded by \makeatletter and \makeatother when not empty
1594 docstring atlyxpreamble;
1596 // Some macros LyX will need
1597 docstring tmppreamble(features.getMacros());
1599 if (!tmppreamble.empty())
1600 atlyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1601 "LyX specific LaTeX commands.\n"
1602 + tmppreamble + '\n';
1604 // the text class specific preamble
1605 tmppreamble = features.getTClassPreamble();
1606 if (!tmppreamble.empty())
1607 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1608 "Textclass specific LaTeX commands.\n"
1609 + tmppreamble + '\n';
1611 // suppress date if selected
1612 // use \@ifundefined because we cannot be sure that every document class
1613 // has a \date command
1615 atlyxpreamble += "\\@ifundefined{date}{}{\\date{}}\n";
1617 /* the user-defined preamble */
1618 if (!containsOnly(preamble, " \n\t"))
1620 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1621 "User specified LaTeX commands.\n"
1622 + from_utf8(preamble) + '\n';
1624 // subfig loads internally the LaTeX package "caption". As
1625 // caption is a very popular package, users will load it in
1626 // the preamble. Therefore we must load subfig behind the
1627 // user-defined preamble and check if the caption package was
1628 // loaded or not. For the case that caption is loaded before
1629 // subfig, there is the subfig option "caption=false". This
1630 // option also works when a koma-script class is used and
1631 // koma's own caption commands are used instead of caption. We
1632 // use \PassOptionsToPackage here because the user could have
1633 // already loaded subfig in the preamble.
1634 if (features.isRequired("subfig")) {
1635 atlyxpreamble += "\\@ifundefined{showcaptionsetup}{}{%\n"
1636 " \\PassOptionsToPackage{caption=false}{subfig}}\n"
1637 "\\usepackage{subfig}\n";
1640 // Itemize bullet settings need to be last in case the user
1641 // defines their own bullets that use a package included
1642 // in the user-defined preamble -- ARRae
1643 // Actually it has to be done much later than that
1644 // since some packages like frenchb make modifications
1645 // at \begin{document} time -- JMarc
1646 docstring bullets_def;
1647 for (int i = 0; i < 4; ++i) {
1648 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1649 if (bullets_def.empty())
1650 bullets_def += "\\AtBeginDocument{\n";
1651 bullets_def += " \\def\\labelitemi";
1653 // `i' is one less than the item to modify
1660 bullets_def += "ii";
1666 bullets_def += '{' +
1667 user_defined_bullet(i).getText()
1672 if (!bullets_def.empty())
1673 atlyxpreamble += bullets_def + "}\n\n";
1675 if (!atlyxpreamble.empty())
1676 lyxpreamble += "\n\\makeatletter\n"
1677 + atlyxpreamble + "\\makeatother\n\n";
1679 // We try to load babel late, in case it interferes with other packages.
1680 // Jurabib and Hyperref have to be called after babel, though.
1681 if (use_babel && !features.isRequired("jurabib")
1682 && !features.isRequired("hyperref")
1683 && !features.isRequired("vietnamese")
1684 && !features.isRequired("japanese")) {
1686 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1687 lyxpreamble += from_utf8(features.getBabelOptions()) + '\n';
1690 docstring const i18npreamble = features.getTClassI18nPreamble(use_babel);
1691 if (!i18npreamble.empty())
1692 lyxpreamble += i18npreamble + '\n';
1695 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1696 texrow.newlines(nlines);
1700 // these packages (xunicode, for that matter) need to be loaded at least
1701 // after amsmath, amssymb, esint and the other packages that provide
1704 os << "\\usepackage{xunicode}\n";
1706 os << "\\usepackage{xltxtra}\n";
1713 void BufferParams::useClassDefaults()
1715 DocumentClass const & tclass = documentClass();
1717 sides = tclass.sides();
1718 columns = tclass.columns();
1719 pagestyle = tclass.pagestyle();
1720 use_default_options = true;
1721 // Only if class has a ToC hierarchy
1722 if (tclass.hasTocLevels()) {
1723 secnumdepth = tclass.secnumdepth();
1724 tocdepth = tclass.tocdepth();
1729 bool BufferParams::hasClassDefaults() const
1731 DocumentClass const & tclass = documentClass();
1733 return sides == tclass.sides()
1734 && columns == tclass.columns()
1735 && pagestyle == tclass.pagestyle()
1736 && use_default_options
1737 && secnumdepth == tclass.secnumdepth()
1738 && tocdepth == tclass.tocdepth();
1742 DocumentClass const & BufferParams::documentClass() const
1748 DocumentClass const * BufferParams::documentClassPtr() const {
1753 void BufferParams::setDocumentClass(DocumentClass const * const tc) {
1754 // evil, but this function is evil
1755 doc_class_ = const_cast<DocumentClass *>(tc);
1759 bool BufferParams::setBaseClass(string const & classname)
1761 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
1762 LayoutFileList & bcl = LayoutFileList::get();
1763 if (!bcl.haveClass(classname)) {
1765 bformat(_("The document class %1$s could not be found. "
1766 "A default textclass with default layouts will be used. "
1767 "LyX might not be able to produce output unless a correct "
1768 "textclass is selected from the document settings dialog."),
1769 from_utf8(classname));
1770 frontend::Alert::error(_("Document class not found"), s);
1771 bcl.addEmptyClass(classname);
1774 bool const success = bcl[classname].load();
1777 bformat(_("The document class %1$s could not be loaded."),
1778 from_utf8(classname));
1779 frontend::Alert::error(_("Could not load class"), s);
1783 pimpl_->baseClass_ = classname;
1784 layoutModules_.adaptToBaseClass(baseClass(), removedModules_);
1789 LayoutFile const * BufferParams::baseClass() const
1791 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
1792 return &(LayoutFileList::get()[pimpl_->baseClass_]);
1798 LayoutFileIndex const & BufferParams::baseClassID() const
1800 return pimpl_->baseClass_;
1804 void BufferParams::makeDocumentClass()
1809 doc_class_ = &(DocumentClassBundle::get().makeDocumentClass(*baseClass(), layoutModules_));
1811 if (!local_layout.empty()) {
1812 if (!doc_class_->read(local_layout, TextClass::MODULE)) {
1813 docstring const msg = _("Error reading internal layout information");
1814 frontend::Alert::warning(_("Read Error"), msg);
1819 bool BufferParams::moduleCanBeAdded(string const & modName) const
1821 return layoutModules_.moduleCanBeAdded(modName, baseClass());
1825 bool BufferParams::addLayoutModule(string const & modName)
1827 LayoutModuleList::const_iterator it = layoutModules_.begin();
1828 LayoutModuleList::const_iterator end = layoutModules_.end();
1829 for (; it != end; it++)
1832 layoutModules_.push_back(modName);
1837 Font const BufferParams::getFont() const
1839 FontInfo f = documentClass().defaultfont();
1840 if (fontsDefaultFamily == "rmdefault")
1841 f.setFamily(ROMAN_FAMILY);
1842 else if (fontsDefaultFamily == "sfdefault")
1843 f.setFamily(SANS_FAMILY);
1844 else if (fontsDefaultFamily == "ttdefault")
1845 f.setFamily(TYPEWRITER_FAMILY);
1846 return Font(f, language);
1850 void BufferParams::readPreamble(Lexer & lex)
1852 if (lex.getString() != "\\begin_preamble")
1853 lyxerr << "Error (BufferParams::readPreamble):"
1854 "consistency check failed." << endl;
1856 preamble = lex.getLongString("\\end_preamble");
1860 void BufferParams::readLocalLayout(Lexer & lex)
1862 if (lex.getString() != "\\begin_local_layout")
1863 lyxerr << "Error (BufferParams::readLocalLayout):"
1864 "consistency check failed." << endl;
1866 local_layout = lex.getLongString("\\end_local_layout");
1870 void BufferParams::readLanguage(Lexer & lex)
1872 if (!lex.next()) return;
1874 string const tmptok = lex.getString();
1876 // check if tmptok is part of tex_babel in tex-defs.h
1877 language = languages.getLanguage(tmptok);
1879 // Language tmptok was not found
1880 language = default_language;
1881 lyxerr << "Warning: Setting language `"
1882 << tmptok << "' to `" << language->lang()
1888 void BufferParams::readGraphicsDriver(Lexer & lex)
1893 string const tmptok = lex.getString();
1894 // check if tmptok is part of tex_graphics in tex_defs.h
1897 string const test = tex_graphics[n++];
1899 if (test == tmptok) {
1900 graphicsDriver = tmptok;
1905 "Warning: graphics driver `$$Token' not recognized!\n"
1906 " Setting graphics driver to `default'.\n");
1907 graphicsDriver = "default";
1914 void BufferParams::readBullets(Lexer & lex)
1919 int const index = lex.getInteger();
1921 int temp_int = lex.getInteger();
1922 user_defined_bullet(index).setFont(temp_int);
1923 temp_bullet(index).setFont(temp_int);
1925 user_defined_bullet(index).setCharacter(temp_int);
1926 temp_bullet(index).setCharacter(temp_int);
1928 user_defined_bullet(index).setSize(temp_int);
1929 temp_bullet(index).setSize(temp_int);
1933 void BufferParams::readBulletsLaTeX(Lexer & lex)
1935 // The bullet class should be able to read this.
1938 int const index = lex.getInteger();
1940 docstring const temp_str = lex.getDocString();
1942 user_defined_bullet(index).setText(temp_str);
1943 temp_bullet(index).setText(temp_str);
1947 void BufferParams::readModules(Lexer & lex)
1949 if (!lex.eatLine()) {
1950 lyxerr << "Error (BufferParams::readModules):"
1951 "Unexpected end of input." << endl;
1955 string mod = lex.getString();
1956 if (mod == "\\end_modules")
1958 addLayoutModule(mod);
1964 void BufferParams::readRemovedModules(Lexer & lex)
1966 if (!lex.eatLine()) {
1967 lyxerr << "Error (BufferParams::readRemovedModules):"
1968 "Unexpected end of input." << endl;
1972 string mod = lex.getString();
1973 if (mod == "\\end_removed_modules")
1975 removedModules_.push_back(mod);
1978 // now we want to remove any removed modules that were previously
1979 // added. normally, that will be because default modules were added in
1980 // setBaseClass(), which gets called when \textclass is read at the
1981 // start of the read.
1982 list<string>::const_iterator rit = removedModules_.begin();
1983 list<string>::const_iterator const ren = removedModules_.end();
1984 for (; rit != ren; rit++) {
1985 LayoutModuleList::iterator const mit = layoutModules_.begin();
1986 LayoutModuleList::iterator const men = layoutModules_.end();
1987 LayoutModuleList::iterator found = find(mit, men, *rit);
1990 layoutModules_.erase(found);
1995 void BufferParams::readIncludeonly(Lexer & lex)
1997 if (!lex.eatLine()) {
1998 lyxerr << "Error (BufferParams::readIncludeonly):"
1999 "Unexpected end of input." << endl;
2003 string child = lex.getString();
2004 if (child == "\\end_includeonly")
2006 includedChildren_.push_back(child);
2012 string BufferParams::paperSizeName(PapersizePurpose purpose) const
2014 char real_papersize = papersize;
2015 if (real_papersize == PAPER_DEFAULT)
2016 real_papersize = lyxrc.default_papersize;
2018 switch (real_papersize) {
2020 // could be anything, so don't guess
2022 case PAPER_CUSTOM: {
2023 if (purpose == XDVI && !paperwidth.empty() &&
2024 !paperheight.empty()) {
2025 // heightxwidth<unit>
2026 string first = paperwidth;
2027 string second = paperheight;
2028 if (orientation == ORIENTATION_LANDSCAPE)
2031 return first.erase(first.length() - 2)
2043 // dvips and dvipdfm do not know this
2044 if (purpose == DVIPS || purpose == DVIPDFM)
2048 // dvipdfm does not know this
2049 if (purpose == DVIPDFM)
2053 // dvipdfm does not know this
2054 if (purpose == DVIPDFM)
2057 case PAPER_USEXECUTIVE:
2058 // dvipdfm does not know this
2059 if (purpose == DVIPDFM)
2064 case PAPER_USLETTER:
2066 if (purpose == XDVI)
2073 string const BufferParams::dvips_options() const
2078 && papersize == PAPER_CUSTOM
2079 && !lyxrc.print_paper_dimension_flag.empty()
2080 && !paperwidth.empty()
2081 && !paperheight.empty()) {
2082 // using a custom papersize
2083 result = lyxrc.print_paper_dimension_flag;
2084 result += ' ' + paperwidth;
2085 result += ',' + paperheight;
2087 string const paper_option = paperSizeName(DVIPS);
2088 if (!paper_option.empty() && (paper_option != "letter" ||
2089 orientation != ORIENTATION_LANDSCAPE)) {
2090 // dvips won't accept -t letter -t landscape.
2091 // In all other cases, include the paper size
2093 result = lyxrc.print_paper_flag;
2094 result += ' ' + paper_option;
2097 if (orientation == ORIENTATION_LANDSCAPE &&
2098 papersize != PAPER_CUSTOM)
2099 result += ' ' + lyxrc.print_landscape_flag;
2104 string const BufferParams::font_encoding() const
2106 return (fontenc == "global") ? lyxrc.fontenc : fontenc;
2110 string BufferParams::babelCall(string const & lang_opts) const
2112 string lang_pack = lyxrc.language_package;
2113 if (lang_pack != "\\usepackage{babel}")
2115 // suppress the babel call when there is no babel language defined
2116 // for the document language in the lib/languages file and if no
2117 // other languages are used (lang_opts is then empty)
2118 if (lang_opts.empty())
2120 // If Vietnamese is used, babel must directly be loaded with the
2121 // language options, see
2122 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
2123 size_t viet = lang_opts.find("vietnam");
2124 // viet = string::npos when not found
2125 // the same is for all other languages that are not directly supported by
2126 // babel, but where LaTeX-packages add babel support.
2127 // this is currently the case for Latvian, Lithuanian, Mongolian
2129 size_t latvian = lang_opts.find("latvian");
2130 size_t lithu = lang_opts.find("lithuanian");
2131 size_t mongo = lang_opts.find("mongolian");
2132 size_t turkmen = lang_opts.find("turkmen");
2133 // If Japanese is used, babel must directly be loaded with the
2134 // language options, see
2135 // http://www.lyx.org/trac/ticket/4597#c4
2136 size_t japan = lang_opts.find("japanese");
2137 if (!lyxrc.language_global_options || viet != string::npos
2138 || japan != string::npos || latvian != string::npos
2139 || lithu != string::npos || mongo != string::npos
2140 || turkmen != string::npos)
2141 return "\\usepackage[" + lang_opts + "]{babel}";
2146 docstring BufferParams::getGraphicsDriver(string const & package) const
2150 if (package == "geometry") {
2151 if (graphicsDriver == "dvips"
2152 || graphicsDriver == "dvipdfm"
2153 || graphicsDriver == "pdftex"
2154 || graphicsDriver == "vtex")
2155 result = from_ascii(graphicsDriver);
2156 else if (graphicsDriver == "dvipdfmx")
2157 result = from_ascii("dvipdfm");
2164 void BufferParams::writeEncodingPreamble(odocstream & os,
2165 LaTeXFeatures & features, TexRow & texrow) const
2169 if (inputenc == "auto") {
2170 string const doc_encoding =
2171 language->encoding()->latexName();
2172 Encoding::Package const package =
2173 language->encoding()->package();
2175 // Create a list with all the input encodings used
2177 set<string> encodings =
2178 features.getEncodingSet(doc_encoding);
2180 // If the "japanese" package (i.e. pLaTeX) is used,
2181 // inputenc must be omitted.
2182 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
2183 if (package == Encoding::japanese)
2184 features.require("japanese");
2186 if ((!encodings.empty() || package == Encoding::inputenc)
2187 && !features.isRequired("japanese")) {
2188 os << "\\usepackage[";
2189 set<string>::const_iterator it = encodings.begin();
2190 set<string>::const_iterator const end = encodings.end();
2192 os << from_ascii(*it);
2195 for (; it != end; ++it)
2196 os << ',' << from_ascii(*it);
2197 if (package == Encoding::inputenc) {
2198 if (!encodings.empty())
2200 os << from_ascii(doc_encoding);
2202 os << "]{inputenc}\n";
2205 if (package == Encoding::CJK || features.mustProvide("CJK")) {
2206 if (language->encoding()->name() == "utf8-cjk"
2207 && LaTeXFeatures::isAvailable("CJKutf8"))
2208 os << "\\usepackage{CJKutf8}\n";
2210 os << "\\usepackage{CJK}\n";
2213 } else if (inputenc != "default") {
2214 switch (encoding().package()) {
2215 case Encoding::none:
2216 case Encoding::japanese:
2218 case Encoding::inputenc:
2219 // do not load inputenc if japanese is used
2220 if (features.isRequired("japanese"))
2222 os << "\\usepackage[" << from_ascii(inputenc)
2227 if (encoding().name() == "utf8-cjk"
2228 && LaTeXFeatures::isAvailable("CJKutf8"))
2229 os << "\\usepackage{CJKutf8}\n";
2231 os << "\\usepackage{CJK}\n";
2237 // The encoding "armscii8" (for Armenian) is only available when
2238 // the package "armtex" is loaded.
2239 if (language->encoding()->latexName() == "armscii8"
2240 || inputenc == "armscii8") {
2241 os << "\\usepackage{armtex}\n";
2247 string const BufferParams::parseFontName(string const & name) const
2249 string mangled = name;
2250 size_t const idx = mangled.find('[');
2251 if (idx == string::npos || idx == 0)
2254 return mangled.substr(0, idx - 1);
2258 string const BufferParams::loadFonts(string const & rm,
2259 string const & sf, string const & tt,
2260 bool const & sc, bool const & osf,
2261 int const & sfscale, int const & ttscale,
2262 bool const & xetex) const
2264 /* The LaTeX font world is in a flux. In the PSNFSS font interface,
2265 several packages have been replaced by others, that might not
2266 be installed on every system. We have to take care for that
2267 (see psnfss.pdf). We try to support all psnfss fonts as well
2268 as the fonts that have become de facto standard in the LaTeX
2269 world (e.g. Latin Modern). We do not support obsolete fonts
2270 (like PSLatex). In general, it should be possible to mix any
2271 rm font with any sf or tt font, respectively. (JSpitzm)
2273 -- separate math fonts.
2276 if (rm == "default" && sf == "default" && tt == "default")
2283 if (rm != "default")
2284 os << "\\setmainfont[Mapping=tex-text]{"
2285 << parseFontName(rm) << "}\n";
2286 if (sf != "default") {
2287 string const sans = parseFontName(sf);
2289 os << "\\setsansfont[Scale="
2290 << float(sfscale) / 100
2291 << ",Mapping=tex-text]{"
2294 os << "\\setsansfont[Mapping=tex-text]{"
2297 if (tt != "default") {
2298 string const mono = parseFontName(tt);
2300 os << "\\setmonofont[Scale="
2301 << float(sfscale) / 100
2305 os << "\\setmonofont[Mapping=tex-text]{"
2309 os << "\\defaultfontfeatures{Numbers=OldStyle}\n";
2314 // Computer Modern (must be explicitly selectable -- there might be classes
2315 // that define a different default font!
2317 os << "\\renewcommand{\\rmdefault}{cmr}\n";
2318 // osf for Computer Modern needs eco.sty
2320 os << "\\usepackage{eco}\n";
2322 // Latin Modern Roman
2323 else if (rm == "lmodern")
2324 os << "\\usepackage{lmodern}\n";
2326 else if (rm == "ae") {
2327 // not needed when using OT1 font encoding.
2328 if (font_encoding() != "default")
2329 os << "\\usepackage{ae,aecompl}\n";
2332 else if (rm == "times") {
2333 // try to load the best available package
2334 if (LaTeXFeatures::isAvailable("mathptmx"))
2335 os << "\\usepackage{mathptmx}\n";
2336 else if (LaTeXFeatures::isAvailable("mathptm"))
2337 os << "\\usepackage{mathptm}\n";
2339 os << "\\usepackage{times}\n";
2342 else if (rm == "palatino") {
2343 // try to load the best available package
2344 if (LaTeXFeatures::isAvailable("mathpazo")) {
2345 os << "\\usepackage";
2351 // "osf" includes "sc"!
2355 os << "{mathpazo}\n";
2357 else if (LaTeXFeatures::isAvailable("mathpple"))
2358 os << "\\usepackage{mathpple}\n";
2360 os << "\\usepackage{palatino}\n";
2363 else if (rm == "utopia") {
2364 // fourier supersedes utopia.sty, but does
2365 // not work with OT1 encoding.
2366 if (LaTeXFeatures::isAvailable("fourier")
2367 && font_encoding() != "default") {
2368 os << "\\usepackage";
2379 os << "{fourier}\n";
2382 os << "\\usepackage{utopia}\n";
2384 // Bera (complete fontset)
2385 else if (rm == "bera" && sf == "default" && tt == "default")
2386 os << "\\usepackage{bera}\n";
2388 else if (rm != "default")
2389 os << "\\usepackage" << "{" << rm << "}\n";
2392 // Helvetica, Bera Sans
2393 if (sf == "helvet" || sf == "berasans") {
2395 os << "\\usepackage[scaled=" << float(sfscale) / 100
2396 << "]{" << sf << "}\n";
2398 os << "\\usepackage{" << sf << "}\n";
2401 else if (sf == "avant")
2402 os << "\\usepackage{" << sf << "}\n";
2403 // Computer Modern, Latin Modern, CM Bright
2404 else if (sf != "default")
2405 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
2407 // monospaced/typewriter
2408 // Courier, LuxiMono
2409 if (tt == "luximono" || tt == "beramono") {
2411 os << "\\usepackage[scaled=" << float(ttscale) / 100
2412 << "]{" << tt << "}\n";
2414 os << "\\usepackage{" << tt << "}\n";
2417 else if (tt == "courier" )
2418 os << "\\usepackage{" << tt << "}\n";
2419 // Computer Modern, Latin Modern, CM Bright
2420 else if (tt != "default")
2421 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
2427 Encoding const & BufferParams::encoding() const
2430 return *(encodings.fromLaTeXName("utf8-plain"));
2431 if (inputenc == "auto" || inputenc == "default")
2432 return *language->encoding();
2433 Encoding const * const enc = encodings.fromLaTeXName(inputenc);
2436 LYXERR0("Unknown inputenc value `" << inputenc
2437 << "'. Using `auto' instead.");
2438 return *language->encoding();
2442 CiteEngine BufferParams::citeEngine() const
2444 // FIXME the class should provide the numerical/
2445 // authoryear choice
2446 if (documentClass().provides("natbib")
2447 && cite_engine_ != ENGINE_NATBIB_NUMERICAL)
2448 return ENGINE_NATBIB_AUTHORYEAR;
2449 return cite_engine_;
2453 void BufferParams::setCiteEngine(CiteEngine cite_engine)
2455 cite_engine_ = cite_engine;