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