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