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