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