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