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