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