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