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