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