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