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;
435 docstring BufferParams::B_(string const & l10n) const
437 LASSERT(language, return from_utf8(l10n));
438 return getMessages(language->code()).get(l10n);
442 BufferParams::Package BufferParams::use_package(std::string const & p) const
444 PackageMap::const_iterator it = use_packages.find(p);
445 if (it == use_packages.end())
451 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
457 map<string, string> const & BufferParams::auto_packages()
459 static map<string, string> packages;
460 if (packages.empty()) {
461 // We could have a race condition here that two threads
462 // discover an empty map at the same time and want to fill
463 // it, but that is no problem, since the same contents is
464 // filled in twice then. Having the locker inside the
465 // packages.empty() condition has the advantage that we
466 // don't need the mutex overhead for simple reading.
468 Mutex::Locker locker(&mutex);
469 // adding a package here implies a file format change!
470 packages["amsmath"] =
471 N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
472 packages["amssymb"] =
473 N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
475 N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
477 N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
478 packages["mathdots"] =
479 N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
480 packages["mathtools"] =
481 N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
483 N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
484 packages["stackrel"] =
485 N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
486 packages["stmaryrd"] =
487 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");
488 packages["undertilde"] =
489 N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
495 AuthorList & BufferParams::authors()
497 return pimpl_->authorlist;
501 AuthorList const & BufferParams::authors() const
503 return pimpl_->authorlist;
507 BranchList & BufferParams::branchlist()
509 return pimpl_->branchlist;
513 BranchList const & BufferParams::branchlist() const
515 return pimpl_->branchlist;
519 IndicesList & BufferParams::indiceslist()
521 return pimpl_->indiceslist;
525 IndicesList const & BufferParams::indiceslist() const
527 return pimpl_->indiceslist;
531 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
533 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
534 return pimpl_->temp_bullets[index];
538 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
540 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
541 return pimpl_->temp_bullets[index];
545 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
547 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
548 return pimpl_->user_defined_bullets[index];
552 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
554 LASSERT(index < 4, return pimpl_->temp_bullets[0]);
555 return pimpl_->user_defined_bullets[index];
559 Spacing & BufferParams::spacing()
561 return pimpl_->spacing;
565 Spacing const & BufferParams::spacing() const
567 return pimpl_->spacing;
571 PDFOptions & BufferParams::pdfoptions()
573 return pimpl_->pdfoptions;
577 PDFOptions const & BufferParams::pdfoptions() const
579 return pimpl_->pdfoptions;
583 HSpace const & BufferParams::getIndentation() const
585 return pimpl_->indentation;
589 void BufferParams::setIndentation(HSpace const & indent)
591 pimpl_->indentation = indent;
595 VSpace const & BufferParams::getDefSkip() const
597 return pimpl_->defskip;
601 void BufferParams::setDefSkip(VSpace const & vs)
603 // DEFSKIP will cause an infinite loop
604 LASSERT(vs.kind() != VSpace::DEFSKIP, return);
605 pimpl_->defskip = vs;
609 string BufferParams::readToken(Lexer & lex, string const & token,
610 FileName const & filepath)
614 if (token == "\\textclass") {
616 string const classname = lex.getString();
617 // if there exists a local layout file, ignore the system one
618 // NOTE: in this case, the textclass (.cls file) is assumed to
621 LayoutFileList & bcl = LayoutFileList::get();
622 if (!filepath.empty()) {
623 // If classname is an absolute path, the document is
624 // using a local layout file which could not be accessed
625 // by a relative path. In this case the path is correct
626 // even if the document was moved to a different
627 // location. However, we will have a problem if the
628 // document was generated on a different platform.
629 bool isabsolute = FileName::isAbsolute(classname);
630 string const classpath = onlyPath(classname);
631 string const path = isabsolute ? classpath
632 : FileName(addPath(filepath.absFileName(),
633 classpath)).realPath();
634 string const oldpath = isabsolute ? string()
635 : FileName(addPath(origin, classpath)).realPath();
636 tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
638 // that returns non-empty if a "local" layout file is found.
640 result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
641 from_utf8(filepath.absFileName())));
644 setBaseClass(onlyFileName(tcp));
646 setBaseClass(onlyFileName(classname));
647 // We assume that a tex class exists for local or unknown
648 // layouts so this warning, will only be given for system layouts.
649 if (!baseClass()->isTeXClassAvailable()) {
650 docstring const desc =
651 translateIfPossible(from_utf8(baseClass()->description()));
652 docstring const prereqs =
653 from_utf8(baseClass()->prerequisites());
654 docstring const msg =
655 bformat(_("The selected document class\n"
657 "requires external files that are not available.\n"
658 "The document class can still be used, but the\n"
659 "document cannot be compiled until the following\n"
660 "prerequisites are installed:\n"
662 "See section 3.1.2.2 (Class Availability) of the\n"
663 "User's Guide for more information."), desc, prereqs);
664 frontend::Alert::warning(_("Document class not available"),
667 } else if (token == "\\origin") {
669 origin = lex.getString();
670 string const sysdirprefix = "/systemlyxdir/";
671 if (prefixIs(origin, sysdirprefix)) {
672 origin.replace(0, sysdirprefix.length() - 1,
673 package().system_support().absFileName());
675 } else if (token == "\\begin_preamble") {
677 } else if (token == "\\begin_local_layout") {
678 readLocalLayout(lex, false);
679 } else if (token == "\\begin_forced_local_layout") {
680 readLocalLayout(lex, true);
681 } else if (token == "\\begin_modules") {
683 } else if (token == "\\begin_removed_modules") {
684 readRemovedModules(lex);
685 } else if (token == "\\begin_includeonly") {
686 readIncludeonly(lex);
687 } else if (token == "\\maintain_unincluded_children") {
688 lex >> maintain_unincluded_children;
689 } else if (token == "\\options") {
691 options = lex.getString();
692 } else if (token == "\\use_default_options") {
693 lex >> use_default_options;
694 } else if (token == "\\master") {
696 master = lex.getString();
697 if (!filepath.empty() && FileName::isAbsolute(origin)) {
698 bool const isabs = FileName::isAbsolute(master);
699 FileName const abspath(isabs ? master : origin + master);
700 bool const moved = filepath != FileName(origin);
701 if (moved && abspath.exists()) {
702 docstring const path = isabs
704 : from_utf8(abspath.realPath());
705 docstring const refpath =
706 from_utf8(filepath.absFileName());
707 master = to_utf8(makeRelPath(path, refpath));
710 } else if (token == "\\suppress_date") {
711 lex >> suppress_date;
712 } else if (token == "\\justification") {
713 lex >> justification;
714 } else if (token == "\\language") {
716 } else if (token == "\\language_package") {
718 lang_package = lex.getString();
719 } else if (token == "\\inputencoding") {
721 } else if (token == "\\graphics") {
722 readGraphicsDriver(lex);
723 } else if (token == "\\default_output_format") {
724 lex >> default_output_format;
725 } else if (token == "\\bibtex_command") {
727 bibtex_command = lex.getString();
728 } else if (token == "\\index_command") {
730 index_command = lex.getString();
731 } else if (token == "\\fontencoding") {
733 fontenc = lex.getString();
734 } else if (token == "\\font_roman") {
735 lex >> fonts_roman[0];
736 lex >> fonts_roman[1];
737 } else if (token == "\\font_sans") {
738 lex >> fonts_sans[0];
739 lex >> fonts_sans[1];
740 } else if (token == "\\font_typewriter") {
741 lex >> fonts_typewriter[0];
742 lex >> fonts_typewriter[1];
743 } else if (token == "\\font_math") {
744 lex >> fonts_math[0];
745 lex >> fonts_math[1];
746 } else if (token == "\\font_default_family") {
747 lex >> fonts_default_family;
748 } else if (token == "\\use_non_tex_fonts") {
749 lex >> useNonTeXFonts;
750 } else if (token == "\\font_sc") {
751 lex >> fonts_expert_sc;
752 } else if (token == "\\font_osf") {
753 lex >> fonts_old_figures;
754 } else if (token == "\\font_sf_scale") {
755 lex >> fonts_sans_scale[0];
756 lex >> fonts_sans_scale[1];
757 } else if (token == "\\font_tt_scale") {
758 lex >> fonts_typewriter_scale[0];
759 lex >> fonts_typewriter_scale[1];
760 } else if (token == "\\font_cjk") {
762 } else if (token == "\\paragraph_separation") {
765 paragraph_separation = parseptranslator().find(parsep);
766 } else if (token == "\\paragraph_indentation") {
768 string indentation = lex.getString();
769 pimpl_->indentation = HSpace(indentation);
770 } else if (token == "\\defskip") {
772 string const defskip = lex.getString();
773 pimpl_->defskip = VSpace(defskip);
774 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
776 pimpl_->defskip = VSpace(VSpace::MEDSKIP);
777 } else if (token == "\\quotes_language") {
780 quotes_language = quoteslangtranslator().find(quotes_lang);
781 } else if (token == "\\papersize") {
784 papersize = papersizetranslator().find(ppsize);
785 } else if (token == "\\use_geometry") {
787 } else if (token == "\\use_package") {
792 use_package(package, packagetranslator().find(use));
793 } else if (token == "\\cite_engine") {
795 vector<string> engine = getVectorFromString(lex.getString());
796 setCiteEngine(engine);
797 } else if (token == "\\cite_engine_type") {
800 cite_engine_type_ = citeenginetypetranslator().find(engine_type);
801 } else if (token == "\\biblio_style") {
803 biblio_style = lex.getString();
804 } else if (token == "\\use_bibtopic") {
806 } else if (token == "\\use_indices") {
808 } else if (token == "\\tracking_changes") {
809 lex >> track_changes;
810 } else if (token == "\\output_changes") {
811 lex >> output_changes;
812 } else if (token == "\\branch") {
814 docstring branch = lex.getDocString();
815 branchlist().add(branch);
818 string const tok = lex.getString();
819 if (tok == "\\end_branch")
821 Branch * branch_ptr = branchlist().find(branch);
822 if (tok == "\\selected") {
825 branch_ptr->setSelected(lex.getInteger());
827 if (tok == "\\filename_suffix") {
830 branch_ptr->setFileNameSuffix(lex.getInteger());
832 if (tok == "\\color") {
834 string color = lex.getString();
836 branch_ptr->setColor(color);
837 // Update also the Color table:
839 color = lcolor.getX11Name(Color_background);
841 lcolor.setColor(to_utf8(branch), color);
844 } else if (token == "\\index") {
846 docstring index = lex.getDocString();
848 indiceslist().add(index);
851 string const tok = lex.getString();
852 if (tok == "\\end_index")
854 Index * index_ptr = indiceslist().find(index);
855 if (tok == "\\shortcut") {
857 shortcut = lex.getDocString();
859 index_ptr->setShortcut(shortcut);
861 if (tok == "\\color") {
863 string color = lex.getString();
865 index_ptr->setColor(color);
866 // Update also the Color table:
868 color = lcolor.getX11Name(Color_background);
870 if (!shortcut.empty())
871 lcolor.setColor(to_utf8(shortcut), color);
874 } else if (token == "\\author") {
876 istringstream ss(lex.getString());
879 author_map[a.bufferId()] = pimpl_->authorlist.record(a);
880 } else if (token == "\\paperorientation") {
883 orientation = paperorientationtranslator().find(orient);
884 } else if (token == "\\backgroundcolor") {
886 backgroundcolor = lyx::rgbFromHexName(lex.getString());
887 isbackgroundcolor = true;
888 } else if (token == "\\fontcolor") {
890 fontcolor = lyx::rgbFromHexName(lex.getString());
892 } else if (token == "\\notefontcolor") {
894 string color = lex.getString();
895 notefontcolor = lyx::rgbFromHexName(color);
896 lcolor.setColor("notefontcolor", color);
897 } else if (token == "\\boxbgcolor") {
899 string color = lex.getString();
900 boxbgcolor = lyx::rgbFromHexName(color);
901 lcolor.setColor("boxbgcolor", color);
902 } else if (token == "\\paperwidth") {
904 } else if (token == "\\paperheight") {
906 } else if (token == "\\leftmargin") {
908 } else if (token == "\\topmargin") {
910 } else if (token == "\\rightmargin") {
912 } else if (token == "\\bottommargin") {
914 } else if (token == "\\headheight") {
916 } else if (token == "\\headsep") {
918 } else if (token == "\\footskip") {
920 } else if (token == "\\columnsep") {
922 } else if (token == "\\paperfontsize") {
924 } else if (token == "\\papercolumns") {
926 } else if (token == "\\listings_params") {
929 listings_params = InsetListingsParams(par).params();
930 } else if (token == "\\papersides") {
933 sides = sidestranslator().find(psides);
934 } else if (token == "\\paperpagestyle") {
936 } else if (token == "\\bullet") {
938 } else if (token == "\\bulletLaTeX") {
939 readBulletsLaTeX(lex);
940 } else if (token == "\\secnumdepth") {
942 } else if (token == "\\tocdepth") {
944 } else if (token == "\\spacing") {
948 if (nspacing == "other") {
951 spacing().set(spacetranslator().find(nspacing), tmp_val);
952 } else if (token == "\\float_placement") {
953 lex >> float_placement;
955 } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
956 string toktmp = pdfoptions().readToken(lex, token);
957 if (!toktmp.empty()) {
958 lyxerr << "PDFOptions::readToken(): Unknown token: " <<
962 } else if (token == "\\html_math_output") {
965 html_math_output = static_cast<MathOutput>(temp);
966 } else if (token == "\\html_be_strict") {
967 lex >> html_be_strict;
968 } else if (token == "\\html_css_as_file") {
969 lex >> html_css_as_file;
970 } else if (token == "\\html_math_img_scale") {
971 lex >> html_math_img_scale;
972 } else if (token == "\\html_latex_start") {
974 html_latex_start = lex.getString();
975 } else if (token == "\\html_latex_end") {
977 html_latex_end = lex.getString();
978 } else if (token == "\\output_sync") {
980 } else if (token == "\\output_sync_macro") {
981 lex >> output_sync_macro;
982 } else if (token == "\\use_refstyle") {
985 lyxerr << "BufferParams::readToken(): Unknown token: " <<
995 // Quote argument if it contains spaces
996 string quoteIfNeeded(string const & str) {
997 if (contains(str, ' '))
998 return "\"" + str + "\"";
1004 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1006 // The top of the file is written by the buffer.
1007 // Prints out the buffer info into the .lyx file given by file
1009 // the document directory
1010 string filepath = buf->filePath();
1011 string const sysdir = package().system_support().absFileName();
1012 if (prefixIs(filepath, sysdir))
1013 filepath.replace(0, sysdir.length(), "/systemlyxdir/");
1014 else if (!lyxrc.save_origin)
1015 filepath = "unavailable";
1016 os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1019 os << "\\textclass "
1020 << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1021 baseClass()->name()), "layout"))
1024 // then the preamble
1025 if (!preamble.empty()) {
1026 // remove '\n' from the end of preamble
1027 string const tmppreamble = rtrim(preamble, "\n");
1028 os << "\\begin_preamble\n"
1030 << "\n\\end_preamble\n";
1034 if (!options.empty()) {
1035 os << "\\options " << options << '\n';
1038 // use the class options defined in the layout?
1039 os << "\\use_default_options "
1040 << convert<string>(use_default_options) << "\n";
1042 // the master document
1043 if (!master.empty()) {
1044 os << "\\master " << master << '\n';
1048 if (!removed_modules_.empty()) {
1049 os << "\\begin_removed_modules" << '\n';
1050 list<string>::const_iterator it = removed_modules_.begin();
1051 list<string>::const_iterator en = removed_modules_.end();
1052 for (; it != en; ++it)
1054 os << "\\end_removed_modules" << '\n';
1058 if (!layout_modules_.empty()) {
1059 os << "\\begin_modules" << '\n';
1060 LayoutModuleList::const_iterator it = layout_modules_.begin();
1061 LayoutModuleList::const_iterator en = layout_modules_.end();
1062 for (; it != en; ++it)
1064 os << "\\end_modules" << '\n';
1068 if (!included_children_.empty()) {
1069 os << "\\begin_includeonly" << '\n';
1070 list<string>::const_iterator it = included_children_.begin();
1071 list<string>::const_iterator en = included_children_.end();
1072 for (; it != en; ++it)
1074 os << "\\end_includeonly" << '\n';
1076 os << "\\maintain_unincluded_children "
1077 << convert<string>(maintain_unincluded_children) << '\n';
1079 // local layout information
1080 string const local_layout = getLocalLayout(false);
1081 if (!local_layout.empty()) {
1082 // remove '\n' from the end
1083 string const tmplocal = rtrim(local_layout, "\n");
1084 os << "\\begin_local_layout\n"
1086 << "\n\\end_local_layout\n";
1088 string const forced_local_layout = getLocalLayout(true);
1089 if (!forced_local_layout.empty()) {
1090 // remove '\n' from the end
1091 string const tmplocal = rtrim(forced_local_layout, "\n");
1092 os << "\\begin_forced_local_layout\n"
1094 << "\n\\end_forced_local_layout\n";
1097 // then the text parameters
1098 if (language != ignore_language)
1099 os << "\\language " << language->lang() << '\n';
1100 os << "\\language_package " << lang_package
1101 << "\n\\inputencoding " << inputenc
1102 << "\n\\fontencoding " << fontenc
1103 << "\n\\font_roman \"" << fonts_roman[0]
1104 << "\" \"" << fonts_roman[1] << '"'
1105 << "\n\\font_sans \"" << fonts_sans[0]
1106 << "\" \"" << fonts_sans[1] << '"'
1107 << "\n\\font_typewriter \"" << fonts_typewriter[0]
1108 << "\" \"" << fonts_typewriter[1] << '"'
1109 << "\n\\font_math \"" << fonts_math[0]
1110 << "\" \"" << fonts_math[1] << '"'
1111 << "\n\\font_default_family " << fonts_default_family
1112 << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1113 << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1114 << "\n\\font_osf " << convert<string>(fonts_old_figures)
1115 << "\n\\font_sf_scale " << fonts_sans_scale[0]
1116 << ' ' << fonts_sans_scale[1]
1117 << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1118 << ' ' << fonts_typewriter_scale[1]
1120 if (!fonts_cjk.empty()) {
1121 os << "\\font_cjk " << fonts_cjk << '\n';
1123 os << "\\graphics " << graphics_driver << '\n';
1124 os << "\\default_output_format " << default_output_format << '\n';
1125 os << "\\output_sync " << output_sync << '\n';
1126 if (!output_sync_macro.empty())
1127 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1128 os << "\\bibtex_command " << bibtex_command << '\n';
1129 os << "\\index_command " << index_command << '\n';
1131 if (!float_placement.empty()) {
1132 os << "\\float_placement " << float_placement << '\n';
1134 os << "\\paperfontsize " << fontsize << '\n';
1136 spacing().writeFile(os);
1137 pdfoptions().writeFile(os);
1139 os << "\\papersize " << string_papersize[papersize]
1140 << "\n\\use_geometry " << convert<string>(use_geometry);
1141 map<string, string> const & packages = auto_packages();
1142 for (map<string, string>::const_iterator it = packages.begin();
1143 it != packages.end(); ++it)
1144 os << "\n\\use_package " << it->first << ' '
1145 << use_package(it->first);
1147 os << "\n\\cite_engine ";
1149 if (!cite_engine_.empty()) {
1150 LayoutModuleList::const_iterator be = cite_engine_.begin();
1151 LayoutModuleList::const_iterator en = cite_engine_.end();
1152 for (LayoutModuleList::const_iterator it = be; it != en; ++it) {
1161 os << "\n\\cite_engine_type " << citeenginetypetranslator().find(cite_engine_type_)
1162 << "\n\\biblio_style " << biblio_style
1163 << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1164 << "\n\\use_indices " << convert<string>(use_indices)
1165 << "\n\\paperorientation " << string_orientation[orientation]
1166 << "\n\\suppress_date " << convert<string>(suppress_date)
1167 << "\n\\justification " << convert<string>(justification)
1168 << "\n\\use_refstyle " << use_refstyle
1170 if (isbackgroundcolor == true)
1171 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1172 if (isfontcolor == true)
1173 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1174 if (notefontcolor != lyx::rgbFromHexName("#cccccc"))
1175 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1176 if (boxbgcolor != lyx::rgbFromHexName("#ff0000"))
1177 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1179 BranchList::const_iterator it = branchlist().begin();
1180 BranchList::const_iterator end = branchlist().end();
1181 for (; it != end; ++it) {
1182 os << "\\branch " << to_utf8(it->branch())
1183 << "\n\\selected " << it->isSelected()
1184 << "\n\\filename_suffix " << it->hasFileNameSuffix()
1185 << "\n\\color " << lyx::X11hexname(it->color())
1190 IndicesList::const_iterator iit = indiceslist().begin();
1191 IndicesList::const_iterator iend = indiceslist().end();
1192 for (; iit != iend; ++iit) {
1193 os << "\\index " << to_utf8(iit->index())
1194 << "\n\\shortcut " << to_utf8(iit->shortcut())
1195 << "\n\\color " << lyx::X11hexname(iit->color())
1200 if (!paperwidth.empty())
1201 os << "\\paperwidth "
1202 << VSpace(paperwidth).asLyXCommand() << '\n';
1203 if (!paperheight.empty())
1204 os << "\\paperheight "
1205 << VSpace(paperheight).asLyXCommand() << '\n';
1206 if (!leftmargin.empty())
1207 os << "\\leftmargin "
1208 << VSpace(leftmargin).asLyXCommand() << '\n';
1209 if (!topmargin.empty())
1210 os << "\\topmargin "
1211 << VSpace(topmargin).asLyXCommand() << '\n';
1212 if (!rightmargin.empty())
1213 os << "\\rightmargin "
1214 << VSpace(rightmargin).asLyXCommand() << '\n';
1215 if (!bottommargin.empty())
1216 os << "\\bottommargin "
1217 << VSpace(bottommargin).asLyXCommand() << '\n';
1218 if (!headheight.empty())
1219 os << "\\headheight "
1220 << VSpace(headheight).asLyXCommand() << '\n';
1221 if (!headsep.empty())
1223 << VSpace(headsep).asLyXCommand() << '\n';
1224 if (!footskip.empty())
1226 << VSpace(footskip).asLyXCommand() << '\n';
1227 if (!columnsep.empty())
1228 os << "\\columnsep "
1229 << VSpace(columnsep).asLyXCommand() << '\n';
1230 os << "\\secnumdepth " << secnumdepth
1231 << "\n\\tocdepth " << tocdepth
1232 << "\n\\paragraph_separation "
1233 << string_paragraph_separation[paragraph_separation];
1234 if (!paragraph_separation)
1235 os << "\n\\paragraph_indentation " << getIndentation().asLyXCommand();
1237 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1238 os << "\n\\quotes_language "
1239 << string_quotes_language[quotes_language]
1240 << "\n\\papercolumns " << columns
1241 << "\n\\papersides " << sides
1242 << "\n\\paperpagestyle " << pagestyle << '\n';
1243 if (!listings_params.empty())
1244 os << "\\listings_params \"" <<
1245 InsetListingsParams(listings_params).encodedString() << "\"\n";
1246 for (int i = 0; i < 4; ++i) {
1247 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1248 if (user_defined_bullet(i).getFont() != -1) {
1249 os << "\\bullet " << i << " "
1250 << user_defined_bullet(i).getFont() << " "
1251 << user_defined_bullet(i).getCharacter() << " "
1252 << user_defined_bullet(i).getSize() << "\n";
1256 os << "\\bulletLaTeX " << i << " \""
1257 << lyx::to_ascii(user_defined_bullet(i).getText())
1263 os << "\\tracking_changes " << convert<string>(track_changes) << '\n'
1264 << "\\output_changes " << convert<string>(output_changes) << '\n'
1265 << "\\html_math_output " << html_math_output << '\n'
1266 << "\\html_css_as_file " << html_css_as_file << '\n'
1267 << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1269 if (html_math_img_scale != 1.0)
1270 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1271 if (!html_latex_start.empty())
1272 os << "\\html_latex_start " << html_latex_start << '\n';
1273 if (!html_latex_end.empty())
1274 os << "\\html_latex_end " << html_latex_end << '\n';
1276 os << pimpl_->authorlist;
1280 void BufferParams::validate(LaTeXFeatures & features) const
1282 features.require(documentClass().requires());
1284 if (columns > 1 && language->rightToLeft())
1285 features.require("rtloutputdblcol");
1287 if (output_changes) {
1288 bool dvipost = LaTeXFeatures::isAvailable("dvipost");
1289 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1290 LaTeXFeatures::isAvailable("xcolor");
1292 switch (features.runparams().flavor) {
1293 case OutputParams::LATEX:
1294 case OutputParams::DVILUATEX:
1296 features.require("ct-dvipost");
1297 features.require("dvipost");
1298 } else if (xcolorulem) {
1299 features.require("ct-xcolor-ulem");
1300 features.require("ulem");
1301 features.require("xcolor");
1303 features.require("ct-none");
1306 case OutputParams::LUATEX:
1307 case OutputParams::PDFLATEX:
1308 case OutputParams::XETEX:
1310 features.require("ct-xcolor-ulem");
1311 features.require("ulem");
1312 features.require("xcolor");
1313 // improves color handling in PDF output
1314 features.require("pdfcolmk");
1316 features.require("ct-none");
1324 // Floats with 'Here definitely' as default setting.
1325 if (float_placement.find('H') != string::npos)
1326 features.require("float");
1328 for (PackageMap::const_iterator it = use_packages.begin();
1329 it != use_packages.end(); ++it) {
1330 if (it->first == "amsmath") {
1331 // AMS Style is at document level
1332 if (it->second == package_on ||
1333 features.isProvided("amsmath"))
1334 features.require(it->first);
1335 } else if (it->second == package_on)
1336 features.require(it->first);
1339 // Document-level line spacing
1340 if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1341 features.require("setspace");
1343 // the bullet shapes are buffer level not paragraph level
1344 // so they are tested here
1345 for (int i = 0; i < 4; ++i) {
1346 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1348 int const font = user_defined_bullet(i).getFont();
1350 int const c = user_defined_bullet(i).getCharacter();
1356 features.require("latexsym");
1358 } else if (font == 1) {
1359 features.require("amssymb");
1360 } else if (font >= 2 && font <= 5) {
1361 features.require("pifont");
1365 if (pdfoptions().use_hyperref) {
1366 features.require("hyperref");
1367 // due to interferences with babel and hyperref, the color package has to
1368 // be loaded after hyperref when hyperref is used with the colorlinks
1369 // option, see http://www.lyx.org/trac/ticket/5291
1370 if (pdfoptions().colorlinks)
1371 features.require("color");
1373 if (!listings_params.empty()) {
1374 // do not test validity because listings_params is
1375 // supposed to be valid
1377 InsetListingsParams(listings_params).separatedParams(true);
1378 // we can't support all packages, but we should load the color package
1379 if (par.find("\\color", 0) != string::npos)
1380 features.require("color");
1383 // some languages are only available via polyglossia
1384 if ((features.runparams().flavor == OutputParams::XETEX
1385 || features.runparams().flavor == OutputParams::LUATEX)
1386 && (features.hasPolyglossiaExclusiveLanguages()
1388 features.require("polyglossia");
1390 if (useNonTeXFonts && fontsMath() != "auto")
1391 features.require("unicode-math");
1393 if (!language->requires().empty())
1394 features.require(language->requires());
1398 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1399 FileName const & filepath) const
1401 // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1402 // !! To use the Fix-cm package, load it before \documentclass, and use the command
1403 // \RequirePackage to do so, rather than the normal \usepackage
1404 // Do not try to load any other package before the document class, unless you
1405 // have a thorough understanding of the LATEX internals and know exactly what you
1407 if (features.mustProvide("fix-cm"))
1408 os << "\\RequirePackage{fix-cm}\n";
1409 // Likewise for fixltx2e. If other packages conflict with this policy,
1410 // treat it as a package bug (and report it!)
1411 // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1412 if (features.mustProvide("fixltx2e"))
1413 os << "\\RequirePackage{fixltx2e}\n";
1415 os << "\\documentclass";
1417 DocumentClass const & tclass = documentClass();
1419 ostringstream clsoptions; // the document class options.
1421 if (tokenPos(tclass.opt_fontsize(),
1422 '|', fontsize) >= 0) {
1423 // only write if existing in list (and not default)
1424 clsoptions << fontsize << "pt,";
1427 // all paper sizes except of A4, A5, B5 and the US sizes need the
1429 bool nonstandard_papersize = papersize != PAPER_DEFAULT
1430 && papersize != PAPER_USLETTER
1431 && papersize != PAPER_USLEGAL
1432 && papersize != PAPER_USEXECUTIVE
1433 && papersize != PAPER_A4
1434 && papersize != PAPER_A5
1435 && papersize != PAPER_B5;
1437 if (!use_geometry) {
1438 switch (papersize) {
1440 clsoptions << "a4paper,";
1442 case PAPER_USLETTER:
1443 clsoptions << "letterpaper,";
1446 clsoptions << "a5paper,";
1449 clsoptions << "b5paper,";
1451 case PAPER_USEXECUTIVE:
1452 clsoptions << "executivepaper,";
1455 clsoptions << "legalpaper,";
1489 if (sides != tclass.sides()) {
1492 clsoptions << "oneside,";
1495 clsoptions << "twoside,";
1501 if (columns != tclass.columns()) {
1503 clsoptions << "twocolumn,";
1505 clsoptions << "onecolumn,";
1509 && orientation == ORIENTATION_LANDSCAPE)
1510 clsoptions << "landscape,";
1512 // language should be a parameter to \documentclass
1513 if (language->babel() == "hebrew"
1514 && default_language->babel() != "hebrew")
1515 // This seems necessary
1516 features.useLanguage(default_language);
1518 ostringstream language_options;
1519 bool const use_babel = features.useBabel() && !features.isProvided("babel");
1520 bool const use_polyglossia = features.usePolyglossia();
1521 bool const global = lyxrc.language_global_options;
1522 if (use_babel || (use_polyglossia && global)) {
1523 language_options << features.getBabelLanguages();
1524 if (!language->babel().empty()) {
1525 if (!language_options.str().empty())
1526 language_options << ',';
1527 language_options << language->babel();
1529 if (global && !features.needBabelLangOptions()
1530 && !language_options.str().empty())
1531 clsoptions << language_options.str() << ',';
1534 // the predefined options from the layout
1535 if (use_default_options && !tclass.options().empty())
1536 clsoptions << tclass.options() << ',';
1538 // the user-defined options
1539 if (!options.empty()) {
1540 clsoptions << options << ',';
1543 string strOptions(clsoptions.str());
1544 if (!strOptions.empty()) {
1545 strOptions = rtrim(strOptions, ",");
1547 os << '[' << from_utf8(strOptions) << ']';
1550 os << '{' << from_ascii(tclass.latexname()) << "}\n";
1551 // end of \documentclass defs
1553 // if we use fontspec or newtxmath, we have to load the AMS packages here
1554 string const ams = features.loadAMSPackages();
1555 bool const ot1 = (font_encoding() == "default" || font_encoding() == "OT1");
1556 bool const use_newtxmath =
1557 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1558 ot1, false, false) == "newtxmath";
1559 if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1560 os << from_ascii(ams);
1562 if (useNonTeXFonts) {
1563 os << "\\usepackage{fontspec}\n";
1564 if (features.mustProvide("unicode-math")
1565 && features.isAvailable("unicode-math"))
1566 os << "\\usepackage{unicode-math}\n";
1569 // font selection must be done before loading fontenc.sty
1570 string const fonts = loadFonts(features);
1572 os << from_utf8(fonts);
1574 if (fonts_default_family != "default")
1575 os << "\\renewcommand{\\familydefault}{\\"
1576 << from_ascii(fonts_default_family) << "}\n";
1578 // set font encoding
1579 // XeTeX and LuaTeX (with OS fonts) do not need fontenc
1580 if (!useNonTeXFonts && !features.isProvided("fontenc")
1581 && font_encoding() != "default") {
1582 // get main font encodings
1583 vector<string> fontencs = font_encodings();
1584 // get font encodings of secondary languages
1585 features.getFontEncodings(fontencs);
1586 if (!fontencs.empty()) {
1587 os << "\\usepackage["
1588 << from_ascii(getStringFromVector(fontencs))
1593 // handle inputenc etc.
1594 writeEncodingPreamble(os, features);
1597 if (!features.runparams().includeall && !included_children_.empty()) {
1598 os << "\\includeonly{";
1599 list<string>::const_iterator it = included_children_.begin();
1600 list<string>::const_iterator en = included_children_.end();
1602 for (; it != en; ++it) {
1603 string incfile = *it;
1604 FileName inc = makeAbsPath(incfile, filepath.absFileName());
1605 string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1607 if (!features.runparams().nice)
1609 // \includeonly doesn't want an extension
1610 incfile = changeExtension(incfile, string());
1611 incfile = support::latex_path(incfile);
1612 if (!incfile.empty()) {
1615 os << from_utf8(incfile);
1622 if (!features.isProvided("geometry")
1623 && (use_geometry || nonstandard_papersize)) {
1624 odocstringstream ods;
1625 if (!getGraphicsDriver("geometry").empty())
1626 ods << getGraphicsDriver("geometry");
1627 if (orientation == ORIENTATION_LANDSCAPE)
1628 ods << ",landscape";
1629 switch (papersize) {
1631 if (!paperwidth.empty())
1632 ods << ",paperwidth="
1633 << from_ascii(paperwidth);
1634 if (!paperheight.empty())
1635 ods << ",paperheight="
1636 << from_ascii(paperheight);
1638 case PAPER_USLETTER:
1639 ods << ",letterpaper";
1642 ods << ",legalpaper";
1644 case PAPER_USEXECUTIVE:
1645 ods << ",executivepaper";
1734 docstring const g_options = trim(ods.str(), ",");
1735 os << "\\usepackage";
1736 if (!g_options.empty())
1737 os << '[' << g_options << ']';
1738 os << "{geometry}\n";
1739 // output this only if use_geometry is true
1741 os << "\\geometry{verbose";
1742 if (!topmargin.empty())
1743 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1744 if (!bottommargin.empty())
1745 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1746 if (!leftmargin.empty())
1747 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1748 if (!rightmargin.empty())
1749 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1750 if (!headheight.empty())
1751 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1752 if (!headsep.empty())
1753 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1754 if (!footskip.empty())
1755 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1756 if (!columnsep.empty())
1757 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1760 } else if (orientation == ORIENTATION_LANDSCAPE
1761 || papersize != PAPER_DEFAULT) {
1762 features.require("papersize");
1765 if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
1766 if (pagestyle == "fancy")
1767 os << "\\usepackage{fancyhdr}\n";
1768 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1771 // only output when the background color is not default
1772 if (isbackgroundcolor == true) {
1773 // only require color here, the background color will be defined
1774 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1776 features.require("color");
1777 features.require("pagecolor");
1780 // only output when the font color is not default
1781 if (isfontcolor == true) {
1782 // only require color here, the font color will be defined
1783 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1785 features.require("color");
1786 features.require("fontcolor");
1789 // Only if class has a ToC hierarchy
1790 if (tclass.hasTocLevels()) {
1791 if (secnumdepth != tclass.secnumdepth()) {
1792 os << "\\setcounter{secnumdepth}{"
1796 if (tocdepth != tclass.tocdepth()) {
1797 os << "\\setcounter{tocdepth}{"
1803 if (paragraph_separation) {
1804 // when skip separation
1805 switch (getDefSkip().kind()) {
1806 case VSpace::SMALLSKIP:
1807 os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1809 case VSpace::MEDSKIP:
1810 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1812 case VSpace::BIGSKIP:
1813 os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1815 case VSpace::LENGTH:
1816 os << "\\setlength{\\parskip}{"
1817 << from_utf8(getDefSkip().length().asLatexString())
1820 default: // should never happen // Then delete it.
1821 os << "\\setlength{\\parskip}{\\medskipamount}\n";
1824 os << "\\setlength{\\parindent}{0pt}\n";
1826 // when separation by indentation
1827 // only output something when a width is given
1828 if (getIndentation().asLyXCommand() != "default") {
1829 os << "\\setlength{\\parindent}{"
1830 << from_utf8(getIndentation().asLatexCommand())
1835 // Now insert the LyX specific LaTeX commands...
1836 docstring lyxpreamble;
1837 features.resolveAlternatives();
1840 if (!output_sync_macro.empty())
1841 lyxpreamble += from_utf8(output_sync_macro) +"\n";
1842 else if (features.runparams().flavor == OutputParams::LATEX)
1843 lyxpreamble += "\\usepackage[active]{srcltx}\n";
1844 else if (features.runparams().flavor == OutputParams::PDFLATEX)
1845 lyxpreamble += "\\synctex=-1\n";
1848 // The package options (via \PassOptionsToPackage)
1849 lyxpreamble += from_ascii(features.getPackageOptions());
1851 // due to interferences with babel and hyperref, the color package has to
1852 // be loaded (when it is not already loaded) before babel when hyperref
1853 // is used with the colorlinks option, see
1854 // http://www.lyx.org/trac/ticket/5291
1855 // we decided therefore to load color always before babel, see
1856 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
1857 lyxpreamble += from_ascii(features.getColorOptions());
1859 // If we use hyperref, jurabib, japanese, varioref or vietnamese,
1860 // we have to call babel before
1862 && (features.isRequired("jurabib")
1863 || features.isRequired("hyperref")
1864 || features.isRequired("varioref")
1865 || features.isRequired("vietnamese")
1866 || features.isRequired("japanese"))) {
1868 lyxpreamble += from_utf8(features.getBabelPresettings());
1869 lyxpreamble += from_utf8(babelCall(language_options.str(),
1870 features.needBabelLangOptions())) + '\n';
1871 lyxpreamble += from_utf8(features.getBabelPostsettings());
1874 // The optional packages;
1875 lyxpreamble += from_ascii(features.getPackages());
1877 // Additional Indices
1878 if (features.isRequired("splitidx")) {
1879 IndicesList::const_iterator iit = indiceslist().begin();
1880 IndicesList::const_iterator iend = indiceslist().end();
1881 for (; iit != iend; ++iit) {
1882 pair<docstring, docstring> indexname_latex =
1883 features.runparams().encoding->latexString(iit->index(),
1884 features.runparams().dryrun);
1885 if (!indexname_latex.second.empty()) {
1886 // issue a warning about omitted characters
1887 // FIXME: should be passed to the error dialog
1888 frontend::Alert::warning(_("Uncodable characters"),
1889 bformat(_("The following characters that are used in an index name are not\n"
1890 "representable in the current encoding and therefore have been omitted:\n%1$s."),
1891 indexname_latex.second));
1893 lyxpreamble += "\\newindex[";
1894 lyxpreamble += indexname_latex.first;
1895 lyxpreamble += "]{";
1896 lyxpreamble += escape(iit->shortcut());
1897 lyxpreamble += "}\n";
1902 lyxpreamble += from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
1905 // * Hyperref manual: "Make sure it comes last of your loaded
1906 // packages, to give it a fighting chance of not being over-written,
1907 // since its job is to redefine many LaTeX commands."
1908 // * Email from Heiko Oberdiek: "It is usually better to load babel
1909 // before hyperref. Then hyperref has a chance to detect babel.
1910 // * Has to be loaded before the "LyX specific LaTeX commands" to
1911 // avoid errors with algorithm floats.
1912 // use hyperref explicitly if it is required
1913 if (features.isRequired("hyperref")) {
1914 // pass what we have to stream here, since we need
1915 // to access the stream itself in PDFOptions.
1918 OutputParams tmp_params = features.runparams();
1919 pdfoptions().writeLaTeX(tmp_params, os,
1920 features.isProvided("hyperref"));
1921 // set back for the rest
1922 lyxpreamble.clear();
1923 // correctly break URLs with hyperref and dvi output
1924 if (features.runparams().flavor == OutputParams::LATEX
1925 && features.isAvailable("breakurl"))
1926 lyxpreamble += "\\usepackage{breakurl}\n";
1927 } else if (features.isRequired("nameref"))
1928 // hyperref loads this automatically
1929 lyxpreamble += "\\usepackage{nameref}\n";
1931 // bibtopic needs to be loaded after hyperref.
1932 // the dot provides the aux file naming which LyX can detect.
1933 if (features.mustProvide("bibtopic"))
1934 lyxpreamble += "\\usepackage[dot]{bibtopic}\n";
1936 // Will be surrounded by \makeatletter and \makeatother when not empty
1937 docstring atlyxpreamble;
1939 // Some macros LyX will need
1940 docstring tmppreamble(features.getMacros());
1942 if (!tmppreamble.empty())
1943 atlyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1944 "LyX specific LaTeX commands.\n"
1945 + tmppreamble + '\n';
1947 // the text class specific preamble
1948 tmppreamble = features.getTClassPreamble();
1949 if (!tmppreamble.empty())
1950 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1951 "Textclass specific LaTeX commands.\n"
1952 + tmppreamble + '\n';
1954 // suppress date if selected
1955 // use \@ifundefined because we cannot be sure that every document class
1956 // has a \date command
1958 atlyxpreamble += "\\@ifundefined{date}{}{\\date{}}\n";
1960 /* the user-defined preamble */
1961 if (!containsOnly(preamble, " \n\t")) {
1963 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1964 "User specified LaTeX commands.\n";
1966 // Check if the user preamble contains uncodable glyphs
1967 docstring const u_preamble = from_utf8(preamble);
1968 odocstringstream user_preamble;
1969 docstring uncodable_glyphs;
1970 Encoding const * const enc = features.runparams().encoding;
1972 for (size_t n = 0; n < u_preamble.size(); ++n) {
1973 char_type c = u_preamble[n];
1974 if (!enc->encodable(c)) {
1975 docstring const glyph(1, c);
1976 LYXERR0("Uncodable character '"
1978 << "' in user preamble!");
1979 uncodable_glyphs += glyph;
1980 if (features.runparams().dryrun) {
1981 user_preamble << "<" << _("LyX Warning: ")
1982 << _("uncodable character") << " '";
1983 user_preamble.put(c);
1984 user_preamble << "'>";
1987 user_preamble.put(c);
1990 user_preamble << u_preamble;
1992 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1993 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1994 frontend::Alert::warning(
1995 _("Uncodable character in user preamble"),
1997 _("The user preamble of your document contains glyphs "
1998 "that are unknown in the current document encoding "
1999 "(namely %1$s).\nThese glyphs are omitted "
2000 " from the output, which may result in "
2001 "incomplete output."
2002 "\n\nPlease select an appropriate "
2003 "document encoding\n"
2004 "(such as utf8) or change the "
2005 "preamble code accordingly."),
2008 atlyxpreamble += user_preamble.str() + '\n';
2011 // footmisc must be loaded after setspace
2012 // Load it here to avoid clashes with footmisc loaded in the user
2013 // preamble. For that reason we also pass the options via
2014 // \PassOptionsToPackage in getPreamble() and not here.
2015 if (features.mustProvide("footmisc"))
2016 atlyxpreamble += "\\usepackage{footmisc}\n";
2018 // subfig loads internally the LaTeX package "caption". As
2019 // caption is a very popular package, users will load it in
2020 // the preamble. Therefore we must load subfig behind the
2021 // user-defined preamble and check if the caption package was
2022 // loaded or not. For the case that caption is loaded before
2023 // subfig, there is the subfig option "caption=false". This
2024 // option also works when a koma-script class is used and
2025 // koma's own caption commands are used instead of caption. We
2026 // use \PassOptionsToPackage here because the user could have
2027 // already loaded subfig in the preamble.
2028 if (features.isRequired("subfig")) {
2029 atlyxpreamble += "\\@ifundefined{showcaptionsetup}{}{%\n"
2030 " \\PassOptionsToPackage{caption=false}{subfig}}\n"
2031 "\\usepackage{subfig}\n";
2034 // Itemize bullet settings need to be last in case the user
2035 // defines their own bullets that use a package included
2036 // in the user-defined preamble -- ARRae
2037 // Actually it has to be done much later than that
2038 // since some packages like frenchb make modifications
2039 // at \begin{document} time -- JMarc
2040 docstring bullets_def;
2041 for (int i = 0; i < 4; ++i) {
2042 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2043 if (bullets_def.empty())
2044 bullets_def += "\\AtBeginDocument{\n";
2045 bullets_def += " \\def\\labelitemi";
2047 // `i' is one less than the item to modify
2054 bullets_def += "ii";
2060 bullets_def += '{' +
2061 user_defined_bullet(i).getText()
2066 if (!bullets_def.empty())
2067 atlyxpreamble += bullets_def + "}\n\n";
2069 if (!atlyxpreamble.empty())
2070 lyxpreamble += "\n\\makeatletter\n"
2071 + atlyxpreamble + "\\makeatother\n\n";
2073 // We try to load babel late, in case it interferes with other packages.
2074 // Jurabib, hyperref, varioref, bicaption and listings (bug 8995) have to be
2075 // called after babel, though.
2076 if (use_babel && !features.isRequired("jurabib")
2077 && !features.isRequired("hyperref")
2078 && !features.isRequired("varioref")
2079 && !features.isRequired("vietnamese")
2080 && !features.isRequired("japanese")) {
2082 lyxpreamble += from_utf8(features.getBabelPresettings());
2083 lyxpreamble += from_utf8(babelCall(language_options.str(),
2084 features.needBabelLangOptions())) + '\n';
2085 lyxpreamble += from_utf8(features.getBabelPostsettings());
2087 if (features.isRequired("bicaption"))
2088 lyxpreamble += "\\usepackage{bicaption}\n";
2089 if (!listings_params.empty() || features.isRequired("listings"))
2090 lyxpreamble += "\\usepackage{listings}\n";
2091 if (!listings_params.empty()) {
2092 lyxpreamble += "\\lstset{";
2093 // do not test validity because listings_params is
2094 // supposed to be valid
2096 InsetListingsParams(listings_params).separatedParams(true);
2097 lyxpreamble += from_utf8(par);
2098 lyxpreamble += "}\n";
2101 // xunicode needs to be loaded at least after amsmath, amssymb,
2102 // esint and the other packages that provide special glyphs
2103 if (features.runparams().flavor == OutputParams::XETEX
2105 lyxpreamble += "\\usepackage{xunicode}\n";
2107 // Polyglossia must be loaded last
2108 if (use_polyglossia) {
2110 lyxpreamble += "\\usepackage{polyglossia}\n";
2111 // set the main language
2112 lyxpreamble += "\\setdefaultlanguage";
2113 if (!language->polyglossiaOpts().empty())
2114 lyxpreamble += "[" + from_ascii(language->polyglossiaOpts()) + "]";
2115 lyxpreamble += "{" + from_ascii(language->polyglossia()) + "}\n";
2116 // now setup the other languages
2117 std::map<std::string, std::string> const polylangs =
2118 features.getPolyglossiaLanguages();
2119 for (std::map<std::string, std::string>::const_iterator mit = polylangs.begin();
2120 mit != polylangs.end() ; ++mit) {
2121 lyxpreamble += "\\setotherlanguage";
2122 if (!mit->second.empty())
2123 lyxpreamble += "[" + from_ascii(mit->second) + "]";
2124 lyxpreamble += "{" + from_ascii(mit->first) + "}\n";
2128 // Load custom language package here
2129 if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2130 if (lang_package == "default")
2131 lyxpreamble += from_utf8(lyxrc.language_custom_package);
2133 lyxpreamble += from_utf8(lang_package);
2134 lyxpreamble += '\n';
2137 docstring const i18npreamble =
2138 features.getTClassI18nPreamble(use_babel, use_polyglossia);
2139 if (!i18npreamble.empty())
2140 lyxpreamble += i18npreamble + '\n';
2148 void BufferParams::useClassDefaults()
2150 DocumentClass const & tclass = documentClass();
2152 sides = tclass.sides();
2153 columns = tclass.columns();
2154 pagestyle = tclass.pagestyle();
2155 use_default_options = true;
2156 // Only if class has a ToC hierarchy
2157 if (tclass.hasTocLevels()) {
2158 secnumdepth = tclass.secnumdepth();
2159 tocdepth = tclass.tocdepth();
2164 bool BufferParams::hasClassDefaults() const
2166 DocumentClass const & tclass = documentClass();
2168 return sides == tclass.sides()
2169 && columns == tclass.columns()
2170 && pagestyle == tclass.pagestyle()
2171 && use_default_options
2172 && secnumdepth == tclass.secnumdepth()
2173 && tocdepth == tclass.tocdepth();
2177 DocumentClass const & BufferParams::documentClass() const
2179 return *doc_class_.get();
2183 DocumentClassConstPtr BufferParams::documentClassPtr() const
2189 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2191 // evil, but this function is evil
2192 doc_class_ = const_pointer_cast<DocumentClass>(tc);
2196 bool BufferParams::setBaseClass(string const & classname)
2198 LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2199 LayoutFileList & bcl = LayoutFileList::get();
2200 if (!bcl.haveClass(classname)) {
2202 bformat(_("The layout file:\n"
2204 "could not be found. A default textclass with default\n"
2205 "layouts will be used. LyX will not be able to produce\n"
2207 from_utf8(classname));
2208 frontend::Alert::error(_("Document class not found"), s);
2209 bcl.addEmptyClass(classname);
2212 bool const success = bcl[classname].load();
2215 bformat(_("Due to some error in it, the layout file:\n"
2217 "could not be loaded. A default textclass with default\n"
2218 "layouts will be used. LyX will not be able to produce\n"
2220 from_utf8(classname));
2221 frontend::Alert::error(_("Could not load class"), s);
2222 bcl.addEmptyClass(classname);
2225 pimpl_->baseClass_ = classname;
2226 layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2231 LayoutFile const * BufferParams::baseClass() const
2233 if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2234 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2240 LayoutFileIndex const & BufferParams::baseClassID() const
2242 return pimpl_->baseClass_;
2246 void BufferParams::makeDocumentClass(bool const clone)
2251 LayoutModuleList mods;
2252 LayoutModuleList::iterator it = layout_modules_.begin();
2253 LayoutModuleList::iterator en = layout_modules_.end();
2254 for (; it != en; ++it)
2255 mods.push_back(*it);
2257 it = cite_engine_.begin();
2258 en = cite_engine_.end();
2259 for (; it != en; ++it)
2260 mods.push_back(*it);
2262 doc_class_ = getDocumentClass(*baseClass(), mods, clone);
2264 TextClass::ReturnValues success = TextClass::OK;
2265 if (!forced_local_layout_.empty())
2266 success = doc_class_->read(forced_local_layout_, TextClass::MODULE);
2267 if (!local_layout_.empty() &&
2268 (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2269 success = doc_class_->read(local_layout_, TextClass::MODULE);
2270 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2271 docstring const msg = _("Error reading internal layout information");
2272 frontend::Alert::warning(_("Read Error"), msg);
2277 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2279 return layout_modules_.moduleCanBeAdded(modName, baseClass());
2283 bool BufferParams::citationModuleCanBeAdded(string const & modName) const
2285 return cite_engine_.moduleCanBeAdded(modName, baseClass());
2289 std::string BufferParams::getLocalLayout(bool forced) const
2292 return doc_class_->forcedLayouts();
2294 return local_layout_;
2298 void BufferParams::setLocalLayout(string const & layout, bool forced)
2301 forced_local_layout_ = layout;
2303 local_layout_ = layout;
2307 bool BufferParams::addLayoutModule(string const & modName)
2309 LayoutModuleList::const_iterator it = layout_modules_.begin();
2310 LayoutModuleList::const_iterator end = layout_modules_.end();
2311 for (; it != end; ++it)
2314 layout_modules_.push_back(modName);
2319 string BufferParams::bufferFormat() const
2321 string format = documentClass().outputFormat();
2322 if (format == "latex") {
2324 return "xetex"; // actually "xetex or luatex"
2325 if (encoding().package() == Encoding::japanese)
2332 bool BufferParams::isExportable(string const & format) const
2334 vector<string> backs = backends();
2335 for (vector<string>::const_iterator it = backs.begin();
2336 it != backs.end(); ++it)
2337 if (theConverters().isReachable(*it, format))
2343 vector<Format const *> BufferParams::exportableFormats(bool only_viewable) const
2345 vector<string> const backs = backends();
2346 set<string> excludes;
2347 if (useNonTeXFonts) {
2348 excludes.insert("latex");
2349 excludes.insert("pdflatex");
2351 vector<Format const *> result =
2352 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2353 for (vector<string>::const_iterator it = backs.begin() + 1;
2354 it != backs.end(); ++it) {
2355 vector<Format const *> r =
2356 theConverters().getReachable(*it, only_viewable, false, excludes);
2357 result.insert(result.end(), r.begin(), r.end());
2363 bool BufferParams::isExportableFormat(string const & format) const
2365 typedef vector<Format const *> Formats;
2367 formats = exportableFormats(true);
2368 Formats::const_iterator fit = formats.begin();
2369 Formats::const_iterator end = formats.end();
2370 for (; fit != end ; ++fit) {
2371 if ((*fit)->name() == format)
2378 vector<string> BufferParams::backends() const
2381 string const buffmt = bufferFormat();
2383 // FIXME: Don't hardcode format names here, but use a flag
2384 if (buffmt == "latex") {
2385 if (!useNonTeXFonts) {
2386 v.push_back("pdflatex");
2387 v.push_back("latex");
2389 v.push_back("luatex");
2390 v.push_back("dviluatex");
2391 v.push_back("xetex");
2392 } else if (buffmt == "xetex") {
2393 v.push_back("xetex");
2394 // FIXME: need to test all languages (bug 8205)
2395 if (!language || !language->isPolyglossiaExclusive()) {
2396 v.push_back("luatex");
2397 v.push_back("dviluatex");
2400 v.push_back(buffmt);
2402 v.push_back("xhtml");
2403 v.push_back("text");
2409 OutputParams::FLAVOR BufferParams::getOutputFlavor(string const & format) const
2411 string const dformat = (format.empty() || format == "default") ?
2412 getDefaultOutputFormat() : format;
2413 DefaultFlavorCache::const_iterator it =
2414 default_flavors_.find(dformat);
2416 if (it != default_flavors_.end())
2419 OutputParams::FLAVOR result = OutputParams::LATEX;
2421 // FIXME It'd be better not to hardcode this, but to do
2422 // something with formats.
2423 if (dformat == "xhtml")
2424 result = OutputParams::HTML;
2425 else if (dformat == "text")
2426 result = OutputParams::TEXT;
2427 else if (dformat == "lyx")
2428 result = OutputParams::LYX;
2429 else if (dformat == "pdflatex")
2430 result = OutputParams::PDFLATEX;
2431 else if (dformat == "xetex")
2432 result = OutputParams::XETEX;
2433 else if (dformat == "luatex")
2434 result = OutputParams::LUATEX;
2435 else if (dformat == "dviluatex")
2436 result = OutputParams::DVILUATEX;
2438 // Try to determine flavor of default output format
2439 vector<string> backs = backends();
2440 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2441 // Get shortest path to format
2442 Graph::EdgePath path;
2443 for (vector<string>::const_iterator it = backs.begin();
2444 it != backs.end(); ++it) {
2445 Graph::EdgePath p = theConverters().getPath(*it, dformat);
2446 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2451 result = theConverters().getFlavor(path);
2454 // cache this flavor
2455 default_flavors_[dformat] = result;
2460 string BufferParams::getDefaultOutputFormat() const
2462 if (!default_output_format.empty()
2463 && default_output_format != "default")
2464 return default_output_format;
2466 || encoding().package() == Encoding::japanese) {
2467 vector<Format const *> const formats = exportableFormats(true);
2468 if (formats.empty())
2470 // return the first we find
2471 return formats.front()->name();
2474 return lyxrc.default_otf_view_format;
2475 return lyxrc.default_view_format;
2478 Font const BufferParams::getFont() const
2480 FontInfo f = documentClass().defaultfont();
2481 if (fonts_default_family == "rmdefault")
2482 f.setFamily(ROMAN_FAMILY);
2483 else if (fonts_default_family == "sfdefault")
2484 f.setFamily(SANS_FAMILY);
2485 else if (fonts_default_family == "ttdefault")
2486 f.setFamily(TYPEWRITER_FAMILY);
2487 return Font(f, language);
2491 InsetQuotes::QuoteLanguage BufferParams::getQuoteStyle(string const & qs) const
2493 return quoteslangtranslator().find(qs);
2497 bool BufferParams::isLatex() const
2499 return documentClass().outputType() == LATEX;
2503 bool BufferParams::isLiterate() const
2505 return documentClass().outputType() == LITERATE;
2509 bool BufferParams::isDocBook() const
2511 return documentClass().outputType() == DOCBOOK;
2515 void BufferParams::readPreamble(Lexer & lex)
2517 if (lex.getString() != "\\begin_preamble")
2518 lyxerr << "Error (BufferParams::readPreamble):"
2519 "consistency check failed." << endl;
2521 preamble = lex.getLongString("\\end_preamble");
2525 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2527 string const expected = forced ? "\\begin_forced_local_layout" :
2528 "\\begin_local_layout";
2529 if (lex.getString() != expected)
2530 lyxerr << "Error (BufferParams::readLocalLayout):"
2531 "consistency check failed." << endl;
2534 forced_local_layout_ =
2535 lex.getLongString("\\end_forced_local_layout");
2537 local_layout_ = lex.getLongString("\\end_local_layout");
2541 bool BufferParams::setLanguage(string const & lang)
2543 Language const *new_language = languages.getLanguage(lang);
2544 if (!new_language) {
2545 // Language lang was not found
2548 language = new_language;
2553 void BufferParams::readLanguage(Lexer & lex)
2555 if (!lex.next()) return;
2557 string const tmptok = lex.getString();
2559 // check if tmptok is part of tex_babel in tex-defs.h
2560 if (!setLanguage(tmptok)) {
2561 // Language tmptok was not found
2562 language = default_language;
2563 lyxerr << "Warning: Setting language `"
2564 << tmptok << "' to `" << language->lang()
2570 void BufferParams::readGraphicsDriver(Lexer & lex)
2575 string const tmptok = lex.getString();
2576 // check if tmptok is part of tex_graphics in tex_defs.h
2579 string const test = tex_graphics[n++];
2581 if (test == tmptok) {
2582 graphics_driver = tmptok;
2587 "Warning: graphics driver `$$Token' not recognized!\n"
2588 " Setting graphics driver to `default'.\n");
2589 graphics_driver = "default";
2596 void BufferParams::readBullets(Lexer & lex)
2601 int const index = lex.getInteger();
2603 int temp_int = lex.getInteger();
2604 user_defined_bullet(index).setFont(temp_int);
2605 temp_bullet(index).setFont(temp_int);
2607 user_defined_bullet(index).setCharacter(temp_int);
2608 temp_bullet(index).setCharacter(temp_int);
2610 user_defined_bullet(index).setSize(temp_int);
2611 temp_bullet(index).setSize(temp_int);
2615 void BufferParams::readBulletsLaTeX(Lexer & lex)
2617 // The bullet class should be able to read this.
2620 int const index = lex.getInteger();
2622 docstring const temp_str = lex.getDocString();
2624 user_defined_bullet(index).setText(temp_str);
2625 temp_bullet(index).setText(temp_str);
2629 void BufferParams::readModules(Lexer & lex)
2631 if (!lex.eatLine()) {
2632 lyxerr << "Error (BufferParams::readModules):"
2633 "Unexpected end of input." << endl;
2637 string mod = lex.getString();
2638 if (mod == "\\end_modules")
2640 addLayoutModule(mod);
2646 void BufferParams::readRemovedModules(Lexer & lex)
2648 if (!lex.eatLine()) {
2649 lyxerr << "Error (BufferParams::readRemovedModules):"
2650 "Unexpected end of input." << endl;
2654 string mod = lex.getString();
2655 if (mod == "\\end_removed_modules")
2657 removed_modules_.push_back(mod);
2660 // now we want to remove any removed modules that were previously
2661 // added. normally, that will be because default modules were added in
2662 // setBaseClass(), which gets called when \textclass is read at the
2663 // start of the read.
2664 list<string>::const_iterator rit = removed_modules_.begin();
2665 list<string>::const_iterator const ren = removed_modules_.end();
2666 for (; rit != ren; ++rit) {
2667 LayoutModuleList::iterator const mit = layout_modules_.begin();
2668 LayoutModuleList::iterator const men = layout_modules_.end();
2669 LayoutModuleList::iterator found = find(mit, men, *rit);
2672 layout_modules_.erase(found);
2677 void BufferParams::readIncludeonly(Lexer & lex)
2679 if (!lex.eatLine()) {
2680 lyxerr << "Error (BufferParams::readIncludeonly):"
2681 "Unexpected end of input." << endl;
2685 string child = lex.getString();
2686 if (child == "\\end_includeonly")
2688 included_children_.push_back(child);
2694 string BufferParams::paperSizeName(PapersizePurpose purpose) const
2696 switch (papersize) {
2698 // could be anything, so don't guess
2700 case PAPER_CUSTOM: {
2701 if (purpose == XDVI && !paperwidth.empty() &&
2702 !paperheight.empty()) {
2703 // heightxwidth<unit>
2704 string first = paperwidth;
2705 string second = paperheight;
2706 if (orientation == ORIENTATION_LANDSCAPE)
2709 return first.erase(first.length() - 2)
2715 // dvips and dvipdfm do not know this
2716 if (purpose == DVIPS || purpose == DVIPDFM)
2720 if (purpose == DVIPS || purpose == DVIPDFM)
2724 if (purpose == DVIPS || purpose == DVIPDFM)
2734 if (purpose == DVIPS || purpose == DVIPDFM)
2738 if (purpose == DVIPS || purpose == DVIPDFM)
2742 if (purpose == DVIPS || purpose == DVIPDFM)
2746 if (purpose == DVIPS || purpose == DVIPDFM)
2750 if (purpose == DVIPS || purpose == DVIPDFM)
2754 // dvipdfm does not know this
2755 if (purpose == DVIPDFM)
2759 if (purpose == DVIPDFM)
2763 if (purpose == DVIPS || purpose == DVIPDFM)
2767 if (purpose == DVIPS || purpose == DVIPDFM)
2771 if (purpose == DVIPS || purpose == DVIPDFM)
2775 if (purpose == DVIPS || purpose == DVIPDFM)
2779 if (purpose == DVIPS || purpose == DVIPDFM)
2783 if (purpose == DVIPS || purpose == DVIPDFM)
2787 if (purpose == DVIPS || purpose == DVIPDFM)
2791 if (purpose == DVIPS || purpose == DVIPDFM)
2795 if (purpose == DVIPS || purpose == DVIPDFM)
2799 if (purpose == DVIPS || purpose == DVIPDFM)
2803 if (purpose == DVIPS || purpose == DVIPDFM)
2807 if (purpose == DVIPS || purpose == DVIPDFM)
2811 if (purpose == DVIPS || purpose == DVIPDFM)
2815 if (purpose == DVIPS || purpose == DVIPDFM)
2819 if (purpose == DVIPS || purpose == DVIPDFM)
2822 case PAPER_USEXECUTIVE:
2823 // dvipdfm does not know this
2824 if (purpose == DVIPDFM)
2829 case PAPER_USLETTER:
2831 if (purpose == XDVI)
2838 string const BufferParams::dvips_options() const
2842 // If the class loads the geometry package, we do not know which
2843 // paper size is used, since we do not set it (bug 7013).
2844 // Therefore we must not specify any argument here.
2845 // dvips gets the correct paper size via DVI specials in this case
2846 // (if the class uses the geometry package correctly).
2847 if (documentClass().provides("geometry"))
2851 && papersize == PAPER_CUSTOM
2852 && !lyxrc.print_paper_dimension_flag.empty()
2853 && !paperwidth.empty()
2854 && !paperheight.empty()) {
2855 // using a custom papersize
2856 result = lyxrc.print_paper_dimension_flag;
2857 result += ' ' + paperwidth;
2858 result += ',' + paperheight;
2860 string const paper_option = paperSizeName(DVIPS);
2861 if (!paper_option.empty() && (paper_option != "letter" ||
2862 orientation != ORIENTATION_LANDSCAPE)) {
2863 // dvips won't accept -t letter -t landscape.
2864 // In all other cases, include the paper size
2866 result = lyxrc.print_paper_flag;
2867 result += ' ' + paper_option;
2870 if (orientation == ORIENTATION_LANDSCAPE &&
2871 papersize != PAPER_CUSTOM)
2872 result += ' ' + lyxrc.print_landscape_flag;
2877 string const BufferParams::font_encoding() const
2879 return font_encodings().empty() ? "default" : font_encodings().back();
2883 vector<string> const BufferParams::font_encodings() const
2885 string doc_fontenc = (fontenc == "global") ? lyxrc.fontenc : fontenc;
2887 vector<string> fontencs;
2889 // "default" means "no explicit font encoding"
2890 if (doc_fontenc != "default") {
2891 fontencs = getVectorFromString(doc_fontenc);
2892 if (!language->fontenc().empty()
2893 && ascii_lowercase(language->fontenc()) != "none") {
2894 vector<string> fencs = getVectorFromString(language->fontenc());
2895 vector<string>::const_iterator fit = fencs.begin();
2896 for (; fit != fencs.end(); ++fit) {
2897 if (find(fontencs.begin(), fontencs.end(), *fit) == fontencs.end())
2898 fontencs.push_back(*fit);
2907 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
2909 // suppress the babel call if there is no BabelName defined
2910 // for the document language in the lib/languages file and if no
2911 // other languages are used (lang_opts is then empty)
2912 if (lang_opts.empty())
2914 // either a specific language (AsBabelOptions setting in
2915 // lib/languages) or the prefs require the languages to
2916 // be submitted to babel itself (not the class).
2918 return "\\usepackage[" + lang_opts + "]{babel}";
2919 return "\\usepackage{babel}";
2923 docstring BufferParams::getGraphicsDriver(string const & package) const
2927 if (package == "geometry") {
2928 if (graphics_driver == "dvips"
2929 || graphics_driver == "dvipdfm"
2930 || graphics_driver == "pdftex"
2931 || graphics_driver == "vtex")
2932 result = from_ascii(graphics_driver);
2933 else if (graphics_driver == "dvipdfmx")
2934 result = from_ascii("dvipdfm");
2941 void BufferParams::writeEncodingPreamble(otexstream & os,
2942 LaTeXFeatures & features) const
2944 // XeTeX/LuaTeX: (see also #9740)
2945 // With Unicode fonts we use utf8-plain without encoding package.
2946 // With TeX fonts, we cannot use utf8-plain, but "inputenc" fails.
2947 // XeTeX must use ASCII encoding, for LuaTeX, we load
2948 // "luainputenc" (see below).
2949 if (useNonTeXFonts || features.runparams().flavor == OutputParams::XETEX)
2952 if (inputenc == "auto") {
2953 string const doc_encoding =
2954 language->encoding()->latexName();
2955 Encoding::Package const package =
2956 language->encoding()->package();
2958 // Create list of inputenc options:
2959 set<string> encodings;
2960 // luainputenc fails with more than one encoding
2961 if (!features.runparams().isFullUnicode()) // if we reach this point, this means LuaTeX with TeX fonts
2962 // list all input encodings used in the document
2963 encodings = features.getEncodingSet(doc_encoding);
2965 // If the "japanese" package (i.e. pLaTeX) is used,
2966 // inputenc must be omitted.
2967 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
2968 if ((!encodings.empty() || package == Encoding::inputenc)
2969 && !features.isRequired("japanese")
2970 && !features.isProvided("inputenc")) {
2971 os << "\\usepackage[";
2972 set<string>::const_iterator it = encodings.begin();
2973 set<string>::const_iterator const end = encodings.end();
2975 os << from_ascii(*it);
2978 for (; it != end; ++it)
2979 os << ',' << from_ascii(*it);
2980 if (package == Encoding::inputenc) {
2981 if (!encodings.empty())
2983 os << from_ascii(doc_encoding);
2985 if (features.runparams().flavor == OutputParams::LUATEX
2986 || features.runparams().flavor == OutputParams::DVILUATEX)
2987 os << "]{luainputenc}\n";
2989 os << "]{inputenc}\n";
2991 if (package == Encoding::CJK || features.mustProvide("CJK")) {
2992 if (language->encoding()->name() == "utf8-cjk"
2993 && LaTeXFeatures::isAvailable("CJKutf8"))
2994 os << "\\usepackage{CJKutf8}\n";
2996 os << "\\usepackage{CJK}\n";
2998 } else if (inputenc != "default") {
2999 switch (encoding().package()) {
3000 case Encoding::none:
3001 case Encoding::japanese:
3003 case Encoding::inputenc:
3004 // do not load inputenc if japanese is used
3005 // or if the class provides inputenc
3006 if (features.isRequired("japanese")
3007 || features.isProvided("inputenc"))
3009 os << "\\usepackage[" << from_ascii(encoding().latexName());
3010 if (features.runparams().flavor == OutputParams::LUATEX
3011 || features.runparams().flavor == OutputParams::DVILUATEX)
3012 os << "]{luainputenc}\n";
3014 os << "]{inputenc}\n";
3017 if (encoding().name() == "utf8-cjk"
3018 && LaTeXFeatures::isAvailable("CJKutf8"))
3019 os << "\\usepackage{CJKutf8}\n";
3021 os << "\\usepackage{CJK}\n";
3024 // Load the CJK package if needed by a secondary language.
3025 // If the main encoding is some variant of UTF8, use CJKutf8.
3026 if (encoding().package() != Encoding::CJK && features.mustProvide("CJK")) {
3027 if (encoding().iconvName() == "UTF-8"
3028 && LaTeXFeatures::isAvailable("CJKutf8"))
3029 os << "\\usepackage{CJKutf8}\n";
3031 os << "\\usepackage{CJK}\n";
3037 string const BufferParams::parseFontName(string const & name) const
3039 string mangled = name;
3040 size_t const idx = mangled.find('[');
3041 if (idx == string::npos || idx == 0)
3044 return mangled.substr(0, idx - 1);
3048 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3050 if (fontsRoman() == "default" && fontsSans() == "default"
3051 && fontsTypewriter() == "default"
3052 && (fontsMath() == "default" || fontsMath() == "auto"))
3058 /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3059 * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3060 * Mapping=tex-text option assures TeX ligatures (such as "--")
3061 * are resolved. Note that tt does not use these ligatures.
3063 * -- add more GUI options?
3064 * -- add more fonts (fonts for other scripts)
3065 * -- if there's a way to find out if a font really supports
3066 * OldStyle, enable/disable the widget accordingly.
3068 if (useNonTeXFonts && features.isAvailable("fontspec")) {
3069 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3070 // However, until v.2 (2010/07/11) fontspec only knew
3071 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3072 // was introduced for both XeTeX and LuaTeX (LuaTeX
3073 // didn't understand "Mapping=tex-text", while XeTeX
3074 // understood both. With most recent versions, both
3075 // variants are understood by both engines. However,
3076 // we want to provide support for at least TeXLive 2009
3077 // (for XeTeX; LuaTeX is only supported as of v.2)
3078 string const texmapping =
3079 (features.runparams().flavor == OutputParams::XETEX) ?
3080 "Mapping=tex-text" : "Ligatures=TeX";
3081 if (fontsRoman() != "default") {
3082 os << "\\setmainfont[" << texmapping;
3083 if (fonts_old_figures)
3084 os << ",Numbers=OldStyle";
3085 os << "]{" << parseFontName(fontsRoman()) << "}\n";
3087 if (fontsSans() != "default") {
3088 string const sans = parseFontName(fontsSans());
3089 if (fontsSansScale() != 100)
3090 os << "\\setsansfont[Scale="
3091 << float(fontsSansScale()) / 100
3092 << "," << texmapping << "]{"
3095 os << "\\setsansfont[" << texmapping << "]{"
3098 if (fontsTypewriter() != "default") {
3099 string const mono = parseFontName(fontsTypewriter());
3100 if (fontsTypewriterScale() != 100)
3101 os << "\\setmonofont[Scale="
3102 << float(fontsTypewriterScale()) / 100
3106 os << "\\setmonofont{"
3113 bool const ot1 = (font_encoding() == "default" || font_encoding() == "OT1");
3114 bool const dryrun = features.runparams().dryrun;
3115 bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3116 bool const nomath = (fontsMath() == "default");
3119 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3120 dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures,
3124 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3125 dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures,
3126 nomath, fontsSansScale());
3128 // MONOSPACED/TYPEWRITER
3129 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3130 dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures,
3131 nomath, fontsTypewriterScale());
3134 os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3135 dryrun, ot1, complete, fonts_expert_sc, fonts_old_figures,
3142 Encoding const & BufferParams::encoding() const
3144 // Main encoding for LaTeX output.
3146 // Exception: XeTeX with 8-bit TeX fonts requires ASCII (see #9740).
3147 // As the "flavor" is only known once export started, this
3148 // cannot be handled here. Instead, runparams.encoding is set
3149 // to ASCII in Buffer::makeLaTeXFile (for export)
3150 // and Buffer::writeLaTeXSource (for preview).
3152 return *(encodings.fromLyXName("utf8-plain"));
3153 if (inputenc == "auto" || inputenc == "default")
3154 return *language->encoding();
3155 Encoding const * const enc = encodings.fromLyXName(inputenc);
3158 LYXERR0("Unknown inputenc value `" << inputenc
3159 << "'. Using `auto' instead.");
3160 return *language->encoding();
3164 bool BufferParams::addCiteEngine(string const & engine)
3166 LayoutModuleList::const_iterator it = cite_engine_.begin();
3167 LayoutModuleList::const_iterator en = cite_engine_.end();
3168 for (; it != en; ++it)
3171 cite_engine_.push_back(engine);
3176 bool BufferParams::addCiteEngine(vector<string> const & engine)
3178 vector<string>::const_iterator it = engine.begin();
3179 vector<string>::const_iterator en = engine.end();
3181 for (; it != en; ++it)
3182 if (!addCiteEngine(*it))
3188 string const & BufferParams::defaultBiblioStyle() const
3190 return documentClass().defaultBiblioStyle();
3194 bool const & BufferParams::fullAuthorList() const
3196 return documentClass().fullAuthorList();
3200 void BufferParams::setCiteEngine(string const & engine)
3203 addCiteEngine(engine);
3207 void BufferParams::setCiteEngine(vector<string> const & engine)
3210 addCiteEngine(engine);
3214 vector<string> BufferParams::citeCommands() const
3216 static CitationStyle const default_style;
3217 vector<string> commands =
3218 documentClass().citeCommands(citeEngineType());
3219 if (commands.empty())
3220 commands.push_back(default_style.cmd);
3225 vector<CitationStyle> BufferParams::citeStyles() const
3227 static CitationStyle const default_style;
3228 vector<CitationStyle> styles =
3229 documentClass().citeStyles(citeEngineType());
3231 styles.push_back(default_style);