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