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 "LayoutFile.h"
22 #include "BranchList.h"
24 #include "buffer_funcs.h"
28 #include "Converter.h"
31 #include "IndicesList.h"
33 #include "LaTeXFeatures.h"
34 #include "LaTeXFonts.h"
35 #include "ModuleList.h"
39 #include "OutputParams.h"
43 #include "PDFOptions.h"
45 #include "frontends/alert.h"
47 #include "insets/InsetListingsParams.h"
49 #include "support/convert.h"
50 #include "support/debug.h"
51 #include "support/docstream.h"
52 #include "support/FileName.h"
53 #include "support/filetools.h"
54 #include "support/gettext.h"
55 #include "support/Messages.h"
56 #include "support/mutex.h"
57 #include "support/Package.h"
58 #include "support/Translator.h"
59 #include "support/lstrings.h"
65 using namespace lyx::support;
68 static char const * const string_paragraph_separation[] = {
73 static char const * const string_quotes_language[] = {
74 "english", "swedish", "german", "polish", "french", "danish", ""
78 static char const * const string_papersize[] = {
79 "default", "custom", "letterpaper", "legalpaper", "executivepaper",
80 "a0paper", "a1paper", "a2paper", "a3paper", "a4paper", "a5paper",
81 "a6paper", "b0paper", "b1paper", "b2paper","b3paper", "b4paper",
82 "b5paper", "b6paper", "c0paper", "c1paper", "c2paper", "c3paper",
83 "c4paper", "c5paper", "c6paper", "b0j", "b1j", "b2j", "b3j", "b4j", "b5j",
88 static char const * const string_orientation[] = {
89 "portrait", "landscape", ""
93 static char const * const tex_graphics[] = {
94 "default", "dvialw", "dvilaser", "dvipdf", "dvipdfm", "dvipdfmx",
95 "dvips", "dvipsone", "dvitops", "dviwin", "dviwindo", "dvi2ps", "emtex",
96 "ln", "oztex", "pctexhp", "pctexps", "pctexwin", "pctex32", "pdftex",
97 "psprint", "pubps", "tcidvi", "textures", "truetex", "vtex", "xdvi",
108 // Paragraph separation
109 typedef Translator<string, BufferParams::ParagraphSeparation> ParSepTranslator;
112 ParSepTranslator const init_parseptranslator()
114 ParSepTranslator translator
115 (string_paragraph_separation[0], BufferParams::ParagraphIndentSeparation);
116 translator.addPair(string_paragraph_separation[1], BufferParams::ParagraphSkipSeparation);
121 ParSepTranslator const & parseptranslator()
123 static ParSepTranslator const translator =
124 init_parseptranslator();
130 typedef Translator<string, InsetQuotes::QuoteLanguage> QuotesLangTranslator;
133 QuotesLangTranslator const init_quoteslangtranslator()
135 QuotesLangTranslator translator
136 (string_quotes_language[0], InsetQuotes::EnglishQuotes);
137 translator.addPair(string_quotes_language[1], InsetQuotes::SwedishQuotes);
138 translator.addPair(string_quotes_language[2], InsetQuotes::GermanQuotes);
139 translator.addPair(string_quotes_language[3], InsetQuotes::PolishQuotes);
140 translator.addPair(string_quotes_language[4], InsetQuotes::FrenchQuotes);
141 translator.addPair(string_quotes_language[5], InsetQuotes::DanishQuotes);
146 QuotesLangTranslator const & quoteslangtranslator()
148 static QuotesLangTranslator const translator =
149 init_quoteslangtranslator();
155 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
158 static PaperSizeTranslator initPaperSizeTranslator()
160 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
161 translator.addPair(string_papersize[1], PAPER_CUSTOM);
162 translator.addPair(string_papersize[2], PAPER_USLETTER);
163 translator.addPair(string_papersize[3], PAPER_USLEGAL);
164 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
165 translator.addPair(string_papersize[5], PAPER_A0);
166 translator.addPair(string_papersize[6], PAPER_A1);
167 translator.addPair(string_papersize[7], PAPER_A2);
168 translator.addPair(string_papersize[8], PAPER_A3);
169 translator.addPair(string_papersize[9], PAPER_A4);
170 translator.addPair(string_papersize[10], PAPER_A5);
171 translator.addPair(string_papersize[11], PAPER_A6);
172 translator.addPair(string_papersize[12], PAPER_B0);
173 translator.addPair(string_papersize[13], PAPER_B1);
174 translator.addPair(string_papersize[14], PAPER_B2);
175 translator.addPair(string_papersize[15], PAPER_B3);
176 translator.addPair(string_papersize[16], PAPER_B4);
177 translator.addPair(string_papersize[17], PAPER_B5);
178 translator.addPair(string_papersize[18], PAPER_B6);
179 translator.addPair(string_papersize[19], PAPER_C0);
180 translator.addPair(string_papersize[20], PAPER_C1);
181 translator.addPair(string_papersize[21], PAPER_C2);
182 translator.addPair(string_papersize[22], PAPER_C3);
183 translator.addPair(string_papersize[23], PAPER_C4);
184 translator.addPair(string_papersize[24], PAPER_C5);
185 translator.addPair(string_papersize[25], PAPER_C6);
186 translator.addPair(string_papersize[26], PAPER_JISB0);
187 translator.addPair(string_papersize[27], PAPER_JISB1);
188 translator.addPair(string_papersize[28], PAPER_JISB2);
189 translator.addPair(string_papersize[29], PAPER_JISB3);
190 translator.addPair(string_papersize[30], PAPER_JISB4);
191 translator.addPair(string_papersize[31], PAPER_JISB5);
192 translator.addPair(string_papersize[32], PAPER_JISB6);
197 PaperSizeTranslator const & papersizetranslator()
199 static PaperSizeTranslator const translator =
200 initPaperSizeTranslator();
206 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
209 PaperOrientationTranslator const init_paperorientationtranslator()
211 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
212 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
217 PaperOrientationTranslator const & paperorientationtranslator()
219 static PaperOrientationTranslator const translator =
220 init_paperorientationtranslator();
226 typedef Translator<int, PageSides> SidesTranslator;
229 SidesTranslator const init_sidestranslator()
231 SidesTranslator translator(1, OneSide);
232 translator.addPair(2, TwoSides);
237 SidesTranslator const & sidestranslator()
239 static SidesTranslator const translator = init_sidestranslator();
245 typedef Translator<int, BufferParams::Package> PackageTranslator;
248 PackageTranslator const init_packagetranslator()
250 PackageTranslator translator(0, BufferParams::package_off);
251 translator.addPair(1, BufferParams::package_auto);
252 translator.addPair(2, BufferParams::package_on);
257 PackageTranslator const & packagetranslator()
259 static PackageTranslator const translator =
260 init_packagetranslator();
266 typedef Translator<string, CiteEngineType> CiteEngineTypeTranslator;
269 CiteEngineTypeTranslator const init_citeenginetypetranslator()
271 CiteEngineTypeTranslator translator("authoryear", ENGINE_TYPE_AUTHORYEAR);
272 translator.addPair("numerical", ENGINE_TYPE_NUMERICAL);
273 translator.addPair("default", ENGINE_TYPE_DEFAULT);
278 CiteEngineTypeTranslator const & citeenginetypetranslator()
280 static CiteEngineTypeTranslator const translator =
281 init_citeenginetypetranslator();
287 typedef Translator<string, Spacing::Space> SpaceTranslator;
290 SpaceTranslator const init_spacetranslator()
292 SpaceTranslator translator("default", Spacing::Default);
293 translator.addPair("single", Spacing::Single);
294 translator.addPair("onehalf", Spacing::Onehalf);
295 translator.addPair("double", Spacing::Double);
296 translator.addPair("other", Spacing::Other);
301 SpaceTranslator const & spacetranslator()
303 static SpaceTranslator const translator = init_spacetranslator();
310 class BufferParams::Impl
315 AuthorList authorlist;
316 BranchList branchlist;
317 Bullet temp_bullets[4];
318 Bullet user_defined_bullets[4];
319 IndicesList indiceslist;
321 /** This is the amount of space used for paragraph_separation "skip",
322 * and for detached paragraphs in "indented" documents.
326 PDFOptions pdfoptions;
327 LayoutFileIndex baseClass_;
331 BufferParams::Impl::Impl()
332 : defskip(VSpace::MEDSKIP), baseClass_(string(""))
334 // set initial author
336 authorlist.record(Author(from_utf8(lyxrc.user_name), from_utf8(lyxrc.user_email)));
341 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
344 return new BufferParams::Impl(*ptr);
348 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
354 BufferParams::BufferParams()
357 setBaseClass(defaultBaseclass());
358 cite_engine_.push_back("basic");
359 cite_engine_type_ = ENGINE_TYPE_DEFAULT;
361 paragraph_separation = ParagraphIndentSeparation;
362 quotes_language = InsetQuotes::EnglishQuotes;
363 fontsize = "default";
366 papersize = PAPER_DEFAULT;
367 orientation = ORIENTATION_PORTRAIT;
368 use_geometry = false;
369 biblio_style = "plain";
370 use_bibtopic = false;
372 track_changes = false;
373 output_changes = false;
374 use_default_options = true;
375 maintain_unincluded_children = false;
378 language = default_language;
380 fonts_roman[0] = "default";
381 fonts_roman[1] = "default";
382 fonts_sans[0] = "default";
383 fonts_sans[1] = "default";
384 fonts_typewriter[0] = "default";
385 fonts_typewriter[1] = "default";
386 fonts_math[0] = "auto";
387 fonts_math[1] = "auto";
388 fonts_default_family = "default";
389 useNonTeXFonts = false;
390 fonts_expert_sc = false;
391 fonts_old_figures = false;
392 fonts_sans_scale[0] = 100;
393 fonts_sans_scale[1] = 100;
394 fonts_typewriter_scale[0] = 100;
395 fonts_typewriter_scale[1] = 100;
397 lang_package = "default";
398 graphics_driver = "default";
399 default_output_format = "default";
400 bibtex_command = "default";
401 index_command = "default";
404 listings_params = string();
405 pagestyle = "default";
406 suppress_date = false;
407 justification = true;
408 // no color is the default (white)
409 backgroundcolor = lyx::rgbFromHexName("#ffffff");
410 isbackgroundcolor = false;
411 // no color is the default (black)
412 fontcolor = lyx::rgbFromHexName("#000000");
414 // light gray is the default font color for greyed-out notes
415 notefontcolor = lyx::rgbFromHexName("#cccccc");
416 boxbgcolor = lyx::rgbFromHexName("#ff0000");
417 compressed = lyxrc.save_compressed;
418 for (int iter = 0; iter < 4; ++iter) {
419 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
420 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
423 indiceslist().addDefault(B_("Index"));
424 html_be_strict = false;
425 html_math_output = MathML;
426 html_math_img_scale = 1.0;
427 html_css_as_file = false;
428 display_pixel_ratio = 1.0;
433 // map current author
434 author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
438 docstring BufferParams::B_(string const & l10n) const
440 LASSERT(language, return from_utf8(l10n));
441 return getMessages(language->code()).get(l10n);
445 BufferParams::Package BufferParams::use_package(std::string const & p) const
447 PackageMap::const_iterator it = use_packages.find(p);
448 if (it == use_packages.end())
454 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
460 map<string, string> const & BufferParams::auto_packages()
462 static map<string, string> packages;
463 if (packages.empty()) {
464 // We could have a race condition here that two threads
465 // discover an empty map at the same time and want to fill
466 // it, but that is no problem, since the same contents is
467 // filled in twice then. Having the locker inside the
468 // packages.empty() condition has the advantage that we
469 // don't need the mutex overhead for simple reading.
471 Mutex::Locker locker(&mutex);
472 // adding a package here implies a file format change!
473 packages["amsmath"] =
474 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
475 packages["amssymb"] =
476 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
478 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
480 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
481 packages["mathdots"] =
482 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
483 packages["mathtools"] =
484 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
486 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
487 packages["stackrel"] =
488 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
489 packages["stmaryrd"] =
490 N_("The LaTeX package stmaryrd is only used if symbols from the St Mary's Road symbol font for theoretical computer science are inserted into formulas");
491 packages["undertilde"] =
492 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
498 AuthorList & BufferParams::authors()
500 return pimpl_->authorlist;
504 AuthorList const & BufferParams::authors() const
506 return pimpl_->authorlist;
510 void BufferParams::addAuthor(Author a)
512 author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
516 BranchList & BufferParams::branchlist()
518 return pimpl_->branchlist;
522 BranchList const & BufferParams::branchlist() const
524 return pimpl_->branchlist;
528 IndicesList & BufferParams::indiceslist()
530 return pimpl_->indiceslist;
534 IndicesList const & BufferParams::indiceslist() const
536 return pimpl_->indiceslist;
540 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
542 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
543 return pimpl_->temp_bullets[index];
547 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
549 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
550 return pimpl_->temp_bullets[index];
554 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
556 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
557 return pimpl_->user_defined_bullets[index];
561 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
563 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
564 return pimpl_->user_defined_bullets[index];
568 Spacing & BufferParams::spacing()
570 return pimpl_->spacing;
574 Spacing const & BufferParams::spacing() const
576 return pimpl_->spacing;
580 PDFOptions & BufferParams::pdfoptions()
582 return pimpl_->pdfoptions;
586 PDFOptions const & BufferParams::pdfoptions() const
588 return pimpl_->pdfoptions;
592 HSpace const & BufferParams::getIndentation() const
594 return pimpl_->indentation;
598 void BufferParams::setIndentation(HSpace const & indent)
600 pimpl_->indentation = indent;
604 VSpace const & BufferParams::getDefSkip() const
606 return pimpl_->defskip;
610 void BufferParams::setDefSkip(VSpace const & vs)
612 // DEFSKIP will cause an infinite loop
613 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
614 pimpl_->defskip = vs;
618 string BufferParams::readToken(Lexer & lex, string const & token,
619 FileName const & filepath)
623 if (token == "\\textclass") {
625 string const classname = lex.getString();
626 // if there exists a local layout file, ignore the system one
627 // NOTE: in this case, the textclass (.cls file) is assumed to
630 LayoutFileList & bcl = LayoutFileList::get();
631 if (!filepath.empty()) {
632 // If classname is an absolute path, the document is
633 // using a local layout file which could not be accessed
634 // by a relative path. In this case the path is correct
635 // even if the document was moved to a different
636 // location. However, we will have a problem if the
637 // document was generated on a different platform.
638 bool isabsolute = FileName::isAbsolute(classname);
639 string const classpath = onlyPath(classname);
640 string const path = isabsolute ? classpath
641 : FileName(addPath(filepath.absFileName(),
642 classpath)).realPath();
643 string const oldpath = isabsolute ? string()
644 : FileName(addPath(origin, classpath)).realPath();
645 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
647 // that returns non-empty if a "local" layout file is found.
649 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
650 from_utf8(filepath.absFileName())));
653 setBaseClass(onlyFileName(tcp));
655 setBaseClass(onlyFileName(classname));
656 // We assume that a tex class exists for local or unknown
657 // layouts so this warning, will only be given for system layouts.
658 if (!baseClass()->isTeXClassAvailable()) {
659 docstring const desc =
660 translateIfPossible(from_utf8(baseClass()->description()));
661 docstring const prereqs =
662 from_utf8(baseClass()->prerequisites());
663 docstring const msg =
664 bformat(_("The selected document class\n"
666 "requires external files that are not available.\n"
667 "The document class can still be used, but the\n"
668 "document cannot be compiled until the following\n"
669 "prerequisites are installed:\n"
671 "See section 3.1.2.2 (Class Availability) of the\n"
672 "User's Guide for more information."), desc, prereqs);
673 frontend::Alert::warning(_("Document class not available"),
676 } else if (token == "\\origin") {
678 origin = lex.getString();
679 string const sysdirprefix = "/systemlyxdir/";
680 if (prefixIs(origin, sysdirprefix)) {
681 origin.replace(0, sysdirprefix.length() - 1,
682 package().system_support().absFileName());
684 } else if (token == "\\begin_preamble") {
686 } else if (token == "\\begin_local_layout") {
687 readLocalLayout(lex, false);
688 } else if (token == "\\begin_forced_local_layout") {
689 readLocalLayout(lex, true);
690 } else if (token == "\\begin_modules") {
692 } else if (token == "\\begin_removed_modules") {
693 readRemovedModules(lex);
694 } else if (token == "\\begin_includeonly") {
695 readIncludeonly(lex);
696 } else if (token == "\\maintain_unincluded_children") {
697 lex >> maintain_unincluded_children;
698 } else if (token == "\\options") {
700 options = lex.getString();
701 } else if (token == "\\use_default_options") {
702 lex >> use_default_options;
703 } else if (token == "\\master") {
705 master = lex.getString();
706 if (!filepath.empty() && FileName::isAbsolute(origin)) {
707 bool const isabs = FileName::isAbsolute(master);
708 FileName const abspath(isabs ? master : origin + master);
709 bool const moved = filepath != FileName(origin);
710 if (moved && abspath.exists()) {
711 docstring const path = isabs
713 : from_utf8(abspath.realPath());
714 docstring const refpath =
715 from_utf8(filepath.absFileName());
716 master = to_utf8(makeRelPath(path, refpath));
719 } else if (token == "\\suppress_date") {
720 lex >> suppress_date;
721 } else if (token == "\\justification") {
722 lex >> justification;
723 } else if (token == "\\language") {
725 } else if (token == "\\language_package") {
727 lang_package = lex.getString();
728 } else if (token == "\\inputencoding") {
730 } else if (token == "\\graphics") {
731 readGraphicsDriver(lex);
732 } else if (token == "\\default_output_format") {
733 lex >> default_output_format;
734 } else if (token == "\\bibtex_command") {
736 bibtex_command = lex.getString();
737 } else if (token == "\\index_command") {
739 index_command = lex.getString();
740 } else if (token == "\\fontencoding") {
742 fontenc = lex.getString();
743 } else if (token == "\\font_roman") {
744 lex >> fonts_roman[0];
745 lex >> fonts_roman[1];
746 } else if (token == "\\font_sans") {
747 lex >> fonts_sans[0];
748 lex >> fonts_sans[1];
749 } else if (token == "\\font_typewriter") {
750 lex >> fonts_typewriter[0];
751 lex >> fonts_typewriter[1];
752 } else if (token == "\\font_math") {
753 lex >> fonts_math[0];
754 lex >> fonts_math[1];
755 } else if (token == "\\font_default_family") {
756 lex >> fonts_default_family;
757 } else if (token == "\\use_non_tex_fonts") {
758 lex >> useNonTeXFonts;
759 } else if (token == "\\font_sc") {
760 lex >> fonts_expert_sc;
761 } else if (token == "\\font_osf") {
762 lex >> fonts_old_figures;
763 } else if (token == "\\font_sf_scale") {
764 lex >> fonts_sans_scale[0];
765 lex >> fonts_sans_scale[1];
766 } else if (token == "\\font_tt_scale") {
767 lex >> fonts_typewriter_scale[0];
768 lex >> fonts_typewriter_scale[1];
769 } else if (token == "\\font_cjk") {
771 } else if (token == "\\paragraph_separation") {
774 paragraph_separation = parseptranslator().find(parsep);
775 } else if (token == "\\paragraph_indentation") {
777 string indentation = lex.getString();
778 pimpl_->indentation = HSpace(indentation);
779 } else if (token == "\\defskip") {
781 string const defskip = lex.getString();
782 pimpl_->defskip = VSpace(defskip);
783 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
785 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
786 } else if (token == "\\quotes_language") {
789 quotes_language = quoteslangtranslator().find(quotes_lang);
790 } else if (token == "\\papersize") {
793 papersize = papersizetranslator().find(ppsize);
794 } else if (token == "\\use_geometry") {
796 } else if (token == "\\use_package") {
801 use_package(package, packagetranslator().find(use));
802 } else if (token == "\\cite_engine") {
804 vector<string> engine = getVectorFromString(lex.getString());
805 setCiteEngine(engine);
806 } else if (token == "\\cite_engine_type") {
809 cite_engine_type_ = citeenginetypetranslator().find(engine_type);
810 } else if (token == "\\biblio_style") {
812 biblio_style = lex.getString();
813 } else if (token == "\\use_bibtopic") {
815 } else if (token == "\\use_indices") {
817 } else if (token == "\\tracking_changes") {
818 lex >> track_changes;
819 } else if (token == "\\output_changes") {
820 lex >> output_changes;
821 } else if (token == "\\branch") {
823 docstring branch = lex.getDocString();
824 branchlist().add(branch);
827 string const tok = lex.getString();
828 if (tok == "\\end_branch")
830 Branch * branch_ptr = branchlist().find(branch);
831 if (tok == "\\selected") {
834 branch_ptr->setSelected(lex.getInteger());
836 if (tok == "\\filename_suffix") {
839 branch_ptr->setFileNameSuffix(lex.getInteger());
841 if (tok == "\\color") {
843 string color = lex.getString();
845 branch_ptr->setColor(color);
846 // Update also the Color table:
848 color = lcolor.getX11Name(Color_background);
850 lcolor.setColor(to_utf8(branch), color);
853 } else if (token == "\\index") {
855 docstring index = lex.getDocString();
857 indiceslist().add(index);
860 string const tok = lex.getString();
861 if (tok == "\\end_index")
863 Index * index_ptr = indiceslist().find(index);
864 if (tok == "\\shortcut") {
866 shortcut = lex.getDocString();
868 index_ptr->setShortcut(shortcut);
870 if (tok == "\\color") {
872 string color = lex.getString();
874 index_ptr->setColor(color);
875 // Update also the Color table:
877 color = lcolor.getX11Name(Color_background);
879 if (!shortcut.empty())
880 lcolor.setColor(to_utf8(shortcut), color);
883 } else if (token == "\\author") {
885 istringstream ss(lex.getString());
889 } else if (token == "\\paperorientation") {
892 orientation = paperorientationtranslator().find(orient);
893 } else if (token == "\\backgroundcolor") {
895 backgroundcolor = lyx::rgbFromHexName(lex.getString());
896 isbackgroundcolor = true;
897 } else if (token == "\\fontcolor") {
899 fontcolor = lyx::rgbFromHexName(lex.getString());
901 } else if (token == "\\notefontcolor") {
903 string color = lex.getString();
904 notefontcolor = lyx::rgbFromHexName(color);
905 lcolor.setColor("notefontcolor", color);
906 } else if (token == "\\boxbgcolor") {
908 string color = lex.getString();
909 boxbgcolor = lyx::rgbFromHexName(color);
910 lcolor.setColor("boxbgcolor", color);
911 } else if (token == "\\paperwidth") {
913 } else if (token == "\\paperheight") {
915 } else if (token == "\\leftmargin") {
917 } else if (token == "\\topmargin") {
919 } else if (token == "\\rightmargin") {
921 } else if (token == "\\bottommargin") {
923 } else if (token == "\\headheight") {
925 } else if (token == "\\headsep") {
927 } else if (token == "\\footskip") {
929 } else if (token == "\\columnsep") {
931 } else if (token == "\\paperfontsize") {
933 } else if (token == "\\papercolumns") {
935 } else if (token == "\\listings_params") {
938 listings_params = InsetListingsParams(par).params();
939 } else if (token == "\\papersides") {
942 sides = sidestranslator().find(psides);
943 } else if (token == "\\paperpagestyle") {
945 } else if (token == "\\bullet") {
947 } else if (token == "\\bulletLaTeX") {
948 readBulletsLaTeX(lex);
949 } else if (token == "\\secnumdepth") {
951 } else if (token == "\\tocdepth") {
953 } else if (token == "\\spacing") {
957 if (nspacing == "other") {
960 spacing().set(spacetranslator().find(nspacing), tmp_val);
961 } else if (token == "\\float_placement") {
962 lex >> float_placement;
964 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
965 string toktmp = pdfoptions().readToken(lex, token);
966 if (!toktmp.empty()) {
967 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
971 } else if (token == "\\html_math_output") {
974 html_math_output = static_cast<MathOutput>(temp);
975 } else if (token == "\\html_be_strict") {
976 lex >> html_be_strict;
977 } else if (token == "\\html_css_as_file") {
978 lex >> html_css_as_file;
979 } else if (token == "\\html_math_img_scale") {
980 lex >> html_math_img_scale;
981 } else if (token == "\\html_latex_start") {
983 html_latex_start = lex.getString();
984 } else if (token == "\\html_latex_end") {
986 html_latex_end = lex.getString();
987 } else if (token == "\\output_sync") {
989 } else if (token == "\\output_sync_macro") {
990 lex >> output_sync_macro;
991 } else if (token == "\\use_refstyle") {
994 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1004 // Quote argument if it contains spaces
1005 string quoteIfNeeded(string const & str) {
1006 if (contains(str, ' '))
1007 return "\"" + str + "\"";
1013 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1015 // The top of the file is written by the buffer.
1016 // Prints out the buffer info into the .lyx file given by file
1018 // the document directory (must end with a path separator)
1019 // realPath() is used to resolve symlinks, while addPath(..., "")
1020 // ensures a trailing path separator.
1021 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1022 string const sysdir = addPath(package().system_support().realPath(), "");
1023 string const relpath =
1024 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1025 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1026 filepath = addPath("/systemlyxdir", relpath);
1027 else if (!lyxrc.save_origin)
1028 filepath = "unavailable";
1029 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1032 os << "\\textclass "
1033 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1034 baseClass()->name()), "layout"))
1037 // then the preamble
1038 if (!preamble.empty()) {
1039 // remove '\n' from the end of preamble
1040 string const tmppreamble = rtrim(preamble, "\n");
1041 os << "\\begin_preamble\n"
1043 << "\n\\end_preamble\n";
1047 if (!options.empty()) {
1048 os << "\\options " << options << '\n';
1051 // use the class options defined in the layout?
1052 os << "\\use_default_options "
1053 << convert<string>(use_default_options) << "\n";
1055 // the master document
1056 if (!master.empty()) {
1057 os << "\\master " << master << '\n';
1061 if (!removed_modules_.empty()) {
1062 os << "\\begin_removed_modules" << '\n';
1063 list<string>::const_iterator it = removed_modules_.begin();
1064 list<string>::const_iterator en = removed_modules_.end();
1065 for (; it != en; ++it)
1067 os << "\\end_removed_modules" << '\n';
1071 if (!layout_modules_.empty()) {
1072 os << "\\begin_modules" << '\n';
1073 LayoutModuleList::const_iterator it = layout_modules_.begin();
1074 LayoutModuleList::const_iterator en = layout_modules_.end();
1075 for (; it != en; ++it)
1077 os << "\\end_modules" << '\n';
1081 if (!included_children_.empty()) {
1082 os << "\\begin_includeonly" << '\n';
1083 list<string>::const_iterator it = included_children_.begin();
1084 list<string>::const_iterator en = included_children_.end();
1085 for (; it != en; ++it)
1087 os << "\\end_includeonly" << '\n';
1089 os << "\\maintain_unincluded_children "
1090 << convert<string>(maintain_unincluded_children) << '\n';
1092 // local layout information
1093 string const local_layout = getLocalLayout(false);
1094 if (!local_layout.empty()) {
1095 // remove '\n' from the end
1096 string const tmplocal = rtrim(local_layout, "\n");
1097 os << "\\begin_local_layout\n"
1099 << "\n\\end_local_layout\n";
1101 string const forced_local_layout = getLocalLayout(true);
1102 if (!forced_local_layout.empty()) {
1103 // remove '\n' from the end
1104 string const tmplocal = rtrim(forced_local_layout, "\n");
1105 os << "\\begin_forced_local_layout\n"
1107 << "\n\\end_forced_local_layout\n";
1110 // then the text parameters
1111 if (language != ignore_language)
1112 os << "\\language " << language->lang() << '\n';
1113 os << "\\language_package " << lang_package
1114 << "\n\\inputencoding " << inputenc
1115 << "\n\\fontencoding " << fontenc
1116 << "\n\\font_roman \"" << fonts_roman[0]
1117 << "\" \"" << fonts_roman[1] << '"'
1118 << "\n\\font_sans \"" << fonts_sans[0]
1119 << "\" \"" << fonts_sans[1] << '"'
1120 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1121 << "\" \"" << fonts_typewriter[1] << '"'
1122 << "\n\\font_math \"" << fonts_math[0]
1123 << "\" \"" << fonts_math[1] << '"'
1124 << "\n\\font_default_family " << fonts_default_family
1125 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1126 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1127 << "\n\\font_osf " << convert<string>(fonts_old_figures)
1128 << "\n\\font_sf_scale " << fonts_sans_scale[0]
1129 << ' ' << fonts_sans_scale[1]
1130 << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1131 << ' ' << fonts_typewriter_scale[1]
1133 if (!fonts_cjk.empty()) {
1134 os << "\\font_cjk " << fonts_cjk << '\n';
1136 os << "\\graphics " << graphics_driver << '\n';
1137 os << "\\default_output_format " << default_output_format << '\n';
1138 os << "\\output_sync " << output_sync << '\n';
1139 if (!output_sync_macro.empty())
1140 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1141 os << "\\bibtex_command " << bibtex_command << '\n';
1142 os << "\\index_command " << index_command << '\n';
1144 if (!float_placement.empty()) {
1145 os << "\\float_placement " << float_placement << '\n';
1147 os << "\\paperfontsize " << fontsize << '\n';
1149 spacing().writeFile(os);
1150 pdfoptions().writeFile(os);
1152 os << "\\papersize " << string_papersize[papersize]
1153 << "\n\\use_geometry " << convert<string>(use_geometry);
1154 map<string, string> const & packages = auto_packages();
1155 for (map<string, string>::const_iterator it = packages.begin();
1156 it != packages.end(); ++it)
1157 os << "\n\\use_package " << it->first << ' '
1158 << use_package(it->first);
1160 os << "\n\\cite_engine ";
1162 if (!cite_engine_.empty()) {
1163 LayoutModuleList::const_iterator be = cite_engine_.begin();
1164 LayoutModuleList::const_iterator en = cite_engine_.end();
1165 for (LayoutModuleList::const_iterator it = be; it != en; ++it) {
1174 os << "\n\\cite_engine_type " << citeenginetypetranslator().find(cite_engine_type_)
1175 << "\n\\biblio_style " << biblio_style
1176 << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1177 << "\n\\use_indices " << convert<string>(use_indices)
1178 << "\n\\paperorientation " << string_orientation[orientation]
1179 << "\n\\suppress_date " << convert<string>(suppress_date)
1180 << "\n\\justification " << convert<string>(justification)
1181 << "\n\\use_refstyle " << use_refstyle
1183 if (isbackgroundcolor == true)
1184 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1185 if (isfontcolor == true)
1186 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1187 if (notefontcolor != lyx::rgbFromHexName("#cccccc"))
1188 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1189 if (boxbgcolor != lyx::rgbFromHexName("#ff0000"))
1190 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1192 BranchList::const_iterator it = branchlist().begin();
1193 BranchList::const_iterator end = branchlist().end();
1194 for (; it != end; ++it) {
1195 os << "\\branch " << to_utf8(it->branch())
1196 << "\n\\selected " << it->isSelected()
1197 << "\n\\filename_suffix " << it->hasFileNameSuffix()
1198 << "\n\\color " << lyx::X11hexname(it->color())
1203 IndicesList::const_iterator iit = indiceslist().begin();
1204 IndicesList::const_iterator iend = indiceslist().end();
1205 for (; iit != iend; ++iit) {
1206 os << "\\index " << to_utf8(iit->index())
1207 << "\n\\shortcut " << to_utf8(iit->shortcut())
1208 << "\n\\color " << lyx::X11hexname(iit->color())
1213 if (!paperwidth.empty())
1214 os << "\\paperwidth "
1215 << VSpace(paperwidth).asLyXCommand() << '\n';
1216 if (!paperheight.empty())
1217 os << "\\paperheight "
1218 << VSpace(paperheight).asLyXCommand() << '\n';
1219 if (!leftmargin.empty())
1220 os << "\\leftmargin "
1221 << VSpace(leftmargin).asLyXCommand() << '\n';
1222 if (!topmargin.empty())
1223 os << "\\topmargin "
1224 << VSpace(topmargin).asLyXCommand() << '\n';
1225 if (!rightmargin.empty())
1226 os << "\\rightmargin "
1227 << VSpace(rightmargin).asLyXCommand() << '\n';
1228 if (!bottommargin.empty())
1229 os << "\\bottommargin "
1230 << VSpace(bottommargin).asLyXCommand() << '\n';
1231 if (!headheight.empty())
1232 os << "\\headheight "
1233 << VSpace(headheight).asLyXCommand() << '\n';
1234 if (!headsep.empty())
1236 << VSpace(headsep).asLyXCommand() << '\n';
1237 if (!footskip.empty())
1239 << VSpace(footskip).asLyXCommand() << '\n';
1240 if (!columnsep.empty())
1241 os << "\\columnsep "
1242 << VSpace(columnsep).asLyXCommand() << '\n';
1243 os << "\\secnumdepth " << secnumdepth
1244 << "\n\\tocdepth " << tocdepth
1245 << "\n\\paragraph_separation "
1246 << string_paragraph_separation[paragraph_separation];
1247 if (!paragraph_separation)
1248 os << "\n\\paragraph_indentation " << getIndentation().asLyXCommand();
1250 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1251 os << "\n\\quotes_language "
1252 << string_quotes_language[quotes_language]
1253 << "\n\\papercolumns " << columns
1254 << "\n\\papersides " << sides
1255 << "\n\\paperpagestyle " << pagestyle << '\n';
1256 if (!listings_params.empty())
1257 os << "\\listings_params \"" <<
1258 InsetListingsParams(listings_params).encodedString() << "\"\n";
1259 for (int i = 0; i < 4; ++i) {
1260 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1261 if (user_defined_bullet(i).getFont() != -1) {
1262 os << "\\bullet " << i << " "
1263 << user_defined_bullet(i).getFont() << " "
1264 << user_defined_bullet(i).getCharacter() << " "
1265 << user_defined_bullet(i).getSize() << "\n";
1269 os << "\\bulletLaTeX " << i << " \""
1270 << lyx::to_ascii(user_defined_bullet(i).getText())
1276 os << "\\tracking_changes " << convert<string>(track_changes) << '\n'
1277 << "\\output_changes " << convert<string>(output_changes) << '\n'
1278 << "\\html_math_output " << html_math_output << '\n'
1279 << "\\html_css_as_file " << html_css_as_file << '\n'
1280 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1282 if (html_math_img_scale != 1.0)
1283 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1284 if (!html_latex_start.empty())
1285 os << "\\html_latex_start " << html_latex_start << '\n';
1286 if (!html_latex_end.empty())
1287 os << "\\html_latex_end " << html_latex_end << '\n';
1289 os << pimpl_->authorlist;
1293 void BufferParams::validate(LaTeXFeatures & features) const
1295 features.require(documentClass().requires());
1297 if (columns > 1 && language->rightToLeft())
1298 features.require("rtloutputdblcol");
1300 if (output_changes) {
1301 bool dvipost = LaTeXFeatures::isAvailable("dvipost");
1302 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1303 LaTeXFeatures::isAvailable("xcolor");
1305 switch (features.runparams().flavor) {
1306 case OutputParams::LATEX:
1307 case OutputParams::DVILUATEX:
1309 features.require("ct-dvipost");
1310 features.require("dvipost");
1311 } else if (xcolorulem) {
1312 features.require("ct-xcolor-ulem");
1313 features.require("ulem");
1314 features.require("xcolor");
1316 features.require("ct-none");
1319 case OutputParams::LUATEX:
1320 case OutputParams::PDFLATEX:
1321 case OutputParams::XETEX:
1323 features.require("ct-xcolor-ulem");
1324 features.require("ulem");
1325 features.require("xcolor");
1326 // improves color handling in PDF output
1327 features.require("pdfcolmk");
1329 features.require("ct-none");
1337 // Floats with 'Here definitely' as default setting.
1338 if (float_placement.find('H') != string::npos)
1339 features.require("float");
1341 for (PackageMap::const_iterator it = use_packages.begin();
1342 it != use_packages.end(); ++it) {
1343 if (it->first == "amsmath") {
1344 // AMS Style is at document level
1345 if (it->second == package_on ||
1346 features.isProvided("amsmath"))
1347 features.require(it->first);
1348 } else if (it->second == package_on)
1349 features.require(it->first);
1352 // Document-level line spacing
1353 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1354 features.require("setspace");
1356 // the bullet shapes are buffer level not paragraph level
1357 // so they are tested here
1358 for (int i = 0; i < 4; ++i) {
1359 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1361 int const font = user_defined_bullet(i).getFont();
1363 int const c = user_defined_bullet(i).getCharacter();
1369 features.require("latexsym");
1371 } else if (font == 1) {
1372 features.require("amssymb");
1373 } else if (font >= 2 && font <= 5) {
1374 features.require("pifont");
1378 if (pdfoptions().use_hyperref) {
1379 features.require("hyperref");
1380 // due to interferences with babel and hyperref, the color package has to
1381 // be loaded after hyperref when hyperref is used with the colorlinks
1382 // option, see http://www.lyx.org/trac/ticket/5291
1383 if (pdfoptions().colorlinks)
1384 features.require("color");
1386 if (!listings_params.empty()) {
1387 // do not test validity because listings_params is
1388 // supposed to be valid
1390 InsetListingsParams(listings_params).separatedParams(true);
1391 // we can't support all packages, but we should load the color package
1392 if (par.find("\\color", 0) != string::npos)
1393 features.require("color");
1396 // some languages are only available via polyglossia
1397 if (features.hasPolyglossiaExclusiveLanguages())
1398 features.require("polyglossia");
1400 if (useNonTeXFonts && fontsMath() != "auto")
1401 features.require("unicode-math");
1403 if (!language->requires().empty())
1404 features.require(language->requires());
1408 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1409 FileName const & filepath) const
1411 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1412 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1413 // \RequirePackage to do so, rather than the normal \usepackage
1414 // Do not try to load any other package before the document class, unless you
1415 // have a thorough understanding of the LATEX internals and know exactly what you
1417 if (features.mustProvide("fix-cm"))
1418 os << "\\RequirePackage{fix-cm}\n";
1419 // Likewise for fixltx2e. If other packages conflict with this policy,
1420 // treat it as a package bug (and report it!)
1421 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1422 if (features.mustProvide("fixltx2e"))
1423 os << "\\RequirePackage{fixltx2e}\n";
1425 os << "\\documentclass";
1427 DocumentClass const & tclass = documentClass();
1429 ostringstream clsoptions; // the document class options.
1431 if (tokenPos(tclass.opt_fontsize(),
1432 '|', fontsize) >= 0) {
1433 // only write if existing in list (and not default)
1434 clsoptions << fontsize << "pt,";
1437 // all paper sizes except of A4, A5, B5 and the US sizes need the
1439 bool nonstandard_papersize = papersize != PAPER_DEFAULT
1440 && papersize != PAPER_USLETTER
1441 && papersize != PAPER_USLEGAL
1442 && papersize != PAPER_USEXECUTIVE
1443 && papersize != PAPER_A4
1444 && papersize != PAPER_A5
1445 && papersize != PAPER_B5;
1447 if (!use_geometry) {
1448 switch (papersize) {
1450 clsoptions << "a4paper,";
1452 case PAPER_USLETTER:
1453 clsoptions << "letterpaper,";
1456 clsoptions << "a5paper,";
1459 clsoptions << "b5paper,";
1461 case PAPER_USEXECUTIVE:
1462 clsoptions << "executivepaper,";
1465 clsoptions << "legalpaper,";
1499 if (sides != tclass.sides()) {
1502 clsoptions << "oneside,";
1505 clsoptions << "twoside,";
1511 if (columns != tclass.columns()) {
1513 clsoptions << "twocolumn,";
1515 clsoptions << "onecolumn,";
1519 && orientation == ORIENTATION_LANDSCAPE)
1520 clsoptions << "landscape,";
1522 // language should be a parameter to \documentclass
1523 if (language->babel() == "hebrew"
1524 && default_language->babel() != "hebrew")
1525 // This seems necessary
1526 features.useLanguage(default_language);
1528 ostringstream language_options;
1529 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1530 bool const use_polyglossia = features.usePolyglossia();
1531 bool const global = lyxrc.language_global_options;
1532 if (use_babel || (use_polyglossia && global)) {
1533 language_options << features.getBabelLanguages();
1534 if (!language->babel().empty()) {
1535 if (!language_options.str().empty())
1536 language_options << ',';
1537 language_options << language->babel();
1539 if (global && !features.needBabelLangOptions()
1540 && !language_options.str().empty())
1541 clsoptions << language_options.str() << ',';
1544 // the predefined options from the layout
1545 if (use_default_options && !tclass.options().empty())
1546 clsoptions << tclass.options() << ',';
1548 // the user-defined options
1549 if (!options.empty()) {
1550 clsoptions << options << ',';
1553 string strOptions(clsoptions.str());
1554 if (!strOptions.empty()) {
1555 strOptions = rtrim(strOptions, ",");
1557 os << '[' << from_utf8(strOptions) << ']';
1560 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1561 // end of \documentclass defs
1563 // if we use fontspec or newtxmath, we have to load the AMS packages here
1564 string const ams = features.loadAMSPackages();
1565 bool const ot1 = (font_encoding() == "default" || font_encoding() == "OT1");
1566 bool const use_newtxmath =
1567 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1568 ot1, false, false) == "newtxmath";
1569 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1570 os << from_ascii(ams);
1572 if (useNonTeXFonts) {
1573 os << "\\usepackage{fontspec}\n";
1574 if (features.mustProvide("unicode-math")
1575 && features.isAvailable("unicode-math"))
1576 os << "\\usepackage{unicode-math}\n";
1579 // font selection must be done before loading fontenc.sty
1580 string const fonts = loadFonts(features);
1582 os << from_utf8(fonts);
1584 if (fonts_default_family != "default")
1585 os << "\\renewcommand{\\familydefault}{\\"
1586 << from_ascii(fonts_default_family) << "}\n";
1588 // set font encoding
1589 // XeTeX and LuaTeX (with OS fonts) do not need fontenc
1590 if (!useNonTeXFonts && !features.isProvided("fontenc")
1591 && font_encoding() != "default") {
1592 // get main font encodings
1593 vector<string> fontencs = font_encodings();
1594 // get font encodings of secondary languages
1595 features.getFontEncodings(fontencs);
1596 if (!fontencs.empty()) {
1597 os << "\\usepackage["
1598 << from_ascii(getStringFromVector(fontencs))
1603 // handle inputenc etc.
1604 writeEncodingPreamble(os, features);
1607 if (!features.runparams().includeall && !included_children_.empty()) {
1608 os << "\\includeonly{";
1609 list<string>::const_iterator it = included_children_.begin();
1610 list<string>::const_iterator en = included_children_.end();
1612 for (; it != en; ++it) {
1613 string incfile = *it;
1614 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1615 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1617 if (!features.runparams().nice)
1619 // \includeonly doesn't want an extension
1620 incfile = changeExtension(incfile, string());
1621 incfile = support::latex_path(incfile);
1622 if (!incfile.empty()) {
1625 os << from_utf8(incfile);
1632 if (!features.isProvided("geometry")
1633 && (use_geometry || nonstandard_papersize)) {
1634 odocstringstream ods;
1635 if (!getGraphicsDriver("geometry").empty())
1636 ods << getGraphicsDriver("geometry");
1637 if (orientation == ORIENTATION_LANDSCAPE)
1638 ods << ",landscape";
1639 switch (papersize) {
1641 if (!paperwidth.empty())
1642 ods << ",paperwidth="
1643 << from_ascii(paperwidth);
1644 if (!paperheight.empty())
1645 ods << ",paperheight="
1646 << from_ascii(paperheight);
1648 case PAPER_USLETTER:
1649 ods << ",letterpaper";
1652 ods << ",legalpaper";
1654 case PAPER_USEXECUTIVE:
1655 ods << ",executivepaper";
1744 docstring const g_options = trim(ods.str(), ",");
1745 os << "\\usepackage";
1746 if (!g_options.empty())
1747 os << '[' << g_options << ']';
1748 os << "{geometry}\n";
1749 // output this only if use_geometry is true
1751 os << "\\geometry{verbose";
1752 if (!topmargin.empty())
1753 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1754 if (!bottommargin.empty())
1755 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1756 if (!leftmargin.empty())
1757 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1758 if (!rightmargin.empty())
1759 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1760 if (!headheight.empty())
1761 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1762 if (!headsep.empty())
1763 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1764 if (!footskip.empty())
1765 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1766 if (!columnsep.empty())
1767 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1770 } else if (orientation == ORIENTATION_LANDSCAPE
1771 || papersize != PAPER_DEFAULT) {
1772 features.require("papersize");
1775 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
1776 if (pagestyle == "fancy")
1777 os << "\\usepackage{fancyhdr}\n";
1778 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1781 // only output when the background color is not default
1782 if (isbackgroundcolor == true) {
1783 // only require color here, the background color will be defined
1784 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1786 features.require("color");
1787 features.require("pagecolor");
1790 // only output when the font color is not default
1791 if (isfontcolor == true) {
1792 // only require color here, the font color will be defined
1793 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1795 features.require("color");
1796 features.require("fontcolor");
1799 // Only if class has a ToC hierarchy
1800 if (tclass.hasTocLevels()) {
1801 if (secnumdepth != tclass.secnumdepth()) {
1802 os << "\\setcounter{secnumdepth}{"
1806 if (tocdepth != tclass.tocdepth()) {
1807 os << "\\setcounter{tocdepth}{"
1813 if (paragraph_separation) {
1814 // when skip separation
1815 switch (getDefSkip().kind()) {
1816 case VSpace::SMALLSKIP:
1817 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1819 case VSpace::MEDSKIP:
1820 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1822 case VSpace::BIGSKIP:
1823 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1825 case VSpace::LENGTH:
1826 os << "\\setlength{\\parskip}{"
1827 << from_utf8(getDefSkip().length().asLatexString())
1830 default: // should never happen // Then delete it.
1831 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1834 os << "\\setlength{\\parindent}{0pt}\n";
1836 // when separation by indentation
1837 // only output something when a width is given
1838 if (getIndentation().asLyXCommand() != "default") {
1839 os << "\\setlength{\\parindent}{"
1840 << from_utf8(getIndentation().asLatexCommand())
1845 // Now insert the LyX specific LaTeX commands...
1846 docstring lyxpreamble;
1847 features.resolveAlternatives();
1850 if (!output_sync_macro.empty())
1851 lyxpreamble += from_utf8(output_sync_macro) +"\n";
1852 else if (features.runparams().flavor == OutputParams::LATEX)
1853 lyxpreamble += "\\usepackage[active]{srcltx}\n";
1854 else if (features.runparams().flavor == OutputParams::PDFLATEX)
1855 lyxpreamble += "\\synctex=-1\n";
1858 // The package options (via \PassOptionsToPackage)
1859 lyxpreamble += from_ascii(features.getPackageOptions());
1861 // due to interferences with babel and hyperref, the color package has to
1862 // be loaded (when it is not already loaded) before babel when hyperref
1863 // is used with the colorlinks option, see
1864 // http://www.lyx.org/trac/ticket/5291
1865 // we decided therefore to load color always before babel, see
1866 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
1867 lyxpreamble += from_ascii(features.getColorOptions());
1869 // If we use hyperref, jurabib, japanese, varioref or vietnamese,
1870 // we have to call babel before
1872 && (features.isRequired("jurabib")
1873 || features.isRequired("hyperref")
1874 || features.isRequired("varioref")
1875 || features.isRequired("vietnamese")
1876 || features.isRequired("japanese"))) {
1878 lyxpreamble += from_utf8(features.getBabelPresettings());
1879 lyxpreamble += from_utf8(babelCall(language_options.str(),
1880 features.needBabelLangOptions())) + '\n';
1881 lyxpreamble += from_utf8(features.getBabelPostsettings());
1884 // The optional packages;
1885 lyxpreamble += from_ascii(features.getPackages());
1887 // Additional Indices
1888 if (features.isRequired("splitidx")) {
1889 IndicesList::const_iterator iit = indiceslist().begin();
1890 IndicesList::const_iterator iend = indiceslist().end();
1891 for (; iit != iend; ++iit) {
1892 pair<docstring, docstring> indexname_latex =
1893 features.runparams().encoding->latexString(iit->index(),
1894 features.runparams().dryrun);
1895 if (!indexname_latex.second.empty()) {
1896 // issue a warning about omitted characters
1897 // FIXME: should be passed to the error dialog
1898 frontend::Alert::warning(_("Uncodable characters"),
1899 bformat(_("The following characters that are used in an index name are not\n"
1900 "representable in the current encoding and therefore have been omitted:\n%1$s."),
1901 indexname_latex.second));
1903 lyxpreamble += "\\newindex[";
1904 lyxpreamble += indexname_latex.first;
1905 lyxpreamble += "]{";
1906 lyxpreamble += escape(iit->shortcut());
1907 lyxpreamble += "}\n";
1912 lyxpreamble += from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
1915 // * Hyperref manual: "Make sure it comes last of your loaded
1916 // packages, to give it a fighting chance of not being over-written,
1917 // since its job is to redefine many LaTeX commands."
1918 // * Email from Heiko Oberdiek: "It is usually better to load babel
1919 // before hyperref. Then hyperref has a chance to detect babel.
1920 // * Has to be loaded before the "LyX specific LaTeX commands" to
1921 // avoid errors with algorithm floats.
1922 // use hyperref explicitly if it is required
1923 if (features.isRequired("hyperref")) {
1924 // pass what we have to stream here, since we need
1925 // to access the stream itself in PDFOptions.
1928 OutputParams tmp_params = features.runparams();
1929 pdfoptions().writeLaTeX(tmp_params, os,
1930 features.isProvided("hyperref"));
1931 // set back for the rest
1932 lyxpreamble.clear();
1933 // correctly break URLs with hyperref and dvi output
1934 if (features.runparams().flavor == OutputParams::LATEX
1935 && features.isAvailable("breakurl"))
1936 lyxpreamble += "\\usepackage{breakurl}\n";
1937 } else if (features.isRequired("nameref"))
1938 // hyperref loads this automatically
1939 lyxpreamble += "\\usepackage{nameref}\n";
1941 // bibtopic needs to be loaded after hyperref.
1942 // the dot provides the aux file naming which LyX can detect.
1943 if (features.mustProvide("bibtopic"))
1944 lyxpreamble += "\\usepackage[dot]{bibtopic}\n";
1946 // Will be surrounded by \makeatletter and \makeatother when not empty
1947 docstring atlyxpreamble;
1949 // Some macros LyX will need
1950 docstring tmppreamble(features.getMacros());
1952 if (!tmppreamble.empty())
1953 atlyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1954 "LyX specific LaTeX commands.\n"
1955 + tmppreamble + '\n';
1957 // the text class specific preamble
1958 tmppreamble = features.getTClassPreamble();
1959 if (!tmppreamble.empty())
1960 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1961 "Textclass specific LaTeX commands.\n"
1962 + tmppreamble + '\n';
1964 // suppress date if selected
1965 // use \@ifundefined because we cannot be sure that every document class
1966 // has a \date command
1968 atlyxpreamble += "\\@ifundefined{date}{}{\\date{}}\n";
1970 /* the user-defined preamble */
1971 if (!containsOnly(preamble, " \n\t")) {
1973 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1974 "User specified LaTeX commands.\n";
1976 // Check if the user preamble contains uncodable glyphs
1977 docstring const u_preamble = from_utf8(preamble);
1978 odocstringstream user_preamble;
1979 docstring uncodable_glyphs;
1980 Encoding const * const enc = features.runparams().encoding;
1982 for (size_t n = 0; n < u_preamble.size(); ++n) {
1983 char_type c = u_preamble[n];
1984 if (!enc->encodable(c)) {
1985 docstring const glyph(1, c);
1986 LYXERR0("Uncodable character '"
1988 << "' in user preamble!");
1989 uncodable_glyphs += glyph;
1990 if (features.runparams().dryrun) {
1991 user_preamble << "<" << _("LyX Warning: ")
1992 << _("uncodable character") << " '";
1993 user_preamble.put(c);
1994 user_preamble << "'>";
1997 user_preamble.put(c);
2000 user_preamble << u_preamble;
2002 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2003 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2004 frontend::Alert::warning(
2005 _("Uncodable character in user preamble"),
2007 _("The user preamble of your document contains glyphs "
2008 "that are unknown in the current document encoding "
2009 "(namely %1$s).\nThese glyphs are omitted "
2010 " from the output, which may result in "
2011 "incomplete output."
2012 "\n\nPlease select an appropriate "
2013 "document encoding\n"
2014 "(such as utf8) or change the "
2015 "preamble code accordingly."),
2018 atlyxpreamble += user_preamble.str() + '\n';
2021 // footmisc must be loaded after setspace
2022 // Load it here to avoid clashes with footmisc loaded in the user
2023 // preamble. For that reason we also pass the options via
2024 // \PassOptionsToPackage in getPreamble() and not here.
2025 if (features.mustProvide("footmisc"))
2026 atlyxpreamble += "\\usepackage{footmisc}\n";
2028 // subfig loads internally the LaTeX package "caption". As
2029 // caption is a very popular package, users will load it in
2030 // the preamble. Therefore we must load subfig behind the
2031 // user-defined preamble and check if the caption package was
2032 // loaded or not. For the case that caption is loaded before
2033 // subfig, there is the subfig option "caption=false". This
2034 // option also works when a koma-script class is used and
2035 // koma's own caption commands are used instead of caption. We
2036 // use \PassOptionsToPackage here because the user could have
2037 // already loaded subfig in the preamble.
2038 if (features.isRequired("subfig")) {
2039 atlyxpreamble += "\\@ifundefined{showcaptionsetup}{}{%\n"
2040 " \\PassOptionsToPackage{caption=false}{subfig}}\n"
2041 "\\usepackage{subfig}\n";
2044 // Itemize bullet settings need to be last in case the user
2045 // defines their own bullets that use a package included
2046 // in the user-defined preamble -- ARRae
2047 // Actually it has to be done much later than that
2048 // since some packages like frenchb make modifications
2049 // at \begin{document} time -- JMarc
2050 docstring bullets_def;
2051 for (int i = 0; i < 4; ++i) {
2052 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2053 if (bullets_def.empty())
2054 bullets_def += "\\AtBeginDocument{\n";
2055 bullets_def += " \\def\\labelitemi";
2057 // `i' is one less than the item to modify
2064 bullets_def += "ii";
2070 bullets_def += '{' +
2071 user_defined_bullet(i).getText()
2076 if (!bullets_def.empty())
2077 atlyxpreamble += bullets_def + "}\n\n";
2079 if (!atlyxpreamble.empty())
2080 lyxpreamble += "\n\\makeatletter\n"
2081 + atlyxpreamble + "\\makeatother\n\n";
2083 // We try to load babel late, in case it interferes with other packages.
2084 // Jurabib, hyperref, varioref, bicaption and listings (bug 8995) have to be
2085 // called after babel, though.
2086 if (use_babel && !features.isRequired("jurabib")
2087 && !features.isRequired("hyperref")
2088 && !features.isRequired("varioref")
2089 && !features.isRequired("vietnamese")
2090 && !features.isRequired("japanese")) {
2092 lyxpreamble += from_utf8(features.getBabelPresettings());
2093 lyxpreamble += from_utf8(babelCall(language_options.str(),
2094 features.needBabelLangOptions())) + '\n';
2095 lyxpreamble += from_utf8(features.getBabelPostsettings());
2097 if (features.isRequired("bicaption"))
2098 lyxpreamble += "\\usepackage{bicaption}\n";
2099 if (!listings_params.empty() || features.isRequired("listings"))
2100 lyxpreamble += "\\usepackage{listings}\n";
2101 if (!listings_params.empty()) {
2102 lyxpreamble += "\\lstset{";
2103 // do not test validity because listings_params is
2104 // supposed to be valid
2106 InsetListingsParams(listings_params).separatedParams(true);
2107 lyxpreamble += from_utf8(par);
2108 lyxpreamble += "}\n";
2111 // xunicode needs to be loaded at least after amsmath, amssymb,
2112 // esint and the other packages that provide special glyphs
2113 if (features.runparams().flavor == OutputParams::XETEX
2115 lyxpreamble += "\\usepackage{xunicode}\n";
2117 // Polyglossia must be loaded last
2118 if (use_polyglossia) {
2120 lyxpreamble += "\\usepackage{polyglossia}\n";
2121 // set the main language
2122 lyxpreamble += "\\setdefaultlanguage";
2123 if (!language->polyglossiaOpts().empty())
2124 lyxpreamble += "[" + from_ascii(language->polyglossiaOpts()) + "]";
2125 lyxpreamble += "{" + from_ascii(language->polyglossia()) + "}\n";
2126 // now setup the other languages
2127 std::map<std::string, std::string> const polylangs =
2128 features.getPolyglossiaLanguages();
2129 for (std::map<std::string, std::string>::const_iterator mit = polylangs.begin();
2130 mit != polylangs.end() ; ++mit) {
2131 lyxpreamble += "\\setotherlanguage";
2132 if (!mit->second.empty())
2133 lyxpreamble += "[" + from_ascii(mit->second) + "]";
2134 lyxpreamble += "{" + from_ascii(mit->first) + "}\n";
2138 // Load custom language package here
2139 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2140 if (lang_package == "default")
2141 lyxpreamble += from_utf8(lyxrc.language_custom_package);
2143 lyxpreamble += from_utf8(lang_package);
2144 lyxpreamble += '\n';
2147 docstring const i18npreamble =
2148 features.getTClassI18nPreamble(use_babel, use_polyglossia);
2149 if (!i18npreamble.empty())
2150 lyxpreamble += i18npreamble + '\n';
2158 void BufferParams::useClassDefaults()
2160 DocumentClass const & tclass = documentClass();
2162 sides = tclass.sides();
2163 columns = tclass.columns();
2164 pagestyle = tclass.pagestyle();
2165 use_default_options = true;
2166 // Only if class has a ToC hierarchy
2167 if (tclass.hasTocLevels()) {
2168 secnumdepth = tclass.secnumdepth();
2169 tocdepth = tclass.tocdepth();
2174 bool BufferParams::hasClassDefaults() const
2176 DocumentClass const & tclass = documentClass();
2178 return sides == tclass.sides()
2179 && columns == tclass.columns()
2180 && pagestyle == tclass.pagestyle()
2181 && use_default_options
2182 && secnumdepth == tclass.secnumdepth()
2183 && tocdepth == tclass.tocdepth();
2187 DocumentClass const & BufferParams::documentClass() const
2189 return *doc_class_.get();
2193 DocumentClassConstPtr BufferParams::documentClassPtr() const
2199 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2201 // evil, but this function is evil
2202 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2206 bool BufferParams::setBaseClass(string const & classname)
2208 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2209 LayoutFileList & bcl = LayoutFileList::get();
2210 if (!bcl.haveClass(classname)) {
2212 bformat(_("The layout file:\n"
2214 "could not be found. A default textclass with default\n"
2215 "layouts will be used. LyX will not be able to produce\n"
2217 from_utf8(classname));
2218 frontend::Alert::error(_("Document class not found"), s);
2219 bcl.addEmptyClass(classname);
2222 bool const success = bcl[classname].load();
2225 bformat(_("Due to some error in it, the layout file:\n"
2227 "could not be loaded. A default textclass with default\n"
2228 "layouts will be used. LyX will not be able to produce\n"
2230 from_utf8(classname));
2231 frontend::Alert::error(_("Could not load class"), s);
2232 bcl.addEmptyClass(classname);
2235 pimpl_->baseClass_ = classname;
2236 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2241 LayoutFile const * BufferParams::baseClass() const
2243 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2244 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2250 LayoutFileIndex const & BufferParams::baseClassID() const
2252 return pimpl_->baseClass_;
2256 void BufferParams::makeDocumentClass(bool const clone)
2261 LayoutModuleList mods;
2262 LayoutModuleList::iterator it = layout_modules_.begin();
2263 LayoutModuleList::iterator en = layout_modules_.end();
2264 for (; it != en; ++it)
2265 mods.push_back(*it);
2267 it = cite_engine_.begin();
2268 en = cite_engine_.end();
2269 for (; it != en; ++it)
2270 mods.push_back(*it);
2272 doc_class_ = getDocumentClass(*baseClass(), mods, clone);
2274 TextClass::ReturnValues success = TextClass::OK;
2275 if (!forced_local_layout_.empty())
2276 success = doc_class_->read(forced_local_layout_, TextClass::MODULE);
2277 if (!local_layout_.empty() &&
2278 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2279 success = doc_class_->read(local_layout_, TextClass::MODULE);
2280 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2281 docstring const msg = _("Error reading internal layout information");
2282 frontend::Alert::warning(_("Read Error"), msg);
2287 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2289 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2293 bool BufferParams::citationModuleCanBeAdded(string const & modName) const
2295 return cite_engine_.moduleCanBeAdded(modName, baseClass());
2299 std::string BufferParams::getLocalLayout(bool forced) const
2302 return doc_class_->forcedLayouts();
2304 return local_layout_;
2308 void BufferParams::setLocalLayout(string const & layout, bool forced)
2311 forced_local_layout_ = layout;
2313 local_layout_ = layout;
2317 bool BufferParams::addLayoutModule(string const & modName)
2319 LayoutModuleList::const_iterator it = layout_modules_.begin();
2320 LayoutModuleList::const_iterator end = layout_modules_.end();
2321 for (; it != end; ++it)
2324 layout_modules_.push_back(modName);
2329 string BufferParams::bufferFormat() const
2331 string format = documentClass().outputFormat();
2332 if (format == "latex") {
2334 return "xetex"; // actually "xetex or luatex"
2335 if (encoding().package() == Encoding::japanese)
2342 bool BufferParams::isExportable(string const & format) const
2344 vector<string> backs = backends();
2345 for (vector<string>::const_iterator it = backs.begin();
2346 it != backs.end(); ++it)
2347 if (theConverters().isReachable(*it, format))
2353 vector<Format const *> BufferParams::exportableFormats(bool only_viewable) const
2355 vector<string> const backs = backends();
2356 set<string> excludes;
2357 if (useNonTeXFonts) {
2358 excludes.insert("latex");
2359 excludes.insert("pdflatex");
2361 vector<Format const *> result =
2362 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2363 for (vector<string>::const_iterator it = backs.begin() + 1;
2364 it != backs.end(); ++it) {
2365 vector<Format const *> r =
2366 theConverters().getReachable(*it, only_viewable, false, excludes);
2367 result.insert(result.end(), r.begin(), r.end());
2373 bool BufferParams::isExportableFormat(string const & format) const
2375 typedef vector<Format const *> Formats;
2377 formats = exportableFormats(true);
2378 Formats::const_iterator fit = formats.begin();
2379 Formats::const_iterator end = formats.end();
2380 for (; fit != end ; ++fit) {
2381 if ((*fit)->name() == format)
2388 vector<string> BufferParams::backends() const
2391 string const buffmt = bufferFormat();
2393 // FIXME: Don't hardcode format names here, but use a flag
2394 if (buffmt == "latex") {
2395 if (!useNonTeXFonts) {
2396 v.push_back("pdflatex");
2397 v.push_back("latex");
2399 v.push_back("luatex");
2400 v.push_back("dviluatex");
2401 v.push_back("xetex");
2402 } else if (buffmt == "xetex") {
2403 v.push_back("xetex");
2404 // FIXME: need to test all languages (bug 8205)
2405 if (!language || !language->isPolyglossiaExclusive()) {
2406 v.push_back("luatex");
2407 v.push_back("dviluatex");
2410 v.push_back(buffmt);
2412 v.push_back("xhtml");
2413 v.push_back("text");
2419 OutputParams::FLAVOR BufferParams::getOutputFlavor(string const & format) const
2421 string const dformat = (format.empty() || format == "default") ?
2422 getDefaultOutputFormat() : format;
2423 DefaultFlavorCache::const_iterator it =
2424 default_flavors_.find(dformat);
2426 if (it != default_flavors_.end())
2429 OutputParams::FLAVOR result = OutputParams::LATEX;
2431 // FIXME It'd be better not to hardcode this, but to do
2432 // something with formats.
2433 if (dformat == "xhtml")
2434 result = OutputParams::HTML;
2435 else if (dformat == "text")
2436 result = OutputParams::TEXT;
2437 else if (dformat == "lyx")
2438 result = OutputParams::LYX;
2439 else if (dformat == "pdflatex")
2440 result = OutputParams::PDFLATEX;
2441 else if (dformat == "xetex")
2442 result = OutputParams::XETEX;
2443 else if (dformat == "luatex")
2444 result = OutputParams::LUATEX;
2445 else if (dformat == "dviluatex")
2446 result = OutputParams::DVILUATEX;
2448 // Try to determine flavor of default output format
2449 vector<string> backs = backends();
2450 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2451 // Get shortest path to format
2452 Graph::EdgePath path;
2453 for (vector<string>::const_iterator it = backs.begin();
2454 it != backs.end(); ++it) {
2455 Graph::EdgePath p = theConverters().getPath(*it, dformat);
2456 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2461 result = theConverters().getFlavor(path);
2464 // cache this flavor
2465 default_flavors_[dformat] = result;
2470 string BufferParams::getDefaultOutputFormat() const
2472 if (!default_output_format.empty()
2473 && default_output_format != "default")
2474 return default_output_format;
2476 || encoding().package() == Encoding::japanese) {
2477 vector<Format const *> const formats = exportableFormats(true);
2478 if (formats.empty())
2480 // return the first we find
2481 return formats.front()->name();
2484 return lyxrc.default_otf_view_format;
2485 return lyxrc.default_view_format;
2488 Font const BufferParams::getFont() const
2490 FontInfo f = documentClass().defaultfont();
2491 if (fonts_default_family == "rmdefault")
2492 f.setFamily(ROMAN_FAMILY);
2493 else if (fonts_default_family == "sfdefault")
2494 f.setFamily(SANS_FAMILY);
2495 else if (fonts_default_family == "ttdefault")
2496 f.setFamily(TYPEWRITER_FAMILY);
2497 return Font(f, language);
2501 InsetQuotes::QuoteLanguage BufferParams::getQuoteStyle(string const & qs) const
2503 return quoteslangtranslator().find(qs);
2507 bool BufferParams::isLatex() const
2509 return documentClass().outputType() == LATEX;
2513 bool BufferParams::isLiterate() const
2515 return documentClass().outputType() == LITERATE;
2519 bool BufferParams::isDocBook() const
2521 return documentClass().outputType() == DOCBOOK;
2525 void BufferParams::readPreamble(Lexer & lex)
2527 if (lex.getString() != "\\begin_preamble")
2528 lyxerr << "Error (BufferParams::readPreamble):"
2529 "consistency check failed." << endl;
2531 preamble = lex.getLongString("\\end_preamble");
2535 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2537 string const expected = forced ? "\\begin_forced_local_layout" :
2538 "\\begin_local_layout";
2539 if (lex.getString() != expected)
2540 lyxerr << "Error (BufferParams::readLocalLayout):"
2541 "consistency check failed." << endl;
2544 forced_local_layout_ =
2545 lex.getLongString("\\end_forced_local_layout");
2547 local_layout_ = lex.getLongString("\\end_local_layout");
2551 bool BufferParams::setLanguage(string const & lang)
2553 Language const *new_language = languages.getLanguage(lang);
2554 if (!new_language) {
2555 // Language lang was not found
2558 language = new_language;
2563 void BufferParams::readLanguage(Lexer & lex)
2565 if (!lex.next()) return;
2567 string const tmptok = lex.getString();
2569 // check if tmptok is part of tex_babel in tex-defs.h
2570 if (!setLanguage(tmptok)) {
2571 // Language tmptok was not found
2572 language = default_language;
2573 lyxerr << "Warning: Setting language `"
2574 << tmptok << "' to `" << language->lang()
2580 void BufferParams::readGraphicsDriver(Lexer & lex)
2585 string const tmptok = lex.getString();
2586 // check if tmptok is part of tex_graphics in tex_defs.h
2589 string const test = tex_graphics[n++];
2591 if (test == tmptok) {
2592 graphics_driver = tmptok;
2597 "Warning: graphics driver `$$Token' not recognized!\n"
2598 " Setting graphics driver to `default'.\n");
2599 graphics_driver = "default";
2606 void BufferParams::readBullets(Lexer & lex)
2611 int const index = lex.getInteger();
2613 int temp_int = lex.getInteger();
2614 user_defined_bullet(index).setFont(temp_int);
2615 temp_bullet(index).setFont(temp_int);
2617 user_defined_bullet(index).setCharacter(temp_int);
2618 temp_bullet(index).setCharacter(temp_int);
2620 user_defined_bullet(index).setSize(temp_int);
2621 temp_bullet(index).setSize(temp_int);
2625 void BufferParams::readBulletsLaTeX(Lexer & lex)
2627 // The bullet class should be able to read this.
2630 int const index = lex.getInteger();
2632 docstring const temp_str = lex.getDocString();
2634 user_defined_bullet(index).setText(temp_str);
2635 temp_bullet(index).setText(temp_str);
2639 void BufferParams::readModules(Lexer & lex)
2641 if (!lex.eatLine()) {
2642 lyxerr << "Error (BufferParams::readModules):"
2643 "Unexpected end of input." << endl;
2647 string mod = lex.getString();
2648 if (mod == "\\end_modules")
2650 addLayoutModule(mod);
2656 void BufferParams::readRemovedModules(Lexer & lex)
2658 if (!lex.eatLine()) {
2659 lyxerr << "Error (BufferParams::readRemovedModules):"
2660 "Unexpected end of input." << endl;
2664 string mod = lex.getString();
2665 if (mod == "\\end_removed_modules")
2667 removed_modules_.push_back(mod);
2670 // now we want to remove any removed modules that were previously
2671 // added. normally, that will be because default modules were added in
2672 // setBaseClass(), which gets called when \textclass is read at the
2673 // start of the read.
2674 list<string>::const_iterator rit = removed_modules_.begin();
2675 list<string>::const_iterator const ren = removed_modules_.end();
2676 for (; rit != ren; ++rit) {
2677 LayoutModuleList::iterator const mit = layout_modules_.begin();
2678 LayoutModuleList::iterator const men = layout_modules_.end();
2679 LayoutModuleList::iterator found = find(mit, men, *rit);
2682 layout_modules_.erase(found);
2687 void BufferParams::readIncludeonly(Lexer & lex)
2689 if (!lex.eatLine()) {
2690 lyxerr << "Error (BufferParams::readIncludeonly):"
2691 "Unexpected end of input." << endl;
2695 string child = lex.getString();
2696 if (child == "\\end_includeonly")
2698 included_children_.push_back(child);
2704 string BufferParams::paperSizeName(PapersizePurpose purpose) const
2706 switch (papersize) {
2708 // could be anything, so don't guess
2710 case PAPER_CUSTOM: {
2711 if (purpose == XDVI && !paperwidth.empty() &&
2712 !paperheight.empty()) {
2713 // heightxwidth<unit>
2714 string first = paperwidth;
2715 string second = paperheight;
2716 if (orientation == ORIENTATION_LANDSCAPE)
2719 return first.erase(first.length() - 2)
2725 // dvips and dvipdfm do not know this
2726 if (purpose == DVIPS || purpose == DVIPDFM)
2730 if (purpose == DVIPS || purpose == DVIPDFM)
2734 if (purpose == DVIPS || purpose == DVIPDFM)
2744 if (purpose == DVIPS || purpose == DVIPDFM)
2748 if (purpose == DVIPS || purpose == DVIPDFM)
2752 if (purpose == DVIPS || purpose == DVIPDFM)
2756 if (purpose == DVIPS || purpose == DVIPDFM)
2760 if (purpose == DVIPS || purpose == DVIPDFM)
2764 // dvipdfm does not know this
2765 if (purpose == DVIPDFM)
2769 if (purpose == DVIPDFM)
2773 if (purpose == DVIPS || purpose == DVIPDFM)
2777 if (purpose == DVIPS || purpose == DVIPDFM)
2781 if (purpose == DVIPS || purpose == DVIPDFM)
2785 if (purpose == DVIPS || purpose == DVIPDFM)
2789 if (purpose == DVIPS || purpose == DVIPDFM)
2793 if (purpose == DVIPS || purpose == DVIPDFM)
2797 if (purpose == DVIPS || purpose == DVIPDFM)
2801 if (purpose == DVIPS || purpose == DVIPDFM)
2805 if (purpose == DVIPS || purpose == DVIPDFM)
2809 if (purpose == DVIPS || purpose == DVIPDFM)
2813 if (purpose == DVIPS || purpose == DVIPDFM)
2817 if (purpose == DVIPS || purpose == DVIPDFM)
2821 if (purpose == DVIPS || purpose == DVIPDFM)
2825 if (purpose == DVIPS || purpose == DVIPDFM)
2829 if (purpose == DVIPS || purpose == DVIPDFM)
2832 case PAPER_USEXECUTIVE:
2833 // dvipdfm does not know this
2834 if (purpose == DVIPDFM)
2839 case PAPER_USLETTER:
2841 if (purpose == XDVI)
2848 string const BufferParams::dvips_options() const
2852 // If the class loads the geometry package, we do not know which
2853 // paper size is used, since we do not set it (bug 7013).
2854 // Therefore we must not specify any argument here.
2855 // dvips gets the correct paper size via DVI specials in this case
2856 // (if the class uses the geometry package correctly).
2857 if (documentClass().provides("geometry"))
2861 && papersize == PAPER_CUSTOM
2862 && !lyxrc.print_paper_dimension_flag.empty()
2863 && !paperwidth.empty()
2864 && !paperheight.empty()) {
2865 // using a custom papersize
2866 result = lyxrc.print_paper_dimension_flag;
2867 result += ' ' + paperwidth;
2868 result += ',' + paperheight;
2870 string const paper_option = paperSizeName(DVIPS);
2871 if (!paper_option.empty() && (paper_option != "letter" ||
2872 orientation != ORIENTATION_LANDSCAPE)) {
2873 // dvips won't accept -t letter -t landscape.
2874 // In all other cases, include the paper size
2876 result = lyxrc.print_paper_flag;
2877 result += ' ' + paper_option;
2880 if (orientation == ORIENTATION_LANDSCAPE &&
2881 papersize != PAPER_CUSTOM)
2882 result += ' ' + lyxrc.print_landscape_flag;
2887 string const BufferParams::font_encoding() const
2889 return font_encodings().empty() ? "default" : font_encodings().back();
2893 vector<string> const BufferParams::font_encodings() const
2895 string doc_fontenc = (fontenc == "global") ? lyxrc.fontenc : fontenc;
2897 vector<string> fontencs;
2899 // "default" means "no explicit font encoding"
2900 if (doc_fontenc != "default") {
2901 fontencs = getVectorFromString(doc_fontenc);
2902 if (!language->fontenc().empty()
2903 && ascii_lowercase(language->fontenc()) != "none") {
2904 vector<string> fencs = getVectorFromString(language->fontenc());
2905 vector<string>::const_iterator fit = fencs.begin();
2906 for (; fit != fencs.end(); ++fit) {
2907 if (find(fontencs.begin(), fontencs.end(), *fit) == fontencs.end())
2908 fontencs.push_back(*fit);
2917 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
2919 // suppress the babel call if there is no BabelName defined
2920 // for the document language in the lib/languages file and if no
2921 // other languages are used (lang_opts is then empty)
2922 if (lang_opts.empty())
2924 // either a specific language (AsBabelOptions setting in
2925 // lib/languages) or the prefs require the languages to
2926 // be submitted to babel itself (not the class).
2928 return "\\usepackage[" + lang_opts + "]{babel}";
2929 return "\\usepackage{babel}";
2933 docstring BufferParams::getGraphicsDriver(string const & package) const
2937 if (package == "geometry") {
2938 if (graphics_driver == "dvips"
2939 || graphics_driver == "dvipdfm"
2940 || graphics_driver == "pdftex"
2941 || graphics_driver == "vtex")
2942 result = from_ascii(graphics_driver);
2943 else if (graphics_driver == "dvipdfmx")
2944 result = from_ascii("dvipdfm");
2951 void BufferParams::writeEncodingPreamble(otexstream & os,
2952 LaTeXFeatures & features) const
2954 // XeTeX/LuaTeX: (see also #9740)
2955 // With Unicode fonts we use utf8-plain without encoding package.
2956 // With TeX fonts, we cannot use utf8-plain, but "inputenc" fails.
2957 // XeTeX must use ASCII encoding, for LuaTeX, we load
2958 // "luainputenc" (see below).
2959 if (useNonTeXFonts || features.runparams().flavor == OutputParams::XETEX)
2962 if (inputenc == "auto") {
2963 string const doc_encoding =
2964 language->encoding()->latexName();
2965 Encoding::Package const package =
2966 language->encoding()->package();
2968 // Create list of inputenc options:
2969 set<string> encodings;
2970 // luainputenc fails with more than one encoding
2971 if (!features.runparams().isFullUnicode()) // if we reach this point, this means LuaTeX with TeX fonts
2972 // list all input encodings used in the document
2973 encodings = features.getEncodingSet(doc_encoding);
2975 // If the "japanese" package (i.e. pLaTeX) is used,
2976 // inputenc must be omitted.
2977 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
2978 if ((!encodings.empty() || package == Encoding::inputenc)
2979 && !features.isRequired("japanese")
2980 && !features.isProvided("inputenc")) {
2981 os << "\\usepackage[";
2982 set<string>::const_iterator it = encodings.begin();
2983 set<string>::const_iterator const end = encodings.end();
2985 os << from_ascii(*it);
2988 for (; it != end; ++it)
2989 os << ',' << from_ascii(*it);
2990 if (package == Encoding::inputenc) {
2991 if (!encodings.empty())
2993 os << from_ascii(doc_encoding);
2995 if (features.runparams().flavor == OutputParams::LUATEX
2996 || features.runparams().flavor == OutputParams::DVILUATEX)
2997 os << "]{luainputenc}\n";
2999 os << "]{inputenc}\n";
3001 if (package == Encoding::CJK || features.mustProvide("CJK")) {
3002 if (language->encoding()->name() == "utf8-cjk"
3003 && LaTeXFeatures::isAvailable("CJKutf8"))
3004 os << "\\usepackage{CJKutf8}\n";
3006 os << "\\usepackage{CJK}\n";
3008 } else if (inputenc != "default") {
3009 switch (encoding().package()) {
3010 case Encoding::none:
3011 case Encoding::japanese:
3013 case Encoding::inputenc:
3014 // do not load inputenc if japanese is used
3015 // or if the class provides inputenc
3016 if (features.isRequired("japanese")
3017 || features.isProvided("inputenc"))
3019 os << "\\usepackage[" << from_ascii(encoding().latexName());
3020 if (features.runparams().flavor == OutputParams::LUATEX
3021 || features.runparams().flavor == OutputParams::DVILUATEX)
3022 os << "]{luainputenc}\n";
3024 os << "]{inputenc}\n";
3027 if (encoding().name() == "utf8-cjk"
3028 && LaTeXFeatures::isAvailable("CJKutf8"))
3029 os << "\\usepackage{CJKutf8}\n";
3031 os << "\\usepackage{CJK}\n";
3034 // Load the CJK package if needed by a secondary language.
3035 // If the main encoding is some variant of UTF8, use CJKutf8.
3036 if (encoding().package() != Encoding::CJK && features.mustProvide("CJK")) {
3037 if (encoding().iconvName() == "UTF-8"
3038 && LaTeXFeatures::isAvailable("CJKutf8"))
3039 os << "\\usepackage{CJKutf8}\n";
3041 os << "\\usepackage{CJK}\n";
3047 string const BufferParams::parseFontName(string const & name) const
3049 string mangled = name;
3050 size_t const idx = mangled.find('[');
3051 if (idx == string::npos || idx == 0)
3054 return mangled.substr(0, idx - 1);
3058 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3060 if (fontsRoman() == "default" && fontsSans() == "default"
3061 && fontsTypewriter() == "default"
3062 && (fontsMath() == "default" || fontsMath() == "auto"))
3068 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3069 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3070 * Mapping=tex-text option assures TeX ligatures (such as "--")
3071 * are resolved. Note that tt does not use these ligatures.
3073 * -- add more GUI options?
3074 * -- add more fonts (fonts for other scripts)
3075 * -- if there's a way to find out if a font really supports
3076 * OldStyle, enable/disable the widget accordingly.
3078 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3079 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3080 // However, until v.2 (2010/07/11) fontspec only knew
3081 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3082 // was introduced for both XeTeX and LuaTeX (LuaTeX
3083 // didn't understand "Mapping=tex-text", while XeTeX
3084 // understood both. With most recent versions, both
3085 // variants are understood by both engines. However,
3086 // we want to provide support for at least TeXLive 2009
3087 // (for XeTeX; LuaTeX is only supported as of v.2)
3088 string const texmapping =
3089 (features.runparams().flavor == OutputParams::XETEX) ?
3090 "Mapping=tex-text" : "Ligatures=TeX";
3091 if (fontsRoman() != "default") {
3092 os << "\\setmainfont[" << texmapping;
3093 if (fonts_old_figures)
3094 os << ",Numbers=OldStyle";
3095 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3097 if (fontsSans() != "default") {
3098 string const sans = parseFontName(fontsSans());
3099 if (fontsSansScale() != 100)
3100 os << "\\setsansfont[Scale="
3101 << float(fontsSansScale()) / 100
3102 << "," << texmapping << "]{"
3105 os << "\\setsansfont[" << texmapping << "]{"
3108 if (fontsTypewriter() != "default") {
3109 string const mono = parseFontName(fontsTypewriter());
3110 if (fontsTypewriterScale() != 100)
3111 os << "\\setmonofont[Scale="
3112 << float(fontsTypewriterScale()) / 100
3116 os << "\\setmonofont{"
3123 bool const ot1 = (font_encoding() == "default" || font_encoding() == "OT1");
3124 bool const dryrun = features.runparams().dryrun;
3125 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3126 bool const nomath = (fontsMath() == "default");
3129 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3130 dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures,
3134 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3135 dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures,
3136 nomath, fontsSansScale());
3138 // MONOSPACED/TYPEWRITER
3139 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3140 dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures,
3141 nomath, fontsTypewriterScale());
3144 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3145 dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures,
3152 Encoding const & BufferParams::encoding() const
3154 // Main encoding for LaTeX output.
3156 // Exception: XeTeX with 8-bit TeX fonts requires ASCII (see #9740).
3157 // As the "flavor" is only known once export started, this
3158 // cannot be handled here. Instead, runparams.encoding is set
3159 // to ASCII in Buffer::makeLaTeXFile (for export)
3160 // and Buffer::writeLaTeXSource (for preview).
3162 return *(encodings.fromLyXName("utf8-plain"));
3163 if (inputenc == "auto" || inputenc == "default")
3164 return *language->encoding();
3165 Encoding const * const enc = encodings.fromLyXName(inputenc);
3168 LYXERR0("Unknown inputenc value `" << inputenc
3169 << "'. Using `auto' instead.");
3170 return *language->encoding();
3174 bool BufferParams::addCiteEngine(string const & engine)
3176 LayoutModuleList::const_iterator it = cite_engine_.begin();
3177 LayoutModuleList::const_iterator en = cite_engine_.end();
3178 for (; it != en; ++it)
3181 cite_engine_.push_back(engine);
3186 bool BufferParams::addCiteEngine(vector<string> const & engine)
3188 vector<string>::const_iterator it = engine.begin();
3189 vector<string>::const_iterator en = engine.end();
3191 for (; it != en; ++it)
3192 if (!addCiteEngine(*it))
3198 string const & BufferParams::defaultBiblioStyle() const
3200 return documentClass().defaultBiblioStyle();
3204 bool const & BufferParams::fullAuthorList() const
3206 return documentClass().fullAuthorList();
3210 void BufferParams::setCiteEngine(string const & engine)
3213 addCiteEngine(engine);
3217 void BufferParams::setCiteEngine(vector<string> const & engine)
3220 addCiteEngine(engine);
3224 vector<string> BufferParams::citeCommands() const
3226 static CitationStyle const default_style;
3227 vector<string> commands =
3228 documentClass().citeCommands(citeEngineType());
3229 if (commands.empty())
3230 commands.push_back(default_style.cmd);
3235 vector<CitationStyle> BufferParams::citeStyles() const
3237 static CitationStyle const default_style;
3238 vector<CitationStyle> styles =
3239 documentClass().citeStyles(citeEngineType());
3241 styles.push_back(default_style);