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