]> git.lyx.org Git - lyx.git/blob - src/BufferParams.cpp
649f3b4c4bc32aeaec82722119302b2ccec484e2
[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                 os << "\\usepackage{xunicode}\n";
1093                 texrow.newline();
1094                 os << "\\usepackage{xltxtra}\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         return use_babel;
1457 }
1458
1459
1460 void BufferParams::useClassDefaults()
1461 {
1462         DocumentClass const & tclass = documentClass();
1463
1464         sides = tclass.sides();
1465         columns = tclass.columns();
1466         pagestyle = tclass.pagestyle();
1467         use_default_options = true;
1468         // Only if class has a ToC hierarchy
1469         if (tclass.hasTocLevels()) {
1470                 secnumdepth = tclass.secnumdepth();
1471                 tocdepth = tclass.tocdepth();
1472         }
1473 }
1474
1475
1476 bool BufferParams::hasClassDefaults() const
1477 {
1478         DocumentClass const & tclass = documentClass();
1479
1480         return sides == tclass.sides()
1481                 && columns == tclass.columns()
1482                 && pagestyle == tclass.pagestyle()
1483                 && use_default_options
1484                 && secnumdepth == tclass.secnumdepth()
1485                 && tocdepth == tclass.tocdepth();
1486 }
1487
1488
1489 DocumentClass const & BufferParams::documentClass() const
1490 {
1491         return *doc_class_;
1492 }
1493
1494
1495 DocumentClass const * BufferParams::documentClassPtr() const {
1496         return doc_class_;
1497 }
1498
1499
1500 void BufferParams::setDocumentClass(DocumentClass const * const tc) {
1501         // evil, but this function is evil
1502         doc_class_ = const_cast<DocumentClass *>(tc);
1503 }
1504
1505
1506 bool BufferParams::setBaseClass(string const & classname)
1507 {
1508         LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
1509         LayoutFileList & bcl = LayoutFileList::get();
1510         if (!bcl.haveClass(classname)) {
1511                 docstring s = 
1512                         bformat(_("The document class %1$s could not be found. "
1513                                 "A default textclass with default layouts will be used. "
1514                                 "LyX might not be able to produce output unless a correct "
1515                                 "textclass is selected from the document settings dialog."),
1516                         from_utf8(classname));
1517                 frontend::Alert::error(_("Document class not found"), s);
1518                 bcl.addEmptyClass(classname);
1519         }
1520
1521         bool const success = bcl[classname].load();
1522         if (!success) {
1523                 docstring s = 
1524                         bformat(_("The document class %1$s could not be loaded."),
1525                         from_utf8(classname));
1526                 frontend::Alert::error(_("Could not load class"), s);
1527                 return false;
1528         }
1529
1530         pimpl_->baseClass_ = classname;
1531         layoutModules_.adaptToBaseClass(baseClass(), removedModules_);
1532         return true;
1533 }
1534
1535
1536 LayoutFile const * BufferParams::baseClass() const
1537 {
1538         if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
1539                 return &(LayoutFileList::get()[pimpl_->baseClass_]);
1540         else 
1541                 return 0;
1542 }
1543
1544
1545 LayoutFileIndex const & BufferParams::baseClassID() const
1546 {
1547         return pimpl_->baseClass_;
1548 }
1549
1550
1551 void BufferParams::makeDocumentClass()
1552 {
1553         if (!baseClass())
1554                 return;
1555
1556         doc_class_ = &(DocumentClassBundle::get().makeDocumentClass(*baseClass(), layoutModules_));
1557
1558         if (!local_layout.empty()) {
1559                 if (!doc_class_->read(local_layout, TextClass::MODULE)) {
1560                         docstring const msg = _("Error reading internal layout information");
1561                         frontend::Alert::warning(_("Read Error"), msg);
1562                 }
1563         }
1564 }
1565
1566 bool BufferParams::moduleCanBeAdded(string const & modName) const
1567 {
1568         return layoutModules_.moduleCanBeAdded(modName, baseClass());
1569 }
1570
1571
1572 bool BufferParams::addLayoutModule(string const & modName)
1573 {
1574         LayoutModuleList::const_iterator it = layoutModules_.begin();
1575         LayoutModuleList::const_iterator end = layoutModules_.end();
1576         for (; it != end; it++)
1577                 if (*it == modName) 
1578                         return false;
1579         layoutModules_.push_back(modName);
1580         return true;
1581 }
1582
1583
1584 Font const BufferParams::getFont() const
1585 {
1586         FontInfo f = documentClass().defaultfont();
1587         if (fontsDefaultFamily == "rmdefault")
1588                 f.setFamily(ROMAN_FAMILY);
1589         else if (fontsDefaultFamily == "sfdefault")
1590                 f.setFamily(SANS_FAMILY);
1591         else if (fontsDefaultFamily == "ttdefault")
1592                 f.setFamily(TYPEWRITER_FAMILY);
1593         return Font(f, language);
1594 }
1595
1596
1597 void BufferParams::readPreamble(Lexer & lex)
1598 {
1599         if (lex.getString() != "\\begin_preamble")
1600                 lyxerr << "Error (BufferParams::readPreamble):"
1601                         "consistency check failed." << endl;
1602
1603         preamble = lex.getLongString("\\end_preamble");
1604 }
1605
1606
1607 void BufferParams::readLocalLayout(Lexer & lex)
1608 {
1609         if (lex.getString() != "\\begin_local_layout")
1610                 lyxerr << "Error (BufferParams::readLocalLayout):"
1611                         "consistency check failed." << endl;
1612
1613         local_layout = lex.getLongString("\\end_local_layout");
1614 }
1615
1616
1617 void BufferParams::readLanguage(Lexer & lex)
1618 {
1619         if (!lex.next()) return;
1620
1621         string const tmptok = lex.getString();
1622
1623         // check if tmptok is part of tex_babel in tex-defs.h
1624         language = languages.getLanguage(tmptok);
1625         if (!language) {
1626                 // Language tmptok was not found
1627                 language = default_language;
1628                 lyxerr << "Warning: Setting language `"
1629                        << tmptok << "' to `" << language->lang()
1630                        << "'." << endl;
1631         }
1632 }
1633
1634
1635 void BufferParams::readGraphicsDriver(Lexer & lex)
1636 {
1637         if (!lex.next()) 
1638                 return;
1639
1640         string const tmptok = lex.getString();
1641         // check if tmptok is part of tex_graphics in tex_defs.h
1642         int n = 0;
1643         while (true) {
1644                 string const test = tex_graphics[n++];
1645
1646                 if (test == tmptok) {
1647                         graphicsDriver = tmptok;
1648                         break;
1649                 }
1650                 if (test.empty()) {
1651                         lex.printError(
1652                                 "Warning: graphics driver `$$Token' not recognized!\n"
1653                                 "         Setting graphics driver to `default'.\n");
1654                         graphicsDriver = "default";
1655                         break;
1656                 }
1657         }
1658 }
1659
1660
1661 void BufferParams::readBullets(Lexer & lex)
1662 {
1663         if (!lex.next()) 
1664                 return;
1665
1666         int const index = lex.getInteger();
1667         lex.next();
1668         int temp_int = lex.getInteger();
1669         user_defined_bullet(index).setFont(temp_int);
1670         temp_bullet(index).setFont(temp_int);
1671         lex >> temp_int;
1672         user_defined_bullet(index).setCharacter(temp_int);
1673         temp_bullet(index).setCharacter(temp_int);
1674         lex >> temp_int;
1675         user_defined_bullet(index).setSize(temp_int);
1676         temp_bullet(index).setSize(temp_int);
1677 }
1678
1679
1680 void BufferParams::readBulletsLaTeX(Lexer & lex)
1681 {
1682         // The bullet class should be able to read this.
1683         if (!lex.next()) 
1684                 return;
1685         int const index = lex.getInteger();
1686         lex.next(true);
1687         docstring const temp_str = lex.getDocString();
1688
1689         user_defined_bullet(index).setText(temp_str);
1690         temp_bullet(index).setText(temp_str);
1691 }
1692
1693
1694 void BufferParams::readModules(Lexer & lex)
1695 {
1696         if (!lex.eatLine()) {
1697                 lyxerr << "Error (BufferParams::readModules):"
1698                                 "Unexpected end of input." << endl;
1699                 return;
1700         }
1701         while (true) {
1702                 string mod = lex.getString();
1703                 if (mod == "\\end_modules")
1704                         break;
1705                 addLayoutModule(mod);
1706                 lex.eatLine();
1707         }
1708 }
1709
1710
1711 void BufferParams::readRemovedModules(Lexer & lex)
1712 {
1713         if (!lex.eatLine()) {
1714                 lyxerr << "Error (BufferParams::readRemovedModules):"
1715                                 "Unexpected end of input." << endl;
1716                 return;
1717         }
1718         while (true) {
1719                 string mod = lex.getString();
1720                 if (mod == "\\end_removed_modules")
1721                         break;
1722                 removedModules_.push_back(mod);
1723                 lex.eatLine();
1724         }
1725         // now we want to remove any removed modules that were previously 
1726         // added. normally, that will be because default modules were added in 
1727         // setBaseClass(), which gets called when \textclass is read at the 
1728         // start of the read.
1729         list<string>::const_iterator rit = removedModules_.begin();
1730         list<string>::const_iterator const ren = removedModules_.end();
1731         for (; rit != ren; rit++) {
1732                 LayoutModuleList::iterator const mit = layoutModules_.begin();
1733                 LayoutModuleList::iterator const men = layoutModules_.end();
1734                 LayoutModuleList::iterator found = find(mit, men, *rit);
1735                 if (found == men)
1736                         continue;
1737                 layoutModules_.erase(found);
1738         }
1739 }
1740
1741
1742 string BufferParams::paperSizeName(PapersizePurpose purpose) const
1743 {
1744         char real_papersize = papersize;
1745         if (real_papersize == PAPER_DEFAULT)
1746                 real_papersize = lyxrc.default_papersize;
1747
1748         switch (real_papersize) {
1749         case PAPER_DEFAULT:
1750                 // could be anything, so don't guess
1751                 return string();
1752         case PAPER_CUSTOM: {
1753                 if (purpose == XDVI && !paperwidth.empty() &&
1754                     !paperheight.empty()) {
1755                         // heightxwidth<unit>
1756                         string first = paperwidth;
1757                         string second = paperheight;
1758                         if (orientation == ORIENTATION_LANDSCAPE)
1759                                 first.swap(second);
1760                         // cut off unit.
1761                         return first.erase(first.length() - 2)
1762                                 + "x" + second;
1763                 }
1764                 return string();
1765         }
1766         case PAPER_A3:
1767                 return "a3";
1768         case PAPER_A4:
1769                 return "a4";
1770         case PAPER_A5:
1771                 return "a5";
1772         case PAPER_B3:
1773                 // dvips and dvipdfm do not know this
1774                 if (purpose == DVIPS || purpose == DVIPDFM)
1775                         return string();
1776                 return "b3";
1777         case PAPER_B4:
1778                 // dvipdfm does not know this
1779                 if (purpose == DVIPDFM)
1780                         return string();
1781                 return "b4";
1782         case PAPER_B5:
1783                 // dvipdfm does not know this
1784                 if (purpose == DVIPDFM)
1785                         return string();
1786                 return "b5";
1787         case PAPER_USEXECUTIVE:
1788                 // dvipdfm does not know this
1789                 if (purpose == DVIPDFM)
1790                         return string();
1791                 return "foolscap";
1792         case PAPER_USLEGAL:
1793                 return "legal";
1794         case PAPER_USLETTER:
1795         default:
1796                 if (purpose == XDVI)
1797                         return "us";
1798                 return "letter";
1799         }
1800 }
1801
1802
1803 string const BufferParams::dvips_options() const
1804 {
1805         string result;
1806
1807         if (use_geometry
1808             && papersize == PAPER_CUSTOM
1809             && !lyxrc.print_paper_dimension_flag.empty()
1810             && !paperwidth.empty()
1811             && !paperheight.empty()) {
1812                 // using a custom papersize
1813                 result = lyxrc.print_paper_dimension_flag;
1814                 result += ' ' + paperwidth;
1815                 result += ',' + paperheight;
1816         } else {
1817                 string const paper_option = paperSizeName(DVIPS);
1818                 if (!paper_option.empty() && (paper_option != "letter" ||
1819                     orientation != ORIENTATION_LANDSCAPE)) {
1820                         // dvips won't accept -t letter -t landscape.
1821                         // In all other cases, include the paper size
1822                         // explicitly.
1823                         result = lyxrc.print_paper_flag;
1824                         result += ' ' + paper_option;
1825                 }
1826         }
1827         if (orientation == ORIENTATION_LANDSCAPE &&
1828             papersize != PAPER_CUSTOM)
1829                 result += ' ' + lyxrc.print_landscape_flag;
1830         return result;
1831 }
1832
1833
1834 string BufferParams::babelCall(string const & lang_opts) const
1835 {
1836         string lang_pack = lyxrc.language_package;
1837         if (lang_pack != "\\usepackage{babel}")
1838                 return lang_pack;
1839         // suppress the babel call when there is no babel language defined
1840         // for the document language in the lib/languages file and if no
1841         // other languages are used (lang_opts is then empty)
1842         if (lang_opts.empty())
1843                 return string();
1844         // If Vietnamese is used, babel must directly be loaded with the
1845         // language options, see
1846         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1847         size_t viet = lang_opts.find("vietnam");
1848         // viet = string::npos when not found
1849         // the same is for all other languages that are not directly supported by
1850         // babel, but where LaTeX-packages add babel support.
1851         // this is currently the case for Latvian, Lithuanian, and Mongolian
1852         size_t latvian = lang_opts.find("latvian");
1853         size_t lithu = lang_opts.find("lithuanian");
1854         size_t mongo = lang_opts.find("mongolian");
1855         // If Japanese is used, babel must directly be loaded with the
1856         // language options, see
1857         // http://bugzilla.lyx.org/show_bug.cgi?id=4597#c4
1858         size_t japan = lang_opts.find("japanese");
1859         if (!lyxrc.language_global_options || viet != string::npos
1860                 || japan != string::npos || latvian != string::npos
1861                 || lithu != string::npos || mongo != string::npos)
1862                 return "\\usepackage[" + lang_opts + "]{babel}";
1863         return lang_pack;
1864 }
1865
1866
1867 docstring BufferParams::getGraphicsDriver(string const & package) const
1868 {
1869         docstring result;
1870
1871         if (package == "geometry") {
1872                 if (graphicsDriver == "dvips"
1873                     || graphicsDriver == "dvipdfm"
1874                     || graphicsDriver == "pdftex"
1875                     || graphicsDriver == "vtex")
1876                         result = from_ascii(graphicsDriver);
1877                 else if (graphicsDriver == "dvipdfmx")
1878                         result = from_ascii("dvipdfm");
1879         }
1880
1881         return result;
1882 }
1883
1884
1885 void BufferParams::writeEncodingPreamble(odocstream & os,
1886                 LaTeXFeatures & features, TexRow & texrow) const
1887 {
1888         if (useXetex)
1889                 return;
1890         if (inputenc == "auto") {
1891                 string const doc_encoding =
1892                         language->encoding()->latexName();
1893                 Encoding::Package const package =
1894                         language->encoding()->package();
1895
1896                 // Create a list with all the input encodings used
1897                 // in the document
1898                 set<string> encodings =
1899                         features.getEncodingSet(doc_encoding);
1900
1901                 // If the "japanese" package (i.e. pLaTeX) is used,
1902                 // inputenc must be omitted.
1903                 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1904                 if (package == Encoding::japanese)
1905                      features.require("japanese");
1906
1907                 if ((!encodings.empty() || package == Encoding::inputenc)
1908                     && !features.isRequired("japanese")) {
1909                         os << "\\usepackage[";
1910                         set<string>::const_iterator it = encodings.begin();
1911                         set<string>::const_iterator const end = encodings.end();
1912                         if (it != end) {
1913                                 os << from_ascii(*it);
1914                                 ++it;
1915                         }
1916                         for (; it != end; ++it)
1917                                 os << ',' << from_ascii(*it);
1918                         if (package == Encoding::inputenc) {
1919                                 if (!encodings.empty())
1920                                         os << ',';
1921                                 os << from_ascii(doc_encoding);
1922                         }
1923                         os << "]{inputenc}\n";
1924                         texrow.newline();
1925                 }
1926                 if (package == Encoding::CJK || features.mustProvide("CJK")) {
1927                         if (language->encoding()->name() == "utf8-cjk"
1928                             && LaTeXFeatures::isAvailable("CJKutf8"))
1929                                 os << "\\usepackage{CJKutf8}\n";
1930                         else
1931                                 os << "\\usepackage{CJK}\n";
1932                         texrow.newline();
1933                 }
1934         } else if (inputenc != "default") {
1935                 switch (encoding().package()) {
1936                 case Encoding::none:
1937                 case Encoding::japanese:
1938                         break;
1939                 case Encoding::inputenc:
1940                         // do not load inputenc if japanese is used
1941                         if (features.isRequired("japanese"))
1942                                 break;
1943                         os << "\\usepackage[" << from_ascii(inputenc)
1944                            << "]{inputenc}\n";
1945                         texrow.newline();
1946                         break;
1947                 case Encoding::CJK:
1948                         if (encoding().name() == "utf8-cjk"
1949                             && LaTeXFeatures::isAvailable("CJKutf8"))
1950                                 os << "\\usepackage{CJKutf8}\n";
1951                         else
1952                                 os << "\\usepackage{CJK}\n";
1953                         texrow.newline();
1954                         break;
1955                 }
1956         }
1957
1958         // The encoding "armscii8" (for Armenian) is only available when
1959         // the package "armtex" is loaded.
1960         if (language->encoding()->latexName() == "armscii8"
1961             || inputenc == "armscii8") {
1962                 os << "\\usepackage{armtex}\n";
1963                 texrow.newline();
1964         }
1965 }
1966
1967
1968 string const BufferParams::parseFontName(string const & name) const
1969 {
1970         string mangled = name;
1971         size_t const idx = mangled.find('[');
1972         if (idx == string::npos || idx == 0)
1973                 return mangled;
1974         else
1975                 return mangled.substr(0, idx - 1);
1976 }
1977
1978
1979 string const BufferParams::loadFonts(string const & rm,
1980                                      string const & sf, string const & tt,
1981                                      bool const & sc, bool const & osf,
1982                                      int const & sfscale, int const & ttscale,
1983                                      bool const & xetex) const
1984 {
1985         /* The LaTeX font world is in a flux. In the PSNFSS font interface,
1986            several packages have been replaced by others, that might not
1987            be installed on every system. We have to take care for that
1988            (see psnfss.pdf). We try to support all psnfss fonts as well
1989            as the fonts that have become de facto standard in the LaTeX
1990            world (e.g. Latin Modern). We do not support obsolete fonts
1991            (like PSLatex). In general, it should be possible to mix any
1992            rm font with any sf or tt font, respectively. (JSpitzm)
1993            TODO:
1994                 -- separate math fonts.
1995         */
1996
1997         if (rm == "default" && sf == "default" && tt == "default")
1998                 //nothing to do
1999                 return string();
2000
2001         ostringstream os;
2002
2003         if (xetex) {
2004                 if (rm != "default")
2005                         os << "\\setmainfont[Mapping=tex-text]{"
2006                            << parseFontName(rm) << "}\n";
2007                 if (sf != "default") {
2008                         string const sans = parseFontName(sf);
2009                         if (sfscale != 100)
2010                                 os << "\\setsansfont[Scale=" 
2011                                    << float(sfscale) / 100 
2012                                    << ",Mapping=tex-text]{"
2013                                    << sans << "}\n";
2014                         else
2015                                 os << "\\setsansfont[Mapping=tex-text]{"
2016                                    << sans << "}\n";
2017                 }
2018                 if (tt != "default") {
2019                         string const mono = parseFontName(tt);
2020                         if (ttscale != 100)
2021                                 os << "\\setmonofont[Scale=" 
2022                                    << float(sfscale) / 100 
2023                                    << "]{"
2024                                    << mono << "}\n";
2025                         else
2026                                 os << "\\setmonofont[Mapping=tex-text]{"
2027                                    << mono << "}\n";
2028                 }
2029                 if (osf)
2030                         os << "\\defaultfontfeatures{Numbers=OldStyle}\n";
2031                 return os.str();
2032         }
2033
2034         // ROMAN FONTS
2035         // Computer Modern (must be explicitely selectable -- there might be classes
2036         // that define a different default font!
2037         if (rm == "cmr") {
2038                 os << "\\renewcommand{\\rmdefault}{cmr}\n";
2039                 // osf for Computer Modern needs eco.sty
2040                 if (osf)
2041                         os << "\\usepackage{eco}\n";
2042         }
2043         // Latin Modern Roman
2044         else if (rm == "lmodern")
2045                 os << "\\usepackage{lmodern}\n";
2046         // AE
2047         else if (rm == "ae") {
2048                 // not needed when using OT1 font encoding.
2049                 if (lyxrc.fontenc != "default")
2050                         os << "\\usepackage{ae,aecompl}\n";
2051         }
2052         // Times
2053         else if (rm == "times") {
2054                 // try to load the best available package
2055                 if (LaTeXFeatures::isAvailable("mathptmx"))
2056                         os << "\\usepackage{mathptmx}\n";
2057                 else if (LaTeXFeatures::isAvailable("mathptm"))
2058                         os << "\\usepackage{mathptm}\n";
2059                 else
2060                         os << "\\usepackage{times}\n";
2061         }
2062         // Palatino
2063         else if (rm == "palatino") {
2064                 // try to load the best available package
2065                 if (LaTeXFeatures::isAvailable("mathpazo")) {
2066                         os << "\\usepackage";
2067                         if (osf || sc) {
2068                                 os << '[';
2069                                 if (!osf)
2070                                         os << "sc";
2071                                 else
2072                                         // "osf" includes "sc"!
2073                                         os << "osf";
2074                                 os << ']';
2075                         }
2076                         os << "{mathpazo}\n";
2077                 }
2078                 else if (LaTeXFeatures::isAvailable("mathpple"))
2079                         os << "\\usepackage{mathpple}\n";
2080                 else
2081                         os << "\\usepackage{palatino}\n";
2082         }
2083         // Utopia
2084         else if (rm == "utopia") {
2085                 // fourier supersedes utopia.sty, but does
2086                 // not work with OT1 encoding.
2087                 if (LaTeXFeatures::isAvailable("fourier")
2088                     && lyxrc.fontenc != "default") {
2089                         os << "\\usepackage";
2090                         if (osf || sc) {
2091                                 os << '[';
2092                                 if (sc)
2093                                         os << "expert";
2094                                 if (osf && sc)
2095                                         os << ',';
2096                                 if (osf)
2097                                         os << "oldstyle";
2098                                 os << ']';
2099                         }
2100                         os << "{fourier}\n";
2101                 }
2102                 else
2103                         os << "\\usepackage{utopia}\n";
2104         }
2105         // Bera (complete fontset)
2106         else if (rm == "bera" && sf == "default" && tt == "default")
2107                 os << "\\usepackage{bera}\n";
2108         // everything else
2109         else if (rm != "default")
2110                 os << "\\usepackage" << "{" << rm << "}\n";
2111
2112         // SANS SERIF
2113         // Helvetica, Bera Sans
2114         if (sf == "helvet" || sf == "berasans") {
2115                 if (sfscale != 100)
2116                         os << "\\usepackage[scaled=" << float(sfscale) / 100
2117                            << "]{" << sf << "}\n";
2118                 else
2119                         os << "\\usepackage{" << sf << "}\n";
2120         }
2121         // Avant Garde
2122         else if (sf == "avant")
2123                 os << "\\usepackage{" << sf << "}\n";
2124         // Computer Modern, Latin Modern, CM Bright
2125         else if (sf != "default")
2126                 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
2127
2128         // monospaced/typewriter
2129         // Courier, LuxiMono
2130         if (tt == "luximono" || tt == "beramono") {
2131                 if (ttscale != 100)
2132                         os << "\\usepackage[scaled=" << float(ttscale) / 100
2133                            << "]{" << tt << "}\n";
2134                 else
2135                         os << "\\usepackage{" << tt << "}\n";
2136         }
2137         // Courier
2138         else if (tt == "courier" )
2139                 os << "\\usepackage{" << tt << "}\n";
2140         // Computer Modern, Latin Modern, CM Bright
2141         else if (tt != "default")
2142                 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
2143
2144         return os.str();
2145 }
2146
2147
2148 Encoding const & BufferParams::encoding() const
2149 {
2150         if (useXetex)
2151                 return *(encodings.fromLaTeXName("utf8-plain"));
2152         if (inputenc == "auto" || inputenc == "default")
2153                 return *language->encoding();
2154         Encoding const * const enc = encodings.fromLaTeXName(inputenc);
2155         if (enc)
2156                 return *enc;
2157         LYXERR0("Unknown inputenc value `" << inputenc
2158                << "'. Using `auto' instead.");
2159         return *language->encoding();
2160 }
2161
2162
2163 CiteEngine BufferParams::citeEngine() const
2164 {
2165         // FIXME the class should provide the numerical/
2166         // authoryear choice
2167         if (documentClass().provides("natbib")
2168             && cite_engine_ != ENGINE_NATBIB_NUMERICAL)
2169                 return ENGINE_NATBIB_AUTHORYEAR;
2170         return cite_engine_;
2171 }
2172
2173
2174 void BufferParams::setCiteEngine(CiteEngine cite_engine)
2175 {
2176         cite_engine_ = cite_engine;
2177 }
2178
2179 } // namespace lyx