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