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