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