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