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