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