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