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