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