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