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"
29 #include "LaTeXFeatures.h"
31 #include "ModuleList.h"
35 #include "TextClassList.h"
36 #include "OutputParams.h"
40 #include "PDFOptions.h"
42 #include "frontends/alert.h"
43 #include "insets/InsetListingsParams.h"
45 #include "support/convert.h"
46 #include "support/docstream.h"
47 #include "support/filetools.h"
48 #include "support/Translator.h"
49 #include "support/lstrings.h"
51 #include <boost/array.hpp>
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, TextClass::PageSides> SidesTranslator;
203 SidesTranslator const init_sidestranslator()
205 SidesTranslator translator(1, TextClass::OneSide);
206 translator.addPair(2, TextClass::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 boost::array<Bullet, 4> temp_bullets;
292 boost::array<Bullet, 4> user_defined_bullets;
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";
357 sides = TextClass::OneSide;
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)
471 if (token == "\\textclass") {
473 string const classname = lex.getString();
474 pair<bool, lyx::textclass_type> pp =
475 textclasslist.numberOfClass(classname);
477 setBaseClass(pp.second);
479 // if text class does not exist, try to load it from filepath
480 pp = textclasslist.addTextClass(classname, filepath);
482 setBaseClass(pp.second);
484 setBaseClass(defaultTextclass());
488 if (!getTextClass().isTeXClassAvailable()) {
489 docstring const msg =
490 bformat(_("The layout file requested by this document,\n"
492 "is not usable. This is probably because a LaTeX\n"
493 "class or style file required by it is not\n"
494 "available. See the Customization documentation\n"
495 "for more information.\n"), from_utf8(classname));
496 frontend::Alert::warning(_("Document class not available"),
497 msg + _("LyX will not be able to produce output."));
500 } else if (token == "\\begin_preamble") {
502 } else if (token == "\\begin_modules") {
505 } else if (token == "\\options") {
507 options = lex.getString();
508 } else if (token == "\\language") {
510 } else if (token == "\\inputencoding") {
512 } else if (token == "\\graphics") {
513 readGraphicsDriver(lex);
514 } else if (token == "\\font_roman") {
516 } else if (token == "\\font_sans") {
518 } else if (token == "\\font_typewriter") {
519 lex >> fontsTypewriter;
520 } else if (token == "\\font_default_family") {
521 lex >> fontsDefaultFamily;
522 } else if (token == "\\font_sc") {
524 } else if (token == "\\font_osf") {
526 } else if (token == "\\font_sf_scale") {
527 lex >> fontsSansScale;
528 } else if (token == "\\font_tt_scale") {
529 lex >> fontsTypewriterScale;
530 } else if (token == "\\paragraph_separation") {
533 paragraph_separation = parseptranslator().find(parsep);
534 } else if (token == "\\defskip") {
536 pimpl_->defskip = VSpace(lex.getString());
537 } else if (token == "\\quotes_language") {
540 quotes_language = quoteslangtranslator().find(quotes_lang);
541 } else if (token == "\\papersize") {
544 papersize = papersizetranslator().find(ppsize);
545 } else if (token == "\\use_geometry") {
547 } else if (token == "\\use_amsmath") {
550 use_amsmath = packagetranslator().find(use_ams);
551 } else if (token == "\\use_esint") {
554 use_esint = packagetranslator().find(useesint);
555 } else if (token == "\\cite_engine") {
558 cite_engine_ = citeenginetranslator().find(engine);
559 } else if (token == "\\use_bibtopic") {
561 } else if (token == "\\tracking_changes") {
563 } else if (token == "\\output_changes") {
564 lex >> outputChanges;
565 } else if (token == "\\branch") {
567 docstring branch = lex.getDocString();
568 branchlist().add(branch);
571 string const tok = lex.getString();
572 if (tok == "\\end_branch")
574 Branch * branch_ptr = branchlist().find(branch);
575 if (tok == "\\selected") {
578 branch_ptr->setSelected(lex.getInteger());
580 // not yet operational
581 if (tok == "\\color") {
583 string color = lex.getString();
585 branch_ptr->setColor(color);
586 // Update also the Color table:
588 color = lcolor.getX11Name(Color_background);
590 lcolor.setColor(to_utf8(branch), color);
594 } else if (token == "\\author") {
596 istringstream ss(lex.getString());
599 author_map.push_back(pimpl_->authorlist.record(a));
600 } else if (token == "\\paperorientation") {
603 orientation = paperorientationtranslator().find(orient);
604 } else if (token == "\\paperwidth") {
606 } else if (token == "\\paperheight") {
608 } else if (token == "\\leftmargin") {
610 } else if (token == "\\topmargin") {
612 } else if (token == "\\rightmargin") {
614 } else if (token == "\\bottommargin") {
616 } else if (token == "\\headheight") {
618 } else if (token == "\\headsep") {
620 } else if (token == "\\footskip") {
622 } else if (token == "\\paperfontsize") {
624 } else if (token == "\\papercolumns") {
626 } else if (token == "\\listings_params") {
629 listings_params = InsetListingsParams(par).params();
630 } else if (token == "\\papersides") {
633 sides = sidestranslator().find(psides);
634 } else if (token == "\\paperpagestyle") {
636 } else if (token == "\\bullet") {
638 } else if (token == "\\bulletLaTeX") {
639 readBulletsLaTeX(lex);
640 } else if (token == "\\secnumdepth") {
642 } else if (token == "\\tocdepth") {
644 } else if (token == "\\spacing") {
648 if (nspacing == "other") {
651 spacing().set(spacetranslator().find(nspacing), tmp_val);
652 } else if (token == "\\float_placement") {
653 lex >> float_placement;
655 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
656 string toktmp = pdfoptions().readToken(lex, token);
657 if (!toktmp.empty()) {
658 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
663 lyxerr << "BufferParams::readToken(): Unknown token: " <<
672 void BufferParams::writeFile(ostream & os) const
674 // The top of the file is written by the buffer.
675 // Prints out the buffer info into the .lyx file given by file
678 os << "\\textclass " << textclasslist[baseClass_].name() << '\n';
681 if (!preamble.empty()) {
682 // remove '\n' from the end of preamble
683 string const tmppreamble = rtrim(preamble, "\n");
684 os << "\\begin_preamble\n"
686 << "\n\\end_preamble\n";
690 if (!options.empty()) {
691 os << "\\options " << options << '\n';
695 if (!layoutModules_.empty()) {
696 os << "\\begin_modules" << '\n';
697 LayoutModuleList::const_iterator it = layoutModules_.begin();
698 for (; it != layoutModules_.end(); it++)
700 os << "\\end_modules" << '\n';
703 // then the text parameters
704 if (language != ignore_language)
705 os << "\\language " << language->lang() << '\n';
706 os << "\\inputencoding " << inputenc
707 << "\n\\font_roman " << fontsRoman
708 << "\n\\font_sans " << fontsSans
709 << "\n\\font_typewriter " << fontsTypewriter
710 << "\n\\font_default_family " << fontsDefaultFamily
711 << "\n\\font_sc " << convert<string>(fontsSC)
712 << "\n\\font_osf " << convert<string>(fontsOSF)
713 << "\n\\font_sf_scale " << fontsSansScale
714 << "\n\\font_tt_scale " << fontsTypewriterScale
715 << "\n\\graphics " << graphicsDriver << '\n';
717 if (!float_placement.empty()) {
718 os << "\\float_placement " << float_placement << '\n';
720 os << "\\paperfontsize " << fontsize << '\n';
722 spacing().writeFile(os);
723 pdfoptions().writeFile(os);
725 os << "\\papersize " << string_papersize[papersize]
726 << "\n\\use_geometry " << convert<string>(use_geometry)
727 << "\n\\use_amsmath " << use_amsmath
728 << "\n\\use_esint " << use_esint
729 << "\n\\cite_engine " << citeenginetranslator().find(cite_engine_)
730 << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
731 << "\n\\paperorientation " << string_orientation[orientation]
734 BranchList::const_iterator it = branchlist().begin();
735 BranchList::const_iterator end = branchlist().end();
736 for (; it != end; ++it) {
737 os << "\\branch " << to_utf8(it->getBranch())
738 << "\n\\selected " << it->getSelected()
739 << "\n\\color " << lyx::X11hexname(it->getColor())
744 if (!paperwidth.empty())
745 os << "\\paperwidth "
746 << VSpace(paperwidth).asLyXCommand() << '\n';
747 if (!paperheight.empty())
748 os << "\\paperheight "
749 << VSpace(paperheight).asLyXCommand() << '\n';
750 if (!leftmargin.empty())
751 os << "\\leftmargin "
752 << VSpace(leftmargin).asLyXCommand() << '\n';
753 if (!topmargin.empty())
755 << VSpace(topmargin).asLyXCommand() << '\n';
756 if (!rightmargin.empty())
757 os << "\\rightmargin "
758 << VSpace(rightmargin).asLyXCommand() << '\n';
759 if (!bottommargin.empty())
760 os << "\\bottommargin "
761 << VSpace(bottommargin).asLyXCommand() << '\n';
762 if (!headheight.empty())
763 os << "\\headheight "
764 << VSpace(headheight).asLyXCommand() << '\n';
765 if (!headsep.empty())
767 << VSpace(headsep).asLyXCommand() << '\n';
768 if (!footskip.empty())
770 << VSpace(footskip).asLyXCommand() << '\n';
771 os << "\\secnumdepth " << secnumdepth
772 << "\n\\tocdepth " << tocdepth
773 << "\n\\paragraph_separation "
774 << string_paragraph_separation[paragraph_separation]
775 << "\n\\defskip " << getDefSkip().asLyXCommand()
776 << "\n\\quotes_language "
777 << string_quotes_language[quotes_language]
778 << "\n\\papercolumns " << columns
779 << "\n\\papersides " << sides
780 << "\n\\paperpagestyle " << pagestyle << '\n';
781 if (!listings_params.empty())
782 os << "\\listings_params \"" <<
783 InsetListingsParams(listings_params).encodedString() << "\"\n";
784 for (int i = 0; i < 4; ++i) {
785 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
786 if (user_defined_bullet(i).getFont() != -1) {
787 os << "\\bullet " << i << " "
788 << user_defined_bullet(i).getFont() << " "
789 << user_defined_bullet(i).getCharacter() << " "
790 << user_defined_bullet(i).getSize() << "\n";
794 os << "\\bulletLaTeX " << i << " \""
795 << lyx::to_ascii(user_defined_bullet(i).getText())
801 os << "\\tracking_changes " << convert<string>(trackChanges) << "\n";
802 os << "\\output_changes " << convert<string>(outputChanges) << "\n";
804 AuthorList::Authors::const_iterator a_it = pimpl_->authorlist.begin();
805 AuthorList::Authors::const_iterator a_end = pimpl_->authorlist.end();
806 for (; a_it != a_end; ++a_it) {
807 if (a_it->second.used())
808 os << "\\author " << a_it->second << "\n";
810 os << "\\author " << Author() << "\n";
815 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
816 TexRow & texrow) const
818 os << "\\documentclass";
820 TextClass const & tclass = getTextClass();
822 ostringstream clsoptions; // the document class options.
824 if (tokenPos(tclass.opt_fontsize(),
825 '|', fontsize) >= 0) {
826 // only write if existing in list (and not default)
827 clsoptions << fontsize << "pt,";
830 // custom, A3, B3 and B4 paper sizes need geometry
831 bool nonstandard_papersize = papersize == PAPER_B3
832 || papersize == PAPER_B4
833 || papersize == PAPER_A3
834 || papersize == PAPER_CUSTOM;
839 clsoptions << "a4paper,";
842 clsoptions << "letterpaper,";
845 clsoptions << "a5paper,";
848 clsoptions << "b5paper,";
850 case PAPER_USEXECUTIVE:
851 clsoptions << "executivepaper,";
854 clsoptions << "legalpaper,";
866 if (sides != tclass.sides()) {
868 case TextClass::OneSide:
869 clsoptions << "oneside,";
871 case TextClass::TwoSides:
872 clsoptions << "twoside,";
878 if (columns != tclass.columns()) {
880 clsoptions << "twocolumn,";
882 clsoptions << "onecolumn,";
886 && orientation == ORIENTATION_LANDSCAPE)
887 clsoptions << "landscape,";
889 // language should be a parameter to \documentclass
890 if (language->babel() == "hebrew"
891 && default_language->babel() != "hebrew")
892 // This seems necessary
893 features.useLanguage(default_language);
895 ostringstream language_options;
896 bool const use_babel = features.useBabel();
898 language_options << features.getLanguages();
899 if (!language->babel().empty()) {
900 if (!language_options.str().empty())
901 language_options << ',';
902 language_options << language->babel();
904 // when Vietnamese is used, babel must directly be loaded with the
905 // language options, not in the class options, see
906 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
907 size_t viet = language_options.str().find("vietnam");
908 // viet = string::npos when not found
909 if (lyxrc.language_global_options && !language_options.str().empty()
910 && viet == string::npos)
911 clsoptions << language_options.str() << ',';
914 // the user-defined options
915 if (!options.empty()) {
916 clsoptions << options << ',';
919 string strOptions(clsoptions.str());
920 if (!strOptions.empty()) {
921 strOptions = rtrim(strOptions, ",");
923 os << '[' << from_utf8(strOptions) << ']';
926 os << '{' << from_ascii(tclass.latexname()) << "}\n";
928 // end of \documentclass defs
930 // font selection must be done before loading fontenc.sty
932 loadFonts(fontsRoman, fontsSans,
933 fontsTypewriter, fontsSC, fontsOSF,
934 fontsSansScale, fontsTypewriterScale);
935 if (!fonts.empty()) {
936 os << from_ascii(fonts);
939 if (fontsDefaultFamily != "default")
940 os << "\\renewcommand{\\familydefault}{\\"
941 << from_ascii(fontsDefaultFamily) << "}\n";
944 // this one is not per buffer
945 // for arabic_arabi and farsi we also need to load the LAE and LFE encoding
946 if (lyxrc.fontenc != "default") {
947 if (language->lang() == "arabic_arabi" || language->lang() == "farsi") {
948 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
949 << ",LFE,LAE]{fontenc}\n";
952 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
958 // handle inputenc etc.
959 writeEncodingPreamble(os, features, texrow);
961 if (!listings_params.empty()) {
962 os << "\\usepackage{listings}\n";
965 // do not test validity because listings_params is supposed to be valid
966 string par = InsetListingsParams(listings_params).separatedParams(true);
967 os << from_ascii(par);
968 // count the number of newlines
969 for (size_t i = 0; i < par.size(); ++i)
975 if (use_geometry || nonstandard_papersize) {
976 os << "\\usepackage{geometry}\n";
978 os << "\\geometry{verbose";
979 if (orientation == ORIENTATION_LANDSCAPE)
983 if (!paperwidth.empty())
985 << from_ascii(paperwidth);
986 if (!paperheight.empty())
987 os << ",paperheight="
988 << from_ascii(paperheight);
991 os << ",letterpaper";
996 case PAPER_USEXECUTIVE:
997 os << ",executivepaper";
1018 // default papersize ie PAPER_DEFAULT
1019 switch (lyxrc.default_papersize) {
1020 case PAPER_DEFAULT: // keep compiler happy
1021 case PAPER_USLETTER:
1022 os << ",letterpaper";
1025 os << ",legalpaper";
1027 case PAPER_USEXECUTIVE:
1028 os << ",executivepaper";
1048 if (!topmargin.empty())
1049 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1050 if (!bottommargin.empty())
1051 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1052 if (!leftmargin.empty())
1053 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1054 if (!rightmargin.empty())
1055 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1056 if (!headheight.empty())
1057 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1058 if (!headsep.empty())
1059 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1060 if (!footskip.empty())
1061 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1066 if (tokenPos(tclass.opt_pagestyle(),
1067 '|', pagestyle) >= 0) {
1068 if (pagestyle == "fancy") {
1069 os << "\\usepackage{fancyhdr}\n";
1072 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1076 // Only if class has a ToC hierarchy
1077 if (tclass.hasTocLevels()) {
1078 if (secnumdepth != tclass.secnumdepth()) {
1079 os << "\\setcounter{secnumdepth}{"
1084 if (tocdepth != tclass.tocdepth()) {
1085 os << "\\setcounter{tocdepth}{"
1092 if (paragraph_separation) {
1093 switch (getDefSkip().kind()) {
1094 case VSpace::SMALLSKIP:
1095 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1097 case VSpace::MEDSKIP:
1098 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1100 case VSpace::BIGSKIP:
1101 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1103 case VSpace::LENGTH:
1104 os << "\\setlength{\\parskip}{"
1105 << from_utf8(getDefSkip().length().asLatexString())
1108 default: // should never happen // Then delete it.
1109 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1114 os << "\\setlength{\\parindent}{0pt}\n";
1118 // If we use jurabib, we have to call babel here.
1119 if (use_babel && features.isRequired("jurabib")) {
1120 os << from_ascii(babelCall(language_options.str()))
1122 << from_ascii(features.getBabelOptions());
1126 // Now insert the LyX specific LaTeX commands...
1128 // The optional packages;
1129 docstring lyxpreamble(from_ascii(features.getPackages()));
1131 // We try to load babel late, in case it interferes
1132 // with other packages. But some packages also need babel to be loaded
1133 // before, e.g. jurabib has to be called after babel.
1134 // So load babel after the optional packages but before the user-defined
1135 // preamble. This allows the users to redefine babel commands, e.g. to
1136 // translate the word "Index" to the German "Stichwortverzeichnis".
1137 // For more infos why this place was chosen, see
1138 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg128425.html
1139 // If you encounter problems, you can shift babel to its old place behind
1140 // the user-defined preamble. But in this case you must change the Vietnamese
1141 // support from currently "\usepackage[vietnamese]{babel}" to:
1142 // \usepackage{vietnamese}
1143 // \usepackage{babel}
1144 // because vietnamese must be loaded before hyperref
1145 if (use_babel && !features.isRequired("jurabib")) {
1147 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1148 lyxpreamble += from_utf8(features.getBabelOptions());
1151 // When the language "japanese-plain" is used, the package "japanese" must
1152 // be loaded behind babel (it provides babel support for Japanese) but before
1154 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1155 if (language->lang() == "japanese-plain" &&
1156 !getTextClass().provides("japanese")) {
1157 //load babel in case it was not loaded due to an empty language list
1158 if (language_options.str().empty())
1159 lyxpreamble += "\\usepackage{babel}\n";
1160 lyxpreamble += "\\usepackage{japanese}\n";
1164 // * Hyperref manual: "Make sure it comes last of your loaded
1165 // packages, to give it a fighting chance of not being over-written,
1166 // since its job is to redefine many LATEX commands."
1167 // * Email from Heiko Oberdiek: "It is usually better to load babel
1168 // before hyperref. Then hyperref has a chance to detect babel.
1169 // * Has to be loaded before the "LyX specific LaTeX commands" to
1170 // avoid errors with algorithm floats.
1171 odocstringstream oss;
1172 // use hyperref explicitely when it is required
1173 pdfoptions().writeLaTeX(oss, features.isRequired("hyperref"));
1174 lyxpreamble += oss.str();
1176 // this might be useful...
1177 lyxpreamble += "\n\\makeatletter\n";
1179 // Some macros LyX will need
1180 docstring tmppreamble(from_ascii(features.getMacros()));
1182 if (!tmppreamble.empty()) {
1183 lyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1184 "LyX specific LaTeX commands.\n"
1185 + tmppreamble + '\n';
1188 // the text class specific preamble
1189 tmppreamble = features.getTClassPreamble();
1190 if (!tmppreamble.empty()) {
1191 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1192 "Textclass specific LaTeX commands.\n"
1193 + tmppreamble + '\n';
1196 /* the user-defined preamble */
1197 if (!preamble.empty()) {
1199 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1200 "User specified LaTeX commands.\n"
1201 + from_utf8(preamble) + '\n';
1204 // Itemize bullet settings need to be last in case the user
1205 // defines their own bullets that use a package included
1206 // in the user-defined preamble -- ARRae
1207 // Actually it has to be done much later than that
1208 // since some packages like frenchb make modifications
1209 // at \begin{document} time -- JMarc
1210 docstring bullets_def;
1211 for (int i = 0; i < 4; ++i) {
1212 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1213 if (bullets_def.empty())
1214 bullets_def += "\\AtBeginDocument{\n";
1215 bullets_def += " \\def\\labelitemi";
1217 // `i' is one less than the item to modify
1224 bullets_def += "ii";
1230 bullets_def += '{' +
1231 user_defined_bullet(i).getText()
1236 if (!bullets_def.empty())
1237 lyxpreamble += bullets_def + "}\n\n";
1239 lyxpreamble += "\\makeatother\n\n";
1242 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1243 for (int j = 0; j != nlines; ++j) {
1252 void BufferParams::useClassDefaults()
1254 TextClass const & tclass = textclasslist[baseClass_];
1256 sides = tclass.sides();
1257 columns = tclass.columns();
1258 pagestyle = tclass.pagestyle();
1259 options = tclass.options();
1260 // Only if class has a ToC hierarchy
1261 if (tclass.hasTocLevels()) {
1262 secnumdepth = tclass.secnumdepth();
1263 tocdepth = tclass.tocdepth();
1268 bool BufferParams::hasClassDefaults() const
1270 TextClass const & tclass = textclasslist[baseClass_];
1272 return (sides == tclass.sides()
1273 && columns == tclass.columns()
1274 && pagestyle == tclass.pagestyle()
1275 && options == tclass.options()
1276 && secnumdepth == tclass.secnumdepth()
1277 && tocdepth == tclass.tocdepth());
1281 TextClass const & BufferParams::getTextClass() const
1287 TextClassPtr BufferParams::getTextClassPtr() const {
1292 void BufferParams::setTextClass(TextClassPtr tc) {
1297 bool BufferParams::setBaseClass(textclass_type tc)
1300 if (textclasslist[tc].load())
1304 bformat(_("The document class %1$s could not be loaded."),
1305 from_utf8(textclasslist[tc].name()));
1306 frontend::Alert::error(_("Could not load class"), s);
1314 void BufferParams::setJustBaseClass(textclass_type tc)
1320 textclass_type BufferParams::getBaseClass() const
1326 void BufferParams::makeTextClass()
1328 textClass_.reset(new TextClass(textclasslist[getBaseClass()]));
1329 //FIXME It might be worth loading the children's modules here,
1330 //just as we load their bibliographies and such, instead of just
1331 //doing a check in InsetInclude.
1332 LayoutModuleList::const_iterator it = layoutModules_.begin();
1333 for (; it != layoutModules_.end(); it++) {
1334 string const modName = *it;
1335 LyXModule * lm = moduleList[modName];
1337 docstring const msg =
1338 bformat(_("The module %1$s has been requested by\n"
1339 "this document but has not been found in the list of\n"
1340 "available modules. If you recently installed it, you\n"
1341 "probalby need to reconfigure LyX.\n"), from_utf8(modName));
1342 frontend::Alert::warning(_("Module not available"),
1343 msg + _("Some layouts may not be available."));
1344 lyxerr << "BufferParams::makeTextClass(): Module " <<
1345 modName << " requested but not found in module list." <<
1349 FileName layout_file = libFileSearch("layouts", lm->filename);
1350 textClass_->read(layout_file, TextClass::MODULE);
1355 std::vector<string> const & BufferParams::getModules() const {
1356 return layoutModules_;
1361 bool BufferParams::addLayoutModule(string modName, bool makeClass) {
1362 LayoutModuleList::const_iterator it = layoutModules_.begin();
1363 LayoutModuleList::const_iterator end = layoutModules_.end();
1364 for (; it != end; it++) {
1368 if (it != layoutModules_.end())
1370 layoutModules_.push_back(modName);
1377 bool BufferParams::addLayoutModules(std::vector<string>modNames)
1380 std::vector<string>::const_iterator it = modNames.begin();
1381 std::vector<string>::const_iterator end = modNames.end();
1382 for (; it != end; ++it)
1383 retval &= addLayoutModule(*it, false);
1389 void BufferParams::clearLayoutModules() {
1390 layoutModules_.clear();
1395 Font const BufferParams::getFont() const
1397 FontInfo f = getTextClass().defaultfont();
1398 if (fontsDefaultFamily == "rmdefault")
1399 f.setFamily(ROMAN_FAMILY);
1400 else if (fontsDefaultFamily == "sfdefault")
1401 f.setFamily(SANS_FAMILY);
1402 else if (fontsDefaultFamily == "ttdefault")
1403 f.setFamily(TYPEWRITER_FAMILY);
1404 return Font(f, language);
1408 void BufferParams::readPreamble(Lexer & lex)
1410 if (lex.getString() != "\\begin_preamble")
1411 lyxerr << "Error (BufferParams::readPreamble):"
1412 "consistency check failed." << endl;
1414 preamble = lex.getLongString("\\end_preamble");
1418 void BufferParams::readLanguage(Lexer & lex)
1420 if (!lex.next()) return;
1422 string const tmptok = lex.getString();
1424 // check if tmptok is part of tex_babel in tex-defs.h
1425 language = languages.getLanguage(tmptok);
1427 // Language tmptok was not found
1428 language = default_language;
1429 lyxerr << "Warning: Setting language `"
1430 << tmptok << "' to `" << language->lang()
1436 void BufferParams::readGraphicsDriver(Lexer & lex)
1438 if (!lex.next()) return;
1440 string const tmptok = lex.getString();
1441 // check if tmptok is part of tex_graphics in tex_defs.h
1444 string const test = tex_graphics[n++];
1446 if (test == tmptok) {
1447 graphicsDriver = tmptok;
1449 } else if (test == "") {
1451 "Warning: graphics driver `$$Token' not recognized!\n"
1452 " Setting graphics driver to `default'.\n");
1453 graphicsDriver = "default";
1460 void BufferParams::readBullets(Lexer & lex)
1462 if (!lex.next()) return;
1464 int const index = lex.getInteger();
1466 int temp_int = lex.getInteger();
1467 user_defined_bullet(index).setFont(temp_int);
1468 temp_bullet(index).setFont(temp_int);
1470 user_defined_bullet(index).setCharacter(temp_int);
1471 temp_bullet(index).setCharacter(temp_int);
1473 user_defined_bullet(index).setSize(temp_int);
1474 temp_bullet(index).setSize(temp_int);
1478 void BufferParams::readBulletsLaTeX(Lexer & lex)
1480 // The bullet class should be able to read this.
1481 if (!lex.next()) return;
1482 int const index = lex.getInteger();
1484 docstring const temp_str = lex.getDocString();
1486 user_defined_bullet(index).setText(temp_str);
1487 temp_bullet(index).setText(temp_str);
1491 void BufferParams::readModules(Lexer & lex)
1493 if (!lex.eatLine()) {
1494 lyxerr << "Error (BufferParams::readModules):"
1495 "Unexpected end of input." << endl;
1499 string mod = lex.getString();
1500 if (mod == "\\end_modules")
1502 addLayoutModule(mod);
1508 string const BufferParams::paperSizeName() const
1510 char real_papersize = papersize;
1511 if (real_papersize == PAPER_DEFAULT)
1512 real_papersize = lyxrc.default_papersize;
1514 switch (real_papersize) {
1523 case PAPER_USEXECUTIVE:
1527 case PAPER_USLETTER:
1534 string const BufferParams::dvips_options() const
1539 && papersize == PAPER_CUSTOM
1540 && !lyxrc.print_paper_dimension_flag.empty()
1541 && !paperwidth.empty()
1542 && !paperheight.empty()) {
1543 // using a custom papersize
1544 result = lyxrc.print_paper_dimension_flag;
1545 result += ' ' + paperwidth;
1546 result += ',' + paperheight;
1548 string const paper_option = paperSizeName();
1549 if (paper_option != "letter" ||
1550 orientation != ORIENTATION_LANDSCAPE) {
1551 // dvips won't accept -t letter -t landscape.
1552 // In all other cases, include the paper size
1554 result = lyxrc.print_paper_flag;
1555 result += ' ' + paper_option;
1558 if (orientation == ORIENTATION_LANDSCAPE &&
1559 papersize != PAPER_CUSTOM)
1560 result += ' ' + lyxrc.print_landscape_flag;
1565 string const BufferParams::babelCall(string const & lang_opts) const
1567 string lang_pack = lyxrc.language_package;
1568 if (lang_pack != "\\usepackage{babel}")
1570 // suppress the babel call when there is no babel language defined
1571 // for the document language in the lib/languages file and if no
1572 // other languages are used (lang_opts is then empty)
1573 if (lang_opts.empty())
1575 // when Vietnamese is used, babel must directly be loaded with the
1576 // language options, see
1577 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1578 size_t viet = lang_opts.find("vietnam");
1579 // viet = string::npos when not found
1580 if (!lyxrc.language_global_options || viet != string::npos)
1581 return "\\usepackage[" + lang_opts + "]{babel}";
1586 void BufferParams::writeEncodingPreamble(odocstream & os,
1587 LaTeXFeatures & features, TexRow & texrow) const
1589 if (inputenc == "auto") {
1590 string const doc_encoding =
1591 language->encoding()->latexName();
1592 Encoding::Package const package =
1593 language->encoding()->package();
1595 // Create a list with all the input encodings used
1597 std::set<string> encodings =
1598 features.getEncodingSet(doc_encoding);
1600 // When the encodings EUC-JP-plain, JIS-plain, or SJIS-plainare used, the
1601 // package inputenc must be omitted. Therefore set the encoding to empty.
1602 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1603 if (doc_encoding == "EUC-JP-plain" || doc_encoding == "JIS-plain" ||
1604 doc_encoding == "SJIS-plain")
1607 if (!encodings.empty() || package == Encoding::inputenc) {
1608 os << "\\usepackage[";
1609 std::set<string>::const_iterator it = encodings.begin();
1610 std::set<string>::const_iterator const end = encodings.end();
1612 os << from_ascii(*it);
1615 for (; it != end; ++it)
1616 os << ',' << from_ascii(*it);
1617 if (package == Encoding::inputenc) {
1618 if (!encodings.empty())
1620 os << from_ascii(doc_encoding);
1622 os << "]{inputenc}\n";
1625 if (package == Encoding::CJK) {
1626 os << "\\usepackage{CJK}\n";
1629 } else if (inputenc != "default") {
1630 switch (encoding().package()) {
1631 case Encoding::none:
1633 case Encoding::inputenc:
1634 os << "\\usepackage[" << from_ascii(inputenc)
1639 os << "\\usepackage{CJK}\n";
1645 // The encoding "armscii8" is only available when the package "armtex" is loaded.
1646 // armscii8 is used for Armenian.
1647 if (language->encoding()->latexName() == "armscii8" || inputenc == "armscii8") {
1648 os << "\\usepackage{armtex}\n";
1654 string const BufferParams::loadFonts(string const & rm,
1655 string const & sf, string const & tt,
1656 bool const & sc, bool const & osf,
1657 int const & sfscale, int const & ttscale) const
1659 /* The LaTeX font world is in a flux. In the PSNFSS font interface,
1660 several packages have been replaced by others, that might not
1661 be installed on every system. We have to take care for that
1662 (see psnfss.pdf). We try to support all psnfss fonts as well
1663 as the fonts that have become de facto standard in the LaTeX
1664 world (e.g. Latin Modern). We do not support obsolete fonts
1665 (like PSLatex). In general, it should be possible to mix any
1666 rm font with any sf or tt font, respectively. (JSpitzm)
1668 -- separate math fonts.
1671 if (rm == "default" && sf == "default" && tt == "default")
1678 // Computer Modern (must be explicitely selectable -- there might be classes
1679 // that define a different default font!
1681 os << "\\renewcommand{\\rmdefault}{cmr}\n";
1682 // osf for Computer Modern needs eco.sty
1684 os << "\\usepackage{eco}\n";
1686 // Latin Modern Roman
1687 else if (rm == "lmodern")
1688 os << "\\usepackage{lmodern}\n";
1690 else if (rm == "ae") {
1691 // not needed when using OT1 font encoding.
1692 if (lyxrc.fontenc != "default")
1693 os << "\\usepackage{ae,aecompl}\n";
1696 else if (rm == "times") {
1697 // try to load the best available package
1698 if (LaTeXFeatures::isAvailable("mathptmx"))
1699 os << "\\usepackage{mathptmx}\n";
1700 else if (LaTeXFeatures::isAvailable("mathptm"))
1701 os << "\\usepackage{mathptm}\n";
1703 os << "\\usepackage{times}\n";
1706 else if (rm == "palatino") {
1707 // try to load the best available package
1708 if (LaTeXFeatures::isAvailable("mathpazo")) {
1709 os << "\\usepackage";
1715 // "osf" includes "sc"!
1719 os << "{mathpazo}\n";
1721 else if (LaTeXFeatures::isAvailable("mathpple"))
1722 os << "\\usepackage{mathpple}\n";
1724 os << "\\usepackage{palatino}\n";
1727 else if (rm == "utopia") {
1728 // fourier supersedes utopia.sty, but does
1729 // not work with OT1 encoding.
1730 if (LaTeXFeatures::isAvailable("fourier")
1731 && lyxrc.fontenc != "default") {
1732 os << "\\usepackage";
1743 os << "{fourier}\n";
1746 os << "\\usepackage{utopia}\n";
1748 // Bera (complete fontset)
1749 else if (rm == "bera" && sf == "default" && tt == "default")
1750 os << "\\usepackage{bera}\n";
1752 else if (rm != "default")
1753 os << "\\usepackage" << "{" << rm << "}\n";
1756 // Helvetica, Bera Sans
1757 if (sf == "helvet" || sf == "berasans") {
1759 os << "\\usepackage[scaled=" << float(sfscale) / 100
1760 << "]{" << sf << "}\n";
1762 os << "\\usepackage{" << sf << "}\n";
1765 else if (sf == "avant")
1766 os << "\\usepackage{" << sf << "}\n";
1767 // Computer Modern, Latin Modern, CM Bright
1768 else if (sf != "default")
1769 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
1771 // monospaced/typewriter
1772 // Courier, LuxiMono
1773 if (tt == "luximono" || tt == "beramono") {
1775 os << "\\usepackage[scaled=" << float(ttscale) / 100
1776 << "]{" << tt << "}\n";
1778 os << "\\usepackage{" << tt << "}\n";
1781 else if (tt == "courier" )
1782 os << "\\usepackage{" << tt << "}\n";
1783 // Computer Modern, Latin Modern, CM Bright
1784 else if (tt != "default")
1785 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
1791 Encoding const & BufferParams::encoding() const
1793 if (inputenc == "auto" || inputenc == "default")
1794 return *(language->encoding());
1795 Encoding const * const enc =
1796 encodings.getFromLaTeXName(inputenc);
1799 lyxerr << "Unknown inputenc value `" << inputenc
1800 << "'. Using `auto' instead." << endl;
1801 return *(language->encoding());
1805 biblio::CiteEngine BufferParams::getEngine() const
1807 // FIXME the class should provide the numerical/
1808 // authoryear choice
1809 if (getTextClass().provides("natbib")
1810 && cite_engine_ != biblio::ENGINE_NATBIB_NUMERICAL)
1811 return biblio::ENGINE_NATBIB_AUTHORYEAR;
1812 return cite_engine_;
1816 void BufferParams::setCiteEngine(biblio::CiteEngine const cite_engine)
1818 cite_engine_ = cite_engine;