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