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