]> git.lyx.org Git - lyx.git/blob - src/bufferparams.C
split out header parsing
[lyx.git] / src / bufferparams.C
1 /* This file is part of
2  * ======================================================
3  *
4  *           LyX, The Document Processor
5  *
6  *           Copyright 1995 Matthias Ettrich
7  *           Copyright 1995-2001 The LyX Team.
8  *
9  * ====================================================== */
10
11 #include <config.h>
12
13 #include "bufferparams.h"
14 #include "tex-strings.h"
15 #include "encoding.h"
16 #include "layout.h"
17 #include "vspace.h"
18 #include "debug.h"
19 #include "lyxrc.h"
20 #include "language.h"
21 #include "lyxtextclasslist.h"
22 #include "lyxlex.h"
23 #include "Lsstream.h"
24 #include "author.h"
25
26 #include "support/lyxalgo.h" // for lyx::count
27 #include "support/lyxlib.h"
28 #include "support/lstrings.h"
29 #include "support/types.h"
30
31 #include <cstdlib>
32 #include <algorithm>
33
34 using std::ostream;
35 using std::endl;
36 using std::pair;
37
38 #ifdef WITH_WARNINGS
39 #warning Do we need this horrible thing? (JMarc)
40 #endif
41 bool use_babel;
42
43 BufferParams::BufferParams()
44         // Initialize textclass to point to article. if `first' is
45         // true in the returned pair, then `second' is the textclass
46         // number; if it is false, second is 0. In both cases, second
47         // is what we want.
48         : textclass(textclasslist.NumberOfClass("article").second)
49 {
50         paragraph_separation = PARSEP_INDENT;
51         defskip = VSpace(VSpace::MEDSKIP);
52         quotes_language = InsetQuotes::EnglishQ;
53         quotes_times = InsetQuotes::DoubleQ;
54         fontsize = "default";
55
56         /*  PaperLayout */
57         papersize = PAPER_DEFAULT;
58         papersize2 = VM_PAPER_DEFAULT; /* DEFAULT */
59         paperpackage = PACKAGE_NONE;
60         orientation = ORIENTATION_PORTRAIT;
61         use_geometry = false;
62         use_amsmath = AMS_AUTO;
63         use_natbib = false;
64         use_numerical_citations = false;
65         tracking_changes = false;
66         secnumdepth = 3;
67         tocdepth = 3;
68         language = default_language;
69         fonts = "default";
70         inputenc = "auto";
71         graphicsDriver = "default";
72         sides = LyXTextClass::OneSide;
73         columns = 1;
74         pagestyle = "default";
75         for (int iter = 0; iter < 4; ++iter) {
76                 user_defined_bullets[iter] = ITEMIZE_DEFAULTS[iter];
77                 temp_bullets[iter] = ITEMIZE_DEFAULTS[iter];
78         }
79 }
80
81
82 string const BufferParams::readToken(LyXLex & lex, string const & token)
83 {
84         if (token == "\\textclass") {
85                 lex.eatLine();
86                 string const classname = lex.getString();
87                 pair<bool, lyx::textclass_type> pp =
88                         textclasslist.NumberOfClass(classname);
89                 if (pp.first) {
90                         textclass = pp.second;
91                 } else {
92                         textclass = 0;
93                         return classname;
94                 }
95         } else if (token == "\\begin_preamble") {
96                 readPreamble(lex);
97         } else if (token == "\\options") {
98                 lex.eatLine();
99                 options = lex.getString();
100         } else if (token == "\\language") {
101                 readLanguage(lex);
102         } else if (token == "\\inputencoding") {
103                 lex.eatLine();
104                 inputenc = lex.getString();
105         } else if (token == "\\graphics") {
106                 readGraphicsDriver(lex);
107         } else if (token == "\\fontscheme") {
108                 lex.eatLine();
109                 fonts = lex.getString();
110         } else if (token == "\\paragraph_separation") {
111                 int tmpret = lex.findToken(string_paragraph_separation);
112                 if (tmpret == -1)
113                         ++tmpret;
114                 paragraph_separation =
115                         static_cast<BufferParams::PARSEP>(tmpret);
116         } else if (token == "\\defskip") {
117                 lex.nextToken();
118                 defskip = VSpace(lex.getString());
119         } else if (token == "\\quotes_language") {
120                 // FIXME: should be params.readQuotes()
121                 int tmpret = lex.findToken(string_quotes_language);
122                 if (tmpret == -1)
123                         ++tmpret;
124                 InsetQuotes::quote_language tmpl =
125                         InsetQuotes::EnglishQ;
126                 switch (tmpret) {
127                 case 0:
128                         tmpl = InsetQuotes::EnglishQ;
129                         break;
130                 case 1:
131                         tmpl = InsetQuotes::SwedishQ;
132                         break;
133                 case 2:
134                         tmpl = InsetQuotes::GermanQ;
135                         break;
136                 case 3:
137                         tmpl = InsetQuotes::PolishQ;
138                         break;
139                 case 4:
140                         tmpl = InsetQuotes::FrenchQ;
141                         break;
142                 case 5:
143                         tmpl = InsetQuotes::DanishQ;
144                         break;
145                 }
146                 quotes_language = tmpl;
147         } else if (token == "\\quotes_times") {
148                 // FIXME: should be params.readQuotes()
149                 lex.nextToken();
150                 switch (lex.getInteger()) {
151                 case 1:
152                         quotes_times = InsetQuotes::SingleQ;
153                         break;
154                 case 2:
155                         quotes_times = InsetQuotes::DoubleQ;
156                         break;
157                 }
158         } else if (token == "\\papersize") {
159                 int tmpret = lex.findToken(string_papersize);
160                 if (tmpret == -1)
161                         ++tmpret;
162                 else
163                         papersize2 = tmpret;
164         } else if (token == "\\paperpackage") {
165                 int tmpret = lex.findToken(string_paperpackages);
166                 if (tmpret == -1) {
167                         ++tmpret;
168                         paperpackage = BufferParams::PACKAGE_NONE;
169                 } else
170                         paperpackage = tmpret;
171         } else if (token == "\\use_geometry") {
172                 lex.nextToken();
173                 use_geometry = lex.getInteger();
174         } else if (token == "\\use_amsmath") {
175                 lex.nextToken();
176                 use_amsmath = static_cast<BufferParams::AMS>(
177                         lex.getInteger());
178         } else if (token == "\\use_natbib") {
179                 lex.nextToken();
180                 use_natbib = lex.getInteger();
181         } else if (token == "\\use_numerical_citations") {
182                 lex.nextToken();
183                 use_numerical_citations = lex.getInteger();
184         } else if (token == "\\tracking_changes") {
185                 lex.nextToken();
186                 tracking_changes = lex.getInteger();
187         } else if (token == "\\author") {
188                 lex.nextToken();
189                 istringstream ss(lex.getString());
190                 Author a;
191                 ss >> a;
192                 int aid(authorlist.record(a));
193                 author_ids.push_back(aid);
194         } else if (token == "\\paperorientation") {
195                 int tmpret = lex.findToken(string_orientation);
196                 if (tmpret == -1)
197                         ++tmpret;
198                 orientation =
199                         static_cast<BufferParams::PAPER_ORIENTATION>(tmpret);
200         } else if (token == "\\paperwidth") {
201                 lex.next();
202                 paperwidth = lex.getString();
203         } else if (token == "\\paperheight") {
204                 lex.next();
205                 paperheight = lex.getString();
206         } else if (token == "\\leftmargin") {
207                 lex.next();
208                 leftmargin = lex.getString();
209         } else if (token == "\\topmargin") {
210                 lex.next();
211                 topmargin = lex.getString();
212         } else if (token == "\\rightmargin") {
213                 lex.next();
214                 rightmargin = lex.getString();
215         } else if (token == "\\bottommargin") {
216                 lex.next();
217                 bottommargin = lex.getString();
218         } else if (token == "\\headheight") {
219                 lex.next();
220                 headheight = lex.getString();
221         } else if (token == "\\headsep") {
222                 lex.next();
223                 headsep = lex.getString();
224         } else if (token == "\\footskip") {
225                 lex.next();
226                 footskip = lex.getString();
227         } else if (token == "\\paperfontsize") {
228                 lex.nextToken();
229                 fontsize = rtrim(lex.getString());
230         } else if (token == "\\papercolumns") {
231                 lex.nextToken();
232                 columns = lex.getInteger();
233         } else if (token == "\\papersides") {
234                 lex.nextToken();
235                 switch (lex.getInteger()) {
236                 default:
237                 case 1: sides = LyXTextClass::OneSide; break;
238                 case 2: sides = LyXTextClass::TwoSides; break;
239                 }
240         } else if (token == "\\paperpagestyle") {
241                 lex.nextToken();
242                 pagestyle = rtrim(lex.getString());
243         } else if (token == "\\bullet") {
244                 // FIXME: should be params.readBullets()
245                 lex.nextToken();
246                 int const index = lex.getInteger();
247                 lex.nextToken();
248                 int temp_int = lex.getInteger();
249                 user_defined_bullets[index].setFont(temp_int);
250                 temp_bullets[index].setFont(temp_int);
251                 lex.nextToken();
252                 temp_int = lex.getInteger();
253                 user_defined_bullets[index].setCharacter(temp_int);
254                 temp_bullets[index].setCharacter(temp_int);
255                 lex.nextToken();
256                 temp_int = lex.getInteger();
257                 user_defined_bullets[index].setSize(temp_int);
258                 temp_bullets[index].setSize(temp_int);
259                 lex.nextToken();
260                 string const temp_str = lex.getString();
261                 if (temp_str != "\\end_bullet") {
262                                 // this element isn't really necessary for
263                                 // parsing but is easier for humans
264                                 // to understand bullets. Put it back and
265                                 // set a debug message?
266                         lex.printError("\\end_bullet expected, got" + temp_str);
267                                 //how can I put it back?
268                 }
269         } else if (token == "\\bulletLaTeX") {
270                 // The bullet class should be able to read this.
271                 lex.nextToken();
272                 int const index = lex.getInteger();
273                 lex.next();
274                 string temp_str = lex.getString();
275                 string sum_str;
276                 while (temp_str != "\\end_bullet") {
277                                 // this loop structure is needed when user
278                                 // enters an empty string since the first
279                                 // thing returned will be the \\end_bullet
280                                 // OR
281                                 // if the LaTeX entry has spaces. Each element
282                                 // therefore needs to be read in turn
283                         sum_str += temp_str;
284                         lex.next();
285                         temp_str = lex.getString();
286                 }
287
288                 user_defined_bullets[index].setText(sum_str);
289                 temp_bullets[index].setText(sum_str);
290         } else if (token == "\\secnumdepth") {
291                 lex.nextToken();
292                 secnumdepth = lex.getInteger();
293         } else if (token == "\\tocdepth") {
294                 lex.nextToken();
295                 tocdepth = lex.getInteger();
296         } else if (token == "\\spacing") {
297                 lex.next();
298                 string const tmp = rtrim(lex.getString());
299                 Spacing::Space tmp_space = Spacing::Default;
300                 float tmp_val = 0.0;
301                 if (tmp == "single") {
302                         tmp_space = Spacing::Single;
303                 } else if (tmp == "onehalf") {
304                         tmp_space = Spacing::Onehalf;
305                 } else if (tmp == "double") {
306                         tmp_space = Spacing::Double;
307                 } else if (tmp == "other") {
308                         lex.next();
309                         tmp_space = Spacing::Other;
310                         tmp_val = lex.getFloat();
311                 } else {
312                         lex.printError("Unknown spacing token: '$$Token'");
313                 }
314 #if 0 // FIXME: Handled in lyx2lyx ?
315                 // Small hack so that files written with klyx will be
316                 // parsed correctly.
317                 if (first_par)
318                         par->params().spacing(Spacing(tmp_space, tmp_val));
319 #endif
320                 spacing.set(tmp_space, tmp_val);
321         } else if (token == "\\float_placement") {
322                 lex.nextToken();
323                 float_placement = lex.getString();
324         } else {
325                 return token;
326         }
327
328         return string();
329 }
330
331
332 void BufferParams::writeFile(ostream & os) const
333 {
334         // The top of the file is written by the buffer.
335         // Prints out the buffer info into the .lyx file given by file
336
337         // the textclass
338         os << "\\textclass " << textclasslist[textclass].name() << '\n';
339
340         // then the the preamble
341         if (!preamble.empty()) {
342                 // remove '\n' from the end of preamble
343                 string const tmppreamble = rtrim(preamble, "\n");
344                 os << "\\begin_preamble\n"
345                    << tmppreamble
346                    << "\n\\end_preamble\n";
347         }
348
349         /* the options */
350         if (!options.empty()) {
351                 os << "\\options " << options << '\n';
352         }
353
354         /* then the text parameters */
355         if (language != ignore_language)
356                 os << "\\language " << language->lang() << '\n';
357         os << "\\inputencoding " << inputenc
358            << "\n\\fontscheme " << fonts
359            << "\n\\graphics " << graphicsDriver << '\n';
360
361         if (!float_placement.empty()) {
362                 os << "\\float_placement " << float_placement << '\n';
363         }
364         os << "\\paperfontsize " << fontsize << '\n';
365
366         spacing.writeFile(os);
367
368         os << "\\papersize " << string_papersize[papersize2]
369            << "\n\\paperpackage " << string_paperpackages[paperpackage]
370            << "\n\\use_geometry " << use_geometry
371            << "\n\\use_amsmath " << use_amsmath
372            << "\n\\use_natbib " << use_natbib
373            << "\n\\use_numerical_citations " << use_numerical_citations
374            << "\n\\paperorientation " << string_orientation[orientation]
375            << '\n';
376         if (!paperwidth.empty())
377                 os << "\\paperwidth "
378                    << VSpace(paperwidth).asLyXCommand() << '\n';
379         if (!paperheight.empty())
380                 os << "\\paperheight "
381                    << VSpace(paperheight).asLyXCommand() << '\n';
382         if (!leftmargin.empty())
383                 os << "\\leftmargin "
384                    << VSpace(leftmargin).asLyXCommand() << '\n';
385         if (!topmargin.empty())
386                 os << "\\topmargin "
387                    << VSpace(topmargin).asLyXCommand() << '\n';
388         if (!rightmargin.empty())
389                 os << "\\rightmargin "
390                    << VSpace(rightmargin).asLyXCommand() << '\n';
391         if (!bottommargin.empty())
392                 os << "\\bottommargin "
393                    << VSpace(bottommargin).asLyXCommand() << '\n';
394         if (!headheight.empty())
395                 os << "\\headheight "
396                    << VSpace(headheight).asLyXCommand() << '\n';
397         if (!headsep.empty())
398                 os << "\\headsep "
399                    << VSpace(headsep).asLyXCommand() << '\n';
400         if (!footskip.empty())
401                 os << "\\footskip "
402                    << VSpace(footskip).asLyXCommand() << '\n';
403         os << "\\secnumdepth " << secnumdepth
404            << "\n\\tocdepth " << tocdepth
405            << "\n\\paragraph_separation "
406            << string_paragraph_separation[paragraph_separation]
407            << "\n\\defskip " << defskip.asLyXCommand()
408            << "\n\\quotes_language "
409            << string_quotes_language[quotes_language] << '\n';
410         switch (quotes_times) {
411                 // An output operator for insetquotes would be nice
412         case InsetQuotes::SingleQ:
413                 os << "\\quotes_times 1\n"; break;
414         case InsetQuotes::DoubleQ:
415                 os << "\\quotes_times 2\n"; break;
416         }
417         os << "\\papercolumns " << columns
418            << "\n\\papersides " << sides
419            << "\n\\paperpagestyle " << pagestyle << '\n';
420         for (int i = 0; i < 4; ++i) {
421                 if (user_defined_bullets[i] != ITEMIZE_DEFAULTS[i]) {
422                         if (user_defined_bullets[i].getFont() != -1) {
423                                 os << "\\bullet " << i
424                                    << "\n\t"
425                                    << user_defined_bullets[i].getFont()
426                                    << "\n\t"
427                                    << user_defined_bullets[i].getCharacter()
428                                    << "\n\t"
429                                    << user_defined_bullets[i].getSize()
430                                    << "\n\\end_bullet\n";
431                         }
432                         else {
433                                 os << "\\bulletLaTeX " << i
434                                    << "\n\t\""
435                                    << user_defined_bullets[i].getText()
436                                    << "\"\n\\end_bullet\n";
437                         }
438                 }
439         }
440
441         os << "\\tracking_changes " << tracking_changes << "\n";
442
443         if (tracking_changes) {
444                 AuthorList::Authors::const_iterator it = authorlist.begin();
445                 AuthorList::Authors::const_iterator end = authorlist.end();
446                 for (; it != end; ++it) {
447                         os << "\\author " << it->second << "\n";
448                 }
449         }
450 }
451
452
453 void BufferParams::writeLaTeX(ostream & os, LaTeXFeatures & features,
454                               TexRow & texrow) const
455 {
456         os << "\\documentclass";
457
458         LyXTextClass const & tclass = getLyXTextClass();
459
460         ostringstream clsoptions; // the document class options.
461
462         if (tokenPos(tclass.opt_fontsize(),
463                      '|', fontsize) >= 0) {
464                 // only write if existing in list (and not default)
465                 clsoptions << fontsize << "pt,";
466         }
467
468
469         if (!use_geometry &&
470             (paperpackage == PACKAGE_NONE)) {
471                 switch (papersize) {
472                 case PAPER_A4PAPER:
473                         clsoptions << "a4paper,";
474                         break;
475                 case PAPER_USLETTER:
476                         clsoptions << "letterpaper,";
477                         break;
478                 case PAPER_A5PAPER:
479                         clsoptions << "a5paper,";
480                         break;
481                 case PAPER_B5PAPER:
482                         clsoptions << "b5paper,";
483                         break;
484                 case PAPER_EXECUTIVEPAPER:
485                         clsoptions << "executivepaper,";
486                         break;
487                 case PAPER_LEGALPAPER:
488                         clsoptions << "legalpaper,";
489                         break;
490                 }
491         }
492
493         // if needed
494         if (sides != tclass.sides()) {
495                 switch (sides) {
496                 case LyXTextClass::OneSide:
497                         clsoptions << "oneside,";
498                         break;
499                 case LyXTextClass::TwoSides:
500                         clsoptions << "twoside,";
501                         break;
502                 }
503         }
504
505         // if needed
506         if (columns != tclass.columns()) {
507                 if (columns == 2)
508                         clsoptions << "twocolumn,";
509                 else
510                         clsoptions << "onecolumn,";
511         }
512
513         if (!use_geometry
514             && orientation == ORIENTATION_LANDSCAPE)
515                 clsoptions << "landscape,";
516
517         // language should be a parameter to \documentclass
518         use_babel = false;
519         ostringstream language_options;
520         if (language->babel() == "hebrew"
521             && default_language->babel() != "hebrew")
522                 // This seems necessary
523                 features.useLanguage(default_language);
524
525         if (lyxrc.language_use_babel ||
526             language->lang() != lyxrc.default_language ||
527             features.hasLanguages()) {
528                 use_babel = true;
529                 language_options << features.getLanguages();
530                 language_options << language->babel();
531                 if (lyxrc.language_global_options)
532                         clsoptions << language_options.str() << ',';
533         }
534
535         // the user-defined options
536         if (!options.empty()) {
537                 clsoptions << options << ',';
538         }
539
540         string strOptions(STRCONV(clsoptions.str()));
541         if (!strOptions.empty()) {
542                 strOptions = rtrim(strOptions, ",");
543                 os << '[' << strOptions << ']';
544         }
545
546         os << '{' << tclass.latexname() << "}\n";
547         texrow.newline();
548         // end of \documentclass defs
549
550         // font selection must be done before loading fontenc.sty
551         // The ae package is not needed when using OT1 font encoding.
552         if (fonts != "default" &&
553             (fonts != "ae" || lyxrc.fontenc != "default")) {
554                 os << "\\usepackage{" << fonts << "}\n";
555                 texrow.newline();
556                 if (fonts == "ae") {
557                         os << "\\usepackage{aecompl}\n";
558                         texrow.newline();
559                 }
560         }
561         // this one is not per buffer
562         if (lyxrc.fontenc != "default") {
563                 os << "\\usepackage[" << lyxrc.fontenc
564                    << "]{fontenc}\n";
565                 texrow.newline();
566         }
567
568         if (inputenc == "auto") {
569                 string const doc_encoding =
570                         language->encoding()->LatexName();
571
572                 // Create a list with all the input encodings used
573                 // in the document
574                 std::set<string> encodings =
575                         features.getEncodingSet(doc_encoding);
576
577                 os << "\\usepackage[";
578                 std::copy(encodings.begin(), encodings.end(),
579                           std::ostream_iterator<string>(os, ","));
580                 os << doc_encoding << "]{inputenc}\n";
581                 texrow.newline();
582         } else if (inputenc != "default") {
583                 os << "\\usepackage[" << inputenc
584                    << "]{inputenc}\n";
585                 texrow.newline();
586         }
587
588         // At the very beginning the text parameters.
589         if (paperpackage != PACKAGE_NONE) {
590                 switch (paperpackage) {
591                 case PACKAGE_A4:
592                         os << "\\usepackage{a4}\n";
593                         texrow.newline();
594                         break;
595                 case PACKAGE_A4WIDE:
596                         os << "\\usepackage{a4wide}\n";
597                         texrow.newline();
598                         break;
599                 case PACKAGE_WIDEMARGINSA4:
600                         os << "\\usepackage[widemargins]{a4}\n";
601                         texrow.newline();
602                         break;
603                 }
604         }
605         if (use_geometry) {
606                 os << "\\usepackage{geometry}\n";
607                 texrow.newline();
608                 os << "\\geometry{verbose";
609                 if (orientation == ORIENTATION_LANDSCAPE)
610                         os << ",landscape";
611                 switch (papersize2) {
612                 case VM_PAPER_CUSTOM:
613                         if (!paperwidth.empty())
614                                 os << ",paperwidth="
615                                    << paperwidth;
616                         if (!paperheight.empty())
617                                 os << ",paperheight="
618                                    << paperheight;
619                         break;
620                 case VM_PAPER_USLETTER:
621                         os << ",letterpaper";
622                         break;
623                 case VM_PAPER_USLEGAL:
624                         os << ",legalpaper";
625                         break;
626                 case VM_PAPER_USEXECUTIVE:
627                         os << ",executivepaper";
628                         break;
629                 case VM_PAPER_A3:
630                         os << ",a3paper";
631                         break;
632                 case VM_PAPER_A4:
633                         os << ",a4paper";
634                         break;
635                 case VM_PAPER_A5:
636                         os << ",a5paper";
637                         break;
638                 case VM_PAPER_B3:
639                         os << ",b3paper";
640                         break;
641                 case VM_PAPER_B4:
642                         os << ",b4paper";
643                         break;
644                 case VM_PAPER_B5:
645                         os << ",b5paper";
646                         break;
647                 default:
648                                 // default papersize ie VM_PAPER_DEFAULT
649                         switch (lyxrc.default_papersize) {
650                         case PAPER_DEFAULT: // keep compiler happy
651                         case PAPER_USLETTER:
652                                 os << ",letterpaper";
653                                 break;
654                         case PAPER_LEGALPAPER:
655                                 os << ",legalpaper";
656                                 break;
657                         case PAPER_EXECUTIVEPAPER:
658                                 os << ",executivepaper";
659                                 break;
660                         case PAPER_A3PAPER:
661                                 os << ",a3paper";
662                                 break;
663                         case PAPER_A4PAPER:
664                                 os << ",a4paper";
665                                 break;
666                         case PAPER_A5PAPER:
667                                 os << ",a5paper";
668                                 break;
669                         case PAPER_B5PAPER:
670                                 os << ",b5paper";
671                                 break;
672                         }
673                 }
674                 if (!topmargin.empty())
675                         os << ",tmargin=" << topmargin;
676                 if (!bottommargin.empty())
677                         os << ",bmargin=" << bottommargin;
678                 if (!leftmargin.empty())
679                         os << ",lmargin=" << leftmargin;
680                 if (!rightmargin.empty())
681                         os << ",rmargin=" << rightmargin;
682                 if (!headheight.empty())
683                         os << ",headheight=" << headheight;
684                 if (!headsep.empty())
685                         os << ",headsep=" << headsep;
686                 if (!footskip.empty())
687                         os << ",footskip=" << footskip;
688                 os << "}\n";
689                 texrow.newline();
690         }
691
692         if (tokenPos(tclass.opt_pagestyle(),
693                      '|', pagestyle) >= 0) {
694                 if (pagestyle == "fancy") {
695                         os << "\\usepackage{fancyhdr}\n";
696                         texrow.newline();
697                 }
698                 os << "\\pagestyle{" << pagestyle << "}\n";
699                 texrow.newline();
700         }
701
702         if (secnumdepth != tclass.secnumdepth()) {
703                 os << "\\setcounter{secnumdepth}{"
704                    << secnumdepth
705                    << "}\n";
706                 texrow.newline();
707         }
708         if (tocdepth != tclass.tocdepth()) {
709                 os << "\\setcounter{tocdepth}{"
710                    << tocdepth
711                    << "}\n";
712                 texrow.newline();
713         }
714
715         if (paragraph_separation) {
716                 switch (defskip.kind()) {
717                 case VSpace::SMALLSKIP:
718                         os << "\\setlength\\parskip{\\smallskipamount}\n";
719                         break;
720                 case VSpace::MEDSKIP:
721                         os << "\\setlength\\parskip{\\medskipamount}\n";
722                         break;
723                 case VSpace::BIGSKIP:
724                         os << "\\setlength\\parskip{\\bigskipamount}\n";
725                         break;
726                 case VSpace::LENGTH:
727                         os << "\\setlength\\parskip{"
728                            << defskip.length().asLatexString()
729                            << "}\n";
730                         break;
731                 default: // should never happen // Then delete it.
732                         os << "\\setlength\\parskip{\\medskipamount}\n";
733                         break;
734                 }
735                 texrow.newline();
736
737                 os << "\\setlength\\parindent{0pt}\n";
738                 texrow.newline();
739         }
740
741         // Now insert the LyX specific LaTeX commands...
742
743         // The optional packages;
744         string lyxpreamble(features.getPackages());
745
746         // this might be useful...
747         lyxpreamble += "\n\\makeatletter\n";
748
749         // Some macros LyX will need
750         string tmppreamble(features.getMacros());
751
752         if (!tmppreamble.empty()) {
753                 lyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
754                         "LyX specific LaTeX commands.\n"
755                         + tmppreamble + '\n';
756         }
757
758         // the text class specific preamble
759         tmppreamble = features.getTClassPreamble();
760         if (!tmppreamble.empty()) {
761                 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
762                         "Textclass specific LaTeX commands.\n"
763                         + tmppreamble + '\n';
764         }
765
766         /* the user-defined preamble */
767         if (!preamble.empty()) {
768                 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
769                         "User specified LaTeX commands.\n"
770                         + preamble + '\n';
771         }
772
773         // Itemize bullet settings need to be last in case the user
774         // defines their own bullets that use a package included
775         // in the user-defined preamble -- ARRae
776         // Actually it has to be done much later than that
777         // since some packages like frenchb make modifications
778         // at \begin{document} time -- JMarc
779         string bullets_def;
780         for (int i = 0; i < 4; ++i) {
781                 if (user_defined_bullets[i] != ITEMIZE_DEFAULTS[i]) {
782                         if (bullets_def.empty())
783                                 bullets_def="\\AtBeginDocument{\n";
784                         bullets_def += "  \\renewcommand{\\labelitemi";
785                         switch (i) {
786                                 // `i' is one less than the item to modify
787                         case 0:
788                                 break;
789                         case 1:
790                                 bullets_def += 'i';
791                                 break;
792                         case 2:
793                                 bullets_def += "ii";
794                                 break;
795                         case 3:
796                                 bullets_def += 'v';
797                                 break;
798                         }
799                         bullets_def += "}{" +
800                                 user_defined_bullets[i].getText()
801                                 + "}\n";
802                 }
803         }
804
805         if (!bullets_def.empty())
806                 lyxpreamble += bullets_def + "}\n\n";
807
808         // We try to load babel late, in case it interferes
809         // with other packages.
810         if (use_babel) {
811                 string tmp = lyxrc.language_package;
812                 if (!lyxrc.language_global_options
813                     && tmp == "\\usepackage{babel}")
814                         tmp = string("\\usepackage[") +
815                                 STRCONV(language_options.str()) +
816                                 "]{babel}";
817                 lyxpreamble += tmp + "\n";
818                 lyxpreamble += features.getBabelOptions();
819         }
820
821         lyxpreamble += "\\makeatother\n";
822
823         // dvipost settings come after everything else
824         if (tracking_changes) {
825                 lyxpreamble +=
826                         "\\dvipostlayout\n"
827                         "\\dvipost{osstart color push Red}\n"
828                         "\\dvipost{osend color pop}\n"
829                         "\\dvipost{cbstart color push Blue}\n"
830                         "\\dvipost{cbend color pop} \n";
831         }
832
833         int const nlines =
834                 int(lyx::count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
835         for (int j = 0; j != nlines; ++j) {
836                 texrow.newline();
837         }
838
839         os << lyxpreamble;
840 }
841
842 void BufferParams::setPaperStuff()
843 {
844         papersize = PAPER_DEFAULT;
845         char const c1 = paperpackage;
846         if (c1 == PACKAGE_NONE) {
847                 char const c2 = papersize2;
848                 if (c2 == VM_PAPER_USLETTER)
849                         papersize = PAPER_USLETTER;
850                 else if (c2 == VM_PAPER_USLEGAL)
851                         papersize = PAPER_LEGALPAPER;
852                 else if (c2 == VM_PAPER_USEXECUTIVE)
853                         papersize = PAPER_EXECUTIVEPAPER;
854                 else if (c2 == VM_PAPER_A3)
855                         papersize = PAPER_A3PAPER;
856                 else if (c2 == VM_PAPER_A4)
857                         papersize = PAPER_A4PAPER;
858                 else if (c2 == VM_PAPER_A5)
859                         papersize = PAPER_A5PAPER;
860                 else if ((c2 == VM_PAPER_B3) || (c2 == VM_PAPER_B4) ||
861                          (c2 == VM_PAPER_B5))
862                         papersize = PAPER_B5PAPER;
863         } else if ((c1 == PACKAGE_A4) || (c1 == PACKAGE_A4WIDE) ||
864                    (c1 == PACKAGE_WIDEMARGINSA4))
865                 papersize = PAPER_A4PAPER;
866 }
867
868
869 void BufferParams::useClassDefaults()
870 {
871         LyXTextClass const & tclass = textclasslist[textclass];
872
873         sides = tclass.sides();
874         columns = tclass.columns();
875         pagestyle = tclass.pagestyle();
876         options = tclass.options();
877         secnumdepth = tclass.secnumdepth();
878         tocdepth = tclass.tocdepth();
879 }
880
881
882 bool BufferParams::hasClassDefaults() const
883 {
884         LyXTextClass const & tclass = textclasslist[textclass];
885
886         return (sides == tclass.sides()
887                 && columns == tclass.columns()
888                 && pagestyle == tclass.pagestyle()
889                 && options == tclass.options()
890                 && secnumdepth == tclass.secnumdepth()
891                 && tocdepth == tclass.tocdepth());
892 }
893
894
895 LyXTextClass const & BufferParams::getLyXTextClass() const
896 {
897         return textclasslist[textclass];
898 }
899
900
901 void BufferParams::readPreamble(LyXLex & lex)
902 {
903         if (lex.getString() != "\\begin_preamble")
904                 lyxerr << "Error (BufferParams::readPreamble):"
905                         "consistency check failed." << endl;
906
907         preamble = lex.getLongString("\\end_preamble");
908 }
909
910
911 void BufferParams::readLanguage(LyXLex & lex)
912 {
913         if (!lex.next()) return;
914
915         string const tmptok = lex.getString();
916
917         // check if tmptok is part of tex_babel in tex-defs.h
918         language = languages.getLanguage(tmptok);
919         if (!language) {
920                 // Language tmptok was not found
921                 language = default_language;
922                 lyxerr << "Warning: Setting language `"
923                        << tmptok << "' to `" << language->lang()
924                        << "'." << endl;
925         }
926 }
927
928
929 void BufferParams::readGraphicsDriver(LyXLex & lex)
930 {
931         if (!lex.next()) return;
932
933         string const tmptok = lex.getString();
934         // check if tmptok is part of tex_graphics in tex_defs.h
935         int n = 0;
936         while (true) {
937                 string const test = tex_graphics[n++];
938
939                 if (test == tmptok) {
940                         graphicsDriver = tmptok;
941                         break;
942                 } else if (test == "last_item") {
943                         lex.printError(
944                                 "Warning: graphics driver `$$Token' not recognized!\n"
945                                 "         Setting graphics driver to `default'.\n");
946                         graphicsDriver = "default";
947                         break;
948                 }
949         }
950 }