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