]> git.lyx.org Git - features.git/blob - src/LaTeXFeatures.cpp
Change the way we output formatted references under refstyle to avoid
[features.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         "refstyle",
511         /*For a successful cooperation of the `wrapfig' package with the
512           `float' package you should load the `wrapfig' package *after*
513           the `float' package. See the caption package documentation
514           for explanation.*/
515         "float",
516         "rotfloat",
517         "wrapfig",
518         "booktabs",
519         "dvipost",
520         "fancybox",
521         "calc",
522         "units",
523         "tipa",
524         "tipx",
525         "framed",
526         "soul",
527         "textcomp",
528         "pmboxdraw",
529         "bbding",
530         "ifsym",
531         "marvosym",
532         "txfonts",
533         "mathrsfs",
534         "ascii",
535         "url",
536         "covington",
537         "csquotes",
538         "enumitem",
539         "endnotes",
540         "ifthen",
541         "amsthm",
542         // listings is handled in BufferParams.cpp
543         "bm",
544         "pdfpages",
545         "amscd",
546         "slashed",
547         "multirow"
548 };
549
550 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
551
552 }
553
554
555 string const LaTeXFeatures::getColorOptions() const
556 {
557         ostringstream colors;
558
559         // Handling the color packages separately is needed to be able to load them
560         // before babel when hyperref is loaded with the colorlinks option
561         // for more info see Bufferparams.cpp
562
563         // [x]color.sty
564         if (mustProvide("color") || mustProvide("xcolor")) {
565                 string const package =
566                         (mustProvide("xcolor") ? "xcolor" : "color");
567                 if (params_.graphicsDriver == "default"
568                         || params_.graphicsDriver == "none")
569                         colors << "\\usepackage{" << package << "}\n";
570                 else
571                         colors << "\\usepackage["
572                                  << params_.graphicsDriver
573                                  << "]{" << package << "}\n";
574         }
575
576         // pdfcolmk must be loaded after color
577         if (mustProvide("pdfcolmk"))
578                 colors << "\\usepackage{pdfcolmk}\n";
579
580         // the following 3 color commands must be set after color
581         // is loaded and before pdfpages, therefore add the command
582         // here define the set color
583         if (mustProvide("pagecolor")) {
584                 colors << "\\definecolor{page_backgroundcolor}{rgb}{";
585                 colors << outputLaTeXColor(params_.backgroundcolor) << "}\n";
586                 // set the page color
587                 colors << "\\pagecolor{page_backgroundcolor}\n";
588         }
589
590         if (mustProvide("fontcolor")) {
591                 colors << "\\definecolor{document_fontcolor}{rgb}{";
592                 colors << outputLaTeXColor(params_.fontcolor) << "}\n";
593                 // set the color
594                 colors << "\\color{document_fontcolor}\n";
595         }
596
597         if (mustProvide("lyxgreyedout")) {
598                 colors << "\\definecolor{note_fontcolor}{rgb}{";
599                 colors << outputLaTeXColor(params_.notefontcolor) << "}\n";
600                 // the color will be set together with the definition of
601                 // the lyxgreyedout environment (see lyxgreyedout_def)
602         }
603
604         // color for shaded boxes
605         if (isRequired("framed") && mustProvide("color")) {
606                 colors << "\\definecolor{shadecolor}{rgb}{";
607                 colors << outputLaTeXColor(params_.boxbgcolor) << "}\n";
608                 // this color is automatically used by the LaTeX-package "framed"
609         }
610
611         return colors.str();
612 }
613
614
615 string const LaTeXFeatures::getPackages() const
616 {
617         ostringstream packages;
618         DocumentClass const & tclass = params_.documentClass();
619
620         // FIXME: currently, we can only load packages and macros known
621         // to LyX.
622         // However, with the Require tag of layouts/custom insets,
623         // also inknown packages can be requested. They are silently
624         // swallowed now. We should change this eventually.
625
626         //
627         //  These are all the 'simple' includes.  i.e
628         //  packages which we just \usepackage{package}
629         //
630         for (int i = 0; i < nb_simplefeatures; ++i) {
631                 if (mustProvide(simplefeatures[i]))
632                         packages << "\\usepackage{"
633                                  << simplefeatures[i] << "}\n";
634         }
635
636         //
637         // The rest of these packages are somewhat more complicated
638         // than those above.
639         //
640
641         // esint is preferred for esintoramsmath
642         if ((mustProvide("amsmath")
643              && params_.use_amsmath != BufferParams::package_off)
644             || (mustProvide("esintoramsmath")
645                 && params_.use_esint == BufferParams::package_off
646                 && params_.use_amsmath != BufferParams::package_off)) {
647                 packages << "\\usepackage{amsmath}\n";
648         } else {
649                 // amsbsy and amstext are already provided by amsmath
650                 if (mustProvide("amsbsy"))
651                         packages << "\\usepackage{amsbsy}\n";
652                 if (mustProvide("amstext"))
653                         packages << "\\usepackage{amstext}\n";
654         }
655         
656         // wasysym is a simple feature, but it must be after amsmath if both
657         // are used
658         // wasysym redefines some integrals (e.g. iint) from amsmath. That
659         // leads to inconsistent integrals. We only load this package if
660         // the document does not contain integrals (then isRequired("esint")
661         // is false) or if esint is used, since esint redefines all relevant
662         // integral symbols from wasysym and amsmath.
663         // See http://www.lyx.org/trac/ticket/1942
664         if (mustProvide("wasysym") &&
665             (params_.use_esint != BufferParams::package_off || !isRequired("esint")))
666                 packages << "\\usepackage{wasysym}\n";
667
668         // accents must be loaded after amsmath
669         if (mustProvide("accents"))
670                 packages << "\\usepackage{accents}\n";
671
672         // mathdots must be loaded after amsmath
673         if (mustProvide("mathdots") &&
674                 params_.use_mathdots != BufferParams::package_off)
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("feyn"))
751                 packages << "\\usepackage{feyn}\n"; //Diagram
752
753         if (mustProvide("ulem"))
754                 packages << "\\PassOptionsToPackage{normalem}{ulem}\n"
755                             "\\usepackage{ulem}\n";
756
757         if (mustProvide("mhchem") &&
758                 params_.use_mhchem != BufferParams::package_off)
759                 packages << "\\PassOptionsToPackage{version=3}{mhchem}\n"
760                             "\\usepackage{mhchem}\n";
761
762         if (mustProvide("nomencl")) {
763                 // Make it work with the new and old version of the package,
764                 // but don't use the compatibility option since it is
765                 // incompatible to other packages.
766                 packages << "\\usepackage{nomencl}\n"
767                             "% the following is useful when we have the old nomencl.sty package\n"
768                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
769                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
770                             "\\makenomenclature\n";
771         }
772
773         return packages.str();
774 }
775
776
777 string LaTeXFeatures::getPreambleSnippets() const 
778 {
779         ostringstream snip;
780         SnippetList::const_iterator pit  = preamble_snippets_.begin();
781         SnippetList::const_iterator pend = preamble_snippets_.end();
782         for (; pit != pend; ++pit)
783                 snip << *pit << '\n';
784         return snip.str();
785 }
786
787
788 docstring const LaTeXFeatures::getMacros() const
789 {
790         odocstringstream macros;
791
792         if (!preamble_snippets_.empty()) {
793                 macros << '\n';
794                 macros << from_utf8(getPreambleSnippets());
795         }
796
797         if (mustProvide("papersize")) {
798                 if (runparams_.flavor == OutputParams::LATEX)
799                         macros << papersizedvi_def << '\n';
800                 else
801                         macros << papersizepdf_def << '\n';
802         }
803
804         if (mustProvide("LyX"))
805                 macros << lyx_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