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