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