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