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