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 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
812 TexRow & texrow) const
814 os << "\\documentclass";
816 TextClass const & tclass = getTextClass();
818 ostringstream clsoptions; // the document class options.
820 if (tokenPos(tclass.opt_fontsize(),
821 '|', fontsize) >= 0) {
822 // only write if existing in list (and not default)
823 clsoptions << fontsize << "pt,";
826 // custom, A3, B3 and B4 paper sizes need geometry
827 bool nonstandard_papersize = papersize == PAPER_B3
828 || papersize == PAPER_B4
829 || papersize == PAPER_A3
830 || papersize == PAPER_CUSTOM;
835 clsoptions << "a4paper,";
838 clsoptions << "letterpaper,";
841 clsoptions << "a5paper,";
844 clsoptions << "b5paper,";
846 case PAPER_USEXECUTIVE:
847 clsoptions << "executivepaper,";
850 clsoptions << "legalpaper,";
862 if (sides != tclass.sides()) {
865 clsoptions << "oneside,";
868 clsoptions << "twoside,";
874 if (columns != tclass.columns()) {
876 clsoptions << "twocolumn,";
878 clsoptions << "onecolumn,";
882 && orientation == ORIENTATION_LANDSCAPE)
883 clsoptions << "landscape,";
885 // language should be a parameter to \documentclass
886 if (language->babel() == "hebrew"
887 && default_language->babel() != "hebrew")
888 // This seems necessary
889 features.useLanguage(default_language);
891 ostringstream language_options;
892 bool const use_babel = features.useBabel();
894 language_options << features.getLanguages();
895 if (!language->babel().empty()) {
896 if (!language_options.str().empty())
897 language_options << ',';
898 language_options << language->babel();
900 // when Vietnamese is used, babel must directly be loaded with the
901 // language options, not in the class options, see
902 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
903 size_t viet = language_options.str().find("vietnam");
904 // viet = string::npos when not found
905 if (lyxrc.language_global_options && !language_options.str().empty()
906 && viet == string::npos)
907 clsoptions << language_options.str() << ',';
910 // the user-defined options
911 if (!options.empty()) {
912 clsoptions << options << ',';
915 string strOptions(clsoptions.str());
916 if (!strOptions.empty()) {
917 strOptions = rtrim(strOptions, ",");
919 os << '[' << from_utf8(strOptions) << ']';
922 os << '{' << from_ascii(tclass.latexname()) << "}\n";
924 // end of \documentclass defs
926 // font selection must be done before loading fontenc.sty
928 loadFonts(fontsRoman, fontsSans,
929 fontsTypewriter, fontsSC, fontsOSF,
930 fontsSansScale, fontsTypewriterScale);
931 if (!fonts.empty()) {
932 os << from_ascii(fonts);
935 if (fontsDefaultFamily != "default")
936 os << "\\renewcommand{\\familydefault}{\\"
937 << from_ascii(fontsDefaultFamily) << "}\n";
940 // this one is not per buffer
941 // for arabic_arabi and farsi we also need to load the LAE and LFE encoding
942 if (lyxrc.fontenc != "default") {
943 if (language->lang() == "arabic_arabi" || language->lang() == "farsi") {
944 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
945 << ",LFE,LAE]{fontenc}\n";
948 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
954 // handle inputenc etc.
955 writeEncodingPreamble(os, features, texrow);
957 if (!listings_params.empty()) {
958 os << "\\usepackage{listings}\n";
961 // do not test validity because listings_params is supposed to be valid
962 string par = InsetListingsParams(listings_params).separatedParams(true);
963 os << from_ascii(par);
964 // count the number of newlines
965 for (size_t i = 0; i < par.size(); ++i)
971 if (use_geometry || nonstandard_papersize) {
972 os << "\\usepackage{geometry}\n";
974 os << "\\geometry{verbose";
975 if (orientation == ORIENTATION_LANDSCAPE)
979 if (!paperwidth.empty())
981 << from_ascii(paperwidth);
982 if (!paperheight.empty())
983 os << ",paperheight="
984 << from_ascii(paperheight);
987 os << ",letterpaper";
992 case PAPER_USEXECUTIVE:
993 os << ",executivepaper";
1014 // default papersize ie PAPER_DEFAULT
1015 switch (lyxrc.default_papersize) {
1016 case PAPER_DEFAULT: // keep compiler happy
1017 case PAPER_USLETTER:
1018 os << ",letterpaper";
1021 os << ",legalpaper";
1023 case PAPER_USEXECUTIVE:
1024 os << ",executivepaper";
1044 if (!topmargin.empty())
1045 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1046 if (!bottommargin.empty())
1047 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1048 if (!leftmargin.empty())
1049 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1050 if (!rightmargin.empty())
1051 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1052 if (!headheight.empty())
1053 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1054 if (!headsep.empty())
1055 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1056 if (!footskip.empty())
1057 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1062 if (tokenPos(tclass.opt_pagestyle(),
1063 '|', pagestyle) >= 0) {
1064 if (pagestyle == "fancy") {
1065 os << "\\usepackage{fancyhdr}\n";
1068 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1072 // Only if class has a ToC hierarchy
1073 if (tclass.hasTocLevels()) {
1074 if (secnumdepth != tclass.secnumdepth()) {
1075 os << "\\setcounter{secnumdepth}{"
1080 if (tocdepth != tclass.tocdepth()) {
1081 os << "\\setcounter{tocdepth}{"
1088 if (paragraph_separation) {
1089 switch (getDefSkip().kind()) {
1090 case VSpace::SMALLSKIP:
1091 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1093 case VSpace::MEDSKIP:
1094 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1096 case VSpace::BIGSKIP:
1097 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1099 case VSpace::LENGTH:
1100 os << "\\setlength{\\parskip}{"
1101 << from_utf8(getDefSkip().length().asLatexString())
1104 default: // should never happen // Then delete it.
1105 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1110 os << "\\setlength{\\parindent}{0pt}\n";
1114 // If we use jurabib, we have to call babel here.
1115 if (use_babel && features.isRequired("jurabib")) {
1116 os << from_ascii(babelCall(language_options.str()))
1118 << from_ascii(features.getBabelOptions());
1122 // Now insert the LyX specific LaTeX commands...
1124 // The optional packages;
1125 docstring lyxpreamble(from_ascii(features.getPackages()));
1127 // We try to load babel late, in case it interferes
1128 // with other packages. But some packages also need babel to be loaded
1129 // before, e.g. jurabib has to be called after babel.
1130 // So load babel after the optional packages but before the user-defined
1131 // preamble. This allows the users to redefine babel commands, e.g. to
1132 // translate the word "Index" to the German "Stichwortverzeichnis".
1133 // For more infos why this place was chosen, see
1134 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg128425.html
1135 // If you encounter problems, you can shift babel to its old place behind
1136 // the user-defined preamble. But in this case you must change the Vietnamese
1137 // support from currently "\usepackage[vietnamese]{babel}" to:
1138 // \usepackage{vietnamese}
1139 // \usepackage{babel}
1140 // because vietnamese must be loaded before hyperref
1141 if (use_babel && !features.isRequired("jurabib")) {
1143 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1144 lyxpreamble += from_utf8(features.getBabelOptions());
1147 // When the language "japanese-plain" is used, the package "japanese" must
1148 // be loaded behind babel (it provides babel support for Japanese) but before
1150 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1151 if (language->lang() == "japanese-plain" &&
1152 !getTextClass().provides("japanese")) {
1153 //load babel in case it was not loaded due to an empty language list
1154 if (language_options.str().empty())
1155 lyxpreamble += "\\usepackage{babel}\n";
1156 lyxpreamble += "\\usepackage{japanese}\n";
1160 // * Hyperref manual: "Make sure it comes last of your loaded
1161 // packages, to give it a fighting chance of not being over-written,
1162 // since its job is to redefine many LATEX commands."
1163 // * Email from Heiko Oberdiek: "It is usually better to load babel
1164 // before hyperref. Then hyperref has a chance to detect babel.
1165 // * Has to be loaded before the "LyX specific LaTeX commands" to
1166 // avoid errors with algorithm floats.
1167 odocstringstream oss;
1168 // use hyperref explicitely when it is required
1169 pdfoptions().writeLaTeX(oss, features.isRequired("hyperref"));
1170 lyxpreamble += oss.str();
1172 // this might be useful...
1173 lyxpreamble += "\n\\makeatletter\n";
1175 // Some macros LyX will need
1176 docstring tmppreamble(from_ascii(features.getMacros()));
1178 if (!tmppreamble.empty()) {
1179 lyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1180 "LyX specific LaTeX commands.\n"
1181 + tmppreamble + '\n';
1184 // the text class specific preamble
1185 tmppreamble = features.getTClassPreamble();
1186 if (!tmppreamble.empty()) {
1187 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1188 "Textclass specific LaTeX commands.\n"
1189 + tmppreamble + '\n';
1192 /* the user-defined preamble */
1193 if (!preamble.empty()) {
1195 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1196 "User specified LaTeX commands.\n"
1197 + from_utf8(preamble) + '\n';
1200 // Itemize bullet settings need to be last in case the user
1201 // defines their own bullets that use a package included
1202 // in the user-defined preamble -- ARRae
1203 // Actually it has to be done much later than that
1204 // since some packages like frenchb make modifications
1205 // at \begin{document} time -- JMarc
1206 docstring bullets_def;
1207 for (int i = 0; i < 4; ++i) {
1208 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1209 if (bullets_def.empty())
1210 bullets_def += "\\AtBeginDocument{\n";
1211 bullets_def += " \\def\\labelitemi";
1213 // `i' is one less than the item to modify
1220 bullets_def += "ii";
1226 bullets_def += '{' +
1227 user_defined_bullet(i).getText()
1232 if (!bullets_def.empty())
1233 lyxpreamble += bullets_def + "}\n\n";
1235 lyxpreamble += "\\makeatother\n\n";
1238 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1239 for (int j = 0; j != nlines; ++j) {
1248 void BufferParams::useClassDefaults()
1250 TextClass const & tclass = textclasslist[baseClass_];
1252 sides = tclass.sides();
1253 columns = tclass.columns();
1254 pagestyle = tclass.pagestyle();
1255 options = tclass.options();
1256 // Only if class has a ToC hierarchy
1257 if (tclass.hasTocLevels()) {
1258 secnumdepth = tclass.secnumdepth();
1259 tocdepth = tclass.tocdepth();
1264 bool BufferParams::hasClassDefaults() const
1266 TextClass const & tclass = textclasslist[baseClass_];
1268 return (sides == tclass.sides()
1269 && columns == tclass.columns()
1270 && pagestyle == tclass.pagestyle()
1271 && options == tclass.options()
1272 && secnumdepth == tclass.secnumdepth()
1273 && tocdepth == tclass.tocdepth());
1277 TextClass const & BufferParams::getTextClass() const
1283 TextClassPtr BufferParams::getTextClassPtr() const {
1288 void BufferParams::setTextClass(TextClassPtr tc) {
1293 bool BufferParams::setBaseClass(textclass_type tc)
1296 if (textclasslist[tc].load())
1300 bformat(_("The document class %1$s could not be loaded."),
1301 from_utf8(textclasslist[tc].name()));
1302 frontend::Alert::error(_("Could not load class"), s);
1310 void BufferParams::setJustBaseClass(textclass_type tc)
1316 textclass_type BufferParams::getBaseClass() const
1322 void BufferParams::makeTextClass()
1324 textClass_.reset(new TextClass(textclasslist[getBaseClass()]));
1325 //FIXME It might be worth loading the children's modules here,
1326 //just as we load their bibliographies and such, instead of just
1327 //doing a check in InsetInclude.
1328 LayoutModuleList::const_iterator it = layoutModules_.begin();
1329 for (; it != layoutModules_.end(); it++) {
1330 string const modName = *it;
1331 LyXModule * lm = moduleList[modName];
1333 docstring const msg =
1334 bformat(_("The module %1$s has been requested by\n"
1335 "this document but has not been found in the list of\n"
1336 "available modules. If you recently installed it, you\n"
1337 "probably need to reconfigure LyX.\n"), from_utf8(modName));
1338 frontend::Alert::warning(_("Module not available"),
1339 msg + _("Some layouts may not be available."));
1340 lyxerr << "BufferParams::makeTextClass(): Module " <<
1341 modName << " requested but not found in module list." <<
1345 FileName layout_file = libFileSearch("layouts", lm->filename);
1346 textClass_->read(layout_file, TextClass::MODULE);
1351 vector<string> const & BufferParams::getModules() const {
1352 return layoutModules_;
1357 bool BufferParams::addLayoutModule(string modName, bool makeClass) {
1358 LayoutModuleList::const_iterator it = layoutModules_.begin();
1359 LayoutModuleList::const_iterator end = layoutModules_.end();
1360 for (; it != end; it++) {
1364 if (it != layoutModules_.end())
1366 layoutModules_.push_back(modName);
1373 bool BufferParams::addLayoutModules(vector<string>modNames)
1376 vector<string>::const_iterator it = modNames.begin();
1377 vector<string>::const_iterator end = modNames.end();
1378 for (; it != end; ++it)
1379 retval &= addLayoutModule(*it, false);
1385 void BufferParams::clearLayoutModules() {
1386 layoutModules_.clear();
1391 Font const BufferParams::getFont() const
1393 FontInfo f = getTextClass().defaultfont();
1394 if (fontsDefaultFamily == "rmdefault")
1395 f.setFamily(ROMAN_FAMILY);
1396 else if (fontsDefaultFamily == "sfdefault")
1397 f.setFamily(SANS_FAMILY);
1398 else if (fontsDefaultFamily == "ttdefault")
1399 f.setFamily(TYPEWRITER_FAMILY);
1400 return Font(f, language);
1404 void BufferParams::readPreamble(Lexer & lex)
1406 if (lex.getString() != "\\begin_preamble")
1407 lyxerr << "Error (BufferParams::readPreamble):"
1408 "consistency check failed." << endl;
1410 preamble = lex.getLongString("\\end_preamble");
1414 void BufferParams::readLanguage(Lexer & lex)
1416 if (!lex.next()) return;
1418 string const tmptok = lex.getString();
1420 // check if tmptok is part of tex_babel in tex-defs.h
1421 language = languages.getLanguage(tmptok);
1423 // Language tmptok was not found
1424 language = default_language;
1425 lyxerr << "Warning: Setting language `"
1426 << tmptok << "' to `" << language->lang()
1432 void BufferParams::readGraphicsDriver(Lexer & lex)
1434 if (!lex.next()) return;
1436 string const tmptok = lex.getString();
1437 // check if tmptok is part of tex_graphics in tex_defs.h
1440 string const test = tex_graphics[n++];
1442 if (test == tmptok) {
1443 graphicsDriver = tmptok;
1445 } else if (test == "") {
1447 "Warning: graphics driver `$$Token' not recognized!\n"
1448 " Setting graphics driver to `default'.\n");
1449 graphicsDriver = "default";
1456 void BufferParams::readBullets(Lexer & lex)
1458 if (!lex.next()) return;
1460 int const index = lex.getInteger();
1462 int temp_int = lex.getInteger();
1463 user_defined_bullet(index).setFont(temp_int);
1464 temp_bullet(index).setFont(temp_int);
1466 user_defined_bullet(index).setCharacter(temp_int);
1467 temp_bullet(index).setCharacter(temp_int);
1469 user_defined_bullet(index).setSize(temp_int);
1470 temp_bullet(index).setSize(temp_int);
1474 void BufferParams::readBulletsLaTeX(Lexer & lex)
1476 // The bullet class should be able to read this.
1477 if (!lex.next()) return;
1478 int const index = lex.getInteger();
1480 docstring const temp_str = lex.getDocString();
1482 user_defined_bullet(index).setText(temp_str);
1483 temp_bullet(index).setText(temp_str);
1487 void BufferParams::readModules(Lexer & lex)
1489 if (!lex.eatLine()) {
1490 lyxerr << "Error (BufferParams::readModules):"
1491 "Unexpected end of input." << endl;
1495 string mod = lex.getString();
1496 if (mod == "\\end_modules")
1498 addLayoutModule(mod);
1504 string const BufferParams::paperSizeName() const
1506 char real_papersize = papersize;
1507 if (real_papersize == PAPER_DEFAULT)
1508 real_papersize = lyxrc.default_papersize;
1510 switch (real_papersize) {
1519 case PAPER_USEXECUTIVE:
1523 case PAPER_USLETTER:
1530 string const BufferParams::dvips_options() const
1535 && papersize == PAPER_CUSTOM
1536 && !lyxrc.print_paper_dimension_flag.empty()
1537 && !paperwidth.empty()
1538 && !paperheight.empty()) {
1539 // using a custom papersize
1540 result = lyxrc.print_paper_dimension_flag;
1541 result += ' ' + paperwidth;
1542 result += ',' + paperheight;
1544 string const paper_option = paperSizeName();
1545 if (paper_option != "letter" ||
1546 orientation != ORIENTATION_LANDSCAPE) {
1547 // dvips won't accept -t letter -t landscape.
1548 // In all other cases, include the paper size
1550 result = lyxrc.print_paper_flag;
1551 result += ' ' + paper_option;
1554 if (orientation == ORIENTATION_LANDSCAPE &&
1555 papersize != PAPER_CUSTOM)
1556 result += ' ' + lyxrc.print_landscape_flag;
1561 string const BufferParams::babelCall(string const & lang_opts) const
1563 string lang_pack = lyxrc.language_package;
1564 if (lang_pack != "\\usepackage{babel}")
1566 // suppress the babel call when there is no babel language defined
1567 // for the document language in the lib/languages file and if no
1568 // other languages are used (lang_opts is then empty)
1569 if (lang_opts.empty())
1571 // when Vietnamese is used, babel must directly be loaded with the
1572 // language options, see
1573 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1574 size_t viet = lang_opts.find("vietnam");
1575 // viet = string::npos when not found
1576 if (!lyxrc.language_global_options || viet != string::npos)
1577 return "\\usepackage[" + lang_opts + "]{babel}";
1582 void BufferParams::writeEncodingPreamble(odocstream & os,
1583 LaTeXFeatures & features, TexRow & texrow) const
1585 if (inputenc == "auto") {
1586 string const doc_encoding =
1587 language->encoding()->latexName();
1588 Encoding::Package const package =
1589 language->encoding()->package();
1591 // Create a list with all the input encodings used
1593 set<string> encodings =
1594 features.getEncodingSet(doc_encoding);
1596 // When the encodings EUC-JP-plain, JIS-plain, or SJIS-plainare used, the
1597 // package inputenc must be omitted. Therefore set the encoding to empty.
1598 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1599 if (doc_encoding == "EUC-JP-plain" || doc_encoding == "JIS-plain" ||
1600 doc_encoding == "SJIS-plain")
1603 if (!encodings.empty() || package == Encoding::inputenc) {
1604 os << "\\usepackage[";
1605 set<string>::const_iterator it = encodings.begin();
1606 set<string>::const_iterator const end = encodings.end();
1608 os << from_ascii(*it);
1611 for (; it != end; ++it)
1612 os << ',' << from_ascii(*it);
1613 if (package == Encoding::inputenc) {
1614 if (!encodings.empty())
1616 os << from_ascii(doc_encoding);
1618 os << "]{inputenc}\n";
1621 if (package == Encoding::CJK || features.mustProvide("CJK")) {
1622 os << "\\usepackage{CJK}\n";
1625 } else if (inputenc != "default") {
1626 switch (encoding().package()) {
1627 case Encoding::none:
1629 case Encoding::inputenc:
1630 os << "\\usepackage[" << from_ascii(inputenc)
1635 os << "\\usepackage{CJK}\n";
1641 // The encoding "armscii8" is only available when the package "armtex" is loaded.
1642 // armscii8 is used for Armenian.
1643 if (language->encoding()->latexName() == "armscii8" || inputenc == "armscii8") {
1644 os << "\\usepackage{armtex}\n";
1650 string const BufferParams::loadFonts(string const & rm,
1651 string const & sf, string const & tt,
1652 bool const & sc, bool const & osf,
1653 int const & sfscale, int const & ttscale) const
1655 /* The LaTeX font world is in a flux. In the PSNFSS font interface,
1656 several packages have been replaced by others, that might not
1657 be installed on every system. We have to take care for that
1658 (see psnfss.pdf). We try to support all psnfss fonts as well
1659 as the fonts that have become de facto standard in the LaTeX
1660 world (e.g. Latin Modern). We do not support obsolete fonts
1661 (like PSLatex). In general, it should be possible to mix any
1662 rm font with any sf or tt font, respectively. (JSpitzm)
1664 -- separate math fonts.
1667 if (rm == "default" && sf == "default" && tt == "default")
1674 // Computer Modern (must be explicitely selectable -- there might be classes
1675 // that define a different default font!
1677 os << "\\renewcommand{\\rmdefault}{cmr}\n";
1678 // osf for Computer Modern needs eco.sty
1680 os << "\\usepackage{eco}\n";
1682 // Latin Modern Roman
1683 else if (rm == "lmodern")
1684 os << "\\usepackage{lmodern}\n";
1686 else if (rm == "ae") {
1687 // not needed when using OT1 font encoding.
1688 if (lyxrc.fontenc != "default")
1689 os << "\\usepackage{ae,aecompl}\n";
1692 else if (rm == "times") {
1693 // try to load the best available package
1694 if (LaTeXFeatures::isAvailable("mathptmx"))
1695 os << "\\usepackage{mathptmx}\n";
1696 else if (LaTeXFeatures::isAvailable("mathptm"))
1697 os << "\\usepackage{mathptm}\n";
1699 os << "\\usepackage{times}\n";
1702 else if (rm == "palatino") {
1703 // try to load the best available package
1704 if (LaTeXFeatures::isAvailable("mathpazo")) {
1705 os << "\\usepackage";
1711 // "osf" includes "sc"!
1715 os << "{mathpazo}\n";
1717 else if (LaTeXFeatures::isAvailable("mathpple"))
1718 os << "\\usepackage{mathpple}\n";
1720 os << "\\usepackage{palatino}\n";
1723 else if (rm == "utopia") {
1724 // fourier supersedes utopia.sty, but does
1725 // not work with OT1 encoding.
1726 if (LaTeXFeatures::isAvailable("fourier")
1727 && lyxrc.fontenc != "default") {
1728 os << "\\usepackage";
1739 os << "{fourier}\n";
1742 os << "\\usepackage{utopia}\n";
1744 // Bera (complete fontset)
1745 else if (rm == "bera" && sf == "default" && tt == "default")
1746 os << "\\usepackage{bera}\n";
1748 else if (rm != "default")
1749 os << "\\usepackage" << "{" << rm << "}\n";
1752 // Helvetica, Bera Sans
1753 if (sf == "helvet" || sf == "berasans") {
1755 os << "\\usepackage[scaled=" << float(sfscale) / 100
1756 << "]{" << sf << "}\n";
1758 os << "\\usepackage{" << sf << "}\n";
1761 else if (sf == "avant")
1762 os << "\\usepackage{" << sf << "}\n";
1763 // Computer Modern, Latin Modern, CM Bright
1764 else if (sf != "default")
1765 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
1767 // monospaced/typewriter
1768 // Courier, LuxiMono
1769 if (tt == "luximono" || tt == "beramono") {
1771 os << "\\usepackage[scaled=" << float(ttscale) / 100
1772 << "]{" << tt << "}\n";
1774 os << "\\usepackage{" << tt << "}\n";
1777 else if (tt == "courier" )
1778 os << "\\usepackage{" << tt << "}\n";
1779 // Computer Modern, Latin Modern, CM Bright
1780 else if (tt != "default")
1781 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
1787 Encoding const & BufferParams::encoding() const
1789 if (inputenc == "auto" || inputenc == "default")
1790 return *(language->encoding());
1791 Encoding const * const enc =
1792 encodings.getFromLaTeXName(inputenc);
1795 lyxerr << "Unknown inputenc value `" << inputenc
1796 << "'. Using `auto' instead." << endl;
1797 return *(language->encoding());
1801 biblio::CiteEngine BufferParams::getEngine() const
1803 // FIXME the class should provide the numerical/
1804 // authoryear choice
1805 if (getTextClass().provides("natbib")
1806 && cite_engine_ != biblio::ENGINE_NATBIB_NUMERICAL)
1807 return biblio::ENGINE_NATBIB_AUTHORYEAR;
1808 return cite_engine_;
1812 void BufferParams::setCiteEngine(biblio::CiteEngine const cite_engine)
1814 cite_engine_ = cite_engine;