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