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