]> git.lyx.org Git - lyx.git/blob - src/bufferparams.C
remove LFUN_TOOLTIPS_TOGGLE and associated Dialog::tooltipsEnabled() method.
[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         trackChanges = false;
304         outputChanges = 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 >> trackChanges;
494         } else if (token == "\\output_changes") {
495                 lex >> outputChanges;
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>(trackChanges) << "\n";
703         os << "\\output_changes " << convert<string>(outputChanges) << "\n";
704
705         if (trackChanges) {
706                 // FIXME: Change tracking (MG)
707                 AuthorList::Authors::const_iterator it = pimpl_->authorlist.begin();
708                 AuthorList::Authors::const_iterator end = pimpl_->authorlist.end();
709                 for (; it != end; ++it) {
710                         os << "\\author " << it->second << "\n";
711                 }
712         }
713 }
714
715
716 bool BufferParams::writeLaTeX(ostream & os, LaTeXFeatures & features,
717                               TexRow & texrow) const
718 {
719         os << "\\documentclass";
720
721         LyXTextClass const & tclass = getLyXTextClass();
722
723         ostringstream clsoptions; // the document class options.
724
725         if (tokenPos(tclass.opt_fontsize(),
726                      '|', fontsize) >= 0) {
727                 // only write if existing in list (and not default)
728                 clsoptions << fontsize << "pt,";
729         }
730
731         // custom, A3, B3 and B4 paper sizes need geometry
732         bool nonstandard_papersize = (papersize == PAPER_B3) ||
733                                      (papersize == PAPER_B4) ||
734                                      (papersize == PAPER_A3) ||
735                                      (papersize == PAPER_CUSTOM);
736
737         if (!use_geometry) {
738                 switch (papersize) {
739                 case PAPER_A4:
740                         clsoptions << "a4paper,";
741                         break;
742                 case PAPER_USLETTER:
743                         clsoptions << "letterpaper,";
744                         break;
745                 case PAPER_A5:
746                         clsoptions << "a5paper,";
747                         break;
748                 case PAPER_B5:
749                         clsoptions << "b5paper,";
750                         break;
751                 case PAPER_USEXECUTIVE:
752                         clsoptions << "executivepaper,";
753                         break;
754                 case PAPER_USLEGAL:
755                         clsoptions << "legalpaper,";
756                         break;
757                 case PAPER_DEFAULT:
758                 case PAPER_A3:
759                 case PAPER_B3:
760                 case PAPER_B4:
761                 case PAPER_CUSTOM:
762                         break;
763                 }
764         }
765
766         // if needed
767         if (sides != tclass.sides()) {
768                 switch (sides) {
769                 case LyXTextClass::OneSide:
770                         clsoptions << "oneside,";
771                         break;
772                 case LyXTextClass::TwoSides:
773                         clsoptions << "twoside,";
774                         break;
775                 }
776         }
777
778         // if needed
779         if (columns != tclass.columns()) {
780                 if (columns == 2)
781                         clsoptions << "twocolumn,";
782                 else
783                         clsoptions << "onecolumn,";
784         }
785
786         if (!use_geometry
787             && orientation == ORIENTATION_LANDSCAPE)
788                 clsoptions << "landscape,";
789
790         // language should be a parameter to \documentclass
791         if (language->babel() == "hebrew"
792             && default_language->babel() != "hebrew")
793                 // This seems necessary
794                 features.useLanguage(default_language);
795
796         ostringstream language_options;
797         bool const use_babel = features.useBabel();
798         if (use_babel) {
799                 language_options << features.getLanguages();
800                 language_options << language->babel();
801                 if (lyxrc.language_global_options)
802                         clsoptions << language_options.str() << ',';
803         }
804
805         // the user-defined options
806         if (!options.empty()) {
807                 clsoptions << options << ',';
808         }
809
810         string strOptions(clsoptions.str());
811         if (!strOptions.empty()) {
812                 strOptions = rtrim(strOptions, ",");
813                 os << '[' << strOptions << ']';
814         }
815
816         os << '{' << tclass.latexname() << "}\n";
817         texrow.newline();
818         // end of \documentclass defs
819
820         // font selection must be done before loading fontenc.sty
821         string const fonts =
822                 loadFonts(features, fontsRoman, fontsSans,
823                           fontsTypewriter, fontsSC, fontsOSF,
824                           fontsSansScale, fontsTypewriterScale);
825         if (!fonts.empty()) {
826                 os << fonts;
827                 texrow.newline();
828         }
829         if (fontsDefaultFamily != "default")
830                 os << "\\renewcommand{\\familydefault}{\\"
831                    << fontsDefaultFamily << "}\n";
832         // this one is not per buffer
833         if (lyxrc.fontenc != "default") {
834                 os << "\\usepackage[" << lyxrc.fontenc
835                    << "]{fontenc}\n";
836                 texrow.newline();
837         }
838
839         if (inputenc == "auto") {
840                 string const doc_encoding =
841                         language->encoding()->latexName();
842
843                 // Create a list with all the input encodings used
844                 // in the document
845                 std::set<string> encodings =
846                         features.getEncodingSet(doc_encoding);
847
848                 os << "\\usepackage[";
849                 std::copy(encodings.begin(), encodings.end(),
850                           std::ostream_iterator<string>(os, ","));
851                 os << doc_encoding << "]{inputenc}\n";
852                 texrow.newline();
853         } else if (inputenc != "default") {
854                 os << "\\usepackage[" << inputenc
855                    << "]{inputenc}\n";
856                 texrow.newline();
857         }
858
859         if (use_geometry || nonstandard_papersize) {
860                 os << "\\usepackage{geometry}\n";
861                 texrow.newline();
862                 os << "\\geometry{verbose";
863                 if (orientation == ORIENTATION_LANDSCAPE)
864                         os << ",landscape";
865                 switch (papersize) {
866                 case PAPER_CUSTOM:
867                         if (!paperwidth.empty())
868                                 os << ",paperwidth="
869                                    << paperwidth;
870                         if (!paperheight.empty())
871                                 os << ",paperheight="
872                                    << paperheight;
873                         break;
874                 case PAPER_USLETTER:
875                         os << ",letterpaper";
876                         break;
877                 case PAPER_USLEGAL:
878                         os << ",legalpaper";
879                         break;
880                 case PAPER_USEXECUTIVE:
881                         os << ",executivepaper";
882                         break;
883                 case PAPER_A3:
884                         os << ",a3paper";
885                         break;
886                 case PAPER_A4:
887                         os << ",a4paper";
888                         break;
889                 case PAPER_A5:
890                         os << ",a5paper";
891                         break;
892                 case PAPER_B3:
893                         os << ",b3paper";
894                         break;
895                 case PAPER_B4:
896                         os << ",b4paper";
897                         break;
898                 case PAPER_B5:
899                         os << ",b5paper";
900                         break;
901                 default:
902                         // default papersize ie PAPER_DEFAULT
903                         switch (lyxrc.default_papersize) {
904                         case PAPER_DEFAULT: // keep compiler happy
905                         case PAPER_USLETTER:
906                                 os << ",letterpaper";
907                                 break;
908                         case PAPER_USLEGAL:
909                                 os << ",legalpaper";
910                                 break;
911                         case PAPER_USEXECUTIVE:
912                                 os << ",executivepaper";
913                                 break;
914                         case PAPER_A3:
915                                 os << ",a3paper";
916                                 break;
917                         case PAPER_A4:
918                                 os << ",a4paper";
919                                 break;
920                         case PAPER_A5:
921                                 os << ",a5paper";
922                                 break;
923                         case PAPER_B5:
924                                 os << ",b5paper";
925                                 break;
926                         case PAPER_B3:
927                         case PAPER_B4:
928                         case PAPER_CUSTOM:
929                                 break;
930                         }
931                 }
932                 if (!topmargin.empty())
933                         os << ",tmargin=" << topmargin;
934                 if (!bottommargin.empty())
935                         os << ",bmargin=" << bottommargin;
936                 if (!leftmargin.empty())
937                         os << ",lmargin=" << leftmargin;
938                 if (!rightmargin.empty())
939                         os << ",rmargin=" << rightmargin;
940                 if (!headheight.empty())
941                         os << ",headheight=" << headheight;
942                 if (!headsep.empty())
943                         os << ",headsep=" << headsep;
944                 if (!footskip.empty())
945                         os << ",footskip=" << footskip;
946                 os << "}\n";
947                 texrow.newline();
948         }
949
950         if (tokenPos(tclass.opt_pagestyle(),
951                      '|', pagestyle) >= 0) {
952                 if (pagestyle == "fancy") {
953                         os << "\\usepackage{fancyhdr}\n";
954                         texrow.newline();
955                 }
956                 os << "\\pagestyle{" << pagestyle << "}\n";
957                 texrow.newline();
958         }
959
960         // Only if class has a ToC hierarchy
961         if (tclass.hasTocLevels()) {
962                 if (secnumdepth != tclass.secnumdepth()) {
963                         os << "\\setcounter{secnumdepth}{"
964                            << secnumdepth
965                            << "}\n";
966                         texrow.newline();
967                 }
968                 if (tocdepth != tclass.tocdepth()) {
969                         os << "\\setcounter{tocdepth}{"
970                            << tocdepth
971                            << "}\n";
972                         texrow.newline();
973                 }
974         }
975
976         if (paragraph_separation) {
977                 switch (getDefSkip().kind()) {
978                 case VSpace::SMALLSKIP:
979                         os << "\\setlength\\parskip{\\smallskipamount}\n";
980                         break;
981                 case VSpace::MEDSKIP:
982                         os << "\\setlength\\parskip{\\medskipamount}\n";
983                         break;
984                 case VSpace::BIGSKIP:
985                         os << "\\setlength\\parskip{\\bigskipamount}\n";
986                         break;
987                 case VSpace::LENGTH:
988                         os << "\\setlength\\parskip{"
989                            << getDefSkip().length().asLatexString()
990                            << "}\n";
991                         break;
992                 default: // should never happen // Then delete it.
993                         os << "\\setlength\\parskip{\\medskipamount}\n";
994                         break;
995                 }
996                 texrow.newline();
997
998                 os << "\\setlength\\parindent{0pt}\n";
999                 texrow.newline();
1000         }
1001
1002         // If we use jurabib, we have to call babel here.
1003         if (use_babel && features.isRequired("jurabib")) {
1004                 os << babelCall(language_options.str())
1005                    << '\n'
1006                    << features.getBabelOptions();
1007                 texrow.newline();
1008         }
1009
1010         // Now insert the LyX specific LaTeX commands...
1011
1012         // The optional packages;
1013         string lyxpreamble(features.getPackages());
1014
1015         // this might be useful...
1016         lyxpreamble += "\n\\makeatletter\n";
1017
1018         // Some macros LyX will need
1019         string tmppreamble(features.getMacros());
1020
1021         if (!tmppreamble.empty()) {
1022                 lyxpreamble += "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1023                         "LyX specific LaTeX commands.\n"
1024                         + tmppreamble + '\n';
1025         }
1026
1027         // the text class specific preamble
1028         tmppreamble = features.getTClassPreamble();
1029         if (!tmppreamble.empty()) {
1030                 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1031                         "Textclass specific LaTeX commands.\n"
1032                         + tmppreamble + '\n';
1033         }
1034
1035         /* the user-defined preamble */
1036         if (!preamble.empty()) {
1037                 lyxpreamble += "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "
1038                         "User specified LaTeX commands.\n"
1039                         + preamble + '\n';
1040         }
1041
1042         // Itemize bullet settings need to be last in case the user
1043         // defines their own bullets that use a package included
1044         // in the user-defined preamble -- ARRae
1045         // Actually it has to be done much later than that
1046         // since some packages like frenchb make modifications
1047         // at \begin{document} time -- JMarc
1048         string bullets_def;
1049         for (int i = 0; i < 4; ++i) {
1050                 if (user_defined_bullet(i) != ITEMIZE_DEFAULTS[i]) {
1051                         if (bullets_def.empty())
1052                                 bullets_def="\\AtBeginDocument{\n";
1053                         bullets_def += "  \\def\\labelitemi";
1054                         switch (i) {
1055                                 // `i' is one less than the item to modify
1056                         case 0:
1057                                 break;
1058                         case 1:
1059                                 bullets_def += 'i';
1060                                 break;
1061                         case 2:
1062                                 bullets_def += "ii";
1063                                 break;
1064                         case 3:
1065                                 bullets_def += 'v';
1066                                 break;
1067                         }
1068                         bullets_def += '{' +
1069                                 user_defined_bullet(i).getText()
1070                                 + "}\n";
1071                 }
1072         }
1073
1074         if (!bullets_def.empty())
1075                 lyxpreamble += bullets_def + "}\n\n";
1076
1077         // We try to load babel late, in case it interferes
1078         // with other packages.
1079         // Jurabib has to be called after babel, though.
1080         if (use_babel && !features.isRequired("jurabib")) {
1081                 lyxpreamble += babelCall(language_options.str()) + '\n';
1082                 lyxpreamble += features.getBabelOptions();
1083         }
1084
1085         lyxpreamble += "\\makeatother\n";
1086
1087         // dvipost settings come after everything else
1088         if (features.isAvailable("dvipost") && outputChanges) {
1089                 lyxpreamble +=
1090                         "\\dvipostlayout\n"
1091                         "\\dvipost{osstart color push Red}\n"
1092                         "\\dvipost{osend color pop}\n"
1093                         "\\dvipost{cbstart color push Blue}\n"
1094                         "\\dvipost{cbend color pop}\n";
1095         }
1096
1097         int const nlines =
1098                 int(lyx::count(lyxpreamble.begin(), lyxpreamble.end(), '\n'));
1099         for (int j = 0; j != nlines; ++j) {
1100                 texrow.newline();
1101         }
1102
1103         os << lyxpreamble;
1104         return use_babel;
1105 }
1106
1107
1108 void BufferParams::useClassDefaults()
1109 {
1110         LyXTextClass const & tclass = textclasslist[textclass];
1111
1112         sides = tclass.sides();
1113         columns = tclass.columns();
1114         pagestyle = tclass.pagestyle();
1115         options = tclass.options();
1116         // Only if class has a ToC hierarchy
1117         if (tclass.hasTocLevels()) {
1118                 secnumdepth = tclass.secnumdepth();
1119                 tocdepth = tclass.tocdepth();
1120         }
1121 }
1122
1123
1124 bool BufferParams::hasClassDefaults() const
1125 {
1126         LyXTextClass const & tclass = textclasslist[textclass];
1127
1128         return (sides == tclass.sides()
1129                 && columns == tclass.columns()
1130                 && pagestyle == tclass.pagestyle()
1131                 && options == tclass.options()
1132                 && secnumdepth == tclass.secnumdepth()
1133                 && tocdepth == tclass.tocdepth());
1134 }
1135
1136
1137 LyXTextClass const & BufferParams::getLyXTextClass() const
1138 {
1139         return textclasslist[textclass];
1140 }
1141
1142
1143 LyXFont const BufferParams::getFont() const
1144 {
1145         LyXFont f = getLyXTextClass().defaultfont();
1146         f.setLanguage(language);
1147         if (fontsDefaultFamily == "rmdefault")
1148                 f.setFamily(LyXFont::ROMAN_FAMILY);
1149         else if (fontsDefaultFamily == "sfdefault")
1150                 f.setFamily(LyXFont::SANS_FAMILY);
1151         else if (fontsDefaultFamily == "ttdefault")
1152                 f.setFamily(LyXFont::TYPEWRITER_FAMILY);
1153         return f;
1154 }
1155
1156
1157 void BufferParams::readPreamble(LyXLex & lex)
1158 {
1159         if (lex.getString() != "\\begin_preamble")
1160                 lyxerr << "Error (BufferParams::readPreamble):"
1161                         "consistency check failed." << endl;
1162
1163         preamble = lex.getLongString("\\end_preamble");
1164 }
1165
1166
1167 void BufferParams::readLanguage(LyXLex & lex)
1168 {
1169         if (!lex.next()) return;
1170
1171         string const tmptok = lex.getString();
1172
1173         // check if tmptok is part of tex_babel in tex-defs.h
1174         language = languages.getLanguage(tmptok);
1175         if (!language) {
1176                 // Language tmptok was not found
1177                 language = default_language;
1178                 lyxerr << "Warning: Setting language `"
1179                        << tmptok << "' to `" << language->lang()
1180                        << "'." << endl;
1181         }
1182 }
1183
1184
1185 void BufferParams::readGraphicsDriver(LyXLex & lex)
1186 {
1187         if (!lex.next()) return;
1188
1189         string const tmptok = lex.getString();
1190         // check if tmptok is part of tex_graphics in tex_defs.h
1191         int n = 0;
1192         while (true) {
1193                 string const test = tex_graphics[n++];
1194
1195                 if (test == tmptok) {
1196                         graphicsDriver = tmptok;
1197                         break;
1198                 } else if (test == "") {
1199                         lex.printError(
1200                                 "Warning: graphics driver `$$Token' not recognized!\n"
1201                                 "         Setting graphics driver to `default'.\n");
1202                         graphicsDriver = "default";
1203                         break;
1204                 }
1205         }
1206 }
1207
1208
1209 void BufferParams::readBullets(LyXLex & lex)
1210 {
1211         if (!lex.next()) return;
1212
1213         int const index = lex.getInteger();
1214         lex.next();
1215         int temp_int = lex.getInteger();
1216         user_defined_bullet(index).setFont(temp_int);
1217         temp_bullet(index).setFont(temp_int);
1218         lex >> temp_int;
1219         user_defined_bullet(index).setCharacter(temp_int);
1220         temp_bullet(index).setCharacter(temp_int);
1221         lex >> temp_int;
1222         user_defined_bullet(index).setSize(temp_int);
1223         temp_bullet(index).setSize(temp_int);
1224 }
1225
1226
1227 void BufferParams::readBulletsLaTeX(LyXLex & lex)
1228 {
1229         // The bullet class should be able to read this.
1230         if (!lex.next()) return;
1231         int const index = lex.getInteger();
1232         lex.next(true);
1233         string const temp_str = lex.getString();
1234
1235         user_defined_bullet(index).setText(temp_str);
1236         temp_bullet(index).setText(temp_str);
1237 }
1238
1239
1240 string const BufferParams::paperSizeName() const
1241 {
1242         char real_papersize = papersize;
1243         if (real_papersize == PAPER_DEFAULT)
1244                 real_papersize = lyxrc.default_papersize;
1245
1246         switch (real_papersize) {
1247         case PAPER_A3:
1248                 return "a3";
1249         case PAPER_A4:
1250                 return "a4";
1251         case PAPER_A5:
1252                 return "a5";
1253         case PAPER_B5:
1254                 return "b5";
1255         case PAPER_USEXECUTIVE:
1256                 return "foolscap";
1257         case PAPER_USLEGAL:
1258                 return "legal";
1259         case PAPER_USLETTER:
1260         default:
1261                 return "letter";
1262         }
1263 }
1264
1265
1266 string const BufferParams::dvips_options() const
1267 {
1268         string result;
1269
1270         if (use_geometry
1271             && papersize == PAPER_CUSTOM
1272             && !lyxrc.print_paper_dimension_flag.empty()
1273             && !paperwidth.empty()
1274             && !paperheight.empty()) {
1275                 // using a custom papersize
1276                 result = lyxrc.print_paper_dimension_flag;
1277                 result += ' ' + paperwidth;
1278                 result += ',' + paperheight;
1279         } else {
1280                 string const paper_option = paperSizeName();
1281                 if (paper_option != "letter" ||
1282                     orientation != ORIENTATION_LANDSCAPE) {
1283                         // dvips won't accept -t letter -t landscape.
1284                         // In all other cases, include the paper size
1285                         // explicitly.
1286                         result = lyxrc.print_paper_flag;
1287                         result += ' ' + paper_option;
1288                 }
1289         }
1290         if (orientation == ORIENTATION_LANDSCAPE &&
1291             papersize != PAPER_CUSTOM)
1292                 result += ' ' + lyxrc.print_landscape_flag;
1293         return result;
1294 }
1295
1296
1297 string const BufferParams::babelCall(string const & lang_opts) const
1298 {
1299         string tmp = lyxrc.language_package;
1300         if (!lyxrc.language_global_options && tmp == "\\usepackage{babel}")
1301                 tmp = string("\\usepackage[") + lang_opts + "]{babel}";
1302         return tmp;
1303 }
1304
1305
1306 string const BufferParams::loadFonts(LaTeXFeatures & features, string const & rm,
1307                                      string const & sf, string const & tt,
1308                                      bool const & sc, bool const & osf,
1309                                      int const & sfscale, int const & ttscale) const
1310 {
1311         /* The LaTeX font world is in a flux. In the PSNFSS font interface,
1312            several packages have been replaced by others, that might not
1313            be installed on every system. We have to take care for that
1314            (see psnfss.pdf). We try to support all psnfss fonts as well
1315            as the fonts that have become de facto standard in the LaTeX
1316            world (e.g. Latin Modern). We do not support obsolete fonts
1317            (like PSLatex). In general, it should be possible to mix any
1318            rm font with any sf or tt font, respectively. (JSpitzm)
1319            TODO:
1320                 -- separate math fonts.
1321         */
1322
1323         if (rm == "default" && sf == "default" && tt == "default")
1324                 //nothing to do
1325                 return string();
1326
1327         ostringstream os;
1328
1329         // ROMAN FONTS
1330         // Computer Modern (must be explicitely selectable -- there might be classes
1331         // that define a different default font!
1332         if (rm == "cmr") {
1333                 os << "\\renewcommand{\\rmdefault}{cmr}\n";
1334                 // osf for Computer Modern needs eco.sty
1335                 if (osf)
1336                         os << "\\usepackage{eco}\n";
1337         }
1338         // Latin Modern Roman
1339         else if (rm == "lmodern")
1340                 os << "\\usepackage{lmodern}\n";
1341         // AE
1342         else if (rm == "ae") {
1343                 // not needed when using OT1 font encoding.
1344                 if (lyxrc.fontenc != "default")
1345                         os << "\\usepackage{ae,aecompl}\n";
1346         }
1347         // Times
1348         else if (rm == "times") {
1349                 // try to load the best available package
1350                 if (features.isAvailable("mathptmx"))
1351                         os << "\\usepackage{mathptmx}\n";
1352                 else if (features.isAvailable("mathptm"))
1353                         os << "\\usepackage{mathptm}\n";
1354                 else
1355                         os << "\\usepackage{times}\n";
1356         }
1357         // Palatino
1358         else if (rm == "palatino") {
1359                 // try to load the best available package
1360                 if (features.isAvailable("mathpazo")) {
1361                         os << "\\usepackage";
1362                         if (osf || sc) {
1363                                 os << '[';
1364                                 if (!osf)
1365                                         os << "sc";
1366                                 else
1367                                         // "osf" includes "sc"!
1368                                         os << "osf";
1369                                 os << ']';
1370                         }
1371                         os << "{mathpazo}\n";
1372                 }
1373                 else if (features.isAvailable("mathpple"))
1374                         os << "\\usepackage{mathpple}\n";
1375                 else
1376                         os << "\\usepackage{palatino}\n";
1377         }
1378         // Utopia
1379         else if (rm == "utopia") {
1380                 // fourier supersedes utopia.sty, but does
1381                 // not work with OT1 encoding.
1382                 if (features.isAvailable("fourier")
1383                     && lyxrc.fontenc != "default") {
1384                         os << "\\usepackage";
1385                         if (osf || sc) {
1386                                 os << '[';
1387                                 if (sc)
1388                                         os << "expert";
1389                                 if (osf && sc)
1390                                         os << ',';
1391                                 if (osf)
1392                                         os << "oldstyle";
1393                                 os << ']';
1394                         }
1395                         os << "{fourier}\n";
1396                 }
1397                 else
1398                         os << "\\usepackage{utopia}\n";
1399         }
1400         // Bera (complete fontset)
1401         else if (rm == "bera" && sf == "default" && tt == "default")
1402                 os << "\\usepackage{bera}\n";
1403         // everything else
1404         else if (rm != "default")
1405                 os << "\\usepackage" << "{" << rm << "}\n";
1406
1407         // SANS SERIF
1408         // Helvetica, Bera Sans
1409         if (sf == "helvet" || sf == "berasans") {
1410                 if (sfscale != 100)
1411                         os << "\\usepackage[scaled=" << float(sfscale) / 100
1412                            << "]{" << sf << "}\n";
1413                 else
1414                         os << "\\usepackage{" << sf << "}\n";
1415         }
1416         // Avant Garde
1417         else if (sf == "avant")
1418                 os << "\\usepackage{" << sf << "}\n";
1419         // Computer Modern, Latin Modern, CM Bright
1420         else if (sf != "default")
1421                 os << "\\renewcommand{\\sfdefault}{" << sf << "}\n";
1422
1423         // monospaced/typewriter
1424         // Courier, LuxiMono
1425         if (tt == "luximono" || tt == "beramono") {
1426                 if (ttscale != 100)
1427                         os << "\\usepackage[scaled=" << float(ttscale) / 100
1428                            << "]{" << tt << "}\n";
1429                 else
1430                         os << "\\usepackage{" << tt << "}\n";
1431         }
1432         // Courier
1433         else if (tt == "courier" )
1434                 os << "\\usepackage{" << tt << "}\n";
1435         // Computer Modern, Latin Modern, CM Bright
1436         else if  (tt != "default")
1437                 os << "\\renewcommand{\\ttdefault}{" << tt << "}\n";
1438
1439         return os.str();
1440 }