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