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