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