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