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