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