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