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