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