]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.cpp
Revert 23154.
[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 "Encoding.h"
22 #include "Floating.h"
23 #include "FloatList.h"
24 #include "Language.h"
25 #include "Layout.h"
26 #include "Lexer.h"
27 #include "LyXRC.h"
28 #include "TextClass.h"
29
30 #include "support/debug.h"
31 #include "support/docstream.h"
32 #include "support/FileName.h"
33 #include "support/filetools.h"
34 #include "support/lstrings.h"
35
36 using namespace std;
37 using namespace lyx::support;
38
39 namespace lyx {
40
41 /////////////////////////////////////////////////////////////////////
42 //
43 // Strings
44 //
45 /////////////////////////////////////////////////////////////////////
46
47 //\NeedsTeXFormat{LaTeX2e}
48 //\ProvidesPackage{lyx}[1996/01/11 LLE v0.2 (LyX LaTeX Extensions)]
49 //\message{LyX LaTeX Extensions (LLE v0.2) of 11-Jan-1996.}
50
51 static string const lyx_def =
52         "\\providecommand{\\LyX}{L\\kern-.1667em\\lower.25em\\hbox{Y}\\kern-.125emX\\@}";
53
54 static string const lyxline_def =
55         "\\newcommand{\\lyxline}[1][1pt]{%\n"
56         "  \\par\\noindent%\n"
57         "  \\rule[.5ex]{\\linewidth}{#1}\\par}";
58
59 static string const noun_def = "\\newcommand{\\noun}[1]{\\textsc{#1}}";
60
61 static string const lyxarrow_def =
62         "\\newcommand{\\lyxarrow}{\\leavevmode\\,$\\triangleright$\\,\\allowbreak}";
63
64 // for quotes without babel. This does not give perfect results, but
65 // anybody serious about non-english quotes should use babel (JMarc).
66
67 static string const quotedblbase_def =
68         "\\ProvideTextCommandDefault{\\quotedblbase}{%\n"
69         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquotedblright}%\n"
70         "  \\penalty10000\\hskip0em\\relax%\n"
71         "}";
72
73 static string const quotesinglbase_def =
74         "\\ProvideTextCommandDefault{\\quotesinglbase}{%\n"
75         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquoteright}%\n"
76         "  \\penalty10000\\hskip0em\\relax%\n"
77         "}";
78
79 static string const guillemotleft_def =
80         "\\ProvideTextCommandDefault{\\guillemotleft}{%\n"
81         "  {\\usefont{U}{lasy}{m}{n}\\char'50\\kern-.15em\\char'50}%\n"
82         "\\penalty10000\\hskip0pt\\relax%\n"
83         "}";
84
85 static string const guillemotright_def =
86         "\\ProvideTextCommandDefault{\\guillemotright}{%\n"
87         "  \\penalty10000\\hskip0pt%\n"
88         "  {\\usefont{U}{lasy}{m}{n}\\char'51\\kern-.15em\\char'51}%\n"
89         "}";
90
91 static string const guilsinglleft_def =
92         "\\ProvideTextCommandDefault{\\guilsinglleft}{%\n"
93         "  {\\usefont{U}{lasy}{m}{n}\\char'50}%\n"
94         "  \\penalty10000\\hskip0pt\\relax%\n"
95         "}";
96
97 static string const guilsinglright_def =
98         "\\ProvideTextCommandDefault{\\guilsinglright}{%\n"
99         "  \\penalty10000\\hskip0pt%\n"
100         "  {\\usefont{U}{lasy}{m}{n}\\char'51}%\n"
101         "}";
102
103 static string const paragraphleftindent_def =
104         "\\newenvironment{LyXParagraphLeftIndent}[1]%\n"
105         "{\n"
106         "  \\begin{list}{}{%\n"
107         "    \\setlength{\\topsep}{0pt}%\n"
108         "    \\addtolength{\\leftmargin}{#1}\n"
109 // ho hum, yet more things commented out with no hint as to why they
110 // weren't just removed
111 //      "%%    \\addtolength{\\leftmargin}{#1\\textwidth}\n"
112 //      "%%    \\setlength{\\textwidth}{#2\\textwidth}\n"
113 //      "%%    \\setlength\\listparindent\\parindent%\n"
114 //      "%%    \\setlength\\itemindent\\parindent%\n"
115         "    \\setlength{\\parsep}{0pt plus 1pt}%\n"
116         "  }\n"
117         "  \\item[]\n"
118         "}\n"
119         "{\\end{list}}\n";
120
121 static string const floatingfootnote_def =
122         "%% Special footnote code from the package 'stblftnt.sty'\n"
123         "%% Author: Robin Fairbairns -- Last revised Dec 13 1996\n"
124         "\\let\\SF@@footnote\\footnote\n"
125         "\\def\\footnote{\\ifx\\protect\\@typeset@protect\n"
126         "    \\expandafter\\SF@@footnote\n"
127         "  \\else\n"
128         "    \\expandafter\\SF@gobble@opt\n"
129         "  \\fi\n"
130         "}\n"
131         "\\expandafter\\def\\csname SF@gobble@opt \\endcsname{\\@ifnextchar[%]\n"
132         "  \\SF@gobble@twobracket\n"
133         "  \\@gobble\n"
134         "}\n"
135         "\\edef\\SF@gobble@opt{\\noexpand\\protect\n"
136         "  \\expandafter\\noexpand\\csname SF@gobble@opt \\endcsname}\n"
137         "\\def\\SF@gobble@twobracket[#1]#2{}\n";
138
139 static string const boldsymbol_def =
140         "%% Bold symbol macro for standard LaTeX users\n"
141         "\\providecommand{\\boldsymbol}[1]{\\mbox{\\boldmath $#1$}}\n";
142
143 static string const binom_def =
144         "%% Binom macro for standard LaTeX users\n"
145         "\\newcommand{\\binom}[2]{{#1 \\choose #2}}\n";
146
147 static string const mathcircumflex_def =
148         "%% For printing a cirumflex inside a formula\n"
149         "\\newcommand{\\mathcircumflex}[0]{\\mbox{\\^{}}}\n";
150
151 static string const tabularnewline_def =
152         "%% Because html converters don't know tabularnewline\n"
153         "\\providecommand{\\tabularnewline}{\\\\}\n";
154         
155 static string const lyxgreyedout_def =
156         "%% The greyedout annotation environment\n"
157         "\\newenvironment{lyxgreyedout}{\\textcolor[gray]{0.8}\\bgroup}{\\egroup}\n";
158
159 // We want to omit the file extension for includegraphics, but this does not
160 // work when the filename contains other dots.
161 // Idea from http://www.tex.ac.uk/cgi-bin/texfaq2html?label=unkgrfextn
162 static string const lyxdot_def =
163         "%% A simple dot to overcome graphicx limitations\n"
164         "\\newcommand{\\lyxdot}{.}\n";
165
166 static string const changetracking_dvipost_def =
167         "%% Change tracking with dvipost\n"
168         "\\dvipostlayout\n"
169         "\\dvipost{osstart color push Red}\n"
170         "\\dvipost{osend color pop}\n"
171         "\\dvipost{cbstart color push Blue}\n"
172         "\\dvipost{cbend color pop}\n"
173         "\\newcommand{\\lyxadded}[3]{\\changestart#3\\changeend}\n"
174         "\\newcommand{\\lyxdeleted}[3]{%\n"
175         "\\changestart\\overstrikeon#3\\overstrikeoff\\changeend}\n";
176
177 static string const changetracking_xcolor_soul_def =
178         "%% Change tracking with soul\n"
179         "\\newcommand{\\lyxadded}[3]{{\\color{lyxadded}#3}}\n"
180         "\\newcommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\st{#3}}}\n";
181
182 static string const changetracking_xcolor_soul_hyperref_def =
183         "%% Change tracking with soul\n"
184         "\\newcommand{\\lyxadded}[3]{{\\texorpdfstring{\\color{lyxadded}}{}#3}}\n"
185         "\\newcommand{\\lyxdeleted}[3]{{\\texorpdfstring{\\color{lyxdeleted}\\st{#3}}{}}}\n";
186
187 static string const changetracking_none_def =
188         "\\newcommand{\\lyxadded}[3]{#3}\n"
189         "\\newcommand{\\lyxdeleted}[3]{}\n";
190
191 static string const textgreek_def =
192         "\\DeclareRobustCommand{\\greektext}{%\n"
193         " \\fontencoding{LGR}\\selectfont\n"
194         " \\def\\encodingdefault{LGR}}\n"
195         "\\DeclareRobustCommand{\\textgreek}[1]{\\leavevmode{\\greektext #1}}\n"
196         "\\DeclareFontEncoding{LGR}{}{}\n";
197
198 static string const textcyr_def =
199         "\\DeclareRobustCommand{\\cyrtext}{%\n"
200         " \\fontencoding{T2A}\\selectfont\n"
201         " \\def\\encodingdefault{T2A}}\n"
202         "\\DeclareRobustCommand{\\textcyr}[1]{\\leavevmode{\\cyrtext #1}}\n"
203         "\\DeclareFontEncoding{T2A}{}{}\n";
204
205 static string const newlyxcommand_def =
206         "%% Math macros with multiple optional parameters\n"
207         "% #1<-\\foo\n"
208         "\\def\\newlyxcommand#1{\n"
209         "  \\@ifnextchar[%]\n"
210         "  {\\newlyxcommand@arity{#1}}\n"
211         "  {\\newlyxcommand@arity{#1}[0]}\n"
212         "}\n"
213         "\n"
214         "% #1<-\\foo #2<-arity\n"
215         "\\def\\newlyxcommand@arity#1[#2]{\n"
216         "  \\@ifnextchar[%]\n"
217         "  {\\newlyxcommand@firstopt{#1}{}{#2}}\n"
218         "  {\\newlyxcommand@def#1{#2}}\n"
219         "}\n"
220         "\n"
221         "% #1<-\\foo #2<-iii #3<-arity #4<-default value for (#2+1)th argument\n"
222         "\\def\\newlyxcommand@firstopt#1#2#3[#4]{\n"
223         "  % ##1<-\\foo@\n"
224         "  \\def\\@defclause##1{\n"
225         "    \\def#1{\n"
226         "      \\@ifnextchar[%]\n"
227         "      {##1{}{#4}}\n"
228         "      {##1{}{#4}[#4]}}\n"
229         "  }\n"
230         "  \\expandafter\\@defclause\\csname\\expandafter\\@gobble\\string#1@\\endcsname\n"
231         "  \\@ifnextchar[%]\n"
232         "  {\\newlyxcommand@opt{#1}{#2}{#3}}\n"
233         "  {\\newlyxcommand@last{#1}{#2}{#3}[#4]}\n"
234         "}\n"
235         "\n"
236         "\\begingroup\n"
237         "\\catcode`\\Q=3\n"
238         "\\gdef\\@myempty{Q}\n"
239         "\\endgroup\n"
240         "\n"
241         "% #1<-\\foo #2<-iii #3<-arity #4<-default value for (#2+1)th argument\n"
242         "\\def\\newlyxcommand@opt#1#2#3[#4]{\n"
243         "  % ##1<-\\foo@iii ##2<-\\foo@iiii \n"
244         "  % ####1<-{a}{b}{c} ####2<-default value ####3<- default arg\n"
245         "  \\def\\@defclause##1##2{\n"
246         "    \\def##1####1####2[####3]{\n"
247         "      \\ifx\\@myempty####3\\@myempty%\n"
248         "        \\def\\@callnext{\n"
249         "          \\@ifnextchar[%]\n"
250         "          {##2{####1{####2}}{#4}}\n"
251         "          {##2{####1{####2}}{#4}[#4]}\n"
252         "      }\n"
253         "      \\else\n"
254         "        \\def\\@callnext{\n"
255         "          \\@ifnextchar[%]\n"
256         "          {##2{####1{####3}}{#4}}\n"
257         "          {##2{####1{####3}}{#4}[#4]}\n"
258         "      }\n"
259         "      \\fi\n"
260         "      \\@callnext\n"
261         "    }\n"
262         "  }\n"
263         "  \\expandafter\\def\\expandafter\\@clausename\\expandafter{\\csname\\expandafter\\@gobble\\string#1@#2\\endcsname}\n"
264         "  \\expandafter\\def\\expandafter\\@nextclausename\\expandafter{\\csname\\expandafter\\@gobble\\string#1@#2i\\endcsname}\n"
265         "  \\expandafter\\expandafter\\expandafter  \n"
266         "  \\@defclause\\expandafter\\@clausename\\@nextclausename\n"
267         "  \\@ifnextchar[%]\n"
268         "  {\\newlyxcommand@opt{#1}{#2i}{#3}}\n"
269         "  {\\newlyxcommand@last{#1}{#2i}{#3}[#4]}\n"
270         "}\n"
271         "\n"
272         "% #1<-\\foo #2<-iii #3<-arity #4<-default value for (#2+1)th argument\n"
273         "\\def\\newlyxcommand@last#1#2#3[#4]{\n"
274         "  \\def\\@defclause##1##2{\n"
275         "    \\def##1####1####2[####3]{\n"
276         "      \\ifx\\@myempty####3\\@myempty%\n"
277         "        \\def\\@callnext{##2####1{####2}}\n"
278         "      \\else\n"
279         "        \\def\\@callnext{##2####1{####3}}\n"
280         "      \\fi\n"
281         "      \\@callnext\n"
282         "    }\n"
283         "  }\n"
284         "  \\expandafter\\def\\expandafter\\@clausename\\expandafter{\\csname\\expandafter\\@gobble\\string#1@#2\\endcsname}\n"
285         "  \\expandafter\\def\\expandafter\\@nextclausename\\expandafter{\\csname\\expandafter\\@gobble\\string#1@#2i\\endcsname}\n"
286         "  \\expandafter\\expandafter\\expandafter\n"
287         "  \\@defclause\\expandafter\\@clausename\\@nextclausename\n"
288         "  \\expandafter\\newlyxcommand@def\\csname\\expandafter\\@gobble\\string#1@#2i\\endcsname{#3}\n"
289         "}\n"
290         "\n"
291         "% #1<-\\foo #2<-arity #3<-definition\n"
292         "\\def\\newlyxcommand@def#1#2#3{\n"
293         "  \\ifx#20\n"
294         "  \\def#1{#3}\n"
295         "  \\else\n"
296         "  \\def\\@splitargs##1#2##2.{\\def#1##1#2}\\@splitargs##1##2##3##4##5##6##7##8##9.{#3}\n"
297         "  \\fi\n"
298         "}\n";
299         
300 /////////////////////////////////////////////////////////////////////
301 //
302 // LaTeXFeatures
303 //
304 /////////////////////////////////////////////////////////////////////
305
306 LaTeXFeatures::Packages LaTeXFeatures::packages_;
307
308
309 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p,
310                              OutputParams const & r)
311         : buffer_(&b), params_(p), runparams_(r)
312 {}
313
314
315 bool LaTeXFeatures::useBabel() const
316 {
317         return lyxrc.language_use_babel ||
318                 (bufferParams().language->lang() != lyxrc.default_language &&
319                  !bufferParams().language->babel().empty()) ||
320                 this->hasLanguages();
321 }
322
323
324 void LaTeXFeatures::require(string const & name)
325 {
326         features_.insert(name);
327 }
328
329
330 void LaTeXFeatures::require(set<string> const & names)
331 {
332         features_.insert(names.begin(), names.end());
333 }
334
335
336 void LaTeXFeatures::getAvailable()
337 {
338         Lexer lex(0, 0);
339         support::FileName const real_file = libFileSearch("", "packages.lst");
340
341         if (real_file.empty())
342                 return;
343
344         lex.setFile(real_file);
345
346         if (!lex.isOK())
347                 return;
348
349         // Make sure that we are clean
350         packages_.clear();
351
352         bool finished = false;
353         // Parse config-file
354         while (lex.isOK() && !finished) {
355                 switch (lex.lex()) {
356                 case Lexer::LEX_FEOF:
357                         finished = true;
358                         break;
359                 default:
360                         packages_.insert(lex.getString());
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                 if (find(usedLayouts_.begin(), usedLayouts_.end(), layoutname) 
382                     != usedLayouts_.end())
383                         return;
384
385                 Layout const & layout = *tclass[layoutname];
386                 require(layout.requires());
387
388                 if (!layout.depends_on().empty()) {
389                         ++level;
390                         useLayout(layout.depends_on());
391                         --level;
392                 }
393                 usedLayouts_.push_back(layoutname);
394         } else {
395                 lyxerr << "LaTeXFeatures::useLayout: layout `"
396                        << to_utf8(layoutname) << "' does not exist in this class"
397                        << endl;
398         }
399
400         --level;
401 }
402
403
404 bool LaTeXFeatures::isRequired(string const & name) const
405 {
406         return features_.find(name) != features_.end();
407 }
408
409
410 bool LaTeXFeatures::mustProvide(string const & name) const
411 {
412         return isRequired(name) && !params_.getTextClass().provides(name);
413 }
414
415
416 bool LaTeXFeatures::isAvailable(string const & name)
417 {
418         if (packages_.empty())
419                 getAvailable();
420         string n = name;
421         if (suffixIs(n, ".sty"))
422                 n.erase(name.length() - 4);
423         return packages_.find(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         "tipx",
530         "framed",
531         "soul",
532         "textcomp",
533         "pmboxdraw",
534         "bbding",
535         "ifsym",
536         "marvosym",
537         "txfonts",
538         "mathrsfs",
539         "ascii",
540         "url",
541         "covington",
542         "csquotes",
543         "enumitem",
544         "endnotes",
545         "ifthen",
546         "amsthm",
547         "listings"
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 (mustProvide("setspace") && !tclass.provides("SetSpace"))
656                     packages << "\\usepackage{setspace}\n";
657
658         // amssymb.sty
659         if (mustProvide("amssymb")
660             || params_.use_amsmath == BufferParams::package_on)
661                 packages << "\\usepackage{amssymb}\n";
662
663         // esint must be after amsmath and wasysym, since it will redeclare
664         // inconsistent integral symbols
665         if ((mustProvide("esint") || mustProvide("esintoramsmath")) &&
666             params_.use_esint != BufferParams::package_off)
667                 packages << "\\usepackage{esint}\n";
668
669         // natbib.sty
670         if (mustProvide("natbib")) {
671                 packages << "\\usepackage[";
672                 if (params_.getEngine() == biblio::ENGINE_NATBIB_NUMERICAL) {
673                         packages << "numbers";
674                 } else {
675                         packages << "authoryear";
676                 }
677                 packages << "]{natbib}\n";
678         }
679
680         // jurabib -- we need version 0.6 at least.
681         if (mustProvide("jurabib")) {
682                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
683         }
684
685         // bibtopic -- the dot provides the aux file naming which
686         // LyX can detect.
687         if (mustProvide("bibtopic")) {
688                 packages << "\\usepackage[dot]{bibtopic}\n";
689         }
690
691         if (mustProvide("xy"))
692                 packages << "\\usepackage[all]{xy}\n";
693
694         if (mustProvide("nomencl")) {
695                 // Make it work with the new and old version of the package,
696                 // but don't use the compatibility option since it is
697                 // incompatible to other packages.
698                 packages << "\\usepackage{nomencl}\n"
699                             "% the following is useful when we have the old nomencl.sty package\n"
700                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
701                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
702                             "\\makenomenclature\n";
703         }
704
705         return packages.str();
706 }
707
708
709 string const LaTeXFeatures::getMacros() const
710 {
711         ostringstream macros;
712
713         if (!preamble_snippets_.empty())
714                 macros << '\n';
715         SnippetList::const_iterator pit  = preamble_snippets_.begin();
716         SnippetList::const_iterator pend = preamble_snippets_.end();
717         for (; pit != pend; ++pit)
718                 macros << *pit << '\n';
719
720         if (mustProvide("LyX"))
721                 macros << lyx_def << '\n';
722
723         if (mustProvide("lyxline"))
724                 macros << lyxline_def << '\n';
725
726         if (mustProvide("noun"))
727                 macros << noun_def << '\n';
728
729         if (mustProvide("lyxarrow"))
730                 macros << lyxarrow_def << '\n';
731
732         if (mustProvide("textgreek"))
733                 macros << textgreek_def << '\n';
734
735         if (mustProvide("textcyr"))
736                 macros << textcyr_def << '\n';
737
738         // quotes.
739         if (mustProvide("quotesinglbase"))
740                 macros << quotesinglbase_def << '\n';
741         if (mustProvide("quotedblbase"))
742                 macros << quotedblbase_def << '\n';
743         if (mustProvide("guilsinglleft"))
744                 macros << guilsinglleft_def << '\n';
745         if (mustProvide("guilsinglright"))
746                 macros << guilsinglright_def << '\n';
747         if (mustProvide("guillemotleft"))
748                 macros << guillemotleft_def << '\n';
749         if (mustProvide("guillemotright"))
750                 macros << guillemotright_def << '\n';
751
752         // Math mode
753         if (mustProvide("boldsymbol") && !isRequired("amsmath"))
754                 macros << boldsymbol_def << '\n';
755         if (mustProvide("binom") && !isRequired("amsmath"))
756                 macros << binom_def << '\n';
757         if (mustProvide("mathcircumflex"))
758                 macros << mathcircumflex_def << '\n';
759         if (mustProvide("newlyxcommand"))
760                 macros << newlyxcommand_def << '\n';
761
762         // other
763         if (mustProvide("ParagraphLeftIndent"))
764                 macros << paragraphleftindent_def;
765         if (mustProvide("NeedLyXFootnoteCode"))
766                 macros << floatingfootnote_def;
767
768         // some problems with tex->html converters
769         if (mustProvide("NeedTabularnewline"))
770                 macros << tabularnewline_def;
771
772         // greyedout environment (note inset)
773         if (mustProvide("lyxgreyedout"))
774                 macros << lyxgreyedout_def;
775
776         if (mustProvide("lyxdot"))
777                 macros << lyxdot_def << '\n';
778
779         // floats
780         getFloatDefinitions(macros);
781
782         // change tracking
783         if (mustProvide("ct-dvipost"))
784                 macros << changetracking_dvipost_def;
785
786         if (mustProvide("ct-xcolor-soul")) {
787                 int const prec = macros.precision(2);
788         
789                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
790                 macros << "\\providecolor{lyxadded}{rgb}{"
791                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
792
793                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
794                 macros << "\\providecolor{lyxdeleted}{rgb}{"
795                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
796
797                 macros.precision(prec);
798                 
799                 if (isRequired("hyperref"))
800                         macros << changetracking_xcolor_soul_hyperref_def;
801                 else
802                         macros << changetracking_xcolor_soul_def;
803         }
804
805         if (mustProvide("ct-none"))
806                 macros << changetracking_none_def;
807
808         return macros.str();
809 }
810
811
812 string const LaTeXFeatures::getBabelOptions() const
813 {
814         ostringstream tmp;
815
816         LanguageList::const_iterator it  = UsedLanguages_.begin();
817         LanguageList::const_iterator end =  UsedLanguages_.end();
818         for (; it != end; ++it)
819                 if (!(*it)->latex_options().empty())
820                         tmp << (*it)->latex_options() << '\n';
821         if (!params_.language->latex_options().empty())
822                 tmp << params_.language->latex_options() << '\n';
823
824         return tmp.str();
825 }
826
827
828 docstring const LaTeXFeatures::getTClassPreamble() const
829 {
830         // the text class specific preamble
831         TextClass const & tclass = params_.getTextClass();
832         odocstringstream tcpreamble;
833
834         tcpreamble << tclass.preamble();
835
836         list<docstring>::const_iterator cit = usedLayouts_.begin();
837         list<docstring>::const_iterator end = usedLayouts_.end();
838         for (; cit != end; ++cit) {
839                 tcpreamble << tclass[*cit]->preamble();
840         }
841
842         return tcpreamble.str();
843 }
844
845
846 docstring const LaTeXFeatures::getLyXSGMLEntities() const
847 {
848         // Definition of entities used in the document that are LyX related.
849         odocstringstream entities;
850
851         if (mustProvide("lyxarrow")) {
852                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
853         }
854
855         return entities.str();
856 }
857
858
859 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
860 {
861         odocstringstream sgmlpreamble;
862         // FIXME UNICODE
863         docstring const basename(from_utf8(onlyPath(fname)));
864
865         FileMap::const_iterator end = IncludedFiles_.end();
866         for (FileMap::const_iterator fi = IncludedFiles_.begin();
867              fi != end; ++fi)
868                 // FIXME UNICODE
869                 sgmlpreamble << "\n<!ENTITY " << fi->first
870                              << (isSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
871                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
872
873         return sgmlpreamble.str();
874 }
875
876
877 void LaTeXFeatures::showStruct() const {
878         lyxerr << "LyX needs the following commands when LaTeXing:"
879                << "\n***** Packages:" << getPackages()
880                << "\n***** Macros:" << getMacros()
881                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
882                << "\n***** done." << endl;
883 }
884
885
886 Buffer const & LaTeXFeatures::buffer() const
887 {
888         return *buffer_;
889 }
890
891
892 void LaTeXFeatures::setBuffer(Buffer const & buffer)
893 {
894         buffer_ = &buffer;
895 }
896
897
898 BufferParams const & LaTeXFeatures::bufferParams() const
899 {
900         return params_;
901 }
902
903
904 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
905 {
906         FloatList const & floats = params_.getTextClass().floats();
907
908         // Here we will output the code to create the needed float styles.
909         // We will try to do this as minimal as possible.
910         // \floatstyle{ruled}
911         // \newfloat{algorithm}{htbp}{loa}
912         // \floatname{algorithm}{Algorithm}
913         UsedFloats::const_iterator cit = usedFloats_.begin();
914         UsedFloats::const_iterator end = usedFloats_.end();
915         // ostringstream floats;
916         for (; cit != end; ++cit) {
917                 Floating const & fl = floats.getType((*cit));
918
919                 // For builtin floats we do nothing.
920                 if (fl.builtin()) continue;
921
922                 // We have to special case "table" and "figure"
923                 if (fl.type() == "tabular" || fl.type() == "figure") {
924                         // Output code to modify "table" or "figure"
925                         // but only if builtin == false
926                         // and that have to be true at this point in the
927                         // function.
928                         string const type = fl.type();
929                         string const placement = fl.placement();
930                         string const style = fl.style();
931                         if (!style.empty()) {
932                                 os << "\\floatstyle{" << style << "}\n"
933                                    << "\\restylefloat{" << type << "}\n";
934                         }
935                         if (!placement.empty()) {
936                                 os << "\\floatplacement{" << type << "}{"
937                                    << placement << "}\n";
938                         }
939                 } else {
940                         // The other non builtin floats.
941
942                         string const type = fl.type();
943                         string const placement = fl.placement();
944                         string const ext = fl.ext();
945                         string const within = fl.within();
946                         string const style = fl.style();
947                         string const name = fl.name();
948                         os << "\\floatstyle{" << style << "}\n"
949                            << "\\newfloat{" << type << "}{" << placement
950                            << "}{" << ext << '}';
951                         if (!within.empty())
952                                 os << '[' << within << ']';
953                         os << '\n'
954                            << "\\floatname{" << type << "}{"
955                            << name << "}\n";
956
957                         // What missing here is to code to minimalize the code
958                         // output so that the same floatstyle will not be
959                         // used several times, when the same style is still in
960                         // effect. (Lgb)
961                 }
962         }
963 }
964
965
966 } // namespace lyx