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