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