]> git.lyx.org Git - lyx.git/blob - src/BufferParams.cpp
Fix Qt6 deprecation warning about QString::fromUcs4
[lyx.git] / src / BufferParams.cpp
1 /**
2  * \file BufferParams.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alfredo Braunstein
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author John Levon
10  * \author André Pönitz
11  * \author Martin Vermeer
12  *
13  * Full author contact details are available in file CREDITS.
14  */
15
16 #include <config.h>
17
18 #include "BufferParams.h"
19
20 #include "Author.h"
21 #include "LayoutFile.h"
22 #include "BranchList.h"
23 #include "Buffer.h"
24 #include "Bullet.h"
25 #include "CiteEnginesList.h"
26 #include "Color.h"
27 #include "ColorSet.h"
28 #include "Converter.h"
29 #include "Encoding.h"
30 #include "Format.h"
31 #include "IndicesList.h"
32 #include "Language.h"
33 #include "LaTeXFeatures.h"
34 #include "LaTeXFonts.h"
35 #include "Font.h"
36 #include "Lexer.h"
37 #include "LyXRC.h"
38 #include "OutputParams.h"
39 #include "Spacing.h"
40 #include "texstream.h"
41 #include "TexRow.h"
42 #include "VSpace.h"
43 #include "PDFOptions.h"
44
45 #include "frontends/alert.h"
46
47 #include "insets/InsetListingsParams.h"
48 #include "insets/InsetQuotes.h"
49
50 #include "support/convert.h"
51 #include "support/debug.h"
52 #include "support/FileName.h"
53 #include "support/filetools.h"
54 #include "support/gettext.h"
55 #include "support/Length.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"
61
62 #include <algorithm>
63 #include <sstream>
64
65 using namespace std;
66 using namespace lyx::support;
67
68
69 static char const * const string_paragraph_separation[] = {
70         "indent", "skip", ""
71 };
72
73
74 static char const * const string_quotes_style[] = {
75         "english", "swedish", "german", "polish", "swiss", "danish", "plain",
76         "british", "swedishg", "french", "frenchin", "russian", "cjk", "cjkangle",
77         "hungarian", ""
78 };
79
80
81 static char const * const string_papersize[] = {
82         "default", "custom", "letter", "legal", "executive",
83         "a0", "a1", "a2", "a3", "a4", "a5", "a6",
84         "b0", "b1", "b2", "b3", "b4", "b5", "b6",
85         "c0", "c1", "c2", "c3", "c4", "c5", "c6",
86         "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", ""
87 };
88
89
90 static char const * const string_papersize_geometry[] = {
91         "default", "custom", "letterpaper", "legalpaper", "executivepaper",
92         "a0paper", "a1paper", "a2paper", "a3paper", "a4paper", "a5paper", "a6paper",
93         "b0paper", "b1paper", "b2paper", "b3paper", "b4paper", "b5paper", "b6paper",
94         "c0paper", "c1paper", "c2paper", "c3paper", "c4paper", "c5paper", "c6paper",
95         "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", ""
96 };
97
98
99 static char const * const string_orientation[] = {
100         "portrait", "landscape", ""
101 };
102
103
104 static char const * const tex_graphics[] = {
105         "default", "dvialw", "dvilaser", "dvipdf", "dvipdfm", "dvipdfmx",
106         "dvips", "dvipsone", "dvitops", "dviwin", "dviwindo", "dvi2ps", "emtex",
107         "ln", "oztex", "pctexhp", "pctexps", "pctexwin", "pctex32", "pdftex",
108         "psprint", "pubps", "tcidvi", "textures", "truetex", "vtex", "xdvi",
109         "xetex", "none", ""
110 };
111
112
113 namespace lyx {
114
115 // Local translators
116 namespace {
117
118 // Paragraph separation
119 typedef Translator<string, BufferParams::ParagraphSeparation> ParSepTranslator;
120
121
122 ParSepTranslator const init_parseptranslator()
123 {
124         ParSepTranslator translator
125                 (string_paragraph_separation[0], BufferParams::ParagraphIndentSeparation);
126         translator.addPair(string_paragraph_separation[1], BufferParams::ParagraphSkipSeparation);
127         return translator;
128 }
129
130
131 ParSepTranslator const & parseptranslator()
132 {
133         static ParSepTranslator const translator =
134                 init_parseptranslator();
135         return translator;
136 }
137
138
139 // Quotes style
140 typedef Translator<string, QuoteStyle> QuotesStyleTranslator;
141
142
143 QuotesStyleTranslator const init_quotesstyletranslator()
144 {
145         QuotesStyleTranslator translator
146                 (string_quotes_style[0], QuoteStyle::English);
147         translator.addPair(string_quotes_style[1], QuoteStyle::Swedish);
148         translator.addPair(string_quotes_style[2], QuoteStyle::German);
149         translator.addPair(string_quotes_style[3], QuoteStyle::Polish);
150         translator.addPair(string_quotes_style[4], QuoteStyle::Swiss);
151         translator.addPair(string_quotes_style[5], QuoteStyle::Danish);
152         translator.addPair(string_quotes_style[6], QuoteStyle::Plain);
153         translator.addPair(string_quotes_style[7], QuoteStyle::British);
154         translator.addPair(string_quotes_style[8], QuoteStyle::SwedishG);
155         translator.addPair(string_quotes_style[9], QuoteStyle::French);
156         translator.addPair(string_quotes_style[10], QuoteStyle::FrenchIN);
157         translator.addPair(string_quotes_style[11], QuoteStyle::Russian);
158         translator.addPair(string_quotes_style[12], QuoteStyle::CJK);
159         translator.addPair(string_quotes_style[13], QuoteStyle::CJKAngle);
160         translator.addPair(string_quotes_style[14], QuoteStyle::Hungarian);
161         return translator;
162 }
163
164
165 QuotesStyleTranslator const & quotesstyletranslator()
166 {
167         static QuotesStyleTranslator const translator =
168                 init_quotesstyletranslator();
169         return translator;
170 }
171
172
173 // Paper size
174 typedef Translator<string, PAPER_SIZE> PaperSizeTranslator;
175
176
177 static PaperSizeTranslator initPaperSizeTranslator()
178 {
179         PaperSizeTranslator translator(string_papersize[0], PAPER_DEFAULT);
180         translator.addPair(string_papersize[1], PAPER_CUSTOM);
181         translator.addPair(string_papersize[2], PAPER_USLETTER);
182         translator.addPair(string_papersize[3], PAPER_USLEGAL);
183         translator.addPair(string_papersize[4], PAPER_USEXECUTIVE);
184         translator.addPair(string_papersize[5], PAPER_A0);
185         translator.addPair(string_papersize[6], PAPER_A1);
186         translator.addPair(string_papersize[7], PAPER_A2);
187         translator.addPair(string_papersize[8], PAPER_A3);
188         translator.addPair(string_papersize[9], PAPER_A4);
189         translator.addPair(string_papersize[10], PAPER_A5);
190         translator.addPair(string_papersize[11], PAPER_A6);
191         translator.addPair(string_papersize[12], PAPER_B0);
192         translator.addPair(string_papersize[13], PAPER_B1);
193         translator.addPair(string_papersize[14], PAPER_B2);
194         translator.addPair(string_papersize[15], PAPER_B3);
195         translator.addPair(string_papersize[16], PAPER_B4);
196         translator.addPair(string_papersize[17], PAPER_B5);
197         translator.addPair(string_papersize[18], PAPER_B6);
198         translator.addPair(string_papersize[19], PAPER_C0);
199         translator.addPair(string_papersize[20], PAPER_C1);
200         translator.addPair(string_papersize[21], PAPER_C2);
201         translator.addPair(string_papersize[22], PAPER_C3);
202         translator.addPair(string_papersize[23], PAPER_C4);
203         translator.addPair(string_papersize[24], PAPER_C5);
204         translator.addPair(string_papersize[25], PAPER_C6);
205         translator.addPair(string_papersize[26], PAPER_JISB0);
206         translator.addPair(string_papersize[27], PAPER_JISB1);
207         translator.addPair(string_papersize[28], PAPER_JISB2);
208         translator.addPair(string_papersize[29], PAPER_JISB3);
209         translator.addPair(string_papersize[30], PAPER_JISB4);
210         translator.addPair(string_papersize[31], PAPER_JISB5);
211         translator.addPair(string_papersize[32], PAPER_JISB6);
212         return translator;
213 }
214
215
216 PaperSizeTranslator const & papersizetranslator()
217 {
218         static PaperSizeTranslator const translator =
219                 initPaperSizeTranslator();
220         return translator;
221 }
222
223
224 // Paper orientation
225 typedef Translator<string, PAPER_ORIENTATION> PaperOrientationTranslator;
226
227
228 PaperOrientationTranslator const init_paperorientationtranslator()
229 {
230         PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
231         translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
232         return translator;
233 }
234
235
236 PaperOrientationTranslator const & paperorientationtranslator()
237 {
238         static PaperOrientationTranslator const translator =
239             init_paperorientationtranslator();
240         return translator;
241 }
242
243
244 // Page sides
245 typedef Translator<int, PageSides> SidesTranslator;
246
247
248 SidesTranslator const init_sidestranslator()
249 {
250         SidesTranslator translator(1, OneSide);
251         translator.addPair(2, TwoSides);
252         return translator;
253 }
254
255
256 SidesTranslator const & sidestranslator()
257 {
258         static SidesTranslator const translator = init_sidestranslator();
259         return translator;
260 }
261
262
263 // LaTeX packages
264 typedef Translator<int, BufferParams::Package> PackageTranslator;
265
266
267 PackageTranslator const init_packagetranslator()
268 {
269         PackageTranslator translator(0, BufferParams::package_off);
270         translator.addPair(1, BufferParams::package_auto);
271         translator.addPair(2, BufferParams::package_on);
272         return translator;
273 }
274
275
276 PackageTranslator const & packagetranslator()
277 {
278         static PackageTranslator const translator =
279                 init_packagetranslator();
280         return translator;
281 }
282
283
284 // Spacing
285 typedef Translator<string, Spacing::Space> SpaceTranslator;
286
287
288 SpaceTranslator const init_spacetranslator()
289 {
290         SpaceTranslator translator("default", Spacing::Default);
291         translator.addPair("single", Spacing::Single);
292         translator.addPair("onehalf", Spacing::Onehalf);
293         translator.addPair("double", Spacing::Double);
294         translator.addPair("other", Spacing::Other);
295         return translator;
296 }
297
298
299 SpaceTranslator const & spacetranslator()
300 {
301         static SpaceTranslator const translator = init_spacetranslator();
302         return translator;
303 }
304
305
306 bool inSystemDir(FileName const & document_dir, string & system_dir)
307 {
308         // A document is assumed to be in a system LyX directory (not
309         // necessarily the system directory of the running instance)
310         // if both "configure.py" and "chkconfig.ltx" are found in
311         // either document_dir/../ or document_dir/../../.
312         // If true, the system directory path is returned in system_dir
313         // with a trailing path separator.
314
315         string const msg = "Checking whether document is in a system dir...";
316
317         string dir = document_dir.absFileName();
318
319         for (int i = 0; i < 3; ++i) {
320                 dir = addPath(dir, "..");
321                 if (!fileSearch(dir, "configure.py").empty() &&
322                     !fileSearch(dir, "chkconfig.ltx").empty()) {
323                         LYXERR(Debug::FILES, msg << " yes");
324                         system_dir = addPath(FileName(dir).realPath(), "");
325                         return true;
326                 }
327         }
328
329         LYXERR(Debug::FILES, msg << " no");
330         system_dir = string();
331         return false;
332 }
333
334 } // namespace
335
336
337 class BufferParams::Impl
338 {
339 public:
340         Impl();
341
342         AuthorList authorlist;
343         BranchList branchlist;
344         IgnoreList spellignore;
345         Bullet temp_bullets[4];
346         Bullet user_defined_bullets[4];
347         IndicesList indiceslist;
348         Spacing spacing;
349         Length parindent;
350         Length mathindent;
351         /** This is the amount of space used for paragraph_separation "skip",
352          * and for detached paragraphs in "indented" documents.
353          */
354         VSpace defskip;
355         PDFOptions pdfoptions;
356         LayoutFileIndex baseClass_;
357         FormatList exportableFormatList;
358         FormatList viewableFormatList;
359         bool isViewCacheValid;
360         bool isExportCacheValid;
361 };
362
363
364 BufferParams::Impl::Impl()
365         : defskip(VSpace::MEDSKIP), baseClass_(string("")),
366           isViewCacheValid(false), isExportCacheValid(false)
367 {
368         // set initial author
369         // FIXME UNICODE
370         authorlist.record(Author(from_utf8(lyxrc.user_name),
371                                  from_utf8(lyxrc.user_email),
372                                  from_utf8(lyxrc.user_initials)));
373 }
374
375
376 BufferParams::Impl *
377 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
378 {
379         LBUFERR(ptr);
380         return new BufferParams::Impl(*ptr);
381 }
382
383
384 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
385 {
386         delete ptr;
387 }
388
389
390 BufferParams::BufferParams()
391         : pimpl_(new Impl)
392 {
393         setBaseClass(defaultBaseclass());
394         cite_engine_ = "basic";
395         cite_engine_type_ = ENGINE_TYPE_DEFAULT;
396         makeDocumentClass();
397         paragraph_separation = ParagraphIndentSeparation;
398         is_math_indent = false;
399         math_numbering_side = DEFAULT;
400         quotes_style = QuoteStyle::English;
401         dynamic_quotes = false;
402         fontsize = "default";
403
404         /*  PaperLayout */
405         papersize = PAPER_DEFAULT;
406         orientation = ORIENTATION_PORTRAIT;
407         use_geometry = false;
408         biblio_style = string();
409         use_bibtopic = false;
410         multibib = string();
411         use_indices = false;
412         save_transient_properties = true;
413         track_changes = false;
414         output_changes = false;
415         change_bars = false;
416         postpone_fragile_content = true;
417         use_default_options = true;
418         maintain_unincluded_children = CM_None;
419         secnumdepth = 3;
420         tocdepth = 3;
421         language = default_language;
422         fontenc = "auto";
423         fonts_roman[0] = "default";
424         fonts_roman[1] = "default";
425         fonts_sans[0] = "default";
426         fonts_sans[1] = "default";
427         fonts_typewriter[0] = "default";
428         fonts_typewriter[1] = "default";
429         fonts_math[0] = "auto";
430         fonts_math[1] = "auto";
431         fonts_default_family = "default";
432         useNonTeXFonts = false;
433         use_microtype = false;
434         use_dash_ligatures = true;
435         fonts_expert_sc = false;
436         fonts_roman_osf = false;
437         fonts_sans_osf = false;
438         fonts_typewriter_osf = false;
439         fonts_sans_scale[0] = 100;
440         fonts_sans_scale[1] = 100;
441         fonts_typewriter_scale[0] = 100;
442         fonts_typewriter_scale[1] = 100;
443         inputenc = "utf8";
444         lang_package = "default";
445         graphics_driver = "default";
446         default_output_format = "default";
447         bibtex_command = "default";
448         index_command = "default";
449         sides = OneSide;
450         columns = 1;
451         listings_params = string();
452         pagestyle = "default";
453         tablestyle = "default";
454         float_alignment = "class";
455         float_placement = "class";
456         suppress_date = false;
457         justification = true;
458         // no color is the default (white)
459         backgroundcolor = lyx::rgbFromHexName("#ffffff");
460         isbackgroundcolor = false;
461         // no color is the default (black)
462         fontcolor = lyx::rgbFromHexName("#000000");
463         isfontcolor = false;
464         // light gray is the default font color for greyed-out notes
465         notefontcolor = lyx::rgbFromHexName("#cccccc");
466         isnotefontcolor = false;
467         boxbgcolor = lyx::rgbFromHexName("#ff0000");
468         isboxbgcolor = false;
469         compressed = lyxrc.save_compressed;
470         for (int iter = 0; iter < 4; ++iter) {
471                 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
472                 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
473         }
474         // default index
475         indiceslist().addDefault(B_("Index"));
476         html_be_strict = false;
477         html_math_output = MathML;
478         html_math_img_scale = 1.0;
479         html_css_as_file = false;
480         docbook_table_output = HTMLTable;
481         display_pixel_ratio = 1.0;
482
483         shell_escape = false;
484         output_sync = false;
485         use_refstyle = true;
486         use_minted = false;
487         use_lineno = false;
488
489         // map current author
490         author_map_[pimpl_->authorlist.get(0).bufferId()] = 0;
491 }
492
493
494 docstring BufferParams::B_(string const & l10n) const
495 {
496         LASSERT(language, return from_utf8(l10n));
497         return getMessages(language->code()).get(l10n);
498 }
499
500
501 BufferParams::Package BufferParams::use_package(std::string const & p) const
502 {
503         PackageMap::const_iterator it = use_packages.find(p);
504         if (it == use_packages.end())
505                 return package_auto;
506         return it->second;
507 }
508
509
510 void BufferParams::use_package(std::string const & p, BufferParams::Package u)
511 {
512         use_packages[p] = u;
513 }
514
515
516 map<string, string> const & BufferParams::auto_packages()
517 {
518         static map<string, string> packages;
519         if (packages.empty()) {
520                 // We could have a race condition here that two threads
521                 // discover an empty map at the same time and want to fill
522                 // it, but that is no problem, since the same contents is
523                 // filled in twice then. Having the locker inside the
524                 // packages.empty() condition has the advantage that we
525                 // don't need the mutex overhead for simple reading.
526                 static Mutex mutex;
527                 Mutex::Locker locker(&mutex);
528                 // adding a package here implies a file format change!
529                 packages["amsmath"] =
530                         N_("The LaTeX package amsmath is only used if AMS formula types or symbols from the AMS math toolbars are inserted into formulas");
531                 packages["amssymb"] =
532                         N_("The LaTeX package amssymb is only used if symbols from the AMS math toolbars are inserted into formulas");
533                 packages["cancel"] =
534                         N_("The LaTeX package cancel is only used if \\cancel commands are used in formulas");
535                 packages["esint"] =
536                         N_("The LaTeX package esint is only used if special integral symbols are inserted into formulas");
537                 packages["mathdots"] =
538                         N_("The LaTeX package mathdots is only used if the command \\iddots is inserted into formulas");
539                 packages["mathtools"] =
540                         N_("The LaTeX package mathtools is only used if some mathematical relations are inserted into formulas");
541                 packages["mhchem"] =
542                         N_("The LaTeX package mhchem is only used if either the command \\ce or \\cf is inserted into formulas");
543                 packages["stackrel"] =
544                         N_("The LaTeX package stackrel is only used if the command \\stackrel with subscript is inserted into formulas");
545                 packages["stmaryrd"] =
546                         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");
547                 packages["undertilde"] =
548                         N_("The LaTeX package undertilde is only used if you use the math frame decoration 'utilde'");
549         }
550         return packages;
551 }
552
553
554 bool BufferParams::useBibtopic() const
555 {
556         if (useBiblatex())
557                 return false;
558         return (use_bibtopic || (!multibib.empty() && multibib != "child"));
559 }
560
561
562 AuthorList & BufferParams::authors()
563 {
564         return pimpl_->authorlist;
565 }
566
567
568 AuthorList const & BufferParams::authors() const
569 {
570         return pimpl_->authorlist;
571 }
572
573
574 void BufferParams::addAuthor(Author const & a)
575 {
576         author_map_[a.bufferId()] = pimpl_->authorlist.record(a);
577 }
578
579
580 BranchList & BufferParams::branchlist()
581 {
582         return pimpl_->branchlist;
583 }
584
585
586 BranchList const & BufferParams::branchlist() const
587 {
588         return pimpl_->branchlist;
589 }
590
591
592 IndicesList & BufferParams::indiceslist()
593 {
594         return pimpl_->indiceslist;
595 }
596
597
598 IndicesList const & BufferParams::indiceslist() const
599 {
600         return pimpl_->indiceslist;
601 }
602
603
604 typedef std::vector<WordLangTuple> IgnoreList;
605
606
607 IgnoreList & BufferParams::spellignore()
608 {
609         return pimpl_->spellignore;
610 }
611
612
613 IgnoreList const & BufferParams::spellignore() const
614 {
615         return pimpl_->spellignore;
616 }
617
618
619 bool BufferParams::spellignored(WordLangTuple const & wl) const
620 {
621         bool has_item = false;
622         vector<WordLangTuple> il = spellignore();
623         vector<WordLangTuple>::const_iterator it = il.begin();
624         for (; it != il.end(); ++it) {
625                 if (it->lang()->code() != wl.lang()->code())
626                         continue;
627                 if (it->word() == wl.word()) {
628                         has_item = true;
629                         break;
630                 }
631         }
632         return has_item;
633 }
634
635
636 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
637 {
638         LASSERT(index < 4, return pimpl_->temp_bullets[0]);
639         return pimpl_->temp_bullets[index];
640 }
641
642
643 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
644 {
645         LASSERT(index < 4, return pimpl_->temp_bullets[0]);
646         return pimpl_->temp_bullets[index];
647 }
648
649
650 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
651 {
652         LASSERT(index < 4, return pimpl_->temp_bullets[0]);
653         return pimpl_->user_defined_bullets[index];
654 }
655
656
657 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
658 {
659         LASSERT(index < 4, return pimpl_->temp_bullets[0]);
660         return pimpl_->user_defined_bullets[index];
661 }
662
663
664 Spacing & BufferParams::spacing()
665 {
666         return pimpl_->spacing;
667 }
668
669
670 Spacing const & BufferParams::spacing() const
671 {
672         return pimpl_->spacing;
673 }
674
675
676 PDFOptions & BufferParams::pdfoptions()
677 {
678         return pimpl_->pdfoptions;
679 }
680
681
682 PDFOptions const & BufferParams::pdfoptions() const
683 {
684         return pimpl_->pdfoptions;
685 }
686
687
688 Length const & BufferParams::getMathIndent() const
689 {
690         return pimpl_->mathindent;
691 }
692
693
694 void BufferParams::setMathIndent(Length const & indent)
695 {
696         pimpl_->mathindent = indent;
697 }
698
699
700 Length const & BufferParams::getParIndent() const
701 {
702         return pimpl_->parindent;
703 }
704
705
706 void BufferParams::setParIndent(Length const & indent)
707 {
708         pimpl_->parindent = indent;
709 }
710
711
712 VSpace const & BufferParams::getDefSkip() const
713 {
714         return pimpl_->defskip;
715 }
716
717
718 void BufferParams::setDefSkip(VSpace const & vs)
719 {
720         // DEFSKIP will cause an infinite loop
721         LASSERT(vs.kind() != VSpace::DEFSKIP, return);
722         pimpl_->defskip = vs;
723 }
724
725
726 BufferParams::MathNumber BufferParams::getMathNumber() const
727 {
728         if (math_numbering_side != DEFAULT)
729                 return math_numbering_side;
730         // FIXME: do not hardcode language here
731         else if (language->lang() == "arabic_arabi"
732                  || documentClass().provides("leqno"))
733                 return LEFT;
734         else
735                 return RIGHT;
736 }
737
738
739 string BufferParams::readToken(Lexer & lex, string const & token,
740         FileName const & filename)
741 {
742         string result;
743         FileName const & filepath = filename.onlyPath();
744
745         if (token == "\\textclass") {
746                 lex.next();
747                 string const classname = lex.getString();
748                 // if there exists a local layout file, ignore the system one
749                 // NOTE: in this case, the textclass (.cls file) is assumed to
750                 // be available.
751                 string tcp;
752                 LayoutFileList & bcl = LayoutFileList::get();
753                 if (!filepath.empty()) {
754                         // If classname is an absolute path, the document is
755                         // using a local layout file which could not be accessed
756                         // by a relative path. In this case the path is correct
757                         // even if the document was moved to a different
758                         // location. However, we will have a problem if the
759                         // document was generated on a different platform.
760                         bool isabsolute = FileName::isAbsolute(classname);
761                         string const classpath = onlyPath(classname);
762                         string const path = isabsolute ? classpath
763                                 : FileName(addPath(filepath.absFileName(),
764                                                 classpath)).realPath();
765                         string const oldpath = isabsolute ? string()
766                                 : FileName(addPath(origin, classpath)).realPath();
767                         tcp = bcl.addLocalLayout(onlyFileName(classname), path, oldpath);
768                 }
769                 // that returns non-empty if a "local" layout file is found.
770                 if (!tcp.empty()) {
771                         result = to_utf8(makeRelPath(from_utf8(onlyPath(tcp)),
772                                                 from_utf8(filepath.absFileName())));
773                         if (result.empty())
774                                 result = ".";
775                         setBaseClass(onlyFileName(tcp));
776                 } else
777                         setBaseClass(onlyFileName(classname));
778                 // We assume that a tex class exists for local or unknown
779                 // layouts so this warning, will only be given for system layouts.
780                 if (!baseClass()->isTeXClassAvailable()) {
781                         docstring const desc =
782                                 translateIfPossible(from_utf8(baseClass()->description()));
783                         docstring const prereqs =
784                                 from_utf8(baseClass()->prerequisites());
785                         docstring const msg =
786                                 bformat(_("The selected document class\n"
787                                                  "\t%1$s\n"
788                                                  "requires external files that are not available.\n"
789                                                  "The document class can still be used, but the\n"
790                                                  "document cannot be compiled until the following\n"
791                                                  "prerequisites are installed:\n"
792                                                  "\t%2$s\n"
793                                                  "See section 3.1.2.2 (Class Availability) of the\n"
794                                                  "User's Guide for more information."), desc, prereqs);
795                         frontend::Alert::warning(_("Document class not available"),
796                                        msg, true);
797                 }
798         } else if (token == "\\save_transient_properties") {
799                 lex >> save_transient_properties;
800         } else if (token == "\\origin") {
801                 lex.eatLine();
802                 origin = lex.getString();
803                 string const sysdirprefix = "/systemlyxdir/";
804                 if (prefixIs(origin, sysdirprefix)) {
805                         string docsys;
806                         if (inSystemDir(filepath, docsys))
807                                 origin.replace(0, sysdirprefix.length() - 1, docsys);
808                         else
809                                 origin.replace(0, sysdirprefix.length() - 1,
810                                         package().system_support().absFileName());
811                 }
812         } else if (token == "\\begin_preamble") {
813                 readPreamble(lex);
814         } else if (token == "\\begin_local_layout") {
815                 readLocalLayout(lex, false);
816         } else if (token == "\\begin_forced_local_layout") {
817                 readLocalLayout(lex, true);
818         } else if (token == "\\begin_modules") {
819                 readModules(lex);
820         } else if (token == "\\begin_removed_modules") {
821                 readRemovedModules(lex);
822         } else if (token == "\\begin_includeonly") {
823                 readIncludeonly(lex);
824         } else if (token == "\\maintain_unincluded_children") {
825                 string tmp;
826                 lex >> tmp;
827                 if (tmp == "no")
828                         maintain_unincluded_children = CM_None;
829                 else if (tmp == "mostly")
830                         maintain_unincluded_children = CM_Mostly;
831                 else if (tmp == "strict")
832                         maintain_unincluded_children = CM_Strict;
833         } else if (token == "\\options") {
834                 lex.eatLine();
835                 options = lex.getString();
836         } else if (token == "\\use_default_options") {
837                 lex >> use_default_options;
838         } else if (token == "\\master") {
839                 lex.eatLine();
840                 master = lex.getString();
841                 if (!filepath.empty() && FileName::isAbsolute(origin)) {
842                         bool const isabs = FileName::isAbsolute(master);
843                         FileName const abspath(isabs ? master : origin + master);
844                         bool const moved = filepath != FileName(origin);
845                         if (moved && abspath.exists()) {
846                                 docstring const path = isabs
847                                         ? from_utf8(master)
848                                         : from_utf8(abspath.realPath());
849                                 docstring const refpath =
850                                         from_utf8(filepath.absFileName());
851                                 master = to_utf8(makeRelPath(path, refpath));
852                         }
853                 }
854         } else if (token == "\\suppress_date") {
855                 lex >> suppress_date;
856         } else if (token == "\\justification") {
857                 lex >> justification;
858         } else if (token == "\\language") {
859                 readLanguage(lex);
860         } else if (token == "\\language_package") {
861                 lex.eatLine();
862                 lang_package = lex.getString();
863         } else if (token == "\\inputencoding") {
864                 lex >> inputenc;
865         } else if (token == "\\graphics") {
866                 readGraphicsDriver(lex);
867         } else if (token == "\\default_output_format") {
868                 lex >> default_output_format;
869         } else if (token == "\\bibtex_command") {
870                 lex.eatLine();
871                 bibtex_command = lex.getString();
872         } else if (token == "\\index_command") {
873                 lex.eatLine();
874                 index_command = lex.getString();
875         } else if (token == "\\fontencoding") {
876                 lex.eatLine();
877                 fontenc = lex.getString();
878         } else if (token == "\\font_roman") {
879                 lex >> fonts_roman[0];
880                 lex >> fonts_roman[1];
881         } else if (token == "\\font_sans") {
882                 lex >> fonts_sans[0];
883                 lex >> fonts_sans[1];
884         } else if (token == "\\font_typewriter") {
885                 lex >> fonts_typewriter[0];
886                 lex >> fonts_typewriter[1];
887         } else if (token == "\\font_math") {
888                 lex >> fonts_math[0];
889                 lex >> fonts_math[1];
890         } else if (token == "\\font_default_family") {
891                 lex >> fonts_default_family;
892         } else if (token == "\\use_non_tex_fonts") {
893                 lex >> useNonTeXFonts;
894         } else if (token == "\\font_sc") {
895                 lex >> fonts_expert_sc;
896         } else if (token == "\\font_roman_osf") {
897                 lex >> fonts_roman_osf;
898         } else if (token == "\\font_sans_osf") {
899                 lex >> fonts_sans_osf;
900         } else if (token == "\\font_typewriter_osf") {
901                 lex >> fonts_typewriter_osf;
902         } else if (token == "\\font_roman_opts") {
903                 lex >> font_roman_opts;
904         } else if (token == "\\font_sf_scale") {
905                 lex >> fonts_sans_scale[0];
906                 lex >> fonts_sans_scale[1];
907         } else if (token == "\\font_sans_opts") {
908                 lex >> font_sans_opts;
909         } else if (token == "\\font_tt_scale") {
910                 lex >> fonts_typewriter_scale[0];
911                 lex >> fonts_typewriter_scale[1];
912         } else if (token == "\\font_typewriter_opts") {
913                 lex >> font_typewriter_opts;
914         } else if (token == "\\font_cjk") {
915                 lex >> fonts_cjk;
916         } else if (token == "\\use_microtype") {
917                 lex >> use_microtype;
918         } else if (token == "\\use_dash_ligatures") {
919                 lex >> use_dash_ligatures;
920         } else if (token == "\\paragraph_separation") {
921                 string parsep;
922                 lex >> parsep;
923                 paragraph_separation = parseptranslator().find(parsep);
924         } else if (token == "\\paragraph_indentation") {
925                 lex.next();
926                 string parindent = lex.getString();
927                 if (parindent == "default")
928                         pimpl_->parindent = Length();
929                 else
930                         pimpl_->parindent = Length(parindent);
931         } else if (token == "\\defskip") {
932                 lex.next();
933                 string const defskip = lex.getString();
934                 pimpl_->defskip = VSpace(defskip);
935                 if (pimpl_->defskip.kind() == VSpace::DEFSKIP)
936                         // that is invalid
937                         pimpl_->defskip = VSpace(VSpace::MEDSKIP);
938         } else if (token == "\\is_math_indent") {
939                 lex >> is_math_indent;
940         } else if (token == "\\math_indentation") {
941                 lex.next();
942                 string mathindent = lex.getString();
943                 if (mathindent == "default")
944                         pimpl_->mathindent = Length();
945                 else
946                         pimpl_->mathindent = Length(mathindent);
947         } else if (token == "\\math_numbering_side") {
948                 string tmp;
949                 lex >> tmp;
950                 if (tmp == "left")
951                         math_numbering_side = LEFT;
952                 else if (tmp == "right")
953                         math_numbering_side = RIGHT;
954                 else
955                         math_numbering_side = DEFAULT;
956         } else if (token == "\\quotes_style") {
957                 string qstyle;
958                 lex >> qstyle;
959                 quotes_style = quotesstyletranslator().find(qstyle);
960         } else if (token == "\\dynamic_quotes") {
961                 lex >> dynamic_quotes;
962         } else if (token == "\\papersize") {
963                 string ppsize;
964                 lex >> ppsize;
965                 papersize = papersizetranslator().find(ppsize);
966         } else if (token == "\\use_geometry") {
967                 lex >> use_geometry;
968         } else if (token == "\\use_package") {
969                 string package;
970                 int use;
971                 lex >> package;
972                 lex >> use;
973                 use_package(package, packagetranslator().find(use));
974         } else if (token == "\\cite_engine") {
975                 lex.eatLine();
976                 cite_engine_ = lex.getString();
977         } else if (token == "\\cite_engine_type") {
978                 string engine_type;
979                 lex >> engine_type;
980                 cite_engine_type_ = theCiteEnginesList.getType(engine_type);
981         } else if (token == "\\biblio_style") {
982                 lex.eatLine();
983                 biblio_style = lex.getString();
984         } else if (token == "\\biblio_options") {
985                 lex.eatLine();
986                 biblio_opts = trim(lex.getString());
987         } else if (token == "\\biblatex_bibstyle") {
988                 lex.eatLine();
989                 biblatex_bibstyle = trim(lex.getString());
990         } else if (token == "\\biblatex_citestyle") {
991                 lex.eatLine();
992                 biblatex_citestyle = trim(lex.getString());
993         } else if (token == "\\use_bibtopic") {
994                 lex >> use_bibtopic;
995         } else if (token == "\\multibib") {
996                 lex >> multibib;
997         } else if (token == "\\use_indices") {
998                 lex >> use_indices;
999         } else if (token == "\\tracking_changes") {
1000                 lex >> track_changes;
1001         } else if (token == "\\output_changes") {
1002                 lex >> output_changes;
1003         } else if (token == "\\change_bars") {
1004                 lex >> change_bars;
1005         } else if (token == "\\postpone_fragile_content") {
1006                 lex >> postpone_fragile_content;
1007         } else if (token == "\\branch") {
1008                 lex.eatLine();
1009                 docstring branch = lex.getDocString();
1010                 branchlist().add(branch);
1011                 while (true) {
1012                         lex.next();
1013                         string const tok = lex.getString();
1014                         if (tok == "\\end_branch")
1015                                 break;
1016                         Branch * branch_ptr = branchlist().find(branch);
1017                         if (tok == "\\selected") {
1018                                 lex.next();
1019                                 if (branch_ptr)
1020                                         branch_ptr->setSelected(lex.getInteger());
1021                         }
1022                         if (tok == "\\filename_suffix") {
1023                                 lex.next();
1024                                 if (branch_ptr)
1025                                         branch_ptr->setFileNameSuffix(lex.getInteger());
1026                         }
1027                         if (tok == "\\color") {
1028                                 lex.eatLine();
1029                                 vector<string> const colors = getVectorFromString(lex.getString(), " ");
1030                                 string const lmcolor = colors.front();
1031                                 string dmcolor;
1032                                 if (colors.size() > 1)
1033                                         dmcolor = colors.back();
1034                                 if (branch_ptr)
1035                                         branch_ptr->setColors(lmcolor, dmcolor);
1036                         }
1037                 }
1038         } else if (token == "\\index") {
1039                 lex.eatLine();
1040                 docstring index = lex.getDocString();
1041                 docstring shortcut;
1042                 indiceslist().add(index);
1043                 while (true) {
1044                         lex.next();
1045                         string const tok = lex.getString();
1046                         if (tok == "\\end_index")
1047                                 break;
1048                         Index * index_ptr = indiceslist().find(index);
1049                         if (tok == "\\shortcut") {
1050                                 lex.next();
1051                                 shortcut = lex.getDocString();
1052                                 if (index_ptr)
1053                                         index_ptr->setShortcut(shortcut);
1054                         }
1055                         if (tok == "\\color") {
1056                                 lex.eatLine();
1057                                 string color = lex.getString();
1058                                 if (index_ptr)
1059                                         index_ptr->setColor(color);
1060                                 // Update also the Color table:
1061                                 if (color == "none")
1062                                         color = lcolor.getX11HexName(Color_background);
1063                                 // FIXME UNICODE
1064                                 if (!shortcut.empty())
1065                                         lcolor.setColor(to_utf8(shortcut)+ "@" + filename.absFileName(), color);
1066                         }
1067                 }
1068         } else if (token == "\\spellchecker_ignore") {
1069                 lex.eatLine();
1070                 docstring wl = lex.getDocString();
1071                 docstring language;
1072                 docstring word = split(wl, language, ' ');
1073                 Language const * lang = languages.getLanguage(to_ascii(language));
1074                 if (lang)
1075                         spellignore().push_back(WordLangTuple(word, lang));
1076         } else if (token == "\\author") {
1077                 lex.eatLine();
1078                 istringstream ss(lex.getString());
1079                 Author a;
1080                 ss >> a;
1081                 addAuthor(a);
1082         } else if (token == "\\paperorientation") {
1083                 string orient;
1084                 lex >> orient;
1085                 orientation = paperorientationtranslator().find(orient);
1086         } else if (token == "\\backgroundcolor") {
1087                 lex.eatLine();
1088                 backgroundcolor = lyx::rgbFromHexName(lex.getString());
1089                 isbackgroundcolor = true;
1090         } else if (token == "\\fontcolor") {
1091                 lex.eatLine();
1092                 fontcolor = lyx::rgbFromHexName(lex.getString());
1093                 isfontcolor = true;
1094         } else if (token == "\\notefontcolor") {
1095                 lex.eatLine();
1096                 string color = lex.getString();
1097                 notefontcolor = lyx::rgbFromHexName(color);
1098                 lcolor.setColor("notefontcolor", color);
1099                 lcolor.setLaTeXName("notefontcolor", "note_fontcolor");
1100                 lcolor.setGUIName("notefontcolor", N_("greyedout inset text"));
1101                 // set a local name for the painter
1102                 lcolor.setColor("notefontcolor@" + filename.absFileName(), color);
1103                 isnotefontcolor = true;
1104         } else if (token == "\\boxbgcolor") {
1105                 lex.eatLine();
1106                 string color = lex.getString();
1107                 boxbgcolor = lyx::rgbFromHexName(color);
1108                 lcolor.setColor("boxbgcolor@" + filename.absFileName(), color);
1109                 isboxbgcolor = true;
1110         } else if (token == "\\paperwidth") {
1111                 lex >> paperwidth;
1112         } else if (token == "\\paperheight") {
1113                 lex >> paperheight;
1114         } else if (token == "\\leftmargin") {
1115                 lex >> leftmargin;
1116         } else if (token == "\\topmargin") {
1117                 lex >> topmargin;
1118         } else if (token == "\\rightmargin") {
1119                 lex >> rightmargin;
1120         } else if (token == "\\bottommargin") {
1121                 lex >> bottommargin;
1122         } else if (token == "\\headheight") {
1123                 lex >> headheight;
1124         } else if (token == "\\headsep") {
1125                 lex >> headsep;
1126         } else if (token == "\\footskip") {
1127                 lex >> footskip;
1128         } else if (token == "\\columnsep") {
1129                 lex >> columnsep;
1130         } else if (token == "\\paperfontsize") {
1131                 lex >> fontsize;
1132         } else if (token == "\\papercolumns") {
1133                 lex >> columns;
1134         } else if (token == "\\listings_params") {
1135                 string par;
1136                 lex >> par;
1137                 listings_params = InsetListingsParams(par).params();
1138         } else if (token == "\\papersides") {
1139                 int psides;
1140                 lex >> psides;
1141                 sides = sidestranslator().find(psides);
1142         } else if (token == "\\paperpagestyle") {
1143                 lex >> pagestyle;
1144         } else if (token == "\\tablestyle") {
1145                 lex >> tablestyle;
1146         } else if (token == "\\bullet") {
1147                 readBullets(lex);
1148         } else if (token == "\\bulletLaTeX") {
1149                 readBulletsLaTeX(lex);
1150         } else if (token == "\\secnumdepth") {
1151                 lex >> secnumdepth;
1152         } else if (token == "\\tocdepth") {
1153                 lex >> tocdepth;
1154         } else if (token == "\\spacing") {
1155                 string nspacing;
1156                 lex >> nspacing;
1157                 string tmp_val;
1158                 if (nspacing == "other") {
1159                         lex >> tmp_val;
1160                 }
1161                 spacing().set(spacetranslator().find(nspacing), tmp_val);
1162         } else if (token == "\\float_placement") {
1163                 lex >> float_placement;
1164         } else if (token == "\\float_alignment") {
1165                 lex >> float_alignment;
1166
1167         } else if (prefixIs(token, "\\pdf_") || token == "\\use_hyperref") {
1168                 string toktmp = pdfoptions().readToken(lex, token);
1169                 if (!toktmp.empty()) {
1170                         lyxerr << "PDFOptions::readToken(): Unknown token: " <<
1171                                 toktmp << endl;
1172                         return toktmp;
1173                 }
1174         } else if (token == "\\html_math_output") {
1175                 int temp;
1176                 lex >> temp;
1177                 html_math_output = static_cast<MathOutput>(temp);
1178         } else if (token == "\\html_be_strict") {
1179                 lex >> html_be_strict;
1180         } else if (token == "\\html_css_as_file") {
1181                 lex >> html_css_as_file;
1182         } else if (token == "\\html_math_img_scale") {
1183                 lex >> html_math_img_scale;
1184         } else if (token == "\\html_latex_start") {
1185                 lex.eatLine();
1186                 html_latex_start = lex.getString();
1187         } else if (token == "\\html_latex_end") {
1188                 lex.eatLine();
1189                 html_latex_end = lex.getString();
1190         } else if (token == "\\docbook_table_output") {
1191                 int temp;
1192                 lex >> temp;
1193                 docbook_table_output = static_cast<TableOutput>(temp);
1194         } else if (token == "\\output_sync") {
1195                 lex >> output_sync;
1196         } else if (token == "\\output_sync_macro") {
1197                 lex >> output_sync_macro;
1198         } else if (token == "\\use_refstyle") {
1199                 lex >> use_refstyle;
1200         } else if (token == "\\use_minted") {
1201                 lex >> use_minted;
1202         } else if (token == "\\use_lineno") {
1203                 lex >> use_lineno;
1204         } else if (token == "\\lineno_options") {
1205                 lex.eatLine();
1206                 lineno_opts = trim(lex.getString());
1207         } else {
1208                 lyxerr << "BufferParams::readToken(): Unknown token: " <<
1209                         token << endl;
1210                 return token;
1211         }
1212
1213         return result;
1214 }
1215
1216
1217 namespace {
1218         // Quote argument if it contains spaces
1219         string quoteIfNeeded(string const & str) {
1220                 if (contains(str, ' '))
1221                         return "\"" + str + "\"";
1222                 return str;
1223         }
1224 } // namespace
1225
1226
1227 void BufferParams::writeFile(ostream & os, Buffer const * buf) const
1228 {
1229         // The top of the file is written by the buffer.
1230         // Prints out the buffer info into the .lyx file given by file
1231
1232         os << "\\save_transient_properties "
1233            << convert<string>(save_transient_properties) << '\n';
1234
1235         // the document directory (must end with a path separator)
1236         // realPath() is used to resolve symlinks, while addPath(..., "")
1237         // ensures a trailing path separator.
1238         string docsys;
1239         string filepath = addPath(buf->fileName().onlyPath().realPath(), "");
1240         string const sysdir = inSystemDir(FileName(filepath), docsys) ? docsys
1241                         : addPath(package().system_support().realPath(), "");
1242         string const relpath =
1243                 to_utf8(makeRelPath(from_utf8(filepath), from_utf8(sysdir)));
1244         if (!prefixIs(relpath, "../") && !FileName::isAbsolute(relpath))
1245                 filepath = addPath("/systemlyxdir", relpath);
1246         else if (!save_transient_properties || !lyxrc.save_origin)
1247                 filepath = "unavailable";
1248         os << "\\origin " << quoteIfNeeded(filepath) << '\n';
1249
1250         // the textclass
1251         os << "\\textclass "
1252            << quoteIfNeeded(buf->includedFilePath(addName(buf->layoutPos(),
1253                                                 baseClass()->name()), "layout"))
1254            << '\n';
1255
1256         // then the preamble
1257         if (!preamble.empty()) {
1258                 // remove '\n' from the end of preamble
1259                 docstring const tmppreamble = rtrim(preamble, "\n");
1260                 os << "\\begin_preamble\n"
1261                    << to_utf8(tmppreamble)
1262                    << "\n\\end_preamble\n";
1263         }
1264
1265         // the options
1266         if (!options.empty()) {
1267                 os << "\\options " << options << '\n';
1268         }
1269
1270         // use the class options defined in the layout?
1271         os << "\\use_default_options "
1272            << convert<string>(use_default_options) << "\n";
1273
1274         // the master document
1275         if (!master.empty()) {
1276                 os << "\\master " << master << '\n';
1277         }
1278
1279         // removed modules
1280         if (!removed_modules_.empty()) {
1281                 os << "\\begin_removed_modules" << '\n';
1282                 for (auto const & mod : removed_modules_)
1283                         os << mod << '\n';
1284                 os << "\\end_removed_modules" << '\n';
1285         }
1286
1287         // the modules
1288         if (!layout_modules_.empty()) {
1289                 os << "\\begin_modules" << '\n';
1290                 for (auto const & mod : layout_modules_)
1291                         os << mod << '\n';
1292                 os << "\\end_modules" << '\n';
1293         }
1294
1295         // includeonly
1296         if (!included_children_.empty()) {
1297                 os << "\\begin_includeonly" << '\n';
1298                 for (auto const & c : included_children_)
1299                         os << c << '\n';
1300                 os << "\\end_includeonly" << '\n';
1301         }
1302         string muc = "no";
1303         switch (maintain_unincluded_children) {
1304         case CM_Mostly:
1305                 muc = "mostly";
1306                 break;
1307         case CM_Strict:
1308                 muc = "strict";
1309                 break;
1310         case CM_None:
1311         default:
1312                 break;
1313         }
1314         os << "\\maintain_unincluded_children " << muc << '\n';
1315
1316         // local layout information
1317         docstring const local_layout = getLocalLayout(false);
1318         if (!local_layout.empty()) {
1319                 // remove '\n' from the end
1320                 docstring const tmplocal = rtrim(local_layout, "\n");
1321                 os << "\\begin_local_layout\n"
1322                    << to_utf8(tmplocal)
1323                    << "\n\\end_local_layout\n";
1324         }
1325         docstring const forced_local_layout = getLocalLayout(true);
1326         if (!forced_local_layout.empty()) {
1327                 // remove '\n' from the end
1328                 docstring const tmplocal = rtrim(forced_local_layout, "\n");
1329                 os << "\\begin_forced_local_layout\n"
1330                    << to_utf8(tmplocal)
1331                    << "\n\\end_forced_local_layout\n";
1332         }
1333
1334         // then the text parameters
1335         if (language != ignore_language)
1336                 os << "\\language " << language->lang() << '\n';
1337         os << "\\language_package " << lang_package
1338            << "\n\\inputencoding " << inputenc
1339            << "\n\\fontencoding " << fontenc
1340            << "\n\\font_roman \"" << fonts_roman[0]
1341            << "\" \"" << fonts_roman[1] << '"'
1342            << "\n\\font_sans \"" << fonts_sans[0]
1343            << "\" \"" << fonts_sans[1] << '"'
1344            << "\n\\font_typewriter \"" << fonts_typewriter[0]
1345            << "\" \"" << fonts_typewriter[1] << '"'
1346            << "\n\\font_math \"" << fonts_math[0]
1347            << "\" \"" << fonts_math[1] << '"'
1348            << "\n\\font_default_family " << fonts_default_family
1349            << "\n\\use_non_tex_fonts " << convert<string>(useNonTeXFonts)
1350            << "\n\\font_sc " << convert<string>(fonts_expert_sc)
1351            << "\n\\font_roman_osf " << convert<string>(fonts_roman_osf)
1352            << "\n\\font_sans_osf " << convert<string>(fonts_sans_osf)
1353            << "\n\\font_typewriter_osf " << convert<string>(fonts_typewriter_osf);
1354         if (!font_roman_opts.empty())
1355                 os << "\n\\font_roman_opts \"" << font_roman_opts << "\"";
1356         os << "\n\\font_sf_scale " << fonts_sans_scale[0]
1357            << ' ' << fonts_sans_scale[1];
1358         if (!font_sans_opts.empty())
1359                 os << "\n\\font_sans_opts \"" << font_sans_opts << "\"";
1360         os << "\n\\font_tt_scale " << fonts_typewriter_scale[0]
1361            << ' ' << fonts_typewriter_scale[1];
1362         if (!font_typewriter_opts.empty())
1363                 os << "\n\\font_typewriter_opts \"" << font_typewriter_opts << "\"";
1364         os << '\n';
1365         if (!fonts_cjk.empty())
1366                 os << "\\font_cjk " << fonts_cjk << '\n';
1367         os << "\\use_microtype " << convert<string>(use_microtype) << '\n';
1368         os << "\\use_dash_ligatures " << convert<string>(use_dash_ligatures) << '\n';
1369         os << "\\graphics " << graphics_driver << '\n';
1370         os << "\\default_output_format " << default_output_format << '\n';
1371         os << "\\output_sync " << output_sync << '\n';
1372         if (!output_sync_macro.empty())
1373                 os << "\\output_sync_macro \"" << output_sync_macro << "\"\n";
1374         os << "\\bibtex_command " << bibtex_command << '\n';
1375         os << "\\index_command " << index_command << '\n';
1376
1377         if (!float_placement.empty())
1378                 os << "\\float_placement " << float_placement << '\n';
1379         if (!float_alignment.empty())
1380                 os << "\\float_alignment " << float_alignment << '\n';
1381         os << "\\paperfontsize " << fontsize << '\n';
1382
1383         spacing().writeFile(os);
1384         pdfoptions().writeFile(os);
1385
1386         os << "\\papersize " << string_papersize[papersize]
1387            << "\n\\use_geometry " << convert<string>(use_geometry);
1388         map<string, string> const & packages = auto_packages();
1389         for (auto const & pack : packages)
1390                 os << "\n\\use_package " << pack.first << ' '
1391                    << use_package(pack.first);
1392
1393         os << "\n\\cite_engine ";
1394
1395         if (!cite_engine_.empty())
1396                 os << cite_engine_;
1397         else
1398                 os << "basic";
1399
1400         os << "\n\\cite_engine_type " << theCiteEnginesList.getTypeAsString(cite_engine_type_);
1401
1402         if (!biblio_style.empty())
1403                 os << "\n\\biblio_style " << biblio_style;
1404         if (!biblio_opts.empty())
1405                 os << "\n\\biblio_options " << biblio_opts;
1406         if (!biblatex_bibstyle.empty())
1407                 os << "\n\\biblatex_bibstyle " << biblatex_bibstyle;
1408         if (!biblatex_citestyle.empty())
1409                 os << "\n\\biblatex_citestyle " << biblatex_citestyle;
1410         if (!multibib.empty())
1411                 os << "\n\\multibib " << multibib;
1412
1413         os << "\n\\use_bibtopic " << convert<string>(use_bibtopic)
1414            << "\n\\use_indices " << convert<string>(use_indices)
1415            << "\n\\paperorientation " << string_orientation[orientation]
1416            << "\n\\suppress_date " << convert<string>(suppress_date)
1417            << "\n\\justification " << convert<string>(justification)
1418            << "\n\\use_refstyle " << use_refstyle
1419            << "\n\\use_minted " << use_minted
1420            << "\n\\use_lineno " << use_lineno
1421            << '\n';
1422
1423         if (!lineno_opts.empty())
1424                 os << "\\lineno_options " << lineno_opts << '\n';
1425
1426         if (isbackgroundcolor)
1427                 os << "\\backgroundcolor " << lyx::X11hexname(backgroundcolor) << '\n';
1428         if (isfontcolor)
1429                 os << "\\fontcolor " << lyx::X11hexname(fontcolor) << '\n';
1430         if (isnotefontcolor)
1431                 os << "\\notefontcolor " << lyx::X11hexname(notefontcolor) << '\n';
1432         if (isboxbgcolor)
1433                 os << "\\boxbgcolor " << lyx::X11hexname(boxbgcolor) << '\n';
1434
1435         for (auto const & br : branchlist()) {
1436                 os << "\\branch " << to_utf8(br.branch())
1437                    << "\n\\selected " << br.isSelected()
1438                    << "\n\\filename_suffix " << br.hasFileNameSuffix()
1439                    << "\n\\color " << br.lightModeColor() << " " << br.darkModeColor()
1440                    << "\n\\end_branch"
1441                    << "\n";
1442         }
1443
1444         for (auto const & id : indiceslist()) {
1445                 os << "\\index " << to_utf8(id.index())
1446                    << "\n\\shortcut " << to_utf8(id.shortcut())
1447                    << "\n\\color " << lyx::X11hexname(id.color())
1448                    << "\n\\end_index"
1449                    << "\n";
1450         }
1451
1452         for (auto const & si : spellignore()) {
1453                 os << "\\spellchecker_ignore " << si.lang()->lang()
1454                    << " " << to_utf8(si.word())
1455                    << "\n";
1456         }
1457
1458         if (!paperwidth.empty())
1459                 os << "\\paperwidth "
1460                    << VSpace(paperwidth).asLyXCommand() << '\n';
1461         if (!paperheight.empty())
1462                 os << "\\paperheight "
1463                    << VSpace(paperheight).asLyXCommand() << '\n';
1464         if (!leftmargin.empty())
1465                 os << "\\leftmargin "
1466                    << VSpace(leftmargin).asLyXCommand() << '\n';
1467         if (!topmargin.empty())
1468                 os << "\\topmargin "
1469                    << VSpace(topmargin).asLyXCommand() << '\n';
1470         if (!rightmargin.empty())
1471                 os << "\\rightmargin "
1472                    << VSpace(rightmargin).asLyXCommand() << '\n';
1473         if (!bottommargin.empty())
1474                 os << "\\bottommargin "
1475                    << VSpace(bottommargin).asLyXCommand() << '\n';
1476         if (!headheight.empty())
1477                 os << "\\headheight "
1478                    << VSpace(headheight).asLyXCommand() << '\n';
1479         if (!headsep.empty())
1480                 os << "\\headsep "
1481                    << VSpace(headsep).asLyXCommand() << '\n';
1482         if (!footskip.empty())
1483                 os << "\\footskip "
1484                    << VSpace(footskip).asLyXCommand() << '\n';
1485         if (!columnsep.empty())
1486                 os << "\\columnsep "
1487                          << VSpace(columnsep).asLyXCommand() << '\n';
1488         os << "\\secnumdepth " << secnumdepth
1489            << "\n\\tocdepth " << tocdepth
1490            << "\n\\paragraph_separation "
1491            << string_paragraph_separation[paragraph_separation];
1492         if (!paragraph_separation)
1493                 os << "\n\\paragraph_indentation "
1494                    << (getParIndent().empty() ? "default" : getParIndent().asString());
1495         else
1496                 os << "\n\\defskip " << getDefSkip().asLyXCommand();
1497         os << "\n\\is_math_indent " << is_math_indent;
1498         if (is_math_indent)
1499                 os << "\n\\math_indentation "
1500                    << (getMathIndent().empty() ? "default" : getMathIndent().asString());
1501         os << "\n\\math_numbering_side ";
1502         switch(math_numbering_side) {
1503         case LEFT:
1504                 os << "left";
1505                 break;
1506         case RIGHT:
1507                 os << "right";
1508                 break;
1509         case DEFAULT:
1510                 os << "default";
1511         }
1512         os << "\n\\quotes_style "
1513            << string_quotes_style[static_cast<int>(quotes_style)]
1514            << "\n\\dynamic_quotes " << dynamic_quotes
1515            << "\n\\papercolumns " << columns
1516            << "\n\\papersides " << sides
1517            << "\n\\paperpagestyle " << pagestyle
1518            << "\n\\tablestyle " << tablestyle << '\n';
1519         if (!listings_params.empty())
1520                 os << "\\listings_params \"" <<
1521                         InsetListingsParams(listings_params).encodedString() << "\"\n";
1522         for (int i = 0; i < 4; ++i) {
1523                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1524                         if (user_defined_bullet(i).getFont() != -1) {
1525                                 os << "\\bullet " << i << " "
1526                                    << user_defined_bullet(i).getFont() << " "
1527                                    << user_defined_bullet(i).getCharacter() << " "
1528                                    << user_defined_bullet(i).getSize() << "\n";
1529                         }
1530                         else {
1531                                 // FIXME UNICODE
1532                                 os << "\\bulletLaTeX " << i << " \""
1533                                    << lyx::to_ascii(user_defined_bullet(i).getText())
1534                                    << "\"\n";
1535                         }
1536                 }
1537         }
1538
1539         os << "\\tracking_changes "
1540            << (save_transient_properties ? convert<string>(track_changes) : "false")
1541            << '\n';
1542
1543         os << "\\output_changes "
1544            << (save_transient_properties ? convert<string>(output_changes) : "false")
1545            << '\n';
1546
1547         os << "\\change_bars "
1548            << (save_transient_properties ? convert<string>(change_bars) : "false")
1549            << '\n';
1550
1551         os << "\\postpone_fragile_content " << convert<string>(postpone_fragile_content) << '\n';
1552
1553         os << "\\html_math_output " << html_math_output << '\n'
1554            << "\\html_css_as_file " << html_css_as_file << '\n'
1555            << "\\html_be_strict " << convert<string>(html_be_strict) << '\n';
1556
1557         os << "\\docbook_table_output " << docbook_table_output << '\n';
1558
1559         if (html_math_img_scale != 1.0)
1560                 os << "\\html_math_img_scale " << convert<string>(html_math_img_scale) << '\n';
1561         if (!html_latex_start.empty())
1562                 os << "\\html_latex_start " << html_latex_start << '\n';
1563         if (!html_latex_end.empty())
1564                  os << "\\html_latex_end " << html_latex_end << '\n';
1565
1566         os << pimpl_->authorlist;
1567 }
1568
1569
1570 void BufferParams::validate(LaTeXFeatures & features) const
1571 {
1572         features.require(documentClass().required());
1573
1574         if (columns > 1 && language->rightToLeft())
1575                 features.require("rtloutputdblcol");
1576
1577         if (output_changes) {
1578                 bool xcolorulem = LaTeXFeatures::isAvailable("ulem") &&
1579                                   LaTeXFeatures::isAvailable("xcolor");
1580
1581                 switch (features.runparams().flavor) {
1582                 case Flavor::LaTeX:
1583                 case Flavor::DviLuaTeX:
1584                         if (xcolorulem) {
1585                                 features.require("ct-xcolor-ulem");
1586                                 features.require("ulem");
1587                                 features.require("xcolor");
1588                         } else {
1589                                 features.require("ct-none");
1590                         }
1591                         break;
1592                 case Flavor::LuaTeX:
1593                 case Flavor::PdfLaTeX:
1594                 case Flavor::XeTeX:
1595                         if (xcolorulem) {
1596                                 features.require("ct-xcolor-ulem");
1597                                 features.require("ulem");
1598                                 features.require("xcolor");
1599                                 // improves color handling in PDF output
1600                                 features.require("pdfcolmk");
1601                         } else {
1602                                 features.require("ct-none");
1603                         }
1604                         break;
1605                 default:
1606                         break;
1607                 }
1608                 if (change_bars)
1609                         features.require("changebar");
1610         }
1611
1612         // Floats with 'Here definitely' as default setting.
1613         if (float_placement.find('H') != string::npos)
1614                 features.require("float");
1615
1616         for (auto const & pm : use_packages) {
1617                 if (pm.first == "amsmath") {
1618                         // AMS Style is at document level
1619                         if (pm.second == package_on ||
1620                             features.isProvided("amsmath"))
1621                                 features.require(pm.first);
1622                 } else if (pm.second == package_on)
1623                         features.require(pm.first);
1624         }
1625
1626         // Document-level line spacing
1627         if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
1628                 features.require("setspace");
1629
1630         // the bullet shapes are buffer level not paragraph level
1631         // so they are tested here
1632         for (int i = 0; i < 4; ++i) {
1633                 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i])
1634                         continue;
1635                 int const font = user_defined_bullet(i).getFont();
1636                 if (font == 0) {
1637                         int const c = user_defined_bullet(i).getCharacter();
1638                         if (c == 16
1639                             || c == 17
1640                             || c == 25
1641                             || c == 26
1642                             || c == 31) {
1643                                 features.require("latexsym");
1644                         }
1645                 } else if (font == 1) {
1646                         features.require("amssymb");
1647                 } else if (font >= 2 && font <= 5) {
1648                         features.require("pifont");
1649                 }
1650         }
1651
1652         if (pdfoptions().use_hyperref) {
1653                 features.require("hyperref");
1654                 // due to interferences with babel and hyperref, the color package has to
1655                 // be loaded after hyperref when hyperref is used with the colorlinks
1656                 // option, see http://www.lyx.org/trac/ticket/5291
1657                 if (pdfoptions().colorlinks)
1658                         features.require("color");
1659         }
1660         if (!listings_params.empty()) {
1661                 // do not test validity because listings_params is
1662                 // supposed to be valid
1663                 string par =
1664                         InsetListingsParams(listings_params).separatedParams(true);
1665                 // we can't support all packages, but we should load the color package
1666                 if (par.find("\\color", 0) != string::npos)
1667                         features.require("color");
1668         }
1669
1670         // some languages are only available via polyglossia
1671         if (features.hasPolyglossiaExclusiveLanguages())
1672                 features.require("polyglossia");
1673
1674         if (useNonTeXFonts && fontsMath() != "auto")
1675                 features.require("unicode-math");
1676
1677         if (use_microtype)
1678                 features.require("microtype");
1679
1680         if (!language->required().empty())
1681                 features.require(language->required());
1682 }
1683
1684
1685 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1686                               FileName const & filepath) const
1687 {
1688         // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1689         // !! To use the Fix-cm package, load it before \documentclass, and use the command
1690         // \RequirePackage to do so, rather than the normal \usepackage
1691         // Do not try to load any other package before the document class, unless you
1692         // have a thorough understanding of the LATEX internals and know exactly what you
1693         // are doing!
1694         if (features.mustProvide("fix-cm"))
1695                 os << "\\RequirePackage{fix-cm}\n";
1696         // Likewise for fixltx2e. If other packages conflict with this policy,
1697         // treat it as a package bug (and report it!)
1698         // See http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/4407
1699         if (features.mustProvide("fixltx2e"))
1700                 os << "\\RequirePackage{fixltx2e}\n";
1701
1702         os << "\\documentclass";
1703
1704         DocumentClass const & tclass = documentClass();
1705
1706         ostringstream clsoptions; // the document class options.
1707
1708         if (tokenPos(tclass.opt_fontsize(),
1709                      '|', fontsize) >= 0) {
1710                 // only write if existing in list (and not default)
1711                 clsoptions << subst(tclass.fontsizeformat(), "$$s", fontsize) << ",";
1712         }
1713
1714         // paper sizes not supported by the class itself need the
1715         // geometry package
1716         vector<string> classpsizes = getVectorFromString(tclass.opt_pagesize(), "|");
1717         bool class_supported_papersize = papersize == PAPER_DEFAULT
1718                 || find(classpsizes.begin(), classpsizes.end(), string_papersize[papersize]) != classpsizes.end();
1719
1720         if ((!use_geometry || features.isProvided("geometry-light"))
1721             && class_supported_papersize && papersize != PAPER_DEFAULT)
1722                 clsoptions << subst(tclass.pagesizeformat(), "$$s", string_papersize[papersize]) << ",";
1723
1724         // if needed
1725         if (sides != tclass.sides()) {
1726                 switch (sides) {
1727                 case OneSide:
1728                         clsoptions << "oneside,";
1729                         break;
1730                 case TwoSides:
1731                         clsoptions << "twoside,";
1732                         break;
1733                 }
1734         }
1735
1736         // if needed
1737         if (columns != tclass.columns()) {
1738                 if (columns == 2)
1739                         clsoptions << "twocolumn,";
1740                 else
1741                         clsoptions << "onecolumn,";
1742         }
1743
1744         if (!use_geometry
1745             && orientation == ORIENTATION_LANDSCAPE)
1746                 clsoptions << "landscape,";
1747
1748         if (is_math_indent)
1749                 clsoptions << "fleqn,";
1750
1751         switch(math_numbering_side) {
1752         case LEFT:
1753                 clsoptions << "leqno,";
1754                 break;
1755         case RIGHT:
1756                 clsoptions << "reqno,";
1757                 features.require("amsmath");
1758                 break;
1759         case DEFAULT:
1760                 break;
1761         }
1762
1763         // language should be a parameter to \documentclass
1764         if (language->babel() == "hebrew"
1765             && default_language->babel() != "hebrew")
1766                 // This seems necessary
1767                 features.useLanguage(default_language);
1768
1769         ostringstream language_options;
1770         bool const use_babel = features.useBabel() && !features.isProvided("babel");
1771         bool const use_polyglossia = features.usePolyglossia();
1772         bool const global = lyxrc.language_global_options;
1773         if (features.useBabel() || (use_polyglossia && global)) {
1774                 language_options << features.getBabelLanguages();
1775                 if (!language->babel().empty()) {
1776                         if (!language_options.str().empty())
1777                                 language_options << ',';
1778                         language_options << language->babel();
1779                 }
1780                 if (global && !language_options.str().empty())
1781                         clsoptions << language_options.str() << ',';
1782         }
1783
1784         // the predefined options from the layout
1785         if (use_default_options && !tclass.options().empty())
1786                 clsoptions << tclass.options() << ',';
1787
1788         // the user-defined options
1789         if (!options.empty()) {
1790                 clsoptions << options << ',';
1791         }
1792         
1793         docstring const strOptions = from_utf8(clsoptions.str());
1794         if (!strOptions.empty()) {
1795                 // Check if class options contain uncodable glyphs
1796                 docstring uncodable_glyphs;
1797                 docstring options_encodable;
1798                 Encoding const * const enc = features.runparams().encoding;
1799                 if (enc) {
1800                         for (char_type c : strOptions) {
1801                                 if (!enc->encodable(c)) {
1802                                         docstring const glyph(1, c);
1803                                         LYXERR0("Uncodable character '"
1804                                                 << glyph
1805                                                 << "' in class options!");
1806                                         uncodable_glyphs += glyph;
1807                                         if (features.runparams().dryrun) {
1808                                                 options_encodable += "<" + _("LyX Warning: ")
1809                                                    + _("uncodable character") + " '";
1810                                                 options_encodable += c;
1811                                                 options_encodable += "'>";
1812                                         }
1813                                 } else
1814                                         options_encodable += c;
1815                         }
1816                 } else
1817                         options_encodable = strOptions;
1818         
1819                 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
1820                 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
1821                         frontend::Alert::warning(
1822                                 _("Uncodable character in class options"),
1823                                 support::bformat(
1824                                   _("The class options of your document contain glyphs "
1825                                     "that are unknown in the current document encoding "
1826                                     "(namely %1$s).\nThese glyphs are omitted "
1827                                     " from the output, which may result in "
1828                                     "incomplete output."
1829                                     "\n\nPlease select an appropriate "
1830                                     "document encoding\n"
1831                                     "(such as utf8) or change the "
1832                                     "class options accordingly."),
1833                                   uncodable_glyphs));
1834                 }
1835                 options_encodable = rtrim(options_encodable, ",");
1836                 os << '[' << options_encodable << ']';
1837         }
1838
1839         os << '{' << from_ascii(tclass.latexname()) << "}\n";
1840         // end of \documentclass defs
1841
1842         // The package options (via \PassOptionsToPackage)
1843         os << from_ascii(features.getPackageOptions());
1844
1845         // if we use fontspec or newtxmath, we have to load the AMS packages here
1846         string const ams = features.loadAMSPackages();
1847         bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
1848         bool const use_newtxmath =
1849                 theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getUsedPackage(
1850                         ot1, false, false) == "newtxmath";
1851         if ((useNonTeXFonts || use_newtxmath) && !ams.empty())
1852                 os << from_ascii(ams);
1853
1854         if (useNonTeXFonts) {
1855                 // Babel (as of 2017/11/03) loads fontspec itself
1856                 if (!features.isProvided("fontspec")
1857                     && !(features.useBabel() && features.isAvailable("babel-2017/11/03")))
1858                         os << "\\usepackage{fontspec}\n";
1859                 if (features.mustProvide("unicode-math")
1860                     && features.isAvailable("unicode-math"))
1861                         os << "\\usepackage{unicode-math}\n";
1862         }
1863
1864         // load CJK support package before font selection
1865         // (see autotests/export/latex/CJK/micro-sign_utf8-cjk-libertine.lyx)
1866         if (!useNonTeXFonts && encoding().package() != Encoding::none && inputenc != "utf8x"
1867                 && (encoding().package() == Encoding::CJK || features.mustProvide("CJK"))) {
1868                 if (inputenc == "utf8-cjk" || inputenc == "utf8")
1869                         os << "\\usepackage{CJKutf8}\n";
1870                 else
1871                         os << "\\usepackage[encapsulated]{CJK}\n";
1872         }
1873
1874         // font selection must be done before loading fontenc.sty
1875         // but after babel with non-TeX fonts
1876         string const fonts = loadFonts(features);
1877         if (!fonts.empty() && (!features.useBabel() || !useNonTeXFonts))
1878                 os << from_utf8(fonts);
1879
1880         if (fonts_default_family != "default")
1881                 os << "\\renewcommand{\\familydefault}{\\"
1882                    << from_ascii(fonts_default_family) << "}\n";
1883
1884         // set font encoding
1885         // non-TeX fonts use font encoding TU (set by fontspec)
1886         if (!useNonTeXFonts && !features.isProvided("fontenc")
1887             && main_font_encoding() != "default") {
1888                 // get main font encodings
1889                 vector<string> fontencs = font_encodings();
1890                 // get font encodings of secondary languages
1891                 // FIXME: some languages (hebrew, ...) assume a standard font encoding as last
1892                 // option (for text in other languages).
1893                 features.getFontEncodings(fontencs);
1894                 if (!fontencs.empty()) {
1895                         os << "\\usepackage["
1896                            << from_ascii(getStringFromVector(fontencs))
1897                            << "]{fontenc}\n";
1898                 }
1899         }
1900
1901         // Load textcomp and pmboxdraw before (lua)inputenc (#11454)
1902         if (features.mustProvide("textcomp"))
1903                 os << "\\usepackage{textcomp}\n";
1904         if (features.mustProvide("pmboxdraw"))
1905                 os << "\\usepackage{pmboxdraw}\n";
1906         
1907         // handle inputenc etc.
1908         // (In documents containing text in Thai language, 
1909         // we must load inputenc after babel, see lib/languages).
1910         if (!contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
1911                 writeEncodingPreamble(os, features);
1912
1913         // includeonly
1914         if (!features.runparams().includeall && !included_children_.empty()) {
1915                 os << "\\includeonly{";
1916                 bool first = true;
1917                 for (auto incfile : included_children_) {
1918                         FileName inc = makeAbsPath(incfile, filepath.absFileName());
1919                         string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1920                                         mangledFileName();
1921                         if (!features.runparams().nice)
1922                                 incfile = mangled;
1923                         // \includeonly doesn't want an extension
1924                         incfile = changeExtension(incfile, string());
1925                         incfile = support::latex_path(incfile);
1926                         if (!incfile.empty()) {
1927                                 if (!first)
1928                                         os << ",";
1929                                 os << from_utf8(incfile);
1930                         }
1931                         first = false;
1932                 }
1933                 os << "}\n";
1934         }
1935
1936         if (!features.isProvided("geometry")
1937             && (use_geometry || !class_supported_papersize)) {
1938                 odocstringstream ods;
1939                 if (!getGraphicsDriver("geometry").empty())
1940                         ods << getGraphicsDriver("geometry");
1941                 if (orientation == ORIENTATION_LANDSCAPE)
1942                         ods << ",landscape";
1943                 switch (papersize) {
1944                 case PAPER_CUSTOM:
1945                         if (!paperwidth.empty())
1946                                 ods << ",paperwidth="
1947                                    << from_ascii(paperwidth);
1948                         if (!paperheight.empty())
1949                                 ods << ",paperheight="
1950                                    << from_ascii(paperheight);
1951                         break;
1952                 case PAPER_USLETTER:
1953                 case PAPER_USLEGAL:
1954                 case PAPER_USEXECUTIVE:
1955                 case PAPER_A0:
1956                 case PAPER_A1:
1957                 case PAPER_A2:
1958                 case PAPER_A3:
1959                 case PAPER_A4:
1960                 case PAPER_A5:
1961                 case PAPER_A6:
1962                 case PAPER_B0:
1963                 case PAPER_B1:
1964                 case PAPER_B2:
1965                 case PAPER_B3:
1966                 case PAPER_B4:
1967                 case PAPER_B5:
1968                 case PAPER_B6:
1969                 case PAPER_C0:
1970                 case PAPER_C1:
1971                 case PAPER_C2:
1972                 case PAPER_C3:
1973                 case PAPER_C4:
1974                 case PAPER_C5:
1975                 case PAPER_C6:
1976                 case PAPER_JISB0:
1977                 case PAPER_JISB1:
1978                 case PAPER_JISB2:
1979                 case PAPER_JISB3:
1980                 case PAPER_JISB4:
1981                 case PAPER_JISB5:
1982                 case PAPER_JISB6:
1983                         ods << "," << from_ascii(string_papersize_geometry[papersize]);
1984                         break;
1985                 case PAPER_DEFAULT:
1986                         break;
1987                 }
1988                 docstring g_options = trim(ods.str(), ",");
1989                 os << "\\usepackage";
1990                 // geometry-light means that the class works with geometry, but overwrites
1991                 // the package options and paper sizes (memoir does this).
1992                 // In this case, all options need to go to \geometry
1993                 // and the standard paper sizes need to go to the class options.
1994                 if (!g_options.empty() && !features.isProvided("geometry-light")) {
1995                         os << '[' << g_options << ']';
1996                         g_options.clear();
1997                 }
1998                 os << "{geometry}\n";
1999                 if (use_geometry || features.isProvided("geometry-light")) {
2000                         os << "\\geometry{verbose";
2001                         if (!g_options.empty())
2002                                 // Output general options here with "geometry light".
2003                                 os << "," << g_options;
2004                         // output this only if use_geometry is true
2005                         if (use_geometry) {
2006                                 if (!topmargin.empty())
2007                                         os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
2008                                 if (!bottommargin.empty())
2009                                         os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
2010                                 if (!leftmargin.empty())
2011                                         os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
2012                                 if (!rightmargin.empty())
2013                                         os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
2014                                 if (!headheight.empty())
2015                                         os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
2016                                 if (!headsep.empty())
2017                                         os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
2018                                 if (!footskip.empty())
2019                                         os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
2020                                 if (!columnsep.empty())
2021                                         os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
2022                         }
2023                 os << "}\n";
2024                 }
2025         } else if (orientation == ORIENTATION_LANDSCAPE
2026                    || papersize != PAPER_DEFAULT) {
2027                 features.require("papersize");
2028         }
2029
2030         if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
2031                 if (pagestyle == "fancy")
2032                         os << "\\usepackage{fancyhdr}\n";
2033                 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
2034         }
2035
2036         // only output when the background color is not default
2037         if (isbackgroundcolor) {
2038                 // only require color here, the background color will be defined
2039                 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2040                 // package pdfpages
2041                 features.require("color");
2042                 features.require("pagecolor");
2043         }
2044
2045         // only output when the font color is not default
2046         if (isfontcolor) {
2047                 // only require color here, the font color will be defined
2048                 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
2049                 // package pdfpages
2050                 features.require("color");
2051                 features.require("fontcolor");
2052         }
2053
2054         // Only if class has a ToC hierarchy
2055         if (tclass.hasTocLevels()) {
2056                 if (secnumdepth != tclass.secnumdepth()) {
2057                         os << "\\setcounter{secnumdepth}{"
2058                            << secnumdepth
2059                            << "}\n";
2060                 }
2061                 if (tocdepth != tclass.tocdepth()) {
2062                         os << "\\setcounter{tocdepth}{"
2063                            << tocdepth
2064                            << "}\n";
2065                 }
2066         }
2067
2068         if (paragraph_separation) {
2069                 // when skip separation
2070                 string psopt;
2071                 switch (getDefSkip().kind()) {
2072                 case VSpace::SMALLSKIP:
2073                         psopt = "\\smallskipamount";
2074                         break;
2075                 case VSpace::MEDSKIP:
2076                         psopt = "\\medskipamount";
2077                         break;
2078                 case VSpace::BIGSKIP:
2079                         psopt = "\\bigskipamount";
2080                         break;
2081                 case VSpace::HALFLINE:
2082                         // default (no option)
2083                         break;
2084                 case VSpace::FULLLINE:
2085                         psopt = "\\baselineskip";
2086                         break;
2087                 case VSpace::LENGTH:
2088                         psopt = getDefSkip().length().asLatexString();
2089                         break;
2090                 default:
2091                         break;
2092                 }
2093                 if (!features.isProvided("parskip")) {
2094                         if (!psopt.empty())
2095                                 psopt = "[skip=" + psopt + "]";
2096                         os << "\\usepackage" + psopt + "{parskip}\n";
2097                 } else {
2098                         os << "\\setlength{\\parskip}{" + psopt + "}\n";
2099                 }
2100         } else {
2101                 // when separation by indentation
2102                 // only output something when a width is given
2103                 if (!getParIndent().empty()) {
2104                         os << "\\setlength{\\parindent}{"
2105                            << from_utf8(getParIndent().asLatexString())
2106                            << "}\n";
2107                 }
2108         }
2109
2110         if (is_math_indent) {
2111                 // when formula indentation
2112                 // only output something when it is not the default
2113                 if (!getMathIndent().empty()) {
2114                         os << "\\setlength{\\mathindent}{"
2115                            << from_utf8(getMathIndent().asString())
2116                            << "}\n";
2117                 }
2118         }
2119
2120         // Now insert the LyX specific LaTeX commands...
2121         features.resolveAlternatives();
2122         features.expandMultiples();
2123
2124         if (output_sync) {
2125                 if (!output_sync_macro.empty())
2126                         os << from_utf8(output_sync_macro) +"\n";
2127                 else if (features.runparams().flavor == Flavor::LaTeX)
2128                         os << "\\usepackage[active]{srcltx}\n";
2129                 else if (features.runparams().flavor == Flavor::PdfLaTeX)
2130                         os << "\\synctex=-1\n";
2131         }
2132
2133         // due to interferences with babel and hyperref, the color package has to
2134         // be loaded (when it is not already loaded) before babel when hyperref
2135         // is used with the colorlinks option, see
2136         // http://www.lyx.org/trac/ticket/5291
2137         // we decided therefore to load color always before babel, see
2138         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
2139         os << from_ascii(features.getColorOptions());
2140
2141         // If we use hyperref, jurabib, japanese or varioref,
2142         // we have to call babel before
2143         if (use_babel
2144             && (features.isRequired("jurabib")
2145                 || features.isRequired("hyperref")
2146                 || features.isRequired("varioref")
2147                 || features.isRequired("japanese"))) {
2148                         os << features.getBabelPresettings();
2149                         // FIXME UNICODE
2150                         os << from_utf8(babelCall(language_options.str(),
2151                                                                           !lyxrc.language_global_options)) + '\n';
2152                         os << features.getBabelPostsettings();
2153         }
2154
2155         // The optional packages;
2156         os << from_ascii(features.getPackages());
2157
2158         // Additional Indices
2159         if (features.isRequired("splitidx")) {
2160                 for (auto const & idx : indiceslist()) {
2161                         os << "\\newindex{";
2162                         os << escape(idx.shortcut());
2163                         os << "}\n";
2164                 }
2165         }
2166
2167         // Line spacing
2168         os << from_utf8(spacing().writePreamble(features.isProvided("SetSpace")));
2169
2170         // PDF support.
2171         // * Hyperref manual: "Make sure it comes last of your loaded
2172         //   packages, to give it a fighting chance of not being over-written,
2173         //   since its job is to redefine many LaTeX commands."
2174         // * Email from Heiko Oberdiek: "It is usually better to load babel
2175         //   before hyperref. Then hyperref has a chance to detect babel.
2176         // * Has to be loaded before the "LyX specific LaTeX commands" to
2177         //   avoid errors with algorithm floats.
2178         // use hyperref explicitly if it is required
2179         if (features.isRequired("hyperref")) {
2180                 OutputParams tmp_params = features.runparams();
2181                 pdfoptions().writeLaTeX(tmp_params, os,
2182                                         features.isProvided("hyperref"));
2183                 // correctly break URLs with hyperref and dvi/ps output
2184                 if (features.runparams().hyperref_driver == "dvips"
2185                     && features.isAvailable("breakurl"))
2186                         os << "\\usepackage{breakurl}\n";
2187         } else if (features.isRequired("nameref"))
2188                 // hyperref loads this automatically
2189                 os << "\\usepackage{nameref}\n";
2190
2191         if (use_lineno){
2192                 os << "\\usepackage";
2193                 if (!lineno_opts.empty())
2194                         os << "[" << lineno_opts << "]";
2195                 os << "{lineno}\n";
2196                 os << "\\linenumbers\n";
2197         }
2198
2199         // bibtopic needs to be loaded after hyperref.
2200         // the dot provides the aux file naming which LyX can detect.
2201         if (features.mustProvide("bibtopic"))
2202                 os << "\\usepackage[dot]{bibtopic}\n";
2203
2204         // Will be surrounded by \makeatletter and \makeatother when not empty
2205         otexstringstream atlyxpreamble;
2206
2207         // Some macros LyX will need
2208         {
2209                 TexString tmppreamble = features.getMacros();
2210                 if (!tmppreamble.str.empty())
2211                         atlyxpreamble << "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2212                                          "LyX specific LaTeX commands.\n"
2213                                       << move(tmppreamble)
2214                                       << '\n';
2215         }
2216         // the text class specific preamble
2217         {
2218                 docstring tmppreamble = features.getTClassPreamble();
2219                 if (!tmppreamble.empty())
2220                         atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2221                                          "Textclass specific LaTeX commands.\n"
2222                                       << tmppreamble
2223                                       << '\n';
2224         }
2225         // suppress date if selected
2226         // use \@ifundefined because we cannot be sure that every document class
2227         // has a \date command
2228         if (suppress_date)
2229                 atlyxpreamble << "\\@ifundefined{date}{}{\\date{}}\n";
2230
2231         /* the user-defined preamble */
2232         if (!containsOnly(preamble, " \n\t")) {
2233                 // FIXME UNICODE
2234                 atlyxpreamble << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
2235                                  "User specified LaTeX commands.\n";
2236
2237                 // Check if the user preamble contains uncodable glyphs
2238                 odocstringstream user_preamble;
2239                 docstring uncodable_glyphs;
2240                 Encoding const * const enc = features.runparams().encoding;
2241                 if (enc) {
2242                         for (char_type c : preamble) {
2243                                 if (!enc->encodable(c)) {
2244                                         docstring const glyph(1, c);
2245                                         LYXERR0("Uncodable character '"
2246                                                 << glyph
2247                                                 << "' in user preamble!");
2248                                         uncodable_glyphs += glyph;
2249                                         if (features.runparams().dryrun) {
2250                                                 user_preamble << "<" << _("LyX Warning: ")
2251                                                    << _("uncodable character") << " '";
2252                                                 user_preamble.put(c);
2253                                                 user_preamble << "'>";
2254                                         }
2255                                 } else
2256                                         user_preamble.put(c);
2257                         }
2258                 } else
2259                         user_preamble << preamble;
2260
2261                 // On BUFFER_VIEW|UPDATE, warn user if we found uncodable glyphs
2262                 if (!features.runparams().dryrun && !uncodable_glyphs.empty()) {
2263                         frontend::Alert::warning(
2264                                 _("Uncodable character in user preamble"),
2265                                 support::bformat(
2266                                   _("The user preamble of your document contains glyphs "
2267                                     "that are unknown in the current document encoding "
2268                                     "(namely %1$s).\nThese glyphs are omitted "
2269                                     " from the output, which may result in "
2270                                     "incomplete output."
2271                                     "\n\nPlease select an appropriate "
2272                                     "document encoding\n"
2273                                     "(such as utf8) or change the "
2274                                     "preamble code accordingly."),
2275                                   uncodable_glyphs));
2276                 }
2277                 atlyxpreamble << user_preamble.str() << '\n';
2278         }
2279
2280         // footmisc must be loaded after setspace
2281         // Load it here to avoid clashes with footmisc loaded in the user
2282         // preamble. For that reason we also pass the options via
2283         // \PassOptionsToPackage in getPreamble() and not here.
2284         if (features.mustProvide("footmisc"))
2285                 atlyxpreamble << "\\usepackage{footmisc}\n";
2286
2287         // subfig loads internally the LaTeX package "caption". As
2288         // caption is a very popular package, users will load it in
2289         // the preamble. Therefore we must load subfig behind the
2290         // user-defined preamble and check if the caption package was
2291         // loaded or not. For the case that caption is loaded before
2292         // subfig, there is the subfig option "caption=false". This
2293         // option also works when a koma-script class is used and
2294         // koma's own caption commands are used instead of caption. We
2295         // use \PassOptionsToPackage here because the user could have
2296         // already loaded subfig in the preamble.
2297         if (features.mustProvide("subfig"))
2298                 atlyxpreamble << "\\ifdefined\\showcaptionsetup\n"
2299                                  " % Caption package is used. Advise subfig not to load it again.\n"
2300                                  " \\PassOptionsToPackage{caption=false}{subfig}\n"
2301                                  "\\fi\n"
2302                                  "\\usepackage{subfig}\n";
2303
2304         // Itemize bullet settings need to be last in case the user
2305         // defines their own bullets that use a package included
2306         // in the user-defined preamble -- ARRae
2307         // Actually it has to be done much later than that
2308         // since some packages like frenchb make modifications
2309         // at \begin{document} time -- JMarc
2310         docstring bullets_def;
2311         for (int i = 0; i < 4; ++i) {
2312                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
2313                         if (bullets_def.empty())
2314                                 bullets_def += "\\AtBeginDocument{\n";
2315                         bullets_def += "  \\def\\labelitemi";
2316                         switch (i) {
2317                                 // `i' is one less than the item to modify
2318                         case 0:
2319                                 break;
2320                         case 1:
2321                                 bullets_def += 'i';
2322                                 break;
2323                         case 2:
2324                                 bullets_def += "ii";
2325                                 break;
2326                         case 3:
2327                                 bullets_def += 'v';
2328                                 break;
2329                         }
2330                         bullets_def += '{' +
2331                                 user_defined_bullet(i).getText()
2332                                 + "}\n";
2333                 }
2334         }
2335
2336         if (!bullets_def.empty())
2337                 atlyxpreamble << bullets_def << "}\n\n";
2338
2339         if (!atlyxpreamble.empty())
2340                 os << "\n\\makeatletter\n"
2341                    << atlyxpreamble.release()
2342                    << "\\makeatother\n\n";
2343
2344         // We try to load babel late, in case it interferes with other packages.
2345         // Jurabib, hyperref, varioref, bicaption, menukeys and listings (bug 8995)
2346         // have to be called after babel, though.
2347         if (use_babel && !features.isRequired("jurabib")
2348             && !features.isRequired("hyperref")
2349             && !features.isRequired("varioref")
2350             && !features.isRequired("japanese")) {
2351                 os << features.getBabelPresettings();
2352                 // FIXME UNICODE
2353                 os << from_utf8(babelCall(language_options.str(),
2354                                           !lyxrc.language_global_options)) + '\n';
2355                 os << features.getBabelPostsettings();
2356         }
2357         // In documents containing text in Thai language, 
2358         // we must load inputenc after babel (see lib/languages).
2359         if (contains(features.getBabelPostsettings(), from_ascii("thai.ldf")))
2360                 writeEncodingPreamble(os, features);
2361
2362         // font selection must be done after babel with non-TeX fonts
2363         if (!fonts.empty() && features.useBabel() && useNonTeXFonts)
2364                 os << from_utf8(fonts);
2365
2366         if (features.isRequired("bicaption"))
2367                 os << "\\usepackage{bicaption}\n";
2368         if (!listings_params.empty()
2369             || features.mustProvide("listings")
2370             || features.mustProvide("minted")) {
2371                 if (use_minted)
2372                         os << "\\usepackage{minted}\n";
2373                 else
2374                         os << "\\usepackage{listings}\n";
2375         }
2376         string lst_params = listings_params;
2377         // If minted, do not output the language option (bug 11203)
2378         if (use_minted && contains(lst_params, "language=")) {
2379                 vector<string> opts =
2380                         getVectorFromString(lst_params, ",", false);
2381                 for (size_t i = 0; i < opts.size(); ++i) {
2382                         if (prefixIs(opts[i], "language="))
2383                                 opts.erase(opts.begin() + i--);
2384                 }
2385                 lst_params = getStringFromVector(opts, ",");
2386         }
2387         if (!lst_params.empty()) {
2388                 if (use_minted)
2389                         os << "\\setminted{";
2390                 else
2391                         os << "\\lstset{";
2392                 // do not test validity because listings_params is
2393                 // supposed to be valid
2394                 string par =
2395                         InsetListingsParams(lst_params).separatedParams(true);
2396                 os << from_utf8(par);
2397                 os << "}\n";
2398         }
2399
2400         // xunicode only needs to be loaded if tipa is used
2401         // (the rest is obsoleted by the new TU encoding).
2402         // It needs to be loaded at least after amsmath, amssymb,
2403         // esint and the other packages that provide special glyphs
2404         if (features.mustProvide("tipa") && useNonTeXFonts
2405             && !features.isProvided("xunicode")) {
2406                 // The `xunicode` package officially only supports XeTeX,
2407                 //  but also works with LuaTeX. We work around its XeTeX test.
2408                 if (features.runparams().flavor != Flavor::XeTeX) {
2409                         os << "% Pretend to xunicode that we are XeTeX\n"
2410                            << "\\def\\XeTeXpicfile{}\n";
2411                 }
2412                 os << "\\usepackage{xunicode}\n";
2413         }
2414
2415         // covington must be loaded after beamerarticle
2416         if (features.isRequired("covington"))
2417             os << "\\usepackage{covington}\n";
2418
2419         // Polyglossia must be loaded last ...
2420         if (use_polyglossia) {
2421                 // call the package
2422                 os << "\\usepackage{polyglossia}\n";
2423                 // set the main language
2424                 os << "\\setdefaultlanguage";
2425                 if (!language->polyglossiaOpts().empty())
2426                         os << "[" << from_ascii(language->polyglossiaOpts()) << "]";
2427                 os << "{" << from_ascii(language->polyglossia()) << "}\n";
2428                 // now setup the other languages
2429                 set<string> const polylangs =
2430                         features.getPolyglossiaLanguages();
2431                 for (auto const & pl : polylangs) {
2432                         // We do not output the options here; they are output in
2433                         // the language switch commands. This is safer if multiple
2434                         // varieties are used.
2435                         if (pl == language->polyglossia())
2436                                 continue;
2437                         os << "\\setotherlanguage";
2438                         os << "{" << from_ascii(pl) << "}\n";
2439                 }
2440         }
2441
2442         // ... but before biblatex (see #7065)
2443         if ((features.mustProvide("biblatex")
2444              || features.isRequired("biblatex-chicago"))
2445             && !features.isProvided("biblatex-chicago")
2446             && !features.isProvided("biblatex-natbib")
2447             && !features.isProvided("natbib-internal")
2448             && !features.isProvided("natbib")
2449             && !features.isProvided("jurabib")) {
2450                 // The biblatex-chicago package has a differing interface
2451                 // it uses a wrapper package and loads styles via fixed options
2452                 bool const chicago = features.isRequired("biblatex-chicago");
2453                 string delim = "";
2454                 string opts;
2455                 os << "\\usepackage";
2456                 if (!biblatex_bibstyle.empty()
2457                     && (biblatex_bibstyle == biblatex_citestyle)
2458                     && !chicago) {
2459                         opts = "style=" + biblatex_bibstyle;
2460                         delim = ",";
2461                 } else if (!chicago) {
2462                         if (!biblatex_bibstyle.empty()) {
2463                                 opts = "bibstyle=" + biblatex_bibstyle;
2464                                 delim = ",";
2465                         }
2466                         if (!biblatex_citestyle.empty()) {
2467                                 opts += delim + "citestyle=" + biblatex_citestyle;
2468                                 delim = ",";
2469                         }
2470                 }
2471                 if (!multibib.empty() && multibib != "child") {
2472                         opts += delim + "refsection=" + multibib;
2473                         delim = ",";
2474                 }
2475                 if (bibtexCommand() == "bibtex8"
2476                     || prefixIs(bibtexCommand(), "bibtex8 ")) {
2477                         opts += delim + "backend=bibtex8";
2478                         delim = ",";
2479                 } else if (bibtexCommand() == "bibtex"
2480                            || prefixIs(bibtexCommand(), "bibtex ")) {
2481                         opts += delim + "backend=bibtex";
2482                         delim = ",";
2483                 }
2484                 if (!bib_encoding.empty() && encodings.fromLyXName(bib_encoding)) {
2485                         opts += delim + "bibencoding="
2486                                 + encodings.fromLyXName(bib_encoding)->latexName();
2487                         delim = ",";
2488                 }
2489                 if (!biblio_opts.empty())
2490                         opts += delim + biblio_opts;
2491                 if (!opts.empty())
2492                         os << "[" << opts << "]";
2493                 if (chicago)
2494                         os << "{biblatex-chicago}\n";
2495                 else
2496                         os << "{biblatex}\n";
2497         }
2498
2499
2500         // Load custom language package here
2501         if (features.langPackage() == LaTeXFeatures::LANG_PACK_CUSTOM) {
2502                 if (lang_package == "default")
2503                         os << from_utf8(lyxrc.language_custom_package);
2504                 else
2505                         os << from_utf8(lang_package);
2506                 os << '\n';
2507         }
2508
2509         // Since menukeys uses catoptions, which does some heavy changes on key-value options,
2510         // it is recommended to load menukeys as the last package (even after hyperref)
2511         if (features.isRequired("menukeys"))
2512                 os << "\\usepackage{menukeys}\n";
2513
2514         docstring const i18npreamble =
2515                 features.getTClassI18nPreamble(use_babel, use_polyglossia,
2516                                                use_minted);
2517         if (!i18npreamble.empty())
2518                 os << i18npreamble + '\n';
2519
2520         return use_babel;
2521 }
2522
2523
2524 void BufferParams::useClassDefaults()
2525 {
2526         DocumentClass const & tclass = documentClass();
2527
2528         sides = tclass.sides();
2529         columns = tclass.columns();
2530         pagestyle = tclass.pagestyle();
2531         tablestyle = tclass.tablestyle();
2532         use_default_options = true;
2533         // Only if class has a ToC hierarchy
2534         if (tclass.hasTocLevels()) {
2535                 secnumdepth = tclass.secnumdepth();
2536                 tocdepth = tclass.tocdepth();
2537         }
2538 }
2539
2540
2541 bool BufferParams::hasClassDefaults() const
2542 {
2543         DocumentClass const & tclass = documentClass();
2544
2545         return sides == tclass.sides()
2546                 && columns == tclass.columns()
2547                 && pagestyle == tclass.pagestyle()
2548                 && tablestyle == tclass.tablestyle()
2549                 && use_default_options
2550                 && secnumdepth == tclass.secnumdepth()
2551                 && tocdepth == tclass.tocdepth();
2552 }
2553
2554
2555 DocumentClass const & BufferParams::documentClass() const
2556 {
2557         return *doc_class_;
2558 }
2559
2560
2561 DocumentClassConstPtr BufferParams::documentClassPtr() const
2562 {
2563         return doc_class_;
2564 }
2565
2566
2567 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
2568 {
2569         // evil, but this function is evil
2570         doc_class_ = const_pointer_cast<DocumentClass>(tc);
2571         invalidateConverterCache();
2572 }
2573
2574
2575 bool BufferParams::setBaseClass(string const & classname, string const & path)
2576 {
2577         LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
2578         LayoutFileList & bcl = LayoutFileList::get();
2579         if (!bcl.haveClass(classname)) {
2580                 docstring s =
2581                         bformat(_("The layout file:\n"
2582                                 "%1$s\n"
2583                                 "could not be found. A default textclass with default\n"
2584                                 "layouts will be used. LyX will not be able to produce\n"
2585                                 "correct output."),
2586                         from_utf8(classname));
2587                 frontend::Alert::error(_("Document class not found"), s);
2588                 bcl.addEmptyClass(classname);
2589         }
2590
2591         bool const success = bcl[classname].load(path);
2592         if (!success) {
2593                 docstring s =
2594                         bformat(_("Due to some error in it, the layout file:\n"
2595                                 "%1$s\n"
2596                                 "could not be loaded. A default textclass with default\n"
2597                                 "layouts will be used. LyX will not be able to produce\n"
2598                                 "correct output."),
2599                         from_utf8(classname));
2600                 frontend::Alert::error(_("Could not load class"), s);
2601                 bcl.addEmptyClass(classname);
2602         }
2603
2604         pimpl_->baseClass_ = classname;
2605         layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2606         return true;
2607 }
2608
2609
2610 LayoutFile const * BufferParams::baseClass() const
2611 {
2612         if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2613                 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2614
2615         return nullptr;
2616 }
2617
2618
2619 LayoutFileIndex const & BufferParams::baseClassID() const
2620 {
2621         return pimpl_->baseClass_;
2622 }
2623
2624
2625 void BufferParams::makeDocumentClass(bool clone, bool internal)
2626 {
2627         if (!baseClass())
2628                 return;
2629
2630         invalidateConverterCache();
2631         LayoutModuleList mods;
2632         for (auto const & mod : layout_modules_)
2633                 mods.push_back(mod);
2634
2635         doc_class_ = getDocumentClass(*baseClass(), mods, cite_engine_, clone, internal);
2636
2637         TextClass::ReturnValues success = TextClass::OK;
2638         if (!forced_local_layout_.empty())
2639                 success = doc_class_->read(to_utf8(forced_local_layout_),
2640                                            TextClass::MODULE);
2641         if (!local_layout_.empty() &&
2642             (success == TextClass::OK || success == TextClass::OK_OLDFORMAT))
2643                 success = doc_class_->read(to_utf8(local_layout_), TextClass::MODULE);
2644         if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2645                 docstring const msg = _("Error reading internal layout information");
2646                 frontend::Alert::warning(_("Read Error"), msg);
2647         }
2648 }
2649
2650
2651 bool BufferParams::layoutModuleCanBeAdded(string const & modName) const
2652 {
2653         return layout_modules_.moduleCanBeAdded(modName, baseClass());
2654 }
2655
2656
2657 docstring BufferParams::getLocalLayout(bool forced) const
2658 {
2659         if (forced)
2660                 return from_utf8(doc_class_->forcedLayouts());
2661         else
2662                 return local_layout_;
2663 }
2664
2665
2666 void BufferParams::setLocalLayout(docstring const & layout, bool forced)
2667 {
2668         if (forced)
2669                 forced_local_layout_ = layout;
2670         else
2671                 local_layout_ = layout;
2672 }
2673
2674
2675 bool BufferParams::addLayoutModule(string const & modName)
2676 {
2677         for (auto const & mod : layout_modules_)
2678                 if (mod == modName)
2679                         return false;
2680         layout_modules_.push_back(modName);
2681         return true;
2682 }
2683
2684
2685 string BufferParams::bufferFormat() const
2686 {
2687         return documentClass().outputFormat();
2688 }
2689
2690
2691 bool BufferParams::isExportable(string const & format, bool need_viewable) const
2692 {
2693         FormatList const & formats = exportableFormats(need_viewable);
2694         for (auto const & fmt : formats) {
2695                 if (fmt->name() == format)
2696                         return true;
2697         }
2698         return false;
2699 }
2700
2701
2702 FormatList const & BufferParams::exportableFormats(bool only_viewable) const
2703 {
2704         FormatList & cached = only_viewable ?
2705                         pimpl_->viewableFormatList : pimpl_->exportableFormatList;
2706         bool & valid = only_viewable ?
2707                         pimpl_->isViewCacheValid : pimpl_->isExportCacheValid;
2708         if (valid)
2709                 return cached;
2710
2711         vector<string> const backs = backends();
2712         set<string> excludes;
2713         if (useNonTeXFonts) {
2714                 excludes.insert("latex");
2715                 excludes.insert("pdflatex");
2716         } else if (inputenc != "ascii" && inputenc != "utf8-plain") {
2717                   // XeTeX with TeX fonts requires input encoding ascii (#10600).
2718                   excludes.insert("xetex");
2719         }
2720
2721         FormatList result =
2722                 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2723         vector<string>::const_iterator it = backs.begin() + 1;
2724         for (; it != backs.end(); ++it) {
2725                 FormatList r = theConverters().getReachable(*it, only_viewable,
2726                                                                                                         false, excludes);
2727                 result.insert(result.end(), r.begin(), r.end());
2728         }
2729         sort(result.begin(), result.end(), Format::formatSorter);
2730         cached = result;
2731         valid = true;
2732         return cached;
2733 }
2734
2735
2736 vector<string> BufferParams::backends() const
2737 {
2738         vector<string> v;
2739         string const buffmt = bufferFormat();
2740
2741         // FIXME: Don't hardcode format names here, but use a flag
2742         if (buffmt == "latex") {
2743                 if (encoding().package() == Encoding::japanese)
2744                         v.push_back("platex");
2745                 else {
2746                         if (!useNonTeXFonts) {
2747                                 v.push_back("pdflatex");
2748                                 v.push_back("latex");
2749                         }
2750                         if (useNonTeXFonts 
2751                                 || inputenc == "ascii" || inputenc == "utf8-plain")
2752                                 v.push_back("xetex");
2753                         v.push_back("luatex");
2754                         v.push_back("dviluatex");
2755                 }
2756         } else {
2757                 string rbuffmt = buffmt;
2758                 // If we use an OutputFormat in Japanese docs,
2759                 // we need special format in order to get the path
2760                 // via pLaTeX (#8823)
2761                 if (documentClass().hasOutputFormat()
2762                     && encoding().package() == Encoding::japanese)
2763                         rbuffmt += "-ja";
2764                 v.push_back(rbuffmt);
2765         }
2766
2767         v.push_back("xhtml");
2768         v.push_back("docbook5");
2769         v.push_back("text");
2770         v.push_back("lyx");
2771         return v;
2772 }
2773
2774
2775 Flavor BufferParams::getOutputFlavor(string const & format) const
2776 {
2777         string const dformat = (format.empty() || format == "default") ?
2778                 getDefaultOutputFormat() : format;
2779         DefaultFlavorCache::const_iterator it =
2780                 default_flavors_.find(dformat);
2781
2782         if (it != default_flavors_.end())
2783                 return it->second;
2784
2785         Flavor result = Flavor::LaTeX;
2786
2787         // FIXME It'd be better not to hardcode this, but to do
2788         //       something with formats.
2789         if (dformat == "xhtml")
2790                 result = Flavor::Html;
2791         else if (dformat == "docbook5")
2792                 result = Flavor::DocBook5;
2793         else if (dformat == "text")
2794                 result = Flavor::Text;
2795         else if (dformat == "lyx")
2796                 result = Flavor::LyX;
2797         else if (dformat == "pdflatex")
2798                 result = Flavor::PdfLaTeX;
2799         else if (dformat == "xetex")
2800                 result = Flavor::XeTeX;
2801         else if (dformat == "luatex")
2802                 result = Flavor::LuaTeX;
2803         else if (dformat == "dviluatex")
2804                 result = Flavor::DviLuaTeX;
2805         else {
2806                 // Try to determine flavor of default output format
2807                 vector<string> backs = backends();
2808                 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2809                         // Get shortest path to format
2810                         Graph::EdgePath path;
2811                         for (auto const & bvar : backs) {
2812                                 Graph::EdgePath p = theConverters().getPath(bvar, dformat);
2813                                 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2814                                         path = p;
2815                                 }
2816                         }
2817                         if (!path.empty())
2818                                 result = theConverters().getFlavor(path);
2819                 }
2820         }
2821         // cache this flavor
2822         default_flavors_[dformat] = result;
2823         return result;
2824 }
2825
2826
2827 string BufferParams::getDefaultOutputFormat() const
2828 {
2829         if (!default_output_format.empty()
2830             && default_output_format != "default")
2831                 return default_output_format;
2832         if (encoding().package() == Encoding::japanese)
2833                 return lyxrc.default_platex_view_format;
2834         if (useNonTeXFonts)
2835                 return lyxrc.default_otf_view_format;
2836         return lyxrc.default_view_format;
2837 }
2838
2839 Font const BufferParams::getFont() const
2840 {
2841         FontInfo f = documentClass().defaultfont();
2842         if (fonts_default_family == "rmdefault")
2843                 f.setFamily(ROMAN_FAMILY);
2844         else if (fonts_default_family == "sfdefault")
2845                 f.setFamily(SANS_FAMILY);
2846         else if (fonts_default_family == "ttdefault")
2847                 f.setFamily(TYPEWRITER_FAMILY);
2848         return Font(f, language);
2849 }
2850
2851
2852 QuoteStyle BufferParams::getQuoteStyle(string const & qs) const
2853 {
2854         return quotesstyletranslator().find(qs);
2855 }
2856
2857
2858 bool BufferParams::isLatex() const
2859 {
2860         return documentClass().outputType() == LATEX;
2861 }
2862
2863
2864 bool BufferParams::isLiterate() const
2865 {
2866         return documentClass().outputType() == LITERATE;
2867 }
2868
2869
2870 void BufferParams::readPreamble(Lexer & lex)
2871 {
2872         if (lex.getString() != "\\begin_preamble")
2873                 lyxerr << "Error (BufferParams::readPreamble):"
2874                         "consistency check failed." << endl;
2875
2876         preamble = lex.getLongString(from_ascii("\\end_preamble"));
2877 }
2878
2879
2880 void BufferParams::readLocalLayout(Lexer & lex, bool forced)
2881 {
2882         string const expected = forced ? "\\begin_forced_local_layout" :
2883                                          "\\begin_local_layout";
2884         if (lex.getString() != expected)
2885                 lyxerr << "Error (BufferParams::readLocalLayout):"
2886                         "consistency check failed." << endl;
2887
2888         if (forced)
2889                 forced_local_layout_ =
2890                         lex.getLongString(from_ascii("\\end_forced_local_layout"));
2891         else
2892                 local_layout_ = lex.getLongString(from_ascii("\\end_local_layout"));
2893 }
2894
2895
2896 bool BufferParams::setLanguage(string const & lang)
2897 {
2898         Language const *new_language = languages.getLanguage(lang);
2899         if (!new_language) {
2900                 // Language lang was not found
2901                 return false;
2902         }
2903         language = new_language;
2904         return true;
2905 }
2906
2907
2908 void BufferParams::readLanguage(Lexer & lex)
2909 {
2910         if (!lex.next()) return;
2911
2912         string const tmptok = lex.getString();
2913
2914         // check if tmptok is part of tex_babel in tex-defs.h
2915         if (!setLanguage(tmptok)) {
2916                 // Language tmptok was not found
2917                 language = default_language;
2918                 lyxerr << "Warning: Setting language `"
2919                        << tmptok << "' to `" << language->lang()
2920                        << "'." << endl;
2921         }
2922 }
2923
2924
2925 void BufferParams::readGraphicsDriver(Lexer & lex)
2926 {
2927         if (!lex.next())
2928                 return;
2929
2930         string const tmptok = lex.getString();
2931         // check if tmptok is part of tex_graphics in tex_defs.h
2932         int n = 0;
2933         while (true) {
2934                 string const test = tex_graphics[n++];
2935
2936                 if (test == tmptok) {
2937                         graphics_driver = tmptok;
2938                         break;
2939                 }
2940                 if (test.empty()) {
2941                         lex.printError(
2942                                 "Warning: graphics driver `$$Token' not recognized!\n"
2943                                 "         Setting graphics driver to `default'.\n");
2944                         graphics_driver = "default";
2945                         break;
2946                 }
2947         }
2948 }
2949
2950
2951 void BufferParams::readBullets(Lexer & lex)
2952 {
2953         if (!lex.next())
2954                 return;
2955
2956         int const index = lex.getInteger();
2957         lex.next();
2958         int temp_int = lex.getInteger();
2959         user_defined_bullet(index).setFont(temp_int);
2960         temp_bullet(index).setFont(temp_int);
2961         lex >> temp_int;
2962         user_defined_bullet(index).setCharacter(temp_int);
2963         temp_bullet(index).setCharacter(temp_int);
2964         lex >> temp_int;
2965         user_defined_bullet(index).setSize(temp_int);
2966         temp_bullet(index).setSize(temp_int);
2967 }
2968
2969
2970 void BufferParams::readBulletsLaTeX(Lexer & lex)
2971 {
2972         // The bullet class should be able to read this.
2973         if (!lex.next())
2974                 return;
2975         int const index = lex.getInteger();
2976         lex.next(true);
2977         docstring const temp_str = lex.getDocString();
2978
2979         user_defined_bullet(index).setText(temp_str);
2980         temp_bullet(index).setText(temp_str);
2981 }
2982
2983
2984 void BufferParams::readModules(Lexer & lex)
2985 {
2986         if (!lex.eatLine()) {
2987                 lyxerr << "Error (BufferParams::readModules):"
2988                                 "Unexpected end of input." << endl;
2989                 return;
2990         }
2991         while (true) {
2992                 string mod = lex.getString();
2993                 if (mod == "\\end_modules")
2994                         break;
2995                 addLayoutModule(mod);
2996                 lex.eatLine();
2997         }
2998 }
2999
3000
3001 void BufferParams::readRemovedModules(Lexer & lex)
3002 {
3003         if (!lex.eatLine()) {
3004                 lyxerr << "Error (BufferParams::readRemovedModules):"
3005                                 "Unexpected end of input." << endl;
3006                 return;
3007         }
3008         while (true) {
3009                 string mod = lex.getString();
3010                 if (mod == "\\end_removed_modules")
3011                         break;
3012                 removed_modules_.push_back(mod);
3013                 lex.eatLine();
3014         }
3015         // now we want to remove any removed modules that were previously
3016         // added. normally, that will be because default modules were added in
3017         // setBaseClass(), which gets called when \textclass is read at the
3018         // start of the read.
3019         for (auto const & rm : removed_modules_) {
3020                 LayoutModuleList::iterator const mit = layout_modules_.begin();
3021                 LayoutModuleList::iterator const men = layout_modules_.end();
3022                 LayoutModuleList::iterator found = find(mit, men, rm);
3023                 if (found == men)
3024                         continue;
3025                 layout_modules_.erase(found);
3026         }
3027 }
3028
3029
3030 void BufferParams::readIncludeonly(Lexer & lex)
3031 {
3032         if (!lex.eatLine()) {
3033                 lyxerr << "Error (BufferParams::readIncludeonly):"
3034                                 "Unexpected end of input." << endl;
3035                 return;
3036         }
3037         while (true) {
3038                 string child = lex.getString();
3039                 if (child == "\\end_includeonly")
3040                         break;
3041                 included_children_.push_back(child);
3042                 lex.eatLine();
3043         }
3044 }
3045
3046
3047 string BufferParams::paperSizeName(PapersizePurpose purpose, string const & psize) const
3048 {
3049         PAPER_SIZE ppsize = psize.empty() ? papersize : papersizetranslator().find(psize);
3050         switch (ppsize) {
3051         case PAPER_DEFAULT:
3052                 if (documentClass().pagesize() == "default")
3053                         // could be anything, so don't guess
3054                         return string();
3055                 return paperSizeName(purpose, documentClass().pagesize());
3056         case PAPER_CUSTOM: {
3057                 if (purpose == XDVI && !paperwidth.empty() &&
3058                     !paperheight.empty()) {
3059                         // heightxwidth<unit>
3060                         string first = paperwidth;
3061                         string second = paperheight;
3062                         if (orientation == ORIENTATION_LANDSCAPE)
3063                                 first.swap(second);
3064                         // cut off unit.
3065                         return first.erase(first.length() - 2)
3066                                 + "x" + second;
3067                 }
3068                 return string();
3069         }
3070         case PAPER_A0:
3071                 // dvips and dvipdfm do not know this
3072                 if (purpose == DVIPS || purpose == DVIPDFM)
3073                         return string();
3074                 return "a0";
3075         case PAPER_A1:
3076                 if (purpose == DVIPS || purpose == DVIPDFM)
3077                         return string();
3078                 return "a1";
3079         case PAPER_A2:
3080                 if (purpose == DVIPS || purpose == DVIPDFM)
3081                         return string();
3082                 return "a2";
3083         case PAPER_A3:
3084                 return "a3";
3085         case PAPER_A4:
3086                 return "a4";
3087         case PAPER_A5:
3088                 return "a5";
3089         case PAPER_A6:
3090                 if (purpose == DVIPS || purpose == DVIPDFM)
3091                         return string();
3092                 return "a6";
3093         case PAPER_B0:
3094                 if (purpose == DVIPS || purpose == DVIPDFM)
3095                         return string();
3096                 return "b0";
3097         case PAPER_B1:
3098                 if (purpose == DVIPS || purpose == DVIPDFM)
3099                         return string();
3100                 return "b1";
3101         case PAPER_B2:
3102                 if (purpose == DVIPS || purpose == DVIPDFM)
3103                         return string();
3104                 return "b2";
3105         case PAPER_B3:
3106                 if (purpose == DVIPS || purpose == DVIPDFM)
3107                         return string();
3108                 return "b3";
3109         case PAPER_B4:
3110                 // dvipdfm does not know this
3111                 if (purpose == DVIPDFM)
3112                         return string();
3113                 return "b4";
3114         case PAPER_B5:
3115                 if (purpose == DVIPDFM)
3116                         return string();
3117                 return "b5";
3118         case PAPER_B6:
3119                 if (purpose == DVIPS || purpose == DVIPDFM)
3120                         return string();
3121                 return "b6";
3122         case PAPER_C0:
3123                 if (purpose == DVIPS || purpose == DVIPDFM)
3124                         return string();
3125                 return "c0";
3126         case PAPER_C1:
3127                 if (purpose == DVIPS || purpose == DVIPDFM)
3128                         return string();
3129                 return "c1";
3130         case PAPER_C2:
3131                 if (purpose == DVIPS || purpose == DVIPDFM)
3132                         return string();
3133                 return "c2";
3134         case PAPER_C3:
3135                 if (purpose == DVIPS || purpose == DVIPDFM)
3136                         return string();
3137                 return "c3";
3138         case PAPER_C4:
3139                 if (purpose == DVIPS || purpose == DVIPDFM)
3140                         return string();
3141                 return "c4";
3142         case PAPER_C5:
3143                 if (purpose == DVIPS || purpose == DVIPDFM)
3144                         return string();
3145                 return "c5";
3146         case PAPER_C6:
3147                 if (purpose == DVIPS || purpose == DVIPDFM)
3148                         return string();
3149                 return "c6";
3150         case PAPER_JISB0:
3151                 if (purpose == DVIPS || purpose == DVIPDFM)
3152                         return string();
3153                 return "jisb0";
3154         case PAPER_JISB1:
3155                 if (purpose == DVIPS || purpose == DVIPDFM)
3156                         return string();
3157                 return "jisb1";
3158         case PAPER_JISB2:
3159                 if (purpose == DVIPS || purpose == DVIPDFM)
3160                         return string();
3161                 return "jisb2";
3162         case PAPER_JISB3:
3163                 if (purpose == DVIPS || purpose == DVIPDFM)
3164                         return string();
3165                 return "jisb3";
3166         case PAPER_JISB4:
3167                 if (purpose == DVIPS || purpose == DVIPDFM)
3168                         return string();
3169                 return "jisb4";
3170         case PAPER_JISB5:
3171                 if (purpose == DVIPS || purpose == DVIPDFM)
3172                         return string();
3173                 return "jisb5";
3174         case PAPER_JISB6:
3175                 if (purpose == DVIPS || purpose == DVIPDFM)
3176                         return string();
3177                 return "jisb6";
3178         case PAPER_USEXECUTIVE:
3179                 // dvipdfm does not know this
3180                 if (purpose == DVIPDFM)
3181                         return string();
3182                 return "foolscap";
3183         case PAPER_USLEGAL:
3184                 return "legal";
3185         case PAPER_USLETTER:
3186         default:
3187                 if (purpose == XDVI)
3188                         return "us";
3189                 return "letter";
3190         }
3191 }
3192
3193
3194 string const BufferParams::dvips_options() const
3195 {
3196         string result;
3197
3198         // If the class loads the geometry package, we do not know which
3199         // paper size is used, since we do not set it (bug 7013).
3200         // Therefore we must not specify any argument here.
3201         // dvips gets the correct paper size via DVI specials in this case
3202         // (if the class uses the geometry package correctly).
3203         if (documentClass().provides("geometry"))
3204                 return result;
3205
3206         if (use_geometry
3207             && papersize == PAPER_CUSTOM
3208             && !lyxrc.print_paper_dimension_flag.empty()
3209             && !paperwidth.empty()
3210             && !paperheight.empty()) {
3211                 // using a custom papersize
3212                 result = lyxrc.print_paper_dimension_flag;
3213                 result += ' ' + paperwidth;
3214                 result += ',' + paperheight;
3215         } else {
3216                 string const paper_option = paperSizeName(DVIPS);
3217                 if (!paper_option.empty() && (paper_option != "letter" ||
3218                     orientation != ORIENTATION_LANDSCAPE)) {
3219                         // dvips won't accept -t letter -t landscape.
3220                         // In all other cases, include the paper size
3221                         // explicitly.
3222                         result = lyxrc.print_paper_flag;
3223                         result += ' ' + paper_option;
3224                 }
3225         }
3226         if (orientation == ORIENTATION_LANDSCAPE &&
3227             papersize != PAPER_CUSTOM)
3228                 result += ' ' + lyxrc.print_landscape_flag;
3229         return result;
3230 }
3231
3232
3233 string const BufferParams::main_font_encoding() const
3234 {
3235         if (font_encodings().empty()) {
3236                 if (ascii_lowercase(language->fontenc(*this)) == "none")
3237                         return "none";
3238                 return "default";
3239         }
3240         return font_encodings().back();
3241 }
3242
3243
3244 vector<string> const BufferParams::font_encodings() const
3245 {
3246         string doc_fontenc = (fontenc == "auto") ? string() : fontenc;
3247
3248         vector<string> fontencs;
3249
3250         // "default" means "no explicit font encoding"
3251         if (doc_fontenc != "default") {
3252                 if (!doc_fontenc.empty())
3253                         // If we have a custom setting, we use only that!
3254                         return getVectorFromString(doc_fontenc);
3255                 if (!language->fontenc(*this).empty()
3256                     && ascii_lowercase(language->fontenc(*this)) != "none") {
3257                         vector<string> fencs = getVectorFromString(language->fontenc(*this));
3258                         for (auto & fe : fencs) {
3259                                 if (find(fontencs.begin(), fontencs.end(), fe) == fontencs.end())
3260                                         fontencs.push_back(fe);
3261                         }
3262                 }
3263         }
3264
3265         return fontencs;
3266 }
3267
3268
3269 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
3270 {
3271         // suppress the babel call if there is no BabelName defined
3272         // for the document language in the lib/languages file and if no
3273         // other languages are used (lang_opts is then empty)
3274         if (lang_opts.empty())
3275                 return string();
3276         // The prefs may require the languages to
3277         // be submitted to babel itself (not the class).
3278         if (langoptions)
3279                 return "\\usepackage[" + lang_opts + "]{babel}";
3280         return "\\usepackage{babel}";
3281 }
3282
3283
3284 docstring BufferParams::getGraphicsDriver(string const & package) const
3285 {
3286         docstring result;
3287
3288         if (package == "geometry") {
3289                 if (graphics_driver == "dvips"
3290                     || graphics_driver == "dvipdfm"
3291                     || graphics_driver == "pdftex"
3292                     || graphics_driver == "vtex")
3293                         result = from_ascii(graphics_driver);
3294                 else if (graphics_driver == "dvipdfmx")
3295                         result = from_ascii("dvipdfm");
3296         }
3297
3298         return result;
3299 }
3300
3301
3302 void BufferParams::writeEncodingPreamble(otexstream & os,
3303                                          LaTeXFeatures & features) const
3304 {
3305         // With no-TeX fonts we use utf8-plain without encoding package.
3306         if (useNonTeXFonts)
3307                 return;
3308
3309         if (inputenc == "auto-legacy") {
3310                 string const doc_encoding =
3311                         language->encoding()->latexName();
3312                 Encoding::Package const package =
3313                         language->encoding()->package();
3314
3315                 // Create list of inputenc options:
3316                 set<string> encoding_set;
3317                 // luainputenc fails with more than one encoding
3318                 if (features.runparams().flavor != Flavor::LuaTeX
3319                         && features.runparams().flavor != Flavor::DviLuaTeX)
3320                         // list all input encodings used in the document
3321                         encoding_set = features.getEncodingSet(doc_encoding);
3322
3323                 // The "japanese" babel-language requires  the pLaTeX engine
3324                 // which conflicts with "inputenc".
3325                 // See http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
3326                 if ((!encoding_set.empty() || package == Encoding::inputenc)
3327                     && !features.isRequired("japanese")
3328                     && !features.isProvided("inputenc")) {
3329                         os << "\\usepackage[";
3330                         set<string>::const_iterator it = encoding_set.begin();
3331                         set<string>::const_iterator const end = encoding_set.end();
3332                         if (it != end) {
3333                                 os << from_ascii(*it);
3334                                 ++it;
3335                         }
3336                         for (; it != end; ++it)
3337                                 os << ',' << from_ascii(*it);
3338                         if (package == Encoding::inputenc) {
3339                                 if (!encoding_set.empty())
3340                                         os << ',';
3341                                 os << from_ascii(doc_encoding);
3342                         }
3343                         if (features.runparams().flavor == Flavor::LuaTeX
3344                             || features.runparams().flavor == Flavor::DviLuaTeX)
3345                                 os << "]{luainputenc}\n";
3346                         else
3347                                 os << "]{inputenc}\n";
3348                 }
3349         } else if (inputenc != "auto-legacy-plain") {
3350                 switch (encoding().package()) {
3351                 case Encoding::none:
3352                 case Encoding::CJK:
3353                 case Encoding::japanese:
3354                         if (encoding().iconvName() != "UTF-8"
3355                                 && !features.runparams().isFullUnicode())
3356                           // don't default to [utf8]{inputenc} with TeXLive >= 18
3357                           os << "\\ifdefined\\UseRawInputEncoding\n"
3358                                  << "  \\UseRawInputEncoding\\fi\n";
3359                         break;
3360                 case Encoding::inputenc:
3361                         // do not load inputenc if japanese is used
3362                         // or if the class provides inputenc
3363                         if (features.isRequired("japanese")
3364                             || features.isProvided("inputenc"))
3365                                 break;
3366                         os << "\\usepackage[" << from_ascii(encoding().latexName());
3367                         if (features.runparams().flavor == Flavor::LuaTeX
3368                             || features.runparams().flavor == Flavor::DviLuaTeX)
3369                                 os << "]{luainputenc}\n";
3370                         else
3371                                 os << "]{inputenc}\n";
3372                         break;
3373                 }
3374         }
3375         if (inputenc == "auto-legacy-plain" || features.isRequired("japanese")) {
3376                 // don't default to [utf8]{inputenc} with TeXLive >= 18
3377                 os << "\\ifdefined\\UseRawInputEncoding\n";
3378                 os << "  \\UseRawInputEncoding\\fi\n";
3379         }
3380 }
3381
3382
3383 string const BufferParams::parseFontName(string const & name) const
3384 {
3385         string mangled = name;
3386         size_t const idx = mangled.find('[');
3387         if (idx == string::npos || idx == 0)
3388                 return mangled;
3389         else
3390                 return mangled.substr(0, idx - 1);
3391 }
3392
3393
3394 string const BufferParams::loadFonts(LaTeXFeatures & features) const
3395 {
3396         if (fontsRoman() == "default" && fontsSans() == "default"
3397             && fontsTypewriter() == "default"
3398             && (fontsMath() == "default" || fontsMath() == "auto"))
3399                 //nothing to do
3400                 return string();
3401
3402         ostringstream os;
3403
3404         /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
3405          * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
3406          * Mapping=tex-text option assures TeX ligatures (such as "--")
3407          * are resolved. Note that tt does not use these ligatures.
3408          * TODO:
3409          *    -- add more GUI options?
3410          *    -- add more fonts (fonts for other scripts)
3411          *    -- if there's a way to find out if a font really supports
3412          *       OldStyle, enable/disable the widget accordingly.
3413         */
3414         if (useNonTeXFonts && features.isAvailable("fontspec")) {
3415                 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
3416                 // However, until v.2 (2010/07/11) fontspec only knew
3417                 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
3418                 // was introduced for both XeTeX and LuaTeX (LuaTeX
3419                 // didn't understand "Mapping=tex-text", while XeTeX
3420                 // understood both. With most recent versions, both
3421                 // variants are understood by both engines. However,
3422                 // we want to provide support for at least TeXLive 2009
3423                 // (for XeTeX; LuaTeX is only supported as of v.2)
3424                 // As of 2017/11/03, Babel has its own higher-level
3425                 // interface on top of fontspec that is to be used.
3426                 bool const babelfonts = features.useBabel()
3427                                 && features.isAvailable("babel-2017/11/03");
3428                 string const texmapping =
3429                         (features.runparams().flavor == Flavor::XeTeX) ?
3430                         "Mapping=tex-text" : "Ligatures=TeX";
3431                 if (fontsRoman() != "default") {
3432                         if (babelfonts)
3433                                 os << "\\babelfont{rm}[";
3434                         else
3435                                 os << "\\setmainfont[";
3436                         if (!font_roman_opts.empty())
3437                                 os << font_roman_opts << ',';
3438                         os << texmapping;
3439                         if (fonts_roman_osf)
3440                                 os << ",Numbers=OldStyle";
3441                         os << "]{" << parseFontName(fontsRoman()) << "}\n";
3442                 }
3443                 if (fontsSans() != "default") {
3444                         string const sans = parseFontName(fontsSans());
3445                         if (fontsSansScale() != 100) {
3446                                 if (babelfonts)
3447                                         os << "\\babelfont{sf}";
3448                                 else
3449                                         os << "\\setsansfont";
3450                                 os << "[Scale="
3451                                    << float(fontsSansScale()) / 100 << ',';
3452                                 if (fonts_sans_osf)
3453                                         os << "Numbers=OldStyle,";
3454                                 if (!font_sans_opts.empty())
3455                                         os << font_sans_opts << ',';
3456                                 os << texmapping << "]{"
3457                                    << sans << "}\n";
3458                         } else {
3459                                 if (babelfonts)
3460                                         os << "\\babelfont{sf}[";
3461                                 else
3462                                         os << "\\setsansfont[";
3463                                 if (fonts_sans_osf)
3464                                         os << "Numbers=OldStyle,";
3465                                 if (!font_sans_opts.empty())
3466                                         os << font_sans_opts << ',';
3467                                 os << texmapping << "]{"
3468                                    << sans << "}\n";
3469                         }
3470                 }
3471                 if (fontsTypewriter() != "default") {
3472                         string const mono = parseFontName(fontsTypewriter());
3473                         if (fontsTypewriterScale() != 100) {
3474                                 if (babelfonts)
3475                                         os << "\\babelfont{tt}";
3476                                 else
3477                                         os << "\\setmonofont";
3478                                 os << "[Scale="
3479                                    << float(fontsTypewriterScale()) / 100;
3480                                 if (fonts_typewriter_osf)
3481                                         os << ",Numbers=OldStyle";
3482                                 if (!font_typewriter_opts.empty())
3483                                         os << ',' << font_typewriter_opts;
3484                                 os << "]{"
3485                                    << mono << "}\n";
3486                         } else {
3487                                 if (babelfonts)
3488                                         os << "\\babelfont{tt}";
3489                                 else
3490                                         os << "\\setmonofont";
3491                                 if (!font_typewriter_opts.empty() || fonts_typewriter_osf) {
3492                                         os << '[';
3493                                         if (fonts_typewriter_osf)
3494                                                 os << "Numbers=OldStyle";
3495                                         if (!font_typewriter_opts.empty()) {
3496                                                 if (fonts_typewriter_osf)
3497                                                         os << ',';
3498                                                 os << font_typewriter_opts;
3499                                         }
3500                                         os << ']';
3501                                 }
3502                                 os << '{' << mono << "}\n";
3503                         }
3504                 }
3505                 return os.str();
3506         }
3507
3508         // Tex Fonts
3509         bool const ot1 = (main_font_encoding() == "default" || main_font_encoding() == "OT1");
3510         bool const dryrun = features.runparams().dryrun;
3511         bool const complete = (fontsSans() == "default" && fontsTypewriter() == "default");
3512         bool const nomath = (fontsMath() != "auto");
3513
3514         // ROMAN FONTS
3515         os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsRoman())).getLaTeXCode(
3516                 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3517                 nomath, font_roman_opts);
3518
3519         // SANS SERIF
3520         os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsSans())).getLaTeXCode(
3521                 dryrun, ot1, complete, fonts_expert_sc, fonts_sans_osf,
3522                 nomath, font_sans_opts, fontsSansScale());
3523
3524         // MONOSPACED/TYPEWRITER
3525         os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsTypewriter())).getLaTeXCode(
3526                 dryrun, ot1, complete, fonts_expert_sc, fonts_typewriter_osf,
3527                 nomath, font_typewriter_opts, fontsTypewriterScale());
3528
3529         // MATH
3530         os << theLaTeXFonts().getLaTeXFont(from_ascii(fontsMath())).getLaTeXCode(
3531                 dryrun, ot1, complete, fonts_expert_sc, fonts_roman_osf,
3532                 nomath);
3533
3534         return os.str();
3535 }
3536
3537
3538 Encoding const & BufferParams::encoding() const
3539 {
3540         // Main encoding for LaTeX output.
3541         if (useNonTeXFonts)
3542                 return *(encodings.fromLyXName("utf8-plain"));
3543         if (inputenc == "auto-legacy" || inputenc == "auto-legacy-plain")
3544                 return *language->encoding();
3545         if (inputenc == "utf8" && language->lang() == "japanese")
3546                 return *(encodings.fromLyXName("utf8-platex"));
3547         Encoding const * const enc = encodings.fromLyXName(inputenc);
3548         if (enc)
3549                 return *enc;
3550         LYXERR0("Unknown inputenc value `" << inputenc
3551                << "'. Using `auto' instead.");
3552         return *language->encoding();
3553 }
3554
3555
3556 string const & BufferParams::defaultBiblioStyle() const
3557 {
3558         if (!biblio_style.empty())
3559                 return biblio_style;
3560
3561         map<string, string> const & bs = documentClass().defaultBiblioStyle();
3562         auto cit = bs.find(theCiteEnginesList.getTypeAsString(citeEngineType()));
3563         if (cit != bs.end())
3564                 return cit->second;
3565         else
3566                 return empty_string();
3567 }
3568
3569
3570 bool BufferParams::fullAuthorList() const
3571 {
3572         return documentClass().fullAuthorList();
3573 }
3574
3575
3576 string BufferParams::getCiteAlias(string const & s) const
3577 {
3578         vector<string> commands =
3579                 documentClass().citeCommands(citeEngineType());
3580         // If it is a real command, don't treat it as an alias
3581         if (find(commands.begin(), commands.end(), s) != commands.end())
3582                 return string();
3583         map<string,string> aliases = documentClass().citeCommandAliases();
3584         if (aliases.find(s) != aliases.end())
3585                 return aliases[s];
3586         return string();
3587 }
3588
3589
3590 vector<string> BufferParams::citeCommands() const
3591 {
3592         static CitationStyle const default_style;
3593         vector<string> commands =
3594                 documentClass().citeCommands(citeEngineType());
3595         if (commands.empty())
3596                 commands.push_back(default_style.name);
3597         return commands;
3598 }
3599
3600
3601 vector<CitationStyle> BufferParams::citeStyles() const
3602 {
3603         static CitationStyle const default_style;
3604         vector<CitationStyle> styles =
3605                 documentClass().citeStyles(citeEngineType());
3606         if (styles.empty())
3607                 styles.push_back(default_style);
3608         return styles;
3609 }
3610
3611
3612 string const BufferParams::bibtexCommand() const
3613 {
3614         // Return document-specific setting if available
3615         if (bibtex_command != "default")
3616                 return bibtex_command;
3617
3618         // If we have "default" in document settings, consult the prefs
3619         // 1. Japanese (uses a specific processor)
3620         if (encoding().package() == Encoding::japanese) {
3621                 if (lyxrc.jbibtex_command != "automatic")
3622                         // Return the specified program, if "automatic" is not set
3623                         return lyxrc.jbibtex_command;
3624                 else if (!useBiblatex()) {
3625                         // With classic BibTeX, return pbibtex, jbibtex, bibtex
3626                         if (lyxrc.jbibtex_alternatives.find("pbibtex") != lyxrc.jbibtex_alternatives.end())
3627                                 return "pbibtex";
3628                         if (lyxrc.jbibtex_alternatives.find("jbibtex") != lyxrc.jbibtex_alternatives.end())
3629                                 return "jbibtex";
3630                         return "bibtex";
3631                 }
3632         }
3633         // 2. All other languages
3634         else if (lyxrc.bibtex_command != "automatic")
3635                 // Return the specified program, if "automatic" is not set
3636                 return lyxrc.bibtex_command;
3637
3638         // 3. Automatic: find the most suitable for the current cite framework
3639         if (useBiblatex()) {
3640                 // For Biblatex, we prefer biber (also for Japanese)
3641                 // and fall back to bibtex8 and, as last resort, bibtex
3642                 if (lyxrc.bibtex_alternatives.find("biber") != lyxrc.bibtex_alternatives.end())
3643                         return "biber";
3644                 else if (lyxrc.bibtex_alternatives.find("bibtex8") != lyxrc.bibtex_alternatives.end())
3645                         return "bibtex8";
3646         }
3647         return "bibtex";
3648 }
3649
3650
3651 bool BufferParams::useBiblatex() const
3652 {
3653         return theCiteEnginesList[citeEngine()]->getCiteFramework() == "biblatex";
3654 }
3655
3656
3657 void BufferParams::invalidateConverterCache() const
3658 {
3659         pimpl_->isExportCacheValid = false;
3660         pimpl_->isViewCacheValid = false;
3661 }
3662
3663
3664 // We shouldn't need to reset the params here, since anything
3665 // we need will be recopied.
3666 void BufferParams::copyForAdvFR(const BufferParams & bp)
3667 {
3668         string const & lang = bp.language->lang();
3669         setLanguage(lang);
3670         layout_modules_ = bp.layout_modules_;
3671         string const & doc_class = bp.documentClass().name();
3672         setBaseClass(doc_class);
3673 }
3674
3675
3676 void BufferParams::setBibFileEncoding(string const & file, string const & enc)
3677 {
3678         bib_encodings[file] = enc;
3679 }
3680
3681
3682 string const BufferParams::bibFileEncoding(string const & file) const
3683 {
3684         if (bib_encodings.find(file) == bib_encodings.end())
3685                 return string();
3686         return bib_encodings.find(file)->second;
3687 }
3688
3689
3690
3691 } // namespace lyx