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