]> git.lyx.org Git - lyx.git/blob - src/BufferParams.cpp
8f6d7fc5356f58adf045a4748b1b190841f7c6f8
[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 layout file:\n"
1768                                 "%1$s\n"
1769                                 "could not be found. A default textclass with default\n"
1770                                 "layouts will be used. LyX will not be able to produce\n"
1771                                 "correct output."),
1772                         from_utf8(classname));
1773                 frontend::Alert::error(_("Document class not found"), s);
1774                 bcl.addEmptyClass(classname);
1775         }
1776
1777         bool const success = bcl[classname].load();
1778         if (!success) {
1779                 docstring s = 
1780                         bformat(_("Due to some error in it, the layout file:\n"
1781                                 "%1$s\n"
1782                                 "could not be loaded. A default textclass with default\n"
1783                                 "layouts will be used. LyX will not be able to produce\n"
1784                                 "correct output."),
1785                         from_utf8(classname));
1786                 frontend::Alert::error(_("Could not load class"), s);
1787                 bcl.addEmptyClass(classname);
1788         }
1789
1790         pimpl_->baseClass_ = classname;
1791         layoutModules_.adaptToBaseClass(baseClass(), removedModules_);
1792         return true;
1793 }
1794
1795
1796 LayoutFile const * BufferParams::baseClass() const
1797 {
1798         if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
1799                 return &(LayoutFileList::get()[pimpl_->baseClass_]);
1800         else 
1801                 return 0;
1802 }
1803
1804
1805 LayoutFileIndex const & BufferParams::baseClassID() const
1806 {
1807         return pimpl_->baseClass_;
1808 }
1809
1810
1811 void BufferParams::makeDocumentClass()
1812 {
1813         if (!baseClass())
1814                 return;
1815
1816         doc_class_ = &(DocumentClassBundle::get().makeDocumentClass(*baseClass(), layoutModules_));
1817
1818         if (!local_layout.empty()) {
1819                 if (!doc_class_->read(local_layout, TextClass::MODULE)) {
1820                         docstring const msg = _("Error reading internal layout information");
1821                         frontend::Alert::warning(_("Read Error"), msg);
1822                 }
1823         }
1824 }
1825
1826
1827 bool BufferParams::moduleCanBeAdded(string const & modName) const
1828 {
1829         return layoutModules_.moduleCanBeAdded(modName, baseClass());
1830 }
1831
1832
1833 bool BufferParams::addLayoutModule(string const & modName)
1834 {
1835         LayoutModuleList::const_iterator it = layoutModules_.begin();
1836         LayoutModuleList::const_iterator end = layoutModules_.end();
1837         for (; it != end; it++)
1838                 if (*it == modName) 
1839                         return false;
1840         layoutModules_.push_back(modName);
1841         return true;
1842 }
1843
1844
1845 Font const BufferParams::getFont() const
1846 {
1847         FontInfo f = documentClass().defaultfont();
1848         if (fontsDefaultFamily == "rmdefault")
1849                 f.setFamily(ROMAN_FAMILY);
1850         else if (fontsDefaultFamily == "sfdefault")
1851                 f.setFamily(SANS_FAMILY);
1852         else if (fontsDefaultFamily == "ttdefault")
1853                 f.setFamily(TYPEWRITER_FAMILY);
1854         return Font(f, language);
1855 }
1856
1857
1858 void BufferParams::readPreamble(Lexer & lex)
1859 {
1860         if (lex.getString() != "\\begin_preamble")
1861                 lyxerr << "Error (BufferParams::readPreamble):"
1862                         "consistency check failed." << endl;
1863
1864         preamble = lex.getLongString("\\end_preamble");
1865 }
1866
1867
1868 void BufferParams::readLocalLayout(Lexer & lex)
1869 {
1870         if (lex.getString() != "\\begin_local_layout")
1871                 lyxerr << "Error (BufferParams::readLocalLayout):"
1872                         "consistency check failed." << endl;
1873
1874         local_layout = lex.getLongString("\\end_local_layout");
1875 }
1876
1877
1878 void BufferParams::readLanguage(Lexer & lex)
1879 {
1880         if (!lex.next()) return;
1881
1882         string const tmptok = lex.getString();
1883
1884         // check if tmptok is part of tex_babel in tex-defs.h
1885         language = languages.getLanguage(tmptok);
1886         if (!language) {
1887                 // Language tmptok was not found
1888                 language = default_language;
1889                 lyxerr << "Warning: Setting language `"
1890                        << tmptok << "' to `" << language->lang()
1891                        << "'." << endl;
1892         }
1893 }
1894
1895
1896 void BufferParams::readGraphicsDriver(Lexer & lex)
1897 {
1898         if (!lex.next()) 
1899                 return;
1900
1901         string const tmptok = lex.getString();
1902         // check if tmptok is part of tex_graphics in tex_defs.h
1903         int n = 0;
1904         while (true) {
1905                 string const test = tex_graphics[n++];
1906
1907                 if (test == tmptok) {
1908                         graphicsDriver = tmptok;
1909                         break;
1910                 }
1911                 if (test.empty()) {
1912                         lex.printError(
1913                                 "Warning: graphics driver `$$Token' not recognized!\n"
1914                                 "         Setting graphics driver to `default'.\n");
1915                         graphicsDriver = "default";
1916                         break;
1917                 }
1918         }
1919 }
1920
1921
1922 void BufferParams::readBullets(Lexer & lex)
1923 {
1924         if (!lex.next()) 
1925                 return;
1926
1927         int const index = lex.getInteger();
1928         lex.next();
1929         int temp_int = lex.getInteger();
1930         user_defined_bullet(index).setFont(temp_int);
1931         temp_bullet(index).setFont(temp_int);
1932         lex >> temp_int;
1933         user_defined_bullet(index).setCharacter(temp_int);
1934         temp_bullet(index).setCharacter(temp_int);
1935         lex >> temp_int;
1936         user_defined_bullet(index).setSize(temp_int);
1937         temp_bullet(index).setSize(temp_int);
1938 }
1939
1940
1941 void BufferParams::readBulletsLaTeX(Lexer & lex)
1942 {
1943         // The bullet class should be able to read this.
1944         if (!lex.next()) 
1945                 return;
1946         int const index = lex.getInteger();
1947         lex.next(true);
1948         docstring const temp_str = lex.getDocString();
1949
1950         user_defined_bullet(index).setText(temp_str);
1951         temp_bullet(index).setText(temp_str);
1952 }
1953
1954
1955 void BufferParams::readModules(Lexer & lex)
1956 {
1957         if (!lex.eatLine()) {
1958                 lyxerr << "Error (BufferParams::readModules):"
1959                                 "Unexpected end of input." << endl;
1960                 return;
1961         }
1962         while (true) {
1963                 string mod = lex.getString();
1964                 if (mod == "\\end_modules")
1965                         break;
1966                 addLayoutModule(mod);
1967                 lex.eatLine();
1968         }
1969 }
1970
1971
1972 void BufferParams::readRemovedModules(Lexer & lex)
1973 {
1974         if (!lex.eatLine()) {
1975                 lyxerr << "Error (BufferParams::readRemovedModules):"
1976                                 "Unexpected end of input." << endl;
1977                 return;
1978         }
1979         while (true) {
1980                 string mod = lex.getString();
1981                 if (mod == "\\end_removed_modules")
1982                         break;
1983                 removedModules_.push_back(mod);
1984                 lex.eatLine();
1985         }
1986         // now we want to remove any removed modules that were previously 
1987         // added. normally, that will be because default modules were added in 
1988         // setBaseClass(), which gets called when \textclass is read at the 
1989         // start of the read.
1990         list<string>::const_iterator rit = removedModules_.begin();
1991         list<string>::const_iterator const ren = removedModules_.end();
1992         for (; rit != ren; rit++) {
1993                 LayoutModuleList::iterator const mit = layoutModules_.begin();
1994                 LayoutModuleList::iterator const men = layoutModules_.end();
1995                 LayoutModuleList::iterator found = find(mit, men, *rit);
1996                 if (found == men)
1997                         continue;
1998                 layoutModules_.erase(found);
1999         }
2000 }
2001
2002
2003 void BufferParams::readIncludeonly(Lexer & lex)
2004 {
2005         if (!lex.eatLine()) {
2006                 lyxerr << "Error (BufferParams::readIncludeonly):"
2007                                 "Unexpected end of input." << endl;
2008                 return;
2009         }
2010         while (true) {
2011                 string child = lex.getString();
2012                 if (child == "\\end_includeonly")
2013                         break;
2014                 includedChildren_.push_back(child);
2015                 lex.eatLine();
2016         }
2017 }
2018
2019
2020 string BufferParams::paperSizeName(PapersizePurpose purpose) const
2021 {
2022         char real_papersize = papersize;
2023         if (real_papersize == PAPER_DEFAULT)
2024                 real_papersize = lyxrc.default_papersize;
2025
2026         switch (real_papersize) {
2027         case PAPER_DEFAULT:
2028                 // could be anything, so don't guess
2029                 return string();
2030         case PAPER_CUSTOM: {
2031                 if (purpose == XDVI && !paperwidth.empty() &&
2032                     !paperheight.empty()) {
2033                         // heightxwidth<unit>
2034                         string first = paperwidth;
2035                         string second = paperheight;
2036                         if (orientation == ORIENTATION_LANDSCAPE)
2037                                 first.swap(second);
2038                         // cut off unit.
2039                         return first.erase(first.length() - 2)
2040                                 + "x" + second;
2041                 }
2042                 return string();
2043         }
2044         case PAPER_A3:
2045                 return "a3";
2046         case PAPER_A4:
2047                 return "a4";
2048         case PAPER_A5:
2049                 return "a5";
2050         case PAPER_B3:
2051                 // dvips and dvipdfm do not know this
2052                 if (purpose == DVIPS || purpose == DVIPDFM)
2053                         return string();
2054                 return "b3";
2055         case PAPER_B4:
2056                 // dvipdfm does not know this
2057                 if (purpose == DVIPDFM)
2058                         return string();
2059                 return "b4";
2060         case PAPER_B5:
2061                 // dvipdfm does not know this
2062                 if (purpose == DVIPDFM)
2063                         return string();
2064                 return "b5";
2065         case PAPER_USEXECUTIVE:
2066                 // dvipdfm does not know this
2067                 if (purpose == DVIPDFM)
2068                         return string();
2069                 return "foolscap";
2070         case PAPER_USLEGAL:
2071                 return "legal";
2072         case PAPER_USLETTER:
2073         default:
2074                 if (purpose == XDVI)
2075                         return "us";
2076                 return "letter";
2077         }
2078 }
2079
2080
2081 string const BufferParams::dvips_options() const
2082 {
2083         string result;
2084
2085         if (use_geometry
2086             && papersize == PAPER_CUSTOM
2087             && !lyxrc.print_paper_dimension_flag.empty()
2088             && !paperwidth.empty()
2089             && !paperheight.empty()) {
2090                 // using a custom papersize
2091                 result = lyxrc.print_paper_dimension_flag;
2092                 result += ' ' + paperwidth;
2093                 result += ',' + paperheight;
2094         } else {
2095                 string const paper_option = paperSizeName(DVIPS);
2096                 if (!paper_option.empty() && (paper_option != "letter" ||
2097                     orientation != ORIENTATION_LANDSCAPE)) {
2098                         // dvips won't accept -t letter -t landscape.
2099                         // In all other cases, include the paper size
2100                         // explicitly.
2101                         result = lyxrc.print_paper_flag;
2102                         result += ' ' + paper_option;
2103                 }
2104         }
2105         if (orientation == ORIENTATION_LANDSCAPE &&
2106             papersize != PAPER_CUSTOM)
2107                 result += ' ' + lyxrc.print_landscape_flag;
2108         return result;
2109 }
2110
2111
2112 string const BufferParams::font_encoding() const
2113 {
2114         return (fontenc == "global") ? lyxrc.fontenc : fontenc;
2115 }
2116
2117
2118 string BufferParams::babelCall(string const & lang_opts) const
2119 {
2120         string lang_pack = lyxrc.language_package;
2121         if (lang_pack != "\\usepackage{babel}")
2122                 return lang_pack;
2123         // suppress the babel call when there is no babel language defined
2124         // for the document language in the lib/languages file and if no
2125         // other languages are used (lang_opts is then empty)
2126         if (lang_opts.empty())
2127                 return string();
2128         // If Vietnamese is used, babel must directly be loaded with the
2129         // language options, see
2130         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
2131         size_t viet = lang_opts.find("vietnam");
2132         // viet = string::npos when not found
2133         // the same is for all other languages that are not directly supported by
2134         // babel, but where LaTeX-packages add babel support.
2135         // this is currently the case for Latvian, Lithuanian, Mongolian
2136         // and Turkmen
2137         size_t latvian = lang_opts.find("latvian");
2138         size_t lithu = lang_opts.find("lithuanian");
2139         size_t mongo = lang_opts.find("mongolian");
2140         size_t turkmen = lang_opts.find("turkmen");
2141         // If Japanese is used, babel must directly be loaded with the
2142         // language options, see
2143         // http://www.lyx.org/trac/ticket/4597#c4
2144         size_t japan = lang_opts.find("japanese");
2145         if (!lyxrc.language_global_options || viet != string::npos
2146                 || japan != string::npos || latvian != string::npos
2147                 || lithu != string::npos || mongo != string::npos
2148                 || turkmen != string::npos)
2149                 return "\\usepackage[" + lang_opts + "]{babel}";
2150         return lang_pack;
2151 }
2152
2153
2154 docstring BufferParams::getGraphicsDriver(string const & package) const
2155 {
2156         docstring result;
2157
2158         if (package == "geometry") {
2159                 if (graphicsDriver == "dvips"
2160                     || graphicsDriver == "dvipdfm"
2161                     || graphicsDriver == "pdftex"
2162                     || graphicsDriver == "vtex")
2163                         result = from_ascii(graphicsDriver);
2164                 else if (graphicsDriver == "dvipdfmx")
2165                         result = from_ascii("dvipdfm");
2166         }
2167
2168         return result;
2169 }
2170
2171
2172 void BufferParams::writeEncodingPreamble(odocstream & os,
2173                 LaTeXFeatures & features, TexRow & texrow) const
2174 {
2175         if (useXetex)
2176                 return;
2177         if (inputenc == "auto") {
2178                 string const doc_encoding =
2179                         language->encoding()->latexName();
2180                 Encoding::Package const package =
2181                         language->encoding()->package();
2182
2183                 // Create a list with all the input encodings used
2184                 // in the document
2185                 set<string> encodings =
2186                         features.getEncodingSet(doc_encoding);
2187
2188                 // If the "japanese" package (i.e. pLaTeX) is used,
2189                 // inputenc must be omitted.
2190                 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
2191                 if (package == Encoding::japanese)
2192                      features.require("japanese");
2193
2194                 if ((!encodings.empty() || package == Encoding::inputenc)
2195                     && !features.isRequired("japanese")) {
2196                         os << "\\usepackage[";
2197                         set<string>::const_iterator it = encodings.begin();
2198                         set<string>::const_iterator const end = encodings.end();
2199                         if (it != end) {
2200                                 os << from_ascii(*it);
2201                                 ++it;
2202                         }
2203                         for (; it != end; ++it)
2204                                 os << ',' << from_ascii(*it);
2205                         if (package == Encoding::inputenc) {
2206                                 if (!encodings.empty())
2207                                         os << ',';
2208                                 os << from_ascii(doc_encoding);
2209                         }
2210                         os << "]{inputenc}\n";
2211                         texrow.newline();
2212                 }
2213                 if (package == Encoding::CJK || features.mustProvide("CJK")) {
2214                         if (language->encoding()->name() == "utf8-cjk"
2215                             && LaTeXFeatures::isAvailable("CJKutf8"))
2216                                 os << "\\usepackage{CJKutf8}\n";
2217                         else
2218                                 os << "\\usepackage{CJK}\n";
2219                         texrow.newline();
2220                 }
2221         } else if (inputenc != "default") {
2222                 switch (encoding().package()) {
2223                 case Encoding::none:
2224                 case Encoding::japanese:
2225                         break;
2226                 case Encoding::inputenc:
2227                         // do not load inputenc if japanese is used
2228                         if (features.isRequired("japanese"))
2229                                 break;
2230                         os << "\\usepackage[" << from_ascii(inputenc)
2231                            << "]{inputenc}\n";
2232                         texrow.newline();
2233                         break;
2234                 case Encoding::CJK:
2235                         if (encoding().name() == "utf8-cjk"
2236                             && LaTeXFeatures::isAvailable("CJKutf8"))
2237                                 os << "\\usepackage{CJKutf8}\n";
2238                         else
2239                                 os << "\\usepackage{CJK}\n";
2240                         texrow.newline();
2241                         break;
2242                 }
2243         }
2244
2245         // The encoding "armscii8" (for Armenian) is only available when
2246         // the package "armtex" is loaded.
2247         if (language->encoding()->latexName() == "armscii8"
2248             || inputenc == "armscii8") {
2249                 os << "\\usepackage{armtex}\n";
2250                 texrow.newline();
2251         }
2252 }
2253
2254
2255 string const BufferParams::parseFontName(string const & name) const
2256 {
2257         string mangled = name;
2258         size_t const idx = mangled.find('[');
2259         if (idx == string::npos || idx == 0)
2260                 return mangled;
2261         else
2262                 return mangled.substr(0, idx - 1);
2263 }
2264
2265
2266 string const BufferParams::loadFonts(string const & rm,
2267                                      string const & sf, string const & tt,
2268                                      bool const & sc, bool const & osf,
2269                                      int const & sfscale, int const & ttscale,
2270                                      bool const & xetex) const
2271 {
2272         /* The LaTeX font world is in a flux. In the PSNFSS font interface,
2273            several packages have been replaced by others, that might not
2274            be installed on every system. We have to take care for that
2275            (see psnfss.pdf). We try to support all psnfss fonts as well
2276            as the fonts that have become de facto standard in the LaTeX
2277            world (e.g. Latin Modern). We do not support obsolete fonts
2278            (like PSLatex). In general, it should be possible to mix any
2279            rm font with any sf or tt font, respectively. (JSpitzm)
2280            TODO:
2281                 -- separate math fonts.
2282         */
2283
2284         if (rm == "default" && sf == "default" && tt == "default")
2285                 //nothing to do
2286                 return string();
2287
2288         ostringstream os;
2289
2290         if (xetex) {
2291                 if (rm != "default")
2292                         os << "\\setmainfont[Mapping=tex-text]{"
2293                            << parseFontName(rm) << "}\n";
2294                 if (sf != "default") {
2295                         string const sans = parseFontName(sf);
2296                         if (sfscale != 100)
2297                                 os << "\\setsansfont[Scale=" 
2298                                    << float(sfscale) / 100 
2299                                    << ",Mapping=tex-text]{"
2300                                    << sans << "}\n";
2301                         else
2302                                 os << "\\setsansfont[Mapping=tex-text]{"
2303                                    << sans << "}\n";
2304                 }
2305                 if (tt != "default") {
2306                         string const mono = parseFontName(tt);
2307                         if (ttscale != 100)
2308                                 os << "\\setmonofont[Scale=" 
2309                                    << float(sfscale) / 100 
2310                                    << "]{"
2311                                    << mono << "}\n";
2312                         else
2313                                 os << "\\setmonofont[Mapping=tex-text]{"
2314                                    << mono << "}\n";
2315                 }
2316                 if (osf)
2317                         os << "\\defaultfontfeatures{Numbers=OldStyle}\n";
2318                 return os.str();
2319         }
2320
2321         // ROMAN FONTS
2322         // Computer Modern (must be explicitly selectable -- there might be classes
2323         // that define a different default font!
2324         if (rm == "cmr") {
2325                 os << "\\renewcommand{\\rmdefault}{cmr}\n";
2326                 // osf for Computer Modern needs eco.sty
2327                 if (osf)
2328                         os << "\\usepackage{eco}\n";
2329         }
2330         // Latin Modern Roman
2331         else if (rm == "lmodern")
2332                 os << "\\usepackage{lmodern}\n";
2333         // AE
2334         else if (rm == "ae") {
2335                 // not needed when using OT1 font encoding.
2336                 if (font_encoding() != "default")
2337                         os << "\\usepackage{ae,aecompl}\n";
2338         }
2339         // Times
2340         else if (rm == "times") {
2341                 // try to load the best available package
2342                 if (LaTeXFeatures::isAvailable("mathptmx"))
2343                         os << "\\usepackage{mathptmx}\n";
2344                 else if (LaTeXFeatures::isAvailable("mathptm"))
2345                         os << "\\usepackage{mathptm}\n";
2346                 else
2347                         os << "\\usepackage{times}\n";
2348         }
2349         // Palatino
2350         else if (rm == "palatino") {
2351                 // try to load the best available package
2352                 if (LaTeXFeatures::isAvailable("mathpazo")) {
2353                         os << "\\usepackage";
2354                         if (osf || sc) {
2355                                 os << '[';
2356                                 if (!osf)
2357                                         os << "sc";
2358                                 else
2359                                         // "osf" includes "sc"!
2360                                         os << "osf";
2361                                 os << ']';
2362                         }
2363                         os << "{mathpazo}\n";
2364                 }
2365                 else if (LaTeXFeatures::isAvailable("mathpple"))
2366                         os << "\\usepackage{mathpple}\n";
2367                 else
2368                         os << "\\usepackage{palatino}\n";
2369         }
2370         // Utopia
2371         else if (rm == "utopia") {
2372                 // fourier supersedes utopia.sty, but does
2373                 // not work with OT1 encoding.
2374                 if (LaTeXFeatures::isAvailable("fourier")
2375                     && font_encoding() != "default") {
2376                         os << "\\usepackage";
2377                         if (osf || sc) {
2378                                 os << '[';
2379                                 if (sc)
2380                                         os << "expert";
2381                                 if (osf && sc)
2382                                         os << ',';
2383                                 if (osf)
2384                                         os << "oldstyle";
2385                                 os << ']';
2386                         }
2387                         os << "{fourier}\n";
2388                 }
2389                 else
2390                         os << "\\usepackage{utopia}\n";
2391         }
2392         // Bera (complete fontset)
2393         else if (rm == "bera" && sf == "default" && tt == "default")
2394                 os << "\\usepackage{bera}\n";
2395         // everything else
2396         else if (rm != "default")
2397                 os << "\\usepackage" << "{" << rm << "}\n";
2398
2399         // SANS SERIF
2400         // Helvetica, Bera Sans
2401         if (sf == "helvet" || sf == "berasans") {
2402                 if (sfscale != 100)
2403                         os << "\\usepackage[scaled=" << float(sfscale) / 100
2404                            << "]{" << sf << "}\n";
2405                 else
2406                         os << "\\usepackage{" << sf << "}\n";
2407         }
2408         // Avant Garde
2409         else if (sf == "avant")
2410                 os << "\\usepackage{" << sf << "}\n";
2411         // Computer Modern, Latin Modern, CM Bright
2412         else if (sf != "default")
2413                 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
2414
2415         // monospaced/typewriter
2416         // Courier, LuxiMono
2417         if (tt == "luximono" || tt == "beramono") {
2418                 if (ttscale != 100)
2419                         os << "\\usepackage[scaled=" << float(ttscale) / 100
2420                            << "]{" << tt << "}\n";
2421                 else
2422                         os << "\\usepackage{" << tt << "}\n";
2423         }
2424         // Courier
2425         else if (tt == "courier" )
2426                 os << "\\usepackage{" << tt << "}\n";
2427         // Computer Modern, Latin Modern, CM Bright
2428         else if (tt != "default")
2429                 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
2430
2431         return os.str();
2432 }
2433
2434
2435 Encoding const & BufferParams::encoding() const
2436 {
2437         if (useXetex)
2438                 return *(encodings.fromLaTeXName("utf8-plain"));
2439         if (inputenc == "auto" || inputenc == "default")
2440                 return *language->encoding();
2441         Encoding const * const enc = encodings.fromLaTeXName(inputenc);
2442         if (enc)
2443                 return *enc;
2444         LYXERR0("Unknown inputenc value `" << inputenc
2445                << "'. Using `auto' instead.");
2446         return *language->encoding();
2447 }
2448
2449
2450 CiteEngine BufferParams::citeEngine() const
2451 {
2452         // FIXME the class should provide the numerical/
2453         // authoryear choice
2454         if (documentClass().provides("natbib")
2455             && cite_engine_ != ENGINE_NATBIB_NUMERICAL)
2456                 return ENGINE_NATBIB_AUTHORYEAR;
2457         return cite_engine_;
2458 }
2459
2460
2461 void BufferParams::setCiteEngine(CiteEngine cite_engine)
2462 {
2463         cite_engine_ = cite_engine;
2464 }
2465
2466 } // namespace lyx