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