]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.cpp
Push latest Andre's changes toward their true direction:
[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 }
358
359
360 void LaTeXFeatures::includeFile(docstring const & key, string const & name)
361 {
362         IncludedFiles_[key] = name;
363 }
364
365
366 bool LaTeXFeatures::hasLanguages() const
367 {
368         return !UsedLanguages_.empty();
369 }
370
371
372 string LaTeXFeatures::getLanguages() const
373 {
374         ostringstream languages;
375
376         LanguageList::const_iterator const begin = UsedLanguages_.begin();
377         for (LanguageList::const_iterator cit = begin;
378              cit != UsedLanguages_.end();
379              ++cit) {
380                 if (cit != begin)
381                         languages << ',';
382                 languages << (*cit)->babel();
383         }
384         return languages.str();
385 }
386
387
388 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
389 {
390         // This does only find encodings of languages supported by babel, but
391         // that does not matter since we don't have a language with an
392         // encoding supported by inputenc but without babel support.
393         set<string> encodings;
394         LanguageList::const_iterator it  = UsedLanguages_.begin();
395         LanguageList::const_iterator end = UsedLanguages_.end();
396         for (; it != end; ++it)
397                 if ((*it)->encoding()->latexName() != doc_encoding &&
398                     (*it)->encoding()->package() == Encoding::inputenc)
399                         encodings.insert((*it)->encoding()->latexName());
400         return encodings;
401 }
402
403 namespace {
404
405 char const * simplefeatures[] = {
406 // note that the package order here will be the same in the LaTeX-output
407         "array",
408         "verbatim",
409         "longtable",
410         "rotating",
411         "latexsym",
412         "pifont",
413         "subfigure",
414         "varioref",
415         "prettyref",
416         /*For a successful cooperation of the `wrapfig' package with the
417           `float' package you should load the `wrapfig' package *after*
418           the `float' package. See the caption package documentation
419           for explanation.*/
420         "float",
421         "wrapfig",
422         "booktabs",
423         "dvipost",
424         "fancybox",
425         "calc",
426         "units",
427         "tipa",
428         "framed",
429         "pdfcolmk",
430         "soul",
431         "textcomp",
432         "xcolor",
433         "pmboxdraw",
434         "bbding",
435         "ifsym",
436         "marvosym",
437         "txfonts",
438         "mathrsfs",
439         "ascii",
440         "url",
441 };
442
443 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
444
445 }
446
447
448 string const LaTeXFeatures::getPackages() const
449 {
450         ostringstream packages;
451         TextClass const & tclass = params_.getTextClass();
452
453         //
454         //  These are all the 'simple' includes.  i.e
455         //  packages which we just \usepackage{package}
456         //
457         for (int i = 0; i < nb_simplefeatures; ++i) {
458                 if (mustProvide(simplefeatures[i]))
459                         packages << "\\usepackage{"
460                                  << simplefeatures[i] << "}\n";
461         }
462
463         //
464         // The rest of these packages are somewhat more complicated
465         // than those above.
466         //
467
468         // esint is preferred for esintoramsmath
469         if ((mustProvide("amsmath") &&
470              params_.use_amsmath != BufferParams::package_off) ||
471             (mustProvide("esintoramsmath") &&
472              params_.use_esint == BufferParams::package_off)) {
473                 packages << "\\usepackage{amsmath}\n";
474         }
475
476         // wasysym is a simple feature, but it must be after amsmath if both
477         // are used
478         // wasysym redefines some integrals (e.g. iint) from amsmath. That
479         // leads to inconsistent integrals. We only load this package if
480         // the document does not contain integrals (then isRequired("esint")
481         // is false) or if esint is used, since esint redefines all relevant
482         // integral symbols from wasysym and amsmath.
483         // See http://bugzilla.lyx.org/show_bug.cgi?id=1942
484         if (mustProvide("wasysym") &&
485             (params_.use_esint != BufferParams::package_off || !isRequired("esint")))
486                 packages << "\\usepackage{wasysym}\n";
487
488         // color.sty
489         if (mustProvide("color")) {
490                 if (params_.graphicsDriver == "default")
491                         packages << "\\usepackage{color}\n";
492                 else
493                         packages << "\\usepackage["
494                                  << params_.graphicsDriver
495                                  << "]{color}\n";
496         }
497
498         // makeidx.sty
499         if (isRequired("makeidx")) {
500                 if (!tclass.provides("makeidx"))
501                         packages << "\\usepackage{makeidx}\n";
502                 packages << "\\makeindex\n";
503         }
504
505         // graphicx.sty
506         if (mustProvide("graphicx") && params_.graphicsDriver != "none") {
507                 if (params_.graphicsDriver == "default")
508                         packages << "\\usepackage{graphicx}\n";
509                 else
510                         packages << "\\usepackage["
511                                  << params_.graphicsDriver
512                                  << "]{graphicx}\n";
513         }
514         // shadecolor for shaded
515         if (mustProvide("framed") && mustProvide("color")) {
516                 RGBColor c = rgbFromHexName(lcolor.getX11Name(Color_shadedbg));
517                 //255.0 to force conversion to double
518                 //NOTE As Jürgen Spitzmüller pointed out, an alternative would be
519                 //to use the xcolor package instead, and then we can do
520                 // \define{shadcolor}{RGB}...
521                 //and not do any conversion. We'd then need to require xcolor
522                 //in InsetNote::validate().
523                 int const stmSize = packages.precision(2);
524                 packages << "\\definecolor{shadecolor}{rgb}{"
525                         << c.r / 255.0 << ',' << c.g / 255.0 << ',' << c.b / 255.0 << "}\n";
526                 packages.precision(stmSize);
527         }
528
529         // lyxskak.sty --- newer chess support based on skak.sty
530         if (mustProvide("chess")) {
531                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
532         }
533
534         // setspace.sty
535         if ((params_.spacing().getSpace() != Spacing::Single
536              && !params_.spacing().isDefault())
537             || isRequired("setspace")) {
538                 packages << "\\usepackage{setspace}\n";
539         }
540         switch (params_.spacing().getSpace()) {
541         case Spacing::Default:
542         case Spacing::Single:
543                 // we dont use setspace.sty so dont print anything
544                 //packages += "\\singlespacing\n";
545                 break;
546         case Spacing::Onehalf:
547                 packages << "\\onehalfspacing\n";
548                 break;
549         case Spacing::Double:
550                 packages << "\\doublespacing\n";
551                 break;
552         case Spacing::Other:
553                 packages << "\\setstretch{"
554                          << params_.spacing().getValue() << "}\n";
555                 break;
556         }
557
558         // amssymb.sty
559         if (mustProvide("amssymb")
560             || params_.use_amsmath == BufferParams::package_on)
561                 packages << "\\usepackage{amssymb}\n";
562
563         // esint must be after amsmath and wasysym, since it will redeclare
564         // inconsistent integral symbols
565         if ((mustProvide("esint") || mustProvide("esintoramsmath")) &&
566             params_.use_esint != BufferParams::package_off)
567                 packages << "\\usepackage{esint}\n";
568
569         // natbib.sty
570         if (mustProvide("natbib")) {
571                 packages << "\\usepackage[";
572                 if (params_.getEngine() == biblio::ENGINE_NATBIB_NUMERICAL) {
573                         packages << "numbers";
574                 } else {
575                         packages << "authoryear";
576                 }
577                 packages << "]{natbib}\n";
578         }
579
580         // jurabib -- we need version 0.6 at least.
581         if (mustProvide("jurabib")) {
582                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
583         }
584
585         // bibtopic -- the dot provides the aux file naming which
586         // LyX can detect.
587         if (mustProvide("bibtopic")) {
588                 packages << "\\usepackage[dot]{bibtopic}\n";
589         }
590
591         if (mustProvide("xy"))
592                 packages << "\\usepackage[all]{xy}\n";
593
594         if (mustProvide("nomencl")) {
595                 // Make it work with the new and old version of the package,
596                 // but don't use the compatibility option since it is
597                 // incompatible to other packages.
598                 packages << "\\usepackage{nomencl}\n"
599                             "% the following is useful when we have the old nomencl.sty package\n"
600                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
601                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
602                             "\\makenomenclature\n";
603         }
604
605         if (mustProvide("listings"))
606                 packages << "\\usepackage{listings}\n";
607
608         return packages.str();
609 }
610
611
612 string const LaTeXFeatures::getMacros() const
613 {
614         ostringstream macros;
615
616         if (!preamble_snippets_.empty())
617                 macros << '\n';
618         FeaturesList::const_iterator pit  = preamble_snippets_.begin();
619         FeaturesList::const_iterator pend = preamble_snippets_.end();
620         for (; pit != pend; ++pit)
621                 macros << *pit << '\n';
622
623         if (mustProvide("LyX"))
624                 macros << lyx_def << '\n';
625
626         if (mustProvide("lyxline"))
627                 macros << lyxline_def << '\n';
628
629         if (mustProvide("noun"))
630                 macros << noun_def << '\n';
631
632         if (mustProvide("lyxarrow"))
633                 macros << lyxarrow_def << '\n';
634
635         if (mustProvide("textgreek"))
636                 macros << textgreek_def << '\n';
637
638         if (mustProvide("textcyr"))
639                 macros << textcyr_def << '\n';
640
641         // quotes.
642         if (mustProvide("quotesinglbase"))
643                 macros << quotesinglbase_def << '\n';
644         if (mustProvide("quotedblbase"))
645                 macros << quotedblbase_def << '\n';
646         if (mustProvide("guilsinglleft"))
647                 macros << guilsinglleft_def << '\n';
648         if (mustProvide("guilsinglright"))
649                 macros << guilsinglright_def << '\n';
650         if (mustProvide("guillemotleft"))
651                 macros << guillemotleft_def << '\n';
652         if (mustProvide("guillemotright"))
653                 macros << guillemotright_def << '\n';
654
655         // Math mode
656         if (mustProvide("boldsymbol") && !isRequired("amsmath"))
657                 macros << boldsymbol_def << '\n';
658         if (mustProvide("binom") && !isRequired("amsmath"))
659                 macros << binom_def << '\n';
660         if (mustProvide("mathcircumflex"))
661                 macros << mathcircumflex_def << '\n';
662
663         // other
664         if (mustProvide("ParagraphLeftIndent"))
665                 macros << paragraphleftindent_def;
666         if (mustProvide("NeedLyXFootnoteCode"))
667                 macros << floatingfootnote_def;
668
669         // some problems with tex->html converters
670         if (mustProvide("NeedTabularnewline"))
671                 macros << tabularnewline_def;
672
673         // greyedout environment (note inset)
674         if (mustProvide("lyxgreyedout"))
675                 macros << lyxgreyedout_def;
676
677         if (mustProvide("lyxdot"))
678                 macros << lyxdot_def << '\n';
679
680         // floats
681         getFloatDefinitions(macros);
682
683         // change tracking
684         if (mustProvide("ct-dvipost"))
685                 macros << changetracking_dvipost_def;
686
687         if (mustProvide("ct-xcolor-soul")) {
688                 int const prec = macros.precision(2);
689         
690                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
691                 macros << "\\providecolor{lyxadded}{rgb}{"
692                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
693
694                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
695                 macros << "\\providecolor{lyxdeleted}{rgb}{"
696                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
697
698                 macros.precision(prec);
699
700                 macros << "\\newcommand{\\lyxadded}[3]{{\\color{lyxadded}#3}}\n"
701                        << "\\newcommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\st{#3}}}\n";
702         }
703
704         if (mustProvide("ct-none"))
705                 macros << changetracking_none_def;
706
707         return macros.str();
708 }
709
710
711 string const LaTeXFeatures::getBabelOptions() const
712 {
713         ostringstream tmp;
714
715         LanguageList::const_iterator it  = UsedLanguages_.begin();
716         LanguageList::const_iterator end =  UsedLanguages_.end();
717         for (; it != end; ++it)
718                 if (!(*it)->latex_options().empty())
719                         tmp << (*it)->latex_options() << '\n';
720         if (!params_.language->latex_options().empty())
721                 tmp << params_.language->latex_options() << '\n';
722
723         return tmp.str();
724 }
725
726
727 docstring const LaTeXFeatures::getTClassPreamble() const
728 {
729         // the text class specific preamble
730         TextClass const & tclass = params_.getTextClass();
731         odocstringstream tcpreamble;
732
733         tcpreamble << tclass.preamble();
734
735         list<docstring>::const_iterator cit = usedLayouts_.begin();
736         list<docstring>::const_iterator end = usedLayouts_.end();
737         for (; cit != end; ++cit) {
738                 tcpreamble << tclass[*cit]->preamble();
739         }
740
741         InsetLayouts const & insetlayouts = tclass.insetlayouts();
742         InsetLayouts::const_iterator cit2 = insetlayouts.begin();
743         InsetLayouts::const_iterator end2 = insetlayouts.end();
744         for (; cit2 != end2; ++cit2) {
745                 if (isRequired(to_utf8(cit2->first))) {
746                         tcpreamble << from_utf8(cit2->second.preamble);
747                 }
748         }
749
750         return tcpreamble.str();
751 }
752
753
754 docstring const LaTeXFeatures::getLyXSGMLEntities() const
755 {
756         // Definition of entities used in the document that are LyX related.
757         odocstringstream entities;
758
759         if (mustProvide("lyxarrow")) {
760                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
761         }
762
763         return entities.str();
764 }
765
766
767 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
768 {
769         odocstringstream sgmlpreamble;
770         // FIXME UNICODE
771         docstring const basename(from_utf8(onlyPath(fname)));
772
773         FileMap::const_iterator end = IncludedFiles_.end();
774         for (FileMap::const_iterator fi = IncludedFiles_.begin();
775              fi != end; ++fi)
776                 // FIXME UNICODE
777                 sgmlpreamble << "\n<!ENTITY " << fi->first
778                              << (isSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
779                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
780
781         return sgmlpreamble.str();
782 }
783
784
785 void LaTeXFeatures::showStruct() const {
786         lyxerr << "LyX needs the following commands when LaTeXing:"
787                << "\n***** Packages:" << getPackages()
788                << "\n***** Macros:" << getMacros()
789                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
790                << "\n***** done." << endl;
791 }
792
793
794 Buffer const & LaTeXFeatures::buffer() const
795 {
796         return *buffer_;
797 }
798
799
800 void LaTeXFeatures::setBuffer(Buffer const & buffer)
801 {
802         buffer_ = &buffer;
803 }
804
805
806 BufferParams const & LaTeXFeatures::bufferParams() const
807 {
808         return params_;
809 }
810
811
812 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
813 {
814         FloatList const & floats = params_.getTextClass().floats();
815
816         // Here we will output the code to create the needed float styles.
817         // We will try to do this as minimal as possible.
818         // \floatstyle{ruled}
819         // \newfloat{algorithm}{htbp}{loa}
820         // \floatname{algorithm}{Algorithm}
821         UsedFloats::const_iterator cit = usedFloats_.begin();
822         UsedFloats::const_iterator end = usedFloats_.end();
823         // ostringstream floats;
824         for (; cit != end; ++cit) {
825                 Floating const & fl = floats.getType((*cit));
826
827                 // For builtin floats we do nothing.
828                 if (fl.builtin()) continue;
829
830                 // We have to special case "table" and "figure"
831                 if (fl.type() == "tabular" || fl.type() == "figure") {
832                         // Output code to modify "table" or "figure"
833                         // but only if builtin == false
834                         // and that have to be true at this point in the
835                         // function.
836                         string const type = fl.type();
837                         string const placement = fl.placement();
838                         string const style = fl.style();
839                         if (!style.empty()) {
840                                 os << "\\floatstyle{" << style << "}\n"
841                                    << "\\restylefloat{" << type << "}\n";
842                         }
843                         if (!placement.empty()) {
844                                 os << "\\floatplacement{" << type << "}{"
845                                    << placement << "}\n";
846                         }
847                 } else {
848                         // The other non builtin floats.
849
850                         string const type = fl.type();
851                         string const placement = fl.placement();
852                         string const ext = fl.ext();
853                         string const within = fl.within();
854                         string const style = fl.style();
855                         string const name = fl.name();
856                         os << "\\floatstyle{" << style << "}\n"
857                            << "\\newfloat{" << type << "}{" << placement
858                            << "}{" << ext << '}';
859                         if (!within.empty())
860                                 os << '[' << within << ']';
861                         os << '\n'
862                            << "\\floatname{" << type << "}{"
863                            << name << "}\n";
864
865                         // What missing here is to code to minimalize the code
866                         // output so that the same floatstyle will not be
867                         // used several times, when the same style is still in
868                         // effect. (Lgb)
869                 }
870         }
871 }
872
873
874 } // namespace lyx