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