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