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