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