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