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