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