* qt_helpers.cpp:
[lyx.git] / src / LaTeXFeatures.cpp
blob8c04af2547189b3a665fcb9ac3e1e371c517850f
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.
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
12 * Full author contact details are available in file CREDITS.
15 #include <config.h>
17 #include "LaTeXFeatures.h"
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"
32 #include "insets/InsetLayout.h"
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"
41 using namespace std;
42 using namespace lyx::support;
45 namespace lyx {
47 /////////////////////////////////////////////////////////////////////
49 // Strings
51 /////////////////////////////////////////////////////////////////////
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.}
57 static docstring const lyx_def = from_ascii(
58 "\\providecommand{\\LyX}{L\\kern-.1667em\\lower.25em\\hbox{Y}\\kern-.125emX\\@}");
60 static docstring const lyxline_def = from_ascii(
61 "\\newcommand{\\lyxline}[1][1pt]{%\n"
62 " \\par\\noindent%\n"
63 " \\rule[.5ex]{\\linewidth}{#1}\\par}");
65 static docstring const noun_def = from_ascii(
66 "\\newcommand{\\noun}[1]{\\textsc{#1}}");
68 static docstring const lyxarrow_def = from_ascii(
69 "\\DeclareRobustCommand*{\\lyxarrow}{%\n"
70 "\\@ifstar\n"
71 "{\\leavevmode\\,$\\triangleleft$\\,\\allowbreak}\n"
72 "{\\leavevmode\\,$\\triangleright$\\,\\allowbreak}}");
74 // for quotes without babel. This does not give perfect results, but
75 // anybody serious about non-english quotes should use babel (JMarc).
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 "}");
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 "}");
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 "}");
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 "}");
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 "}");
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 "}");
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");
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");
149 static docstring const binom_def = from_ascii(
150 "%% Binom macro for standard LaTeX users\n"
151 "\\newcommand{\\binom}[2]{{#1 \\choose #2}}\n");
153 static docstring const mathcircumflex_def = from_ascii(
154 "%% For printing a cirumflex inside a formula\n"
155 "\\newcommand{\\mathcircumflex}[0]{\\mbox{\\^{}}}\n");
157 static docstring const tabularnewline_def = from_ascii(
158 "%% Because html converters don't know tabularnewline\n"
159 "\\providecommand{\\tabularnewline}{\\\\}\n");
161 static docstring const lyxgreyedout_def = from_ascii(
162 "%% The greyedout annotation environment\n"
163 "\\newenvironment{lyxgreyedout}{\\textcolor[gray]{0.8}\\bgroup}{\\egroup}\n");
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");
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");
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");
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");
193 static docstring const changetracking_none_def = from_ascii(
194 "\\newcommand{\\lyxadded}[3]{#3}\n"
195 "\\newcommand{\\lyxdeleted}[3]{}\n");
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");
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");
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");
216 static docstring const papersizedvi_def = from_ascii(
217 "\\special{papersize=\\the\\paperwidth,\\the\\paperheight}\n");
219 static docstring const papersizepdf_def = from_ascii(
220 "\\pdfpageheight\\paperheight\n"
221 "\\pdfpagewidth\\paperwidth\n");
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");
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");
231 static docstring const subdot_def = from_ascii(
232 "\\newcommand{\\dosubdot}[2]{\\underaccent{#1.}{#2}}\n"
233 "\\newcommand{\\subdot}[1]{\\mathpalette\\dosubdot{#1}}\n");
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");
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");
243 static docstring const dacute_def = from_ascii(
244 "\\DeclareMathAccent{\\dacute}{\\mathalpha}{operators}{'175}\n");
246 static docstring const tipasymb_def = from_ascii(
247 "\\DeclareFontEncoding{T3}{}{}\n"
248 "\\DeclareSymbolFont{tipasymb}{T3}{cmr}{m}{n}\n");
250 static docstring const dgrave_def = from_ascii(
251 "\\DeclareMathAccent{\\dgrave}{\\mathord}{tipasymb}{'15}\n");
253 static docstring const rcap_def = from_ascii(
254 "\\DeclareMathAccent{\\rcap}{\\mathord}{tipasymb}{'20}\n");
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");
263 /////////////////////////////////////////////////////////////////////
265 // LaTeXFeatures
267 /////////////////////////////////////////////////////////////////////
269 LaTeXFeatures::Packages LaTeXFeatures::packages_;
272 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p,
273 OutputParams const & r)
274 : buffer_(&b), params_(p), runparams_(r), in_float_(false)
278 bool LaTeXFeatures::useBabel() const
280 return lyxrc.language_use_babel ||
281 (bufferParams().language->lang() != lyxrc.default_language &&
282 !bufferParams().language->babel().empty()) ||
283 this->hasLanguages();
287 void LaTeXFeatures::require(string const & name)
289 features_.insert(name);
293 void LaTeXFeatures::require(set<string> const & names)
295 features_.insert(names.begin(), names.end());
299 void LaTeXFeatures::getAvailable()
301 Lexer lex;
302 support::FileName const real_file = libFileSearch("", "packages.lst");
304 if (real_file.empty())
305 return;
307 lex.setFile(real_file);
309 if (!lex.isOK())
310 return;
312 // Make sure that we are clean
313 packages_.clear();
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());
329 void LaTeXFeatures::useLayout(docstring const & layoutname)
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;
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;
348 Layout const & layout = tclass[layoutname];
349 require(layout.requires());
351 if (!layout.depends_on().empty()) {
352 ++level;
353 useLayout(layout.depends_on());
354 --level;
356 usedLayouts_.push_back(layoutname);
357 } else {
358 lyxerr << "LaTeXFeatures::useLayout: layout `"
359 << to_utf8(layoutname) << "' does not exist in this class"
360 << endl;
363 --level;
367 void LaTeXFeatures::useInsetLayout(InsetLayout const & lay)
369 docstring const & lname = lay.name();
370 DocumentClass const & tclass = params_.documentClass();
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;
380 require(lay.requires());
381 usedInsetLayouts_.push_back(lname);
385 bool LaTeXFeatures::isRequired(string const & name) const
387 return features_.find(name) != features_.end();
391 bool LaTeXFeatures::mustProvide(string const & name) const
393 return isRequired(name) && !params_.documentClass().provides(name);
397 bool LaTeXFeatures::isAvailable(string const & name)
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);
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();
416 void LaTeXFeatures::addPreambleSnippet(string const & preamble)
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);
425 void LaTeXFeatures::useFloat(string const & name, bool subfloat)
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.type().empty() && !fl.builtin()) {
436 require("float");
441 void LaTeXFeatures::useLanguage(Language const * lang)
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");
457 void LaTeXFeatures::includeFile(docstring const & key, string const & name)
459 IncludedFiles_[key] = name;
463 bool LaTeXFeatures::hasLanguages() const
465 return !UsedLanguages_.empty();
469 string LaTeXFeatures::getLanguages() const
471 ostringstream languages;
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();
481 return languages.str();
485 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
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;
501 namespace {
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"
552 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
557 string const LaTeXFeatures::getColorOptions() const
559 ostringstream colors;
561 // Handling the color packages separately is needed to be able to load them
562 // before babel when hyperref is loaded with the colorlinks option
563 // for more info see Bufferparams.cpp
565 // [x]color.sty
566 if (mustProvide("color") || mustProvide("xcolor")) {
567 string const package =
568 (mustProvide("xcolor") ? "xcolor" : "color");
569 if (params_.graphicsDriver == "default"
570 || params_.graphicsDriver == "none")
571 colors << "\\usepackage{" << package << "}\n";
572 else
573 colors << "\\usepackage["
574 << params_.graphicsDriver
575 << "]{" << package << "}\n";
578 // pdfcolmk must be loaded after color
579 if (mustProvide("pdfcolmk"))
580 colors << "\\usepackage{pdfcolmk}\n";
582 if (mustProvide("pagecolor")) {
583 // the \pagecolor command must be set after color is loaded and
584 // before pdfpages, therefore add the command here
585 // define the set color
586 colors << "\\definecolor{page_backgroundcolor}{rgb}{";
587 colors << outputLaTeXColor(params_.backgroundcolor) << "}\n";
588 // set the page color
589 colors << "\\pagecolor{page_backgroundcolor}\n";
592 return colors.str();
596 string const LaTeXFeatures::getPackages() const
598 ostringstream packages;
599 DocumentClass const & tclass = params_.documentClass();
601 // FIXME: currently, we can only load packages and macros known
602 // to LyX.
603 // However, with the Require tag of layouts/custom insets,
604 // also inknown packages can be requested. They are silently
605 // swallowed now. We should change this eventually.
608 // These are all the 'simple' includes. i.e
609 // packages which we just \usepackage{package}
611 for (int i = 0; i < nb_simplefeatures; ++i) {
612 if (mustProvide(simplefeatures[i]))
613 packages << "\\usepackage{"
614 << simplefeatures[i] << "}\n";
618 // The rest of these packages are somewhat more complicated
619 // than those above.
622 // esint is preferred for esintoramsmath
623 if ((mustProvide("amsmath")
624 && params_.use_amsmath != BufferParams::package_off)
625 || (mustProvide("esintoramsmath")
626 && params_.use_esint == BufferParams::package_off
627 && params_.use_amsmath != BufferParams::package_off)) {
628 packages << "\\usepackage{amsmath}\n";
629 } else {
630 // amsbsy and amstext are already provided by amsmath
631 if (mustProvide("amsbsy"))
632 packages << "\\usepackage{amsbsy}\n";
633 if (mustProvide("amstext"))
634 packages << "\\usepackage{amstext}\n";
637 // wasysym is a simple feature, but it must be after amsmath if both
638 // are used
639 // wasysym redefines some integrals (e.g. iint) from amsmath. That
640 // leads to inconsistent integrals. We only load this package if
641 // the document does not contain integrals (then isRequired("esint")
642 // is false) or if esint is used, since esint redefines all relevant
643 // integral symbols from wasysym and amsmath.
644 // See http://bugzilla.lyx.org/show_bug.cgi?id=1942
645 if (mustProvide("wasysym") &&
646 (params_.use_esint != BufferParams::package_off || !isRequired("esint")))
647 packages << "\\usepackage{wasysym}\n";
649 // accents must be loaded after amsmath
650 if (mustProvide("accents"))
651 packages << "\\usepackage{accents}\n";
653 // mathdots must be loaded after amsmath
654 if (mustProvide("mathdots"))
655 packages << "\\usepackage{mathdots}\n";
657 // yhmath must be loaded after amsmath
658 if (mustProvide("yhmath"))
659 packages << "\\usepackage{yhmath}\n";
661 // [x]color and pdfcolmk are handled in getColorOptions() above
663 // makeidx.sty
664 if (isRequired("makeidx") || isRequired("splitidx")) {
665 if (!tclass.provides("makeidx") && !isRequired("splitidx"))
666 packages << "\\usepackage{makeidx}\n";
667 if (!tclass.provides("splitidx") && isRequired("splitidx"))
668 packages << "\\usepackage{splitidx}\n";
669 packages << "\\makeindex\n";
672 // graphicx.sty
673 if (mustProvide("graphicx") && params_.graphicsDriver != "none") {
674 if (params_.graphicsDriver == "default")
675 packages << "\\usepackage{graphicx}\n";
676 else
677 packages << "\\usepackage["
678 << params_.graphicsDriver
679 << "]{graphicx}\n";
681 // shadecolor for shaded
682 if (isRequired("framed") && mustProvide("color")) {
683 RGBColor c = rgbFromHexName(lcolor.getX11Name(Color_shadedbg));
684 //255.0 to force conversion to double
685 //NOTE As Jürgen Spitzmüller pointed out, an alternative would be
686 //to use the xcolor package instead, and then we can do
687 // \define{shadcolor}{RGB}...
688 //and not do any conversion. We'd then need to require xcolor
689 //in InsetNote::validate().
690 int const stmSize = packages.precision(2);
691 packages << "\\definecolor{shadecolor}{rgb}{"
692 << c.r / 255.0 << ',' << c.g / 255.0 << ',' << c.b / 255.0 << "}\n";
693 packages.precision(stmSize);
696 // lyxskak.sty --- newer chess support based on skak.sty
697 if (mustProvide("chess"))
698 packages << "\\usepackage[ps,mover]{lyxskak}\n";
700 // setspace.sty
701 if (mustProvide("setspace") && !tclass.provides("SetSpace"))
702 packages << "\\usepackage{setspace}\n";
704 // amssymb.sty
705 if (mustProvide("amssymb")
706 || params_.use_amsmath == BufferParams::package_on)
707 packages << "\\usepackage{amssymb}\n";
709 // esint must be after amsmath and wasysym, since it will redeclare
710 // inconsistent integral symbols
711 if ((mustProvide("esint") || mustProvide("esintoramsmath")) &&
712 params_.use_esint != BufferParams::package_off)
713 packages << "\\usepackage{esint}\n";
715 // natbib.sty
716 // Some classes load natbib themselves, but still allow (or even require)
717 // plain numeric citations (ReVTeX is such a case, see bug 5182).
718 // This special case is indicated by the "natbib-internal" key.
719 if (mustProvide("natbib") && !tclass.provides("natbib-internal")) {
720 packages << "\\usepackage[";
721 if (params_.citeEngine() == ENGINE_NATBIB_NUMERICAL)
722 packages << "numbers";
723 else
724 packages << "authoryear";
725 packages << "]{natbib}\n";
728 // jurabib -- we need version 0.6 at least.
729 if (mustProvide("jurabib"))
730 packages << "\\usepackage{jurabib}[2004/01/25]\n";
732 // xargs -- we need version 1.09 at least
733 if (mustProvide("xargs"))
734 packages << "\\usepackage{xargs}[2008/03/08]\n";
736 // bibtopic -- the dot provides the aux file naming which
737 // LyX can detect.
738 if (mustProvide("bibtopic"))
739 packages << "\\usepackage[dot]{bibtopic}\n";
741 if (mustProvide("xy"))
742 packages << "\\usepackage[all]{xy}\n";
744 if (mustProvide("ulem"))
745 packages << "\\PassOptionsToPackage{normalem}{ulem}\n"
746 "\\usepackage{ulem}\n";
748 if (mustProvide("mhchem"))
749 packages << "\\PassOptionsToPackage{version=3}{mhchem}\n"
750 "\\usepackage{mhchem}\n";
752 if (mustProvide("nomencl")) {
753 // Make it work with the new and old version of the package,
754 // but don't use the compatibility option since it is
755 // incompatible to other packages.
756 packages << "\\usepackage{nomencl}\n"
757 "% the following is useful when we have the old nomencl.sty package\n"
758 "\\providecommand{\\printnomenclature}{\\printglossary}\n"
759 "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
760 "\\makenomenclature\n";
763 return packages.str();
767 docstring const LaTeXFeatures::getMacros() const
769 odocstringstream macros;
771 if (!preamble_snippets_.empty())
772 macros << '\n';
773 SnippetList::const_iterator pit = preamble_snippets_.begin();
774 SnippetList::const_iterator pend = preamble_snippets_.end();
775 for (; pit != pend; ++pit)
776 macros << *pit << '\n';
778 if (mustProvide("papersize")) {
779 if (runparams_.flavor == OutputParams::LATEX)
780 macros << papersizedvi_def << '\n';
781 else
782 macros << papersizepdf_def << '\n';
785 if (mustProvide("LyX"))
786 macros << lyx_def << '\n';
788 if (mustProvide("lyxline"))
789 macros << lyxline_def << '\n';
791 if (mustProvide("noun"))
792 macros << noun_def << '\n';
794 if (mustProvide("lyxarrow"))
795 macros << lyxarrow_def << '\n';
797 if (mustProvide("textgreek"))
798 macros << textgreek_def << '\n';
800 if (mustProvide("textcyr"))
801 macros << textcyr_def << '\n';
803 if (mustProvide("lyxmathsym"))
804 macros << lyxmathsym_def << '\n';
806 if (mustProvide("cedilla"))
807 macros << cedilla_def << '\n';
809 if (mustProvide("subring"))
810 macros << subring_def << '\n';
812 if (mustProvide("subdot"))
813 macros << subdot_def << '\n';
815 if (mustProvide("subhat"))
816 macros << subhat_def << '\n';
818 if (mustProvide("subtilde"))
819 macros << subtilde_def << '\n';
821 if (mustProvide("dacute"))
822 macros << dacute_def << '\n';
824 if (mustProvide("tipasymb"))
825 macros << tipasymb_def << '\n';
827 if (mustProvide("dgrave"))
828 macros << dgrave_def << '\n';
830 if (mustProvide("rcap"))
831 macros << rcap_def << '\n';
833 if (mustProvide("ogonek"))
834 macros << ogonek_def << '\n';
836 // quotes.
837 if (mustProvide("quotesinglbase"))
838 macros << quotesinglbase_def << '\n';
839 if (mustProvide("quotedblbase"))
840 macros << quotedblbase_def << '\n';
841 if (mustProvide("guilsinglleft"))
842 macros << guilsinglleft_def << '\n';
843 if (mustProvide("guilsinglright"))
844 macros << guilsinglright_def << '\n';
845 if (mustProvide("guillemotleft"))
846 macros << guillemotleft_def << '\n';
847 if (mustProvide("guillemotright"))
848 macros << guillemotright_def << '\n';
850 // Math mode
851 if (mustProvide("binom") && !isRequired("amsmath"))
852 macros << binom_def << '\n';
853 if (mustProvide("mathcircumflex"))
854 macros << mathcircumflex_def << '\n';
856 // other
857 if (mustProvide("ParagraphLeftIndent"))
858 macros << paragraphleftindent_def;
859 if (mustProvide("NeedLyXFootnoteCode"))
860 macros << floatingfootnote_def;
862 // some problems with tex->html converters
863 if (mustProvide("NeedTabularnewline"))
864 macros << tabularnewline_def;
866 // greyedout environment (note inset)
867 if (mustProvide("lyxgreyedout"))
868 macros << lyxgreyedout_def;
870 if (mustProvide("lyxdot"))
871 macros << lyxdot_def << '\n';
873 // floats
874 getFloatDefinitions(macros);
876 // change tracking
877 if (mustProvide("ct-dvipost"))
878 macros << changetracking_dvipost_def;
880 if (mustProvide("ct-xcolor-ulem")) {
881 int const prec = macros.precision(2);
883 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
884 macros << "\\providecolor{lyxadded}{rgb}{"
885 << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
887 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
888 macros << "\\providecolor{lyxdeleted}{rgb}{"
889 << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
891 macros.precision(prec);
893 if (isRequired("hyperref"))
894 macros << changetracking_xcolor_ulem_hyperref_def;
895 else
896 macros << changetracking_xcolor_ulem_def;
899 if (mustProvide("ct-none"))
900 macros << changetracking_none_def;
902 return macros.str();
906 string const LaTeXFeatures::getBabelOptions() const
908 ostringstream tmp;
910 LanguageList::const_iterator it = UsedLanguages_.begin();
911 LanguageList::const_iterator end = UsedLanguages_.end();
912 for (; it != end; ++it)
913 if (!(*it)->latex_options().empty())
914 tmp << (*it)->latex_options() << '\n';
915 if (!params_.language->latex_options().empty())
916 tmp << params_.language->latex_options() << '\n';
918 return tmp.str();
922 docstring const LaTeXFeatures::getTClassPreamble() const
924 // the text class specific preamble
925 DocumentClass const & tclass = params_.documentClass();
926 odocstringstream tcpreamble;
928 tcpreamble << tclass.preamble();
930 list<docstring>::const_iterator cit = usedLayouts_.begin();
931 list<docstring>::const_iterator end = usedLayouts_.end();
932 for (; cit != end; ++cit)
933 tcpreamble << tclass[*cit].preamble();
935 cit = usedInsetLayouts_.begin();
936 end = usedInsetLayouts_.end();
937 TextClass::InsetLayouts const & ils = tclass.insetLayouts();
938 for (; cit != end; ++cit) {
939 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
940 if (it == ils.end())
941 continue;
942 tcpreamble << it->second.preamble();
945 return tcpreamble.str();
949 docstring const LaTeXFeatures::getTClassHTMLPreamble() const
951 DocumentClass const & tclass = params_.documentClass();
952 odocstringstream tcpreamble;
954 tcpreamble << tclass.htmlpreamble();
956 list<docstring>::const_iterator cit = usedLayouts_.begin();
957 list<docstring>::const_iterator end = usedLayouts_.end();
958 for (; cit != end; ++cit)
959 tcpreamble << tclass[*cit].htmlpreamble();
961 cit = usedInsetLayouts_.begin();
962 end = usedInsetLayouts_.end();
963 TextClass::InsetLayouts const & ils = tclass.insetLayouts();
964 for (; cit != end; ++cit) {
965 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
966 if (it == ils.end())
967 continue;
968 tcpreamble << it->second.htmlpreamble();
971 return tcpreamble.str();
975 docstring const LaTeXFeatures::getTClassHTMLStyles() const {
976 DocumentClass const & tclass = params_.documentClass();
977 odocstringstream tcpreamble;
979 list<docstring>::const_iterator cit = usedLayouts_.begin();
980 list<docstring>::const_iterator end = usedLayouts_.end();
981 for (; cit != end; ++cit)
982 tcpreamble << tclass[*cit].htmlstyle();
984 cit = usedInsetLayouts_.begin();
985 end = usedInsetLayouts_.end();
986 TextClass::InsetLayouts const & ils = tclass.insetLayouts();
987 for (; cit != end; ++cit) {
988 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
989 if (it == ils.end())
990 continue;
991 tcpreamble << it->second.htmlstyle();
994 return tcpreamble.str();
998 namespace {
999 docstring const getFloatI18nPreamble(docstring const & type, docstring const & name, docstring const & lang)
1001 odocstringstream os;
1002 os << "\\addto\\captions" << lang
1003 << "{\\renewcommand{\\" << type << "name}{" << name << "}}\n";
1004 return os.str();
1009 docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel) const
1011 DocumentClass const & tclass = params_.documentClass();
1012 // collect preamble snippets in a set to prevent multiple identical
1013 // commands (would happen if e.g. both theorem and theorem* are used)
1014 set<docstring> snippets;
1015 typedef LanguageList::const_iterator lang_it;
1016 lang_it const lbeg = UsedLanguages_.begin();
1017 lang_it const lend = UsedLanguages_.end();
1018 list<docstring>::const_iterator cit = usedLayouts_.begin();
1019 list<docstring>::const_iterator end = usedLayouts_.end();
1020 for (; cit != end; ++cit) {
1021 // language dependent commands (once per document)
1022 snippets.insert(tclass[*cit].langpreamble(buffer().language()));
1023 // commands for language changing (for multilanguage documents)
1024 if (use_babel && !UsedLanguages_.empty()) {
1025 snippets.insert(tclass[*cit].babelpreamble(buffer().language()));
1026 for (lang_it lit = lbeg; lit != lend; ++lit)
1027 snippets.insert(tclass[*cit].babelpreamble(*lit));
1030 if (use_babel && !UsedLanguages_.empty()) {
1031 FloatList const & floats = params_.documentClass().floats();
1032 UsedFloats::const_iterator fit = usedFloats_.begin();
1033 UsedFloats::const_iterator fend = usedFloats_.end();
1034 for (; fit != fend; ++fit) {
1035 Floating const & fl = floats.getType(fit->first);
1036 docstring const type = from_ascii(fl.type());
1037 docstring const flname = from_utf8(fl.name());
1038 docstring name = translateIfPossible(flname,
1039 buffer().language()->code());
1040 snippets.insert(getFloatI18nPreamble(
1041 type, name,
1042 from_ascii(buffer().language()->babel())));
1043 for (lang_it lit = lbeg; lit != lend; ++lit) {
1044 name = translateIfPossible(flname,
1045 (*lit)->code());
1046 snippets.insert(getFloatI18nPreamble(
1047 type, name,
1048 from_ascii((*lit)->babel())));
1053 odocstringstream tcpreamble;
1054 set<docstring>::const_iterator const send = snippets.end();
1055 set<docstring>::const_iterator it = snippets.begin();
1056 for (; it != send; ++it)
1057 tcpreamble << *it;
1058 return tcpreamble.str();
1062 docstring const LaTeXFeatures::getLyXSGMLEntities() const
1064 // Definition of entities used in the document that are LyX related.
1065 odocstringstream entities;
1067 if (mustProvide("lyxarrow")) {
1068 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
1071 return entities.str();
1075 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
1077 odocstringstream sgmlpreamble;
1078 // FIXME UNICODE
1079 docstring const basename(from_utf8(onlyPath(fname)));
1081 FileMap::const_iterator end = IncludedFiles_.end();
1082 for (FileMap::const_iterator fi = IncludedFiles_.begin();
1083 fi != end; ++fi)
1084 // FIXME UNICODE
1085 sgmlpreamble << "\n<!ENTITY " << fi->first
1086 << (isSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
1087 << makeRelPath(from_utf8(fi->second), basename) << "\">";
1089 return sgmlpreamble.str();
1093 void LaTeXFeatures::showStruct() const
1095 lyxerr << "LyX needs the following commands when LaTeXing:"
1096 << "\n***** Packages:" << getPackages()
1097 << "\n***** Macros:" << to_utf8(getMacros())
1098 << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
1099 << "\n***** done." << endl;
1103 Buffer const & LaTeXFeatures::buffer() const
1105 return *buffer_;
1109 void LaTeXFeatures::setBuffer(Buffer const & buffer)
1111 buffer_ = &buffer;
1115 BufferParams const & LaTeXFeatures::bufferParams() const
1117 return params_;
1121 void LaTeXFeatures::getFloatDefinitions(odocstream & os) const
1123 FloatList const & floats = params_.documentClass().floats();
1125 // Here we will output the code to create the needed float styles.
1126 // We will try to do this as minimal as possible.
1127 // \floatstyle{ruled}
1128 // \newfloat{algorithm}{htbp}{loa}
1129 // \providecommand{\algorithmname}{Algorithm}
1130 // \floatname{algorithm}{\protect\algorithmname}
1131 UsedFloats::const_iterator cit = usedFloats_.begin();
1132 UsedFloats::const_iterator end = usedFloats_.end();
1133 for (; cit != end; ++cit) {
1134 Floating const & fl = floats.getType(cit->first);
1136 // For builtin floats we do nothing.
1137 if (fl.builtin()) continue;
1139 // We have to special case "table" and "figure"
1140 if (fl.type() == "tabular" || fl.type() == "figure") {
1141 // Output code to modify "table" or "figure"
1142 // but only if builtin == false
1143 // and that have to be true at this point in the
1144 // function.
1145 docstring const type = from_ascii(fl.type());
1146 docstring const placement = from_ascii(fl.placement());
1147 docstring const style = from_ascii(fl.style());
1148 if (!style.empty()) {
1149 os << "\\floatstyle{" << style << "}\n"
1150 << "\\restylefloat{" << type << "}\n";
1152 if (!placement.empty()) {
1153 os << "\\floatplacement{" << type << "}{"
1154 << placement << "}\n";
1156 } else {
1157 // The other non builtin floats.
1159 docstring const type = from_ascii(fl.type());
1160 docstring const placement = from_ascii(fl.placement());
1161 docstring const ext = from_ascii(fl.ext());
1162 docstring const within = from_ascii(fl.within());
1163 docstring const style = from_ascii(fl.style());
1164 docstring const name = translateIfPossible(
1165 from_utf8(fl.name()),
1166 buffer().language()->code());
1167 os << "\\floatstyle{" << style << "}\n"
1168 << "\\newfloat{" << type << "}{" << placement
1169 << "}{" << ext << '}';
1170 if (!within.empty())
1171 os << '[' << within << ']';
1172 os << '\n'
1173 << "\\providecommand{\\" << type << "name}{"
1174 << name << "}\n"
1175 << "\\floatname{" << type << "}{\\protect\\"
1176 << type << "name}\n";
1178 // What missing here is to code to minimalize the code
1179 // output so that the same floatstyle will not be
1180 // used several times, when the same style is still in
1181 // effect. (Lgb)
1183 if (cit->second)
1184 os << "\n\\newsubfloat{" << from_ascii(fl.type()) << "}\n";
1189 } // namespace lyx