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