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