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