]> git.lyx.org Git - lyx.git/blob - src/BufferParams.cpp
again some things which cherry pick did not catch, sorry
[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 if (dformat == "text")
2176                 result = OutputParams::TEXT;
2177         else {
2178                 // Try to determine flavor of default output format
2179                 vector<string> backs = backends();
2180                 if (find(backs.begin(), backs.end(), dformat) == backs.end()) {
2181                         // Get shortest path to format
2182                         Graph::EdgePath path;
2183                         for (vector<string>::const_iterator it = backs.begin();
2184                             it != backs.end(); ++it) {
2185                                 Graph::EdgePath p = theConverters().getPath(*it, dformat);
2186                                 if (!p.empty() && (path.empty() || p.size() < path.size())) {
2187                                         path = p;
2188                                 }
2189                         }
2190                         if (!path.empty())
2191                                 result = theConverters().getFlavor(path);
2192                 }
2193         }
2194         // cache this flavor
2195         default_flavors_[dformat] = result;
2196         return result;
2197 }
2198
2199
2200 string BufferParams::getDefaultOutputFormat() const
2201 {
2202         if (!default_output_format.empty()
2203             && default_output_format != "default")
2204                 return default_output_format;
2205         if (isDocBook()
2206             || useNonTeXFonts
2207             || encoding().package() == Encoding::japanese) {
2208                 vector<Format const *> const formats = exportableFormats(true);
2209                 if (formats.empty())
2210                         return string();
2211                 // return the first we find
2212                 return formats.front()->name();
2213         }
2214         return lyxrc.default_view_format;
2215 }
2216
2217 Font const BufferParams::getFont() const
2218 {
2219         FontInfo f = documentClass().defaultfont();
2220         if (fonts_default_family == "rmdefault")
2221                 f.setFamily(ROMAN_FAMILY);
2222         else if (fonts_default_family == "sfdefault")
2223                 f.setFamily(SANS_FAMILY);
2224         else if (fonts_default_family == "ttdefault")
2225                 f.setFamily(TYPEWRITER_FAMILY);
2226         return Font(f, language);
2227 }
2228
2229
2230 bool BufferParams::isLatex() const
2231 {
2232         return documentClass().outputType() == LATEX;
2233 }
2234
2235
2236 bool BufferParams::isLiterate() const
2237 {
2238         return documentClass().outputType() == LITERATE;
2239 }
2240
2241
2242 bool BufferParams::isDocBook() const
2243 {
2244         return documentClass().outputType() == DOCBOOK;
2245 }
2246
2247
2248 void BufferParams::readPreamble(Lexer & lex)
2249 {
2250         if (lex.getString() != "\\begin_preamble")
2251                 lyxerr << "Error (BufferParams::readPreamble):"
2252                         "consistency check failed." << endl;
2253
2254         preamble = lex.getLongString("\\end_preamble");
2255 }
2256
2257
2258 void BufferParams::readLocalLayout(Lexer & lex)
2259 {
2260         if (lex.getString() != "\\begin_local_layout")
2261                 lyxerr << "Error (BufferParams::readLocalLayout):"
2262                         "consistency check failed." << endl;
2263
2264         local_layout = lex.getLongString("\\end_local_layout");
2265 }
2266
2267
2268 bool BufferParams::setLanguage(string const & lang)
2269 {
2270         Language const *new_language = languages.getLanguage(lang);
2271         if (!new_language) {
2272                 // Language lang was not found
2273                 return false;
2274         }
2275         language = new_language;
2276         return true;
2277 }
2278
2279
2280 void BufferParams::readLanguage(Lexer & lex)
2281 {
2282         if (!lex.next()) return;
2283
2284         string const tmptok = lex.getString();
2285
2286         // check if tmptok is part of tex_babel in tex-defs.h
2287         if (!setLanguage(tmptok)) {
2288                 // Language tmptok was not found
2289                 language = default_language;
2290                 lyxerr << "Warning: Setting language `"
2291                        << tmptok << "' to `" << language->lang()
2292                        << "'." << endl;
2293         }
2294 }
2295
2296
2297 void BufferParams::readGraphicsDriver(Lexer & lex)
2298 {
2299         if (!lex.next())
2300                 return;
2301
2302         string const tmptok = lex.getString();
2303         // check if tmptok is part of tex_graphics in tex_defs.h
2304         int n = 0;
2305         while (true) {
2306                 string const test = tex_graphics[n++];
2307
2308                 if (test == tmptok) {
2309                         graphics_driver = tmptok;
2310                         break;
2311                 }
2312                 if (test.empty()) {
2313                         lex.printError(
2314                                 "Warning: graphics driver `$$Token' not recognized!\n"
2315                                 "         Setting graphics driver to `default'.\n");
2316                         graphics_driver = "default";
2317                         break;
2318                 }
2319         }
2320 }
2321
2322
2323 void BufferParams::readBullets(Lexer & lex)
2324 {
2325         if (!lex.next())
2326                 return;
2327
2328         int const index = lex.getInteger();
2329         lex.next();
2330         int temp_int = lex.getInteger();
2331         user_defined_bullet(index).setFont(temp_int);
2332         temp_bullet(index).setFont(temp_int);
2333         lex >> temp_int;
2334         user_defined_bullet(index).setCharacter(temp_int);
2335         temp_bullet(index).setCharacter(temp_int);
2336         lex >> temp_int;
2337         user_defined_bullet(index).setSize(temp_int);
2338         temp_bullet(index).setSize(temp_int);
2339 }
2340
2341
2342 void BufferParams::readBulletsLaTeX(Lexer & lex)
2343 {
2344         // The bullet class should be able to read this.
2345         if (!lex.next())
2346                 return;
2347         int const index = lex.getInteger();
2348         lex.next(true);
2349         docstring const temp_str = lex.getDocString();
2350
2351         user_defined_bullet(index).setText(temp_str);
2352         temp_bullet(index).setText(temp_str);
2353 }
2354
2355
2356 void BufferParams::readModules(Lexer & lex)
2357 {
2358         if (!lex.eatLine()) {
2359                 lyxerr << "Error (BufferParams::readModules):"
2360                                 "Unexpected end of input." << endl;
2361                 return;
2362         }
2363         while (true) {
2364                 string mod = lex.getString();
2365                 if (mod == "\\end_modules")
2366                         break;
2367                 addLayoutModule(mod);
2368                 lex.eatLine();
2369         }
2370 }
2371
2372
2373 void BufferParams::readRemovedModules(Lexer & lex)
2374 {
2375         if (!lex.eatLine()) {
2376                 lyxerr << "Error (BufferParams::readRemovedModules):"
2377                                 "Unexpected end of input." << endl;
2378                 return;
2379         }
2380         while (true) {
2381                 string mod = lex.getString();
2382                 if (mod == "\\end_removed_modules")
2383                         break;
2384                 removed_modules_.push_back(mod);
2385                 lex.eatLine();
2386         }
2387         // now we want to remove any removed modules that were previously
2388         // added. normally, that will be because default modules were added in
2389         // setBaseClass(), which gets called when \textclass is read at the
2390         // start of the read.
2391         list<string>::const_iterator rit = removed_modules_.begin();
2392         list<string>::const_iterator const ren = removed_modules_.end();
2393         for (; rit != ren; rit++) {
2394                 LayoutModuleList::iterator const mit = layout_modules_.begin();
2395                 LayoutModuleList::iterator const men = layout_modules_.end();
2396                 LayoutModuleList::iterator found = find(mit, men, *rit);
2397                 if (found == men)
2398                         continue;
2399                 layout_modules_.erase(found);
2400         }
2401 }
2402
2403
2404 void BufferParams::readIncludeonly(Lexer & lex)
2405 {
2406         if (!lex.eatLine()) {
2407                 lyxerr << "Error (BufferParams::readIncludeonly):"
2408                                 "Unexpected end of input." << endl;
2409                 return;
2410         }
2411         while (true) {
2412                 string child = lex.getString();
2413                 if (child == "\\end_includeonly")
2414                         break;
2415                 included_children_.push_back(child);
2416                 lex.eatLine();
2417         }
2418 }
2419
2420
2421 string BufferParams::paperSizeName(PapersizePurpose purpose) const
2422 {
2423         switch (papersize) {
2424         case PAPER_DEFAULT:
2425                 // could be anything, so don't guess
2426                 return string();
2427         case PAPER_CUSTOM: {
2428                 if (purpose == XDVI && !paperwidth.empty() &&
2429                     !paperheight.empty()) {
2430                         // heightxwidth<unit>
2431                         string first = paperwidth;
2432                         string second = paperheight;
2433                         if (orientation == ORIENTATION_LANDSCAPE)
2434                                 first.swap(second);
2435                         // cut off unit.
2436                         return first.erase(first.length() - 2)
2437                                 + "x" + second;
2438                 }
2439                 return string();
2440         }
2441         case PAPER_A0:
2442                 // dvips and dvipdfm do not know this
2443                 if (purpose == DVIPS || purpose == DVIPDFM)
2444                         return string();
2445                 return "a0";
2446         case PAPER_A1:
2447                 if (purpose == DVIPS || purpose == DVIPDFM)
2448                         return string();
2449                 return "a1";
2450         case PAPER_A2:
2451                 if (purpose == DVIPS || purpose == DVIPDFM)
2452                         return string();
2453                 return "a2";
2454         case PAPER_A3:
2455                 return "a3";
2456         case PAPER_A4:
2457                 return "a4";
2458         case PAPER_A5:
2459                 return "a5";
2460         case PAPER_A6:
2461                 if (purpose == DVIPS || purpose == DVIPDFM)
2462                         return string();
2463                 return "a6";
2464         case PAPER_B0:
2465                 if (purpose == DVIPS || purpose == DVIPDFM)
2466                         return string();
2467                 return "b0";
2468         case PAPER_B1:
2469                 if (purpose == DVIPS || purpose == DVIPDFM)
2470                         return string();
2471                 return "b1";
2472         case PAPER_B2:
2473                 if (purpose == DVIPS || purpose == DVIPDFM)
2474                         return string();
2475                 return "b2";
2476         case PAPER_B3:
2477                 if (purpose == DVIPS || purpose == DVIPDFM)
2478                         return string();
2479                 return "b3";
2480         case PAPER_B4:
2481                 // dvipdfm does not know this
2482                 if (purpose == DVIPDFM)
2483                         return string();
2484                 return "b4";
2485         case PAPER_B5:
2486                 if (purpose == DVIPDFM)
2487                         return string();
2488                 return "b5";
2489         case PAPER_B6:
2490                 if (purpose == DVIPS || purpose == DVIPDFM)
2491                         return string();
2492                 return "b6";
2493         case PAPER_C0:
2494                 if (purpose == DVIPS || purpose == DVIPDFM)
2495                         return string();
2496                 return "c0";
2497         case PAPER_C1:
2498                 if (purpose == DVIPS || purpose == DVIPDFM)
2499                         return string();
2500                 return "c1";
2501         case PAPER_C2:
2502                 if (purpose == DVIPS || purpose == DVIPDFM)
2503                         return string();
2504                 return "c2";
2505         case PAPER_C3:
2506                 if (purpose == DVIPS || purpose == DVIPDFM)
2507                         return string();
2508                 return "c3";
2509         case PAPER_C4:
2510                 if (purpose == DVIPS || purpose == DVIPDFM)
2511                         return string();
2512                 return "c4";
2513         case PAPER_C5:
2514                 if (purpose == DVIPS || purpose == DVIPDFM)
2515                         return string();
2516                 return "c5";
2517         case PAPER_C6:
2518                 if (purpose == DVIPS || purpose == DVIPDFM)
2519                         return string();
2520                 return "c6";
2521         case PAPER_JISB0:
2522                 if (purpose == DVIPS || purpose == DVIPDFM)
2523                         return string();
2524                 return "jisb0";
2525         case PAPER_JISB1:
2526                 if (purpose == DVIPS || purpose == DVIPDFM)
2527                         return string();
2528                 return "jisb1";
2529         case PAPER_JISB2:
2530                 if (purpose == DVIPS || purpose == DVIPDFM)
2531                         return string();
2532                 return "jisb2";
2533         case PAPER_JISB3:
2534                 if (purpose == DVIPS || purpose == DVIPDFM)
2535                         return string();
2536                 return "jisb3";
2537         case PAPER_JISB4:
2538                 if (purpose == DVIPS || purpose == DVIPDFM)
2539                         return string();
2540                 return "jisb4";
2541         case PAPER_JISB5:
2542                 if (purpose == DVIPS || purpose == DVIPDFM)
2543                         return string();
2544                 return "jisb5";
2545         case PAPER_JISB6:
2546                 if (purpose == DVIPS || purpose == DVIPDFM)
2547                         return string();
2548                 return "jisb6";
2549         case PAPER_USEXECUTIVE:
2550                 // dvipdfm does not know this
2551                 if (purpose == DVIPDFM)
2552                         return string();
2553                 return "foolscap";
2554         case PAPER_USLEGAL:
2555                 return "legal";
2556         case PAPER_USLETTER:
2557         default:
2558                 if (purpose == XDVI)
2559                         return "us";
2560                 return "letter";
2561         }
2562 }
2563
2564
2565 string const BufferParams::dvips_options() const
2566 {
2567         string result;
2568
2569         // If the class loads the geometry package, we do not know which
2570         // paper size is used, since we do not set it (bug 7013).
2571         // Therefore we must not specify any argument here.
2572         // dvips gets the correct paper size via DVI specials in this case
2573         // (if the class uses the geometry package correctly).
2574         if (documentClass().provides("geometry"))
2575                 return result;
2576
2577         if (use_geometry
2578             && papersize == PAPER_CUSTOM
2579             && !lyxrc.print_paper_dimension_flag.empty()
2580             && !paperwidth.empty()
2581             && !paperheight.empty()) {
2582                 // using a custom papersize
2583                 result = lyxrc.print_paper_dimension_flag;
2584                 result += ' ' + paperwidth;
2585                 result += ',' + paperheight;
2586         } else {
2587                 string const paper_option = paperSizeName(DVIPS);
2588                 if (!paper_option.empty() && (paper_option != "letter" ||
2589                     orientation != ORIENTATION_LANDSCAPE)) {
2590                         // dvips won't accept -t letter -t landscape.
2591                         // In all other cases, include the paper size
2592                         // explicitly.
2593                         result = lyxrc.print_paper_flag;
2594                         result += ' ' + paper_option;
2595                 }
2596         }
2597         if (orientation == ORIENTATION_LANDSCAPE &&
2598             papersize != PAPER_CUSTOM)
2599                 result += ' ' + lyxrc.print_landscape_flag;
2600         return result;
2601 }
2602
2603
2604 string const BufferParams::font_encoding() const
2605 {
2606         return (fontenc == "global") ? lyxrc.fontenc : fontenc;
2607 }
2608
2609
2610 string BufferParams::babelCall(string const & lang_opts, bool const langoptions) const
2611 {
2612         if (lang_package != "auto" && lang_package != "babel"
2613             && lang_package != "default" && lang_package != "none")
2614                 return lang_package;
2615         if (lyxrc.language_package_selection == LyXRC::LP_CUSTOM)
2616                 return lyxrc.language_custom_package;
2617         // suppress the babel call if there is no BabelName defined
2618         // for the document language in the lib/languages file and if no
2619         // other languages are used (lang_opts is then empty)
2620         if (lang_opts.empty())
2621                 return string();
2622         // either a specific language (AsBabelOptions setting in
2623         // lib/languages) or the prefs require the languages to
2624         // be submitted to babel itself (not the class).
2625         if (langoptions)
2626                 return "\\usepackage[" + lang_opts + "]{babel}";
2627         return "\\usepackage{babel}";
2628 }
2629
2630
2631 docstring BufferParams::getGraphicsDriver(string const & package) const
2632 {
2633         docstring result;
2634
2635         if (package == "geometry") {
2636                 if (graphics_driver == "dvips"
2637                     || graphics_driver == "dvipdfm"
2638                     || graphics_driver == "pdftex"
2639                     || graphics_driver == "vtex")
2640                         result = from_ascii(graphics_driver);
2641                 else if (graphics_driver == "dvipdfmx")
2642                         result = from_ascii("dvipdfm");
2643         }
2644
2645         return result;
2646 }
2647
2648
2649 void BufferParams::writeEncodingPreamble(otexstream & os,
2650                                          LaTeXFeatures & features) const
2651 {
2652         // XeTeX does not need this
2653         if (features.runparams().flavor == OutputParams::XETEX)
2654                 return;
2655         // LuaTeX neither, but with tex fonts, we need to load
2656         // the luainputenc package.
2657         if (features.runparams().flavor == OutputParams::LUATEX
2658                 || features.runparams().flavor == OutputParams::DVILUATEX) {
2659                 if (!useNonTeXFonts && inputenc != "default"
2660                     && ((inputenc == "auto" && language->encoding()->package() == Encoding::inputenc)
2661                         || (inputenc != "auto" && encoding().package() == Encoding::inputenc))) {
2662                         os << "\\usepackage[utf8]{luainputenc}\n";
2663                 }
2664                 return;
2665         }
2666         if (inputenc == "auto") {
2667                 string const doc_encoding =
2668                         language->encoding()->latexName();
2669                 Encoding::Package const package =
2670                         language->encoding()->package();
2671
2672                 // Create a list with all the input encodings used
2673                 // in the document
2674                 set<string> encodings =
2675                         features.getEncodingSet(doc_encoding);
2676
2677                 // If the "japanese" package (i.e. pLaTeX) is used,
2678                 // inputenc must be omitted.
2679                 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
2680                 if (package == Encoding::japanese)
2681                      features.require("japanese");
2682
2683                 if ((!encodings.empty() || package == Encoding::inputenc)
2684                     && !features.isRequired("japanese")) {
2685                         os << "\\usepackage[";
2686                         set<string>::const_iterator it = encodings.begin();
2687                         set<string>::const_iterator const end = encodings.end();
2688                         if (it != end) {
2689                                 os << from_ascii(*it);
2690                                 ++it;
2691                         }
2692                         for (; it != end; ++it)
2693                                 os << ',' << from_ascii(*it);
2694                         if (package == Encoding::inputenc) {
2695                                 if (!encodings.empty())
2696                                         os << ',';
2697                                 os << from_ascii(doc_encoding);
2698                         }
2699                         os << "]{inputenc}\n";
2700                 }
2701                 if (package == Encoding::CJK || features.mustProvide("CJK")) {
2702                         if (language->encoding()->name() == "utf8-cjk"
2703                             && LaTeXFeatures::isAvailable("CJKutf8"))
2704                                 os << "\\usepackage{CJKutf8}\n";
2705                         else
2706                                 os << "\\usepackage{CJK}\n";
2707                 }
2708         } else if (inputenc != "default") {
2709                 switch (encoding().package()) {
2710                 case Encoding::none:
2711                 case Encoding::japanese:
2712                         break;
2713                 case Encoding::inputenc:
2714                         // do not load inputenc if japanese is used
2715                         if (features.isRequired("japanese"))
2716                                 break;
2717                         os << "\\usepackage[" << from_ascii(inputenc)
2718                            << "]{inputenc}\n";
2719                         break;
2720                 case Encoding::CJK:
2721                         if (encoding().name() == "utf8-cjk"
2722                             && LaTeXFeatures::isAvailable("CJKutf8"))
2723                                 os << "\\usepackage{CJKutf8}\n";
2724                         else
2725                                 os << "\\usepackage{CJK}\n";
2726                         break;
2727                 }
2728         }
2729
2730         // The encoding "armscii8" (for Armenian) is only available when
2731         // the package "armtex" is loaded.
2732         if (language->encoding()->latexName() == "armscii8"
2733             || inputenc == "armscii8")
2734                 os << "\\usepackage{armtex}\n";
2735 }
2736
2737
2738 string const BufferParams::parseFontName(string const & name) const
2739 {
2740         string mangled = name;
2741         size_t const idx = mangled.find('[');
2742         if (idx == string::npos || idx == 0)
2743                 return mangled;
2744         else
2745                 return mangled.substr(0, idx - 1);
2746 }
2747
2748
2749 string const BufferParams::loadFonts(string const & rm,
2750                                      string const & sf, string const & tt,
2751                                      bool const & sc, bool const & osf,
2752                                      int const & sfscale, int const & ttscale,
2753                                      bool const & use_systemfonts,
2754                                      LaTeXFeatures & features) const
2755 {
2756         /* The LaTeX font world is in a flux. In the PSNFSS font interface,
2757            several packages have been replaced by others, that might not
2758            be installed on every system. We have to take care for that
2759            (see psnfss.pdf). We try to support all psnfss fonts as well
2760            as the fonts that have become de facto standard in the LaTeX
2761            world (e.g. Latin Modern). We do not support obsolete fonts
2762            (like PSLatex). In general, it should be possible to mix any
2763            rm font with any sf or tt font, respectively. (JSpitzm)
2764            TODO:
2765                 -- separate math fonts.
2766         */
2767
2768         if (rm == "default" && sf == "default" && tt == "default")
2769                 //nothing to do
2770                 return string();
2771
2772         ostringstream os;
2773
2774         /* Fontspec (XeTeX, LuaTeX): we provide GUI support for oldstyle
2775          * numbers (Numbers=OldStyle) and sf/tt scaling. The Ligatures=TeX/
2776          * Mapping=tex-text option assures TeX ligatures (such as "--")
2777          * are resolved. Note that tt does not use these ligatures.
2778          * TODO:
2779          *    -- add more GUI options?
2780          *    -- add more fonts (fonts for other scripts)
2781          *    -- if there's a way to find out if a font really supports
2782          *       OldStyle, enable/disable the widget accordingly.
2783         */
2784         if (use_systemfonts && features.isAvailable("fontspec")) {
2785                 // "Mapping=tex-text" and "Ligatures=TeX" are equivalent.
2786                 // However, until v.2 (2010/07/11) fontspec only knew
2787                 // Mapping=tex-text (for XeTeX only); then "Ligatures=TeX"
2788                 // was introduced for both XeTeX and LuaTeX (LuaTeX
2789                 // didn't understand "Mapping=tex-text", while XeTeX
2790                 // understood both. With most recent versions, both
2791                 // variants are understood by both engines. However,
2792                 // we want to provide support for at least TeXLive 2009
2793                 // (for XeTeX; LuaTeX is only supported as of v.2)
2794                 string const texmapping =
2795                         (features.runparams().flavor == OutputParams::XETEX) ?
2796                         "Mapping=tex-text" : "Ligatures=TeX";
2797                 if (rm != "default") {
2798                         os << "\\setmainfont[" << texmapping;
2799                         if (osf)
2800                                 os << ",Numbers=OldStyle";
2801                         os << "]{" << parseFontName(rm) << "}\n";
2802                 }
2803                 if (sf != "default") {
2804                         string const sans = parseFontName(sf);
2805                         if (sfscale != 100)
2806                                 os << "\\setsansfont[Scale="
2807                                    << float(sfscale) / 100
2808                                    << "," << texmapping << "]{"
2809                                    << sans << "}\n";
2810                         else
2811                                 os << "\\setsansfont[" << texmapping << "]{"
2812                                    << sans << "}\n";
2813                 }
2814                 if (tt != "default") {
2815                         string const mono = parseFontName(tt);
2816                         if (ttscale != 100)
2817                                 os << "\\setmonofont[Scale="
2818                                    << float(ttscale) / 100
2819                                    << "]{"
2820                                    << mono << "}\n";
2821                         else
2822                                 os << "\\setmonofont{"
2823                                    << mono << "}\n";
2824                 }
2825                 return os.str();
2826         }
2827
2828         // ROMAN FONTS
2829         // Computer Modern (must be explicitly selectable -- there might be classes
2830         // that define a different default font!
2831         if (rm == "cmr") {
2832                 os << "\\renewcommand{\\rmdefault}{cmr}\n";
2833                 // osf for Computer Modern needs eco.sty
2834                 if (osf)
2835                         os << "\\usepackage{eco}\n";
2836         }
2837         // Latin Modern Roman
2838         else if (rm == "lmodern")
2839                 os << "\\usepackage{lmodern}\n";
2840         // AE
2841         else if (rm == "ae") {
2842                 // not needed when using OT1 font encoding.
2843                 if (font_encoding() != "default")
2844                         os << "\\usepackage{ae,aecompl}\n";
2845         }
2846         // Times
2847         else if (rm == "times") {
2848                 // try to load the best available package
2849                 if (LaTeXFeatures::isAvailable("mathptmx"))
2850                         os << "\\usepackage{mathptmx}\n";
2851                 else if (LaTeXFeatures::isAvailable("mathptm"))
2852                         os << "\\usepackage{mathptm}\n";
2853                 else
2854                         os << "\\usepackage{times}\n";
2855         }
2856         // Palatino
2857         else if (rm == "palatino") {
2858                 // try to load the best available package
2859                 if (LaTeXFeatures::isAvailable("mathpazo")) {
2860                         os << "\\usepackage";
2861                         if (osf || sc) {
2862                                 os << '[';
2863                                 if (!osf)
2864                                         os << "sc";
2865                                 else
2866                                         // "osf" includes "sc"!
2867                                         os << "osf";
2868                                 os << ']';
2869                         }
2870                         os << "{mathpazo}\n";
2871                 }
2872                 else if (LaTeXFeatures::isAvailable("mathpple"))
2873                         os << "\\usepackage{mathpple}\n";
2874                 else
2875                         os << "\\usepackage{palatino}\n";
2876         }
2877         // Utopia
2878         else if (rm == "utopia") {
2879                 // fourier supersedes utopia.sty, but does
2880                 // not work with OT1 encoding.
2881                 if (LaTeXFeatures::isAvailable("fourier")
2882                     && font_encoding() != "default") {
2883                         os << "\\usepackage";
2884                         if (osf || sc) {
2885                                 os << '[';
2886                                 if (sc)
2887                                         os << "expert";
2888                                 if (osf && sc)
2889                                         os << ',';
2890                                 if (osf)
2891                                         os << "oldstyle";
2892                                 os << ']';
2893                         }
2894                         os << "{fourier}\n";
2895                 }
2896                 else
2897                         os << "\\usepackage{utopia}\n";
2898         }
2899         // Bera (complete fontset)
2900         else if (rm == "bera" && sf == "default" && tt == "default")
2901                 os << "\\usepackage{bera}\n";
2902         // everything else
2903         else if (rm != "default")
2904                 os << "\\usepackage" << "{" << rm << "}\n";
2905
2906         // SANS SERIF
2907         // Helvetica, Bera Sans
2908         if (sf == "helvet" || sf == "berasans") {
2909                 if (sfscale != 100)
2910                         os << "\\usepackage[scaled=" << float(sfscale) / 100
2911                            << "]{" << sf << "}\n";
2912                 else
2913                         os << "\\usepackage{" << sf << "}\n";
2914         }
2915         // Avant Garde
2916         else if (sf == "avant")
2917                 os << "\\usepackage{" << sf << "}\n";
2918         // Computer Modern, Latin Modern, CM Bright
2919         else if (sf != "default")
2920                 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
2921
2922         // monospaced/typewriter
2923         // Courier, LuxiMono
2924         if (tt == "luximono" || tt == "beramono") {
2925                 if (ttscale != 100)
2926                         os << "\\usepackage[scaled=" << float(ttscale) / 100
2927                            << "]{" << tt << "}\n";
2928                 else
2929                         os << "\\usepackage{" << tt << "}\n";
2930         }
2931         // Courier
2932         else if (tt == "courier" )
2933                 os << "\\usepackage{" << tt << "}\n";
2934         // Computer Modern, Latin Modern, CM Bright
2935         else if (tt != "default")
2936                 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
2937
2938         return os.str();
2939 }
2940
2941
2942 Encoding const & BufferParams::encoding() const
2943 {
2944         // FIXME: actually, we should check for the flavor
2945         // or runparams.isFullyUnicode() here:
2946         // This check will not work with XeTeX/LuaTeX and tex fonts.
2947         // Thus we have to reset the encoding in Buffer::makeLaTeXFile.
2948         if (useNonTeXFonts)
2949                 return *(encodings.fromLaTeXName("utf8-plain"));
2950         if (inputenc == "auto" || inputenc == "default")
2951                 return *language->encoding();
2952         Encoding const * const enc = encodings.fromLaTeXName(inputenc);
2953         if (enc)
2954                 return *enc;
2955         LYXERR0("Unknown inputenc value `" << inputenc
2956                << "'. Using `auto' instead.");
2957         return *language->encoding();
2958 }
2959
2960
2961 bool BufferParams::addCiteEngine(string const & engine)
2962 {
2963         LayoutModuleList::const_iterator it = cite_engine_.begin();
2964         LayoutModuleList::const_iterator en = cite_engine_.end();
2965         for (; it != en; ++it)
2966                 if (*it == engine)
2967                         return false;
2968         cite_engine_.push_back(engine);
2969         return true;
2970 }
2971
2972
2973 bool BufferParams::addCiteEngine(vector<string> const & engine)
2974 {
2975         vector<string>::const_iterator it = engine.begin();
2976         vector<string>::const_iterator en = engine.end();
2977         bool ret = true;
2978         for (; it != en; ++it)
2979                 if (!addCiteEngine(*it))
2980                         ret = false;
2981         return ret;
2982 }
2983
2984
2985 string const & BufferParams::defaultBiblioStyle() const
2986 {
2987         return documentClass().defaultBiblioStyle();
2988 }
2989
2990
2991 bool const & BufferParams::fullAuthorList() const
2992 {
2993         return documentClass().fullAuthorList();
2994 }
2995
2996
2997 void BufferParams::setCiteEngine(string const & engine)
2998 {
2999         clearCiteEngine();
3000         addCiteEngine(engine);
3001 }
3002
3003
3004 void BufferParams::setCiteEngine(vector<string> const & engine)
3005 {
3006         clearCiteEngine();
3007         addCiteEngine(engine);
3008 }
3009
3010
3011 vector<string> BufferParams::citeCommands() const
3012 {
3013         static CitationStyle const default_style;
3014         vector<string> commands =
3015                 documentClass().citeCommands(citeEngineType());
3016         if (commands.empty())
3017                 commands.push_back(default_style.cmd);
3018         return commands;
3019 }
3020
3021
3022 vector<CitationStyle> BufferParams::citeStyles() const
3023 {
3024         static CitationStyle const default_style;
3025         vector<CitationStyle> styles =
3026                 documentClass().citeStyles(citeEngineType());
3027         if (styles.empty())
3028                 styles.push_back(default_style);
3029         return styles;
3030 }
3031
3032 } // namespace lyx