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