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