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"
58 using lyx::support::FileName;
59 using lyx::support::libFileSearch;
60 using lyx::support::bformat;
61 using lyx::support::rtrim;
62 using lyx::support::tokenPos;
63 using lyx::support::prefixIs;
66 static char const * const string_paragraph_separation[] = {
71 static char const * const string_quotes_language[] = {
72 "english", "swedish", "german", "polish", "french", "danish", ""
76 static char const * const string_papersize[] = {
77 "default", "custom", "letterpaper", "executivepaper", "legalpaper",
78 "a3paper", "a4paper", "a5paper", "b3paper", "b4paper", "b5paper", ""
82 static char const * const string_orientation[] = {
83 "portrait", "landscape", ""
87 static char const * const string_footnotekinds[] = {
88 "footnote", "margin", "fig", "tab", "alg", "wide-fig", "wide-tab", ""
92 static char const * const tex_graphics[] = {
93 "default", "dvips", "dvitops", "emtex",
94 "ln", "oztex", "textures", "none", ""
103 // Paragraph separation
104 typedef Translator<string, BufferParams::PARSEP> ParSepTranslator;
107 ParSepTranslator const init_parseptranslator()
109 ParSepTranslator translator(string_paragraph_separation[0], BufferParams::PARSEP_INDENT);
110 translator.addPair(string_paragraph_separation[1], BufferParams::PARSEP_SKIP);
115 ParSepTranslator const & parseptranslator()
117 static ParSepTranslator translator = init_parseptranslator();
123 typedef Translator<string, InsetQuotes::quote_language> QuotesLangTranslator;
126 QuotesLangTranslator const init_quoteslangtranslator()
128 QuotesLangTranslator translator(string_quotes_language[0], InsetQuotes::EnglishQ);
129 translator.addPair(string_quotes_language[1], InsetQuotes::SwedishQ);
130 translator.addPair(string_quotes_language[2], InsetQuotes::GermanQ);
131 translator.addPair(string_quotes_language[3], InsetQuotes::PolishQ);
132 translator.addPair(string_quotes_language[4], InsetQuotes::FrenchQ);
133 translator.addPair(string_quotes_language[5], InsetQuotes::DanishQ);
138 QuotesLangTranslator const & quoteslangtranslator()
140 static QuotesLangTranslator translator = init_quoteslangtranslator();
146 typedef Translator<std::string, PAPER_SIZE> PaperSizeTranslator;
149 PaperSizeTranslator const init_papersizetranslator()
151 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
152 translator.addPair(string_papersize[1], PAPER_CUSTOM);
153 translator.addPair(string_papersize[2], PAPER_USLETTER);
154 translator.addPair(string_papersize[3], PAPER_USLEGAL);
155 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
156 translator.addPair(string_papersize[5], PAPER_A3);
157 translator.addPair(string_papersize[6], PAPER_A4);
158 translator.addPair(string_papersize[7], PAPER_A5);
159 translator.addPair(string_papersize[8], PAPER_B3);
160 translator.addPair(string_papersize[9], PAPER_B4);
161 translator.addPair(string_papersize[10], PAPER_B5);
166 PaperSizeTranslator const & papersizetranslator()
168 static PaperSizeTranslator translator = init_papersizetranslator();
174 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
177 PaperOrientationTranslator const init_paperorientationtranslator()
179 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
180 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
185 PaperOrientationTranslator const & paperorientationtranslator()
187 static PaperOrientationTranslator translator = init_paperorientationtranslator();
193 typedef Translator<int, PageSides> SidesTranslator;
196 SidesTranslator const init_sidestranslator()
198 SidesTranslator translator(1, OneSide);
199 translator.addPair(2, TwoSides);
204 SidesTranslator const & sidestranslator()
206 static SidesTranslator translator = init_sidestranslator();
212 typedef Translator<int, BufferParams::Package> PackageTranslator;
215 PackageTranslator const init_packagetranslator()
217 PackageTranslator translator(0, BufferParams::package_off);
218 translator.addPair(1, BufferParams::package_auto);
219 translator.addPair(2, BufferParams::package_on);
224 PackageTranslator const & packagetranslator()
226 static PackageTranslator translator = init_packagetranslator();
232 typedef Translator<string, biblio::CiteEngine> CiteEngineTranslator;
235 CiteEngineTranslator const init_citeenginetranslator()
237 CiteEngineTranslator translator("basic", biblio::ENGINE_BASIC);
238 translator.addPair("natbib_numerical", biblio::ENGINE_NATBIB_NUMERICAL);
239 translator.addPair("natbib_authoryear", biblio::ENGINE_NATBIB_AUTHORYEAR);
240 translator.addPair("jurabib", biblio::ENGINE_JURABIB);
245 CiteEngineTranslator const & citeenginetranslator()
247 static CiteEngineTranslator translator = init_citeenginetranslator();
253 typedef Translator<string, Spacing::Space> SpaceTranslator;
256 SpaceTranslator const init_spacetranslator()
258 SpaceTranslator translator("default", Spacing::Default);
259 translator.addPair("single", Spacing::Single);
260 translator.addPair("onehalf", Spacing::Onehalf);
261 translator.addPair("double", Spacing::Double);
262 translator.addPair("other", Spacing::Other);
267 SpaceTranslator const & spacetranslator()
269 static SpaceTranslator translator = init_spacetranslator();
277 class BufferParams::Impl
282 AuthorList authorlist;
283 BranchList branchlist;
284 Bullet temp_bullets[4];
285 Bullet user_defined_bullets[4];
287 /** This is the amount of space used for paragraph_separation "skip",
288 * and for detached paragraphs in "indented" documents.
291 PDFOptions pdfoptions;
295 BufferParams::Impl::Impl()
296 : defskip(VSpace::MEDSKIP)
298 // set initial author
300 authorlist.record(Author(from_utf8(lyxrc.user_name), from_utf8(lyxrc.user_email)));
305 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
309 return new BufferParams::Impl(*ptr);
313 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
319 BufferParams::BufferParams()
322 setBaseClass(defaultTextclass());
323 paragraph_separation = PARSEP_INDENT;
324 quotes_language = InsetQuotes::EnglishQ;
325 fontsize = "default";
328 papersize = PAPER_DEFAULT;
329 orientation = ORIENTATION_PORTRAIT;
330 use_geometry = false;
331 use_amsmath = package_auto;
332 use_esint = package_auto;
333 cite_engine_ = biblio::ENGINE_BASIC;
334 use_bibtopic = false;
335 trackChanges = false;
336 outputChanges = false;
339 language = default_language;
340 fontsRoman = "default";
341 fontsSans = "default";
342 fontsTypewriter = "default";
343 fontsDefaultFamily = "default";
346 fontsSansScale = 100;
347 fontsTypewriterScale = 100;
349 graphicsDriver = "default";
352 listings_params = string();
353 pagestyle = "default";
356 for (int iter = 0; iter < 4; ++iter) {
357 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
358 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
363 BufferParams::~BufferParams()
367 docstring const BufferParams::B_(string const & l10n) const
369 BOOST_ASSERT(language);
370 return getMessages(language->code()).get(l10n);
374 AuthorList & BufferParams::authors()
376 return pimpl_->authorlist;
380 AuthorList const & BufferParams::authors() const
382 return pimpl_->authorlist;
386 BranchList & BufferParams::branchlist()
388 return pimpl_->branchlist;
392 BranchList const & BufferParams::branchlist() const
394 return pimpl_->branchlist;
398 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
400 BOOST_ASSERT(index < 4);
401 return pimpl_->temp_bullets[index];
405 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
407 BOOST_ASSERT(index < 4);
408 return pimpl_->temp_bullets[index];
412 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
414 BOOST_ASSERT(index < 4);
415 return pimpl_->user_defined_bullets[index];
419 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
421 BOOST_ASSERT(index < 4);
422 return pimpl_->user_defined_bullets[index];
426 Spacing & BufferParams::spacing()
428 return pimpl_->spacing;
432 Spacing const & BufferParams::spacing() const
434 return pimpl_->spacing;
438 PDFOptions & BufferParams::pdfoptions()
440 return pimpl_->pdfoptions;
444 PDFOptions const & BufferParams::pdfoptions() const
446 return pimpl_->pdfoptions;
450 VSpace const & BufferParams::getDefSkip() const
452 return pimpl_->defskip;
456 void BufferParams::setDefSkip(VSpace const & vs)
458 pimpl_->defskip = vs;
462 string const BufferParams::readToken(Lexer & lex, string const & token,
463 FileName const & filepath)
465 if (token == "\\textclass") {
467 string const classname = lex.getString();
468 // if there exists a local layout file, ignore the system one
469 // NOTE: in this case, the textclass (.cls file) is assumed to be available.
470 pair<bool, lyx::textclass_type> pp =
471 make_pair(false, textclass_type(0));
472 if (!filepath.empty())
473 pp = textclasslist.addTextClass(
474 classname, filepath.absFilename());
476 setBaseClass(pp.second);
478 pp = textclasslist.numberOfClass(classname);
480 setBaseClass(pp.second);
482 // a warning will be given for unknown class
483 setBaseClass(defaultTextclass());
487 // FIXME: this warning will be given even if there exists a local .cls
488 // file. Even worse, the .lyx file can not be compiled or exported
489 // because the textclass is marked as unavilable.
490 if (!getTextClass().isTeXClassAvailable()) {
491 docstring const msg =
492 bformat(_("The layout file requested by this document,\n"
494 "is not usable. This is probably because a LaTeX\n"
495 "class or style file required by it is not\n"
496 "available. See the Customization documentation\n"
497 "for more information.\n"), from_utf8(classname));
498 frontend::Alert::warning(_("Document class not available"),
499 msg + _("LyX will not be able to produce output."));
502 } else if (token == "\\begin_preamble") {
504 } else if (token == "\\begin_modules") {
507 } else if (token == "\\options") {
509 options = lex.getString();
510 } else if (token == "\\language") {
512 } else if (token == "\\inputencoding") {
514 } else if (token == "\\graphics") {
515 readGraphicsDriver(lex);
516 } else if (token == "\\font_roman") {
518 } else if (token == "\\font_sans") {
520 } else if (token == "\\font_typewriter") {
521 lex >> fontsTypewriter;
522 } else if (token == "\\font_default_family") {
523 lex >> fontsDefaultFamily;
524 } else if (token == "\\font_sc") {
526 } else if (token == "\\font_osf") {
528 } else if (token == "\\font_sf_scale") {
529 lex >> fontsSansScale;
530 } else if (token == "\\font_tt_scale") {
531 lex >> fontsTypewriterScale;
532 } else if (token == "\\paragraph_separation") {
535 paragraph_separation = parseptranslator().find(parsep);
536 } else if (token == "\\defskip") {
538 pimpl_->defskip = VSpace(lex.getString());
539 } else if (token == "\\quotes_language") {
542 quotes_language = quoteslangtranslator().find(quotes_lang);
543 } else if (token == "\\papersize") {
546 papersize = papersizetranslator().find(ppsize);
547 } else if (token == "\\use_geometry") {
549 } else if (token == "\\use_amsmath") {
552 use_amsmath = packagetranslator().find(use_ams);
553 } else if (token == "\\use_esint") {
556 use_esint = packagetranslator().find(useesint);
557 } else if (token == "\\cite_engine") {
560 cite_engine_ = citeenginetranslator().find(engine);
561 } else if (token == "\\use_bibtopic") {
563 } else if (token == "\\tracking_changes") {
565 } else if (token == "\\output_changes") {
566 lex >> outputChanges;
567 } else if (token == "\\branch") {
569 docstring branch = lex.getDocString();
570 branchlist().add(branch);
573 string const tok = lex.getString();
574 if (tok == "\\end_branch")
576 Branch * branch_ptr = branchlist().find(branch);
577 if (tok == "\\selected") {
580 branch_ptr->setSelected(lex.getInteger());
582 // not yet operational
583 if (tok == "\\color") {
585 string color = lex.getString();
587 branch_ptr->setColor(color);
588 // Update also the Color table:
590 color = lcolor.getX11Name(Color_background);
592 lcolor.setColor(to_utf8(branch), color);
596 } else if (token == "\\author") {
598 istringstream ss(lex.getString());
601 author_map.push_back(pimpl_->authorlist.record(a));
602 } else if (token == "\\paperorientation") {
605 orientation = paperorientationtranslator().find(orient);
606 } else if (token == "\\paperwidth") {
608 } else if (token == "\\paperheight") {
610 } else if (token == "\\leftmargin") {
612 } else if (token == "\\topmargin") {
614 } else if (token == "\\rightmargin") {
616 } else if (token == "\\bottommargin") {
618 } else if (token == "\\headheight") {
620 } else if (token == "\\headsep") {
622 } else if (token == "\\footskip") {
624 } else if (token == "\\paperfontsize") {
626 } else if (token == "\\papercolumns") {
628 } else if (token == "\\listings_params") {
631 listings_params = InsetListingsParams(par).params();
632 } else if (token == "\\papersides") {
635 sides = sidestranslator().find(psides);
636 } else if (token == "\\paperpagestyle") {
638 } else if (token == "\\bullet") {
640 } else if (token == "\\bulletLaTeX") {
641 readBulletsLaTeX(lex);
642 } else if (token == "\\secnumdepth") {
644 } else if (token == "\\tocdepth") {
646 } else if (token == "\\spacing") {
650 if (nspacing == "other") {
653 spacing().set(spacetranslator().find(nspacing), tmp_val);
654 } else if (token == "\\float_placement") {
655 lex >> float_placement;
657 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
658 string toktmp = pdfoptions().readToken(lex, token);
659 if (!toktmp.empty()) {
660 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
665 lyxerr << "BufferParams::readToken(): Unknown token: " <<
674 void BufferParams::writeFile(ostream & os) const
676 // The top of the file is written by the buffer.
677 // Prints out the buffer info into the .lyx file given by file
680 os << "\\textclass " << textclasslist[baseClass_].name() << '\n';
683 if (!preamble.empty()) {
684 // remove '\n' from the end of preamble
685 string const tmppreamble = rtrim(preamble, "\n");
686 os << "\\begin_preamble\n"
688 << "\n\\end_preamble\n";
692 if (!options.empty()) {
693 os << "\\options " << options << '\n';
697 if (!layoutModules_.empty()) {
698 os << "\\begin_modules" << '\n';
699 LayoutModuleList::const_iterator it = layoutModules_.begin();
700 for (; it != layoutModules_.end(); it++)
702 os << "\\end_modules" << '\n';
705 // then the text parameters
706 if (language != ignore_language)
707 os << "\\language " << language->lang() << '\n';
708 os << "\\inputencoding " << inputenc
709 << "\n\\font_roman " << fontsRoman
710 << "\n\\font_sans " << fontsSans
711 << "\n\\font_typewriter " << fontsTypewriter
712 << "\n\\font_default_family " << fontsDefaultFamily
713 << "\n\\font_sc " << convert<string>(fontsSC)
714 << "\n\\font_osf " << convert<string>(fontsOSF)
715 << "\n\\font_sf_scale " << fontsSansScale
716 << "\n\\font_tt_scale " << fontsTypewriterScale
717 << "\n\\graphics " << graphicsDriver << '\n';
719 if (!float_placement.empty()) {
720 os << "\\float_placement " << float_placement << '\n';
722 os << "\\paperfontsize " << fontsize << '\n';
724 spacing().writeFile(os);
725 pdfoptions().writeFile(os);
727 os << "\\papersize " << string_papersize[papersize]
728 << "\n\\use_geometry " << convert<string>(use_geometry)
729 << "\n\\use_amsmath " << use_amsmath
730 << "\n\\use_esint " << use_esint
731 << "\n\\cite_engine " << citeenginetranslator().find(cite_engine_)
732 << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
733 << "\n\\paperorientation " << string_orientation[orientation]
736 BranchList::const_iterator it = branchlist().begin();
737 BranchList::const_iterator end = branchlist().end();
738 for (; it != end; ++it) {
739 os << "\\branch " << to_utf8(it->getBranch())
740 << "\n\\selected " << it->getSelected()
741 << "\n\\color " << lyx::X11hexname(it->getColor())
746 if (!paperwidth.empty())
747 os << "\\paperwidth "
748 << VSpace(paperwidth).asLyXCommand() << '\n';
749 if (!paperheight.empty())
750 os << "\\paperheight "
751 << VSpace(paperheight).asLyXCommand() << '\n';
752 if (!leftmargin.empty())
753 os << "\\leftmargin "
754 << VSpace(leftmargin).asLyXCommand() << '\n';
755 if (!topmargin.empty())
757 << VSpace(topmargin).asLyXCommand() << '\n';
758 if (!rightmargin.empty())
759 os << "\\rightmargin "
760 << VSpace(rightmargin).asLyXCommand() << '\n';
761 if (!bottommargin.empty())
762 os << "\\bottommargin "
763 << VSpace(bottommargin).asLyXCommand() << '\n';
764 if (!headheight.empty())
765 os << "\\headheight "
766 << VSpace(headheight).asLyXCommand() << '\n';
767 if (!headsep.empty())
769 << VSpace(headsep).asLyXCommand() << '\n';
770 if (!footskip.empty())
772 << VSpace(footskip).asLyXCommand() << '\n';
773 os << "\\secnumdepth " << secnumdepth
774 << "\n\\tocdepth " << tocdepth
775 << "\n\\paragraph_separation "
776 << string_paragraph_separation[paragraph_separation]
777 << "\n\\defskip " << getDefSkip().asLyXCommand()
778 << "\n\\quotes_language "
779 << string_quotes_language[quotes_language]
780 << "\n\\papercolumns " << columns
781 << "\n\\papersides " << sides
782 << "\n\\paperpagestyle " << pagestyle << '\n';
783 if (!listings_params.empty())
784 os << "\\listings_params \"" <<
785 InsetListingsParams(listings_params).encodedString() << "\"\n";
786 for (int i = 0; i < 4; ++i) {
787 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
788 if (user_defined_bullet(i).getFont() != -1) {
789 os << "\\bullet " << i << " "
790 << user_defined_bullet(i).getFont() << " "
791 << user_defined_bullet(i).getCharacter() << " "
792 << user_defined_bullet(i).getSize() << "\n";
796 os << "\\bulletLaTeX " << i << " \""
797 << lyx::to_ascii(user_defined_bullet(i).getText())
803 os << "\\tracking_changes " << convert<string>(trackChanges) << "\n";
804 os << "\\output_changes " << convert<string>(outputChanges) << "\n";
806 AuthorList::Authors::const_iterator a_it = pimpl_->authorlist.begin();
807 AuthorList::Authors::const_iterator a_end = pimpl_->authorlist.end();
808 for (; a_it != a_end; ++a_it) {
809 if (a_it->second.used())
810 os << "\\author " << a_it->second << "\n";
812 os << "\\author " << Author() << "\n";
817 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
818 TexRow & texrow) const
820 os << "\\documentclass";
822 TextClass const & tclass = getTextClass();
824 ostringstream clsoptions; // the document class options.
826 if (tokenPos(tclass.opt_fontsize(),
827 '|', fontsize) >= 0) {
828 // only write if existing in list (and not default)
829 clsoptions << fontsize << "pt,";
832 // custom, A3, B3 and B4 paper sizes need geometry
833 bool nonstandard_papersize = papersize == PAPER_B3
834 || papersize == PAPER_B4
835 || papersize == PAPER_A3
836 || papersize == PAPER_CUSTOM;
841 clsoptions << "a4paper,";
844 clsoptions << "letterpaper,";
847 clsoptions << "a5paper,";
850 clsoptions << "b5paper,";
852 case PAPER_USEXECUTIVE:
853 clsoptions << "executivepaper,";
856 clsoptions << "legalpaper,";
868 if (sides != tclass.sides()) {
871 clsoptions << "oneside,";
874 clsoptions << "twoside,";
880 if (columns != tclass.columns()) {
882 clsoptions << "twocolumn,";
884 clsoptions << "onecolumn,";
888 && orientation == ORIENTATION_LANDSCAPE)
889 clsoptions << "landscape,";
891 // language should be a parameter to \documentclass
892 if (language->babel() == "hebrew"
893 && default_language->babel() != "hebrew")
894 // This seems necessary
895 features.useLanguage(default_language);
897 ostringstream language_options;
898 bool const use_babel = features.useBabel();
900 language_options << features.getLanguages();
901 if (!language->babel().empty()) {
902 if (!language_options.str().empty())
903 language_options << ',';
904 language_options << language->babel();
906 // when Vietnamese is used, babel must directly be loaded with the
907 // language options, not in the class options, see
908 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
909 size_t viet = language_options.str().find("vietnam");
910 // viet = string::npos when not found
911 if (lyxrc.language_global_options && !language_options.str().empty()
912 && viet == string::npos)
913 clsoptions << language_options.str() << ',';
916 // the user-defined options
917 if (!options.empty()) {
918 clsoptions << options << ',';
921 string strOptions(clsoptions.str());
922 if (!strOptions.empty()) {
923 strOptions = rtrim(strOptions, ",");
925 os << '[' << from_utf8(strOptions) << ']';
928 os << '{' << from_ascii(tclass.latexname()) << "}\n";
930 // end of \documentclass defs
932 // font selection must be done before loading fontenc.sty
934 loadFonts(fontsRoman, fontsSans,
935 fontsTypewriter, fontsSC, fontsOSF,
936 fontsSansScale, fontsTypewriterScale);
937 if (!fonts.empty()) {
938 os << from_ascii(fonts);
941 if (fontsDefaultFamily != "default")
942 os << "\\renewcommand{\\familydefault}{\\"
943 << from_ascii(fontsDefaultFamily) << "}\n";
946 // this one is not per buffer
947 // for arabic_arabi and farsi we also need to load the LAE and LFE encoding
948 if (lyxrc.fontenc != "default") {
949 if (language->lang() == "arabic_arabi" || language->lang() == "farsi") {
950 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
951 << ",LFE,LAE]{fontenc}\n";
954 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
960 // handle inputenc etc.
961 writeEncodingPreamble(os, features, texrow);
963 if (!listings_params.empty()) {
964 os << "\\usepackage{listings}\n";
967 // do not test validity because listings_params is supposed to be valid
968 string par = InsetListingsParams(listings_params).separatedParams(true);
969 os << from_ascii(par);
970 // count the number of newlines
971 for (size_t i = 0; i < par.size(); ++i)
977 if (use_geometry || nonstandard_papersize) {
978 os << "\\usepackage{geometry}\n";
980 os << "\\geometry{verbose";
981 if (orientation == ORIENTATION_LANDSCAPE)
985 if (!paperwidth.empty())
987 << from_ascii(paperwidth);
988 if (!paperheight.empty())
989 os << ",paperheight="
990 << from_ascii(paperheight);
993 os << ",letterpaper";
998 case PAPER_USEXECUTIVE:
999 os << ",executivepaper";
1020 // default papersize ie PAPER_DEFAULT
1021 switch (lyxrc.default_papersize) {
1022 case PAPER_DEFAULT: // keep compiler happy
1023 case PAPER_USLETTER:
1024 os << ",letterpaper";
1027 os << ",legalpaper";
1029 case PAPER_USEXECUTIVE:
1030 os << ",executivepaper";
1050 if (!topmargin.empty())
1051 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1052 if (!bottommargin.empty())
1053 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1054 if (!leftmargin.empty())
1055 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1056 if (!rightmargin.empty())
1057 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1058 if (!headheight.empty())
1059 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1060 if (!headsep.empty())
1061 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1062 if (!footskip.empty())
1063 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1068 if (tokenPos(tclass.opt_pagestyle(),
1069 '|', pagestyle) >= 0) {
1070 if (pagestyle == "fancy") {
1071 os << "\\usepackage{fancyhdr}\n";
1074 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1078 // Only if class has a ToC hierarchy
1079 if (tclass.hasTocLevels()) {
1080 if (secnumdepth != tclass.secnumdepth()) {
1081 os << "\\setcounter{secnumdepth}{"
1086 if (tocdepth != tclass.tocdepth()) {
1087 os << "\\setcounter{tocdepth}{"
1094 if (paragraph_separation) {
1095 switch (getDefSkip().kind()) {
1096 case VSpace::SMALLSKIP:
1097 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1099 case VSpace::MEDSKIP:
1100 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1102 case VSpace::BIGSKIP:
1103 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1105 case VSpace::LENGTH:
1106 os << "\\setlength{\\parskip}{"
1107 << from_utf8(getDefSkip().length().asLatexString())
1110 default: // should never happen // Then delete it.
1111 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1116 os << "\\setlength{\\parindent}{0pt}\n";
1120 // If we use jurabib, we have to call babel here.
1121 if (use_babel && features.isRequired("jurabib")) {
1122 os << from_ascii(babelCall(language_options.str()))
1124 << from_ascii(features.getBabelOptions());
1128 // Now insert the LyX specific LaTeX commands...
1130 // The optional packages;
1131 docstring lyxpreamble(from_ascii(features.getPackages()));
1133 // We try to load babel late, in case it interferes
1134 // with other packages. But some packages also need babel to be loaded
1135 // before, e.g. jurabib has to be called after babel.
1136 // So load babel after the optional packages but before the user-defined
1137 // preamble. This allows the users to redefine babel commands, e.g. to
1138 // translate the word "Index" to the German "Stichwortverzeichnis".
1139 // For more infos why this place was chosen, see
1140 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg128425.html
1141 // If you encounter problems, you can shift babel to its old place behind
1142 // the user-defined preamble. But in this case you must change the Vietnamese
1143 // support from currently "\usepackage[vietnamese]{babel}" to:
1144 // \usepackage{vietnamese}
1145 // \usepackage{babel}
1146 // because vietnamese must be loaded before hyperref
1147 if (use_babel && !features.isRequired("jurabib")) {
1149 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1150 lyxpreamble += from_utf8(features.getBabelOptions());
1153 // When the language "japanese-plain" is used, the package "japanese" must
1154 // be loaded behind babel (it provides babel support for Japanese) but before
1156 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1157 if (language->lang() == "japanese-plain" &&
1158 !getTextClass().provides("japanese")) {
1159 //load babel in case it was not loaded due to an empty language list
1160 if (language_options.str().empty())
1161 lyxpreamble += "\\usepackage{babel}\n";
1162 lyxpreamble += "\\usepackage{japanese}\n";
1166 // * Hyperref manual: "Make sure it comes last of your loaded
1167 // packages, to give it a fighting chance of not being over-written,
1168 // since its job is to redefine many LATEX commands."
1169 // * Email from Heiko Oberdiek: "It is usually better to load babel
1170 // before hyperref. Then hyperref has a chance to detect babel.
1171 // * Has to be loaded before the "LyX specific LaTeX commands" to
1172 // avoid errors with algorithm floats.
1173 odocstringstream oss;
1174 // use hyperref explicitely when it is required
1175 pdfoptions().writeLaTeX(oss, features.isRequired("hyperref"));
1176 lyxpreamble += oss.str();
1178 // this might be useful...
1179 lyxpreamble += "\n\\makeatletter\n";
1181 // Some macros LyX will need
1182 docstring tmppreamble(from_ascii(features.getMacros()));
1184 if (!tmppreamble.empty()) {
1185 lyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1186 "LyX specific LaTeX commands.\n"
1187 + tmppreamble + '\n';
1190 // the text class specific preamble
1191 tmppreamble = features.getTClassPreamble();
1192 if (!tmppreamble.empty()) {
1193 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1194 "Textclass specific LaTeX commands.\n"
1195 + tmppreamble + '\n';
1198 /* the user-defined preamble */
1199 if (!preamble.empty()) {
1201 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1202 "User specified LaTeX commands.\n"
1203 + from_utf8(preamble) + '\n';
1206 // Itemize bullet settings need to be last in case the user
1207 // defines their own bullets that use a package included
1208 // in the user-defined preamble -- ARRae
1209 // Actually it has to be done much later than that
1210 // since some packages like frenchb make modifications
1211 // at \begin{document} time -- JMarc
1212 docstring bullets_def;
1213 for (int i = 0; i < 4; ++i) {
1214 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1215 if (bullets_def.empty())
1216 bullets_def += "\\AtBeginDocument{\n";
1217 bullets_def += " \\def\\labelitemi";
1219 // `i' is one less than the item to modify
1226 bullets_def += "ii";
1232 bullets_def += '{' +
1233 user_defined_bullet(i).getText()
1238 if (!bullets_def.empty())
1239 lyxpreamble += bullets_def + "}\n\n";
1241 lyxpreamble += "\\makeatother\n\n";
1244 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1245 for (int j = 0; j != nlines; ++j) {
1254 void BufferParams::useClassDefaults()
1256 TextClass const & tclass = textclasslist[baseClass_];
1258 sides = tclass.sides();
1259 columns = tclass.columns();
1260 pagestyle = tclass.pagestyle();
1261 options = tclass.options();
1262 // Only if class has a ToC hierarchy
1263 if (tclass.hasTocLevels()) {
1264 secnumdepth = tclass.secnumdepth();
1265 tocdepth = tclass.tocdepth();
1270 bool BufferParams::hasClassDefaults() const
1272 TextClass const & tclass = textclasslist[baseClass_];
1274 return (sides == tclass.sides()
1275 && columns == tclass.columns()
1276 && pagestyle == tclass.pagestyle()
1277 && options == tclass.options()
1278 && secnumdepth == tclass.secnumdepth()
1279 && tocdepth == tclass.tocdepth());
1283 TextClass const & BufferParams::getTextClass() const
1289 TextClassPtr BufferParams::getTextClassPtr() const {
1294 void BufferParams::setTextClass(TextClassPtr tc) {
1299 bool BufferParams::setBaseClass(textclass_type tc)
1302 if (textclasslist[tc].load())
1306 bformat(_("The document class %1$s could not be loaded."),
1307 from_utf8(textclasslist[tc].name()));
1308 frontend::Alert::error(_("Could not load class"), s);
1316 void BufferParams::setJustBaseClass(textclass_type tc)
1322 textclass_type BufferParams::getBaseClass() const
1328 void BufferParams::makeTextClass()
1330 textClass_.reset(new TextClass(textclasslist[getBaseClass()]));
1331 //FIXME It might be worth loading the children's modules here,
1332 //just as we load their bibliographies and such, instead of just
1333 //doing a check in InsetInclude.
1334 LayoutModuleList::const_iterator it = layoutModules_.begin();
1335 for (; it != layoutModules_.end(); it++) {
1336 string const modName = *it;
1337 LyXModule * lm = moduleList[modName];
1339 docstring const msg =
1340 bformat(_("The module %1$s has been requested by\n"
1341 "this document but has not been found in the list of\n"
1342 "available modules. If you recently installed it, you\n"
1343 "probably need to reconfigure LyX.\n"), from_utf8(modName));
1344 frontend::Alert::warning(_("Module not available"),
1345 msg + _("Some layouts may not be available."));
1346 lyxerr << "BufferParams::makeTextClass(): Module " <<
1347 modName << " requested but not found in module list." <<
1351 FileName layout_file = libFileSearch("layouts", lm->filename);
1352 textClass_->read(layout_file, TextClass::MODULE);
1357 std::vector<string> const & BufferParams::getModules() const {
1358 return layoutModules_;
1363 bool BufferParams::addLayoutModule(string modName, bool makeClass) {
1364 LayoutModuleList::const_iterator it = layoutModules_.begin();
1365 LayoutModuleList::const_iterator end = layoutModules_.end();
1366 for (; it != end; it++) {
1370 if (it != layoutModules_.end())
1372 layoutModules_.push_back(modName);
1379 bool BufferParams::addLayoutModules(std::vector<string>modNames)
1382 std::vector<string>::const_iterator it = modNames.begin();
1383 std::vector<string>::const_iterator end = modNames.end();
1384 for (; it != end; ++it)
1385 retval &= addLayoutModule(*it, false);
1391 void BufferParams::clearLayoutModules() {
1392 layoutModules_.clear();
1397 Font const BufferParams::getFont() const
1399 FontInfo f = getTextClass().defaultfont();
1400 if (fontsDefaultFamily == "rmdefault")
1401 f.setFamily(ROMAN_FAMILY);
1402 else if (fontsDefaultFamily == "sfdefault")
1403 f.setFamily(SANS_FAMILY);
1404 else if (fontsDefaultFamily == "ttdefault")
1405 f.setFamily(TYPEWRITER_FAMILY);
1406 return Font(f, language);
1410 void BufferParams::readPreamble(Lexer & lex)
1412 if (lex.getString() != "\\begin_preamble")
1413 lyxerr << "Error (BufferParams::readPreamble):"
1414 "consistency check failed." << endl;
1416 preamble = lex.getLongString("\\end_preamble");
1420 void BufferParams::readLanguage(Lexer & lex)
1422 if (!lex.next()) return;
1424 string const tmptok = lex.getString();
1426 // check if tmptok is part of tex_babel in tex-defs.h
1427 language = languages.getLanguage(tmptok);
1429 // Language tmptok was not found
1430 language = default_language;
1431 lyxerr << "Warning: Setting language `"
1432 << tmptok << "' to `" << language->lang()
1438 void BufferParams::readGraphicsDriver(Lexer & lex)
1440 if (!lex.next()) return;
1442 string const tmptok = lex.getString();
1443 // check if tmptok is part of tex_graphics in tex_defs.h
1446 string const test = tex_graphics[n++];
1448 if (test == tmptok) {
1449 graphicsDriver = tmptok;
1451 } else if (test == "") {
1453 "Warning: graphics driver `$$Token' not recognized!\n"
1454 " Setting graphics driver to `default'.\n");
1455 graphicsDriver = "default";
1462 void BufferParams::readBullets(Lexer & lex)
1464 if (!lex.next()) return;
1466 int const index = lex.getInteger();
1468 int temp_int = lex.getInteger();
1469 user_defined_bullet(index).setFont(temp_int);
1470 temp_bullet(index).setFont(temp_int);
1472 user_defined_bullet(index).setCharacter(temp_int);
1473 temp_bullet(index).setCharacter(temp_int);
1475 user_defined_bullet(index).setSize(temp_int);
1476 temp_bullet(index).setSize(temp_int);
1480 void BufferParams::readBulletsLaTeX(Lexer & lex)
1482 // The bullet class should be able to read this.
1483 if (!lex.next()) return;
1484 int const index = lex.getInteger();
1486 docstring const temp_str = lex.getDocString();
1488 user_defined_bullet(index).setText(temp_str);
1489 temp_bullet(index).setText(temp_str);
1493 void BufferParams::readModules(Lexer & lex)
1495 if (!lex.eatLine()) {
1496 lyxerr << "Error (BufferParams::readModules):"
1497 "Unexpected end of input." << endl;
1501 string mod = lex.getString();
1502 if (mod == "\\end_modules")
1504 addLayoutModule(mod);
1510 string const BufferParams::paperSizeName() const
1512 char real_papersize = papersize;
1513 if (real_papersize == PAPER_DEFAULT)
1514 real_papersize = lyxrc.default_papersize;
1516 switch (real_papersize) {
1525 case PAPER_USEXECUTIVE:
1529 case PAPER_USLETTER:
1536 string const BufferParams::dvips_options() const
1541 && papersize == PAPER_CUSTOM
1542 && !lyxrc.print_paper_dimension_flag.empty()
1543 && !paperwidth.empty()
1544 && !paperheight.empty()) {
1545 // using a custom papersize
1546 result = lyxrc.print_paper_dimension_flag;
1547 result += ' ' + paperwidth;
1548 result += ',' + paperheight;
1550 string const paper_option = paperSizeName();
1551 if (paper_option != "letter" ||
1552 orientation != ORIENTATION_LANDSCAPE) {
1553 // dvips won't accept -t letter -t landscape.
1554 // In all other cases, include the paper size
1556 result = lyxrc.print_paper_flag;
1557 result += ' ' + paper_option;
1560 if (orientation == ORIENTATION_LANDSCAPE &&
1561 papersize != PAPER_CUSTOM)
1562 result += ' ' + lyxrc.print_landscape_flag;
1567 string const BufferParams::babelCall(string const & lang_opts) const
1569 string lang_pack = lyxrc.language_package;
1570 if (lang_pack != "\\usepackage{babel}")
1572 // suppress the babel call when there is no babel language defined
1573 // for the document language in the lib/languages file and if no
1574 // other languages are used (lang_opts is then empty)
1575 if (lang_opts.empty())
1577 // when Vietnamese is used, babel must directly be loaded with the
1578 // language options, see
1579 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1580 size_t viet = lang_opts.find("vietnam");
1581 // viet = string::npos when not found
1582 if (!lyxrc.language_global_options || viet != string::npos)
1583 return "\\usepackage[" + lang_opts + "]{babel}";
1588 void BufferParams::writeEncodingPreamble(odocstream & os,
1589 LaTeXFeatures & features, TexRow & texrow) const
1591 if (inputenc == "auto") {
1592 string const doc_encoding =
1593 language->encoding()->latexName();
1594 Encoding::Package const package =
1595 language->encoding()->package();
1597 // Create a list with all the input encodings used
1599 std::set<string> encodings =
1600 features.getEncodingSet(doc_encoding);
1602 // When the encodings EUC-JP-plain, JIS-plain, or SJIS-plainare used, the
1603 // package inputenc must be omitted. Therefore set the encoding to empty.
1604 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1605 if (doc_encoding == "EUC-JP-plain" || doc_encoding == "JIS-plain" ||
1606 doc_encoding == "SJIS-plain")
1609 if (!encodings.empty() || package == Encoding::inputenc) {
1610 os << "\\usepackage[";
1611 std::set<string>::const_iterator it = encodings.begin();
1612 std::set<string>::const_iterator const end = encodings.end();
1614 os << from_ascii(*it);
1617 for (; it != end; ++it)
1618 os << ',' << from_ascii(*it);
1619 if (package == Encoding::inputenc) {
1620 if (!encodings.empty())
1622 os << from_ascii(doc_encoding);
1624 os << "]{inputenc}\n";
1627 if (package == Encoding::CJK || features.mustProvide("CJK")) {
1628 os << "\\usepackage{CJK}\n";
1631 } else if (inputenc != "default") {
1632 switch (encoding().package()) {
1633 case Encoding::none:
1635 case Encoding::inputenc:
1636 os << "\\usepackage[" << from_ascii(inputenc)
1641 os << "\\usepackage{CJK}\n";
1647 // The encoding "armscii8" is only available when the package "armtex" is loaded.
1648 // armscii8 is used for Armenian.
1649 if (language->encoding()->latexName() == "armscii8" || inputenc == "armscii8") {
1650 os << "\\usepackage{armtex}\n";
1656 string const BufferParams::loadFonts(string const & rm,
1657 string const & sf, string const & tt,
1658 bool const & sc, bool const & osf,
1659 int const & sfscale, int const & ttscale) const
1661 /* The LaTeX font world is in a flux. In the PSNFSS font interface,
1662 several packages have been replaced by others, that might not
1663 be installed on every system. We have to take care for that
1664 (see psnfss.pdf). We try to support all psnfss fonts as well
1665 as the fonts that have become de facto standard in the LaTeX
1666 world (e.g. Latin Modern). We do not support obsolete fonts
1667 (like PSLatex). In general, it should be possible to mix any
1668 rm font with any sf or tt font, respectively. (JSpitzm)
1670 -- separate math fonts.
1673 if (rm == "default" && sf == "default" && tt == "default")
1680 // Computer Modern (must be explicitely selectable -- there might be classes
1681 // that define a different default font!
1683 os << "\\renewcommand{\\rmdefault}{cmr}\n";
1684 // osf for Computer Modern needs eco.sty
1686 os << "\\usepackage{eco}\n";
1688 // Latin Modern Roman
1689 else if (rm == "lmodern")
1690 os << "\\usepackage{lmodern}\n";
1692 else if (rm == "ae") {
1693 // not needed when using OT1 font encoding.
1694 if (lyxrc.fontenc != "default")
1695 os << "\\usepackage{ae,aecompl}\n";
1698 else if (rm == "times") {
1699 // try to load the best available package
1700 if (LaTeXFeatures::isAvailable("mathptmx"))
1701 os << "\\usepackage{mathptmx}\n";
1702 else if (LaTeXFeatures::isAvailable("mathptm"))
1703 os << "\\usepackage{mathptm}\n";
1705 os << "\\usepackage{times}\n";
1708 else if (rm == "palatino") {
1709 // try to load the best available package
1710 if (LaTeXFeatures::isAvailable("mathpazo")) {
1711 os << "\\usepackage";
1717 // "osf" includes "sc"!
1721 os << "{mathpazo}\n";
1723 else if (LaTeXFeatures::isAvailable("mathpple"))
1724 os << "\\usepackage{mathpple}\n";
1726 os << "\\usepackage{palatino}\n";
1729 else if (rm == "utopia") {
1730 // fourier supersedes utopia.sty, but does
1731 // not work with OT1 encoding.
1732 if (LaTeXFeatures::isAvailable("fourier")
1733 && lyxrc.fontenc != "default") {
1734 os << "\\usepackage";
1745 os << "{fourier}\n";
1748 os << "\\usepackage{utopia}\n";
1750 // Bera (complete fontset)
1751 else if (rm == "bera" && sf == "default" && tt == "default")
1752 os << "\\usepackage{bera}\n";
1754 else if (rm != "default")
1755 os << "\\usepackage" << "{" << rm << "}\n";
1758 // Helvetica, Bera Sans
1759 if (sf == "helvet" || sf == "berasans") {
1761 os << "\\usepackage[scaled=" << float(sfscale) / 100
1762 << "]{" << sf << "}\n";
1764 os << "\\usepackage{" << sf << "}\n";
1767 else if (sf == "avant")
1768 os << "\\usepackage{" << sf << "}\n";
1769 // Computer Modern, Latin Modern, CM Bright
1770 else if (sf != "default")
1771 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
1773 // monospaced/typewriter
1774 // Courier, LuxiMono
1775 if (tt == "luximono" || tt == "beramono") {
1777 os << "\\usepackage[scaled=" << float(ttscale) / 100
1778 << "]{" << tt << "}\n";
1780 os << "\\usepackage{" << tt << "}\n";
1783 else if (tt == "courier" )
1784 os << "\\usepackage{" << tt << "}\n";
1785 // Computer Modern, Latin Modern, CM Bright
1786 else if (tt != "default")
1787 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
1793 Encoding const & BufferParams::encoding() const
1795 if (inputenc == "auto" || inputenc == "default")
1796 return *(language->encoding());
1797 Encoding const * const enc =
1798 encodings.getFromLaTeXName(inputenc);
1801 lyxerr << "Unknown inputenc value `" << inputenc
1802 << "'. Using `auto' instead." << endl;
1803 return *(language->encoding());
1807 biblio::CiteEngine BufferParams::getEngine() const
1809 // FIXME the class should provide the numerical/
1810 // authoryear choice
1811 if (getTextClass().provides("natbib")
1812 && cite_engine_ != biblio::ENGINE_NATBIB_NUMERICAL)
1813 return biblio::ENGINE_NATBIB_AUTHORYEAR;
1814 return cite_engine_;
1818 void BufferParams::setCiteEngine(biblio::CiteEngine const cite_engine)
1820 cite_engine_ = cite_engine;