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