]> git.lyx.org Git - lyx.git/blob - src/BufferParams.cpp
Fix compilation with Qt4.2
[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 = 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 when it is required
1538         if (features.isRequired("hyperref")) {
1539                 odocstringstream oss;
1540                 pdfoptions().writeLaTeX(oss, documentClass().provides("hyperref"));
1541                 lyxpreamble += oss.str();
1542         }
1543         
1544         // Will be surrounded by \makeatletter and \makeatother when not empty
1545         docstring atlyxpreamble;
1546
1547         // Some macros LyX will need
1548         docstring tmppreamble(features.getMacros());
1549
1550         if (!tmppreamble.empty())
1551                 atlyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1552                         "LyX specific LaTeX commands.\n"
1553                         + tmppreamble + '\n';
1554
1555         // the text class specific preamble
1556         tmppreamble = features.getTClassPreamble();
1557         if (!tmppreamble.empty())
1558                 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1559                         "Textclass specific LaTeX commands.\n"
1560                         + tmppreamble + '\n';
1561
1562         // suppress date if selected
1563         // use \@ifundefined because we cannot be sure that every document class
1564         // has a \date command
1565         if (suppress_date)
1566                 atlyxpreamble += "\\@ifundefined{date}{}{\\date{}}\n";
1567
1568         /* the user-defined preamble */
1569         if (!containsOnly(preamble, " \n\t"))
1570                 // FIXME UNICODE
1571                 atlyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1572                         "User specified LaTeX commands.\n"
1573                         + from_utf8(preamble) + '\n';
1574
1575         // subfig loads internally the LaTeX package "caption". As
1576         // caption is a very popular package, users will load it in
1577         // the preamble. Therefore we must load subfig behind the
1578         // user-defined preamble and check if the caption package was
1579         // loaded or not. For the case that caption is loaded before
1580         // subfig, there is the subfig option "caption=false". This
1581         // option also works when a koma-script class is used and
1582         // koma's own caption commands are used instead of caption. We
1583         // use \PassOptionsToPackage here because the user could have
1584         // already loaded subfig in the preamble.
1585         if (features.isRequired("subfig")) {
1586                 atlyxpreamble += "\\@ifundefined{showcaptionsetup}{}{%\n"
1587                         " \\PassOptionsToPackage{caption=false}{subfig}}\n"
1588                         "\\usepackage{subfig}\n";
1589         }
1590
1591         // Itemize bullet settings need to be last in case the user
1592         // defines their own bullets that use a package included
1593         // in the user-defined preamble -- ARRae
1594         // Actually it has to be done much later than that
1595         // since some packages like frenchb make modifications
1596         // at \begin{document} time -- JMarc
1597         docstring bullets_def;
1598         for (int i = 0; i < 4; ++i) {
1599                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1600                         if (bullets_def.empty())
1601                                 bullets_def += "\\AtBeginDocument{\n";
1602                         bullets_def += "  \\def\\labelitemi";
1603                         switch (i) {
1604                                 // `i' is one less than the item to modify
1605                         case 0:
1606                                 break;
1607                         case 1:
1608                                 bullets_def += 'i';
1609                                 break;
1610                         case 2:
1611                                 bullets_def += "ii";
1612                                 break;
1613                         case 3:
1614                                 bullets_def += 'v';
1615                                 break;
1616                         }
1617                         bullets_def += '{' +
1618                                 user_defined_bullet(i).getText()
1619                                 + "}\n";
1620                 }
1621         }
1622
1623         if (!bullets_def.empty())
1624                 atlyxpreamble += bullets_def + "}\n\n";
1625
1626         if (!atlyxpreamble.empty())
1627                 lyxpreamble += "\n\\makeatletter\n"
1628                         + atlyxpreamble + "\\makeatother\n\n";
1629
1630         // We try to load babel late, in case it interferes with other packages.
1631         // Jurabib and Hyperref have to be called after babel, though.
1632         if (use_babel && !features.isRequired("jurabib")
1633             && !features.isRequired("hyperref")
1634             && !features.isRequired("vietnamese")
1635             && !features.isRequired("japanese")) {
1636                 // FIXME UNICODE
1637                 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1638                 lyxpreamble += from_utf8(features.getBabelOptions()) + '\n';
1639         }
1640
1641         docstring const i18npreamble = features.getTClassI18nPreamble(use_babel);
1642         if (!i18npreamble.empty())
1643                 lyxpreamble += i18npreamble + '\n';
1644
1645         int const nlines =
1646                 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1647         for (int j = 0; j != nlines; ++j) {
1648                 texrow.newline();
1649         }
1650
1651         os << lyxpreamble;
1652
1653         // these packages (xunicode, for that matter) need to be loaded at least
1654         // after amsmath, amssymb, esint and the other packages that provide 
1655         // special glyphs
1656         if (useXetex) {
1657                 os << "\\usepackage{xunicode}\n";
1658                 texrow.newline();
1659                 os << "\\usepackage{xltxtra}\n";
1660                 texrow.newline();
1661         }
1662         return use_babel;
1663 }
1664
1665
1666 void BufferParams::useClassDefaults()
1667 {
1668         DocumentClass const & tclass = documentClass();
1669
1670         sides = tclass.sides();
1671         columns = tclass.columns();
1672         pagestyle = tclass.pagestyle();
1673         use_default_options = true;
1674         // Only if class has a ToC hierarchy
1675         if (tclass.hasTocLevels()) {
1676                 secnumdepth = tclass.secnumdepth();
1677                 tocdepth = tclass.tocdepth();
1678         }
1679 }
1680
1681
1682 bool BufferParams::hasClassDefaults() const
1683 {
1684         DocumentClass const & tclass = documentClass();
1685
1686         return sides == tclass.sides()
1687                 && columns == tclass.columns()
1688                 && pagestyle == tclass.pagestyle()
1689                 && use_default_options
1690                 && secnumdepth == tclass.secnumdepth()
1691                 && tocdepth == tclass.tocdepth();
1692 }
1693
1694
1695 DocumentClass const & BufferParams::documentClass() const
1696 {
1697         return *doc_class_;
1698 }
1699
1700
1701 DocumentClass const * BufferParams::documentClassPtr() const {
1702         return doc_class_;
1703 }
1704
1705
1706 void BufferParams::setDocumentClass(DocumentClass const * const tc) {
1707         // evil, but this function is evil
1708         doc_class_ = const_cast<DocumentClass *>(tc);
1709 }
1710
1711
1712 bool BufferParams::setBaseClass(string const & classname)
1713 {
1714         LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
1715         LayoutFileList & bcl = LayoutFileList::get();
1716         if (!bcl.haveClass(classname)) {
1717                 docstring s = 
1718                         bformat(_("The document class %1$s could not be found. "
1719                                 "A default textclass with default layouts will be used. "
1720                                 "LyX might not be able to produce output unless a correct "
1721                                 "textclass is selected from the document settings dialog."),
1722                         from_utf8(classname));
1723                 frontend::Alert::error(_("Document class not found"), s);
1724                 bcl.addEmptyClass(classname);
1725         }
1726
1727         bool const success = bcl[classname].load();
1728         if (!success) {
1729                 docstring s = 
1730                         bformat(_("The document class %1$s could not be loaded."),
1731                         from_utf8(classname));
1732                 frontend::Alert::error(_("Could not load class"), s);
1733                 return false;
1734         }
1735
1736         pimpl_->baseClass_ = classname;
1737         layoutModules_.adaptToBaseClass(baseClass(), removedModules_);
1738         return true;
1739 }
1740
1741
1742 LayoutFile const * BufferParams::baseClass() const
1743 {
1744         if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
1745                 return &(LayoutFileList::get()[pimpl_->baseClass_]);
1746         else 
1747                 return 0;
1748 }
1749
1750
1751 LayoutFileIndex const & BufferParams::baseClassID() const
1752 {
1753         return pimpl_->baseClass_;
1754 }
1755
1756
1757 void BufferParams::makeDocumentClass()
1758 {
1759         if (!baseClass())
1760                 return;
1761
1762         doc_class_ = &(DocumentClassBundle::get().makeDocumentClass(*baseClass(), layoutModules_));
1763
1764         if (!local_layout.empty()) {
1765                 if (!doc_class_->read(local_layout, TextClass::MODULE)) {
1766                         docstring const msg = _("Error reading internal layout information");
1767                         frontend::Alert::warning(_("Read Error"), msg);
1768                 }
1769         }
1770 }
1771
1772 bool BufferParams::moduleCanBeAdded(string const & modName) const
1773 {
1774         return layoutModules_.moduleCanBeAdded(modName, baseClass());
1775 }
1776
1777
1778 bool BufferParams::addLayoutModule(string const & modName)
1779 {
1780         LayoutModuleList::const_iterator it = layoutModules_.begin();
1781         LayoutModuleList::const_iterator end = layoutModules_.end();
1782         for (; it != end; it++)
1783                 if (*it == modName) 
1784                         return false;
1785         layoutModules_.push_back(modName);
1786         return true;
1787 }
1788
1789
1790 Font const BufferParams::getFont() const
1791 {
1792         FontInfo f = documentClass().defaultfont();
1793         if (fontsDefaultFamily == "rmdefault")
1794                 f.setFamily(ROMAN_FAMILY);
1795         else if (fontsDefaultFamily == "sfdefault")
1796                 f.setFamily(SANS_FAMILY);
1797         else if (fontsDefaultFamily == "ttdefault")
1798                 f.setFamily(TYPEWRITER_FAMILY);
1799         return Font(f, language);
1800 }
1801
1802
1803 void BufferParams::readPreamble(Lexer & lex)
1804 {
1805         if (lex.getString() != "\\begin_preamble")
1806                 lyxerr << "Error (BufferParams::readPreamble):"
1807                         "consistency check failed." << endl;
1808
1809         preamble = lex.getLongString("\\end_preamble");
1810 }
1811
1812
1813 void BufferParams::readLocalLayout(Lexer & lex)
1814 {
1815         if (lex.getString() != "\\begin_local_layout")
1816                 lyxerr << "Error (BufferParams::readLocalLayout):"
1817                         "consistency check failed." << endl;
1818
1819         local_layout = lex.getLongString("\\end_local_layout");
1820 }
1821
1822
1823 void BufferParams::readLanguage(Lexer & lex)
1824 {
1825         if (!lex.next()) return;
1826
1827         string const tmptok = lex.getString();
1828
1829         // check if tmptok is part of tex_babel in tex-defs.h
1830         language = languages.getLanguage(tmptok);
1831         if (!language) {
1832                 // Language tmptok was not found
1833                 language = default_language;
1834                 lyxerr << "Warning: Setting language `"
1835                        << tmptok << "' to `" << language->lang()
1836                        << "'." << endl;
1837         }
1838 }
1839
1840
1841 void BufferParams::readGraphicsDriver(Lexer & lex)
1842 {
1843         if (!lex.next()) 
1844                 return;
1845
1846         string const tmptok = lex.getString();
1847         // check if tmptok is part of tex_graphics in tex_defs.h
1848         int n = 0;
1849         while (true) {
1850                 string const test = tex_graphics[n++];
1851
1852                 if (test == tmptok) {
1853                         graphicsDriver = tmptok;
1854                         break;
1855                 }
1856                 if (test.empty()) {
1857                         lex.printError(
1858                                 "Warning: graphics driver `$$Token' not recognized!\n"
1859                                 "         Setting graphics driver to `default'.\n");
1860                         graphicsDriver = "default";
1861                         break;
1862                 }
1863         }
1864 }
1865
1866
1867 void BufferParams::readBullets(Lexer & lex)
1868 {
1869         if (!lex.next()) 
1870                 return;
1871
1872         int const index = lex.getInteger();
1873         lex.next();
1874         int temp_int = lex.getInteger();
1875         user_defined_bullet(index).setFont(temp_int);
1876         temp_bullet(index).setFont(temp_int);
1877         lex >> temp_int;
1878         user_defined_bullet(index).setCharacter(temp_int);
1879         temp_bullet(index).setCharacter(temp_int);
1880         lex >> temp_int;
1881         user_defined_bullet(index).setSize(temp_int);
1882         temp_bullet(index).setSize(temp_int);
1883 }
1884
1885
1886 void BufferParams::readBulletsLaTeX(Lexer & lex)
1887 {
1888         // The bullet class should be able to read this.
1889         if (!lex.next()) 
1890                 return;
1891         int const index = lex.getInteger();
1892         lex.next(true);
1893         docstring const temp_str = lex.getDocString();
1894
1895         user_defined_bullet(index).setText(temp_str);
1896         temp_bullet(index).setText(temp_str);
1897 }
1898
1899
1900 void BufferParams::readModules(Lexer & lex)
1901 {
1902         if (!lex.eatLine()) {
1903                 lyxerr << "Error (BufferParams::readModules):"
1904                                 "Unexpected end of input." << endl;
1905                 return;
1906         }
1907         while (true) {
1908                 string mod = lex.getString();
1909                 if (mod == "\\end_modules")
1910                         break;
1911                 addLayoutModule(mod);
1912                 lex.eatLine();
1913         }
1914 }
1915
1916
1917 void BufferParams::readRemovedModules(Lexer & lex)
1918 {
1919         if (!lex.eatLine()) {
1920                 lyxerr << "Error (BufferParams::readRemovedModules):"
1921                                 "Unexpected end of input." << endl;
1922                 return;
1923         }
1924         while (true) {
1925                 string mod = lex.getString();
1926                 if (mod == "\\end_removed_modules")
1927                         break;
1928                 removedModules_.push_back(mod);
1929                 lex.eatLine();
1930         }
1931         // now we want to remove any removed modules that were previously 
1932         // added. normally, that will be because default modules were added in 
1933         // setBaseClass(), which gets called when \textclass is read at the 
1934         // start of the read.
1935         list<string>::const_iterator rit = removedModules_.begin();
1936         list<string>::const_iterator const ren = removedModules_.end();
1937         for (; rit != ren; rit++) {
1938                 LayoutModuleList::iterator const mit = layoutModules_.begin();
1939                 LayoutModuleList::iterator const men = layoutModules_.end();
1940                 LayoutModuleList::iterator found = find(mit, men, *rit);
1941                 if (found == men)
1942                         continue;
1943                 layoutModules_.erase(found);
1944         }
1945 }
1946
1947
1948 void BufferParams::readIncludeonly(Lexer & lex)
1949 {
1950         if (!lex.eatLine()) {
1951                 lyxerr << "Error (BufferParams::readIncludeonly):"
1952                                 "Unexpected end of input." << endl;
1953                 return;
1954         }
1955         while (true) {
1956                 string child = lex.getString();
1957                 if (child == "\\end_includeonly")
1958                         break;
1959                 includedChildren_.push_back(child);
1960                 lex.eatLine();
1961         }
1962 }
1963
1964
1965 string BufferParams::paperSizeName(PapersizePurpose purpose) const
1966 {
1967         char real_papersize = papersize;
1968         if (real_papersize == PAPER_DEFAULT)
1969                 real_papersize = lyxrc.default_papersize;
1970
1971         switch (real_papersize) {
1972         case PAPER_DEFAULT:
1973                 // could be anything, so don't guess
1974                 return string();
1975         case PAPER_CUSTOM: {
1976                 if (purpose == XDVI && !paperwidth.empty() &&
1977                     !paperheight.empty()) {
1978                         // heightxwidth<unit>
1979                         string first = paperwidth;
1980                         string second = paperheight;
1981                         if (orientation == ORIENTATION_LANDSCAPE)
1982                                 first.swap(second);
1983                         // cut off unit.
1984                         return first.erase(first.length() - 2)
1985                                 + "x" + second;
1986                 }
1987                 return string();
1988         }
1989         case PAPER_A3:
1990                 return "a3";
1991         case PAPER_A4:
1992                 return "a4";
1993         case PAPER_A5:
1994                 return "a5";
1995         case PAPER_B3:
1996                 // dvips and dvipdfm do not know this
1997                 if (purpose == DVIPS || purpose == DVIPDFM)
1998                         return string();
1999                 return "b3";
2000         case PAPER_B4:
2001                 // dvipdfm does not know this
2002                 if (purpose == DVIPDFM)
2003                         return string();
2004                 return "b4";
2005         case PAPER_B5:
2006                 // dvipdfm does not know this
2007                 if (purpose == DVIPDFM)
2008                         return string();
2009                 return "b5";
2010         case PAPER_USEXECUTIVE:
2011                 // dvipdfm does not know this
2012                 if (purpose == DVIPDFM)
2013                         return string();
2014                 return "foolscap";
2015         case PAPER_USLEGAL:
2016                 return "legal";
2017         case PAPER_USLETTER:
2018         default:
2019                 if (purpose == XDVI)
2020                         return "us";
2021                 return "letter";
2022         }
2023 }
2024
2025
2026 string const BufferParams::dvips_options() const
2027 {
2028         string result;
2029
2030         if (use_geometry
2031             && papersize == PAPER_CUSTOM
2032             && !lyxrc.print_paper_dimension_flag.empty()
2033             && !paperwidth.empty()
2034             && !paperheight.empty()) {
2035                 // using a custom papersize
2036                 result = lyxrc.print_paper_dimension_flag;
2037                 result += ' ' + paperwidth;
2038                 result += ',' + paperheight;
2039         } else {
2040                 string const paper_option = paperSizeName(DVIPS);
2041                 if (!paper_option.empty() && (paper_option != "letter" ||
2042                     orientation != ORIENTATION_LANDSCAPE)) {
2043                         // dvips won't accept -t letter -t landscape.
2044                         // In all other cases, include the paper size
2045                         // explicitly.
2046                         result = lyxrc.print_paper_flag;
2047                         result += ' ' + paper_option;
2048                 }
2049         }
2050         if (orientation == ORIENTATION_LANDSCAPE &&
2051             papersize != PAPER_CUSTOM)
2052                 result += ' ' + lyxrc.print_landscape_flag;
2053         return result;
2054 }
2055
2056
2057 string const BufferParams::font_encoding() const
2058 {
2059         return (fontenc == "global") ? lyxrc.fontenc : fontenc;
2060 }
2061
2062
2063 string BufferParams::babelCall(string const & lang_opts) const
2064 {
2065         string lang_pack = lyxrc.language_package;
2066         if (lang_pack != "\\usepackage{babel}")
2067                 return lang_pack;
2068         // suppress the babel call when there is no babel language defined
2069         // for the document language in the lib/languages file and if no
2070         // other languages are used (lang_opts is then empty)
2071         if (lang_opts.empty())
2072                 return string();
2073         // If Vietnamese is used, babel must directly be loaded with the
2074         // language options, see
2075         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
2076         size_t viet = lang_opts.find("vietnam");
2077         // viet = string::npos when not found
2078         // the same is for all other languages that are not directly supported by
2079         // babel, but where LaTeX-packages add babel support.
2080         // this is currently the case for Latvian, Lithuanian, and Mongolian
2081         size_t latvian = lang_opts.find("latvian");
2082         size_t lithu = lang_opts.find("lithuanian");
2083         size_t mongo = lang_opts.find("mongolian");
2084         // If Japanese is used, babel must directly be loaded with the
2085         // language options, see
2086         // http://www.lyx.org/trac/ticket/4597#c4
2087         size_t japan = lang_opts.find("japanese");
2088         if (!lyxrc.language_global_options || viet != string::npos
2089                 || japan != string::npos || latvian != string::npos
2090                 || lithu != string::npos || mongo != string::npos)
2091                 return "\\usepackage[" + lang_opts + "]{babel}";
2092         return lang_pack;
2093 }
2094
2095
2096 docstring BufferParams::getGraphicsDriver(string const & package) const
2097 {
2098         docstring result;
2099
2100         if (package == "geometry") {
2101                 if (graphicsDriver == "dvips"
2102                     || graphicsDriver == "dvipdfm"
2103                     || graphicsDriver == "pdftex"
2104                     || graphicsDriver == "vtex")
2105                         result = from_ascii(graphicsDriver);
2106                 else if (graphicsDriver == "dvipdfmx")
2107                         result = from_ascii("dvipdfm");
2108         }
2109
2110         return result;
2111 }
2112
2113
2114 void BufferParams::writeEncodingPreamble(odocstream & os,
2115                 LaTeXFeatures & features, TexRow & texrow) const
2116 {
2117         if (useXetex)
2118                 return;
2119         if (inputenc == "auto") {
2120                 string const doc_encoding =
2121                         language->encoding()->latexName();
2122                 Encoding::Package const package =
2123                         language->encoding()->package();
2124
2125                 // Create a list with all the input encodings used
2126                 // in the document
2127                 set<string> encodings =
2128                         features.getEncodingSet(doc_encoding);
2129
2130                 // If the "japanese" package (i.e. pLaTeX) is used,
2131                 // inputenc must be omitted.
2132                 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
2133                 if (package == Encoding::japanese)
2134                      features.require("japanese");
2135
2136                 if ((!encodings.empty() || package == Encoding::inputenc)
2137                     && !features.isRequired("japanese")) {
2138                         os << "\\usepackage[";
2139                         set<string>::const_iterator it = encodings.begin();
2140                         set<string>::const_iterator const end = encodings.end();
2141                         if (it != end) {
2142                                 os << from_ascii(*it);
2143                                 ++it;
2144                         }
2145                         for (; it != end; ++it)
2146                                 os << ',' << from_ascii(*it);
2147                         if (package == Encoding::inputenc) {
2148                                 if (!encodings.empty())
2149                                         os << ',';
2150                                 os << from_ascii(doc_encoding);
2151                         }
2152                         os << "]{inputenc}\n";
2153                         texrow.newline();
2154                 }
2155                 if (package == Encoding::CJK || features.mustProvide("CJK")) {
2156                         if (language->encoding()->name() == "utf8-cjk"
2157                             && LaTeXFeatures::isAvailable("CJKutf8"))
2158                                 os << "\\usepackage{CJKutf8}\n";
2159                         else
2160                                 os << "\\usepackage{CJK}\n";
2161                         texrow.newline();
2162                 }
2163         } else if (inputenc != "default") {
2164                 switch (encoding().package()) {
2165                 case Encoding::none:
2166                 case Encoding::japanese:
2167                         break;
2168                 case Encoding::inputenc:
2169                         // do not load inputenc if japanese is used
2170                         if (features.isRequired("japanese"))
2171                                 break;
2172                         os << "\\usepackage[" << from_ascii(inputenc)
2173                            << "]{inputenc}\n";
2174                         texrow.newline();
2175                         break;
2176                 case Encoding::CJK:
2177                         if (encoding().name() == "utf8-cjk"
2178                             && LaTeXFeatures::isAvailable("CJKutf8"))
2179                                 os << "\\usepackage{CJKutf8}\n";
2180                         else
2181                                 os << "\\usepackage{CJK}\n";
2182                         texrow.newline();
2183                         break;
2184                 }
2185         }
2186
2187         // The encoding "armscii8" (for Armenian) is only available when
2188         // the package "armtex" is loaded.
2189         if (language->encoding()->latexName() == "armscii8"
2190             || inputenc == "armscii8") {
2191                 os << "\\usepackage{armtex}\n";
2192                 texrow.newline();
2193         }
2194 }
2195
2196
2197 string const BufferParams::parseFontName(string const & name) const
2198 {
2199         string mangled = name;
2200         size_t const idx = mangled.find('[');
2201         if (idx == string::npos || idx == 0)
2202                 return mangled;
2203         else
2204                 return mangled.substr(0, idx - 1);
2205 }
2206
2207
2208 string const BufferParams::loadFonts(string const & rm,
2209                                      string const & sf, string const & tt,
2210                                      bool const & sc, bool const & osf,
2211                                      int const & sfscale, int const & ttscale,
2212                                      bool const & xetex) const
2213 {
2214         /* The LaTeX font world is in a flux. In the PSNFSS font interface,
2215            several packages have been replaced by others, that might not
2216            be installed on every system. We have to take care for that
2217            (see psnfss.pdf). We try to support all psnfss fonts as well
2218            as the fonts that have become de facto standard in the LaTeX
2219            world (e.g. Latin Modern). We do not support obsolete fonts
2220            (like PSLatex). In general, it should be possible to mix any
2221            rm font with any sf or tt font, respectively. (JSpitzm)
2222            TODO:
2223                 -- separate math fonts.
2224         */
2225
2226         if (rm == "default" && sf == "default" && tt == "default")
2227                 //nothing to do
2228                 return string();
2229
2230         ostringstream os;
2231
2232         if (xetex) {
2233                 if (rm != "default")
2234                         os << "\\setmainfont[Mapping=tex-text]{"
2235                            << parseFontName(rm) << "}\n";
2236                 if (sf != "default") {
2237                         string const sans = parseFontName(sf);
2238                         if (sfscale != 100)
2239                                 os << "\\setsansfont[Scale=" 
2240                                    << float(sfscale) / 100 
2241                                    << ",Mapping=tex-text]{"
2242                                    << sans << "}\n";
2243                         else
2244                                 os << "\\setsansfont[Mapping=tex-text]{"
2245                                    << sans << "}\n";
2246                 }
2247                 if (tt != "default") {
2248                         string const mono = parseFontName(tt);
2249                         if (ttscale != 100)
2250                                 os << "\\setmonofont[Scale=" 
2251                                    << float(sfscale) / 100 
2252                                    << "]{"
2253                                    << mono << "}\n";
2254                         else
2255                                 os << "\\setmonofont[Mapping=tex-text]{"
2256                                    << mono << "}\n";
2257                 }
2258                 if (osf)
2259                         os << "\\defaultfontfeatures{Numbers=OldStyle}\n";
2260                 return os.str();
2261         }
2262
2263         // ROMAN FONTS
2264         // Computer Modern (must be explicitly selectable -- there might be classes
2265         // that define a different default font!
2266         if (rm == "cmr") {
2267                 os << "\\renewcommand{\\rmdefault}{cmr}\n";
2268                 // osf for Computer Modern needs eco.sty
2269                 if (osf)
2270                         os << "\\usepackage{eco}\n";
2271         }
2272         // Latin Modern Roman
2273         else if (rm == "lmodern")
2274                 os << "\\usepackage{lmodern}\n";
2275         // AE
2276         else if (rm == "ae") {
2277                 // not needed when using OT1 font encoding.
2278                 if (font_encoding() != "default")
2279                         os << "\\usepackage{ae,aecompl}\n";
2280         }
2281         // Times
2282         else if (rm == "times") {
2283                 // try to load the best available package
2284                 if (LaTeXFeatures::isAvailable("mathptmx"))
2285                         os << "\\usepackage{mathptmx}\n";
2286                 else if (LaTeXFeatures::isAvailable("mathptm"))
2287                         os << "\\usepackage{mathptm}\n";
2288                 else
2289                         os << "\\usepackage{times}\n";
2290         }
2291         // Palatino
2292         else if (rm == "palatino") {
2293                 // try to load the best available package
2294                 if (LaTeXFeatures::isAvailable("mathpazo")) {
2295                         os << "\\usepackage";
2296                         if (osf || sc) {
2297                                 os << '[';
2298                                 if (!osf)
2299                                         os << "sc";
2300                                 else
2301                                         // "osf" includes "sc"!
2302                                         os << "osf";
2303                                 os << ']';
2304                         }
2305                         os << "{mathpazo}\n";
2306                 }
2307                 else if (LaTeXFeatures::isAvailable("mathpple"))
2308                         os << "\\usepackage{mathpple}\n";
2309                 else
2310                         os << "\\usepackage{palatino}\n";
2311         }
2312         // Utopia
2313         else if (rm == "utopia") {
2314                 // fourier supersedes utopia.sty, but does
2315                 // not work with OT1 encoding.
2316                 if (LaTeXFeatures::isAvailable("fourier")
2317                     && font_encoding() != "default") {
2318                         os << "\\usepackage";
2319                         if (osf || sc) {
2320                                 os << '[';
2321                                 if (sc)
2322                                         os << "expert";
2323                                 if (osf && sc)
2324                                         os << ',';
2325                                 if (osf)
2326                                         os << "oldstyle";
2327                                 os << ']';
2328                         }
2329                         os << "{fourier}\n";
2330                 }
2331                 else
2332                         os << "\\usepackage{utopia}\n";
2333         }
2334         // Bera (complete fontset)
2335         else if (rm == "bera" && sf == "default" && tt == "default")
2336                 os << "\\usepackage{bera}\n";
2337         // everything else
2338         else if (rm != "default")
2339                 os << "\\usepackage" << "{" << rm << "}\n";
2340
2341         // SANS SERIF
2342         // Helvetica, Bera Sans
2343         if (sf == "helvet" || sf == "berasans") {
2344                 if (sfscale != 100)
2345                         os << "\\usepackage[scaled=" << float(sfscale) / 100
2346                            << "]{" << sf << "}\n";
2347                 else
2348                         os << "\\usepackage{" << sf << "}\n";
2349         }
2350         // Avant Garde
2351         else if (sf == "avant")
2352                 os << "\\usepackage{" << sf << "}\n";
2353         // Computer Modern, Latin Modern, CM Bright
2354         else if (sf != "default")
2355                 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
2356
2357         // monospaced/typewriter
2358         // Courier, LuxiMono
2359         if (tt == "luximono" || tt == "beramono") {
2360                 if (ttscale != 100)
2361                         os << "\\usepackage[scaled=" << float(ttscale) / 100
2362                            << "]{" << tt << "}\n";
2363                 else
2364                         os << "\\usepackage{" << tt << "}\n";
2365         }
2366         // Courier
2367         else if (tt == "courier" )
2368                 os << "\\usepackage{" << tt << "}\n";
2369         // Computer Modern, Latin Modern, CM Bright
2370         else if (tt != "default")
2371                 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
2372
2373         return os.str();
2374 }
2375
2376
2377 Encoding const & BufferParams::encoding() const
2378 {
2379         if (useXetex)
2380                 return *(encodings.fromLaTeXName("utf8-plain"));
2381         if (inputenc == "auto" || inputenc == "default")
2382                 return *language->encoding();
2383         Encoding const * const enc = encodings.fromLaTeXName(inputenc);
2384         if (enc)
2385                 return *enc;
2386         LYXERR0("Unknown inputenc value `" << inputenc
2387                << "'. Using `auto' instead.");
2388         return *language->encoding();
2389 }
2390
2391
2392 CiteEngine BufferParams::citeEngine() const
2393 {
2394         // FIXME the class should provide the numerical/
2395         // authoryear choice
2396         if (documentClass().provides("natbib")
2397             && cite_engine_ != ENGINE_NATBIB_NUMERICAL)
2398                 return ENGINE_NATBIB_AUTHORYEAR;
2399         return cite_engine_;
2400 }
2401
2402
2403 void BufferParams::setCiteEngine(CiteEngine cite_engine)
2404 {
2405         cite_engine_ = cite_engine;
2406 }
2407
2408 } // namespace lyx