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