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