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