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