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