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';
1422 docstring const i18npreamble = features.getTClassI18nPreamble(use_babel);
1423 if (!i18npreamble.empty())
1424 lyxpreamble += i18npreamble + '\n';
1427 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1428 for (int j = 0; j != nlines; ++j) {
1437 void BufferParams::useClassDefaults()
1439 DocumentClass const & tclass = documentClass();
1441 sides = tclass.sides();
1442 columns = tclass.columns();
1443 pagestyle = tclass.pagestyle();
1444 use_default_options = true;
1445 // Only if class has a ToC hierarchy
1446 if (tclass.hasTocLevels()) {
1447 secnumdepth = tclass.secnumdepth();
1448 tocdepth = tclass.tocdepth();
1453 bool BufferParams::hasClassDefaults() const
1455 DocumentClass const & tclass = documentClass();
1457 return sides == tclass.sides()
1458 && columns == tclass.columns()
1459 && pagestyle == tclass.pagestyle()
1460 && use_default_options
1461 && secnumdepth == tclass.secnumdepth()
1462 && tocdepth == tclass.tocdepth();
1466 DocumentClass const & BufferParams::documentClass() const
1472 DocumentClass const * BufferParams::documentClassPtr() const {
1477 void BufferParams::setDocumentClass(DocumentClass const * const tc) {
1478 // evil, but this function is evil
1479 doc_class_ = const_cast<DocumentClass *>(tc);
1483 bool BufferParams::removeBadModules()
1485 // we'll write a new list of modules, since we can't just remove them,
1486 // as that would invalidate our iterators
1487 LayoutModuleList oldModules = layoutModules_;
1488 clearLayoutModules();
1490 LayoutModuleList const & provmods = baseClass()->providedModules();
1491 LayoutModuleList const & exclmods = baseClass()->excludedModules();
1492 bool consistent = true; // set to false if we have to do anything
1494 LayoutModuleList::const_iterator oit = oldModules.begin();
1495 LayoutModuleList::const_iterator const oen = oldModules.end();
1496 for (; oit != oen; ++oit) {
1497 string const & modname = *oit;
1498 // skip modules that the class provides
1499 if (find(provmods.begin(), provmods.end(), modname) != provmods.end()) {
1500 LYXERR0("Module `" << modname << "' dropped because provided by document class.");
1504 // are we excluded by the document class?
1505 if (find(exclmods.begin(), exclmods.end(), modname) != exclmods.end()) {
1506 LYXERR0("Module `" << modname << "' dropped because excluded by document class.");
1510 // determine whether some provided module excludes us or we exclude it
1511 LayoutModuleList::const_iterator pit = provmods.begin();
1512 LayoutModuleList::const_iterator const pen = provmods.end();
1513 bool excluded = false;
1514 for (; !excluded && pit != pen; ++pit) {
1515 if (!LyXModule::areCompatible(modname, *pit)) {
1516 LYXERR0("Module " << modname <<
1517 " dropped becuase it conflicts with provided module `" << *pit << "'.");
1524 layoutModules_.push_back(modname);
1530 void BufferParams::addDefaultModules()
1532 // add any default modules not already in use
1533 LayoutModuleList const & mods = baseClass()->defaultModules();
1534 LayoutModuleList::const_iterator mit = mods.begin();
1535 LayoutModuleList::const_iterator men = mods.end();
1537 // We want to insert the default modules at the beginning of
1538 // the list, but also to insert them in the correct order.
1539 // The obvious thing to do would be to collect them and then
1540 // insert them, but that doesn't work because a later default
1541 // module may require an earlier one, and then the test below
1542 // moduleCanBeAdded(modname)
1543 // will fail. So we have to do it a more complicated way.
1544 LayoutModuleList::iterator insertpos = layoutModules_.begin();
1547 for (; mit != men; mit++) {
1548 string const & modName = *mit;
1549 // make sure the user hasn't removed it
1550 if (find(removedModules_.begin(), removedModules_.end(), modName) !=
1551 removedModules_.end()) {
1552 LYXERR(Debug::TCLASS, "Default module `" << modName <<
1553 "' not added because removed by user.");
1557 if (!moduleCanBeAdded(modName)) {
1558 // FIXME This could be because it's already present, so we should
1559 // probably return something indicating that.
1560 LYXERR(Debug::TCLASS, "Default module `" << modName <<
1561 "' could not be added.");
1564 LYXERR(Debug::TCLASS, "Default module `" << modName << "' added.");
1565 layoutModules_.insert(insertpos, modName);
1566 // now we reset insertpos
1568 insertpos = layoutModules_.begin();
1569 advance(insertpos, numinserts);
1574 // Perform a consistency check on the set of modules. We need to make
1575 // sure that none of the modules exclude each other and that requires
1577 bool BufferParams::checkModuleConsistency() {
1578 bool consistent = true;
1579 LayoutModuleList oldModules = layoutModules_;
1580 clearLayoutModules();
1581 LayoutModuleList::const_iterator oit = oldModules.begin();
1582 LayoutModuleList::const_iterator oen = oldModules.end();
1583 LayoutModuleList const & provmods = baseClass()->providedModules();
1584 for (; oit != oen; ++oit) {
1585 string const & modname = *oit;
1586 bool excluded = false;
1587 // Determine whether some prior module excludes us, or we exclude it
1588 LayoutModuleList::const_iterator lit = layoutModules_.begin();
1589 LayoutModuleList::const_iterator len = layoutModules_.end();
1590 for (; !excluded && lit != len; ++lit) {
1591 if (!LyXModule::areCompatible(modname, *lit)) {
1593 LYXERR0("Module " << modname <<
1594 " dropped because it is excluded by prior module " << *lit);
1602 // determine whether some provided module or some prior module
1603 // satisfies our requirements
1604 LyXModule const * const oldmod = moduleList[modname];
1606 LYXERR0("Default module " << modname <<
1607 " added although it is unavailable and can't check requirements.");
1611 vector<string> const & reqs = oldmod->getRequiredModules();
1612 if (!reqs.empty()) {
1613 // we now set excluded to true, meaning that we haven't
1614 // yet found a required module.
1616 vector<string>::const_iterator rit = reqs.begin();
1617 vector<string>::const_iterator ren = reqs.end();
1618 for (; rit != ren; ++rit) {
1619 string const reqmod = *rit;
1620 if (find(provmods.begin(), provmods.end(), reqmod) !=
1625 if (find(layoutModules_.begin(), layoutModules_.end(), reqmod) !=
1626 layoutModules_.end()) {
1634 LYXERR0("Module " << modname << " dropped because requirements not met.");
1636 LYXERR(Debug::TCLASS, "Module " << modname << " passed consistency check.");
1637 layoutModules_.push_back(modname);
1644 bool BufferParams::setBaseClass(string const & classname)
1646 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
1647 LayoutFileList & bcl = LayoutFileList::get();
1648 if (!bcl.haveClass(classname)) {
1650 bformat(_("The document class %1$s could not be found. "
1651 "A default textclass with default layouts will be used. "
1652 "LyX might not be able to produce output unless a correct "
1653 "textclass is selected from the document settings dialog."),
1654 from_utf8(classname));
1655 frontend::Alert::error(_("Document class not found"), s);
1656 bcl.addEmptyClass(classname);
1659 bool const success = bcl[classname].load();
1662 bformat(_("The document class %1$s could not be loaded."),
1663 from_utf8(classname));
1664 frontend::Alert::error(_("Could not load class"), s);
1668 pimpl_->baseClass_ = classname;
1669 // the previous document class may have loaded some modules that the
1670 // new one excludes, and the new class may provide, etc, some that
1671 // conflict with ones that were already loaded. So we need to go
1672 // through the list and fix everything. I suppose there are various
1673 // ways this could be done, but the following seems to work at the
1674 // moment. (Thanks to Philippe Charpentier for helping work out all
1677 // first, we remove any modules the new document class itself provides,
1678 // those it excludes, and those that conflict with ones it excludes.
1679 // this has to be done first because, otherwise, a module we're about
1680 // to remove could prevent a default module from being added.
1682 // next, we add any default modules the new class provides.
1683 addDefaultModules();
1684 // finally, we perform a general consistency check on the set of
1686 checkModuleConsistency();
1687 // FIXME removeBadModules() and checkModuleConsistency() both return
1688 // a boolean indicating whether something had to be changed. It might
1689 // be worth popping a message to the user if so.
1695 LayoutFile const * BufferParams::baseClass() const
1697 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
1698 return &(LayoutFileList::get()[pimpl_->baseClass_]);
1704 LayoutFileIndex const & BufferParams::baseClassID() const
1706 return pimpl_->baseClass_;
1710 void BufferParams::makeDocumentClass()
1715 doc_class_ = &(DocumentClassBundle::get().makeDocumentClass(*baseClass(), layoutModules_));
1717 if (!local_layout.empty()) {
1718 if (!doc_class_->read(local_layout, TextClass::MODULE)) {
1719 docstring const msg = _("Error reading internal layout information");
1720 frontend::Alert::warning(_("Read Error"), msg);
1726 bool BufferParams::moduleCanBeAdded(string const & modName) const
1728 // Is the module already present?
1729 LayoutModuleList::const_iterator it = layoutModules_.begin();
1730 LayoutModuleList::const_iterator end = layoutModules_.end();
1731 for (; it != end; it++)
1735 LyXModule const * const lm = moduleList[modName];
1739 // Is this module explicitly excluded by the document class?
1740 LayoutModuleList::const_iterator const exclmodstart =
1741 baseClass()->excludedModules().begin();
1742 LayoutModuleList::const_iterator const exclmodend =
1743 baseClass()->excludedModules().end();
1744 if (find(exclmodstart, exclmodend, modName) != exclmodend)
1747 // Is this module already provided by the document class?
1748 LayoutModuleList::const_iterator const provmodstart =
1749 baseClass()->providedModules().begin();
1750 LayoutModuleList::const_iterator const provmodend =
1751 baseClass()->providedModules().end();
1752 if (find(provmodstart, provmodend, modName) != provmodend)
1755 // Check for conflicts with used modules
1756 // first the provided modules...
1757 LayoutModuleList::const_iterator provmodit = provmodstart;
1758 for (; provmodit != provmodend; ++provmodit) {
1759 if (!LyXModule::areCompatible(modName, *provmodit))
1762 // and then the selected modules
1763 LayoutModuleList::const_iterator mit = layoutModules_.begin();
1764 LayoutModuleList::const_iterator const men = layoutModules_.end();
1765 for (; mit != men; ++mit)
1766 if (!LyXModule::areCompatible(modName, *mit))
1769 // Check whether some required module is available
1770 vector<string> const reqs = lm->getRequiredModules();
1774 mit = layoutModules_.begin(); // reset
1775 vector<string>::const_iterator rit = reqs.begin();
1776 vector<string>::const_iterator ren = reqs.end();
1777 bool foundone = false;
1778 for (; rit != ren; ++rit) {
1779 if (find(mit, men, *rit) != men ||
1780 find(provmodstart, provmodend, *rit) != provmodend) {
1790 bool BufferParams::addLayoutModule(string const & modName)
1792 LayoutModuleList::const_iterator it = layoutModules_.begin();
1793 LayoutModuleList::const_iterator end = layoutModules_.end();
1794 for (; it != end; it++)
1797 layoutModules_.push_back(modName);
1802 Font const BufferParams::getFont() const
1804 FontInfo f = documentClass().defaultfont();
1805 if (fontsDefaultFamily == "rmdefault")
1806 f.setFamily(ROMAN_FAMILY);
1807 else if (fontsDefaultFamily == "sfdefault")
1808 f.setFamily(SANS_FAMILY);
1809 else if (fontsDefaultFamily == "ttdefault")
1810 f.setFamily(TYPEWRITER_FAMILY);
1811 return Font(f, language);
1815 void BufferParams::readPreamble(Lexer & lex)
1817 if (lex.getString() != "\\begin_preamble")
1818 lyxerr << "Error (BufferParams::readPreamble):"
1819 "consistency check failed." << endl;
1821 preamble = lex.getLongString("\\end_preamble");
1825 void BufferParams::readLocalLayout(Lexer & lex)
1827 if (lex.getString() != "\\begin_local_layout")
1828 lyxerr << "Error (BufferParams::readLocalLayout):"
1829 "consistency check failed." << endl;
1831 local_layout = lex.getLongString("\\end_local_layout");
1835 void BufferParams::readLanguage(Lexer & lex)
1837 if (!lex.next()) return;
1839 string const tmptok = lex.getString();
1841 // check if tmptok is part of tex_babel in tex-defs.h
1842 language = languages.getLanguage(tmptok);
1844 // Language tmptok was not found
1845 language = default_language;
1846 lyxerr << "Warning: Setting language `"
1847 << tmptok << "' to `" << language->lang()
1853 void BufferParams::readGraphicsDriver(Lexer & lex)
1858 string const tmptok = lex.getString();
1859 // check if tmptok is part of tex_graphics in tex_defs.h
1862 string const test = tex_graphics[n++];
1864 if (test == tmptok) {
1865 graphicsDriver = tmptok;
1870 "Warning: graphics driver `$$Token' not recognized!\n"
1871 " Setting graphics driver to `default'.\n");
1872 graphicsDriver = "default";
1879 void BufferParams::readBullets(Lexer & lex)
1884 int const index = lex.getInteger();
1886 int temp_int = lex.getInteger();
1887 user_defined_bullet(index).setFont(temp_int);
1888 temp_bullet(index).setFont(temp_int);
1890 user_defined_bullet(index).setCharacter(temp_int);
1891 temp_bullet(index).setCharacter(temp_int);
1893 user_defined_bullet(index).setSize(temp_int);
1894 temp_bullet(index).setSize(temp_int);
1898 void BufferParams::readBulletsLaTeX(Lexer & lex)
1900 // The bullet class should be able to read this.
1903 int const index = lex.getInteger();
1905 docstring const temp_str = lex.getDocString();
1907 user_defined_bullet(index).setText(temp_str);
1908 temp_bullet(index).setText(temp_str);
1912 void BufferParams::readModules(Lexer & lex)
1914 if (!lex.eatLine()) {
1915 lyxerr << "Error (BufferParams::readModules):"
1916 "Unexpected end of input." << endl;
1920 string mod = lex.getString();
1921 if (mod == "\\end_modules")
1923 addLayoutModule(mod);
1929 void BufferParams::readRemovedModules(Lexer & lex)
1931 if (!lex.eatLine()) {
1932 lyxerr << "Error (BufferParams::readRemovedModules):"
1933 "Unexpected end of input." << endl;
1937 string mod = lex.getString();
1938 if (mod == "\\end_removed_modules")
1940 removedModules_.insert(mod);
1943 // now we want to remove any removed modules that were previously
1944 // added. normally, that will be because default modules were added in
1945 // setBaseClass(), which gets called when \textclass is read at the
1946 // start of the read.
1947 set<string>::const_iterator rit = removedModules_.begin();
1948 set<string>::const_iterator const ren = removedModules_.end();
1949 for (; rit != ren; rit++) {
1950 LayoutModuleList::iterator const mit = layoutModules_.begin();
1951 LayoutModuleList::iterator const men = layoutModules_.end();
1952 LayoutModuleList::iterator found = find(mit, men, *rit);
1955 layoutModules_.erase(found);
1960 string BufferParams::paperSizeName(PapersizePurpose purpose) const
1962 char real_papersize = papersize;
1963 if (real_papersize == PAPER_DEFAULT)
1964 real_papersize = lyxrc.default_papersize;
1966 switch (real_papersize) {
1968 // could be anything, so don't guess
1970 case PAPER_CUSTOM: {
1971 if (purpose == XDVI && !paperwidth.empty() &&
1972 !paperheight.empty()) {
1973 // heightxwidth<unit>
1974 string first = paperwidth;
1975 string second = paperheight;
1976 if (orientation == ORIENTATION_LANDSCAPE)
1979 return first.erase(first.length() - 2)
1991 // dvips and dvipdfm do not know this
1992 if (purpose == DVIPS || purpose == DVIPDFM)
1996 // dvipdfm does not know this
1997 if (purpose == DVIPDFM)
2001 // dvipdfm does not know this
2002 if (purpose == DVIPDFM)
2005 case PAPER_USEXECUTIVE:
2006 // dvipdfm does not know this
2007 if (purpose == DVIPDFM)
2012 case PAPER_USLETTER:
2014 if (purpose == XDVI)
2021 string const BufferParams::dvips_options() const
2026 && papersize == PAPER_CUSTOM
2027 && !lyxrc.print_paper_dimension_flag.empty()
2028 && !paperwidth.empty()
2029 && !paperheight.empty()) {
2030 // using a custom papersize
2031 result = lyxrc.print_paper_dimension_flag;
2032 result += ' ' + paperwidth;
2033 result += ',' + paperheight;
2035 string const paper_option = paperSizeName(DVIPS);
2036 if (!paper_option.empty() && (paper_option != "letter" ||
2037 orientation != ORIENTATION_LANDSCAPE)) {
2038 // dvips won't accept -t letter -t landscape.
2039 // In all other cases, include the paper size
2041 result = lyxrc.print_paper_flag;
2042 result += ' ' + paper_option;
2045 if (orientation == ORIENTATION_LANDSCAPE &&
2046 papersize != PAPER_CUSTOM)
2047 result += ' ' + lyxrc.print_landscape_flag;
2052 string BufferParams::babelCall(string const & lang_opts) const
2054 string lang_pack = lyxrc.language_package;
2055 if (lang_pack != "\\usepackage{babel}")
2057 // suppress the babel call when there is no babel language defined
2058 // for the document language in the lib/languages file and if no
2059 // other languages are used (lang_opts is then empty)
2060 if (lang_opts.empty())
2062 // If Vietnamese is used, babel must directly be loaded with the
2063 // language options, see
2064 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
2065 size_t viet = lang_opts.find("vietnam");
2066 // viet = string::npos when not found
2067 // the same is for all other languages that are not directly supported by
2068 // babel, but where LaTeX-packages add babel support.
2069 // this is currently the case for Latvian, Lithuanian, and Mongolian
2070 size_t latvian = lang_opts.find("latvian");
2071 size_t lithu = lang_opts.find("lithuanian");
2072 size_t mongo = lang_opts.find("mongolian");
2073 // If Japanese is used, babel must directly be loaded with the
2074 // language options, see
2075 // http://bugzilla.lyx.org/show_bug.cgi?id=4597#c4
2076 size_t japan = lang_opts.find("japanese");
2077 if (!lyxrc.language_global_options || viet != string::npos
2078 || japan != string::npos || latvian != string::npos
2079 || lithu != string::npos || mongo != string::npos)
2080 return "\\usepackage[" + lang_opts + "]{babel}";
2085 docstring BufferParams::getGraphicsDriver(string const & package) const
2089 if (package == "geometry") {
2090 if (graphicsDriver == "dvips"
2091 || graphicsDriver == "dvipdfm"
2092 || graphicsDriver == "pdftex"
2093 || graphicsDriver == "vtex")
2094 result = from_ascii(graphicsDriver);
2095 else if (graphicsDriver == "dvipdfmx")
2096 result = from_ascii("dvipdfm");
2103 void BufferParams::writeEncodingPreamble(odocstream & os,
2104 LaTeXFeatures & features, TexRow & texrow) const
2106 if (inputenc == "auto") {
2107 string const doc_encoding =
2108 language->encoding()->latexName();
2109 Encoding::Package const package =
2110 language->encoding()->package();
2112 // Create a list with all the input encodings used
2114 set<string> encodings =
2115 features.getEncodingSet(doc_encoding);
2117 // If the "japanese" package (i.e. pLaTeX) is used,
2118 // inputenc must be omitted.
2119 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
2120 if (package == Encoding::japanese)
2121 features.require("japanese");
2123 if ((!encodings.empty() || package == Encoding::inputenc)
2124 && !features.isRequired("japanese")) {
2125 os << "\\usepackage[";
2126 set<string>::const_iterator it = encodings.begin();
2127 set<string>::const_iterator const end = encodings.end();
2129 os << from_ascii(*it);
2132 for (; it != end; ++it)
2133 os << ',' << from_ascii(*it);
2134 if (package == Encoding::inputenc) {
2135 if (!encodings.empty())
2137 os << from_ascii(doc_encoding);
2139 os << "]{inputenc}\n";
2142 if (package == Encoding::CJK || features.mustProvide("CJK")) {
2143 if (language->encoding()->name() == "utf8-cjk"
2144 && features.isAvailable("CJKutf8"))
2145 os << "\\usepackage{CJKutf8}\n";
2147 os << "\\usepackage{CJK}\n";
2150 } else if (inputenc != "default") {
2151 switch (encoding().package()) {
2152 case Encoding::none:
2153 case Encoding::japanese:
2155 case Encoding::inputenc:
2156 // do not load inputenc if japanese is used
2157 if (features.isRequired("japanese"))
2159 os << "\\usepackage[" << from_ascii(inputenc)
2164 if (encoding().name() == "utf8-cjk"
2165 && features.isAvailable("CJKutf8"))
2166 os << "\\usepackage{CJKutf8}\n";
2168 os << "\\usepackage{CJK}\n";
2174 // The encoding "armscii8" (for Armenian) is only available when
2175 // the package "armtex" is loaded.
2176 if (language->encoding()->latexName() == "armscii8"
2177 || inputenc == "armscii8") {
2178 os << "\\usepackage{armtex}\n";
2184 string const BufferParams::loadFonts(string const & rm,
2185 string const & sf, string const & tt,
2186 bool const & sc, bool const & osf,
2187 int const & sfscale, int const & ttscale) const
2189 /* The LaTeX font world is in a flux. In the PSNFSS font interface,
2190 several packages have been replaced by others, that might not
2191 be installed on every system. We have to take care for that
2192 (see psnfss.pdf). We try to support all psnfss fonts as well
2193 as the fonts that have become de facto standard in the LaTeX
2194 world (e.g. Latin Modern). We do not support obsolete fonts
2195 (like PSLatex). In general, it should be possible to mix any
2196 rm font with any sf or tt font, respectively. (JSpitzm)
2198 -- separate math fonts.
2201 if (rm == "default" && sf == "default" && tt == "default")
2208 // Computer Modern (must be explicitely selectable -- there might be classes
2209 // that define a different default font!
2211 os << "\\renewcommand{\\rmdefault}{cmr}\n";
2212 // osf for Computer Modern needs eco.sty
2214 os << "\\usepackage{eco}\n";
2216 // Latin Modern Roman
2217 else if (rm == "lmodern")
2218 os << "\\usepackage{lmodern}\n";
2220 else if (rm == "ae") {
2221 // not needed when using OT1 font encoding.
2222 if (lyxrc.fontenc != "default")
2223 os << "\\usepackage{ae,aecompl}\n";
2226 else if (rm == "times") {
2227 // try to load the best available package
2228 if (LaTeXFeatures::isAvailable("mathptmx"))
2229 os << "\\usepackage{mathptmx}\n";
2230 else if (LaTeXFeatures::isAvailable("mathptm"))
2231 os << "\\usepackage{mathptm}\n";
2233 os << "\\usepackage{times}\n";
2236 else if (rm == "palatino") {
2237 // try to load the best available package
2238 if (LaTeXFeatures::isAvailable("mathpazo")) {
2239 os << "\\usepackage";
2245 // "osf" includes "sc"!
2249 os << "{mathpazo}\n";
2251 else if (LaTeXFeatures::isAvailable("mathpple"))
2252 os << "\\usepackage{mathpple}\n";
2254 os << "\\usepackage{palatino}\n";
2257 else if (rm == "utopia") {
2258 // fourier supersedes utopia.sty, but does
2259 // not work with OT1 encoding.
2260 if (LaTeXFeatures::isAvailable("fourier")
2261 && lyxrc.fontenc != "default") {
2262 os << "\\usepackage";
2273 os << "{fourier}\n";
2276 os << "\\usepackage{utopia}\n";
2278 // Bera (complete fontset)
2279 else if (rm == "bera" && sf == "default" && tt == "default")
2280 os << "\\usepackage{bera}\n";
2282 else if (rm != "default")
2283 os << "\\usepackage" << "{" << rm << "}\n";
2286 // Helvetica, Bera Sans
2287 if (sf == "helvet" || sf == "berasans") {
2289 os << "\\usepackage[scaled=" << float(sfscale) / 100
2290 << "]{" << sf << "}\n";
2292 os << "\\usepackage{" << sf << "}\n";
2295 else if (sf == "avant")
2296 os << "\\usepackage{" << sf << "}\n";
2297 // Computer Modern, Latin Modern, CM Bright
2298 else if (sf != "default")
2299 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
2301 // monospaced/typewriter
2302 // Courier, LuxiMono
2303 if (tt == "luximono" || tt == "beramono") {
2305 os << "\\usepackage[scaled=" << float(ttscale) / 100
2306 << "]{" << tt << "}\n";
2308 os << "\\usepackage{" << tt << "}\n";
2311 else if (tt == "courier" )
2312 os << "\\usepackage{" << tt << "}\n";
2313 // Computer Modern, Latin Modern, CM Bright
2314 else if (tt != "default")
2315 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
2321 Encoding const & BufferParams::encoding() const
2323 if (inputenc == "auto" || inputenc == "default")
2324 return *language->encoding();
2325 Encoding const * const enc = encodings.fromLaTeXName(inputenc);
2328 LYXERR0("Unknown inputenc value `" << inputenc
2329 << "'. Using `auto' instead.");
2330 return *language->encoding();
2334 CiteEngine BufferParams::citeEngine() const
2336 // FIXME the class should provide the numerical/
2337 // authoryear choice
2338 if (documentClass().provides("natbib")
2339 && cite_engine_ != ENGINE_NATBIB_NUMERICAL)
2340 return ENGINE_NATBIB_AUTHORYEAR;
2341 return cite_engine_;
2345 void BufferParams::setCiteEngine(CiteEngine cite_engine)
2347 cite_engine_ = cite_engine;