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