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