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