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