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