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