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