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