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"
41 #include "texstream.h"
44 #include "PDFOptions.h"
46 #include "frontends/alert.h"
48 #include "insets/InsetListingsParams.h"
50 #include "support/convert.h"
51 #include "support/debug.h"
52 #include "support/docstream.h"
53 #include "support/FileName.h"
54 #include "support/filetools.h"
55 #include "support/gettext.h"
56 #include "support/Messages.h"
57 #include "support/mutex.h"
58 #include "support/Package.h"
59 #include "support/Translator.h"
60 #include "support/lstrings.h"
66 using namespace lyx::support;
69 static char const * const string_paragraph_separation[] = {
74 static char const * const string_quotes_style[] = {
75 "english", "swedish", "german", "polish", "swiss", "danish", "plain",
76 "british", "swedishg", "french", "frenchin", "russian", ""
80 static char const * const string_papersize[] = {
81 "default", "custom", "letterpaper", "legalpaper", "executivepaper",
82 "a0paper", "a1paper", "a2paper", "a3paper", "a4paper", "a5paper",
83 "a6paper", "b0paper", "b1paper", "b2paper","b3paper", "b4paper",
84 "b5paper", "b6paper", "c0paper", "c1paper", "c2paper", "c3paper",
85 "c4paper", "c5paper", "c6paper", "b0j", "b1j", "b2j", "b3j", "b4j", "b5j",
90 static char const * const string_orientation[] = {
91 "portrait", "landscape", ""
95 static char const * const tex_graphics[] = {
96 "default", "dvialw", "dvilaser", "dvipdf", "dvipdfm", "dvipdfmx",
97 "dvips", "dvipsone", "dvitops", "dviwin", "dviwindo", "dvi2ps", "emtex",
98 "ln", "oztex", "pctexhp", "pctexps", "pctexwin", "pctex32", "pdftex",
99 "psprint", "pubps", "tcidvi", "textures", "truetex", "vtex", "xdvi",
110 // Paragraph separation
111 typedef Translator<string, BufferParams::ParagraphSeparation> ParSepTranslator;
114 ParSepTranslator const init_parseptranslator()
116 ParSepTranslator translator
117 (string_paragraph_separation[0], BufferParams::ParagraphIndentSeparation);
118 translator.addPair(string_paragraph_separation[1], BufferParams::ParagraphSkipSeparation);
123 ParSepTranslator const & parseptranslator()
125 static ParSepTranslator const translator =
126 init_parseptranslator();
132 typedef Translator<string, InsetQuotesParams::QuoteStyle> QuotesStyleTranslator;
135 QuotesStyleTranslator const init_quotesstyletranslator()
137 QuotesStyleTranslator translator
138 (string_quotes_style[0], InsetQuotesParams::EnglishQuotes);
139 translator.addPair(string_quotes_style[1], InsetQuotesParams::SwedishQuotes);
140 translator.addPair(string_quotes_style[2], InsetQuotesParams::GermanQuotes);
141 translator.addPair(string_quotes_style[3], InsetQuotesParams::PolishQuotes);
142 translator.addPair(string_quotes_style[4], InsetQuotesParams::SwissQuotes);
143 translator.addPair(string_quotes_style[5], InsetQuotesParams::DanishQuotes);
144 translator.addPair(string_quotes_style[6], InsetQuotesParams::PlainQuotes);
145 translator.addPair(string_quotes_style[7], InsetQuotesParams::BritishQuotes);
146 translator.addPair(string_quotes_style[8], InsetQuotesParams::SwedishGQuotes);
147 translator.addPair(string_quotes_style[9], InsetQuotesParams::FrenchQuotes);
148 translator.addPair(string_quotes_style[10], InsetQuotesParams::FrenchINQuotes);
149 translator.addPair(string_quotes_style[11], InsetQuotesParams::RussianQuotes);
154 QuotesStyleTranslator const & quotesstyletranslator()
156 static QuotesStyleTranslator const translator =
157 init_quotesstyletranslator();
163 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
166 static PaperSizeTranslator initPaperSizeTranslator()
168 PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
169 translator.addPair(string_papersize[1], PAPER_CUSTOM);
170 translator.addPair(string_papersize[2], PAPER_USLETTER);
171 translator.addPair(string_papersize[3], PAPER_USLEGAL);
172 translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
173 translator.addPair(string_papersize[5], PAPER_A0);
174 translator.addPair(string_papersize[6], PAPER_A1);
175 translator.addPair(string_papersize[7], PAPER_A2);
176 translator.addPair(string_papersize[8], PAPER_A3);
177 translator.addPair(string_papersize[9], PAPER_A4);
178 translator.addPair(string_papersize[10], PAPER_A5);
179 translator.addPair(string_papersize[11], PAPER_A6);
180 translator.addPair(string_papersize[12], PAPER_B0);
181 translator.addPair(string_papersize[13], PAPER_B1);
182 translator.addPair(string_papersize[14], PAPER_B2);
183 translator.addPair(string_papersize[15], PAPER_B3);
184 translator.addPair(string_papersize[16], PAPER_B4);
185 translator.addPair(string_papersize[17], PAPER_B5);
186 translator.addPair(string_papersize[18], PAPER_B6);
187 translator.addPair(string_papersize[19], PAPER_C0);
188 translator.addPair(string_papersize[20], PAPER_C1);
189 translator.addPair(string_papersize[21], PAPER_C2);
190 translator.addPair(string_papersize[22], PAPER_C3);
191 translator.addPair(string_papersize[23], PAPER_C4);
192 translator.addPair(string_papersize[24], PAPER_C5);
193 translator.addPair(string_papersize[25], PAPER_C6);
194 translator.addPair(string_papersize[26], PAPER_JISB0);
195 translator.addPair(string_papersize[27], PAPER_JISB1);
196 translator.addPair(string_papersize[28], PAPER_JISB2);
197 translator.addPair(string_papersize[29], PAPER_JISB3);
198 translator.addPair(string_papersize[30], PAPER_JISB4);
199 translator.addPair(string_papersize[31], PAPER_JISB5);
200 translator.addPair(string_papersize[32], PAPER_JISB6);
205 PaperSizeTranslator const & papersizetranslator()
207 static PaperSizeTranslator const translator =
208 initPaperSizeTranslator();
214 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
217 PaperOrientationTranslator const init_paperorientationtranslator()
219 PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
220 translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
225 PaperOrientationTranslator const & paperorientationtranslator()
227 static PaperOrientationTranslator const translator =
228 init_paperorientationtranslator();
234 typedef Translator<int, PageSides> SidesTranslator;
237 SidesTranslator const init_sidestranslator()
239 SidesTranslator translator(1, OneSide);
240 translator.addPair(2, TwoSides);
245 SidesTranslator const & sidestranslator()
247 static SidesTranslator const translator = init_sidestranslator();
253 typedef Translator<int, BufferParams::Package> PackageTranslator;
256 PackageTranslator const init_packagetranslator()
258 PackageTranslator translator(0, BufferParams::package_off);
259 translator.addPair(1, BufferParams::package_auto);
260 translator.addPair(2, BufferParams::package_on);
265 PackageTranslator const & packagetranslator()
267 static PackageTranslator const translator =
268 init_packagetranslator();
274 typedef Translator<string, CiteEngineType> CiteEngineTypeTranslator;
277 CiteEngineTypeTranslator const init_citeenginetypetranslator()
279 CiteEngineTypeTranslator translator("authoryear", ENGINE_TYPE_AUTHORYEAR);
280 translator.addPair("numerical", ENGINE_TYPE_NUMERICAL);
281 translator.addPair("default", ENGINE_TYPE_DEFAULT);
286 CiteEngineTypeTranslator const & citeenginetypetranslator()
288 static CiteEngineTypeTranslator const translator =
289 init_citeenginetypetranslator();
295 typedef Translator<string, Spacing::Space> SpaceTranslator;
298 SpaceTranslator const init_spacetranslator()
300 SpaceTranslator translator("default", Spacing::Default);
301 translator.addPair("single", Spacing::Single);
302 translator.addPair("onehalf", Spacing::Onehalf);
303 translator.addPair("double", Spacing::Double);
304 translator.addPair("other", Spacing::Other);
309 SpaceTranslator const & spacetranslator()
311 static SpaceTranslator const translator = init_spacetranslator();
316 bool inSystemDir(FileName const & document_dir, string & system_dir)
318 // A document is assumed to be in a system LyX directory (not
319 // necessarily the system directory of the running instance)
320 // if both "configure.py" and "chkconfig.ltx" are found in
321 // either document_dir/../ or document_dir/../../.
322 // If true, the system directory path is returned in system_dir
323 // with a trailing path separator.
325 string const msg = "Checking whether document is in a system dir...";
327 string dir = document_dir.absFileName();
329 for (int i = 0; i < 2; ++i) {
330 dir = addPath(dir, "..");
331 if (!fileSearch(dir, "configure.py").empty() &&
332 !fileSearch(dir, "chkconfig.ltx").empty()) {
333 LYXERR(Debug::FILES, msg << " yes");
334 system_dir = addPath(FileName(dir).realPath(), "");
339 LYXERR(Debug::FILES, msg << " no");
340 system_dir = string();
347 class BufferParams::Impl
352 AuthorList authorlist;
353 BranchList branchlist;
354 Bullet temp_bullets[4];
355 Bullet user_defined_bullets[4];
356 IndicesList indiceslist;
358 /** This is the amount of space used for paragraph_separation "skip",
359 * and for detached paragraphs in "indented" documents.
363 PDFOptions pdfoptions;
364 LayoutFileIndex baseClass_;
365 FormatList exportableFormatList;
366 FormatList viewableFormatList;
367 bool isViewCacheValid;
368 bool isExportCacheValid;
372 BufferParams::Impl::Impl()
373 : defskip(VSpace::MEDSKIP), baseClass_(string("")),
374 isViewCacheValid(false), isExportCacheValid(false)
376 // set initial author
378 authorlist.record(Author(from_utf8(lyxrc.user_name), from_utf8(lyxrc.user_email)));
383 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
386 return new BufferParams::Impl(*ptr);
390 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
396 BufferParams::BufferParams()
399 setBaseClass(defaultBaseclass());
400 cite_engine_.push_back("basic");
401 cite_engine_type_ = ENGINE_TYPE_DEFAULT;
403 paragraph_separation = ParagraphIndentSeparation;
404 quotes_style = InsetQuotesParams::EnglishQuotes;
405 dynamic_quotes = false;
406 fontsize = "default";
409 papersize = PAPER_DEFAULT;
410 orientation = ORIENTATION_PORTRAIT;
411 use_geometry = false;
412 biblio_style = "plain";
413 use_bibtopic = false;
415 save_transient_properties = true;
416 track_changes = false;
417 output_changes = false;
418 use_default_options = true;
419 maintain_unincluded_children = false;
422 language = default_language;
424 fonts_roman[0] = "default";
425 fonts_roman[1] = "default";
426 fonts_sans[0] = "default";
427 fonts_sans[1] = "default";
428 fonts_typewriter[0] = "default";
429 fonts_typewriter[1] = "default";
430 fonts_math[0] = "auto";
431 fonts_math[1] = "auto";
432 fonts_default_family = "default";
433 useNonTeXFonts = false;
434 use_microtype = false;
435 fonts_expert_sc = false;
436 fonts_old_figures = false;
437 fonts_sans_scale[0] = 100;
438 fonts_sans_scale[1] = 100;
439 fonts_typewriter_scale[0] = 100;
440 fonts_typewriter_scale[1] = 100;
442 lang_package = "default";
443 graphics_driver = "default";
444 default_output_format = "default";
445 bibtex_command = "default";
446 index_command = "default";
449 listings_params = string();
450 pagestyle = "default";
451 suppress_date = false;
452 justification = true;
453 // no color is the default (white)
454 backgroundcolor = lyx::rgbFromHexName("#ffffff");
455 isbackgroundcolor = false;
456 // no color is the default (black)
457 fontcolor = lyx::rgbFromHexName("#000000");
459 // light gray is the default font color for greyed-out notes
460 notefontcolor = lyx::rgbFromHexName("#cccccc");
461 boxbgcolor = lyx::rgbFromHexName("#ff0000");
462 compressed = lyxrc.save_compressed;
463 for (int iter = 0; iter < 4; ++iter) {
464 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
465 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
468 indiceslist().addDefault(B_("Index"));
469 html_be_strict = false;
470 html_math_output = MathML;
471 html_math_img_scale = 1.0;
472 html_css_as_file = false;
473 display_pixel_ratio = 1.0;
478 // map current author
479 author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
483 docstring BufferParams::B_(string const & l10n) const
485 LASSERT(language, return from_utf8(l10n));
486 return getMessages(language->code()).get(l10n);
490 BufferParams::Package BufferParams::use_package(std::string const & p) const
492 PackageMap::const_iterator it = use_packages.find(p);
493 if (it == use_packages.end())
499 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
505 map<string, string> const & BufferParams::auto_packages()
507 static map<string, string> packages;
508 if (packages.empty()) {
509 // We could have a race condition here that two threads
510 // discover an empty map at the same time and want to fill
511 // it, but that is no problem, since the same contents is
512 // filled in twice then. Having the locker inside the
513 // packages.empty() condition has the advantage that we
514 // don't need the mutex overhead for simple reading.
516 Mutex::Locker locker(&mutex);
517 // adding a package here implies a file format change!
518 packages["amsmath"] =
519 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
520 packages["amssymb"] =
521 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
523 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
525 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
526 packages["mathdots"] =
527 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
528 packages["mathtools"] =
529 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
531 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
532 packages["stackrel"] =
533 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
534 packages["stmaryrd"] =
535 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");
536 packages["undertilde"] =
537 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
543 AuthorList & BufferParams::authors()
545 return pimpl_->authorlist;
549 AuthorList const & BufferParams::authors() const
551 return pimpl_->authorlist;
555 void BufferParams::addAuthor(Author a)
557 author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
561 BranchList & BufferParams::branchlist()
563 return pimpl_->branchlist;
567 BranchList const & BufferParams::branchlist() const
569 return pimpl_->branchlist;
573 IndicesList & BufferParams::indiceslist()
575 return pimpl_->indiceslist;
579 IndicesList const & BufferParams::indiceslist() const
581 return pimpl_->indiceslist;
585 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
587 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
588 return pimpl_->temp_bullets[index];
592 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
594 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
595 return pimpl_->temp_bullets[index];
599 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
601 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
602 return pimpl_->user_defined_bullets[index];
606 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
608 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
609 return pimpl_->user_defined_bullets[index];
613 Spacing & BufferParams::spacing()
615 return pimpl_->spacing;
619 Spacing const & BufferParams::spacing() const
621 return pimpl_->spacing;
625 PDFOptions & BufferParams::pdfoptions()
627 return pimpl_->pdfoptions;
631 PDFOptions const & BufferParams::pdfoptions() const
633 return pimpl_->pdfoptions;
637 HSpace const & BufferParams::getIndentation() const
639 return pimpl_->indentation;
643 void BufferParams::setIndentation(HSpace const & indent)
645 pimpl_->indentation = indent;
649 VSpace const & BufferParams::getDefSkip() const
651 return pimpl_->defskip;
655 void BufferParams::setDefSkip(VSpace const & vs)
657 // DEFSKIP will cause an infinite loop
658 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
659 pimpl_->defskip = vs;
663 string BufferParams::readToken(Lexer & lex, string const & token,
664 FileName const & filepath)
668 if (token == "\\textclass") {
670 string const classname = lex.getString();
671 // if there exists a local layout file, ignore the system one
672 // NOTE: in this case, the textclass (.cls file) is assumed to
675 LayoutFileList & bcl = LayoutFileList::get();
676 if (!filepath.empty()) {
677 // If classname is an absolute path, the document is
678 // using a local layout file which could not be accessed
679 // by a relative path. In this case the path is correct
680 // even if the document was moved to a different
681 // location. However, we will have a problem if the
682 // document was generated on a different platform.
683 bool isabsolute = FileName::isAbsolute(classname);
684 string const classpath = onlyPath(classname);
685 string const path = isabsolute ? classpath
686 : FileName(addPath(filepath.absFileName(),
687 classpath)).realPath();
688 string const oldpath = isabsolute ? string()
689 : FileName(addPath(origin, classpath)).realPath();
690 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
692 // that returns non-empty if a "local" layout file is found.
694 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
695 from_utf8(filepath.absFileName())));
698 setBaseClass(onlyFileName(tcp));
700 setBaseClass(onlyFileName(classname));
701 // We assume that a tex class exists for local or unknown
702 // layouts so this warning, will only be given for system layouts.
703 if (!baseClass()->isTeXClassAvailable()) {
704 docstring const desc =
705 translateIfPossible(from_utf8(baseClass()->description()));
706 docstring const prereqs =
707 from_utf8(baseClass()->prerequisites());
708 docstring const msg =
709 bformat(_("The selected document class\n"
711 "requires external files that are not available.\n"
712 "The document class can still be used, but the\n"
713 "document cannot be compiled until the following\n"
714 "prerequisites are installed:\n"
716 "See section 3.1.2.2 (Class Availability) of the\n"
717 "User's Guide for more information."), desc, prereqs);
718 frontend::Alert::warning(_("Document class not available"),
721 } else if (token == "\\save_transient_properties") {
722 lex >> save_transient_properties;
723 } else if (token == "\\origin") {
725 origin = lex.getString();
726 string const sysdirprefix = "/systemlyxdir/";
727 if (prefixIs(origin, sysdirprefix)) {
729 if (inSystemDir(filepath, docsys))
730 origin.replace(0, sysdirprefix.length() - 1, docsys);
732 origin.replace(0, sysdirprefix.length() - 1,
733 package().system_support().absFileName());
735 } else if (token == "\\begin_preamble") {
737 } else if (token == "\\begin_local_layout") {
738 readLocalLayout(lex, false);
739 } else if (token == "\\begin_forced_local_layout") {
740 readLocalLayout(lex, true);
741 } else if (token == "\\begin_modules") {
743 } else if (token == "\\begin_removed_modules") {
744 readRemovedModules(lex);
745 } else if (token == "\\begin_includeonly") {
746 readIncludeonly(lex);
747 } else if (token == "\\maintain_unincluded_children") {
748 lex >> maintain_unincluded_children;
749 } else if (token == "\\options") {
751 options = lex.getString();
752 } else if (token == "\\use_default_options") {
753 lex >> use_default_options;
754 } else if (token == "\\master") {
756 master = lex.getString();
757 if (!filepath.empty() && FileName::isAbsolute(origin)) {
758 bool const isabs = FileName::isAbsolute(master);
759 FileName const abspath(isabs ? master : origin + master);
760 bool const moved = filepath != FileName(origin);
761 if (moved && abspath.exists()) {
762 docstring const path = isabs
764 : from_utf8(abspath.realPath());
765 docstring const refpath =
766 from_utf8(filepath.absFileName());
767 master = to_utf8(makeRelPath(path, refpath));
770 } else if (token == "\\suppress_date") {
771 lex >> suppress_date;
772 } else if (token == "\\justification") {
773 lex >> justification;
774 } else if (token == "\\language") {
776 } else if (token == "\\language_package") {
778 lang_package = lex.getString();
779 } else if (token == "\\inputencoding") {
781 } else if (token == "\\graphics") {
782 readGraphicsDriver(lex);
783 } else if (token == "\\default_output_format") {
784 lex >> default_output_format;
785 } else if (token == "\\bibtex_command") {
787 bibtex_command = lex.getString();
788 } else if (token == "\\index_command") {
790 index_command = lex.getString();
791 } else if (token == "\\fontencoding") {
793 fontenc = lex.getString();
794 } else if (token == "\\font_roman") {
795 lex >> fonts_roman[0];
796 lex >> fonts_roman[1];
797 } else if (token == "\\font_sans") {
798 lex >> fonts_sans[0];
799 lex >> fonts_sans[1];
800 } else if (token == "\\font_typewriter") {
801 lex >> fonts_typewriter[0];
802 lex >> fonts_typewriter[1];
803 } else if (token == "\\font_math") {
804 lex >> fonts_math[0];
805 lex >> fonts_math[1];
806 } else if (token == "\\font_default_family") {
807 lex >> fonts_default_family;
808 } else if (token == "\\use_non_tex_fonts") {
809 lex >> useNonTeXFonts;
810 } else if (token == "\\font_sc") {
811 lex >> fonts_expert_sc;
812 } else if (token == "\\font_osf") {
813 lex >> fonts_old_figures;
814 } else if (token == "\\font_sf_scale") {
815 lex >> fonts_sans_scale[0];
816 lex >> fonts_sans_scale[1];
817 } else if (token == "\\font_tt_scale") {
818 lex >> fonts_typewriter_scale[0];
819 lex >> fonts_typewriter_scale[1];
820 } else if (token == "\\font_cjk") {
822 } else if (token == "\\use_microtype") {
823 lex >> use_microtype;
824 } else if (token == "\\paragraph_separation") {
827 paragraph_separation = parseptranslator().find(parsep);
828 } else if (token == "\\paragraph_indentation") {
830 string indentation = lex.getString();
831 pimpl_->indentation = HSpace(indentation);
832 } else if (token == "\\defskip") {
834 string const defskip = lex.getString();
835 pimpl_->defskip = VSpace(defskip);
836 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
838 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
839 } else if (token == "\\quotes_style") {
842 quotes_style = quotesstyletranslator().find(qstyle);
843 } else if (token == "\\dynamic_quotes") {
844 lex >> dynamic_quotes;
845 } else if (token == "\\papersize") {
848 papersize = papersizetranslator().find(ppsize);
849 } else if (token == "\\use_geometry") {
851 } else if (token == "\\use_package") {
856 use_package(package, packagetranslator().find(use));
857 } else if (token == "\\cite_engine") {
859 vector<string> engine = getVectorFromString(lex.getString());
860 setCiteEngine(engine);
861 } else if (token == "\\cite_engine_type") {
864 cite_engine_type_ = citeenginetypetranslator().find(engine_type);
865 } else if (token == "\\biblio_style") {
867 biblio_style = lex.getString();
868 } else if (token == "\\use_bibtopic") {
870 } else if (token == "\\use_indices") {
872 } else if (token == "\\tracking_changes") {
873 lex >> track_changes;
874 } else if (token == "\\output_changes") {
875 lex >> output_changes;
876 } else if (token == "\\branch") {
878 docstring branch = lex.getDocString();
879 branchlist().add(branch);
882 string const tok = lex.getString();
883 if (tok == "\\end_branch")
885 Branch * branch_ptr = branchlist().find(branch);
886 if (tok == "\\selected") {
889 branch_ptr->setSelected(lex.getInteger());
891 if (tok == "\\filename_suffix") {
894 branch_ptr->setFileNameSuffix(lex.getInteger());
896 if (tok == "\\color") {
898 string color = lex.getString();
900 branch_ptr->setColor(color);
901 // Update also the Color table:
903 color = lcolor.getX11Name(Color_background);
905 lcolor.setColor(to_utf8(branch), color);
908 } else if (token == "\\index") {
910 docstring index = lex.getDocString();
912 indiceslist().add(index);
915 string const tok = lex.getString();
916 if (tok == "\\end_index")
918 Index * index_ptr = indiceslist().find(index);
919 if (tok == "\\shortcut") {
921 shortcut = lex.getDocString();
923 index_ptr->setShortcut(shortcut);
925 if (tok == "\\color") {
927 string color = lex.getString();
929 index_ptr->setColor(color);
930 // Update also the Color table:
932 color = lcolor.getX11Name(Color_background);
934 if (!shortcut.empty())
935 lcolor.setColor(to_utf8(shortcut), color);
938 } else if (token == "\\author") {
940 istringstream ss(lex.getString());
944 } else if (token == "\\paperorientation") {
947 orientation = paperorientationtranslator().find(orient);
948 } else if (token == "\\backgroundcolor") {
950 backgroundcolor = lyx::rgbFromHexName(lex.getString());
951 isbackgroundcolor = true;
952 } else if (token == "\\fontcolor") {
954 fontcolor = lyx::rgbFromHexName(lex.getString());
956 } else if (token == "\\notefontcolor") {
958 string color = lex.getString();
959 notefontcolor = lyx::rgbFromHexName(color);
960 lcolor.setColor("notefontcolor", color);
961 } else if (token == "\\boxbgcolor") {
963 string color = lex.getString();
964 boxbgcolor = lyx::rgbFromHexName(color);
965 lcolor.setColor("boxbgcolor", color);
966 } else if (token == "\\paperwidth") {
968 } else if (token == "\\paperheight") {
970 } else if (token == "\\leftmargin") {
972 } else if (token == "\\topmargin") {
974 } else if (token == "\\rightmargin") {
976 } else if (token == "\\bottommargin") {
978 } else if (token == "\\headheight") {
980 } else if (token == "\\headsep") {
982 } else if (token == "\\footskip") {
984 } else if (token == "\\columnsep") {
986 } else if (token == "\\paperfontsize") {
988 } else if (token == "\\papercolumns") {
990 } else if (token == "\\listings_params") {
993 listings_params = InsetListingsParams(par).params();
994 } else if (token == "\\papersides") {
997 sides = sidestranslator().find(psides);
998 } else if (token == "\\paperpagestyle") {
1000 } else if (token == "\\bullet") {
1002 } else if (token == "\\bulletLaTeX") {
1003 readBulletsLaTeX(lex);
1004 } else if (token == "\\secnumdepth") {
1006 } else if (token == "\\tocdepth") {
1008 } else if (token == "\\spacing") {
1012 if (nspacing == "other") {
1015 spacing().set(spacetranslator().find(nspacing), tmp_val);
1016 } else if (token == "\\float_placement") {
1017 lex >> float_placement;
1019 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1020 string toktmp = pdfoptions().readToken(lex, token);
1021 if (!toktmp.empty()) {
1022 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1026 } else if (token == "\\html_math_output") {
1029 html_math_output = static_cast<MathOutput>(temp);
1030 } else if (token == "\\html_be_strict") {
1031 lex >> html_be_strict;
1032 } else if (token == "\\html_css_as_file") {
1033 lex >> html_css_as_file;
1034 } else if (token == "\\html_math_img_scale") {
1035 lex >> html_math_img_scale;
1036 } else if (token == "\\html_latex_start") {
1038 html_latex_start = lex.getString();
1039 } else if (token == "\\html_latex_end") {
1041 html_latex_end = lex.getString();
1042 } else if (token == "\\output_sync") {
1044 } else if (token == "\\output_sync_macro") {
1045 lex >> output_sync_macro;
1046 } else if (token == "\\use_refstyle") {
1047 lex >> use_refstyle;
1049 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1059 // Quote argument if it contains spaces
1060 string quoteIfNeeded(string const & str) {
1061 if (contains(str, ' '))
1062 return "\"" + str + "\"";
1068 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1070 // The top of the file is written by the buffer.
1071 // Prints out the buffer info into the .lyx file given by file
1073 os << "\\save_transient_properties "
1074 << convert<string>(save_transient_properties) << '\n';
1076 // the document directory (must end with a path separator)
1077 // realPath() is used to resolve symlinks, while addPath(..., "")
1078 // ensures a trailing path separator.
1080 string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1081 string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1082 : addPath(package().system_support().realPath(), "");
1083 string const relpath =
1084 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1085 if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1086 filepath = addPath("/systemlyxdir", relpath);
1087 else if (!save_transient_properties || !lyxrc.save_origin)
1088 filepath = "unavailable";
1089 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1092 os << "\\textclass "
1093 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1094 baseClass()->name()), "layout"))
1097 // then the preamble
1098 if (!preamble.empty()) {
1099 // remove '\n' from the end of preamble
1100 docstring const tmppreamble = rtrim(preamble, "\n");
1101 os << "\\begin_preamble\n"
1102 << to_utf8(tmppreamble)
1103 << "\n\\end_preamble\n";
1107 if (!options.empty()) {
1108 os << "\\options " << options << '\n';
1111 // use the class options defined in the layout?
1112 os << "\\use_default_options "
1113 << convert<string>(use_default_options) << "\n";
1115 // the master document
1116 if (!master.empty()) {
1117 os << "\\master " << master << '\n';
1121 if (!removed_modules_.empty()) {
1122 os << "\\begin_removed_modules" << '\n';
1123 list<string>::const_iterator it = removed_modules_.begin();
1124 list<string>::const_iterator en = removed_modules_.end();
1125 for (; it != en; ++it)
1127 os << "\\end_removed_modules" << '\n';
1131 if (!layout_modules_.empty()) {
1132 os << "\\begin_modules" << '\n';
1133 LayoutModuleList::const_iterator it = layout_modules_.begin();
1134 LayoutModuleList::const_iterator en = layout_modules_.end();
1135 for (; it != en; ++it)
1137 os << "\\end_modules" << '\n';
1141 if (!included_children_.empty()) {
1142 os << "\\begin_includeonly" << '\n';
1143 list<string>::const_iterator it = included_children_.begin();
1144 list<string>::const_iterator en = included_children_.end();
1145 for (; it != en; ++it)
1147 os << "\\end_includeonly" << '\n';
1149 os << "\\maintain_unincluded_children "
1150 << convert<string>(maintain_unincluded_children) << '\n';
1152 // local layout information
1153 docstring const local_layout = getLocalLayout(false);
1154 if (!local_layout.empty()) {
1155 // remove '\n' from the end
1156 docstring const tmplocal = rtrim(local_layout, "\n");
1157 os << "\\begin_local_layout\n"
1158 << to_utf8(tmplocal)
1159 << "\n\\end_local_layout\n";
1161 docstring const forced_local_layout = getLocalLayout(true);
1162 if (!forced_local_layout.empty()) {
1163 // remove '\n' from the end
1164 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1165 os << "\\begin_forced_local_layout\n"
1166 << to_utf8(tmplocal)
1167 << "\n\\end_forced_local_layout\n";
1170 // then the text parameters
1171 if (language != ignore_language)
1172 os << "\\language " << language->lang() << '\n';
1173 os << "\\language_package " << lang_package
1174 << "\n\\inputencoding " << inputenc
1175 << "\n\\fontencoding " << fontenc
1176 << "\n\\font_roman \"" << fonts_roman[0]
1177 << "\" \"" << fonts_roman[1] << '"'
1178 << "\n\\font_sans \"" << fonts_sans[0]
1179 << "\" \"" << fonts_sans[1] << '"'
1180 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1181 << "\" \"" << fonts_typewriter[1] << '"'
1182 << "\n\\font_math \"" << fonts_math[0]
1183 << "\" \"" << fonts_math[1] << '"'
1184 << "\n\\font_default_family " << fonts_default_family
1185 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1186 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1187 << "\n\\font_osf " << convert<string>(fonts_old_figures)
1188 << "\n\\font_sf_scale " << fonts_sans_scale[0]
1189 << ' ' << fonts_sans_scale[1]
1190 << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1191 << ' ' << fonts_typewriter_scale[1]
1193 if (!fonts_cjk.empty()) {
1194 os << "\\font_cjk " << fonts_cjk << '\n';
1196 os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1197 os << "\\graphics " << graphics_driver << '\n';
1198 os << "\\default_output_format " << default_output_format << '\n';
1199 os << "\\output_sync " << output_sync << '\n';
1200 if (!output_sync_macro.empty())
1201 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1202 os << "\\bibtex_command " << bibtex_command << '\n';
1203 os << "\\index_command " << index_command << '\n';
1205 if (!float_placement.empty()) {
1206 os << "\\float_placement " << float_placement << '\n';
1208 os << "\\paperfontsize " << fontsize << '\n';
1210 spacing().writeFile(os);
1211 pdfoptions().writeFile(os);
1213 os << "\\papersize " << string_papersize[papersize]
1214 << "\n\\use_geometry " << convert<string>(use_geometry);
1215 map<string, string> const & packages = auto_packages();
1216 for (map<string, string>::const_iterator it = packages.begin();
1217 it != packages.end(); ++it)
1218 os << "\n\\use_package " << it->first << ' '
1219 << use_package(it->first);
1221 os << "\n\\cite_engine ";
1223 if (!cite_engine_.empty()) {
1224 LayoutModuleList::const_iterator be = cite_engine_.begin();
1225 LayoutModuleList::const_iterator en = cite_engine_.end();
1226 for (LayoutModuleList::const_iterator it = be; it != en; ++it) {
1235 os << "\n\\cite_engine_type " << citeenginetypetranslator().find(cite_engine_type_)
1236 << "\n\\biblio_style " << biblio_style
1237 << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1238 << "\n\\use_indices " << convert<string>(use_indices)
1239 << "\n\\paperorientation " << string_orientation[orientation]
1240 << "\n\\suppress_date " << convert<string>(suppress_date)
1241 << "\n\\justification " << convert<string>(justification)
1242 << "\n\\use_refstyle " << use_refstyle
1244 if (isbackgroundcolor == true)
1245 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1246 if (isfontcolor == true)
1247 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1248 if (notefontcolor != lyx::rgbFromHexName("#cccccc"))
1249 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1250 if (boxbgcolor != lyx::rgbFromHexName("#ff0000"))
1251 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1253 BranchList::const_iterator it = branchlist().begin();
1254 BranchList::const_iterator end = branchlist().end();
1255 for (; it != end; ++it) {
1256 os << "\\branch " << to_utf8(it->branch())
1257 << "\n\\selected " << it->isSelected()
1258 << "\n\\filename_suffix " << it->hasFileNameSuffix()
1259 << "\n\\color " << lyx::X11hexname(it->color())
1264 IndicesList::const_iterator iit = indiceslist().begin();
1265 IndicesList::const_iterator iend = indiceslist().end();
1266 for (; iit != iend; ++iit) {
1267 os << "\\index " << to_utf8(iit->index())
1268 << "\n\\shortcut " << to_utf8(iit->shortcut())
1269 << "\n\\color " << lyx::X11hexname(iit->color())
1274 if (!paperwidth.empty())
1275 os << "\\paperwidth "
1276 << VSpace(paperwidth).asLyXCommand() << '\n';
1277 if (!paperheight.empty())
1278 os << "\\paperheight "
1279 << VSpace(paperheight).asLyXCommand() << '\n';
1280 if (!leftmargin.empty())
1281 os << "\\leftmargin "
1282 << VSpace(leftmargin).asLyXCommand() << '\n';
1283 if (!topmargin.empty())
1284 os << "\\topmargin "
1285 << VSpace(topmargin).asLyXCommand() << '\n';
1286 if (!rightmargin.empty())
1287 os << "\\rightmargin "
1288 << VSpace(rightmargin).asLyXCommand() << '\n';
1289 if (!bottommargin.empty())
1290 os << "\\bottommargin "
1291 << VSpace(bottommargin).asLyXCommand() << '\n';
1292 if (!headheight.empty())
1293 os << "\\headheight "
1294 << VSpace(headheight).asLyXCommand() << '\n';
1295 if (!headsep.empty())
1297 << VSpace(headsep).asLyXCommand() << '\n';
1298 if (!footskip.empty())
1300 << VSpace(footskip).asLyXCommand() << '\n';
1301 if (!columnsep.empty())
1302 os << "\\columnsep "
1303 << VSpace(columnsep).asLyXCommand() << '\n';
1304 os << "\\secnumdepth " << secnumdepth
1305 << "\n\\tocdepth " << tocdepth
1306 << "\n\\paragraph_separation "
1307 << string_paragraph_separation[paragraph_separation];
1308 if (!paragraph_separation)
1309 os << "\n\\paragraph_indentation " << getIndentation().asLyXCommand();
1311 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1312 os << "\n\\quotes_style "
1313 << string_quotes_style[quotes_style]
1314 << "\n\\dynamic_quotes " << dynamic_quotes
1315 << "\n\\papercolumns " << columns
1316 << "\n\\papersides " << sides
1317 << "\n\\paperpagestyle " << pagestyle << '\n';
1318 if (!listings_params.empty())
1319 os << "\\listings_params \"" <<
1320 InsetListingsParams(listings_params).encodedString() << "\"\n";
1321 for (int i = 0; i < 4; ++i) {
1322 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1323 if (user_defined_bullet(i).getFont() != -1) {
1324 os << "\\bullet " << i << " "
1325 << user_defined_bullet(i).getFont() << " "
1326 << user_defined_bullet(i).getCharacter() << " "
1327 << user_defined_bullet(i).getSize() << "\n";
1331 os << "\\bulletLaTeX " << i << " \""
1332 << lyx::to_ascii(user_defined_bullet(i).getText())
1338 os << "\\tracking_changes "
1339 << (save_transient_properties ? convert<string>(track_changes) : "false")
1342 os << "\\output_changes "
1343 << (save_transient_properties ? convert<string>(output_changes) : "false")
1346 os << "\\html_math_output " << html_math_output << '\n'
1347 << "\\html_css_as_file " << html_css_as_file << '\n'
1348 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1350 if (html_math_img_scale != 1.0)
1351 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1352 if (!html_latex_start.empty())
1353 os << "\\html_latex_start " << html_latex_start << '\n';
1354 if (!html_latex_end.empty())
1355 os << "\\html_latex_end " << html_latex_end << '\n';
1357 os << pimpl_->authorlist;
1361 void BufferParams::validate(LaTeXFeatures & features) const
1363 features.require(documentClass().requires());
1365 if (columns > 1 && language->rightToLeft())
1366 features.require("rtloutputdblcol");
1368 if (output_changes) {
1369 bool dvipost = LaTeXFeatures::isAvailable("dvipost");
1370 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1371 LaTeXFeatures::isAvailable("xcolor");
1373 switch (features.runparams().flavor) {
1374 case OutputParams::LATEX:
1375 case OutputParams::DVILUATEX:
1377 features.require("ct-dvipost");
1378 features.require("dvipost");
1379 } else if (xcolorulem) {
1380 features.require("ct-xcolor-ulem");
1381 features.require("ulem");
1382 features.require("xcolor");
1384 features.require("ct-none");
1387 case OutputParams::LUATEX:
1388 case OutputParams::PDFLATEX:
1389 case OutputParams::XETEX:
1391 features.require("ct-xcolor-ulem");
1392 features.require("ulem");
1393 features.require("xcolor");
1394 // improves color handling in PDF output
1395 features.require("pdfcolmk");
1397 features.require("ct-none");
1405 // Floats with 'Here definitely' as default setting.
1406 if (float_placement.find('H') != string::npos)
1407 features.require("float");
1409 for (PackageMap::const_iterator it = use_packages.begin();
1410 it != use_packages.end(); ++it) {
1411 if (it->first == "amsmath") {
1412 // AMS Style is at document level
1413 if (it->second == package_on ||
1414 features.isProvided("amsmath"))
1415 features.require(it->first);
1416 } else if (it->second == package_on)
1417 features.require(it->first);
1420 // Document-level line spacing
1421 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1422 features.require("setspace");
1424 // the bullet shapes are buffer level not paragraph level
1425 // so they are tested here
1426 for (int i = 0; i < 4; ++i) {
1427 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1429 int const font = user_defined_bullet(i).getFont();
1431 int const c = user_defined_bullet(i).getCharacter();
1437 features.require("latexsym");
1439 } else if (font == 1) {
1440 features.require("amssymb");
1441 } else if (font >= 2 && font <= 5) {
1442 features.require("pifont");
1446 if (pdfoptions().use_hyperref) {
1447 features.require("hyperref");
1448 // due to interferences with babel and hyperref, the color package has to
1449 // be loaded after hyperref when hyperref is used with the colorlinks
1450 // option, see http://www.lyx.org/trac/ticket/5291
1451 if (pdfoptions().colorlinks)
1452 features.require("color");
1454 if (!listings_params.empty()) {
1455 // do not test validity because listings_params is
1456 // supposed to be valid
1458 InsetListingsParams(listings_params).separatedParams(true);
1459 // we can't support all packages, but we should load the color package
1460 if (par.find("\\color", 0) != string::npos)
1461 features.require("color");
1464 // some languages are only available via polyglossia
1465 if (features.hasPolyglossiaExclusiveLanguages())
1466 features.require("polyglossia");
1468 if (useNonTeXFonts && fontsMath() != "auto")
1469 features.require("unicode-math");
1472 features.require("microtype");
1474 if (!language->requires().empty())
1475 features.require(language->requires());
1479 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1480 FileName const & filepath) const
1482 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1483 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1484 // \RequirePackage to do so, rather than the normal \usepackage
1485 // Do not try to load any other package before the document class, unless you
1486 // have a thorough understanding of the LATEX internals and know exactly what you
1488 if (features.mustProvide("fix-cm"))
1489 os << "\\RequirePackage{fix-cm}\n";
1490 // Likewise for fixltx2e. If other packages conflict with this policy,
1491 // treat it as a package bug (and report it!)
1492 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1493 if (features.mustProvide("fixltx2e"))
1494 os << "\\RequirePackage{fixltx2e}\n";
1496 os << "\\documentclass";
1498 DocumentClass const & tclass = documentClass();
1500 ostringstream clsoptions; // the document class options.
1502 if (tokenPos(tclass.opt_fontsize(),
1503 '|', fontsize) >= 0) {
1504 // only write if existing in list (and not default)
1505 clsoptions << fontsize << "pt,";
1508 // all paper sizes except of A4, A5, B5 and the US sizes need the
1510 bool nonstandard_papersize = papersize != PAPER_DEFAULT
1511 && papersize != PAPER_USLETTER
1512 && papersize != PAPER_USLEGAL
1513 && papersize != PAPER_USEXECUTIVE
1514 && papersize != PAPER_A4
1515 && papersize != PAPER_A5
1516 && papersize != PAPER_B5;
1518 if (!use_geometry) {
1519 switch (papersize) {
1521 clsoptions << "a4paper,";
1523 case PAPER_USLETTER:
1524 clsoptions << "letterpaper,";
1527 clsoptions << "a5paper,";
1530 clsoptions << "b5paper,";
1532 case PAPER_USEXECUTIVE:
1533 clsoptions << "executivepaper,";
1536 clsoptions << "legalpaper,";
1570 if (sides != tclass.sides()) {
1573 clsoptions << "oneside,";
1576 clsoptions << "twoside,";
1582 if (columns != tclass.columns()) {
1584 clsoptions << "twocolumn,";
1586 clsoptions << "onecolumn,";
1590 && orientation == ORIENTATION_LANDSCAPE)
1591 clsoptions << "landscape,";
1593 // language should be a parameter to \documentclass
1594 if (language->babel() == "hebrew"
1595 && default_language->babel() != "hebrew")
1596 // This seems necessary
1597 features.useLanguage(default_language);
1599 ostringstream language_options;
1600 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1601 bool const use_polyglossia = features.usePolyglossia();
1602 bool const global = lyxrc.language_global_options;
1603 if (use_babel || (use_polyglossia && global)) {
1604 language_options << features.getBabelLanguages();
1605 if (!language->babel().empty()) {
1606 if (!language_options.str().empty())
1607 language_options << ',';
1608 language_options << language->babel();
1610 if (global && !features.needBabelLangOptions()
1611 && !language_options.str().empty())
1612 clsoptions << language_options.str() << ',';
1615 // the predefined options from the layout
1616 if (use_default_options && !tclass.options().empty())
1617 clsoptions << tclass.options() << ',';
1619 // the user-defined options
1620 if (!options.empty()) {
1621 clsoptions << options << ',';
1624 string strOptions(clsoptions.str());
1625 if (!strOptions.empty()) {
1626 strOptions = rtrim(strOptions, ",");
1628 os << '[' << from_utf8(strOptions) << ']';
1631 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1632 // end of \documentclass defs
1634 // if we use fontspec or newtxmath, we have to load the AMS packages here
1635 string const ams = features.loadAMSPackages();
1636 bool const ot1 = (font_encoding() == "default" || font_encoding() == "OT1");
1637 bool const use_newtxmath =
1638 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1639 ot1, false, false) == "newtxmath";
1640 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1641 os << from_ascii(ams);
1643 if (useNonTeXFonts) {
1644 if (!features.isProvided("fontspec"))
1645 os << "\\usepackage{fontspec}\n";
1646 if (features.mustProvide("unicode-math")
1647 && features.isAvailable("unicode-math"))
1648 os << "\\usepackage{unicode-math}\n";
1651 // font selection must be done before loading fontenc.sty
1652 string const fonts = loadFonts(features);
1654 os << from_utf8(fonts);
1656 if (fonts_default_family != "default")
1657 os << "\\renewcommand{\\familydefault}{\\"
1658 << from_ascii(fonts_default_family) << "}\n";
1660 // set font encoding
1661 // XeTeX and LuaTeX (with OS fonts) do not need fontenc
1662 if (!useNonTeXFonts && !features.isProvided("fontenc")
1663 && font_encoding() != "default") {
1664 // get main font encodings
1665 vector<string> fontencs = font_encodings();
1666 // get font encodings of secondary languages
1667 features.getFontEncodings(fontencs);
1668 if (!fontencs.empty()) {
1669 os << "\\usepackage["
1670 << from_ascii(getStringFromVector(fontencs))
1675 // handle inputenc etc.
1676 writeEncodingPreamble(os, features);
1679 if (!features.runparams().includeall && !included_children_.empty()) {
1680 os << "\\includeonly{";
1681 list<string>::const_iterator it = included_children_.begin();
1682 list<string>::const_iterator en = included_children_.end();
1684 for (; it != en; ++it) {
1685 string incfile = *it;
1686 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1687 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1689 if (!features.runparams().nice)
1691 // \includeonly doesn't want an extension
1692 incfile = changeExtension(incfile, string());
1693 incfile = support::latex_path(incfile);
1694 if (!incfile.empty()) {
1697 os << from_utf8(incfile);
1704 if (!features.isProvided("geometry")
1705 && (use_geometry || nonstandard_papersize)) {
1706 odocstringstream ods;
1707 if (!getGraphicsDriver("geometry").empty())
1708 ods << getGraphicsDriver("geometry");
1709 if (orientation == ORIENTATION_LANDSCAPE)
1710 ods << ",landscape";
1711 switch (papersize) {
1713 if (!paperwidth.empty())
1714 ods << ",paperwidth="
1715 << from_ascii(paperwidth);
1716 if (!paperheight.empty())
1717 ods << ",paperheight="
1718 << from_ascii(paperheight);
1720 case PAPER_USLETTER:
1721 ods << ",letterpaper";
1724 ods << ",legalpaper";
1726 case PAPER_USEXECUTIVE:
1727 ods << ",executivepaper";
1816 docstring const g_options = trim(ods.str(), ",");
1817 os << "\\usepackage";
1818 if (!g_options.empty())
1819 os << '[' << g_options << ']';
1820 os << "{geometry}\n";
1821 // output this only if use_geometry is true
1823 os << "\\geometry{verbose";
1824 if (!topmargin.empty())
1825 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1826 if (!bottommargin.empty())
1827 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1828 if (!leftmargin.empty())
1829 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1830 if (!rightmargin.empty())
1831 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1832 if (!headheight.empty())
1833 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1834 if (!headsep.empty())
1835 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1836 if (!footskip.empty())
1837 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1838 if (!columnsep.empty())
1839 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1842 } else if (orientation == ORIENTATION_LANDSCAPE
1843 || papersize != PAPER_DEFAULT) {
1844 features.require("papersize");
1847 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
1848 if (pagestyle == "fancy")
1849 os << "\\usepackage{fancyhdr}\n";
1850 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1853 // only output when the background color is not default
1854 if (isbackgroundcolor == true) {
1855 // only require color here, the background color will be defined
1856 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1858 features.require("color");
1859 features.require("pagecolor");
1862 // only output when the font color is not default
1863 if (isfontcolor == true) {
1864 // only require color here, the font color will be defined
1865 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1867 features.require("color");
1868 features.require("fontcolor");
1871 // Only if class has a ToC hierarchy
1872 if (tclass.hasTocLevels()) {
1873 if (secnumdepth != tclass.secnumdepth()) {
1874 os << "\\setcounter{secnumdepth}{"
1878 if (tocdepth != tclass.tocdepth()) {
1879 os << "\\setcounter{tocdepth}{"
1885 if (paragraph_separation) {
1886 // when skip separation
1887 switch (getDefSkip().kind()) {
1888 case VSpace::SMALLSKIP:
1889 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1891 case VSpace::MEDSKIP:
1892 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1894 case VSpace::BIGSKIP:
1895 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1897 case VSpace::LENGTH:
1898 os << "\\setlength{\\parskip}{"
1899 << from_utf8(getDefSkip().length().asLatexString())
1902 default: // should never happen // Then delete it.
1903 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1906 os << "\\setlength{\\parindent}{0pt}\n";
1908 // when separation by indentation
1909 // only output something when a width is given
1910 if (getIndentation().asLyXCommand() != "default") {
1911 os << "\\setlength{\\parindent}{"
1912 << from_utf8(getIndentation().asLatexCommand())
1917 // Now insert the LyX specific LaTeX commands...
1918 features.resolveAlternatives();
1919 features.expandMultiples();
1922 if (!output_sync_macro.empty())
1923 os << from_utf8(output_sync_macro) +"\n";
1924 else if (features.runparams().flavor == OutputParams::LATEX)
1925 os << "\\usepackage[active]{srcltx}\n";
1926 else if (features.runparams().flavor == OutputParams::PDFLATEX)
1927 os << "\\synctex=-1\n";
1930 // The package options (via \PassOptionsToPackage)
1931 os << from_ascii(features.getPackageOptions());
1933 // due to interferences with babel and hyperref, the color package has to
1934 // be loaded (when it is not already loaded) before babel when hyperref
1935 // is used with the colorlinks option, see
1936 // http://www.lyx.org/trac/ticket/5291
1937 // we decided therefore to load color always before babel, see
1938 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
1939 os << from_ascii(features.getColorOptions());
1941 // If we use hyperref, jurabib, japanese, varioref or vietnamese,
1942 // we have to call babel before
1944 && (features.isRequired("jurabib")
1945 || features.isRequired("hyperref")
1946 || features.isRequired("varioref")
1947 || features.isRequired("vietnamese")
1948 || features.isRequired("japanese"))) {
1949 os << features.getBabelPresettings();
1951 os << from_utf8(babelCall(language_options.str(),
1952 features.needBabelLangOptions())) + '\n';
1953 os << features.getBabelPostsettings();
1956 // The optional packages;
1957 os << from_ascii(features.getPackages());
1959 // Additional Indices
1960 if (features.isRequired("splitidx")) {
1961 IndicesList::const_iterator iit = indiceslist().begin();
1962 IndicesList::const_iterator iend = indiceslist().end();
1963 for (; iit != iend; ++iit) {
1964 pair<docstring, docstring> indexname_latex =
1965 features.runparams().encoding->latexString(iit->index(),
1966 features.runparams().dryrun);
1967 if (!indexname_latex.second.empty()) {
1968 // issue a warning about omitted characters
1969 // FIXME: should be passed to the error dialog
1970 frontend::Alert::warning(_("Uncodable characters"),
1971 bformat(_("The following characters that are used in an index name are not\n"
1972 "representable in the current encoding and therefore have been omitted:\n%1$s."),
1973 indexname_latex.second));
1975 os << "\\newindex[";
1976 os << indexname_latex.first;
1978 os << escape(iit->shortcut());
1984 os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
1987 // * Hyperref manual: "Make sure it comes last of your loaded
1988 // packages, to give it a fighting chance of not being over-written,
1989 // since its job is to redefine many LaTeX commands."
1990 // * Email from Heiko Oberdiek: "It is usually better to load babel
1991 // before hyperref. Then hyperref has a chance to detect babel.
1992 // * Has to be loaded before the "LyX specific LaTeX commands" to
1993 // avoid errors with algorithm floats.
1994 // use hyperref explicitly if it is required
1995 if (features.isRequired("hyperref")) {
1996 OutputParams tmp_params = features.runparams();
1997 pdfoptions().writeLaTeX(tmp_params, os,
1998 features.isProvided("hyperref"));
1999 // correctly break URLs with hyperref and dvi output
2000 if (features.runparams().flavor == OutputParams::LATEX
2001 && features.isAvailable("breakurl"))
2002 os << "\\usepackage{breakurl}\n";
2003 } else if (features.isRequired("nameref"))
2004 // hyperref loads this automatically
2005 os << "\\usepackage{nameref}\n";
2007 // bibtopic needs to be loaded after hyperref.
2008 // the dot provides the aux file naming which LyX can detect.
2009 if (features.mustProvide("bibtopic"))
2010 os << "\\usepackage[dot]{bibtopic}\n";
2012 // Will be surrounded by \makeatletter and \makeatother when not empty
2013 otexstringstream atlyxpreamble;
2015 // Some macros LyX will need
2017 TexString tmppreamble = features.getMacros();
2018 if (!tmppreamble.str.empty())
2019 atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2020 "LyX specific LaTeX commands.\n"
2021 << move(tmppreamble)
2024 // the text class specific preamble
2026 docstring tmppreamble = features.getTClassPreamble();
2027 if (!tmppreamble.empty())
2028 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2029 "Textclass specific LaTeX commands.\n"
2033 // suppress date if selected
2034 // use \@ifundefined because we cannot be sure that every document class
2035 // has a \date command
2037 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2039 /* the user-defined preamble */
2040 if (!containsOnly(preamble, " \n\t")) {
2042 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2043 "User specified LaTeX commands.\n";
2045 // Check if the user preamble contains uncodable glyphs
2046 odocstringstream user_preamble;
2047 docstring uncodable_glyphs;
2048 Encoding const * const enc = features.runparams().encoding;
2050 for (size_t n = 0; n < preamble.size(); ++n) {
2051 char_type c = preamble[n];
2052 if (!enc->encodable(c)) {
2053 docstring const glyph(1, c);
2054 LYXERR0("Uncodable character '"
2056 << "' in user preamble!");
2057 uncodable_glyphs += glyph;
2058 if (features.runparams().dryrun) {
2059 user_preamble << "<" << _("LyX Warning: ")
2060 << _("uncodable character") << " '";
2061 user_preamble.put(c);
2062 user_preamble << "'>";
2065 user_preamble.put(c);
2068 user_preamble << preamble;
2070 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2071 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2072 frontend::Alert::warning(
2073 _("Uncodable character in user preamble"),
2075 _("The user preamble of your document contains glyphs "
2076 "that are unknown in the current document encoding "
2077 "(namely %1$s).\nThese glyphs are omitted "
2078 " from the output, which may result in "
2079 "incomplete output."
2080 "\n\nPlease select an appropriate "
2081 "document encoding\n"
2082 "(such as utf8) or change the "
2083 "preamble code accordingly."),
2086 atlyxpreamble << user_preamble.str() << '\n';
2089 // footmisc must be loaded after setspace
2090 // Load it here to avoid clashes with footmisc loaded in the user
2091 // preamble. For that reason we also pass the options via
2092 // \PassOptionsToPackage in getPreamble() and not here.
2093 if (features.mustProvide("footmisc"))
2094 atlyxpreamble << "\\usepackage{footmisc}\n";
2096 // subfig loads internally the LaTeX package "caption". As
2097 // caption is a very popular package, users will load it in
2098 // the preamble. Therefore we must load subfig behind the
2099 // user-defined preamble and check if the caption package was
2100 // loaded or not. For the case that caption is loaded before
2101 // subfig, there is the subfig option "caption=false". This
2102 // option also works when a koma-script class is used and
2103 // koma's own caption commands are used instead of caption. We
2104 // use \PassOptionsToPackage here because the user could have
2105 // already loaded subfig in the preamble.
2106 if (features.mustProvide("subfig"))
2107 atlyxpreamble << "\\@ifundefined{showcaptionsetup}{}{%\n"
2108 " \\PassOptionsToPackage{caption=false}{subfig}}\n"
2109 "\\usepackage{subfig}\n";
2111 // Itemize bullet settings need to be last in case the user
2112 // defines their own bullets that use a package included
2113 // in the user-defined preamble -- ARRae
2114 // Actually it has to be done much later than that
2115 // since some packages like frenchb make modifications
2116 // at \begin{document} time -- JMarc
2117 docstring bullets_def;
2118 for (int i = 0; i < 4; ++i) {
2119 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2120 if (bullets_def.empty())
2121 bullets_def += "\\AtBeginDocument{\n";
2122 bullets_def += " \\def\\labelitemi";
2124 // `i' is one less than the item to modify
2131 bullets_def += "ii";
2137 bullets_def += '{' +
2138 user_defined_bullet(i).getText()
2143 if (!bullets_def.empty())
2144 atlyxpreamble << bullets_def << "}\n\n";
2146 if (!atlyxpreamble.empty())
2147 os << "\n\\makeatletter\n"
2148 << atlyxpreamble.release()
2149 << "\\makeatother\n\n";
2151 // We try to load babel late, in case it interferes with other packages.
2152 // Jurabib, hyperref, varioref, bicaption and listings (bug 8995) have to be
2153 // called after babel, though.
2154 if (use_babel && !features.isRequired("jurabib")
2155 && !features.isRequired("hyperref")
2156 && !features.isRequired("varioref")
2157 && !features.isRequired("vietnamese")
2158 && !features.isRequired("japanese")) {
2159 os << features.getBabelPresettings();
2161 os << from_utf8(babelCall(language_options.str(),
2162 features.needBabelLangOptions())) + '\n';
2163 os << features.getBabelPostsettings();
2165 if (features.isRequired("bicaption"))
2166 os << "\\usepackage{bicaption}\n";
2167 if (!listings_params.empty() || features.mustProvide("listings"))
2168 os << "\\usepackage{listings}\n";
2169 if (!listings_params.empty()) {
2171 // do not test validity because listings_params is
2172 // supposed to be valid
2174 InsetListingsParams(listings_params).separatedParams(true);
2175 os << from_utf8(par);
2179 // xunicode needs to be loaded at least after amsmath, amssymb,
2180 // esint and the other packages that provide special glyphs
2181 // The package only supports XeTeX currently.
2182 if (features.runparams().flavor == OutputParams::XETEX
2184 os << "\\usepackage{xunicode}\n";
2186 // Polyglossia must be loaded last
2187 if (use_polyglossia) {
2189 os << "\\usepackage{polyglossia}\n";
2190 // set the main language
2191 os << "\\setdefaultlanguage";
2192 if (!language->polyglossiaOpts().empty())
2193 os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2194 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2195 // now setup the other languages
2196 set<string> const polylangs =
2197 features.getPolyglossiaLanguages();
2198 for (set<string>::const_iterator mit = polylangs.begin();
2199 mit != polylangs.end() ; ++mit) {
2200 // We do not output the options here; they are output in
2201 // the language switch commands. This is safer if multiple
2202 // varieties are used.
2203 if (*mit == language->polyglossia())
2205 os << "\\setotherlanguage";
2206 os << "{" << from_ascii(*mit) << "}\n";
2210 // Load custom language package here
2211 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2212 if (lang_package == "default")
2213 os << from_utf8(lyxrc.language_custom_package);
2215 os << from_utf8(lang_package);
2219 docstring const i18npreamble =
2220 features.getTClassI18nPreamble(use_babel, use_polyglossia);
2221 if (!i18npreamble.empty())
2222 os << i18npreamble + '\n';
2228 void BufferParams::useClassDefaults()
2230 DocumentClass const & tclass = documentClass();
2232 sides = tclass.sides();
2233 columns = tclass.columns();
2234 pagestyle = tclass.pagestyle();
2235 use_default_options = true;
2236 // Only if class has a ToC hierarchy
2237 if (tclass.hasTocLevels()) {
2238 secnumdepth = tclass.secnumdepth();
2239 tocdepth = tclass.tocdepth();
2244 bool BufferParams::hasClassDefaults() const
2246 DocumentClass const & tclass = documentClass();
2248 return sides == tclass.sides()
2249 && columns == tclass.columns()
2250 && pagestyle == tclass.pagestyle()
2251 && use_default_options
2252 && secnumdepth == tclass.secnumdepth()
2253 && tocdepth == tclass.tocdepth();
2257 DocumentClass const & BufferParams::documentClass() const
2263 DocumentClassConstPtr BufferParams::documentClassPtr() const
2269 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2271 // evil, but this function is evil
2272 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2273 invalidateConverterCache();
2277 bool BufferParams::setBaseClass(string const & classname)
2279 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2280 LayoutFileList & bcl = LayoutFileList::get();
2281 if (!bcl.haveClass(classname)) {
2283 bformat(_("The layout file:\n"
2285 "could not be found. A default textclass with default\n"
2286 "layouts will be used. LyX will not be able to produce\n"
2288 from_utf8(classname));
2289 frontend::Alert::error(_("Document class not found"), s);
2290 bcl.addEmptyClass(classname);
2293 bool const success = bcl[classname].load();
2296 bformat(_("Due to some error in it, the layout file:\n"
2298 "could not be loaded. A default textclass with default\n"
2299 "layouts will be used. LyX will not be able to produce\n"
2301 from_utf8(classname));
2302 frontend::Alert::error(_("Could not load class"), s);
2303 bcl.addEmptyClass(classname);
2306 pimpl_->baseClass_ = classname;
2307 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2312 LayoutFile const * BufferParams::baseClass() const
2314 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2315 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2321 LayoutFileIndex const & BufferParams::baseClassID() const
2323 return pimpl_->baseClass_;
2327 void BufferParams::makeDocumentClass(bool const clone)
2332 invalidateConverterCache();
2333 LayoutModuleList mods;
2334 LayoutModuleList::iterator it = layout_modules_.begin();
2335 LayoutModuleList::iterator en = layout_modules_.end();
2336 for (; it != en; ++it)
2337 mods.push_back(*it);
2339 it = cite_engine_.begin();
2340 en = cite_engine_.end();
2341 for (; it != en; ++it)
2342 mods.push_back(*it);
2344 doc_class_ = getDocumentClass(*baseClass(), mods, clone);
2346 TextClass::ReturnValues success = TextClass::OK;
2347 if (!forced_local_layout_.empty())
2348 success = doc_class_->read(to_utf8(forced_local_layout_),
2350 if (!local_layout_.empty() &&
2351 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2352 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2353 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2354 docstring const msg = _("Error reading internal layout information");
2355 frontend::Alert::warning(_("Read Error"), msg);
2360 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2362 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2366 bool BufferParams::citationModuleCanBeAdded(string const & modName) const
2368 return cite_engine_.moduleCanBeAdded(modName, baseClass());
2372 docstring BufferParams::getLocalLayout(bool forced) const
2375 return from_utf8(doc_class_->forcedLayouts());
2377 return local_layout_;
2381 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2384 forced_local_layout_ = layout;
2386 local_layout_ = layout;
2390 bool BufferParams::addLayoutModule(string const & modName)
2392 LayoutModuleList::const_iterator it = layout_modules_.begin();
2393 LayoutModuleList::const_iterator end = layout_modules_.end();
2394 for (; it != end; ++it)
2397 layout_modules_.push_back(modName);
2402 string BufferParams::bufferFormat() const
2404 return documentClass().outputFormat();
2408 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2410 FormatList const & formats = exportableFormats(need_viewable);
2411 FormatList::const_iterator fit = formats.begin();
2412 FormatList::const_iterator end = formats.end();
2413 for (; fit != end ; ++fit) {
2414 if ((*fit)->name() == format)
2421 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2423 FormatList & cached = only_viewable ?
2424 pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2425 bool & valid = only_viewable ?
2426 pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2430 vector<string> const backs = backends();
2431 set<string> excludes;
2432 if (useNonTeXFonts) {
2433 excludes.insert("latex");
2434 excludes.insert("pdflatex");
2437 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2438 for (vector<string>::const_iterator it = backs.begin() + 1;
2439 it != backs.end(); ++it) {
2440 FormatList r = theConverters().getReachable(*it, only_viewable,
2442 result.insert(result.end(), r.begin(), r.end());
2444 sort(result.begin(), result.end(), Format::formatSorter);
2451 vector<string> BufferParams::backends() const
2454 string const buffmt = bufferFormat();
2456 // FIXME: Don't hardcode format names here, but use a flag
2457 if (buffmt == "latex") {
2458 if (encoding().package() == Encoding::japanese)
2459 v.push_back("platex");
2461 if (!useNonTeXFonts) {
2462 v.push_back("pdflatex");
2463 v.push_back("latex");
2465 v.push_back("xetex");
2466 v.push_back("luatex");
2467 v.push_back("dviluatex");
2470 v.push_back(buffmt);
2472 v.push_back("xhtml");
2473 v.push_back("text");
2479 OutputParams::FLAVOR BufferParams::getOutputFlavor(string const & format) const
2481 string const dformat = (format.empty() || format == "default") ?
2482 getDefaultOutputFormat() : format;
2483 DefaultFlavorCache::const_iterator it =
2484 default_flavors_.find(dformat);
2486 if (it != default_flavors_.end())
2489 OutputParams::FLAVOR result = OutputParams::LATEX;
2491 // FIXME It'd be better not to hardcode this, but to do
2492 // something with formats.
2493 if (dformat == "xhtml")
2494 result = OutputParams::HTML;
2495 else if (dformat == "text")
2496 result = OutputParams::TEXT;
2497 else if (dformat == "lyx")
2498 result = OutputParams::LYX;
2499 else if (dformat == "pdflatex")
2500 result = OutputParams::PDFLATEX;
2501 else if (dformat == "xetex")
2502 result = OutputParams::XETEX;
2503 else if (dformat == "luatex")
2504 result = OutputParams::LUATEX;
2505 else if (dformat == "dviluatex")
2506 result = OutputParams::DVILUATEX;
2508 // Try to determine flavor of default output format
2509 vector<string> backs = backends();
2510 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2511 // Get shortest path to format
2512 Graph::EdgePath path;
2513 for (vector<string>::const_iterator it = backs.begin();
2514 it != backs.end(); ++it) {
2515 Graph::EdgePath p = theConverters().getPath(*it, dformat);
2516 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2521 result = theConverters().getFlavor(path);
2524 // cache this flavor
2525 default_flavors_[dformat] = result;
2530 string BufferParams::getDefaultOutputFormat() const
2532 if (!default_output_format.empty()
2533 && default_output_format != "default")
2534 return default_output_format;
2536 || encoding().package() == Encoding::japanese) {
2537 FormatList const & formats = exportableFormats(true);
2538 if (formats.empty())
2540 // return the first we find
2541 return formats.front()->name();
2544 return lyxrc.default_otf_view_format;
2545 return lyxrc.default_view_format;
2548 Font const BufferParams::getFont() const
2550 FontInfo f = documentClass().defaultfont();
2551 if (fonts_default_family == "rmdefault")
2552 f.setFamily(ROMAN_FAMILY);
2553 else if (fonts_default_family == "sfdefault")
2554 f.setFamily(SANS_FAMILY);
2555 else if (fonts_default_family == "ttdefault")
2556 f.setFamily(TYPEWRITER_FAMILY);
2557 return Font(f, language);
2561 InsetQuotesParams::QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2563 return quotesstyletranslator().find(qs);
2567 bool BufferParams::isLatex() const
2569 return documentClass().outputType() == LATEX;
2573 bool BufferParams::isLiterate() const
2575 return documentClass().outputType() == LITERATE;
2579 bool BufferParams::isDocBook() const
2581 return documentClass().outputType() == DOCBOOK;
2585 void BufferParams::readPreamble(Lexer & lex)
2587 if (lex.getString() != "\\begin_preamble")
2588 lyxerr << "Error (BufferParams::readPreamble):"
2589 "consistency check failed." << endl;
2591 preamble = lex.getLongString(from_ascii("\\end_preamble"));
2595 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2597 string const expected = forced ? "\\begin_forced_local_layout" :
2598 "\\begin_local_layout";
2599 if (lex.getString() != expected)
2600 lyxerr << "Error (BufferParams::readLocalLayout):"
2601 "consistency check failed." << endl;
2604 forced_local_layout_ =
2605 lex.getLongString(from_ascii("\\end_forced_local_layout"));
2607 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2611 bool BufferParams::setLanguage(string const & lang)
2613 Language const *new_language = languages.getLanguage(lang);
2614 if (!new_language) {
2615 // Language lang was not found
2618 language = new_language;
2623 void BufferParams::readLanguage(Lexer & lex)
2625 if (!lex.next()) return;
2627 string const tmptok = lex.getString();
2629 // check if tmptok is part of tex_babel in tex-defs.h
2630 if (!setLanguage(tmptok)) {
2631 // Language tmptok was not found
2632 language = default_language;
2633 lyxerr << "Warning: Setting language `"
2634 << tmptok << "' to `" << language->lang()
2640 void BufferParams::readGraphicsDriver(Lexer & lex)
2645 string const tmptok = lex.getString();
2646 // check if tmptok is part of tex_graphics in tex_defs.h
2649 string const test = tex_graphics[n++];
2651 if (test == tmptok) {
2652 graphics_driver = tmptok;
2657 "Warning: graphics driver `$$Token' not recognized!\n"
2658 " Setting graphics driver to `default'.\n");
2659 graphics_driver = "default";
2666 void BufferParams::readBullets(Lexer & lex)
2671 int const index = lex.getInteger();
2673 int temp_int = lex.getInteger();
2674 user_defined_bullet(index).setFont(temp_int);
2675 temp_bullet(index).setFont(temp_int);
2677 user_defined_bullet(index).setCharacter(temp_int);
2678 temp_bullet(index).setCharacter(temp_int);
2680 user_defined_bullet(index).setSize(temp_int);
2681 temp_bullet(index).setSize(temp_int);
2685 void BufferParams::readBulletsLaTeX(Lexer & lex)
2687 // The bullet class should be able to read this.
2690 int const index = lex.getInteger();
2692 docstring const temp_str = lex.getDocString();
2694 user_defined_bullet(index).setText(temp_str);
2695 temp_bullet(index).setText(temp_str);
2699 void BufferParams::readModules(Lexer & lex)
2701 if (!lex.eatLine()) {
2702 lyxerr << "Error (BufferParams::readModules):"
2703 "Unexpected end of input." << endl;
2707 string mod = lex.getString();
2708 if (mod == "\\end_modules")
2710 addLayoutModule(mod);
2716 void BufferParams::readRemovedModules(Lexer & lex)
2718 if (!lex.eatLine()) {
2719 lyxerr << "Error (BufferParams::readRemovedModules):"
2720 "Unexpected end of input." << endl;
2724 string mod = lex.getString();
2725 if (mod == "\\end_removed_modules")
2727 removed_modules_.push_back(mod);
2730 // now we want to remove any removed modules that were previously
2731 // added. normally, that will be because default modules were added in
2732 // setBaseClass(), which gets called when \textclass is read at the
2733 // start of the read.
2734 list<string>::const_iterator rit = removed_modules_.begin();
2735 list<string>::const_iterator const ren = removed_modules_.end();
2736 for (; rit != ren; ++rit) {
2737 LayoutModuleList::iterator const mit = layout_modules_.begin();
2738 LayoutModuleList::iterator const men = layout_modules_.end();
2739 LayoutModuleList::iterator found = find(mit, men, *rit);
2742 layout_modules_.erase(found);
2747 void BufferParams::readIncludeonly(Lexer & lex)
2749 if (!lex.eatLine()) {
2750 lyxerr << "Error (BufferParams::readIncludeonly):"
2751 "Unexpected end of input." << endl;
2755 string child = lex.getString();
2756 if (child == "\\end_includeonly")
2758 included_children_.push_back(child);
2764 string BufferParams::paperSizeName(PapersizePurpose purpose) const
2766 switch (papersize) {
2768 // could be anything, so don't guess
2770 case PAPER_CUSTOM: {
2771 if (purpose == XDVI && !paperwidth.empty() &&
2772 !paperheight.empty()) {
2773 // heightxwidth<unit>
2774 string first = paperwidth;
2775 string second = paperheight;
2776 if (orientation == ORIENTATION_LANDSCAPE)
2779 return first.erase(first.length() - 2)
2785 // dvips and dvipdfm do not know this
2786 if (purpose == DVIPS || purpose == DVIPDFM)
2790 if (purpose == DVIPS || purpose == DVIPDFM)
2794 if (purpose == DVIPS || purpose == DVIPDFM)
2804 if (purpose == DVIPS || purpose == DVIPDFM)
2808 if (purpose == DVIPS || purpose == DVIPDFM)
2812 if (purpose == DVIPS || purpose == DVIPDFM)
2816 if (purpose == DVIPS || purpose == DVIPDFM)
2820 if (purpose == DVIPS || purpose == DVIPDFM)
2824 // dvipdfm does not know this
2825 if (purpose == DVIPDFM)
2829 if (purpose == DVIPDFM)
2833 if (purpose == DVIPS || purpose == DVIPDFM)
2837 if (purpose == DVIPS || purpose == DVIPDFM)
2841 if (purpose == DVIPS || purpose == DVIPDFM)
2845 if (purpose == DVIPS || purpose == DVIPDFM)
2849 if (purpose == DVIPS || purpose == DVIPDFM)
2853 if (purpose == DVIPS || purpose == DVIPDFM)
2857 if (purpose == DVIPS || purpose == DVIPDFM)
2861 if (purpose == DVIPS || purpose == DVIPDFM)
2865 if (purpose == DVIPS || purpose == DVIPDFM)
2869 if (purpose == DVIPS || purpose == DVIPDFM)
2873 if (purpose == DVIPS || purpose == DVIPDFM)
2877 if (purpose == DVIPS || purpose == DVIPDFM)
2881 if (purpose == DVIPS || purpose == DVIPDFM)
2885 if (purpose == DVIPS || purpose == DVIPDFM)
2889 if (purpose == DVIPS || purpose == DVIPDFM)
2892 case PAPER_USEXECUTIVE:
2893 // dvipdfm does not know this
2894 if (purpose == DVIPDFM)
2899 case PAPER_USLETTER:
2901 if (purpose == XDVI)
2908 string const BufferParams::dvips_options() const
2912 // If the class loads the geometry package, we do not know which
2913 // paper size is used, since we do not set it (bug 7013).
2914 // Therefore we must not specify any argument here.
2915 // dvips gets the correct paper size via DVI specials in this case
2916 // (if the class uses the geometry package correctly).
2917 if (documentClass().provides("geometry"))
2921 && papersize == PAPER_CUSTOM
2922 && !lyxrc.print_paper_dimension_flag.empty()
2923 && !paperwidth.empty()
2924 && !paperheight.empty()) {
2925 // using a custom papersize
2926 result = lyxrc.print_paper_dimension_flag;
2927 result += ' ' + paperwidth;
2928 result += ',' + paperheight;
2930 string const paper_option = paperSizeName(DVIPS);
2931 if (!paper_option.empty() && (paper_option != "letter" ||
2932 orientation != ORIENTATION_LANDSCAPE)) {
2933 // dvips won't accept -t letter -t landscape.
2934 // In all other cases, include the paper size
2936 result = lyxrc.print_paper_flag;
2937 result += ' ' + paper_option;
2940 if (orientation == ORIENTATION_LANDSCAPE &&
2941 papersize != PAPER_CUSTOM)
2942 result += ' ' + lyxrc.print_landscape_flag;
2947 string const BufferParams::font_encoding() const
2949 return font_encodings().empty() ? "default" : font_encodings().back();
2953 vector<string> const BufferParams::font_encodings() const
2955 string doc_fontenc = (fontenc == "global") ? lyxrc.fontenc : fontenc;
2957 vector<string> fontencs;
2959 // "default" means "no explicit font encoding"
2960 if (doc_fontenc != "default") {
2961 fontencs = getVectorFromString(doc_fontenc);
2962 if (!language->fontenc().empty()
2963 && ascii_lowercase(language->fontenc()) != "none") {
2964 vector<string> fencs = getVectorFromString(language->fontenc());
2965 vector<string>::const_iterator fit = fencs.begin();
2966 for (; fit != fencs.end(); ++fit) {
2967 if (find(fontencs.begin(), fontencs.end(), *fit) == fontencs.end())
2968 fontencs.push_back(*fit);
2977 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
2979 // suppress the babel call if there is no BabelName defined
2980 // for the document language in the lib/languages file and if no
2981 // other languages are used (lang_opts is then empty)
2982 if (lang_opts.empty())
2984 // either a specific language (AsBabelOptions setting in
2985 // lib/languages) or the prefs require the languages to
2986 // be submitted to babel itself (not the class).
2988 return "\\usepackage[" + lang_opts + "]{babel}";
2989 return "\\usepackage{babel}";
2993 docstring BufferParams::getGraphicsDriver(string const & package) const
2997 if (package == "geometry") {
2998 if (graphics_driver == "dvips"
2999 || graphics_driver == "dvipdfm"
3000 || graphics_driver == "pdftex"
3001 || graphics_driver == "vtex")
3002 result = from_ascii(graphics_driver);
3003 else if (graphics_driver == "dvipdfmx")
3004 result = from_ascii("dvipdfm");
3011 void BufferParams::writeEncodingPreamble(otexstream & os,
3012 LaTeXFeatures & features) const
3014 // XeTeX/LuaTeX: (see also #9740)
3015 // With Unicode fonts we use utf8-plain without encoding package.
3016 // With TeX fonts, we cannot use utf8-plain, but "inputenc" fails.
3017 // XeTeX must use ASCII encoding (see Buffer.cpp),
3018 // for LuaTeX, we load "luainputenc" (see below).
3019 if (useNonTeXFonts || features.runparams().flavor == OutputParams::XETEX)
3022 if (inputenc == "auto") {
3023 string const doc_encoding =
3024 language->encoding()->latexName();
3025 Encoding::Package const package =
3026 language->encoding()->package();
3028 // Create list of inputenc options:
3029 set<string> encodings;
3030 // luainputenc fails with more than one encoding
3031 if (!features.runparams().isFullUnicode()) // if we reach this point, this means LuaTeX with TeX fonts
3032 // list all input encodings used in the document
3033 encodings = features.getEncodingSet(doc_encoding);
3035 // If the "japanese" package (i.e. pLaTeX) is used,
3036 // inputenc must be omitted.
3037 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3038 if ((!encodings.empty() || package == Encoding::inputenc)
3039 && !features.isRequired("japanese")
3040 && !features.isProvided("inputenc")) {
3041 os << "\\usepackage[";
3042 set<string>::const_iterator it = encodings.begin();
3043 set<string>::const_iterator const end = encodings.end();
3045 os << from_ascii(*it);
3048 for (; it != end; ++it)
3049 os << ',' << from_ascii(*it);
3050 if (package == Encoding::inputenc) {
3051 if (!encodings.empty())
3053 os << from_ascii(doc_encoding);
3055 if (features.runparams().flavor == OutputParams::LUATEX
3056 || features.runparams().flavor == OutputParams::DVILUATEX)
3057 os << "]{luainputenc}\n";
3059 os << "]{inputenc}\n";
3061 if (package == Encoding::CJK || features.mustProvide("CJK")) {
3062 if (language->encoding()->name() == "utf8-cjk"
3063 && LaTeXFeatures::isAvailable("CJKutf8"))
3064 os << "\\usepackage{CJKutf8}\n";
3066 os << "\\usepackage{CJK}\n";
3068 } else if (inputenc != "default") {
3069 switch (encoding().package()) {
3070 case Encoding::none:
3071 case Encoding::japanese:
3073 case Encoding::inputenc:
3074 // do not load inputenc if japanese is used
3075 // or if the class provides inputenc
3076 if (features.isRequired("japanese")
3077 || features.isProvided("inputenc"))
3079 os << "\\usepackage[" << from_ascii(encoding().latexName());
3080 if (features.runparams().flavor == OutputParams::LUATEX
3081 || features.runparams().flavor == OutputParams::DVILUATEX)
3082 os << "]{luainputenc}\n";
3084 os << "]{inputenc}\n";
3087 if (encoding().name() == "utf8-cjk"
3088 && LaTeXFeatures::isAvailable("CJKutf8"))
3089 os << "\\usepackage{CJKutf8}\n";
3091 os << "\\usepackage{CJK}\n";
3094 // Load the CJK package if needed by a secondary language.
3095 // If the main encoding is some variant of UTF8, use CJKutf8.
3096 if (encoding().package() != Encoding::CJK && features.mustProvide("CJK")) {
3097 if (encoding().iconvName() == "UTF-8"
3098 && LaTeXFeatures::isAvailable("CJKutf8"))
3099 os << "\\usepackage{CJKutf8}\n";
3101 os << "\\usepackage{CJK}\n";
3107 string const BufferParams::parseFontName(string const & name) const
3109 string mangled = name;
3110 size_t const idx = mangled.find('[');
3111 if (idx == string::npos || idx == 0)
3114 return mangled.substr(0, idx - 1);
3118 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3120 if (fontsRoman() == "default" && fontsSans() == "default"
3121 && fontsTypewriter() == "default"
3122 && (fontsMath() == "default" || fontsMath() == "auto"))
3128 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3129 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3130 * Mapping=tex-text option assures TeX ligatures (such as "--")
3131 * are resolved. Note that tt does not use these ligatures.
3133 * -- add more GUI options?
3134 * -- add more fonts (fonts for other scripts)
3135 * -- if there's a way to find out if a font really supports
3136 * OldStyle, enable/disable the widget accordingly.
3138 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3139 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3140 // However, until v.2 (2010/07/11) fontspec only knew
3141 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3142 // was introduced for both XeTeX and LuaTeX (LuaTeX
3143 // didn't understand "Mapping=tex-text", while XeTeX
3144 // understood both. With most recent versions, both
3145 // variants are understood by both engines. However,
3146 // we want to provide support for at least TeXLive 2009
3147 // (for XeTeX; LuaTeX is only supported as of v.2)
3148 string const texmapping =
3149 (features.runparams().flavor == OutputParams::XETEX) ?
3150 "Mapping=tex-text" : "Ligatures=TeX";
3151 if (fontsRoman() != "default") {
3152 os << "\\setmainfont[" << texmapping;
3153 if (fonts_old_figures)
3154 os << ",Numbers=OldStyle";
3155 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3157 if (fontsSans() != "default") {
3158 string const sans = parseFontName(fontsSans());
3159 if (fontsSansScale() != 100)
3160 os << "\\setsansfont[Scale="
3161 << float(fontsSansScale()) / 100
3162 << "," << texmapping << "]{"
3165 os << "\\setsansfont[" << texmapping << "]{"
3168 if (fontsTypewriter() != "default") {
3169 string const mono = parseFontName(fontsTypewriter());
3170 if (fontsTypewriterScale() != 100)
3171 os << "\\setmonofont[Scale="
3172 << float(fontsTypewriterScale()) / 100
3176 os << "\\setmonofont{"
3183 bool const ot1 = (font_encoding() == "default" || font_encoding() == "OT1");
3184 bool const dryrun = features.runparams().dryrun;
3185 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3186 bool const nomath = (fontsMath() == "default");
3189 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3190 dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures,
3194 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3195 dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures,
3196 nomath, fontsSansScale());
3198 // MONOSPACED/TYPEWRITER
3199 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3200 dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures,
3201 nomath, fontsTypewriterScale());
3204 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3205 dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures,
3212 Encoding const & BufferParams::encoding() const
3214 // Main encoding for LaTeX output.
3216 // Exception: XeTeX with 8-bit TeX fonts requires ASCII (see #9740).
3217 // As the "flavor" is only known once export started, this
3218 // cannot be handled here. Instead, runparams.encoding is set
3219 // to ASCII in Buffer::makeLaTeXFile (for export)
3220 // and Buffer::writeLaTeXSource (for preview).
3222 return *(encodings.fromLyXName("utf8-plain"));
3223 if (inputenc == "auto" || inputenc == "default")
3224 return *language->encoding();
3225 Encoding const * const enc = encodings.fromLyXName(inputenc);
3228 LYXERR0("Unknown inputenc value `" << inputenc
3229 << "'. Using `auto' instead.");
3230 return *language->encoding();
3234 bool BufferParams::addCiteEngine(string const & engine)
3236 LayoutModuleList::const_iterator it = cite_engine_.begin();
3237 LayoutModuleList::const_iterator en = cite_engine_.end();
3238 for (; it != en; ++it)
3241 cite_engine_.push_back(engine);
3246 bool BufferParams::addCiteEngine(vector<string> const & engine)
3248 vector<string>::const_iterator it = engine.begin();
3249 vector<string>::const_iterator en = engine.end();
3251 for (; it != en; ++it)
3252 if (!addCiteEngine(*it))
3258 string const & BufferParams::defaultBiblioStyle() const
3260 return documentClass().defaultBiblioStyle();
3264 bool const & BufferParams::fullAuthorList() const
3266 return documentClass().fullAuthorList();
3270 void BufferParams::setCiteEngine(string const & engine)
3273 addCiteEngine(engine);
3277 void BufferParams::setCiteEngine(vector<string> const & engine)
3280 addCiteEngine(engine);
3284 vector<string> BufferParams::citeCommands() const
3286 static CitationStyle const default_style;
3287 vector<string> commands =
3288 documentClass().citeCommands(citeEngineType());
3289 if (commands.empty())
3290 commands.push_back(default_style.cmd);
3295 vector<CitationStyle> BufferParams::citeStyles() const
3297 static CitationStyle const default_style;
3298 vector<CitationStyle> styles =
3299 documentClass().citeStyles(citeEngineType());
3301 styles.push_back(default_style);
3305 void BufferParams::invalidateConverterCache() const
3307 pimpl_->isExportCacheValid = false;
3308 pimpl_->isViewCacheValid = false;