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