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