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