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