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