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