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