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