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