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