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"
60 using std::istringstream;
62 using std::ostringstream;
65 using lyx::support::FileName;
66 using lyx::support::libFileSearch;
67 using lyx::support::bformat;
68 using lyx::support::rtrim;
69 using lyx::support::tokenPos;
70 using lyx::support::prefixIs;
73 static char const * const string_paragraph_separation[] = {
78 static char const * const string_quotes_language[] = {
79 "english", "swedish", "german", "polish", "french", "danish", ""
83 static char const * const string_papersize[] = {
84 "default", "custom", "letterpaper", "executivepaper", "legalpaper",
85 "a3paper", "a4paper", "a5paper", "b3paper", "b4paper", "b5paper", ""
89 static char const * const string_orientation[] = {
90 "portrait", "landscape", ""
94 static char const * const string_footnotekinds[] = {
95 "footnote", "margin", "fig", "tab", "alg", "wide-fig", "wide-tab", ""
99 static char const * const tex_graphics[] = {
100 "default", "dvips", "dvitops", "emtex",
101 "ln", "oztex", "textures", "none", ""
110 // Paragraph separation
111 typedef Translator<string, BufferParams::PARSEP> ParSepTranslator;
114 ParSepTranslator const init_parseptranslator()
116 ParSepTranslator translator(string_paragraph_separation[0], BufferParams::PARSEP_INDENT);
117 translator.addPair(string_paragraph_separation[1], BufferParams::PARSEP_SKIP);
122 ParSepTranslator const & parseptranslator()
124 static ParSepTranslator translator = init_parseptranslator();
130 typedef Translator<string, InsetQuotes::quote_language> QuotesLangTranslator;
133 QuotesLangTranslator const init_quoteslangtranslator()
135 QuotesLangTranslator translator(string_quotes_language[0], InsetQuotes::EnglishQ);
136 translator.addPair(string_quotes_language[1], InsetQuotes::SwedishQ);
137 translator.addPair(string_quotes_language[2], InsetQuotes::GermanQ);
138 translator.addPair(string_quotes_language[3], InsetQuotes::PolishQ);
139 translator.addPair(string_quotes_language[4], InsetQuotes::FrenchQ);
140 translator.addPair(string_quotes_language[5], InsetQuotes::DanishQ);
145 QuotesLangTranslator const & quoteslangtranslator()
147 static QuotesLangTranslator translator = init_quoteslangtranslator();
153 typedef Translator<std::string, PAPER_SIZE> PaperSizeTranslator;
156 PaperSizeTranslator const init_papersizetranslator()
158 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
159 translator.addPair(string_papersize[1], PAPER_CUSTOM);
160 translator.addPair(string_papersize[2], PAPER_USLETTER);
161 translator.addPair(string_papersize[3], PAPER_USLEGAL);
162 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
163 translator.addPair(string_papersize[5], PAPER_A3);
164 translator.addPair(string_papersize[6], PAPER_A4);
165 translator.addPair(string_papersize[7], PAPER_A5);
166 translator.addPair(string_papersize[8], PAPER_B3);
167 translator.addPair(string_papersize[9], PAPER_B4);
168 translator.addPair(string_papersize[10], PAPER_B5);
173 PaperSizeTranslator const & papersizetranslator()
175 static PaperSizeTranslator translator = init_papersizetranslator();
181 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
184 PaperOrientationTranslator const init_paperorientationtranslator()
186 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
187 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
192 PaperOrientationTranslator const & paperorientationtranslator()
194 static PaperOrientationTranslator translator = init_paperorientationtranslator();
200 typedef Translator<int, PageSides> SidesTranslator;
203 SidesTranslator const init_sidestranslator()
205 SidesTranslator translator(1, OneSide);
206 translator.addPair(2, TwoSides);
211 SidesTranslator const & sidestranslator()
213 static SidesTranslator translator = init_sidestranslator();
219 typedef Translator<int, BufferParams::Package> PackageTranslator;
222 PackageTranslator const init_packagetranslator()
224 PackageTranslator translator(0, BufferParams::package_off);
225 translator.addPair(1, BufferParams::package_auto);
226 translator.addPair(2, BufferParams::package_on);
231 PackageTranslator const & packagetranslator()
233 static PackageTranslator translator = init_packagetranslator();
239 typedef Translator<string, biblio::CiteEngine> CiteEngineTranslator;
242 CiteEngineTranslator const init_citeenginetranslator()
244 CiteEngineTranslator translator("basic", biblio::ENGINE_BASIC);
245 translator.addPair("natbib_numerical", biblio::ENGINE_NATBIB_NUMERICAL);
246 translator.addPair("natbib_authoryear", biblio::ENGINE_NATBIB_AUTHORYEAR);
247 translator.addPair("jurabib", biblio::ENGINE_JURABIB);
252 CiteEngineTranslator const & citeenginetranslator()
254 static CiteEngineTranslator translator = init_citeenginetranslator();
260 typedef Translator<string, Spacing::Space> SpaceTranslator;
263 SpaceTranslator const init_spacetranslator()
265 SpaceTranslator translator("default", Spacing::Default);
266 translator.addPair("single", Spacing::Single);
267 translator.addPair("onehalf", Spacing::Onehalf);
268 translator.addPair("double", Spacing::Double);
269 translator.addPair("other", Spacing::Other);
274 SpaceTranslator const & spacetranslator()
276 static SpaceTranslator translator = init_spacetranslator();
284 class BufferParams::Impl
289 AuthorList authorlist;
290 BranchList branchlist;
291 Bullet temp_bullets[4];
292 Bullet user_defined_bullets[4];
294 /** This is the amount of space used for paragraph_separation "skip",
295 * and for detached paragraphs in "indented" documents.
298 PDFOptions pdfoptions;
302 BufferParams::Impl::Impl()
303 : defskip(VSpace::MEDSKIP)
305 // set initial author
307 authorlist.record(Author(from_utf8(lyxrc.user_name), from_utf8(lyxrc.user_email)));
312 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
316 return new BufferParams::Impl(*ptr);
320 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
326 BufferParams::BufferParams()
329 setBaseClass(defaultTextclass());
330 paragraph_separation = PARSEP_INDENT;
331 quotes_language = InsetQuotes::EnglishQ;
332 fontsize = "default";
335 papersize = PAPER_DEFAULT;
336 orientation = ORIENTATION_PORTRAIT;
337 use_geometry = false;
338 use_amsmath = package_auto;
339 use_esint = package_auto;
340 cite_engine_ = biblio::ENGINE_BASIC;
341 use_bibtopic = false;
342 trackChanges = false;
343 outputChanges = false;
346 language = default_language;
347 fontsRoman = "default";
348 fontsSans = "default";
349 fontsTypewriter = "default";
350 fontsDefaultFamily = "default";
353 fontsSansScale = 100;
354 fontsTypewriterScale = 100;
356 graphicsDriver = "default";
359 listings_params = string();
360 pagestyle = "default";
363 for (int iter = 0; iter < 4; ++iter) {
364 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
365 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
370 BufferParams::~BufferParams()
374 docstring const BufferParams::B_(string const & l10n) const
376 BOOST_ASSERT(language);
377 return getMessages(language->code()).get(l10n);
381 AuthorList & BufferParams::authors()
383 return pimpl_->authorlist;
387 AuthorList const & BufferParams::authors() const
389 return pimpl_->authorlist;
393 BranchList & BufferParams::branchlist()
395 return pimpl_->branchlist;
399 BranchList const & BufferParams::branchlist() const
401 return pimpl_->branchlist;
405 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
407 BOOST_ASSERT(index < 4);
408 return pimpl_->temp_bullets[index];
412 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
414 BOOST_ASSERT(index < 4);
415 return pimpl_->temp_bullets[index];
419 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
421 BOOST_ASSERT(index < 4);
422 return pimpl_->user_defined_bullets[index];
426 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
428 BOOST_ASSERT(index < 4);
429 return pimpl_->user_defined_bullets[index];
433 Spacing & BufferParams::spacing()
435 return pimpl_->spacing;
439 Spacing const & BufferParams::spacing() const
441 return pimpl_->spacing;
445 PDFOptions & BufferParams::pdfoptions()
447 return pimpl_->pdfoptions;
451 PDFOptions const & BufferParams::pdfoptions() const
453 return pimpl_->pdfoptions;
457 VSpace const & BufferParams::getDefSkip() const
459 return pimpl_->defskip;
463 void BufferParams::setDefSkip(VSpace const & vs)
465 pimpl_->defskip = vs;
469 string const BufferParams::readToken(Lexer & lex, string const & token,
470 FileName const & filepath)
472 if (token == "\\textclass") {
474 string const classname = lex.getString();
475 // if there exists a local layout file, ignore the system one
476 // NOTE: in this case, the textclass (.cls file) is assumed to be available.
477 pair<bool, lyx::textclass_type> pp;
478 if (!filepath.empty())
479 pp = textclasslist.addTextClass(
480 classname, filepath.absFilename());
482 setBaseClass(pp.second);
484 pp = textclasslist.numberOfClass(classname);
486 setBaseClass(pp.second);
488 // a warning will be given for unknown class
489 setBaseClass(defaultTextclass());
493 // FIXME: this warning will be given even if there exists a local .cls
494 // file. Even worse, the .lyx file can not be compiled or exported
495 // because the textclass is marked as unavilable.
496 if (!getTextClass().isTeXClassAvailable()) {
497 docstring const msg =
498 bformat(_("The layout file requested by this document,\n"
500 "is not usable. This is probably because a LaTeX\n"
501 "class or style file required by it is not\n"
502 "available. See the Customization documentation\n"
503 "for more information.\n"), from_utf8(classname));
504 frontend::Alert::warning(_("Document class not available"),
505 msg + _("LyX will not be able to produce output."));
508 } else if (token == "\\begin_preamble") {
510 } else if (token == "\\begin_modules") {
513 } else if (token == "\\options") {
515 options = lex.getString();
516 } else if (token == "\\language") {
518 } else if (token == "\\inputencoding") {
520 } else if (token == "\\graphics") {
521 readGraphicsDriver(lex);
522 } else if (token == "\\font_roman") {
524 } else if (token == "\\font_sans") {
526 } else if (token == "\\font_typewriter") {
527 lex >> fontsTypewriter;
528 } else if (token == "\\font_default_family") {
529 lex >> fontsDefaultFamily;
530 } else if (token == "\\font_sc") {
532 } else if (token == "\\font_osf") {
534 } else if (token == "\\font_sf_scale") {
535 lex >> fontsSansScale;
536 } else if (token == "\\font_tt_scale") {
537 lex >> fontsTypewriterScale;
538 } else if (token == "\\paragraph_separation") {
541 paragraph_separation = parseptranslator().find(parsep);
542 } else if (token == "\\defskip") {
544 pimpl_->defskip = VSpace(lex.getString());
545 } else if (token == "\\quotes_language") {
548 quotes_language = quoteslangtranslator().find(quotes_lang);
549 } else if (token == "\\papersize") {
552 papersize = papersizetranslator().find(ppsize);
553 } else if (token == "\\use_geometry") {
555 } else if (token == "\\use_amsmath") {
558 use_amsmath = packagetranslator().find(use_ams);
559 } else if (token == "\\use_esint") {
562 use_esint = packagetranslator().find(useesint);
563 } else if (token == "\\cite_engine") {
566 cite_engine_ = citeenginetranslator().find(engine);
567 } else if (token == "\\use_bibtopic") {
569 } else if (token == "\\tracking_changes") {
571 } else if (token == "\\output_changes") {
572 lex >> outputChanges;
573 } else if (token == "\\branch") {
575 docstring branch = lex.getDocString();
576 branchlist().add(branch);
579 string const tok = lex.getString();
580 if (tok == "\\end_branch")
582 Branch * branch_ptr = branchlist().find(branch);
583 if (tok == "\\selected") {
586 branch_ptr->setSelected(lex.getInteger());
588 // not yet operational
589 if (tok == "\\color") {
591 string color = lex.getString();
593 branch_ptr->setColor(color);
594 // Update also the Color table:
596 color = lcolor.getX11Name(Color_background);
598 lcolor.setColor(to_utf8(branch), color);
602 } else if (token == "\\author") {
604 istringstream ss(lex.getString());
607 author_map.push_back(pimpl_->authorlist.record(a));
608 } else if (token == "\\paperorientation") {
611 orientation = paperorientationtranslator().find(orient);
612 } else if (token == "\\paperwidth") {
614 } else if (token == "\\paperheight") {
616 } else if (token == "\\leftmargin") {
618 } else if (token == "\\topmargin") {
620 } else if (token == "\\rightmargin") {
622 } else if (token == "\\bottommargin") {
624 } else if (token == "\\headheight") {
626 } else if (token == "\\headsep") {
628 } else if (token == "\\footskip") {
630 } else if (token == "\\paperfontsize") {
632 } else if (token == "\\papercolumns") {
634 } else if (token == "\\listings_params") {
637 listings_params = InsetListingsParams(par).params();
638 } else if (token == "\\papersides") {
641 sides = sidestranslator().find(psides);
642 } else if (token == "\\paperpagestyle") {
644 } else if (token == "\\bullet") {
646 } else if (token == "\\bulletLaTeX") {
647 readBulletsLaTeX(lex);
648 } else if (token == "\\secnumdepth") {
650 } else if (token == "\\tocdepth") {
652 } else if (token == "\\spacing") {
656 if (nspacing == "other") {
659 spacing().set(spacetranslator().find(nspacing), tmp_val);
660 } else if (token == "\\float_placement") {
661 lex >> float_placement;
663 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
664 string toktmp = pdfoptions().readToken(lex, token);
665 if (!toktmp.empty()) {
666 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
671 lyxerr << "BufferParams::readToken(): Unknown token: " <<
680 void BufferParams::writeFile(ostream & os) const
682 // The top of the file is written by the buffer.
683 // Prints out the buffer info into the .lyx file given by file
686 os << "\\textclass " << textclasslist[baseClass_].name() << '\n';
689 if (!preamble.empty()) {
690 // remove '\n' from the end of preamble
691 string const tmppreamble = rtrim(preamble, "\n");
692 os << "\\begin_preamble\n"
694 << "\n\\end_preamble\n";
698 if (!options.empty()) {
699 os << "\\options " << options << '\n';
703 if (!layoutModules_.empty()) {
704 os << "\\begin_modules" << '\n';
705 LayoutModuleList::const_iterator it = layoutModules_.begin();
706 for (; it != layoutModules_.end(); it++)
708 os << "\\end_modules" << '\n';
711 // then the text parameters
712 if (language != ignore_language)
713 os << "\\language " << language->lang() << '\n';
714 os << "\\inputencoding " << inputenc
715 << "\n\\font_roman " << fontsRoman
716 << "\n\\font_sans " << fontsSans
717 << "\n\\font_typewriter " << fontsTypewriter
718 << "\n\\font_default_family " << fontsDefaultFamily
719 << "\n\\font_sc " << convert<string>(fontsSC)
720 << "\n\\font_osf " << convert<string>(fontsOSF)
721 << "\n\\font_sf_scale " << fontsSansScale
722 << "\n\\font_tt_scale " << fontsTypewriterScale
723 << "\n\\graphics " << graphicsDriver << '\n';
725 if (!float_placement.empty()) {
726 os << "\\float_placement " << float_placement << '\n';
728 os << "\\paperfontsize " << fontsize << '\n';
730 spacing().writeFile(os);
731 pdfoptions().writeFile(os);
733 os << "\\papersize " << string_papersize[papersize]
734 << "\n\\use_geometry " << convert<string>(use_geometry)
735 << "\n\\use_amsmath " << use_amsmath
736 << "\n\\use_esint " << use_esint
737 << "\n\\cite_engine " << citeenginetranslator().find(cite_engine_)
738 << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
739 << "\n\\paperorientation " << string_orientation[orientation]
742 BranchList::const_iterator it = branchlist().begin();
743 BranchList::const_iterator end = branchlist().end();
744 for (; it != end; ++it) {
745 os << "\\branch " << to_utf8(it->getBranch())
746 << "\n\\selected " << it->getSelected()
747 << "\n\\color " << lyx::X11hexname(it->getColor())
752 if (!paperwidth.empty())
753 os << "\\paperwidth "
754 << VSpace(paperwidth).asLyXCommand() << '\n';
755 if (!paperheight.empty())
756 os << "\\paperheight "
757 << VSpace(paperheight).asLyXCommand() << '\n';
758 if (!leftmargin.empty())
759 os << "\\leftmargin "
760 << VSpace(leftmargin).asLyXCommand() << '\n';
761 if (!topmargin.empty())
763 << VSpace(topmargin).asLyXCommand() << '\n';
764 if (!rightmargin.empty())
765 os << "\\rightmargin "
766 << VSpace(rightmargin).asLyXCommand() << '\n';
767 if (!bottommargin.empty())
768 os << "\\bottommargin "
769 << VSpace(bottommargin).asLyXCommand() << '\n';
770 if (!headheight.empty())
771 os << "\\headheight "
772 << VSpace(headheight).asLyXCommand() << '\n';
773 if (!headsep.empty())
775 << VSpace(headsep).asLyXCommand() << '\n';
776 if (!footskip.empty())
778 << VSpace(footskip).asLyXCommand() << '\n';
779 os << "\\secnumdepth " << secnumdepth
780 << "\n\\tocdepth " << tocdepth
781 << "\n\\paragraph_separation "
782 << string_paragraph_separation[paragraph_separation]
783 << "\n\\defskip " << getDefSkip().asLyXCommand()
784 << "\n\\quotes_language "
785 << string_quotes_language[quotes_language]
786 << "\n\\papercolumns " << columns
787 << "\n\\papersides " << sides
788 << "\n\\paperpagestyle " << pagestyle << '\n';
789 if (!listings_params.empty())
790 os << "\\listings_params \"" <<
791 InsetListingsParams(listings_params).encodedString() << "\"\n";
792 for (int i = 0; i < 4; ++i) {
793 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
794 if (user_defined_bullet(i).getFont() != -1) {
795 os << "\\bullet " << i << " "
796 << user_defined_bullet(i).getFont() << " "
797 << user_defined_bullet(i).getCharacter() << " "
798 << user_defined_bullet(i).getSize() << "\n";
802 os << "\\bulletLaTeX " << i << " \""
803 << lyx::to_ascii(user_defined_bullet(i).getText())
809 os << "\\tracking_changes " << convert<string>(trackChanges) << "\n";
810 os << "\\output_changes " << convert<string>(outputChanges) << "\n";
812 AuthorList::Authors::const_iterator a_it = pimpl_->authorlist.begin();
813 AuthorList::Authors::const_iterator a_end = pimpl_->authorlist.end();
814 for (; a_it != a_end; ++a_it) {
815 if (a_it->second.used())
816 os << "\\author " << a_it->second << "\n";
818 os << "\\author " << Author() << "\n";
823 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
824 TexRow & texrow) const
826 os << "\\documentclass";
828 TextClass const & tclass = getTextClass();
830 ostringstream clsoptions; // the document class options.
832 if (tokenPos(tclass.opt_fontsize(),
833 '|', fontsize) >= 0) {
834 // only write if existing in list (and not default)
835 clsoptions << fontsize << "pt,";
838 // custom, A3, B3 and B4 paper sizes need geometry
839 bool nonstandard_papersize = papersize == PAPER_B3
840 || papersize == PAPER_B4
841 || papersize == PAPER_A3
842 || papersize == PAPER_CUSTOM;
847 clsoptions << "a4paper,";
850 clsoptions << "letterpaper,";
853 clsoptions << "a5paper,";
856 clsoptions << "b5paper,";
858 case PAPER_USEXECUTIVE:
859 clsoptions << "executivepaper,";
862 clsoptions << "legalpaper,";
874 if (sides != tclass.sides()) {
877 clsoptions << "oneside,";
880 clsoptions << "twoside,";
886 if (columns != tclass.columns()) {
888 clsoptions << "twocolumn,";
890 clsoptions << "onecolumn,";
894 && orientation == ORIENTATION_LANDSCAPE)
895 clsoptions << "landscape,";
897 // language should be a parameter to \documentclass
898 if (language->babel() == "hebrew"
899 && default_language->babel() != "hebrew")
900 // This seems necessary
901 features.useLanguage(default_language);
903 ostringstream language_options;
904 bool const use_babel = features.useBabel();
906 language_options << features.getLanguages();
907 if (!language->babel().empty()) {
908 if (!language_options.str().empty())
909 language_options << ',';
910 language_options << language->babel();
912 // when Vietnamese is used, babel must directly be loaded with the
913 // language options, not in the class options, see
914 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
915 size_t viet = language_options.str().find("vietnam");
916 // viet = string::npos when not found
917 if (lyxrc.language_global_options && !language_options.str().empty()
918 && viet == string::npos)
919 clsoptions << language_options.str() << ',';
922 // the user-defined options
923 if (!options.empty()) {
924 clsoptions << options << ',';
927 string strOptions(clsoptions.str());
928 if (!strOptions.empty()) {
929 strOptions = rtrim(strOptions, ",");
931 os << '[' << from_utf8(strOptions) << ']';
934 os << '{' << from_ascii(tclass.latexname()) << "}\n";
936 // end of \documentclass defs
938 // font selection must be done before loading fontenc.sty
940 loadFonts(fontsRoman, fontsSans,
941 fontsTypewriter, fontsSC, fontsOSF,
942 fontsSansScale, fontsTypewriterScale);
943 if (!fonts.empty()) {
944 os << from_ascii(fonts);
947 if (fontsDefaultFamily != "default")
948 os << "\\renewcommand{\\familydefault}{\\"
949 << from_ascii(fontsDefaultFamily) << "}\n";
952 // this one is not per buffer
953 // for arabic_arabi and farsi we also need to load the LAE and LFE encoding
954 if (lyxrc.fontenc != "default") {
955 if (language->lang() == "arabic_arabi" || language->lang() == "farsi") {
956 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
957 << ",LFE,LAE]{fontenc}\n";
960 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
966 // handle inputenc etc.
967 writeEncodingPreamble(os, features, texrow);
969 if (!listings_params.empty()) {
970 os << "\\usepackage{listings}\n";
973 // do not test validity because listings_params is supposed to be valid
974 string par = InsetListingsParams(listings_params).separatedParams(true);
975 os << from_ascii(par);
976 // count the number of newlines
977 for (size_t i = 0; i < par.size(); ++i)
983 if (use_geometry || nonstandard_papersize) {
984 os << "\\usepackage{geometry}\n";
986 os << "\\geometry{verbose";
987 if (orientation == ORIENTATION_LANDSCAPE)
991 if (!paperwidth.empty())
993 << from_ascii(paperwidth);
994 if (!paperheight.empty())
995 os << ",paperheight="
996 << from_ascii(paperheight);
999 os << ",letterpaper";
1002 os << ",legalpaper";
1004 case PAPER_USEXECUTIVE:
1005 os << ",executivepaper";
1026 // default papersize ie PAPER_DEFAULT
1027 switch (lyxrc.default_papersize) {
1028 case PAPER_DEFAULT: // keep compiler happy
1029 case PAPER_USLETTER:
1030 os << ",letterpaper";
1033 os << ",legalpaper";
1035 case PAPER_USEXECUTIVE:
1036 os << ",executivepaper";
1056 if (!topmargin.empty())
1057 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1058 if (!bottommargin.empty())
1059 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1060 if (!leftmargin.empty())
1061 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1062 if (!rightmargin.empty())
1063 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1064 if (!headheight.empty())
1065 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1066 if (!headsep.empty())
1067 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1068 if (!footskip.empty())
1069 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1074 if (tokenPos(tclass.opt_pagestyle(),
1075 '|', pagestyle) >= 0) {
1076 if (pagestyle == "fancy") {
1077 os << "\\usepackage{fancyhdr}\n";
1080 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1084 // Only if class has a ToC hierarchy
1085 if (tclass.hasTocLevels()) {
1086 if (secnumdepth != tclass.secnumdepth()) {
1087 os << "\\setcounter{secnumdepth}{"
1092 if (tocdepth != tclass.tocdepth()) {
1093 os << "\\setcounter{tocdepth}{"
1100 if (paragraph_separation) {
1101 switch (getDefSkip().kind()) {
1102 case VSpace::SMALLSKIP:
1103 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1105 case VSpace::MEDSKIP:
1106 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1108 case VSpace::BIGSKIP:
1109 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1111 case VSpace::LENGTH:
1112 os << "\\setlength{\\parskip}{"
1113 << from_utf8(getDefSkip().length().asLatexString())
1116 default: // should never happen // Then delete it.
1117 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1122 os << "\\setlength{\\parindent}{0pt}\n";
1126 // If we use jurabib, we have to call babel here.
1127 if (use_babel && features.isRequired("jurabib")) {
1128 os << from_ascii(babelCall(language_options.str()))
1130 << from_ascii(features.getBabelOptions());
1134 // Now insert the LyX specific LaTeX commands...
1136 // The optional packages;
1137 docstring lyxpreamble(from_ascii(features.getPackages()));
1139 // We try to load babel late, in case it interferes
1140 // with other packages. But some packages also need babel to be loaded
1141 // before, e.g. jurabib has to be called after babel.
1142 // So load babel after the optional packages but before the user-defined
1143 // preamble. This allows the users to redefine babel commands, e.g. to
1144 // translate the word "Index" to the German "Stichwortverzeichnis".
1145 // For more infos why this place was chosen, see
1146 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg128425.html
1147 // If you encounter problems, you can shift babel to its old place behind
1148 // the user-defined preamble. But in this case you must change the Vietnamese
1149 // support from currently "\usepackage[vietnamese]{babel}" to:
1150 // \usepackage{vietnamese}
1151 // \usepackage{babel}
1152 // because vietnamese must be loaded before hyperref
1153 if (use_babel && !features.isRequired("jurabib")) {
1155 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1156 lyxpreamble += from_utf8(features.getBabelOptions());
1159 // When the language "japanese-plain" is used, the package "japanese" must
1160 // be loaded behind babel (it provides babel support for Japanese) but before
1162 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1163 if (language->lang() == "japanese-plain" &&
1164 !getTextClass().provides("japanese")) {
1165 //load babel in case it was not loaded due to an empty language list
1166 if (language_options.str().empty())
1167 lyxpreamble += "\\usepackage{babel}\n";
1168 lyxpreamble += "\\usepackage{japanese}\n";
1172 // * Hyperref manual: "Make sure it comes last of your loaded
1173 // packages, to give it a fighting chance of not being over-written,
1174 // since its job is to redefine many LATEX commands."
1175 // * Email from Heiko Oberdiek: "It is usually better to load babel
1176 // before hyperref. Then hyperref has a chance to detect babel.
1177 // * Has to be loaded before the "LyX specific LaTeX commands" to
1178 // avoid errors with algorithm floats.
1179 odocstringstream oss;
1180 // use hyperref explicitely when it is required
1181 pdfoptions().writeLaTeX(oss, features.isRequired("hyperref"));
1182 lyxpreamble += oss.str();
1184 // this might be useful...
1185 lyxpreamble += "\n\\makeatletter\n";
1187 // Some macros LyX will need
1188 docstring tmppreamble(from_ascii(features.getMacros()));
1190 if (!tmppreamble.empty()) {
1191 lyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1192 "LyX specific LaTeX commands.\n"
1193 + tmppreamble + '\n';
1196 // the text class specific preamble
1197 tmppreamble = features.getTClassPreamble();
1198 if (!tmppreamble.empty()) {
1199 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1200 "Textclass specific LaTeX commands.\n"
1201 + tmppreamble + '\n';
1204 /* the user-defined preamble */
1205 if (!preamble.empty()) {
1207 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1208 "User specified LaTeX commands.\n"
1209 + from_utf8(preamble) + '\n';
1212 // Itemize bullet settings need to be last in case the user
1213 // defines their own bullets that use a package included
1214 // in the user-defined preamble -- ARRae
1215 // Actually it has to be done much later than that
1216 // since some packages like frenchb make modifications
1217 // at \begin{document} time -- JMarc
1218 docstring bullets_def;
1219 for (int i = 0; i < 4; ++i) {
1220 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1221 if (bullets_def.empty())
1222 bullets_def += "\\AtBeginDocument{\n";
1223 bullets_def += " \\def\\labelitemi";
1225 // `i' is one less than the item to modify
1232 bullets_def += "ii";
1238 bullets_def += '{' +
1239 user_defined_bullet(i).getText()
1244 if (!bullets_def.empty())
1245 lyxpreamble += bullets_def + "}\n\n";
1247 lyxpreamble += "\\makeatother\n\n";
1250 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1251 for (int j = 0; j != nlines; ++j) {
1260 void BufferParams::useClassDefaults()
1262 TextClass const & tclass = textclasslist[baseClass_];
1264 sides = tclass.sides();
1265 columns = tclass.columns();
1266 pagestyle = tclass.pagestyle();
1267 options = tclass.options();
1268 // Only if class has a ToC hierarchy
1269 if (tclass.hasTocLevels()) {
1270 secnumdepth = tclass.secnumdepth();
1271 tocdepth = tclass.tocdepth();
1276 bool BufferParams::hasClassDefaults() const
1278 TextClass const & tclass = textclasslist[baseClass_];
1280 return (sides == tclass.sides()
1281 && columns == tclass.columns()
1282 && pagestyle == tclass.pagestyle()
1283 && options == tclass.options()
1284 && secnumdepth == tclass.secnumdepth()
1285 && tocdepth == tclass.tocdepth());
1289 TextClass const & BufferParams::getTextClass() const
1295 TextClassPtr BufferParams::getTextClassPtr() const {
1300 void BufferParams::setTextClass(TextClassPtr tc) {
1305 bool BufferParams::setBaseClass(textclass_type tc)
1308 if (textclasslist[tc].load())
1312 bformat(_("The document class %1$s could not be loaded."),
1313 from_utf8(textclasslist[tc].name()));
1314 frontend::Alert::error(_("Could not load class"), s);
1322 void BufferParams::setJustBaseClass(textclass_type tc)
1328 textclass_type BufferParams::getBaseClass() const
1334 void BufferParams::makeTextClass()
1336 textClass_.reset(new TextClass(textclasslist[getBaseClass()]));
1337 //FIXME It might be worth loading the children's modules here,
1338 //just as we load their bibliographies and such, instead of just
1339 //doing a check in InsetInclude.
1340 LayoutModuleList::const_iterator it = layoutModules_.begin();
1341 for (; it != layoutModules_.end(); it++) {
1342 string const modName = *it;
1343 LyXModule * lm = moduleList[modName];
1345 docstring const msg =
1346 bformat(_("The module %1$s has been requested by\n"
1347 "this document but has not been found in the list of\n"
1348 "available modules. If you recently installed it, you\n"
1349 "probalby need to reconfigure LyX.\n"), from_utf8(modName));
1350 frontend::Alert::warning(_("Module not available"),
1351 msg + _("Some layouts may not be available."));
1352 lyxerr << "BufferParams::makeTextClass(): Module " <<
1353 modName << " requested but not found in module list." <<
1357 FileName layout_file = libFileSearch("layouts", lm->filename);
1358 textClass_->read(layout_file, TextClass::MODULE);
1363 std::vector<string> const & BufferParams::getModules() const {
1364 return layoutModules_;
1369 bool BufferParams::addLayoutModule(string modName, bool makeClass) {
1370 LayoutModuleList::const_iterator it = layoutModules_.begin();
1371 LayoutModuleList::const_iterator end = layoutModules_.end();
1372 for (; it != end; it++) {
1376 if (it != layoutModules_.end())
1378 layoutModules_.push_back(modName);
1385 bool BufferParams::addLayoutModules(std::vector<string>modNames)
1388 std::vector<string>::const_iterator it = modNames.begin();
1389 std::vector<string>::const_iterator end = modNames.end();
1390 for (; it != end; ++it)
1391 retval &= addLayoutModule(*it, false);
1397 void BufferParams::clearLayoutModules() {
1398 layoutModules_.clear();
1403 Font const BufferParams::getFont() const
1405 FontInfo f = getTextClass().defaultfont();
1406 if (fontsDefaultFamily == "rmdefault")
1407 f.setFamily(ROMAN_FAMILY);
1408 else if (fontsDefaultFamily == "sfdefault")
1409 f.setFamily(SANS_FAMILY);
1410 else if (fontsDefaultFamily == "ttdefault")
1411 f.setFamily(TYPEWRITER_FAMILY);
1412 return Font(f, language);
1416 void BufferParams::readPreamble(Lexer & lex)
1418 if (lex.getString() != "\\begin_preamble")
1419 lyxerr << "Error (BufferParams::readPreamble):"
1420 "consistency check failed." << endl;
1422 preamble = lex.getLongString("\\end_preamble");
1426 void BufferParams::readLanguage(Lexer & lex)
1428 if (!lex.next()) return;
1430 string const tmptok = lex.getString();
1432 // check if tmptok is part of tex_babel in tex-defs.h
1433 language = languages.getLanguage(tmptok);
1435 // Language tmptok was not found
1436 language = default_language;
1437 lyxerr << "Warning: Setting language `"
1438 << tmptok << "' to `" << language->lang()
1444 void BufferParams::readGraphicsDriver(Lexer & lex)
1446 if (!lex.next()) return;
1448 string const tmptok = lex.getString();
1449 // check if tmptok is part of tex_graphics in tex_defs.h
1452 string const test = tex_graphics[n++];
1454 if (test == tmptok) {
1455 graphicsDriver = tmptok;
1457 } else if (test == "") {
1459 "Warning: graphics driver `$$Token' not recognized!\n"
1460 " Setting graphics driver to `default'.\n");
1461 graphicsDriver = "default";
1468 void BufferParams::readBullets(Lexer & lex)
1470 if (!lex.next()) return;
1472 int const index = lex.getInteger();
1474 int temp_int = lex.getInteger();
1475 user_defined_bullet(index).setFont(temp_int);
1476 temp_bullet(index).setFont(temp_int);
1478 user_defined_bullet(index).setCharacter(temp_int);
1479 temp_bullet(index).setCharacter(temp_int);
1481 user_defined_bullet(index).setSize(temp_int);
1482 temp_bullet(index).setSize(temp_int);
1486 void BufferParams::readBulletsLaTeX(Lexer & lex)
1488 // The bullet class should be able to read this.
1489 if (!lex.next()) return;
1490 int const index = lex.getInteger();
1492 docstring const temp_str = lex.getDocString();
1494 user_defined_bullet(index).setText(temp_str);
1495 temp_bullet(index).setText(temp_str);
1499 void BufferParams::readModules(Lexer & lex)
1501 if (!lex.eatLine()) {
1502 lyxerr << "Error (BufferParams::readModules):"
1503 "Unexpected end of input." << endl;
1507 string mod = lex.getString();
1508 if (mod == "\\end_modules")
1510 addLayoutModule(mod);
1516 string const BufferParams::paperSizeName() const
1518 char real_papersize = papersize;
1519 if (real_papersize == PAPER_DEFAULT)
1520 real_papersize = lyxrc.default_papersize;
1522 switch (real_papersize) {
1531 case PAPER_USEXECUTIVE:
1535 case PAPER_USLETTER:
1542 string const BufferParams::dvips_options() const
1547 && papersize == PAPER_CUSTOM
1548 && !lyxrc.print_paper_dimension_flag.empty()
1549 && !paperwidth.empty()
1550 && !paperheight.empty()) {
1551 // using a custom papersize
1552 result = lyxrc.print_paper_dimension_flag;
1553 result += ' ' + paperwidth;
1554 result += ',' + paperheight;
1556 string const paper_option = paperSizeName();
1557 if (paper_option != "letter" ||
1558 orientation != ORIENTATION_LANDSCAPE) {
1559 // dvips won't accept -t letter -t landscape.
1560 // In all other cases, include the paper size
1562 result = lyxrc.print_paper_flag;
1563 result += ' ' + paper_option;
1566 if (orientation == ORIENTATION_LANDSCAPE &&
1567 papersize != PAPER_CUSTOM)
1568 result += ' ' + lyxrc.print_landscape_flag;
1573 string const BufferParams::babelCall(string const & lang_opts) const
1575 string lang_pack = lyxrc.language_package;
1576 if (lang_pack != "\\usepackage{babel}")
1578 // suppress the babel call when there is no babel language defined
1579 // for the document language in the lib/languages file and if no
1580 // other languages are used (lang_opts is then empty)
1581 if (lang_opts.empty())
1583 // when Vietnamese is used, babel must directly be loaded with the
1584 // language options, see
1585 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1586 size_t viet = lang_opts.find("vietnam");
1587 // viet = string::npos when not found
1588 if (!lyxrc.language_global_options || viet != string::npos)
1589 return "\\usepackage[" + lang_opts + "]{babel}";
1594 void BufferParams::writeEncodingPreamble(odocstream & os,
1595 LaTeXFeatures & features, TexRow & texrow) const
1597 if (inputenc == "auto") {
1598 string const doc_encoding =
1599 language->encoding()->latexName();
1600 Encoding::Package const package =
1601 language->encoding()->package();
1603 // Create a list with all the input encodings used
1605 std::set<string> encodings =
1606 features.getEncodingSet(doc_encoding);
1608 // When the encodings EUC-JP-plain, JIS-plain, or SJIS-plainare used, the
1609 // package inputenc must be omitted. Therefore set the encoding to empty.
1610 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1611 if (doc_encoding == "EUC-JP-plain" || doc_encoding == "JIS-plain" ||
1612 doc_encoding == "SJIS-plain")
1615 if (!encodings.empty() || package == Encoding::inputenc) {
1616 os << "\\usepackage[";
1617 std::set<string>::const_iterator it = encodings.begin();
1618 std::set<string>::const_iterator const end = encodings.end();
1620 os << from_ascii(*it);
1623 for (; it != end; ++it)
1624 os << ',' << from_ascii(*it);
1625 if (package == Encoding::inputenc) {
1626 if (!encodings.empty())
1628 os << from_ascii(doc_encoding);
1630 os << "]{inputenc}\n";
1633 if (package == Encoding::CJK || features.mustProvide("CJK")) {
1634 os << "\\usepackage{CJK}\n";
1637 } else if (inputenc != "default") {
1638 switch (encoding().package()) {
1639 case Encoding::none:
1641 case Encoding::inputenc:
1642 os << "\\usepackage[" << from_ascii(inputenc)
1647 os << "\\usepackage{CJK}\n";
1653 // The encoding "armscii8" is only available when the package "armtex" is loaded.
1654 // armscii8 is used for Armenian.
1655 if (language->encoding()->latexName() == "armscii8" || inputenc == "armscii8") {
1656 os << "\\usepackage{armtex}\n";
1662 string const BufferParams::loadFonts(string const & rm,
1663 string const & sf, string const & tt,
1664 bool const & sc, bool const & osf,
1665 int const & sfscale, int const & ttscale) const
1667 /* The LaTeX font world is in a flux. In the PSNFSS font interface,
1668 several packages have been replaced by others, that might not
1669 be installed on every system. We have to take care for that
1670 (see psnfss.pdf). We try to support all psnfss fonts as well
1671 as the fonts that have become de facto standard in the LaTeX
1672 world (e.g. Latin Modern). We do not support obsolete fonts
1673 (like PSLatex). In general, it should be possible to mix any
1674 rm font with any sf or tt font, respectively. (JSpitzm)
1676 -- separate math fonts.
1679 if (rm == "default" && sf == "default" && tt == "default")
1686 // Computer Modern (must be explicitely selectable -- there might be classes
1687 // that define a different default font!
1689 os << "\\renewcommand{\\rmdefault}{cmr}\n";
1690 // osf for Computer Modern needs eco.sty
1692 os << "\\usepackage{eco}\n";
1694 // Latin Modern Roman
1695 else if (rm == "lmodern")
1696 os << "\\usepackage{lmodern}\n";
1698 else if (rm == "ae") {
1699 // not needed when using OT1 font encoding.
1700 if (lyxrc.fontenc != "default")
1701 os << "\\usepackage{ae,aecompl}\n";
1704 else if (rm == "times") {
1705 // try to load the best available package
1706 if (LaTeXFeatures::isAvailable("mathptmx"))
1707 os << "\\usepackage{mathptmx}\n";
1708 else if (LaTeXFeatures::isAvailable("mathptm"))
1709 os << "\\usepackage{mathptm}\n";
1711 os << "\\usepackage{times}\n";
1714 else if (rm == "palatino") {
1715 // try to load the best available package
1716 if (LaTeXFeatures::isAvailable("mathpazo")) {
1717 os << "\\usepackage";
1723 // "osf" includes "sc"!
1727 os << "{mathpazo}\n";
1729 else if (LaTeXFeatures::isAvailable("mathpple"))
1730 os << "\\usepackage{mathpple}\n";
1732 os << "\\usepackage{palatino}\n";
1735 else if (rm == "utopia") {
1736 // fourier supersedes utopia.sty, but does
1737 // not work with OT1 encoding.
1738 if (LaTeXFeatures::isAvailable("fourier")
1739 && lyxrc.fontenc != "default") {
1740 os << "\\usepackage";
1751 os << "{fourier}\n";
1754 os << "\\usepackage{utopia}\n";
1756 // Bera (complete fontset)
1757 else if (rm == "bera" && sf == "default" && tt == "default")
1758 os << "\\usepackage{bera}\n";
1760 else if (rm != "default")
1761 os << "\\usepackage" << "{" << rm << "}\n";
1764 // Helvetica, Bera Sans
1765 if (sf == "helvet" || sf == "berasans") {
1767 os << "\\usepackage[scaled=" << float(sfscale) / 100
1768 << "]{" << sf << "}\n";
1770 os << "\\usepackage{" << sf << "}\n";
1773 else if (sf == "avant")
1774 os << "\\usepackage{" << sf << "}\n";
1775 // Computer Modern, Latin Modern, CM Bright
1776 else if (sf != "default")
1777 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
1779 // monospaced/typewriter
1780 // Courier, LuxiMono
1781 if (tt == "luximono" || tt == "beramono") {
1783 os << "\\usepackage[scaled=" << float(ttscale) / 100
1784 << "]{" << tt << "}\n";
1786 os << "\\usepackage{" << tt << "}\n";
1789 else if (tt == "courier" )
1790 os << "\\usepackage{" << tt << "}\n";
1791 // Computer Modern, Latin Modern, CM Bright
1792 else if (tt != "default")
1793 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
1799 Encoding const & BufferParams::encoding() const
1801 if (inputenc == "auto" || inputenc == "default")
1802 return *(language->encoding());
1803 Encoding const * const enc =
1804 encodings.getFromLaTeXName(inputenc);
1807 lyxerr << "Unknown inputenc value `" << inputenc
1808 << "'. Using `auto' instead." << endl;
1809 return *(language->encoding());
1813 biblio::CiteEngine BufferParams::getEngine() const
1815 // FIXME the class should provide the numerical/
1816 // authoryear choice
1817 if (getTextClass().provides("natbib")
1818 && cite_engine_ != biblio::ENGINE_NATBIB_NUMERICAL)
1819 return biblio::ENGINE_NATBIB_AUTHORYEAR;
1820 return cite_engine_;
1824 void BufferParams::setCiteEngine(biblio::CiteEngine const cite_engine)
1826 cite_engine_ = cite_engine;