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