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