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