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