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 = textclasslist.addTextClass(
478 classname, filepath.absFilename());
480 setBaseClass(pp.second);
482 pp = textclasslist.numberOfClass(classname);
484 setBaseClass(pp.second);
486 // a warning will be given for unknown class
487 setBaseClass(defaultTextclass());
491 // FIXME: this warning will be given even if there exists a local .cls
492 // file. Even worse, the .lyx file can not be compiled or exported
493 // because the textclass is marked as unavilable.
494 if (!getTextClass().isTeXClassAvailable()) {
495 docstring const msg =
496 bformat(_("The layout file requested by this document,\n"
498 "is not usable. This is probably because a LaTeX\n"
499 "class or style file required by it is not\n"
500 "available. See the Customization documentation\n"
501 "for more information.\n"), from_utf8(classname));
502 frontend::Alert::warning(_("Document class not available"),
503 msg + _("LyX will not be able to produce output."));
506 } else if (token == "\\begin_preamble") {
508 } else if (token == "\\begin_modules") {
511 } else if (token == "\\options") {
513 options = lex.getString();
514 } else if (token == "\\language") {
516 } else if (token == "\\inputencoding") {
518 } else if (token == "\\graphics") {
519 readGraphicsDriver(lex);
520 } else if (token == "\\font_roman") {
522 } else if (token == "\\font_sans") {
524 } else if (token == "\\font_typewriter") {
525 lex >> fontsTypewriter;
526 } else if (token == "\\font_default_family") {
527 lex >> fontsDefaultFamily;
528 } else if (token == "\\font_sc") {
530 } else if (token == "\\font_osf") {
532 } else if (token == "\\font_sf_scale") {
533 lex >> fontsSansScale;
534 } else if (token == "\\font_tt_scale") {
535 lex >> fontsTypewriterScale;
536 } else if (token == "\\paragraph_separation") {
539 paragraph_separation = parseptranslator().find(parsep);
540 } else if (token == "\\defskip") {
542 pimpl_->defskip = VSpace(lex.getString());
543 } else if (token == "\\quotes_language") {
546 quotes_language = quoteslangtranslator().find(quotes_lang);
547 } else if (token == "\\papersize") {
550 papersize = papersizetranslator().find(ppsize);
551 } else if (token == "\\use_geometry") {
553 } else if (token == "\\use_amsmath") {
556 use_amsmath = packagetranslator().find(use_ams);
557 } else if (token == "\\use_esint") {
560 use_esint = packagetranslator().find(useesint);
561 } else if (token == "\\cite_engine") {
564 cite_engine_ = citeenginetranslator().find(engine);
565 } else if (token == "\\use_bibtopic") {
567 } else if (token == "\\tracking_changes") {
569 } else if (token == "\\output_changes") {
570 lex >> outputChanges;
571 } else if (token == "\\branch") {
573 docstring branch = lex.getDocString();
574 branchlist().add(branch);
577 string const tok = lex.getString();
578 if (tok == "\\end_branch")
580 Branch * branch_ptr = branchlist().find(branch);
581 if (tok == "\\selected") {
584 branch_ptr->setSelected(lex.getInteger());
586 // not yet operational
587 if (tok == "\\color") {
589 string color = lex.getString();
591 branch_ptr->setColor(color);
592 // Update also the Color table:
594 color = lcolor.getX11Name(Color_background);
596 lcolor.setColor(to_utf8(branch), color);
600 } else if (token == "\\author") {
602 istringstream ss(lex.getString());
605 author_map.push_back(pimpl_->authorlist.record(a));
606 } else if (token == "\\paperorientation") {
609 orientation = paperorientationtranslator().find(orient);
610 } else if (token == "\\paperwidth") {
612 } else if (token == "\\paperheight") {
614 } else if (token == "\\leftmargin") {
616 } else if (token == "\\topmargin") {
618 } else if (token == "\\rightmargin") {
620 } else if (token == "\\bottommargin") {
622 } else if (token == "\\headheight") {
624 } else if (token == "\\headsep") {
626 } else if (token == "\\footskip") {
628 } else if (token == "\\paperfontsize") {
630 } else if (token == "\\papercolumns") {
632 } else if (token == "\\listings_params") {
635 listings_params = InsetListingsParams(par).params();
636 } else if (token == "\\papersides") {
639 sides = sidestranslator().find(psides);
640 } else if (token == "\\paperpagestyle") {
642 } else if (token == "\\bullet") {
644 } else if (token == "\\bulletLaTeX") {
645 readBulletsLaTeX(lex);
646 } else if (token == "\\secnumdepth") {
648 } else if (token == "\\tocdepth") {
650 } else if (token == "\\spacing") {
654 if (nspacing == "other") {
657 spacing().set(spacetranslator().find(nspacing), tmp_val);
658 } else if (token == "\\float_placement") {
659 lex >> float_placement;
661 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
662 string toktmp = pdfoptions().readToken(lex, token);
663 if (!toktmp.empty()) {
664 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
669 lyxerr << "BufferParams::readToken(): Unknown token: " <<
678 void BufferParams::writeFile(ostream & os) const
680 // The top of the file is written by the buffer.
681 // Prints out the buffer info into the .lyx file given by file
684 os << "\\textclass " << textclasslist[baseClass_].name() << '\n';
687 if (!preamble.empty()) {
688 // remove '\n' from the end of preamble
689 string const tmppreamble = rtrim(preamble, "\n");
690 os << "\\begin_preamble\n"
692 << "\n\\end_preamble\n";
696 if (!options.empty()) {
697 os << "\\options " << options << '\n';
701 if (!layoutModules_.empty()) {
702 os << "\\begin_modules" << '\n';
703 LayoutModuleList::const_iterator it = layoutModules_.begin();
704 for (; it != layoutModules_.end(); it++)
706 os << "\\end_modules" << '\n';
709 // then the text parameters
710 if (language != ignore_language)
711 os << "\\language " << language->lang() << '\n';
712 os << "\\inputencoding " << inputenc
713 << "\n\\font_roman " << fontsRoman
714 << "\n\\font_sans " << fontsSans
715 << "\n\\font_typewriter " << fontsTypewriter
716 << "\n\\font_default_family " << fontsDefaultFamily
717 << "\n\\font_sc " << convert<string>(fontsSC)
718 << "\n\\font_osf " << convert<string>(fontsOSF)
719 << "\n\\font_sf_scale " << fontsSansScale
720 << "\n\\font_tt_scale " << fontsTypewriterScale
721 << "\n\\graphics " << graphicsDriver << '\n';
723 if (!float_placement.empty()) {
724 os << "\\float_placement " << float_placement << '\n';
726 os << "\\paperfontsize " << fontsize << '\n';
728 spacing().writeFile(os);
729 pdfoptions().writeFile(os);
731 os << "\\papersize " << string_papersize[papersize]
732 << "\n\\use_geometry " << convert<string>(use_geometry)
733 << "\n\\use_amsmath " << use_amsmath
734 << "\n\\use_esint " << use_esint
735 << "\n\\cite_engine " << citeenginetranslator().find(cite_engine_)
736 << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
737 << "\n\\paperorientation " << string_orientation[orientation]
740 BranchList::const_iterator it = branchlist().begin();
741 BranchList::const_iterator end = branchlist().end();
742 for (; it != end; ++it) {
743 os << "\\branch " << to_utf8(it->getBranch())
744 << "\n\\selected " << it->getSelected()
745 << "\n\\color " << lyx::X11hexname(it->getColor())
750 if (!paperwidth.empty())
751 os << "\\paperwidth "
752 << VSpace(paperwidth).asLyXCommand() << '\n';
753 if (!paperheight.empty())
754 os << "\\paperheight "
755 << VSpace(paperheight).asLyXCommand() << '\n';
756 if (!leftmargin.empty())
757 os << "\\leftmargin "
758 << VSpace(leftmargin).asLyXCommand() << '\n';
759 if (!topmargin.empty())
761 << VSpace(topmargin).asLyXCommand() << '\n';
762 if (!rightmargin.empty())
763 os << "\\rightmargin "
764 << VSpace(rightmargin).asLyXCommand() << '\n';
765 if (!bottommargin.empty())
766 os << "\\bottommargin "
767 << VSpace(bottommargin).asLyXCommand() << '\n';
768 if (!headheight.empty())
769 os << "\\headheight "
770 << VSpace(headheight).asLyXCommand() << '\n';
771 if (!headsep.empty())
773 << VSpace(headsep).asLyXCommand() << '\n';
774 if (!footskip.empty())
776 << VSpace(footskip).asLyXCommand() << '\n';
777 os << "\\secnumdepth " << secnumdepth
778 << "\n\\tocdepth " << tocdepth
779 << "\n\\paragraph_separation "
780 << string_paragraph_separation[paragraph_separation]
781 << "\n\\defskip " << getDefSkip().asLyXCommand()
782 << "\n\\quotes_language "
783 << string_quotes_language[quotes_language]
784 << "\n\\papercolumns " << columns
785 << "\n\\papersides " << sides
786 << "\n\\paperpagestyle " << pagestyle << '\n';
787 if (!listings_params.empty())
788 os << "\\listings_params \"" <<
789 InsetListingsParams(listings_params).encodedString() << "\"\n";
790 for (int i = 0; i < 4; ++i) {
791 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
792 if (user_defined_bullet(i).getFont() != -1) {
793 os << "\\bullet " << i << " "
794 << user_defined_bullet(i).getFont() << " "
795 << user_defined_bullet(i).getCharacter() << " "
796 << user_defined_bullet(i).getSize() << "\n";
800 os << "\\bulletLaTeX " << i << " \""
801 << lyx::to_ascii(user_defined_bullet(i).getText())
807 os << "\\tracking_changes " << convert<string>(trackChanges) << "\n";
808 os << "\\output_changes " << convert<string>(outputChanges) << "\n";
810 AuthorList::Authors::const_iterator a_it = pimpl_->authorlist.begin();
811 AuthorList::Authors::const_iterator a_end = pimpl_->authorlist.end();
812 for (; a_it != a_end; ++a_it) {
813 if (a_it->second.used())
814 os << "\\author " << a_it->second << "\n";
816 os << "\\author " << Author() << "\n";
821 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
822 TexRow & texrow) const
824 os << "\\documentclass";
826 TextClass const & tclass = getTextClass();
828 ostringstream clsoptions; // the document class options.
830 if (tokenPos(tclass.opt_fontsize(),
831 '|', fontsize) >= 0) {
832 // only write if existing in list (and not default)
833 clsoptions << fontsize << "pt,";
836 // custom, A3, B3 and B4 paper sizes need geometry
837 bool nonstandard_papersize = papersize == PAPER_B3
838 || papersize == PAPER_B4
839 || papersize == PAPER_A3
840 || papersize == PAPER_CUSTOM;
845 clsoptions << "a4paper,";
848 clsoptions << "letterpaper,";
851 clsoptions << "a5paper,";
854 clsoptions << "b5paper,";
856 case PAPER_USEXECUTIVE:
857 clsoptions << "executivepaper,";
860 clsoptions << "legalpaper,";
872 if (sides != tclass.sides()) {
875 clsoptions << "oneside,";
878 clsoptions << "twoside,";
884 if (columns != tclass.columns()) {
886 clsoptions << "twocolumn,";
888 clsoptions << "onecolumn,";
892 && orientation == ORIENTATION_LANDSCAPE)
893 clsoptions << "landscape,";
895 // language should be a parameter to \documentclass
896 if (language->babel() == "hebrew"
897 && default_language->babel() != "hebrew")
898 // This seems necessary
899 features.useLanguage(default_language);
901 ostringstream language_options;
902 bool const use_babel = features.useBabel();
904 language_options << features.getLanguages();
905 if (!language->babel().empty()) {
906 if (!language_options.str().empty())
907 language_options << ',';
908 language_options << language->babel();
910 // when Vietnamese is used, babel must directly be loaded with the
911 // language options, not in the class options, see
912 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
913 size_t viet = language_options.str().find("vietnam");
914 // viet = string::npos when not found
915 if (lyxrc.language_global_options && !language_options.str().empty()
916 && viet == string::npos)
917 clsoptions << language_options.str() << ',';
920 // the user-defined options
921 if (!options.empty()) {
922 clsoptions << options << ',';
925 string strOptions(clsoptions.str());
926 if (!strOptions.empty()) {
927 strOptions = rtrim(strOptions, ",");
929 os << '[' << from_utf8(strOptions) << ']';
932 os << '{' << from_ascii(tclass.latexname()) << "}\n";
934 // end of \documentclass defs
936 // font selection must be done before loading fontenc.sty
938 loadFonts(fontsRoman, fontsSans,
939 fontsTypewriter, fontsSC, fontsOSF,
940 fontsSansScale, fontsTypewriterScale);
941 if (!fonts.empty()) {
942 os << from_ascii(fonts);
945 if (fontsDefaultFamily != "default")
946 os << "\\renewcommand{\\familydefault}{\\"
947 << from_ascii(fontsDefaultFamily) << "}\n";
950 // this one is not per buffer
951 // for arabic_arabi and farsi we also need to load the LAE and LFE encoding
952 if (lyxrc.fontenc != "default") {
953 if (language->lang() == "arabic_arabi" || language->lang() == "farsi") {
954 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
955 << ",LFE,LAE]{fontenc}\n";
958 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
964 // handle inputenc etc.
965 writeEncodingPreamble(os, features, texrow);
967 if (!listings_params.empty()) {
968 os << "\\usepackage{listings}\n";
971 // do not test validity because listings_params is supposed to be valid
972 string par = InsetListingsParams(listings_params).separatedParams(true);
973 os << from_ascii(par);
974 // count the number of newlines
975 for (size_t i = 0; i < par.size(); ++i)
981 if (use_geometry || nonstandard_papersize) {
982 os << "\\usepackage{geometry}\n";
984 os << "\\geometry{verbose";
985 if (orientation == ORIENTATION_LANDSCAPE)
989 if (!paperwidth.empty())
991 << from_ascii(paperwidth);
992 if (!paperheight.empty())
993 os << ",paperheight="
994 << from_ascii(paperheight);
997 os << ",letterpaper";
1000 os << ",legalpaper";
1002 case PAPER_USEXECUTIVE:
1003 os << ",executivepaper";
1024 // default papersize ie PAPER_DEFAULT
1025 switch (lyxrc.default_papersize) {
1026 case PAPER_DEFAULT: // keep compiler happy
1027 case PAPER_USLETTER:
1028 os << ",letterpaper";
1031 os << ",legalpaper";
1033 case PAPER_USEXECUTIVE:
1034 os << ",executivepaper";
1054 if (!topmargin.empty())
1055 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1056 if (!bottommargin.empty())
1057 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1058 if (!leftmargin.empty())
1059 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1060 if (!rightmargin.empty())
1061 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1062 if (!headheight.empty())
1063 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1064 if (!headsep.empty())
1065 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1066 if (!footskip.empty())
1067 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1072 if (tokenPos(tclass.opt_pagestyle(),
1073 '|', pagestyle) >= 0) {
1074 if (pagestyle == "fancy") {
1075 os << "\\usepackage{fancyhdr}\n";
1078 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1082 // Only if class has a ToC hierarchy
1083 if (tclass.hasTocLevels()) {
1084 if (secnumdepth != tclass.secnumdepth()) {
1085 os << "\\setcounter{secnumdepth}{"
1090 if (tocdepth != tclass.tocdepth()) {
1091 os << "\\setcounter{tocdepth}{"
1098 if (paragraph_separation) {
1099 switch (getDefSkip().kind()) {
1100 case VSpace::SMALLSKIP:
1101 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1103 case VSpace::MEDSKIP:
1104 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1106 case VSpace::BIGSKIP:
1107 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1109 case VSpace::LENGTH:
1110 os << "\\setlength{\\parskip}{"
1111 << from_utf8(getDefSkip().length().asLatexString())
1114 default: // should never happen // Then delete it.
1115 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1120 os << "\\setlength{\\parindent}{0pt}\n";
1124 // If we use jurabib, we have to call babel here.
1125 if (use_babel && features.isRequired("jurabib")) {
1126 os << from_ascii(babelCall(language_options.str()))
1128 << from_ascii(features.getBabelOptions());
1132 // Now insert the LyX specific LaTeX commands...
1134 // The optional packages;
1135 docstring lyxpreamble(from_ascii(features.getPackages()));
1137 // We try to load babel late, in case it interferes
1138 // with other packages. But some packages also need babel to be loaded
1139 // before, e.g. jurabib has to be called after babel.
1140 // So load babel after the optional packages but before the user-defined
1141 // preamble. This allows the users to redefine babel commands, e.g. to
1142 // translate the word "Index" to the German "Stichwortverzeichnis".
1143 // For more infos why this place was chosen, see
1144 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg128425.html
1145 // If you encounter problems, you can shift babel to its old place behind
1146 // the user-defined preamble. But in this case you must change the Vietnamese
1147 // support from currently "\usepackage[vietnamese]{babel}" to:
1148 // \usepackage{vietnamese}
1149 // \usepackage{babel}
1150 // because vietnamese must be loaded before hyperref
1151 if (use_babel && !features.isRequired("jurabib")) {
1153 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1154 lyxpreamble += from_utf8(features.getBabelOptions());
1157 // When the language "japanese-plain" is used, the package "japanese" must
1158 // be loaded behind babel (it provides babel support for Japanese) but before
1160 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1161 if (language->lang() == "japanese-plain" &&
1162 !getTextClass().provides("japanese")) {
1163 //load babel in case it was not loaded due to an empty language list
1164 if (language_options.str().empty())
1165 lyxpreamble += "\\usepackage{babel}\n";
1166 lyxpreamble += "\\usepackage{japanese}\n";
1170 // * Hyperref manual: "Make sure it comes last of your loaded
1171 // packages, to give it a fighting chance of not being over-written,
1172 // since its job is to redefine many LATEX commands."
1173 // * Email from Heiko Oberdiek: "It is usually better to load babel
1174 // before hyperref. Then hyperref has a chance to detect babel.
1175 // * Has to be loaded before the "LyX specific LaTeX commands" to
1176 // avoid errors with algorithm floats.
1177 odocstringstream oss;
1178 // use hyperref explicitely when it is required
1179 pdfoptions().writeLaTeX(oss, features.isRequired("hyperref"));
1180 lyxpreamble += oss.str();
1182 // this might be useful...
1183 lyxpreamble += "\n\\makeatletter\n";
1185 // Some macros LyX will need
1186 docstring tmppreamble(from_ascii(features.getMacros()));
1188 if (!tmppreamble.empty()) {
1189 lyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1190 "LyX specific LaTeX commands.\n"
1191 + tmppreamble + '\n';
1194 // the text class specific preamble
1195 tmppreamble = features.getTClassPreamble();
1196 if (!tmppreamble.empty()) {
1197 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1198 "Textclass specific LaTeX commands.\n"
1199 + tmppreamble + '\n';
1202 /* the user-defined preamble */
1203 if (!preamble.empty()) {
1205 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1206 "User specified LaTeX commands.\n"
1207 + from_utf8(preamble) + '\n';
1210 // Itemize bullet settings need to be last in case the user
1211 // defines their own bullets that use a package included
1212 // in the user-defined preamble -- ARRae
1213 // Actually it has to be done much later than that
1214 // since some packages like frenchb make modifications
1215 // at \begin{document} time -- JMarc
1216 docstring bullets_def;
1217 for (int i = 0; i < 4; ++i) {
1218 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1219 if (bullets_def.empty())
1220 bullets_def += "\\AtBeginDocument{\n";
1221 bullets_def += " \\def\\labelitemi";
1223 // `i' is one less than the item to modify
1230 bullets_def += "ii";
1236 bullets_def += '{' +
1237 user_defined_bullet(i).getText()
1242 if (!bullets_def.empty())
1243 lyxpreamble += bullets_def + "}\n\n";
1245 lyxpreamble += "\\makeatother\n\n";
1248 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1249 for (int j = 0; j != nlines; ++j) {
1258 void BufferParams::useClassDefaults()
1260 TextClass const & tclass = textclasslist[baseClass_];
1262 sides = tclass.sides();
1263 columns = tclass.columns();
1264 pagestyle = tclass.pagestyle();
1265 options = tclass.options();
1266 // Only if class has a ToC hierarchy
1267 if (tclass.hasTocLevels()) {
1268 secnumdepth = tclass.secnumdepth();
1269 tocdepth = tclass.tocdepth();
1274 bool BufferParams::hasClassDefaults() const
1276 TextClass const & tclass = textclasslist[baseClass_];
1278 return (sides == tclass.sides()
1279 && columns == tclass.columns()
1280 && pagestyle == tclass.pagestyle()
1281 && options == tclass.options()
1282 && secnumdepth == tclass.secnumdepth()
1283 && tocdepth == tclass.tocdepth());
1287 TextClass const & BufferParams::getTextClass() const
1293 TextClassPtr BufferParams::getTextClassPtr() const {
1298 void BufferParams::setTextClass(TextClassPtr tc) {
1303 bool BufferParams::setBaseClass(textclass_type tc)
1306 if (textclasslist[tc].load())
1310 bformat(_("The document class %1$s could not be loaded."),
1311 from_utf8(textclasslist[tc].name()));
1312 frontend::Alert::error(_("Could not load class"), s);
1320 void BufferParams::setJustBaseClass(textclass_type tc)
1326 textclass_type BufferParams::getBaseClass() const
1332 void BufferParams::makeTextClass()
1334 textClass_.reset(new TextClass(textclasslist[getBaseClass()]));
1335 //FIXME It might be worth loading the children's modules here,
1336 //just as we load their bibliographies and such, instead of just
1337 //doing a check in InsetInclude.
1338 LayoutModuleList::const_iterator it = layoutModules_.begin();
1339 for (; it != layoutModules_.end(); it++) {
1340 string const modName = *it;
1341 LyXModule * lm = moduleList[modName];
1343 docstring const msg =
1344 bformat(_("The module %1$s has been requested by\n"
1345 "this document but has not been found in the list of\n"
1346 "available modules. If you recently installed it, you\n"
1347 "probalby need to reconfigure LyX.\n"), from_utf8(modName));
1348 frontend::Alert::warning(_("Module not available"),
1349 msg + _("Some layouts may not be available."));
1350 lyxerr << "BufferParams::makeTextClass(): Module " <<
1351 modName << " requested but not found in module list." <<
1355 FileName layout_file = libFileSearch("layouts", lm->filename);
1356 textClass_->read(layout_file, TextClass::MODULE);
1361 std::vector<string> const & BufferParams::getModules() const {
1362 return layoutModules_;
1367 bool BufferParams::addLayoutModule(string modName, bool makeClass) {
1368 LayoutModuleList::const_iterator it = layoutModules_.begin();
1369 LayoutModuleList::const_iterator end = layoutModules_.end();
1370 for (; it != end; it++) {
1374 if (it != layoutModules_.end())
1376 layoutModules_.push_back(modName);
1383 bool BufferParams::addLayoutModules(std::vector<string>modNames)
1386 std::vector<string>::const_iterator it = modNames.begin();
1387 std::vector<string>::const_iterator end = modNames.end();
1388 for (; it != end; ++it)
1389 retval &= addLayoutModule(*it, false);
1395 void BufferParams::clearLayoutModules() {
1396 layoutModules_.clear();
1401 Font const BufferParams::getFont() const
1403 FontInfo f = getTextClass().defaultfont();
1404 if (fontsDefaultFamily == "rmdefault")
1405 f.setFamily(ROMAN_FAMILY);
1406 else if (fontsDefaultFamily == "sfdefault")
1407 f.setFamily(SANS_FAMILY);
1408 else if (fontsDefaultFamily == "ttdefault")
1409 f.setFamily(TYPEWRITER_FAMILY);
1410 return Font(f, language);
1414 void BufferParams::readPreamble(Lexer & lex)
1416 if (lex.getString() != "\\begin_preamble")
1417 lyxerr << "Error (BufferParams::readPreamble):"
1418 "consistency check failed." << endl;
1420 preamble = lex.getLongString("\\end_preamble");
1424 void BufferParams::readLanguage(Lexer & lex)
1426 if (!lex.next()) return;
1428 string const tmptok = lex.getString();
1430 // check if tmptok is part of tex_babel in tex-defs.h
1431 language = languages.getLanguage(tmptok);
1433 // Language tmptok was not found
1434 language = default_language;
1435 lyxerr << "Warning: Setting language `"
1436 << tmptok << "' to `" << language->lang()
1442 void BufferParams::readGraphicsDriver(Lexer & lex)
1444 if (!lex.next()) return;
1446 string const tmptok = lex.getString();
1447 // check if tmptok is part of tex_graphics in tex_defs.h
1450 string const test = tex_graphics[n++];
1452 if (test == tmptok) {
1453 graphicsDriver = tmptok;
1455 } else if (test == "") {
1457 "Warning: graphics driver `$$Token' not recognized!\n"
1458 " Setting graphics driver to `default'.\n");
1459 graphicsDriver = "default";
1466 void BufferParams::readBullets(Lexer & lex)
1468 if (!lex.next()) return;
1470 int const index = lex.getInteger();
1472 int temp_int = lex.getInteger();
1473 user_defined_bullet(index).setFont(temp_int);
1474 temp_bullet(index).setFont(temp_int);
1476 user_defined_bullet(index).setCharacter(temp_int);
1477 temp_bullet(index).setCharacter(temp_int);
1479 user_defined_bullet(index).setSize(temp_int);
1480 temp_bullet(index).setSize(temp_int);
1484 void BufferParams::readBulletsLaTeX(Lexer & lex)
1486 // The bullet class should be able to read this.
1487 if (!lex.next()) return;
1488 int const index = lex.getInteger();
1490 docstring const temp_str = lex.getDocString();
1492 user_defined_bullet(index).setText(temp_str);
1493 temp_bullet(index).setText(temp_str);
1497 void BufferParams::readModules(Lexer & lex)
1499 if (!lex.eatLine()) {
1500 lyxerr << "Error (BufferParams::readModules):"
1501 "Unexpected end of input." << endl;
1505 string mod = lex.getString();
1506 if (mod == "\\end_modules")
1508 addLayoutModule(mod);
1514 string const BufferParams::paperSizeName() const
1516 char real_papersize = papersize;
1517 if (real_papersize == PAPER_DEFAULT)
1518 real_papersize = lyxrc.default_papersize;
1520 switch (real_papersize) {
1529 case PAPER_USEXECUTIVE:
1533 case PAPER_USLETTER:
1540 string const BufferParams::dvips_options() const
1545 && papersize == PAPER_CUSTOM
1546 && !lyxrc.print_paper_dimension_flag.empty()
1547 && !paperwidth.empty()
1548 && !paperheight.empty()) {
1549 // using a custom papersize
1550 result = lyxrc.print_paper_dimension_flag;
1551 result += ' ' + paperwidth;
1552 result += ',' + paperheight;
1554 string const paper_option = paperSizeName();
1555 if (paper_option != "letter" ||
1556 orientation != ORIENTATION_LANDSCAPE) {
1557 // dvips won't accept -t letter -t landscape.
1558 // In all other cases, include the paper size
1560 result = lyxrc.print_paper_flag;
1561 result += ' ' + paper_option;
1564 if (orientation == ORIENTATION_LANDSCAPE &&
1565 papersize != PAPER_CUSTOM)
1566 result += ' ' + lyxrc.print_landscape_flag;
1571 string const BufferParams::babelCall(string const & lang_opts) const
1573 string lang_pack = lyxrc.language_package;
1574 if (lang_pack != "\\usepackage{babel}")
1576 // suppress the babel call when there is no babel language defined
1577 // for the document language in the lib/languages file and if no
1578 // other languages are used (lang_opts is then empty)
1579 if (lang_opts.empty())
1581 // when Vietnamese is used, babel must directly be loaded with the
1582 // language options, see
1583 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1584 size_t viet = lang_opts.find("vietnam");
1585 // viet = string::npos when not found
1586 if (!lyxrc.language_global_options || viet != string::npos)
1587 return "\\usepackage[" + lang_opts + "]{babel}";
1592 void BufferParams::writeEncodingPreamble(odocstream & os,
1593 LaTeXFeatures & features, TexRow & texrow) const
1595 if (inputenc == "auto") {
1596 string const doc_encoding =
1597 language->encoding()->latexName();
1598 Encoding::Package const package =
1599 language->encoding()->package();
1601 // Create a list with all the input encodings used
1603 std::set<string> encodings =
1604 features.getEncodingSet(doc_encoding);
1606 // When the encodings EUC-JP-plain, JIS-plain, or SJIS-plainare used, the
1607 // package inputenc must be omitted. Therefore set the encoding to empty.
1608 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1609 if (doc_encoding == "EUC-JP-plain" || doc_encoding == "JIS-plain" ||
1610 doc_encoding == "SJIS-plain")
1613 if (!encodings.empty() || package == Encoding::inputenc) {
1614 os << "\\usepackage[";
1615 std::set<string>::const_iterator it = encodings.begin();
1616 std::set<string>::const_iterator const end = encodings.end();
1618 os << from_ascii(*it);
1621 for (; it != end; ++it)
1622 os << ',' << from_ascii(*it);
1623 if (package == Encoding::inputenc) {
1624 if (!encodings.empty())
1626 os << from_ascii(doc_encoding);
1628 os << "]{inputenc}\n";
1631 if (package == Encoding::CJK || features.mustProvide("CJK")) {
1632 os << "\\usepackage{CJK}\n";
1635 } else if (inputenc != "default") {
1636 switch (encoding().package()) {
1637 case Encoding::none:
1639 case Encoding::inputenc:
1640 os << "\\usepackage[" << from_ascii(inputenc)
1645 os << "\\usepackage{CJK}\n";
1651 // The encoding "armscii8" is only available when the package "armtex" is loaded.
1652 // armscii8 is used for Armenian.
1653 if (language->encoding()->latexName() == "armscii8" || inputenc == "armscii8") {
1654 os << "\\usepackage{armtex}\n";
1660 string const BufferParams::loadFonts(string const & rm,
1661 string const & sf, string const & tt,
1662 bool const & sc, bool const & osf,
1663 int const & sfscale, int const & ttscale) const
1665 /* The LaTeX font world is in a flux. In the PSNFSS font interface,
1666 several packages have been replaced by others, that might not
1667 be installed on every system. We have to take care for that
1668 (see psnfss.pdf). We try to support all psnfss fonts as well
1669 as the fonts that have become de facto standard in the LaTeX
1670 world (e.g. Latin Modern). We do not support obsolete fonts
1671 (like PSLatex). In general, it should be possible to mix any
1672 rm font with any sf or tt font, respectively. (JSpitzm)
1674 -- separate math fonts.
1677 if (rm == "default" && sf == "default" && tt == "default")
1684 // Computer Modern (must be explicitely selectable -- there might be classes
1685 // that define a different default font!
1687 os << "\\renewcommand{\\rmdefault}{cmr}\n";
1688 // osf for Computer Modern needs eco.sty
1690 os << "\\usepackage{eco}\n";
1692 // Latin Modern Roman
1693 else if (rm == "lmodern")
1694 os << "\\usepackage{lmodern}\n";
1696 else if (rm == "ae") {
1697 // not needed when using OT1 font encoding.
1698 if (lyxrc.fontenc != "default")
1699 os << "\\usepackage{ae,aecompl}\n";
1702 else if (rm == "times") {
1703 // try to load the best available package
1704 if (LaTeXFeatures::isAvailable("mathptmx"))
1705 os << "\\usepackage{mathptmx}\n";
1706 else if (LaTeXFeatures::isAvailable("mathptm"))
1707 os << "\\usepackage{mathptm}\n";
1709 os << "\\usepackage{times}\n";
1712 else if (rm == "palatino") {
1713 // try to load the best available package
1714 if (LaTeXFeatures::isAvailable("mathpazo")) {
1715 os << "\\usepackage";
1721 // "osf" includes "sc"!
1725 os << "{mathpazo}\n";
1727 else if (LaTeXFeatures::isAvailable("mathpple"))
1728 os << "\\usepackage{mathpple}\n";
1730 os << "\\usepackage{palatino}\n";
1733 else if (rm == "utopia") {
1734 // fourier supersedes utopia.sty, but does
1735 // not work with OT1 encoding.
1736 if (LaTeXFeatures::isAvailable("fourier")
1737 && lyxrc.fontenc != "default") {
1738 os << "\\usepackage";
1749 os << "{fourier}\n";
1752 os << "\\usepackage{utopia}\n";
1754 // Bera (complete fontset)
1755 else if (rm == "bera" && sf == "default" && tt == "default")
1756 os << "\\usepackage{bera}\n";
1758 else if (rm != "default")
1759 os << "\\usepackage" << "{" << rm << "}\n";
1762 // Helvetica, Bera Sans
1763 if (sf == "helvet" || sf == "berasans") {
1765 os << "\\usepackage[scaled=" << float(sfscale) / 100
1766 << "]{" << sf << "}\n";
1768 os << "\\usepackage{" << sf << "}\n";
1771 else if (sf == "avant")
1772 os << "\\usepackage{" << sf << "}\n";
1773 // Computer Modern, Latin Modern, CM Bright
1774 else if (sf != "default")
1775 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
1777 // monospaced/typewriter
1778 // Courier, LuxiMono
1779 if (tt == "luximono" || tt == "beramono") {
1781 os << "\\usepackage[scaled=" << float(ttscale) / 100
1782 << "]{" << tt << "}\n";
1784 os << "\\usepackage{" << tt << "}\n";
1787 else if (tt == "courier" )
1788 os << "\\usepackage{" << tt << "}\n";
1789 // Computer Modern, Latin Modern, CM Bright
1790 else if (tt != "default")
1791 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
1797 Encoding const & BufferParams::encoding() const
1799 if (inputenc == "auto" || inputenc == "default")
1800 return *(language->encoding());
1801 Encoding const * const enc =
1802 encodings.getFromLaTeXName(inputenc);
1805 lyxerr << "Unknown inputenc value `" << inputenc
1806 << "'. Using `auto' instead." << endl;
1807 return *(language->encoding());
1811 biblio::CiteEngine BufferParams::getEngine() const
1813 // FIXME the class should provide the numerical/
1814 // authoryear choice
1815 if (getTextClass().provides("natbib")
1816 && cite_engine_ != biblio::ENGINE_NATBIB_NUMERICAL)
1817 return biblio::ENGINE_NATBIB_AUTHORYEAR;
1818 return cite_engine_;
1822 void BufferParams::setCiteEngine(biblio::CiteEngine const cite_engine)
1824 cite_engine_ = cite_engine;