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