]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.cpp
cosmetics
[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         "pdfcolmk",
523         "soul",
524         "textcomp",
525         "xcolor",
526         "pmboxdraw",
527         "bbding",
528         "ifsym",
529         "marvosym",
530         "txfonts",
531         "mathrsfs",
532         "ascii",
533         "url",
534         "covington",
535         "csquotes",
536         "enumitem",
537         "endnotes",
538         "ifthen",
539         "amsthm"
540 };
541
542 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
543
544 }
545
546
547 string const LaTeXFeatures::getPackages() const
548 {
549         ostringstream packages;
550         TextClass const & tclass = params_.getTextClass();
551
552         // FIXME: currently, we can only load packages and macros known
553         // to LyX.
554         // However, with the Require tag of layouts/custom insets,
555         // also inknown packages can be requested. They are silently
556         // swallowed now. We should change this eventually.
557
558         //
559         //  These are all the 'simple' includes.  i.e
560         //  packages which we just \usepackage{package}
561         //
562         for (int i = 0; i < nb_simplefeatures; ++i) {
563                 if (mustProvide(simplefeatures[i]))
564                         packages << "\\usepackage{"
565                                  << simplefeatures[i] << "}\n";
566         }
567
568         //
569         // The rest of these packages are somewhat more complicated
570         // than those above.
571         //
572
573         // esint is preferred for esintoramsmath
574         if ((mustProvide("amsmath") &&
575              params_.use_amsmath != BufferParams::package_off) ||
576             (mustProvide("esintoramsmath") &&
577              params_.use_esint == BufferParams::package_off)) {
578                 packages << "\\usepackage{amsmath}\n";
579         }
580         
581         // wasysym is a simple feature, but it must be after amsmath if both
582         // are used
583         // wasysym redefines some integrals (e.g. iint) from amsmath. That
584         // leads to inconsistent integrals. We only load this package if
585         // the document does not contain integrals (then isRequired("esint")
586         // is false) or if esint is used, since esint redefines all relevant
587         // integral symbols from wasysym and amsmath.
588         // See http://bugzilla.lyx.org/show_bug.cgi?id=1942
589         if (mustProvide("wasysym") &&
590             (params_.use_esint != BufferParams::package_off || !isRequired("esint")))
591                 packages << "\\usepackage{wasysym}\n";
592
593         // color.sty
594         if (mustProvide("color")) {
595                 if (params_.graphicsDriver == "default")
596                         packages << "\\usepackage{color}\n";
597                 else
598                         packages << "\\usepackage["
599                                  << params_.graphicsDriver
600                                  << "]{color}\n";
601         }
602
603         // makeidx.sty
604         if (isRequired("makeidx")) {
605                 if (!tclass.provides("makeidx"))
606                         packages << "\\usepackage{makeidx}\n";
607                 packages << "\\makeindex\n";
608         }
609
610         // graphicx.sty
611         if (mustProvide("graphicx") && params_.graphicsDriver != "none") {
612                 if (params_.graphicsDriver == "default")
613                         packages << "\\usepackage{graphicx}\n";
614                 else
615                         packages << "\\usepackage["
616                                  << params_.graphicsDriver
617                                  << "]{graphicx}\n";
618         }
619         // shadecolor for shaded
620         if (isRequired("framed") && mustProvide("color")) {
621                 RGBColor c = rgbFromHexName(lcolor.getX11Name(Color_shadedbg));
622                 //255.0 to force conversion to double
623                 //NOTE As Jürgen Spitzmüller pointed out, an alternative would be
624                 //to use the xcolor package instead, and then we can do
625                 // \define{shadcolor}{RGB}...
626                 //and not do any conversion. We'd then need to require xcolor
627                 //in InsetNote::validate().
628                 int const stmSize = packages.precision(2);
629                 packages << "\\definecolor{shadecolor}{rgb}{"
630                         << c.r / 255.0 << ',' << c.g / 255.0 << ',' << c.b / 255.0 << "}\n";
631                 packages.precision(stmSize);
632         }
633
634         // lyxskak.sty --- newer chess support based on skak.sty
635         if (mustProvide("chess")) {
636                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
637         }
638
639         // setspace.sty
640         if ((params_.spacing().getSpace() != Spacing::Single
641              && !params_.spacing().isDefault())
642             || isRequired("setspace")) {
643                 packages << "\\usepackage{setspace}\n";
644         }
645         switch (params_.spacing().getSpace()) {
646         case Spacing::Default:
647         case Spacing::Single:
648                 // we dont use setspace.sty so dont print anything
649                 //packages += "\\singlespacing\n";
650                 break;
651         case Spacing::Onehalf:
652                 packages << "\\onehalfspacing\n";
653                 break;
654         case Spacing::Double:
655                 packages << "\\doublespacing\n";
656                 break;
657         case Spacing::Other:
658                 packages << "\\setstretch{"
659                          << params_.spacing().getValue() << "}\n";
660                 break;
661         }
662
663         // amssymb.sty
664         if (mustProvide("amssymb")
665             || params_.use_amsmath == BufferParams::package_on)
666                 packages << "\\usepackage{amssymb}\n";
667
668         // esint must be after amsmath and wasysym, since it will redeclare
669         // inconsistent integral symbols
670         if ((mustProvide("esint") || mustProvide("esintoramsmath")) &&
671             params_.use_esint != BufferParams::package_off)
672                 packages << "\\usepackage{esint}\n";
673
674         // natbib.sty
675         if (mustProvide("natbib")) {
676                 packages << "\\usepackage[";
677                 if (params_.getEngine() == biblio::ENGINE_NATBIB_NUMERICAL) {
678                         packages << "numbers";
679                 } else {
680                         packages << "authoryear";
681                 }
682                 packages << "]{natbib}\n";
683         }
684
685         // jurabib -- we need version 0.6 at least.
686         if (mustProvide("jurabib")) {
687                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
688         }
689
690         // bibtopic -- the dot provides the aux file naming which
691         // LyX can detect.
692         if (mustProvide("bibtopic")) {
693                 packages << "\\usepackage[dot]{bibtopic}\n";
694         }
695
696         if (mustProvide("xy"))
697                 packages << "\\usepackage[all]{xy}\n";
698
699         if (mustProvide("nomencl")) {
700                 // Make it work with the new and old version of the package,
701                 // but don't use the compatibility option since it is
702                 // incompatible to other packages.
703                 packages << "\\usepackage{nomencl}\n"
704                             "% the following is useful when we have the old nomencl.sty package\n"
705                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
706                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
707                             "\\makenomenclature\n";
708         }
709
710         if (mustProvide("listings"))
711                 packages << "\\usepackage{listings}\n";
712
713         return packages.str();
714 }
715
716
717 string const LaTeXFeatures::getMacros() const
718 {
719         ostringstream macros;
720
721         if (!preamble_snippets_.empty())
722                 macros << '\n';
723         FeaturesList::const_iterator pit  = preamble_snippets_.begin();
724         FeaturesList::const_iterator pend = preamble_snippets_.end();
725         for (; pit != pend; ++pit)
726                 macros << *pit << '\n';
727
728         if (mustProvide("LyX"))
729                 macros << lyx_def << '\n';
730
731         if (mustProvide("lyxline"))
732                 macros << lyxline_def << '\n';
733
734         if (mustProvide("noun"))
735                 macros << noun_def << '\n';
736
737         if (mustProvide("lyxarrow"))
738                 macros << lyxarrow_def << '\n';
739
740         if (mustProvide("textgreek"))
741                 macros << textgreek_def << '\n';
742
743         if (mustProvide("textcyr"))
744                 macros << textcyr_def << '\n';
745
746         // quotes.
747         if (mustProvide("quotesinglbase"))
748                 macros << quotesinglbase_def << '\n';
749         if (mustProvide("quotedblbase"))
750                 macros << quotedblbase_def << '\n';
751         if (mustProvide("guilsinglleft"))
752                 macros << guilsinglleft_def << '\n';
753         if (mustProvide("guilsinglright"))
754                 macros << guilsinglright_def << '\n';
755         if (mustProvide("guillemotleft"))
756                 macros << guillemotleft_def << '\n';
757         if (mustProvide("guillemotright"))
758                 macros << guillemotright_def << '\n';
759
760         // Math mode
761         if (mustProvide("boldsymbol") && !isRequired("amsmath"))
762                 macros << boldsymbol_def << '\n';
763         if (mustProvide("binom") && !isRequired("amsmath"))
764                 macros << binom_def << '\n';
765         if (mustProvide("mathcircumflex"))
766                 macros << mathcircumflex_def << '\n';
767         if (mustProvide("newlyxcommand"))
768                 macros << newlyxcommand_def << '\n';
769
770         // other
771         if (mustProvide("ParagraphLeftIndent"))
772                 macros << paragraphleftindent_def;
773         if (mustProvide("NeedLyXFootnoteCode"))
774                 macros << floatingfootnote_def;
775
776         // some problems with tex->html converters
777         if (mustProvide("NeedTabularnewline"))
778                 macros << tabularnewline_def;
779
780         // greyedout environment (note inset)
781         if (mustProvide("lyxgreyedout"))
782                 macros << lyxgreyedout_def;
783
784         if (mustProvide("lyxdot"))
785                 macros << lyxdot_def << '\n';
786
787         // floats
788         getFloatDefinitions(macros);
789
790         // change tracking
791         if (mustProvide("ct-dvipost"))
792                 macros << changetracking_dvipost_def;
793
794         if (mustProvide("ct-xcolor-soul")) {
795                 int const prec = macros.precision(2);
796         
797                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
798                 macros << "\\providecolor{lyxadded}{rgb}{"
799                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
800
801                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
802                 macros << "\\providecolor{lyxdeleted}{rgb}{"
803                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
804
805                 macros.precision(prec);
806
807                 macros << "\\newcommand{\\lyxadded}[3]{{\\color{lyxadded}#3}}\n"
808                        << "\\newcommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\st{#3}}}\n";
809         }
810
811         if (mustProvide("ct-none"))
812                 macros << changetracking_none_def;
813
814         return macros.str();
815 }
816
817
818 string const LaTeXFeatures::getBabelOptions() const
819 {
820         ostringstream tmp;
821
822         LanguageList::const_iterator it  = UsedLanguages_.begin();
823         LanguageList::const_iterator end =  UsedLanguages_.end();
824         for (; it != end; ++it)
825                 if (!(*it)->latex_options().empty())
826                         tmp << (*it)->latex_options() << '\n';
827         if (!params_.language->latex_options().empty())
828                 tmp << params_.language->latex_options() << '\n';
829
830         return tmp.str();
831 }
832
833
834 docstring const LaTeXFeatures::getTClassPreamble() const
835 {
836         // the text class specific preamble
837         TextClass const & tclass = params_.getTextClass();
838         odocstringstream tcpreamble;
839
840         tcpreamble << tclass.preamble();
841
842         list<docstring>::const_iterator cit = usedLayouts_.begin();
843         list<docstring>::const_iterator end = usedLayouts_.end();
844         for (; cit != end; ++cit) {
845                 tcpreamble << tclass[*cit]->preamble();
846         }
847
848         return tcpreamble.str();
849 }
850
851
852 docstring const LaTeXFeatures::getLyXSGMLEntities() const
853 {
854         // Definition of entities used in the document that are LyX related.
855         odocstringstream entities;
856
857         if (mustProvide("lyxarrow")) {
858                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
859         }
860
861         return entities.str();
862 }
863
864
865 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
866 {
867         odocstringstream sgmlpreamble;
868         // FIXME UNICODE
869         docstring const basename(from_utf8(onlyPath(fname)));
870
871         FileMap::const_iterator end = IncludedFiles_.end();
872         for (FileMap::const_iterator fi = IncludedFiles_.begin();
873              fi != end; ++fi)
874                 // FIXME UNICODE
875                 sgmlpreamble << "\n<!ENTITY " << fi->first
876                              << (isSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
877                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
878
879         return sgmlpreamble.str();
880 }
881
882
883 void LaTeXFeatures::showStruct() const {
884         lyxerr << "LyX needs the following commands when LaTeXing:"
885                << "\n***** Packages:" << getPackages()
886                << "\n***** Macros:" << getMacros()
887                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
888                << "\n***** done." << endl;
889 }
890
891
892 Buffer const & LaTeXFeatures::buffer() const
893 {
894         return *buffer_;
895 }
896
897
898 void LaTeXFeatures::setBuffer(Buffer const & buffer)
899 {
900         buffer_ = &buffer;
901 }
902
903
904 BufferParams const & LaTeXFeatures::bufferParams() const
905 {
906         return params_;
907 }
908
909
910 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
911 {
912         FloatList const & floats = params_.getTextClass().floats();
913
914         // Here we will output the code to create the needed float styles.
915         // We will try to do this as minimal as possible.
916         // \floatstyle{ruled}
917         // \newfloat{algorithm}{htbp}{loa}
918         // \floatname{algorithm}{Algorithm}
919         UsedFloats::const_iterator cit = usedFloats_.begin();
920         UsedFloats::const_iterator end = usedFloats_.end();
921         // ostringstream floats;
922         for (; cit != end; ++cit) {
923                 Floating const & fl = floats.getType((*cit));
924
925                 // For builtin floats we do nothing.
926                 if (fl.builtin()) continue;
927
928                 // We have to special case "table" and "figure"
929                 if (fl.type() == "tabular" || fl.type() == "figure") {
930                         // Output code to modify "table" or "figure"
931                         // but only if builtin == false
932                         // and that have to be true at this point in the
933                         // function.
934                         string const type = fl.type();
935                         string const placement = fl.placement();
936                         string const style = fl.style();
937                         if (!style.empty()) {
938                                 os << "\\floatstyle{" << style << "}\n"
939                                    << "\\restylefloat{" << type << "}\n";
940                         }
941                         if (!placement.empty()) {
942                                 os << "\\floatplacement{" << type << "}{"
943                                    << placement << "}\n";
944                         }
945                 } else {
946                         // The other non builtin floats.
947
948                         string const type = fl.type();
949                         string const placement = fl.placement();
950                         string const ext = fl.ext();
951                         string const within = fl.within();
952                         string const style = fl.style();
953                         string const name = fl.name();
954                         os << "\\floatstyle{" << style << "}\n"
955                            << "\\newfloat{" << type << "}{" << placement
956                            << "}{" << ext << '}';
957                         if (!within.empty())
958                                 os << '[' << within << ']';
959                         os << '\n'
960                            << "\\floatname{" << type << "}{"
961                            << name << "}\n";
962
963                         // What missing here is to code to minimalize the code
964                         // output so that the same floatstyle will not be
965                         // used several times, when the same style is still in
966                         // effect. (Lgb)
967                 }
968         }
969 }
970
971
972 } // namespace lyx