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