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