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