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