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