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