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