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", "dvips", "dvitops", "emtex",
88 "ln", "oztex", "textures", "none", ""
97 // Paragraph separation
98 typedef Translator<string, BufferParams::ParagraphSeparation> ParSepTranslator;
101 ParSepTranslator const init_parseptranslator()
103 ParSepTranslator translator
104 (string_paragraph_separation[0], BufferParams::ParagraphIndentSeparation);
105 translator.addPair(string_paragraph_separation[1], BufferParams::ParagraphSkipSeparation);
110 ParSepTranslator const & parseptranslator()
112 static ParSepTranslator translator = init_parseptranslator();
118 typedef Translator<string, InsetQuotes::QuoteLanguage> QuotesLangTranslator;
121 QuotesLangTranslator const init_quoteslangtranslator()
123 QuotesLangTranslator translator
124 (string_quotes_language[0], InsetQuotes::EnglishQuotes);
125 translator.addPair(string_quotes_language[1], InsetQuotes::SwedishQuotes);
126 translator.addPair(string_quotes_language[2], InsetQuotes::GermanQuotes);
127 translator.addPair(string_quotes_language[3], InsetQuotes::PolishQuotes);
128 translator.addPair(string_quotes_language[4], InsetQuotes::FrenchQuotes);
129 translator.addPair(string_quotes_language[5], InsetQuotes::DanishQuotes);
134 QuotesLangTranslator const & quoteslangtranslator()
136 static QuotesLangTranslator translator = init_quoteslangtranslator();
142 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
145 static PaperSizeTranslator initPaperSizeTranslator()
147 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
148 translator.addPair(string_papersize[1], PAPER_CUSTOM);
149 translator.addPair(string_papersize[2], PAPER_USLETTER);
150 translator.addPair(string_papersize[3], PAPER_USLEGAL);
151 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
152 translator.addPair(string_papersize[5], PAPER_A3);
153 translator.addPair(string_papersize[6], PAPER_A4);
154 translator.addPair(string_papersize[7], PAPER_A5);
155 translator.addPair(string_papersize[8], PAPER_B3);
156 translator.addPair(string_papersize[9], PAPER_B4);
157 translator.addPair(string_papersize[10], PAPER_B5);
162 PaperSizeTranslator const & papersizetranslator()
164 static PaperSizeTranslator translator = initPaperSizeTranslator();
170 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
173 PaperOrientationTranslator const init_paperorientationtranslator()
175 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
176 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
181 PaperOrientationTranslator const & paperorientationtranslator()
183 static PaperOrientationTranslator translator = init_paperorientationtranslator();
189 typedef Translator<int, PageSides> SidesTranslator;
192 SidesTranslator const init_sidestranslator()
194 SidesTranslator translator(1, OneSide);
195 translator.addPair(2, TwoSides);
200 SidesTranslator const & sidestranslator()
202 static SidesTranslator translator = init_sidestranslator();
208 typedef Translator<int, BufferParams::Package> PackageTranslator;
211 PackageTranslator const init_packagetranslator()
213 PackageTranslator translator(0, BufferParams::package_off);
214 translator.addPair(1, BufferParams::package_auto);
215 translator.addPair(2, BufferParams::package_on);
220 PackageTranslator const & packagetranslator()
222 static PackageTranslator translator = init_packagetranslator();
228 typedef Translator<string, CiteEngine> CiteEngineTranslator;
231 CiteEngineTranslator const init_citeenginetranslator()
233 CiteEngineTranslator translator("basic", ENGINE_BASIC);
234 translator.addPair("natbib_numerical", ENGINE_NATBIB_NUMERICAL);
235 translator.addPair("natbib_authoryear", ENGINE_NATBIB_AUTHORYEAR);
236 translator.addPair("jurabib", ENGINE_JURABIB);
241 CiteEngineTranslator const & citeenginetranslator()
243 static CiteEngineTranslator translator = init_citeenginetranslator();
249 typedef Translator<string, Spacing::Space> SpaceTranslator;
252 SpaceTranslator const init_spacetranslator()
254 SpaceTranslator translator("default", Spacing::Default);
255 translator.addPair("single", Spacing::Single);
256 translator.addPair("onehalf", Spacing::Onehalf);
257 translator.addPair("double", Spacing::Double);
258 translator.addPair("other", Spacing::Other);
263 SpaceTranslator const & spacetranslator()
265 static SpaceTranslator translator = init_spacetranslator();
273 class BufferParams::Impl
278 AuthorList authorlist;
279 BranchList branchlist;
280 Bullet temp_bullets[4];
281 Bullet user_defined_bullets[4];
283 /** This is the amount of space used for paragraph_separation "skip",
284 * and for detached paragraphs in "indented" documents.
287 PDFOptions pdfoptions;
288 LayoutFileIndex baseClass_;
292 BufferParams::Impl::Impl()
293 : defskip(VSpace::MEDSKIP), baseClass_(string(""))
295 // set initial author
297 authorlist.record(Author(from_utf8(lyxrc.user_name), from_utf8(lyxrc.user_email)));
302 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
306 return new BufferParams::Impl(*ptr);
310 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
316 BufferParams::BufferParams()
319 setBaseClass(defaultBaseclass());
321 paragraph_separation = ParagraphIndentSeparation;
322 quotes_language = InsetQuotes::EnglishQuotes;
323 fontsize = "default";
326 papersize = PAPER_DEFAULT;
327 orientation = ORIENTATION_PORTRAIT;
328 use_geometry = false;
329 use_amsmath = package_auto;
330 use_esint = package_auto;
331 cite_engine_ = ENGINE_BASIC;
332 use_bibtopic = false;
333 trackChanges = false;
334 outputChanges = false;
337 language = default_language;
338 fontsRoman = "default";
339 fontsSans = "default";
340 fontsTypewriter = "default";
341 fontsDefaultFamily = "default";
344 fontsSansScale = 100;
345 fontsTypewriterScale = 100;
347 graphicsDriver = "default";
350 listings_params = string();
351 pagestyle = "default";
353 for (int iter = 0; iter < 4; ++iter) {
354 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
355 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
360 docstring BufferParams::B_(string const & l10n) const
362 LASSERT(language, /**/);
363 return getMessages(language->code()).get(l10n);
367 AuthorList & BufferParams::authors()
369 return pimpl_->authorlist;
373 AuthorList const & BufferParams::authors() const
375 return pimpl_->authorlist;
379 BranchList & BufferParams::branchlist()
381 return pimpl_->branchlist;
385 BranchList const & BufferParams::branchlist() const
387 return pimpl_->branchlist;
391 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
393 LASSERT(index < 4, /**/);
394 return pimpl_->temp_bullets[index];
398 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
400 LASSERT(index < 4, /**/);
401 return pimpl_->temp_bullets[index];
405 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
407 LASSERT(index < 4, /**/);
408 return pimpl_->user_defined_bullets[index];
412 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
414 LASSERT(index < 4, /**/);
415 return pimpl_->user_defined_bullets[index];
419 Spacing & BufferParams::spacing()
421 return pimpl_->spacing;
425 Spacing const & BufferParams::spacing() const
427 return pimpl_->spacing;
431 PDFOptions & BufferParams::pdfoptions()
433 return pimpl_->pdfoptions;
437 PDFOptions const & BufferParams::pdfoptions() const
439 return pimpl_->pdfoptions;
443 VSpace const & BufferParams::getDefSkip() const
445 return pimpl_->defskip;
449 void BufferParams::setDefSkip(VSpace const & vs)
451 pimpl_->defskip = vs;
455 string BufferParams::readToken(Lexer & lex, string const & token,
456 FileName const & filepath)
458 if (token == "\\textclass") {
460 string const classname = lex.getString();
461 // if there exists a local layout file, ignore the system one
462 // NOTE: in this case, the textclass (.cls file) is assumed to be available.
464 LayoutFileList & bcl = LayoutFileList::get();
465 if (tcp.empty() && !filepath.empty())
466 tcp = bcl.addLocalLayout(classname, filepath.absFilename());
470 setBaseClass(classname);
471 // We assume that a tex class exists for local or unknown layouts so this warning
472 // will only be given for system layouts.
473 if (!baseClass()->isTeXClassAvailable()) {
474 docstring const msg =
475 bformat(_("The layout file requested by this document,\n"
477 "is not usable. This is probably because a LaTeX\n"
478 "class or style file required by it is not\n"
479 "available. See the Customization documentation\n"
480 "for more information.\n"), from_utf8(classname));
481 frontend::Alert::warning(_("Document class not available"),
482 msg + _("LyX will not be able to produce output."));
484 } else if (token == "\\begin_preamble") {
486 } else if (token == "\\begin_local_layout") {
487 readLocalLayout(lex);
488 } else if (token == "\\begin_modules") {
490 } else if (token == "\\begin_removed_modules") {
491 readRemovedModules(lex);
492 } else if (token == "\\options") {
494 options = lex.getString();
495 } else if (token == "\\master") {
497 master = lex.getString();
498 } else if (token == "\\language") {
500 } else if (token == "\\inputencoding") {
502 } else if (token == "\\graphics") {
503 readGraphicsDriver(lex);
504 } else if (token == "\\font_roman") {
506 } else if (token == "\\font_sans") {
508 } else if (token == "\\font_typewriter") {
509 lex >> fontsTypewriter;
510 } else if (token == "\\font_default_family") {
511 lex >> fontsDefaultFamily;
512 } else if (token == "\\font_sc") {
514 } else if (token == "\\font_osf") {
516 } else if (token == "\\font_sf_scale") {
517 lex >> fontsSansScale;
518 } else if (token == "\\font_tt_scale") {
519 lex >> fontsTypewriterScale;
520 } else if (token == "\\font_cjk") {
522 } else if (token == "\\paragraph_separation") {
525 paragraph_separation = parseptranslator().find(parsep);
526 } else if (token == "\\defskip") {
528 string defskip = lex.getString();
529 if (defskip == "defskip")
532 pimpl_->defskip = VSpace(defskip);
533 } else if (token == "\\quotes_language") {
536 quotes_language = quoteslangtranslator().find(quotes_lang);
537 } else if (token == "\\papersize") {
540 papersize = papersizetranslator().find(ppsize);
541 } else if (token == "\\use_geometry") {
543 } else if (token == "\\use_amsmath") {
546 use_amsmath = packagetranslator().find(use_ams);
547 } else if (token == "\\use_esint") {
550 use_esint = packagetranslator().find(useesint);
551 } else if (token == "\\cite_engine") {
554 cite_engine_ = citeenginetranslator().find(engine);
555 } else if (token == "\\use_bibtopic") {
557 } else if (token == "\\tracking_changes") {
559 } else if (token == "\\output_changes") {
560 lex >> outputChanges;
561 } else if (token == "\\branch") {
563 docstring branch = lex.getDocString();
564 branchlist().add(branch);
567 string const tok = lex.getString();
568 if (tok == "\\end_branch")
570 Branch * branch_ptr = branchlist().find(branch);
571 if (tok == "\\selected") {
574 branch_ptr->setSelected(lex.getInteger());
576 // not yet operational
577 if (tok == "\\color") {
579 string color = lex.getString();
581 branch_ptr->setColor(color);
582 // Update also the Color table:
584 color = lcolor.getX11Name(Color_background);
586 lcolor.setColor(to_utf8(branch), color);
590 } else if (token == "\\author") {
592 istringstream ss(lex.getString());
595 author_map.push_back(pimpl_->authorlist.record(a));
596 } else if (token == "\\paperorientation") {
599 orientation = paperorientationtranslator().find(orient);
600 } else if (token == "\\paperwidth") {
602 } else if (token == "\\paperheight") {
604 } else if (token == "\\leftmargin") {
606 } else if (token == "\\topmargin") {
608 } else if (token == "\\rightmargin") {
610 } else if (token == "\\bottommargin") {
612 } else if (token == "\\headheight") {
614 } else if (token == "\\headsep") {
616 } else if (token == "\\footskip") {
618 } else if (token == "\\columnsep") {
620 } else if (token == "\\paperfontsize") {
622 } else if (token == "\\papercolumns") {
624 } else if (token == "\\listings_params") {
627 listings_params = InsetListingsParams(par).params();
628 } else if (token == "\\papersides") {
631 sides = sidestranslator().find(psides);
632 } else if (token == "\\paperpagestyle") {
634 } else if (token == "\\bullet") {
636 } else if (token == "\\bulletLaTeX") {
637 readBulletsLaTeX(lex);
638 } else if (token == "\\secnumdepth") {
640 } else if (token == "\\tocdepth") {
642 } else if (token == "\\spacing") {
646 if (nspacing == "other") {
649 spacing().set(spacetranslator().find(nspacing), tmp_val);
650 } else if (token == "\\float_placement") {
651 lex >> float_placement;
653 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
654 string toktmp = pdfoptions().readToken(lex, token);
655 if (!toktmp.empty()) {
656 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
661 lyxerr << "BufferParams::readToken(): Unknown token: " <<
670 void BufferParams::writeFile(ostream & os) const
672 // The top of the file is written by the buffer.
673 // Prints out the buffer info into the .lyx file given by file
676 os << "\\textclass " << baseClass()->name() << '\n';
679 if (!preamble.empty()) {
680 // remove '\n' from the end of preamble
681 string const tmppreamble = rtrim(preamble, "\n");
682 os << "\\begin_preamble\n"
684 << "\n\\end_preamble\n";
688 if (!options.empty()) {
689 os << "\\options " << options << '\n';
692 // the master document
693 if (!master.empty()) {
694 os << "\\master " << master << '\n';
698 if (!removedModules_.empty()) {
699 os << "\\begin_removed_modules" << '\n';
700 set<string>::const_iterator it = removedModules_.begin();
701 set<string>::const_iterator en = removedModules_.end();
702 for (; it != en; it++)
704 os << "\\end_removed_modules" << '\n';
708 if (!layoutModules_.empty()) {
709 os << "\\begin_modules" << '\n';
710 LayoutModuleList::const_iterator it = layoutModules_.begin();
711 LayoutModuleList::const_iterator en = layoutModules_.end();
712 for (; it != en; it++)
714 os << "\\end_modules" << '\n';
717 // local layout information
718 if (!local_layout.empty()) {
719 // remove '\n' from the end
720 string const tmplocal = rtrim(local_layout, "\n");
721 os << "\\begin_local_layout\n"
723 << "\n\\end_local_layout\n";
726 // then the text parameters
727 if (language != ignore_language)
728 os << "\\language " << language->lang() << '\n';
729 os << "\\inputencoding " << inputenc
730 << "\n\\font_roman " << fontsRoman
731 << "\n\\font_sans " << fontsSans
732 << "\n\\font_typewriter " << fontsTypewriter
733 << "\n\\font_default_family " << fontsDefaultFamily
734 << "\n\\font_sc " << convert<string>(fontsSC)
735 << "\n\\font_osf " << convert<string>(fontsOSF)
736 << "\n\\font_sf_scale " << fontsSansScale
737 << "\n\\font_tt_scale " << fontsTypewriterScale
739 if (!fontsCJK.empty()) {
740 os << "\\font_cjk " << fontsCJK << '\n';
742 os << "\n\\graphics " << graphicsDriver << '\n';
744 if (!float_placement.empty()) {
745 os << "\\float_placement " << float_placement << '\n';
747 os << "\\paperfontsize " << fontsize << '\n';
749 spacing().writeFile(os);
750 pdfoptions().writeFile(os);
752 os << "\\papersize " << string_papersize[papersize]
753 << "\n\\use_geometry " << convert<string>(use_geometry)
754 << "\n\\use_amsmath " << use_amsmath
755 << "\n\\use_esint " << use_esint
756 << "\n\\cite_engine " << citeenginetranslator().find(cite_engine_)
757 << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
758 << "\n\\paperorientation " << string_orientation[orientation]
761 BranchList::const_iterator it = branchlist().begin();
762 BranchList::const_iterator end = branchlist().end();
763 for (; it != end; ++it) {
764 os << "\\branch " << to_utf8(it->getBranch())
765 << "\n\\selected " << it->getSelected()
766 << "\n\\color " << lyx::X11hexname(it->getColor())
771 if (!paperwidth.empty())
772 os << "\\paperwidth "
773 << VSpace(paperwidth).asLyXCommand() << '\n';
774 if (!paperheight.empty())
775 os << "\\paperheight "
776 << VSpace(paperheight).asLyXCommand() << '\n';
777 if (!leftmargin.empty())
778 os << "\\leftmargin "
779 << VSpace(leftmargin).asLyXCommand() << '\n';
780 if (!topmargin.empty())
782 << VSpace(topmargin).asLyXCommand() << '\n';
783 if (!rightmargin.empty())
784 os << "\\rightmargin "
785 << VSpace(rightmargin).asLyXCommand() << '\n';
786 if (!bottommargin.empty())
787 os << "\\bottommargin "
788 << VSpace(bottommargin).asLyXCommand() << '\n';
789 if (!headheight.empty())
790 os << "\\headheight "
791 << VSpace(headheight).asLyXCommand() << '\n';
792 if (!headsep.empty())
794 << VSpace(headsep).asLyXCommand() << '\n';
795 if (!footskip.empty())
797 << VSpace(footskip).asLyXCommand() << '\n';
798 if (!columnsep.empty())
800 << VSpace(columnsep).asLyXCommand() << '\n';
801 os << "\\secnumdepth " << secnumdepth
802 << "\n\\tocdepth " << tocdepth
803 << "\n\\paragraph_separation "
804 << string_paragraph_separation[paragraph_separation]
805 << "\n\\defskip " << getDefSkip().asLyXCommand()
806 << "\n\\quotes_language "
807 << string_quotes_language[quotes_language]
808 << "\n\\papercolumns " << columns
809 << "\n\\papersides " << sides
810 << "\n\\paperpagestyle " << pagestyle << '\n';
811 if (!listings_params.empty())
812 os << "\\listings_params \"" <<
813 InsetListingsParams(listings_params).encodedString() << "\"\n";
814 for (int i = 0; i < 4; ++i) {
815 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
816 if (user_defined_bullet(i).getFont() != -1) {
817 os << "\\bullet " << i << " "
818 << user_defined_bullet(i).getFont() << " "
819 << user_defined_bullet(i).getCharacter() << " "
820 << user_defined_bullet(i).getSize() << "\n";
824 os << "\\bulletLaTeX " << i << " \""
825 << lyx::to_ascii(user_defined_bullet(i).getText())
831 os << "\\tracking_changes " << convert<string>(trackChanges) << "\n";
832 os << "\\output_changes " << convert<string>(outputChanges) << "\n";
834 AuthorList::Authors::const_iterator a_it = pimpl_->authorlist.begin();
835 AuthorList::Authors::const_iterator a_end = pimpl_->authorlist.end();
836 for (; a_it != a_end; ++a_it) {
837 if (a_it->second.used())
838 os << "\\author " << a_it->second << "\n";
840 os << "\\author " << Author() << "\n";
845 void BufferParams::validate(LaTeXFeatures & features) const
847 features.require(documentClass().requires());
850 bool dvipost = LaTeXFeatures::isAvailable("dvipost");
851 bool xcolorsoul = LaTeXFeatures::isAvailable("soul") &&
852 LaTeXFeatures::isAvailable("xcolor");
854 switch (features.runparams().flavor) {
855 case OutputParams::LATEX:
857 features.require("ct-dvipost");
858 features.require("dvipost");
859 } else if (xcolorsoul) {
860 features.require("ct-xcolor-soul");
861 features.require("soul");
862 features.require("xcolor");
864 features.require("ct-none");
867 case OutputParams::PDFLATEX:
869 features.require("ct-xcolor-soul");
870 features.require("soul");
871 features.require("xcolor");
872 // improves color handling in PDF output
873 features.require("pdfcolmk");
875 features.require("ct-none");
883 // Floats with 'Here definitely' as default setting.
884 if (float_placement.find('H') != string::npos)
885 features.require("float");
887 // AMS Style is at document level
888 if (use_amsmath == package_on
889 || documentClass().provides("amsmath"))
890 features.require("amsmath");
891 if (use_esint == package_on)
892 features.require("esint");
894 // Document-level line spacing
895 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
896 features.require("setspace");
898 // the bullet shapes are buffer level not paragraph level
899 // so they are tested here
900 for (int i = 0; i < 4; ++i) {
901 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
903 int const font = user_defined_bullet(i).getFont();
905 int const c = user_defined_bullet(i).getCharacter();
911 features.require("latexsym");
913 } else if (font == 1) {
914 features.require("amssymb");
915 } else if (font >= 2 && font <= 5) {
916 features.require("pifont");
920 if (pdfoptions().use_hyperref)
921 features.require("hyperref");
923 if (language->lang() == "vietnamese")
924 features.require("vietnamese");
925 else if (language->lang() == "japanese")
926 features.require("japanese");
930 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
931 TexRow & texrow) const
933 os << "\\documentclass";
935 DocumentClass const & tclass = documentClass();
937 ostringstream clsoptions; // the document class options.
939 if (tokenPos(tclass.opt_fontsize(),
940 '|', fontsize) >= 0) {
941 // only write if existing in list (and not default)
942 clsoptions << fontsize << "pt,";
945 // custom, A3, B3 and B4 paper sizes need geometry
946 bool nonstandard_papersize = papersize == PAPER_B3
947 || papersize == PAPER_B4
948 || papersize == PAPER_A3
949 || papersize == PAPER_CUSTOM;
954 clsoptions << "a4paper,";
957 clsoptions << "letterpaper,";
960 clsoptions << "a5paper,";
963 clsoptions << "b5paper,";
965 case PAPER_USEXECUTIVE:
966 clsoptions << "executivepaper,";
969 clsoptions << "legalpaper,";
981 if (sides != tclass.sides()) {
984 clsoptions << "oneside,";
987 clsoptions << "twoside,";
993 if (columns != tclass.columns()) {
995 clsoptions << "twocolumn,";
997 clsoptions << "onecolumn,";
1001 && orientation == ORIENTATION_LANDSCAPE)
1002 clsoptions << "landscape,";
1004 // language should be a parameter to \documentclass
1005 if (language->babel() == "hebrew"
1006 && default_language->babel() != "hebrew")
1007 // This seems necessary
1008 features.useLanguage(default_language);
1010 ostringstream language_options;
1011 bool const use_babel = features.useBabel();
1013 language_options << features.getLanguages();
1014 if (!language->babel().empty()) {
1015 if (!language_options.str().empty())
1016 language_options << ',';
1017 language_options << language->babel();
1019 // if Vietnamese is used, babel must directly be loaded
1020 // with language options, not in the class options, see
1021 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1022 size_t viet = language_options.str().find("vietnam");
1023 // viet = string::npos when not found
1024 // if Japanese is used, babel must directly be loaded
1025 // with language options, not in the class options, see
1026 // http://bugzilla.lyx.org/show_bug.cgi?id=4597#c4
1027 size_t japan = language_options.str().find("japanese");
1028 // japan = string::npos when not found
1029 if (lyxrc.language_global_options
1030 && !language_options.str().empty()
1031 && viet == string::npos && japan == string::npos)
1032 clsoptions << language_options.str() << ',';
1035 // the user-defined options
1036 if (!options.empty()) {
1037 clsoptions << options << ',';
1040 string strOptions(clsoptions.str());
1041 if (!strOptions.empty()) {
1042 strOptions = rtrim(strOptions, ",");
1044 os << '[' << from_utf8(strOptions) << ']';
1047 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1049 // end of \documentclass defs
1051 // font selection must be done before loading fontenc.sty
1052 string const fonts =
1053 loadFonts(fontsRoman, fontsSans,
1054 fontsTypewriter, fontsSC, fontsOSF,
1055 fontsSansScale, fontsTypewriterScale);
1056 if (!fonts.empty()) {
1057 os << from_ascii(fonts);
1060 if (fontsDefaultFamily != "default")
1061 os << "\\renewcommand{\\familydefault}{\\"
1062 << from_ascii(fontsDefaultFamily) << "}\n";
1064 // set font encoding
1065 // this one is not per buffer
1066 // for arabic_arabi and farsi we also need to load the LAE and
1068 if (lyxrc.fontenc != "default" && language->lang() != "japanese") {
1069 if (language->lang() == "arabic_arabi"
1070 || language->lang() == "farsi") {
1071 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
1072 << ",LFE,LAE]{fontenc}\n";
1075 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
1081 // handle inputenc etc.
1082 writeEncodingPreamble(os, features, texrow);
1084 if (!listings_params.empty()) {
1085 os << "\\usepackage{listings}\n";
1088 // do not test validity because listings_params is
1089 // supposed to be valid
1091 InsetListingsParams(listings_params).separatedParams(true);
1092 os << from_ascii(par);
1093 // count the number of newlines
1094 for (size_t i = 0; i < par.size(); ++i)
1100 if (use_geometry || nonstandard_papersize) {
1101 os << "\\usepackage{geometry}\n";
1103 os << "\\geometry{verbose";
1104 if (orientation == ORIENTATION_LANDSCAPE)
1106 switch (papersize) {
1108 if (!paperwidth.empty())
1109 os << ",paperwidth="
1110 << from_ascii(paperwidth);
1111 if (!paperheight.empty())
1112 os << ",paperheight="
1113 << from_ascii(paperheight);
1115 case PAPER_USLETTER:
1116 os << ",letterpaper";
1119 os << ",legalpaper";
1121 case PAPER_USEXECUTIVE:
1122 os << ",executivepaper";
1143 // default papersize ie PAPER_DEFAULT
1144 switch (lyxrc.default_papersize) {
1145 case PAPER_DEFAULT: // keep compiler happy
1146 case PAPER_USLETTER:
1147 os << ",letterpaper";
1150 os << ",legalpaper";
1152 case PAPER_USEXECUTIVE:
1153 os << ",executivepaper";
1173 if (!topmargin.empty())
1174 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1175 if (!bottommargin.empty())
1176 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1177 if (!leftmargin.empty())
1178 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1179 if (!rightmargin.empty())
1180 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1181 if (!headheight.empty())
1182 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1183 if (!headsep.empty())
1184 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1185 if (!footskip.empty())
1186 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1187 if (!columnsep.empty())
1188 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1191 } else if (orientation == ORIENTATION_LANDSCAPE) {
1192 features.require("papersize");
1195 if (tokenPos(tclass.opt_pagestyle(),
1196 '|', pagestyle) >= 0) {
1197 if (pagestyle == "fancy") {
1198 os << "\\usepackage{fancyhdr}\n";
1201 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1205 // Only if class has a ToC hierarchy
1206 if (tclass.hasTocLevels()) {
1207 if (secnumdepth != tclass.secnumdepth()) {
1208 os << "\\setcounter{secnumdepth}{"
1213 if (tocdepth != tclass.tocdepth()) {
1214 os << "\\setcounter{tocdepth}{"
1221 if (paragraph_separation) {
1222 switch (getDefSkip().kind()) {
1223 case VSpace::SMALLSKIP:
1224 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1226 case VSpace::MEDSKIP:
1227 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1229 case VSpace::BIGSKIP:
1230 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1232 case VSpace::LENGTH:
1233 os << "\\setlength{\\parskip}{"
1234 << from_utf8(getDefSkip().length().asLatexString())
1237 default: // should never happen // Then delete it.
1238 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1243 os << "\\setlength{\\parindent}{0pt}\n";
1247 // If we use hyperref, jurabib, japanese, or vietnamese, we have to call babel here.
1249 && (features.isRequired("jurabib")
1250 || features.isRequired("hyperref")
1251 || features.isRequired("vietnamese")
1252 || features.isRequired("japanese") ) ) {
1254 os << from_utf8(babelCall(language_options.str()))
1256 << from_utf8(features.getBabelOptions());
1260 // Now insert the LyX specific LaTeX commands...
1262 // The optional packages;
1263 docstring lyxpreamble(from_ascii(features.getPackages()));
1266 lyxpreamble += from_utf8(spacing().writePreamble(tclass.provides("SetSpace")));
1269 // * Hyperref manual: "Make sure it comes last of your loaded
1270 // packages, to give it a fighting chance of not being over-written,
1271 // since its job is to redefine many LATEX commands."
1272 // * Email from Heiko Oberdiek: "It is usually better to load babel
1273 // before hyperref. Then hyperref has a chance to detect babel.
1274 // * Has to be loaded before the "LyX specific LaTeX commands" to
1275 // avoid errors with algorithm floats.
1276 // use hyperref explicitely when it is required
1277 if (features.isRequired("hyperref")) {
1278 odocstringstream oss;
1279 pdfoptions().writeLaTeX(oss, documentClass().provides("hyperref"));
1280 lyxpreamble += oss.str();
1283 // Will be surrounded by \makeatletter and \makeatother when needed
1284 docstring atlyxpreamble;
1286 // Some macros LyX will need
1287 docstring tmppreamble(from_ascii(features.getMacros()));
1289 if (!tmppreamble.empty())
1290 atlyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1291 "LyX specific LaTeX commands.\n"
1292 + tmppreamble + '\n';
1294 // the text class specific preamble
1295 tmppreamble = features.getTClassPreamble();
1296 if (!tmppreamble.empty())
1297 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1298 "Textclass specific LaTeX commands.\n"
1299 + tmppreamble + '\n';
1301 /* the user-defined preamble */
1302 if (!preamble.empty())
1304 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1305 "User specified LaTeX commands.\n"
1306 + from_utf8(preamble) + '\n';
1308 // subfig loads internally the LaTeX package "caption". As
1309 // caption is a very popular package, users will load it in
1310 // the preamble. Therefore we must load subfig behind the
1311 // user-defined preamble and check if the caption package was
1312 // loaded or not. For the case that caption is loaded before
1313 // subfig, there is the subfig option "caption=false". This
1314 // option also works when a koma-script class is used and
1315 // koma's own caption commands are used instead of caption. We
1316 // use \PassOptionsToPackage here because the user could have
1317 // already loaded subfig in the preamble.
1318 if (features.isRequired("subfig")) {
1319 atlyxpreamble += "\\@ifundefined{showcaptionsetup}{}{%\n"
1320 " \\PassOptionsToPackage{caption=false}{subfig}}\n"
1321 "\\usepackage{subfig}\n";
1324 // Itemize bullet settings need to be last in case the user
1325 // defines their own bullets that use a package included
1326 // in the user-defined preamble -- ARRae
1327 // Actually it has to be done much later than that
1328 // since some packages like frenchb make modifications
1329 // at \begin{document} time -- JMarc
1330 docstring bullets_def;
1331 for (int i = 0; i < 4; ++i) {
1332 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1333 if (bullets_def.empty())
1334 bullets_def += "\\AtBeginDocument{\n";
1335 bullets_def += " \\def\\labelitemi";
1337 // `i' is one less than the item to modify
1344 bullets_def += "ii";
1350 bullets_def += '{' +
1351 user_defined_bullet(i).getText()
1356 if (!bullets_def.empty())
1357 atlyxpreamble += bullets_def + "}\n\n";
1359 if (atlyxpreamble.find(from_ascii("@")) != docstring::npos)
1360 lyxpreamble += "\n\\makeatletter\n"
1361 + atlyxpreamble + "\\makeatother\n\n";
1363 lyxpreamble += '\n' + atlyxpreamble;
1365 // We try to load babel late, in case it interferes
1366 // with other packages.
1367 // Jurabib and Hyperref have to be called after babel, though.
1368 if (use_babel && !features.isRequired("jurabib")
1369 && !features.isRequired("hyperref")
1370 && !features.isRequired("vietnamese")
1371 && !features.isRequired("japanese")) {
1373 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1374 lyxpreamble += from_utf8(features.getBabelOptions()) + '\n';
1378 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1379 for (int j = 0; j != nlines; ++j) {
1388 void BufferParams::useClassDefaults()
1390 DocumentClass const & tclass = documentClass();
1392 sides = tclass.sides();
1393 columns = tclass.columns();
1394 pagestyle = tclass.pagestyle();
1395 options = tclass.options();
1396 // Only if class has a ToC hierarchy
1397 if (tclass.hasTocLevels()) {
1398 secnumdepth = tclass.secnumdepth();
1399 tocdepth = tclass.tocdepth();
1404 bool BufferParams::hasClassDefaults() const
1406 DocumentClass const & tclass = documentClass();
1408 return sides == tclass.sides()
1409 && columns == tclass.columns()
1410 && pagestyle == tclass.pagestyle()
1411 && options == tclass.options()
1412 && secnumdepth == tclass.secnumdepth()
1413 && tocdepth == tclass.tocdepth();
1417 DocumentClass const & BufferParams::documentClass() const
1423 DocumentClass const * BufferParams::documentClassPtr() const {
1428 void BufferParams::setDocumentClass(DocumentClass const * const tc) {
1429 // evil, but this function is evil
1430 doc_class_ = const_cast<DocumentClass *>(tc);
1434 bool BufferParams::setBaseClass(string const & classname)
1436 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
1437 LayoutFileList & bcl = LayoutFileList::get();
1438 if (!bcl.haveClass(classname)) {
1440 bformat(_("The document class %1$s could not be found. "
1441 "A default textclass with default layouts will be used. "
1442 "LyX might not be able to produce output unless a correct "
1443 "textclass is selected from the document settings dialog."),
1444 from_utf8(classname));
1445 frontend::Alert::error(_("Document class not found"), s);
1446 bcl.addEmptyClass(classname);
1449 bool const success = bcl[classname].load();
1452 bformat(_("The document class %1$s could not be loaded."),
1453 from_utf8(classname));
1454 frontend::Alert::error(_("Could not load class"), s);
1458 pimpl_->baseClass_ = classname;
1460 // add any required modules not already in use
1461 set<string> const & mods = baseClass()->defaultModules();
1462 set<string>::const_iterator mit = mods.begin();
1463 set<string>::const_iterator men = mods.end();
1464 for (; mit != men; mit++) {
1465 string const & modName = *mit;
1466 // see if we're already in use
1467 if (find(layoutModules_.begin(), layoutModules_.end(), modName) !=
1468 layoutModules_.end()) {
1469 LYXERR(Debug::TCLASS, "Default module `" << modName <<
1470 "' not added because already used.");
1473 // make sure the user hasn't removed it
1474 if (find(removedModules_.begin(), removedModules_.end(), modName) !=
1475 removedModules_.end()) {
1476 LYXERR(Debug::TCLASS, "Default module `" << modName <<
1477 "' not added because removed by user.");
1480 // Now we want to check the list of selected modules to see if any of them
1481 // exclude this one.
1482 bool foundit = false;
1483 // so iterate over the selected modules...
1484 LayoutModuleList::const_iterator lit = layoutModules_.begin();
1485 LayoutModuleList::const_iterator len = layoutModules_.end();
1486 for (; lit != len; lit++) {
1487 LyXModule * lm = moduleList[*lit];
1490 vector<string> const & exc = lm->getExcludedModules();
1491 // ...and see if this one excludes us.
1492 if (find(exc.begin(), exc.end(), modName) != exc.end()) {
1494 LYXERR(Debug::TCLASS, "Default module `" << modName <<
1495 "' not added because excluded by loaded module `" <<
1501 LYXERR(Debug::TCLASS, "Default module `" << modName << "' added.");
1502 layoutModules_.push_back(modName);
1509 LayoutFile const * BufferParams::baseClass() const
1511 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
1512 return &(LayoutFileList::get()[pimpl_->baseClass_]);
1518 LayoutFileIndex const & BufferParams::baseClassID() const
1520 return pimpl_->baseClass_;
1524 void BufferParams::makeDocumentClass()
1529 doc_class_ = &(DocumentClassBundle::get().newClass(*baseClass()));
1531 // FIXME It might be worth loading the children's modules here,
1532 // just as we load their bibliographies and such, instead of just
1533 // doing a check in InsetInclude.
1534 LayoutModuleList::const_iterator it = layoutModules_.begin();
1535 for (; it != layoutModules_.end(); it++) {
1536 string const modName = *it;
1537 LyXModule * lm = moduleList[modName];
1539 docstring const msg =
1540 bformat(_("The module %1$s has been requested by\n"
1541 "this document but has not been found in the list of\n"
1542 "available modules. If you recently installed it, you\n"
1543 "probably need to reconfigure LyX.\n"), from_utf8(modName));
1544 frontend::Alert::warning(_("Module not available"),
1545 msg + _("Some layouts may not be available."));
1546 LYXERR0("BufferParams::makeDocumentClass(): Module " <<
1547 modName << " requested but not found in module list.");
1550 if (!lm->isAvailable()) {
1551 docstring const msg =
1552 bformat(_("The module %1$s requires a package that is\n"
1553 "not available in your LaTeX installation. LaTeX output\n"
1554 "may not be possible.\n"), from_utf8(modName));
1555 frontend::Alert::warning(_("Package not available"), msg);
1557 FileName layout_file = libFileSearch("layouts", lm->getFilename());
1558 if (!doc_class_->read(layout_file, TextClass::MODULE)) {
1559 docstring const msg =
1560 bformat(_("Error reading module %1$s\n"), from_utf8(modName));
1561 frontend::Alert::warning(_("Read Error"), msg);
1564 if (!local_layout.empty()) {
1565 if (!doc_class_->read(local_layout, TextClass::MODULE)) {
1566 docstring const msg = _("Error reading internal layout information");
1567 frontend::Alert::warning(_("Read Error"), msg);
1573 bool BufferParams::addLayoutModule(string const & modName)
1575 LayoutModuleList::const_iterator it = layoutModules_.begin();
1576 LayoutModuleList::const_iterator end = layoutModules_.end();
1577 for (; it != end; it++)
1580 layoutModules_.push_back(modName);
1585 Font const BufferParams::getFont() const
1587 FontInfo f = documentClass().defaultfont();
1588 if (fontsDefaultFamily == "rmdefault")
1589 f.setFamily(ROMAN_FAMILY);
1590 else if (fontsDefaultFamily == "sfdefault")
1591 f.setFamily(SANS_FAMILY);
1592 else if (fontsDefaultFamily == "ttdefault")
1593 f.setFamily(TYPEWRITER_FAMILY);
1594 return Font(f, language);
1598 void BufferParams::readPreamble(Lexer & lex)
1600 if (lex.getString() != "\\begin_preamble")
1601 lyxerr << "Error (BufferParams::readPreamble):"
1602 "consistency check failed." << endl;
1604 preamble = lex.getLongString("\\end_preamble");
1608 void BufferParams::readLocalLayout(Lexer & lex)
1610 if (lex.getString() != "\\begin_local_layout")
1611 lyxerr << "Error (BufferParams::readLocalLayout):"
1612 "consistency check failed." << endl;
1614 local_layout = lex.getLongString("\\end_local_layout");
1618 void BufferParams::readLanguage(Lexer & lex)
1620 if (!lex.next()) return;
1622 string const tmptok = lex.getString();
1624 // check if tmptok is part of tex_babel in tex-defs.h
1625 language = languages.getLanguage(tmptok);
1627 // Language tmptok was not found
1628 language = default_language;
1629 lyxerr << "Warning: Setting language `"
1630 << tmptok << "' to `" << language->lang()
1636 void BufferParams::readGraphicsDriver(Lexer & lex)
1641 string const tmptok = lex.getString();
1642 // check if tmptok is part of tex_graphics in tex_defs.h
1645 string const test = tex_graphics[n++];
1647 if (test == tmptok) {
1648 graphicsDriver = tmptok;
1653 "Warning: graphics driver `$$Token' not recognized!\n"
1654 " Setting graphics driver to `default'.\n");
1655 graphicsDriver = "default";
1662 void BufferParams::readBullets(Lexer & lex)
1667 int const index = lex.getInteger();
1669 int temp_int = lex.getInteger();
1670 user_defined_bullet(index).setFont(temp_int);
1671 temp_bullet(index).setFont(temp_int);
1673 user_defined_bullet(index).setCharacter(temp_int);
1674 temp_bullet(index).setCharacter(temp_int);
1676 user_defined_bullet(index).setSize(temp_int);
1677 temp_bullet(index).setSize(temp_int);
1681 void BufferParams::readBulletsLaTeX(Lexer & lex)
1683 // The bullet class should be able to read this.
1686 int const index = lex.getInteger();
1688 docstring const temp_str = lex.getDocString();
1690 user_defined_bullet(index).setText(temp_str);
1691 temp_bullet(index).setText(temp_str);
1695 void BufferParams::readModules(Lexer & lex)
1697 if (!lex.eatLine()) {
1698 lyxerr << "Error (BufferParams::readModules):"
1699 "Unexpected end of input." << endl;
1703 string mod = lex.getString();
1704 if (mod == "\\end_modules")
1706 addLayoutModule(mod);
1712 void BufferParams::readRemovedModules(Lexer & lex)
1714 if (!lex.eatLine()) {
1715 lyxerr << "Error (BufferParams::readRemovedModules):"
1716 "Unexpected end of input." << endl;
1720 string mod = lex.getString();
1721 if (mod == "\\end_removed_modules")
1723 removedModules_.insert(mod);
1726 // now we want to remove any removed modules that were previously
1727 // added. normally, that will be because default modules were added in
1728 // setBaseClass(), which gets called when \textclass is read at the
1729 // start of the read.
1730 set<string>::const_iterator rit = removedModules_.begin();
1731 set<string>::const_iterator const ren = removedModules_.end();
1732 for (; rit != ren; rit++) {
1733 LayoutModuleList::iterator const mit = layoutModules_.begin();
1734 LayoutModuleList::iterator const men = layoutModules_.end();
1735 LayoutModuleList::iterator found = find(mit, men, *rit);
1738 layoutModules_.erase(found);
1743 string BufferParams::paperSizeName(PapersizePurpose purpose) const
1745 char real_papersize = papersize;
1746 if (real_papersize == PAPER_DEFAULT)
1747 real_papersize = lyxrc.default_papersize;
1749 switch (real_papersize) {
1751 // could be anything, so don't guess
1753 case PAPER_CUSTOM: {
1754 if (purpose == XDVI && !paperwidth.empty() &&
1755 !paperheight.empty()) {
1756 // heightxwidth<unit>
1757 string first = paperwidth;
1758 string second = paperheight;
1759 if (orientation == ORIENTATION_LANDSCAPE)
1762 return first.erase(first.length() - 2)
1774 // dvips and dvipdfm do not know this
1775 if (purpose == DVIPS || purpose == DVIPDFM)
1779 // dvipdfm does not know this
1780 if (purpose == DVIPDFM)
1784 // dvipdfm does not know this
1785 if (purpose == DVIPDFM)
1788 case PAPER_USEXECUTIVE:
1789 // dvipdfm does not know this
1790 if (purpose == DVIPDFM)
1795 case PAPER_USLETTER:
1797 if (purpose == XDVI)
1804 string const BufferParams::dvips_options() const
1809 && papersize == PAPER_CUSTOM
1810 && !lyxrc.print_paper_dimension_flag.empty()
1811 && !paperwidth.empty()
1812 && !paperheight.empty()) {
1813 // using a custom papersize
1814 result = lyxrc.print_paper_dimension_flag;
1815 result += ' ' + paperwidth;
1816 result += ',' + paperheight;
1818 string const paper_option = paperSizeName(DVIPS);
1819 if (!paper_option.empty() && (paper_option != "letter" ||
1820 orientation != ORIENTATION_LANDSCAPE)) {
1821 // dvips won't accept -t letter -t landscape.
1822 // In all other cases, include the paper size
1824 result = lyxrc.print_paper_flag;
1825 result += ' ' + paper_option;
1828 if (orientation == ORIENTATION_LANDSCAPE &&
1829 papersize != PAPER_CUSTOM)
1830 result += ' ' + lyxrc.print_landscape_flag;
1835 string BufferParams::babelCall(string const & lang_opts) const
1837 string lang_pack = lyxrc.language_package;
1838 if (lang_pack != "\\usepackage{babel}")
1840 // suppress the babel call when there is no babel language defined
1841 // for the document language in the lib/languages file and if no
1842 // other languages are used (lang_opts is then empty)
1843 if (lang_opts.empty())
1845 // If Vietnamese is used, babel must directly be loaded with the
1846 // language options, see
1847 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1848 size_t viet = lang_opts.find("vietnam");
1849 // viet = string::npos when not found
1850 // If Japanese is used, babel must directly be loaded with the
1851 // language options, see
1852 // http://bugzilla.lyx.org/show_bug.cgi?id=4597#c4
1853 size_t japan = lang_opts.find("japanese");
1854 // japan = string::npos when not found
1855 if (!lyxrc.language_global_options || viet != string::npos || japan != string::npos)
1856 return "\\usepackage[" + lang_opts + "]{babel}";
1861 void BufferParams::writeEncodingPreamble(odocstream & os,
1862 LaTeXFeatures & features, TexRow & texrow) const
1864 if (inputenc == "auto") {
1865 string const doc_encoding =
1866 language->encoding()->latexName();
1867 Encoding::Package const package =
1868 language->encoding()->package();
1870 // Create a list with all the input encodings used
1872 set<string> encodings =
1873 features.getEncodingSet(doc_encoding);
1875 // If the "japanese" package (i.e. pLaTeX) is used,
1876 // inputenc must be omitted.
1877 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1878 if (package == Encoding::japanese)
1879 features.require("japanese");
1881 if ((!encodings.empty() || package == Encoding::inputenc)
1882 && !features.isRequired("japanese")) {
1883 os << "\\usepackage[";
1884 set<string>::const_iterator it = encodings.begin();
1885 set<string>::const_iterator const end = encodings.end();
1887 os << from_ascii(*it);
1890 for (; it != end; ++it)
1891 os << ',' << from_ascii(*it);
1892 if (package == Encoding::inputenc) {
1893 if (!encodings.empty())
1895 os << from_ascii(doc_encoding);
1897 os << "]{inputenc}\n";
1900 if (package == Encoding::CJK || features.mustProvide("CJK")) {
1901 os << "\\usepackage{CJK}\n";
1904 } else if (inputenc != "default") {
1905 switch (encoding().package()) {
1906 case Encoding::none:
1907 case Encoding::japanese:
1909 case Encoding::inputenc:
1910 // do not load inputenc if japanese is used
1911 if (features.isRequired("japanese"))
1913 os << "\\usepackage[" << from_ascii(inputenc)
1918 os << "\\usepackage{CJK}\n";
1924 // The encoding "armscii8" (for Armenian) is only available when
1925 // the package "armtex" is loaded.
1926 if (language->encoding()->latexName() == "armscii8"
1927 || inputenc == "armscii8") {
1928 os << "\\usepackage{armtex}\n";
1934 string const BufferParams::loadFonts(string const & rm,
1935 string const & sf, string const & tt,
1936 bool const & sc, bool const & osf,
1937 int const & sfscale, int const & ttscale) const
1939 /* The LaTeX font world is in a flux. In the PSNFSS font interface,
1940 several packages have been replaced by others, that might not
1941 be installed on every system. We have to take care for that
1942 (see psnfss.pdf). We try to support all psnfss fonts as well
1943 as the fonts that have become de facto standard in the LaTeX
1944 world (e.g. Latin Modern). We do not support obsolete fonts
1945 (like PSLatex). In general, it should be possible to mix any
1946 rm font with any sf or tt font, respectively. (JSpitzm)
1948 -- separate math fonts.
1951 if (rm == "default" && sf == "default" && tt == "default")
1958 // Computer Modern (must be explicitely selectable -- there might be classes
1959 // that define a different default font!
1961 os << "\\renewcommand{\\rmdefault}{cmr}\n";
1962 // osf for Computer Modern needs eco.sty
1964 os << "\\usepackage{eco}\n";
1966 // Latin Modern Roman
1967 else if (rm == "lmodern")
1968 os << "\\usepackage{lmodern}\n";
1970 else if (rm == "ae") {
1971 // not needed when using OT1 font encoding.
1972 if (lyxrc.fontenc != "default")
1973 os << "\\usepackage{ae,aecompl}\n";
1976 else if (rm == "times") {
1977 // try to load the best available package
1978 if (LaTeXFeatures::isAvailable("mathptmx"))
1979 os << "\\usepackage{mathptmx}\n";
1980 else if (LaTeXFeatures::isAvailable("mathptm"))
1981 os << "\\usepackage{mathptm}\n";
1983 os << "\\usepackage{times}\n";
1986 else if (rm == "palatino") {
1987 // try to load the best available package
1988 if (LaTeXFeatures::isAvailable("mathpazo")) {
1989 os << "\\usepackage";
1995 // "osf" includes "sc"!
1999 os << "{mathpazo}\n";
2001 else if (LaTeXFeatures::isAvailable("mathpple"))
2002 os << "\\usepackage{mathpple}\n";
2004 os << "\\usepackage{palatino}\n";
2007 else if (rm == "utopia") {
2008 // fourier supersedes utopia.sty, but does
2009 // not work with OT1 encoding.
2010 if (LaTeXFeatures::isAvailable("fourier")
2011 && lyxrc.fontenc != "default") {
2012 os << "\\usepackage";
2023 os << "{fourier}\n";
2026 os << "\\usepackage{utopia}\n";
2028 // Bera (complete fontset)
2029 else if (rm == "bera" && sf == "default" && tt == "default")
2030 os << "\\usepackage{bera}\n";
2032 else if (rm != "default")
2033 os << "\\usepackage" << "{" << rm << "}\n";
2036 // Helvetica, Bera Sans
2037 if (sf == "helvet" || sf == "berasans") {
2039 os << "\\usepackage[scaled=" << float(sfscale) / 100
2040 << "]{" << sf << "}\n";
2042 os << "\\usepackage{" << sf << "}\n";
2045 else if (sf == "avant")
2046 os << "\\usepackage{" << sf << "}\n";
2047 // Computer Modern, Latin Modern, CM Bright
2048 else if (sf != "default")
2049 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
2051 // monospaced/typewriter
2052 // Courier, LuxiMono
2053 if (tt == "luximono" || tt == "beramono") {
2055 os << "\\usepackage[scaled=" << float(ttscale) / 100
2056 << "]{" << tt << "}\n";
2058 os << "\\usepackage{" << tt << "}\n";
2061 else if (tt == "courier" )
2062 os << "\\usepackage{" << tt << "}\n";
2063 // Computer Modern, Latin Modern, CM Bright
2064 else if (tt != "default")
2065 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
2071 Encoding const & BufferParams::encoding() const
2073 if (inputenc == "auto" || inputenc == "default")
2074 return *language->encoding();
2075 Encoding const * const enc = encodings.fromLaTeXName(inputenc);
2078 LYXERR0("Unknown inputenc value `" << inputenc
2079 << "'. Using `auto' instead.");
2080 return *language->encoding();
2084 CiteEngine BufferParams::citeEngine() const
2086 // FIXME the class should provide the numerical/
2087 // authoryear choice
2088 if (documentClass().provides("natbib")
2089 && cite_engine_ != ENGINE_NATBIB_NUMERICAL)
2090 return ENGINE_NATBIB_AUTHORYEAR;
2091 return cite_engine_;
2095 void BufferParams::setCiteEngine(CiteEngine cite_engine)
2097 cite_engine_ = cite_engine;