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