]> git.lyx.org Git - lyx.git/blob - src/BufferParams.cpp
Simplify scrolling code. Instead of using the actionTriggered() signal we now use...
[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         makeTextClass();
318         paragraph_separation = PARSEP_INDENT;
319         quotes_language = InsetQuotes::EnglishQ;
320         fontsize = "default";
321
322         /*  PaperLayout */
323         papersize = PAPER_DEFAULT;
324         orientation = ORIENTATION_PORTRAIT;
325         use_geometry = false;
326         use_amsmath = package_auto;
327         use_esint = package_auto;
328         cite_engine_ = biblio::ENGINE_BASIC;
329         use_bibtopic = false;
330         trackChanges = false;
331         outputChanges = false;
332         secnumdepth = 3;
333         tocdepth = 3;
334         language = default_language;
335         fontsRoman = "default";
336         fontsSans = "default";
337         fontsTypewriter = "default";
338         fontsDefaultFamily = "default";
339         fontsSC = false;
340         fontsOSF = false;
341         fontsSansScale = 100;
342         fontsTypewriterScale = 100;
343         inputenc = "auto";
344         graphicsDriver = "default";
345         sides = OneSide;
346         columns = 1;
347         listings_params = string();
348         pagestyle = "default";
349         compressed = false;
350         embedded = false;
351         for (int iter = 0; iter < 4; ++iter) {
352                 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
353                 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
354         }
355 }
356
357
358 BufferParams::~BufferParams()
359 {}
360
361
362 docstring const BufferParams::B_(string const & l10n) const
363 {
364         BOOST_ASSERT(language);
365         return getMessages(language->code()).get(l10n);
366 }
367
368
369 AuthorList & BufferParams::authors()
370 {
371         return pimpl_->authorlist;
372 }
373
374
375 AuthorList const & BufferParams::authors() const
376 {
377         return pimpl_->authorlist;
378 }
379
380
381 BranchList & BufferParams::branchlist()
382 {
383         return pimpl_->branchlist;
384 }
385
386
387 BranchList const & BufferParams::branchlist() const
388 {
389         return pimpl_->branchlist;
390 }
391
392
393 Bullet & BufferParams::temp_bullet(lyx::size_type const index)
394 {
395         BOOST_ASSERT(index < 4);
396         return pimpl_->temp_bullets[index];
397 }
398
399
400 Bullet const & BufferParams::temp_bullet(lyx::size_type const index) const
401 {
402         BOOST_ASSERT(index < 4);
403         return pimpl_->temp_bullets[index];
404 }
405
406
407 Bullet & BufferParams::user_defined_bullet(lyx::size_type const index)
408 {
409         BOOST_ASSERT(index < 4);
410         return pimpl_->user_defined_bullets[index];
411 }
412
413
414 Bullet const & BufferParams::user_defined_bullet(lyx::size_type const index) const
415 {
416         BOOST_ASSERT(index < 4);
417         return pimpl_->user_defined_bullets[index];
418 }
419
420
421 Spacing & BufferParams::spacing()
422 {
423         return pimpl_->spacing;
424 }
425
426
427 Spacing const & BufferParams::spacing() const
428 {
429         return pimpl_->spacing;
430 }
431
432
433 PDFOptions & BufferParams::pdfoptions()
434 {
435         return pimpl_->pdfoptions;
436 }
437
438
439 PDFOptions const & BufferParams::pdfoptions() const
440 {
441         return pimpl_->pdfoptions;
442 }
443
444
445 VSpace const & BufferParams::getDefSkip() const
446 {
447         return pimpl_->defskip;
448 }
449
450
451 void BufferParams::setDefSkip(VSpace const & vs)
452 {
453         pimpl_->defskip = vs;
454 }
455
456
457 string const BufferParams::readToken(Lexer & lex, string const & token,
458         FileName const & filepath)
459 {
460         if (token == "\\textclass") {
461                 lex.next();
462                 string const classname = lex.getString();
463                 // if there exists a local layout file, ignore the system one
464                 // NOTE: in this case, the textclass (.cls file) is assumed to be available.
465                 pair<bool, lyx::textclass_type> pp =
466                         make_pair(false, textclass_type(0));
467                 if (!filepath.empty())
468                         pp = textclasslist.addTextClass(
469                                 classname, filepath.absFilename());
470                 if (pp.first)
471                         setBaseClass(pp.second);
472                 else {
473                         pp = textclasslist.numberOfClass(classname);
474                         if (pp.first)
475                                 setBaseClass(pp.second);
476                         else {
477                                 // a warning will be given for unknown class
478                                 setBaseClass(defaultTextclass());
479                                 return classname;
480                         }
481                 }
482                 // FIXME: this warning will be given even if there exists a local .cls
483                 // file. Even worse, the .lyx file can not be compiled or exported
484                 // because the textclass is marked as unavilable.
485                 if (!getTextClass().isTeXClassAvailable()) {
486                         docstring const msg =
487                                 bformat(_("The layout file requested by this document,\n"
488                                                  "%1$s.layout,\n"
489                                                  "is not usable. This is probably because a LaTeX\n"
490                                                  "class or style file required by it is not\n"
491                                                  "available. See the Customization documentation\n"
492                                                  "for more information.\n"), from_utf8(classname));
493                         frontend::Alert::warning(_("Document class not available"),
494                                        msg + _("LyX will not be able to produce output."));
495                 } 
496                 
497         } else if (token == "\\begin_preamble") {
498                 readPreamble(lex);
499         } else if (token == "\\begin_modules") {
500                 readModules(lex);
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 (!getTextClass().requires().empty()) {
814                 vector<string> req = getTextClass().requires();
815                 for (vector<string>::const_iterator it = req.begin();
816                      it != req.end(); ++it) {
817                         features.require(*it);
818                 }
819         }
820
821         if (outputChanges) {
822                 bool dvipost    = LaTeXFeatures::isAvailable("dvipost");
823                 bool xcolorsoul = LaTeXFeatures::isAvailable("soul") &&
824                                   LaTeXFeatures::isAvailable("xcolor");
825
826                 switch (features.runparams().flavor) {
827                 case OutputParams::LATEX:
828                         if (dvipost) {
829                                 features.require("ct-dvipost");
830                                 features.require("dvipost");
831                         } else if (xcolorsoul) {
832                                 features.require("ct-xcolor-soul");
833                                 features.require("soul");
834                                 features.require("xcolor");
835                         } else {
836                                 features.require("ct-none");
837                         }
838                         break;
839                 case OutputParams::PDFLATEX:
840                         if (xcolorsoul) {
841                                 features.require("ct-xcolor-soul");
842                                 features.require("soul");
843                                 features.require("xcolor");
844                                 // improves color handling in PDF output
845                                 features.require("pdfcolmk"); 
846                         } else {
847                                 features.require("ct-none");
848                         }
849                         break;
850                 default:
851                         break;
852                 }
853         }
854
855         // Floats with 'Here definitely' as default setting.
856         if (float_placement.find('H') != string::npos)
857                 features.require("float");
858
859         // AMS Style is at document level
860         if (use_amsmath == package_on
861             || getTextClass().provides("amsmath"))
862                 features.require("amsmath");
863         if (use_esint == package_on)
864                 features.require("esint");
865
866         // Document-level line spacing
867         if (spacing().getSpace() != Spacing::Single && !spacing().isDefault())
868                 features.require("setspace");
869
870         // the bullet shapes are buffer level not paragraph level
871         // so they are tested here
872         for (int i = 0; i < 4; ++i) {
873                 if (user_defined_bullet(i) == ITEMIZE_DEFAULTS[i]) 
874                         continue;
875                 int const font = user_defined_bullet(i).getFont();
876                 if (font == 0) {
877                         int const c = user_defined_bullet(i).getCharacter();
878                         if (c == 16
879                             || c == 17
880                             || c == 25
881                             || c == 26
882                             || c == 31) {
883                                 features.require("latexsym");
884                         }
885                 } else if (font == 1) {
886                         features.require("amssymb");
887                 } else if (font >= 2 && font <= 5) {
888                         features.require("pifont");
889                 }
890         }
891
892         if (pdfoptions().use_hyperref)
893                 features.require("hyperref");
894 }
895
896
897 bool BufferParams::writeLaTeX(odocstream & os, LaTeXFeatures & features,
898                               TexRow & texrow) const
899 {
900         os << "\\documentclass";
901
902         TextClass const & tclass = getTextClass();
903
904         ostringstream clsoptions; // the document class options.
905
906         if (tokenPos(tclass.opt_fontsize(),
907                      '|', fontsize) >= 0) {
908                 // only write if existing in list (and not default)
909                 clsoptions << fontsize << "pt,";
910         }
911
912         // custom, A3, B3 and B4 paper sizes need geometry
913         bool nonstandard_papersize = papersize == PAPER_B3
914                 || papersize == PAPER_B4
915                 || papersize == PAPER_A3
916                 || papersize == PAPER_CUSTOM;
917
918         if (!use_geometry) {
919                 switch (papersize) {
920                 case PAPER_A4:
921                         clsoptions << "a4paper,";
922                         break;
923                 case PAPER_USLETTER:
924                         clsoptions << "letterpaper,";
925                         break;
926                 case PAPER_A5:
927                         clsoptions << "a5paper,";
928                         break;
929                 case PAPER_B5:
930                         clsoptions << "b5paper,";
931                         break;
932                 case PAPER_USEXECUTIVE:
933                         clsoptions << "executivepaper,";
934                         break;
935                 case PAPER_USLEGAL:
936                         clsoptions << "legalpaper,";
937                         break;
938                 case PAPER_DEFAULT:
939                 case PAPER_A3:
940                 case PAPER_B3:
941                 case PAPER_B4:
942                 case PAPER_CUSTOM:
943                         break;
944                 }
945         }
946
947         // if needed
948         if (sides != tclass.sides()) {
949                 switch (sides) {
950                 case OneSide:
951                         clsoptions << "oneside,";
952                         break;
953                 case TwoSides:
954                         clsoptions << "twoside,";
955                         break;
956                 }
957         }
958
959         // if needed
960         if (columns != tclass.columns()) {
961                 if (columns == 2)
962                         clsoptions << "twocolumn,";
963                 else
964                         clsoptions << "onecolumn,";
965         }
966
967         if (!use_geometry
968             && orientation == ORIENTATION_LANDSCAPE)
969                 clsoptions << "landscape,";
970
971         // language should be a parameter to \documentclass
972         if (language->babel() == "hebrew"
973             && default_language->babel() != "hebrew")
974                 // This seems necessary
975                 features.useLanguage(default_language);
976
977         ostringstream language_options;
978         bool const use_babel = features.useBabel();
979         if (use_babel) {
980                 language_options << features.getLanguages();
981                 if (!language->babel().empty()) {
982                         if (!language_options.str().empty())
983                                 language_options << ',';
984                         language_options << language->babel();
985                 }
986                 // when Vietnamese is used, babel must directly be loaded with the
987                 // language options, not in the class options, see
988                 // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
989                 size_t viet = language_options.str().find("vietnam");
990                 // viet = string::npos when not found
991                 if (lyxrc.language_global_options && !language_options.str().empty()
992                         && viet == string::npos)
993                         clsoptions << language_options.str() << ',';
994         }
995
996         // the user-defined options
997         if (!options.empty()) {
998                 clsoptions << options << ',';
999         }
1000
1001         string strOptions(clsoptions.str());
1002         if (!strOptions.empty()) {
1003                 strOptions = rtrim(strOptions, ",");
1004                 // FIXME UNICODE
1005                 os << '[' << from_utf8(strOptions) << ']';
1006         }
1007
1008         os << '{' << from_ascii(tclass.latexname()) << "}\n";
1009         texrow.newline();
1010         // end of \documentclass defs
1011
1012         // font selection must be done before loading fontenc.sty
1013         string const fonts =
1014                 loadFonts(fontsRoman, fontsSans,
1015                           fontsTypewriter, fontsSC, fontsOSF,
1016                           fontsSansScale, fontsTypewriterScale);
1017         if (!fonts.empty()) {
1018                 os << from_ascii(fonts);
1019                 texrow.newline();
1020         }
1021         if (fontsDefaultFamily != "default")
1022                 os << "\\renewcommand{\\familydefault}{\\"
1023                    << from_ascii(fontsDefaultFamily) << "}\n";
1024
1025         // set font encoding
1026         // this one is not per buffer
1027         // for arabic_arabi and farsi we also need to load the LAE and LFE encoding
1028         if (lyxrc.fontenc != "default") {
1029                 if (language->lang() == "arabic_arabi" || language->lang() == "farsi") {
1030                         os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
1031                            << ",LFE,LAE]{fontenc}\n";
1032                         texrow.newline();
1033                 } else {
1034                         os << "\\usepackage[" << from_ascii(lyxrc.fontenc)
1035                            << "]{fontenc}\n";
1036                         texrow.newline();
1037                 }
1038         }
1039
1040         // handle inputenc etc.
1041         writeEncodingPreamble(os, features, texrow);
1042
1043         if (!listings_params.empty()) {
1044                 os << "\\usepackage{listings}\n";
1045                 texrow.newline();
1046                 os << "\\lstset{";
1047                 // do not test validity because listings_params is supposed to be valid
1048                 string par = InsetListingsParams(listings_params).separatedParams(true);
1049                 os << from_ascii(par);
1050                 // count the number of newlines
1051                 for (size_t i = 0; i < par.size(); ++i)
1052                         if (par[i] == '\n')
1053                                 texrow.newline();
1054                 os << "}\n";
1055                 texrow.newline();
1056         }
1057         if (use_geometry || nonstandard_papersize) {
1058                 os << "\\usepackage{geometry}\n";
1059                 texrow.newline();
1060                 os << "\\geometry{verbose";
1061                 if (orientation == ORIENTATION_LANDSCAPE)
1062                         os << ",landscape";
1063                 switch (papersize) {
1064                 case PAPER_CUSTOM:
1065                         if (!paperwidth.empty())
1066                                 os << ",paperwidth="
1067                                    << from_ascii(paperwidth);
1068                         if (!paperheight.empty())
1069                                 os << ",paperheight="
1070                                    << from_ascii(paperheight);
1071                         break;
1072                 case PAPER_USLETTER:
1073                         os << ",letterpaper";
1074                         break;
1075                 case PAPER_USLEGAL:
1076                         os << ",legalpaper";
1077                         break;
1078                 case PAPER_USEXECUTIVE:
1079                         os << ",executivepaper";
1080                         break;
1081                 case PAPER_A3:
1082                         os << ",a3paper";
1083                         break;
1084                 case PAPER_A4:
1085                         os << ",a4paper";
1086                         break;
1087                 case PAPER_A5:
1088                         os << ",a5paper";
1089                         break;
1090                 case PAPER_B3:
1091                         os << ",b3paper";
1092                         break;
1093                 case PAPER_B4:
1094                         os << ",b4paper";
1095                         break;
1096                 case PAPER_B5:
1097                         os << ",b5paper";
1098                         break;
1099                 default:
1100                         // default papersize ie PAPER_DEFAULT
1101                         switch (lyxrc.default_papersize) {
1102                         case PAPER_DEFAULT: // keep compiler happy
1103                         case PAPER_USLETTER:
1104                                 os << ",letterpaper";
1105                                 break;
1106                         case PAPER_USLEGAL:
1107                                 os << ",legalpaper";
1108                                 break;
1109                         case PAPER_USEXECUTIVE:
1110                                 os << ",executivepaper";
1111                                 break;
1112                         case PAPER_A3:
1113                                 os << ",a3paper";
1114                                 break;
1115                         case PAPER_A4:
1116                                 os << ",a4paper";
1117                                 break;
1118                         case PAPER_A5:
1119                                 os << ",a5paper";
1120                                 break;
1121                         case PAPER_B5:
1122                                 os << ",b5paper";
1123                                 break;
1124                         case PAPER_B3:
1125                         case PAPER_B4:
1126                         case PAPER_CUSTOM:
1127                                 break;
1128                         }
1129                 }
1130                 if (!topmargin.empty())
1131                         os << ",tmargin=" << from_ascii(Length(topmargin).asLatexString());
1132                 if (!bottommargin.empty())
1133                         os << ",bmargin=" << from_ascii(Length(bottommargin).asLatexString());
1134                 if (!leftmargin.empty())
1135                         os << ",lmargin=" << from_ascii(Length(leftmargin).asLatexString());
1136                 if (!rightmargin.empty())
1137                         os << ",rmargin=" << from_ascii(Length(rightmargin).asLatexString());
1138                 if (!headheight.empty())
1139                         os << ",headheight=" << from_ascii(Length(headheight).asLatexString());
1140                 if (!headsep.empty())
1141                         os << ",headsep=" << from_ascii(Length(headsep).asLatexString());
1142                 if (!footskip.empty())
1143                         os << ",footskip=" << from_ascii(Length(footskip).asLatexString());
1144                 os << "}\n";
1145                 texrow.newline();
1146         }
1147
1148         if (tokenPos(tclass.opt_pagestyle(),
1149                      '|', pagestyle) >= 0) {
1150                 if (pagestyle == "fancy") {
1151                         os << "\\usepackage{fancyhdr}\n";
1152                         texrow.newline();
1153                 }
1154                 os << "\\pagestyle{" << from_ascii(pagestyle) << "}\n";
1155                 texrow.newline();
1156         }
1157
1158         // Only if class has a ToC hierarchy
1159         if (tclass.hasTocLevels()) {
1160                 if (secnumdepth != tclass.secnumdepth()) {
1161                         os << "\\setcounter{secnumdepth}{"
1162                            << secnumdepth
1163                            << "}\n";
1164                         texrow.newline();
1165                 }
1166                 if (tocdepth != tclass.tocdepth()) {
1167                         os << "\\setcounter{tocdepth}{"
1168                            << tocdepth
1169                            << "}\n";
1170                         texrow.newline();
1171                 }
1172         }
1173
1174         if (paragraph_separation) {
1175                 switch (getDefSkip().kind()) {
1176                 case VSpace::SMALLSKIP:
1177                         os << "\\setlength{\\parskip}{\\smallskipamount}\n";
1178                         break;
1179                 case VSpace::MEDSKIP:
1180                         os << "\\setlength{\\parskip}{\\medskipamount}\n";
1181                         break;
1182                 case VSpace::BIGSKIP:
1183                         os << "\\setlength{\\parskip}{\\bigskipamount}\n";
1184                         break;
1185                 case VSpace::LENGTH:
1186                         os << "\\setlength{\\parskip}{"
1187                            << from_utf8(getDefSkip().length().asLatexString())
1188                            << "}\n";
1189                         break;
1190                 default: // should never happen // Then delete it.
1191                         os << "\\setlength{\\parskip}{\\medskipamount}\n";
1192                         break;
1193                 }
1194                 texrow.newline();
1195
1196                 os << "\\setlength{\\parindent}{0pt}\n";
1197                 texrow.newline();
1198         }
1199
1200         // If we use jurabib, we have to call babel here.
1201         if (use_babel && features.isRequired("jurabib")) {
1202                 os << from_ascii(babelCall(language_options.str()))
1203                    << '\n'
1204                    << from_ascii(features.getBabelOptions());
1205                 texrow.newline();
1206         }
1207
1208         // Now insert the LyX specific LaTeX commands...
1209
1210         // The optional packages;
1211         docstring lyxpreamble(from_ascii(features.getPackages()));
1212
1213         // Line spacing
1214         lyxpreamble += from_utf8(spacing().writePreamble(tclass.provides("SetSpace")));
1215
1216         // We try to load babel late, in case it interferes
1217         // with other packages. But some packages also need babel to be loaded
1218         // before, e.g. jurabib has to be called after babel.
1219         // So load babel after the optional packages but before the user-defined
1220         // preamble. This allows the users to redefine babel commands, e.g. to
1221         // translate the word "Index" to the German "Stichwortverzeichnis".
1222         // For more infos why this place was chosen, see
1223         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg128425.html
1224         // If you encounter problems, you can shift babel to its old place behind
1225         // the user-defined preamble. But in this case you must change the Vietnamese
1226         // support from currently "\usepackage[vietnamese]{babel}" to:
1227         // \usepackage{vietnamese}
1228         // \usepackage{babel}
1229         // because vietnamese must be loaded before hyperref
1230         if (use_babel && !features.isRequired("jurabib")) {
1231                 // FIXME UNICODE
1232                 lyxpreamble += from_utf8(babelCall(language_options.str())) + '\n';
1233                 lyxpreamble += from_utf8(features.getBabelOptions());
1234         }
1235
1236         // When the language "japanese-plain" is used, the package "japanese" must
1237         // be loaded behind babel (it provides babel support for Japanese) but before
1238         // hyperref, see
1239         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1240         if (language->lang() == "japanese-plain" &&
1241                 !getTextClass().provides("japanese")) {
1242                 //load babel in case it was not loaded due to an empty language list
1243                 if (language_options.str().empty())
1244                         lyxpreamble += "\\usepackage{babel}\n";
1245                 lyxpreamble += "\\usepackage{japanese}\n";
1246         }
1247
1248         // PDF support.
1249         // * Hyperref manual: "Make sure it comes last of your loaded
1250         //   packages, to give it a fighting chance of not being over-written,
1251         //   since its job is to redefine many LATEX commands."
1252         // * Email from Heiko Oberdiek: "It is usually better to load babel
1253         //   before hyperref. Then hyperref has a chance to detect babel.
1254         // * Has to be loaded before the "LyX specific LaTeX commands" to
1255         //   avoid errors with algorithm floats.
1256         // use hyperref explicitely when it is required
1257         if (features.isRequired("hyperref")) {
1258                 odocstringstream oss;
1259                 pdfoptions().writeLaTeX(oss, getTextClass().provides("hyperref"));
1260                 lyxpreamble += oss.str();
1261         }
1262
1263         // this might be useful...
1264         lyxpreamble += "\n\\makeatletter\n";
1265
1266         // Some macros LyX will need
1267         docstring tmppreamble(from_ascii(features.getMacros()));
1268
1269         if (!tmppreamble.empty()) {
1270                 lyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1271                         "LyX specific LaTeX commands.\n"
1272                         + tmppreamble + '\n';
1273         }
1274
1275         // the text class specific preamble
1276         tmppreamble = features.getTClassPreamble();
1277         if (!tmppreamble.empty()) {
1278                 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1279                         "Textclass specific LaTeX commands.\n"
1280                         + tmppreamble + '\n';
1281         }
1282
1283         /* the user-defined preamble */
1284         if (!preamble.empty()) {
1285                 // FIXME UNICODE
1286                 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1287                         "User specified LaTeX commands.\n"
1288                         + from_utf8(preamble) + '\n';
1289         }
1290
1291         // Itemize bullet settings need to be last in case the user
1292         // defines their own bullets that use a package included
1293         // in the user-defined preamble -- ARRae
1294         // Actually it has to be done much later than that
1295         // since some packages like frenchb make modifications
1296         // at \begin{document} time -- JMarc
1297         docstring bullets_def;
1298         for (int i = 0; i < 4; ++i) {
1299                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1300                         if (bullets_def.empty())
1301                                 bullets_def += "\\AtBeginDocument{\n";
1302                         bullets_def += "  \\def\\labelitemi";
1303                         switch (i) {
1304                                 // `i' is one less than the item to modify
1305                         case 0:
1306                                 break;
1307                         case 1:
1308                                 bullets_def += 'i';
1309                                 break;
1310                         case 2:
1311                                 bullets_def += "ii";
1312                                 break;
1313                         case 3:
1314                                 bullets_def += 'v';
1315                                 break;
1316                         }
1317                         bullets_def += '{' +
1318                                 user_defined_bullet(i).getText()
1319                                 + "}\n";
1320                 }
1321         }
1322
1323         if (!bullets_def.empty())
1324                 lyxpreamble += bullets_def + "}\n\n";
1325
1326         lyxpreamble += "\\makeatother\n\n";
1327
1328         int const nlines =
1329                 int(count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1330         for (int j = 0; j != nlines; ++j) {
1331                 texrow.newline();
1332         }
1333
1334         os << lyxpreamble;
1335         return use_babel;
1336 }
1337
1338
1339 void BufferParams::useClassDefaults()
1340 {
1341         TextClass const & tclass = textclasslist[baseClass_];
1342
1343         sides = tclass.sides();
1344         columns = tclass.columns();
1345         pagestyle = tclass.pagestyle();
1346         options = tclass.options();
1347         // Only if class has a ToC hierarchy
1348         if (tclass.hasTocLevels()) {
1349                 secnumdepth = tclass.secnumdepth();
1350                 tocdepth = tclass.tocdepth();
1351         }
1352 }
1353
1354
1355 bool BufferParams::hasClassDefaults() const
1356 {
1357         TextClass const & tclass = textclasslist[baseClass_];
1358
1359         return (sides == tclass.sides()
1360                 && columns == tclass.columns()
1361                 && pagestyle == tclass.pagestyle()
1362                 && options == tclass.options()
1363                 && secnumdepth == tclass.secnumdepth()
1364                 && tocdepth == tclass.tocdepth());
1365 }
1366
1367
1368 TextClass const & BufferParams::getTextClass() const
1369 {
1370         return *textClass_;
1371 }
1372
1373
1374 TextClassPtr BufferParams::getTextClassPtr() const {
1375         return textClass_;
1376 }
1377
1378
1379 void BufferParams::setTextClass(TextClassPtr tc) {
1380         textClass_ = tc;
1381 }
1382
1383
1384 bool BufferParams::setBaseClass(textclass_type tc)
1385 {
1386         if (textclasslist[tc].load()) {
1387                 baseClass_ = tc;
1388                 return true;
1389         }
1390         
1391         docstring s = 
1392                 bformat(_("The document class %1$s could not be loaded."),
1393                 from_utf8(textclasslist[tc].name()));
1394         frontend::Alert::error(_("Could not load class"), s);
1395         return false;
1396 }
1397
1398
1399 textclass_type BufferParams::getBaseClass() const
1400 {
1401         return baseClass_;
1402 }
1403
1404
1405 void BufferParams::makeTextClass()
1406 {
1407         textClass_.reset(new TextClass(textclasslist[getBaseClass()]));
1408         
1409         //FIXME It might be worth loading the children's modules here,
1410         //just as we load their bibliographies and such, instead of just 
1411         //doing a check in InsetInclude.
1412         LayoutModuleList::const_iterator it = layoutModules_.begin();
1413         for (; it != layoutModules_.end(); it++) {
1414                 string const modName = *it;
1415                 LyXModule * lm = moduleList[modName];
1416                 if (!lm) {
1417                         docstring const msg =
1418                                 bformat(_("The module %1$s has been requested by\n"
1419                                         "this document but has not been found in the list of\n"
1420                                         "available modules. If you recently installed it, you\n"
1421                                         "probably need to reconfigure LyX.\n"), from_utf8(modName));
1422                         frontend::Alert::warning(_("Module not available"),
1423                                         msg + _("Some layouts may not be available."));
1424                         lyxerr << "BufferParams::makeTextClass(): Module " <<
1425                                         modName << " requested but not found in module list." <<
1426                                         endl;
1427                         continue;
1428                 }
1429                 if (!lm->isAvailable()) {
1430                         docstring const msg =
1431                                                 bformat(_("The module %1$s requires a package that is\n"
1432                                                 "not available in your LaTeX installation. LaTeX output\n"
1433                                                 "may not be possible.\n"), from_utf8(modName));
1434                         frontend::Alert::warning(_("Package not available"), msg);
1435                 }
1436                 FileName layout_file = libFileSearch("layouts", lm->getFilename());
1437                 textClass_->read(layout_file, TextClass::MODULE);
1438         }
1439 }
1440
1441
1442 vector<string> const & BufferParams::getModules() const {
1443         return layoutModules_;
1444 }
1445
1446
1447
1448 bool BufferParams::addLayoutModule(string const & modName) {
1449         LayoutModuleList::const_iterator it = layoutModules_.begin();
1450         LayoutModuleList::const_iterator end = layoutModules_.end();
1451         for (; it != end; it++) {
1452                 if (*it == modName) 
1453                         break;
1454         }
1455         if (it != layoutModules_.end())
1456                 return false;
1457         layoutModules_.push_back(modName);
1458         return true;
1459 }
1460
1461
1462 void BufferParams::clearLayoutModules() {
1463         layoutModules_.clear();
1464 }
1465
1466
1467 Font const BufferParams::getFont() const
1468 {
1469         FontInfo f = getTextClass().defaultfont();
1470         if (fontsDefaultFamily == "rmdefault")
1471                 f.setFamily(ROMAN_FAMILY);
1472         else if (fontsDefaultFamily == "sfdefault")
1473                 f.setFamily(SANS_FAMILY);
1474         else if (fontsDefaultFamily == "ttdefault")
1475                 f.setFamily(TYPEWRITER_FAMILY);
1476         return Font(f, language);
1477 }
1478
1479
1480 void BufferParams::readPreamble(Lexer & lex)
1481 {
1482         if (lex.getString() != "\\begin_preamble")
1483                 lyxerr << "Error (BufferParams::readPreamble):"
1484                         "consistency check failed." << endl;
1485
1486         preamble = lex.getLongString("\\end_preamble");
1487 }
1488
1489
1490 void BufferParams::readLanguage(Lexer & lex)
1491 {
1492         if (!lex.next()) return;
1493
1494         string const tmptok = lex.getString();
1495
1496         // check if tmptok is part of tex_babel in tex-defs.h
1497         language = languages.getLanguage(tmptok);
1498         if (!language) {
1499                 // Language tmptok was not found
1500                 language = default_language;
1501                 lyxerr << "Warning: Setting language `"
1502                        << tmptok << "' to `" << language->lang()
1503                        << "'." << endl;
1504         }
1505 }
1506
1507
1508 void BufferParams::readGraphicsDriver(Lexer & lex)
1509 {
1510         if (!lex.next()) return;
1511
1512         string const tmptok = lex.getString();
1513         // check if tmptok is part of tex_graphics in tex_defs.h
1514         int n = 0;
1515         while (true) {
1516                 string const test = tex_graphics[n++];
1517
1518                 if (test == tmptok) {
1519                         graphicsDriver = tmptok;
1520                         break;
1521                 } else if (test == "") {
1522                         lex.printError(
1523                                 "Warning: graphics driver `$$Token' not recognized!\n"
1524                                 "         Setting graphics driver to `default'.\n");
1525                         graphicsDriver = "default";
1526                         break;
1527                 }
1528         }
1529 }
1530
1531
1532 void BufferParams::readBullets(Lexer & lex)
1533 {
1534         if (!lex.next()) return;
1535
1536         int const index = lex.getInteger();
1537         lex.next();
1538         int temp_int = lex.getInteger();
1539         user_defined_bullet(index).setFont(temp_int);
1540         temp_bullet(index).setFont(temp_int);
1541         lex >> temp_int;
1542         user_defined_bullet(index).setCharacter(temp_int);
1543         temp_bullet(index).setCharacter(temp_int);
1544         lex >> temp_int;
1545         user_defined_bullet(index).setSize(temp_int);
1546         temp_bullet(index).setSize(temp_int);
1547 }
1548
1549
1550 void BufferParams::readBulletsLaTeX(Lexer & lex)
1551 {
1552         // The bullet class should be able to read this.
1553         if (!lex.next()) return;
1554         int const index = lex.getInteger();
1555         lex.next(true);
1556         docstring const temp_str = lex.getDocString();
1557
1558         user_defined_bullet(index).setText(temp_str);
1559         temp_bullet(index).setText(temp_str);
1560 }
1561
1562
1563 void BufferParams::readModules(Lexer & lex)
1564 {
1565         if (!lex.eatLine()) {
1566                 lyxerr << "Error (BufferParams::readModules):"
1567                                 "Unexpected end of input." << endl;
1568                 return;
1569         }
1570         while (true) {
1571                 string mod = lex.getString();
1572                 if (mod == "\\end_modules")
1573                         break;
1574                 addLayoutModule(mod);
1575                 lex.eatLine();
1576         }
1577 }
1578
1579
1580 string const BufferParams::paperSizeName(Papersize_Purpose const & purpose) const
1581 {
1582         char real_papersize = papersize;
1583         if (real_papersize == PAPER_DEFAULT)
1584                 real_papersize = lyxrc.default_papersize;
1585
1586         switch (real_papersize) {
1587         case PAPER_DEFAULT:
1588                 // could be anything, so don't guess
1589                 return string();
1590         case PAPER_CUSTOM: {
1591                 if (purpose == XDVI && !paperwidth.empty() &&
1592                     !paperheight.empty()) {
1593                         // heightxwidth<unit>
1594                         string first = paperwidth;
1595                         string second = paperheight;
1596                         if (orientation == ORIENTATION_LANDSCAPE)
1597                                 first.swap(second);
1598                         // cut off unit.
1599                         return first.erase(first.length() - 2)
1600                                 + "x" + second;
1601                 }
1602                 return string();
1603         }
1604         case PAPER_A3:
1605                 return "a3";
1606         case PAPER_A4:
1607                 return "a4";
1608         case PAPER_A5:
1609                 return "a5";
1610         case PAPER_B3:
1611                 // dvips and dvipdfm do not know this
1612                 if (purpose == DVIPS || purpose == DVIPDFM)
1613                         return string();
1614                 return "b3";
1615         case PAPER_B4:
1616                 // dvipdfm does not know this
1617                 if (purpose == DVIPDFM)
1618                         return string();
1619                 return "b4";
1620         case PAPER_B5:
1621                 // dvipdfm does not know this
1622                 if (purpose == DVIPDFM)
1623                         return string();
1624                 return "b5";
1625         case PAPER_USEXECUTIVE:
1626                 // dvipdfm does not know this
1627                 if (purpose == DVIPDFM)
1628                         return string();
1629                 return "foolscap";
1630         case PAPER_USLEGAL:
1631                 return "legal";
1632         case PAPER_USLETTER:
1633         default:
1634                 if (purpose == XDVI)
1635                         return "us";
1636                 return "letter";
1637         }
1638 }
1639
1640
1641 string const BufferParams::dvips_options() const
1642 {
1643         string result;
1644
1645         if (use_geometry
1646             && papersize == PAPER_CUSTOM
1647             && !lyxrc.print_paper_dimension_flag.empty()
1648             && !paperwidth.empty()
1649             && !paperheight.empty()) {
1650                 // using a custom papersize
1651                 result = lyxrc.print_paper_dimension_flag;
1652                 result += ' ' + paperwidth;
1653                 result += ',' + paperheight;
1654         } else {
1655                 string const paper_option = paperSizeName(DVIPS);
1656                 if (!paper_option.empty() && (paper_option != "letter" ||
1657                     orientation != ORIENTATION_LANDSCAPE)) {
1658                         // dvips won't accept -t letter -t landscape.
1659                         // In all other cases, include the paper size
1660                         // explicitly.
1661                         result = lyxrc.print_paper_flag;
1662                         result += ' ' + paper_option;
1663                 }
1664         }
1665         if (orientation == ORIENTATION_LANDSCAPE &&
1666             papersize != PAPER_CUSTOM)
1667                 result += ' ' + lyxrc.print_landscape_flag;
1668         return result;
1669 }
1670
1671
1672 string const BufferParams::babelCall(string const & lang_opts) const
1673 {
1674         string lang_pack = lyxrc.language_package;
1675         if (lang_pack != "\\usepackage{babel}")
1676                 return lang_pack;
1677         // suppress the babel call when there is no babel language defined
1678         // for the document language in the lib/languages file and if no
1679         // other languages are used (lang_opts is then empty)
1680         if (lang_opts.empty())
1681                 return string();
1682         // when Vietnamese is used, babel must directly be loaded with the
1683         // language options, see
1684         // http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129417.html
1685         size_t viet = lang_opts.find("vietnam");
1686         // viet = string::npos when not found
1687         if (!lyxrc.language_global_options || viet != string::npos)
1688                 return "\\usepackage[" + lang_opts + "]{babel}";
1689         return lang_pack;
1690 }
1691
1692
1693 void BufferParams::writeEncodingPreamble(odocstream & os,
1694                 LaTeXFeatures & features, TexRow & texrow) const
1695 {
1696         if (inputenc == "auto") {
1697                 string const doc_encoding =
1698                         language->encoding()->latexName();
1699                 Encoding::Package const package =
1700                         language->encoding()->package();
1701
1702                 // Create a list with all the input encodings used
1703                 // in the document
1704                 set<string> encodings =
1705                         features.getEncodingSet(doc_encoding);
1706
1707                 // When the encodings EUC-JP-plain, JIS-plain, or SJIS-plainare used, the
1708                 // package inputenc must be omitted. Therefore set the encoding to empty.
1709                 // see http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg129680.html
1710                 if (doc_encoding == "EUC-JP-plain" || doc_encoding == "JIS-plain" ||
1711                         doc_encoding == "SJIS-plain")
1712                         encodings.clear();
1713
1714                 if (!encodings.empty() || package == Encoding::inputenc) {
1715                         os << "\\usepackage[";
1716                         set<string>::const_iterator it = encodings.begin();
1717                         set<string>::const_iterator const end = encodings.end();
1718                         if (it != end) {
1719                                 os << from_ascii(*it);
1720                                 ++it;
1721                         }
1722                         for (; it != end; ++it)
1723                                 os << ',' << from_ascii(*it);
1724                         if (package == Encoding::inputenc) {
1725                                 if (!encodings.empty())
1726                                         os << ',';
1727                                 os << from_ascii(doc_encoding);
1728                         }
1729                         os << "]{inputenc}\n";
1730                         texrow.newline();
1731                 }
1732                 if (package == Encoding::CJK || features.mustProvide("CJK")) {
1733                         os << "\\usepackage{CJK}\n";
1734                         texrow.newline();
1735                 }
1736         } else if (inputenc != "default") {
1737                 switch (encoding().package()) {
1738                 case Encoding::none:
1739                         break;
1740                 case Encoding::inputenc:
1741                         os << "\\usepackage[" << from_ascii(inputenc)
1742                            << "]{inputenc}\n";
1743                         texrow.newline();
1744                         break;
1745                 case Encoding::CJK:
1746                         os << "\\usepackage{CJK}\n";
1747                         texrow.newline();
1748                         break;
1749                 }
1750         }
1751
1752         // The encoding "armscii8" is only available when the package "armtex" is loaded.
1753         // armscii8 is used for Armenian.
1754         if (language->encoding()->latexName() == "armscii8" || inputenc == "armscii8") {
1755                 os << "\\usepackage{armtex}\n";
1756                 texrow.newline();
1757         }
1758 }
1759
1760
1761 string const BufferParams::loadFonts(string const & rm,
1762                                      string const & sf, string const & tt,
1763                                      bool const & sc, bool const & osf,
1764                                      int const & sfscale, int const & ttscale) const
1765 {
1766         /* The LaTeX font world is in a flux. In the PSNFSS font interface,
1767            several packages have been replaced by others, that might not
1768            be installed on every system. We have to take care for that
1769            (see psnfss.pdf). We try to support all psnfss fonts as well
1770            as the fonts that have become de facto standard in the LaTeX
1771            world (e.g. Latin Modern). We do not support obsolete fonts
1772            (like PSLatex). In general, it should be possible to mix any
1773            rm font with any sf or tt font, respectively. (JSpitzm)
1774            TODO:
1775                 -- separate math fonts.
1776         */
1777
1778         if (rm == "default" && sf == "default" && tt == "default")
1779                 //nothing to do
1780                 return string();
1781
1782         ostringstream os;
1783
1784         // ROMAN FONTS
1785         // Computer Modern (must be explicitely selectable -- there might be classes
1786         // that define a different default font!
1787         if (rm == "cmr") {
1788                 os << "\\renewcommand{\\rmdefault}{cmr}\n";
1789                 // osf for Computer Modern needs eco.sty
1790                 if (osf)
1791                         os << "\\usepackage{eco}\n";
1792         }
1793         // Latin Modern Roman
1794         else if (rm == "lmodern")
1795                 os << "\\usepackage{lmodern}\n";
1796         // AE
1797         else if (rm == "ae") {
1798                 // not needed when using OT1 font encoding.
1799                 if (lyxrc.fontenc != "default")
1800                         os << "\\usepackage{ae,aecompl}\n";
1801         }
1802         // Times
1803         else if (rm == "times") {
1804                 // try to load the best available package
1805                 if (LaTeXFeatures::isAvailable("mathptmx"))
1806                         os << "\\usepackage{mathptmx}\n";
1807                 else if (LaTeXFeatures::isAvailable("mathptm"))
1808                         os << "\\usepackage{mathptm}\n";
1809                 else
1810                         os << "\\usepackage{times}\n";
1811         }
1812         // Palatino
1813         else if (rm == "palatino") {
1814                 // try to load the best available package
1815                 if (LaTeXFeatures::isAvailable("mathpazo")) {
1816                         os << "\\usepackage";
1817                         if (osf || sc) {
1818                                 os << '[';
1819                                 if (!osf)
1820                                         os << "sc";
1821                                 else
1822                                         // "osf" includes "sc"!
1823                                         os << "osf";
1824                                 os << ']';
1825                         }
1826                         os << "{mathpazo}\n";
1827                 }
1828                 else if (LaTeXFeatures::isAvailable("mathpple"))
1829                         os << "\\usepackage{mathpple}\n";
1830                 else
1831                         os << "\\usepackage{palatino}\n";
1832         }
1833         // Utopia
1834         else if (rm == "utopia") {
1835                 // fourier supersedes utopia.sty, but does
1836                 // not work with OT1 encoding.
1837                 if (LaTeXFeatures::isAvailable("fourier")
1838                     && lyxrc.fontenc != "default") {
1839                         os << "\\usepackage";
1840                         if (osf || sc) {
1841                                 os << '[';
1842                                 if (sc)
1843                                         os << "expert";
1844                                 if (osf && sc)
1845                                         os << ',';
1846                                 if (osf)
1847                                         os << "oldstyle";
1848                                 os << ']';
1849                         }
1850                         os << "{fourier}\n";
1851                 }
1852                 else
1853                         os << "\\usepackage{utopia}\n";
1854         }
1855         // Bera (complete fontset)
1856         else if (rm == "bera" && sf == "default" && tt == "default")
1857                 os << "\\usepackage{bera}\n";
1858         // everything else
1859         else if (rm != "default")
1860                 os << "\\usepackage" << "{" << rm << "}\n";
1861
1862         // SANS SERIF
1863         // Helvetica, Bera Sans
1864         if (sf == "helvet" || sf == "berasans") {
1865                 if (sfscale != 100)
1866                         os << "\\usepackage[scaled=" << float(sfscale) / 100
1867                            << "]{" << sf << "}\n";
1868                 else
1869                         os << "\\usepackage{" << sf << "}\n";
1870         }
1871         // Avant Garde
1872         else if (sf == "avant")
1873                 os << "\\usepackage{" << sf << "}\n";
1874         // Computer Modern, Latin Modern, CM Bright
1875         else if (sf != "default")
1876                 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
1877
1878         // monospaced/typewriter
1879         // Courier, LuxiMono
1880         if (tt == "luximono" || tt == "beramono") {
1881                 if (ttscale != 100)
1882                         os << "\\usepackage[scaled=" << float(ttscale) / 100
1883                            << "]{" << tt << "}\n";
1884                 else
1885                         os << "\\usepackage{" << tt << "}\n";
1886         }
1887         // Courier
1888         else if (tt == "courier" )
1889                 os << "\\usepackage{" << tt << "}\n";
1890         // Computer Modern, Latin Modern, CM Bright
1891         else if  (tt != "default")
1892                 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
1893
1894         return os.str();
1895 }
1896
1897
1898 Encoding const & BufferParams::encoding() const
1899 {
1900         if (inputenc == "auto" || inputenc == "default")
1901                 return *(language->encoding());
1902         Encoding const * const enc =
1903                 encodings.getFromLaTeXName(inputenc);
1904         if (enc)
1905                 return *enc;
1906         lyxerr << "Unknown inputenc value `" << inputenc
1907                << "'. Using `auto' instead." << endl;
1908         return *(language->encoding());
1909 }
1910
1911
1912 biblio::CiteEngine BufferParams::getEngine() const
1913 {
1914         // FIXME the class should provide the numerical/
1915         // authoryear choice
1916         if (getTextClass().provides("natbib")
1917             && cite_engine_ != biblio::ENGINE_NATBIB_NUMERICAL)
1918                 return biblio::ENGINE_NATBIB_AUTHORYEAR;
1919         return cite_engine_;
1920 }
1921
1922
1923 void BufferParams::setCiteEngine(biblio::CiteEngine const cite_engine)
1924 {
1925         cite_engine_ = cite_engine;
1926 }
1927
1928 } // namespace lyx