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