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