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