]> git.lyx.org Git - lyx.git/blob - src/BufferParams.cpp
isAvailable is static
[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 (use_geometry || nonstandard_papersize) {
1133                 odocstringstream ods;
1134                 if (!getGraphicsDriver("geometry").empty())
1135                         ods << getGraphicsDriver("geometry");
1136                 if (orientation == ORIENTATION_LANDSCAPE)
1137                         ods << ",landscape";
1138                 switch (papersize) {
1139                 case PAPER_CUSTOM:
1140                         if (!paperwidth.empty())
1141                                 ods << ",paperwidth="
1142                                    << from_ascii(paperwidth);
1143                         if (!paperheight.empty())
1144                                 ods << ",paperheight="
1145                                    << from_ascii(paperheight);
1146                         break;
1147                 case PAPER_USLETTER:
1148                         ods << ",letterpaper";
1149                         break;
1150                 case PAPER_USLEGAL:
1151                         ods << ",legalpaper";
1152                         break;
1153                 case PAPER_USEXECUTIVE:
1154                         ods << ",executivepaper";
1155                         break;
1156                 case PAPER_A3:
1157                         ods << ",a3paper";
1158                         break;
1159                 case PAPER_A4:
1160                         ods << ",a4paper";
1161                         break;
1162                 case PAPER_A5:
1163                         ods << ",a5paper";
1164                         break;
1165                 case PAPER_B3:
1166                         ods << ",b3paper";
1167                         break;
1168                 case PAPER_B4:
1169                         ods << ",b4paper";
1170                         break;
1171                 case PAPER_B5:
1172                         ods << ",b5paper";
1173                         break;
1174                 default:
1175                         // default papersize ie PAPER_DEFAULT
1176                         switch (lyxrc.default_papersize) {
1177                         case PAPER_DEFAULT: // keep compiler happy
1178                         case PAPER_USLETTER:
1179                                 ods << ",letterpaper";
1180                                 break;
1181                         case PAPER_USLEGAL:
1182                                 ods << ",legalpaper";
1183                                 break;
1184                         case PAPER_USEXECUTIVE:
1185                                 ods << ",executivepaper";
1186                                 break;
1187                         case PAPER_A3:
1188                                 ods << ",a3paper";
1189                                 break;
1190                         case PAPER_A4:
1191                                 ods << ",a4paper";
1192                                 break;
1193                         case PAPER_A5:
1194                                 ods << ",a5paper";
1195                                 break;
1196                         case PAPER_B5:
1197                                 ods << ",b5paper";
1198                                 break;
1199                         case PAPER_B3:
1200                         case PAPER_B4:
1201                         case PAPER_CUSTOM:
1202                                 break;
1203                         }
1204                 }
1205                 docstring const g_options = trim(ods.str(), ",");
1206                 os << "\\usepackage";
1207                 if (!g_options.empty())
1208                         os << '[' << g_options << ']';
1209                 os << "{geometry}\n";
1210                 texrow.newline();
1211                 os << "\\geometry{verbose";
1212                 if (!topmargin.empty())
1213                         os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1214                 if (!bottommargin.empty())
1215                         os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1216                 if (!leftmargin.empty())
1217                         os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1218                 if (!rightmargin.empty())
1219                         os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1220                 if (!headheight.empty())
1221                         os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1222                 if (!headsep.empty())
1223                         os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1224                 if (!footskip.empty())
1225                         os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1226                 if (!columnsep.empty())
1227                         os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1228                 os << "}\n";
1229                 texrow.newline();
1230         } else if (orientation == ORIENTATION_LANDSCAPE) {
1231                 features.require("papersize");
1232         }
1233
1234         if (tokenPos(tclass.opt_pagestyle(),
1235                      '|', pagestyle) >= 0) {
1236                 if (pagestyle == "fancy") {
1237                         os << "\\usepackage{fancyhdr}\n";
1238                         texrow.newline();
1239                 }
1240                 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1241                 texrow.newline();
1242         }
1243
1244         // Only if class has a ToC hierarchy
1245         if (tclass.hasTocLevels()) {
1246                 if (secnumdepth != tclass.secnumdepth()) {
1247                         os << "\\setcounter{secnumdepth}{"
1248                            << secnumdepth
1249                            << "}\n";
1250                         texrow.newline();
1251                 }
1252                 if (tocdepth != tclass.tocdepth()) {
1253                         os << "\\setcounter{tocdepth}{"
1254                            << tocdepth
1255                            << "}\n";
1256                         texrow.newline();
1257                 }
1258         }
1259
1260         if (paragraph_separation) {
1261                 switch (getDefSkip().kind()) {
1262                 case VSpace::SMALLSKIP:
1263                         os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1264                         break;
1265                 case VSpace::MEDSKIP:
1266                         os << "\\setlength{\\parskip}{\\medskipamount}\n";
1267                         break;
1268                 case VSpace::BIGSKIP:
1269                         os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1270                         break;
1271                 case VSpace::LENGTH:
1272                         os << "\\setlength{\\parskip}{"
1273                            << from_utf8(getDefSkip().length().asLatexString())
1274                            << "}\n";
1275                         break;
1276                 default: // should never happen // Then delete it.
1277                         os << "\\setlength{\\parskip}{\\medskipamount}\n";
1278                         break;
1279                 }
1280                 texrow.newline();
1281
1282                 os << "\\setlength{\\parindent}{0pt}\n";
1283                 texrow.newline();
1284         }
1285
1286         // Now insert the LyX specific LaTeX commands...
1287         docstring lyxpreamble;
1288
1289         // due to interferences with babel and hyperref, the color package has to
1290         // be loaded (when it is not already loaded) before babel when hyperref
1291         // is used with the colorlinks option, see
1292         // http://bugzilla.lyx.org/show_bug.cgi?id=5291
1293         // we decided therefore to load color always before babel, see
1294         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg144349.html
1295         lyxpreamble += from_ascii(features.getColorOptions());
1296         
1297         // If we use hyperref, jurabib, japanese, or vietnamese, we have to call babel before them.
1298         if (use_babel
1299                 && (features.isRequired("jurabib")
1300                         || features.isRequired("hyperref")
1301                         || features.isRequired("vietnamese")
1302                         || features.isRequired("japanese") ) ) {
1303                                 // FIXME UNICODE
1304                                 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1305                                 lyxpreamble += from_utf8(features.getBabelOptions()) + '\n';
1306         }
1307
1308         // The optional packages;
1309         lyxpreamble += from_ascii(features.getPackages());
1310
1311         // Line spacing
1312         lyxpreamble += from_utf8(spacing().writePreamble(tclass.provides("SetSpace")));
1313
1314         // PDF support.
1315         // * Hyperref manual: "Make sure it comes last of your loaded
1316         //   packages, to give it a fighting chance of not being over-written,
1317         //   since its job is to redefine many LaTeX commands."
1318         // * Email from Heiko Oberdiek: "It is usually better to load babel
1319         //   before hyperref. Then hyperref has a chance to detect babel.
1320         // * Has to be loaded before the "LyX specific LaTeX commands" to
1321         //   avoid errors with algorithm floats.
1322         // use hyperref explicitely when it is required
1323         if (features.isRequired("hyperref")) {
1324                 odocstringstream oss;
1325                 pdfoptions().writeLaTeX(oss, documentClass().provides("hyperref"));
1326                 lyxpreamble += oss.str();
1327         }
1328         
1329         // Will be surrounded by \makeatletter and \makeatother when needed
1330         docstring atlyxpreamble;
1331
1332         // Some macros LyX will need
1333         docstring tmppreamble(from_ascii(features.getMacros()));
1334
1335         if (!tmppreamble.empty())
1336                 atlyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1337                         "LyX specific LaTeX commands.\n"
1338                         + tmppreamble + '\n';
1339
1340         // the text class specific preamble
1341         tmppreamble = features.getTClassPreamble();
1342         if (!tmppreamble.empty())
1343                 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1344                         "Textclass specific LaTeX commands.\n"
1345                         + tmppreamble + '\n';
1346
1347         /* the user-defined preamble */
1348         if (!preamble.empty())
1349                 // FIXME UNICODE
1350                 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1351                         "User specified LaTeX commands.\n"
1352                         + from_utf8(preamble) + '\n';
1353
1354         // subfig loads internally the LaTeX package "caption". As
1355         // caption is a very popular package, users will load it in
1356         // the preamble. Therefore we must load subfig behind the
1357         // user-defined preamble and check if the caption package was
1358         // loaded or not. For the case that caption is loaded before
1359         // subfig, there is the subfig option "caption=false". This
1360         // option also works when a koma-script class is used and
1361         // koma's own caption commands are used instead of caption. We
1362         // use \PassOptionsToPackage here because the user could have
1363         // already loaded subfig in the preamble.
1364         if (features.isRequired("subfig")) {
1365                 atlyxpreamble += "\\@ifundefined{showcaptionsetup}{}{%\n"
1366                         " \\PassOptionsToPackage{caption=false}{subfig}}\n"
1367                         "\\usepackage{subfig}\n";
1368         }
1369
1370         // Itemize bullet settings need to be last in case the user
1371         // defines their own bullets that use a package included
1372         // in the user-defined preamble -- ARRae
1373         // Actually it has to be done much later than that
1374         // since some packages like frenchb make modifications
1375         // at \begin{document} time -- JMarc
1376         docstring bullets_def;
1377         for (int i = 0; i < 4; ++i) {
1378                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1379                         if (bullets_def.empty())
1380                                 bullets_def += "\\AtBeginDocument{\n";
1381                         bullets_def += "  \\def\\labelitemi";
1382                         switch (i) {
1383                                 // `i' is one less than the item to modify
1384                         case 0:
1385                                 break;
1386                         case 1:
1387                                 bullets_def += 'i';
1388                                 break;
1389                         case 2:
1390                                 bullets_def += "ii";
1391                                 break;
1392                         case 3:
1393                                 bullets_def += 'v';
1394                                 break;
1395                         }
1396                         bullets_def += '{' +
1397                                 user_defined_bullet(i).getText()
1398                                 + "}\n";
1399                 }
1400         }
1401
1402         if (!bullets_def.empty())
1403                 atlyxpreamble += bullets_def + "}\n\n";
1404
1405         if (atlyxpreamble.find(from_ascii("@")) != docstring::npos)
1406                 lyxpreamble += "\n\\makeatletter\n"
1407                         + atlyxpreamble + "\\makeatother\n\n";
1408         else
1409                 lyxpreamble += '\n' + atlyxpreamble;
1410
1411         // We try to load babel late, in case it interferes with other packages.
1412         // Jurabib and Hyperref have to be called after babel, though.
1413         if (use_babel && !features.isRequired("jurabib")
1414             && !features.isRequired("hyperref")
1415             && !features.isRequired("vietnamese")
1416             && !features.isRequired("japanese")) {
1417                 // FIXME UNICODE
1418                 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1419                 lyxpreamble += from_utf8(features.getBabelOptions()) + '\n';
1420         }
1421
1422         docstring const i18npreamble = features.getTClassI18nPreamble(use_babel);
1423         if (!i18npreamble.empty())
1424                 lyxpreamble += i18npreamble + '\n';
1425
1426         int const nlines =
1427                 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1428         for (int j = 0; j != nlines; ++j) {
1429                 texrow.newline();
1430         }
1431
1432         os << lyxpreamble;
1433         return use_babel;
1434 }
1435
1436
1437 void BufferParams::useClassDefaults()
1438 {
1439         DocumentClass const & tclass = documentClass();
1440
1441         sides = tclass.sides();
1442         columns = tclass.columns();
1443         pagestyle = tclass.pagestyle();
1444         use_default_options = true;
1445         // Only if class has a ToC hierarchy
1446         if (tclass.hasTocLevels()) {
1447                 secnumdepth = tclass.secnumdepth();
1448                 tocdepth = tclass.tocdepth();
1449         }
1450 }
1451
1452
1453 bool BufferParams::hasClassDefaults() const
1454 {
1455         DocumentClass const & tclass = documentClass();
1456
1457         return sides == tclass.sides()
1458                 && columns == tclass.columns()
1459                 && pagestyle == tclass.pagestyle()
1460                 && use_default_options
1461                 && secnumdepth == tclass.secnumdepth()
1462                 && tocdepth == tclass.tocdepth();
1463 }
1464
1465
1466 DocumentClass const & BufferParams::documentClass() const
1467 {
1468         return *doc_class_;
1469 }
1470
1471
1472 DocumentClass const * BufferParams::documentClassPtr() const {
1473         return doc_class_;
1474 }
1475
1476
1477 void BufferParams::setDocumentClass(DocumentClass const * const tc) {
1478         // evil, but this function is evil
1479         doc_class_ = const_cast<DocumentClass *>(tc);
1480 }
1481
1482
1483 bool BufferParams::setBaseClass(string const & classname)
1484 {
1485         LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
1486         LayoutFileList & bcl = LayoutFileList::get();
1487         if (!bcl.haveClass(classname)) {
1488                 docstring s = 
1489                         bformat(_("The document class %1$s could not be found. "
1490                                 "A default textclass with default layouts will be used. "
1491                                 "LyX might not be able to produce output unless a correct "
1492                                 "textclass is selected from the document settings dialog."),
1493                         from_utf8(classname));
1494                 frontend::Alert::error(_("Document class not found"), s);
1495                 bcl.addEmptyClass(classname);
1496         }
1497
1498         bool const success = bcl[classname].load();
1499         if (!success) {
1500                 docstring s = 
1501                         bformat(_("The document class %1$s could not be loaded."),
1502                         from_utf8(classname));
1503                 frontend::Alert::error(_("Could not load class"), s);
1504                 return false;
1505         }
1506
1507         pimpl_->baseClass_ = classname;
1508         layoutModules_.adaptToBaseClass(baseClass(), removedModules_);
1509         return true;
1510 }
1511
1512
1513 LayoutFile const * BufferParams::baseClass() const
1514 {
1515         if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
1516                 return &(LayoutFileList::get()[pimpl_->baseClass_]);
1517         else 
1518                 return 0;
1519 }
1520
1521
1522 LayoutFileIndex const & BufferParams::baseClassID() const
1523 {
1524         return pimpl_->baseClass_;
1525 }
1526
1527
1528 void BufferParams::makeDocumentClass()
1529 {
1530         if (!baseClass())
1531                 return;
1532
1533         doc_class_ = &(DocumentClassBundle::get().makeDocumentClass(*baseClass(), layoutModules_));
1534
1535         if (!local_layout.empty()) {
1536                 if (!doc_class_->read(local_layout, TextClass::MODULE)) {
1537                         docstring const msg = _("Error reading internal layout information");
1538                         frontend::Alert::warning(_("Read Error"), msg);
1539                 }
1540         }
1541 }
1542
1543 bool BufferParams::moduleCanBeAdded(string const & modName) const
1544 {
1545         return layoutModules_.moduleCanBeAdded(modName, baseClass());
1546 }
1547
1548
1549 bool BufferParams::addLayoutModule(string const & modName)
1550 {
1551         LayoutModuleList::const_iterator it = layoutModules_.begin();
1552         LayoutModuleList::const_iterator end = layoutModules_.end();
1553         for (; it != end; it++)
1554                 if (*it == modName) 
1555                         return false;
1556         layoutModules_.push_back(modName);
1557         return true;
1558 }
1559
1560
1561 Font const BufferParams::getFont() const
1562 {
1563         FontInfo f = documentClass().defaultfont();
1564         if (fontsDefaultFamily == "rmdefault")
1565                 f.setFamily(ROMAN_FAMILY);
1566         else if (fontsDefaultFamily == "sfdefault")
1567                 f.setFamily(SANS_FAMILY);
1568         else if (fontsDefaultFamily == "ttdefault")
1569                 f.setFamily(TYPEWRITER_FAMILY);
1570         return Font(f, language);
1571 }
1572
1573
1574 void BufferParams::readPreamble(Lexer & lex)
1575 {
1576         if (lex.getString() != "\\begin_preamble")
1577                 lyxerr << "Error (BufferParams::readPreamble):"
1578                         "consistency check failed." << endl;
1579
1580         preamble = lex.getLongString("\\end_preamble");
1581 }
1582
1583
1584 void BufferParams::readLocalLayout(Lexer & lex)
1585 {
1586         if (lex.getString() != "\\begin_local_layout")
1587                 lyxerr << "Error (BufferParams::readLocalLayout):"
1588                         "consistency check failed." << endl;
1589
1590         local_layout = lex.getLongString("\\end_local_layout");
1591 }
1592
1593
1594 void BufferParams::readLanguage(Lexer & lex)
1595 {
1596         if (!lex.next()) return;
1597
1598         string const tmptok = lex.getString();
1599
1600         // check if tmptok is part of tex_babel in tex-defs.h
1601         language = languages.getLanguage(tmptok);
1602         if (!language) {
1603                 // Language tmptok was not found
1604                 language = default_language;
1605                 lyxerr << "Warning: Setting language `"
1606                        << tmptok << "' to `" << language->lang()
1607                        << "'." << endl;
1608         }
1609 }
1610
1611
1612 void BufferParams::readGraphicsDriver(Lexer & lex)
1613 {
1614         if (!lex.next()) 
1615                 return;
1616
1617         string const tmptok = lex.getString();
1618         // check if tmptok is part of tex_graphics in tex_defs.h
1619         int n = 0;
1620         while (true) {
1621                 string const test = tex_graphics[n++];
1622
1623                 if (test == tmptok) {
1624                         graphicsDriver = tmptok;
1625                         break;
1626                 }
1627                 if (test.empty()) {
1628                         lex.printError(
1629                                 "Warning: graphics driver `$$Token' not recognized!\n"
1630                                 "         Setting graphics driver to `default'.\n");
1631                         graphicsDriver = "default";
1632                         break;
1633                 }
1634         }
1635 }
1636
1637
1638 void BufferParams::readBullets(Lexer & lex)
1639 {
1640         if (!lex.next()) 
1641                 return;
1642
1643         int const index = lex.getInteger();
1644         lex.next();
1645         int temp_int = lex.getInteger();
1646         user_defined_bullet(index).setFont(temp_int);
1647         temp_bullet(index).setFont(temp_int);
1648         lex >> temp_int;
1649         user_defined_bullet(index).setCharacter(temp_int);
1650         temp_bullet(index).setCharacter(temp_int);
1651         lex >> temp_int;
1652         user_defined_bullet(index).setSize(temp_int);
1653         temp_bullet(index).setSize(temp_int);
1654 }
1655
1656
1657 void BufferParams::readBulletsLaTeX(Lexer & lex)
1658 {
1659         // The bullet class should be able to read this.
1660         if (!lex.next()) 
1661                 return;
1662         int const index = lex.getInteger();
1663         lex.next(true);
1664         docstring const temp_str = lex.getDocString();
1665
1666         user_defined_bullet(index).setText(temp_str);
1667         temp_bullet(index).setText(temp_str);
1668 }
1669
1670
1671 void BufferParams::readModules(Lexer & lex)
1672 {
1673         if (!lex.eatLine()) {
1674                 lyxerr << "Error (BufferParams::readModules):"
1675                                 "Unexpected end of input." << endl;
1676                 return;
1677         }
1678         while (true) {
1679                 string mod = lex.getString();
1680                 if (mod == "\\end_modules")
1681                         break;
1682                 addLayoutModule(mod);
1683                 lex.eatLine();
1684         }
1685 }
1686
1687
1688 void BufferParams::readRemovedModules(Lexer & lex)
1689 {
1690         if (!lex.eatLine()) {
1691                 lyxerr << "Error (BufferParams::readRemovedModules):"
1692                                 "Unexpected end of input." << endl;
1693                 return;
1694         }
1695         while (true) {
1696                 string mod = lex.getString();
1697                 if (mod == "\\end_removed_modules")
1698                         break;
1699                 removedModules_.push_back(mod);
1700                 lex.eatLine();
1701         }
1702         // now we want to remove any removed modules that were previously 
1703         // added. normally, that will be because default modules were added in 
1704         // setBaseClass(), which gets called when \textclass is read at the 
1705         // start of the read.
1706         list<string>::const_iterator rit = removedModules_.begin();
1707         list<string>::const_iterator const ren = removedModules_.end();
1708         for (; rit != ren; rit++) {
1709                 LayoutModuleList::iterator const mit = layoutModules_.begin();
1710                 LayoutModuleList::iterator const men = layoutModules_.end();
1711                 LayoutModuleList::iterator found = find(mit, men, *rit);
1712                 if (found == men)
1713                         continue;
1714                 layoutModules_.erase(found);
1715         }
1716 }
1717
1718
1719 string BufferParams::paperSizeName(PapersizePurpose purpose) const
1720 {
1721         char real_papersize = papersize;
1722         if (real_papersize == PAPER_DEFAULT)
1723                 real_papersize = lyxrc.default_papersize;
1724
1725         switch (real_papersize) {
1726         case PAPER_DEFAULT:
1727                 // could be anything, so don't guess
1728                 return string();
1729         case PAPER_CUSTOM: {
1730                 if (purpose == XDVI && !paperwidth.empty() &&
1731                     !paperheight.empty()) {
1732                         // heightxwidth<unit>
1733                         string first = paperwidth;
1734                         string second = paperheight;
1735                         if (orientation == ORIENTATION_LANDSCAPE)
1736                                 first.swap(second);
1737                         // cut off unit.
1738                         return first.erase(first.length() - 2)
1739                                 + "x" + second;
1740                 }
1741                 return string();
1742         }
1743         case PAPER_A3:
1744                 return "a3";
1745         case PAPER_A4:
1746                 return "a4";
1747         case PAPER_A5:
1748                 return "a5";
1749         case PAPER_B3:
1750                 // dvips and dvipdfm do not know this
1751                 if (purpose == DVIPS || purpose == DVIPDFM)
1752                         return string();
1753                 return "b3";
1754         case PAPER_B4:
1755                 // dvipdfm does not know this
1756                 if (purpose == DVIPDFM)
1757                         return string();
1758                 return "b4";
1759         case PAPER_B5:
1760                 // dvipdfm does not know this
1761                 if (purpose == DVIPDFM)
1762                         return string();
1763                 return "b5";
1764         case PAPER_USEXECUTIVE:
1765                 // dvipdfm does not know this
1766                 if (purpose == DVIPDFM)
1767                         return string();
1768                 return "foolscap";
1769         case PAPER_USLEGAL:
1770                 return "legal";
1771         case PAPER_USLETTER:
1772         default:
1773                 if (purpose == XDVI)
1774                         return "us";
1775                 return "letter";
1776         }
1777 }
1778
1779
1780 string const BufferParams::dvips_options() const
1781 {
1782         string result;
1783
1784         if (use_geometry
1785             && papersize == PAPER_CUSTOM
1786             && !lyxrc.print_paper_dimension_flag.empty()
1787             && !paperwidth.empty()
1788             && !paperheight.empty()) {
1789                 // using a custom papersize
1790                 result = lyxrc.print_paper_dimension_flag;
1791                 result += ' ' + paperwidth;
1792                 result += ',' + paperheight;
1793         } else {
1794                 string const paper_option = paperSizeName(DVIPS);
1795                 if (!paper_option.empty() && (paper_option != "letter" ||
1796                     orientation != ORIENTATION_LANDSCAPE)) {
1797                         // dvips won't accept -t letter -t landscape.
1798                         // In all other cases, include the paper size
1799                         // explicitly.
1800                         result = lyxrc.print_paper_flag;
1801                         result += ' ' + paper_option;
1802                 }
1803         }
1804         if (orientation == ORIENTATION_LANDSCAPE &&
1805             papersize != PAPER_CUSTOM)
1806                 result += ' ' + lyxrc.print_landscape_flag;
1807         return result;
1808 }
1809
1810
1811 string BufferParams::babelCall(string const & lang_opts) const
1812 {
1813         string lang_pack = lyxrc.language_package;
1814         if (lang_pack != "\\usepackage{babel}")
1815                 return lang_pack;
1816         // suppress the babel call when there is no babel language defined
1817         // for the document language in the lib/languages file and if no
1818         // other languages are used (lang_opts is then empty)
1819         if (lang_opts.empty())
1820                 return string();
1821         // If Vietnamese is used, babel must directly be loaded with the
1822         // language options, see
1823         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1824         size_t viet = lang_opts.find("vietnam");
1825         // viet = string::npos when not found
1826         // the same is for all other languages that are not directly supported by
1827         // babel, but where LaTeX-packages add babel support.
1828         // this is currently the case for Latvian, Lithuanian, and Mongolian
1829         size_t latvian = lang_opts.find("latvian");
1830         size_t lithu = lang_opts.find("lithuanian");
1831         size_t mongo = lang_opts.find("mongolian");
1832         // If Japanese is used, babel must directly be loaded with the
1833         // language options, see
1834         // http://bugzilla.lyx.org/show_bug.cgi?id=4597#c4
1835         size_t japan = lang_opts.find("japanese");
1836         if (!lyxrc.language_global_options || viet != string::npos
1837                 || japan != string::npos || latvian != string::npos
1838                 || lithu != string::npos || mongo != string::npos)
1839                 return "\\usepackage[" + lang_opts + "]{babel}";
1840         return lang_pack;
1841 }
1842
1843
1844 docstring BufferParams::getGraphicsDriver(string const & package) const
1845 {
1846         docstring result;
1847
1848         if (package == "geometry") {
1849                 if (graphicsDriver == "dvips"
1850                     || graphicsDriver == "dvipdfm"
1851                     || graphicsDriver == "pdftex"
1852                     || graphicsDriver == "vtex")
1853                         result = from_ascii(graphicsDriver);
1854                 else if (graphicsDriver == "dvipdfmx")
1855                         result = from_ascii("dvipdfm");
1856         }
1857
1858         return result;
1859 }
1860
1861
1862 void BufferParams::writeEncodingPreamble(odocstream & os,
1863                 LaTeXFeatures & features, TexRow & texrow) const
1864 {
1865         if (inputenc == "auto") {
1866                 string const doc_encoding =
1867                         language->encoding()->latexName();
1868                 Encoding::Package const package =
1869                         language->encoding()->package();
1870
1871                 // Create a list with all the input encodings used
1872                 // in the document
1873                 set<string> encodings =
1874                         features.getEncodingSet(doc_encoding);
1875
1876                 // If the "japanese" package (i.e. pLaTeX) is used,
1877                 // inputenc must be omitted.
1878                 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1879                 if (package == Encoding::japanese)
1880                      features.require("japanese");
1881
1882                 if ((!encodings.empty() || package == Encoding::inputenc)
1883                     && !features.isRequired("japanese")) {
1884                         os << "\\usepackage[";
1885                         set<string>::const_iterator it = encodings.begin();
1886                         set<string>::const_iterator const end = encodings.end();
1887                         if (it != end) {
1888                                 os << from_ascii(*it);
1889                                 ++it;
1890                         }
1891                         for (; it != end; ++it)
1892                                 os << ',' << from_ascii(*it);
1893                         if (package == Encoding::inputenc) {
1894                                 if (!encodings.empty())
1895                                         os << ',';
1896                                 os << from_ascii(doc_encoding);
1897                         }
1898                         os << "]{inputenc}\n";
1899                         texrow.newline();
1900                 }
1901                 if (package == Encoding::CJK || features.mustProvide("CJK")) {
1902                         if (language->encoding()->name() == "utf8-cjk"
1903                             && LaTeXFeatures::isAvailable("CJKutf8"))
1904                                 os << "\\usepackage{CJKutf8}\n";
1905                         else
1906                                 os << "\\usepackage{CJK}\n";
1907                         texrow.newline();
1908                 }
1909         } else if (inputenc != "default") {
1910                 switch (encoding().package()) {
1911                 case Encoding::none:
1912                 case Encoding::japanese:
1913                         break;
1914                 case Encoding::inputenc:
1915                         // do not load inputenc if japanese is used
1916                         if (features.isRequired("japanese"))
1917                                 break;
1918                         os << "\\usepackage[" << from_ascii(inputenc)
1919                            << "]{inputenc}\n";
1920                         texrow.newline();
1921                         break;
1922                 case Encoding::CJK:
1923                         if (encoding().name() == "utf8-cjk"
1924                             && LaTeXFeatures::isAvailable("CJKutf8"))
1925                                 os << "\\usepackage{CJKutf8}\n";
1926                         else
1927                                 os << "\\usepackage{CJK}\n";
1928                         texrow.newline();
1929                         break;
1930                 }
1931         }
1932
1933         // The encoding "armscii8" (for Armenian) is only available when
1934         // the package "armtex" is loaded.
1935         if (language->encoding()->latexName() == "armscii8"
1936             || inputenc == "armscii8") {
1937                 os << "\\usepackage{armtex}\n";
1938                 texrow.newline();
1939         }
1940 }
1941
1942
1943 string const BufferParams::loadFonts(string const & rm,
1944                                      string const & sf, string const & tt,
1945                                      bool const & sc, bool const & osf,
1946                                      int const & sfscale, int const & ttscale) const
1947 {
1948         /* The LaTeX font world is in a flux. In the PSNFSS font interface,
1949            several packages have been replaced by others, that might not
1950            be installed on every system. We have to take care for that
1951            (see psnfss.pdf). We try to support all psnfss fonts as well
1952            as the fonts that have become de facto standard in the LaTeX
1953            world (e.g. Latin Modern). We do not support obsolete fonts
1954            (like PSLatex). In general, it should be possible to mix any
1955            rm font with any sf or tt font, respectively. (JSpitzm)
1956            TODO:
1957                 -- separate math fonts.
1958         */
1959
1960         if (rm == "default" && sf == "default" && tt == "default")
1961                 //nothing to do
1962                 return string();
1963
1964         ostringstream os;
1965
1966         // ROMAN FONTS
1967         // Computer Modern (must be explicitely selectable -- there might be classes
1968         // that define a different default font!
1969         if (rm == "cmr") {
1970                 os << "\\renewcommand{\\rmdefault}{cmr}\n";
1971                 // osf for Computer Modern needs eco.sty
1972                 if (osf)
1973                         os << "\\usepackage{eco}\n";
1974         }
1975         // Latin Modern Roman
1976         else if (rm == "lmodern")
1977                 os << "\\usepackage{lmodern}\n";
1978         // AE
1979         else if (rm == "ae") {
1980                 // not needed when using OT1 font encoding.
1981                 if (lyxrc.fontenc != "default")
1982                         os << "\\usepackage{ae,aecompl}\n";
1983         }
1984         // Times
1985         else if (rm == "times") {
1986                 // try to load the best available package
1987                 if (LaTeXFeatures::isAvailable("mathptmx"))
1988                         os << "\\usepackage{mathptmx}\n";
1989                 else if (LaTeXFeatures::isAvailable("mathptm"))
1990                         os << "\\usepackage{mathptm}\n";
1991                 else
1992                         os << "\\usepackage{times}\n";
1993         }
1994         // Palatino
1995         else if (rm == "palatino") {
1996                 // try to load the best available package
1997                 if (LaTeXFeatures::isAvailable("mathpazo")) {
1998                         os << "\\usepackage";
1999                         if (osf || sc) {
2000                                 os << '[';
2001                                 if (!osf)
2002                                         os << "sc";
2003                                 else
2004                                         // "osf" includes "sc"!
2005                                         os << "osf";
2006                                 os << ']';
2007                         }
2008                         os << "{mathpazo}\n";
2009                 }
2010                 else if (LaTeXFeatures::isAvailable("mathpple"))
2011                         os << "\\usepackage{mathpple}\n";
2012                 else
2013                         os << "\\usepackage{palatino}\n";
2014         }
2015         // Utopia
2016         else if (rm == "utopia") {
2017                 // fourier supersedes utopia.sty, but does
2018                 // not work with OT1 encoding.
2019                 if (LaTeXFeatures::isAvailable("fourier")
2020                     && lyxrc.fontenc != "default") {
2021                         os << "\\usepackage";
2022                         if (osf || sc) {
2023                                 os << '[';
2024                                 if (sc)
2025                                         os << "expert";
2026                                 if (osf && sc)
2027                                         os << ',';
2028                                 if (osf)
2029                                         os << "oldstyle";
2030                                 os << ']';
2031                         }
2032                         os << "{fourier}\n";
2033                 }
2034                 else
2035                         os << "\\usepackage{utopia}\n";
2036         }
2037         // Bera (complete fontset)
2038         else if (rm == "bera" && sf == "default" && tt == "default")
2039                 os << "\\usepackage{bera}\n";
2040         // everything else
2041         else if (rm != "default")
2042                 os << "\\usepackage" << "{" << rm << "}\n";
2043
2044         // SANS SERIF
2045         // Helvetica, Bera Sans
2046         if (sf == "helvet" || sf == "berasans") {
2047                 if (sfscale != 100)
2048                         os << "\\usepackage[scaled=" << float(sfscale) / 100
2049                            << "]{" << sf << "}\n";
2050                 else
2051                         os << "\\usepackage{" << sf << "}\n";
2052         }
2053         // Avant Garde
2054         else if (sf == "avant")
2055                 os << "\\usepackage{" << sf << "}\n";
2056         // Computer Modern, Latin Modern, CM Bright
2057         else if (sf != "default")
2058                 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
2059
2060         // monospaced/typewriter
2061         // Courier, LuxiMono
2062         if (tt == "luximono" || tt == "beramono") {
2063                 if (ttscale != 100)
2064                         os << "\\usepackage[scaled=" << float(ttscale) / 100
2065                            << "]{" << tt << "}\n";
2066                 else
2067                         os << "\\usepackage{" << tt << "}\n";
2068         }
2069         // Courier
2070         else if (tt == "courier" )
2071                 os << "\\usepackage{" << tt << "}\n";
2072         // Computer Modern, Latin Modern, CM Bright
2073         else if (tt != "default")
2074                 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
2075
2076         return os.str();
2077 }
2078
2079
2080 Encoding const & BufferParams::encoding() const
2081 {
2082         if (inputenc == "auto" || inputenc == "default")
2083                 return *language->encoding();
2084         Encoding const * const enc = encodings.fromLaTeXName(inputenc);
2085         if (enc)
2086                 return *enc;
2087         LYXERR0("Unknown inputenc value `" << inputenc
2088                << "'. Using `auto' instead.");
2089         return *language->encoding();
2090 }
2091
2092
2093 CiteEngine BufferParams::citeEngine() const
2094 {
2095         // FIXME the class should provide the numerical/
2096         // authoryear choice
2097         if (documentClass().provides("natbib")
2098             && cite_engine_ != ENGINE_NATBIB_NUMERICAL)
2099                 return ENGINE_NATBIB_AUTHORYEAR;
2100         return cite_engine_;
2101 }
2102
2103
2104 void BufferParams::setCiteEngine(CiteEngine cite_engine)
2105 {
2106         cite_engine_ = cite_engine;
2107 }
2108
2109 } // namespace lyx