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