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