]> git.lyx.org Git - features.git/blob - src/LaTeXFeatures.cpp
d1d6fdb8dcf04b0992d52e90c212c6543b3be1eb
[features.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         "\\AtBeginDocument{\\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         if (lang->lang() == "vietnamese")
375                 require("vietnamese");
376         // CJK languages do not have a babel name.
377         // They use the CJK package
378         if (lang->encoding()->package() == Encoding::CJK)
379                 require("CJK");
380         // japanese package is special
381         if (lang->encoding()->package() == Encoding::japanese)
382                 require("japanese");
383 }
384
385
386 void LaTeXFeatures::includeFile(docstring const & key, string const & name)
387 {
388         IncludedFiles_[key] = name;
389 }
390
391
392 bool LaTeXFeatures::hasLanguages() const
393 {
394         return !UsedLanguages_.empty();
395 }
396
397
398 string LaTeXFeatures::getLanguages() const
399 {
400         ostringstream languages;
401
402         LanguageList::const_iterator const begin = UsedLanguages_.begin();
403         for (LanguageList::const_iterator cit = begin;
404              cit != UsedLanguages_.end();
405              ++cit) {
406                 if (cit != begin)
407                         languages << ',';
408                 languages << (*cit)->babel();
409         }
410         return languages.str();
411 }
412
413
414 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
415 {
416         // This does only find encodings of languages supported by babel, but
417         // that does not matter since we don't have a language with an
418         // encoding supported by inputenc but without babel support.
419         set<string> encodings;
420         LanguageList::const_iterator it  = UsedLanguages_.begin();
421         LanguageList::const_iterator end = UsedLanguages_.end();
422         for (; it != end; ++it)
423                 if ((*it)->encoding()->latexName() != doc_encoding &&
424                     ((*it)->encoding()->package() == Encoding::inputenc
425                      || (*it)->encoding()->package() == Encoding::japanese))
426                         encodings.insert((*it)->encoding()->latexName());
427         return encodings;
428 }
429
430 namespace {
431
432 char const * simplefeatures[] = {
433 // note that the package order here will be the same in the LaTeX-output
434         "array",
435         "verbatim",
436         "longtable",
437         "rotating",
438         "latexsym",
439         "pifont",
440         // subfig is handled in BufferParams.cpp
441         "varioref",
442         "prettyref",
443         /*For a successful cooperation of the `wrapfig' package with the
444           `float' package you should load the `wrapfig' package *after*
445           the `float' package. See the caption package documentation
446           for explanation.*/
447         "float",
448         "rotfloat",
449         "wrapfig",
450         "booktabs",
451         "dvipost",
452         "fancybox",
453         "calc",
454         "units",
455         "tipa",
456         "tipx",
457         "framed",
458         "soul",
459         "textcomp",
460         "pmboxdraw",
461         "bbding",
462         "ifsym",
463         "marvosym",
464         "txfonts",
465         "mathrsfs",
466         "ascii",
467         "url",
468         "covington",
469         "csquotes",
470         "enumitem",
471         "endnotes",
472         "ifthen",
473         "amsthm",
474         // listings is handled in BufferParams.cpp
475         "bm",
476         "pdfpages",
477         "relsize",
478         "amscd"
479 };
480
481 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
482
483 }
484
485
486 string const LaTeXFeatures::getPackages() const
487 {
488         ostringstream packages;
489         DocumentClass const & tclass = params_.documentClass();
490
491         // FIXME: currently, we can only load packages and macros known
492         // to LyX.
493         // However, with the Require tag of layouts/custom insets,
494         // also inknown packages can be requested. They are silently
495         // swallowed now. We should change this eventually.
496
497         //
498         //  These are all the 'simple' includes.  i.e
499         //  packages which we just \usepackage{package}
500         //
501         for (int i = 0; i < nb_simplefeatures; ++i) {
502                 if (mustProvide(simplefeatures[i]))
503                         packages << "\\usepackage{"
504                                  << simplefeatures[i] << "}\n";
505         }
506
507         //
508         // The rest of these packages are somewhat more complicated
509         // than those above.
510         //
511
512         // esint is preferred for esintoramsmath
513         if ((mustProvide("amsmath") &&
514              params_.use_amsmath != BufferParams::package_off) ||
515             (mustProvide("esintoramsmath") &&
516              params_.use_esint == BufferParams::package_off)) {
517                 packages << "\\usepackage{amsmath}\n";
518         } else if (mustProvide("amsbsy")) {
519                 // amsbsy is already provided by amsmath
520                 packages << "\\usepackage{amsbsy}\n";
521         }
522         
523         // wasysym is a simple feature, but it must be after amsmath if both
524         // are used
525         // wasysym redefines some integrals (e.g. iint) from amsmath. That
526         // leads to inconsistent integrals. We only load this package if
527         // the document does not contain integrals (then isRequired("esint")
528         // is false) or if esint is used, since esint redefines all relevant
529         // integral symbols from wasysym and amsmath.
530         // See http://bugzilla.lyx.org/show_bug.cgi?id=1942
531         if (mustProvide("wasysym") &&
532             (params_.use_esint != BufferParams::package_off || !isRequired("esint")))
533                 packages << "\\usepackage{wasysym}\n";
534
535         // [x]color.sty
536         if (mustProvide("color") || mustProvide("xcolor")) {
537                 string const package =
538                         (mustProvide("xcolor") ? "xcolor" : "color");
539                 if (params_.graphicsDriver == "default")
540                         packages << "\\usepackage{" << package << "}\n";
541                 else
542                         packages << "\\usepackage["
543                                  << params_.graphicsDriver
544                                  << "]{" << package << "}\n";
545         }
546
547         // pdfcolmk must be loaded after color
548         if (mustProvide("pdfcolmk"))
549                 packages << "\\usepackage{pdfcolmk}\n";
550
551         // makeidx.sty
552         if (isRequired("makeidx")) {
553                 if (!tclass.provides("makeidx"))
554                         packages << "\\usepackage{makeidx}\n";
555                 packages << "\\makeindex\n";
556         }
557
558         // graphicx.sty
559         if (mustProvide("graphicx") && params_.graphicsDriver != "none") {
560                 if (params_.graphicsDriver == "default")
561                         packages << "\\usepackage{graphicx}\n";
562                 else
563                         packages << "\\usepackage["
564                                  << params_.graphicsDriver
565                                  << "]{graphicx}\n";
566         }
567         // shadecolor for shaded
568         if (isRequired("framed") && mustProvide("color")) {
569                 RGBColor c = rgbFromHexName(lcolor.getX11Name(Color_shadedbg));
570                 //255.0 to force conversion to double
571                 //NOTE As Jürgen Spitzmüller pointed out, an alternative would be
572                 //to use the xcolor package instead, and then we can do
573                 // \define{shadcolor}{RGB}...
574                 //and not do any conversion. We'd then need to require xcolor
575                 //in InsetNote::validate().
576                 int const stmSize = packages.precision(2);
577                 packages << "\\definecolor{shadecolor}{rgb}{"
578                         << c.r / 255.0 << ',' << c.g / 255.0 << ',' << c.b / 255.0 << "}\n";
579                 packages.precision(stmSize);
580         }
581
582         // lyxskak.sty --- newer chess support based on skak.sty
583         if (mustProvide("chess"))
584                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
585
586         // setspace.sty
587         if (mustProvide("setspace") && !tclass.provides("SetSpace"))
588                 packages << "\\usepackage{setspace}\n";
589
590         // amssymb.sty
591         if (mustProvide("amssymb")
592             || params_.use_amsmath == BufferParams::package_on)
593                 packages << "\\usepackage{amssymb}\n";
594
595         // esint must be after amsmath and wasysym, since it will redeclare
596         // inconsistent integral symbols
597         if ((mustProvide("esint") || mustProvide("esintoramsmath")) &&
598             params_.use_esint != BufferParams::package_off)
599                 packages << "\\usepackage{esint}\n";
600
601         // natbib.sty
602         // Some classes load natbib themselves, but still allow (or even require)
603         // plain numeric citations (ReVTeX is such a case, see bug 5182).
604         // This special case is indicated by the "natbib-internal" key.
605         if (mustProvide("natbib") && !tclass.provides("natbib-internal")) {
606                 packages << "\\usepackage[";
607                 if (params_.citeEngine() == ENGINE_NATBIB_NUMERICAL)
608                         packages << "numbers";
609                 else
610                         packages << "authoryear";
611                 packages << "]{natbib}\n";
612         }
613
614         // jurabib -- we need version 0.6 at least.
615         if (mustProvide("jurabib"))
616                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
617         
618         // xargs -- we need version 1.09 at least
619         if (mustProvide("xargs"))
620                 packages << "\\usepackage{xargs}[2008/03/08]\n";
621
622         // bibtopic -- the dot provides the aux file naming which
623         // LyX can detect.
624         if (mustProvide("bibtopic"))
625                 packages << "\\usepackage[dot]{bibtopic}\n";
626
627         if (mustProvide("xy"))
628                 packages << "\\usepackage[all]{xy}\n";
629
630         if (mustProvide("nomencl")) {
631                 // Make it work with the new and old version of the package,
632                 // but don't use the compatibility option since it is
633                 // incompatible to other packages.
634                 packages << "\\usepackage{nomencl}\n"
635                             "% the following is useful when we have the old nomencl.sty package\n"
636                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
637                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
638                             "\\makenomenclature\n";
639         }
640
641         return packages.str();
642 }
643
644
645 string const LaTeXFeatures::getMacros() const
646 {
647         ostringstream macros;
648
649         if (!preamble_snippets_.empty())
650                 macros << '\n';
651         SnippetList::const_iterator pit  = preamble_snippets_.begin();
652         SnippetList::const_iterator pend = preamble_snippets_.end();
653         for (; pit != pend; ++pit)
654                 macros << *pit << '\n';
655
656         if (mustProvide("papersize"))
657                 if (runparams_.flavor == OutputParams::LATEX)
658                         macros << papersizedvi_def << '\n';
659                 else
660                         macros << papersizepdf_def << '\n';
661
662         if (mustProvide("LyX"))
663                 macros << lyx_def << '\n';
664
665         if (mustProvide("lyxline"))
666                 macros << lyxline_def << '\n';
667
668         if (mustProvide("noun"))
669                 macros << noun_def << '\n';
670
671         if (mustProvide("lyxarrow"))
672                 macros << lyxarrow_def << '\n';
673
674         if (mustProvide("textgreek"))
675                 macros << textgreek_def << '\n';
676
677         if (mustProvide("textcyr"))
678                 macros << textcyr_def << '\n';
679
680         if (mustProvide("lyxmathsym"))
681                 macros << lyxmathsym_def << '\n';
682
683         // quotes.
684         if (mustProvide("quotesinglbase"))
685                 macros << quotesinglbase_def << '\n';
686         if (mustProvide("quotedblbase"))
687                 macros << quotedblbase_def << '\n';
688         if (mustProvide("guilsinglleft"))
689                 macros << guilsinglleft_def << '\n';
690         if (mustProvide("guilsinglright"))
691                 macros << guilsinglright_def << '\n';
692         if (mustProvide("guillemotleft"))
693                 macros << guillemotleft_def << '\n';
694         if (mustProvide("guillemotright"))
695                 macros << guillemotright_def << '\n';
696
697         // Math mode
698         if (mustProvide("binom") && !isRequired("amsmath"))
699                 macros << binom_def << '\n';
700         if (mustProvide("mathcircumflex"))
701                 macros << mathcircumflex_def << '\n';
702
703         // other
704         if (mustProvide("ParagraphLeftIndent"))
705                 macros << paragraphleftindent_def;
706         if (mustProvide("NeedLyXFootnoteCode"))
707                 macros << floatingfootnote_def;
708
709         // some problems with tex->html converters
710         if (mustProvide("NeedTabularnewline"))
711                 macros << tabularnewline_def;
712
713         // greyedout environment (note inset)
714         if (mustProvide("lyxgreyedout"))
715                 macros << lyxgreyedout_def;
716
717         if (mustProvide("lyxdot"))
718                 macros << lyxdot_def << '\n';
719
720         // floats
721         getFloatDefinitions(macros);
722
723         // change tracking
724         if (mustProvide("ct-dvipost"))
725                 macros << changetracking_dvipost_def;
726
727         if (mustProvide("ct-xcolor-soul")) {
728                 int const prec = macros.precision(2);
729         
730                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
731                 macros << "\\providecolor{lyxadded}{rgb}{"
732                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
733
734                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
735                 macros << "\\providecolor{lyxdeleted}{rgb}{"
736                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
737
738                 macros.precision(prec);
739                 
740                 if (isRequired("hyperref"))
741                         macros << changetracking_xcolor_soul_hyperref_def;
742                 else
743                         macros << changetracking_xcolor_soul_def;
744         }
745
746         if (mustProvide("ct-none"))
747                 macros << changetracking_none_def;
748
749         return macros.str();
750 }
751
752
753 string const LaTeXFeatures::getBabelOptions() const
754 {
755         ostringstream tmp;
756
757         LanguageList::const_iterator it  = UsedLanguages_.begin();
758         LanguageList::const_iterator end =  UsedLanguages_.end();
759         for (; it != end; ++it)
760                 if (!(*it)->latex_options().empty())
761                         tmp << (*it)->latex_options() << '\n';
762         if (!params_.language->latex_options().empty())
763                 tmp << params_.language->latex_options() << '\n';
764
765         return tmp.str();
766 }
767
768
769 docstring const LaTeXFeatures::getTClassPreamble() const
770 {
771         // the text class specific preamble
772         DocumentClass const & tclass = params_.documentClass();
773         odocstringstream tcpreamble;
774
775         tcpreamble << tclass.preamble();
776
777         list<docstring>::const_iterator cit = usedLayouts_.begin();
778         list<docstring>::const_iterator end = usedLayouts_.end();
779         for (; cit != end; ++cit) {
780                 tcpreamble << tclass[*cit].preamble();
781         }
782
783         return tcpreamble.str();
784 }
785
786
787 docstring const LaTeXFeatures::getLyXSGMLEntities() const
788 {
789         // Definition of entities used in the document that are LyX related.
790         odocstringstream entities;
791
792         if (mustProvide("lyxarrow")) {
793                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
794         }
795
796         return entities.str();
797 }
798
799
800 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
801 {
802         odocstringstream sgmlpreamble;
803         // FIXME UNICODE
804         docstring const basename(from_utf8(onlyPath(fname)));
805
806         FileMap::const_iterator end = IncludedFiles_.end();
807         for (FileMap::const_iterator fi = IncludedFiles_.begin();
808              fi != end; ++fi)
809                 // FIXME UNICODE
810                 sgmlpreamble << "\n<!ENTITY " << fi->first
811                              << (isSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
812                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
813
814         return sgmlpreamble.str();
815 }
816
817
818 void LaTeXFeatures::showStruct() const
819 {
820         lyxerr << "LyX needs the following commands when LaTeXing:"
821                << "\n***** Packages:" << getPackages()
822                << "\n***** Macros:" << getMacros()
823                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
824                << "\n***** done." << endl;
825 }
826
827
828 Buffer const & LaTeXFeatures::buffer() const
829 {
830         return *buffer_;
831 }
832
833
834 void LaTeXFeatures::setBuffer(Buffer const & buffer)
835 {
836         buffer_ = &buffer;
837 }
838
839
840 BufferParams const & LaTeXFeatures::bufferParams() const
841 {
842         return params_;
843 }
844
845
846 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
847 {
848         FloatList const & floats = params_.documentClass().floats();
849
850         // Here we will output the code to create the needed float styles.
851         // We will try to do this as minimal as possible.
852         // \floatstyle{ruled}
853         // \newfloat{algorithm}{htbp}{loa}
854         // \floatname{algorithm}{Algorithm}
855         UsedFloats::const_iterator cit = usedFloats_.begin();
856         UsedFloats::const_iterator end = usedFloats_.end();
857         // ostringstream floats;
858         for (; cit != end; ++cit) {
859                 Floating const & fl = floats.getType((cit->first));
860
861                 // For builtin floats we do nothing.
862                 if (fl.builtin()) continue;
863
864                 // We have to special case "table" and "figure"
865                 if (fl.type() == "tabular" || fl.type() == "figure") {
866                         // Output code to modify "table" or "figure"
867                         // but only if builtin == false
868                         // and that have to be true at this point in the
869                         // function.
870                         string const type = fl.type();
871                         string const placement = fl.placement();
872                         string const style = fl.style();
873                         if (!style.empty()) {
874                                 os << "\\floatstyle{" << style << "}\n"
875                                    << "\\restylefloat{" << type << "}\n";
876                         }
877                         if (!placement.empty()) {
878                                 os << "\\floatplacement{" << type << "}{"
879                                    << placement << "}\n";
880                         }
881                 } else {
882                         // The other non builtin floats.
883
884                         string const type = fl.type();
885                         string const placement = fl.placement();
886                         string const ext = fl.ext();
887                         string const within = fl.within();
888                         string const style = fl.style();
889                         string const name = fl.name();
890                         os << "\\floatstyle{" << style << "}\n"
891                            << "\\newfloat{" << type << "}{" << placement
892                            << "}{" << ext << '}';
893                         if (!within.empty())
894                                 os << '[' << within << ']';
895                         os << '\n'
896                            << "\\floatname{" << type << "}{"
897                            << name << "}\n";
898
899                         // What missing here is to code to minimalize the code
900                         // output so that the same floatstyle will not be
901                         // used several times, when the same style is still in
902                         // effect. (Lgb)
903                 }
904                 if (cit->second)
905                         os << "\n\\newsubfloat{" << fl.type() << "}\n";
906         }
907 }
908
909
910 } // namespace lyx