]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.cpp
compile fix (missing forward declaration)
[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 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 };
453
454 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
455
456 }
457
458
459 string const LaTeXFeatures::getPackages() const
460 {
461         ostringstream packages;
462         DocumentClass const & tclass = params_.documentClass();
463
464         // FIXME: currently, we can only load packages and macros known
465         // to LyX.
466         // However, with the Require tag of layouts/custom insets,
467         // also inknown packages can be requested. They are silently
468         // swallowed now. We should change this eventually.
469
470         //
471         //  These are all the 'simple' includes.  i.e
472         //  packages which we just \usepackage{package}
473         //
474         for (int i = 0; i < nb_simplefeatures; ++i) {
475                 if (mustProvide(simplefeatures[i]))
476                         packages << "\\usepackage{"
477                                  << simplefeatures[i] << "}\n";
478         }
479
480         //
481         // The rest of these packages are somewhat more complicated
482         // than those above.
483         //
484
485         // esint is preferred for esintoramsmath
486         if ((mustProvide("amsmath") &&
487              params_.use_amsmath != BufferParams::package_off) ||
488             (mustProvide("esintoramsmath") &&
489              params_.use_esint == BufferParams::package_off)) {
490                 packages << "\\usepackage{amsmath}\n";
491         }
492         
493         // wasysym is a simple feature, but it must be after amsmath if both
494         // are used
495         // wasysym redefines some integrals (e.g. iint) from amsmath. That
496         // leads to inconsistent integrals. We only load this package if
497         // the document does not contain integrals (then isRequired("esint")
498         // is false) or if esint is used, since esint redefines all relevant
499         // integral symbols from wasysym and amsmath.
500         // See http://bugzilla.lyx.org/show_bug.cgi?id=1942
501         if (mustProvide("wasysym") &&
502             (params_.use_esint != BufferParams::package_off || !isRequired("esint")))
503                 packages << "\\usepackage{wasysym}\n";
504
505         // [x]color.sty
506         if (mustProvide("color") || mustProvide("xcolor")) {
507                 string const package =
508                         (mustProvide("xcolor") ? "xcolor" : "color");
509                 if (params_.graphicsDriver == "default")
510                         packages << "\\usepackage{" << package << "}\n";
511                 else
512                         packages << "\\usepackage["
513                                  << params_.graphicsDriver
514                                  << "]{" << package << "}\n";
515         }
516
517         // pdfcolmk must be loaded after color
518         if (mustProvide("pdfcolmk")) {
519                 packages << "\\usepackage{pdfcolmk}\n";
520         }
521
522         // makeidx.sty
523         if (isRequired("makeidx")) {
524                 if (!tclass.provides("makeidx"))
525                         packages << "\\usepackage{makeidx}\n";
526                 packages << "\\makeindex\n";
527         }
528
529         // graphicx.sty
530         if (mustProvide("graphicx") && params_.graphicsDriver != "none") {
531                 if (params_.graphicsDriver == "default")
532                         packages << "\\usepackage{graphicx}\n";
533                 else
534                         packages << "\\usepackage["
535                                  << params_.graphicsDriver
536                                  << "]{graphicx}\n";
537         }
538         // shadecolor for shaded
539         if (isRequired("framed") && mustProvide("color")) {
540                 RGBColor c = rgbFromHexName(lcolor.getX11Name(Color_shadedbg));
541                 //255.0 to force conversion to double
542                 //NOTE As Jürgen Spitzmüller pointed out, an alternative would be
543                 //to use the xcolor package instead, and then we can do
544                 // \define{shadcolor}{RGB}...
545                 //and not do any conversion. We'd then need to require xcolor
546                 //in InsetNote::validate().
547                 int const stmSize = packages.precision(2);
548                 packages << "\\definecolor{shadecolor}{rgb}{"
549                         << c.r / 255.0 << ',' << c.g / 255.0 << ',' << c.b / 255.0 << "}\n";
550                 packages.precision(stmSize);
551         }
552
553         // lyxskak.sty --- newer chess support based on skak.sty
554         if (mustProvide("chess")) {
555                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
556         }
557
558         // setspace.sty
559         if (mustProvide("setspace") && !tclass.provides("SetSpace"))
560                     packages << "\\usepackage{setspace}\n";
561
562         // amssymb.sty
563         if (mustProvide("amssymb")
564             || params_.use_amsmath == BufferParams::package_on)
565                 packages << "\\usepackage{amssymb}\n";
566
567         // esint must be after amsmath and wasysym, since it will redeclare
568         // inconsistent integral symbols
569         if ((mustProvide("esint") || mustProvide("esintoramsmath")) &&
570             params_.use_esint != BufferParams::package_off)
571                 packages << "\\usepackage{esint}\n";
572
573         // natbib.sty
574         if (mustProvide("natbib")) {
575                 packages << "\\usepackage[";
576                 if (params_.getEngine() == biblio::ENGINE_NATBIB_NUMERICAL) {
577                         packages << "numbers";
578                 } else {
579                         packages << "authoryear";
580                 }
581                 packages << "]{natbib}\n";
582         }
583
584         // jurabib -- we need version 0.6 at least.
585         if (mustProvide("jurabib")) {
586                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
587         }
588         
589         // xargs -- we need version 1.09 at least
590         if (mustProvide("xargs")) {
591                 packages << "\\usepackage{xargs}[2008/03/08]\n";
592         }
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
600         if (mustProvide("xy"))
601                 packages << "\\usepackage[all]{xy}\n";
602
603         if (mustProvide("nomencl")) {
604                 // Make it work with the new and old version of the package,
605                 // but don't use the compatibility option since it is
606                 // incompatible to other packages.
607                 packages << "\\usepackage{nomencl}\n"
608                             "% the following is useful when we have the old nomencl.sty package\n"
609                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
610                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
611                             "\\makenomenclature\n";
612         }
613
614         // bm -- this package interrogates the font allocations to determine
615         // which bold fonts are available, so it is best loaded as the last one,
616         // and, in any case, after amsmath.
617         if (mustProvide("bm"))
618                 packages << "\\usepackage{bm}\n";
619
620         return packages.str();
621 }
622
623
624 string const LaTeXFeatures::getMacros() const
625 {
626         ostringstream macros;
627
628         if (!preamble_snippets_.empty())
629                 macros << '\n';
630         SnippetList::const_iterator pit  = preamble_snippets_.begin();
631         SnippetList::const_iterator pend = preamble_snippets_.end();
632         for (; pit != pend; ++pit)
633                 macros << *pit << '\n';
634
635         if (mustProvide("LyX"))
636                 macros << lyx_def << '\n';
637
638         if (mustProvide("lyxline"))
639                 macros << lyxline_def << '\n';
640
641         if (mustProvide("noun"))
642                 macros << noun_def << '\n';
643
644         if (mustProvide("lyxarrow"))
645                 macros << lyxarrow_def << '\n';
646
647         if (mustProvide("textgreek"))
648                 macros << textgreek_def << '\n';
649
650         if (mustProvide("textcyr"))
651                 macros << textcyr_def << '\n';
652
653         // quotes.
654         if (mustProvide("quotesinglbase"))
655                 macros << quotesinglbase_def << '\n';
656         if (mustProvide("quotedblbase"))
657                 macros << quotedblbase_def << '\n';
658         if (mustProvide("guilsinglleft"))
659                 macros << guilsinglleft_def << '\n';
660         if (mustProvide("guilsinglright"))
661                 macros << guilsinglright_def << '\n';
662         if (mustProvide("guillemotleft"))
663                 macros << guillemotleft_def << '\n';
664         if (mustProvide("guillemotright"))
665                 macros << guillemotright_def << '\n';
666
667         // Math mode
668         if (mustProvide("binom") && !isRequired("amsmath"))
669                 macros << binom_def << '\n';
670         if (mustProvide("mathcircumflex"))
671                 macros << mathcircumflex_def << '\n';
672
673         // other
674         if (mustProvide("ParagraphLeftIndent"))
675                 macros << paragraphleftindent_def;
676         if (mustProvide("NeedLyXFootnoteCode"))
677                 macros << floatingfootnote_def;
678
679         // some problems with tex->html converters
680         if (mustProvide("NeedTabularnewline"))
681                 macros << tabularnewline_def;
682
683         // greyedout environment (note inset)
684         if (mustProvide("lyxgreyedout"))
685                 macros << lyxgreyedout_def;
686
687         if (mustProvide("lyxdot"))
688                 macros << lyxdot_def << '\n';
689
690         // floats
691         getFloatDefinitions(macros);
692
693         // change tracking
694         if (mustProvide("ct-dvipost"))
695                 macros << changetracking_dvipost_def;
696
697         if (mustProvide("ct-xcolor-soul")) {
698                 int const prec = macros.precision(2);
699         
700                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
701                 macros << "\\providecolor{lyxadded}{rgb}{"
702                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
703
704                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
705                 macros << "\\providecolor{lyxdeleted}{rgb}{"
706                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
707
708                 macros.precision(prec);
709                 
710                 if (isRequired("hyperref"))
711                         macros << changetracking_xcolor_soul_hyperref_def;
712                 else
713                         macros << changetracking_xcolor_soul_def;
714         }
715
716         if (mustProvide("ct-none"))
717                 macros << changetracking_none_def;
718
719         return macros.str();
720 }
721
722
723 string const LaTeXFeatures::getBabelOptions() const
724 {
725         ostringstream tmp;
726
727         LanguageList::const_iterator it  = UsedLanguages_.begin();
728         LanguageList::const_iterator end =  UsedLanguages_.end();
729         for (; it != end; ++it)
730                 if (!(*it)->latex_options().empty())
731                         tmp << (*it)->latex_options() << '\n';
732         if (!params_.language->latex_options().empty())
733                 tmp << params_.language->latex_options() << '\n';
734
735         return tmp.str();
736 }
737
738
739 docstring const LaTeXFeatures::getTClassPreamble() const
740 {
741         // the text class specific preamble
742         DocumentClass const & tclass = params_.documentClass();
743         odocstringstream tcpreamble;
744
745         tcpreamble << tclass.preamble();
746
747         list<docstring>::const_iterator cit = usedLayouts_.begin();
748         list<docstring>::const_iterator end = usedLayouts_.end();
749         for (; cit != end; ++cit) {
750                 tcpreamble << tclass[*cit].preamble();
751         }
752
753         return tcpreamble.str();
754 }
755
756
757 docstring const LaTeXFeatures::getLyXSGMLEntities() const
758 {
759         // Definition of entities used in the document that are LyX related.
760         odocstringstream entities;
761
762         if (mustProvide("lyxarrow")) {
763                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
764         }
765
766         return entities.str();
767 }
768
769
770 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
771 {
772         odocstringstream sgmlpreamble;
773         // FIXME UNICODE
774         docstring const basename(from_utf8(onlyPath(fname)));
775
776         FileMap::const_iterator end = IncludedFiles_.end();
777         for (FileMap::const_iterator fi = IncludedFiles_.begin();
778              fi != end; ++fi)
779                 // FIXME UNICODE
780                 sgmlpreamble << "\n<!ENTITY " << fi->first
781                              << (isSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
782                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
783
784         return sgmlpreamble.str();
785 }
786
787
788 void LaTeXFeatures::showStruct() const {
789         lyxerr << "LyX needs the following commands when LaTeXing:"
790                << "\n***** Packages:" << getPackages()
791                << "\n***** Macros:" << getMacros()
792                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
793                << "\n***** done." << endl;
794 }
795
796
797 Buffer const & LaTeXFeatures::buffer() const
798 {
799         return *buffer_;
800 }
801
802
803 void LaTeXFeatures::setBuffer(Buffer const & buffer)
804 {
805         buffer_ = &buffer;
806 }
807
808
809 BufferParams const & LaTeXFeatures::bufferParams() const
810 {
811         return params_;
812 }
813
814
815 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
816 {
817         FloatList const & floats = params_.documentClass().floats();
818
819         // Here we will output the code to create the needed float styles.
820         // We will try to do this as minimal as possible.
821         // \floatstyle{ruled}
822         // \newfloat{algorithm}{htbp}{loa}
823         // \floatname{algorithm}{Algorithm}
824         UsedFloats::const_iterator cit = usedFloats_.begin();
825         UsedFloats::const_iterator end = usedFloats_.end();
826         // ostringstream floats;
827         for (; cit != end; ++cit) {
828                 Floating const & fl = floats.getType((cit->first));
829
830                 // For builtin floats we do nothing.
831                 if (fl.builtin()) continue;
832
833                 // We have to special case "table" and "figure"
834                 if (fl.type() == "tabular" || fl.type() == "figure") {
835                         // Output code to modify "table" or "figure"
836                         // but only if builtin == false
837                         // and that have to be true at this point in the
838                         // function.
839                         string const type = fl.type();
840                         string const placement = fl.placement();
841                         string const style = fl.style();
842                         if (!style.empty()) {
843                                 os << "\\floatstyle{" << style << "}\n"
844                                    << "\\restylefloat{" << type << "}\n";
845                         }
846                         if (!placement.empty()) {
847                                 os << "\\floatplacement{" << type << "}{"
848                                    << placement << "}\n";
849                         }
850                 } else {
851                         // The other non builtin floats.
852
853                         string const type = fl.type();
854                         string const placement = fl.placement();
855                         string const ext = fl.ext();
856                         string const within = fl.within();
857                         string const style = fl.style();
858                         string const name = fl.name();
859                         os << "\\floatstyle{" << style << "}\n"
860                            << "\\newfloat{" << type << "}{" << placement
861                            << "}{" << ext << '}';
862                         if (!within.empty())
863                                 os << '[' << within << ']';
864                         os << '\n'
865                            << "\\floatname{" << type << "}{"
866                            << name << "}\n";
867
868                         // What missing here is to code to minimalize the code
869                         // output so that the same floatstyle will not be
870                         // used several times, when the same style is still in
871                         // effect. (Lgb)
872                 }
873                 if (cit->second)
874                         os << "\n\\newsubfloat{" << fl.type() << "}\n";
875         }
876 }
877
878
879 } // namespace lyx