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