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