]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.cpp
Add support for greek and cyrillic chars such that it is not
[lyx.git] / src / LaTeXFeatures.cpp
1 /**
2  * \file LaTeXFeatures.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author José Matos
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author Jürgen Vigna
10  * \author André Pönitz
11  *
12  * Full author contact details are available in file CREDITS.
13  */
14
15 #include <config.h>
16
17 #include "LaTeXFeatures.h"
18
19 #include "BufferParams.h"
20 #include "Color.h"
21 #include "debug.h"
22 #include "Encoding.h"
23 #include "Floating.h"
24 #include "FloatList.h"
25 #include "Language.h"
26 #include "Layout.h"
27 #include "Lexer.h"
28 #include "LyXRC.h"
29
30 #include "support/docstream.h"
31 #include "support/filetools.h"
32
33 using std::endl;
34 using std::find;
35 using std::string;
36 using std::list;
37 using std::ostream;
38 using std::ostringstream;
39 using std::set;
40
41
42 namespace lyx {
43
44 using support::isSGMLFilename;
45 using support::libFileSearch;
46 using support::makeRelPath;
47 using support::onlyPath;
48
49 /////////////////////////////////////////////////////////////////////
50 //
51 // Strings
52 //
53 /////////////////////////////////////////////////////////////////////
54
55 //\NeedsTeXFormat{LaTeX2e}
56 //\ProvidesPackage{lyx}[1996/01/11 LLE v0.2 (LyX LaTeX Extensions)]
57 //\message{LyX LaTeX Extensions (LLE v0.2) of 11-Jan-1996.}
58
59 static string const lyx_def =
60         "\\providecommand{\\LyX}{L\\kern-.1667em\\lower.25em\\hbox{Y}\\kern-.125emX\\@}";
61
62 static string const lyxline_def =
63         "\\newcommand{\\lyxline}[1][1pt]{%\n"
64         "  \\par\\noindent%\n"
65         "  \\rule[.5ex]{\\linewidth}{#1}\\par}";
66
67 static string const noun_def = "\\newcommand{\\noun}[1]{\\textsc{#1}}";
68
69 static string const lyxarrow_def =
70         "\\newcommand{\\lyxarrow}{\\leavevmode\\,$\\triangleright$\\,\\allowbreak}";
71
72 // for quotes without babel. This does not give perfect results, but
73 // anybody serious about non-english quotes should use babel (JMarc).
74
75 static string const quotedblbase_def =
76         "\\ProvideTextCommandDefault{\\quotedblbase}{%\n"
77         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquotedblright}%\n"
78         "  \\penalty10000\\hskip0em\\relax%\n"
79         "}";
80
81 static string const quotesinglbase_def =
82         "\\ProvideTextCommandDefault{\\quotesinglbase}{%\n"
83         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquoteright}%\n"
84         "  \\penalty10000\\hskip0em\\relax%\n"
85         "}";
86
87 static string const guillemotleft_def =
88         "\\ProvideTextCommandDefault{\\guillemotleft}{%\n"
89         "  {\\usefont{U}{lasy}{m}{n}\\char'50\\kern-.15em\\char'50}%\n"
90         "\\penalty10000\\hskip0pt\\relax%\n"
91         "}";
92
93 static string const guillemotright_def =
94         "\\ProvideTextCommandDefault{\\guillemotright}{%\n"
95         "  \\penalty10000\\hskip0pt%\n"
96         "  {\\usefont{U}{lasy}{m}{n}\\char'51\\kern-.15em\\char'51}%\n"
97         "}";
98
99 static string const guilsinglleft_def =
100         "\\ProvideTextCommandDefault{\\guilsinglleft}{%\n"
101         "  {\\usefont{U}{lasy}{m}{n}\\char'50}%\n"
102         "  \\penalty10000\\hskip0pt\\relax%\n"
103         "}";
104
105 static string const guilsinglright_def =
106         "\\ProvideTextCommandDefault{\\guilsinglright}{%\n"
107         "  \\penalty10000\\hskip0pt%\n"
108         "  {\\usefont{U}{lasy}{m}{n}\\char'51}%\n"
109         "}";
110
111 static string const paragraphleftindent_def =
112         "\\newenvironment{LyXParagraphLeftIndent}[1]%\n"
113         "{\n"
114         "  \\begin{list}{}{%\n"
115         "    \\setlength{\\topsep}{0pt}%\n"
116         "    \\addtolength{\\leftmargin}{#1}\n"
117 // ho hum, yet more things commented out with no hint as to why they
118 // weren't just removed
119 //      "%%    \\addtolength{\\leftmargin}{#1\\textwidth}\n"
120 //      "%%    \\setlength{\\textwidth}{#2\\textwidth}\n"
121 //      "%%    \\setlength\\listparindent\\parindent%\n"
122 //      "%%    \\setlength\\itemindent\\parindent%\n"
123         "    \\setlength{\\parsep}{0pt plus 1pt}%\n"
124         "  }\n"
125         "  \\item[]\n"
126         "}\n"
127         "{\\end{list}}\n";
128
129 static string const floatingfootnote_def =
130         "%% Special footnote code from the package 'stblftnt.sty'\n"
131         "%% Author: Robin Fairbairns -- Last revised Dec 13 1996\n"
132         "\\let\\SF@@footnote\\footnote\n"
133         "\\def\\footnote{\\ifx\\protect\\@typeset@protect\n"
134         "    \\expandafter\\SF@@footnote\n"
135         "  \\else\n"
136         "    \\expandafter\\SF@gobble@opt\n"
137         "  \\fi\n"
138         "}\n"
139         "\\expandafter\\def\\csname SF@gobble@opt \\endcsname{\\@ifnextchar[%]\n"
140         "  \\SF@gobble@twobracket\n"
141         "  \\@gobble\n"
142         "}\n"
143         "\\edef\\SF@gobble@opt{\\noexpand\\protect\n"
144         "  \\expandafter\\noexpand\\csname SF@gobble@opt \\endcsname}\n"
145         "\\def\\SF@gobble@twobracket[#1]#2{}\n";
146
147 static string const boldsymbol_def =
148         "%% Bold symbol macro for standard LaTeX users\n"
149         "\\providecommand{\\boldsymbol}[1]{\\mbox{\\boldmath $#1$}}\n";
150
151 static string const binom_def =
152         "%% Binom macro for standard LaTeX users\n"
153         "\\newcommand{\\binom}[2]{{#1 \\choose #2}}\n";
154
155 static string const mathcircumflex_def =
156         "%% For printing a cirumflex inside a formula\n"
157         "\\newcommand{\\mathcircumflex}[0]{\\mbox{\\^{}}}\n";
158
159 static string const tabularnewline_def =
160         "%% Because html converters don't know tabularnewline\n"
161         "\\providecommand{\\tabularnewline}{\\\\}\n";
162
163 static string const lyxgreyedout_def =
164         "%% The greyedout annotation environment\n"
165         "\\newenvironment{lyxgreyedout}{\\textcolor[gray]{0.8}\\bgroup}{\\egroup}\n";
166
167 // We want to omit the file extension for includegraphics, but this does not
168 // work when the filename contains other dots.
169 // Idea from http://www.tex.ac.uk/cgi-bin/texfaq2html?label=unkgrfextn
170 static string const lyxdot_def =
171         "%% A simple dot to overcome graphicx limitations\n"
172         "\\newcommand{\\lyxdot}{.}\n";
173
174 static string const changetracking_dvipost_def =
175         "%% Change tracking with dvipost\n"
176         "\\dvipostlayout\n"
177         "\\dvipost{osstart color push Red}\n"
178         "\\dvipost{osend color pop}\n"
179         "\\dvipost{cbstart color push Blue}\n"
180         "\\dvipost{cbend color pop}\n"
181         "\\newcommand{\\lyxadded}[3]{\\changestart#3\\changeend}\n"
182         "\\newcommand{\\lyxdeleted}[3]{%\n"
183         "\\changestart\\overstrikeon#3\\overstrikeoff\\changeend}\n";
184
185 static string const changetracking_none_def =
186         "\\newcommand{\\lyxadded}[3]{#3}\n"
187         "\\newcommand{\\lyxdeleted}[3]{}\n";
188
189 static string const textgreek_def =
190         "\\DeclareRobustCommand{\\greektext}{%\n"
191         " \\fontencoding{LGR}\\selectfont\n"
192         " \\def\\encodingdefault{LGR}}\n"
193         "\\DeclareRobustCommand{\\textgreek}[1]{\\leavevmode{\\greektext #1}}\n"
194         "\\DeclareFontEncoding{LGR}{}{}\n";
195
196 static string const textcyr_def =
197         "\\DeclareRobustCommand{\\cyrtext}{%\n"
198         " \\fontencoding{T2A}\\selectfont\n"
199         " \\def\\encodingdefault{T2A}}\n"
200         "\\DeclareRobustCommand{\\textcyr}[1]{\\leavevmode{\\cyrtext #1}}\n"
201         "\\DeclareFontEncoding{T2A}{}{}\n";
202
203
204 /////////////////////////////////////////////////////////////////////
205 //
206 // LaTeXFeatures
207 //
208 /////////////////////////////////////////////////////////////////////
209
210 LaTeXFeatures::PackagesList LaTeXFeatures::packages_;
211
212
213 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p,
214                              OutputParams const & r)
215         : buffer_(&b), params_(p), runparams_(r)
216 {}
217
218
219 bool LaTeXFeatures::useBabel() const
220 {
221         return lyxrc.language_use_babel ||
222                 (bufferParams().language->lang() != lyxrc.default_language &&
223                  !bufferParams().language->babel().empty()) ||
224                 this->hasLanguages();
225 }
226
227
228 void LaTeXFeatures::require(string const & name)
229 {
230         if (isRequired(name))
231                 return;
232
233         features_.push_back(name);
234 }
235
236
237 void LaTeXFeatures::getAvailable()
238 {
239         Lexer lex(0, 0);
240         support::FileName const real_file = libFileSearch("", "packages.lst");
241
242         if (real_file.empty())
243                 return;
244
245         lex.setFile(real_file);
246
247         if (!lex.isOK())
248                 return;
249
250         // Make sure that we are clean
251         packages_.clear();
252
253         bool finished = false;
254         // Parse config-file
255         while (lex.isOK() && !finished) {
256                 switch (lex.lex()) {
257                 case Lexer::LEX_FEOF:
258                         finished = true;
259                         break;
260                 default:
261                         string const name = lex.getString();
262                         PackagesList::const_iterator begin = packages_.begin();
263                         PackagesList::const_iterator end   = packages_.end();
264                         if (find(begin, end, name) == end)
265                                 packages_.push_back(name);
266                 }
267         }
268 }
269
270
271 void LaTeXFeatures::useLayout(docstring const & layoutname)
272 {
273         // Some code to avoid loops in dependency definition
274         static int level = 0;
275         const int maxlevel = 30;
276         if (level > maxlevel) {
277                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
278                        << "recursion attained by layout "
279                        << to_utf8(layoutname) << endl;
280                 return;
281         }
282
283         TextClass const & tclass = params_.getTextClass();
284         if (tclass.hasLayout(layoutname)) {
285                 // Is this layout already in usedLayouts?
286                 list<docstring>::const_iterator cit = usedLayouts_.begin();
287                 list<docstring>::const_iterator end = usedLayouts_.end();
288                 for (; cit != end; ++cit) {
289                         if (layoutname == *cit)
290                                 return;
291                 }
292
293                 LayoutPtr const & lyt = tclass[layoutname];
294                 if (!lyt->depends_on().empty()) {
295                         ++level;
296                         useLayout(lyt->depends_on());
297                         --level;
298                 }
299                 usedLayouts_.push_back(layoutname);
300         } else {
301                 lyxerr << "LaTeXFeatures::useLayout: layout `"
302                        << to_utf8(layoutname) << "' does not exist in this class"
303                        << endl;
304         }
305
306         --level;
307 }
308
309
310 bool LaTeXFeatures::isRequired(string const & name) const
311 {
312         return find(features_.begin(), features_.end(), name) != features_.end();
313 }
314
315
316 bool LaTeXFeatures::mustProvide(string const & name) const
317 {
318         return isRequired(name) && !params_.getTextClass().provides(name);
319 }
320
321
322 bool LaTeXFeatures::isAvailable(string const & name)
323 {
324         if (packages_.empty())
325                 getAvailable();
326         return find(packages_.begin(), packages_.end(), name) != packages_.end();
327 }
328
329
330 void LaTeXFeatures::addPreambleSnippet(string const & preamble)
331 {
332         FeaturesList::const_iterator begin = preamble_snippets_.begin();
333         FeaturesList::const_iterator end   = preamble_snippets_.end();
334         if (find(begin, end, preamble) == end)
335                 preamble_snippets_.push_back(preamble);
336 }
337
338
339 void LaTeXFeatures::useFloat(string const & name)
340 {
341         usedFloats_.insert(name);
342         // We only need float.sty if we use non builtin floats, or if we
343         // use the "H" modifier. This includes modified table and
344         // figure floats. (Lgb)
345         Floating const & fl = params_.getTextClass().floats().getType(name);
346         if (!fl.type().empty() && !fl.builtin()) {
347                 require("float");
348         }
349 }
350
351
352 void LaTeXFeatures::useLanguage(Language const * lang)
353 {
354         if (!lang->babel().empty())
355                 UsedLanguages_.insert(lang);
356 }
357
358
359 void LaTeXFeatures::includeFile(docstring const & key, string const & name)
360 {
361         IncludedFiles_[key] = name;
362 }
363
364
365 bool LaTeXFeatures::hasLanguages() const
366 {
367         return !UsedLanguages_.empty();
368 }
369
370
371 string LaTeXFeatures::getLanguages() const
372 {
373         ostringstream languages;
374
375         LanguageList::const_iterator const begin = UsedLanguages_.begin();
376         for (LanguageList::const_iterator cit = begin;
377              cit != UsedLanguages_.end();
378              ++cit) {
379                 if (cit != begin)
380                         languages << ',';
381                 languages << (*cit)->babel();
382         }
383         return languages.str();
384 }
385
386
387 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
388 {
389         // This does only find encodings of languages supported by babel, but
390         // that does not matter since we don't have a language with an
391         // encoding supported by inputenc but without babel support.
392         set<string> encodings;
393         LanguageList::const_iterator it  = UsedLanguages_.begin();
394         LanguageList::const_iterator end = UsedLanguages_.end();
395         for (; it != end; ++it)
396                 if ((*it)->encoding()->latexName() != doc_encoding &&
397                     (*it)->encoding()->package() == Encoding::inputenc)
398                         encodings.insert((*it)->encoding()->latexName());
399         return encodings;
400 }
401
402 namespace {
403
404 char const * simplefeatures[] = {
405 // note that the package order here will be the same in the LaTeX-output
406         "array",
407         "verbatim",
408         "longtable",
409         "rotating",
410         "latexsym",
411         "pifont",
412         "subfigure",
413         "varioref",
414         "prettyref",
415         /*For a successful cooperation of the `wrapfig' package with the
416           `float' package you should load the `wrapfig' package *after*
417           the `float' package. See the caption package documentation
418           for explanation.*/
419         "float",
420         "wrapfig",
421         "booktabs",
422         "dvipost",
423         "fancybox",
424         "calc",
425         "units",
426         "tipa",
427         "framed",
428         "pdfcolmk",
429         "soul",
430         "textcomp",
431         "xcolor",
432         "pmboxdraw",
433         "bbding",
434         "ifsym",
435         "marvosym",
436         "txfonts",
437         "mathrsfs",
438         "ascii",
439         "url",
440 };
441
442 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
443
444 }
445
446
447 string const LaTeXFeatures::getPackages() const
448 {
449         ostringstream packages;
450         TextClass const & tclass = params_.getTextClass();
451
452         //
453         //  These are all the 'simple' includes.  i.e
454         //  packages which we just \usepackage{package}
455         //
456         for (int i = 0; i < nb_simplefeatures; ++i) {
457                 if (mustProvide(simplefeatures[i]))
458                         packages << "\\usepackage{"
459                                  << simplefeatures[i] << "}\n";
460         }
461
462         //
463         // The rest of these packages are somewhat more complicated
464         // than those above.
465         //
466
467         // esint is preferred for esintoramsmath
468         if ((mustProvide("amsmath") &&
469              params_.use_amsmath != BufferParams::package_off) ||
470             (mustProvide("esintoramsmath") &&
471              params_.use_esint == BufferParams::package_off)) {
472                 packages << "\\usepackage{amsmath}\n";
473         }
474
475         // wasysym is a simple feature, but it must be after amsmath if both
476         // are used
477         // wasysym redefines some integrals (e.g. iint) from amsmath. That
478         // leads to inconsistent integrals. We only load this package if
479         // the document does not contain integrals (then isRequired("esint")
480         // is false) or if esint is used, since esint redefines all relevant
481         // integral symbols from wasysym and amsmath.
482         // See http://bugzilla.lyx.org/show_bug.cgi?id=1942
483         if (mustProvide("wasysym") &&
484             (params_.use_esint != BufferParams::package_off || !isRequired("esint")))
485                 packages << "\\usepackage{wasysym}\n";
486
487         // color.sty
488         if (mustProvide("color")) {
489                 if (params_.graphicsDriver == "default")
490                         packages << "\\usepackage{color}\n";
491                 else
492                         packages << "\\usepackage["
493                                  << params_.graphicsDriver
494                                  << "]{color}\n";
495         }
496
497         // makeidx.sty
498         if (isRequired("makeidx")) {
499                 if (!tclass.provides("makeidx"))
500                         packages << "\\usepackage{makeidx}\n";
501                 packages << "\\makeindex\n";
502         }
503
504         // graphicx.sty
505         if (mustProvide("graphicx") && params_.graphicsDriver != "none") {
506                 if (params_.graphicsDriver == "default")
507                         packages << "\\usepackage{graphicx}\n";
508                 else
509                         packages << "\\usepackage["
510                                  << params_.graphicsDriver
511                                  << "]{graphicx}\n";
512         }
513         // shadecolor for shaded
514         if (mustProvide("framed") && mustProvide("color")) {
515                 RGBColor c = RGBColor(lcolor.getX11Name(Color::shadedbg));
516                 //255.0 to force conversion to double
517                 //NOTE As Jürgen Spitzmüller pointed out, an alternative would be
518                 //to use the xcolor package instead, and then we can do
519                 // \define{shadcolor}{RGB}...
520                 //and not do any conversion. We'd then need to require xcolor
521                 //in InsetNote::validate().
522                 int const stmSize = packages.precision(2);
523                 packages << "\\definecolor{shadecolor}{rgb}{"
524                         << c.r / 255.0 << ',' << c.g / 255.0 << ',' << c.b / 255.0 << "}\n";
525                 packages.precision(stmSize);
526         }
527
528         // lyxskak.sty --- newer chess support based on skak.sty
529         if (mustProvide("chess")) {
530                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
531         }
532
533         // setspace.sty
534         if ((params_.spacing().getSpace() != Spacing::Single
535              && !params_.spacing().isDefault())
536             || isRequired("setspace")) {
537                 packages << "\\usepackage{setspace}\n";
538         }
539         switch (params_.spacing().getSpace()) {
540         case Spacing::Default:
541         case Spacing::Single:
542                 // we dont use setspace.sty so dont print anything
543                 //packages += "\\singlespacing\n";
544                 break;
545         case Spacing::Onehalf:
546                 packages << "\\onehalfspacing\n";
547                 break;
548         case Spacing::Double:
549                 packages << "\\doublespacing\n";
550                 break;
551         case Spacing::Other:
552                 packages << "\\setstretch{"
553                          << params_.spacing().getValue() << "}\n";
554                 break;
555         }
556
557         // amssymb.sty
558         if (mustProvide("amssymb")
559             || params_.use_amsmath == BufferParams::package_on)
560                 packages << "\\usepackage{amssymb}\n";
561
562         // esint must be after amsmath and wasysym, since it will redeclare
563         // inconsistent integral symbols
564         if ((mustProvide("esint") || mustProvide("esintoramsmath")) &&
565             params_.use_esint != BufferParams::package_off)
566                 packages << "\\usepackage{esint}\n";
567
568         // natbib.sty
569         if (mustProvide("natbib")) {
570                 packages << "\\usepackage[";
571                 if (params_.getEngine() == biblio::ENGINE_NATBIB_NUMERICAL) {
572                         packages << "numbers";
573                 } else {
574                         packages << "authoryear";
575                 }
576                 packages << "]{natbib}\n";
577         }
578
579         // jurabib -- we need version 0.6 at least.
580         if (mustProvide("jurabib")) {
581                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
582         }
583
584         // bibtopic -- the dot provides the aux file naming which
585         // LyX can detect.
586         if (mustProvide("bibtopic")) {
587                 packages << "\\usepackage[dot]{bibtopic}\n";
588         }
589
590         if (mustProvide("xy"))
591                 packages << "\\usepackage[all]{xy}\n";
592
593         if (mustProvide("nomencl")) {
594                 // Make it work with the new and old version of the package,
595                 // but don't use the compatibility option since it is
596                 // incompatible to other packages.
597                 packages << "\\usepackage{nomencl}\n"
598                             "% the following is useful when we have the old nomencl.sty package\n"
599                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
600                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
601                             "\\makenomenclature\n";
602         }
603
604         if (mustProvide("listings"))
605                 packages << "\\usepackage{listings}\n";
606
607         return packages.str();
608 }
609
610
611 string const LaTeXFeatures::getMacros() const
612 {
613         ostringstream macros;
614
615         if (!preamble_snippets_.empty())
616                 macros << '\n';
617         FeaturesList::const_iterator pit  = preamble_snippets_.begin();
618         FeaturesList::const_iterator pend = preamble_snippets_.end();
619         for (; pit != pend; ++pit) {
620                 macros << *pit << '\n';
621         }
622
623         if (mustProvide("LyX"))
624                 macros << lyx_def << '\n';
625
626         if (mustProvide("lyxline"))
627                 macros << lyxline_def << '\n';
628
629         if (mustProvide("noun"))
630                 macros << noun_def << '\n';
631
632         if (mustProvide("lyxarrow"))
633                 macros << lyxarrow_def << '\n';
634
635         if (mustProvide("textgreek"))
636                 macros << textgreek_def << '\n';
637
638         if (mustProvide("textcyr"))
639                 macros << textcyr_def << '\n';
640
641         // quotes.
642         if (mustProvide("quotesinglbase"))
643                 macros << quotesinglbase_def << '\n';
644         if (mustProvide("quotedblbase"))
645                 macros << quotedblbase_def << '\n';
646         if (mustProvide("guilsinglleft"))
647                 macros << guilsinglleft_def << '\n';
648         if (mustProvide("guilsinglright"))
649                 macros << guilsinglright_def << '\n';
650         if (mustProvide("guillemotleft"))
651                 macros << guillemotleft_def << '\n';
652         if (mustProvide("guillemotright"))
653                 macros << guillemotright_def << '\n';
654
655         // Math mode
656         if (mustProvide("boldsymbol") && !isRequired("amsmath"))
657                 macros << boldsymbol_def << '\n';
658         if (mustProvide("binom") && !isRequired("amsmath"))
659                 macros << binom_def << '\n';
660         if (mustProvide("mathcircumflex"))
661                 macros << mathcircumflex_def << '\n';
662
663         // other
664         if (mustProvide("ParagraphLeftIndent"))
665                 macros << paragraphleftindent_def;
666         if (mustProvide("NeedLyXFootnoteCode"))
667                 macros << floatingfootnote_def;
668
669         // some problems with tex->html converters
670         if (mustProvide("NeedTabularnewline"))
671                 macros << tabularnewline_def;
672
673         // greyedout environment (note inset)
674         if (mustProvide("lyxgreyedout"))
675                 macros << lyxgreyedout_def;
676
677         if (mustProvide("lyxdot"))
678                 macros << lyxdot_def << '\n';
679
680         // floats
681         getFloatDefinitions(macros);
682
683         // change tracking
684         if (mustProvide("ct-dvipost")) {
685                 macros << changetracking_dvipost_def;
686         }
687         if (mustProvide("ct-xcolor-soul")) {
688                 int const prec = macros.precision(2);
689         
690                 RGBColor cadd = RGBColor(lcolor.getX11Name(Color::addedtext));
691                 macros << "\\providecolor{lyxadded}{rgb}{"
692                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
693
694                 RGBColor cdel = RGBColor(lcolor.getX11Name(Color::deletedtext));
695                 macros << "\\providecolor{lyxdeleted}{rgb}{"
696                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
697
698                 macros.precision(prec);
699
700                 macros << "\\newcommand{\\lyxadded}[3]{{\\color{lyxadded}#3}}\n"
701                        << "\\newcommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\st{#3}}}\n";
702         }
703         if (mustProvide("ct-none")) {
704                 macros << changetracking_none_def;
705         }
706
707         return macros.str();
708 }
709
710
711 string const LaTeXFeatures::getBabelOptions() const
712 {
713         ostringstream tmp;
714
715         LanguageList::const_iterator it  = UsedLanguages_.begin();
716         LanguageList::const_iterator end =  UsedLanguages_.end();
717         for (; it != end; ++it)
718                 if (!(*it)->latex_options().empty())
719                         tmp << (*it)->latex_options() << '\n';
720         if (!params_.language->latex_options().empty())
721                 tmp << params_.language->latex_options() << '\n';
722
723         return tmp.str();
724 }
725
726
727 docstring const LaTeXFeatures::getTClassPreamble() const
728 {
729         // the text class specific preamble
730         TextClass const & tclass = params_.getTextClass();
731         odocstringstream tcpreamble;
732
733         tcpreamble << tclass.preamble();
734
735         list<docstring>::const_iterator cit = usedLayouts_.begin();
736         list<docstring>::const_iterator end = usedLayouts_.end();
737         for (; cit != end; ++cit) {
738                 tcpreamble << tclass[*cit]->preamble();
739         }
740
741         InsetLayouts const & insetlayouts = tclass.insetlayouts();
742         InsetLayouts::const_iterator cit2 = insetlayouts.begin();
743         InsetLayouts::const_iterator end2 = insetlayouts.end();
744         for (; cit2 != end2; ++cit2) {
745                 if (isRequired(to_utf8(cit2->first))) {
746                         tcpreamble << from_utf8(cit2->second.preamble);
747                 }
748         }
749
750         return tcpreamble.str();
751 }
752
753
754 docstring const LaTeXFeatures::getLyXSGMLEntities() const
755 {
756         // Definition of entities used in the document that are LyX related.
757         odocstringstream entities;
758
759         if (mustProvide("lyxarrow")) {
760                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
761         }
762
763         return entities.str();
764 }
765
766
767 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
768 {
769         odocstringstream sgmlpreamble;
770         // FIXME UNICODE
771         docstring const basename(from_utf8(onlyPath(fname)));
772
773         FileMap::const_iterator end = IncludedFiles_.end();
774         for (FileMap::const_iterator fi = IncludedFiles_.begin();
775              fi != end; ++fi)
776                 // FIXME UNICODE
777                 sgmlpreamble << "\n<!ENTITY " << fi->first
778                              << (isSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
779                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
780
781         return sgmlpreamble.str();
782 }
783
784
785 void LaTeXFeatures::showStruct() const {
786         lyxerr << "LyX needs the following commands when LaTeXing:"
787                << "\n***** Packages:" << getPackages()
788                << "\n***** Macros:" << getMacros()
789                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
790                << "\n***** done." << endl;
791 }
792
793
794 Buffer const & LaTeXFeatures::buffer() const
795 {
796         return *buffer_;
797 }
798
799
800 void LaTeXFeatures::setBuffer(Buffer const & buffer)
801 {
802         buffer_ = &buffer;
803 }
804
805
806 BufferParams const & LaTeXFeatures::bufferParams() const
807 {
808         return params_;
809 }
810
811
812 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
813 {
814         FloatList const & floats = params_.getTextClass().floats();
815
816         // Here we will output the code to create the needed float styles.
817         // We will try to do this as minimal as possible.
818         // \floatstyle{ruled}
819         // \newfloat{algorithm}{htbp}{loa}
820         // \floatname{algorithm}{Algorithm}
821         UsedFloats::const_iterator cit = usedFloats_.begin();
822         UsedFloats::const_iterator end = usedFloats_.end();
823         // ostringstream floats;
824         for (; cit != end; ++cit) {
825                 Floating const & fl = floats.getType((*cit));
826
827                 // For builtin floats we do nothing.
828                 if (fl.builtin()) continue;
829
830                 // We have to special case "table" and "figure"
831                 if (fl.type() == "tabular" || fl.type() == "figure") {
832                         // Output code to modify "table" or "figure"
833                         // but only if builtin == false
834                         // and that have to be true at this point in the
835                         // function.
836                         string const type = fl.type();
837                         string const placement = fl.placement();
838                         string const style = fl.style();
839                         if (!style.empty()) {
840                                 os << "\\floatstyle{" << style << "}\n"
841                                    << "\\restylefloat{" << type << "}\n";
842                         }
843                         if (!placement.empty()) {
844                                 os << "\\floatplacement{" << type << "}{"
845                                    << placement << "}\n";
846                         }
847                 } else {
848                         // The other non builtin floats.
849
850                         string const type = fl.type();
851                         string const placement = fl.placement();
852                         string const ext = fl.ext();
853                         string const within = fl.within();
854                         string const style = fl.style();
855                         string const name = fl.name();
856                         os << "\\floatstyle{" << style << "}\n"
857                            << "\\newfloat{" << type << "}{" << placement
858                            << "}{" << ext << '}';
859                         if (!within.empty())
860                                 os << '[' << within << ']';
861                         os << '\n'
862                            << "\\floatname{" << type << "}{"
863                            << name << "}\n";
864
865                         // What missing here is to code to minimalize the code
866                         // output so that the same floatstyle will not be
867                         // used several times, when the same style is still in
868                         // effect. (Lgb)
869                 }
870         }
871 }
872
873
874 } // namespace lyx