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