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