]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.cpp
Compile fix.
[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         "\\def\\lyxref#1{\\@lyxref#1:@@@@@:}\n"
262         "\\def\\@lyxref#1:#2:{%\n"
263         "\\ifthenelse{\\equal{#2}{@@@@@}}%\n"
264         "       {\\ref{#1}}%\n"
265         "       {\\@@lyxref#1:#2:}%\n"
266         "}\n"
267         "\\def\\@@lyxref#1:#2:@@@@@:{%\n"
268         "       \\RS@ifundefined{#1ref}%\n"
269         "       {\\ref{#1:#2}}%\n"
270         "       {\\RS@nameuse{#1ref}{#2}}%\n"
271         "}\n"
272         "\\RS@ifundefined{\thmref}\n"
273         "  {\\def\\RSthmtxt{theorem~}\\newref{thm}{name = \\RSthmtxt}}\n"
274         "  {}\n"
275         "\\makeatother\n"
276         );
277
278 /////////////////////////////////////////////////////////////////////
279 //
280 // LaTeXFeatures
281 //
282 /////////////////////////////////////////////////////////////////////
283
284 LaTeXFeatures::Packages LaTeXFeatures::packages_;
285
286
287 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p,
288                              OutputParams const & r)
289         : buffer_(&b), params_(p), runparams_(r), in_float_(false)
290 {}
291
292
293 bool LaTeXFeatures::useBabel() const
294 {
295         return lyxrc.language_use_babel ||
296                 (bufferParams().language->lang() != lyxrc.default_language &&
297                  !bufferParams().language->babel().empty()) ||
298                 this->hasLanguages();
299 }
300
301
302 void LaTeXFeatures::require(string const & name)
303 {
304         features_.insert(name);
305 }
306
307
308 void LaTeXFeatures::require(set<string> const & names)
309 {
310         features_.insert(names.begin(), names.end());
311 }
312
313
314 void LaTeXFeatures::getAvailable()
315 {
316         Lexer lex;
317         support::FileName const real_file = libFileSearch("", "packages.lst");
318
319         if (real_file.empty())
320                 return;
321
322         lex.setFile(real_file);
323
324         if (!lex.isOK())
325                 return;
326
327         // Make sure that we are clean
328         packages_.clear();
329
330         bool finished = false;
331         // Parse config-file
332         while (lex.isOK() && !finished) {
333                 switch (lex.lex()) {
334                 case Lexer::LEX_FEOF:
335                         finished = true;
336                         break;
337                 default:
338                         packages_.insert(lex.getString());
339                 }
340         }
341 }
342
343
344 void LaTeXFeatures::useLayout(docstring const & layoutname)
345 {
346         // Some code to avoid loops in dependency definition
347         static int level = 0;
348         const int maxlevel = 30;
349         if (level > maxlevel) {
350                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
351                        << "recursion attained by layout "
352                        << to_utf8(layoutname) << endl;
353                 return;
354         }
355
356         DocumentClass const & tclass = params_.documentClass();
357         if (tclass.hasLayout(layoutname)) {
358                 // Is this layout already in usedLayouts?
359                 if (find(usedLayouts_.begin(), usedLayouts_.end(), layoutname) 
360                     != usedLayouts_.end())
361                         return;
362
363                 Layout const & layout = tclass[layoutname];
364                 require(layout.requires());
365
366                 if (!layout.depends_on().empty()) {
367                         ++level;
368                         useLayout(layout.depends_on());
369                         --level;
370                 }
371                 usedLayouts_.push_back(layoutname);
372         } else {
373                 lyxerr << "LaTeXFeatures::useLayout: layout `"
374                        << to_utf8(layoutname) << "' does not exist in this class"
375                        << endl;
376         }
377
378         --level;
379 }
380
381
382 void LaTeXFeatures::useInsetLayout(InsetLayout const & lay)
383 {
384         docstring const & lname = lay.name();
385         DocumentClass const & tclass = params_.documentClass();
386
387         // this is a default inset layout, nothing useful here
388         if (!tclass.hasInsetLayout(lname))
389                 return;
390         // Is this layout already in usedInsetLayouts?
391         if (find(usedInsetLayouts_.begin(), usedInsetLayouts_.end(), lname) 
392                         != usedInsetLayouts_.end())
393                 return;
394
395         require(lay.requires());
396         usedInsetLayouts_.push_back(lname);
397 }
398
399
400 bool LaTeXFeatures::isRequired(string const & name) const
401 {
402         return features_.find(name) != features_.end();
403 }
404
405
406 bool LaTeXFeatures::mustProvide(string const & name) const
407 {
408         return isRequired(name) && !params_.documentClass().provides(name);
409 }
410
411
412 bool LaTeXFeatures::isAvailable(string const & name)
413 {
414         string::size_type const i = name.find("->");
415         if (i != string::npos) {
416                 string const from = name.substr(0,i);
417                 string const to = name.substr(i+2);
418                 //LYXERR0("from=[" << from << "] to=[" << to << "]");
419                 return theConverters().isReachable(from, to);
420         }
421
422         if (packages_.empty())
423                 getAvailable();
424         string n = name;
425         if (suffixIs(n, ".sty"))
426                 n.erase(name.length() - 4);
427         return packages_.find(n) != packages_.end();
428 }
429
430
431 void LaTeXFeatures::addPreambleSnippet(string const & preamble)
432 {
433         SnippetList::const_iterator begin = preamble_snippets_.begin();
434         SnippetList::const_iterator end   = preamble_snippets_.end();
435         if (find(begin, end, preamble) == end)
436                 preamble_snippets_.push_back(preamble);
437 }
438
439
440 void LaTeXFeatures::useFloat(string const & name, bool subfloat)
441 {
442         if (!usedFloats_[name])
443                 usedFloats_[name] = subfloat;
444         if (subfloat)
445                 require("subfig");
446         // We only need float.sty if we use non builtin floats, or if we
447         // use the "H" modifier. This includes modified table and
448         // figure floats. (Lgb)
449         Floating const & fl = params_.documentClass().floats().getType(name);
450         if (!fl.floattype().empty() && fl.needsFloatPkg()) {
451                 require("float");
452         }
453 }
454
455
456 void LaTeXFeatures::useLanguage(Language const * lang)
457 {
458         if (!lang->babel().empty())
459                 UsedLanguages_.insert(lang);
460         if (lang->lang() == "vietnamese")
461                 require("vietnamese");
462         // CJK languages do not have a babel name.
463         // They use the CJK package
464         if (lang->encoding()->package() == Encoding::CJK)
465                 require("CJK");
466         // japanese package is special
467         if (lang->encoding()->package() == Encoding::japanese)
468                 require("japanese");
469 }
470
471
472 void LaTeXFeatures::includeFile(docstring const & key, string const & name)
473 {
474         IncludedFiles_[key] = name;
475 }
476
477
478 bool LaTeXFeatures::hasLanguages() const
479 {
480         return !UsedLanguages_.empty();
481 }
482
483
484 string LaTeXFeatures::getLanguages() const
485 {
486         ostringstream languages;
487
488         LanguageList::const_iterator const begin = UsedLanguages_.begin();
489         for (LanguageList::const_iterator cit = begin;
490              cit != UsedLanguages_.end();
491              ++cit) {
492                 if (cit != begin)
493                         languages << ',';
494                 languages << (*cit)->babel();
495         }
496         return languages.str();
497 }
498
499
500 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
501 {
502         // This does only find encodings of languages supported by babel, but
503         // that does not matter since we don't have a language with an
504         // encoding supported by inputenc but without babel support.
505         set<string> encodings;
506         LanguageList::const_iterator it  = UsedLanguages_.begin();
507         LanguageList::const_iterator end = UsedLanguages_.end();
508         for (; it != end; ++it)
509                 if ((*it)->encoding()->latexName() != doc_encoding &&
510                     ((*it)->encoding()->package() == Encoding::inputenc
511                      || (*it)->encoding()->package() == Encoding::japanese))
512                         encodings.insert((*it)->encoding()->latexName());
513         return encodings;
514 }
515
516 namespace {
517
518 char const * simplefeatures[] = {
519 // note that the package order here will be the same in the LaTeX-output
520         "array",
521         "verbatim",
522         "longtable",
523         "rotating",
524         "latexsym",
525         "pifont",
526         // subfig is handled in BufferParams.cpp
527         "varioref",
528         "prettyref",
529         "refstyle",
530         /*For a successful cooperation of the `wrapfig' package with the
531           `float' package you should load the `wrapfig' package *after*
532           the `float' package. See the caption package documentation
533           for explanation.*/
534         "float",
535         "rotfloat",
536         "wrapfig",
537         "booktabs",
538         "dvipost",
539         "fancybox",
540         "calc",
541         "units",
542         "tipa",
543         "tipx",
544         "framed",
545         "soul",
546         "textcomp",
547         "pmboxdraw",
548         "bbding",
549         "ifsym",
550         "marvosym",
551         "txfonts",
552         "mathrsfs",
553         "ascii",
554         "url",
555         "covington",
556         "csquotes",
557         "enumitem",
558         "endnotes",
559         "ifthen",
560         "amsthm",
561         // listings is handled in BufferParams.cpp
562         "bm",
563         "pdfpages",
564         "amscd",
565         "slashed",
566         "multirow"
567 };
568
569 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
570
571 }
572
573
574 string const LaTeXFeatures::getColorOptions() const
575 {
576         ostringstream colors;
577
578         // Handling the color packages separately is needed to be able to load them
579         // before babel when hyperref is loaded with the colorlinks option
580         // for more info see Bufferparams.cpp
581
582         // [x]color.sty
583         if (mustProvide("color") || mustProvide("xcolor")) {
584                 string const package =
585                         (mustProvide("xcolor") ? "xcolor" : "color");
586                 if (params_.graphicsDriver == "default"
587                         || params_.graphicsDriver == "none")
588                         colors << "\\usepackage{" << package << "}\n";
589                 else
590                         colors << "\\usepackage["
591                                  << params_.graphicsDriver
592                                  << "]{" << package << "}\n";
593         }
594
595         // pdfcolmk must be loaded after color
596         if (mustProvide("pdfcolmk"))
597                 colors << "\\usepackage{pdfcolmk}\n";
598
599         // the following 3 color commands must be set after color
600         // is loaded and before pdfpages, therefore add the command
601         // here define the set color
602         if (mustProvide("pagecolor")) {
603                 colors << "\\definecolor{page_backgroundcolor}{rgb}{";
604                 colors << outputLaTeXColor(params_.backgroundcolor) << "}\n";
605                 // set the page color
606                 colors << "\\pagecolor{page_backgroundcolor}\n";
607         }
608
609         if (mustProvide("fontcolor")) {
610                 colors << "\\definecolor{document_fontcolor}{rgb}{";
611                 colors << outputLaTeXColor(params_.fontcolor) << "}\n";
612                 // set the color
613                 colors << "\\color{document_fontcolor}\n";
614         }
615
616         if (mustProvide("lyxgreyedout")) {
617                 colors << "\\definecolor{note_fontcolor}{rgb}{";
618                 colors << outputLaTeXColor(params_.notefontcolor) << "}\n";
619                 // the color will be set together with the definition of
620                 // the lyxgreyedout environment (see lyxgreyedout_def)
621         }
622
623         // color for shaded boxes
624         if (isRequired("framed") && mustProvide("color")) {
625                 colors << "\\definecolor{shadecolor}{rgb}{";
626                 colors << outputLaTeXColor(params_.boxbgcolor) << "}\n";
627                 // this color is automatically used by the LaTeX-package "framed"
628         }
629
630         return colors.str();
631 }
632
633
634 string const LaTeXFeatures::getPackages() const
635 {
636         ostringstream packages;
637         DocumentClass const & tclass = params_.documentClass();
638
639         // FIXME: currently, we can only load packages and macros known
640         // to LyX.
641         // However, with the Require tag of layouts/custom insets,
642         // also inknown packages can be requested. They are silently
643         // swallowed now. We should change this eventually.
644
645         //
646         //  These are all the 'simple' includes.  i.e
647         //  packages which we just \usepackage{package}
648         //
649         for (int i = 0; i < nb_simplefeatures; ++i) {
650                 if (mustProvide(simplefeatures[i]))
651                         packages << "\\usepackage{"
652                                  << simplefeatures[i] << "}\n";
653         }
654
655         //
656         // The rest of these packages are somewhat more complicated
657         // than those above.
658         //
659
660         // esint is preferred for esintoramsmath
661         if ((mustProvide("amsmath")
662              && params_.use_amsmath != BufferParams::package_off)
663             || (mustProvide("esintoramsmath")
664                 && params_.use_esint == BufferParams::package_off
665                 && params_.use_amsmath != BufferParams::package_off)) {
666                 packages << "\\usepackage{amsmath}\n";
667         } else {
668                 // amsbsy and amstext are already provided by amsmath
669                 if (mustProvide("amsbsy"))
670                         packages << "\\usepackage{amsbsy}\n";
671                 if (mustProvide("amstext"))
672                         packages << "\\usepackage{amstext}\n";
673         }
674         
675         // wasysym is a simple feature, but it must be after amsmath if both
676         // are used
677         // wasysym redefines some integrals (e.g. iint) from amsmath. That
678         // leads to inconsistent integrals. We only load this package if
679         // the document does not contain integrals (then isRequired("esint")
680         // is false) or if esint is used, since esint redefines all relevant
681         // integral symbols from wasysym and amsmath.
682         // See http://www.lyx.org/trac/ticket/1942
683         if (mustProvide("wasysym") &&
684             (params_.use_esint != BufferParams::package_off || !isRequired("esint")))
685                 packages << "\\usepackage{wasysym}\n";
686
687         // accents must be loaded after amsmath
688         if (mustProvide("accents"))
689                 packages << "\\usepackage{accents}\n";
690
691         // mathdots must be loaded after amsmath
692         if (mustProvide("mathdots") &&
693                 params_.use_mathdots != BufferParams::package_off)
694                 packages << "\\usepackage{mathdots}\n";
695
696         // yhmath must be loaded after amsmath
697         if (mustProvide("yhmath"))
698                 packages << "\\usepackage{yhmath}\n";
699
700         // [x]color and pdfcolmk are handled in getColorOptions() above
701         
702         // makeidx.sty
703         if (isRequired("makeidx") || isRequired("splitidx")) {
704                 if (!tclass.provides("makeidx") && !isRequired("splitidx"))
705                         packages << "\\usepackage{makeidx}\n";
706                 if (!tclass.provides("splitidx") && isRequired("splitidx"))
707                         packages << "\\usepackage{splitidx}\n";
708                 packages << "\\makeindex\n";
709         }
710
711         // graphicx.sty
712         if (mustProvide("graphicx") && params_.graphicsDriver != "none") {
713                 if (params_.graphicsDriver == "default")
714                         packages << "\\usepackage{graphicx}\n";
715                 else
716                         packages << "\\usepackage["
717                                  << params_.graphicsDriver
718                                  << "]{graphicx}\n";
719         }
720         
721         // lyxskak.sty --- newer chess support based on skak.sty
722         if (mustProvide("chess"))
723                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
724
725         // setspace.sty
726         if (mustProvide("setspace") && !tclass.provides("SetSpace"))
727                 packages << "\\usepackage{setspace}\n";
728
729         // amssymb.sty
730         if (mustProvide("amssymb")
731             || params_.use_amsmath == BufferParams::package_on)
732                 packages << "\\usepackage{amssymb}\n";
733
734         // esint must be after amsmath and wasysym, since it will redeclare
735         // inconsistent integral symbols
736         if ((mustProvide("esint") || mustProvide("esintoramsmath")) &&
737             params_.use_esint != BufferParams::package_off)
738                 packages << "\\usepackage{esint}\n";
739
740         // natbib.sty
741         // Some classes load natbib themselves, but still allow (or even require)
742         // plain numeric citations (ReVTeX is such a case, see bug 5182).
743         // This special case is indicated by the "natbib-internal" key.
744         if (mustProvide("natbib") && !tclass.provides("natbib-internal")) {
745                 packages << "\\usepackage[";
746                 if (params_.citeEngine() == ENGINE_NATBIB_NUMERICAL)
747                         packages << "numbers";
748                 else
749                         packages << "authoryear";
750                 packages << "]{natbib}\n";
751         }
752
753         // jurabib -- we need version 0.6 at least.
754         if (mustProvide("jurabib"))
755                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
756         
757         // xargs -- we need version 1.09 at least
758         if (mustProvide("xargs"))
759                 packages << "\\usepackage{xargs}[2008/03/08]\n";
760
761         // bibtopic -- the dot provides the aux file naming which
762         // LyX can detect.
763         if (mustProvide("bibtopic"))
764                 packages << "\\usepackage[dot]{bibtopic}\n";
765
766         if (mustProvide("xy"))
767                 packages << "\\usepackage[all]{xy}\n";
768
769         if (mustProvide("feyn"))
770                 packages << "\\usepackage{feyn}\n"; //Diagram
771
772         if (mustProvide("ulem"))
773                 packages << "\\PassOptionsToPackage{normalem}{ulem}\n"
774                             "\\usepackage{ulem}\n";
775
776         if (mustProvide("mhchem") &&
777                 params_.use_mhchem != BufferParams::package_off)
778                 packages << "\\PassOptionsToPackage{version=3}{mhchem}\n"
779                             "\\usepackage{mhchem}\n";
780
781         if (mustProvide("nomencl")) {
782                 // Make it work with the new and old version of the package,
783                 // but don't use the compatibility option since it is
784                 // incompatible to other packages.
785                 packages << "\\usepackage{nomencl}\n"
786                             "% the following is useful when we have the old nomencl.sty package\n"
787                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
788                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
789                             "\\makenomenclature\n";
790         }
791
792         return packages.str();
793 }
794
795
796 string LaTeXFeatures::getPreambleSnippets() const 
797 {
798         ostringstream snip;
799         SnippetList::const_iterator pit  = preamble_snippets_.begin();
800         SnippetList::const_iterator pend = preamble_snippets_.end();
801         for (; pit != pend; ++pit)
802                 snip << *pit << '\n';
803         return snip.str();
804 }
805
806
807 docstring const LaTeXFeatures::getMacros() const
808 {
809         odocstringstream macros;
810
811         if (!preamble_snippets_.empty()) {
812                 macros << '\n';
813                 macros << from_utf8(getPreambleSnippets());
814         }
815
816         if (mustProvide("papersize")) {
817                 if (runparams_.flavor == OutputParams::LATEX)
818                         macros << papersizedvi_def << '\n';
819                 else
820                         macros << papersizepdf_def << '\n';
821         }
822
823         if (mustProvide("LyX"))
824                 macros << lyx_def << '\n';
825
826         if (mustProvide("noun"))
827                 macros << noun_def << '\n';
828
829         if (mustProvide("lyxarrow"))
830                 macros << lyxarrow_def << '\n';
831
832         if (mustProvide("textgreek")) {
833                 // Avoid a LaTeX error if times fonts are used and the grtimes
834                 // package is installed but actual fonts are not (bug 6469).
835                 if (params_.fontsRoman == "times")
836                         macros << subst(textgreek_def,
837                                         from_ascii("\\greektext #1"),
838                                         from_ascii("%\n  \\IfFileExists"
839                                                    "{grtm10.tfm}{}{\\fontfamily"
840                                                    "{cmr}}\\greektext #1"))
841                                << '\n';
842                 else
843                         macros << textgreek_def << '\n';
844         }
845
846         if (mustProvide("textcyr"))
847                 macros << textcyr_def << '\n';
848
849         if (mustProvide("lyxmathsym"))
850                 macros << lyxmathsym_def << '\n';
851
852         if (mustProvide("cedilla"))
853                 macros << cedilla_def << '\n';
854
855         if (mustProvide("subring"))
856                 macros << subring_def << '\n';
857
858         if (mustProvide("subdot"))
859                 macros << subdot_def << '\n';
860
861         if (mustProvide("subhat"))
862                 macros << subhat_def << '\n';
863
864         if (mustProvide("subtilde"))
865                 macros << subtilde_def << '\n';
866
867         if (mustProvide("dacute"))
868                 macros << dacute_def << '\n';
869
870         if (mustProvide("tipasymb"))
871                 macros << tipasymb_def << '\n';
872
873         if (mustProvide("dgrave"))
874                 macros << dgrave_def << '\n';
875
876         if (mustProvide("rcap"))
877                 macros << rcap_def << '\n';
878
879         if (mustProvide("ogonek"))
880                 macros << ogonek_def << '\n';
881
882         // quotes.
883         if (mustProvide("quotesinglbase"))
884                 macros << quotesinglbase_def << '\n';
885         if (mustProvide("quotedblbase"))
886                 macros << quotedblbase_def << '\n';
887         if (mustProvide("guilsinglleft"))
888                 macros << guilsinglleft_def << '\n';
889         if (mustProvide("guilsinglright"))
890                 macros << guilsinglright_def << '\n';
891         if (mustProvide("guillemotleft"))
892                 macros << guillemotleft_def << '\n';
893         if (mustProvide("guillemotright"))
894                 macros << guillemotright_def << '\n';
895
896         // Math mode
897         if (mustProvide("binom") && !isRequired("amsmath"))
898                 macros << binom_def << '\n';
899         if (mustProvide("mathcircumflex"))
900                 macros << mathcircumflex_def << '\n';
901
902         // other
903         if (mustProvide("ParagraphLeftIndent"))
904                 macros << paragraphleftindent_def;
905         if (mustProvide("NeedLyXFootnoteCode"))
906                 macros << floatingfootnote_def;
907
908         // some problems with tex->html converters
909         if (mustProvide("NeedTabularnewline"))
910                 macros << tabularnewline_def;
911
912         // greyed-out environment (note inset)
913         // the color is specified in the routine
914         // getColorOptions() to avoid LaTeX-package clashes
915         if (mustProvide("lyxgreyedout"))
916                 macros << lyxgreyedout_def;
917
918         if (mustProvide("lyxdot"))
919                 macros << lyxdot_def << '\n';
920
921         // floats
922         getFloatDefinitions(macros);
923         
924         if (mustProvide("refstyle"))
925                 macros << lyxref_def << '\n';
926
927         // change tracking
928         if (mustProvide("ct-dvipost"))
929                 macros << changetracking_dvipost_def;
930
931         if (mustProvide("ct-xcolor-ulem")) {
932                 int const prec = macros.precision(2);
933         
934                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
935                 macros << "\\providecolor{lyxadded}{rgb}{"
936                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
937
938                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
939                 macros << "\\providecolor{lyxdeleted}{rgb}{"
940                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
941
942                 macros.precision(prec);
943                 
944                 if (isRequired("hyperref"))
945                         macros << changetracking_xcolor_ulem_hyperref_def;
946                 else
947                         macros << changetracking_xcolor_ulem_def;
948         }
949
950         if (mustProvide("ct-none"))
951                 macros << changetracking_none_def;
952
953         return macros.str();
954 }
955
956
957 string const LaTeXFeatures::getBabelOptions() const
958 {
959         ostringstream tmp;
960
961         LanguageList::const_iterator it  = UsedLanguages_.begin();
962         LanguageList::const_iterator end =  UsedLanguages_.end();
963         for (; it != end; ++it)
964                 if (!(*it)->latex_options().empty())
965                         tmp << (*it)->latex_options() << '\n';
966         if (!params_.language->latex_options().empty())
967                 tmp << params_.language->latex_options() << '\n';
968
969         return tmp.str();
970 }
971
972
973 docstring const LaTeXFeatures::getTClassPreamble() const
974 {
975         // the text class specific preamble
976         DocumentClass const & tclass = params_.documentClass();
977         odocstringstream tcpreamble;
978
979         tcpreamble << tclass.preamble();
980
981         list<docstring>::const_iterator cit = usedLayouts_.begin();
982         list<docstring>::const_iterator end = usedLayouts_.end();
983         for (; cit != end; ++cit)
984                 tcpreamble << tclass[*cit].preamble();
985
986         cit = usedInsetLayouts_.begin();
987         end = usedInsetLayouts_.end();
988         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
989         for (; cit != end; ++cit) {
990                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
991                 if (it == ils.end())
992                         continue;
993                 tcpreamble << it->second.preamble();
994         }
995
996         return tcpreamble.str();
997 }
998
999
1000 docstring const LaTeXFeatures::getTClassHTMLPreamble() const 
1001 {
1002         DocumentClass const & tclass = params_.documentClass();
1003         odocstringstream tcpreamble;
1004
1005         tcpreamble << tclass.htmlpreamble();
1006
1007         list<docstring>::const_iterator cit = usedLayouts_.begin();
1008         list<docstring>::const_iterator end = usedLayouts_.end();
1009         for (; cit != end; ++cit)
1010                 tcpreamble << tclass[*cit].htmlpreamble();
1011
1012         cit = usedInsetLayouts_.begin();
1013         end = usedInsetLayouts_.end();
1014         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1015         for (; cit != end; ++cit) {
1016                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1017                 if (it == ils.end())
1018                         continue;
1019                 tcpreamble << it->second.htmlpreamble();
1020         }
1021
1022         return tcpreamble.str();
1023 }
1024
1025
1026 docstring const LaTeXFeatures::getTClassHTMLStyles() const {
1027         DocumentClass const & tclass = params_.documentClass();
1028         odocstringstream tcpreamble;
1029
1030         list<docstring>::const_iterator cit = usedLayouts_.begin();
1031         list<docstring>::const_iterator end = usedLayouts_.end();
1032         for (; cit != end; ++cit)
1033                 tcpreamble << tclass[*cit].htmlstyle();
1034
1035         cit = usedInsetLayouts_.begin();
1036         end = usedInsetLayouts_.end();
1037         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1038         for (; cit != end; ++cit) {
1039                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1040                 if (it == ils.end())
1041                         continue;
1042                 tcpreamble << it->second.htmlstyle();
1043         }
1044
1045         return tcpreamble.str();
1046 }
1047
1048
1049 namespace {
1050 docstring const getFloatI18nPreamble(docstring const & type, docstring const & name, docstring const & lang)
1051 {
1052         odocstringstream os;
1053         os << "\\addto\\captions" << lang
1054            << "{\\renewcommand{\\" << type << "name}{" << name << "}}\n";
1055         return os.str();
1056 }
1057 }
1058
1059
1060 docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel) const
1061 {
1062         DocumentClass const & tclass = params_.documentClass();
1063         // collect preamble snippets in a set to prevent multiple identical
1064         // commands (would happen if e.g. both theorem and theorem* are used)
1065         set<docstring> snippets;
1066         typedef LanguageList::const_iterator lang_it;
1067         lang_it const lbeg = UsedLanguages_.begin();
1068         lang_it const lend =  UsedLanguages_.end();
1069         list<docstring>::const_iterator cit = usedLayouts_.begin();
1070         list<docstring>::const_iterator end = usedLayouts_.end();
1071         for (; cit != end; ++cit) {
1072                 // language dependent commands (once per document)
1073                 snippets.insert(tclass[*cit].langpreamble(buffer().language()));
1074                 // commands for language changing (for multilanguage documents)
1075                 if (use_babel && !UsedLanguages_.empty()) {
1076                         snippets.insert(tclass[*cit].babelpreamble(buffer().language()));
1077                         for (lang_it lit = lbeg; lit != lend; ++lit)
1078                                 snippets.insert(tclass[*cit].babelpreamble(*lit));
1079                 }
1080         }
1081         if (use_babel && !UsedLanguages_.empty()) {
1082                 FloatList const & floats = params_.documentClass().floats();
1083                 UsedFloats::const_iterator fit = usedFloats_.begin();
1084                 UsedFloats::const_iterator fend = usedFloats_.end();
1085                 for (; fit != fend; ++fit) {
1086                         Floating const & fl = floats.getType(fit->first);
1087                         docstring const type = from_ascii(fl.floattype());
1088                         docstring const flname = from_utf8(fl.name());
1089                         docstring name = translateIfPossible(flname,
1090                                 buffer().language()->code());
1091                         snippets.insert(getFloatI18nPreamble(
1092                                 type, name,
1093                                 from_ascii(buffer().language()->babel())));
1094                         for (lang_it lit = lbeg; lit != lend; ++lit) {
1095                                 name = translateIfPossible(flname,
1096                                         (*lit)->code());
1097                                 snippets.insert(getFloatI18nPreamble(
1098                                         type, name,
1099                                         from_ascii((*lit)->babel())));
1100                         }
1101                 }
1102         }
1103
1104         odocstringstream tcpreamble;
1105         set<docstring>::const_iterator const send = snippets.end();
1106         set<docstring>::const_iterator it = snippets.begin();
1107         for (; it != send; ++it)
1108                 tcpreamble << *it;
1109         return tcpreamble.str();
1110 }
1111
1112
1113 docstring const LaTeXFeatures::getLyXSGMLEntities() const
1114 {
1115         // Definition of entities used in the document that are LyX related.
1116         odocstringstream entities;
1117
1118         if (mustProvide("lyxarrow")) {
1119                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
1120         }
1121
1122         return entities.str();
1123 }
1124
1125
1126 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
1127 {
1128         odocstringstream sgmlpreamble;
1129         // FIXME UNICODE
1130         docstring const basename(from_utf8(onlyPath(fname)));
1131
1132         FileMap::const_iterator end = IncludedFiles_.end();
1133         for (FileMap::const_iterator fi = IncludedFiles_.begin();
1134              fi != end; ++fi)
1135                 // FIXME UNICODE
1136                 sgmlpreamble << "\n<!ENTITY " << fi->first
1137                              << (isSGMLFileName(fi->second) ? " SYSTEM \"" : " \"")
1138                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
1139
1140         return sgmlpreamble.str();
1141 }
1142
1143
1144 void LaTeXFeatures::showStruct() const
1145 {
1146         lyxerr << "LyX needs the following commands when LaTeXing:"
1147                << "\n***** Packages:" << getPackages()
1148                << "\n***** Macros:" << to_utf8(getMacros())
1149                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
1150                << "\n***** done." << endl;
1151 }
1152
1153
1154 Buffer const & LaTeXFeatures::buffer() const
1155 {
1156         return *buffer_;
1157 }
1158
1159
1160 void LaTeXFeatures::setBuffer(Buffer const & buffer)
1161 {
1162         buffer_ = &buffer;
1163 }
1164
1165
1166 BufferParams const & LaTeXFeatures::bufferParams() const
1167 {
1168         return params_;
1169 }
1170
1171
1172 void LaTeXFeatures::getFloatDefinitions(odocstream & os) const
1173 {
1174         FloatList const & floats = params_.documentClass().floats();
1175
1176         // Here we will output the code to create the needed float styles.
1177         // We will try to do this as minimal as possible.
1178         // \floatstyle{ruled}
1179         // \newfloat{algorithm}{htbp}{loa}
1180         // \providecommand{\algorithmname}{Algorithm}
1181         // \floatname{algorithm}{\protect\algorithmname}
1182         UsedFloats::const_iterator cit = usedFloats_.begin();
1183         UsedFloats::const_iterator end = usedFloats_.end();
1184         for (; cit != end; ++cit) {
1185                 Floating const & fl = floats.getType(cit->first);
1186
1187                 // For builtin floats we do nothing.
1188                 if (!fl.needsFloatPkg()) 
1189                         continue;
1190
1191                 // We have to special case "table" and "figure"
1192                 if (fl.floattype() == "tabular" || fl.floattype() == "figure") {
1193                         // Output code to modify "table" or "figure"
1194                         // but only if builtin == false
1195                         // and that have to be true at this point in the
1196                         // function.
1197                         docstring const type = from_ascii(fl.floattype());
1198                         docstring const placement = from_ascii(fl.placement());
1199                         docstring const style = from_ascii(fl.style());
1200                         if (!style.empty()) {
1201                                 os << "\\floatstyle{" << style << "}\n"
1202                                    << "\\restylefloat{" << type << "}\n";
1203                         }
1204                         if (!placement.empty()) {
1205                                 os << "\\floatplacement{" << type << "}{"
1206                                    << placement << "}\n";
1207                         }
1208                 } else {
1209                         // The other non builtin floats.
1210
1211                         docstring const type = from_ascii(fl.floattype());
1212                         docstring const placement = from_ascii(fl.placement());
1213                         docstring const ext = from_ascii(fl.ext());
1214                         docstring const within = from_ascii(fl.within());
1215                         docstring const style = from_ascii(fl.style());
1216                         docstring const name = translateIfPossible(
1217                                         from_utf8(fl.name()),
1218                                         buffer().language()->code());
1219                         os << "\\floatstyle{" << style << "}\n"
1220                            << "\\newfloat{" << type << "}{" << placement
1221                            << "}{" << ext << '}';
1222                         if (!within.empty())
1223                                 os << '[' << within << ']';
1224                         os << '\n'
1225                            << "\\providecommand{\\" << type << "name}{"
1226                            << name << "}\n"
1227                            << "\\floatname{" << type << "}{\\protect\\"
1228                            << type << "name}\n";
1229
1230                         // What missing here is to code to minimalize the code
1231                         // output so that the same floatstyle will not be
1232                         // used several times, when the same style is still in
1233                         // effect. (Lgb)
1234                 }
1235                 if (cit->second)
1236                         os << "\n\\newsubfloat{" << from_ascii(fl.floattype()) << "}\n";
1237         }
1238 }
1239
1240
1241 } // namespace lyx