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