]> git.lyx.org Git - lyx.git/blob - src/BufferParams.cpp
- support a bunch of new languages (fileformat change)
[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                   || language->lang() == "ancientgreek"
1250                   || language->lang() == "coptic"
1251                   || language->lang() == "divehi"
1252                   || language->lang() == "hindi"
1253                   || language->lang() == "kurmanji"
1254                   || language->lang() == "lao"
1255                   || language->lang() == "marathi"
1256                   || language->lang() == "occitan"
1257                   || language->lang() == "sanskrit"
1258                   || language->lang() == "syriac"
1259                   || language->lang() == "tamil"
1260                   || language->lang() == "telugu"
1261                   || language->lang() == "urdu"
1262                  ) && useNonTeXFonts)
1263                 features.require("polyglossia");
1264
1265         if (language->lang() == "vietnamese")
1266                 features.require("vietnamese");
1267         else if (language->lang() == "japanese")
1268                 features.require("japanese");
1269 }
1270
1271
1272 bool BufferParams::writeLaTeX(otexstream & os, LaTeXFeatures & features,
1273                               FileName const & filepath) const
1274 {
1275         // http://www.tug.org/texmf-dist/doc/latex/base/fixltx2e.pdf
1276         // !! To use the Fix-cm package, load it before \documentclass, and use the command
1277         // \RequirePackage to do so, rather than the normal \usepackage
1278         // Do not try to load any other package before the document class, unless you
1279         // have a thorough understanding of the LATEX internals and know exactly what you
1280         // are doing!
1281         if (features.mustProvide("fix-cm"))
1282                 os << "\\RequirePackage{fix-cm}\n";
1283
1284         os << "\\documentclass";
1285
1286         DocumentClass const & tclass = documentClass();
1287
1288         ostringstream clsoptions; // the document class options.
1289
1290         if (tokenPos(tclass.opt_fontsize(),
1291                      '|', fontsize) >= 0) {
1292                 // only write if existing in list (and not default)
1293                 clsoptions << fontsize << "pt,";
1294         }
1295
1296         // all paper sizes except of A4, A5, B5 and the US sizes need the
1297         // geometry package
1298         bool nonstandard_papersize = papersize != PAPER_DEFAULT
1299                 && papersize != PAPER_USLETTER
1300                 && papersize != PAPER_USLEGAL
1301                 && papersize != PAPER_USEXECUTIVE
1302                 && papersize != PAPER_A4
1303                 && papersize != PAPER_A5
1304                 && papersize != PAPER_B5;
1305
1306         if (!use_geometry) {
1307                 switch (papersize) {
1308                 case PAPER_A4:
1309                         clsoptions << "a4paper,";
1310                         break;
1311                 case PAPER_USLETTER:
1312                         clsoptions << "letterpaper,";
1313                         break;
1314                 case PAPER_A5:
1315                         clsoptions << "a5paper,";
1316                         break;
1317                 case PAPER_B5:
1318                         clsoptions << "b5paper,";
1319                         break;
1320                 case PAPER_USEXECUTIVE:
1321                         clsoptions << "executivepaper,";
1322                         break;
1323                 case PAPER_USLEGAL:
1324                         clsoptions << "legalpaper,";
1325                         break;
1326                 case PAPER_DEFAULT:
1327                 case PAPER_A0:
1328                 case PAPER_A1:
1329                 case PAPER_A2:
1330                 case PAPER_A3:
1331                 case PAPER_A6:
1332                 case PAPER_B0:
1333                 case PAPER_B1:
1334                 case PAPER_B2:
1335                 case PAPER_B3:
1336                 case PAPER_B4:
1337                 case PAPER_B6:
1338                 case PAPER_C0:
1339                 case PAPER_C1:
1340                 case PAPER_C2:
1341                 case PAPER_C3:
1342                 case PAPER_C4:
1343                 case PAPER_C5:
1344                 case PAPER_C6:
1345                 case PAPER_JISB0:
1346                 case PAPER_JISB1:
1347                 case PAPER_JISB2:
1348                 case PAPER_JISB3:
1349                 case PAPER_JISB4:
1350                 case PAPER_JISB5:
1351                 case PAPER_JISB6:
1352                 case PAPER_CUSTOM:
1353                         break;
1354                 }
1355         }
1356
1357         // if needed
1358         if (sides != tclass.sides()) {
1359                 switch (sides) {
1360                 case OneSide:
1361                         clsoptions << "oneside,";
1362                         break;
1363                 case TwoSides:
1364                         clsoptions << "twoside,";
1365                         break;
1366                 }
1367         }
1368
1369         // if needed
1370         if (columns != tclass.columns()) {
1371                 if (columns == 2)
1372                         clsoptions << "twocolumn,";
1373                 else
1374                         clsoptions << "onecolumn,";
1375         }
1376
1377         if (!use_geometry
1378             && orientation == ORIENTATION_LANDSCAPE)
1379                 clsoptions << "landscape,";
1380
1381         // language should be a parameter to \documentclass
1382         if (language->babel() == "hebrew"
1383             && default_language->babel() != "hebrew")
1384                 // This seems necessary
1385                 features.useLanguage(default_language);
1386
1387         ostringstream language_options;
1388         bool const use_babel = features.useBabel() && !tclass.provides("babel");
1389         bool const use_polyglossia = features.usePolyglossia();
1390         bool const global = lyxrc.language_global_options;
1391         if (use_babel || (use_polyglossia && global)) {
1392                 language_options << features.getLanguages();
1393                 if (!language->babel().empty()) {
1394                         if (!language_options.str().empty())
1395                                 language_options << ',';
1396                         language_options << language->babel();
1397                 }
1398                 if (global && !features.needBabelLangOptions())
1399                         clsoptions << language_options.str() << ',';
1400         }
1401
1402         // the predefined options from the layout
1403         if (use_default_options && !tclass.options().empty())
1404                 clsoptions << tclass.options() << ',';
1405
1406         // the user-defined options
1407         if (!options.empty()) {
1408                 clsoptions << options << ',';
1409         }
1410
1411         string strOptions(clsoptions.str());
1412         if (!strOptions.empty()) {
1413                 strOptions = rtrim(strOptions, ",");
1414                 // FIXME UNICODE
1415                 os << '[' << from_utf8(strOptions) << ']';
1416         }
1417
1418         os << '{' << from_ascii(tclass.latexname()) << "}\n";
1419         // end of \documentclass defs
1420
1421         // if we use fontspec, we have to load the AMS packages here
1422         string const ams = features.loadAMSPackages();
1423         if (useNonTeXFonts && !ams.empty())
1424                 os << from_ascii(ams);
1425
1426         if (useNonTeXFonts)
1427                 os << "\\usepackage{fontspec}\n";
1428
1429         // font selection must be done before loading fontenc.sty
1430         string const fonts =
1431                 loadFonts(fonts_roman, fonts_sans, fonts_typewriter,
1432                           fonts_expert_sc, fonts_old_figures,
1433                           fonts_sans_scale, fonts_typewriter_scale,
1434                           useNonTeXFonts, features);
1435         if (!fonts.empty())
1436                 os << from_utf8(fonts);
1437
1438         if (fonts_default_family != "default")
1439                 os << "\\renewcommand{\\familydefault}{\\"
1440                    << from_ascii(fonts_default_family) << "}\n";
1441
1442         // set font encoding
1443         // for arabic_arabi and farsi we also need to load the LAE and
1444         // LFE encoding
1445         // XeTeX and LuaTeX (with OS fonts) work without fontenc
1446         if (font_encoding() != "default" && language->lang() != "japanese"
1447             && !useNonTeXFonts && !tclass.provides("fontenc")) {
1448                 size_t fars = language_options.str().find("farsi");
1449                 size_t arab = language_options.str().find("arabic");
1450                 if (language->lang() == "arabic_arabi"
1451                         || language->lang() == "farsi" || fars != string::npos
1452                         || arab != string::npos) {
1453                         os << "\\usepackage[" << from_ascii(font_encoding())
1454                            << ",LFE,LAE]{fontenc}\n";
1455                 } else {
1456                         os << "\\usepackage[" << from_ascii(font_encoding())
1457                            << "]{fontenc}\n";
1458                 }
1459         }
1460
1461         // handle inputenc etc.
1462         writeEncodingPreamble(os, features);
1463
1464         // includeonly
1465         if (!features.runparams().includeall && !included_children_.empty()) {
1466                 os << "\\includeonly{";
1467                 list<string>::const_iterator it = included_children_.begin();
1468                 list<string>::const_iterator en = included_children_.end();
1469                 bool first = true;
1470                 for (; it != en; ++it) {
1471                         string incfile = *it;
1472                         FileName inc = makeAbsPath(incfile, filepath.absFileName());
1473                         string mangled = DocFileName(changeExtension(inc.absFileName(), ".tex")).
1474                         mangledFileName();
1475                         if (!features.runparams().nice)
1476                                 incfile = mangled;
1477                         // \includeonly doesn't want an extension
1478                         incfile = changeExtension(incfile, string());
1479                         incfile = support::latex_path(incfile);
1480                         if (!incfile.empty()) {
1481                                 if (!first)
1482                                         os << ",";
1483                                 os << from_utf8(incfile);
1484                         }
1485                         first = false;
1486                 }
1487                 os << "}\n";
1488         }
1489
1490         if (!listings_params.empty() || features.isRequired("listings"))
1491                 os << "\\usepackage{listings}\n";
1492
1493         if (!listings_params.empty()) {
1494                 os << "\\lstset{";
1495                 // do not test validity because listings_params is
1496                 // supposed to be valid
1497                 string par =
1498                         InsetListingsParams(listings_params).separatedParams(true);
1499                 // we can't support all packages, but we should load the color package
1500                 if (par.find("\\color", 0) != string::npos)
1501                         features.require("color");
1502                 os << from_utf8(par)
1503                    << "}\n";
1504         }
1505         if (!tclass.provides("geometry")
1506             && (use_geometry || nonstandard_papersize)) {
1507                 odocstringstream ods;
1508                 if (!getGraphicsDriver("geometry").empty())
1509                         ods << getGraphicsDriver("geometry");
1510                 if (orientation == ORIENTATION_LANDSCAPE)
1511                         ods << ",landscape";
1512                 switch (papersize) {
1513                 case PAPER_CUSTOM:
1514                         if (!paperwidth.empty())
1515                                 ods << ",paperwidth="
1516                                    << from_ascii(paperwidth);
1517                         if (!paperheight.empty())
1518                                 ods << ",paperheight="
1519                                    << from_ascii(paperheight);
1520                         break;
1521                 case PAPER_USLETTER:
1522                         ods << ",letterpaper";
1523                         break;
1524                 case PAPER_USLEGAL:
1525                         ods << ",legalpaper";
1526                         break;
1527                 case PAPER_USEXECUTIVE:
1528                         ods << ",executivepaper";
1529                         break;
1530                 case PAPER_A0:
1531                         ods << ",a0paper";
1532                         break;
1533                 case PAPER_A1:
1534                         ods << ",a1paper";
1535                         break;
1536                 case PAPER_A2:
1537                         ods << ",a2paper";
1538                         break;
1539                 case PAPER_A3:
1540                         ods << ",a3paper";
1541                         break;
1542                 case PAPER_A4:
1543                         ods << ",a4paper";
1544                         break;
1545                 case PAPER_A5:
1546                         ods << ",a5paper";
1547                         break;
1548                 case PAPER_A6:
1549                         ods << ",a6paper";
1550                         break;
1551                 case PAPER_B0:
1552                         ods << ",b0paper";
1553                         break;
1554                 case PAPER_B1:
1555                         ods << ",b1paper";
1556                         break;
1557                 case PAPER_B2:
1558                         ods << ",b2paper";
1559                         break;
1560                 case PAPER_B3:
1561                         ods << ",b3paper";
1562                         break;
1563                 case PAPER_B4:
1564                         ods << ",b4paper";
1565                         break;
1566                 case PAPER_B5:
1567                         ods << ",b5paper";
1568                         break;
1569                 case PAPER_B6:
1570                         ods << ",b6paper";
1571                         break;
1572                 case PAPER_C0:
1573                         ods << ",c0paper";
1574                         break;
1575                 case PAPER_C1:
1576                         ods << ",c1paper";
1577                         break;
1578                 case PAPER_C2:
1579                         ods << ",c2paper";
1580                         break;
1581                 case PAPER_C3:
1582                         ods << ",c3paper";
1583                         break;
1584                 case PAPER_C4:
1585                         ods << ",c4paper";
1586                         break;
1587                 case PAPER_C5:
1588                         ods << ",c5paper";
1589                         break;
1590                 case PAPER_C6:
1591                         ods << ",c6paper";
1592                         break;
1593                 case PAPER_JISB0:
1594                         ods << ",b0j";
1595                         break;
1596                 case PAPER_JISB1:
1597                         ods << ",b1j";
1598                         break;
1599                 case PAPER_JISB2:
1600                         ods << ",b2j";
1601                         break;
1602                 case PAPER_JISB3:
1603                         ods << ",b3j";
1604                         break;
1605                 case PAPER_JISB4:
1606                         ods << ",b4j";
1607                         break;
1608                 case PAPER_JISB5:
1609                         ods << ",b5j";
1610                         break;
1611                 case PAPER_JISB6:
1612                         ods << ",b6j";
1613                         break;
1614                 case PAPER_DEFAULT:
1615                         break;
1616                 }
1617                 docstring const g_options = trim(ods.str(), ",");
1618                 os << "\\usepackage";
1619                 if (!g_options.empty())
1620                         os << '[' << g_options << ']';
1621                 os << "{geometry}\n";
1622                 // output this only if use_geometry is true
1623                 if (use_geometry) {
1624                         os << "\\geometry{verbose";
1625                         if (!topmargin.empty())
1626                                 os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1627                         if (!bottommargin.empty())
1628                                 os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1629                         if (!leftmargin.empty())
1630                                 os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1631                         if (!rightmargin.empty())
1632                                 os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1633                         if (!headheight.empty())
1634                                 os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1635                         if (!headsep.empty())
1636                                 os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1637                         if (!footskip.empty())
1638                                 os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1639                         if (!columnsep.empty())
1640                                 os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1641                         os << "}\n";
1642                 }
1643         } else if (orientation == ORIENTATION_LANDSCAPE
1644                    || papersize != PAPER_DEFAULT) {
1645                 features.require("papersize");
1646         }
1647
1648         if (tokenPos(tclass.opt_pagestyle(), '|', pagestyle) >= 0) {
1649                 if (pagestyle == "fancy")
1650                         os << "\\usepackage{fancyhdr}\n";
1651                 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1652         }
1653
1654         // only output when the background color is not default
1655         if (isbackgroundcolor == true) {
1656                 // only require color here, the background color will be defined
1657                 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1658                 // package pdfpages
1659                 features.require("color");
1660                 features.require("pagecolor");
1661         }
1662
1663         // only output when the font color is not default
1664         if (isfontcolor == true) {
1665                 // only require color here, the font color will be defined
1666                 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1667                 // package pdfpages
1668                 features.require("color");
1669                 features.require("fontcolor");
1670         }
1671
1672         // Only if class has a ToC hierarchy
1673         if (tclass.hasTocLevels()) {
1674                 if (secnumdepth != tclass.secnumdepth()) {
1675                         os << "\\setcounter{secnumdepth}{"
1676                            << secnumdepth
1677                            << "}\n";
1678                 }
1679                 if (tocdepth != tclass.tocdepth()) {
1680                         os << "\\setcounter{tocdepth}{"
1681                            << tocdepth
1682                            << "}\n";
1683                 }
1684         }
1685
1686         if (paragraph_separation) {
1687                 // when skip separation
1688                 switch (getDefSkip().kind()) {
1689                 case VSpace::SMALLSKIP:
1690                         os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1691                         break;
1692                 case VSpace::MEDSKIP:
1693                         os << "\\setlength{\\parskip}{\\medskipamount}\n";
1694                         break;
1695                 case VSpace::BIGSKIP:
1696                         os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1697                         break;
1698                 case VSpace::LENGTH:
1699                         os << "\\setlength{\\parskip}{"
1700                            << from_utf8(getDefSkip().length().asLatexString())
1701                            << "}\n";
1702                         break;
1703                 default: // should never happen // Then delete it.
1704                         os << "\\setlength{\\parskip}{\\medskipamount}\n";
1705                         break;
1706                 }
1707                 os << "\\setlength{\\parindent}{0pt}\n";
1708         } else {
1709                 // when separation by indentation
1710                 // only output something when a width is given
1711                 if (getIndentation().asLyXCommand() != "default") {
1712                         os << "\\setlength{\\parindent}{"
1713                            << from_utf8(getIndentation().asLatexCommand())
1714                            << "}\n";
1715                 }
1716         }
1717
1718         // Now insert the LyX specific LaTeX commands...
1719         docstring lyxpreamble;
1720         features.resolveAlternatives();
1721
1722         if (output_sync) {
1723                 if (!output_sync_macro.empty())
1724                         lyxpreamble += from_utf8(output_sync_macro) +"\n";
1725                 else if (features.runparams().flavor == OutputParams::LATEX)
1726                         lyxpreamble += "\\usepackage[active]{srcltx}\n";
1727                 else if (features.runparams().flavor == OutputParams::PDFLATEX)
1728                         lyxpreamble += "\\synctex=-1\n";
1729         }
1730
1731         // due to interferences with babel and hyperref, the color package has to
1732         // be loaded (when it is not already loaded) before babel when hyperref
1733         // is used with the colorlinks option, see
1734         // http://www.lyx.org/trac/ticket/5291
1735         // we decided therefore to load color always before babel, see
1736         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
1737         lyxpreamble += from_ascii(features.getColorOptions());
1738
1739         // If we use hyperref, jurabib, japanese, or vietnamese, we have to call babel before them.
1740         if (use_babel
1741             && (features.isRequired("jurabib")
1742                 || features.isRequired("hyperref")
1743                 || features.isRequired("vietnamese")
1744                 || features.isRequired("japanese"))) {
1745                         // FIXME UNICODE
1746                         lyxpreamble += from_utf8(features.getBabelPresettings());
1747                         lyxpreamble += from_utf8(babelCall(language_options.str(),
1748                                                            features.needBabelLangOptions())) + '\n';
1749                         lyxpreamble += from_utf8(features.getBabelPostsettings());
1750         }
1751
1752         // The optional packages;
1753         lyxpreamble += from_ascii(features.getPackages());
1754
1755         // Additional Indices
1756         if (features.isRequired("splitidx")) {
1757                 IndicesList::const_iterator iit = indiceslist().begin();
1758                 IndicesList::const_iterator iend = indiceslist().end();
1759                 for (; iit != iend; ++iit) {
1760                         lyxpreamble += "\\newindex[";
1761                         lyxpreamble += iit->index();
1762                         lyxpreamble += "]{";
1763                         lyxpreamble += iit->shortcut();
1764                         lyxpreamble += "}\n";
1765                 }
1766         }
1767
1768         // Line spacing
1769         lyxpreamble += from_utf8(spacing().writePreamble(tclass.provides("SetSpace")));
1770
1771         // PDF support.
1772         // * Hyperref manual: "Make sure it comes last of your loaded
1773         //   packages, to give it a fighting chance of not being over-written,
1774         //   since its job is to redefine many LaTeX commands."
1775         // * Email from Heiko Oberdiek: "It is usually better to load babel
1776         //   before hyperref. Then hyperref has a chance to detect babel.
1777         // * Has to be loaded before the "LyX specific LaTeX commands" to
1778         //   avoid errors with algorithm floats.
1779         // use hyperref explicitly if it is required
1780         if (features.isRequired("hyperref")) {
1781                 // pass what we have to stream here, since we need
1782                 // to access the stream itself in PDFOptions.
1783                 os << lyxpreamble;
1784
1785                 OutputParams tmp_params = features.runparams();
1786                 pdfoptions().writeLaTeX(tmp_params, os,
1787                                         documentClass().provides("hyperref"));
1788                 // set back for the rest
1789                 lyxpreamble.clear();
1790                 // correctly break URLs with hyperref and dvi output
1791                 if (features.runparams().flavor == OutputParams::LATEX
1792                     && features.isAvailable("breakurl"))
1793                         lyxpreamble += "\\usepackage{breakurl}\n";
1794         } else if (features.isRequired("nameref"))
1795                 // hyperref loads this automatically
1796                 lyxpreamble += "\\usepackage{nameref}\n";
1797
1798         // bibtopic needs to be loaded after hyperref.
1799         // the dot provides the aux file naming which LyX can detect.
1800         if (features.mustProvide("bibtopic"))
1801                 lyxpreamble += "\\usepackage[dot]{bibtopic}\n";
1802
1803         // Will be surrounded by \makeatletter and \makeatother when not empty
1804         docstring atlyxpreamble;
1805
1806         // Some macros LyX will need
1807         docstring tmppreamble(features.getMacros());
1808
1809         if (!tmppreamble.empty())
1810                 atlyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1811                         "LyX specific LaTeX commands.\n"
1812                         + tmppreamble + '\n';
1813
1814         // the text class specific preamble
1815         tmppreamble = features.getTClassPreamble();
1816         if (!tmppreamble.empty())
1817                 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1818                         "Textclass specific LaTeX commands.\n"
1819                         + tmppreamble + '\n';
1820
1821         // suppress date if selected
1822         // use \@ifundefined because we cannot be sure that every document class
1823         // has a \date command
1824         if (suppress_date)
1825                 atlyxpreamble += "\\@ifundefined{date}{}{\\date{}}\n";
1826
1827         /* the user-defined preamble */
1828         if (!containsOnly(preamble, " \n\t"))
1829                 // FIXME UNICODE
1830                 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1831                         "User specified LaTeX commands.\n"
1832                         + from_utf8(preamble) + '\n';
1833
1834         // subfig loads internally the LaTeX package "caption". As
1835         // caption is a very popular package, users will load it in
1836         // the preamble. Therefore we must load subfig behind the
1837         // user-defined preamble and check if the caption package was
1838         // loaded or not. For the case that caption is loaded before
1839         // subfig, there is the subfig option "caption=false". This
1840         // option also works when a koma-script class is used and
1841         // koma's own caption commands are used instead of caption. We
1842         // use \PassOptionsToPackage here because the user could have
1843         // already loaded subfig in the preamble.
1844         if (features.isRequired("subfig")) {
1845                 atlyxpreamble += "\\@ifundefined{showcaptionsetup}{}{%\n"
1846                         " \\PassOptionsToPackage{caption=false}{subfig}}\n"
1847                         "\\usepackage{subfig}\n";
1848         }
1849
1850         // Itemize bullet settings need to be last in case the user
1851         // defines their own bullets that use a package included
1852         // in the user-defined preamble -- ARRae
1853         // Actually it has to be done much later than that
1854         // since some packages like frenchb make modifications
1855         // at \begin{document} time -- JMarc
1856         docstring bullets_def;
1857         for (int i = 0; i < 4; ++i) {
1858                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1859                         if (bullets_def.empty())
1860                                 bullets_def += "\\AtBeginDocument{\n";
1861                         bullets_def += "  \\def\\labelitemi";
1862                         switch (i) {
1863                                 // `i' is one less than the item to modify
1864                         case 0:
1865                                 break;
1866                         case 1:
1867                                 bullets_def += 'i';
1868                                 break;
1869                         case 2:
1870                                 bullets_def += "ii";
1871                                 break;
1872                         case 3:
1873                                 bullets_def += 'v';
1874                                 break;
1875                         }
1876                         bullets_def += '{' +
1877                                 user_defined_bullet(i).getText()
1878                                 + "}\n";
1879                 }
1880         }
1881
1882         if (!bullets_def.empty())
1883                 atlyxpreamble += bullets_def + "}\n\n";
1884
1885         if (!atlyxpreamble.empty())
1886                 lyxpreamble += "\n\\makeatletter\n"
1887                         + atlyxpreamble + "\\makeatother\n\n";
1888
1889         // We try to load babel late, in case it interferes with other packages.
1890         // Jurabib and Hyperref have to be called after babel, though.
1891         if (use_babel && !features.isRequired("jurabib")
1892             && !features.isRequired("hyperref")
1893             && !features.isRequired("vietnamese")
1894             && !features.isRequired("japanese")) {
1895                 // FIXME UNICODE
1896                 lyxpreamble += from_utf8(features.getBabelPresettings());
1897                 lyxpreamble += from_utf8(babelCall(language_options.str(),
1898                                                    features.needBabelLangOptions())) + '\n';
1899                 lyxpreamble += from_utf8(features.getBabelPostsettings());
1900         }
1901
1902         // xunicode needs to be loaded at least after amsmath, amssymb,
1903         // esint and the other packages that provide special glyphs
1904         if (features.runparams().flavor == OutputParams::XETEX)
1905                 lyxpreamble += "\\usepackage{xunicode}\n";
1906
1907         // Polyglossia must be loaded last
1908         if (use_polyglossia) {
1909                 // call the package
1910                 lyxpreamble += "\\usepackage{polyglossia}\n";
1911                 // set the main language
1912                 lyxpreamble += "\\setdefaultlanguage";
1913                 if (!language->polyglossiaOpts().empty())
1914                         lyxpreamble += "[" + from_ascii(language->polyglossiaOpts()) + "]";
1915                 lyxpreamble += "{" + from_ascii(language->polyglossia()) + "}\n";
1916                 // now setup the other languages
1917                 std::map<std::string, std::string> const polylangs =
1918                         features.getPolyglossiaLanguages();
1919                 for (std::map<std::string, std::string>::const_iterator mit = polylangs.begin();
1920                      mit != polylangs.end() ; ++mit) {
1921                         lyxpreamble += "\\setotherlanguage";
1922                         if (!mit->second.empty())
1923                                 lyxpreamble += "[" + from_ascii(mit->second) + "]";
1924                         lyxpreamble += "{" + from_ascii(mit->first) + "}\n";
1925                 }
1926         }
1927
1928         docstring const i18npreamble =
1929                 features.getTClassI18nPreamble(use_babel, use_polyglossia);
1930         if (!i18npreamble.empty())
1931                 lyxpreamble += i18npreamble + '\n';
1932
1933         os << lyxpreamble;
1934
1935         return use_babel;
1936 }
1937
1938
1939 void BufferParams::useClassDefaults()
1940 {
1941         DocumentClass const & tclass = documentClass();
1942
1943         sides = tclass.sides();
1944         columns = tclass.columns();
1945         pagestyle = tclass.pagestyle();
1946         use_default_options = true;
1947         // Only if class has a ToC hierarchy
1948         if (tclass.hasTocLevels()) {
1949                 secnumdepth = tclass.secnumdepth();
1950                 tocdepth = tclass.tocdepth();
1951         }
1952 }
1953
1954
1955 bool BufferParams::hasClassDefaults() const
1956 {
1957         DocumentClass const & tclass = documentClass();
1958
1959         return sides == tclass.sides()
1960                 && columns == tclass.columns()
1961                 && pagestyle == tclass.pagestyle()
1962                 && use_default_options
1963                 && secnumdepth == tclass.secnumdepth()
1964                 && tocdepth == tclass.tocdepth();
1965 }
1966
1967
1968 DocumentClass const & BufferParams::documentClass() const
1969 {
1970         return *doc_class_.get();
1971 }
1972
1973
1974 DocumentClassConstPtr BufferParams::documentClassPtr() const
1975 {
1976         return doc_class_;
1977 }
1978
1979
1980 void BufferParams::setDocumentClass(DocumentClassConstPtr tc)
1981 {
1982         // evil, but this function is evil
1983         doc_class_ = const_pointer_cast<DocumentClass>(tc);
1984 }
1985
1986
1987 bool BufferParams::setBaseClass(string const & classname)
1988 {
1989         LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
1990         LayoutFileList & bcl = LayoutFileList::get();
1991         if (!bcl.haveClass(classname)) {
1992                 docstring s =
1993                         bformat(_("The layout file:\n"
1994                                 "%1$s\n"
1995                                 "could not be found. A default textclass with default\n"
1996                                 "layouts will be used. LyX will not be able to produce\n"
1997                                 "correct output."),
1998                         from_utf8(classname));
1999                 frontend::Alert::error(_("Document class not found"), s);
2000                 bcl.addEmptyClass(classname);
2001         }
2002
2003         bool const success = bcl[classname].load();
2004         if (!success) {
2005                 docstring s =
2006                         bformat(_("Due to some error in it, the layout file:\n"
2007                                 "%1$s\n"
2008                                 "could not be loaded. A default textclass with default\n"
2009                                 "layouts will be used. LyX will not be able to produce\n"
2010                                 "correct output."),
2011                         from_utf8(classname));
2012                 frontend::Alert::error(_("Could not load class"), s);
2013                 bcl.addEmptyClass(classname);
2014         }
2015
2016         pimpl_->baseClass_ = classname;
2017         layout_modules_.adaptToBaseClass(baseClass(), removed_modules_);
2018         return true;
2019 }
2020
2021
2022 LayoutFile const * BufferParams::baseClass() const
2023 {
2024         if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
2025                 return &(LayoutFileList::get()[pimpl_->baseClass_]);
2026         else
2027                 return 0;
2028 }
2029
2030
2031 LayoutFileIndex const & BufferParams::baseClassID() const
2032 {
2033         return pimpl_->baseClass_;
2034 }
2035
2036
2037 void BufferParams::makeDocumentClass()
2038 {
2039         if (!baseClass())
2040                 return;
2041
2042         LayoutModuleList mods;
2043         LayoutModuleList::iterator it;
2044         LayoutModuleList::iterator en;
2045
2046         it = layout_modules_.begin();
2047         en = layout_modules_.end();
2048         for (; it != en; ++it)
2049                 mods.push_back(*it);
2050         it = cite_engine_.begin();
2051         en = cite_engine_.end();
2052         for (; it != en; ++it)
2053                 mods.push_back(*it);
2054         doc_class_ = getDocumentClass(*baseClass(), mods);
2055
2056         if (!local_layout.empty()) {
2057                 TextClass::ReturnValues success =
2058                         doc_class_->read(local_layout, TextClass::MODULE);
2059                 if (success != TextClass::OK && success != TextClass::OK_OLDFORMAT) {
2060                         docstring const msg = _("Error reading internal layout information");
2061                         frontend::Alert::warning(_("Read Error"), msg);
2062                 }
2063         }
2064 }
2065
2066
2067 bool BufferParams::moduleCanBeAdded(string const & modName) const
2068 {
2069         return cite_engine_.moduleCanBeAdded(modName, baseClass()) &&
2070                 layout_modules_.moduleCanBeAdded(modName, baseClass());
2071 }
2072
2073
2074 bool BufferParams::addLayoutModule(string const & modName)
2075 {
2076         LayoutModuleList::const_iterator it = layout_modules_.begin();
2077         LayoutModuleList::const_iterator end = layout_modules_.end();
2078         for (; it != end; ++it)
2079                 if (*it == modName)
2080                         return false;
2081         layout_modules_.push_back(modName);
2082         return true;
2083 }
2084
2085
2086 string BufferParams::bufferFormat() const
2087 {
2088         string format = documentClass().outputFormat();
2089         if (format == "latex") {
2090                 if (useNonTeXFonts)
2091                         return "xetex";
2092                 if (encoding().package() == Encoding::japanese)
2093                         return "platex";
2094         }
2095         return format;
2096 }
2097
2098
2099 bool BufferParams::isExportable(string const & format) const
2100 {
2101         vector<string> backs = backends();
2102         for (vector<string>::const_iterator it = backs.begin();
2103              it != backs.end(); ++it)
2104                 if (theConverters().isReachable(*it, format))
2105                         return true;
2106         return false;
2107 }
2108
2109
2110 namespace {
2111 bool formatSorter(Format const * lhs, Format const * rhs) {
2112         return _(lhs->prettyname()) < _(rhs->prettyname());
2113 }
2114 }
2115
2116
2117 vector<Format const *> BufferParams::exportableFormats(bool only_viewable) const
2118 {
2119         vector<string> const backs = backends();
2120         set<string> excludes;
2121         if (useNonTeXFonts) {
2122                 excludes.insert("latex");
2123                 excludes.insert("pdflatex");
2124         }
2125         vector<Format const *> result =
2126                 theConverters().getReachable(backs[0], only_viewable, true, excludes);
2127         for (vector<string>::const_iterator it = backs.begin() + 1;
2128              it != backs.end(); ++it) {
2129                 vector<Format const *>  r =
2130                         theConverters().getReachable(*it, only_viewable, false, excludes);
2131                 result.insert(result.end(), r.begin(), r.end());
2132         }
2133         sort(result.begin(), result.end(), formatSorter);
2134         return result;
2135 }
2136
2137
2138 bool BufferParams::isExportableFormat(string const & format) const
2139 {
2140         typedef vector<Format const *> Formats;
2141         Formats formats;
2142         formats = exportableFormats(true);
2143         Formats::const_iterator fit = formats.begin();
2144         Formats::const_iterator end = formats.end();
2145         for (; fit != end ; ++fit) {
2146                 if ((*fit)->name() == format)
2147                         return true;
2148         }
2149         return false;
2150 }
2151
2152
2153 vector<string> BufferParams::backends() const
2154 {
2155         vector<string> v;
2156         string const buffmt = bufferFormat();
2157
2158         // FIXME: Don't hardcode format names here, but use a flag
2159         if (buffmt == "latex") {
2160                 if (!useNonTeXFonts) {
2161                         v.push_back("pdflatex");
2162                         v.push_back("latex");
2163                 }
2164                 v.push_back("luatex");
2165                 v.push_back("dviluatex");
2166                 v.push_back("xetex");
2167         } else if (buffmt == "xetex") {
2168                 v.push_back("xetex");
2169                 v.push_back("luatex");
2170                 v.push_back("dviluatex");
2171         } else
2172                 v.push_back(buffmt);
2173
2174         v.push_back("xhtml");
2175         v.push_back("text");
2176         v.push_back("lyx");
2177         return v;
2178 }
2179
2180
2181 OutputParams::FLAVOR BufferParams::getOutputFlavor(string const format) const
2182 {
2183         string const dformat = (format.empty() || format == "default") ?
2184                 getDefaultOutputFormat() : format;
2185         DefaultFlavorCache::const_iterator it =
2186                 default_flavors_.find(dformat);
2187
2188         if (it != default_flavors_.end())
2189                 return it->second;
2190
2191         OutputParams::FLAVOR result = OutputParams::LATEX;
2192
2193         if (dformat == "xhtml")
2194                 result = OutputParams::HTML;
2195         else if (dformat == "text")
2196                 result = OutputParams::TEXT;
2197         else if (dformat == "lyx")
2198                 result = OutputParams::LYX;
2199         else {
2200                 // Try to determine flavor of default output format
2201                 vector<string> backs = backends();
2202                 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2203                         // Get shortest path to format
2204                         Graph::EdgePath path;
2205                         for (vector<string>::const_iterator it = backs.begin();
2206                             it != backs.end(); ++it) {
2207                                 Graph::EdgePath p = theConverters().getPath(*it, dformat);
2208                                 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2209                                         path = p;
2210                                 }
2211                         }
2212                         if (!path.empty())
2213                                 result = theConverters().getFlavor(path);
2214                 }
2215         }
2216         // cache this flavor
2217         default_flavors_[dformat] = result;
2218         return result;
2219 }
2220
2221
2222 string BufferParams::getDefaultOutputFormat() const
2223 {
2224         if (!default_output_format.empty()
2225             && default_output_format != "default")
2226                 return default_output_format;
2227         if (isDocBook()
2228             || useNonTeXFonts
2229             || encoding().package() == Encoding::japanese) {
2230                 vector<Format const *> const formats = exportableFormats(true);
2231                 if (formats.empty())
2232                         return string();
2233                 // return the first we find
2234                 return formats.front()->name();
2235         }
2236         return lyxrc.default_view_format;
2237 }
2238
2239 Font const BufferParams::getFont() const
2240 {
2241         FontInfo f = documentClass().defaultfont();
2242         if (fonts_default_family == "rmdefault")
2243                 f.setFamily(ROMAN_FAMILY);
2244         else if (fonts_default_family == "sfdefault")
2245                 f.setFamily(SANS_FAMILY);
2246         else if (fonts_default_family == "ttdefault")
2247                 f.setFamily(TYPEWRITER_FAMILY);
2248         return Font(f, language);
2249 }
2250
2251
2252 bool BufferParams::isLatex() const
2253 {
2254         return documentClass().outputType() == LATEX;
2255 }
2256
2257
2258 bool BufferParams::isLiterate() const
2259 {
2260         return documentClass().outputType() == LITERATE;
2261 }
2262
2263
2264 bool BufferParams::isDocBook() const
2265 {
2266         return documentClass().outputType() == DOCBOOK;
2267 }
2268
2269
2270 void BufferParams::readPreamble(Lexer & lex)
2271 {
2272         if (lex.getString() != "\\begin_preamble")
2273                 lyxerr << "Error (BufferParams::readPreamble):"
2274                         "consistency check failed." << endl;
2275
2276         preamble = lex.getLongString("\\end_preamble");
2277 }
2278
2279
2280 void BufferParams::readLocalLayout(Lexer & lex)
2281 {
2282         if (lex.getString() != "\\begin_local_layout")
2283                 lyxerr << "Error (BufferParams::readLocalLayout):"
2284                         "consistency check failed." << endl;
2285
2286         local_layout = lex.getLongString("\\end_local_layout");
2287 }
2288
2289
2290 bool BufferParams::setLanguage(string const & lang)
2291 {
2292         Language const *new_language = languages.getLanguage(lang);
2293         if (!new_language) {
2294                 // Language lang was not found
2295                 return false;
2296         }
2297         language = new_language;
2298         return true;
2299 }
2300
2301
2302 void BufferParams::readLanguage(Lexer & lex)
2303 {
2304         if (!lex.next()) return;
2305
2306         string const tmptok = lex.getString();
2307
2308         // check if tmptok is part of tex_babel in tex-defs.h
2309         if (!setLanguage(tmptok)) {
2310                 // Language tmptok was not found
2311                 language = default_language;
2312                 lyxerr << "Warning: Setting language `"
2313                        << tmptok << "' to `" << language->lang()
2314                        << "'." << endl;
2315         }
2316 }
2317
2318
2319 void BufferParams::readGraphicsDriver(Lexer & lex)
2320 {
2321         if (!lex.next())
2322                 return;
2323
2324         string const tmptok = lex.getString();
2325         // check if tmptok is part of tex_graphics in tex_defs.h
2326         int n = 0;
2327         while (true) {
2328                 string const test = tex_graphics[n++];
2329
2330                 if (test == tmptok) {
2331                         graphics_driver = tmptok;
2332                         break;
2333                 }
2334                 if (test.empty()) {
2335                         lex.printError(
2336                                 "Warning: graphics driver `$$Token' not recognized!\n"
2337                                 "         Setting graphics driver to `default'.\n");
2338                         graphics_driver = "default";
2339                         break;
2340                 }
2341         }
2342 }
2343
2344
2345 void BufferParams::readBullets(Lexer & lex)
2346 {
2347         if (!lex.next())
2348                 return;
2349
2350         int const index = lex.getInteger();
2351         lex.next();
2352         int temp_int = lex.getInteger();
2353         user_defined_bullet(index).setFont(temp_int);
2354         temp_bullet(index).setFont(temp_int);
2355         lex >> temp_int;
2356         user_defined_bullet(index).setCharacter(temp_int);
2357         temp_bullet(index).setCharacter(temp_int);
2358         lex >> temp_int;
2359         user_defined_bullet(index).setSize(temp_int);
2360         temp_bullet(index).setSize(temp_int);
2361 }
2362
2363
2364 void BufferParams::readBulletsLaTeX(Lexer & lex)
2365 {
2366         // The bullet class should be able to read this.
2367         if (!lex.next())
2368                 return;
2369         int const index = lex.getInteger();
2370         lex.next(true);
2371         docstring const temp_str = lex.getDocString();
2372
2373         user_defined_bullet(index).setText(temp_str);
2374         temp_bullet(index).setText(temp_str);
2375 }
2376
2377
2378 void BufferParams::readModules(Lexer & lex)
2379 {
2380         if (!lex.eatLine()) {
2381                 lyxerr << "Error (BufferParams::readModules):"
2382                                 "Unexpected end of input." << endl;
2383                 return;
2384         }
2385         while (true) {
2386                 string mod = lex.getString();
2387                 if (mod == "\\end_modules")
2388                         break;
2389                 addLayoutModule(mod);
2390                 lex.eatLine();
2391         }
2392 }
2393
2394
2395 void BufferParams::readRemovedModules(Lexer & lex)
2396 {
2397         if (!lex.eatLine()) {
2398                 lyxerr << "Error (BufferParams::readRemovedModules):"
2399                                 "Unexpected end of input." << endl;
2400                 return;
2401         }
2402         while (true) {
2403                 string mod = lex.getString();
2404                 if (mod == "\\end_removed_modules")
2405                         break;
2406                 removed_modules_.push_back(mod);
2407                 lex.eatLine();
2408         }
2409         // now we want to remove any removed modules that were previously
2410         // added. normally, that will be because default modules were added in
2411         // setBaseClass(), which gets called when \textclass is read at the
2412         // start of the read.
2413         list<string>::const_iterator rit = removed_modules_.begin();
2414         list<string>::const_iterator const ren = removed_modules_.end();
2415         for (; rit != ren; ++rit) {
2416                 LayoutModuleList::iterator const mit = layout_modules_.begin();
2417                 LayoutModuleList::iterator const men = layout_modules_.end();
2418                 LayoutModuleList::iterator found = find(mit, men, *rit);
2419                 if (found == men)
2420                         continue;
2421                 layout_modules_.erase(found);
2422         }
2423 }
2424
2425
2426 void BufferParams::readIncludeonly(Lexer & lex)
2427 {
2428         if (!lex.eatLine()) {
2429                 lyxerr << "Error (BufferParams::readIncludeonly):"
2430                                 "Unexpected end of input." << endl;
2431                 return;
2432         }
2433         while (true) {
2434                 string child = lex.getString();
2435                 if (child == "\\end_includeonly")
2436                         break;
2437                 included_children_.push_back(child);
2438                 lex.eatLine();
2439         }
2440 }
2441
2442
2443 string BufferParams::paperSizeName(PapersizePurpose purpose) const
2444 {
2445         switch (papersize) {
2446         case PAPER_DEFAULT:
2447                 // could be anything, so don't guess
2448                 return string();
2449         case PAPER_CUSTOM: {
2450                 if (purpose == XDVI && !paperwidth.empty() &&
2451                     !paperheight.empty()) {
2452                         // heightxwidth<unit>
2453                         string first = paperwidth;
2454                         string second = paperheight;
2455                         if (orientation == ORIENTATION_LANDSCAPE)
2456                                 first.swap(second);
2457                         // cut off unit.
2458                         return first.erase(first.length() - 2)
2459                                 + "x" + second;
2460                 }
2461                 return string();
2462         }
2463         case PAPER_A0:
2464                 // dvips and dvipdfm do not know this
2465                 if (purpose == DVIPS || purpose == DVIPDFM)
2466                         return string();
2467                 return "a0";
2468         case PAPER_A1:
2469                 if (purpose == DVIPS || purpose == DVIPDFM)
2470                         return string();
2471                 return "a1";
2472         case PAPER_A2:
2473                 if (purpose == DVIPS || purpose == DVIPDFM)
2474                         return string();
2475                 return "a2";
2476         case PAPER_A3:
2477                 return "a3";
2478         case PAPER_A4:
2479                 return "a4";
2480         case PAPER_A5:
2481                 return "a5";
2482         case PAPER_A6:
2483                 if (purpose == DVIPS || purpose == DVIPDFM)
2484                         return string();
2485                 return "a6";
2486         case PAPER_B0:
2487                 if (purpose == DVIPS || purpose == DVIPDFM)
2488                         return string();
2489                 return "b0";
2490         case PAPER_B1:
2491                 if (purpose == DVIPS || purpose == DVIPDFM)
2492                         return string();
2493                 return "b1";
2494         case PAPER_B2:
2495                 if (purpose == DVIPS || purpose == DVIPDFM)
2496                         return string();
2497                 return "b2";
2498         case PAPER_B3:
2499                 if (purpose == DVIPS || purpose == DVIPDFM)
2500                         return string();
2501                 return "b3";
2502         case PAPER_B4:
2503                 // dvipdfm does not know this
2504                 if (purpose == DVIPDFM)
2505                         return string();
2506                 return "b4";
2507         case PAPER_B5:
2508                 if (purpose == DVIPDFM)
2509                         return string();
2510                 return "b5";
2511         case PAPER_B6:
2512                 if (purpose == DVIPS || purpose == DVIPDFM)
2513                         return string();
2514                 return "b6";
2515         case PAPER_C0:
2516                 if (purpose == DVIPS || purpose == DVIPDFM)
2517                         return string();
2518                 return "c0";
2519         case PAPER_C1:
2520                 if (purpose == DVIPS || purpose == DVIPDFM)
2521                         return string();
2522                 return "c1";
2523         case PAPER_C2:
2524                 if (purpose == DVIPS || purpose == DVIPDFM)
2525                         return string();
2526                 return "c2";
2527         case PAPER_C3:
2528                 if (purpose == DVIPS || purpose == DVIPDFM)
2529                         return string();
2530                 return "c3";
2531         case PAPER_C4:
2532                 if (purpose == DVIPS || purpose == DVIPDFM)
2533                         return string();
2534                 return "c4";
2535         case PAPER_C5:
2536                 if (purpose == DVIPS || purpose == DVIPDFM)
2537                         return string();
2538                 return "c5";
2539         case PAPER_C6:
2540                 if (purpose == DVIPS || purpose == DVIPDFM)
2541                         return string();
2542                 return "c6";
2543         case PAPER_JISB0:
2544                 if (purpose == DVIPS || purpose == DVIPDFM)
2545                         return string();
2546                 return "jisb0";
2547         case PAPER_JISB1:
2548                 if (purpose == DVIPS || purpose == DVIPDFM)
2549                         return string();
2550                 return "jisb1";
2551         case PAPER_JISB2:
2552                 if (purpose == DVIPS || purpose == DVIPDFM)
2553                         return string();
2554                 return "jisb2";
2555         case PAPER_JISB3:
2556                 if (purpose == DVIPS || purpose == DVIPDFM)
2557                         return string();
2558                 return "jisb3";
2559         case PAPER_JISB4:
2560                 if (purpose == DVIPS || purpose == DVIPDFM)
2561                         return string();
2562                 return "jisb4";
2563         case PAPER_JISB5:
2564                 if (purpose == DVIPS || purpose == DVIPDFM)
2565                         return string();
2566                 return "jisb5";
2567         case PAPER_JISB6:
2568                 if (purpose == DVIPS || purpose == DVIPDFM)
2569                         return string();
2570                 return "jisb6";
2571         case PAPER_USEXECUTIVE:
2572                 // dvipdfm does not know this
2573                 if (purpose == DVIPDFM)
2574                         return string();
2575                 return "foolscap";
2576         case PAPER_USLEGAL:
2577                 return "legal";
2578         case PAPER_USLETTER:
2579         default:
2580                 if (purpose == XDVI)
2581                         return "us";
2582                 return "letter";
2583         }
2584 }
2585
2586
2587 string const BufferParams::dvips_options() const
2588 {
2589         string result;
2590
2591         // If the class loads the geometry package, we do not know which
2592         // paper size is used, since we do not set it (bug 7013).
2593         // Therefore we must not specify any argument here.
2594         // dvips gets the correct paper size via DVI specials in this case
2595         // (if the class uses the geometry package correctly).
2596         if (documentClass().provides("geometry"))
2597                 return result;
2598
2599         if (use_geometry
2600             && papersize == PAPER_CUSTOM
2601             && !lyxrc.print_paper_dimension_flag.empty()
2602             && !paperwidth.empty()
2603             && !paperheight.empty()) {
2604                 // using a custom papersize
2605                 result = lyxrc.print_paper_dimension_flag;
2606                 result += ' ' + paperwidth;
2607                 result += ',' + paperheight;
2608         } else {
2609                 string const paper_option = paperSizeName(DVIPS);
2610                 if (!paper_option.empty() && (paper_option != "letter" ||
2611                     orientation != ORIENTATION_LANDSCAPE)) {
2612                         // dvips won't accept -t letter -t landscape.
2613                         // In all other cases, include the paper size
2614                         // explicitly.
2615                         result = lyxrc.print_paper_flag;
2616                         result += ' ' + paper_option;
2617                 }
2618         }
2619         if (orientation == ORIENTATION_LANDSCAPE &&
2620             papersize != PAPER_CUSTOM)
2621                 result += ' ' + lyxrc.print_landscape_flag;
2622         return result;
2623 }
2624
2625
2626 string const BufferParams::font_encoding() const
2627 {
2628         return (fontenc == "global") ? lyxrc.fontenc : fontenc;
2629 }
2630
2631
2632 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
2633 {
2634         if (lang_package != "auto" && lang_package != "babel"
2635             && lang_package != "default" && lang_package != "none")
2636                 return lang_package;
2637         if (lyxrc.language_package_selection == LyXRC::LP_CUSTOM)
2638                 return lyxrc.language_custom_package;
2639         // suppress the babel call if there is no BabelName defined
2640         // for the document language in the lib/languages file and if no
2641         // other languages are used (lang_opts is then empty)
2642         if (lang_opts.empty())
2643                 return string();
2644         // either a specific language (AsBabelOptions setting in
2645         // lib/languages) or the prefs require the languages to
2646         // be submitted to babel itself (not the class).
2647         if (langoptions)
2648                 return "\\usepackage[" + lang_opts + "]{babel}";
2649         return "\\usepackage{babel}";
2650 }
2651
2652
2653 docstring BufferParams::getGraphicsDriver(string const & package) const
2654 {
2655         docstring result;
2656
2657         if (package == "geometry") {
2658                 if (graphics_driver == "dvips"
2659                     || graphics_driver == "dvipdfm"
2660                     || graphics_driver == "pdftex"
2661                     || graphics_driver == "vtex")
2662                         result = from_ascii(graphics_driver);
2663                 else if (graphics_driver == "dvipdfmx")
2664                         result = from_ascii("dvipdfm");
2665         }
2666
2667         return result;
2668 }
2669
2670
2671 void BufferParams::writeEncodingPreamble(otexstream & os,
2672                                          LaTeXFeatures & features) const
2673 {
2674         // XeTeX does not need this
2675         if (features.runparams().flavor == OutputParams::XETEX)
2676                 return;
2677         // LuaTeX neither, but with tex fonts, we need to load
2678         // the luainputenc package.
2679         if (features.runparams().flavor == OutputParams::LUATEX
2680                 || features.runparams().flavor == OutputParams::DVILUATEX) {
2681                 if (!useNonTeXFonts && inputenc != "default"
2682                     && ((inputenc == "auto" && language->encoding()->package() == Encoding::inputenc)
2683                         || (inputenc != "auto" && encoding().package() == Encoding::inputenc))) {
2684                         os << "\\usepackage[utf8]{luainputenc}\n";
2685                 }
2686                 return;
2687         }
2688         if (inputenc == "auto") {
2689                 string const doc_encoding =
2690                         language->encoding()->latexName();
2691                 Encoding::Package const package =
2692                         language->encoding()->package();
2693
2694                 // Create a list with all the input encodings used
2695                 // in the document
2696                 set<string> encodings =
2697                         features.getEncodingSet(doc_encoding);
2698
2699                 // If the "japanese" package (i.e. pLaTeX) is used,
2700                 // inputenc must be omitted.
2701                 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
2702                 if (package == Encoding::japanese)
2703                      features.require("japanese");
2704
2705                 if ((!encodings.empty() || package == Encoding::inputenc)
2706                     && !features.isRequired("japanese")) {
2707                         os << "\\usepackage[";
2708                         set<string>::const_iterator it = encodings.begin();
2709                         set<string>::const_iterator const end = encodings.end();
2710                         if (it != end) {
2711                                 os << from_ascii(*it);
2712                                 ++it;
2713                         }
2714                         for (; it != end; ++it)
2715                                 os << ',' << from_ascii(*it);
2716                         if (package == Encoding::inputenc) {
2717                                 if (!encodings.empty())
2718                                         os << ',';
2719                                 os << from_ascii(doc_encoding);
2720                         }
2721                         os << "]{inputenc}\n";
2722                 }
2723                 if (package == Encoding::CJK || features.mustProvide("CJK")) {
2724                         if (language->encoding()->name() == "utf8-cjk"
2725                             && LaTeXFeatures::isAvailable("CJKutf8"))
2726                                 os << "\\usepackage{CJKutf8}\n";
2727                         else
2728                                 os << "\\usepackage{CJK}\n";
2729                 }
2730         } else if (inputenc != "default") {
2731                 switch (encoding().package()) {
2732                 case Encoding::none:
2733                 case Encoding::japanese:
2734                         break;
2735                 case Encoding::inputenc:
2736                         // do not load inputenc if japanese is used
2737                         if (features.isRequired("japanese"))
2738                                 break;
2739                         os << "\\usepackage[" << from_ascii(inputenc)
2740                            << "]{inputenc}\n";
2741                         break;
2742                 case Encoding::CJK:
2743                         if (encoding().name() == "utf8-cjk"
2744                             && LaTeXFeatures::isAvailable("CJKutf8"))
2745                                 os << "\\usepackage{CJKutf8}\n";
2746                         else
2747                                 os << "\\usepackage{CJK}\n";
2748                         break;
2749                 }
2750         }
2751
2752         // The encoding "armscii8" (for Armenian) is only available when
2753         // the package "armtex" is loaded.
2754         if (language->encoding()->latexName() == "armscii8"
2755             || inputenc == "armscii8")
2756                 os << "\\usepackage{armtex}\n";
2757 }
2758
2759
2760 string const BufferParams::parseFontName(string const & name) const
2761 {
2762         string mangled = name;
2763         size_t const idx = mangled.find('[');
2764         if (idx == string::npos || idx == 0)
2765                 return mangled;
2766         else
2767                 return mangled.substr(0, idx - 1);
2768 }
2769
2770
2771 string const BufferParams::loadFonts(string const & rm,
2772                                      string const & sf, string const & tt,
2773                                      bool const & sc, bool const & osf,
2774                                      int const & sfscale, int const & ttscale,
2775                                      bool const & use_systemfonts,
2776                                      LaTeXFeatures & features) const
2777 {
2778         /* The LaTeX font world is in a flux. In the PSNFSS font interface,
2779            several packages have been replaced by others, that might not
2780            be installed on every system. We have to take care for that
2781            (see psnfss.pdf). We try to support all psnfss fonts as well
2782            as the fonts that have become de facto standard in the LaTeX
2783            world (e.g. Latin Modern). We do not support obsolete fonts
2784            (like PSLatex). In general, it should be possible to mix any
2785            rm font with any sf or tt font, respectively. (JSpitzm)
2786            TODO:
2787                 -- separate math fonts.
2788         */
2789
2790         if (rm == "default" && sf == "default" && tt == "default")
2791                 //nothing to do
2792                 return string();
2793
2794         ostringstream os;
2795
2796         /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
2797          * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
2798          * Mapping=tex-text option assures TeX ligatures (such as "--")
2799          * are resolved. Note that tt does not use these ligatures.
2800          * TODO:
2801          *    -- add more GUI options?
2802          *    -- add more fonts (fonts for other scripts)
2803          *    -- if there's a way to find out if a font really supports
2804          *       OldStyle, enable/disable the widget accordingly.
2805         */
2806         if (use_systemfonts && features.isAvailable("fontspec")) {
2807                 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
2808                 // However, until v.2 (2010/07/11) fontspec only knew
2809                 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
2810                 // was introduced for both XeTeX and LuaTeX (LuaTeX
2811                 // didn't understand "Mapping=tex-text", while XeTeX
2812                 // understood both. With most recent versions, both
2813                 // variants are understood by both engines. However,
2814                 // we want to provide support for at least TeXLive 2009
2815                 // (for XeTeX; LuaTeX is only supported as of v.2)
2816                 string const texmapping =
2817                         (features.runparams().flavor == OutputParams::XETEX) ?
2818                         "Mapping=tex-text" : "Ligatures=TeX";
2819                 if (rm != "default") {
2820                         os << "\\setmainfont[" << texmapping;
2821                         if (osf)
2822                                 os << ",Numbers=OldStyle";
2823                         os << "]{" << parseFontName(rm) << "}\n";
2824                 }
2825                 if (sf != "default") {
2826                         string const sans = parseFontName(sf);
2827                         if (sfscale != 100)
2828                                 os << "\\setsansfont[Scale="
2829                                    << float(sfscale) / 100
2830                                    << "," << texmapping << "]{"
2831                                    << sans << "}\n";
2832                         else
2833                                 os << "\\setsansfont[" << texmapping << "]{"
2834                                    << sans << "}\n";
2835                 }
2836                 if (tt != "default") {
2837                         string const mono = parseFontName(tt);
2838                         if (ttscale != 100)
2839                                 os << "\\setmonofont[Scale="
2840                                    << float(ttscale) / 100
2841                                    << "]{"
2842                                    << mono << "}\n";
2843                         else
2844                                 os << "\\setmonofont{"
2845                                    << mono << "}\n";
2846                 }
2847                 return os.str();
2848         }
2849
2850         // ROMAN FONTS
2851         // Computer Modern (must be explicitly selectable -- there might be classes
2852         // that define a different default font!
2853         if (rm == "cmr") {
2854                 os << "\\renewcommand{\\rmdefault}{cmr}\n";
2855                 // osf for Computer Modern needs eco.sty
2856                 if (osf)
2857                         os << "\\usepackage{eco}\n";
2858         }
2859         // Latin Modern Roman
2860         else if (rm == "lmodern")
2861                 os << "\\usepackage{lmodern}\n";
2862         // AE
2863         else if (rm == "ae") {
2864                 // not needed when using OT1 font encoding.
2865                 if (font_encoding() != "default")
2866                         os << "\\usepackage{ae,aecompl}\n";
2867         }
2868         // Times
2869         else if (rm == "times") {
2870                 // try to load the best available package
2871                 if (LaTeXFeatures::isAvailable("mathptmx"))
2872                         os << "\\usepackage{mathptmx}\n";
2873                 else if (LaTeXFeatures::isAvailable("mathptm"))
2874                         os << "\\usepackage{mathptm}\n";
2875                 else
2876                         os << "\\usepackage{times}\n";
2877         }
2878         // Palatino
2879         else if (rm == "palatino") {
2880                 // try to load the best available package
2881                 if (LaTeXFeatures::isAvailable("mathpazo")) {
2882                         os << "\\usepackage";
2883                         if (osf || sc) {
2884                                 os << '[';
2885                                 if (!osf)
2886                                         os << "sc";
2887                                 else
2888                                         // "osf" includes "sc"!
2889                                         os << "osf";
2890                                 os << ']';
2891                         }
2892                         os << "{mathpazo}\n";
2893                 }
2894                 else if (LaTeXFeatures::isAvailable("mathpple"))
2895                         os << "\\usepackage{mathpple}\n";
2896                 else
2897                         os << "\\usepackage{palatino}\n";
2898         }
2899         // Utopia
2900         else if (rm == "utopia") {
2901                 // fourier supersedes utopia.sty, but does
2902                 // not work with OT1 encoding.
2903                 if (LaTeXFeatures::isAvailable("fourier")
2904                     && font_encoding() != "default") {
2905                         os << "\\usepackage";
2906                         if (osf || sc) {
2907                                 os << '[';
2908                                 if (sc)
2909                                         os << "expert";
2910                                 if (osf && sc)
2911                                         os << ',';
2912                                 if (osf)
2913                                         os << "oldstyle";
2914                                 os << ']';
2915                         }
2916                         os << "{fourier}\n";
2917                 }
2918                 else
2919                         os << "\\usepackage{utopia}\n";
2920         }
2921         // Bera (complete fontset)
2922         else if (rm == "bera" && sf == "default" && tt == "default")
2923                 os << "\\usepackage{bera}\n";
2924         // everything else
2925         else if (rm != "default")
2926                 os << "\\usepackage" << "{" << rm << "}\n";
2927
2928         // SANS SERIF
2929         // Helvetica, Bera Sans
2930         if (sf == "helvet" || sf == "berasans") {
2931                 if (sfscale != 100)
2932                         os << "\\usepackage[scaled=" << float(sfscale) / 100
2933                            << "]{" << sf << "}\n";
2934                 else
2935                         os << "\\usepackage{" << sf << "}\n";
2936         }
2937         // Avant Garde
2938         else if (sf == "avant")
2939                 os << "\\usepackage{" << sf << "}\n";
2940         // Computer Modern, Latin Modern, CM Bright
2941         else if (sf != "default")
2942                 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
2943
2944         // monospaced/typewriter
2945         // Courier, LuxiMono
2946         if (tt == "luximono" || tt == "beramono") {
2947                 if (ttscale != 100)
2948                         os << "\\usepackage[scaled=" << float(ttscale) / 100
2949                            << "]{" << tt << "}\n";
2950                 else
2951                         os << "\\usepackage{" << tt << "}\n";
2952         }
2953         // Courier
2954         else if (tt == "courier" )
2955                 os << "\\usepackage{" << tt << "}\n";
2956         // Computer Modern, Latin Modern, CM Bright
2957         else if (tt != "default")
2958                 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
2959
2960         return os.str();
2961 }
2962
2963
2964 Encoding const & BufferParams::encoding() const
2965 {
2966         // FIXME: actually, we should check for the flavor
2967         // or runparams.isFullyUnicode() here:
2968         // This check will not work with XeTeX/LuaTeX and tex fonts.
2969         // Thus we have to reset the encoding in Buffer::makeLaTeXFile.
2970         if (useNonTeXFonts)
2971                 return *(encodings.fromLaTeXName("utf8-plain"));
2972         if (inputenc == "auto" || inputenc == "default")
2973                 return *language->encoding();
2974         Encoding const * const enc = encodings.fromLaTeXName(inputenc);
2975         if (enc)
2976                 return *enc;
2977         LYXERR0("Unknown inputenc value `" << inputenc
2978                << "'. Using `auto' instead.");
2979         return *language->encoding();
2980 }
2981
2982
2983 bool BufferParams::addCiteEngine(string const & engine)
2984 {
2985         LayoutModuleList::const_iterator it = cite_engine_.begin();
2986         LayoutModuleList::const_iterator en = cite_engine_.end();
2987         for (; it != en; ++it)
2988                 if (*it == engine)
2989                         return false;
2990         cite_engine_.push_back(engine);
2991         return true;
2992 }
2993
2994
2995 bool BufferParams::addCiteEngine(vector<string> const & engine)
2996 {
2997         vector<string>::const_iterator it = engine.begin();
2998         vector<string>::const_iterator en = engine.end();
2999         bool ret = true;
3000         for (; it != en; ++it)
3001                 if (!addCiteEngine(*it))
3002                         ret = false;
3003         return ret;
3004 }
3005
3006
3007 string const & BufferParams::defaultBiblioStyle() const
3008 {
3009         return documentClass().defaultBiblioStyle();
3010 }
3011
3012
3013 bool const & BufferParams::fullAuthorList() const
3014 {
3015         return documentClass().fullAuthorList();
3016 }
3017
3018
3019 void BufferParams::setCiteEngine(string const & engine)
3020 {
3021         clearCiteEngine();
3022         addCiteEngine(engine);
3023 }
3024
3025
3026 void BufferParams::setCiteEngine(vector<string> const & engine)
3027 {
3028         clearCiteEngine();
3029         addCiteEngine(engine);
3030 }
3031
3032
3033 vector<string> BufferParams::citeCommands() const
3034 {
3035         static CitationStyle const default_style;
3036         vector<string> commands =
3037                 documentClass().citeCommands(citeEngineType());
3038         if (commands.empty())
3039                 commands.push_back(default_style.cmd);
3040         return commands;
3041 }
3042
3043
3044 vector<CitationStyle> BufferParams::citeStyles() const
3045 {
3046         static CitationStyle const default_style;
3047         vector<CitationStyle> styles =
3048                 documentClass().citeStyles(citeEngineType());
3049         if (styles.empty())
3050                 styles.push_back(default_style);
3051         return styles;
3052 }
3053
3054 } // namespace lyx