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