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