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