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