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