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 "BranchList.h"
22 #include "buffer_funcs.h"
27 #include "LaTeXFeatures.h"
28 #include "ModuleList.h"
32 #include "TextClassList.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", "executivepaper", "legalpaper",
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::PARSEP> ParSepTranslator;
101 ParSepTranslator const init_parseptranslator()
103 ParSepTranslator translator(string_paragraph_separation[0], BufferParams::PARSEP_INDENT);
104 translator.addPair(string_paragraph_separation[1], BufferParams::PARSEP_SKIP);
109 ParSepTranslator const & parseptranslator()
111 static ParSepTranslator translator = init_parseptranslator();
117 typedef Translator<string, InsetQuotes::quote_language> QuotesLangTranslator;
120 QuotesLangTranslator const init_quoteslangtranslator()
122 QuotesLangTranslator translator(string_quotes_language[0], InsetQuotes::EnglishQ);
123 translator.addPair(string_quotes_language[1], InsetQuotes::SwedishQ);
124 translator.addPair(string_quotes_language[2], InsetQuotes::GermanQ);
125 translator.addPair(string_quotes_language[3], InsetQuotes::PolishQ);
126 translator.addPair(string_quotes_language[4], InsetQuotes::FrenchQ);
127 translator.addPair(string_quotes_language[5], InsetQuotes::DanishQ);
132 QuotesLangTranslator const & quoteslangtranslator()
134 static QuotesLangTranslator translator = init_quoteslangtranslator();
140 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
143 PaperSizeTranslator const init_papersizetranslator()
145 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
146 translator.addPair(string_papersize[1], PAPER_CUSTOM);
147 translator.addPair(string_papersize[2], PAPER_USLETTER);
148 translator.addPair(string_papersize[3], PAPER_USLEGAL);
149 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
150 translator.addPair(string_papersize[5], PAPER_A3);
151 translator.addPair(string_papersize[6], PAPER_A4);
152 translator.addPair(string_papersize[7], PAPER_A5);
153 translator.addPair(string_papersize[8], PAPER_B3);
154 translator.addPair(string_papersize[9], PAPER_B4);
155 translator.addPair(string_papersize[10], PAPER_B5);
160 PaperSizeTranslator const & papersizetranslator()
162 static PaperSizeTranslator translator = init_papersizetranslator();
168 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
171 PaperOrientationTranslator const init_paperorientationtranslator()
173 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
174 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
179 PaperOrientationTranslator const & paperorientationtranslator()
181 static PaperOrientationTranslator translator = init_paperorientationtranslator();
187 typedef Translator<int, PageSides> SidesTranslator;
190 SidesTranslator const init_sidestranslator()
192 SidesTranslator translator(1, OneSide);
193 translator.addPair(2, TwoSides);
198 SidesTranslator const & sidestranslator()
200 static SidesTranslator translator = init_sidestranslator();
206 typedef Translator<int, BufferParams::Package> PackageTranslator;
209 PackageTranslator const init_packagetranslator()
211 PackageTranslator translator(0, BufferParams::package_off);
212 translator.addPair(1, BufferParams::package_auto);
213 translator.addPair(2, BufferParams::package_on);
218 PackageTranslator const & packagetranslator()
220 static PackageTranslator translator = init_packagetranslator();
226 typedef Translator<string, biblio::CiteEngine> CiteEngineTranslator;
229 CiteEngineTranslator const init_citeenginetranslator()
231 CiteEngineTranslator translator("basic", biblio::ENGINE_BASIC);
232 translator.addPair("natbib_numerical", biblio::ENGINE_NATBIB_NUMERICAL);
233 translator.addPair("natbib_authoryear", biblio::ENGINE_NATBIB_AUTHORYEAR);
234 translator.addPair("jurabib", biblio::ENGINE_JURABIB);
239 CiteEngineTranslator const & citeenginetranslator()
241 static CiteEngineTranslator translator = init_citeenginetranslator();
247 typedef Translator<string, Spacing::Space> SpaceTranslator;
250 SpaceTranslator const init_spacetranslator()
252 SpaceTranslator translator("default", Spacing::Default);
253 translator.addPair("single", Spacing::Single);
254 translator.addPair("onehalf", Spacing::Onehalf);
255 translator.addPair("double", Spacing::Double);
256 translator.addPair("other", Spacing::Other);
261 SpaceTranslator const & spacetranslator()
263 static SpaceTranslator translator = init_spacetranslator();
271 class BufferParams::Impl
276 AuthorList authorlist;
277 BranchList branchlist;
278 Bullet temp_bullets[4];
279 Bullet user_defined_bullets[4];
281 /** This is the amount of space used for paragraph_separation "skip",
282 * and for detached paragraphs in "indented" documents.
285 PDFOptions pdfoptions;
289 BufferParams::Impl::Impl()
290 : defskip(VSpace::MEDSKIP)
292 // set initial author
294 authorlist.record(Author(from_utf8(lyxrc.user_name), from_utf8(lyxrc.user_email)));
299 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
303 return new BufferParams::Impl(*ptr);
307 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
313 BufferParams::BufferParams()
316 setBaseClass(defaultTextclass());
317 paragraph_separation = PARSEP_INDENT;
318 quotes_language = InsetQuotes::EnglishQ;
319 fontsize = "default";
322 papersize = PAPER_DEFAULT;
323 orientation = ORIENTATION_PORTRAIT;
324 use_geometry = false;
325 use_amsmath = package_auto;
326 use_esint = package_auto;
327 cite_engine_ = biblio::ENGINE_BASIC;
328 use_bibtopic = false;
329 trackChanges = false;
330 outputChanges = false;
333 language = default_language;
334 fontsRoman = "default";
335 fontsSans = "default";
336 fontsTypewriter = "default";
337 fontsDefaultFamily = "default";
340 fontsSansScale = 100;
341 fontsTypewriterScale = 100;
343 graphicsDriver = "default";
346 listings_params = string();
347 pagestyle = "default";
350 for (int iter = 0; iter < 4; ++iter) {
351 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
352 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
357 BufferParams::~BufferParams()
361 docstring const BufferParams::B_(string const & l10n) const
363 BOOST_ASSERT(language);
364 return getMessages(language->code()).get(l10n);
368 AuthorList & BufferParams::authors()
370 return pimpl_->authorlist;
374 AuthorList const & BufferParams::authors() const
376 return pimpl_->authorlist;
380 BranchList & BufferParams::branchlist()
382 return pimpl_->branchlist;
386 BranchList const & BufferParams::branchlist() const
388 return pimpl_->branchlist;
392 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
394 BOOST_ASSERT(index < 4);
395 return pimpl_->temp_bullets[index];
399 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
401 BOOST_ASSERT(index < 4);
402 return pimpl_->temp_bullets[index];
406 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
408 BOOST_ASSERT(index < 4);
409 return pimpl_->user_defined_bullets[index];
413 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
415 BOOST_ASSERT(index < 4);
416 return pimpl_->user_defined_bullets[index];
420 Spacing & BufferParams::spacing()
422 return pimpl_->spacing;
426 Spacing const & BufferParams::spacing() const
428 return pimpl_->spacing;
432 PDFOptions & BufferParams::pdfoptions()
434 return pimpl_->pdfoptions;
438 PDFOptions const & BufferParams::pdfoptions() const
440 return pimpl_->pdfoptions;
444 VSpace const & BufferParams::getDefSkip() const
446 return pimpl_->defskip;
450 void BufferParams::setDefSkip(VSpace const & vs)
452 pimpl_->defskip = vs;
456 string const BufferParams::readToken(Lexer & lex, string const & token,
457 FileName const & filepath)
459 if (token == "\\textclass") {
461 string const classname = lex.getString();
462 // if there exists a local layout file, ignore the system one
463 // NOTE: in this case, the textclass (.cls file) is assumed to be available.
464 pair<bool, lyx::textclass_type> pp =
465 make_pair(false, textclass_type(0));
466 if (!filepath.empty())
467 pp = textclasslist.addTextClass(
468 classname, filepath.absFilename());
470 setBaseClass(pp.second);
472 pp = textclasslist.numberOfClass(classname);
474 setBaseClass(pp.second);
476 // a warning will be given for unknown class
477 setBaseClass(defaultTextclass());
481 // FIXME: this warning will be given even if there exists a local .cls
482 // file. Even worse, the .lyx file can not be compiled or exported
483 // because the textclass is marked as unavilable.
484 if (!getTextClass().isTeXClassAvailable()) {
485 docstring const msg =
486 bformat(_("The layout file requested by this document,\n"
488 "is not usable. This is probably because a LaTeX\n"
489 "class or style file required by it is not\n"
490 "available. See the Customization documentation\n"
491 "for more information.\n"), from_utf8(classname));
492 frontend::Alert::warning(_("Document class not available"),
493 msg + _("LyX will not be able to produce output."));
496 } else if (token == "\\begin_preamble") {
498 } else if (token == "\\begin_modules") {
501 } else if (token == "\\options") {
503 options = lex.getString();
504 } else if (token == "\\language") {
506 } else if (token == "\\inputencoding") {
508 } else if (token == "\\graphics") {
509 readGraphicsDriver(lex);
510 } else if (token == "\\font_roman") {
512 } else if (token == "\\font_sans") {
514 } else if (token == "\\font_typewriter") {
515 lex >> fontsTypewriter;
516 } else if (token == "\\font_default_family") {
517 lex >> fontsDefaultFamily;
518 } else if (token == "\\font_sc") {
520 } else if (token == "\\font_osf") {
522 } else if (token == "\\font_sf_scale") {
523 lex >> fontsSansScale;
524 } else if (token == "\\font_tt_scale") {
525 lex >> fontsTypewriterScale;
526 } else if (token == "\\paragraph_separation") {
529 paragraph_separation = parseptranslator().find(parsep);
530 } else if (token == "\\defskip") {
532 pimpl_->defskip = VSpace(lex.getString());
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 == "\\paperfontsize") {
620 } else if (token == "\\papercolumns") {
622 } else if (token == "\\listings_params") {
625 listings_params = InsetListingsParams(par).params();
626 } else if (token == "\\papersides") {
629 sides = sidestranslator().find(psides);
630 } else if (token == "\\paperpagestyle") {
632 } else if (token == "\\bullet") {
634 } else if (token == "\\bulletLaTeX") {
635 readBulletsLaTeX(lex);
636 } else if (token == "\\secnumdepth") {
638 } else if (token == "\\tocdepth") {
640 } else if (token == "\\spacing") {
644 if (nspacing == "other") {
647 spacing().set(spacetranslator().find(nspacing), tmp_val);
648 } else if (token == "\\float_placement") {
649 lex >> float_placement;
651 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
652 string toktmp = pdfoptions().readToken(lex, token);
653 if (!toktmp.empty()) {
654 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
659 lyxerr << "BufferParams::readToken(): Unknown token: " <<
668 void BufferParams::writeFile(ostream & os) const
670 // The top of the file is written by the buffer.
671 // Prints out the buffer info into the .lyx file given by file
674 os << "\\textclass " << textclasslist[baseClass_].name() << '\n';
677 if (!preamble.empty()) {
678 // remove '\n' from the end of preamble
679 string const tmppreamble = rtrim(preamble, "\n");
680 os << "\\begin_preamble\n"
682 << "\n\\end_preamble\n";
686 if (!options.empty()) {
687 os << "\\options " << options << '\n';
691 if (!layoutModules_.empty()) {
692 os << "\\begin_modules" << '\n';
693 LayoutModuleList::const_iterator it = layoutModules_.begin();
694 for (; it != layoutModules_.end(); it++)
696 os << "\\end_modules" << '\n';
699 // then the text parameters
700 if (language != ignore_language)
701 os << "\\language " << language->lang() << '\n';
702 os << "\\inputencoding " << inputenc
703 << "\n\\font_roman " << fontsRoman
704 << "\n\\font_sans " << fontsSans
705 << "\n\\font_typewriter " << fontsTypewriter
706 << "\n\\font_default_family " << fontsDefaultFamily
707 << "\n\\font_sc " << convert<string>(fontsSC)
708 << "\n\\font_osf " << convert<string>(fontsOSF)
709 << "\n\\font_sf_scale " << fontsSansScale
710 << "\n\\font_tt_scale " << fontsTypewriterScale
711 << "\n\\graphics " << graphicsDriver << '\n';
713 if (!float_placement.empty()) {
714 os << "\\float_placement " << float_placement << '\n';
716 os << "\\paperfontsize " << fontsize << '\n';
718 spacing().writeFile(os);
719 pdfoptions().writeFile(os);
721 os << "\\papersize " << string_papersize[papersize]
722 << "\n\\use_geometry " << convert<string>(use_geometry)
723 << "\n\\use_amsmath " << use_amsmath
724 << "\n\\use_esint " << use_esint
725 << "\n\\cite_engine " << citeenginetranslator().find(cite_engine_)
726 << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
727 << "\n\\paperorientation " << string_orientation[orientation]
730 BranchList::const_iterator it = branchlist().begin();
731 BranchList::const_iterator end = branchlist().end();
732 for (; it != end; ++it) {
733 os << "\\branch " << to_utf8(it->getBranch())
734 << "\n\\selected " << it->getSelected()
735 << "\n\\color " << lyx::X11hexname(it->getColor())
740 if (!paperwidth.empty())
741 os << "\\paperwidth "
742 << VSpace(paperwidth).asLyXCommand() << '\n';
743 if (!paperheight.empty())
744 os << "\\paperheight "
745 << VSpace(paperheight).asLyXCommand() << '\n';
746 if (!leftmargin.empty())
747 os << "\\leftmargin "
748 << VSpace(leftmargin).asLyXCommand() << '\n';
749 if (!topmargin.empty())
751 << VSpace(topmargin).asLyXCommand() << '\n';
752 if (!rightmargin.empty())
753 os << "\\rightmargin "
754 << VSpace(rightmargin).asLyXCommand() << '\n';
755 if (!bottommargin.empty())
756 os << "\\bottommargin "
757 << VSpace(bottommargin).asLyXCommand() << '\n';
758 if (!headheight.empty())
759 os << "\\headheight "
760 << VSpace(headheight).asLyXCommand() << '\n';
761 if (!headsep.empty())
763 << VSpace(headsep).asLyXCommand() << '\n';
764 if (!footskip.empty())
766 << VSpace(footskip).asLyXCommand() << '\n';
767 os << "\\secnumdepth " << secnumdepth
768 << "\n\\tocdepth " << tocdepth
769 << "\n\\paragraph_separation "
770 << string_paragraph_separation[paragraph_separation]
771 << "\n\\defskip " << getDefSkip().asLyXCommand()
772 << "\n\\quotes_language "
773 << string_quotes_language[quotes_language]
774 << "\n\\papercolumns " << columns
775 << "\n\\papersides " << sides
776 << "\n\\paperpagestyle " << pagestyle << '\n';
777 if (!listings_params.empty())
778 os << "\\listings_params \"" <<
779 InsetListingsParams(listings_params).encodedString() << "\"\n";
780 for (int i = 0; i < 4; ++i) {
781 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
782 if (user_defined_bullet(i).getFont() != -1) {
783 os << "\\bullet " << i << " "
784 << user_defined_bullet(i).getFont() << " "
785 << user_defined_bullet(i).getCharacter() << " "
786 << user_defined_bullet(i).getSize() << "\n";
790 os << "\\bulletLaTeX " << i << " \""
791 << lyx::to_ascii(user_defined_bullet(i).getText())
797 os << "\\tracking_changes " << convert<string>(trackChanges) << "\n";
798 os << "\\output_changes " << convert<string>(outputChanges) << "\n";
800 AuthorList::Authors::const_iterator a_it = pimpl_->authorlist.begin();
801 AuthorList::Authors::const_iterator a_end = pimpl_->authorlist.end();
802 for (; a_it != a_end; ++a_it) {
803 if (a_it->second.used())
804 os << "\\author " << a_it->second << "\n";
806 os << "\\author " << Author() << "\n";
811 void BufferParams::validate(LaTeXFeatures & features) const
814 bool dvipost = LaTeXFeatures::isAvailable("dvipost");
815 bool xcolorsoul = LaTeXFeatures::isAvailable("soul") &&
816 LaTeXFeatures::isAvailable("xcolor");
818 switch (features.runparams().flavor) {
819 case OutputParams::LATEX:
821 features.require("ct-dvipost");
822 features.require("dvipost");
823 } else if (xcolorsoul) {
824 features.require("ct-xcolor-soul");
825 features.require("soul");
826 features.require("xcolor");
828 features.require("ct-none");
831 case OutputParams::PDFLATEX:
833 features.require("ct-xcolor-soul");
834 features.require("soul");
835 features.require("xcolor");
836 // improves color handling in PDF output
837 features.require("pdfcolmk");
839 features.require("ct-none");
847 // Floats with 'Here definitely' as default setting.
848 if (float_placement.find('H') != string::npos)
849 features.require("float");
851 // AMS Style is at document level
852 if (use_amsmath == package_on
853 || getTextClass().provides("amsmath"))
854 features.require("amsmath");
855 if (use_esint == package_on)
856 features.require("esint");
858 // the bullet shapes are buffer level not paragraph level
859 // so they are tested here
860 for (int i = 0; i < 4; ++i) {
861 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
863 int const font = user_defined_bullet(i).getFont();
865 int const c = user_defined_bullet(i).getCharacter();
871 features.require("latexsym");
873 } else if (font == 1) {
874 features.require("amssymb");
875 } else if (font >= 2 && font <= 5) {
876 features.require("pifont");
882 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
883 TexRow & texrow) const
885 os << "\\documentclass";
887 TextClass const & tclass = getTextClass();
889 ostringstream clsoptions; // the document class options.
891 if (tokenPos(tclass.opt_fontsize(),
892 '|', fontsize) >= 0) {
893 // only write if existing in list (and not default)
894 clsoptions << fontsize << "pt,";
897 // custom, A3, B3 and B4 paper sizes need geometry
898 bool nonstandard_papersize = papersize == PAPER_B3
899 || papersize == PAPER_B4
900 || papersize == PAPER_A3
901 || papersize == PAPER_CUSTOM;
906 clsoptions << "a4paper,";
909 clsoptions << "letterpaper,";
912 clsoptions << "a5paper,";
915 clsoptions << "b5paper,";
917 case PAPER_USEXECUTIVE:
918 clsoptions << "executivepaper,";
921 clsoptions << "legalpaper,";
933 if (sides != tclass.sides()) {
936 clsoptions << "oneside,";
939 clsoptions << "twoside,";
945 if (columns != tclass.columns()) {
947 clsoptions << "twocolumn,";
949 clsoptions << "onecolumn,";
953 && orientation == ORIENTATION_LANDSCAPE)
954 clsoptions << "landscape,";
956 // language should be a parameter to \documentclass
957 if (language->babel() == "hebrew"
958 && default_language->babel() != "hebrew")
959 // This seems necessary
960 features.useLanguage(default_language);
962 ostringstream language_options;
963 bool const use_babel = features.useBabel();
965 language_options << features.getLanguages();
966 if (!language->babel().empty()) {
967 if (!language_options.str().empty())
968 language_options << ',';
969 language_options << language->babel();
971 // when Vietnamese is used, babel must directly be loaded with the
972 // language options, not in the class options, see
973 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
974 size_t viet = language_options.str().find("vietnam");
975 // viet = string::npos when not found
976 if (lyxrc.language_global_options && !language_options.str().empty()
977 && viet == string::npos)
978 clsoptions << language_options.str() << ',';
981 // the user-defined options
982 if (!options.empty()) {
983 clsoptions << options << ',';
986 string strOptions(clsoptions.str());
987 if (!strOptions.empty()) {
988 strOptions = rtrim(strOptions, ",");
990 os << '[' << from_utf8(strOptions) << ']';
993 os << '{' << from_ascii(tclass.latexname()) << "}\n";
995 // end of \documentclass defs
997 // font selection must be done before loading fontenc.sty
999 loadFonts(fontsRoman, fontsSans,
1000 fontsTypewriter, fontsSC, fontsOSF,
1001 fontsSansScale, fontsTypewriterScale);
1002 if (!fonts.empty()) {
1003 os << from_ascii(fonts);
1006 if (fontsDefaultFamily != "default")
1007 os << "\\renewcommand{\\familydefault}{\\"
1008 << from_ascii(fontsDefaultFamily) << "}\n";
1010 // set font encoding
1011 // this one is not per buffer
1012 // for arabic_arabi and farsi we also need to load the LAE and LFE encoding
1013 if (lyxrc.fontenc != "default") {
1014 if (language->lang() == "arabic_arabi" || language->lang() == "farsi") {
1015 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
1016 << ",LFE,LAE]{fontenc}\n";
1019 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
1025 // handle inputenc etc.
1026 writeEncodingPreamble(os, features, texrow);
1028 if (!listings_params.empty()) {
1029 os << "\\usepackage{listings}\n";
1032 // do not test validity because listings_params is supposed to be valid
1033 string par = InsetListingsParams(listings_params).separatedParams(true);
1034 os << from_ascii(par);
1035 // count the number of newlines
1036 for (size_t i = 0; i < par.size(); ++i)
1042 if (use_geometry || nonstandard_papersize) {
1043 os << "\\usepackage{geometry}\n";
1045 os << "\\geometry{verbose";
1046 if (orientation == ORIENTATION_LANDSCAPE)
1048 switch (papersize) {
1050 if (!paperwidth.empty())
1051 os << ",paperwidth="
1052 << from_ascii(paperwidth);
1053 if (!paperheight.empty())
1054 os << ",paperheight="
1055 << from_ascii(paperheight);
1057 case PAPER_USLETTER:
1058 os << ",letterpaper";
1061 os << ",legalpaper";
1063 case PAPER_USEXECUTIVE:
1064 os << ",executivepaper";
1085 // default papersize ie PAPER_DEFAULT
1086 switch (lyxrc.default_papersize) {
1087 case PAPER_DEFAULT: // keep compiler happy
1088 case PAPER_USLETTER:
1089 os << ",letterpaper";
1092 os << ",legalpaper";
1094 case PAPER_USEXECUTIVE:
1095 os << ",executivepaper";
1115 if (!topmargin.empty())
1116 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1117 if (!bottommargin.empty())
1118 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1119 if (!leftmargin.empty())
1120 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1121 if (!rightmargin.empty())
1122 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1123 if (!headheight.empty())
1124 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1125 if (!headsep.empty())
1126 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1127 if (!footskip.empty())
1128 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1133 if (tokenPos(tclass.opt_pagestyle(),
1134 '|', pagestyle) >= 0) {
1135 if (pagestyle == "fancy") {
1136 os << "\\usepackage{fancyhdr}\n";
1139 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1143 // Only if class has a ToC hierarchy
1144 if (tclass.hasTocLevels()) {
1145 if (secnumdepth != tclass.secnumdepth()) {
1146 os << "\\setcounter{secnumdepth}{"
1151 if (tocdepth != tclass.tocdepth()) {
1152 os << "\\setcounter{tocdepth}{"
1159 if (paragraph_separation) {
1160 switch (getDefSkip().kind()) {
1161 case VSpace::SMALLSKIP:
1162 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1164 case VSpace::MEDSKIP:
1165 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1167 case VSpace::BIGSKIP:
1168 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1170 case VSpace::LENGTH:
1171 os << "\\setlength{\\parskip}{"
1172 << from_utf8(getDefSkip().length().asLatexString())
1175 default: // should never happen // Then delete it.
1176 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1181 os << "\\setlength{\\parindent}{0pt}\n";
1185 // If we use jurabib, we have to call babel here.
1186 if (use_babel && features.isRequired("jurabib")) {
1187 os << from_ascii(babelCall(language_options.str()))
1189 << from_ascii(features.getBabelOptions());
1193 // Now insert the LyX specific LaTeX commands...
1195 // The optional packages;
1196 docstring lyxpreamble(from_ascii(features.getPackages()));
1198 // We try to load babel late, in case it interferes
1199 // with other packages. But some packages also need babel to be loaded
1200 // before, e.g. jurabib has to be called after babel.
1201 // So load babel after the optional packages but before the user-defined
1202 // preamble. This allows the users to redefine babel commands, e.g. to
1203 // translate the word "Index" to the German "Stichwortverzeichnis".
1204 // For more infos why this place was chosen, see
1205 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg128425.html
1206 // If you encounter problems, you can shift babel to its old place behind
1207 // the user-defined preamble. But in this case you must change the Vietnamese
1208 // support from currently "\usepackage[vietnamese]{babel}" to:
1209 // \usepackage{vietnamese}
1210 // \usepackage{babel}
1211 // because vietnamese must be loaded before hyperref
1212 if (use_babel && !features.isRequired("jurabib")) {
1214 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1215 lyxpreamble += from_utf8(features.getBabelOptions());
1218 // When the language "japanese-plain" is used, the package "japanese" must
1219 // be loaded behind babel (it provides babel support for Japanese) but before
1221 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1222 if (language->lang() == "japanese-plain" &&
1223 !getTextClass().provides("japanese")) {
1224 //load babel in case it was not loaded due to an empty language list
1225 if (language_options.str().empty())
1226 lyxpreamble += "\\usepackage{babel}\n";
1227 lyxpreamble += "\\usepackage{japanese}\n";
1231 // * Hyperref manual: "Make sure it comes last of your loaded
1232 // packages, to give it a fighting chance of not being over-written,
1233 // since its job is to redefine many LATEX commands."
1234 // * Email from Heiko Oberdiek: "It is usually better to load babel
1235 // before hyperref. Then hyperref has a chance to detect babel.
1236 // * Has to be loaded before the "LyX specific LaTeX commands" to
1237 // avoid errors with algorithm floats.
1238 odocstringstream oss;
1239 // use hyperref explicitely when it is required
1240 pdfoptions().writeLaTeX(oss, features.isRequired("hyperref"));
1241 lyxpreamble += oss.str();
1243 // this might be useful...
1244 lyxpreamble += "\n\\makeatletter\n";
1246 // Some macros LyX will need
1247 docstring tmppreamble(from_ascii(features.getMacros()));
1249 if (!tmppreamble.empty()) {
1250 lyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1251 "LyX specific LaTeX commands.\n"
1252 + tmppreamble + '\n';
1255 // the text class specific preamble
1256 tmppreamble = features.getTClassPreamble();
1257 if (!tmppreamble.empty()) {
1258 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1259 "Textclass specific LaTeX commands.\n"
1260 + tmppreamble + '\n';
1263 /* the user-defined preamble */
1264 if (!preamble.empty()) {
1266 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1267 "User specified LaTeX commands.\n"
1268 + from_utf8(preamble) + '\n';
1271 // Itemize bullet settings need to be last in case the user
1272 // defines their own bullets that use a package included
1273 // in the user-defined preamble -- ARRae
1274 // Actually it has to be done much later than that
1275 // since some packages like frenchb make modifications
1276 // at \begin{document} time -- JMarc
1277 docstring bullets_def;
1278 for (int i = 0; i < 4; ++i) {
1279 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1280 if (bullets_def.empty())
1281 bullets_def += "\\AtBeginDocument{\n";
1282 bullets_def += " \\def\\labelitemi";
1284 // `i' is one less than the item to modify
1291 bullets_def += "ii";
1297 bullets_def += '{' +
1298 user_defined_bullet(i).getText()
1303 if (!bullets_def.empty())
1304 lyxpreamble += bullets_def + "}\n\n";
1306 lyxpreamble += "\\makeatother\n\n";
1309 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1310 for (int j = 0; j != nlines; ++j) {
1319 void BufferParams::useClassDefaults()
1321 TextClass const & tclass = textclasslist[baseClass_];
1323 sides = tclass.sides();
1324 columns = tclass.columns();
1325 pagestyle = tclass.pagestyle();
1326 options = tclass.options();
1327 // Only if class has a ToC hierarchy
1328 if (tclass.hasTocLevels()) {
1329 secnumdepth = tclass.secnumdepth();
1330 tocdepth = tclass.tocdepth();
1335 bool BufferParams::hasClassDefaults() const
1337 TextClass const & tclass = textclasslist[baseClass_];
1339 return (sides == tclass.sides()
1340 && columns == tclass.columns()
1341 && pagestyle == tclass.pagestyle()
1342 && options == tclass.options()
1343 && secnumdepth == tclass.secnumdepth()
1344 && tocdepth == tclass.tocdepth());
1348 TextClass const & BufferParams::getTextClass() const
1354 TextClassPtr BufferParams::getTextClassPtr() const {
1359 void BufferParams::setTextClass(TextClassPtr tc) {
1364 bool BufferParams::setBaseClass(textclass_type tc)
1367 if (textclasslist[tc].load())
1371 bformat(_("The document class %1$s could not be loaded."),
1372 from_utf8(textclasslist[tc].name()));
1373 frontend::Alert::error(_("Could not load class"), s);
1381 void BufferParams::setJustBaseClass(textclass_type tc)
1387 textclass_type BufferParams::getBaseClass() const
1393 void BufferParams::makeTextClass()
1395 textClass_.reset(new TextClass(textclasslist[getBaseClass()]));
1396 //FIXME It might be worth loading the children's modules here,
1397 //just as we load their bibliographies and such, instead of just
1398 //doing a check in InsetInclude.
1399 LayoutModuleList::const_iterator it = layoutModules_.begin();
1400 for (; it != layoutModules_.end(); it++) {
1401 string const modName = *it;
1402 LyXModule * lm = moduleList[modName];
1404 docstring const msg =
1405 bformat(_("The module %1$s has been requested by\n"
1406 "this document but has not been found in the list of\n"
1407 "available modules. If you recently installed it, you\n"
1408 "probably need to reconfigure LyX.\n"), from_utf8(modName));
1409 frontend::Alert::warning(_("Module not available"),
1410 msg + _("Some layouts may not be available."));
1411 lyxerr << "BufferParams::makeTextClass(): Module " <<
1412 modName << " requested but not found in module list." <<
1416 if (!lm->isAvailable()) {
1417 docstring const msg =
1418 bformat(_("The module %1$s requires a package that is\n"
1419 "not available in your LaTeX installation. LaTeX output\n"
1420 "may not be possible.\n"), from_utf8(modName));
1421 frontend::Alert::warning(_("Package not available"), msg);
1423 FileName layout_file = libFileSearch("layouts", lm->filename);
1424 textClass_->read(layout_file, TextClass::MODULE);
1429 vector<string> const & BufferParams::getModules() const {
1430 return layoutModules_;
1435 bool BufferParams::addLayoutModule(string modName, bool makeClass) {
1436 LayoutModuleList::const_iterator it = layoutModules_.begin();
1437 LayoutModuleList::const_iterator end = layoutModules_.end();
1438 for (; it != end; it++) {
1442 if (it != layoutModules_.end())
1444 layoutModules_.push_back(modName);
1451 bool BufferParams::addLayoutModules(vector<string>modNames)
1454 vector<string>::const_iterator it = modNames.begin();
1455 vector<string>::const_iterator end = modNames.end();
1456 for (; it != end; ++it)
1457 retval &= addLayoutModule(*it, false);
1463 void BufferParams::clearLayoutModules() {
1464 layoutModules_.clear();
1469 Font const BufferParams::getFont() const
1471 FontInfo f = getTextClass().defaultfont();
1472 if (fontsDefaultFamily == "rmdefault")
1473 f.setFamily(ROMAN_FAMILY);
1474 else if (fontsDefaultFamily == "sfdefault")
1475 f.setFamily(SANS_FAMILY);
1476 else if (fontsDefaultFamily == "ttdefault")
1477 f.setFamily(TYPEWRITER_FAMILY);
1478 return Font(f, language);
1482 void BufferParams::readPreamble(Lexer & lex)
1484 if (lex.getString() != "\\begin_preamble")
1485 lyxerr << "Error (BufferParams::readPreamble):"
1486 "consistency check failed." << endl;
1488 preamble = lex.getLongString("\\end_preamble");
1492 void BufferParams::readLanguage(Lexer & lex)
1494 if (!lex.next()) return;
1496 string const tmptok = lex.getString();
1498 // check if tmptok is part of tex_babel in tex-defs.h
1499 language = languages.getLanguage(tmptok);
1501 // Language tmptok was not found
1502 language = default_language;
1503 lyxerr << "Warning: Setting language `"
1504 << tmptok << "' to `" << language->lang()
1510 void BufferParams::readGraphicsDriver(Lexer & lex)
1512 if (!lex.next()) return;
1514 string const tmptok = lex.getString();
1515 // check if tmptok is part of tex_graphics in tex_defs.h
1518 string const test = tex_graphics[n++];
1520 if (test == tmptok) {
1521 graphicsDriver = tmptok;
1523 } else if (test == "") {
1525 "Warning: graphics driver `$$Token' not recognized!\n"
1526 " Setting graphics driver to `default'.\n");
1527 graphicsDriver = "default";
1534 void BufferParams::readBullets(Lexer & lex)
1536 if (!lex.next()) return;
1538 int const index = lex.getInteger();
1540 int temp_int = lex.getInteger();
1541 user_defined_bullet(index).setFont(temp_int);
1542 temp_bullet(index).setFont(temp_int);
1544 user_defined_bullet(index).setCharacter(temp_int);
1545 temp_bullet(index).setCharacter(temp_int);
1547 user_defined_bullet(index).setSize(temp_int);
1548 temp_bullet(index).setSize(temp_int);
1552 void BufferParams::readBulletsLaTeX(Lexer & lex)
1554 // The bullet class should be able to read this.
1555 if (!lex.next()) return;
1556 int const index = lex.getInteger();
1558 docstring const temp_str = lex.getDocString();
1560 user_defined_bullet(index).setText(temp_str);
1561 temp_bullet(index).setText(temp_str);
1565 void BufferParams::readModules(Lexer & lex)
1567 if (!lex.eatLine()) {
1568 lyxerr << "Error (BufferParams::readModules):"
1569 "Unexpected end of input." << endl;
1573 string mod = lex.getString();
1574 if (mod == "\\end_modules")
1576 addLayoutModule(mod);
1582 string const BufferParams::paperSizeName() const
1584 char real_papersize = papersize;
1585 if (real_papersize == PAPER_DEFAULT)
1586 real_papersize = lyxrc.default_papersize;
1588 switch (real_papersize) {
1597 case PAPER_USEXECUTIVE:
1601 case PAPER_USLETTER:
1608 string const BufferParams::dvips_options() const
1613 && papersize == PAPER_CUSTOM
1614 && !lyxrc.print_paper_dimension_flag.empty()
1615 && !paperwidth.empty()
1616 && !paperheight.empty()) {
1617 // using a custom papersize
1618 result = lyxrc.print_paper_dimension_flag;
1619 result += ' ' + paperwidth;
1620 result += ',' + paperheight;
1622 string const paper_option = paperSizeName();
1623 if (paper_option != "letter" ||
1624 orientation != ORIENTATION_LANDSCAPE) {
1625 // dvips won't accept -t letter -t landscape.
1626 // In all other cases, include the paper size
1628 result = lyxrc.print_paper_flag;
1629 result += ' ' + paper_option;
1632 if (orientation == ORIENTATION_LANDSCAPE &&
1633 papersize != PAPER_CUSTOM)
1634 result += ' ' + lyxrc.print_landscape_flag;
1639 string const BufferParams::babelCall(string const & lang_opts) const
1641 string lang_pack = lyxrc.language_package;
1642 if (lang_pack != "\\usepackage{babel}")
1644 // suppress the babel call when there is no babel language defined
1645 // for the document language in the lib/languages file and if no
1646 // other languages are used (lang_opts is then empty)
1647 if (lang_opts.empty())
1649 // when Vietnamese is used, babel must directly be loaded with the
1650 // language options, see
1651 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1652 size_t viet = lang_opts.find("vietnam");
1653 // viet = string::npos when not found
1654 if (!lyxrc.language_global_options || viet != string::npos)
1655 return "\\usepackage[" + lang_opts + "]{babel}";
1660 void BufferParams::writeEncodingPreamble(odocstream & os,
1661 LaTeXFeatures & features, TexRow & texrow) const
1663 if (inputenc == "auto") {
1664 string const doc_encoding =
1665 language->encoding()->latexName();
1666 Encoding::Package const package =
1667 language->encoding()->package();
1669 // Create a list with all the input encodings used
1671 set<string> encodings =
1672 features.getEncodingSet(doc_encoding);
1674 // When the encodings EUC-JP-plain, JIS-plain, or SJIS-plainare used, the
1675 // package inputenc must be omitted. Therefore set the encoding to empty.
1676 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1677 if (doc_encoding == "EUC-JP-plain" || doc_encoding == "JIS-plain" ||
1678 doc_encoding == "SJIS-plain")
1681 if (!encodings.empty() || package == Encoding::inputenc) {
1682 os << "\\usepackage[";
1683 set<string>::const_iterator it = encodings.begin();
1684 set<string>::const_iterator const end = encodings.end();
1686 os << from_ascii(*it);
1689 for (; it != end; ++it)
1690 os << ',' << from_ascii(*it);
1691 if (package == Encoding::inputenc) {
1692 if (!encodings.empty())
1694 os << from_ascii(doc_encoding);
1696 os << "]{inputenc}\n";
1699 if (package == Encoding::CJK || features.mustProvide("CJK")) {
1700 os << "\\usepackage{CJK}\n";
1703 } else if (inputenc != "default") {
1704 switch (encoding().package()) {
1705 case Encoding::none:
1707 case Encoding::inputenc:
1708 os << "\\usepackage[" << from_ascii(inputenc)
1713 os << "\\usepackage{CJK}\n";
1719 // The encoding "armscii8" is only available when the package "armtex" is loaded.
1720 // armscii8 is used for Armenian.
1721 if (language->encoding()->latexName() == "armscii8" || inputenc == "armscii8") {
1722 os << "\\usepackage{armtex}\n";
1728 string const BufferParams::loadFonts(string const & rm,
1729 string const & sf, string const & tt,
1730 bool const & sc, bool const & osf,
1731 int const & sfscale, int const & ttscale) const
1733 /* The LaTeX font world is in a flux. In the PSNFSS font interface,
1734 several packages have been replaced by others, that might not
1735 be installed on every system. We have to take care for that
1736 (see psnfss.pdf). We try to support all psnfss fonts as well
1737 as the fonts that have become de facto standard in the LaTeX
1738 world (e.g. Latin Modern). We do not support obsolete fonts
1739 (like PSLatex). In general, it should be possible to mix any
1740 rm font with any sf or tt font, respectively. (JSpitzm)
1742 -- separate math fonts.
1745 if (rm == "default" && sf == "default" && tt == "default")
1752 // Computer Modern (must be explicitely selectable -- there might be classes
1753 // that define a different default font!
1755 os << "\\renewcommand{\\rmdefault}{cmr}\n";
1756 // osf for Computer Modern needs eco.sty
1758 os << "\\usepackage{eco}\n";
1760 // Latin Modern Roman
1761 else if (rm == "lmodern")
1762 os << "\\usepackage{lmodern}\n";
1764 else if (rm == "ae") {
1765 // not needed when using OT1 font encoding.
1766 if (lyxrc.fontenc != "default")
1767 os << "\\usepackage{ae,aecompl}\n";
1770 else if (rm == "times") {
1771 // try to load the best available package
1772 if (LaTeXFeatures::isAvailable("mathptmx"))
1773 os << "\\usepackage{mathptmx}\n";
1774 else if (LaTeXFeatures::isAvailable("mathptm"))
1775 os << "\\usepackage{mathptm}\n";
1777 os << "\\usepackage{times}\n";
1780 else if (rm == "palatino") {
1781 // try to load the best available package
1782 if (LaTeXFeatures::isAvailable("mathpazo")) {
1783 os << "\\usepackage";
1789 // "osf" includes "sc"!
1793 os << "{mathpazo}\n";
1795 else if (LaTeXFeatures::isAvailable("mathpple"))
1796 os << "\\usepackage{mathpple}\n";
1798 os << "\\usepackage{palatino}\n";
1801 else if (rm == "utopia") {
1802 // fourier supersedes utopia.sty, but does
1803 // not work with OT1 encoding.
1804 if (LaTeXFeatures::isAvailable("fourier")
1805 && lyxrc.fontenc != "default") {
1806 os << "\\usepackage";
1817 os << "{fourier}\n";
1820 os << "\\usepackage{utopia}\n";
1822 // Bera (complete fontset)
1823 else if (rm == "bera" && sf == "default" && tt == "default")
1824 os << "\\usepackage{bera}\n";
1826 else if (rm != "default")
1827 os << "\\usepackage" << "{" << rm << "}\n";
1830 // Helvetica, Bera Sans
1831 if (sf == "helvet" || sf == "berasans") {
1833 os << "\\usepackage[scaled=" << float(sfscale) / 100
1834 << "]{" << sf << "}\n";
1836 os << "\\usepackage{" << sf << "}\n";
1839 else if (sf == "avant")
1840 os << "\\usepackage{" << sf << "}\n";
1841 // Computer Modern, Latin Modern, CM Bright
1842 else if (sf != "default")
1843 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
1845 // monospaced/typewriter
1846 // Courier, LuxiMono
1847 if (tt == "luximono" || tt == "beramono") {
1849 os << "\\usepackage[scaled=" << float(ttscale) / 100
1850 << "]{" << tt << "}\n";
1852 os << "\\usepackage{" << tt << "}\n";
1855 else if (tt == "courier" )
1856 os << "\\usepackage{" << tt << "}\n";
1857 // Computer Modern, Latin Modern, CM Bright
1858 else if (tt != "default")
1859 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
1865 Encoding const & BufferParams::encoding() const
1867 if (inputenc == "auto" || inputenc == "default")
1868 return *(language->encoding());
1869 Encoding const * const enc =
1870 encodings.getFromLaTeXName(inputenc);
1873 lyxerr << "Unknown inputenc value `" << inputenc
1874 << "'. Using `auto' instead." << endl;
1875 return *(language->encoding());
1879 biblio::CiteEngine BufferParams::getEngine() const
1881 // FIXME the class should provide the numerical/
1882 // authoryear choice
1883 if (getTextClass().provides("natbib")
1884 && cite_engine_ != biblio::ENGINE_NATBIB_NUMERICAL)
1885 return biblio::ENGINE_NATBIB_AUTHORYEAR;
1886 return cite_engine_;
1890 void BufferParams::setCiteEngine(biblio::CiteEngine const cite_engine)
1892 cite_engine_ = cite_engine;