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