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