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