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/FileName.h"
48 #include "support/filetools.h"
49 #include "support/Translator.h"
50 #include "support/lstrings.h"
59 using std::istringstream;
61 using std::ostringstream;
64 using lyx::support::FileName;
65 using lyx::support::libFileSearch;
66 using lyx::support::bformat;
67 using lyx::support::rtrim;
68 using lyx::support::tokenPos;
69 using lyx::support::prefixIs;
72 static char const * const string_paragraph_separation[] = {
77 static char const * const string_quotes_language[] = {
78 "english", "swedish", "german", "polish", "french", "danish", ""
82 static char const * const string_papersize[] = {
83 "default", "custom", "letterpaper", "executivepaper", "legalpaper",
84 "a3paper", "a4paper", "a5paper", "b3paper", "b4paper", "b5paper", ""
88 static char const * const string_orientation[] = {
89 "portrait", "landscape", ""
93 static char const * const string_footnotekinds[] = {
94 "footnote", "margin", "fig", "tab", "alg", "wide-fig", "wide-tab", ""
98 static char const * const tex_graphics[] = {
99 "default", "dvips", "dvitops", "emtex",
100 "ln", "oztex", "textures", "none", ""
109 // Paragraph separation
110 typedef Translator<string, BufferParams::PARSEP> ParSepTranslator;
113 ParSepTranslator const init_parseptranslator()
115 ParSepTranslator translator(string_paragraph_separation[0], BufferParams::PARSEP_INDENT);
116 translator.addPair(string_paragraph_separation[1], BufferParams::PARSEP_SKIP);
121 ParSepTranslator const & parseptranslator()
123 static ParSepTranslator translator = init_parseptranslator();
129 typedef Translator<string, InsetQuotes::quote_language> QuotesLangTranslator;
132 QuotesLangTranslator const init_quoteslangtranslator()
134 QuotesLangTranslator translator(string_quotes_language[0], InsetQuotes::EnglishQ);
135 translator.addPair(string_quotes_language[1], InsetQuotes::SwedishQ);
136 translator.addPair(string_quotes_language[2], InsetQuotes::GermanQ);
137 translator.addPair(string_quotes_language[3], InsetQuotes::PolishQ);
138 translator.addPair(string_quotes_language[4], InsetQuotes::FrenchQ);
139 translator.addPair(string_quotes_language[5], InsetQuotes::DanishQ);
144 QuotesLangTranslator const & quoteslangtranslator()
146 static QuotesLangTranslator translator = init_quoteslangtranslator();
152 typedef Translator<std::string, PAPER_SIZE> PaperSizeTranslator;
155 PaperSizeTranslator const init_papersizetranslator()
157 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
158 translator.addPair(string_papersize[1], PAPER_CUSTOM);
159 translator.addPair(string_papersize[2], PAPER_USLETTER);
160 translator.addPair(string_papersize[3], PAPER_USLEGAL);
161 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
162 translator.addPair(string_papersize[5], PAPER_A3);
163 translator.addPair(string_papersize[6], PAPER_A4);
164 translator.addPair(string_papersize[7], PAPER_A5);
165 translator.addPair(string_papersize[8], PAPER_B3);
166 translator.addPair(string_papersize[9], PAPER_B4);
167 translator.addPair(string_papersize[10], PAPER_B5);
172 PaperSizeTranslator const & papersizetranslator()
174 static PaperSizeTranslator translator = init_papersizetranslator();
180 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
183 PaperOrientationTranslator const init_paperorientationtranslator()
185 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
186 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
191 PaperOrientationTranslator const & paperorientationtranslator()
193 static PaperOrientationTranslator translator = init_paperorientationtranslator();
199 typedef Translator<int, PageSides> SidesTranslator;
202 SidesTranslator const init_sidestranslator()
204 SidesTranslator translator(1, OneSide);
205 translator.addPair(2, TwoSides);
210 SidesTranslator const & sidestranslator()
212 static SidesTranslator translator = init_sidestranslator();
218 typedef Translator<int, BufferParams::Package> PackageTranslator;
221 PackageTranslator const init_packagetranslator()
223 PackageTranslator translator(0, BufferParams::package_off);
224 translator.addPair(1, BufferParams::package_auto);
225 translator.addPair(2, BufferParams::package_on);
230 PackageTranslator const & packagetranslator()
232 static PackageTranslator translator = init_packagetranslator();
238 typedef Translator<string, biblio::CiteEngine> CiteEngineTranslator;
241 CiteEngineTranslator const init_citeenginetranslator()
243 CiteEngineTranslator translator("basic", biblio::ENGINE_BASIC);
244 translator.addPair("natbib_numerical", biblio::ENGINE_NATBIB_NUMERICAL);
245 translator.addPair("natbib_authoryear", biblio::ENGINE_NATBIB_AUTHORYEAR);
246 translator.addPair("jurabib", biblio::ENGINE_JURABIB);
251 CiteEngineTranslator const & citeenginetranslator()
253 static CiteEngineTranslator translator = init_citeenginetranslator();
259 typedef Translator<string, Spacing::Space> SpaceTranslator;
262 SpaceTranslator const init_spacetranslator()
264 SpaceTranslator translator("default", Spacing::Default);
265 translator.addPair("single", Spacing::Single);
266 translator.addPair("onehalf", Spacing::Onehalf);
267 translator.addPair("double", Spacing::Double);
268 translator.addPair("other", Spacing::Other);
273 SpaceTranslator const & spacetranslator()
275 static SpaceTranslator translator = init_spacetranslator();
283 class BufferParams::Impl
288 AuthorList authorlist;
289 BranchList branchlist;
290 Bullet temp_bullets[4];
291 Bullet user_defined_bullets[4];
293 /** This is the amount of space used for paragraph_separation "skip",
294 * and for detached paragraphs in "indented" documents.
297 PDFOptions pdfoptions;
301 BufferParams::Impl::Impl()
302 : defskip(VSpace::MEDSKIP)
304 // set initial author
306 authorlist.record(Author(from_utf8(lyxrc.user_name), from_utf8(lyxrc.user_email)));
311 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
315 return new BufferParams::Impl(*ptr);
319 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
325 BufferParams::BufferParams()
328 setBaseClass(defaultTextclass());
329 paragraph_separation = PARSEP_INDENT;
330 quotes_language = InsetQuotes::EnglishQ;
331 fontsize = "default";
334 papersize = PAPER_DEFAULT;
335 orientation = ORIENTATION_PORTRAIT;
336 use_geometry = false;
337 use_amsmath = package_auto;
338 use_esint = package_auto;
339 cite_engine_ = biblio::ENGINE_BASIC;
340 use_bibtopic = false;
341 trackChanges = false;
342 outputChanges = false;
345 language = default_language;
346 fontsRoman = "default";
347 fontsSans = "default";
348 fontsTypewriter = "default";
349 fontsDefaultFamily = "default";
352 fontsSansScale = 100;
353 fontsTypewriterScale = 100;
355 graphicsDriver = "default";
358 listings_params = string();
359 pagestyle = "default";
362 for (int iter = 0; iter < 4; ++iter) {
363 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
364 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
369 BufferParams::~BufferParams()
373 docstring const BufferParams::B_(string const & l10n) const
375 BOOST_ASSERT(language);
376 return getMessages(language->code()).get(l10n);
380 AuthorList & BufferParams::authors()
382 return pimpl_->authorlist;
386 AuthorList const & BufferParams::authors() const
388 return pimpl_->authorlist;
392 BranchList & BufferParams::branchlist()
394 return pimpl_->branchlist;
398 BranchList const & BufferParams::branchlist() const
400 return pimpl_->branchlist;
404 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
406 BOOST_ASSERT(index < 4);
407 return pimpl_->temp_bullets[index];
411 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
413 BOOST_ASSERT(index < 4);
414 return pimpl_->temp_bullets[index];
418 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
420 BOOST_ASSERT(index < 4);
421 return pimpl_->user_defined_bullets[index];
425 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
427 BOOST_ASSERT(index < 4);
428 return pimpl_->user_defined_bullets[index];
432 Spacing & BufferParams::spacing()
434 return pimpl_->spacing;
438 Spacing const & BufferParams::spacing() const
440 return pimpl_->spacing;
444 PDFOptions & BufferParams::pdfoptions()
446 return pimpl_->pdfoptions;
450 PDFOptions const & BufferParams::pdfoptions() const
452 return pimpl_->pdfoptions;
456 VSpace const & BufferParams::getDefSkip() const
458 return pimpl_->defskip;
462 void BufferParams::setDefSkip(VSpace const & vs)
464 pimpl_->defskip = vs;
468 string const BufferParams::readToken(Lexer & lex, string const & token,
469 FileName const & filepath)
471 if (token == "\\textclass") {
473 string const classname = lex.getString();
474 // if there exists a local layout file, ignore the system one
475 // NOTE: in this case, the textclass (.cls file) is assumed to be available.
476 pair<bool, lyx::textclass_type> pp = textclasslist.addTextClass(
477 classname, filepath.absFilename());
479 setBaseClass(pp.second);
481 pp = textclasslist.numberOfClass(classname);
483 setBaseClass(pp.second);
485 // a warning will be given for unknown class
486 setBaseClass(defaultTextclass());
490 // FIXME: this warning will be given even if there exists a local .cls
491 // file. Even worse, the .lyx file can not be compiled or exported
492 // because the textclass is marked as unavilable.
493 if (!getTextClass().isTeXClassAvailable()) {
494 docstring const msg =
495 bformat(_("The layout file requested by this document,\n"
497 "is not usable. This is probably because a LaTeX\n"
498 "class or style file required by it is not\n"
499 "available. See the Customization documentation\n"
500 "for more information.\n"), from_utf8(classname));
501 frontend::Alert::warning(_("Document class not available"),
502 msg + _("LyX will not be able to produce output."));
505 } else if (token == "\\begin_preamble") {
507 } else if (token == "\\begin_modules") {
510 } else if (token == "\\options") {
512 options = lex.getString();
513 } else if (token == "\\language") {
515 } else if (token == "\\inputencoding") {
517 } else if (token == "\\graphics") {
518 readGraphicsDriver(lex);
519 } else if (token == "\\font_roman") {
521 } else if (token == "\\font_sans") {
523 } else if (token == "\\font_typewriter") {
524 lex >> fontsTypewriter;
525 } else if (token == "\\font_default_family") {
526 lex >> fontsDefaultFamily;
527 } else if (token == "\\font_sc") {
529 } else if (token == "\\font_osf") {
531 } else if (token == "\\font_sf_scale") {
532 lex >> fontsSansScale;
533 } else if (token == "\\font_tt_scale") {
534 lex >> fontsTypewriterScale;
535 } else if (token == "\\paragraph_separation") {
538 paragraph_separation = parseptranslator().find(parsep);
539 } else if (token == "\\defskip") {
541 pimpl_->defskip = VSpace(lex.getString());
542 } else if (token == "\\quotes_language") {
545 quotes_language = quoteslangtranslator().find(quotes_lang);
546 } else if (token == "\\papersize") {
549 papersize = papersizetranslator().find(ppsize);
550 } else if (token == "\\use_geometry") {
552 } else if (token == "\\use_amsmath") {
555 use_amsmath = packagetranslator().find(use_ams);
556 } else if (token == "\\use_esint") {
559 use_esint = packagetranslator().find(useesint);
560 } else if (token == "\\cite_engine") {
563 cite_engine_ = citeenginetranslator().find(engine);
564 } else if (token == "\\use_bibtopic") {
566 } else if (token == "\\tracking_changes") {
568 } else if (token == "\\output_changes") {
569 lex >> outputChanges;
570 } else if (token == "\\branch") {
572 docstring branch = lex.getDocString();
573 branchlist().add(branch);
576 string const tok = lex.getString();
577 if (tok == "\\end_branch")
579 Branch * branch_ptr = branchlist().find(branch);
580 if (tok == "\\selected") {
583 branch_ptr->setSelected(lex.getInteger());
585 // not yet operational
586 if (tok == "\\color") {
588 string color = lex.getString();
590 branch_ptr->setColor(color);
591 // Update also the Color table:
593 color = lcolor.getX11Name(Color_background);
595 lcolor.setColor(to_utf8(branch), color);
599 } else if (token == "\\author") {
601 istringstream ss(lex.getString());
604 author_map.push_back(pimpl_->authorlist.record(a));
605 } else if (token == "\\paperorientation") {
608 orientation = paperorientationtranslator().find(orient);
609 } else if (token == "\\paperwidth") {
611 } else if (token == "\\paperheight") {
613 } else if (token == "\\leftmargin") {
615 } else if (token == "\\topmargin") {
617 } else if (token == "\\rightmargin") {
619 } else if (token == "\\bottommargin") {
621 } else if (token == "\\headheight") {
623 } else if (token == "\\headsep") {
625 } else if (token == "\\footskip") {
627 } else if (token == "\\paperfontsize") {
629 } else if (token == "\\papercolumns") {
631 } else if (token == "\\listings_params") {
634 listings_params = InsetListingsParams(par).params();
635 } else if (token == "\\papersides") {
638 sides = sidestranslator().find(psides);
639 } else if (token == "\\paperpagestyle") {
641 } else if (token == "\\bullet") {
643 } else if (token == "\\bulletLaTeX") {
644 readBulletsLaTeX(lex);
645 } else if (token == "\\secnumdepth") {
647 } else if (token == "\\tocdepth") {
649 } else if (token == "\\spacing") {
653 if (nspacing == "other") {
656 spacing().set(spacetranslator().find(nspacing), tmp_val);
657 } else if (token == "\\float_placement") {
658 lex >> float_placement;
660 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
661 string toktmp = pdfoptions().readToken(lex, token);
662 if (!toktmp.empty()) {
663 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
668 lyxerr << "BufferParams::readToken(): Unknown token: " <<
677 void BufferParams::writeFile(ostream & os) const
679 // The top of the file is written by the buffer.
680 // Prints out the buffer info into the .lyx file given by file
683 os << "\\textclass " << textclasslist[baseClass_].name() << '\n';
686 if (!preamble.empty()) {
687 // remove '\n' from the end of preamble
688 string const tmppreamble = rtrim(preamble, "\n");
689 os << "\\begin_preamble\n"
691 << "\n\\end_preamble\n";
695 if (!options.empty()) {
696 os << "\\options " << options << '\n';
700 if (!layoutModules_.empty()) {
701 os << "\\begin_modules" << '\n';
702 LayoutModuleList::const_iterator it = layoutModules_.begin();
703 for (; it != layoutModules_.end(); it++)
705 os << "\\end_modules" << '\n';
708 // then the text parameters
709 if (language != ignore_language)
710 os << "\\language " << language->lang() << '\n';
711 os << "\\inputencoding " << inputenc
712 << "\n\\font_roman " << fontsRoman
713 << "\n\\font_sans " << fontsSans
714 << "\n\\font_typewriter " << fontsTypewriter
715 << "\n\\font_default_family " << fontsDefaultFamily
716 << "\n\\font_sc " << convert<string>(fontsSC)
717 << "\n\\font_osf " << convert<string>(fontsOSF)
718 << "\n\\font_sf_scale " << fontsSansScale
719 << "\n\\font_tt_scale " << fontsTypewriterScale
720 << "\n\\graphics " << graphicsDriver << '\n';
722 if (!float_placement.empty()) {
723 os << "\\float_placement " << float_placement << '\n';
725 os << "\\paperfontsize " << fontsize << '\n';
727 spacing().writeFile(os);
728 pdfoptions().writeFile(os);
730 os << "\\papersize " << string_papersize[papersize]
731 << "\n\\use_geometry " << convert<string>(use_geometry)
732 << "\n\\use_amsmath " << use_amsmath
733 << "\n\\use_esint " << use_esint
734 << "\n\\cite_engine " << citeenginetranslator().find(cite_engine_)
735 << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
736 << "\n\\paperorientation " << string_orientation[orientation]
739 BranchList::const_iterator it = branchlist().begin();
740 BranchList::const_iterator end = branchlist().end();
741 for (; it != end; ++it) {
742 os << "\\branch " << to_utf8(it->getBranch())
743 << "\n\\selected " << it->getSelected()
744 << "\n\\color " << lyx::X11hexname(it->getColor())
749 if (!paperwidth.empty())
750 os << "\\paperwidth "
751 << VSpace(paperwidth).asLyXCommand() << '\n';
752 if (!paperheight.empty())
753 os << "\\paperheight "
754 << VSpace(paperheight).asLyXCommand() << '\n';
755 if (!leftmargin.empty())
756 os << "\\leftmargin "
757 << VSpace(leftmargin).asLyXCommand() << '\n';
758 if (!topmargin.empty())
760 << VSpace(topmargin).asLyXCommand() << '\n';
761 if (!rightmargin.empty())
762 os << "\\rightmargin "
763 << VSpace(rightmargin).asLyXCommand() << '\n';
764 if (!bottommargin.empty())
765 os << "\\bottommargin "
766 << VSpace(bottommargin).asLyXCommand() << '\n';
767 if (!headheight.empty())
768 os << "\\headheight "
769 << VSpace(headheight).asLyXCommand() << '\n';
770 if (!headsep.empty())
772 << VSpace(headsep).asLyXCommand() << '\n';
773 if (!footskip.empty())
775 << VSpace(footskip).asLyXCommand() << '\n';
776 os << "\\secnumdepth " << secnumdepth
777 << "\n\\tocdepth " << tocdepth
778 << "\n\\paragraph_separation "
779 << string_paragraph_separation[paragraph_separation]
780 << "\n\\defskip " << getDefSkip().asLyXCommand()
781 << "\n\\quotes_language "
782 << string_quotes_language[quotes_language]
783 << "\n\\papercolumns " << columns
784 << "\n\\papersides " << sides
785 << "\n\\paperpagestyle " << pagestyle << '\n';
786 if (!listings_params.empty())
787 os << "\\listings_params \"" <<
788 InsetListingsParams(listings_params).encodedString() << "\"\n";
789 for (int i = 0; i < 4; ++i) {
790 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
791 if (user_defined_bullet(i).getFont() != -1) {
792 os << "\\bullet " << i << " "
793 << user_defined_bullet(i).getFont() << " "
794 << user_defined_bullet(i).getCharacter() << " "
795 << user_defined_bullet(i).getSize() << "\n";
799 os << "\\bulletLaTeX " << i << " \""
800 << lyx::to_ascii(user_defined_bullet(i).getText())
806 os << "\\tracking_changes " << convert<string>(trackChanges) << "\n";
807 os << "\\output_changes " << convert<string>(outputChanges) << "\n";
809 AuthorList::Authors::const_iterator a_it = pimpl_->authorlist.begin();
810 AuthorList::Authors::const_iterator a_end = pimpl_->authorlist.end();
811 for (; a_it != a_end; ++a_it) {
812 if (a_it->second.used())
813 os << "\\author " << a_it->second << "\n";
815 os << "\\author " << Author() << "\n";
820 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
821 TexRow & texrow) const
823 os << "\\documentclass";
825 TextClass const & tclass = getTextClass();
827 ostringstream clsoptions; // the document class options.
829 if (tokenPos(tclass.opt_fontsize(),
830 '|', fontsize) >= 0) {
831 // only write if existing in list (and not default)
832 clsoptions << fontsize << "pt,";
835 // custom, A3, B3 and B4 paper sizes need geometry
836 bool nonstandard_papersize = papersize == PAPER_B3
837 || papersize == PAPER_B4
838 || papersize == PAPER_A3
839 || papersize == PAPER_CUSTOM;
844 clsoptions << "a4paper,";
847 clsoptions << "letterpaper,";
850 clsoptions << "a5paper,";
853 clsoptions << "b5paper,";
855 case PAPER_USEXECUTIVE:
856 clsoptions << "executivepaper,";
859 clsoptions << "legalpaper,";
871 if (sides != tclass.sides()) {
874 clsoptions << "oneside,";
877 clsoptions << "twoside,";
883 if (columns != tclass.columns()) {
885 clsoptions << "twocolumn,";
887 clsoptions << "onecolumn,";
891 && orientation == ORIENTATION_LANDSCAPE)
892 clsoptions << "landscape,";
894 // language should be a parameter to \documentclass
895 if (language->babel() == "hebrew"
896 && default_language->babel() != "hebrew")
897 // This seems necessary
898 features.useLanguage(default_language);
900 ostringstream language_options;
901 bool const use_babel = features.useBabel();
903 language_options << features.getLanguages();
904 if (!language->babel().empty()) {
905 if (!language_options.str().empty())
906 language_options << ',';
907 language_options << language->babel();
909 // when Vietnamese is used, babel must directly be loaded with the
910 // language options, not in the class options, see
911 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
912 size_t viet = language_options.str().find("vietnam");
913 // viet = string::npos when not found
914 if (lyxrc.language_global_options && !language_options.str().empty()
915 && viet == string::npos)
916 clsoptions << language_options.str() << ',';
919 // the user-defined options
920 if (!options.empty()) {
921 clsoptions << options << ',';
924 string strOptions(clsoptions.str());
925 if (!strOptions.empty()) {
926 strOptions = rtrim(strOptions, ",");
928 os << '[' << from_utf8(strOptions) << ']';
931 os << '{' << from_ascii(tclass.latexname()) << "}\n";
933 // end of \documentclass defs
935 // font selection must be done before loading fontenc.sty
937 loadFonts(fontsRoman, fontsSans,
938 fontsTypewriter, fontsSC, fontsOSF,
939 fontsSansScale, fontsTypewriterScale);
940 if (!fonts.empty()) {
941 os << from_ascii(fonts);
944 if (fontsDefaultFamily != "default")
945 os << "\\renewcommand{\\familydefault}{\\"
946 << from_ascii(fontsDefaultFamily) << "}\n";
949 // this one is not per buffer
950 // for arabic_arabi and farsi we also need to load the LAE and LFE encoding
951 if (lyxrc.fontenc != "default") {
952 if (language->lang() == "arabic_arabi" || language->lang() == "farsi") {
953 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
954 << ",LFE,LAE]{fontenc}\n";
957 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
963 // handle inputenc etc.
964 writeEncodingPreamble(os, features, texrow);
966 if (!listings_params.empty()) {
967 os << "\\usepackage{listings}\n";
970 // do not test validity because listings_params is supposed to be valid
971 string par = InsetListingsParams(listings_params).separatedParams(true);
972 os << from_ascii(par);
973 // count the number of newlines
974 for (size_t i = 0; i < par.size(); ++i)
980 if (use_geometry || nonstandard_papersize) {
981 os << "\\usepackage{geometry}\n";
983 os << "\\geometry{verbose";
984 if (orientation == ORIENTATION_LANDSCAPE)
988 if (!paperwidth.empty())
990 << from_ascii(paperwidth);
991 if (!paperheight.empty())
992 os << ",paperheight="
993 << from_ascii(paperheight);
996 os << ",letterpaper";
1001 case PAPER_USEXECUTIVE:
1002 os << ",executivepaper";
1023 // default papersize ie PAPER_DEFAULT
1024 switch (lyxrc.default_papersize) {
1025 case PAPER_DEFAULT: // keep compiler happy
1026 case PAPER_USLETTER:
1027 os << ",letterpaper";
1030 os << ",legalpaper";
1032 case PAPER_USEXECUTIVE:
1033 os << ",executivepaper";
1053 if (!topmargin.empty())
1054 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1055 if (!bottommargin.empty())
1056 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1057 if (!leftmargin.empty())
1058 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1059 if (!rightmargin.empty())
1060 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1061 if (!headheight.empty())
1062 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1063 if (!headsep.empty())
1064 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1065 if (!footskip.empty())
1066 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1071 if (tokenPos(tclass.opt_pagestyle(),
1072 '|', pagestyle) >= 0) {
1073 if (pagestyle == "fancy") {
1074 os << "\\usepackage{fancyhdr}\n";
1077 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1081 // Only if class has a ToC hierarchy
1082 if (tclass.hasTocLevels()) {
1083 if (secnumdepth != tclass.secnumdepth()) {
1084 os << "\\setcounter{secnumdepth}{"
1089 if (tocdepth != tclass.tocdepth()) {
1090 os << "\\setcounter{tocdepth}{"
1097 if (paragraph_separation) {
1098 switch (getDefSkip().kind()) {
1099 case VSpace::SMALLSKIP:
1100 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1102 case VSpace::MEDSKIP:
1103 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1105 case VSpace::BIGSKIP:
1106 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1108 case VSpace::LENGTH:
1109 os << "\\setlength{\\parskip}{"
1110 << from_utf8(getDefSkip().length().asLatexString())
1113 default: // should never happen // Then delete it.
1114 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1119 os << "\\setlength{\\parindent}{0pt}\n";
1123 // If we use jurabib, we have to call babel here.
1124 if (use_babel && features.isRequired("jurabib")) {
1125 os << from_ascii(babelCall(language_options.str()))
1127 << from_ascii(features.getBabelOptions());
1131 // Now insert the LyX specific LaTeX commands...
1133 // The optional packages;
1134 docstring lyxpreamble(from_ascii(features.getPackages()));
1136 // We try to load babel late, in case it interferes
1137 // with other packages. But some packages also need babel to be loaded
1138 // before, e.g. jurabib has to be called after babel.
1139 // So load babel after the optional packages but before the user-defined
1140 // preamble. This allows the users to redefine babel commands, e.g. to
1141 // translate the word "Index" to the German "Stichwortverzeichnis".
1142 // For more infos why this place was chosen, see
1143 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg128425.html
1144 // If you encounter problems, you can shift babel to its old place behind
1145 // the user-defined preamble. But in this case you must change the Vietnamese
1146 // support from currently "\usepackage[vietnamese]{babel}" to:
1147 // \usepackage{vietnamese}
1148 // \usepackage{babel}
1149 // because vietnamese must be loaded before hyperref
1150 if (use_babel && !features.isRequired("jurabib")) {
1152 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1153 lyxpreamble += from_utf8(features.getBabelOptions());
1156 // When the language "japanese-plain" is used, the package "japanese" must
1157 // be loaded behind babel (it provides babel support for Japanese) but before
1159 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1160 if (language->lang() == "japanese-plain" &&
1161 !getTextClass().provides("japanese")) {
1162 //load babel in case it was not loaded due to an empty language list
1163 if (language_options.str().empty())
1164 lyxpreamble += "\\usepackage{babel}\n";
1165 lyxpreamble += "\\usepackage{japanese}\n";
1169 // * Hyperref manual: "Make sure it comes last of your loaded
1170 // packages, to give it a fighting chance of not being over-written,
1171 // since its job is to redefine many LATEX commands."
1172 // * Email from Heiko Oberdiek: "It is usually better to load babel
1173 // before hyperref. Then hyperref has a chance to detect babel.
1174 // * Has to be loaded before the "LyX specific LaTeX commands" to
1175 // avoid errors with algorithm floats.
1176 odocstringstream oss;
1177 // use hyperref explicitely when it is required
1178 pdfoptions().writeLaTeX(oss, features.isRequired("hyperref"));
1179 lyxpreamble += oss.str();
1181 // this might be useful...
1182 lyxpreamble += "\n\\makeatletter\n";
1184 // Some macros LyX will need
1185 docstring tmppreamble(from_ascii(features.getMacros()));
1187 if (!tmppreamble.empty()) {
1188 lyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1189 "LyX specific LaTeX commands.\n"
1190 + tmppreamble + '\n';
1193 // the text class specific preamble
1194 tmppreamble = features.getTClassPreamble();
1195 if (!tmppreamble.empty()) {
1196 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1197 "Textclass specific LaTeX commands.\n"
1198 + tmppreamble + '\n';
1201 /* the user-defined preamble */
1202 if (!preamble.empty()) {
1204 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1205 "User specified LaTeX commands.\n"
1206 + from_utf8(preamble) + '\n';
1209 // Itemize bullet settings need to be last in case the user
1210 // defines their own bullets that use a package included
1211 // in the user-defined preamble -- ARRae
1212 // Actually it has to be done much later than that
1213 // since some packages like frenchb make modifications
1214 // at \begin{document} time -- JMarc
1215 docstring bullets_def;
1216 for (int i = 0; i < 4; ++i) {
1217 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1218 if (bullets_def.empty())
1219 bullets_def += "\\AtBeginDocument{\n";
1220 bullets_def += " \\def\\labelitemi";
1222 // `i' is one less than the item to modify
1229 bullets_def += "ii";
1235 bullets_def += '{' +
1236 user_defined_bullet(i).getText()
1241 if (!bullets_def.empty())
1242 lyxpreamble += bullets_def + "}\n\n";
1244 lyxpreamble += "\\makeatother\n\n";
1247 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1248 for (int j = 0; j != nlines; ++j) {
1257 void BufferParams::useClassDefaults()
1259 TextClass const & tclass = textclasslist[baseClass_];
1261 sides = tclass.sides();
1262 columns = tclass.columns();
1263 pagestyle = tclass.pagestyle();
1264 options = tclass.options();
1265 // Only if class has a ToC hierarchy
1266 if (tclass.hasTocLevels()) {
1267 secnumdepth = tclass.secnumdepth();
1268 tocdepth = tclass.tocdepth();
1273 bool BufferParams::hasClassDefaults() const
1275 TextClass const & tclass = textclasslist[baseClass_];
1277 return (sides == tclass.sides()
1278 && columns == tclass.columns()
1279 && pagestyle == tclass.pagestyle()
1280 && options == tclass.options()
1281 && secnumdepth == tclass.secnumdepth()
1282 && tocdepth == tclass.tocdepth());
1286 TextClass const & BufferParams::getTextClass() const
1292 TextClassPtr BufferParams::getTextClassPtr() const {
1297 void BufferParams::setTextClass(TextClassPtr tc) {
1302 bool BufferParams::setBaseClass(textclass_type tc)
1305 if (textclasslist[tc].load())
1309 bformat(_("The document class %1$s could not be loaded."),
1310 from_utf8(textclasslist[tc].name()));
1311 frontend::Alert::error(_("Could not load class"), s);
1319 void BufferParams::setJustBaseClass(textclass_type tc)
1325 textclass_type BufferParams::getBaseClass() const
1331 void BufferParams::makeTextClass()
1333 textClass_.reset(new TextClass(textclasslist[getBaseClass()]));
1334 //FIXME It might be worth loading the children's modules here,
1335 //just as we load their bibliographies and such, instead of just
1336 //doing a check in InsetInclude.
1337 LayoutModuleList::const_iterator it = layoutModules_.begin();
1338 for (; it != layoutModules_.end(); it++) {
1339 string const modName = *it;
1340 LyXModule * lm = moduleList[modName];
1342 docstring const msg =
1343 bformat(_("The module %1$s has been requested by\n"
1344 "this document but has not been found in the list of\n"
1345 "available modules. If you recently installed it, you\n"
1346 "probalby need to reconfigure LyX.\n"), from_utf8(modName));
1347 frontend::Alert::warning(_("Module not available"),
1348 msg + _("Some layouts may not be available."));
1349 lyxerr << "BufferParams::makeTextClass(): Module " <<
1350 modName << " requested but not found in module list." <<
1354 FileName layout_file = libFileSearch("layouts", lm->filename);
1355 textClass_->read(layout_file, TextClass::MODULE);
1360 std::vector<string> const & BufferParams::getModules() const {
1361 return layoutModules_;
1366 bool BufferParams::addLayoutModule(string modName, bool makeClass) {
1367 LayoutModuleList::const_iterator it = layoutModules_.begin();
1368 LayoutModuleList::const_iterator end = layoutModules_.end();
1369 for (; it != end; it++) {
1373 if (it != layoutModules_.end())
1375 layoutModules_.push_back(modName);
1382 bool BufferParams::addLayoutModules(std::vector<string>modNames)
1385 std::vector<string>::const_iterator it = modNames.begin();
1386 std::vector<string>::const_iterator end = modNames.end();
1387 for (; it != end; ++it)
1388 retval &= addLayoutModule(*it, false);
1394 void BufferParams::clearLayoutModules() {
1395 layoutModules_.clear();
1400 Font const BufferParams::getFont() const
1402 FontInfo f = getTextClass().defaultfont();
1403 if (fontsDefaultFamily == "rmdefault")
1404 f.setFamily(ROMAN_FAMILY);
1405 else if (fontsDefaultFamily == "sfdefault")
1406 f.setFamily(SANS_FAMILY);
1407 else if (fontsDefaultFamily == "ttdefault")
1408 f.setFamily(TYPEWRITER_FAMILY);
1409 return Font(f, language);
1413 void BufferParams::readPreamble(Lexer & lex)
1415 if (lex.getString() != "\\begin_preamble")
1416 lyxerr << "Error (BufferParams::readPreamble):"
1417 "consistency check failed." << endl;
1419 preamble = lex.getLongString("\\end_preamble");
1423 void BufferParams::readLanguage(Lexer & lex)
1425 if (!lex.next()) return;
1427 string const tmptok = lex.getString();
1429 // check if tmptok is part of tex_babel in tex-defs.h
1430 language = languages.getLanguage(tmptok);
1432 // Language tmptok was not found
1433 language = default_language;
1434 lyxerr << "Warning: Setting language `"
1435 << tmptok << "' to `" << language->lang()
1441 void BufferParams::readGraphicsDriver(Lexer & lex)
1443 if (!lex.next()) return;
1445 string const tmptok = lex.getString();
1446 // check if tmptok is part of tex_graphics in tex_defs.h
1449 string const test = tex_graphics[n++];
1451 if (test == tmptok) {
1452 graphicsDriver = tmptok;
1454 } else if (test == "") {
1456 "Warning: graphics driver `$$Token' not recognized!\n"
1457 " Setting graphics driver to `default'.\n");
1458 graphicsDriver = "default";
1465 void BufferParams::readBullets(Lexer & lex)
1467 if (!lex.next()) return;
1469 int const index = lex.getInteger();
1471 int temp_int = lex.getInteger();
1472 user_defined_bullet(index).setFont(temp_int);
1473 temp_bullet(index).setFont(temp_int);
1475 user_defined_bullet(index).setCharacter(temp_int);
1476 temp_bullet(index).setCharacter(temp_int);
1478 user_defined_bullet(index).setSize(temp_int);
1479 temp_bullet(index).setSize(temp_int);
1483 void BufferParams::readBulletsLaTeX(Lexer & lex)
1485 // The bullet class should be able to read this.
1486 if (!lex.next()) return;
1487 int const index = lex.getInteger();
1489 docstring const temp_str = lex.getDocString();
1491 user_defined_bullet(index).setText(temp_str);
1492 temp_bullet(index).setText(temp_str);
1496 void BufferParams::readModules(Lexer & lex)
1498 if (!lex.eatLine()) {
1499 lyxerr << "Error (BufferParams::readModules):"
1500 "Unexpected end of input." << endl;
1504 string mod = lex.getString();
1505 if (mod == "\\end_modules")
1507 addLayoutModule(mod);
1513 string const BufferParams::paperSizeName() const
1515 char real_papersize = papersize;
1516 if (real_papersize == PAPER_DEFAULT)
1517 real_papersize = lyxrc.default_papersize;
1519 switch (real_papersize) {
1528 case PAPER_USEXECUTIVE:
1532 case PAPER_USLETTER:
1539 string const BufferParams::dvips_options() const
1544 && papersize == PAPER_CUSTOM
1545 && !lyxrc.print_paper_dimension_flag.empty()
1546 && !paperwidth.empty()
1547 && !paperheight.empty()) {
1548 // using a custom papersize
1549 result = lyxrc.print_paper_dimension_flag;
1550 result += ' ' + paperwidth;
1551 result += ',' + paperheight;
1553 string const paper_option = paperSizeName();
1554 if (paper_option != "letter" ||
1555 orientation != ORIENTATION_LANDSCAPE) {
1556 // dvips won't accept -t letter -t landscape.
1557 // In all other cases, include the paper size
1559 result = lyxrc.print_paper_flag;
1560 result += ' ' + paper_option;
1563 if (orientation == ORIENTATION_LANDSCAPE &&
1564 papersize != PAPER_CUSTOM)
1565 result += ' ' + lyxrc.print_landscape_flag;
1570 string const BufferParams::babelCall(string const & lang_opts) const
1572 string lang_pack = lyxrc.language_package;
1573 if (lang_pack != "\\usepackage{babel}")
1575 // suppress the babel call when there is no babel language defined
1576 // for the document language in the lib/languages file and if no
1577 // other languages are used (lang_opts is then empty)
1578 if (lang_opts.empty())
1580 // when Vietnamese is used, babel must directly be loaded with the
1581 // language options, see
1582 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1583 size_t viet = lang_opts.find("vietnam");
1584 // viet = string::npos when not found
1585 if (!lyxrc.language_global_options || viet != string::npos)
1586 return "\\usepackage[" + lang_opts + "]{babel}";
1591 void BufferParams::writeEncodingPreamble(odocstream & os,
1592 LaTeXFeatures & features, TexRow & texrow) const
1594 if (inputenc == "auto") {
1595 string const doc_encoding =
1596 language->encoding()->latexName();
1597 Encoding::Package const package =
1598 language->encoding()->package();
1600 // Create a list with all the input encodings used
1602 std::set<string> encodings =
1603 features.getEncodingSet(doc_encoding);
1605 // When the encodings EUC-JP-plain, JIS-plain, or SJIS-plainare used, the
1606 // package inputenc must be omitted. Therefore set the encoding to empty.
1607 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1608 if (doc_encoding == "EUC-JP-plain" || doc_encoding == "JIS-plain" ||
1609 doc_encoding == "SJIS-plain")
1612 if (!encodings.empty() || package == Encoding::inputenc) {
1613 os << "\\usepackage[";
1614 std::set<string>::const_iterator it = encodings.begin();
1615 std::set<string>::const_iterator const end = encodings.end();
1617 os << from_ascii(*it);
1620 for (; it != end; ++it)
1621 os << ',' << from_ascii(*it);
1622 if (package == Encoding::inputenc) {
1623 if (!encodings.empty())
1625 os << from_ascii(doc_encoding);
1627 os << "]{inputenc}\n";
1630 if (package == Encoding::CJK || features.mustProvide("CJK")) {
1631 os << "\\usepackage{CJK}\n";
1634 } else if (inputenc != "default") {
1635 switch (encoding().package()) {
1636 case Encoding::none:
1638 case Encoding::inputenc:
1639 os << "\\usepackage[" << from_ascii(inputenc)
1644 os << "\\usepackage{CJK}\n";
1650 // The encoding "armscii8" is only available when the package "armtex" is loaded.
1651 // armscii8 is used for Armenian.
1652 if (language->encoding()->latexName() == "armscii8" || inputenc == "armscii8") {
1653 os << "\\usepackage{armtex}\n";
1659 string const BufferParams::loadFonts(string const & rm,
1660 string const & sf, string const & tt,
1661 bool const & sc, bool const & osf,
1662 int const & sfscale, int const & ttscale) const
1664 /* The LaTeX font world is in a flux. In the PSNFSS font interface,
1665 several packages have been replaced by others, that might not
1666 be installed on every system. We have to take care for that
1667 (see psnfss.pdf). We try to support all psnfss fonts as well
1668 as the fonts that have become de facto standard in the LaTeX
1669 world (e.g. Latin Modern). We do not support obsolete fonts
1670 (like PSLatex). In general, it should be possible to mix any
1671 rm font with any sf or tt font, respectively. (JSpitzm)
1673 -- separate math fonts.
1676 if (rm == "default" && sf == "default" && tt == "default")
1683 // Computer Modern (must be explicitely selectable -- there might be classes
1684 // that define a different default font!
1686 os << "\\renewcommand{\\rmdefault}{cmr}\n";
1687 // osf for Computer Modern needs eco.sty
1689 os << "\\usepackage{eco}\n";
1691 // Latin Modern Roman
1692 else if (rm == "lmodern")
1693 os << "\\usepackage{lmodern}\n";
1695 else if (rm == "ae") {
1696 // not needed when using OT1 font encoding.
1697 if (lyxrc.fontenc != "default")
1698 os << "\\usepackage{ae,aecompl}\n";
1701 else if (rm == "times") {
1702 // try to load the best available package
1703 if (LaTeXFeatures::isAvailable("mathptmx"))
1704 os << "\\usepackage{mathptmx}\n";
1705 else if (LaTeXFeatures::isAvailable("mathptm"))
1706 os << "\\usepackage{mathptm}\n";
1708 os << "\\usepackage{times}\n";
1711 else if (rm == "palatino") {
1712 // try to load the best available package
1713 if (LaTeXFeatures::isAvailable("mathpazo")) {
1714 os << "\\usepackage";
1720 // "osf" includes "sc"!
1724 os << "{mathpazo}\n";
1726 else if (LaTeXFeatures::isAvailable("mathpple"))
1727 os << "\\usepackage{mathpple}\n";
1729 os << "\\usepackage{palatino}\n";
1732 else if (rm == "utopia") {
1733 // fourier supersedes utopia.sty, but does
1734 // not work with OT1 encoding.
1735 if (LaTeXFeatures::isAvailable("fourier")
1736 && lyxrc.fontenc != "default") {
1737 os << "\\usepackage";
1748 os << "{fourier}\n";
1751 os << "\\usepackage{utopia}\n";
1753 // Bera (complete fontset)
1754 else if (rm == "bera" && sf == "default" && tt == "default")
1755 os << "\\usepackage{bera}\n";
1757 else if (rm != "default")
1758 os << "\\usepackage" << "{" << rm << "}\n";
1761 // Helvetica, Bera Sans
1762 if (sf == "helvet" || sf == "berasans") {
1764 os << "\\usepackage[scaled=" << float(sfscale) / 100
1765 << "]{" << sf << "}\n";
1767 os << "\\usepackage{" << sf << "}\n";
1770 else if (sf == "avant")
1771 os << "\\usepackage{" << sf << "}\n";
1772 // Computer Modern, Latin Modern, CM Bright
1773 else if (sf != "default")
1774 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
1776 // monospaced/typewriter
1777 // Courier, LuxiMono
1778 if (tt == "luximono" || tt == "beramono") {
1780 os << "\\usepackage[scaled=" << float(ttscale) / 100
1781 << "]{" << tt << "}\n";
1783 os << "\\usepackage{" << tt << "}\n";
1786 else if (tt == "courier" )
1787 os << "\\usepackage{" << tt << "}\n";
1788 // Computer Modern, Latin Modern, CM Bright
1789 else if (tt != "default")
1790 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
1796 Encoding const & BufferParams::encoding() const
1798 if (inputenc == "auto" || inputenc == "default")
1799 return *(language->encoding());
1800 Encoding const * const enc =
1801 encodings.getFromLaTeXName(inputenc);
1804 lyxerr << "Unknown inputenc value `" << inputenc
1805 << "'. Using `auto' instead." << endl;
1806 return *(language->encoding());
1810 biblio::CiteEngine BufferParams::getEngine() const
1812 // FIXME the class should provide the numerical/
1813 // authoryear choice
1814 if (getTextClass().provides("natbib")
1815 && cite_engine_ != biblio::ENGINE_NATBIB_NUMERICAL)
1816 return biblio::ENGINE_NATBIB_AUTHORYEAR;
1817 return cite_engine_;
1821 void BufferParams::setCiteEngine(biblio::CiteEngine const cite_engine)
1823 cite_engine_ = cite_engine;