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