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"
28 #include "LaTeXFeatures.h"
29 #include "ModuleList.h"
33 #include "OutputParams.h"
37 #include "PDFOptions.h"
39 #include "frontends/alert.h"
41 #include "insets/InsetListingsParams.h"
43 #include "support/convert.h"
44 #include "support/debug.h"
45 #include "support/docstream.h"
46 #include "support/FileName.h"
47 #include "support/filetools.h"
48 #include "support/gettext.h"
49 #include "support/Messages.h"
50 #include "support/Translator.h"
51 #include "support/lstrings.h"
57 using namespace lyx::support;
60 static char const * const string_paragraph_separation[] = {
65 static char const * const string_quotes_language[] = {
66 "english", "swedish", "german", "polish", "french", "danish", ""
70 static char const * const string_papersize[] = {
71 "default", "custom", "letterpaper", "legalpaper", "executivepaper",
72 "a3paper", "a4paper", "a5paper", "b3paper", "b4paper", "b5paper", ""
76 static char const * const string_orientation[] = {
77 "portrait", "landscape", ""
81 static char const * const string_footnotekinds[] = {
82 "footnote", "margin", "fig", "tab", "alg", "wide-fig", "wide-tab", ""
86 static char const * const tex_graphics[] = {
87 "default", "dvialw", "dvilaser", "dvipdf", "dvipdfm", "dvipdfmx",
88 "dvips", "dvipsone", "dvitops", "dviwin", "dviwindo", "dvi2ps", "emtex",
89 "ln", "oztex", "pctexhp", "pctexps", "pctexwin", "pctex32", "pdftex",
90 "psprint", "pubps", "tcidvi", "textures", "truetex", "vtex", "xdvi",
100 // Paragraph separation
101 typedef Translator<string, BufferParams::ParagraphSeparation> ParSepTranslator;
104 ParSepTranslator const init_parseptranslator()
106 ParSepTranslator translator
107 (string_paragraph_separation[0], BufferParams::ParagraphIndentSeparation);
108 translator.addPair(string_paragraph_separation[1], BufferParams::ParagraphSkipSeparation);
113 ParSepTranslator const & parseptranslator()
115 static ParSepTranslator translator = init_parseptranslator();
121 typedef Translator<string, InsetQuotes::QuoteLanguage> QuotesLangTranslator;
124 QuotesLangTranslator const init_quoteslangtranslator()
126 QuotesLangTranslator translator
127 (string_quotes_language[0], InsetQuotes::EnglishQuotes);
128 translator.addPair(string_quotes_language[1], InsetQuotes::SwedishQuotes);
129 translator.addPair(string_quotes_language[2], InsetQuotes::GermanQuotes);
130 translator.addPair(string_quotes_language[3], InsetQuotes::PolishQuotes);
131 translator.addPair(string_quotes_language[4], InsetQuotes::FrenchQuotes);
132 translator.addPair(string_quotes_language[5], InsetQuotes::DanishQuotes);
137 QuotesLangTranslator const & quoteslangtranslator()
139 static QuotesLangTranslator translator = init_quoteslangtranslator();
145 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
148 static PaperSizeTranslator initPaperSizeTranslator()
150 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
151 translator.addPair(string_papersize[1], PAPER_CUSTOM);
152 translator.addPair(string_papersize[2], PAPER_USLETTER);
153 translator.addPair(string_papersize[3], PAPER_USLEGAL);
154 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
155 translator.addPair(string_papersize[5], PAPER_A3);
156 translator.addPair(string_papersize[6], PAPER_A4);
157 translator.addPair(string_papersize[7], PAPER_A5);
158 translator.addPair(string_papersize[8], PAPER_B3);
159 translator.addPair(string_papersize[9], PAPER_B4);
160 translator.addPair(string_papersize[10], PAPER_B5);
165 PaperSizeTranslator const & papersizetranslator()
167 static PaperSizeTranslator translator = initPaperSizeTranslator();
173 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
176 PaperOrientationTranslator const init_paperorientationtranslator()
178 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
179 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
184 PaperOrientationTranslator const & paperorientationtranslator()
186 static PaperOrientationTranslator translator = init_paperorientationtranslator();
192 typedef Translator<int, PageSides> SidesTranslator;
195 SidesTranslator const init_sidestranslator()
197 SidesTranslator translator(1, OneSide);
198 translator.addPair(2, TwoSides);
203 SidesTranslator const & sidestranslator()
205 static SidesTranslator translator = init_sidestranslator();
211 typedef Translator<int, BufferParams::Package> PackageTranslator;
214 PackageTranslator const init_packagetranslator()
216 PackageTranslator translator(0, BufferParams::package_off);
217 translator.addPair(1, BufferParams::package_auto);
218 translator.addPair(2, BufferParams::package_on);
223 PackageTranslator const & packagetranslator()
225 static PackageTranslator translator = init_packagetranslator();
231 typedef Translator<string, CiteEngine> CiteEngineTranslator;
234 CiteEngineTranslator const init_citeenginetranslator()
236 CiteEngineTranslator translator("basic", ENGINE_BASIC);
237 translator.addPair("natbib_numerical", ENGINE_NATBIB_NUMERICAL);
238 translator.addPair("natbib_authoryear", ENGINE_NATBIB_AUTHORYEAR);
239 translator.addPair("jurabib", ENGINE_JURABIB);
244 CiteEngineTranslator const & citeenginetranslator()
246 static CiteEngineTranslator translator = init_citeenginetranslator();
252 typedef Translator<string, Spacing::Space> SpaceTranslator;
255 SpaceTranslator const init_spacetranslator()
257 SpaceTranslator translator("default", Spacing::Default);
258 translator.addPair("single", Spacing::Single);
259 translator.addPair("onehalf", Spacing::Onehalf);
260 translator.addPair("double", Spacing::Double);
261 translator.addPair("other", Spacing::Other);
266 SpaceTranslator const & spacetranslator()
268 static SpaceTranslator translator = init_spacetranslator();
276 class BufferParams::Impl
281 AuthorList authorlist;
282 BranchList branchlist;
283 Bullet temp_bullets[4];
284 Bullet user_defined_bullets[4];
286 /** This is the amount of space used for paragraph_separation "skip",
287 * and for detached paragraphs in "indented" documents.
290 PDFOptions pdfoptions;
291 LayoutFileIndex baseClass_;
295 BufferParams::Impl::Impl()
296 : defskip(VSpace::MEDSKIP), baseClass_(string(""))
298 // set initial author
300 authorlist.record(Author(from_utf8(lyxrc.user_name), from_utf8(lyxrc.user_email)));
305 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
309 return new BufferParams::Impl(*ptr);
313 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
319 BufferParams::BufferParams()
322 setBaseClass(defaultBaseclass());
324 paragraph_separation = ParagraphIndentSeparation;
325 quotes_language = InsetQuotes::EnglishQuotes;
326 fontsize = "default";
329 papersize = PAPER_DEFAULT;
330 orientation = ORIENTATION_PORTRAIT;
331 use_geometry = false;
332 use_amsmath = package_auto;
333 use_esint = package_auto;
334 cite_engine_ = ENGINE_BASIC;
335 use_bibtopic = false;
336 trackChanges = false;
337 outputChanges = false;
338 use_default_options = true;
341 language = default_language;
342 fontsRoman = "default";
343 fontsSans = "default";
344 fontsTypewriter = "default";
345 fontsDefaultFamily = "default";
348 fontsSansScale = 100;
349 fontsTypewriterScale = 100;
351 graphicsDriver = "default";
354 listings_params = string();
355 pagestyle = "default";
357 for (int iter = 0; iter < 4; ++iter) {
358 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
359 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
364 docstring BufferParams::B_(string const & l10n) const
366 LASSERT(language, /**/);
367 return getMessages(language->code()).get(l10n);
371 AuthorList & BufferParams::authors()
373 return pimpl_->authorlist;
377 AuthorList const & BufferParams::authors() const
379 return pimpl_->authorlist;
383 BranchList & BufferParams::branchlist()
385 return pimpl_->branchlist;
389 BranchList const & BufferParams::branchlist() const
391 return pimpl_->branchlist;
395 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
397 LASSERT(index < 4, /**/);
398 return pimpl_->temp_bullets[index];
402 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
404 LASSERT(index < 4, /**/);
405 return pimpl_->temp_bullets[index];
409 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
411 LASSERT(index < 4, /**/);
412 return pimpl_->user_defined_bullets[index];
416 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
418 LASSERT(index < 4, /**/);
419 return pimpl_->user_defined_bullets[index];
423 Spacing & BufferParams::spacing()
425 return pimpl_->spacing;
429 Spacing const & BufferParams::spacing() const
431 return pimpl_->spacing;
435 PDFOptions & BufferParams::pdfoptions()
437 return pimpl_->pdfoptions;
441 PDFOptions const & BufferParams::pdfoptions() const
443 return pimpl_->pdfoptions;
447 VSpace const & BufferParams::getDefSkip() const
449 return pimpl_->defskip;
453 void BufferParams::setDefSkip(VSpace const & vs)
455 pimpl_->defskip = vs;
459 string BufferParams::readToken(Lexer & lex, string const & token,
460 FileName const & filepath)
462 if (token == "\\textclass") {
464 string const classname = lex.getString();
465 // if there exists a local layout file, ignore the system one
466 // NOTE: in this case, the textclass (.cls file) is assumed to be available.
468 LayoutFileList & bcl = LayoutFileList::get();
469 if (tcp.empty() && !filepath.empty())
470 tcp = bcl.addLocalLayout(classname, filepath.absFilename());
474 setBaseClass(classname);
475 // We assume that a tex class exists for local or unknown layouts so this warning
476 // will only be given for system layouts.
477 if (!baseClass()->isTeXClassAvailable()) {
478 docstring const msg =
479 bformat(_("The layout file requested by this document,\n"
481 "is not usable. This is probably because a LaTeX\n"
482 "class or style file required by it is not\n"
483 "available. See the Customization documentation\n"
484 "for more information.\n"), from_utf8(classname));
485 frontend::Alert::warning(_("Document class not available"),
486 msg + _("LyX will not be able to produce output."));
488 } else if (token == "\\begin_preamble") {
490 } else if (token == "\\begin_local_layout") {
491 readLocalLayout(lex);
492 } else if (token == "\\begin_modules") {
494 } else if (token == "\\begin_removed_modules") {
495 readRemovedModules(lex);
496 } else if (token == "\\options") {
498 options = lex.getString();
499 } else if (token == "\\use_default_options") {
500 lex >> use_default_options;
501 } else if (token == "\\master") {
503 master = lex.getString();
504 } else if (token == "\\language") {
506 } else if (token == "\\inputencoding") {
508 } else if (token == "\\graphics") {
509 readGraphicsDriver(lex);
510 } else if (token == "\\font_roman") {
512 } else if (token == "\\font_sans") {
514 } else if (token == "\\font_typewriter") {
515 lex >> fontsTypewriter;
516 } else if (token == "\\font_default_family") {
517 lex >> fontsDefaultFamily;
518 } else if (token == "\\font_sc") {
520 } else if (token == "\\font_osf") {
522 } else if (token == "\\font_sf_scale") {
523 lex >> fontsSansScale;
524 } else if (token == "\\font_tt_scale") {
525 lex >> fontsTypewriterScale;
526 } else if (token == "\\font_cjk") {
528 } else if (token == "\\paragraph_separation") {
531 paragraph_separation = parseptranslator().find(parsep);
532 } else if (token == "\\defskip") {
534 string defskip = lex.getString();
535 if (defskip == "defskip")
538 pimpl_->defskip = VSpace(defskip);
539 } else if (token == "\\quotes_language") {
542 quotes_language = quoteslangtranslator().find(quotes_lang);
543 } else if (token == "\\papersize") {
546 papersize = papersizetranslator().find(ppsize);
547 } else if (token == "\\use_geometry") {
549 } else if (token == "\\use_amsmath") {
552 use_amsmath = packagetranslator().find(use_ams);
553 } else if (token == "\\use_esint") {
556 use_esint = packagetranslator().find(useesint);
557 } else if (token == "\\cite_engine") {
560 cite_engine_ = citeenginetranslator().find(engine);
561 } else if (token == "\\use_bibtopic") {
563 } else if (token == "\\tracking_changes") {
565 } else if (token == "\\output_changes") {
566 lex >> outputChanges;
567 } else if (token == "\\branch") {
569 docstring branch = lex.getDocString();
570 branchlist().add(branch);
573 string const tok = lex.getString();
574 if (tok == "\\end_branch")
576 Branch * branch_ptr = branchlist().find(branch);
577 if (tok == "\\selected") {
580 branch_ptr->setSelected(lex.getInteger());
582 // not yet operational
583 if (tok == "\\color") {
585 string color = lex.getString();
587 branch_ptr->setColor(color);
588 // Update also the Color table:
590 color = lcolor.getX11Name(Color_background);
592 lcolor.setColor(to_utf8(branch), color);
596 } else if (token == "\\author") {
598 istringstream ss(lex.getString());
601 author_map.push_back(pimpl_->authorlist.record(a));
602 } else if (token == "\\paperorientation") {
605 orientation = paperorientationtranslator().find(orient);
606 } else if (token == "\\paperwidth") {
608 } else if (token == "\\paperheight") {
610 } else if (token == "\\leftmargin") {
612 } else if (token == "\\topmargin") {
614 } else if (token == "\\rightmargin") {
616 } else if (token == "\\bottommargin") {
618 } else if (token == "\\headheight") {
620 } else if (token == "\\headsep") {
622 } else if (token == "\\footskip") {
624 } else if (token == "\\columnsep") {
626 } else if (token == "\\paperfontsize") {
628 } else if (token == "\\papercolumns") {
630 } else if (token == "\\listings_params") {
633 listings_params = InsetListingsParams(par).params();
634 } else if (token == "\\papersides") {
637 sides = sidestranslator().find(psides);
638 } else if (token == "\\paperpagestyle") {
640 } else if (token == "\\bullet") {
642 } else if (token == "\\bulletLaTeX") {
643 readBulletsLaTeX(lex);
644 } else if (token == "\\secnumdepth") {
646 } else if (token == "\\tocdepth") {
648 } else if (token == "\\spacing") {
652 if (nspacing == "other") {
655 spacing().set(spacetranslator().find(nspacing), tmp_val);
656 } else if (token == "\\float_placement") {
657 lex >> float_placement;
659 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
660 string toktmp = pdfoptions().readToken(lex, token);
661 if (!toktmp.empty()) {
662 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
667 lyxerr << "BufferParams::readToken(): Unknown token: " <<
676 void BufferParams::writeFile(ostream & os) const
678 // The top of the file is written by the buffer.
679 // Prints out the buffer info into the .lyx file given by file
682 os << "\\textclass " << baseClass()->name() << '\n';
685 if (!preamble.empty()) {
686 // remove '\n' from the end of preamble
687 string const tmppreamble = rtrim(preamble, "\n");
688 os << "\\begin_preamble\n"
690 << "\n\\end_preamble\n";
694 if (!options.empty()) {
695 os << "\\options " << options << '\n';
698 // use the class options defined in the layout?
699 os << "\\use_default_options "
700 << convert<string>(use_default_options) << "\n";
702 // the master document
703 if (!master.empty()) {
704 os << "\\master " << master << '\n';
708 if (!removedModules_.empty()) {
709 os << "\\begin_removed_modules" << '\n';
710 set<string>::const_iterator it = removedModules_.begin();
711 set<string>::const_iterator en = removedModules_.end();
712 for (; it != en; it++)
714 os << "\\end_removed_modules" << '\n';
718 if (!layoutModules_.empty()) {
719 os << "\\begin_modules" << '\n';
720 LayoutModuleList::const_iterator it = layoutModules_.begin();
721 LayoutModuleList::const_iterator en = layoutModules_.end();
722 for (; it != en; it++)
724 os << "\\end_modules" << '\n';
727 // local layout information
728 if (!local_layout.empty()) {
729 // remove '\n' from the end
730 string const tmplocal = rtrim(local_layout, "\n");
731 os << "\\begin_local_layout\n"
733 << "\n\\end_local_layout\n";
736 // then the text parameters
737 if (language != ignore_language)
738 os << "\\language " << language->lang() << '\n';
739 os << "\\inputencoding " << inputenc
740 << "\n\\font_roman " << fontsRoman
741 << "\n\\font_sans " << fontsSans
742 << "\n\\font_typewriter " << fontsTypewriter
743 << "\n\\font_default_family " << fontsDefaultFamily
744 << "\n\\font_sc " << convert<string>(fontsSC)
745 << "\n\\font_osf " << convert<string>(fontsOSF)
746 << "\n\\font_sf_scale " << fontsSansScale
747 << "\n\\font_tt_scale " << fontsTypewriterScale
749 if (!fontsCJK.empty()) {
750 os << "\\font_cjk " << fontsCJK << '\n';
752 os << "\n\\graphics " << graphicsDriver << '\n';
754 if (!float_placement.empty()) {
755 os << "\\float_placement " << float_placement << '\n';
757 os << "\\paperfontsize " << fontsize << '\n';
759 spacing().writeFile(os);
760 pdfoptions().writeFile(os);
762 os << "\\papersize " << string_papersize[papersize]
763 << "\n\\use_geometry " << convert<string>(use_geometry)
764 << "\n\\use_amsmath " << use_amsmath
765 << "\n\\use_esint " << use_esint
766 << "\n\\cite_engine " << citeenginetranslator().find(cite_engine_)
767 << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
768 << "\n\\paperorientation " << string_orientation[orientation]
771 BranchList::const_iterator it = branchlist().begin();
772 BranchList::const_iterator end = branchlist().end();
773 for (; it != end; ++it) {
774 os << "\\branch " << to_utf8(it->branch())
775 << "\n\\selected " << it->isSelected()
776 << "\n\\color " << lyx::X11hexname(it->color())
781 if (!paperwidth.empty())
782 os << "\\paperwidth "
783 << VSpace(paperwidth).asLyXCommand() << '\n';
784 if (!paperheight.empty())
785 os << "\\paperheight "
786 << VSpace(paperheight).asLyXCommand() << '\n';
787 if (!leftmargin.empty())
788 os << "\\leftmargin "
789 << VSpace(leftmargin).asLyXCommand() << '\n';
790 if (!topmargin.empty())
792 << VSpace(topmargin).asLyXCommand() << '\n';
793 if (!rightmargin.empty())
794 os << "\\rightmargin "
795 << VSpace(rightmargin).asLyXCommand() << '\n';
796 if (!bottommargin.empty())
797 os << "\\bottommargin "
798 << VSpace(bottommargin).asLyXCommand() << '\n';
799 if (!headheight.empty())
800 os << "\\headheight "
801 << VSpace(headheight).asLyXCommand() << '\n';
802 if (!headsep.empty())
804 << VSpace(headsep).asLyXCommand() << '\n';
805 if (!footskip.empty())
807 << VSpace(footskip).asLyXCommand() << '\n';
808 if (!columnsep.empty())
810 << VSpace(columnsep).asLyXCommand() << '\n';
811 os << "\\secnumdepth " << secnumdepth
812 << "\n\\tocdepth " << tocdepth
813 << "\n\\paragraph_separation "
814 << string_paragraph_separation[paragraph_separation]
815 << "\n\\defskip " << getDefSkip().asLyXCommand()
816 << "\n\\quotes_language "
817 << string_quotes_language[quotes_language]
818 << "\n\\papercolumns " << columns
819 << "\n\\papersides " << sides
820 << "\n\\paperpagestyle " << pagestyle << '\n';
821 if (!listings_params.empty())
822 os << "\\listings_params \"" <<
823 InsetListingsParams(listings_params).encodedString() << "\"\n";
824 for (int i = 0; i < 4; ++i) {
825 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
826 if (user_defined_bullet(i).getFont() != -1) {
827 os << "\\bullet " << i << " "
828 << user_defined_bullet(i).getFont() << " "
829 << user_defined_bullet(i).getCharacter() << " "
830 << user_defined_bullet(i).getSize() << "\n";
834 os << "\\bulletLaTeX " << i << " \""
835 << lyx::to_ascii(user_defined_bullet(i).getText())
841 os << "\\tracking_changes " << convert<string>(trackChanges) << "\n";
842 os << "\\output_changes " << convert<string>(outputChanges) << "\n";
844 AuthorList::Authors::const_iterator a_it = pimpl_->authorlist.begin();
845 AuthorList::Authors::const_iterator a_end = pimpl_->authorlist.end();
846 for (; a_it != a_end; ++a_it) {
847 if (a_it->second.used())
848 os << "\\author " << a_it->second << "\n";
850 os << "\\author " << Author() << "\n";
855 void BufferParams::validate(LaTeXFeatures & features) const
857 features.require(documentClass().requires());
860 bool dvipost = LaTeXFeatures::isAvailable("dvipost");
861 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
862 LaTeXFeatures::isAvailable("xcolor");
864 switch (features.runparams().flavor) {
865 case OutputParams::LATEX:
867 features.require("ct-dvipost");
868 features.require("dvipost");
869 } else if (xcolorulem) {
870 features.require("ct-xcolor-ulem");
871 features.require("ulem");
872 features.require("xcolor");
874 features.require("ct-none");
877 case OutputParams::PDFLATEX:
879 features.require("ct-xcolor-ulem");
880 features.require("ulem");
881 features.require("xcolor");
882 // improves color handling in PDF output
883 features.require("pdfcolmk");
885 features.require("ct-none");
893 // Floats with 'Here definitely' as default setting.
894 if (float_placement.find('H') != string::npos)
895 features.require("float");
897 // AMS Style is at document level
898 if (use_amsmath == package_on
899 || documentClass().provides("amsmath"))
900 features.require("amsmath");
901 if (use_esint == package_on)
902 features.require("esint");
904 // Document-level line spacing
905 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
906 features.require("setspace");
908 // the bullet shapes are buffer level not paragraph level
909 // so they are tested here
910 for (int i = 0; i < 4; ++i) {
911 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
913 int const font = user_defined_bullet(i).getFont();
915 int const c = user_defined_bullet(i).getCharacter();
921 features.require("latexsym");
923 } else if (font == 1) {
924 features.require("amssymb");
925 } else if (font >= 2 && font <= 5) {
926 features.require("pifont");
930 if (pdfoptions().use_hyperref) {
931 features.require("hyperref");
932 // due to interferences with babel and hyperref, the color package has to
933 // be loaded after hyperref when hyperref is used with the colorlinks
934 // option, see http://bugzilla.lyx.org/show_bug.cgi?id=5291
935 if (pdfoptions().colorlinks)
936 features.require("color");
939 if (language->lang() == "vietnamese")
940 features.require("vietnamese");
941 else if (language->lang() == "japanese")
942 features.require("japanese");
946 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
947 TexRow & texrow) const
949 os << "\\documentclass";
951 DocumentClass const & tclass = documentClass();
953 ostringstream clsoptions; // the document class options.
955 if (tokenPos(tclass.opt_fontsize(),
956 '|', fontsize) >= 0) {
957 // only write if existing in list (and not default)
958 clsoptions << fontsize << "pt,";
961 // custom, A3, B3 and B4 paper sizes need geometry
962 bool nonstandard_papersize = papersize == PAPER_B3
963 || papersize == PAPER_B4
964 || papersize == PAPER_A3
965 || papersize == PAPER_CUSTOM;
970 clsoptions << "a4paper,";
973 clsoptions << "letterpaper,";
976 clsoptions << "a5paper,";
979 clsoptions << "b5paper,";
981 case PAPER_USEXECUTIVE:
982 clsoptions << "executivepaper,";
985 clsoptions << "legalpaper,";
997 if (sides != tclass.sides()) {
1000 clsoptions << "oneside,";
1003 clsoptions << "twoside,";
1009 if (columns != tclass.columns()) {
1011 clsoptions << "twocolumn,";
1013 clsoptions << "onecolumn,";
1017 && orientation == ORIENTATION_LANDSCAPE)
1018 clsoptions << "landscape,";
1020 // language should be a parameter to \documentclass
1021 if (language->babel() == "hebrew"
1022 && default_language->babel() != "hebrew")
1023 // This seems necessary
1024 features.useLanguage(default_language);
1026 ostringstream language_options;
1027 bool const use_babel = features.useBabel();
1029 language_options << features.getLanguages();
1030 if (!language->babel().empty()) {
1031 if (!language_options.str().empty())
1032 language_options << ',';
1033 language_options << language->babel();
1035 // if Vietnamese is used, babel must directly be loaded
1036 // with language options, not in the class options, see
1037 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1038 size_t viet = language_options.str().find("vietnam");
1039 // viet = string::npos when not found
1040 // the same is for all other languages that are not directly supported by
1041 // babel, but where LaTeX-packages add babel support.
1042 // this is currently the case for Latvian, Lithuanian, and Mongolian
1043 size_t latvian = language_options.str().find("latvian");
1044 size_t lithu = language_options.str().find("lithuanian");
1045 size_t mongo = language_options.str().find("mongolian");
1046 // if Japanese is used, babel must directly be loaded
1047 // with language options, not in the class options, see
1048 // http://bugzilla.lyx.org/show_bug.cgi?id=4597#c4
1049 size_t japan = language_options.str().find("japanese");
1050 if (lyxrc.language_global_options && !language_options.str().empty()
1051 && viet == string::npos && japan == string::npos
1052 && latvian == string::npos && lithu == string::npos
1053 && mongo == string::npos)
1054 clsoptions << language_options.str() << ',';
1057 // the predefined options from the layout
1058 if (use_default_options && !tclass.options().empty())
1059 clsoptions << tclass.options() << ',';
1061 // the user-defined options
1062 if (!options.empty()) {
1063 clsoptions << options << ',';
1066 string strOptions(clsoptions.str());
1067 if (!strOptions.empty()) {
1068 strOptions = rtrim(strOptions, ",");
1070 os << '[' << from_utf8(strOptions) << ']';
1073 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1075 // end of \documentclass defs
1077 // font selection must be done before loading fontenc.sty
1078 string const fonts =
1079 loadFonts(fontsRoman, fontsSans,
1080 fontsTypewriter, fontsSC, fontsOSF,
1081 fontsSansScale, fontsTypewriterScale);
1082 if (!fonts.empty()) {
1083 os << from_ascii(fonts);
1086 if (fontsDefaultFamily != "default")
1087 os << "\\renewcommand{\\familydefault}{\\"
1088 << from_ascii(fontsDefaultFamily) << "}\n";
1090 // set font encoding
1091 // this one is not per buffer
1092 // for arabic_arabi and farsi we also need to load the LAE and
1094 if (lyxrc.fontenc != "default" && language->lang() != "japanese") {
1095 if (language->lang() == "arabic_arabi"
1096 || language->lang() == "farsi") {
1097 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
1098 << ",LFE,LAE]{fontenc}\n";
1101 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
1107 // handle inputenc etc.
1108 writeEncodingPreamble(os, features, texrow);
1110 if (!listings_params.empty() || features.isRequired("listings")) {
1111 os << "\\usepackage{listings}\n";
1114 if (!listings_params.empty()) {
1116 // do not test validity because listings_params is
1117 // supposed to be valid
1119 InsetListingsParams(listings_params).separatedParams(true);
1120 // we can't support all packages, but we should load the color package
1121 if (par.find("\\color", 0) != string::npos)
1122 features.require("color");
1123 os << from_utf8(par);
1124 // count the number of newlines
1125 for (size_t i = 0; i < par.size(); ++i)
1131 if (use_geometry || nonstandard_papersize) {
1132 odocstringstream ods;
1133 if (!getGraphicsDriver("geometry").empty())
1134 ods << getGraphicsDriver("geometry");
1135 if (orientation == ORIENTATION_LANDSCAPE)
1136 ods << ",landscape";
1137 switch (papersize) {
1139 if (!paperwidth.empty())
1140 ods << ",paperwidth="
1141 << from_ascii(paperwidth);
1142 if (!paperheight.empty())
1143 ods << ",paperheight="
1144 << from_ascii(paperheight);
1146 case PAPER_USLETTER:
1147 ods << ",letterpaper";
1150 ods << ",legalpaper";
1152 case PAPER_USEXECUTIVE:
1153 ods << ",executivepaper";
1174 // default papersize ie PAPER_DEFAULT
1175 switch (lyxrc.default_papersize) {
1176 case PAPER_DEFAULT: // keep compiler happy
1177 case PAPER_USLETTER:
1178 ods << ",letterpaper";
1181 ods << ",legalpaper";
1183 case PAPER_USEXECUTIVE:
1184 ods << ",executivepaper";
1204 docstring const g_options = trim(ods.str(), ",");
1205 os << "\\usepackage";
1206 if (!g_options.empty())
1207 os << '[' << g_options << ']';
1208 os << "{geometry}\n";
1210 os << "\\geometry{verbose";
1211 if (!topmargin.empty())
1212 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1213 if (!bottommargin.empty())
1214 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1215 if (!leftmargin.empty())
1216 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1217 if (!rightmargin.empty())
1218 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1219 if (!headheight.empty())
1220 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1221 if (!headsep.empty())
1222 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1223 if (!footskip.empty())
1224 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1225 if (!columnsep.empty())
1226 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1229 } else if (orientation == ORIENTATION_LANDSCAPE) {
1230 features.require("papersize");
1233 if (tokenPos(tclass.opt_pagestyle(),
1234 '|', pagestyle) >= 0) {
1235 if (pagestyle == "fancy") {
1236 os << "\\usepackage{fancyhdr}\n";
1239 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1243 // Only if class has a ToC hierarchy
1244 if (tclass.hasTocLevels()) {
1245 if (secnumdepth != tclass.secnumdepth()) {
1246 os << "\\setcounter{secnumdepth}{"
1251 if (tocdepth != tclass.tocdepth()) {
1252 os << "\\setcounter{tocdepth}{"
1259 if (paragraph_separation) {
1260 switch (getDefSkip().kind()) {
1261 case VSpace::SMALLSKIP:
1262 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1264 case VSpace::MEDSKIP:
1265 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1267 case VSpace::BIGSKIP:
1268 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1270 case VSpace::LENGTH:
1271 os << "\\setlength{\\parskip}{"
1272 << from_utf8(getDefSkip().length().asLatexString())
1275 default: // should never happen // Then delete it.
1276 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1281 os << "\\setlength{\\parindent}{0pt}\n";
1285 // Now insert the LyX specific LaTeX commands...
1286 docstring lyxpreamble;
1288 // due to interferences with babel and hyperref, the color package has to
1289 // be loaded (when it is not already loaded) before babel when hyperref
1290 // is used with the colorlinks option, see
1291 // http://bugzilla.lyx.org/show_bug.cgi?id=5291
1292 // we decided therefore to load color always before babel, see
1293 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
1294 lyxpreamble += from_ascii(features.getColorOptions());
1296 // If we use hyperref, jurabib, japanese, or vietnamese, we have to call babel before them.
1298 && (features.isRequired("jurabib")
1299 || features.isRequired("hyperref")
1300 || features.isRequired("vietnamese")
1301 || features.isRequired("japanese") ) ) {
1303 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1304 lyxpreamble += from_utf8(features.getBabelOptions()) + '\n';
1307 // The optional packages;
1308 lyxpreamble += from_ascii(features.getPackages());
1311 lyxpreamble += from_utf8(spacing().writePreamble(tclass.provides("SetSpace")));
1314 // * Hyperref manual: "Make sure it comes last of your loaded
1315 // packages, to give it a fighting chance of not being over-written,
1316 // since its job is to redefine many LaTeX commands."
1317 // * Email from Heiko Oberdiek: "It is usually better to load babel
1318 // before hyperref. Then hyperref has a chance to detect babel.
1319 // * Has to be loaded before the "LyX specific LaTeX commands" to
1320 // avoid errors with algorithm floats.
1321 // use hyperref explicitely when it is required
1322 if (features.isRequired("hyperref")) {
1323 odocstringstream oss;
1324 pdfoptions().writeLaTeX(oss, documentClass().provides("hyperref"));
1325 lyxpreamble += oss.str();
1328 // Will be surrounded by \makeatletter and \makeatother when needed
1329 docstring atlyxpreamble;
1331 // Some macros LyX will need
1332 docstring tmppreamble(from_ascii(features.getMacros()));
1334 if (!tmppreamble.empty())
1335 atlyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1336 "LyX specific LaTeX commands.\n"
1337 + tmppreamble + '\n';
1339 // the text class specific preamble
1340 tmppreamble = features.getTClassPreamble();
1341 if (!tmppreamble.empty())
1342 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1343 "Textclass specific LaTeX commands.\n"
1344 + tmppreamble + '\n';
1346 /* the user-defined preamble */
1347 if (!preamble.empty())
1349 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1350 "User specified LaTeX commands.\n"
1351 + from_utf8(preamble) + '\n';
1353 // subfig loads internally the LaTeX package "caption". As
1354 // caption is a very popular package, users will load it in
1355 // the preamble. Therefore we must load subfig behind the
1356 // user-defined preamble and check if the caption package was
1357 // loaded or not. For the case that caption is loaded before
1358 // subfig, there is the subfig option "caption=false". This
1359 // option also works when a koma-script class is used and
1360 // koma's own caption commands are used instead of caption. We
1361 // use \PassOptionsToPackage here because the user could have
1362 // already loaded subfig in the preamble.
1363 if (features.isRequired("subfig")) {
1364 atlyxpreamble += "\\@ifundefined{showcaptionsetup}{}{%\n"
1365 " \\PassOptionsToPackage{caption=false}{subfig}}\n"
1366 "\\usepackage{subfig}\n";
1369 // Itemize bullet settings need to be last in case the user
1370 // defines their own bullets that use a package included
1371 // in the user-defined preamble -- ARRae
1372 // Actually it has to be done much later than that
1373 // since some packages like frenchb make modifications
1374 // at \begin{document} time -- JMarc
1375 docstring bullets_def;
1376 for (int i = 0; i < 4; ++i) {
1377 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1378 if (bullets_def.empty())
1379 bullets_def += "\\AtBeginDocument{\n";
1380 bullets_def += " \\def\\labelitemi";
1382 // `i' is one less than the item to modify
1389 bullets_def += "ii";
1395 bullets_def += '{' +
1396 user_defined_bullet(i).getText()
1401 if (!bullets_def.empty())
1402 atlyxpreamble += bullets_def + "}\n\n";
1404 if (atlyxpreamble.find(from_ascii("@")) != docstring::npos)
1405 lyxpreamble += "\n\\makeatletter\n"
1406 + atlyxpreamble + "\\makeatother\n\n";
1408 lyxpreamble += '\n' + atlyxpreamble;
1410 // We try to load babel late, in case it interferes with other packages.
1411 // Jurabib and Hyperref have to be called after babel, though.
1412 if (use_babel && !features.isRequired("jurabib")
1413 && !features.isRequired("hyperref")
1414 && !features.isRequired("vietnamese")
1415 && !features.isRequired("japanese")) {
1417 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1418 lyxpreamble += from_utf8(features.getBabelOptions()) + '\n';
1422 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1423 for (int j = 0; j != nlines; ++j) {
1432 void BufferParams::useClassDefaults()
1434 DocumentClass const & tclass = documentClass();
1436 sides = tclass.sides();
1437 columns = tclass.columns();
1438 pagestyle = tclass.pagestyle();
1439 use_default_options = true;
1440 // Only if class has a ToC hierarchy
1441 if (tclass.hasTocLevels()) {
1442 secnumdepth = tclass.secnumdepth();
1443 tocdepth = tclass.tocdepth();
1448 bool BufferParams::hasClassDefaults() const
1450 DocumentClass const & tclass = documentClass();
1452 return sides == tclass.sides()
1453 && columns == tclass.columns()
1454 && pagestyle == tclass.pagestyle()
1455 && use_default_options
1456 && secnumdepth == tclass.secnumdepth()
1457 && tocdepth == tclass.tocdepth();
1461 DocumentClass const & BufferParams::documentClass() const
1467 DocumentClass const * BufferParams::documentClassPtr() const {
1472 void BufferParams::setDocumentClass(DocumentClass const * const tc) {
1473 // evil, but this function is evil
1474 doc_class_ = const_cast<DocumentClass *>(tc);
1478 bool BufferParams::removeBadModules()
1480 // we'll write a new list of modules, since we can't just remove them,
1481 // as that would invalidate our iterators
1482 list<string> oldModules = getModules();
1483 clearLayoutModules();
1485 list<string> const & provmods = baseClass()->providedModules();
1486 list<string> const & exclmods = baseClass()->excludedModules();
1487 bool consistent = true; // set to false if we have to do anything
1489 list<string>::const_iterator oit = oldModules.begin();
1490 list<string>::const_iterator const oen = oldModules.end();
1491 for (; oit != oen; ++oit) {
1492 string const & modname = *oit;
1493 // skip modules that the class provides
1494 if (find(provmods.begin(), provmods.end(), modname) != provmods.end()) {
1495 LYXERR0("Module `" << modname << "' dropped because provided by document class.");
1499 // are we excluded by the document class?
1500 if (find(exclmods.begin(), exclmods.end(), modname) != exclmods.end()) {
1501 LYXERR0("Module `" << modname << "' dropped because excluded by document class.");
1505 // determine whether some provided module excludes us or we exclude it
1506 list<string>::const_iterator pit = provmods.begin();
1507 list<string>::const_iterator const pen = provmods.end();
1508 bool excluded = false;
1509 for (; !excluded && pit != pen; ++pit) {
1510 if (!LyXModule::areCompatible(modname, *pit)) {
1511 LYXERR0("Module " << modname <<
1512 " dropped becuase it conflicts with provided module `" << *pit << "'.");
1519 layoutModules_.push_back(modname);
1525 void BufferParams::addDefaultModules()
1527 // add any default modules not already in use
1528 list<string> const & mods = baseClass()->defaultModules();
1529 list<string>::const_iterator mit = mods.begin();
1530 list<string>::const_iterator men = mods.end();
1532 // We want to insert the default modules at the beginning of
1533 // the list, but also to insert them in the correct order.
1534 // The obvious thing to do would be to collect them and then
1535 // insert them, but that doesn't work because a later default
1536 // module may require an earlier one, and then the test below
1537 // moduleCanBeAdded(modname)
1538 // will fail. So we have to do it a more complicated way.
1539 list<string>::iterator insertpos = layoutModules_.begin();
1542 for (; mit != men; mit++) {
1543 string const & modName = *mit;
1544 // make sure the user hasn't removed it
1545 if (find(removedModules_.begin(), removedModules_.end(), modName) !=
1546 removedModules_.end()) {
1547 LYXERR(Debug::TCLASS, "Default module `" << modName <<
1548 "' not added because removed by user.");
1552 if (!moduleCanBeAdded(modName)) {
1553 // FIXME This could be because it's already present, so we should
1554 // probably return something indicating that.
1555 LYXERR(Debug::TCLASS, "Default module `" << modName <<
1556 "' could not be added.");
1559 LYXERR(Debug::TCLASS, "Default module `" << modName << "' added.");
1560 layoutModules_.insert(insertpos, modName);
1561 // now we reset insertpos
1563 insertpos = layoutModules_.begin();
1564 advance(insertpos, numinserts);
1569 bool BufferParams::checkModuleConsistency() {
1570 bool consistent = true;
1571 // Perform a consistency check on the set of modules. We need to make
1572 // sure that none of the modules exclude each other and that requires
1574 list<string> oldModules = getModules();
1575 clearLayoutModules();
1576 list<string>::const_iterator oit = oldModules.begin();
1577 list<string>::const_iterator oen = oldModules.end();
1578 list<string> const & provmods = baseClass()->providedModules();
1579 for (; oit != oen; ++oit) {
1580 string const & modname = *oit;
1581 bool excluded = false;
1582 // Determine whether some prior module excludes us, or we exclude it
1583 list<string>::const_iterator lit = layoutModules_.begin();
1584 list<string>::const_iterator len = layoutModules_.end();
1585 for (; !excluded && lit != len; ++lit) {
1586 if (!LyXModule::areCompatible(modname, *lit)) {
1588 LYXERR0("Module " << modname <<
1589 " dropped because it is excluded by prior module " << *lit);
1597 // determine whether some provided module or some prior module
1598 // satisfies our requirements
1599 LyXModule const * const oldmod = moduleList[modname];
1601 LYXERR0("Default module " << modname <<
1602 " added although it is unavailable and can't check requirements.");
1606 vector<string> const & reqs = oldmod->getRequiredModules();
1607 if (!reqs.empty()) {
1608 // we now set excluded to true, meaning that we haven't
1609 // yet found a required module.
1611 vector<string>::const_iterator rit = reqs.begin();
1612 vector<string>::const_iterator ren = reqs.end();
1613 for (; rit != ren; ++rit) {
1614 string const reqmod = *rit;
1615 if (find(provmods.begin(), provmods.end(), reqmod) !=
1620 if (find(layoutModules_.begin(), layoutModules_.end(), reqmod) !=
1621 layoutModules_.end()) {
1629 LYXERR0("Module " << modname << " dropped because requirements not met.");
1631 LYXERR(Debug::TCLASS, "Module " << modname << " passed consistency check.");
1632 layoutModules_.push_back(modname);
1639 bool BufferParams::setBaseClass(string const & classname)
1641 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
1642 LayoutFileList & bcl = LayoutFileList::get();
1643 if (!bcl.haveClass(classname)) {
1645 bformat(_("The document class %1$s could not be found. "
1646 "A default textclass with default layouts will be used. "
1647 "LyX might not be able to produce output unless a correct "
1648 "textclass is selected from the document settings dialog."),
1649 from_utf8(classname));
1650 frontend::Alert::error(_("Document class not found"), s);
1651 bcl.addEmptyClass(classname);
1654 bool const success = bcl[classname].load();
1657 bformat(_("The document class %1$s could not be loaded."),
1658 from_utf8(classname));
1659 frontend::Alert::error(_("Could not load class"), s);
1663 pimpl_->baseClass_ = classname;
1664 // the previous document class may have loaded some modules that the
1665 // new one excludes, and the new class may provide, etc, some that
1666 // conflict with ones that were already loaded. So we need to go
1667 // through the list and fix everything. I suppose there are various
1668 // ways this could be done, but the following seems to work at the
1669 // moment. (Thanks to Philippe Charpentier for helping work out all
1672 // first, we remove any modules the new document class itself provides,
1673 // those it excludes, and those that conflict with ones it excludes.
1674 // this has to be done first because, otherwise, a module we're about
1675 // to remove could prevent a default module from being added.
1677 // next, we add any default modules the new class provides.
1678 addDefaultModules();
1679 // finally, we perform a general consistency check on the set of
1681 checkModuleConsistency();
1682 // FIXME removeBadModules() and checkModuleConsistency() both return
1683 // a boolean indicating whether something had to be changed. It might
1684 // be worth popping a message to the user if so.
1690 LayoutFile const * BufferParams::baseClass() const
1692 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
1693 return &(LayoutFileList::get()[pimpl_->baseClass_]);
1699 LayoutFileIndex const & BufferParams::baseClassID() const
1701 return pimpl_->baseClass_;
1705 void BufferParams::makeDocumentClass()
1710 doc_class_ = &(DocumentClassBundle::get().newClass(*baseClass()));
1712 // FIXME It might be worth loading the children's modules here,
1713 // just as we load their bibliographies and such, instead of just
1714 // doing a check in InsetInclude.
1715 LayoutModuleList::const_iterator it = layoutModules_.begin();
1716 for (; it != layoutModules_.end(); it++) {
1717 string const modName = *it;
1718 LyXModule * lm = moduleList[modName];
1720 docstring const msg =
1721 bformat(_("The module %1$s has been requested by\n"
1722 "this document but has not been found in the list of\n"
1723 "available modules. If you recently installed it, you\n"
1724 "probably need to reconfigure LyX.\n"), from_utf8(modName));
1725 frontend::Alert::warning(_("Module not available"),
1726 msg + _("Some layouts may not be available."));
1727 LYXERR0("BufferParams::makeDocumentClass(): Module " <<
1728 modName << " requested but not found in module list.");
1731 if (!lm->isAvailable()) {
1732 docstring const msg =
1733 bformat(_("The module %1$s requires a package that is\n"
1734 "not available in your LaTeX installation. LaTeX output\n"
1735 "may not be possible.\n"), from_utf8(modName));
1736 frontend::Alert::warning(_("Package not available"), msg);
1738 FileName layout_file = libFileSearch("layouts", lm->getFilename());
1739 if (!doc_class_->read(layout_file, TextClass::MODULE)) {
1740 docstring const msg =
1741 bformat(_("Error reading module %1$s\n"), from_utf8(modName));
1742 frontend::Alert::warning(_("Read Error"), msg);
1745 if (!local_layout.empty()) {
1746 if (!doc_class_->read(local_layout, TextClass::MODULE)) {
1747 docstring const msg = _("Error reading internal layout information");
1748 frontend::Alert::warning(_("Read Error"), msg);
1754 bool BufferParams::moduleCanBeAdded(string const & modName) const
1756 // Is the module already present?
1757 LayoutModuleList::const_iterator it = layoutModules_.begin();
1758 LayoutModuleList::const_iterator end = layoutModules_.end();
1759 for (; it != end; it++)
1763 LyXModule const * const lm = moduleList[modName];
1767 // Is this module explicitly excluded by the document class?
1768 list<string>::const_iterator const exclmodstart =
1769 baseClass()->excludedModules().begin();
1770 list<string>::const_iterator const exclmodend =
1771 baseClass()->excludedModules().end();
1772 if (find(exclmodstart, exclmodend, modName) != exclmodend)
1775 // Is this module already provided by the document class?
1776 list<string>::const_iterator const provmodstart =
1777 baseClass()->providedModules().begin();
1778 list<string>::const_iterator const provmodend =
1779 baseClass()->providedModules().end();
1780 if (find(provmodstart, provmodend, modName) != provmodend)
1783 // Check for conflicts with used modules
1784 // first the provided modules...
1785 list<string>::const_iterator provmodit = provmodstart;
1786 for (; provmodit != provmodend; ++provmodit) {
1787 if (!LyXModule::areCompatible(modName, *provmodit))
1790 // and then the selected modules
1791 LayoutModuleList::const_iterator mit = getModules().begin();
1792 LayoutModuleList::const_iterator const men = getModules().end();
1793 for (; mit != men; ++mit)
1794 if (!LyXModule::areCompatible(modName, *mit))
1797 // Check whether some required module is available
1798 vector<string> const reqs = lm->getRequiredModules();
1802 mit = getModules().begin(); // reset
1803 vector<string>::const_iterator rit = reqs.begin();
1804 vector<string>::const_iterator ren = reqs.end();
1805 bool foundone = false;
1806 for (; rit != ren; ++rit) {
1807 if (find(mit, men, *rit) != men ||
1808 find(provmodstart, provmodend, *rit) != provmodend) {
1818 bool BufferParams::addLayoutModule(string const & modName)
1820 LayoutModuleList::const_iterator it = layoutModules_.begin();
1821 LayoutModuleList::const_iterator end = layoutModules_.end();
1822 for (; it != end; it++)
1825 layoutModules_.push_back(modName);
1830 Font const BufferParams::getFont() const
1832 FontInfo f = documentClass().defaultfont();
1833 if (fontsDefaultFamily == "rmdefault")
1834 f.setFamily(ROMAN_FAMILY);
1835 else if (fontsDefaultFamily == "sfdefault")
1836 f.setFamily(SANS_FAMILY);
1837 else if (fontsDefaultFamily == "ttdefault")
1838 f.setFamily(TYPEWRITER_FAMILY);
1839 return Font(f, language);
1843 void BufferParams::readPreamble(Lexer & lex)
1845 if (lex.getString() != "\\begin_preamble")
1846 lyxerr << "Error (BufferParams::readPreamble):"
1847 "consistency check failed." << endl;
1849 preamble = lex.getLongString("\\end_preamble");
1853 void BufferParams::readLocalLayout(Lexer & lex)
1855 if (lex.getString() != "\\begin_local_layout")
1856 lyxerr << "Error (BufferParams::readLocalLayout):"
1857 "consistency check failed." << endl;
1859 local_layout = lex.getLongString("\\end_local_layout");
1863 void BufferParams::readLanguage(Lexer & lex)
1865 if (!lex.next()) return;
1867 string const tmptok = lex.getString();
1869 // check if tmptok is part of tex_babel in tex-defs.h
1870 language = languages.getLanguage(tmptok);
1872 // Language tmptok was not found
1873 language = default_language;
1874 lyxerr << "Warning: Setting language `"
1875 << tmptok << "' to `" << language->lang()
1881 void BufferParams::readGraphicsDriver(Lexer & lex)
1886 string const tmptok = lex.getString();
1887 // check if tmptok is part of tex_graphics in tex_defs.h
1890 string const test = tex_graphics[n++];
1892 if (test == tmptok) {
1893 graphicsDriver = tmptok;
1898 "Warning: graphics driver `$$Token' not recognized!\n"
1899 " Setting graphics driver to `default'.\n");
1900 graphicsDriver = "default";
1907 void BufferParams::readBullets(Lexer & lex)
1912 int const index = lex.getInteger();
1914 int temp_int = lex.getInteger();
1915 user_defined_bullet(index).setFont(temp_int);
1916 temp_bullet(index).setFont(temp_int);
1918 user_defined_bullet(index).setCharacter(temp_int);
1919 temp_bullet(index).setCharacter(temp_int);
1921 user_defined_bullet(index).setSize(temp_int);
1922 temp_bullet(index).setSize(temp_int);
1926 void BufferParams::readBulletsLaTeX(Lexer & lex)
1928 // The bullet class should be able to read this.
1931 int const index = lex.getInteger();
1933 docstring const temp_str = lex.getDocString();
1935 user_defined_bullet(index).setText(temp_str);
1936 temp_bullet(index).setText(temp_str);
1940 void BufferParams::readModules(Lexer & lex)
1942 if (!lex.eatLine()) {
1943 lyxerr << "Error (BufferParams::readModules):"
1944 "Unexpected end of input." << endl;
1948 string mod = lex.getString();
1949 if (mod == "\\end_modules")
1951 addLayoutModule(mod);
1957 void BufferParams::readRemovedModules(Lexer & lex)
1959 if (!lex.eatLine()) {
1960 lyxerr << "Error (BufferParams::readRemovedModules):"
1961 "Unexpected end of input." << endl;
1965 string mod = lex.getString();
1966 if (mod == "\\end_removed_modules")
1968 removedModules_.insert(mod);
1971 // now we want to remove any removed modules that were previously
1972 // added. normally, that will be because default modules were added in
1973 // setBaseClass(), which gets called when \textclass is read at the
1974 // start of the read.
1975 set<string>::const_iterator rit = removedModules_.begin();
1976 set<string>::const_iterator const ren = removedModules_.end();
1977 for (; rit != ren; rit++) {
1978 LayoutModuleList::iterator const mit = layoutModules_.begin();
1979 LayoutModuleList::iterator const men = layoutModules_.end();
1980 LayoutModuleList::iterator found = find(mit, men, *rit);
1983 layoutModules_.erase(found);
1988 string BufferParams::paperSizeName(PapersizePurpose purpose) const
1990 char real_papersize = papersize;
1991 if (real_papersize == PAPER_DEFAULT)
1992 real_papersize = lyxrc.default_papersize;
1994 switch (real_papersize) {
1996 // could be anything, so don't guess
1998 case PAPER_CUSTOM: {
1999 if (purpose == XDVI && !paperwidth.empty() &&
2000 !paperheight.empty()) {
2001 // heightxwidth<unit>
2002 string first = paperwidth;
2003 string second = paperheight;
2004 if (orientation == ORIENTATION_LANDSCAPE)
2007 return first.erase(first.length() - 2)
2019 // dvips and dvipdfm do not know this
2020 if (purpose == DVIPS || purpose == DVIPDFM)
2024 // dvipdfm does not know this
2025 if (purpose == DVIPDFM)
2029 // dvipdfm does not know this
2030 if (purpose == DVIPDFM)
2033 case PAPER_USEXECUTIVE:
2034 // dvipdfm does not know this
2035 if (purpose == DVIPDFM)
2040 case PAPER_USLETTER:
2042 if (purpose == XDVI)
2049 string const BufferParams::dvips_options() const
2054 && papersize == PAPER_CUSTOM
2055 && !lyxrc.print_paper_dimension_flag.empty()
2056 && !paperwidth.empty()
2057 && !paperheight.empty()) {
2058 // using a custom papersize
2059 result = lyxrc.print_paper_dimension_flag;
2060 result += ' ' + paperwidth;
2061 result += ',' + paperheight;
2063 string const paper_option = paperSizeName(DVIPS);
2064 if (!paper_option.empty() && (paper_option != "letter" ||
2065 orientation != ORIENTATION_LANDSCAPE)) {
2066 // dvips won't accept -t letter -t landscape.
2067 // In all other cases, include the paper size
2069 result = lyxrc.print_paper_flag;
2070 result += ' ' + paper_option;
2073 if (orientation == ORIENTATION_LANDSCAPE &&
2074 papersize != PAPER_CUSTOM)
2075 result += ' ' + lyxrc.print_landscape_flag;
2080 string BufferParams::babelCall(string const & lang_opts) const
2082 string lang_pack = lyxrc.language_package;
2083 if (lang_pack != "\\usepackage{babel}")
2085 // suppress the babel call when there is no babel language defined
2086 // for the document language in the lib/languages file and if no
2087 // other languages are used (lang_opts is then empty)
2088 if (lang_opts.empty())
2090 // If Vietnamese is used, babel must directly be loaded with the
2091 // language options, see
2092 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
2093 size_t viet = lang_opts.find("vietnam");
2094 // viet = string::npos when not found
2095 // the same is for all other languages that are not directly supported by
2096 // babel, but where LaTeX-packages add babel support.
2097 // this is currently the case for Latvian, Lithuanian, and Mongolian
2098 size_t latvian = lang_opts.find("latvian");
2099 size_t lithu = lang_opts.find("lithuanian");
2100 size_t mongo = lang_opts.find("mongolian");
2101 // If Japanese is used, babel must directly be loaded with the
2102 // language options, see
2103 // http://bugzilla.lyx.org/show_bug.cgi?id=4597#c4
2104 size_t japan = lang_opts.find("japanese");
2105 if (!lyxrc.language_global_options || viet != string::npos
2106 || japan != string::npos || latvian != string::npos
2107 || lithu != string::npos || mongo != string::npos)
2108 return "\\usepackage[" + lang_opts + "]{babel}";
2113 docstring BufferParams::getGraphicsDriver(string const & package) const
2117 if (package == "geometry") {
2118 if (graphicsDriver == "dvips"
2119 || graphicsDriver == "dvipdfm"
2120 || graphicsDriver == "pdftex"
2121 || graphicsDriver == "vtex")
2122 result = from_ascii(graphicsDriver);
2123 else if (graphicsDriver == "dvipdfmx")
2124 result = from_ascii("dvipdfm");
2131 void BufferParams::writeEncodingPreamble(odocstream & os,
2132 LaTeXFeatures & features, TexRow & texrow) const
2134 if (inputenc == "auto") {
2135 string const doc_encoding =
2136 language->encoding()->latexName();
2137 Encoding::Package const package =
2138 language->encoding()->package();
2140 // Create a list with all the input encodings used
2142 set<string> encodings =
2143 features.getEncodingSet(doc_encoding);
2145 // If the "japanese" package (i.e. pLaTeX) is used,
2146 // inputenc must be omitted.
2147 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
2148 if (package == Encoding::japanese)
2149 features.require("japanese");
2151 if ((!encodings.empty() || package == Encoding::inputenc)
2152 && !features.isRequired("japanese")) {
2153 os << "\\usepackage[";
2154 set<string>::const_iterator it = encodings.begin();
2155 set<string>::const_iterator const end = encodings.end();
2157 os << from_ascii(*it);
2160 for (; it != end; ++it)
2161 os << ',' << from_ascii(*it);
2162 if (package == Encoding::inputenc) {
2163 if (!encodings.empty())
2165 os << from_ascii(doc_encoding);
2167 os << "]{inputenc}\n";
2170 if (package == Encoding::CJK || features.mustProvide("CJK")) {
2171 if (language->encoding()->name() == "utf8-cjk"
2172 && features.isAvailable("CJKutf8"))
2173 os << "\\usepackage{CJKutf8}\n";
2175 os << "\\usepackage{CJK}\n";
2178 } else if (inputenc != "default") {
2179 switch (encoding().package()) {
2180 case Encoding::none:
2181 case Encoding::japanese:
2183 case Encoding::inputenc:
2184 // do not load inputenc if japanese is used
2185 if (features.isRequired("japanese"))
2187 os << "\\usepackage[" << from_ascii(inputenc)
2192 if (encoding().name() == "utf8-cjk"
2193 && features.isAvailable("CJKutf8"))
2194 os << "\\usepackage{CJKutf8}\n";
2196 os << "\\usepackage{CJK}\n";
2202 // The encoding "armscii8" (for Armenian) is only available when
2203 // the package "armtex" is loaded.
2204 if (language->encoding()->latexName() == "armscii8"
2205 || inputenc == "armscii8") {
2206 os << "\\usepackage{armtex}\n";
2212 string const BufferParams::loadFonts(string const & rm,
2213 string const & sf, string const & tt,
2214 bool const & sc, bool const & osf,
2215 int const & sfscale, int const & ttscale) const
2217 /* The LaTeX font world is in a flux. In the PSNFSS font interface,
2218 several packages have been replaced by others, that might not
2219 be installed on every system. We have to take care for that
2220 (see psnfss.pdf). We try to support all psnfss fonts as well
2221 as the fonts that have become de facto standard in the LaTeX
2222 world (e.g. Latin Modern). We do not support obsolete fonts
2223 (like PSLatex). In general, it should be possible to mix any
2224 rm font with any sf or tt font, respectively. (JSpitzm)
2226 -- separate math fonts.
2229 if (rm == "default" && sf == "default" && tt == "default")
2236 // Computer Modern (must be explicitely selectable -- there might be classes
2237 // that define a different default font!
2239 os << "\\renewcommand{\\rmdefault}{cmr}\n";
2240 // osf for Computer Modern needs eco.sty
2242 os << "\\usepackage{eco}\n";
2244 // Latin Modern Roman
2245 else if (rm == "lmodern")
2246 os << "\\usepackage{lmodern}\n";
2248 else if (rm == "ae") {
2249 // not needed when using OT1 font encoding.
2250 if (lyxrc.fontenc != "default")
2251 os << "\\usepackage{ae,aecompl}\n";
2254 else if (rm == "times") {
2255 // try to load the best available package
2256 if (LaTeXFeatures::isAvailable("mathptmx"))
2257 os << "\\usepackage{mathptmx}\n";
2258 else if (LaTeXFeatures::isAvailable("mathptm"))
2259 os << "\\usepackage{mathptm}\n";
2261 os << "\\usepackage{times}\n";
2264 else if (rm == "palatino") {
2265 // try to load the best available package
2266 if (LaTeXFeatures::isAvailable("mathpazo")) {
2267 os << "\\usepackage";
2273 // "osf" includes "sc"!
2277 os << "{mathpazo}\n";
2279 else if (LaTeXFeatures::isAvailable("mathpple"))
2280 os << "\\usepackage{mathpple}\n";
2282 os << "\\usepackage{palatino}\n";
2285 else if (rm == "utopia") {
2286 // fourier supersedes utopia.sty, but does
2287 // not work with OT1 encoding.
2288 if (LaTeXFeatures::isAvailable("fourier")
2289 && lyxrc.fontenc != "default") {
2290 os << "\\usepackage";
2301 os << "{fourier}\n";
2304 os << "\\usepackage{utopia}\n";
2306 // Bera (complete fontset)
2307 else if (rm == "bera" && sf == "default" && tt == "default")
2308 os << "\\usepackage{bera}\n";
2310 else if (rm != "default")
2311 os << "\\usepackage" << "{" << rm << "}\n";
2314 // Helvetica, Bera Sans
2315 if (sf == "helvet" || sf == "berasans") {
2317 os << "\\usepackage[scaled=" << float(sfscale) / 100
2318 << "]{" << sf << "}\n";
2320 os << "\\usepackage{" << sf << "}\n";
2323 else if (sf == "avant")
2324 os << "\\usepackage{" << sf << "}\n";
2325 // Computer Modern, Latin Modern, CM Bright
2326 else if (sf != "default")
2327 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
2329 // monospaced/typewriter
2330 // Courier, LuxiMono
2331 if (tt == "luximono" || tt == "beramono") {
2333 os << "\\usepackage[scaled=" << float(ttscale) / 100
2334 << "]{" << tt << "}\n";
2336 os << "\\usepackage{" << tt << "}\n";
2339 else if (tt == "courier" )
2340 os << "\\usepackage{" << tt << "}\n";
2341 // Computer Modern, Latin Modern, CM Bright
2342 else if (tt != "default")
2343 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
2349 Encoding const & BufferParams::encoding() const
2351 if (inputenc == "auto" || inputenc == "default")
2352 return *language->encoding();
2353 Encoding const * const enc = encodings.fromLaTeXName(inputenc);
2356 LYXERR0("Unknown inputenc value `" << inputenc
2357 << "'. Using `auto' instead.");
2358 return *language->encoding();
2362 CiteEngine BufferParams::citeEngine() const
2364 // FIXME the class should provide the numerical/
2365 // authoryear choice
2366 if (documentClass().provides("natbib")
2367 && cite_engine_ != ENGINE_NATBIB_NUMERICAL)
2368 return ENGINE_NATBIB_AUTHORYEAR;
2369 return cite_engine_;
2373 void BufferParams::setCiteEngine(CiteEngine cite_engine)
2375 cite_engine_ = cite_engine;