]> git.lyx.org Git - lyx.git/blob - src/bufferparams.C
get rid of broken_header.h and some unneeded tests
[lyx.git] / src / bufferparams.C
1 /**
2  * \file bufferparams.C
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 "Bullet.h"
23 #include "debug.h"
24 #include "encoding.h"
25 #include "gettext.h"
26 #include "language.h"
27 #include "LaTeXFeatures.h"
28 #include "LColor.h"
29 #include "lyxlex.h"
30 #include "lyxrc.h"
31 #include "lyxtextclasslist.h"
32 #include "outputparams.h"
33 #include "tex-strings.h"
34 #include "Spacing.h"
35 #include "texrow.h"
36 #include "vspace.h"
37
38 #include "frontends/Alert.h"
39
40 #include "support/lyxalgo.h" // for lyx::count
41 #include "support/tostr.h"
42 #include "support/translator.h"
43
44 #include <boost/array.hpp>
45
46 #include <sstream>
47
48 namespace support = lyx::support;
49 using lyx::support::bformat;
50 using lyx::support::rtrim;
51 using lyx::support::tokenPos;
52
53 using std::endl;
54 using std::string;
55 using std::istringstream;
56 using std::ostream;
57 using std::ostringstream;
58 using std::pair;
59
60 namespace biblio = lyx::biblio;
61
62
63 // Local translators
64 namespace {
65
66 // Paragraph separation
67 typedef Translator<std::string, BufferParams::PARSEP> ParSepTranslator;
68
69
70 ParSepTranslator const init_parseptranslator() {
71         ParSepTranslator translator(string_paragraph_separation[0], BufferParams::PARSEP_INDENT);
72         translator.addPair(string_paragraph_separation[1], BufferParams::PARSEP_SKIP);
73         return translator;
74 }
75
76
77 ParSepTranslator const & parseptranslator() {
78         static ParSepTranslator translator = init_parseptranslator();
79         return translator;
80 }
81
82 // Quotes language
83 typedef Translator<std::string, InsetQuotes::quote_language> QuotesLangTranslator;
84
85
86 QuotesLangTranslator const init_quoteslangtranslator() {
87         QuotesLangTranslator translator(string_quotes_language[0], InsetQuotes::EnglishQ);
88         translator.addPair(string_quotes_language[1], InsetQuotes::SwedishQ);
89         translator.addPair(string_quotes_language[2], InsetQuotes::GermanQ);
90         translator.addPair(string_quotes_language[3], InsetQuotes::PolishQ);
91         translator.addPair(string_quotes_language[4], InsetQuotes::FrenchQ);
92         translator.addPair(string_quotes_language[5], InsetQuotes::DanishQ);
93         return translator;
94 }
95
96
97 QuotesLangTranslator const & quoteslangtranslator() {
98         static QuotesLangTranslator translator = init_quoteslangtranslator();
99         return translator;
100 }
101
102 // Quote times
103 typedef Translator<int, InsetQuotes::quote_times> QuotesTimesTranslator;
104
105
106 QuotesTimesTranslator const init_quotestimestranslator() {
107         QuotesTimesTranslator translator(1, InsetQuotes::SingleQ);
108         translator.addPair(2, InsetQuotes::DoubleQ);
109         return translator;
110 }
111
112
113 QuotesTimesTranslator const & quotestimestranslator() {
114         static QuotesTimesTranslator translator = init_quotestimestranslator();
115         return translator;
116 }
117
118 // Paper size
119 typedef Translator<std::string, VMARGIN_PAPER_TYPE> PaperSizeTranslator;
120
121
122 PaperSizeTranslator const init_papersizetranslator() {
123         PaperSizeTranslator translator(string_papersize[0], VM_PAPER_DEFAULT);
124         translator.addPair(string_papersize[1], VM_PAPER_CUSTOM);
125         translator.addPair(string_papersize[2], VM_PAPER_USLETTER);
126         translator.addPair(string_papersize[3], VM_PAPER_USLEGAL);
127         translator.addPair(string_papersize[4], VM_PAPER_USEXECUTIVE);
128         translator.addPair(string_papersize[5], VM_PAPER_A3);
129         translator.addPair(string_papersize[6], VM_PAPER_A4);
130         translator.addPair(string_papersize[7], VM_PAPER_A5);
131         translator.addPair(string_papersize[8], VM_PAPER_B3);
132         translator.addPair(string_papersize[9], VM_PAPER_B4);
133         translator.addPair(string_papersize[10], VM_PAPER_B5);
134         return translator;
135 }
136
137
138 PaperSizeTranslator const & papersizetranslator() {
139         static PaperSizeTranslator translator = init_papersizetranslator();
140         return translator;
141 }
142
143 // Paper packages
144 typedef Translator<std::string, PAPER_PACKAGES> PaperPackagesTranslator;
145
146
147 PaperPackagesTranslator const init_paperpackagestranslator() {
148         PaperPackagesTranslator translator(string_paperpackages[0], PACKAGE_NONE);
149         translator.addPair(string_paperpackages[1], PACKAGE_A4);
150         translator.addPair(string_paperpackages[2], PACKAGE_A4WIDE);
151         translator.addPair(string_paperpackages[3], PACKAGE_WIDEMARGINSA4);
152         return translator;
153 }
154
155
156 PaperPackagesTranslator const & paperpackagestranslator() {
157         static PaperPackagesTranslator translator = init_paperpackagestranslator();
158         return translator;
159 }
160
161
162 // Paper orientation
163 typedef Translator<std::string, PAPER_ORIENTATION> PaperOrientationTranslator;
164
165
166 PaperOrientationTranslator const init_paperorientationtranslator() {
167         PaperOrientationTranslator translator(string_orientation[0], ORIENTATION_PORTRAIT);
168         translator.addPair(string_orientation[1], ORIENTATION_LANDSCAPE);
169         return translator;
170 }
171
172
173 PaperOrientationTranslator const & paperorientationtranslator() {
174         static PaperOrientationTranslator translator = init_paperorientationtranslator();
175         return translator;
176 }
177
178
179 // Page sides
180 typedef Translator<int, LyXTextClass::PageSides> SidesTranslator;
181
182
183 SidesTranslator const init_sidestranslator() {
184         SidesTranslator translator(1, LyXTextClass::OneSide);
185         translator.addPair(2, LyXTextClass::TwoSides);
186         return translator;
187 }
188
189
190 SidesTranslator const & sidestranslator() {
191         static SidesTranslator translator = init_sidestranslator();
192         return translator;
193 }
194
195
196
197 // AMS
198 typedef Translator<int, BufferParams::AMS> AMSTranslator;
199
200
201 AMSTranslator const init_amstranslator() {
202         AMSTranslator translator(0, BufferParams::AMS_OFF);
203         translator.addPair(1, BufferParams::AMS_AUTO);
204         translator.addPair(2, BufferParams::AMS_ON);
205         return translator;
206 }
207
208
209 AMSTranslator const & amstranslator() {
210         static AMSTranslator translator = init_amstranslator();
211         return translator;
212 }
213
214
215
216 // Cite engine
217 typedef Translator<string, biblio::CiteEngine> CiteEngineTranslator;
218
219
220 CiteEngineTranslator const init_citeenginetranslator() {
221         CiteEngineTranslator translator("basic", biblio::ENGINE_BASIC);
222         translator.addPair("natbib_numerical", biblio::ENGINE_NATBIB_NUMERICAL);
223         translator.addPair("natbib_authoryear", biblio::ENGINE_NATBIB_AUTHORYEAR);
224         translator.addPair("jurabib", biblio::ENGINE_JURABIB);
225         return translator;
226 }
227
228
229 CiteEngineTranslator const & citeenginetranslator() {
230         static CiteEngineTranslator translator = init_citeenginetranslator();
231         return translator;
232 }
233
234
235 // Spacing
236 typedef Translator<string, Spacing::Space> SpaceTranslator;
237
238
239 SpaceTranslator const init_spacetranslator() {
240         SpaceTranslator translator("default", Spacing::Default);
241         translator.addPair("single", Spacing::Single);
242         translator.addPair("onehalf", Spacing::Onehalf);
243         translator.addPair("double", Spacing::Double);
244         return translator;
245 }
246
247
248 SpaceTranslator const & spacetranslator() {
249         static SpaceTranslator translator = init_spacetranslator();
250         return translator;
251 }
252
253 // ends annonym namespace
254 }
255
256
257 struct BufferParams::Impl
258 {
259         Impl();
260
261         AuthorList authorlist;
262         BranchList branchlist;
263         boost::array<Bullet, 4> temp_bullets;
264         boost::array<Bullet, 4> user_defined_bullets;
265         Spacing spacing;
266         /** This is the amount of space used for paragraph_separation "skip",
267          * and for detached paragraphs in "indented" documents.
268          */
269         VSpace defskip;
270 };
271
272
273 BufferParams::Impl::Impl()
274         : defskip(VSpace::MEDSKIP)
275 {
276         // set initial author
277         authorlist.record(Author(lyxrc.user_name, lyxrc.user_email));
278 }
279
280
281 BufferParams::Impl *
282 BufferParams::MemoryTraits::clone(BufferParams::Impl const * ptr)
283 {
284         return new BufferParams::Impl(*ptr);
285 }
286
287
288 void BufferParams::MemoryTraits::destroy(BufferParams::Impl * ptr)
289 {
290         delete ptr;
291 }
292
293
294 BufferParams::BufferParams()
295         : // Initialize textclass to point to article. if `first' is
296           // true in the returned pair, then `second' is the textclass
297           // number; if it is false, second is 0. In both cases, second
298           // is what we want.
299         textclass(textclasslist.NumberOfClass("article").second),
300         pimpl_(new Impl)
301 {
302         paragraph_separation = PARSEP_INDENT;
303         quotes_language = InsetQuotes::EnglishQ;
304         quotes_times = InsetQuotes::DoubleQ;
305         fontsize = "default";
306
307         /*  PaperLayout */
308         papersize = PAPER_DEFAULT;
309         papersize2 = VM_PAPER_DEFAULT; /* DEFAULT */
310         paperpackage = PACKAGE_NONE;
311         orientation = ORIENTATION_PORTRAIT;
312         use_geometry = false;
313         use_amsmath = AMS_AUTO;
314         cite_engine = biblio::ENGINE_BASIC;
315         use_bibtopic = false;
316         tracking_changes = false;
317         secnumdepth = 3;
318         tocdepth = 3;
319         language = default_language;
320         fonts = "default";
321         inputenc = "auto";
322         graphicsDriver = "default";
323         sides = LyXTextClass::OneSide;
324         columns = 1;
325         pagestyle = "default";
326         compressed = false;
327         for (int iter = 0; iter < 4; ++iter) {
328                 user_defined_bullet(iter) = ITEMIZE_DEFAULTS[iter];
329                 temp_bullet(iter) = ITEMIZE_DEFAULTS[iter];
330         }
331 }
332
333
334 BufferParams::~BufferParams()
335 {}
336
337
338 AuthorList & BufferParams::authors()
339 {
340         return pimpl_->authorlist;
341 }
342
343
344 AuthorList const & BufferParams::authors() const
345 {
346         return pimpl_->authorlist;
347 }
348
349
350 BranchList & BufferParams::branchlist()
351 {
352         return pimpl_->branchlist;
353 }
354
355
356 BranchList const & BufferParams::branchlist() const
357 {
358         return pimpl_->branchlist;
359 }
360
361
362 Bullet & BufferParams::temp_bullet(lyx::size_type index)
363 {
364         BOOST_ASSERT(index < 4);
365         return pimpl_->temp_bullets[index];
366 }
367
368
369 Bullet const & BufferParams::temp_bullet(lyx::size_type index) const
370 {
371         BOOST_ASSERT(index < 4);
372         return pimpl_->temp_bullets[index];
373 }
374
375
376 Bullet & BufferParams::user_defined_bullet(lyx::size_type index)
377 {
378         BOOST_ASSERT(index < 4);
379         return pimpl_->user_defined_bullets[index];
380 }
381
382
383 Bullet const & BufferParams::user_defined_bullet(lyx::size_type index) const
384 {
385         BOOST_ASSERT(index < 4);
386         return pimpl_->user_defined_bullets[index];
387 }
388
389
390 Spacing & BufferParams::spacing()
391 {
392         return pimpl_->spacing;
393 }
394
395
396 Spacing const & BufferParams::spacing() const
397 {
398         return pimpl_->spacing;
399 }
400
401
402 VSpace const & BufferParams::getDefSkip() const
403 {
404         return pimpl_->defskip;
405 }
406
407
408 void BufferParams::setDefSkip(VSpace const & vs)
409 {
410         pimpl_->defskip = vs;
411 }
412
413
414 string const BufferParams::readToken(LyXLex & lex, string const & token)
415 {
416         if (token == "\\textclass") {
417                 lex.next();
418                 string const classname = lex.getString();
419                 pair<bool, lyx::textclass_type> pp =
420                         textclasslist.NumberOfClass(classname);
421                 if (pp.first) {
422                         textclass = pp.second;
423                 } else {
424                         textclass = 0;
425                         return classname;
426                 }
427                 if (!getLyXTextClass().isTeXClassAvailable()) {
428                         string msg = bformat(_("The document uses a missing "
429                                 "TeX class \"%1$s\".\n"), classname);
430                         Alert::warning(_("Document class not available"),
431                                        msg + _("LyX will not be able to produce output."));
432                 }
433         } else if (token == "\\begin_preamble") {
434                 readPreamble(lex);
435         } else if (token == "\\options") {
436                 lex.eatLine();
437                 options = lex.getString();
438         } else if (token == "\\language") {
439                 readLanguage(lex);
440         } else if (token == "\\inputencoding") {
441                 lex >> inputenc;
442         } else if (token == "\\graphics") {
443                 readGraphicsDriver(lex);
444         } else if (token == "\\fontscheme") {
445                 lex >> fonts;
446         } else if (token == "\\paragraph_separation") {
447                 string parsep;
448                 lex >> parsep;
449                 paragraph_separation = parseptranslator().find(parsep);
450         } else if (token == "\\defskip") {
451                 lex.next();
452                 pimpl_->defskip = VSpace(lex.getString());
453         } else if (token == "\\quotes_language") {
454                 string quotes_lang;
455                 lex >> quotes_lang;
456                 quotes_language = quoteslangtranslator().find(quotes_lang);
457         } else if (token == "\\quotes_times") {
458                 int qtimes;
459                 lex >> qtimes;
460                 quotes_times = quotestimestranslator().find(qtimes);
461         } else if (token == "\\papersize") {
462                 string ppsize;
463                 lex >> ppsize;
464                 papersize2 = papersizetranslator().find(ppsize);
465         } else if (token == "\\paperpackage") {
466                 string ppackage;
467                 lex >> ppackage;
468                 paperpackage = paperpackagestranslator().find(ppackage);
469         } else if (token == "\\use_geometry") {
470                 lex >> use_geometry;
471         } else if (token == "\\use_amsmath") {
472                 int use_ams;
473                 lex >> use_ams;
474                 use_amsmath = amstranslator().find(use_ams);
475         } else if (token == "\\cite_engine") {
476                 string engine;
477                 lex >> engine;
478                 cite_engine = citeenginetranslator().find(engine);
479         } else if (token == "\\use_bibtopic") {
480                 lex >> use_bibtopic;
481         } else if (token == "\\tracking_changes") {
482                 lex >> tracking_changes;
483         } else if (token == "\\branch") {
484                 lex.next();
485                 string branch = lex.getString();
486                 branchlist().add(branch);
487                 while (true) {
488                         lex.next();
489                         string const tok = lex.getString();
490                         if (tok == "\\end_branch")
491                                 break;
492                         Branch * branch_ptr = branchlist().find(branch);
493                         if (tok == "\\selected") {
494                                 lex.next();
495                                 if (branch_ptr)
496                                         branch_ptr->setSelected(lex.getInteger());
497                         }
498                         // not yet operational
499                         if (tok == "\\color") {
500                                 lex.eatLine();
501                                 string color = lex.getString();
502                                 if (branch_ptr)
503                                         branch_ptr->setColor(color);
504                                 // Update also the LColor table:
505                                 if (color == "none")
506                                         color = lcolor.getX11Name(LColor::background);
507                                 lcolor.setColor(branch, color);
508
509                         }
510                 }
511         } else if (token == "\\author") {
512                 lex.eatLine();
513                 istringstream ss(lex.getString());
514                 Author a;
515                 ss >> a;
516                 author_map.push_back(pimpl_->authorlist.record(a));
517         } else if (token == "\\paperorientation") {
518                 string orient;
519                 lex >> orient;
520                 orientation = paperorientationtranslator().find(orient);
521         } else if (token == "\\paperwidth") {
522                 lex >> paperwidth;
523         } else if (token == "\\paperheight") {
524                 lex >> paperheight;
525         } else if (token == "\\leftmargin") {
526                 lex >> leftmargin;
527         } else if (token == "\\topmargin") {
528                 lex >> topmargin;
529         } else if (token == "\\rightmargin") {
530                 lex >> rightmargin;
531         } else if (token == "\\bottommargin") {
532                 lex >> bottommargin;
533         } else if (token == "\\headheight") {
534                 lex >> headheight;
535         } else if (token == "\\headsep") {
536                 lex >> headsep;
537         } else if (token == "\\footskip") {
538                 lex >> footskip;
539         } else if (token == "\\paperfontsize") {
540                 lex >> fontsize;
541         } else if (token == "\\papercolumns") {
542                 lex >> columns;
543         } else if (token == "\\papersides") {
544                 int psides;
545                 lex >> psides;
546                 sides = sidestranslator().find(psides);
547         } else if (token == "\\paperpagestyle") {
548                 lex >> pagestyle;
549         } else if (token == "\\bullet") {
550                 readBullets(lex);
551         } else if (token == "\\bulletLaTeX") {
552                 readBulletsLaTeX(lex);
553         } else if (token == "\\secnumdepth") {
554                 lex >> secnumdepth;
555         } else if (token == "\\tocdepth") {
556                 lex >> tocdepth;
557         } else if (token == "\\spacing") {
558                 string nspacing;
559                 lex >> nspacing;
560                 float tmp_val = 0.0;
561                 if (nspacing == "other") {
562                         lex >> tmp_val;
563                 }
564                 spacing().set(spacetranslator().find(nspacing), tmp_val);
565         } else if (token == "\\float_placement") {
566                 lex >> float_placement;
567         } else {
568                 return token;
569         }
570
571         return string();
572 }
573
574
575 void BufferParams::writeFile(ostream & os) const
576 {
577         // The top of the file is written by the buffer.
578         // Prints out the buffer info into the .lyx file given by file
579
580         // the textclass
581         os << "\\textclass " << textclasslist[textclass].name() << '\n';
582
583         // then the the preamble
584         if (!preamble.empty()) {
585                 // remove '\n' from the end of preamble
586                 string const tmppreamble = rtrim(preamble, "\n");
587                 os << "\\begin_preamble\n"
588                    << tmppreamble
589                    << "\n\\end_preamble\n";
590         }
591
592         /* the options */
593         if (!options.empty()) {
594                 os << "\\options " << options << '\n';
595         }
596
597         /* then the text parameters */
598         if (language != ignore_language)
599                 os << "\\language " << language->lang() << '\n';
600         os << "\\inputencoding " << inputenc
601            << "\n\\fontscheme " << fonts
602            << "\n\\graphics " << graphicsDriver << '\n';
603
604         if (!float_placement.empty()) {
605                 os << "\\float_placement " << float_placement << '\n';
606         }
607         os << "\\paperfontsize " << fontsize << '\n';
608
609         spacing().writeFile(os);
610
611         os << "\\papersize " << string_papersize[papersize2]
612            << "\n\\paperpackage " << string_paperpackages[paperpackage]
613            << "\n\\use_geometry " << tostr(use_geometry)
614            << "\n\\use_amsmath " << use_amsmath
615            << "\n\\cite_engine " << citeenginetranslator().find(cite_engine)
616            << "\n\\use_bibtopic " << tostr(use_bibtopic)
617            << "\n\\paperorientation " << string_orientation[orientation]
618            << '\n';
619
620         std::list<Branch>::const_iterator it = branchlist().begin();
621         std::list<Branch>::const_iterator end = branchlist().end();
622         for (; it != end; ++it) {
623                 os << "\\branch " << it->getBranch()
624                    << "\n\\selected " << it->getSelected()
625                    << "\n\\color " << it->getColor()
626                    << "\n\\end_branch"
627                    << "\n";
628         }
629
630         if (!paperwidth.empty())
631                 os << "\\paperwidth "
632                    << VSpace(paperwidth).asLyXCommand() << '\n';
633         if (!paperheight.empty())
634                 os << "\\paperheight "
635                    << VSpace(paperheight).asLyXCommand() << '\n';
636         if (!leftmargin.empty())
637                 os << "\\leftmargin "
638                    << VSpace(leftmargin).asLyXCommand() << '\n';
639         if (!topmargin.empty())
640                 os << "\\topmargin "
641                    << VSpace(topmargin).asLyXCommand() << '\n';
642         if (!rightmargin.empty())
643                 os << "\\rightmargin "
644                    << VSpace(rightmargin).asLyXCommand() << '\n';
645         if (!bottommargin.empty())
646                 os << "\\bottommargin "
647                    << VSpace(bottommargin).asLyXCommand() << '\n';
648         if (!headheight.empty())
649                 os << "\\headheight "
650                    << VSpace(headheight).asLyXCommand() << '\n';
651         if (!headsep.empty())
652                 os << "\\headsep "
653                    << VSpace(headsep).asLyXCommand() << '\n';
654         if (!footskip.empty())
655                 os << "\\footskip "
656                    << VSpace(footskip).asLyXCommand() << '\n';
657         os << "\\secnumdepth " << secnumdepth
658            << "\n\\tocdepth " << tocdepth
659            << "\n\\paragraph_separation "
660            << string_paragraph_separation[paragraph_separation]
661            << "\n\\defskip " << getDefSkip().asLyXCommand()
662            << "\n\\quotes_language "
663            << string_quotes_language[quotes_language] << '\n'
664            << "\\quotes_times "
665            << quotestimestranslator().find(quotes_times)
666            << "\n\\papercolumns " << columns
667            << "\n\\papersides " << sides
668            << "\n\\paperpagestyle " << pagestyle << '\n';
669         for (int i = 0; i < 4; ++i) {
670                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
671                         if (user_defined_bullet(i).getFont() != -1) {
672                                 os << "\\bullet " << i << " "
673                                    << user_defined_bullet(i).getFont() << " "
674                                    << user_defined_bullet(i).getCharacter() << " "
675                                    << user_defined_bullet(i).getSize() << "\n";
676                         }
677                         else {
678                                 os << "\\bulletLaTeX " << i << " \""
679                                    << user_defined_bullet(i).getText()
680                                    << "\"\n";
681                         }
682                 }
683         }
684
685         os << "\\tracking_changes " << tostr(tracking_changes) << "\n";
686
687         if (tracking_changes) {
688                 AuthorList::Authors::const_iterator it = pimpl_->authorlist.begin();
689                 AuthorList::Authors::const_iterator end = pimpl_->authorlist.end();
690                 for (; it != end; ++it) {
691                         os << "\\author " << it->second << "\n";
692                 }
693         }
694 }
695
696
697 bool BufferParams::writeLaTeX(ostream & os, LaTeXFeatures & features,
698                               TexRow & texrow) const
699 {
700         os << "\\documentclass";
701
702         LyXTextClass const & tclass = getLyXTextClass();
703
704         ostringstream clsoptions; // the document class options.
705
706         if (tokenPos(tclass.opt_fontsize(),
707                      '|', fontsize) >= 0) {
708                 // only write if existing in list (and not default)
709                 clsoptions << fontsize << "pt,";
710         }
711
712
713         if (!use_geometry &&
714             (paperpackage == PACKAGE_NONE)) {
715                 switch (papersize) {
716                 case PAPER_A3PAPER:
717                         clsoptions << "a3paper,";
718                         break;
719                 case PAPER_A4PAPER:
720                         clsoptions << "a4paper,";
721                         break;
722                 case PAPER_USLETTER:
723                         clsoptions << "letterpaper,";
724                         break;
725                 case PAPER_A5PAPER:
726                         clsoptions << "a5paper,";
727                         break;
728                 case PAPER_B5PAPER:
729                         clsoptions << "b5paper,";
730                         break;
731                 case PAPER_EXECUTIVEPAPER:
732                         clsoptions << "executivepaper,";
733                         break;
734                 case PAPER_LEGALPAPER:
735                         clsoptions << "legalpaper,";
736                         break;
737                 case PAPER_DEFAULT:
738                         break;
739                 }
740         }
741
742         // if needed
743         if (sides != tclass.sides()) {
744                 switch (sides) {
745                 case LyXTextClass::OneSide:
746                         clsoptions << "oneside,";
747                         break;
748                 case LyXTextClass::TwoSides:
749                         clsoptions << "twoside,";
750                         break;
751                 }
752         }
753
754         // if needed
755         if (columns != tclass.columns()) {
756                 if (columns == 2)
757                         clsoptions << "twocolumn,";
758                 else
759                         clsoptions << "onecolumn,";
760         }
761
762         if (!use_geometry
763             && orientation == ORIENTATION_LANDSCAPE)
764                 clsoptions << "landscape,";
765
766         // language should be a parameter to \documentclass
767         if (language->babel() == "hebrew"
768             && default_language->babel() != "hebrew")
769                 // This seems necessary
770                 features.useLanguage(default_language);
771
772         ostringstream language_options;
773         bool const use_babel = features.useBabel();
774         if (use_babel) {
775                 language_options << features.getLanguages();
776                 language_options << language->babel();
777                 if (lyxrc.language_global_options)
778                         clsoptions << language_options.str() << ',';
779         }
780
781         // the user-defined options
782         if (!options.empty()) {
783                 clsoptions << options << ',';
784         }
785
786         string strOptions(clsoptions.str());
787         if (!strOptions.empty()) {
788                 strOptions = rtrim(strOptions, ",");
789                 os << '[' << strOptions << ']';
790         }
791
792         os << '{' << tclass.latexname() << "}\n";
793         texrow.newline();
794         // end of \documentclass defs
795
796         // font selection must be done before loading fontenc.sty
797         // The ae package is not needed when using OT1 font encoding.
798         if (fonts != "default" &&
799             (fonts != "ae" || lyxrc.fontenc != "default")) {
800                 os << "\\usepackage{" << fonts << "}\n";
801                 texrow.newline();
802                 if (fonts == "ae") {
803                         os << "\\usepackage{aecompl}\n";
804                         texrow.newline();
805                 }
806         }
807         // this one is not per buffer
808         if (lyxrc.fontenc != "default") {
809                 os << "\\usepackage[" << lyxrc.fontenc
810                    << "]{fontenc}\n";
811                 texrow.newline();
812         }
813
814         if (inputenc == "auto") {
815                 string const doc_encoding =
816                         language->encoding()->LatexName();
817
818                 // Create a list with all the input encodings used
819                 // in the document
820                 std::set<string> encodings =
821                         features.getEncodingSet(doc_encoding);
822
823                 os << "\\usepackage[";
824                 std::copy(encodings.begin(), encodings.end(),
825                           std::ostream_iterator<string>(os, ","));
826                 os << doc_encoding << "]{inputenc}\n";
827                 texrow.newline();
828         } else if (inputenc != "default") {
829                 os << "\\usepackage[" << inputenc
830                    << "]{inputenc}\n";
831                 texrow.newline();
832         }
833
834         // At the very beginning the text parameters.
835         if (paperpackage != PACKAGE_NONE) {
836                 switch (paperpackage) {
837                 case PACKAGE_NONE:
838                         break;
839                 case PACKAGE_A4:
840                         os << "\\usepackage{a4}\n";
841                         texrow.newline();
842                         break;
843                 case PACKAGE_A4WIDE:
844                         os << "\\usepackage{a4wide}\n";
845                         texrow.newline();
846                         break;
847                 case PACKAGE_WIDEMARGINSA4:
848                         os << "\\usepackage[widemargins]{a4}\n";
849                         texrow.newline();
850                         break;
851                 }
852         }
853         if (use_geometry) {
854                 os << "\\usepackage{geometry}\n";
855                 texrow.newline();
856                 os << "\\geometry{verbose";
857                 if (orientation == ORIENTATION_LANDSCAPE)
858                         os << ",landscape";
859                 switch (papersize2) {
860                 case VM_PAPER_CUSTOM:
861                         if (!paperwidth.empty())
862                                 os << ",paperwidth="
863                                    << paperwidth;
864                         if (!paperheight.empty())
865                                 os << ",paperheight="
866                                    << paperheight;
867                         break;
868                 case VM_PAPER_USLETTER:
869                         os << ",letterpaper";
870                         break;
871                 case VM_PAPER_USLEGAL:
872                         os << ",legalpaper";
873                         break;
874                 case VM_PAPER_USEXECUTIVE:
875                         os << ",executivepaper";
876                         break;
877                 case VM_PAPER_A3:
878                         os << ",a3paper";
879                         break;
880                 case VM_PAPER_A4:
881                         os << ",a4paper";
882                         break;
883                 case VM_PAPER_A5:
884                         os << ",a5paper";
885                         break;
886                 case VM_PAPER_B3:
887                         os << ",b3paper";
888                         break;
889                 case VM_PAPER_B4:
890                         os << ",b4paper";
891                         break;
892                 case VM_PAPER_B5:
893                         os << ",b5paper";
894                         break;
895                 default:
896                                 // default papersize ie VM_PAPER_DEFAULT
897                         switch (lyxrc.default_papersize) {
898                         case PAPER_DEFAULT: // keep compiler happy
899                         case PAPER_USLETTER:
900                                 os << ",letterpaper";
901                                 break;
902                         case PAPER_LEGALPAPER:
903                                 os << ",legalpaper";
904                                 break;
905                         case PAPER_EXECUTIVEPAPER:
906                                 os << ",executivepaper";
907                                 break;
908                         case PAPER_A3PAPER:
909                                 os << ",a3paper";
910                                 break;
911                         case PAPER_A4PAPER:
912                                 os << ",a4paper";
913                                 break;
914                         case PAPER_A5PAPER:
915                                 os << ",a5paper";
916                                 break;
917                         case PAPER_B5PAPER:
918                                 os << ",b5paper";
919                                 break;
920                         }
921                 }
922                 if (!topmargin.empty())
923                         os << ",tmargin=" << topmargin;
924                 if (!bottommargin.empty())
925                         os << ",bmargin=" << bottommargin;
926                 if (!leftmargin.empty())
927                         os << ",lmargin=" << leftmargin;
928                 if (!rightmargin.empty())
929                         os << ",rmargin=" << rightmargin;
930                 if (!headheight.empty())
931                         os << ",headheight=" << headheight;
932                 if (!headsep.empty())
933                         os << ",headsep=" << headsep;
934                 if (!footskip.empty())
935                         os << ",footskip=" << footskip;
936                 os << "}\n";
937                 texrow.newline();
938         }
939
940         if (tokenPos(tclass.opt_pagestyle(),
941                      '|', pagestyle) >= 0) {
942                 if (pagestyle == "fancy") {
943                         os << "\\usepackage{fancyhdr}\n";
944                         texrow.newline();
945                 }
946                 os << "\\pagestyle{" << pagestyle << "}\n";
947                 texrow.newline();
948         }
949
950         if (secnumdepth != tclass.secnumdepth()) {
951                 os << "\\setcounter{secnumdepth}{"
952                    << secnumdepth
953                    << "}\n";
954                 texrow.newline();
955         }
956         if (tocdepth != tclass.tocdepth()) {
957                 os << "\\setcounter{tocdepth}{"
958                    << tocdepth
959                    << "}\n";
960                 texrow.newline();
961         }
962
963         if (paragraph_separation) {
964                 switch (getDefSkip().kind()) {
965                 case VSpace::SMALLSKIP:
966                         os << "\\setlength\\parskip{\\smallskipamount}\n";
967                         break;
968                 case VSpace::MEDSKIP:
969                         os << "\\setlength\\parskip{\\medskipamount}\n";
970                         break;
971                 case VSpace::BIGSKIP:
972                         os << "\\setlength\\parskip{\\bigskipamount}\n";
973                         break;
974                 case VSpace::LENGTH:
975                         os << "\\setlength\\parskip{"
976                            << getDefSkip().length().asLatexString()
977                            << "}\n";
978                         break;
979                 default: // should never happen // Then delete it.
980                         os << "\\setlength\\parskip{\\medskipamount}\n";
981                         break;
982                 }
983                 texrow.newline();
984
985                 os << "\\setlength\\parindent{0pt}\n";
986                 texrow.newline();
987         }
988
989         // If we use jurabib, we have to call babel here.
990         if (use_babel && features.isRequired("jurabib")) {
991                 os << babelCall(language_options.str())
992                    << '\n'
993                    << features.getBabelOptions();
994                 texrow.newline();
995         }
996
997         // Now insert the LyX specific LaTeX commands...
998
999         // The optional packages;
1000         string lyxpreamble(features.getPackages());
1001
1002         // this might be useful...
1003         lyxpreamble += "\n\\makeatletter\n";
1004
1005         // Some macros LyX will need
1006         string tmppreamble(features.getMacros());
1007
1008         if (!tmppreamble.empty()) {
1009                 lyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1010                         "LyX specific LaTeX commands.\n"
1011                         + tmppreamble + '\n';
1012         }
1013
1014         // the text class specific preamble
1015         tmppreamble = features.getTClassPreamble();
1016         if (!tmppreamble.empty()) {
1017                 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1018                         "Textclass specific LaTeX commands.\n"
1019                         + tmppreamble + '\n';
1020         }
1021
1022         /* the user-defined preamble */
1023         if (!preamble.empty()) {
1024                 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1025                         "User specified LaTeX commands.\n"
1026                         + preamble + '\n';
1027         }
1028
1029         // Itemize bullet settings need to be last in case the user
1030         // defines their own bullets that use a package included
1031         // in the user-defined preamble -- ARRae
1032         // Actually it has to be done much later than that
1033         // since some packages like frenchb make modifications
1034         // at \begin{document} time -- JMarc
1035         string bullets_def;
1036         for (int i = 0; i < 4; ++i) {
1037                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1038                         if (bullets_def.empty())
1039                                 bullets_def="\\AtBeginDocument{\n";
1040                         bullets_def += "  \\renewcommand{\\labelitemi";
1041                         switch (i) {
1042                                 // `i' is one less than the item to modify
1043                         case 0:
1044                                 break;
1045                         case 1:
1046                                 bullets_def += 'i';
1047                                 break;
1048                         case 2:
1049                                 bullets_def += "ii";
1050                                 break;
1051                         case 3:
1052                                 bullets_def += 'v';
1053                                 break;
1054                         }
1055                         bullets_def += "}{" +
1056                                 user_defined_bullet(i).getText()
1057                                 + "}\n";
1058                 }
1059         }
1060
1061         if (!bullets_def.empty())
1062                 lyxpreamble += bullets_def + "}\n\n";
1063
1064         // We try to load babel late, in case it interferes
1065         // with other packages.
1066         // Jurabib has to be called after babel, though.
1067         if (use_babel && !features.isRequired("jurabib")) {
1068                 lyxpreamble += babelCall(language_options.str()) + '\n';
1069                 lyxpreamble += features.getBabelOptions();
1070         }
1071
1072         lyxpreamble += "\\makeatother\n";
1073
1074         // dvipost settings come after everything else
1075         if (tracking_changes) {
1076                 lyxpreamble +=
1077                         "\\dvipostlayout\n"
1078                         "\\dvipost{osstart color push Red}\n"
1079                         "\\dvipost{osend color pop}\n"
1080                         "\\dvipost{cbstart color push Blue}\n"
1081                         "\\dvipost{cbend color pop}\n";
1082         }
1083
1084         int const nlines =
1085                 int(lyx::count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1086         for (int j = 0; j != nlines; ++j) {
1087                 texrow.newline();
1088         }
1089
1090         os << lyxpreamble;
1091         return use_babel;
1092 }
1093
1094 void BufferParams::setPaperStuff()
1095 {
1096         papersize = PAPER_DEFAULT;
1097         char const c1 = paperpackage;
1098         if (c1 == PACKAGE_NONE) {
1099                 char const c2 = papersize2;
1100                 if (c2 == VM_PAPER_USLETTER)
1101                         papersize = PAPER_USLETTER;
1102                 else if (c2 == VM_PAPER_USLEGAL)
1103                         papersize = PAPER_LEGALPAPER;
1104                 else if (c2 == VM_PAPER_USEXECUTIVE)
1105                         papersize = PAPER_EXECUTIVEPAPER;
1106                 else if (c2 == VM_PAPER_A3)
1107                         papersize = PAPER_A3PAPER;
1108                 else if (c2 == VM_PAPER_A4)
1109                         papersize = PAPER_A4PAPER;
1110                 else if (c2 == VM_PAPER_A5)
1111                         papersize = PAPER_A5PAPER;
1112                 else if ((c2 == VM_PAPER_B3) || (c2 == VM_PAPER_B4) ||
1113                          (c2 == VM_PAPER_B5))
1114                         papersize = PAPER_B5PAPER;
1115         } else if ((c1 == PACKAGE_A4) || (c1 == PACKAGE_A4WIDE) ||
1116                    (c1 == PACKAGE_WIDEMARGINSA4))
1117                 papersize = PAPER_A4PAPER;
1118 }
1119
1120
1121 void BufferParams::useClassDefaults()
1122 {
1123         LyXTextClass const & tclass = textclasslist[textclass];
1124
1125         sides = tclass.sides();
1126         columns = tclass.columns();
1127         pagestyle = tclass.pagestyle();
1128         options = tclass.options();
1129         secnumdepth = tclass.secnumdepth();
1130         tocdepth = tclass.tocdepth();
1131 }
1132
1133
1134 bool BufferParams::hasClassDefaults() const
1135 {
1136         LyXTextClass const & tclass = textclasslist[textclass];
1137
1138         return (sides == tclass.sides()
1139                 && columns == tclass.columns()
1140                 && pagestyle == tclass.pagestyle()
1141                 && options == tclass.options()
1142                 && secnumdepth == tclass.secnumdepth()
1143                 && tocdepth == tclass.tocdepth());
1144 }
1145
1146
1147 LyXTextClass const & BufferParams::getLyXTextClass() const
1148 {
1149         return textclasslist[textclass];
1150 }
1151
1152
1153 void BufferParams::readPreamble(LyXLex & lex)
1154 {
1155         if (lex.getString() != "\\begin_preamble")
1156                 lyxerr << "Error (BufferParams::readPreamble):"
1157                         "consistency check failed." << endl;
1158
1159         preamble = lex.getLongString("\\end_preamble");
1160 }
1161
1162
1163 void BufferParams::readLanguage(LyXLex & lex)
1164 {
1165         if (!lex.next()) return;
1166
1167         string const tmptok = lex.getString();
1168
1169         // check if tmptok is part of tex_babel in tex-defs.h
1170         language = languages.getLanguage(tmptok);
1171         if (!language) {
1172                 // Language tmptok was not found
1173                 language = default_language;
1174                 lyxerr << "Warning: Setting language `"
1175                        << tmptok << "' to `" << language->lang()
1176                        << "'." << endl;
1177         }
1178 }
1179
1180
1181 void BufferParams::readGraphicsDriver(LyXLex & lex)
1182 {
1183         if (!lex.next()) return;
1184
1185         string const tmptok = lex.getString();
1186         // check if tmptok is part of tex_graphics in tex_defs.h
1187         int n = 0;
1188         while (true) {
1189                 string const test = tex_graphics[n++];
1190
1191                 if (test == tmptok) {
1192                         graphicsDriver = tmptok;
1193                         break;
1194                 } else if (test == "last_item") {
1195                         lex.printError(
1196                                 "Warning: graphics driver `$$Token' not recognized!\n"
1197                                 "         Setting graphics driver to `default'.\n");
1198                         graphicsDriver = "default";
1199                         break;
1200                 }
1201         }
1202 }
1203
1204
1205 void BufferParams::readBullets(LyXLex & lex)
1206 {
1207         if (!lex.next()) return;
1208
1209         int const index = lex.getInteger();
1210         lex.next();
1211         int temp_int = lex.getInteger();
1212         user_defined_bullet(index).setFont(temp_int);
1213         temp_bullet(index).setFont(temp_int);
1214         lex >> temp_int;
1215         user_defined_bullet(index).setCharacter(temp_int);
1216         temp_bullet(index).setCharacter(temp_int);
1217         lex >> temp_int;
1218         user_defined_bullet(index).setSize(temp_int);
1219         temp_bullet(index).setSize(temp_int);
1220 }
1221
1222
1223 void BufferParams::readBulletsLaTeX(LyXLex & lex)
1224 {
1225         // The bullet class should be able to read this.
1226         if (!lex.next()) return;
1227         int const index = lex.getInteger();
1228         lex.next(true);
1229         string temp_str = lex.getString();
1230
1231         user_defined_bullet(index).setText(temp_str);
1232         temp_bullet(index).setText(temp_str);
1233 }
1234
1235
1236 string const BufferParams::paperSizeName() const
1237 {
1238         char real_papersize = papersize;
1239         if (real_papersize == PAPER_DEFAULT)
1240                 real_papersize = lyxrc.default_papersize;
1241
1242         switch (real_papersize) {
1243         case PAPER_A3PAPER:
1244                 return "a3";
1245         case PAPER_A4PAPER:
1246                 return "a4";
1247         case PAPER_A5PAPER:
1248                 return "a5";
1249         case PAPER_B5PAPER:
1250                 return "b5";
1251         case PAPER_EXECUTIVEPAPER:
1252                 return "foolscap";
1253         case PAPER_LEGALPAPER:
1254                 return "legal";
1255         case PAPER_USLETTER:
1256         default:
1257                 return "letter";
1258         }
1259 }
1260
1261
1262 string const BufferParams::dvips_options() const
1263 {
1264         string result;
1265
1266         if (use_geometry
1267             && papersize2 == VM_PAPER_CUSTOM
1268             && !lyxrc.print_paper_dimension_flag.empty()
1269             && !paperwidth.empty()
1270             && !paperheight.empty()) {
1271                 // using a custom papersize
1272                 result = lyxrc.print_paper_dimension_flag;
1273                 result += ' ' + paperwidth;
1274                 result += ',' + paperheight;
1275         } else {
1276                 string const paper_option = paperSizeName();
1277                 if (paper_option != "letter" ||
1278                     orientation != ORIENTATION_LANDSCAPE) {
1279                         // dvips won't accept -t letter -t landscape.
1280                         // In all other cases, include the paper size
1281                         // explicitly.
1282                         result = lyxrc.print_paper_flag;
1283                         result += ' ' + paper_option;
1284                 }
1285         }
1286         if (orientation == ORIENTATION_LANDSCAPE &&
1287             papersize2 != VM_PAPER_CUSTOM)
1288                 result += ' ' + lyxrc.print_landscape_flag;
1289         return result;
1290 }
1291
1292
1293 string const BufferParams::babelCall(string const & lang_opts) const
1294 {
1295         string tmp = lyxrc.language_package;
1296         if (!lyxrc.language_global_options && tmp == "\\usepackage{babel}")
1297                 tmp = string("\\usepackage[") + lang_opts + "]{babel}";
1298         return tmp;
1299 }