]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.cpp
make frontend::Application a bit slimmer
[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 "debug.h"
22 #include "Encoding.h"
23 #include "Floating.h"
24 #include "FloatList.h"
25 #include "Language.h"
26 #include "Layout.h"
27 #include "Lexer.h"
28 #include "LyXRC.h"
29 #include "TextClass.h"
30
31 #include "support/docstream.h"
32 #include "support/filetools.h"
33
34 using std::endl;
35 using std::find;
36 using std::string;
37 using std::list;
38 using std::ostream;
39 using std::ostringstream;
40 using std::set;
41
42
43 namespace lyx {
44
45 using support::isSGMLFilename;
46 using support::libFileSearch;
47 using support::makeRelPath;
48 using support::onlyPath;
49
50 /////////////////////////////////////////////////////////////////////
51 //
52 // Strings
53 //
54 /////////////////////////////////////////////////////////////////////
55
56 //\NeedsTeXFormat{LaTeX2e}
57 //\ProvidesPackage{lyx}[1996/01/11 LLE v0.2 (LyX LaTeX Extensions)]
58 //\message{LyX LaTeX Extensions (LLE v0.2) of 11-Jan-1996.}
59
60 static string const lyx_def =
61         "\\providecommand{\\LyX}{L\\kern-.1667em\\lower.25em\\hbox{Y}\\kern-.125emX\\@}";
62
63 static string const lyxline_def =
64         "\\newcommand{\\lyxline}[1][1pt]{%\n"
65         "  \\par\\noindent%\n"
66         "  \\rule[.5ex]{\\linewidth}{#1}\\par}";
67
68 static string const noun_def = "\\newcommand{\\noun}[1]{\\textsc{#1}}";
69
70 static string const lyxarrow_def =
71         "\\newcommand{\\lyxarrow}{\\leavevmode\\,$\\triangleright$\\,\\allowbreak}";
72
73 // for quotes without babel. This does not give perfect results, but
74 // anybody serious about non-english quotes should use babel (JMarc).
75
76 static string const quotedblbase_def =
77         "\\ProvideTextCommandDefault{\\quotedblbase}{%\n"
78         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquotedblright}%\n"
79         "  \\penalty10000\\hskip0em\\relax%\n"
80         "}";
81
82 static string const quotesinglbase_def =
83         "\\ProvideTextCommandDefault{\\quotesinglbase}{%\n"
84         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquoteright}%\n"
85         "  \\penalty10000\\hskip0em\\relax%\n"
86         "}";
87
88 static string const guillemotleft_def =
89         "\\ProvideTextCommandDefault{\\guillemotleft}{%\n"
90         "  {\\usefont{U}{lasy}{m}{n}\\char'50\\kern-.15em\\char'50}%\n"
91         "\\penalty10000\\hskip0pt\\relax%\n"
92         "}";
93
94 static string const guillemotright_def =
95         "\\ProvideTextCommandDefault{\\guillemotright}{%\n"
96         "  \\penalty10000\\hskip0pt%\n"
97         "  {\\usefont{U}{lasy}{m}{n}\\char'51\\kern-.15em\\char'51}%\n"
98         "}";
99
100 static string const guilsinglleft_def =
101         "\\ProvideTextCommandDefault{\\guilsinglleft}{%\n"
102         "  {\\usefont{U}{lasy}{m}{n}\\char'50}%\n"
103         "  \\penalty10000\\hskip0pt\\relax%\n"
104         "}";
105
106 static string const guilsinglright_def =
107         "\\ProvideTextCommandDefault{\\guilsinglright}{%\n"
108         "  \\penalty10000\\hskip0pt%\n"
109         "  {\\usefont{U}{lasy}{m}{n}\\char'51}%\n"
110         "}";
111
112 static string const paragraphleftindent_def =
113         "\\newenvironment{LyXParagraphLeftIndent}[1]%\n"
114         "{\n"
115         "  \\begin{list}{}{%\n"
116         "    \\setlength{\\topsep}{0pt}%\n"
117         "    \\addtolength{\\leftmargin}{#1}\n"
118 // ho hum, yet more things commented out with no hint as to why they
119 // weren't just removed
120 //      "%%    \\addtolength{\\leftmargin}{#1\\textwidth}\n"
121 //      "%%    \\setlength{\\textwidth}{#2\\textwidth}\n"
122 //      "%%    \\setlength\\listparindent\\parindent%\n"
123 //      "%%    \\setlength\\itemindent\\parindent%\n"
124         "    \\setlength{\\parsep}{0pt plus 1pt}%\n"
125         "  }\n"
126         "  \\item[]\n"
127         "}\n"
128         "{\\end{list}}\n";
129
130 static string const floatingfootnote_def =
131         "%% Special footnote code from the package 'stblftnt.sty'\n"
132         "%% Author: Robin Fairbairns -- Last revised Dec 13 1996\n"
133         "\\let\\SF@@footnote\\footnote\n"
134         "\\def\\footnote{\\ifx\\protect\\@typeset@protect\n"
135         "    \\expandafter\\SF@@footnote\n"
136         "  \\else\n"
137         "    \\expandafter\\SF@gobble@opt\n"
138         "  \\fi\n"
139         "}\n"
140         "\\expandafter\\def\\csname SF@gobble@opt \\endcsname{\\@ifnextchar[%]\n"
141         "  \\SF@gobble@twobracket\n"
142         "  \\@gobble\n"
143         "}\n"
144         "\\edef\\SF@gobble@opt{\\noexpand\\protect\n"
145         "  \\expandafter\\noexpand\\csname SF@gobble@opt \\endcsname}\n"
146         "\\def\\SF@gobble@twobracket[#1]#2{}\n";
147
148 static string const boldsymbol_def =
149         "%% Bold symbol macro for standard LaTeX users\n"
150         "\\providecommand{\\boldsymbol}[1]{\\mbox{\\boldmath $#1$}}\n";
151
152 static string const binom_def =
153         "%% Binom macro for standard LaTeX users\n"
154         "\\newcommand{\\binom}[2]{{#1 \\choose #2}}\n";
155
156 static string const mathcircumflex_def =
157         "%% For printing a cirumflex inside a formula\n"
158         "\\newcommand{\\mathcircumflex}[0]{\\mbox{\\^{}}}\n";
159
160 static string const tabularnewline_def =
161         "%% Because html converters don't know tabularnewline\n"
162         "\\providecommand{\\tabularnewline}{\\\\}\n";
163
164 static string const lyxgreyedout_def =
165         "%% The greyedout annotation environment\n"
166         "\\newenvironment{lyxgreyedout}{\\textcolor[gray]{0.8}\\bgroup}{\\egroup}\n";
167
168 // We want to omit the file extension for includegraphics, but this does not
169 // work when the filename contains other dots.
170 // Idea from http://www.tex.ac.uk/cgi-bin/texfaq2html?label=unkgrfextn
171 static string const lyxdot_def =
172         "%% A simple dot to overcome graphicx limitations\n"
173         "\\newcommand{\\lyxdot}{.}\n";
174
175 static string const changetracking_dvipost_def =
176         "%% Change tracking with dvipost\n"
177         "\\dvipostlayout\n"
178         "\\dvipost{osstart color push Red}\n"
179         "\\dvipost{osend color pop}\n"
180         "\\dvipost{cbstart color push Blue}\n"
181         "\\dvipost{cbend color pop}\n"
182         "\\newcommand{\\lyxadded}[3]{\\changestart#3\\changeend}\n"
183         "\\newcommand{\\lyxdeleted}[3]{%\n"
184         "\\changestart\\overstrikeon#3\\overstrikeoff\\changeend}\n";
185
186 static string const changetracking_none_def =
187         "\\newcommand{\\lyxadded}[3]{#3}\n"
188         "\\newcommand{\\lyxdeleted}[3]{}\n";
189
190 static string const textgreek_def =
191         "\\DeclareRobustCommand{\\greektext}{%\n"
192         " \\fontencoding{LGR}\\selectfont\n"
193         " \\def\\encodingdefault{LGR}}\n"
194         "\\DeclareRobustCommand{\\textgreek}[1]{\\leavevmode{\\greektext #1}}\n"
195         "\\DeclareFontEncoding{LGR}{}{}\n";
196
197 static string const textcyr_def =
198         "\\DeclareRobustCommand{\\cyrtext}{%\n"
199         " \\fontencoding{T2A}\\selectfont\n"
200         " \\def\\encodingdefault{T2A}}\n"
201         "\\DeclareRobustCommand{\\textcyr}[1]{\\leavevmode{\\cyrtext #1}}\n"
202         "\\DeclareFontEncoding{T2A}{}{}\n";
203
204
205 /////////////////////////////////////////////////////////////////////
206 //
207 // LaTeXFeatures
208 //
209 /////////////////////////////////////////////////////////////////////
210
211 LaTeXFeatures::PackagesList 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         if (isRequired(name))
232                 return;
233
234         features_.push_back(name);
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                         string const name = lex.getString();
263                         PackagesList::const_iterator begin = packages_.begin();
264                         PackagesList::const_iterator end   = packages_.end();
265                         if (find(begin, end, name) == end)
266                                 packages_.push_back(name);
267                 }
268         }
269 }
270
271
272 void LaTeXFeatures::useLayout(docstring const & layoutname)
273 {
274         // Some code to avoid loops in dependency definition
275         static int level = 0;
276         const int maxlevel = 30;
277         if (level > maxlevel) {
278                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
279                        << "recursion attained by layout "
280                        << to_utf8(layoutname) << endl;
281                 return;
282         }
283
284         TextClass const & tclass = params_.getTextClass();
285         if (tclass.hasLayout(layoutname)) {
286                 // Is this layout already in usedLayouts?
287                 list<docstring>::const_iterator cit = usedLayouts_.begin();
288                 list<docstring>::const_iterator end = usedLayouts_.end();
289                 for (; cit != end; ++cit) {
290                         if (layoutname == *cit)
291                                 return;
292                 }
293
294                 LayoutPtr const & lyt = tclass[layoutname];
295                 if (!lyt->depends_on().empty()) {
296                         ++level;
297                         useLayout(lyt->depends_on());
298                         --level;
299                 }
300                 usedLayouts_.push_back(layoutname);
301         } else {
302                 lyxerr << "LaTeXFeatures::useLayout: layout `"
303                        << to_utf8(layoutname) << "' does not exist in this class"
304                        << endl;
305         }
306
307         --level;
308 }
309
310
311 bool LaTeXFeatures::isRequired(string const & name) const
312 {
313         return find(features_.begin(), features_.end(), name) != features_.end();
314 }
315
316
317 bool LaTeXFeatures::mustProvide(string const & name) const
318 {
319         return isRequired(name) && !params_.getTextClass().provides(name);
320 }
321
322
323 bool LaTeXFeatures::isAvailable(string const & name)
324 {
325         if (packages_.empty())
326                 getAvailable();
327         return find(packages_.begin(), packages_.end(), name) != packages_.end();
328 }
329
330
331 void LaTeXFeatures::addPreambleSnippet(string const & preamble)
332 {
333         FeaturesList::const_iterator begin = preamble_snippets_.begin();
334         FeaturesList::const_iterator end   = preamble_snippets_.end();
335         if (find(begin, end, preamble) == end)
336                 preamble_snippets_.push_back(preamble);
337 }
338
339
340 void LaTeXFeatures::useFloat(string const & name)
341 {
342         usedFloats_.insert(name);
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_.getTextClass().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         "subfigure",
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         "wrapfig",
426         "booktabs",
427         "dvipost",
428         "fancybox",
429         "calc",
430         "units",
431         "tipa",
432         "framed",
433         "pdfcolmk",
434         "soul",
435         "textcomp",
436         "xcolor",
437         "pmboxdraw",
438         "bbding",
439         "ifsym",
440         "marvosym",
441         "txfonts",
442         "mathrsfs",
443         "ascii",
444         "url",
445 };
446
447 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
448
449 }
450
451
452 string const LaTeXFeatures::getPackages() const
453 {
454         ostringstream packages;
455         TextClass const & tclass = params_.getTextClass();
456
457         //
458         //  These are all the 'simple' includes.  i.e
459         //  packages which we just \usepackage{package}
460         //
461         for (int i = 0; i < nb_simplefeatures; ++i) {
462                 if (mustProvide(simplefeatures[i]))
463                         packages << "\\usepackage{"
464                                  << simplefeatures[i] << "}\n";
465         }
466
467         //
468         // The rest of these packages are somewhat more complicated
469         // than those above.
470         //
471
472         // esint is preferred for esintoramsmath
473         if ((mustProvide("amsmath") &&
474              params_.use_amsmath != BufferParams::package_off) ||
475             (mustProvide("esintoramsmath") &&
476              params_.use_esint == BufferParams::package_off)) {
477                 packages << "\\usepackage{amsmath}\n";
478         }
479
480         // wasysym is a simple feature, but it must be after amsmath if both
481         // are used
482         // wasysym redefines some integrals (e.g. iint) from amsmath. That
483         // leads to inconsistent integrals. We only load this package if
484         // the document does not contain integrals (then isRequired("esint")
485         // is false) or if esint is used, since esint redefines all relevant
486         // integral symbols from wasysym and amsmath.
487         // See http://bugzilla.lyx.org/show_bug.cgi?id=1942
488         if (mustProvide("wasysym") &&
489             (params_.use_esint != BufferParams::package_off || !isRequired("esint")))
490                 packages << "\\usepackage{wasysym}\n";
491
492         // color.sty
493         if (mustProvide("color")) {
494                 if (params_.graphicsDriver == "default")
495                         packages << "\\usepackage{color}\n";
496                 else
497                         packages << "\\usepackage["
498                                  << params_.graphicsDriver
499                                  << "]{color}\n";
500         }
501
502         // makeidx.sty
503         if (isRequired("makeidx")) {
504                 if (!tclass.provides("makeidx"))
505                         packages << "\\usepackage{makeidx}\n";
506                 packages << "\\makeindex\n";
507         }
508
509         // graphicx.sty
510         if (mustProvide("graphicx") && params_.graphicsDriver != "none") {
511                 if (params_.graphicsDriver == "default")
512                         packages << "\\usepackage{graphicx}\n";
513                 else
514                         packages << "\\usepackage["
515                                  << params_.graphicsDriver
516                                  << "]{graphicx}\n";
517         }
518         // shadecolor for shaded
519         if (mustProvide("framed") && mustProvide("color")) {
520                 RGBColor c = rgbFromHexName(lcolor.getX11Name(Color_shadedbg));
521                 //255.0 to force conversion to double
522                 //NOTE As Jürgen Spitzmüller pointed out, an alternative would be
523                 //to use the xcolor package instead, and then we can do
524                 // \define{shadcolor}{RGB}...
525                 //and not do any conversion. We'd then need to require xcolor
526                 //in InsetNote::validate().
527                 int const stmSize = packages.precision(2);
528                 packages << "\\definecolor{shadecolor}{rgb}{"
529                         << c.r / 255.0 << ',' << c.g / 255.0 << ',' << c.b / 255.0 << "}\n";
530                 packages.precision(stmSize);
531         }
532
533         // lyxskak.sty --- newer chess support based on skak.sty
534         if (mustProvide("chess")) {
535                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
536         }
537
538         // setspace.sty
539         if ((params_.spacing().getSpace() != Spacing::Single
540              && !params_.spacing().isDefault())
541             || isRequired("setspace")) {
542                 packages << "\\usepackage{setspace}\n";
543         }
544         switch (params_.spacing().getSpace()) {
545         case Spacing::Default:
546         case Spacing::Single:
547                 // we dont use setspace.sty so dont print anything
548                 //packages += "\\singlespacing\n";
549                 break;
550         case Spacing::Onehalf:
551                 packages << "\\onehalfspacing\n";
552                 break;
553         case Spacing::Double:
554                 packages << "\\doublespacing\n";
555                 break;
556         case Spacing::Other:
557                 packages << "\\setstretch{"
558                          << params_.spacing().getValue() << "}\n";
559                 break;
560         }
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         // bibtopic -- the dot provides the aux file naming which
590         // LyX can detect.
591         if (mustProvide("bibtopic")) {
592                 packages << "\\usepackage[dot]{bibtopic}\n";
593         }
594
595         if (mustProvide("xy"))
596                 packages << "\\usepackage[all]{xy}\n";
597
598         if (mustProvide("nomencl")) {
599                 // Make it work with the new and old version of the package,
600                 // but don't use the compatibility option since it is
601                 // incompatible to other packages.
602                 packages << "\\usepackage{nomencl}\n"
603                             "% the following is useful when we have the old nomencl.sty package\n"
604                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
605                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
606                             "\\makenomenclature\n";
607         }
608
609         if (mustProvide("listings"))
610                 packages << "\\usepackage{listings}\n";
611
612         return packages.str();
613 }
614
615
616 string const LaTeXFeatures::getMacros() const
617 {
618         ostringstream macros;
619
620         if (!preamble_snippets_.empty())
621                 macros << '\n';
622         FeaturesList::const_iterator pit  = preamble_snippets_.begin();
623         FeaturesList::const_iterator pend = preamble_snippets_.end();
624         for (; pit != pend; ++pit)
625                 macros << *pit << '\n';
626
627         if (mustProvide("LyX"))
628                 macros << lyx_def << '\n';
629
630         if (mustProvide("lyxline"))
631                 macros << lyxline_def << '\n';
632
633         if (mustProvide("noun"))
634                 macros << noun_def << '\n';
635
636         if (mustProvide("lyxarrow"))
637                 macros << lyxarrow_def << '\n';
638
639         if (mustProvide("textgreek"))
640                 macros << textgreek_def << '\n';
641
642         if (mustProvide("textcyr"))
643                 macros << textcyr_def << '\n';
644
645         // quotes.
646         if (mustProvide("quotesinglbase"))
647                 macros << quotesinglbase_def << '\n';
648         if (mustProvide("quotedblbase"))
649                 macros << quotedblbase_def << '\n';
650         if (mustProvide("guilsinglleft"))
651                 macros << guilsinglleft_def << '\n';
652         if (mustProvide("guilsinglright"))
653                 macros << guilsinglright_def << '\n';
654         if (mustProvide("guillemotleft"))
655                 macros << guillemotleft_def << '\n';
656         if (mustProvide("guillemotright"))
657                 macros << guillemotright_def << '\n';
658
659         // Math mode
660         if (mustProvide("boldsymbol") && !isRequired("amsmath"))
661                 macros << boldsymbol_def << '\n';
662         if (mustProvide("binom") && !isRequired("amsmath"))
663                 macros << binom_def << '\n';
664         if (mustProvide("mathcircumflex"))
665                 macros << mathcircumflex_def << '\n';
666
667         // other
668         if (mustProvide("ParagraphLeftIndent"))
669                 macros << paragraphleftindent_def;
670         if (mustProvide("NeedLyXFootnoteCode"))
671                 macros << floatingfootnote_def;
672
673         // some problems with tex->html converters
674         if (mustProvide("NeedTabularnewline"))
675                 macros << tabularnewline_def;
676
677         // greyedout environment (note inset)
678         if (mustProvide("lyxgreyedout"))
679                 macros << lyxgreyedout_def;
680
681         if (mustProvide("lyxdot"))
682                 macros << lyxdot_def << '\n';
683
684         // floats
685         getFloatDefinitions(macros);
686
687         // change tracking
688         if (mustProvide("ct-dvipost"))
689                 macros << changetracking_dvipost_def;
690
691         if (mustProvide("ct-xcolor-soul")) {
692                 int const prec = macros.precision(2);
693         
694                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
695                 macros << "\\providecolor{lyxadded}{rgb}{"
696                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
697
698                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
699                 macros << "\\providecolor{lyxdeleted}{rgb}{"
700                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
701
702                 macros.precision(prec);
703
704                 macros << "\\newcommand{\\lyxadded}[3]{{\\color{lyxadded}#3}}\n"
705                        << "\\newcommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\st{#3}}}\n";
706         }
707
708         if (mustProvide("ct-none"))
709                 macros << changetracking_none_def;
710
711         return macros.str();
712 }
713
714
715 string const LaTeXFeatures::getBabelOptions() const
716 {
717         ostringstream tmp;
718
719         LanguageList::const_iterator it  = UsedLanguages_.begin();
720         LanguageList::const_iterator end =  UsedLanguages_.end();
721         for (; it != end; ++it)
722                 if (!(*it)->latex_options().empty())
723                         tmp << (*it)->latex_options() << '\n';
724         if (!params_.language->latex_options().empty())
725                 tmp << params_.language->latex_options() << '\n';
726
727         return tmp.str();
728 }
729
730
731 docstring const LaTeXFeatures::getTClassPreamble() const
732 {
733         // the text class specific preamble
734         TextClass const & tclass = params_.getTextClass();
735         odocstringstream tcpreamble;
736
737         tcpreamble << tclass.preamble();
738
739         list<docstring>::const_iterator cit = usedLayouts_.begin();
740         list<docstring>::const_iterator end = usedLayouts_.end();
741         for (; cit != end; ++cit) {
742                 tcpreamble << tclass[*cit]->preamble();
743         }
744
745         InsetLayouts const & insetlayouts = tclass.insetlayouts();
746         InsetLayouts::const_iterator cit2 = insetlayouts.begin();
747         InsetLayouts::const_iterator end2 = insetlayouts.end();
748         for (; cit2 != end2; ++cit2) {
749                 if (isRequired(to_utf8(cit2->first))) {
750                         tcpreamble << from_utf8(cit2->second.preamble);
751                 }
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_.getTextClass().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));
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         }
875 }
876
877
878 } // namespace lyx