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