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