]> git.lyx.org Git - features.git/blob - src/LaTeXFeatures.cpp
The huge URL patch:
[features.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 };
440
441 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
442
443 }
444
445
446 string const LaTeXFeatures::getPackages() const
447 {
448         ostringstream packages;
449         TextClass const & tclass = params_.getTextClass();
450
451         //
452         //  These are all the 'simple' includes.  i.e
453         //  packages which we just \usepackage{package}
454         //
455         for (int i = 0; i < nb_simplefeatures; ++i) {
456                 if (mustProvide(simplefeatures[i]))
457                         packages << "\\usepackage{"
458                                  << simplefeatures[i] << "}\n";
459         }
460
461         //
462         // The rest of these packages are somewhat more complicated
463         // than those above.
464         //
465
466         // esint is preferred for esintoramsmath
467         if ((mustProvide("amsmath") &&
468              params_.use_amsmath != BufferParams::package_off) ||
469             (mustProvide("esintoramsmath") &&
470              params_.use_esint == BufferParams::package_off)) {
471                 packages << "\\usepackage{amsmath}\n";
472         }
473
474         // wasysym is a simple feature, but it must be after amsmath if both
475         // are used
476         // wasysym redefines some integrals (e.g. iint) from amsmath. That
477         // leads to inconsistent integrals. We only load this package if
478         // the document does not contain integrals (then isRequired("esint")
479         // is false) or if esint is used, since esint redefines all relevant
480         // integral symbols from wasysym and amsmath.
481         // See http://bugzilla.lyx.org/show_bug.cgi?id=1942
482         if (mustProvide("wasysym") &&
483             (params_.use_esint != BufferParams::package_off || !isRequired("esint")))
484                 packages << "\\usepackage{wasysym}\n";
485
486         // color.sty
487         if (mustProvide("color")) {
488                 if (params_.graphicsDriver == "default")
489                         packages << "\\usepackage{color}\n";
490                 else
491                         packages << "\\usepackage["
492                                  << params_.graphicsDriver
493                                  << "]{color}\n";
494         }
495
496         // makeidx.sty
497         if (isRequired("makeidx")) {
498                 if (!tclass.provides("makeidx"))
499                         packages << "\\usepackage{makeidx}\n";
500                 packages << "\\makeindex\n";
501         }
502
503         // graphicx.sty
504         if (mustProvide("graphicx") && params_.graphicsDriver != "none") {
505                 if (params_.graphicsDriver == "default")
506                         packages << "\\usepackage{graphicx}\n";
507                 else
508                         packages << "\\usepackage["
509                                  << params_.graphicsDriver
510                                  << "]{graphicx}\n";
511         }
512         // shadecolor for shaded
513         if (mustProvide("framed") && mustProvide("color")) {
514                 RGBColor c = RGBColor(lcolor.getX11Name(Color::shadedbg));
515                 //255.0 to force conversion to double
516                 //NOTE As Jürgen Spitzmüller pointed out, an alternative would be
517                 //to use the xcolor package instead, and then we can do
518                 // \define{shadcolor}{RGB}...
519                 //and not do any conversion. We'd then need to require xcolor
520                 //in InsetNote::validate().
521                 int const stmSize = packages.precision(2);
522                 packages << "\\definecolor{shadecolor}{rgb}{"
523                         << c.r / 255.0 << ',' << c.g / 255.0 << ',' << c.b / 255.0 << "}\n";
524                 packages.precision(stmSize);
525         }
526
527         // lyxskak.sty --- newer chess support based on skak.sty
528         if (mustProvide("chess")) {
529                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
530         }
531
532         // setspace.sty
533         if ((params_.spacing().getSpace() != Spacing::Single
534              && !params_.spacing().isDefault())
535             || isRequired("setspace")) {
536                 packages << "\\usepackage{setspace}\n";
537         }
538         switch (params_.spacing().getSpace()) {
539         case Spacing::Default:
540         case Spacing::Single:
541                 // we dont use setspace.sty so dont print anything
542                 //packages += "\\singlespacing\n";
543                 break;
544         case Spacing::Onehalf:
545                 packages << "\\onehalfspacing\n";
546                 break;
547         case Spacing::Double:
548                 packages << "\\doublespacing\n";
549                 break;
550         case Spacing::Other:
551                 packages << "\\setstretch{"
552                          << params_.spacing().getValue() << "}\n";
553                 break;
554         }
555
556         // amssymb.sty
557         if (mustProvide("amssymb")
558             || params_.use_amsmath == BufferParams::package_on)
559                 packages << "\\usepackage{amssymb}\n";
560
561         // esint must be after amsmath and wasysym, since it will redeclare
562         // inconsistent integral symbols
563         if ((mustProvide("esint") || mustProvide("esintoramsmath")) &&
564             params_.use_esint != BufferParams::package_off)
565                 packages << "\\usepackage{esint}\n";
566
567         // natbib.sty
568         if (mustProvide("natbib")) {
569                 packages << "\\usepackage[";
570                 if (params_.getEngine() == biblio::ENGINE_NATBIB_NUMERICAL) {
571                         packages << "numbers";
572                 } else {
573                         packages << "authoryear";
574                 }
575                 packages << "]{natbib}\n";
576         }
577
578         // jurabib -- we need version 0.6 at least.
579         if (mustProvide("jurabib")) {
580                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
581         }
582
583         // bibtopic -- the dot provides the aux file naming which
584         // LyX can detect.
585         if (mustProvide("bibtopic")) {
586                 packages << "\\usepackage[dot]{bibtopic}\n";
587         }
588
589         if (mustProvide("xy"))
590                 packages << "\\usepackage[all]{xy}\n";
591
592         if (mustProvide("nomencl")) {
593                 // Make it work with the new and old version of the package,
594                 // but don't use the compatibility option since it is
595                 // incompatible to other packages.
596                 packages << "\\usepackage{nomencl}\n"
597                             "% the following is useful when we have the old nomencl.sty package\n"
598                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
599                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
600                             "\\makenomenclature\n";
601         }
602
603         if (mustProvide("listings"))
604                 packages << "\\usepackage{listings}\n";
605
606         return packages.str();
607 }
608
609
610 string const LaTeXFeatures::getMacros() const
611 {
612         ostringstream macros;
613
614         if (!preamble_snippets_.empty())
615                 macros << '\n';
616         FeaturesList::const_iterator pit  = preamble_snippets_.begin();
617         FeaturesList::const_iterator pend = preamble_snippets_.end();
618         for (; pit != pend; ++pit) {
619                 macros << *pit << '\n';
620         }
621
622         if (mustProvide("LyX"))
623                 macros << lyx_def << '\n';
624
625         if (mustProvide("lyxline"))
626                 macros << lyxline_def << '\n';
627
628         if (mustProvide("noun"))
629                 macros << noun_def << '\n';
630
631         if (mustProvide("lyxarrow"))
632                 macros << lyxarrow_def << '\n';
633
634         if (mustProvide("textgreek"))
635                 macros << textgreek_def << '\n';
636
637         if (mustProvide("textcyr"))
638                 macros << textcyr_def << '\n';
639
640         // quotes.
641         if (mustProvide("quotesinglbase"))
642                 macros << quotesinglbase_def << '\n';
643         if (mustProvide("quotedblbase"))
644                 macros << quotedblbase_def << '\n';
645         if (mustProvide("guilsinglleft"))
646                 macros << guilsinglleft_def << '\n';
647         if (mustProvide("guilsinglright"))
648                 macros << guilsinglright_def << '\n';
649         if (mustProvide("guillemotleft"))
650                 macros << guillemotleft_def << '\n';
651         if (mustProvide("guillemotright"))
652                 macros << guillemotright_def << '\n';
653
654         // Math mode
655         if (mustProvide("boldsymbol") && !isRequired("amsmath"))
656                 macros << boldsymbol_def << '\n';
657         if (mustProvide("binom") && !isRequired("amsmath"))
658                 macros << binom_def << '\n';
659         if (mustProvide("mathcircumflex"))
660                 macros << mathcircumflex_def << '\n';
661
662         // other
663         if (mustProvide("ParagraphLeftIndent"))
664                 macros << paragraphleftindent_def;
665         if (mustProvide("NeedLyXFootnoteCode"))
666                 macros << floatingfootnote_def;
667
668         // some problems with tex->html converters
669         if (mustProvide("NeedTabularnewline"))
670                 macros << tabularnewline_def;
671
672         // greyedout environment (note inset)
673         if (mustProvide("lyxgreyedout"))
674                 macros << lyxgreyedout_def;
675
676         if (mustProvide("lyxdot"))
677                 macros << lyxdot_def << '\n';
678
679         // floats
680         getFloatDefinitions(macros);
681
682         // change tracking
683         if (mustProvide("ct-dvipost")) {
684                 macros << changetracking_dvipost_def;
685         }
686         if (mustProvide("ct-xcolor-soul")) {
687                 int const prec = macros.precision(2);
688         
689                 RGBColor cadd = RGBColor(lcolor.getX11Name(Color::addedtext));
690                 macros << "\\providecolor{lyxadded}{rgb}{"
691                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
692
693                 RGBColor cdel = RGBColor(lcolor.getX11Name(Color::deletedtext));
694                 macros << "\\providecolor{lyxdeleted}{rgb}{"
695                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
696
697                 macros.precision(prec);
698
699                 macros << "\\newcommand{\\lyxadded}[3]{{\\color{lyxadded}#3}}\n"
700                        << "\\newcommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\st{#3}}}\n";
701         }
702         if (mustProvide("ct-none")) {
703                 macros << changetracking_none_def;
704         }
705
706         return macros.str();
707 }
708
709
710 string const LaTeXFeatures::getBabelOptions() const
711 {
712         ostringstream tmp;
713
714         LanguageList::const_iterator it  = UsedLanguages_.begin();
715         LanguageList::const_iterator end =  UsedLanguages_.end();
716         for (; it != end; ++it)
717                 if (!(*it)->latex_options().empty())
718                         tmp << (*it)->latex_options() << '\n';
719         if (!params_.language->latex_options().empty())
720                 tmp << params_.language->latex_options() << '\n';
721
722         return tmp.str();
723 }
724
725
726 docstring const LaTeXFeatures::getTClassPreamble() const
727 {
728         // the text class specific preamble
729         TextClass const & tclass = params_.getTextClass();
730         odocstringstream tcpreamble;
731
732         tcpreamble << tclass.preamble();
733
734         list<docstring>::const_iterator cit = usedLayouts_.begin();
735         list<docstring>::const_iterator end = usedLayouts_.end();
736         for (; cit != end; ++cit) {
737                 tcpreamble << tclass[*cit]->preamble();
738         }
739
740         InsetLayouts const & insetlayouts = tclass.insetlayouts();
741         InsetLayouts::const_iterator cit2 = insetlayouts.begin();
742         InsetLayouts::const_iterator end2 = insetlayouts.end();
743         for (; cit2 != end2; ++cit2) {
744                 if (isRequired(to_utf8(cit2->first))) {
745                         tcpreamble << from_utf8(cit2->second.preamble);
746                 }
747         }
748
749         return tcpreamble.str();
750 }
751
752
753 docstring const LaTeXFeatures::getLyXSGMLEntities() const
754 {
755         // Definition of entities used in the document that are LyX related.
756         odocstringstream entities;
757
758         if (mustProvide("lyxarrow")) {
759                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
760         }
761
762         return entities.str();
763 }
764
765
766 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
767 {
768         odocstringstream sgmlpreamble;
769         // FIXME UNICODE
770         docstring const basename(from_utf8(onlyPath(fname)));
771
772         FileMap::const_iterator end = IncludedFiles_.end();
773         for (FileMap::const_iterator fi = IncludedFiles_.begin();
774              fi != end; ++fi)
775                 // FIXME UNICODE
776                 sgmlpreamble << "\n<!ENTITY " << fi->first
777                              << (isSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
778                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
779
780         return sgmlpreamble.str();
781 }
782
783
784 void LaTeXFeatures::showStruct() const {
785         lyxerr << "LyX needs the following commands when LaTeXing:"
786                << "\n***** Packages:" << getPackages()
787                << "\n***** Macros:" << getMacros()
788                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
789                << "\n***** done." << endl;
790 }
791
792
793 Buffer const & LaTeXFeatures::buffer() const
794 {
795         return *buffer_;
796 }
797
798
799 void LaTeXFeatures::setBuffer(Buffer const & buffer)
800 {
801         buffer_ = &buffer;
802 }
803
804
805 BufferParams const & LaTeXFeatures::bufferParams() const
806 {
807         return params_;
808 }
809
810
811 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
812 {
813         FloatList const & floats = params_.getTextClass().floats();
814
815         // Here we will output the code to create the needed float styles.
816         // We will try to do this as minimal as possible.
817         // \floatstyle{ruled}
818         // \newfloat{algorithm}{htbp}{loa}
819         // \floatname{algorithm}{Algorithm}
820         UsedFloats::const_iterator cit = usedFloats_.begin();
821         UsedFloats::const_iterator end = usedFloats_.end();
822         // ostringstream floats;
823         for (; cit != end; ++cit) {
824                 Floating const & fl = floats.getType((*cit));
825
826                 // For builtin floats we do nothing.
827                 if (fl.builtin()) continue;
828
829                 // We have to special case "table" and "figure"
830                 if (fl.type() == "tabular" || fl.type() == "figure") {
831                         // Output code to modify "table" or "figure"
832                         // but only if builtin == false
833                         // and that have to be true at this point in the
834                         // function.
835                         string const type = fl.type();
836                         string const placement = fl.placement();
837                         string const style = fl.style();
838                         if (!style.empty()) {
839                                 os << "\\floatstyle{" << style << "}\n"
840                                    << "\\restylefloat{" << type << "}\n";
841                         }
842                         if (!placement.empty()) {
843                                 os << "\\floatplacement{" << type << "}{"
844                                    << placement << "}\n";
845                         }
846                 } else {
847                         // The other non builtin floats.
848
849                         string const type = fl.type();
850                         string const placement = fl.placement();
851                         string const ext = fl.ext();
852                         string const within = fl.within();
853                         string const style = fl.style();
854                         string const name = fl.name();
855                         os << "\\floatstyle{" << style << "}\n"
856                            << "\\newfloat{" << type << "}{" << placement
857                            << "}{" << ext << '}';
858                         if (!within.empty())
859                                 os << '[' << within << ']';
860                         os << '\n'
861                            << "\\floatname{" << type << "}{"
862                            << name << "}\n";
863
864                         // What missing here is to code to minimalize the code
865                         // output so that the same floatstyle will not be
866                         // used several times, when the same style is still in
867                         // effect. (Lgb)
868                 }
869         }
870 }
871
872
873 } // namespace lyx