2 * \file BufferParams.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
10 * \author André Pönitz
11 * \author Martin Vermeer
13 * Full author contact details are available in file CREDITS.
18 #include "BufferParams.h"
21 #include "BranchList.h"
22 #include "buffer_funcs.h"
27 #include "LaTeXFeatures.h"
28 #include "ModuleList.h"
32 #include "TextClassList.h"
33 #include "OutputParams.h"
37 #include "PDFOptions.h"
39 #include "frontends/alert.h"
41 #include "insets/InsetListingsParams.h"
43 #include "support/convert.h"
44 #include "support/debug.h"
45 #include "support/docstream.h"
46 #include "support/FileName.h"
47 #include "support/filetools.h"
48 #include "support/gettext.h"
49 #include "support/Messages.h"
50 #include "support/Translator.h"
51 #include "support/lstrings.h"
60 using std::istringstream;
63 using std::ostringstream;
66 using lyx::support::FileName;
67 using lyx::support::libFileSearch;
68 using lyx::support::bformat;
69 using lyx::support::rtrim;
70 using lyx::support::tokenPos;
71 using lyx::support::prefixIs;
74 static char const * const string_paragraph_separation[] = {
79 static char const * const string_quotes_language[] = {
80 "english", "swedish", "german", "polish", "french", "danish", ""
84 static char const * const string_papersize[] = {
85 "default", "custom", "letterpaper", "executivepaper", "legalpaper",
86 "a3paper", "a4paper", "a5paper", "b3paper", "b4paper", "b5paper", ""
90 static char const * const string_orientation[] = {
91 "portrait", "landscape", ""
95 static char const * const string_footnotekinds[] = {
96 "footnote", "margin", "fig", "tab", "alg", "wide-fig", "wide-tab", ""
100 static char const * const tex_graphics[] = {
101 "default", "dvips", "dvitops", "emtex",
102 "ln", "oztex", "textures", "none", ""
111 // Paragraph separation
112 typedef Translator<string, BufferParams::PARSEP> ParSepTranslator;
115 ParSepTranslator const init_parseptranslator()
117 ParSepTranslator translator(string_paragraph_separation[0], BufferParams::PARSEP_INDENT);
118 translator.addPair(string_paragraph_separation[1], BufferParams::PARSEP_SKIP);
123 ParSepTranslator const & parseptranslator()
125 static ParSepTranslator translator = init_parseptranslator();
131 typedef Translator<string, InsetQuotes::quote_language> QuotesLangTranslator;
134 QuotesLangTranslator const init_quoteslangtranslator()
136 QuotesLangTranslator translator(string_quotes_language[0], InsetQuotes::EnglishQ);
137 translator.addPair(string_quotes_language[1], InsetQuotes::SwedishQ);
138 translator.addPair(string_quotes_language[2], InsetQuotes::GermanQ);
139 translator.addPair(string_quotes_language[3], InsetQuotes::PolishQ);
140 translator.addPair(string_quotes_language[4], InsetQuotes::FrenchQ);
141 translator.addPair(string_quotes_language[5], InsetQuotes::DanishQ);
146 QuotesLangTranslator const & quoteslangtranslator()
148 static QuotesLangTranslator translator = init_quoteslangtranslator();
154 typedef Translator<std::string, PAPER_SIZE> PaperSizeTranslator;
157 PaperSizeTranslator const init_papersizetranslator()
159 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
160 translator.addPair(string_papersize[1], PAPER_CUSTOM);
161 translator.addPair(string_papersize[2], PAPER_USLETTER);
162 translator.addPair(string_papersize[3], PAPER_USLEGAL);
163 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
164 translator.addPair(string_papersize[5], PAPER_A3);
165 translator.addPair(string_papersize[6], PAPER_A4);
166 translator.addPair(string_papersize[7], PAPER_A5);
167 translator.addPair(string_papersize[8], PAPER_B3);
168 translator.addPair(string_papersize[9], PAPER_B4);
169 translator.addPair(string_papersize[10], PAPER_B5);
174 PaperSizeTranslator const & papersizetranslator()
176 static PaperSizeTranslator translator = init_papersizetranslator();
182 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
185 PaperOrientationTranslator const init_paperorientationtranslator()
187 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
188 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
193 PaperOrientationTranslator const & paperorientationtranslator()
195 static PaperOrientationTranslator translator = init_paperorientationtranslator();
201 typedef Translator<int, PageSides> SidesTranslator;
204 SidesTranslator const init_sidestranslator()
206 SidesTranslator translator(1, OneSide);
207 translator.addPair(2, TwoSides);
212 SidesTranslator const & sidestranslator()
214 static SidesTranslator translator = init_sidestranslator();
220 typedef Translator<int, BufferParams::Package> PackageTranslator;
223 PackageTranslator const init_packagetranslator()
225 PackageTranslator translator(0, BufferParams::package_off);
226 translator.addPair(1, BufferParams::package_auto);
227 translator.addPair(2, BufferParams::package_on);
232 PackageTranslator const & packagetranslator()
234 static PackageTranslator translator = init_packagetranslator();
240 typedef Translator<string, biblio::CiteEngine> CiteEngineTranslator;
243 CiteEngineTranslator const init_citeenginetranslator()
245 CiteEngineTranslator translator("basic", biblio::ENGINE_BASIC);
246 translator.addPair("natbib_numerical", biblio::ENGINE_NATBIB_NUMERICAL);
247 translator.addPair("natbib_authoryear", biblio::ENGINE_NATBIB_AUTHORYEAR);
248 translator.addPair("jurabib", biblio::ENGINE_JURABIB);
253 CiteEngineTranslator const & citeenginetranslator()
255 static CiteEngineTranslator translator = init_citeenginetranslator();
261 typedef Translator<string, Spacing::Space> SpaceTranslator;
264 SpaceTranslator const init_spacetranslator()
266 SpaceTranslator translator("default", Spacing::Default);
267 translator.addPair("single", Spacing::Single);
268 translator.addPair("onehalf", Spacing::Onehalf);
269 translator.addPair("double", Spacing::Double);
270 translator.addPair("other", Spacing::Other);
275 SpaceTranslator const & spacetranslator()
277 static SpaceTranslator translator = init_spacetranslator();
285 class BufferParams::Impl
290 AuthorList authorlist;
291 BranchList branchlist;
292 Bullet temp_bullets[4];
293 Bullet user_defined_bullets[4];
295 /** This is the amount of space used for paragraph_separation "skip",
296 * and for detached paragraphs in "indented" documents.
299 PDFOptions pdfoptions;
303 BufferParams::Impl::Impl()
304 : defskip(VSpace::MEDSKIP)
306 // set initial author
308 authorlist.record(Author(from_utf8(lyxrc.user_name), from_utf8(lyxrc.user_email)));
313 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
317 return new BufferParams::Impl(*ptr);
321 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
327 BufferParams::BufferParams()
330 setBaseClass(defaultTextclass());
331 paragraph_separation = PARSEP_INDENT;
332 quotes_language = InsetQuotes::EnglishQ;
333 fontsize = "default";
336 papersize = PAPER_DEFAULT;
337 orientation = ORIENTATION_PORTRAIT;
338 use_geometry = false;
339 use_amsmath = package_auto;
340 use_esint = package_auto;
341 cite_engine_ = biblio::ENGINE_BASIC;
342 use_bibtopic = false;
343 trackChanges = false;
344 outputChanges = false;
347 language = default_language;
348 fontsRoman = "default";
349 fontsSans = "default";
350 fontsTypewriter = "default";
351 fontsDefaultFamily = "default";
354 fontsSansScale = 100;
355 fontsTypewriterScale = 100;
357 graphicsDriver = "default";
360 listings_params = string();
361 pagestyle = "default";
364 for (int iter = 0; iter < 4; ++iter) {
365 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
366 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
371 BufferParams::~BufferParams()
375 docstring const BufferParams::B_(string const & l10n) const
377 BOOST_ASSERT(language);
378 return getMessages(language->code()).get(l10n);
382 AuthorList & BufferParams::authors()
384 return pimpl_->authorlist;
388 AuthorList const & BufferParams::authors() const
390 return pimpl_->authorlist;
394 BranchList & BufferParams::branchlist()
396 return pimpl_->branchlist;
400 BranchList const & BufferParams::branchlist() const
402 return pimpl_->branchlist;
406 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
408 BOOST_ASSERT(index < 4);
409 return pimpl_->temp_bullets[index];
413 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
415 BOOST_ASSERT(index < 4);
416 return pimpl_->temp_bullets[index];
420 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
422 BOOST_ASSERT(index < 4);
423 return pimpl_->user_defined_bullets[index];
427 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
429 BOOST_ASSERT(index < 4);
430 return pimpl_->user_defined_bullets[index];
434 Spacing & BufferParams::spacing()
436 return pimpl_->spacing;
440 Spacing const & BufferParams::spacing() const
442 return pimpl_->spacing;
446 PDFOptions & BufferParams::pdfoptions()
448 return pimpl_->pdfoptions;
452 PDFOptions const & BufferParams::pdfoptions() const
454 return pimpl_->pdfoptions;
458 VSpace const & BufferParams::getDefSkip() const
460 return pimpl_->defskip;
464 void BufferParams::setDefSkip(VSpace const & vs)
466 pimpl_->defskip = vs;
470 string const BufferParams::readToken(Lexer & lex, string const & token,
471 FileName const & filepath)
473 if (token == "\\textclass") {
475 string const classname = lex.getString();
476 // if there exists a local layout file, ignore the system one
477 // NOTE: in this case, the textclass (.cls file) is assumed to be available.
478 pair<bool, lyx::textclass_type> pp =
479 make_pair(false, textclass_type(0));
480 if (!filepath.empty())
481 pp = textclasslist.addTextClass(
482 classname, filepath.absFilename());
484 setBaseClass(pp.second);
486 pp = textclasslist.numberOfClass(classname);
488 setBaseClass(pp.second);
490 // a warning will be given for unknown class
491 setBaseClass(defaultTextclass());
495 // FIXME: this warning will be given even if there exists a local .cls
496 // file. Even worse, the .lyx file can not be compiled or exported
497 // because the textclass is marked as unavilable.
498 if (!getTextClass().isTeXClassAvailable()) {
499 docstring const msg =
500 bformat(_("The layout file requested by this document,\n"
502 "is not usable. This is probably because a LaTeX\n"
503 "class or style file required by it is not\n"
504 "available. See the Customization documentation\n"
505 "for more information.\n"), from_utf8(classname));
506 frontend::Alert::warning(_("Document class not available"),
507 msg + _("LyX will not be able to produce output."));
510 } else if (token == "\\begin_preamble") {
512 } else if (token == "\\begin_modules") {
515 } else if (token == "\\options") {
517 options = lex.getString();
518 } else if (token == "\\language") {
520 } else if (token == "\\inputencoding") {
522 } else if (token == "\\graphics") {
523 readGraphicsDriver(lex);
524 } else if (token == "\\font_roman") {
526 } else if (token == "\\font_sans") {
528 } else if (token == "\\font_typewriter") {
529 lex >> fontsTypewriter;
530 } else if (token == "\\font_default_family") {
531 lex >> fontsDefaultFamily;
532 } else if (token == "\\font_sc") {
534 } else if (token == "\\font_osf") {
536 } else if (token == "\\font_sf_scale") {
537 lex >> fontsSansScale;
538 } else if (token == "\\font_tt_scale") {
539 lex >> fontsTypewriterScale;
540 } else if (token == "\\paragraph_separation") {
543 paragraph_separation = parseptranslator().find(parsep);
544 } else if (token == "\\defskip") {
546 pimpl_->defskip = VSpace(lex.getString());
547 } else if (token == "\\quotes_language") {
550 quotes_language = quoteslangtranslator().find(quotes_lang);
551 } else if (token == "\\papersize") {
554 papersize = papersizetranslator().find(ppsize);
555 } else if (token == "\\use_geometry") {
557 } else if (token == "\\use_amsmath") {
560 use_amsmath = packagetranslator().find(use_ams);
561 } else if (token == "\\use_esint") {
564 use_esint = packagetranslator().find(useesint);
565 } else if (token == "\\cite_engine") {
568 cite_engine_ = citeenginetranslator().find(engine);
569 } else if (token == "\\use_bibtopic") {
571 } else if (token == "\\tracking_changes") {
573 } else if (token == "\\output_changes") {
574 lex >> outputChanges;
575 } else if (token == "\\branch") {
577 docstring branch = lex.getDocString();
578 branchlist().add(branch);
581 string const tok = lex.getString();
582 if (tok == "\\end_branch")
584 Branch * branch_ptr = branchlist().find(branch);
585 if (tok == "\\selected") {
588 branch_ptr->setSelected(lex.getInteger());
590 // not yet operational
591 if (tok == "\\color") {
593 string color = lex.getString();
595 branch_ptr->setColor(color);
596 // Update also the Color table:
598 color = lcolor.getX11Name(Color_background);
600 lcolor.setColor(to_utf8(branch), color);
604 } else if (token == "\\author") {
606 istringstream ss(lex.getString());
609 author_map.push_back(pimpl_->authorlist.record(a));
610 } else if (token == "\\paperorientation") {
613 orientation = paperorientationtranslator().find(orient);
614 } else if (token == "\\paperwidth") {
616 } else if (token == "\\paperheight") {
618 } else if (token == "\\leftmargin") {
620 } else if (token == "\\topmargin") {
622 } else if (token == "\\rightmargin") {
624 } else if (token == "\\bottommargin") {
626 } else if (token == "\\headheight") {
628 } else if (token == "\\headsep") {
630 } else if (token == "\\footskip") {
632 } else if (token == "\\paperfontsize") {
634 } else if (token == "\\papercolumns") {
636 } else if (token == "\\listings_params") {
639 listings_params = InsetListingsParams(par).params();
640 } else if (token == "\\papersides") {
643 sides = sidestranslator().find(psides);
644 } else if (token == "\\paperpagestyle") {
646 } else if (token == "\\bullet") {
648 } else if (token == "\\bulletLaTeX") {
649 readBulletsLaTeX(lex);
650 } else if (token == "\\secnumdepth") {
652 } else if (token == "\\tocdepth") {
654 } else if (token == "\\spacing") {
658 if (nspacing == "other") {
661 spacing().set(spacetranslator().find(nspacing), tmp_val);
662 } else if (token == "\\float_placement") {
663 lex >> float_placement;
665 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
666 string toktmp = pdfoptions().readToken(lex, token);
667 if (!toktmp.empty()) {
668 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
673 lyxerr << "BufferParams::readToken(): Unknown token: " <<
682 void BufferParams::writeFile(ostream & os) const
684 // The top of the file is written by the buffer.
685 // Prints out the buffer info into the .lyx file given by file
688 os << "\\textclass " << textclasslist[baseClass_].name() << '\n';
691 if (!preamble.empty()) {
692 // remove '\n' from the end of preamble
693 string const tmppreamble = rtrim(preamble, "\n");
694 os << "\\begin_preamble\n"
696 << "\n\\end_preamble\n";
700 if (!options.empty()) {
701 os << "\\options " << options << '\n';
705 if (!layoutModules_.empty()) {
706 os << "\\begin_modules" << '\n';
707 LayoutModuleList::const_iterator it = layoutModules_.begin();
708 for (; it != layoutModules_.end(); it++)
710 os << "\\end_modules" << '\n';
713 // then the text parameters
714 if (language != ignore_language)
715 os << "\\language " << language->lang() << '\n';
716 os << "\\inputencoding " << inputenc
717 << "\n\\font_roman " << fontsRoman
718 << "\n\\font_sans " << fontsSans
719 << "\n\\font_typewriter " << fontsTypewriter
720 << "\n\\font_default_family " << fontsDefaultFamily
721 << "\n\\font_sc " << convert<string>(fontsSC)
722 << "\n\\font_osf " << convert<string>(fontsOSF)
723 << "\n\\font_sf_scale " << fontsSansScale
724 << "\n\\font_tt_scale " << fontsTypewriterScale
725 << "\n\\graphics " << graphicsDriver << '\n';
727 if (!float_placement.empty()) {
728 os << "\\float_placement " << float_placement << '\n';
730 os << "\\paperfontsize " << fontsize << '\n';
732 spacing().writeFile(os);
733 pdfoptions().writeFile(os);
735 os << "\\papersize " << string_papersize[papersize]
736 << "\n\\use_geometry " << convert<string>(use_geometry)
737 << "\n\\use_amsmath " << use_amsmath
738 << "\n\\use_esint " << use_esint
739 << "\n\\cite_engine " << citeenginetranslator().find(cite_engine_)
740 << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
741 << "\n\\paperorientation " << string_orientation[orientation]
744 BranchList::const_iterator it = branchlist().begin();
745 BranchList::const_iterator end = branchlist().end();
746 for (; it != end; ++it) {
747 os << "\\branch " << to_utf8(it->getBranch())
748 << "\n\\selected " << it->getSelected()
749 << "\n\\color " << lyx::X11hexname(it->getColor())
754 if (!paperwidth.empty())
755 os << "\\paperwidth "
756 << VSpace(paperwidth).asLyXCommand() << '\n';
757 if (!paperheight.empty())
758 os << "\\paperheight "
759 << VSpace(paperheight).asLyXCommand() << '\n';
760 if (!leftmargin.empty())
761 os << "\\leftmargin "
762 << VSpace(leftmargin).asLyXCommand() << '\n';
763 if (!topmargin.empty())
765 << VSpace(topmargin).asLyXCommand() << '\n';
766 if (!rightmargin.empty())
767 os << "\\rightmargin "
768 << VSpace(rightmargin).asLyXCommand() << '\n';
769 if (!bottommargin.empty())
770 os << "\\bottommargin "
771 << VSpace(bottommargin).asLyXCommand() << '\n';
772 if (!headheight.empty())
773 os << "\\headheight "
774 << VSpace(headheight).asLyXCommand() << '\n';
775 if (!headsep.empty())
777 << VSpace(headsep).asLyXCommand() << '\n';
778 if (!footskip.empty())
780 << VSpace(footskip).asLyXCommand() << '\n';
781 os << "\\secnumdepth " << secnumdepth
782 << "\n\\tocdepth " << tocdepth
783 << "\n\\paragraph_separation "
784 << string_paragraph_separation[paragraph_separation]
785 << "\n\\defskip " << getDefSkip().asLyXCommand()
786 << "\n\\quotes_language "
787 << string_quotes_language[quotes_language]
788 << "\n\\papercolumns " << columns
789 << "\n\\papersides " << sides
790 << "\n\\paperpagestyle " << pagestyle << '\n';
791 if (!listings_params.empty())
792 os << "\\listings_params \"" <<
793 InsetListingsParams(listings_params).encodedString() << "\"\n";
794 for (int i = 0; i < 4; ++i) {
795 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
796 if (user_defined_bullet(i).getFont() != -1) {
797 os << "\\bullet " << i << " "
798 << user_defined_bullet(i).getFont() << " "
799 << user_defined_bullet(i).getCharacter() << " "
800 << user_defined_bullet(i).getSize() << "\n";
804 os << "\\bulletLaTeX " << i << " \""
805 << lyx::to_ascii(user_defined_bullet(i).getText())
811 os << "\\tracking_changes " << convert<string>(trackChanges) << "\n";
812 os << "\\output_changes " << convert<string>(outputChanges) << "\n";
814 AuthorList::Authors::const_iterator a_it = pimpl_->authorlist.begin();
815 AuthorList::Authors::const_iterator a_end = pimpl_->authorlist.end();
816 for (; a_it != a_end; ++a_it) {
817 if (a_it->second.used())
818 os << "\\author " << a_it->second << "\n";
820 os << "\\author " << Author() << "\n";
825 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
826 TexRow & texrow) const
828 os << "\\documentclass";
830 TextClass const & tclass = getTextClass();
832 ostringstream clsoptions; // the document class options.
834 if (tokenPos(tclass.opt_fontsize(),
835 '|', fontsize) >= 0) {
836 // only write if existing in list (and not default)
837 clsoptions << fontsize << "pt,";
840 // custom, A3, B3 and B4 paper sizes need geometry
841 bool nonstandard_papersize = papersize == PAPER_B3
842 || papersize == PAPER_B4
843 || papersize == PAPER_A3
844 || papersize == PAPER_CUSTOM;
849 clsoptions << "a4paper,";
852 clsoptions << "letterpaper,";
855 clsoptions << "a5paper,";
858 clsoptions << "b5paper,";
860 case PAPER_USEXECUTIVE:
861 clsoptions << "executivepaper,";
864 clsoptions << "legalpaper,";
876 if (sides != tclass.sides()) {
879 clsoptions << "oneside,";
882 clsoptions << "twoside,";
888 if (columns != tclass.columns()) {
890 clsoptions << "twocolumn,";
892 clsoptions << "onecolumn,";
896 && orientation == ORIENTATION_LANDSCAPE)
897 clsoptions << "landscape,";
899 // language should be a parameter to \documentclass
900 if (language->babel() == "hebrew"
901 && default_language->babel() != "hebrew")
902 // This seems necessary
903 features.useLanguage(default_language);
905 ostringstream language_options;
906 bool const use_babel = features.useBabel();
908 language_options << features.getLanguages();
909 if (!language->babel().empty()) {
910 if (!language_options.str().empty())
911 language_options << ',';
912 language_options << language->babel();
914 // when Vietnamese is used, babel must directly be loaded with the
915 // language options, not in the class options, see
916 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
917 size_t viet = language_options.str().find("vietnam");
918 // viet = string::npos when not found
919 if (lyxrc.language_global_options && !language_options.str().empty()
920 && viet == string::npos)
921 clsoptions << language_options.str() << ',';
924 // the user-defined options
925 if (!options.empty()) {
926 clsoptions << options << ',';
929 string strOptions(clsoptions.str());
930 if (!strOptions.empty()) {
931 strOptions = rtrim(strOptions, ",");
933 os << '[' << from_utf8(strOptions) << ']';
936 os << '{' << from_ascii(tclass.latexname()) << "}\n";
938 // end of \documentclass defs
940 // font selection must be done before loading fontenc.sty
942 loadFonts(fontsRoman, fontsSans,
943 fontsTypewriter, fontsSC, fontsOSF,
944 fontsSansScale, fontsTypewriterScale);
945 if (!fonts.empty()) {
946 os << from_ascii(fonts);
949 if (fontsDefaultFamily != "default")
950 os << "\\renewcommand{\\familydefault}{\\"
951 << from_ascii(fontsDefaultFamily) << "}\n";
954 // this one is not per buffer
955 // for arabic_arabi and farsi we also need to load the LAE and LFE encoding
956 if (lyxrc.fontenc != "default") {
957 if (language->lang() == "arabic_arabi" || language->lang() == "farsi") {
958 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
959 << ",LFE,LAE]{fontenc}\n";
962 os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
968 // handle inputenc etc.
969 writeEncodingPreamble(os, features, texrow);
971 if (!listings_params.empty()) {
972 os << "\\usepackage{listings}\n";
975 // do not test validity because listings_params is supposed to be valid
976 string par = InsetListingsParams(listings_params).separatedParams(true);
977 os << from_ascii(par);
978 // count the number of newlines
979 for (size_t i = 0; i < par.size(); ++i)
985 if (use_geometry || nonstandard_papersize) {
986 os << "\\usepackage{geometry}\n";
988 os << "\\geometry{verbose";
989 if (orientation == ORIENTATION_LANDSCAPE)
993 if (!paperwidth.empty())
995 << from_ascii(paperwidth);
996 if (!paperheight.empty())
997 os << ",paperheight="
998 << from_ascii(paperheight);
1000 case PAPER_USLETTER:
1001 os << ",letterpaper";
1004 os << ",legalpaper";
1006 case PAPER_USEXECUTIVE:
1007 os << ",executivepaper";
1028 // default papersize ie PAPER_DEFAULT
1029 switch (lyxrc.default_papersize) {
1030 case PAPER_DEFAULT: // keep compiler happy
1031 case PAPER_USLETTER:
1032 os << ",letterpaper";
1035 os << ",legalpaper";
1037 case PAPER_USEXECUTIVE:
1038 os << ",executivepaper";
1058 if (!topmargin.empty())
1059 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1060 if (!bottommargin.empty())
1061 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1062 if (!leftmargin.empty())
1063 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1064 if (!rightmargin.empty())
1065 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1066 if (!headheight.empty())
1067 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1068 if (!headsep.empty())
1069 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1070 if (!footskip.empty())
1071 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1076 if (tokenPos(tclass.opt_pagestyle(),
1077 '|', pagestyle) >= 0) {
1078 if (pagestyle == "fancy") {
1079 os << "\\usepackage{fancyhdr}\n";
1082 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1086 // Only if class has a ToC hierarchy
1087 if (tclass.hasTocLevels()) {
1088 if (secnumdepth != tclass.secnumdepth()) {
1089 os << "\\setcounter{secnumdepth}{"
1094 if (tocdepth != tclass.tocdepth()) {
1095 os << "\\setcounter{tocdepth}{"
1102 if (paragraph_separation) {
1103 switch (getDefSkip().kind()) {
1104 case VSpace::SMALLSKIP:
1105 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1107 case VSpace::MEDSKIP:
1108 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1110 case VSpace::BIGSKIP:
1111 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1113 case VSpace::LENGTH:
1114 os << "\\setlength{\\parskip}{"
1115 << from_utf8(getDefSkip().length().asLatexString())
1118 default: // should never happen // Then delete it.
1119 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1124 os << "\\setlength{\\parindent}{0pt}\n";
1128 // If we use jurabib, we have to call babel here.
1129 if (use_babel && features.isRequired("jurabib")) {
1130 os << from_ascii(babelCall(language_options.str()))
1132 << from_ascii(features.getBabelOptions());
1136 // Now insert the LyX specific LaTeX commands...
1138 // The optional packages;
1139 docstring lyxpreamble(from_ascii(features.getPackages()));
1141 // We try to load babel late, in case it interferes
1142 // with other packages. But some packages also need babel to be loaded
1143 // before, e.g. jurabib has to be called after babel.
1144 // So load babel after the optional packages but before the user-defined
1145 // preamble. This allows the users to redefine babel commands, e.g. to
1146 // translate the word "Index" to the German "Stichwortverzeichnis".
1147 // For more infos why this place was chosen, see
1148 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg128425.html
1149 // If you encounter problems, you can shift babel to its old place behind
1150 // the user-defined preamble. But in this case you must change the Vietnamese
1151 // support from currently "\usepackage[vietnamese]{babel}" to:
1152 // \usepackage{vietnamese}
1153 // \usepackage{babel}
1154 // because vietnamese must be loaded before hyperref
1155 if (use_babel && !features.isRequired("jurabib")) {
1157 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1158 lyxpreamble += from_utf8(features.getBabelOptions());
1161 // When the language "japanese-plain" is used, the package "japanese" must
1162 // be loaded behind babel (it provides babel support for Japanese) but before
1164 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1165 if (language->lang() == "japanese-plain" &&
1166 !getTextClass().provides("japanese")) {
1167 //load babel in case it was not loaded due to an empty language list
1168 if (language_options.str().empty())
1169 lyxpreamble += "\\usepackage{babel}\n";
1170 lyxpreamble += "\\usepackage{japanese}\n";
1174 // * Hyperref manual: "Make sure it comes last of your loaded
1175 // packages, to give it a fighting chance of not being over-written,
1176 // since its job is to redefine many LATEX commands."
1177 // * Email from Heiko Oberdiek: "It is usually better to load babel
1178 // before hyperref. Then hyperref has a chance to detect babel.
1179 // * Has to be loaded before the "LyX specific LaTeX commands" to
1180 // avoid errors with algorithm floats.
1181 odocstringstream oss;
1182 // use hyperref explicitely when it is required
1183 pdfoptions().writeLaTeX(oss, features.isRequired("hyperref"));
1184 lyxpreamble += oss.str();
1186 // this might be useful...
1187 lyxpreamble += "\n\\makeatletter\n";
1189 // Some macros LyX will need
1190 docstring tmppreamble(from_ascii(features.getMacros()));
1192 if (!tmppreamble.empty()) {
1193 lyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1194 "LyX specific LaTeX commands.\n"
1195 + tmppreamble + '\n';
1198 // the text class specific preamble
1199 tmppreamble = features.getTClassPreamble();
1200 if (!tmppreamble.empty()) {
1201 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1202 "Textclass specific LaTeX commands.\n"
1203 + tmppreamble + '\n';
1206 /* the user-defined preamble */
1207 if (!preamble.empty()) {
1209 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1210 "User specified LaTeX commands.\n"
1211 + from_utf8(preamble) + '\n';
1214 // Itemize bullet settings need to be last in case the user
1215 // defines their own bullets that use a package included
1216 // in the user-defined preamble -- ARRae
1217 // Actually it has to be done much later than that
1218 // since some packages like frenchb make modifications
1219 // at \begin{document} time -- JMarc
1220 docstring bullets_def;
1221 for (int i = 0; i < 4; ++i) {
1222 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1223 if (bullets_def.empty())
1224 bullets_def += "\\AtBeginDocument{\n";
1225 bullets_def += " \\def\\labelitemi";
1227 // `i' is one less than the item to modify
1234 bullets_def += "ii";
1240 bullets_def += '{' +
1241 user_defined_bullet(i).getText()
1246 if (!bullets_def.empty())
1247 lyxpreamble += bullets_def + "}\n\n";
1249 lyxpreamble += "\\makeatother\n\n";
1252 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1253 for (int j = 0; j != nlines; ++j) {
1262 void BufferParams::useClassDefaults()
1264 TextClass const & tclass = textclasslist[baseClass_];
1266 sides = tclass.sides();
1267 columns = tclass.columns();
1268 pagestyle = tclass.pagestyle();
1269 options = tclass.options();
1270 // Only if class has a ToC hierarchy
1271 if (tclass.hasTocLevels()) {
1272 secnumdepth = tclass.secnumdepth();
1273 tocdepth = tclass.tocdepth();
1278 bool BufferParams::hasClassDefaults() const
1280 TextClass const & tclass = textclasslist[baseClass_];
1282 return (sides == tclass.sides()
1283 && columns == tclass.columns()
1284 && pagestyle == tclass.pagestyle()
1285 && options == tclass.options()
1286 && secnumdepth == tclass.secnumdepth()
1287 && tocdepth == tclass.tocdepth());
1291 TextClass const & BufferParams::getTextClass() const
1297 TextClassPtr BufferParams::getTextClassPtr() const {
1302 void BufferParams::setTextClass(TextClassPtr tc) {
1307 bool BufferParams::setBaseClass(textclass_type tc)
1310 if (textclasslist[tc].load())
1314 bformat(_("The document class %1$s could not be loaded."),
1315 from_utf8(textclasslist[tc].name()));
1316 frontend::Alert::error(_("Could not load class"), s);
1324 void BufferParams::setJustBaseClass(textclass_type tc)
1330 textclass_type BufferParams::getBaseClass() const
1336 void BufferParams::makeTextClass()
1338 textClass_.reset(new TextClass(textclasslist[getBaseClass()]));
1339 //FIXME It might be worth loading the children's modules here,
1340 //just as we load their bibliographies and such, instead of just
1341 //doing a check in InsetInclude.
1342 LayoutModuleList::const_iterator it = layoutModules_.begin();
1343 for (; it != layoutModules_.end(); it++) {
1344 string const modName = *it;
1345 LyXModule * lm = moduleList[modName];
1347 docstring const msg =
1348 bformat(_("The module %1$s has been requested by\n"
1349 "this document but has not been found in the list of\n"
1350 "available modules. If you recently installed it, you\n"
1351 "probalby need to reconfigure LyX.\n"), from_utf8(modName));
1352 frontend::Alert::warning(_("Module not available"),
1353 msg + _("Some layouts may not be available."));
1354 lyxerr << "BufferParams::makeTextClass(): Module " <<
1355 modName << " requested but not found in module list." <<
1359 FileName layout_file = libFileSearch("layouts", lm->filename);
1360 textClass_->read(layout_file, TextClass::MODULE);
1365 std::vector<string> const & BufferParams::getModules() const {
1366 return layoutModules_;
1371 bool BufferParams::addLayoutModule(string modName, bool makeClass) {
1372 LayoutModuleList::const_iterator it = layoutModules_.begin();
1373 LayoutModuleList::const_iterator end = layoutModules_.end();
1374 for (; it != end; it++) {
1378 if (it != layoutModules_.end())
1380 layoutModules_.push_back(modName);
1387 bool BufferParams::addLayoutModules(std::vector<string>modNames)
1390 std::vector<string>::const_iterator it = modNames.begin();
1391 std::vector<string>::const_iterator end = modNames.end();
1392 for (; it != end; ++it)
1393 retval &= addLayoutModule(*it, false);
1399 void BufferParams::clearLayoutModules() {
1400 layoutModules_.clear();
1405 Font const BufferParams::getFont() const
1407 FontInfo f = getTextClass().defaultfont();
1408 if (fontsDefaultFamily == "rmdefault")
1409 f.setFamily(ROMAN_FAMILY);
1410 else if (fontsDefaultFamily == "sfdefault")
1411 f.setFamily(SANS_FAMILY);
1412 else if (fontsDefaultFamily == "ttdefault")
1413 f.setFamily(TYPEWRITER_FAMILY);
1414 return Font(f, language);
1418 void BufferParams::readPreamble(Lexer & lex)
1420 if (lex.getString() != "\\begin_preamble")
1421 lyxerr << "Error (BufferParams::readPreamble):"
1422 "consistency check failed." << endl;
1424 preamble = lex.getLongString("\\end_preamble");
1428 void BufferParams::readLanguage(Lexer & lex)
1430 if (!lex.next()) return;
1432 string const tmptok = lex.getString();
1434 // check if tmptok is part of tex_babel in tex-defs.h
1435 language = languages.getLanguage(tmptok);
1437 // Language tmptok was not found
1438 language = default_language;
1439 lyxerr << "Warning: Setting language `"
1440 << tmptok << "' to `" << language->lang()
1446 void BufferParams::readGraphicsDriver(Lexer & lex)
1448 if (!lex.next()) return;
1450 string const tmptok = lex.getString();
1451 // check if tmptok is part of tex_graphics in tex_defs.h
1454 string const test = tex_graphics[n++];
1456 if (test == tmptok) {
1457 graphicsDriver = tmptok;
1459 } else if (test == "") {
1461 "Warning: graphics driver `$$Token' not recognized!\n"
1462 " Setting graphics driver to `default'.\n");
1463 graphicsDriver = "default";
1470 void BufferParams::readBullets(Lexer & lex)
1472 if (!lex.next()) return;
1474 int const index = lex.getInteger();
1476 int temp_int = lex.getInteger();
1477 user_defined_bullet(index).setFont(temp_int);
1478 temp_bullet(index).setFont(temp_int);
1480 user_defined_bullet(index).setCharacter(temp_int);
1481 temp_bullet(index).setCharacter(temp_int);
1483 user_defined_bullet(index).setSize(temp_int);
1484 temp_bullet(index).setSize(temp_int);
1488 void BufferParams::readBulletsLaTeX(Lexer & lex)
1490 // The bullet class should be able to read this.
1491 if (!lex.next()) return;
1492 int const index = lex.getInteger();
1494 docstring const temp_str = lex.getDocString();
1496 user_defined_bullet(index).setText(temp_str);
1497 temp_bullet(index).setText(temp_str);
1501 void BufferParams::readModules(Lexer & lex)
1503 if (!lex.eatLine()) {
1504 lyxerr << "Error (BufferParams::readModules):"
1505 "Unexpected end of input." << endl;
1509 string mod = lex.getString();
1510 if (mod == "\\end_modules")
1512 addLayoutModule(mod);
1518 string const BufferParams::paperSizeName() const
1520 char real_papersize = papersize;
1521 if (real_papersize == PAPER_DEFAULT)
1522 real_papersize = lyxrc.default_papersize;
1524 switch (real_papersize) {
1533 case PAPER_USEXECUTIVE:
1537 case PAPER_USLETTER:
1544 string const BufferParams::dvips_options() const
1549 && papersize == PAPER_CUSTOM
1550 && !lyxrc.print_paper_dimension_flag.empty()
1551 && !paperwidth.empty()
1552 && !paperheight.empty()) {
1553 // using a custom papersize
1554 result = lyxrc.print_paper_dimension_flag;
1555 result += ' ' + paperwidth;
1556 result += ',' + paperheight;
1558 string const paper_option = paperSizeName();
1559 if (paper_option != "letter" ||
1560 orientation != ORIENTATION_LANDSCAPE) {
1561 // dvips won't accept -t letter -t landscape.
1562 // In all other cases, include the paper size
1564 result = lyxrc.print_paper_flag;
1565 result += ' ' + paper_option;
1568 if (orientation == ORIENTATION_LANDSCAPE &&
1569 papersize != PAPER_CUSTOM)
1570 result += ' ' + lyxrc.print_landscape_flag;
1575 string const BufferParams::babelCall(string const & lang_opts) const
1577 string lang_pack = lyxrc.language_package;
1578 if (lang_pack != "\\usepackage{babel}")
1580 // suppress the babel call when there is no babel language defined
1581 // for the document language in the lib/languages file and if no
1582 // other languages are used (lang_opts is then empty)
1583 if (lang_opts.empty())
1585 // when Vietnamese is used, babel must directly be loaded with the
1586 // language options, see
1587 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1588 size_t viet = lang_opts.find("vietnam");
1589 // viet = string::npos when not found
1590 if (!lyxrc.language_global_options || viet != string::npos)
1591 return "\\usepackage[" + lang_opts + "]{babel}";
1596 void BufferParams::writeEncodingPreamble(odocstream & os,
1597 LaTeXFeatures & features, TexRow & texrow) const
1599 if (inputenc == "auto") {
1600 string const doc_encoding =
1601 language->encoding()->latexName();
1602 Encoding::Package const package =
1603 language->encoding()->package();
1605 // Create a list with all the input encodings used
1607 std::set<string> encodings =
1608 features.getEncodingSet(doc_encoding);
1610 // When the encodings EUC-JP-plain, JIS-plain, or SJIS-plainare used, the
1611 // package inputenc must be omitted. Therefore set the encoding to empty.
1612 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1613 if (doc_encoding == "EUC-JP-plain" || doc_encoding == "JIS-plain" ||
1614 doc_encoding == "SJIS-plain")
1617 if (!encodings.empty() || package == Encoding::inputenc) {
1618 os << "\\usepackage[";
1619 std::set<string>::const_iterator it = encodings.begin();
1620 std::set<string>::const_iterator const end = encodings.end();
1622 os << from_ascii(*it);
1625 for (; it != end; ++it)
1626 os << ',' << from_ascii(*it);
1627 if (package == Encoding::inputenc) {
1628 if (!encodings.empty())
1630 os << from_ascii(doc_encoding);
1632 os << "]{inputenc}\n";
1635 if (package == Encoding::CJK || features.mustProvide("CJK")) {
1636 os << "\\usepackage{CJK}\n";
1639 } else if (inputenc != "default") {
1640 switch (encoding().package()) {
1641 case Encoding::none:
1643 case Encoding::inputenc:
1644 os << "\\usepackage[" << from_ascii(inputenc)
1649 os << "\\usepackage{CJK}\n";
1655 // The encoding "armscii8" is only available when the package "armtex" is loaded.
1656 // armscii8 is used for Armenian.
1657 if (language->encoding()->latexName() == "armscii8" || inputenc == "armscii8") {
1658 os << "\\usepackage{armtex}\n";
1664 string const BufferParams::loadFonts(string const & rm,
1665 string const & sf, string const & tt,
1666 bool const & sc, bool const & osf,
1667 int const & sfscale, int const & ttscale) const
1669 /* The LaTeX font world is in a flux. In the PSNFSS font interface,
1670 several packages have been replaced by others, that might not
1671 be installed on every system. We have to take care for that
1672 (see psnfss.pdf). We try to support all psnfss fonts as well
1673 as the fonts that have become de facto standard in the LaTeX
1674 world (e.g. Latin Modern). We do not support obsolete fonts
1675 (like PSLatex). In general, it should be possible to mix any
1676 rm font with any sf or tt font, respectively. (JSpitzm)
1678 -- separate math fonts.
1681 if (rm == "default" && sf == "default" && tt == "default")
1688 // Computer Modern (must be explicitely selectable -- there might be classes
1689 // that define a different default font!
1691 os << "\\renewcommand{\\rmdefault}{cmr}\n";
1692 // osf for Computer Modern needs eco.sty
1694 os << "\\usepackage{eco}\n";
1696 // Latin Modern Roman
1697 else if (rm == "lmodern")
1698 os << "\\usepackage{lmodern}\n";
1700 else if (rm == "ae") {
1701 // not needed when using OT1 font encoding.
1702 if (lyxrc.fontenc != "default")
1703 os << "\\usepackage{ae,aecompl}\n";
1706 else if (rm == "times") {
1707 // try to load the best available package
1708 if (LaTeXFeatures::isAvailable("mathptmx"))
1709 os << "\\usepackage{mathptmx}\n";
1710 else if (LaTeXFeatures::isAvailable("mathptm"))
1711 os << "\\usepackage{mathptm}\n";
1713 os << "\\usepackage{times}\n";
1716 else if (rm == "palatino") {
1717 // try to load the best available package
1718 if (LaTeXFeatures::isAvailable("mathpazo")) {
1719 os << "\\usepackage";
1725 // "osf" includes "sc"!
1729 os << "{mathpazo}\n";
1731 else if (LaTeXFeatures::isAvailable("mathpple"))
1732 os << "\\usepackage{mathpple}\n";
1734 os << "\\usepackage{palatino}\n";
1737 else if (rm == "utopia") {
1738 // fourier supersedes utopia.sty, but does
1739 // not work with OT1 encoding.
1740 if (LaTeXFeatures::isAvailable("fourier")
1741 && lyxrc.fontenc != "default") {
1742 os << "\\usepackage";
1753 os << "{fourier}\n";
1756 os << "\\usepackage{utopia}\n";
1758 // Bera (complete fontset)
1759 else if (rm == "bera" && sf == "default" && tt == "default")
1760 os << "\\usepackage{bera}\n";
1762 else if (rm != "default")
1763 os << "\\usepackage" << "{" << rm << "}\n";
1766 // Helvetica, Bera Sans
1767 if (sf == "helvet" || sf == "berasans") {
1769 os << "\\usepackage[scaled=" << float(sfscale) / 100
1770 << "]{" << sf << "}\n";
1772 os << "\\usepackage{" << sf << "}\n";
1775 else if (sf == "avant")
1776 os << "\\usepackage{" << sf << "}\n";
1777 // Computer Modern, Latin Modern, CM Bright
1778 else if (sf != "default")
1779 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
1781 // monospaced/typewriter
1782 // Courier, LuxiMono
1783 if (tt == "luximono" || tt == "beramono") {
1785 os << "\\usepackage[scaled=" << float(ttscale) / 100
1786 << "]{" << tt << "}\n";
1788 os << "\\usepackage{" << tt << "}\n";
1791 else if (tt == "courier" )
1792 os << "\\usepackage{" << tt << "}\n";
1793 // Computer Modern, Latin Modern, CM Bright
1794 else if (tt != "default")
1795 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
1801 Encoding const & BufferParams::encoding() const
1803 if (inputenc == "auto" || inputenc == "default")
1804 return *(language->encoding());
1805 Encoding const * const enc =
1806 encodings.getFromLaTeXName(inputenc);
1809 lyxerr << "Unknown inputenc value `" << inputenc
1810 << "'. Using `auto' instead." << endl;
1811 return *(language->encoding());
1815 biblio::CiteEngine BufferParams::getEngine() const
1817 // FIXME the class should provide the numerical/
1818 // authoryear choice
1819 if (getTextClass().provides("natbib")
1820 && cite_engine_ != biblio::ENGINE_NATBIB_NUMERICAL)
1821 return biblio::ENGINE_NATBIB_AUTHORYEAR;
1822 return cite_engine_;
1826 void BufferParams::setCiteEngine(biblio::CiteEngine const cite_engine)
1828 cite_engine_ = cite_engine;