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