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