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