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