]> git.lyx.org Git - lyx.git/blob - src/BufferParams.cpp
this we don't need anymore
[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
850
851 void BufferParams::validate(LaTeXFeatures & features) const
852 {
853         features.require(documentClass().requires());
854
855         if (outputChanges) {
856                 bool dvipost    = LaTeXFeatures::isAvailable("dvipost");
857                 bool xcolorsoul = LaTeXFeatures::isAvailable("soul") &&
858                                   LaTeXFeatures::isAvailable("xcolor");
859
860                 switch (features.runparams().flavor) {
861                 case OutputParams::LATEX:
862                         if (dvipost) {
863                                 features.require("ct-dvipost");
864                                 features.require("dvipost");
865                         } else if (xcolorsoul) {
866                                 features.require("ct-xcolor-soul");
867                                 features.require("soul");
868                                 features.require("xcolor");
869                         } else {
870                                 features.require("ct-none");
871                         }
872                         break;
873                 case OutputParams::PDFLATEX:
874                         if (xcolorsoul) {
875                                 features.require("ct-xcolor-soul");
876                                 features.require("soul");
877                                 features.require("xcolor");
878                                 // improves color handling in PDF output
879                                 features.require("pdfcolmk"); 
880                         } else {
881                                 features.require("ct-none");
882                         }
883                         break;
884                 default:
885                         break;
886                 }
887         }
888
889         // Floats with 'Here definitely' as default setting.
890         if (float_placement.find('H') != string::npos)
891                 features.require("float");
892
893         // AMS Style is at document level
894         if (use_amsmath == package_on
895             || documentClass().provides("amsmath"))
896                 features.require("amsmath");
897         if (use_esint == package_on)
898                 features.require("esint");
899
900         // Document-level line spacing
901         if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
902                 features.require("setspace");
903
904         // the bullet shapes are buffer level not paragraph level
905         // so they are tested here
906         for (int i = 0; i < 4; ++i) {
907                 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i]) 
908                         continue;
909                 int const font = user_defined_bullet(i).getFont();
910                 if (font == 0) {
911                         int const c = user_defined_bullet(i).getCharacter();
912                         if (c == 16
913                             || c == 17
914                             || c == 25
915                             || c == 26
916                             || c == 31) {
917                                 features.require("latexsym");
918                         }
919                 } else if (font == 1) {
920                         features.require("amssymb");
921                 } else if (font >= 2 && font <= 5) {
922                         features.require("pifont");
923                 }
924         }
925
926         if (pdfoptions().use_hyperref)
927                 features.require("hyperref");
928 }
929
930
931 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
932                               TexRow & texrow) const
933 {
934         os << "\\documentclass";
935
936         DocumentClass const & tclass = documentClass();
937
938         ostringstream clsoptions; // the document class options.
939
940         if (tokenPos(tclass.opt_fontsize(),
941                      '|', fontsize) >= 0) {
942                 // only write if existing in list (and not default)
943                 clsoptions << fontsize << "pt,";
944         }
945
946         // custom, A3, B3 and B4 paper sizes need geometry
947         bool nonstandard_papersize = papersize == PAPER_B3
948                 || papersize == PAPER_B4
949                 || papersize == PAPER_A3
950                 || papersize == PAPER_CUSTOM;
951
952         if (!use_geometry) {
953                 switch (papersize) {
954                 case PAPER_A4:
955                         clsoptions << "a4paper,";
956                         break;
957                 case PAPER_USLETTER:
958                         clsoptions << "letterpaper,";
959                         break;
960                 case PAPER_A5:
961                         clsoptions << "a5paper,";
962                         break;
963                 case PAPER_B5:
964                         clsoptions << "b5paper,";
965                         break;
966                 case PAPER_USEXECUTIVE:
967                         clsoptions << "executivepaper,";
968                         break;
969                 case PAPER_USLEGAL:
970                         clsoptions << "legalpaper,";
971                         break;
972                 case PAPER_DEFAULT:
973                 case PAPER_A3:
974                 case PAPER_B3:
975                 case PAPER_B4:
976                 case PAPER_CUSTOM:
977                         break;
978                 }
979         }
980
981         // if needed
982         if (sides != tclass.sides()) {
983                 switch (sides) {
984                 case OneSide:
985                         clsoptions << "oneside,";
986                         break;
987                 case TwoSides:
988                         clsoptions << "twoside,";
989                         break;
990                 }
991         }
992
993         // if needed
994         if (columns != tclass.columns()) {
995                 if (columns == 2)
996                         clsoptions << "twocolumn,";
997                 else
998                         clsoptions << "onecolumn,";
999         }
1000
1001         if (!use_geometry
1002             && orientation == ORIENTATION_LANDSCAPE)
1003                 clsoptions << "landscape,";
1004
1005         // language should be a parameter to \documentclass
1006         if (language->babel() == "hebrew"
1007             && default_language->babel() != "hebrew")
1008                 // This seems necessary
1009                 features.useLanguage(default_language);
1010
1011         ostringstream language_options;
1012         bool const use_babel = features.useBabel();
1013         if (use_babel) {
1014                 language_options << features.getLanguages();
1015                 if (!language->babel().empty()) {
1016                         if (!language_options.str().empty())
1017                                 language_options << ',';
1018                         language_options << language->babel();
1019                 }
1020                 // when Vietnamese is used, babel must directly be loaded with the
1021                 // language options, not in the class options, see
1022                 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1023                 size_t viet = language_options.str().find("vietnam");
1024                 // viet = string::npos when not found
1025                 // when Japanese is used, babel must directly be loaded with the
1026                 // language options, not in the class options, see
1027                 // http://bugzilla.lyx.org/show_bug.cgi?id=4597#c4
1028                 size_t japan = language_options.str().find("japanese");
1029                 // japan = string::npos when not found
1030                 if (lyxrc.language_global_options && !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 LFE encoding
1067         if (lyxrc.fontenc != "default") {
1068                 if (language->lang() == "arabic_arabi" || language->lang() == "farsi") {
1069                         os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
1070                            << ",LFE,LAE]{fontenc}\n";
1071                         texrow.newline();
1072                 } else {
1073                         os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
1074                            << "]{fontenc}\n";
1075                         texrow.newline();
1076                 }
1077         }
1078
1079         // handle inputenc etc.
1080         writeEncodingPreamble(os, features, texrow);
1081
1082         if (!listings_params.empty()) {
1083                 os << "\\usepackage{listings}\n";
1084                 texrow.newline();
1085                 os << "\\lstset{";
1086                 // do not test validity because listings_params is supposed to be valid
1087                 string par = InsetListingsParams(listings_params).separatedParams(true);
1088                 os << from_ascii(par);
1089                 // count the number of newlines
1090                 for (size_t i = 0; i < par.size(); ++i)
1091                         if (par[i] == '\n')
1092                                 texrow.newline();
1093                 os << "}\n";
1094                 texrow.newline();
1095         }
1096         if (use_geometry || nonstandard_papersize) {
1097                 os << "\\usepackage{geometry}\n";
1098                 texrow.newline();
1099                 os << "\\geometry{verbose";
1100                 if (orientation == ORIENTATION_LANDSCAPE)
1101                         os << ",landscape";
1102                 switch (papersize) {
1103                 case PAPER_CUSTOM:
1104                         if (!paperwidth.empty())
1105                                 os << ",paperwidth="
1106                                    << from_ascii(paperwidth);
1107                         if (!paperheight.empty())
1108                                 os << ",paperheight="
1109                                    << from_ascii(paperheight);
1110                         break;
1111                 case PAPER_USLETTER:
1112                         os << ",letterpaper";
1113                         break;
1114                 case PAPER_USLEGAL:
1115                         os << ",legalpaper";
1116                         break;
1117                 case PAPER_USEXECUTIVE:
1118                         os << ",executivepaper";
1119                         break;
1120                 case PAPER_A3:
1121                         os << ",a3paper";
1122                         break;
1123                 case PAPER_A4:
1124                         os << ",a4paper";
1125                         break;
1126                 case PAPER_A5:
1127                         os << ",a5paper";
1128                         break;
1129                 case PAPER_B3:
1130                         os << ",b3paper";
1131                         break;
1132                 case PAPER_B4:
1133                         os << ",b4paper";
1134                         break;
1135                 case PAPER_B5:
1136                         os << ",b5paper";
1137                         break;
1138                 default:
1139                         // default papersize ie PAPER_DEFAULT
1140                         switch (lyxrc.default_papersize) {
1141                         case PAPER_DEFAULT: // keep compiler happy
1142                         case PAPER_USLETTER:
1143                                 os << ",letterpaper";
1144                                 break;
1145                         case PAPER_USLEGAL:
1146                                 os << ",legalpaper";
1147                                 break;
1148                         case PAPER_USEXECUTIVE:
1149                                 os << ",executivepaper";
1150                                 break;
1151                         case PAPER_A3:
1152                                 os << ",a3paper";
1153                                 break;
1154                         case PAPER_A4:
1155                                 os << ",a4paper";
1156                                 break;
1157                         case PAPER_A5:
1158                                 os << ",a5paper";
1159                                 break;
1160                         case PAPER_B5:
1161                                 os << ",b5paper";
1162                                 break;
1163                         case PAPER_B3:
1164                         case PAPER_B4:
1165                         case PAPER_CUSTOM:
1166                                 break;
1167                         }
1168                 }
1169                 if (!topmargin.empty())
1170                         os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1171                 if (!bottommargin.empty())
1172                         os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1173                 if (!leftmargin.empty())
1174                         os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1175                 if (!rightmargin.empty())
1176                         os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1177                 if (!headheight.empty())
1178                         os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1179                 if (!headsep.empty())
1180                         os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1181                 if (!footskip.empty())
1182                         os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1183                 if (!columnsep.empty())
1184                         os << ",columnsep=" << from_ascii(Length(columnsep).asLatexString());
1185                 os << "}\n";
1186                 texrow.newline();
1187         }
1188
1189         if (tokenPos(tclass.opt_pagestyle(),
1190                      '|', pagestyle) >= 0) {
1191                 if (pagestyle == "fancy") {
1192                         os << "\\usepackage{fancyhdr}\n";
1193                         texrow.newline();
1194                 }
1195                 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1196                 texrow.newline();
1197         }
1198
1199         // Only if class has a ToC hierarchy
1200         if (tclass.hasTocLevels()) {
1201                 if (secnumdepth != tclass.secnumdepth()) {
1202                         os << "\\setcounter{secnumdepth}{"
1203                            << secnumdepth
1204                            << "}\n";
1205                         texrow.newline();
1206                 }
1207                 if (tocdepth != tclass.tocdepth()) {
1208                         os << "\\setcounter{tocdepth}{"
1209                            << tocdepth
1210                            << "}\n";
1211                         texrow.newline();
1212                 }
1213         }
1214
1215         if (paragraph_separation) {
1216                 switch (getDefSkip().kind()) {
1217                 case VSpace::SMALLSKIP:
1218                         os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1219                         break;
1220                 case VSpace::MEDSKIP:
1221                         os << "\\setlength{\\parskip}{\\medskipamount}\n";
1222                         break;
1223                 case VSpace::BIGSKIP:
1224                         os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1225                         break;
1226                 case VSpace::LENGTH:
1227                         os << "\\setlength{\\parskip}{"
1228                            << from_utf8(getDefSkip().length().asLatexString())
1229                            << "}\n";
1230                         break;
1231                 default: // should never happen // Then delete it.
1232                         os << "\\setlength{\\parskip}{\\medskipamount}\n";
1233                         break;
1234                 }
1235                 texrow.newline();
1236
1237                 os << "\\setlength{\\parindent}{0pt}\n";
1238                 texrow.newline();
1239         }
1240
1241         // If we use jurabib, we have to call babel here.
1242         if (use_babel && features.isRequired("jurabib")) {
1243                 os << from_ascii(babelCall(language_options.str()))
1244                    << '\n'
1245                    << from_ascii(features.getBabelOptions());
1246                 texrow.newline();
1247         }
1248
1249         // Now insert the LyX specific LaTeX commands...
1250
1251         // The optional packages;
1252         docstring lyxpreamble(from_ascii(features.getPackages()));
1253
1254         // Line spacing
1255         lyxpreamble += from_utf8(spacing().writePreamble(tclass.provides("SetSpace")));
1256
1257         // We try to load babel late, in case it interferes
1258         // with other packages. But some packages also need babel to be loaded
1259         // before, e.g. jurabib has to be called after babel.
1260         // So load babel after the optional packages but before the user-defined
1261         // preamble. This allows the users to redefine babel commands, e.g. to
1262         // translate the word "Index" to the German "Stichwortverzeichnis".
1263         // For more infos why this place was chosen, see
1264         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg128425.html
1265         // If you encounter problems, you can shift babel to its old place behind
1266         // the user-defined preamble. But in this case you must change the Vietnamese
1267         // support from currently "\usepackage[vietnamese]{babel}" to:
1268         // \usepackage{vietnamese}
1269         // \usepackage{babel}
1270         // because vietnamese must be loaded before hyperref
1271         if (use_babel && !features.isRequired("jurabib")) {
1272                 // FIXME UNICODE
1273                 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1274                 lyxpreamble += from_utf8(features.getBabelOptions());
1275         }
1276
1277         // PDF support.
1278         // * Hyperref manual: "Make sure it comes last of your loaded
1279         //   packages, to give it a fighting chance of not being over-written,
1280         //   since its job is to redefine many LATEX commands."
1281         // * Email from Heiko Oberdiek: "It is usually better to load babel
1282         //   before hyperref. Then hyperref has a chance to detect babel.
1283         // * Has to be loaded before the "LyX specific LaTeX commands" to
1284         //   avoid errors with algorithm floats.
1285         // use hyperref explicitely when it is required
1286         if (features.isRequired("hyperref")) {
1287                 odocstringstream oss;
1288                 pdfoptions().writeLaTeX(oss, documentClass().provides("hyperref"));
1289                 lyxpreamble += oss.str();
1290         }
1291
1292         // only add \makeatletter and \makeatother when actually needed
1293         bool makeatletter = false;
1294
1295         // Some macros LyX will need
1296         docstring tmppreamble(from_ascii(features.getMacros()));
1297
1298         if (!tmppreamble.empty()) {
1299                 if (!makeatletter) {
1300                         lyxpreamble += "\n\\makeatletter\n";
1301                         makeatletter = true;
1302                 }
1303                 lyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1304                         "LyX specific LaTeX commands.\n"
1305                         + tmppreamble + '\n';
1306         }
1307
1308         // the text class specific preamble
1309         tmppreamble = features.getTClassPreamble();
1310         if (!tmppreamble.empty()) {
1311                 if (!makeatletter) {
1312                         lyxpreamble += "\n\\makeatletter\n";
1313                         makeatletter = true;
1314                 }
1315                 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1316                         "Textclass specific LaTeX commands.\n"
1317                         + tmppreamble + '\n';
1318         }
1319
1320         /* the user-defined preamble */
1321         if (!preamble.empty()) {
1322                 if (!makeatletter) {
1323                         lyxpreamble += "\n\\makeatletter\n";
1324                         makeatletter = true;
1325                 }
1326                 // FIXME UNICODE
1327                 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1328                         "User specified LaTeX commands.\n"
1329                         + from_utf8(preamble) + '\n';
1330         }
1331
1332         // Itemize bullet settings need to be last in case the user
1333         // defines their own bullets that use a package included
1334         // in the user-defined preamble -- ARRae
1335         // Actually it has to be done much later than that
1336         // since some packages like frenchb make modifications
1337         // at \begin{document} time -- JMarc
1338         docstring bullets_def;
1339         for (int i = 0; i < 4; ++i) {
1340                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1341                         if (bullets_def.empty())
1342                                 bullets_def += "\\AtBeginDocument{\n";
1343                         bullets_def += "  \\def\\labelitemi";
1344                         switch (i) {
1345                                 // `i' is one less than the item to modify
1346                         case 0:
1347                                 break;
1348                         case 1:
1349                                 bullets_def += 'i';
1350                                 break;
1351                         case 2:
1352                                 bullets_def += "ii";
1353                                 break;
1354                         case 3:
1355                                 bullets_def += 'v';
1356                                 break;
1357                         }
1358                         bullets_def += '{' +
1359                                 user_defined_bullet(i).getText()
1360                                 + "}\n";
1361                 }
1362         }
1363
1364         if (!bullets_def.empty()) {
1365                 if (!makeatletter) {
1366                         lyxpreamble += "\n\\makeatletter\n";
1367                         makeatletter = true;
1368                 }
1369                 lyxpreamble += bullets_def + "}\n\n";
1370         }
1371
1372         if (makeatletter)
1373                 lyxpreamble += "\\makeatother\n\n";
1374
1375         int const nlines =
1376                 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1377         for (int j = 0; j != nlines; ++j) {
1378                 texrow.newline();
1379         }
1380
1381         os << lyxpreamble;
1382         return use_babel;
1383 }
1384
1385
1386 void BufferParams::useClassDefaults()
1387 {
1388         DocumentClass const & tclass = documentClass();
1389
1390         sides = tclass.sides();
1391         columns = tclass.columns();
1392         pagestyle = tclass.pagestyle();
1393         options = tclass.options();
1394         // Only if class has a ToC hierarchy
1395         if (tclass.hasTocLevels()) {
1396                 secnumdepth = tclass.secnumdepth();
1397                 tocdepth = tclass.tocdepth();
1398         }
1399 }
1400
1401
1402 bool BufferParams::hasClassDefaults() const
1403 {
1404         DocumentClass const & tclass = documentClass();
1405
1406         return sides == tclass.sides()
1407                 && columns == tclass.columns()
1408                 && pagestyle == tclass.pagestyle()
1409                 && options == tclass.options()
1410                 && secnumdepth == tclass.secnumdepth()
1411                 && tocdepth == tclass.tocdepth();
1412 }
1413
1414
1415 DocumentClass const & BufferParams::documentClass() const
1416 {
1417         return *doc_class_;
1418 }
1419
1420
1421 DocumentClass * BufferParams::documentClassPtr() const {
1422         return doc_class_;
1423 }
1424
1425
1426 void BufferParams::setDocumentClass(DocumentClass const * const tc) {
1427         // evil, but this function is evil
1428         doc_class_ = const_cast<DocumentClass *>(tc);
1429 }
1430
1431
1432 bool BufferParams::setBaseClass(string const & classname)
1433 {
1434         LYXERR(Debug::TCLASS, "setBaseClass: " << classname);
1435         LayoutFileList const & bcl = LayoutFileList::get();
1436         if (!bcl.haveClass(classname)) {
1437                 docstring s = 
1438                         bformat(_("The document class %1$s could not be found."),
1439                         from_utf8(classname));
1440                 frontend::Alert::error(_("Class not found"), s);
1441                 return false;
1442         }
1443
1444         if (bcl[classname].load()) {
1445                 pimpl_->baseClass_ = classname;
1446                 return true;
1447         }
1448         
1449         docstring s = 
1450                 bformat(_("The document class %1$s could not be loaded."),
1451                 from_utf8(classname));
1452         frontend::Alert::error(_("Could not load class"), s);
1453         return false;
1454 }
1455
1456
1457 LayoutFile const * BufferParams::baseClass() const
1458 {
1459         if (LayoutFileList::get().haveClass(pimpl_->baseClass_))
1460                 return &(LayoutFileList::get()[pimpl_->baseClass_]);
1461         else 
1462                 return 0;
1463 }
1464
1465
1466 LayoutFileIndex const & BufferParams::baseClassID() const
1467 {
1468         return pimpl_->baseClass_;
1469 }
1470
1471
1472 void BufferParams::makeDocumentClass()
1473 {
1474         if (!baseClass())
1475                 return;
1476
1477         doc_class_ = &(DocumentClassBundle::get().newClass(*baseClass()));
1478         
1479         //FIXME It might be worth loading the children's modules here,
1480         //just as we load their bibliographies and such, instead of just 
1481         //doing a check in InsetInclude.
1482         LayoutModuleList::const_iterator it = layoutModules_.begin();
1483         for (; it != layoutModules_.end(); it++) {
1484                 string const modName = *it;
1485                 LyXModule * lm = moduleList[modName];
1486                 if (!lm) {
1487                         docstring const msg =
1488                                 bformat(_("The module %1$s has been requested by\n"
1489                                         "this document but has not been found in the list of\n"
1490                                         "available modules. If you recently installed it, you\n"
1491                                         "probably need to reconfigure LyX.\n"), from_utf8(modName));
1492                         frontend::Alert::warning(_("Module not available"),
1493                                         msg + _("Some layouts may not be available."));
1494                         lyxerr << "BufferParams::makeDocumentClass(): Module " <<
1495                                         modName << " requested but not found in module list." <<
1496                                         endl;
1497                         continue;
1498                 }
1499                 if (!lm->isAvailable()) {
1500                         docstring const msg =
1501                                                 bformat(_("The module %1$s requires a package that is\n"
1502                                                 "not available in your LaTeX installation. LaTeX output\n"
1503                                                 "may not be possible.\n"), from_utf8(modName));
1504                         frontend::Alert::warning(_("Package not available"), msg);
1505                 }
1506                 FileName layout_file = libFileSearch("layouts", lm->getFilename());
1507                 if (!doc_class_->read(layout_file, TextClass::MODULE)) {
1508                         docstring const msg =
1509                                 bformat(_("Error reading module %1$s\n"), from_utf8(modName));
1510                         frontend::Alert::warning(_("Read Error"), msg);
1511                 }
1512         }
1513         if (!local_layout.empty()) {
1514                 if (!doc_class_->read(local_layout, TextClass::MODULE)) {
1515                         docstring const msg = _("Error reading internal layout information");
1516                         frontend::Alert::warning(_("Read Error"), msg);
1517                 }
1518         }
1519 }
1520
1521
1522 vector<string> const & BufferParams::getModules() const 
1523 {
1524         return layoutModules_;
1525 }
1526
1527
1528
1529 bool BufferParams::addLayoutModule(string const & modName) 
1530 {
1531         LayoutModuleList::const_iterator it = layoutModules_.begin();
1532         LayoutModuleList::const_iterator end = layoutModules_.end();
1533         for (; it != end; it++) {
1534                 if (*it == modName) 
1535                         break;
1536         }
1537         if (it != layoutModules_.end())
1538                 return false;
1539         layoutModules_.push_back(modName);
1540         return true;
1541 }
1542
1543
1544 void BufferParams::clearLayoutModules() 
1545 {
1546         layoutModules_.clear();
1547 }
1548
1549
1550 Font const BufferParams::getFont() const
1551 {
1552         FontInfo f = documentClass().defaultfont();
1553         if (fontsDefaultFamily == "rmdefault")
1554                 f.setFamily(ROMAN_FAMILY);
1555         else if (fontsDefaultFamily == "sfdefault")
1556                 f.setFamily(SANS_FAMILY);
1557         else if (fontsDefaultFamily == "ttdefault")
1558                 f.setFamily(TYPEWRITER_FAMILY);
1559         return Font(f, language);
1560 }
1561
1562
1563 void BufferParams::readPreamble(Lexer & lex)
1564 {
1565         if (lex.getString() != "\\begin_preamble")
1566                 lyxerr << "Error (BufferParams::readPreamble):"
1567                         "consistency check failed." << endl;
1568
1569         preamble = lex.getLongString("\\end_preamble");
1570 }
1571
1572
1573 void BufferParams::readLocalLayout(Lexer & lex)
1574 {
1575         if (lex.getString() != "\\begin_local_layout")
1576                 lyxerr << "Error (BufferParams::readLocalLayout):"
1577                         "consistency check failed." << endl;
1578
1579         local_layout = lex.getLongString("\\end_local_layout");
1580 }
1581
1582
1583 void BufferParams::readLanguage(Lexer & lex)
1584 {
1585         if (!lex.next()) return;
1586
1587         string const tmptok = lex.getString();
1588
1589         // check if tmptok is part of tex_babel in tex-defs.h
1590         language = languages.getLanguage(tmptok);
1591         if (!language) {
1592                 // Language tmptok was not found
1593                 language = default_language;
1594                 lyxerr << "Warning: Setting language `"
1595                        << tmptok << "' to `" << language->lang()
1596                        << "'." << endl;
1597         }
1598 }
1599
1600
1601 void BufferParams::readGraphicsDriver(Lexer & lex)
1602 {
1603         if (!lex.next()) 
1604                 return;
1605
1606         string const tmptok = lex.getString();
1607         // check if tmptok is part of tex_graphics in tex_defs.h
1608         int n = 0;
1609         while (true) {
1610                 string const test = tex_graphics[n++];
1611
1612                 if (test == tmptok) {
1613                         graphicsDriver = tmptok;
1614                         break;
1615                 }
1616                 if (test.empty()) {
1617                         lex.printError(
1618                                 "Warning: graphics driver `$$Token' not recognized!\n"
1619                                 "         Setting graphics driver to `default'.\n");
1620                         graphicsDriver = "default";
1621                         break;
1622                 }
1623         }
1624 }
1625
1626
1627 void BufferParams::readBullets(Lexer & lex)
1628 {
1629         if (!lex.next()) 
1630                 return;
1631
1632         int const index = lex.getInteger();
1633         lex.next();
1634         int temp_int = lex.getInteger();
1635         user_defined_bullet(index).setFont(temp_int);
1636         temp_bullet(index).setFont(temp_int);
1637         lex >> temp_int;
1638         user_defined_bullet(index).setCharacter(temp_int);
1639         temp_bullet(index).setCharacter(temp_int);
1640         lex >> temp_int;
1641         user_defined_bullet(index).setSize(temp_int);
1642         temp_bullet(index).setSize(temp_int);
1643 }
1644
1645
1646 void BufferParams::readBulletsLaTeX(Lexer & lex)
1647 {
1648         // The bullet class should be able to read this.
1649         if (!lex.next()) 
1650                 return;
1651         int const index = lex.getInteger();
1652         lex.next(true);
1653         docstring const temp_str = lex.getDocString();
1654
1655         user_defined_bullet(index).setText(temp_str);
1656         temp_bullet(index).setText(temp_str);
1657 }
1658
1659
1660 void BufferParams::readModules(Lexer & lex)
1661 {
1662         if (!lex.eatLine()) {
1663                 lyxerr << "Error (BufferParams::readModules):"
1664                                 "Unexpected end of input." << endl;
1665                 return;
1666         }
1667         while (true) {
1668                 string mod = lex.getString();
1669                 if (mod == "\\end_modules")
1670                         break;
1671                 addLayoutModule(mod);
1672                 lex.eatLine();
1673         }
1674 }
1675
1676
1677 string BufferParams::paperSizeName(PapersizePurpose purpose) const
1678 {
1679         char real_papersize = papersize;
1680         if (real_papersize == PAPER_DEFAULT)
1681                 real_papersize = lyxrc.default_papersize;
1682
1683         switch (real_papersize) {
1684         case PAPER_DEFAULT:
1685                 // could be anything, so don't guess
1686                 return string();
1687         case PAPER_CUSTOM: {
1688                 if (purpose == XDVI && !paperwidth.empty() &&
1689                     !paperheight.empty()) {
1690                         // heightxwidth<unit>
1691                         string first = paperwidth;
1692                         string second = paperheight;
1693                         if (orientation == ORIENTATION_LANDSCAPE)
1694                                 first.swap(second);
1695                         // cut off unit.
1696                         return first.erase(first.length() - 2)
1697                                 + "x" + second;
1698                 }
1699                 return string();
1700         }
1701         case PAPER_A3:
1702                 return "a3";
1703         case PAPER_A4:
1704                 return "a4";
1705         case PAPER_A5:
1706                 return "a5";
1707         case PAPER_B3:
1708                 // dvips and dvipdfm do not know this
1709                 if (purpose == DVIPS || purpose == DVIPDFM)
1710                         return string();
1711                 return "b3";
1712         case PAPER_B4:
1713                 // dvipdfm does not know this
1714                 if (purpose == DVIPDFM)
1715                         return string();
1716                 return "b4";
1717         case PAPER_B5:
1718                 // dvipdfm does not know this
1719                 if (purpose == DVIPDFM)
1720                         return string();
1721                 return "b5";
1722         case PAPER_USEXECUTIVE:
1723                 // dvipdfm does not know this
1724                 if (purpose == DVIPDFM)
1725                         return string();
1726                 return "foolscap";
1727         case PAPER_USLEGAL:
1728                 return "legal";
1729         case PAPER_USLETTER:
1730         default:
1731                 if (purpose == XDVI)
1732                         return "us";
1733                 return "letter";
1734         }
1735 }
1736
1737
1738 string const BufferParams::dvips_options() const
1739 {
1740         string result;
1741
1742         if (use_geometry
1743             && papersize == PAPER_CUSTOM
1744             && !lyxrc.print_paper_dimension_flag.empty()
1745             && !paperwidth.empty()
1746             && !paperheight.empty()) {
1747                 // using a custom papersize
1748                 result = lyxrc.print_paper_dimension_flag;
1749                 result += ' ' + paperwidth;
1750                 result += ',' + paperheight;
1751         } else {
1752                 string const paper_option = paperSizeName(DVIPS);
1753                 if (!paper_option.empty() && (paper_option != "letter" ||
1754                     orientation != ORIENTATION_LANDSCAPE)) {
1755                         // dvips won't accept -t letter -t landscape.
1756                         // In all other cases, include the paper size
1757                         // explicitly.
1758                         result = lyxrc.print_paper_flag;
1759                         result += ' ' + paper_option;
1760                 }
1761         }
1762         if (orientation == ORIENTATION_LANDSCAPE &&
1763             papersize != PAPER_CUSTOM)
1764                 result += ' ' + lyxrc.print_landscape_flag;
1765         return result;
1766 }
1767
1768
1769 string BufferParams::babelCall(string const & lang_opts) const
1770 {
1771         string lang_pack = lyxrc.language_package;
1772         if (lang_pack != "\\usepackage{babel}")
1773                 return lang_pack;
1774         // suppress the babel call when there is no babel language defined
1775         // for the document language in the lib/languages file and if no
1776         // other languages are used (lang_opts is then empty)
1777         if (lang_opts.empty())
1778                 return string();
1779         // when Vietnamese is used, babel must directly be loaded with the
1780         // language options, see
1781         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1782         size_t viet = lang_opts.find("vietnam");
1783         // viet = string::npos when not found
1784         // when Japanese is used, babel must directly be loaded with the
1785         // language options, see
1786         // http://bugzilla.lyx.org/show_bug.cgi?id=4597#c4
1787         size_t japan = lang_opts.find("japanese");
1788         // japan = string::npos when not found
1789         if (!lyxrc.language_global_options || viet != string::npos || japan != string::npos)
1790                 return "\\usepackage[" + lang_opts + "]{babel}";
1791         return lang_pack;
1792 }
1793
1794
1795 void BufferParams::writeEncodingPreamble(odocstream & os,
1796                 LaTeXFeatures & features, TexRow & texrow) const
1797 {
1798         if (inputenc == "auto") {
1799                 string const doc_encoding =
1800                         language->encoding()->latexName();
1801                 Encoding::Package const package =
1802                         language->encoding()->package();
1803
1804                 // Create a list with all the input encodings used
1805                 // in the document
1806                 set<string> encodings =
1807                         features.getEncodingSet(doc_encoding);
1808
1809                 // When the encodings EUC-JP-plain, JIS-plain, or SJIS-plainare used, the
1810                 // package inputenc must be omitted. Therefore set the encoding to empty.
1811                 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1812                 if (doc_encoding == "EUC-JP-plain" || doc_encoding == "JIS-plain" ||
1813                         doc_encoding == "SJIS-plain")
1814                         encodings.clear();
1815
1816                 if (!encodings.empty() || package == Encoding::inputenc) {
1817                         os << "\\usepackage[";
1818                         set<string>::const_iterator it = encodings.begin();
1819                         set<string>::const_iterator const end = encodings.end();
1820                         if (it != end) {
1821                                 os << from_ascii(*it);
1822                                 ++it;
1823                         }
1824                         for (; it != end; ++it)
1825                                 os << ',' << from_ascii(*it);
1826                         if (package == Encoding::inputenc) {
1827                                 if (!encodings.empty())
1828                                         os << ',';
1829                                 os << from_ascii(doc_encoding);
1830                         }
1831                         os << "]{inputenc}\n";
1832                         texrow.newline();
1833                 }
1834                 if (package == Encoding::CJK || features.mustProvide("CJK")) {
1835                         os << "\\usepackage{CJK}\n";
1836                         texrow.newline();
1837                 }
1838         } else if (inputenc != "default") {
1839                 switch (encoding().package()) {
1840                 case Encoding::none:
1841                         break;
1842                 case Encoding::inputenc:
1843                         os << "\\usepackage[" << from_ascii(inputenc)
1844                            << "]{inputenc}\n";
1845                         texrow.newline();
1846                         break;
1847                 case Encoding::CJK:
1848                         os << "\\usepackage{CJK}\n";
1849                         texrow.newline();
1850                         break;
1851                 }
1852         }
1853
1854         // The encoding "armscii8" is only available when the package "armtex" is loaded.
1855         // armscii8 is used for Armenian.
1856         if (language->encoding()->latexName() == "armscii8" || inputenc == "armscii8") {
1857                 os << "\\usepackage{armtex}\n";
1858                 texrow.newline();
1859         }
1860 }
1861
1862
1863 string const BufferParams::loadFonts(string const & rm,
1864                                      string const & sf, string const & tt,
1865                                      bool const & sc, bool const & osf,
1866                                      int const & sfscale, int const & ttscale) const
1867 {
1868         /* The LaTeX font world is in a flux. In the PSNFSS font interface,
1869            several packages have been replaced by others, that might not
1870            be installed on every system. We have to take care for that
1871            (see psnfss.pdf). We try to support all psnfss fonts as well
1872            as the fonts that have become de facto standard in the LaTeX
1873            world (e.g. Latin Modern). We do not support obsolete fonts
1874            (like PSLatex). In general, it should be possible to mix any
1875            rm font with any sf or tt font, respectively. (JSpitzm)
1876            TODO:
1877                 -- separate math fonts.
1878         */
1879
1880         if (rm == "default" && sf == "default" && tt == "default")
1881                 //nothing to do
1882                 return string();
1883
1884         ostringstream os;
1885
1886         // ROMAN FONTS
1887         // Computer Modern (must be explicitely selectable -- there might be classes
1888         // that define a different default font!
1889         if (rm == "cmr") {
1890                 os << "\\renewcommand{\\rmdefault}{cmr}\n";
1891                 // osf for Computer Modern needs eco.sty
1892                 if (osf)
1893                         os << "\\usepackage{eco}\n";
1894         }
1895         // Latin Modern Roman
1896         else if (rm == "lmodern")
1897                 os << "\\usepackage{lmodern}\n";
1898         // AE
1899         else if (rm == "ae") {
1900                 // not needed when using OT1 font encoding.
1901                 if (lyxrc.fontenc != "default")
1902                         os << "\\usepackage{ae,aecompl}\n";
1903         }
1904         // Times
1905         else if (rm == "times") {
1906                 // try to load the best available package
1907                 if (LaTeXFeatures::isAvailable("mathptmx"))
1908                         os << "\\usepackage{mathptmx}\n";
1909                 else if (LaTeXFeatures::isAvailable("mathptm"))
1910                         os << "\\usepackage{mathptm}\n";
1911                 else
1912                         os << "\\usepackage{times}\n";
1913         }
1914         // Palatino
1915         else if (rm == "palatino") {
1916                 // try to load the best available package
1917                 if (LaTeXFeatures::isAvailable("mathpazo")) {
1918                         os << "\\usepackage";
1919                         if (osf || sc) {
1920                                 os << '[';
1921                                 if (!osf)
1922                                         os << "sc";
1923                                 else
1924                                         // "osf" includes "sc"!
1925                                         os << "osf";
1926                                 os << ']';
1927                         }
1928                         os << "{mathpazo}\n";
1929                 }
1930                 else if (LaTeXFeatures::isAvailable("mathpple"))
1931                         os << "\\usepackage{mathpple}\n";
1932                 else
1933                         os << "\\usepackage{palatino}\n";
1934         }
1935         // Utopia
1936         else if (rm == "utopia") {
1937                 // fourier supersedes utopia.sty, but does
1938                 // not work with OT1 encoding.
1939                 if (LaTeXFeatures::isAvailable("fourier")
1940                     && lyxrc.fontenc != "default") {
1941                         os << "\\usepackage";
1942                         if (osf || sc) {
1943                                 os << '[';
1944                                 if (sc)
1945                                         os << "expert";
1946                                 if (osf && sc)
1947                                         os << ',';
1948                                 if (osf)
1949                                         os << "oldstyle";
1950                                 os << ']';
1951                         }
1952                         os << "{fourier}\n";
1953                 }
1954                 else
1955                         os << "\\usepackage{utopia}\n";
1956         }
1957         // Bera (complete fontset)
1958         else if (rm == "bera" && sf == "default" && tt == "default")
1959                 os << "\\usepackage{bera}\n";
1960         // everything else
1961         else if (rm != "default")
1962                 os << "\\usepackage" << "{" << rm << "}\n";
1963
1964         // SANS SERIF
1965         // Helvetica, Bera Sans
1966         if (sf == "helvet" || sf == "berasans") {
1967                 if (sfscale != 100)
1968                         os << "\\usepackage[scaled=" << float(sfscale) / 100
1969                            << "]{" << sf << "}\n";
1970                 else
1971                         os << "\\usepackage{" << sf << "}\n";
1972         }
1973         // Avant Garde
1974         else if (sf == "avant")
1975                 os << "\\usepackage{" << sf << "}\n";
1976         // Computer Modern, Latin Modern, CM Bright
1977         else if (sf != "default")
1978                 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
1979
1980         // monospaced/typewriter
1981         // Courier, LuxiMono
1982         if (tt == "luximono" || tt == "beramono") {
1983                 if (ttscale != 100)
1984                         os << "\\usepackage[scaled=" << float(ttscale) / 100
1985                            << "]{" << tt << "}\n";
1986                 else
1987                         os << "\\usepackage{" << tt << "}\n";
1988         }
1989         // Courier
1990         else if (tt == "courier" )
1991                 os << "\\usepackage{" << tt << "}\n";
1992         // Computer Modern, Latin Modern, CM Bright
1993         else if (tt != "default")
1994                 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
1995
1996         return os.str();
1997 }
1998
1999
2000 Encoding const & BufferParams::encoding() const
2001 {
2002         if (inputenc == "auto" || inputenc == "default")
2003                 return *language->encoding();
2004         Encoding const * const enc = encodings.fromLaTeXName(inputenc);
2005         if (enc)
2006                 return *enc;
2007         LYXERR0("Unknown inputenc value `" << inputenc
2008                << "'. Using `auto' instead.");
2009         return *language->encoding();
2010 }
2011
2012
2013 biblio::CiteEngine BufferParams::citeEngine() const
2014 {
2015         // FIXME the class should provide the numerical/
2016         // authoryear choice
2017         if (documentClass().provides("natbib")
2018             && cite_engine_ != biblio::ENGINE_NATBIB_NUMERICAL)
2019                 return biblio::ENGINE_NATBIB_AUTHORYEAR;
2020         return cite_engine_;
2021 }
2022
2023
2024 void BufferParams::setCiteEngine(biblio::CiteEngine cite_engine)
2025 {
2026         cite_engine_ = cite_engine;
2027 }
2028
2029 } // namespace lyx