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