]> git.lyx.org Git - lyx.git/blob - src/BufferParams.cpp
HTML for math fonts.
[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, and Mongolian
1214                 size_t latvian = language_options.str().find("latvian");
1215                 size_t lithu = language_options.str().find("lithuanian");
1216                 size_t mongo = language_options.str().find("mongolian");
1217                 // if Japanese is used, babel must directly be loaded
1218                 // with language options, not in the class options, see
1219                 // http://www.lyx.org/trac/ticket/4597#c4
1220                 size_t japan = language_options.str().find("japanese");
1221                 if (lyxrc.language_global_options && !language_options.str().empty()
1222                         && viet == string::npos && japan == string::npos
1223                         && latvian == string::npos && lithu == string::npos
1224                         && mongo == string::npos)
1225                         clsoptions << language_options.str() << ',';
1226         }
1227
1228         // the predefined options from the layout
1229         if (use_default_options && !tclass.options().empty())
1230                 clsoptions << tclass.options() << ',';
1231
1232         // the user-defined options
1233         if (!options.empty()) {
1234                 clsoptions << options << ',';
1235         }
1236
1237         string strOptions(clsoptions.str());
1238         if (!strOptions.empty()) {
1239                 strOptions = rtrim(strOptions, ",");
1240                 // FIXME UNICODE
1241                 os << '[' << from_utf8(strOptions) << ']';
1242         }
1243
1244         os << '{' << from_ascii(tclass.latexname()) << "}\n";
1245         texrow.newline();
1246         // end of \documentclass defs
1247
1248         if (useXetex) {
1249                 os << "\\usepackage{fontspec}\n";
1250                 texrow.newline();
1251         }
1252
1253         // font selection must be done before loading fontenc.sty
1254         string const fonts =
1255                 loadFonts(fontsRoman, fontsSans,
1256                           fontsTypewriter, fontsSC, fontsOSF,
1257                           fontsSansScale, fontsTypewriterScale, useXetex);
1258         if (!fonts.empty()) {
1259                 os << from_ascii(fonts);
1260                 texrow.newline();
1261         }
1262         if (fontsDefaultFamily != "default")
1263                 os << "\\renewcommand{\\familydefault}{\\"
1264                    << from_ascii(fontsDefaultFamily) << "}\n";
1265
1266         // set font encoding
1267         // for arabic_arabi and farsi we also need to load the LAE and
1268         // LFE encoding
1269         // XeTeX works without fontenc
1270         if (font_encoding() != "default" && language->lang() != "japanese"
1271             && !useXetex) {
1272                 if (language->lang() == "arabic_arabi"
1273                     || language->lang() == "farsi") {
1274                         os << "\\usepackage[" << from_ascii(font_encoding())
1275                            << ",LFE,LAE]{fontenc}\n";
1276                         texrow.newline();
1277                 } else {
1278                         os << "\\usepackage[" << from_ascii(font_encoding())
1279                            << "]{fontenc}\n";
1280                         texrow.newline();
1281                 }
1282         }
1283
1284         // handle inputenc etc.
1285         writeEncodingPreamble(os, features, texrow);
1286
1287         // includeonly
1288         if (!features.runparams().includeall && !includedChildren_.empty()) {
1289                 os << "\\includeonly{";
1290                 list<string>::const_iterator it = includedChildren_.begin();
1291                 bool first = true;
1292                 for (; it != includedChildren_.end() ; ++it) {
1293                         string incfile = *it;
1294                         FileName inc = makeAbsPath(incfile, filepath.absFilename());
1295                         string mangled = DocFileName(changeExtension(inc.absFilename(), ".tex")).
1296                         mangledFilename();
1297                         if (!features.runparams().nice)
1298                                 incfile = mangled;
1299                         // \includeonly doesn't want an extension 
1300                         incfile = changeExtension(incfile, string());
1301                         incfile = support::latex_path(incfile);
1302                         if (!incfile.empty()) {
1303                                 if (!first)
1304                                         os << ",";
1305                                 os << from_utf8(incfile);
1306                         }
1307                         first = false;
1308                 }
1309                 os << "}\n";
1310         }
1311
1312         if (!listings_params.empty() || features.isRequired("listings")) {
1313                 os << "\\usepackage{listings}\n";
1314                 texrow.newline();
1315         }
1316         if (!listings_params.empty()) {
1317                 os << "\\lstset{";
1318                 // do not test validity because listings_params is 
1319                 // supposed to be valid
1320                 string par =
1321                         InsetListingsParams(listings_params).separatedParams(true);
1322                 // we can't support all packages, but we should load the color package
1323                 if (par.find("\\color", 0) != string::npos)
1324                         features.require("color");
1325                 os << from_utf8(par);
1326                 // count the number of newlines
1327                 for (size_t i = 0; i < par.size(); ++i)
1328                         if (par[i] == '\n')
1329                                 texrow.newline();
1330                 os << "}\n";
1331                 texrow.newline();
1332         }
1333         if (!tclass.provides("geometry")
1334             && (use_geometry || nonstandard_papersize)) {
1335                 odocstringstream ods;
1336                 if (!getGraphicsDriver("geometry").empty())
1337                         ods << getGraphicsDriver("geometry");
1338                 if (orientation == ORIENTATION_LANDSCAPE)
1339                         ods << ",landscape";
1340                 switch (papersize) {
1341                 case PAPER_CUSTOM:
1342                         if (!paperwidth.empty())
1343                                 ods << ",paperwidth="
1344                                    << from_ascii(paperwidth);
1345                         if (!paperheight.empty())
1346                                 ods << ",paperheight="
1347                                    << from_ascii(paperheight);
1348                         break;
1349                 case PAPER_USLETTER:
1350                         ods << ",letterpaper";
1351                         break;
1352                 case PAPER_USLEGAL:
1353                         ods << ",legalpaper";
1354                         break;
1355                 case PAPER_USEXECUTIVE:
1356                         ods << ",executivepaper";
1357                         break;
1358                 case PAPER_A3:
1359                         ods << ",a3paper";
1360                         break;
1361                 case PAPER_A4:
1362                         ods << ",a4paper";
1363                         break;
1364                 case PAPER_A5:
1365                         ods << ",a5paper";
1366                         break;
1367                 case PAPER_B3:
1368                         ods << ",b3paper";
1369                         break;
1370                 case PAPER_B4:
1371                         ods << ",b4paper";
1372                         break;
1373                 case PAPER_B5:
1374                         ods << ",b5paper";
1375                         break;
1376                 default:
1377                         // default papersize ie PAPER_DEFAULT
1378                         switch (lyxrc.default_papersize) {
1379                         case PAPER_DEFAULT: // keep compiler happy
1380                         case PAPER_USLETTER:
1381                                 ods << ",letterpaper";
1382                                 break;
1383                         case PAPER_USLEGAL:
1384                                 ods << ",legalpaper";
1385                                 break;
1386                         case PAPER_USEXECUTIVE:
1387                                 ods << ",executivepaper";
1388                                 break;
1389                         case PAPER_A3:
1390                                 ods << ",a3paper";
1391                                 break;
1392                         case PAPER_A4:
1393                                 ods << ",a4paper";
1394                                 break;
1395                         case PAPER_A5:
1396                                 ods << ",a5paper";
1397                                 break;
1398                         case PAPER_B5:
1399                                 ods << ",b5paper";
1400                                 break;
1401                         case PAPER_B3:
1402                         case PAPER_B4:
1403                         case PAPER_CUSTOM:
1404                                 break;
1405                         }
1406                 }
1407                 docstring const g_options = trim(ods.str(), ",");
1408                 os << "\\usepackage";
1409                 if (!g_options.empty())
1410                         os << '[' << g_options << ']';
1411                 os << "{geometry}\n";
1412                 texrow.newline();
1413                 os << "\\geometry{verbose";
1414                 if (!topmargin.empty())
1415                         os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1416                 if (!bottommargin.empty())
1417                         os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1418                 if (!leftmargin.empty())
1419                         os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1420                 if (!rightmargin.empty())
1421                         os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1422                 if (!headheight.empty())
1423                         os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1424                 if (!headsep.empty())
1425                         os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1426                 if (!footskip.empty())
1427                         os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1428                 if (!columnsep.empty())
1429                         os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1430                 os << "}\n";
1431                 texrow.newline();
1432         } else if (orientation == ORIENTATION_LANDSCAPE) {
1433                 features.require("papersize");
1434         }
1435
1436         if (tokenPos(tclass.opt_pagestyle(),
1437                      '|', pagestyle) >= 0) {
1438                 if (pagestyle == "fancy") {
1439                         os << "\\usepackage{fancyhdr}\n";
1440                         texrow.newline();
1441                 }
1442                 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1443                 texrow.newline();
1444         }
1445
1446         // only output when the background color is not white
1447         if (backgroundcolor != lyx::rgbFromHexName("#ffffff")) {
1448                 // only require color here, the background color will be defined
1449                 // in LaTeXFeatures.cpp to avoid interferences with the LaTeX
1450                 // package pdfpages 
1451                 features.require("color");
1452                 features.require("pagecolor");
1453         }
1454
1455         // Only if class has a ToC hierarchy
1456         if (tclass.hasTocLevels()) {
1457                 if (secnumdepth != tclass.secnumdepth()) {
1458                         os << "\\setcounter{secnumdepth}{"
1459                            << secnumdepth
1460                            << "}\n";
1461                         texrow.newline();
1462                 }
1463                 if (tocdepth != tclass.tocdepth()) {
1464                         os << "\\setcounter{tocdepth}{"
1465                            << tocdepth
1466                            << "}\n";
1467                         texrow.newline();
1468                 }
1469         }
1470
1471         if (paragraph_separation) {
1472                 // when skip separation
1473                 switch (getDefSkip().kind()) {
1474                 case VSpace::SMALLSKIP:
1475                         os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1476                         break;
1477                 case VSpace::MEDSKIP:
1478                         os << "\\setlength{\\parskip}{\\medskipamount}\n";
1479                         break;
1480                 case VSpace::BIGSKIP:
1481                         os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1482                         break;
1483                 case VSpace::LENGTH:
1484                         os << "\\setlength{\\parskip}{"
1485                            << from_utf8(getDefSkip().length().asLatexString())
1486                            << "}\n";
1487                         break;
1488                 default: // should never happen // Then delete it.
1489                         os << "\\setlength{\\parskip}{\\medskipamount}\n";
1490                         break;
1491                 }
1492                 texrow.newline();
1493                 os << "\\setlength{\\parindent}{0pt}\n";
1494                 texrow.newline();
1495         } else {
1496                 // when separation by indentation
1497                 // only output something when a width is given
1498                 if (getIndentation().asLyXCommand() != "default") {
1499                         os << "\\setlength{\\parindent}{"
1500                                 << from_utf8(getIndentation().asLatexCommand())
1501                            << "}\n";
1502                         texrow.newline();
1503                 }
1504         }
1505
1506         // Now insert the LyX specific LaTeX commands...
1507         docstring lyxpreamble;
1508
1509         // due to interferences with babel and hyperref, the color package has to
1510         // be loaded (when it is not already loaded) before babel when hyperref
1511         // is used with the colorlinks option, see
1512         // http://www.lyx.org/trac/ticket/5291
1513         // we decided therefore to load color always before babel, see
1514         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
1515         lyxpreamble += from_ascii(features.getColorOptions());
1516         
1517         // If we use hyperref, jurabib, japanese, or vietnamese, we have to call babel before them.
1518         if (use_babel
1519                 && (features.isRequired("jurabib")
1520                         || features.isRequired("hyperref")
1521                         || features.isRequired("vietnamese")
1522                         || features.isRequired("japanese") ) ) {
1523                                 // FIXME UNICODE
1524                                 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1525                                 lyxpreamble += from_utf8(features.getBabelOptions()) + '\n';
1526         }
1527
1528         // The optional packages;
1529         lyxpreamble += from_ascii(features.getPackages());
1530
1531         // Additional Indices
1532         if (features.isRequired("splitidx")) {
1533                 IndicesList::const_iterator iit = indiceslist().begin();
1534                 IndicesList::const_iterator iend = indiceslist().end();
1535                 for (; iit != iend; ++iit) {
1536                         lyxpreamble += "\\newindex[";
1537                         lyxpreamble += iit->index();
1538                         lyxpreamble += "]{";
1539                         lyxpreamble += iit->shortcut();
1540                         lyxpreamble += "}\n";
1541                 }
1542         }
1543
1544         // Line spacing
1545         lyxpreamble += from_utf8(spacing().writePreamble(tclass.provides("SetSpace")));
1546
1547         // PDF support.
1548         // * Hyperref manual: "Make sure it comes last of your loaded
1549         //   packages, to give it a fighting chance of not being over-written,
1550         //   since its job is to redefine many LaTeX commands."
1551         // * Email from Heiko Oberdiek: "It is usually better to load babel
1552         //   before hyperref. Then hyperref has a chance to detect babel.
1553         // * Has to be loaded before the "LyX specific LaTeX commands" to
1554         //   avoid errors with algorithm floats.
1555         // use hyperref explicitly if it is required
1556         if (features.isRequired("hyperref")) {
1557                 // pass what we have to stream here, since we need 
1558                 // to access the stream itself in PDFOptions.
1559                 os << lyxpreamble;
1560
1561                 int lines =
1562                         int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1563
1564                 OutputParams tmp_params = features.runparams();
1565                 lines += pdfoptions().writeLaTeX(tmp_params, os,
1566                                         documentClass().provides("hyperref"));
1567                 texrow.newlines(lines);
1568                 // set back for the rest
1569                 lyxpreamble.clear();
1570         }
1571
1572         // Will be surrounded by \makeatletter and \makeatother when not empty
1573         docstring atlyxpreamble;
1574
1575         // Some macros LyX will need
1576         docstring tmppreamble(features.getMacros());
1577
1578         if (!tmppreamble.empty())
1579                 atlyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1580                         "LyX specific LaTeX commands.\n"
1581                         + tmppreamble + '\n';
1582
1583         // the text class specific preamble
1584         tmppreamble = features.getTClassPreamble();
1585         if (!tmppreamble.empty())
1586                 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1587                         "Textclass specific LaTeX commands.\n"
1588                         + tmppreamble + '\n';
1589
1590         // suppress date if selected
1591         // use \@ifundefined because we cannot be sure that every document class
1592         // has a \date command
1593         if (suppress_date)
1594                 atlyxpreamble += "\\@ifundefined{date}{}{\\date{}}\n";
1595
1596         /* the user-defined preamble */
1597         if (!containsOnly(preamble, " \n\t"))
1598                 // FIXME UNICODE
1599                 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1600                         "User specified LaTeX commands.\n"
1601                         + from_utf8(preamble) + '\n';
1602
1603         // subfig loads internally the LaTeX package "caption". As
1604         // caption is a very popular package, users will load it in
1605         // the preamble. Therefore we must load subfig behind the
1606         // user-defined preamble and check if the caption package was
1607         // loaded or not. For the case that caption is loaded before
1608         // subfig, there is the subfig option "caption=false". This
1609         // option also works when a koma-script class is used and
1610         // koma's own caption commands are used instead of caption. We
1611         // use \PassOptionsToPackage here because the user could have
1612         // already loaded subfig in the preamble.
1613         if (features.isRequired("subfig")) {
1614                 atlyxpreamble += "\\@ifundefined{showcaptionsetup}{}{%\n"
1615                         " \\PassOptionsToPackage{caption=false}{subfig}}\n"
1616                         "\\usepackage{subfig}\n";
1617         }
1618
1619         // Itemize bullet settings need to be last in case the user
1620         // defines their own bullets that use a package included
1621         // in the user-defined preamble -- ARRae
1622         // Actually it has to be done much later than that
1623         // since some packages like frenchb make modifications
1624         // at \begin{document} time -- JMarc
1625         docstring bullets_def;
1626         for (int i = 0; i < 4; ++i) {
1627                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1628                         if (bullets_def.empty())
1629                                 bullets_def += "\\AtBeginDocument{\n";
1630                         bullets_def += "  \\def\\labelitemi";
1631                         switch (i) {
1632                                 // `i' is one less than the item to modify
1633                         case 0:
1634                                 break;
1635                         case 1:
1636                                 bullets_def += 'i';
1637                                 break;
1638                         case 2:
1639                                 bullets_def += "ii";
1640                                 break;
1641                         case 3:
1642                                 bullets_def += 'v';
1643                                 break;
1644                         }
1645                         bullets_def += '{' +
1646                                 user_defined_bullet(i).getText()
1647                                 + "}\n";
1648                 }
1649         }
1650
1651         if (!bullets_def.empty())
1652                 atlyxpreamble += bullets_def + "}\n\n";
1653
1654         if (!atlyxpreamble.empty())
1655                 lyxpreamble += "\n\\makeatletter\n"
1656                         + atlyxpreamble + "\\makeatother\n\n";
1657
1658         // We try to load babel late, in case it interferes with other packages.
1659         // Jurabib and Hyperref have to be called after babel, though.
1660         if (use_babel && !features.isRequired("jurabib")
1661             && !features.isRequired("hyperref")
1662             && !features.isRequired("vietnamese")
1663             && !features.isRequired("japanese")) {
1664                 // FIXME UNICODE
1665                 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1666                 lyxpreamble += from_utf8(features.getBabelOptions()) + '\n';
1667         }
1668
1669         docstring const i18npreamble = features.getTClassI18nPreamble(use_babel);
1670         if (!i18npreamble.empty())
1671                 lyxpreamble += i18npreamble + '\n';
1672
1673         int const nlines =
1674                 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1675         texrow.newlines(nlines);
1676
1677         os << lyxpreamble;
1678
1679         // these packages (xunicode, for that matter) need to be loaded at least
1680         // after amsmath, amssymb, esint and the other packages that provide 
1681         // special glyphs
1682         if (useXetex) {
1683                 os << "\\usepackage{xunicode}\n";
1684                 texrow.newline();
1685                 os << "\\usepackage{xltxtra}\n";
1686                 texrow.newline();
1687         }
1688         return use_babel;
1689 }
1690
1691
1692 void BufferParams::useClassDefaults()
1693 {
1694         DocumentClass const & tclass = documentClass();
1695
1696         sides = tclass.sides();
1697         columns = tclass.columns();
1698         pagestyle = tclass.pagestyle();
1699         use_default_options = true;
1700         // Only if class has a ToC hierarchy
1701         if (tclass.hasTocLevels()) {
1702                 secnumdepth = tclass.secnumdepth();
1703                 tocdepth = tclass.tocdepth();
1704         }
1705 }
1706
1707
1708 bool BufferParams::hasClassDefaults() const
1709 {
1710         DocumentClass const & tclass = documentClass();
1711
1712         return sides == tclass.sides()
1713                 && columns == tclass.columns()
1714                 && pagestyle == tclass.pagestyle()
1715                 && use_default_options
1716                 && secnumdepth == tclass.secnumdepth()
1717                 && tocdepth == tclass.tocdepth();
1718 }
1719
1720
1721 DocumentClass const & BufferParams::documentClass() const
1722 {
1723         return *doc_class_;
1724 }
1725
1726
1727 DocumentClass const * BufferParams::documentClassPtr() const {
1728         return doc_class_;
1729 }
1730
1731
1732 void BufferParams::setDocumentClass(DocumentClass const * const tc) {
1733         // evil, but this function is evil
1734         doc_class_ = const_cast<DocumentClass *>(tc);
1735 }
1736
1737
1738 bool BufferParams::setBaseClass(string const & classname)
1739 {
1740         LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
1741         LayoutFileList & bcl = LayoutFileList::get();
1742         if (!bcl.haveClass(classname)) {
1743                 docstring s = 
1744                         bformat(_("The document class %1$s could not be found. "
1745                                 "A default textclass with default layouts will be used. "
1746                                 "LyX might not be able to produce output unless a correct "
1747                                 "textclass is selected from the document settings dialog."),
1748                         from_utf8(classname));
1749                 frontend::Alert::error(_("Document class not found"), s);
1750                 bcl.addEmptyClass(classname);
1751         }
1752
1753         bool const success = bcl[classname].load();
1754         if (!success) {
1755                 docstring s = 
1756                         bformat(_("The document class %1$s could not be loaded."),
1757                         from_utf8(classname));
1758                 frontend::Alert::error(_("Could not load class"), s);
1759                 return false;
1760         }
1761
1762         pimpl_->baseClass_ = classname;
1763         layoutModules_.adaptToBaseClass(baseClass(), removedModules_);
1764         return true;
1765 }
1766
1767
1768 LayoutFile const * BufferParams::baseClass() const
1769 {
1770         if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
1771                 return &(LayoutFileList::get()[pimpl_->baseClass_]);
1772         else 
1773                 return 0;
1774 }
1775
1776
1777 LayoutFileIndex const & BufferParams::baseClassID() const
1778 {
1779         return pimpl_->baseClass_;
1780 }
1781
1782
1783 void BufferParams::makeDocumentClass()
1784 {
1785         if (!baseClass())
1786                 return;
1787
1788         doc_class_ = &(DocumentClassBundle::get().makeDocumentClass(*baseClass(), layoutModules_));
1789
1790         if (!local_layout.empty()) {
1791                 if (!doc_class_->read(local_layout, TextClass::MODULE)) {
1792                         docstring const msg = _("Error reading internal layout information");
1793                         frontend::Alert::warning(_("Read Error"), msg);
1794                 }
1795         }
1796 }
1797
1798 bool BufferParams::moduleCanBeAdded(string const & modName) const
1799 {
1800         return layoutModules_.moduleCanBeAdded(modName, baseClass());
1801 }
1802
1803
1804 bool BufferParams::addLayoutModule(string const & modName)
1805 {
1806         LayoutModuleList::const_iterator it = layoutModules_.begin();
1807         LayoutModuleList::const_iterator end = layoutModules_.end();
1808         for (; it != end; it++)
1809                 if (*it == modName) 
1810                         return false;
1811         layoutModules_.push_back(modName);
1812         return true;
1813 }
1814
1815
1816 Font const BufferParams::getFont() const
1817 {
1818         FontInfo f = documentClass().defaultfont();
1819         if (fontsDefaultFamily == "rmdefault")
1820                 f.setFamily(ROMAN_FAMILY);
1821         else if (fontsDefaultFamily == "sfdefault")
1822                 f.setFamily(SANS_FAMILY);
1823         else if (fontsDefaultFamily == "ttdefault")
1824                 f.setFamily(TYPEWRITER_FAMILY);
1825         return Font(f, language);
1826 }
1827
1828
1829 void BufferParams::readPreamble(Lexer & lex)
1830 {
1831         if (lex.getString() != "\\begin_preamble")
1832                 lyxerr << "Error (BufferParams::readPreamble):"
1833                         "consistency check failed." << endl;
1834
1835         preamble = lex.getLongString("\\end_preamble");
1836 }
1837
1838
1839 void BufferParams::readLocalLayout(Lexer & lex)
1840 {
1841         if (lex.getString() != "\\begin_local_layout")
1842                 lyxerr << "Error (BufferParams::readLocalLayout):"
1843                         "consistency check failed." << endl;
1844
1845         local_layout = lex.getLongString("\\end_local_layout");
1846 }
1847
1848
1849 void BufferParams::readLanguage(Lexer & lex)
1850 {
1851         if (!lex.next()) return;
1852
1853         string const tmptok = lex.getString();
1854
1855         // check if tmptok is part of tex_babel in tex-defs.h
1856         language = languages.getLanguage(tmptok);
1857         if (!language) {
1858                 // Language tmptok was not found
1859                 language = default_language;
1860                 lyxerr << "Warning: Setting language `"
1861                        << tmptok << "' to `" << language->lang()
1862                        << "'." << endl;
1863         }
1864 }
1865
1866
1867 void BufferParams::readGraphicsDriver(Lexer & lex)
1868 {
1869         if (!lex.next()) 
1870                 return;
1871
1872         string const tmptok = lex.getString();
1873         // check if tmptok is part of tex_graphics in tex_defs.h
1874         int n = 0;
1875         while (true) {
1876                 string const test = tex_graphics[n++];
1877
1878                 if (test == tmptok) {
1879                         graphicsDriver = tmptok;
1880                         break;
1881                 }
1882                 if (test.empty()) {
1883                         lex.printError(
1884                                 "Warning: graphics driver `$$Token' not recognized!\n"
1885                                 "         Setting graphics driver to `default'.\n");
1886                         graphicsDriver = "default";
1887                         break;
1888                 }
1889         }
1890 }
1891
1892
1893 void BufferParams::readBullets(Lexer & lex)
1894 {
1895         if (!lex.next()) 
1896                 return;
1897
1898         int const index = lex.getInteger();
1899         lex.next();
1900         int temp_int = lex.getInteger();
1901         user_defined_bullet(index).setFont(temp_int);
1902         temp_bullet(index).setFont(temp_int);
1903         lex >> temp_int;
1904         user_defined_bullet(index).setCharacter(temp_int);
1905         temp_bullet(index).setCharacter(temp_int);
1906         lex >> temp_int;
1907         user_defined_bullet(index).setSize(temp_int);
1908         temp_bullet(index).setSize(temp_int);
1909 }
1910
1911
1912 void BufferParams::readBulletsLaTeX(Lexer & lex)
1913 {
1914         // The bullet class should be able to read this.
1915         if (!lex.next()) 
1916                 return;
1917         int const index = lex.getInteger();
1918         lex.next(true);
1919         docstring const temp_str = lex.getDocString();
1920
1921         user_defined_bullet(index).setText(temp_str);
1922         temp_bullet(index).setText(temp_str);
1923 }
1924
1925
1926 void BufferParams::readModules(Lexer & lex)
1927 {
1928         if (!lex.eatLine()) {
1929                 lyxerr << "Error (BufferParams::readModules):"
1930                                 "Unexpected end of input." << endl;
1931                 return;
1932         }
1933         while (true) {
1934                 string mod = lex.getString();
1935                 if (mod == "\\end_modules")
1936                         break;
1937                 addLayoutModule(mod);
1938                 lex.eatLine();
1939         }
1940 }
1941
1942
1943 void BufferParams::readRemovedModules(Lexer & lex)
1944 {
1945         if (!lex.eatLine()) {
1946                 lyxerr << "Error (BufferParams::readRemovedModules):"
1947                                 "Unexpected end of input." << endl;
1948                 return;
1949         }
1950         while (true) {
1951                 string mod = lex.getString();
1952                 if (mod == "\\end_removed_modules")
1953                         break;
1954                 removedModules_.push_back(mod);
1955                 lex.eatLine();
1956         }
1957         // now we want to remove any removed modules that were previously 
1958         // added. normally, that will be because default modules were added in 
1959         // setBaseClass(), which gets called when \textclass is read at the 
1960         // start of the read.
1961         list<string>::const_iterator rit = removedModules_.begin();
1962         list<string>::const_iterator const ren = removedModules_.end();
1963         for (; rit != ren; rit++) {
1964                 LayoutModuleList::iterator const mit = layoutModules_.begin();
1965                 LayoutModuleList::iterator const men = layoutModules_.end();
1966                 LayoutModuleList::iterator found = find(mit, men, *rit);
1967                 if (found == men)
1968                         continue;
1969                 layoutModules_.erase(found);
1970         }
1971 }
1972
1973
1974 void BufferParams::readIncludeonly(Lexer & lex)
1975 {
1976         if (!lex.eatLine()) {
1977                 lyxerr << "Error (BufferParams::readIncludeonly):"
1978                                 "Unexpected end of input." << endl;
1979                 return;
1980         }
1981         while (true) {
1982                 string child = lex.getString();
1983                 if (child == "\\end_includeonly")
1984                         break;
1985                 includedChildren_.push_back(child);
1986                 lex.eatLine();
1987         }
1988 }
1989
1990
1991 string BufferParams::paperSizeName(PapersizePurpose purpose) const
1992 {
1993         char real_papersize = papersize;
1994         if (real_papersize == PAPER_DEFAULT)
1995                 real_papersize = lyxrc.default_papersize;
1996
1997         switch (real_papersize) {
1998         case PAPER_DEFAULT:
1999                 // could be anything, so don't guess
2000                 return string();
2001         case PAPER_CUSTOM: {
2002                 if (purpose == XDVI && !paperwidth.empty() &&
2003                     !paperheight.empty()) {
2004                         // heightxwidth<unit>
2005                         string first = paperwidth;
2006                         string second = paperheight;
2007                         if (orientation == ORIENTATION_LANDSCAPE)
2008                                 first.swap(second);
2009                         // cut off unit.
2010                         return first.erase(first.length() - 2)
2011                                 + "x" + second;
2012                 }
2013                 return string();
2014         }
2015         case PAPER_A3:
2016                 return "a3";
2017         case PAPER_A4:
2018                 return "a4";
2019         case PAPER_A5:
2020                 return "a5";
2021         case PAPER_B3:
2022                 // dvips and dvipdfm do not know this
2023                 if (purpose == DVIPS || purpose == DVIPDFM)
2024                         return string();
2025                 return "b3";
2026         case PAPER_B4:
2027                 // dvipdfm does not know this
2028                 if (purpose == DVIPDFM)
2029                         return string();
2030                 return "b4";
2031         case PAPER_B5:
2032                 // dvipdfm does not know this
2033                 if (purpose == DVIPDFM)
2034                         return string();
2035                 return "b5";
2036         case PAPER_USEXECUTIVE:
2037                 // dvipdfm does not know this
2038                 if (purpose == DVIPDFM)
2039                         return string();
2040                 return "foolscap";
2041         case PAPER_USLEGAL:
2042                 return "legal";
2043         case PAPER_USLETTER:
2044         default:
2045                 if (purpose == XDVI)
2046                         return "us";
2047                 return "letter";
2048         }
2049 }
2050
2051
2052 string const BufferParams::dvips_options() const
2053 {
2054         string result;
2055
2056         if (use_geometry
2057             && papersize == PAPER_CUSTOM
2058             && !lyxrc.print_paper_dimension_flag.empty()
2059             && !paperwidth.empty()
2060             && !paperheight.empty()) {
2061                 // using a custom papersize
2062                 result = lyxrc.print_paper_dimension_flag;
2063                 result += ' ' + paperwidth;
2064                 result += ',' + paperheight;
2065         } else {
2066                 string const paper_option = paperSizeName(DVIPS);
2067                 if (!paper_option.empty() && (paper_option != "letter" ||
2068                     orientation != ORIENTATION_LANDSCAPE)) {
2069                         // dvips won't accept -t letter -t landscape.
2070                         // In all other cases, include the paper size
2071                         // explicitly.
2072                         result = lyxrc.print_paper_flag;
2073                         result += ' ' + paper_option;
2074                 }
2075         }
2076         if (orientation == ORIENTATION_LANDSCAPE &&
2077             papersize != PAPER_CUSTOM)
2078                 result += ' ' + lyxrc.print_landscape_flag;
2079         return result;
2080 }
2081
2082
2083 string const BufferParams::font_encoding() const
2084 {
2085         return (fontenc == "global") ? lyxrc.fontenc : fontenc;
2086 }
2087
2088
2089 string BufferParams::babelCall(string const & lang_opts) const
2090 {
2091         string lang_pack = lyxrc.language_package;
2092         if (lang_pack != "\\usepackage{babel}")
2093                 return lang_pack;
2094         // suppress the babel call when there is no babel language defined
2095         // for the document language in the lib/languages file and if no
2096         // other languages are used (lang_opts is then empty)
2097         if (lang_opts.empty())
2098                 return string();
2099         // If Vietnamese is used, babel must directly be loaded with the
2100         // language options, see
2101         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
2102         size_t viet = lang_opts.find("vietnam");
2103         // viet = string::npos when not found
2104         // the same is for all other languages that are not directly supported by
2105         // babel, but where LaTeX-packages add babel support.
2106         // this is currently the case for Latvian, Lithuanian, and Mongolian
2107         size_t latvian = lang_opts.find("latvian");
2108         size_t lithu = lang_opts.find("lithuanian");
2109         size_t mongo = lang_opts.find("mongolian");
2110         // If Japanese is used, babel must directly be loaded with the
2111         // language options, see
2112         // http://www.lyx.org/trac/ticket/4597#c4
2113         size_t japan = lang_opts.find("japanese");
2114         if (!lyxrc.language_global_options || viet != string::npos
2115                 || japan != string::npos || latvian != string::npos
2116                 || lithu != string::npos || mongo != string::npos)
2117                 return "\\usepackage[" + lang_opts + "]{babel}";
2118         return lang_pack;
2119 }
2120
2121
2122 docstring BufferParams::getGraphicsDriver(string const & package) const
2123 {
2124         docstring result;
2125
2126         if (package == "geometry") {
2127                 if (graphicsDriver == "dvips"
2128                     || graphicsDriver == "dvipdfm"
2129                     || graphicsDriver == "pdftex"
2130                     || graphicsDriver == "vtex")
2131                         result = from_ascii(graphicsDriver);
2132                 else if (graphicsDriver == "dvipdfmx")
2133                         result = from_ascii("dvipdfm");
2134         }
2135
2136         return result;
2137 }
2138
2139
2140 void BufferParams::writeEncodingPreamble(odocstream & os,
2141                 LaTeXFeatures & features, TexRow & texrow) const
2142 {
2143         if (useXetex)
2144                 return;
2145         if (inputenc == "auto") {
2146                 string const doc_encoding =
2147                         language->encoding()->latexName();
2148                 Encoding::Package const package =
2149                         language->encoding()->package();
2150
2151                 // Create a list with all the input encodings used
2152                 // in the document
2153                 set<string> encodings =
2154                         features.getEncodingSet(doc_encoding);
2155
2156                 // If the "japanese" package (i.e. pLaTeX) is used,
2157                 // inputenc must be omitted.
2158                 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
2159                 if (package == Encoding::japanese)
2160                      features.require("japanese");
2161
2162                 if ((!encodings.empty() || package == Encoding::inputenc)
2163                     && !features.isRequired("japanese")) {
2164                         os << "\\usepackage[";
2165                         set<string>::const_iterator it = encodings.begin();
2166                         set<string>::const_iterator const end = encodings.end();
2167                         if (it != end) {
2168                                 os << from_ascii(*it);
2169                                 ++it;
2170                         }
2171                         for (; it != end; ++it)
2172                                 os << ',' << from_ascii(*it);
2173                         if (package == Encoding::inputenc) {
2174                                 if (!encodings.empty())
2175                                         os << ',';
2176                                 os << from_ascii(doc_encoding);
2177                         }
2178                         os << "]{inputenc}\n";
2179                         texrow.newline();
2180                 }
2181                 if (package == Encoding::CJK || features.mustProvide("CJK")) {
2182                         if (language->encoding()->name() == "utf8-cjk"
2183                             && LaTeXFeatures::isAvailable("CJKutf8"))
2184                                 os << "\\usepackage{CJKutf8}\n";
2185                         else
2186                                 os << "\\usepackage{CJK}\n";
2187                         texrow.newline();
2188                 }
2189         } else if (inputenc != "default") {
2190                 switch (encoding().package()) {
2191                 case Encoding::none:
2192                 case Encoding::japanese:
2193                         break;
2194                 case Encoding::inputenc:
2195                         // do not load inputenc if japanese is used
2196                         if (features.isRequired("japanese"))
2197                                 break;
2198                         os << "\\usepackage[" << from_ascii(inputenc)
2199                            << "]{inputenc}\n";
2200                         texrow.newline();
2201                         break;
2202                 case Encoding::CJK:
2203                         if (encoding().name() == "utf8-cjk"
2204                             && LaTeXFeatures::isAvailable("CJKutf8"))
2205                                 os << "\\usepackage{CJKutf8}\n";
2206                         else
2207                                 os << "\\usepackage{CJK}\n";
2208                         texrow.newline();
2209                         break;
2210                 }
2211         }
2212
2213         // The encoding "armscii8" (for Armenian) is only available when
2214         // the package "armtex" is loaded.
2215         if (language->encoding()->latexName() == "armscii8"
2216             || inputenc == "armscii8") {
2217                 os << "\\usepackage{armtex}\n";
2218                 texrow.newline();
2219         }
2220 }
2221
2222
2223 string const BufferParams::parseFontName(string const & name) const
2224 {
2225         string mangled = name;
2226         size_t const idx = mangled.find('[');
2227         if (idx == string::npos || idx == 0)
2228                 return mangled;
2229         else
2230                 return mangled.substr(0, idx - 1);
2231 }
2232
2233
2234 string const BufferParams::loadFonts(string const & rm,
2235                                      string const & sf, string const & tt,
2236                                      bool const & sc, bool const & osf,
2237                                      int const & sfscale, int const & ttscale,
2238                                      bool const & xetex) const
2239 {
2240         /* The LaTeX font world is in a flux. In the PSNFSS font interface,
2241            several packages have been replaced by others, that might not
2242            be installed on every system. We have to take care for that
2243            (see psnfss.pdf). We try to support all psnfss fonts as well
2244            as the fonts that have become de facto standard in the LaTeX
2245            world (e.g. Latin Modern). We do not support obsolete fonts
2246            (like PSLatex). In general, it should be possible to mix any
2247            rm font with any sf or tt font, respectively. (JSpitzm)
2248            TODO:
2249                 -- separate math fonts.
2250         */
2251
2252         if (rm == "default" && sf == "default" && tt == "default")
2253                 //nothing to do
2254                 return string();
2255
2256         ostringstream os;
2257
2258         if (xetex) {
2259                 if (rm != "default")
2260                         os << "\\setmainfont[Mapping=tex-text]{"
2261                            << parseFontName(rm) << "}\n";
2262                 if (sf != "default") {
2263                         string const sans = parseFontName(sf);
2264                         if (sfscale != 100)
2265                                 os << "\\setsansfont[Scale=" 
2266                                    << float(sfscale) / 100 
2267                                    << ",Mapping=tex-text]{"
2268                                    << sans << "}\n";
2269                         else
2270                                 os << "\\setsansfont[Mapping=tex-text]{"
2271                                    << sans << "}\n";
2272                 }
2273                 if (tt != "default") {
2274                         string const mono = parseFontName(tt);
2275                         if (ttscale != 100)
2276                                 os << "\\setmonofont[Scale=" 
2277                                    << float(sfscale) / 100 
2278                                    << "]{"
2279                                    << mono << "}\n";
2280                         else
2281                                 os << "\\setmonofont[Mapping=tex-text]{"
2282                                    << mono << "}\n";
2283                 }
2284                 if (osf)
2285                         os << "\\defaultfontfeatures{Numbers=OldStyle}\n";
2286                 return os.str();
2287         }
2288
2289         // ROMAN FONTS
2290         // Computer Modern (must be explicitly selectable -- there might be classes
2291         // that define a different default font!
2292         if (rm == "cmr") {
2293                 os << "\\renewcommand{\\rmdefault}{cmr}\n";
2294                 // osf for Computer Modern needs eco.sty
2295                 if (osf)
2296                         os << "\\usepackage{eco}\n";
2297         }
2298         // Latin Modern Roman
2299         else if (rm == "lmodern")
2300                 os << "\\usepackage{lmodern}\n";
2301         // AE
2302         else if (rm == "ae") {
2303                 // not needed when using OT1 font encoding.
2304                 if (font_encoding() != "default")
2305                         os << "\\usepackage{ae,aecompl}\n";
2306         }
2307         // Times
2308         else if (rm == "times") {
2309                 // try to load the best available package
2310                 if (LaTeXFeatures::isAvailable("mathptmx"))
2311                         os << "\\usepackage{mathptmx}\n";
2312                 else if (LaTeXFeatures::isAvailable("mathptm"))
2313                         os << "\\usepackage{mathptm}\n";
2314                 else
2315                         os << "\\usepackage{times}\n";
2316         }
2317         // Palatino
2318         else if (rm == "palatino") {
2319                 // try to load the best available package
2320                 if (LaTeXFeatures::isAvailable("mathpazo")) {
2321                         os << "\\usepackage";
2322                         if (osf || sc) {
2323                                 os << '[';
2324                                 if (!osf)
2325                                         os << "sc";
2326                                 else
2327                                         // "osf" includes "sc"!
2328                                         os << "osf";
2329                                 os << ']';
2330                         }
2331                         os << "{mathpazo}\n";
2332                 }
2333                 else if (LaTeXFeatures::isAvailable("mathpple"))
2334                         os << "\\usepackage{mathpple}\n";
2335                 else
2336                         os << "\\usepackage{palatino}\n";
2337         }
2338         // Utopia
2339         else if (rm == "utopia") {
2340                 // fourier supersedes utopia.sty, but does
2341                 // not work with OT1 encoding.
2342                 if (LaTeXFeatures::isAvailable("fourier")
2343                     && font_encoding() != "default") {
2344                         os << "\\usepackage";
2345                         if (osf || sc) {
2346                                 os << '[';
2347                                 if (sc)
2348                                         os << "expert";
2349                                 if (osf && sc)
2350                                         os << ',';
2351                                 if (osf)
2352                                         os << "oldstyle";
2353                                 os << ']';
2354                         }
2355                         os << "{fourier}\n";
2356                 }
2357                 else
2358                         os << "\\usepackage{utopia}\n";
2359         }
2360         // Bera (complete fontset)
2361         else if (rm == "bera" && sf == "default" && tt == "default")
2362                 os << "\\usepackage{bera}\n";
2363         // everything else
2364         else if (rm != "default")
2365                 os << "\\usepackage" << "{" << rm << "}\n";
2366
2367         // SANS SERIF
2368         // Helvetica, Bera Sans
2369         if (sf == "helvet" || sf == "berasans") {
2370                 if (sfscale != 100)
2371                         os << "\\usepackage[scaled=" << float(sfscale) / 100
2372                            << "]{" << sf << "}\n";
2373                 else
2374                         os << "\\usepackage{" << sf << "}\n";
2375         }
2376         // Avant Garde
2377         else if (sf == "avant")
2378                 os << "\\usepackage{" << sf << "}\n";
2379         // Computer Modern, Latin Modern, CM Bright
2380         else if (sf != "default")
2381                 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
2382
2383         // monospaced/typewriter
2384         // Courier, LuxiMono
2385         if (tt == "luximono" || tt == "beramono") {
2386                 if (ttscale != 100)
2387                         os << "\\usepackage[scaled=" << float(ttscale) / 100
2388                            << "]{" << tt << "}\n";
2389                 else
2390                         os << "\\usepackage{" << tt << "}\n";
2391         }
2392         // Courier
2393         else if (tt == "courier" )
2394                 os << "\\usepackage{" << tt << "}\n";
2395         // Computer Modern, Latin Modern, CM Bright
2396         else if (tt != "default")
2397                 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
2398
2399         return os.str();
2400 }
2401
2402
2403 Encoding const & BufferParams::encoding() const
2404 {
2405         if (useXetex)
2406                 return *(encodings.fromLaTeXName("utf8-plain"));
2407         if (inputenc == "auto" || inputenc == "default")
2408                 return *language->encoding();
2409         Encoding const * const enc = encodings.fromLaTeXName(inputenc);
2410         if (enc)
2411                 return *enc;
2412         LYXERR0("Unknown inputenc value `" << inputenc
2413                << "'. Using `auto' instead.");
2414         return *language->encoding();
2415 }
2416
2417
2418 CiteEngine BufferParams::citeEngine() const
2419 {
2420         // FIXME the class should provide the numerical/
2421         // authoryear choice
2422         if (documentClass().provides("natbib")
2423             && cite_engine_ != ENGINE_NATBIB_NUMERICAL)
2424                 return ENGINE_NATBIB_AUTHORYEAR;
2425         return cite_engine_;
2426 }
2427
2428
2429 void BufferParams::setCiteEngine(CiteEngine cite_engine)
2430 {
2431         cite_engine_ = cite_engine;
2432 }
2433
2434 } // namespace lyx