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