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