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