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 "LaTeXFeatures.h"
30 #include "ModuleList.h"
34 #include "OutputParams.h"
38 #include "PDFOptions.h"
40 #include "frontends/alert.h"
42 #include "insets/InsetListingsParams.h"
44 #include "support/convert.h"
45 #include "support/debug.h"
46 #include "support/docstream.h"
47 #include "support/FileName.h"
48 #include "support/filetools.h"
49 #include "support/gettext.h"
50 #include "support/Messages.h"
51 #include "support/Translator.h"
52 #include "support/lstrings.h"
58 using namespace lyx::support;
61 static char const * const string_paragraph_separation[] = {
66 static char const * const string_quotes_language[] = {
67 "english", "swedish", "german", "polish", "french", "danish", ""
71 static char const * const string_papersize[] = {
72 "default", "custom", "letterpaper", "legalpaper", "executivepaper",
73 "a3paper", "a4paper", "a5paper", "b3paper", "b4paper", "b5paper", ""
77 static char const * const string_orientation[] = {
78 "portrait", "landscape", ""
82 static char const * const string_footnotekinds[] = {
83 "footnote", "margin", "fig", "tab", "alg", "wide-fig", "wide-tab", ""
87 static char const * const tex_graphics[] = {
88 "default", "dvialw", "dvilaser", "dvipdf", "dvipdfm", "dvipdfmx",
89 "dvips", "dvipsone", "dvitops", "dviwin", "dviwindo", "dvi2ps", "emtex",
90 "ln", "oztex", "pctexhp", "pctexps", "pctexwin", "pctex32", "pdftex",
91 "psprint", "pubps", "tcidvi", "textures", "truetex", "vtex", "xdvi",
101 // Paragraph separation
102 typedef Translator<string, BufferParams::ParagraphSeparation> ParSepTranslator;
105 ParSepTranslator const init_parseptranslator()
107 ParSepTranslator translator
108 (string_paragraph_separation[0], BufferParams::ParagraphIndentSeparation);
109 translator.addPair(string_paragraph_separation[1], BufferParams::ParagraphSkipSeparation);
114 ParSepTranslator const & parseptranslator()
116 static ParSepTranslator translator = init_parseptranslator();
122 typedef Translator<string, InsetQuotes::QuoteLanguage> QuotesLangTranslator;
125 QuotesLangTranslator const init_quoteslangtranslator()
127 QuotesLangTranslator translator
128 (string_quotes_language[0], InsetQuotes::EnglishQuotes);
129 translator.addPair(string_quotes_language[1], InsetQuotes::SwedishQuotes);
130 translator.addPair(string_quotes_language[2], InsetQuotes::GermanQuotes);
131 translator.addPair(string_quotes_language[3], InsetQuotes::PolishQuotes);
132 translator.addPair(string_quotes_language[4], InsetQuotes::FrenchQuotes);
133 translator.addPair(string_quotes_language[5], InsetQuotes::DanishQuotes);
138 QuotesLangTranslator const & quoteslangtranslator()
140 static QuotesLangTranslator translator = init_quoteslangtranslator();
146 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
149 static PaperSizeTranslator initPaperSizeTranslator()
151 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
152 translator.addPair(string_papersize[1], PAPER_CUSTOM);
153 translator.addPair(string_papersize[2], PAPER_USLETTER);
154 translator.addPair(string_papersize[3], PAPER_USLEGAL);
155 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
156 translator.addPair(string_papersize[5], PAPER_A3);
157 translator.addPair(string_papersize[6], PAPER_A4);
158 translator.addPair(string_papersize[7], PAPER_A5);
159 translator.addPair(string_papersize[8], PAPER_B3);
160 translator.addPair(string_papersize[9], PAPER_B4);
161 translator.addPair(string_papersize[10], PAPER_B5);
166 PaperSizeTranslator const & papersizetranslator()
168 static PaperSizeTranslator translator = initPaperSizeTranslator();
174 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
177 PaperOrientationTranslator const init_paperorientationtranslator()
179 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
180 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
185 PaperOrientationTranslator const & paperorientationtranslator()
187 static PaperOrientationTranslator translator = init_paperorientationtranslator();
193 typedef Translator<int, PageSides> SidesTranslator;
196 SidesTranslator const init_sidestranslator()
198 SidesTranslator translator(1, OneSide);
199 translator.addPair(2, TwoSides);
204 SidesTranslator const & sidestranslator()
206 static SidesTranslator translator = init_sidestranslator();
212 typedef Translator<int, BufferParams::Package> PackageTranslator;
215 PackageTranslator const init_packagetranslator()
217 PackageTranslator translator(0, BufferParams::package_off);
218 translator.addPair(1, BufferParams::package_auto);
219 translator.addPair(2, BufferParams::package_on);
224 PackageTranslator const & packagetranslator()
226 static PackageTranslator translator = init_packagetranslator();
232 typedef Translator<string, CiteEngine> CiteEngineTranslator;
235 CiteEngineTranslator const init_citeenginetranslator()
237 CiteEngineTranslator translator("basic", ENGINE_BASIC);
238 translator.addPair("natbib_numerical", ENGINE_NATBIB_NUMERICAL);
239 translator.addPair("natbib_authoryear", ENGINE_NATBIB_AUTHORYEAR);
240 translator.addPair("jurabib", ENGINE_JURABIB);
245 CiteEngineTranslator const & citeenginetranslator()
247 static CiteEngineTranslator translator = init_citeenginetranslator();
253 typedef Translator<string, Spacing::Space> SpaceTranslator;
256 SpaceTranslator const init_spacetranslator()
258 SpaceTranslator translator("default", Spacing::Default);
259 translator.addPair("single", Spacing::Single);
260 translator.addPair("onehalf", Spacing::Onehalf);
261 translator.addPair("double", Spacing::Double);
262 translator.addPair("other", Spacing::Other);
267 SpaceTranslator const & spacetranslator()
269 static SpaceTranslator translator = init_spacetranslator();
277 class BufferParams::Impl
282 AuthorList authorlist;
283 BranchList branchlist;
284 Bullet temp_bullets[4];
285 Bullet user_defined_bullets[4];
287 /** This is the amount of space used for paragraph_separation "skip",
288 * and for detached paragraphs in "indented" documents.
291 PDFOptions pdfoptions;
292 LayoutFileIndex baseClass_;
296 BufferParams::Impl::Impl()
297 : defskip(VSpace::MEDSKIP), baseClass_(string(""))
299 // set initial author
301 authorlist.record(Author(from_utf8(lyxrc.user_name), from_utf8(lyxrc.user_email)));
306 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
310 return new BufferParams::Impl(*ptr);
314 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
320 BufferParams::BufferParams()
323 setBaseClass(defaultBaseclass());
325 paragraph_separation = ParagraphIndentSeparation;
326 quotes_language = InsetQuotes::EnglishQuotes;
327 fontsize = "default";
330 papersize = PAPER_DEFAULT;
331 orientation = ORIENTATION_PORTRAIT;
332 use_geometry = false;
333 use_amsmath = package_auto;
334 use_esint = package_auto;
335 cite_engine_ = ENGINE_BASIC;
336 use_bibtopic = false;
337 trackChanges = false;
338 outputChanges = false;
339 use_default_options = true;
342 language = default_language;
343 fontsRoman = "default";
344 fontsSans = "default";
345 fontsTypewriter = "default";
346 fontsDefaultFamily = "default";
349 fontsSansScale = 100;
350 fontsTypewriterScale = 100;
352 graphicsDriver = "default";
355 listings_params = string();
356 pagestyle = "default";
358 for (int iter = 0; iter < 4; ++iter) {
359 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
360 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
365 docstring BufferParams::B_(string const & l10n) const
367 LASSERT(language, /**/);
368 return getMessages(language->code()).get(l10n);
372 AuthorList & BufferParams::authors()
374 return pimpl_->authorlist;
378 AuthorList const & BufferParams::authors() const
380 return pimpl_->authorlist;
384 BranchList & BufferParams::branchlist()
386 return pimpl_->branchlist;
390 BranchList const & BufferParams::branchlist() const
392 return pimpl_->branchlist;
396 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
398 LASSERT(index < 4, /**/);
399 return pimpl_->temp_bullets[index];
403 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
405 LASSERT(index < 4, /**/);
406 return pimpl_->temp_bullets[index];
410 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
412 LASSERT(index < 4, /**/);
413 return pimpl_->user_defined_bullets[index];
417 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
419 LASSERT(index < 4, /**/);
420 return pimpl_->user_defined_bullets[index];
424 Spacing & BufferParams::spacing()
426 return pimpl_->spacing;
430 Spacing const & BufferParams::spacing() const
432 return pimpl_->spacing;
436 PDFOptions & BufferParams::pdfoptions()
438 return pimpl_->pdfoptions;
442 PDFOptions const & BufferParams::pdfoptions() const
444 return pimpl_->pdfoptions;
448 VSpace const & BufferParams::getDefSkip() const
450 return pimpl_->defskip;
454 void BufferParams::setDefSkip(VSpace const & vs)
456 pimpl_->defskip = vs;
460 string BufferParams::readToken(Lexer & lex, string const & token,
461 FileName const & filepath)
463 if (token == "\\textclass") {
465 string const classname = lex.getString();
466 // if there exists a local layout file, ignore the system one
467 // NOTE: in this case, the textclass (.cls file) is assumed to be available.
469 LayoutFileList & bcl = LayoutFileList::get();
470 if (tcp.empty() && !filepath.empty())
471 tcp = bcl.addLocalLayout(classname, filepath.absFilename());
475 setBaseClass(classname);
476 // We assume that a tex class exists for local or unknown layouts so this warning
477 // will only be given for system layouts.
478 if (!baseClass()->isTeXClassAvailable()) {
479 docstring const msg =
480 bformat(_("The layout file requested by this document,\n"
482 "is not usable. This is probably because a LaTeX\n"
483 "class or style file required by it is not\n"
484 "available. See the Customization documentation\n"
485 "for more information.\n"), from_utf8(classname));
486 frontend::Alert::warning(_("Document class not available"),
487 msg + _("LyX will not be able to produce output."));
489 } else if (token == "\\begin_preamble") {
491 } else if (token == "\\begin_local_layout") {
492 readLocalLayout(lex);
493 } else if (token == "\\begin_modules") {
495 } else if (token == "\\begin_removed_modules") {
496 readRemovedModules(lex);
497 } else if (token == "\\options") {
499 options = lex.getString();
500 } else if (token == "\\use_default_options") {
501 lex >> use_default_options;
502 } else if (token == "\\master") {
504 master = lex.getString();
505 } else if (token == "\\language") {
507 } else if (token == "\\inputencoding") {
509 } else if (token == "\\graphics") {
510 readGraphicsDriver(lex);
511 } else if (token == "\\font_roman") {
513 } else if (token == "\\font_sans") {
515 } else if (token == "\\font_typewriter") {
516 lex >> fontsTypewriter;
517 } else if (token == "\\font_default_family") {
518 lex >> fontsDefaultFamily;
519 } else if (token == "\\font_sc") {
521 } else if (token == "\\font_osf") {
523 } else if (token == "\\font_sf_scale") {
524 lex >> fontsSansScale;
525 } else if (token == "\\font_tt_scale") {
526 lex >> fontsTypewriterScale;
527 } else if (token == "\\font_cjk") {
529 } else if (token == "\\paragraph_separation") {
532 paragraph_separation = parseptranslator().find(parsep);
533 } else if (token == "\\defskip") {
535 string defskip = lex.getString();
536 if (defskip == "defskip")
539 pimpl_->defskip = VSpace(defskip);
540 } else if (token == "\\quotes_language") {
543 quotes_language = quoteslangtranslator().find(quotes_lang);
544 } else if (token == "\\papersize") {
547 papersize = papersizetranslator().find(ppsize);
548 } else if (token == "\\use_geometry") {
550 } else if (token == "\\use_amsmath") {
553 use_amsmath = packagetranslator().find(use_ams);
554 } else if (token == "\\use_esint") {
557 use_esint = packagetranslator().find(useesint);
558 } else if (token == "\\cite_engine") {
561 cite_engine_ = citeenginetranslator().find(engine);
562 } else if (token == "\\use_bibtopic") {
564 } else if (token == "\\tracking_changes") {
566 } else if (token == "\\output_changes") {
567 lex >> outputChanges;
568 } else if (token == "\\branch") {
570 docstring branch = lex.getDocString();
571 branchlist().add(branch);
574 string const tok = lex.getString();
575 if (tok == "\\end_branch")
577 Branch * branch_ptr = branchlist().find(branch);
578 if (tok == "\\selected") {
581 branch_ptr->setSelected(lex.getInteger());
583 // not yet operational
584 if (tok == "\\color") {
586 string color = lex.getString();
588 branch_ptr->setColor(color);
589 // Update also the Color table:
591 color = lcolor.getX11Name(Color_background);
593 lcolor.setColor(to_utf8(branch), color);
597 } else if (token == "\\author") {
599 istringstream ss(lex.getString());
602 author_map.push_back(pimpl_->authorlist.record(a));
603 } else if (token == "\\paperorientation") {
606 orientation = paperorientationtranslator().find(orient);
607 } else if (token == "\\paperwidth") {
609 } else if (token == "\\paperheight") {
611 } else if (token == "\\leftmargin") {
613 } else if (token == "\\topmargin") {
615 } else if (token == "\\rightmargin") {
617 } else if (token == "\\bottommargin") {
619 } else if (token == "\\headheight") {
621 } else if (token == "\\headsep") {
623 } else if (token == "\\footskip") {
625 } else if (token == "\\columnsep") {
627 } else if (token == "\\paperfontsize") {
629 } else if (token == "\\papercolumns") {
631 } else if (token == "\\listings_params") {
634 listings_params = InsetListingsParams(par).params();
635 } else if (token == "\\papersides") {
638 sides = sidestranslator().find(psides);
639 } else if (token == "\\paperpagestyle") {
641 } else if (token == "\\bullet") {
643 } else if (token == "\\bulletLaTeX") {
644 readBulletsLaTeX(lex);
645 } else if (token == "\\secnumdepth") {
647 } else if (token == "\\tocdepth") {
649 } else if (token == "\\spacing") {
653 if (nspacing == "other") {
656 spacing().set(spacetranslator().find(nspacing), tmp_val);
657 } else if (token == "\\float_placement") {
658 lex >> float_placement;
660 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
661 string toktmp = pdfoptions().readToken(lex, token);
662 if (!toktmp.empty()) {
663 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
668 lyxerr << "BufferParams::readToken(): Unknown token: " <<
677 void BufferParams::writeFile(ostream & os) const
679 // The top of the file is written by the buffer.
680 // Prints out the buffer info into the .lyx file given by file
683 os << "\\textclass " << baseClass()->name() << '\n';
686 if (!preamble.empty()) {
687 // remove '\n' from the end of preamble
688 string const tmppreamble = rtrim(preamble, "\n");
689 os << "\\begin_preamble\n"
691 << "\n\\end_preamble\n";
695 if (!options.empty()) {
696 os << "\\options " << options << '\n';
699 // use the class options defined in the layout?
700 os << "\\use_default_options "
701 << convert<string>(use_default_options) << "\n";
703 // the master document
704 if (!master.empty()) {
705 os << "\\master " << master << '\n';
709 if (!removedModules_.empty()) {
710 os << "\\begin_removed_modules" << '\n';
711 set<string>::const_iterator it = removedModules_.begin();
712 set<string>::const_iterator en = removedModules_.end();
713 for (; it != en; it++)
715 os << "\\end_removed_modules" << '\n';
719 if (!layoutModules_.empty()) {
720 os << "\\begin_modules" << '\n';
721 LayoutModuleList::const_iterator it = layoutModules_.begin();
722 LayoutModuleList::const_iterator en = layoutModules_.end();
723 for (; it != en; it++)
725 os << "\\end_modules" << '\n';
728 // local layout information
729 if (!local_layout.empty()) {
730 // remove '\n' from the end
731 string const tmplocal = rtrim(local_layout, "\n");
732 os << "\\begin_local_layout\n"
734 << "\n\\end_local_layout\n";
737 // then the text parameters
738 if (language != ignore_language)
739 os << "\\language " << language->lang() << '\n';
740 os << "\\inputencoding " << inputenc
741 << "\n\\font_roman " << fontsRoman
742 << "\n\\font_sans " << fontsSans
743 << "\n\\font_typewriter " << fontsTypewriter
744 << "\n\\font_default_family " << fontsDefaultFamily
745 << "\n\\font_sc " << convert<string>(fontsSC)
746 << "\n\\font_osf " << convert<string>(fontsOSF)
747 << "\n\\font_sf_scale " << fontsSansScale
748 << "\n\\font_tt_scale " << fontsTypewriterScale
750 if (!fontsCJK.empty()) {
751 os << "\\font_cjk " << fontsCJK << '\n';
753 os << "\n\\graphics " << graphicsDriver << '\n';
755 if (!float_placement.empty()) {
756 os << "\\float_placement " << float_placement << '\n';
758 os << "\\paperfontsize " << fontsize << '\n';
760 spacing().writeFile(os);
761 pdfoptions().writeFile(os);
763 os << "\\papersize " << string_papersize[papersize]
764 << "\n\\use_geometry " << convert<string>(use_geometry)
765 << "\n\\use_amsmath " << use_amsmath
766 << "\n\\use_esint " << use_esint
767 << "\n\\cite_engine " << citeenginetranslator().find(cite_engine_)
768 << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
769 << "\n\\paperorientation " << string_orientation[orientation]
772 BranchList::const_iterator it = branchlist().begin();
773 BranchList::const_iterator end = branchlist().end();
774 for (; it != end; ++it) {
775 os << "\\branch " << to_utf8(it->branch())
776 << "\n\\selected " << it->isSelected()
777 << "\n\\color " << lyx::X11hexname(it->color())
782 if (!paperwidth.empty())
783 os << "\\paperwidth "
784 << VSpace(paperwidth).asLyXCommand() << '\n';
785 if (!paperheight.empty())
786 os << "\\paperheight "
787 << VSpace(paperheight).asLyXCommand() << '\n';
788 if (!leftmargin.empty())
789 os << "\\leftmargin "
790 << VSpace(leftmargin).asLyXCommand() << '\n';
791 if (!topmargin.empty())
793 << VSpace(topmargin).asLyXCommand() << '\n';
794 if (!rightmargin.empty())
795 os << "\\rightmargin "
796 << VSpace(rightmargin).asLyXCommand() << '\n';
797 if (!bottommargin.empty())
798 os << "\\bottommargin "
799 << VSpace(bottommargin).asLyXCommand() << '\n';
800 if (!headheight.empty())
801 os << "\\headheight "
802 << VSpace(headheight).asLyXCommand() << '\n';
803 if (!headsep.empty())
805 << VSpace(headsep).asLyXCommand() << '\n';
806 if (!footskip.empty())
808 << VSpace(footskip).asLyXCommand() << '\n';
809 if (!columnsep.empty())
811 << VSpace(columnsep).asLyXCommand() << '\n';
812 os << "\\secnumdepth " << secnumdepth
813 << "\n\\tocdepth " << tocdepth
814 << "\n\\paragraph_separation "
815 << string_paragraph_separation[paragraph_separation]
816 << "\n\\defskip " << getDefSkip().asLyXCommand()
817 << "\n\\quotes_language "
818 << string_quotes_language[quotes_language]
819 << "\n\\papercolumns " << columns
820 << "\n\\papersides " << sides
821 << "\n\\paperpagestyle " << pagestyle << '\n';
822 if (!listings_params.empty())
823 os << "\\listings_params \"" <<
824 InsetListingsParams(listings_params).encodedString() << "\"\n";
825 for (int i = 0; i < 4; ++i) {
826 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
827 if (user_defined_bullet(i).getFont() != -1) {
828 os << "\\bullet " << i << " "
829 << user_defined_bullet(i).getFont() << " "
830 << user_defined_bullet(i).getCharacter() << " "
831 << user_defined_bullet(i).getSize() << "\n";
835 os << "\\bulletLaTeX " << i << " \""
836 << lyx::to_ascii(user_defined_bullet(i).getText())
842 os << "\\tracking_changes " << convert<string>(trackChanges) << "\n";
843 os << "\\output_changes " << convert<string>(outputChanges) << "\n";
845 AuthorList::Authors::const_iterator a_it = pimpl_->authorlist.begin();
846 AuthorList::Authors::const_iterator a_end = pimpl_->authorlist.end();
847 for (; a_it != a_end; ++a_it) {
848 if (a_it->second.used())
849 os << "\\author " << a_it->second << "\n";
851 os << "\\author " << Author() << "\n";
856 void BufferParams::validate(LaTeXFeatures & features) const
858 features.require(documentClass().requires());
861 bool dvipost = LaTeXFeatures::isAvailable("dvipost");
862 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
863 LaTeXFeatures::isAvailable("xcolor");
865 switch (features.runparams().flavor) {
866 case OutputParams::LATEX:
868 features.require("ct-dvipost");
869 features.require("dvipost");
870 } else if (xcolorulem) {
871 features.require("ct-xcolor-ulem");
872 features.require("ulem");
873 features.require("xcolor");
875 features.require("ct-none");
878 case OutputParams::PDFLATEX:
880 features.require("ct-xcolor-ulem");
881 features.require("ulem");
882 features.require("xcolor");
883 // improves color handling in PDF output
884 features.require("pdfcolmk");
886 features.require("ct-none");
894 // Floats with 'Here definitely' as default setting.
895 if (float_placement.find('H') != string::npos)
896 features.require("float");
898 // AMS Style is at document level
899 if (use_amsmath == package_on
900 || documentClass().provides("amsmath"))
901 features.require("amsmath");
902 if (use_esint == package_on)
903 features.require("esint");
905 // Document-level line spacing
906 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
907 features.require("setspace");
909 // the bullet shapes are buffer level not paragraph level
910 // so they are tested here
911 for (int i = 0; i < 4; ++i) {
912 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
914 int const font = user_defined_bullet(i).getFont();
916 int const c = user_defined_bullet(i).getCharacter();
922 features.require("latexsym");
924 } else if (font == 1) {
925 features.require("amssymb");
926 } else if (font >= 2 && font <= 5) {
927 features.require("pifont");
931 if (pdfoptions().use_hyperref) {
932 features.require("hyperref");
933 // due to interferences with babel and hyperref, the color package has to
934 // be loaded after hyperref when hyperref is used with the colorlinks
935 // option, see http://bugzilla.lyx.org/show_bug.cgi?id=5291
936 if (pdfoptions().colorlinks)
937 features.require("color");
940 if (language->lang() == "vietnamese")
941 features.require("vietnamese");
942 else if (language->lang() == "japanese")
943 features.require("japanese");
947 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
948 TexRow & texrow) const
950 os << "\\documentclass";
952 DocumentClass const & tclass = documentClass();
954 ostringstream clsoptions; // the document class options.
956 if (tokenPos(tclass.opt_fontsize(),
957 '|', fontsize) >= 0) {
958 // only write if existing in list (and not default)
959 clsoptions << fontsize << "pt,";
962 // custom, A3, B3 and B4 paper sizes need geometry
963 bool nonstandard_papersize = papersize == PAPER_B3
964 || papersize == PAPER_B4
965 || papersize == PAPER_A3
966 || papersize == PAPER_CUSTOM;
971 clsoptions << "a4paper,";
974 clsoptions << "letterpaper,";
977 clsoptions << "a5paper,";
980 clsoptions << "b5paper,";
982 case PAPER_USEXECUTIVE:
983 clsoptions << "executivepaper,";
986 clsoptions << "legalpaper,";
998 if (sides != tclass.sides()) {
1001 clsoptions << "oneside,";
1004 clsoptions << "twoside,";
1010 if (columns != tclass.columns()) {
1012 clsoptions << "twocolumn,";
1014 clsoptions << "onecolumn,";
1018 && orientation == ORIENTATION_LANDSCAPE)
1019 clsoptions << "landscape,";
1021 // language should be a parameter to \documentclass
1022 if (language->babel() == "hebrew"
1023 && default_language->babel() != "hebrew")
1024 // This seems necessary
1025 features.useLanguage(default_language);
1027 ostringstream language_options;
1028 bool const use_babel = features.useBabel();
1030 language_options << features.getLanguages();
1031 if (!language->babel().empty()) {
1032 if (!language_options.str().empty())
1033 language_options << ',';
1034 language_options << language->babel();
1036 // if Vietnamese is used, babel must directly be loaded
1037 // with language options, not in the class options, see
1038 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1039 size_t viet = language_options.str().find("vietnam");
1040 // viet = string::npos when not found
1041 // the same is for all other languages that are not directly supported by
1042 // babel, but where LaTeX-packages add babel support.
1043 // this is currently the case for Latvian, Lithuanian, and Mongolian
1044 size_t latvian = language_options.str().find("latvian");
1045 size_t lithu = language_options.str().find("lithuanian");
1046 size_t mongo = language_options.str().find("mongolian");
1047 // if Japanese is used, babel must directly be loaded
1048 // with language options, not in the class options, see
1049 // http://bugzilla.lyx.org/show_bug.cgi?id=4597#c4
1050 size_t japan = language_options.str().find("japanese");
1051 if (lyxrc.language_global_options && !language_options.str().empty()
1052 && viet == string::npos && japan == string::npos
1053 && latvian == string::npos && lithu == string::npos
1054 && mongo == string::npos)
1055 clsoptions << language_options.str() << ',';
1058 // the predefined options from the layout
1059 if (use_default_options && !tclass.options().empty())
1060 clsoptions << tclass.options() << ',';
1062 // the user-defined options
1063 if (!options.empty()) {
1064 clsoptions << options << ',';
1067 string strOptions(clsoptions.str());
1068 if (!strOptions.empty()) {
1069 strOptions = rtrim(strOptions, ",");
1071 os << '[' << from_utf8(strOptions) << ']';
1074 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1076 // end of \documentclass defs
1078 // font selection must be done before loading fontenc.sty
1079 string const fonts =
1080 loadFonts(fontsRoman, fontsSans,
1081 fontsTypewriter, fontsSC, fontsOSF,
1082 fontsSansScale, fontsTypewriterScale);
1083 if (!fonts.empty()) {
1084 os << from_ascii(fonts);
1087 if (fontsDefaultFamily != "default")
1088 os << "\\renewcommand{\\familydefault}{\\"
1089 << from_ascii(fontsDefaultFamily) << "}\n";
1091 // set font encoding
1092 // this one is not per buffer
1093 // for arabic_arabi and farsi we also need to load the LAE and
1095 if (lyxrc.fontenc != "default" && language->lang() != "japanese") {
1096 if (language->lang() == "arabic_arabi"
1097 || language->lang() == "farsi") {
1098 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
1099 << ",LFE,LAE]{fontenc}\n";
1102 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
1108 // handle inputenc etc.
1109 writeEncodingPreamble(os, features, texrow);
1111 if (!listings_params.empty() || features.isRequired("listings")) {
1112 os << "\\usepackage{listings}\n";
1115 if (!listings_params.empty()) {
1117 // do not test validity because listings_params is
1118 // supposed to be valid
1120 InsetListingsParams(listings_params).separatedParams(true);
1121 // we can't support all packages, but we should load the color package
1122 if (par.find("\\color", 0) != string::npos)
1123 features.require("color");
1124 os << from_utf8(par);
1125 // count the number of newlines
1126 for (size_t i = 0; i < par.size(); ++i)
1132 if (use_geometry || nonstandard_papersize) {
1133 odocstringstream ods;
1134 if (!getGraphicsDriver("geometry").empty())
1135 ods << getGraphicsDriver("geometry");
1136 if (orientation == ORIENTATION_LANDSCAPE)
1137 ods << ",landscape";
1138 switch (papersize) {
1140 if (!paperwidth.empty())
1141 ods << ",paperwidth="
1142 << from_ascii(paperwidth);
1143 if (!paperheight.empty())
1144 ods << ",paperheight="
1145 << from_ascii(paperheight);
1147 case PAPER_USLETTER:
1148 ods << ",letterpaper";
1151 ods << ",legalpaper";
1153 case PAPER_USEXECUTIVE:
1154 ods << ",executivepaper";
1175 // default papersize ie PAPER_DEFAULT
1176 switch (lyxrc.default_papersize) {
1177 case PAPER_DEFAULT: // keep compiler happy
1178 case PAPER_USLETTER:
1179 ods << ",letterpaper";
1182 ods << ",legalpaper";
1184 case PAPER_USEXECUTIVE:
1185 ods << ",executivepaper";
1205 docstring const g_options = trim(ods.str(), ",");
1206 os << "\\usepackage";
1207 if (!g_options.empty())
1208 os << '[' << g_options << ']';
1209 os << "{geometry}\n";
1211 os << "\\geometry{verbose";
1212 if (!topmargin.empty())
1213 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1214 if (!bottommargin.empty())
1215 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1216 if (!leftmargin.empty())
1217 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1218 if (!rightmargin.empty())
1219 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1220 if (!headheight.empty())
1221 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1222 if (!headsep.empty())
1223 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1224 if (!footskip.empty())
1225 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1226 if (!columnsep.empty())
1227 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1230 } else if (orientation == ORIENTATION_LANDSCAPE) {
1231 features.require("papersize");
1234 if (tokenPos(tclass.opt_pagestyle(),
1235 '|', pagestyle) >= 0) {
1236 if (pagestyle == "fancy") {
1237 os << "\\usepackage{fancyhdr}\n";
1240 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1244 // Only if class has a ToC hierarchy
1245 if (tclass.hasTocLevels()) {
1246 if (secnumdepth != tclass.secnumdepth()) {
1247 os << "\\setcounter{secnumdepth}{"
1252 if (tocdepth != tclass.tocdepth()) {
1253 os << "\\setcounter{tocdepth}{"
1260 if (paragraph_separation) {
1261 switch (getDefSkip().kind()) {
1262 case VSpace::SMALLSKIP:
1263 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1265 case VSpace::MEDSKIP:
1266 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1268 case VSpace::BIGSKIP:
1269 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1271 case VSpace::LENGTH:
1272 os << "\\setlength{\\parskip}{"
1273 << from_utf8(getDefSkip().length().asLatexString())
1276 default: // should never happen // Then delete it.
1277 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1282 os << "\\setlength{\\parindent}{0pt}\n";
1286 // Now insert the LyX specific LaTeX commands...
1287 docstring lyxpreamble;
1289 // due to interferences with babel and hyperref, the color package has to
1290 // be loaded (when it is not already loaded) before babel when hyperref
1291 // is used with the colorlinks option, see
1292 // http://bugzilla.lyx.org/show_bug.cgi?id=5291
1293 // we decided therefore to load color always before babel, see
1294 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
1295 lyxpreamble += from_ascii(features.getColorOptions());
1297 // If we use hyperref, jurabib, japanese, or vietnamese, we have to call babel before them.
1299 && (features.isRequired("jurabib")
1300 || features.isRequired("hyperref")
1301 || features.isRequired("vietnamese")
1302 || features.isRequired("japanese") ) ) {
1304 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1305 lyxpreamble += from_utf8(features.getBabelOptions()) + '\n';
1308 // The optional packages;
1309 lyxpreamble += from_ascii(features.getPackages());
1312 lyxpreamble += from_utf8(spacing().writePreamble(tclass.provides("SetSpace")));
1315 // * Hyperref manual: "Make sure it comes last of your loaded
1316 // packages, to give it a fighting chance of not being over-written,
1317 // since its job is to redefine many LaTeX commands."
1318 // * Email from Heiko Oberdiek: "It is usually better to load babel
1319 // before hyperref. Then hyperref has a chance to detect babel.
1320 // * Has to be loaded before the "LyX specific LaTeX commands" to
1321 // avoid errors with algorithm floats.
1322 // use hyperref explicitely when it is required
1323 if (features.isRequired("hyperref")) {
1324 odocstringstream oss;
1325 pdfoptions().writeLaTeX(oss, documentClass().provides("hyperref"));
1326 lyxpreamble += oss.str();
1329 // Will be surrounded by \makeatletter and \makeatother when needed
1330 docstring atlyxpreamble;
1332 // Some macros LyX will need
1333 docstring tmppreamble(from_ascii(features.getMacros()));
1335 if (!tmppreamble.empty())
1336 atlyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1337 "LyX specific LaTeX commands.\n"
1338 + tmppreamble + '\n';
1340 // the text class specific preamble
1341 tmppreamble = features.getTClassPreamble();
1342 if (!tmppreamble.empty())
1343 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1344 "Textclass specific LaTeX commands.\n"
1345 + tmppreamble + '\n';
1347 /* the user-defined preamble */
1348 if (!preamble.empty())
1350 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1351 "User specified LaTeX commands.\n"
1352 + from_utf8(preamble) + '\n';
1354 // subfig loads internally the LaTeX package "caption". As
1355 // caption is a very popular package, users will load it in
1356 // the preamble. Therefore we must load subfig behind the
1357 // user-defined preamble and check if the caption package was
1358 // loaded or not. For the case that caption is loaded before
1359 // subfig, there is the subfig option "caption=false". This
1360 // option also works when a koma-script class is used and
1361 // koma's own caption commands are used instead of caption. We
1362 // use \PassOptionsToPackage here because the user could have
1363 // already loaded subfig in the preamble.
1364 if (features.isRequired("subfig")) {
1365 atlyxpreamble += "\\@ifundefined{showcaptionsetup}{}{%\n"
1366 " \\PassOptionsToPackage{caption=false}{subfig}}\n"
1367 "\\usepackage{subfig}\n";
1370 // Itemize bullet settings need to be last in case the user
1371 // defines their own bullets that use a package included
1372 // in the user-defined preamble -- ARRae
1373 // Actually it has to be done much later than that
1374 // since some packages like frenchb make modifications
1375 // at \begin{document} time -- JMarc
1376 docstring bullets_def;
1377 for (int i = 0; i < 4; ++i) {
1378 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1379 if (bullets_def.empty())
1380 bullets_def += "\\AtBeginDocument{\n";
1381 bullets_def += " \\def\\labelitemi";
1383 // `i' is one less than the item to modify
1390 bullets_def += "ii";
1396 bullets_def += '{' +
1397 user_defined_bullet(i).getText()
1402 if (!bullets_def.empty())
1403 atlyxpreamble += bullets_def + "}\n\n";
1405 if (atlyxpreamble.find(from_ascii("@")) != docstring::npos)
1406 lyxpreamble += "\n\\makeatletter\n"
1407 + atlyxpreamble + "\\makeatother\n\n";
1409 lyxpreamble += '\n' + atlyxpreamble;
1411 // We try to load babel late, in case it interferes with other packages.
1412 // Jurabib and Hyperref have to be called after babel, though.
1413 if (use_babel && !features.isRequired("jurabib")
1414 && !features.isRequired("hyperref")
1415 && !features.isRequired("vietnamese")
1416 && !features.isRequired("japanese")) {
1418 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1419 lyxpreamble += from_utf8(features.getBabelOptions()) + '\n';
1423 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1424 for (int j = 0; j != nlines; ++j) {
1433 void BufferParams::useClassDefaults()
1435 DocumentClass const & tclass = documentClass();
1437 sides = tclass.sides();
1438 columns = tclass.columns();
1439 pagestyle = tclass.pagestyle();
1440 use_default_options = true;
1441 // Only if class has a ToC hierarchy
1442 if (tclass.hasTocLevels()) {
1443 secnumdepth = tclass.secnumdepth();
1444 tocdepth = tclass.tocdepth();
1449 bool BufferParams::hasClassDefaults() const
1451 DocumentClass const & tclass = documentClass();
1453 return sides == tclass.sides()
1454 && columns == tclass.columns()
1455 && pagestyle == tclass.pagestyle()
1456 && use_default_options
1457 && secnumdepth == tclass.secnumdepth()
1458 && tocdepth == tclass.tocdepth();
1462 DocumentClass const & BufferParams::documentClass() const
1468 DocumentClass const * BufferParams::documentClassPtr() const {
1473 void BufferParams::setDocumentClass(DocumentClass const * const tc) {
1474 // evil, but this function is evil
1475 doc_class_ = const_cast<DocumentClass *>(tc);
1479 bool BufferParams::removeBadModules()
1481 // we'll write a new list of modules, since we can't just remove them,
1482 // as that would invalidate our iterators
1483 LayoutModuleList oldModules = getModules();
1484 clearLayoutModules();
1486 LayoutModuleList const & provmods = baseClass()->providedModules();
1487 LayoutModuleList const & exclmods = baseClass()->excludedModules();
1488 bool consistent = true; // set to false if we have to do anything
1490 LayoutModuleList::const_iterator oit = oldModules.begin();
1491 LayoutModuleList::const_iterator const oen = oldModules.end();
1492 for (; oit != oen; ++oit) {
1493 string const & modname = *oit;
1494 // skip modules that the class provides
1495 if (find(provmods.begin(), provmods.end(), modname) != provmods.end()) {
1496 LYXERR0("Module `" << modname << "' dropped because provided by document class.");
1500 // are we excluded by the document class?
1501 if (find(exclmods.begin(), exclmods.end(), modname) != exclmods.end()) {
1502 LYXERR0("Module `" << modname << "' dropped because excluded by document class.");
1506 // determine whether some provided module excludes us or we exclude it
1507 LayoutModuleList::const_iterator pit = provmods.begin();
1508 LayoutModuleList::const_iterator const pen = provmods.end();
1509 bool excluded = false;
1510 for (; !excluded && pit != pen; ++pit) {
1511 if (!LyXModule::areCompatible(modname, *pit)) {
1512 LYXERR0("Module " << modname <<
1513 " dropped becuase it conflicts with provided module `" << *pit << "'.");
1520 layoutModules_.push_back(modname);
1526 void BufferParams::addDefaultModules()
1528 // add any default modules not already in use
1529 LayoutModuleList const & mods = baseClass()->defaultModules();
1530 LayoutModuleList::const_iterator mit = mods.begin();
1531 LayoutModuleList::const_iterator men = mods.end();
1533 // We want to insert the default modules at the beginning of
1534 // the list, but also to insert them in the correct order.
1535 // The obvious thing to do would be to collect them and then
1536 // insert them, but that doesn't work because a later default
1537 // module may require an earlier one, and then the test below
1538 // moduleCanBeAdded(modname)
1539 // will fail. So we have to do it a more complicated way.
1540 LayoutModuleList::iterator insertpos = layoutModules_.begin();
1543 for (; mit != men; mit++) {
1544 string const & modName = *mit;
1545 // make sure the user hasn't removed it
1546 if (find(removedModules_.begin(), removedModules_.end(), modName) !=
1547 removedModules_.end()) {
1548 LYXERR(Debug::TCLASS, "Default module `" << modName <<
1549 "' not added because removed by user.");
1553 if (!moduleCanBeAdded(modName)) {
1554 // FIXME This could be because it's already present, so we should
1555 // probably return something indicating that.
1556 LYXERR(Debug::TCLASS, "Default module `" << modName <<
1557 "' could not be added.");
1560 LYXERR(Debug::TCLASS, "Default module `" << modName << "' added.");
1561 layoutModules_.insert(insertpos, modName);
1562 // now we reset insertpos
1564 insertpos = layoutModules_.begin();
1565 advance(insertpos, numinserts);
1570 bool BufferParams::checkModuleConsistency() {
1571 bool consistent = true;
1572 // Perform a consistency check on the set of modules. We need to make
1573 // sure that none of the modules exclude each other and that requires
1575 LayoutModuleList oldModules = getModules();
1576 clearLayoutModules();
1577 LayoutModuleList::const_iterator oit = oldModules.begin();
1578 LayoutModuleList::const_iterator oen = oldModules.end();
1579 LayoutModuleList const & provmods = baseClass()->providedModules();
1580 for (; oit != oen; ++oit) {
1581 string const & modname = *oit;
1582 bool excluded = false;
1583 // Determine whether some prior module excludes us, or we exclude it
1584 LayoutModuleList::const_iterator lit = layoutModules_.begin();
1585 LayoutModuleList::const_iterator len = layoutModules_.end();
1586 for (; !excluded && lit != len; ++lit) {
1587 if (!LyXModule::areCompatible(modname, *lit)) {
1589 LYXERR0("Module " << modname <<
1590 " dropped because it is excluded by prior module " << *lit);
1598 // determine whether some provided module or some prior module
1599 // satisfies our requirements
1600 LyXModule const * const oldmod = moduleList[modname];
1602 LYXERR0("Default module " << modname <<
1603 " added although it is unavailable and can't check requirements.");
1607 vector<string> const & reqs = oldmod->getRequiredModules();
1608 if (!reqs.empty()) {
1609 // we now set excluded to true, meaning that we haven't
1610 // yet found a required module.
1612 vector<string>::const_iterator rit = reqs.begin();
1613 vector<string>::const_iterator ren = reqs.end();
1614 for (; rit != ren; ++rit) {
1615 string const reqmod = *rit;
1616 if (find(provmods.begin(), provmods.end(), reqmod) !=
1621 if (find(layoutModules_.begin(), layoutModules_.end(), reqmod) !=
1622 layoutModules_.end()) {
1630 LYXERR0("Module " << modname << " dropped because requirements not met.");
1632 LYXERR(Debug::TCLASS, "Module " << modname << " passed consistency check.");
1633 layoutModules_.push_back(modname);
1640 bool BufferParams::setBaseClass(string const & classname)
1642 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
1643 LayoutFileList & bcl = LayoutFileList::get();
1644 if (!bcl.haveClass(classname)) {
1646 bformat(_("The document class %1$s could not be found. "
1647 "A default textclass with default layouts will be used. "
1648 "LyX might not be able to produce output unless a correct "
1649 "textclass is selected from the document settings dialog."),
1650 from_utf8(classname));
1651 frontend::Alert::error(_("Document class not found"), s);
1652 bcl.addEmptyClass(classname);
1655 bool const success = bcl[classname].load();
1658 bformat(_("The document class %1$s could not be loaded."),
1659 from_utf8(classname));
1660 frontend::Alert::error(_("Could not load class"), s);
1664 pimpl_->baseClass_ = classname;
1665 // the previous document class may have loaded some modules that the
1666 // new one excludes, and the new class may provide, etc, some that
1667 // conflict with ones that were already loaded. So we need to go
1668 // through the list and fix everything. I suppose there are various
1669 // ways this could be done, but the following seems to work at the
1670 // moment. (Thanks to Philippe Charpentier for helping work out all
1673 // first, we remove any modules the new document class itself provides,
1674 // those it excludes, and those that conflict with ones it excludes.
1675 // this has to be done first because, otherwise, a module we're about
1676 // to remove could prevent a default module from being added.
1678 // next, we add any default modules the new class provides.
1679 addDefaultModules();
1680 // finally, we perform a general consistency check on the set of
1682 checkModuleConsistency();
1683 // FIXME removeBadModules() and checkModuleConsistency() both return
1684 // a boolean indicating whether something had to be changed. It might
1685 // be worth popping a message to the user if so.
1691 LayoutFile const * BufferParams::baseClass() const
1693 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
1694 return &(LayoutFileList::get()[pimpl_->baseClass_]);
1700 LayoutFileIndex const & BufferParams::baseClassID() const
1702 return pimpl_->baseClass_;
1706 void BufferParams::makeDocumentClass()
1711 doc_class_ = &(DocumentClassBundle::get().newClass(*baseClass()));
1713 // FIXME It might be worth loading the children's modules here,
1714 // just as we load their bibliographies and such, instead of just
1715 // doing a check in InsetInclude.
1716 LayoutModuleList::const_iterator it = layoutModules_.begin();
1717 for (; it != layoutModules_.end(); it++) {
1718 string const modName = *it;
1719 LyXModule * lm = moduleList[modName];
1721 docstring const msg =
1722 bformat(_("The module %1$s has been requested by\n"
1723 "this document but has not been found in the list of\n"
1724 "available modules. If you recently installed it, you\n"
1725 "probably need to reconfigure LyX.\n"), from_utf8(modName));
1726 frontend::Alert::warning(_("Module not available"),
1727 msg + _("Some layouts may not be available."));
1728 LYXERR0("BufferParams::makeDocumentClass(): Module " <<
1729 modName << " requested but not found in module list.");
1732 if (!lm->isAvailable()) {
1733 docstring const msg =
1734 bformat(_("The module %1$s requires a package that is\n"
1735 "not available in your LaTeX installation. LaTeX output\n"
1736 "may not be possible.\n"), from_utf8(modName));
1737 frontend::Alert::warning(_("Package not available"), msg);
1739 FileName layout_file = libFileSearch("layouts", lm->getFilename());
1740 if (!doc_class_->read(layout_file, TextClass::MODULE)) {
1741 docstring const msg =
1742 bformat(_("Error reading module %1$s\n"), from_utf8(modName));
1743 frontend::Alert::warning(_("Read Error"), msg);
1746 if (!local_layout.empty()) {
1747 if (!doc_class_->read(local_layout, TextClass::MODULE)) {
1748 docstring const msg = _("Error reading internal layout information");
1749 frontend::Alert::warning(_("Read Error"), msg);
1755 bool BufferParams::moduleCanBeAdded(string const & modName) const
1757 // Is the module already present?
1758 LayoutModuleList::const_iterator it = layoutModules_.begin();
1759 LayoutModuleList::const_iterator end = layoutModules_.end();
1760 for (; it != end; it++)
1764 LyXModule const * const lm = moduleList[modName];
1768 // Is this module explicitly excluded by the document class?
1769 LayoutModuleList::const_iterator const exclmodstart =
1770 baseClass()->excludedModules().begin();
1771 LayoutModuleList::const_iterator const exclmodend =
1772 baseClass()->excludedModules().end();
1773 if (find(exclmodstart, exclmodend, modName) != exclmodend)
1776 // Is this module already provided by the document class?
1777 LayoutModuleList::const_iterator const provmodstart =
1778 baseClass()->providedModules().begin();
1779 LayoutModuleList::const_iterator const provmodend =
1780 baseClass()->providedModules().end();
1781 if (find(provmodstart, provmodend, modName) != provmodend)
1784 // Check for conflicts with used modules
1785 // first the provided modules...
1786 LayoutModuleList::const_iterator provmodit = provmodstart;
1787 for (; provmodit != provmodend; ++provmodit) {
1788 if (!LyXModule::areCompatible(modName, *provmodit))
1791 // and then the selected modules
1792 LayoutModuleList::const_iterator mit = getModules().begin();
1793 LayoutModuleList::const_iterator const men = getModules().end();
1794 for (; mit != men; ++mit)
1795 if (!LyXModule::areCompatible(modName, *mit))
1798 // Check whether some required module is available
1799 vector<string> const reqs = lm->getRequiredModules();
1803 mit = getModules().begin(); // reset
1804 vector<string>::const_iterator rit = reqs.begin();
1805 vector<string>::const_iterator ren = reqs.end();
1806 bool foundone = false;
1807 for (; rit != ren; ++rit) {
1808 if (find(mit, men, *rit) != men ||
1809 find(provmodstart, provmodend, *rit) != provmodend) {
1819 bool BufferParams::addLayoutModule(string const & modName)
1821 LayoutModuleList::const_iterator it = layoutModules_.begin();
1822 LayoutModuleList::const_iterator end = layoutModules_.end();
1823 for (; it != end; it++)
1826 layoutModules_.push_back(modName);
1831 Font const BufferParams::getFont() const
1833 FontInfo f = documentClass().defaultfont();
1834 if (fontsDefaultFamily == "rmdefault")
1835 f.setFamily(ROMAN_FAMILY);
1836 else if (fontsDefaultFamily == "sfdefault")
1837 f.setFamily(SANS_FAMILY);
1838 else if (fontsDefaultFamily == "ttdefault")
1839 f.setFamily(TYPEWRITER_FAMILY);
1840 return Font(f, language);
1844 void BufferParams::readPreamble(Lexer & lex)
1846 if (lex.getString() != "\\begin_preamble")
1847 lyxerr << "Error (BufferParams::readPreamble):"
1848 "consistency check failed." << endl;
1850 preamble = lex.getLongString("\\end_preamble");
1854 void BufferParams::readLocalLayout(Lexer & lex)
1856 if (lex.getString() != "\\begin_local_layout")
1857 lyxerr << "Error (BufferParams::readLocalLayout):"
1858 "consistency check failed." << endl;
1860 local_layout = lex.getLongString("\\end_local_layout");
1864 void BufferParams::readLanguage(Lexer & lex)
1866 if (!lex.next()) return;
1868 string const tmptok = lex.getString();
1870 // check if tmptok is part of tex_babel in tex-defs.h
1871 language = languages.getLanguage(tmptok);
1873 // Language tmptok was not found
1874 language = default_language;
1875 lyxerr << "Warning: Setting language `"
1876 << tmptok << "' to `" << language->lang()
1882 void BufferParams::readGraphicsDriver(Lexer & lex)
1887 string const tmptok = lex.getString();
1888 // check if tmptok is part of tex_graphics in tex_defs.h
1891 string const test = tex_graphics[n++];
1893 if (test == tmptok) {
1894 graphicsDriver = tmptok;
1899 "Warning: graphics driver `$$Token' not recognized!\n"
1900 " Setting graphics driver to `default'.\n");
1901 graphicsDriver = "default";
1908 void BufferParams::readBullets(Lexer & lex)
1913 int const index = lex.getInteger();
1915 int temp_int = lex.getInteger();
1916 user_defined_bullet(index).setFont(temp_int);
1917 temp_bullet(index).setFont(temp_int);
1919 user_defined_bullet(index).setCharacter(temp_int);
1920 temp_bullet(index).setCharacter(temp_int);
1922 user_defined_bullet(index).setSize(temp_int);
1923 temp_bullet(index).setSize(temp_int);
1927 void BufferParams::readBulletsLaTeX(Lexer & lex)
1929 // The bullet class should be able to read this.
1932 int const index = lex.getInteger();
1934 docstring const temp_str = lex.getDocString();
1936 user_defined_bullet(index).setText(temp_str);
1937 temp_bullet(index).setText(temp_str);
1941 void BufferParams::readModules(Lexer & lex)
1943 if (!lex.eatLine()) {
1944 lyxerr << "Error (BufferParams::readModules):"
1945 "Unexpected end of input." << endl;
1949 string mod = lex.getString();
1950 if (mod == "\\end_modules")
1952 addLayoutModule(mod);
1958 void BufferParams::readRemovedModules(Lexer & lex)
1960 if (!lex.eatLine()) {
1961 lyxerr << "Error (BufferParams::readRemovedModules):"
1962 "Unexpected end of input." << endl;
1966 string mod = lex.getString();
1967 if (mod == "\\end_removed_modules")
1969 removedModules_.insert(mod);
1972 // now we want to remove any removed modules that were previously
1973 // added. normally, that will be because default modules were added in
1974 // setBaseClass(), which gets called when \textclass is read at the
1975 // start of the read.
1976 set<string>::const_iterator rit = removedModules_.begin();
1977 set<string>::const_iterator const ren = removedModules_.end();
1978 for (; rit != ren; rit++) {
1979 LayoutModuleList::iterator const mit = layoutModules_.begin();
1980 LayoutModuleList::iterator const men = layoutModules_.end();
1981 LayoutModuleList::iterator found = find(mit, men, *rit);
1984 layoutModules_.erase(found);
1989 string BufferParams::paperSizeName(PapersizePurpose purpose) const
1991 char real_papersize = papersize;
1992 if (real_papersize == PAPER_DEFAULT)
1993 real_papersize = lyxrc.default_papersize;
1995 switch (real_papersize) {
1997 // could be anything, so don't guess
1999 case PAPER_CUSTOM: {
2000 if (purpose == XDVI && !paperwidth.empty() &&
2001 !paperheight.empty()) {
2002 // heightxwidth<unit>
2003 string first = paperwidth;
2004 string second = paperheight;
2005 if (orientation == ORIENTATION_LANDSCAPE)
2008 return first.erase(first.length() - 2)
2020 // dvips and dvipdfm do not know this
2021 if (purpose == DVIPS || purpose == DVIPDFM)
2025 // dvipdfm does not know this
2026 if (purpose == DVIPDFM)
2030 // dvipdfm does not know this
2031 if (purpose == DVIPDFM)
2034 case PAPER_USEXECUTIVE:
2035 // dvipdfm does not know this
2036 if (purpose == DVIPDFM)
2041 case PAPER_USLETTER:
2043 if (purpose == XDVI)
2050 string const BufferParams::dvips_options() const
2055 && papersize == PAPER_CUSTOM
2056 && !lyxrc.print_paper_dimension_flag.empty()
2057 && !paperwidth.empty()
2058 && !paperheight.empty()) {
2059 // using a custom papersize
2060 result = lyxrc.print_paper_dimension_flag;
2061 result += ' ' + paperwidth;
2062 result += ',' + paperheight;
2064 string const paper_option = paperSizeName(DVIPS);
2065 if (!paper_option.empty() && (paper_option != "letter" ||
2066 orientation != ORIENTATION_LANDSCAPE)) {
2067 // dvips won't accept -t letter -t landscape.
2068 // In all other cases, include the paper size
2070 result = lyxrc.print_paper_flag;
2071 result += ' ' + paper_option;
2074 if (orientation == ORIENTATION_LANDSCAPE &&
2075 papersize != PAPER_CUSTOM)
2076 result += ' ' + lyxrc.print_landscape_flag;
2081 string BufferParams::babelCall(string const & lang_opts) const
2083 string lang_pack = lyxrc.language_package;
2084 if (lang_pack != "\\usepackage{babel}")
2086 // suppress the babel call when there is no babel language defined
2087 // for the document language in the lib/languages file and if no
2088 // other languages are used (lang_opts is then empty)
2089 if (lang_opts.empty())
2091 // If Vietnamese is used, babel must directly be loaded with the
2092 // language options, see
2093 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
2094 size_t viet = lang_opts.find("vietnam");
2095 // viet = string::npos when not found
2096 // the same is for all other languages that are not directly supported by
2097 // babel, but where LaTeX-packages add babel support.
2098 // this is currently the case for Latvian, Lithuanian, and Mongolian
2099 size_t latvian = lang_opts.find("latvian");
2100 size_t lithu = lang_opts.find("lithuanian");
2101 size_t mongo = lang_opts.find("mongolian");
2102 // If Japanese is used, babel must directly be loaded with the
2103 // language options, see
2104 // http://bugzilla.lyx.org/show_bug.cgi?id=4597#c4
2105 size_t japan = lang_opts.find("japanese");
2106 if (!lyxrc.language_global_options || viet != string::npos
2107 || japan != string::npos || latvian != string::npos
2108 || lithu != string::npos || mongo != string::npos)
2109 return "\\usepackage[" + lang_opts + "]{babel}";
2114 docstring BufferParams::getGraphicsDriver(string const & package) const
2118 if (package == "geometry") {
2119 if (graphicsDriver == "dvips"
2120 || graphicsDriver == "dvipdfm"
2121 || graphicsDriver == "pdftex"
2122 || graphicsDriver == "vtex")
2123 result = from_ascii(graphicsDriver);
2124 else if (graphicsDriver == "dvipdfmx")
2125 result = from_ascii("dvipdfm");
2132 void BufferParams::writeEncodingPreamble(odocstream & os,
2133 LaTeXFeatures & features, TexRow & texrow) const
2135 if (inputenc == "auto") {
2136 string const doc_encoding =
2137 language->encoding()->latexName();
2138 Encoding::Package const package =
2139 language->encoding()->package();
2141 // Create a list with all the input encodings used
2143 set<string> encodings =
2144 features.getEncodingSet(doc_encoding);
2146 // If the "japanese" package (i.e. pLaTeX) is used,
2147 // inputenc must be omitted.
2148 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
2149 if (package == Encoding::japanese)
2150 features.require("japanese");
2152 if ((!encodings.empty() || package == Encoding::inputenc)
2153 && !features.isRequired("japanese")) {
2154 os << "\\usepackage[";
2155 set<string>::const_iterator it = encodings.begin();
2156 set<string>::const_iterator const end = encodings.end();
2158 os << from_ascii(*it);
2161 for (; it != end; ++it)
2162 os << ',' << from_ascii(*it);
2163 if (package == Encoding::inputenc) {
2164 if (!encodings.empty())
2166 os << from_ascii(doc_encoding);
2168 os << "]{inputenc}\n";
2171 if (package == Encoding::CJK || features.mustProvide("CJK")) {
2172 if (language->encoding()->name() == "utf8-cjk"
2173 && features.isAvailable("CJKutf8"))
2174 os << "\\usepackage{CJKutf8}\n";
2176 os << "\\usepackage{CJK}\n";
2179 } else if (inputenc != "default") {
2180 switch (encoding().package()) {
2181 case Encoding::none:
2182 case Encoding::japanese:
2184 case Encoding::inputenc:
2185 // do not load inputenc if japanese is used
2186 if (features.isRequired("japanese"))
2188 os << "\\usepackage[" << from_ascii(inputenc)
2193 if (encoding().name() == "utf8-cjk"
2194 && features.isAvailable("CJKutf8"))
2195 os << "\\usepackage{CJKutf8}\n";
2197 os << "\\usepackage{CJK}\n";
2203 // The encoding "armscii8" (for Armenian) is only available when
2204 // the package "armtex" is loaded.
2205 if (language->encoding()->latexName() == "armscii8"
2206 || inputenc == "armscii8") {
2207 os << "\\usepackage{armtex}\n";
2213 string const BufferParams::loadFonts(string const & rm,
2214 string const & sf, string const & tt,
2215 bool const & sc, bool const & osf,
2216 int const & sfscale, int const & ttscale) const
2218 /* The LaTeX font world is in a flux. In the PSNFSS font interface,
2219 several packages have been replaced by others, that might not
2220 be installed on every system. We have to take care for that
2221 (see psnfss.pdf). We try to support all psnfss fonts as well
2222 as the fonts that have become de facto standard in the LaTeX
2223 world (e.g. Latin Modern). We do not support obsolete fonts
2224 (like PSLatex). In general, it should be possible to mix any
2225 rm font with any sf or tt font, respectively. (JSpitzm)
2227 -- separate math fonts.
2230 if (rm == "default" && sf == "default" && tt == "default")
2237 // Computer Modern (must be explicitely selectable -- there might be classes
2238 // that define a different default font!
2240 os << "\\renewcommand{\\rmdefault}{cmr}\n";
2241 // osf for Computer Modern needs eco.sty
2243 os << "\\usepackage{eco}\n";
2245 // Latin Modern Roman
2246 else if (rm == "lmodern")
2247 os << "\\usepackage{lmodern}\n";
2249 else if (rm == "ae") {
2250 // not needed when using OT1 font encoding.
2251 if (lyxrc.fontenc != "default")
2252 os << "\\usepackage{ae,aecompl}\n";
2255 else if (rm == "times") {
2256 // try to load the best available package
2257 if (LaTeXFeatures::isAvailable("mathptmx"))
2258 os << "\\usepackage{mathptmx}\n";
2259 else if (LaTeXFeatures::isAvailable("mathptm"))
2260 os << "\\usepackage{mathptm}\n";
2262 os << "\\usepackage{times}\n";
2265 else if (rm == "palatino") {
2266 // try to load the best available package
2267 if (LaTeXFeatures::isAvailable("mathpazo")) {
2268 os << "\\usepackage";
2274 // "osf" includes "sc"!
2278 os << "{mathpazo}\n";
2280 else if (LaTeXFeatures::isAvailable("mathpple"))
2281 os << "\\usepackage{mathpple}\n";
2283 os << "\\usepackage{palatino}\n";
2286 else if (rm == "utopia") {
2287 // fourier supersedes utopia.sty, but does
2288 // not work with OT1 encoding.
2289 if (LaTeXFeatures::isAvailable("fourier")
2290 && lyxrc.fontenc != "default") {
2291 os << "\\usepackage";
2302 os << "{fourier}\n";
2305 os << "\\usepackage{utopia}\n";
2307 // Bera (complete fontset)
2308 else if (rm == "bera" && sf == "default" && tt == "default")
2309 os << "\\usepackage{bera}\n";
2311 else if (rm != "default")
2312 os << "\\usepackage" << "{" << rm << "}\n";
2315 // Helvetica, Bera Sans
2316 if (sf == "helvet" || sf == "berasans") {
2318 os << "\\usepackage[scaled=" << float(sfscale) / 100
2319 << "]{" << sf << "}\n";
2321 os << "\\usepackage{" << sf << "}\n";
2324 else if (sf == "avant")
2325 os << "\\usepackage{" << sf << "}\n";
2326 // Computer Modern, Latin Modern, CM Bright
2327 else if (sf != "default")
2328 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
2330 // monospaced/typewriter
2331 // Courier, LuxiMono
2332 if (tt == "luximono" || tt == "beramono") {
2334 os << "\\usepackage[scaled=" << float(ttscale) / 100
2335 << "]{" << tt << "}\n";
2337 os << "\\usepackage{" << tt << "}\n";
2340 else if (tt == "courier" )
2341 os << "\\usepackage{" << tt << "}\n";
2342 // Computer Modern, Latin Modern, CM Bright
2343 else if (tt != "default")
2344 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
2350 Encoding const & BufferParams::encoding() const
2352 if (inputenc == "auto" || inputenc == "default")
2353 return *language->encoding();
2354 Encoding const * const enc = encodings.fromLaTeXName(inputenc);
2357 LYXERR0("Unknown inputenc value `" << inputenc
2358 << "'. Using `auto' instead.");
2359 return *language->encoding();
2363 CiteEngine BufferParams::citeEngine() const
2365 // FIXME the class should provide the numerical/
2366 // authoryear choice
2367 if (documentClass().provides("natbib")
2368 && cite_engine_ != ENGINE_NATBIB_NUMERICAL)
2369 return ENGINE_NATBIB_AUTHORYEAR;
2370 return cite_engine_;
2374 void BufferParams::setCiteEngine(CiteEngine cite_engine)
2376 cite_engine_ = cite_engine;