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