]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.cpp
amsthm 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         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         "covington",
534         "csquotes",
535         "enumitem",
536         "endnotes",
537         "ifthen",
538         "amsthm"
539 };
540
541 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
542
543 }
544
545
546 string const LaTeXFeatures::getPackages() const
547 {
548         ostringstream packages;
549         TextClass const & tclass = params_.getTextClass();
550
551         // FIXME: currently, we can only load packages and macros known
552         // to LyX.
553         // However, with the Require tag of layouts/custom insets,
554         // also inknown packages can be requested. They are silently
555         // swallowed now. We should change this eventually.
556
557         //
558         //  These are all the 'simple' includes.  i.e
559         //  packages which we just \usepackage{package}
560         //
561         for (int i = 0; i < nb_simplefeatures; ++i) {
562                 if (mustProvide(simplefeatures[i]))
563                         packages << "\\usepackage{"
564                                  << simplefeatures[i] << "}\n";
565         }
566
567         //
568         // The rest of these packages are somewhat more complicated
569         // than those above.
570         //
571
572         // esint is preferred for esintoramsmath
573         if ((mustProvide("amsmath") &&
574              params_.use_amsmath != BufferParams::package_off) ||
575             (mustProvide("esintoramsmath") &&
576              params_.use_esint == BufferParams::package_off)) {
577                 packages << "\\usepackage{amsmath}\n";
578         }
579         
580         // wasysym is a simple feature, but it must be after amsmath if both
581         // are used
582         // wasysym redefines some integrals (e.g. iint) from amsmath. That
583         // leads to inconsistent integrals. We only load this package if
584         // the document does not contain integrals (then isRequired("esint")
585         // is false) or if esint is used, since esint redefines all relevant
586         // integral symbols from wasysym and amsmath.
587         // See http://bugzilla.lyx.org/show_bug.cgi?id=1942
588         if (mustProvide("wasysym") &&
589             (params_.use_esint != BufferParams::package_off || !isRequired("esint")))
590                 packages << "\\usepackage{wasysym}\n";
591
592         // color.sty
593         if (mustProvide("color")) {
594                 if (params_.graphicsDriver == "default")
595                         packages << "\\usepackage{color}\n";
596                 else
597                         packages << "\\usepackage["
598                                  << params_.graphicsDriver
599                                  << "]{color}\n";
600         }
601
602         // makeidx.sty
603         if (isRequired("makeidx")) {
604                 if (!tclass.provides("makeidx"))
605                         packages << "\\usepackage{makeidx}\n";
606                 packages << "\\makeindex\n";
607         }
608
609         // graphicx.sty
610         if (mustProvide("graphicx") && params_.graphicsDriver != "none") {
611                 if (params_.graphicsDriver == "default")
612                         packages << "\\usepackage{graphicx}\n";
613                 else
614                         packages << "\\usepackage["
615                                  << params_.graphicsDriver
616                                  << "]{graphicx}\n";
617         }
618         // shadecolor for shaded
619         if (isRequired("framed") && mustProvide("color")) {
620                 RGBColor c = rgbFromHexName(lcolor.getX11Name(Color_shadedbg));
621                 //255.0 to force conversion to double
622                 //NOTE As Jürgen Spitzmüller pointed out, an alternative would be
623                 //to use the xcolor package instead, and then we can do
624                 // \define{shadcolor}{RGB}...
625                 //and not do any conversion. We'd then need to require xcolor
626                 //in InsetNote::validate().
627                 int const stmSize = packages.precision(2);
628                 packages << "\\definecolor{shadecolor}{rgb}{"
629                         << c.r / 255.0 << ',' << c.g / 255.0 << ',' << c.b / 255.0 << "}\n";
630                 packages.precision(stmSize);
631         }
632
633         // lyxskak.sty --- newer chess support based on skak.sty
634         if (mustProvide("chess")) {
635                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
636         }
637
638         // setspace.sty
639         if ((params_.spacing().getSpace() != Spacing::Single
640              && !params_.spacing().isDefault())
641             || isRequired("setspace")) {
642                 packages << "\\usepackage{setspace}\n";
643         }
644         switch (params_.spacing().getSpace()) {
645         case Spacing::Default:
646         case Spacing::Single:
647                 // we dont use setspace.sty so dont print anything
648                 //packages += "\\singlespacing\n";
649                 break;
650         case Spacing::Onehalf:
651                 packages << "\\onehalfspacing\n";
652                 break;
653         case Spacing::Double:
654                 packages << "\\doublespacing\n";
655                 break;
656         case Spacing::Other:
657                 packages << "\\setstretch{"
658                          << params_.spacing().getValue() << "}\n";
659                 break;
660         }
661
662         // amssymb.sty
663         if (mustProvide("amssymb")
664             || params_.use_amsmath == BufferParams::package_on)
665                 packages << "\\usepackage{amssymb}\n";
666
667         // esint must be after amsmath and wasysym, since it will redeclare
668         // inconsistent integral symbols
669         if ((mustProvide("esint") || mustProvide("esintoramsmath")) &&
670             params_.use_esint != BufferParams::package_off)
671                 packages << "\\usepackage{esint}\n";
672
673         // natbib.sty
674         if (mustProvide("natbib")) {
675                 packages << "\\usepackage[";
676                 if (params_.getEngine() == biblio::ENGINE_NATBIB_NUMERICAL) {
677                         packages << "numbers";
678                 } else {
679                         packages << "authoryear";
680                 }
681                 packages << "]{natbib}\n";
682         }
683
684         // jurabib -- we need version 0.6 at least.
685         if (mustProvide("jurabib")) {
686                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
687         }
688
689         // bibtopic -- the dot provides the aux file naming which
690         // LyX can detect.
691         if (mustProvide("bibtopic")) {
692                 packages << "\\usepackage[dot]{bibtopic}\n";
693         }
694
695         if (mustProvide("xy"))
696                 packages << "\\usepackage[all]{xy}\n";
697
698         if (mustProvide("nomencl")) {
699                 // Make it work with the new and old version of the package,
700                 // but don't use the compatibility option since it is
701                 // incompatible to other packages.
702                 packages << "\\usepackage{nomencl}\n"
703                             "% the following is useful when we have the old nomencl.sty package\n"
704                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
705                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
706                             "\\makenomenclature\n";
707         }
708
709         if (mustProvide("listings"))
710                 packages << "\\usepackage{listings}\n";
711
712         return packages.str();
713 }
714
715
716 string const LaTeXFeatures::getMacros() const
717 {
718         ostringstream macros;
719
720         if (!preamble_snippets_.empty())
721                 macros << '\n';
722         FeaturesList::const_iterator pit  = preamble_snippets_.begin();
723         FeaturesList::const_iterator pend = preamble_snippets_.end();
724         for (; pit != pend; ++pit)
725                 macros << *pit << '\n';
726
727         if (mustProvide("LyX"))
728                 macros << lyx_def << '\n';
729
730         if (mustProvide("lyxline"))
731                 macros << lyxline_def << '\n';
732
733         if (mustProvide("noun"))
734                 macros << noun_def << '\n';
735
736         if (mustProvide("lyxarrow"))
737                 macros << lyxarrow_def << '\n';
738
739         if (mustProvide("textgreek"))
740                 macros << textgreek_def << '\n';
741
742         if (mustProvide("textcyr"))
743                 macros << textcyr_def << '\n';
744
745         // quotes.
746         if (mustProvide("quotesinglbase"))
747                 macros << quotesinglbase_def << '\n';
748         if (mustProvide("quotedblbase"))
749                 macros << quotedblbase_def << '\n';
750         if (mustProvide("guilsinglleft"))
751                 macros << guilsinglleft_def << '\n';
752         if (mustProvide("guilsinglright"))
753                 macros << guilsinglright_def << '\n';
754         if (mustProvide("guillemotleft"))
755                 macros << guillemotleft_def << '\n';
756         if (mustProvide("guillemotright"))
757                 macros << guillemotright_def << '\n';
758
759         // Math mode
760         if (mustProvide("boldsymbol") && !isRequired("amsmath"))
761                 macros << boldsymbol_def << '\n';
762         if (mustProvide("binom") && !isRequired("amsmath"))
763                 macros << binom_def << '\n';
764         if (mustProvide("mathcircumflex"))
765                 macros << mathcircumflex_def << '\n';
766         if (mustProvide("newlyxcommand"))
767                 macros << newlyxcommand_def << '\n';
768
769         // other
770         if (mustProvide("ParagraphLeftIndent"))
771                 macros << paragraphleftindent_def;
772         if (mustProvide("NeedLyXFootnoteCode"))
773                 macros << floatingfootnote_def;
774
775         // some problems with tex->html converters
776         if (mustProvide("NeedTabularnewline"))
777                 macros << tabularnewline_def;
778
779         // greyedout environment (note inset)
780         if (mustProvide("lyxgreyedout"))
781                 macros << lyxgreyedout_def;
782
783         if (mustProvide("lyxdot"))
784                 macros << lyxdot_def << '\n';
785
786         // floats
787         getFloatDefinitions(macros);
788
789         // change tracking
790         if (mustProvide("ct-dvipost"))
791                 macros << changetracking_dvipost_def;
792
793         if (mustProvide("ct-xcolor-soul")) {
794                 int const prec = macros.precision(2);
795         
796                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
797                 macros << "\\providecolor{lyxadded}{rgb}{"
798                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
799
800                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
801                 macros << "\\providecolor{lyxdeleted}{rgb}{"
802                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
803
804                 macros.precision(prec);
805
806                 macros << "\\newcommand{\\lyxadded}[3]{{\\color{lyxadded}#3}}\n"
807                        << "\\newcommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\st{#3}}}\n";
808         }
809
810         if (mustProvide("ct-none"))
811                 macros << changetracking_none_def;
812
813         return macros.str();
814 }
815
816
817 string const LaTeXFeatures::getBabelOptions() const
818 {
819         ostringstream tmp;
820
821         LanguageList::const_iterator it  = UsedLanguages_.begin();
822         LanguageList::const_iterator end =  UsedLanguages_.end();
823         for (; it != end; ++it)
824                 if (!(*it)->latex_options().empty())
825                         tmp << (*it)->latex_options() << '\n';
826         if (!params_.language->latex_options().empty())
827                 tmp << params_.language->latex_options() << '\n';
828
829         return tmp.str();
830 }
831
832
833 docstring const LaTeXFeatures::getTClassPreamble() const
834 {
835         // the text class specific preamble
836         TextClass const & tclass = params_.getTextClass();
837         odocstringstream tcpreamble;
838
839         tcpreamble << tclass.preamble();
840
841         list<docstring>::const_iterator cit = usedLayouts_.begin();
842         list<docstring>::const_iterator end = usedLayouts_.end();
843         for (; cit != end; ++cit) {
844                 tcpreamble << tclass[*cit]->preamble();
845         }
846
847         return tcpreamble.str();
848 }
849
850
851 docstring const LaTeXFeatures::getLyXSGMLEntities() const
852 {
853         // Definition of entities used in the document that are LyX related.
854         odocstringstream entities;
855
856         if (mustProvide("lyxarrow")) {
857                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
858         }
859
860         return entities.str();
861 }
862
863
864 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
865 {
866         odocstringstream sgmlpreamble;
867         // FIXME UNICODE
868         docstring const basename(from_utf8(onlyPath(fname)));
869
870         FileMap::const_iterator end = IncludedFiles_.end();
871         for (FileMap::const_iterator fi = IncludedFiles_.begin();
872              fi != end; ++fi)
873                 // FIXME UNICODE
874                 sgmlpreamble << "\n<!ENTITY " << fi->first
875                              << (isSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
876                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
877
878         return sgmlpreamble.str();
879 }
880
881
882 void LaTeXFeatures::showStruct() const {
883         lyxerr << "LyX needs the following commands when LaTeXing:"
884                << "\n***** Packages:" << getPackages()
885                << "\n***** Macros:" << getMacros()
886                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
887                << "\n***** done." << endl;
888 }
889
890
891 Buffer const & LaTeXFeatures::buffer() const
892 {
893         return *buffer_;
894 }
895
896
897 void LaTeXFeatures::setBuffer(Buffer const & buffer)
898 {
899         buffer_ = &buffer;
900 }
901
902
903 BufferParams const & LaTeXFeatures::bufferParams() const
904 {
905         return params_;
906 }
907
908
909 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
910 {
911         FloatList const & floats = params_.getTextClass().floats();
912
913         // Here we will output the code to create the needed float styles.
914         // We will try to do this as minimal as possible.
915         // \floatstyle{ruled}
916         // \newfloat{algorithm}{htbp}{loa}
917         // \floatname{algorithm}{Algorithm}
918         UsedFloats::const_iterator cit = usedFloats_.begin();
919         UsedFloats::const_iterator end = usedFloats_.end();
920         // ostringstream floats;
921         for (; cit != end; ++cit) {
922                 Floating const & fl = floats.getType((*cit));
923
924                 // For builtin floats we do nothing.
925                 if (fl.builtin()) continue;
926
927                 // We have to special case "table" and "figure"
928                 if (fl.type() == "tabular" || fl.type() == "figure") {
929                         // Output code to modify "table" or "figure"
930                         // but only if builtin == false
931                         // and that have to be true at this point in the
932                         // function.
933                         string const type = fl.type();
934                         string const placement = fl.placement();
935                         string const style = fl.style();
936                         if (!style.empty()) {
937                                 os << "\\floatstyle{" << style << "}\n"
938                                    << "\\restylefloat{" << type << "}\n";
939                         }
940                         if (!placement.empty()) {
941                                 os << "\\floatplacement{" << type << "}{"
942                                    << placement << "}\n";
943                         }
944                 } else {
945                         // The other non builtin floats.
946
947                         string const type = fl.type();
948                         string const placement = fl.placement();
949                         string const ext = fl.ext();
950                         string const within = fl.within();
951                         string const style = fl.style();
952                         string const name = fl.name();
953                         os << "\\floatstyle{" << style << "}\n"
954                            << "\\newfloat{" << type << "}{" << placement
955                            << "}{" << ext << '}';
956                         if (!within.empty())
957                                 os << '[' << within << ']';
958                         os << '\n'
959                            << "\\floatname{" << type << "}{"
960                            << name << "}\n";
961
962                         // What missing here is to code to minimalize the code
963                         // output so that the same floatstyle will not be
964                         // used several times, when the same style is still in
965                         // effect. (Lgb)
966                 }
967         }
968 }
969
970
971 } // namespace lyx