]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.cpp
2db41bf4caa51fe2bb43979291d9484ad3aa56f0
[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 "BufferParams.h"
20 #include "Color.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
190 /////////////////////////////////////////////////////////////////////
191 //
192 // LaTeXFeatures
193 //
194 /////////////////////////////////////////////////////////////////////
195
196 LaTeXFeatures::PackagesList LaTeXFeatures::packages_;
197
198
199 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p,
200                              OutputParams const & r)
201         : buffer_(&b), params_(p), runparams_(r)
202 {}
203
204
205 bool LaTeXFeatures::useBabel() const
206 {
207         return lyxrc.language_use_babel ||
208                 (bufferParams().language->lang() != lyxrc.default_language &&
209                  !bufferParams().language->babel().empty()) ||
210                 this->hasLanguages();
211 }
212
213
214 void LaTeXFeatures::require(string const & name)
215 {
216         if (isRequired(name))
217                 return;
218
219         features_.push_back(name);
220 }
221
222
223 void LaTeXFeatures::getAvailable()
224 {
225         Lexer lex(0, 0);
226         support::FileName const real_file = libFileSearch("", "packages.lst");
227
228         if (real_file.empty())
229                 return;
230
231         lex.setFile(real_file);
232
233         if (!lex.isOK())
234                 return;
235
236         // Make sure that we are clean
237         packages_.clear();
238
239         bool finished = false;
240         // Parse config-file
241         while (lex.isOK() && !finished) {
242                 switch (lex.lex()) {
243                 case Lexer::LEX_FEOF:
244                         finished = true;
245                         break;
246                 default:
247                         string const name = lex.getString();
248                         PackagesList::const_iterator begin = packages_.begin();
249                         PackagesList::const_iterator end   = packages_.end();
250                         if (find(begin, end, name) == end)
251                                 packages_.push_back(name);
252                 }
253         }
254 }
255
256
257 void LaTeXFeatures::useLayout(docstring const & layoutname)
258 {
259         // Some code to avoid loops in dependency definition
260         static int level = 0;
261         const int maxlevel = 30;
262         if (level > maxlevel) {
263                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
264                        << "recursion attained by layout "
265                        << to_utf8(layoutname) << endl;
266                 return;
267         }
268
269         TextClass const & tclass = params_.getTextClass();
270         if (tclass.hasLayout(layoutname)) {
271                 // Is this layout already in usedLayouts?
272                 list<docstring>::const_iterator cit = usedLayouts_.begin();
273                 list<docstring>::const_iterator end = usedLayouts_.end();
274                 for (; cit != end; ++cit) {
275                         if (layoutname == *cit)
276                                 return;
277                 }
278
279                 LayoutPtr const & lyt = tclass[layoutname];
280                 if (!lyt->depends_on().empty()) {
281                         ++level;
282                         useLayout(lyt->depends_on());
283                         --level;
284                 }
285                 usedLayouts_.push_back(layoutname);
286         } else {
287                 lyxerr << "LaTeXFeatures::useLayout: layout `"
288                        << to_utf8(layoutname) << "' does not exist in this class"
289                        << endl;
290         }
291
292         --level;
293 }
294
295
296 bool LaTeXFeatures::isRequired(string const & name) const
297 {
298         return find(features_.begin(), features_.end(), name) != features_.end();
299 }
300
301
302 bool LaTeXFeatures::mustProvide(string const & name) const
303 {
304         return isRequired(name) && !params_.getTextClass().provides(name);
305 }
306
307
308 bool LaTeXFeatures::isAvailable(string const & name)
309 {
310         if (packages_.empty())
311                 getAvailable();
312         return find(packages_.begin(), packages_.end(), name) != packages_.end();
313 }
314
315
316 void LaTeXFeatures::addPreambleSnippet(string const & preamble)
317 {
318         FeaturesList::const_iterator begin = preamble_snippets_.begin();
319         FeaturesList::const_iterator end   = preamble_snippets_.end();
320         if (find(begin, end, preamble) == end)
321                 preamble_snippets_.push_back(preamble);
322 }
323
324
325 void LaTeXFeatures::useFloat(string const & name)
326 {
327         usedFloats_.insert(name);
328         // We only need float.sty if we use non builtin floats, or if we
329         // use the "H" modifier. This includes modified table and
330         // figure floats. (Lgb)
331         Floating const & fl = params_.getTextClass().floats().getType(name);
332         if (!fl.type().empty() && !fl.builtin()) {
333                 require("float");
334         }
335 }
336
337
338 void LaTeXFeatures::useLanguage(Language const * lang)
339 {
340         if (!lang->babel().empty())
341                 UsedLanguages_.insert(lang);
342 }
343
344
345 void LaTeXFeatures::includeFile(docstring const & key, string const & name)
346 {
347         IncludedFiles_[key] = name;
348 }
349
350
351 bool LaTeXFeatures::hasLanguages() const
352 {
353         return !UsedLanguages_.empty();
354 }
355
356
357 string LaTeXFeatures::getLanguages() const
358 {
359         ostringstream languages;
360
361         LanguageList::const_iterator const begin = UsedLanguages_.begin();
362         for (LanguageList::const_iterator cit = begin;
363              cit != UsedLanguages_.end();
364              ++cit) {
365                 if (cit != begin)
366                         languages << ',';
367                 languages << (*cit)->babel();
368         }
369         return languages.str();
370 }
371
372
373 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
374 {
375         // This does only find encodings of languages supported by babel, but
376         // that does not matter since we don't have a language with an
377         // encoding supported by inputenc but without babel support.
378         set<string> encodings;
379         LanguageList::const_iterator it  = UsedLanguages_.begin();
380         LanguageList::const_iterator end = UsedLanguages_.end();
381         for (; it != end; ++it)
382                 if ((*it)->encoding()->latexName() != doc_encoding &&
383                     (*it)->encoding()->package() == Encoding::inputenc)
384                         encodings.insert((*it)->encoding()->latexName());
385         return encodings;
386 }
387
388 namespace {
389
390 char const * simplefeatures[] = {
391 // note that the package order here will be the same in the LaTeX-output
392         "array",
393         "verbatim",
394         "longtable",
395         "rotating",
396         "latexsym",
397         "pifont",
398         "subfigure",
399         "varioref",
400         "prettyref",
401         /*For a successful cooperation of the `wrapfig' package with the
402           `float' package you should load the `wrapfig' package *after*
403           the `float' package. See the caption package documentation
404           for explanation.*/
405         "float",
406         "wrapfig",
407         "booktabs",
408         "dvipost",
409         "fancybox",
410         "calc",
411         "units",
412         "tipa",
413         "framed",
414         "pdfcolmk",
415         "soul",
416         "textcomp",
417         "xcolor",
418         "pmboxdraw",
419         "bbding",
420         "ifsym",
421         "marvosym",
422         "txfonts",
423         "mathrsfs",
424         "ascii",
425         "url",
426 };
427
428 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
429
430 }
431
432
433 string const LaTeXFeatures::getPackages() const
434 {
435         ostringstream packages;
436         TextClass const & tclass = params_.getTextClass();
437
438         //
439         //  These are all the 'simple' includes.  i.e
440         //  packages which we just \usepackage{package}
441         //
442         for (int i = 0; i < nb_simplefeatures; ++i) {
443                 if (mustProvide(simplefeatures[i]))
444                         packages << "\\usepackage{"
445                                  << simplefeatures[i] << "}\n";
446         }
447
448         //
449         // The rest of these packages are somewhat more complicated
450         // than those above.
451         //
452
453         // esint is preferred for esintoramsmath
454         if ((mustProvide("amsmath") &&
455              params_.use_amsmath != BufferParams::package_off) ||
456             (mustProvide("esintoramsmath") &&
457              params_.use_esint == BufferParams::package_off)) {
458                 packages << "\\usepackage{amsmath}\n";
459         }
460
461         // wasysym is a simple feature, but it must be after amsmath if both
462         // are used
463         // wasysym redefines some integrals (e.g. iint) from amsmath. That
464         // leads to inconsistent integrals. We only load this package if
465         // the document does not contain integrals (then isRequired("esint")
466         // is false) or if esint is used, since esint redefines all relevant
467         // integral symbols from wasysym and amsmath.
468         // See http://bugzilla.lyx.org/show_bug.cgi?id=1942
469         if (mustProvide("wasysym") &&
470             (params_.use_esint != BufferParams::package_off || !isRequired("esint")))
471                 packages << "\\usepackage{wasysym}\n";
472
473         // color.sty
474         if (mustProvide("color")) {
475                 if (params_.graphicsDriver == "default")
476                         packages << "\\usepackage{color}\n";
477                 else
478                         packages << "\\usepackage["
479                                  << params_.graphicsDriver
480                                  << "]{color}\n";
481         }
482
483         // makeidx.sty
484         if (isRequired("makeidx")) {
485                 if (!tclass.provides("makeidx"))
486                         packages << "\\usepackage{makeidx}\n";
487                 packages << "\\makeindex\n";
488         }
489
490         // graphicx.sty
491         if (mustProvide("graphicx") && params_.graphicsDriver != "none") {
492                 if (params_.graphicsDriver == "default")
493                         packages << "\\usepackage{graphicx}\n";
494                 else
495                         packages << "\\usepackage["
496                                  << params_.graphicsDriver
497                                  << "]{graphicx}\n";
498         }
499         // shadecolor for shaded
500         if (mustProvide("framed") && mustProvide("color")) {
501                 RGBColor c = RGBColor(lcolor.getX11Name(Color::shadedbg));
502                 //255.0 to force conversion to double
503                 //NOTE As Jürgen Spitzmüller pointed out, an alternative would be
504                 //to use the xcolor package instead, and then we can do
505                 // \define{shadcolor}{RGB}...
506                 //and not do any conversion. We'd then need to require xcolor
507                 //in InsetNote::validate().
508                 int const stmSize = packages.precision(2);
509                 packages << "\\definecolor{shadecolor}{rgb}{"
510                         << c.r / 255.0 << ',' << c.g / 255.0 << ',' << c.b / 255.0 << "}\n";
511                 packages.precision(stmSize);
512         }
513
514         // lyxskak.sty --- newer chess support based on skak.sty
515         if (mustProvide("chess")) {
516                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
517         }
518
519         // setspace.sty
520         if ((params_.spacing().getSpace() != Spacing::Single
521              && !params_.spacing().isDefault())
522             || isRequired("setspace")) {
523                 packages << "\\usepackage{setspace}\n";
524         }
525         switch (params_.spacing().getSpace()) {
526         case Spacing::Default:
527         case Spacing::Single:
528                 // we dont use setspace.sty so dont print anything
529                 //packages += "\\singlespacing\n";
530                 break;
531         case Spacing::Onehalf:
532                 packages << "\\onehalfspacing\n";
533                 break;
534         case Spacing::Double:
535                 packages << "\\doublespacing\n";
536                 break;
537         case Spacing::Other:
538                 packages << "\\setstretch{"
539                          << params_.spacing().getValue() << "}\n";
540                 break;
541         }
542
543         // amssymb.sty
544         if (mustProvide("amssymb")
545             || params_.use_amsmath == BufferParams::package_on)
546                 packages << "\\usepackage{amssymb}\n";
547
548         // esint must be after amsmath and wasysym, since it will redeclare
549         // inconsistent integral symbols
550         if ((mustProvide("esint") || mustProvide("esintoramsmath")) &&
551             params_.use_esint != BufferParams::package_off)
552                 packages << "\\usepackage{esint}\n";
553
554         // natbib.sty
555         if (mustProvide("natbib")) {
556                 packages << "\\usepackage[";
557                 if (params_.getEngine() == biblio::ENGINE_NATBIB_NUMERICAL) {
558                         packages << "numbers";
559                 } else {
560                         packages << "authoryear";
561                 }
562                 packages << "]{natbib}\n";
563         }
564
565         // jurabib -- we need version 0.6 at least.
566         if (mustProvide("jurabib")) {
567                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
568         }
569
570         // bibtopic -- the dot provides the aux file naming which
571         // LyX can detect.
572         if (mustProvide("bibtopic")) {
573                 packages << "\\usepackage[dot]{bibtopic}\n";
574         }
575
576         if (mustProvide("xy"))
577                 packages << "\\usepackage[all]{xy}\n";
578
579         if (mustProvide("nomencl")) {
580                 // Make it work with the new and old version of the package,
581                 // but don't use the compatibility option since it is
582                 // incompatible to other packages.
583                 packages << "\\usepackage{nomencl}\n"
584                             "% the following is useful when we have the old nomencl.sty package\n"
585                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
586                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
587                             "\\makenomenclature\n";
588         }
589
590         if (mustProvide("listings"))
591                 packages << "\\usepackage{listings}\n";
592
593         return packages.str();
594 }
595
596
597 string const LaTeXFeatures::getMacros() const
598 {
599         ostringstream macros;
600
601         if (!preamble_snippets_.empty())
602                 macros << '\n';
603         FeaturesList::const_iterator pit  = preamble_snippets_.begin();
604         FeaturesList::const_iterator pend = preamble_snippets_.end();
605         for (; pit != pend; ++pit) {
606                 macros << *pit << '\n';
607         }
608
609         if (mustProvide("LyX"))
610                 macros << lyx_def << '\n';
611
612         if (mustProvide("lyxline"))
613                 macros << lyxline_def << '\n';
614
615         if (mustProvide("noun"))
616                 macros << noun_def << '\n';
617
618         if (mustProvide("lyxarrow"))
619                 macros << lyxarrow_def << '\n';
620
621         // quotes.
622         if (mustProvide("quotesinglbase"))
623                 macros << quotesinglbase_def << '\n';
624         if (mustProvide("quotedblbase"))
625                 macros << quotedblbase_def << '\n';
626         if (mustProvide("guilsinglleft"))
627                 macros << guilsinglleft_def << '\n';
628         if (mustProvide("guilsinglright"))
629                 macros << guilsinglright_def << '\n';
630         if (mustProvide("guillemotleft"))
631                 macros << guillemotleft_def << '\n';
632         if (mustProvide("guillemotright"))
633                 macros << guillemotright_def << '\n';
634
635         // Math mode
636         if (mustProvide("boldsymbol") && !isRequired("amsmath"))
637                 macros << boldsymbol_def << '\n';
638         if (mustProvide("binom") && !isRequired("amsmath"))
639                 macros << binom_def << '\n';
640         if (mustProvide("mathcircumflex"))
641                 macros << mathcircumflex_def << '\n';
642
643         // other
644         if (mustProvide("ParagraphLeftIndent"))
645                 macros << paragraphleftindent_def;
646         if (mustProvide("NeedLyXFootnoteCode"))
647                 macros << floatingfootnote_def;
648
649         // some problems with tex->html converters
650         if (mustProvide("NeedTabularnewline"))
651                 macros << tabularnewline_def;
652
653         // greyedout environment (note inset)
654         if (mustProvide("lyxgreyedout"))
655                 macros << lyxgreyedout_def;
656
657         if (mustProvide("lyxdot"))
658                 macros << lyxdot_def << '\n';
659
660         // floats
661         getFloatDefinitions(macros);
662
663         // change tracking
664         if (mustProvide("ct-dvipost")) {
665                 macros << changetracking_dvipost_def;
666         }
667         if (mustProvide("ct-xcolor-soul")) {
668                 int const prec = macros.precision(2);
669         
670                 RGBColor cadd = RGBColor(lcolor.getX11Name(Color::addedtext));
671                 macros << "\\providecolor{lyxadded}{rgb}{"
672                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
673
674                 RGBColor cdel = RGBColor(lcolor.getX11Name(Color::deletedtext));
675                 macros << "\\providecolor{lyxdeleted}{rgb}{"
676                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
677
678                 macros.precision(prec);
679
680                 macros << "\\newcommand{\\lyxadded}[3]{{\\color{lyxadded}#3}}\n"
681                        << "\\newcommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\st{#3}}}\n";
682         }
683         if (mustProvide("ct-none")) {
684                 macros << changetracking_none_def;
685         }
686
687         return macros.str();
688 }
689
690
691 string const LaTeXFeatures::getBabelOptions() const
692 {
693         ostringstream tmp;
694
695         LanguageList::const_iterator it  = UsedLanguages_.begin();
696         LanguageList::const_iterator end =  UsedLanguages_.end();
697         for (; it != end; ++it)
698                 if (!(*it)->latex_options().empty())
699                         tmp << (*it)->latex_options() << '\n';
700         if (!params_.language->latex_options().empty())
701                 tmp << params_.language->latex_options() << '\n';
702
703         return tmp.str();
704 }
705
706
707 docstring const LaTeXFeatures::getTClassPreamble() const
708 {
709         // the text class specific preamble
710         TextClass const & tclass = params_.getTextClass();
711         odocstringstream tcpreamble;
712
713         tcpreamble << tclass.preamble();
714
715         list<docstring>::const_iterator cit = usedLayouts_.begin();
716         list<docstring>::const_iterator end = usedLayouts_.end();
717         for (; cit != end; ++cit) {
718                 tcpreamble << tclass[*cit]->preamble();
719         }
720
721         InsetLayouts const & insetlayouts = tclass.insetlayouts();
722         InsetLayouts::const_iterator cit2 = insetlayouts.begin();
723         InsetLayouts::const_iterator end2 = insetlayouts.end();
724         for (; cit2 != end2; ++cit2) {
725                 if (isRequired(to_utf8(cit2->first))) {
726                         tcpreamble << from_utf8(cit2->second.preamble);
727                 }
728         }
729
730         return tcpreamble.str();
731 }
732
733
734 docstring const LaTeXFeatures::getLyXSGMLEntities() const
735 {
736         // Definition of entities used in the document that are LyX related.
737         odocstringstream entities;
738
739         if (mustProvide("lyxarrow")) {
740                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
741         }
742
743         return entities.str();
744 }
745
746
747 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
748 {
749         odocstringstream sgmlpreamble;
750         // FIXME UNICODE
751         docstring const basename(from_utf8(onlyPath(fname)));
752
753         FileMap::const_iterator end = IncludedFiles_.end();
754         for (FileMap::const_iterator fi = IncludedFiles_.begin();
755              fi != end; ++fi)
756                 // FIXME UNICODE
757                 sgmlpreamble << "\n<!ENTITY " << fi->first
758                              << (isSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
759                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
760
761         return sgmlpreamble.str();
762 }
763
764
765 void LaTeXFeatures::showStruct() const {
766         lyxerr << "LyX needs the following commands when LaTeXing:"
767                << "\n***** Packages:" << getPackages()
768                << "\n***** Macros:" << getMacros()
769                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
770                << "\n***** done." << endl;
771 }
772
773
774 Buffer const & LaTeXFeatures::buffer() const
775 {
776         return *buffer_;
777 }
778
779
780 void LaTeXFeatures::setBuffer(Buffer const & buffer)
781 {
782         buffer_ = &buffer;
783 }
784
785
786 BufferParams const & LaTeXFeatures::bufferParams() const
787 {
788         return params_;
789 }
790
791
792 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
793 {
794         FloatList const & floats = params_.getTextClass().floats();
795
796         // Here we will output the code to create the needed float styles.
797         // We will try to do this as minimal as possible.
798         // \floatstyle{ruled}
799         // \newfloat{algorithm}{htbp}{loa}
800         // \floatname{algorithm}{Algorithm}
801         UsedFloats::const_iterator cit = usedFloats_.begin();
802         UsedFloats::const_iterator end = usedFloats_.end();
803         // ostringstream floats;
804         for (; cit != end; ++cit) {
805                 Floating const & fl = floats.getType((*cit));
806
807                 // For builtin floats we do nothing.
808                 if (fl.builtin()) continue;
809
810                 // We have to special case "table" and "figure"
811                 if (fl.type() == "tabular" || fl.type() == "figure") {
812                         // Output code to modify "table" or "figure"
813                         // but only if builtin == false
814                         // and that have to be true at this point in the
815                         // function.
816                         string const type = fl.type();
817                         string const placement = fl.placement();
818                         string const style = fl.style();
819                         if (!style.empty()) {
820                                 os << "\\floatstyle{" << style << "}\n"
821                                    << "\\restylefloat{" << type << "}\n";
822                         }
823                         if (!placement.empty()) {
824                                 os << "\\floatplacement{" << type << "}{"
825                                    << placement << "}\n";
826                         }
827                 } else {
828                         // The other non builtin floats.
829
830                         string const type = fl.type();
831                         string const placement = fl.placement();
832                         string const ext = fl.ext();
833                         string const within = fl.within();
834                         string const style = fl.style();
835                         string const name = fl.name();
836                         os << "\\floatstyle{" << style << "}\n"
837                            << "\\newfloat{" << type << "}{" << placement
838                            << "}{" << ext << '}';
839                         if (!within.empty())
840                                 os << '[' << within << ']';
841                         os << '\n'
842                            << "\\floatname{" << type << "}{"
843                            << name << "}\n";
844
845                         // What missing here is to code to minimalize the code
846                         // output so that the same floatstyle will not be
847                         // used several times, when the same style is still in
848                         // effect. (Lgb)
849                 }
850         }
851 }
852
853
854 } // namespace lyx