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