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