]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.cpp
a23837b1f6e9e8b59d4b2cf2f41b3643b5d6dd37
[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 "LaTeXFonts.h"
28 #include "LaTeXPackages.h"
29 #include "Layout.h"
30 #include "Lexer.h"
31 #include "LyXRC.h"
32 #include "TextClass.h"
33
34 #include "insets/InsetLayout.h"
35
36 #include "support/debug.h"
37 #include "support/docstream.h"
38 #include "support/FileName.h"
39 #include "support/filetools.h"
40 #include "support/gettext.h"
41 #include "support/lstrings.h"
42 #include "support/regex.h"
43
44 #include <algorithm>
45
46
47 using namespace std;
48 using namespace lyx::support;
49
50
51 namespace lyx {
52
53 /////////////////////////////////////////////////////////////////////
54 //
55 // Strings
56 //
57 /////////////////////////////////////////////////////////////////////
58
59 //\NeedsTeXFormat{LaTeX2e}
60 //\ProvidesPackage{lyx}[1996/01/11 LLE v0.2 (LyX LaTeX Extensions)]
61 //\message{LyX LaTeX Extensions (LLE v0.2) of 11-Jan-1996.}
62
63 static docstring const lyx_def = from_ascii(
64         "\\providecommand{\\LyX}{L\\kern-.1667em\\lower.25em\\hbox{Y}\\kern-.125emX\\@}");
65
66 static docstring const lyx_hyperref_def = from_ascii(
67         "\\providecommand{\\LyX}{\\texorpdfstring%\n"
68         "  {L\\kern-.1667em\\lower.25em\\hbox{Y}\\kern-.125emX\\@}\n"
69         "  {LyX}}");
70
71 static docstring const noun_def = from_ascii(
72         "\\newcommand{\\noun}[1]{\\textsc{#1}}");
73
74 static docstring const lyxarrow_def = from_ascii(
75         "\\DeclareRobustCommand*{\\lyxarrow}{%\n"
76         "\\@ifstar\n"
77         "{\\leavevmode\\,$\\triangleleft$\\,\\allowbreak}\n"
78         "{\\leavevmode\\,$\\triangleright$\\,\\allowbreak}}");
79
80 // for quotes without babel. This does not give perfect results, but
81 // anybody serious about non-english quotes should use babel (JMarc).
82
83 static docstring const quotedblbase_def = from_ascii(
84         "\\ProvideTextCommandDefault{\\quotedblbase}{%\n"
85         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquotedblright}%\n"
86         "  \\penalty10000\\hskip0em\\relax%\n"
87         "}");
88
89 static docstring const quotesinglbase_def = from_ascii(
90         "\\ProvideTextCommandDefault{\\quotesinglbase}{%\n"
91         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquoteright}%\n"
92         "  \\penalty10000\\hskip0em\\relax%\n"
93         "}");
94
95 static docstring const guillemotleft_def = from_ascii(
96         "\\ProvideTextCommandDefault{\\guillemotleft}{%\n"
97         "  {\\usefont{U}{lasy}{m}{n}\\char'50\\kern-.15em\\char'50}%\n"
98         "\\penalty10000\\hskip0pt\\relax%\n"
99         "}");
100
101 static docstring const guillemotright_def = from_ascii(
102         "\\ProvideTextCommandDefault{\\guillemotright}{%\n"
103         "  \\penalty10000\\hskip0pt%\n"
104         "  {\\usefont{U}{lasy}{m}{n}\\char'51\\kern-.15em\\char'51}%\n"
105         "}");
106
107 static docstring const guilsinglleft_def = from_ascii(
108         "\\ProvideTextCommandDefault{\\guilsinglleft}{%\n"
109         "  {\\usefont{U}{lasy}{m}{n}\\char'50}%\n"
110         "  \\penalty10000\\hskip0pt\\relax%\n"
111         "}");
112
113 static docstring const guilsinglright_def = from_ascii(
114         "\\ProvideTextCommandDefault{\\guilsinglright}{%\n"
115         "  \\penalty10000\\hskip0pt%\n"
116         "  {\\usefont{U}{lasy}{m}{n}\\char'51}%\n"
117         "}");
118
119 static docstring const paragraphleftindent_def = from_ascii(
120         "\\newenvironment{LyXParagraphLeftIndent}[1]%\n"
121         "{\n"
122         "  \\begin{list}{}{%\n"
123         "    \\setlength{\\topsep}{0pt}%\n"
124         "    \\addtolength{\\leftmargin}{#1}\n"
125 // ho hum, yet more things commented out with no hint as to why they
126 // weren't just removed
127 //      "%%    \\addtolength{\\leftmargin}{#1\\textwidth}\n"
128 //      "%%    \\setlength{\\textwidth}{#2\\textwidth}\n"
129 //      "%%    \\setlength\\listparindent\\parindent%\n"
130 //      "%%    \\setlength\\itemindent\\parindent%\n"
131         "    \\setlength{\\parsep}{0pt plus 1pt}%\n"
132         "  }\n"
133         "  \\item[]\n"
134         "}\n"
135         "{\\end{list}}\n");
136
137 static docstring const binom_def = from_ascii(
138         "%% Binom macro for standard LaTeX users\n"
139         "\\newcommand{\\binom}[2]{{#1 \\choose #2}}\n");
140
141 static docstring const mathcircumflex_def = from_ascii(
142         "%% For printing a cirumflex inside a formula\n"
143         "\\newcommand{\\mathcircumflex}[0]{\\mbox{\\^{}}}\n");
144
145 static docstring const tabularnewline_def = from_ascii(
146         "%% Because html converters don't know tabularnewline\n"
147         "\\providecommand{\\tabularnewline}{\\\\}\n");
148
149 static docstring const lyxgreyedout_def = from_ascii(
150         "%% The greyedout annotation environment\n"
151         "\\newenvironment{lyxgreyedout}\n"
152         "  {\\textcolor{note_fontcolor}\\bgroup\\ignorespaces}\n"
153         "  {\\ignorespacesafterend\\egroup}\n");
154
155 // We want to omit the file extension for includegraphics, but this does not
156 // work when the filename contains other dots.
157 // Idea from http://www.tex.ac.uk/cgi-bin/texfaq2html?label=unkgrfextn
158 static docstring const lyxdot_def = from_ascii(
159         "%% A simple dot to overcome graphicx limitations\n"
160         "\\newcommand{\\lyxdot}{.}\n");
161
162 static docstring const changetracking_dvipost_def = from_ascii(
163         "%% Change tracking with dvipost\n"
164         "\\dvipostlayout\n"
165         "\\dvipost{osstart color push Red}\n"
166         "\\dvipost{osend color pop}\n"
167         "\\dvipost{cbstart color push Blue}\n"
168         "\\dvipost{cbend color pop}\n"
169         "\\DeclareRobustCommand{\\lyxadded}[3]{\\changestart#3\\changeend}\n"
170         "\\DeclareRobustCommand{\\lyxdeleted}[3]{%\n"
171         "\\changestart\\overstrikeon#3\\overstrikeoff\\changeend}\n");
172
173 static docstring const changetracking_xcolor_ulem_def = from_ascii(
174         "%% Change tracking with ulem\n"
175         "\\DeclareRobustCommand{\\lyxadded}[3]{{\\color{lyxadded}{}#3}}\n"
176         "\\DeclareRobustCommand{\\lyxdeleted}[3]{{\\color{lyxdeleted}\\sout{#3}}}\n");
177
178 static docstring const changetracking_xcolor_ulem_hyperref_def = from_ascii(
179         "%% Change tracking with ulem\n"
180         "\\DeclareRobustCommand{\\lyxadded}[3]{{\\texorpdfstring{\\color{lyxadded}{}}{}#3}}\n"
181         "\\DeclareRobustCommand{\\lyxdeleted}[3]{{\\texorpdfstring{\\color{lyxdeleted}\\sout{#3}}{}}}\n");
182
183 static docstring const changetracking_none_def = from_ascii(
184         "\\newcommand{\\lyxadded}[3]{#3}\n"
185         "\\newcommand{\\lyxdeleted}[3]{}\n");
186
187 static docstring const textgreek_LGR_def = from_ascii(
188         "\\DeclareFontEncoding{LGR}{}{}\n");
189 static docstring const textgreek_def = from_ascii(
190         "\\DeclareRobustCommand{\\greektext}{%\n"
191         "  \\fontencoding{LGR}\\selectfont\\def\\encodingdefault{LGR}}\n"
192         "\\DeclareRobustCommand{\\textgreek}[1]{\\leavevmode{\\greektext #1}}\n"
193         "\\ProvideTextCommand{\\~}{LGR}[1]{\\char126#1}\n");
194    
195 static docstring const textcyr_def = from_ascii(
196         "\\DeclareRobustCommand{\\cyrtext}{%\n"
197         "  \\fontencoding{T2A}\\selectfont\\def\\encodingdefault{T2A}}\n"
198         "\\DeclareRobustCommand{\\textcyr}[1]{\\leavevmode{\\cyrtext #1}}\n"
199         "\\AtBeginDocument{\\DeclareFontEncoding{T2A}{}{}}\n");
200
201 static docstring const lyxmathsym_def = from_ascii(
202         "\\newcommand{\\lyxmathsym}[1]{\\ifmmode\\begingroup\\def\\b@ld{bold}\n"
203         "  \\text{\\ifx\\math@version\\b@ld\\bfseries\\fi#1}\\endgroup\\else#1\\fi}\n");
204
205 static docstring const papersizedvi_def = from_ascii(
206         "\\special{papersize=\\the\\paperwidth,\\the\\paperheight}\n");
207
208 static docstring const papersizepdf_def = from_ascii(
209         "\\pdfpageheight\\paperheight\n"
210         "\\pdfpagewidth\\paperwidth\n");
211
212 static docstring const cedilla_def = from_ascii(
213         "\\newcommand{\\docedilla}[2]{\\underaccent{#1\\mathchar'30}{#2}}\n"
214         "\\newcommand{\\cedilla}[1]{\\mathpalette\\docedilla{#1}}\n");
215
216 static docstring const subring_def = from_ascii(
217         "\\newcommand{\\dosubring}[2]{\\underaccent{#1\\mathchar'27}{#2}}\n"
218         "\\newcommand{\\subring}[1]{\\mathpalette\\dosubring{#1}}\n");
219
220 static docstring const subdot_def = from_ascii(
221         "\\newcommand{\\dosubdot}[2]{\\underaccent{#1.}{#2}}\n"
222         "\\newcommand{\\subdot}[1]{\\mathpalette\\dosubdot{#1}}\n");
223
224 static docstring const subhat_def = from_ascii(
225         "\\newcommand{\\dosubhat}[2]{\\underaccent{#1\\mathchar'136}{#2}}\n"
226         "\\newcommand{\\subhat}[1]{\\mathpalette\\dosubhat{#1}}\n");
227
228 static docstring const subtilde_def = from_ascii(
229         "\\newcommand{\\dosubtilde}[2]{\\underaccent{#1\\mathchar'176}{#2}}\n"
230         "\\newcommand{\\subtilde}[1]{\\mathpalette\\dosubtilde{#1}}\n");
231
232 static docstring const dacute_def = from_ascii(
233         "\\DeclareMathAccent{\\dacute}{\\mathalpha}{operators}{'175}\n");
234
235 static docstring const tipasymb_def = from_ascii(
236         "\\DeclareFontEncoding{T3}{}{}\n"
237         "\\DeclareSymbolFont{tipasymb}{T3}{cmr}{m}{n}\n");
238
239 static docstring const dgrave_def = from_ascii(
240         "\\DeclareMathAccent{\\dgrave}{\\mathord}{tipasymb}{'15}\n");
241
242 static docstring const rcap_def = from_ascii(
243         "\\DeclareMathAccent{\\rcap}{\\mathord}{tipasymb}{'20}\n");
244
245 static docstring const ogonek_def = from_ascii(
246         "\\newcommand{\\doogonek}[2]{\\setbox0=\\hbox{$#1#2$}\\underaccent{#1\\mkern-6mu\n"
247         "  \\ifx#2O\\hskip0.5\\wd0\\else\\ifx#2U\\hskip0.5\\wd0\\else\\hskip\\wd0\\fi\\fi\n"
248         "  \\ifx#2o\\mkern-2mu\\else\\ifx#2e\\mkern-1mu\\fi\\fi\n"
249         "  \\mathchar\"0\\hexnumber@\\symtipasymb0C}{#2}}\n"
250         "\\newcommand{\\ogonek}[1]{\\mathpalette\\doogonek{#1}}\n");
251
252 static docstring const lyxref_def = from_ascii(
253                 "\\RS@ifundefined{subsecref}\n"
254                 "  {\\newref{subsec}{name = \\RSsectxt}}\n"
255                 "  {}\n"
256                 "\\RS@ifundefined{thmref}\n"
257                 "  {\\def\\RSthmtxt{theorem~}\\newref{thm}{name = \\RSthmtxt}}\n"
258                 "  {}\n"
259                 "\\RS@ifundefined{lemref}\n"
260                 "  {\\def\\RSlemtxt{lemma~}\\newref{lem}{name = \\RSlemtxt}}\n"
261                 "  {}\n");
262
263 // Make sure the columns are also outputed as rtl
264 static docstring const rtloutputdblcol_def = from_ascii(
265         "\\def\\@outputdblcol{%\n"
266         "  \\if@firstcolumn\n"
267         "    \\global \\@firstcolumnfalse\n"
268         "    \\global \\setbox\\@leftcolumn \\box\\@outputbox\n"
269         "  \\else\n"
270         "    \\global \\@firstcolumntrue\n"
271         "    \\setbox\\@outputbox \\vbox {%\n"
272         "      \\hb@xt@\\textwidth {%\n"
273         "      \\kern\\textwidth \\kern-\\columnwidth %**\n"
274         "      \\hb@xt@\\columnwidth {%\n"
275         "         \\box\\@leftcolumn \\hss}%\n"
276         "      \\kern-\\textwidth %**\n"
277         "      \\hfil\n"
278         "      {\\normalcolor\\vrule \\@width\\columnseprule}%\n"
279         "      \\hfil\n"
280         "      \\kern-\\textwidth  %**\n"
281         "      \\hb@xt@\\columnwidth {%\n"
282         "         \\box\\@outputbox \\hss}%\n"
283         "      \\kern-\\columnwidth \\kern\\textwidth %**\n"
284         "    }%\n"
285         "  }%\n"
286         "  \\@combinedblfloats\n"
287         "  \\@outputpage\n"
288         "  \\begingroup\n"
289         "  \\@dblfloatplacement\n"
290         "  \\@startdblcolumn\n"
291         "  \\@whilesw\\if@fcolmade \\fi\n"
292         "  {\\@outputpage\n"
293         "    \\@startdblcolumn}%\n"
294         "  \\endgroup\n"
295         "  \\fi\n"
296         "}\n"
297         "\\@mparswitchtrue\n");
298
299
300 /////////////////////////////////////////////////////////////////////
301 //
302 // LyXHTML strings
303 //
304 /////////////////////////////////////////////////////////////////////
305
306 static docstring const lyxnoun_style = from_ascii(
307         "dfn.lyxnoun {\n"
308         "  font-variant: small-caps;\n"
309         "}\n");
310
311
312 // this is how it normally renders, but it might not always do so.
313 static docstring const lyxstrikeout_style = from_ascii(
314         "del.strikeout {\n"
315         "  text-decoration: line-through;\n"
316         "}\n");
317
318
319 /////////////////////////////////////////////////////////////////////
320 //
321 // LaTeXFeatures
322 //
323 /////////////////////////////////////////////////////////////////////
324
325
326 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p,
327                              OutputParams const & r)
328         : buffer_(&b), params_(p), runparams_(r), in_float_(false)
329 {}
330
331
332 LaTeXFeatures::LangPackage LaTeXFeatures::langPackage() const
333 {
334         string const local_lp = bufferParams().lang_package;
335
336         // Locally, custom is just stored as a string
337         // in bufferParams().lang_package.
338         if (local_lp != "auto"
339             && local_lp != "babel"
340             && local_lp != "default"
341             && local_lp != "none")
342                  return LANG_PACK_CUSTOM;
343
344         if (local_lp == "none")
345                 return LANG_PACK_NONE;
346
347         /* If "auto" is selected, we load polyglossia if required,
348          * else we select babel.
349          * If babel is selected (either directly or via the "auto"
350          * mechanism), we really do only require it if we have
351          * a language that needs it.
352          */
353         bool const polyglossia_required =
354                 isRequired("polyglossia")
355                 && isAvailable("polyglossia")
356                 && !isProvided("babel")
357                 && this->hasOnlyPolyglossiaLanguages();
358         bool const babel_required =
359                 !bufferParams().language->babel().empty()
360                 || !this->getBabelLanguages().empty();
361
362         if (local_lp == "auto") {
363                 // polyglossia requirement has priority over babel
364                 if (polyglossia_required)
365                         return LANG_PACK_POLYGLOSSIA;
366                 else if (babel_required)
367                         return LANG_PACK_BABEL;
368         }
369
370         if (local_lp == "babel") {
371                 if (babel_required)
372                         return LANG_PACK_BABEL;
373         }
374
375         if (local_lp == "default") {
376                 switch (lyxrc.language_package_selection) {
377                 case LyXRC::LP_AUTO:
378                         // polyglossia requirement has priority over babel
379                         if (polyglossia_required)
380                                 return LANG_PACK_POLYGLOSSIA;
381                         else if (babel_required)
382                                 return LANG_PACK_BABEL;
383                         break;
384                 case LyXRC::LP_BABEL:
385                         if (babel_required)
386                                 return LANG_PACK_BABEL;
387                         break;
388                 case LyXRC::LP_CUSTOM:
389                         return LANG_PACK_CUSTOM;
390                 case LyXRC::LP_NONE:
391                         return LANG_PACK_NONE;
392                 }
393         }
394
395         return LANG_PACK_NONE;
396 }
397
398
399 void LaTeXFeatures::require(string const & name)
400 {
401         features_.insert(name);
402 }
403
404
405 void LaTeXFeatures::require(set<string> const & names)
406 {
407         features_.insert(names.begin(), names.end());
408 }
409
410
411 void LaTeXFeatures::useLayout(docstring const & layoutname)
412 {
413         useLayout(layoutname, 0);
414 }
415
416
417 void LaTeXFeatures::useLayout(docstring const & layoutname, int level)
418 {
419         // Some code to avoid loops in dependency definition
420         const int maxlevel = 30;
421         if (level > maxlevel) {
422                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
423                        << "recursion attained by layout "
424                        << to_utf8(layoutname) << endl;
425                 return;
426         }
427
428         DocumentClass const & tclass = params_.documentClass();
429         if (tclass.hasLayout(layoutname)) {
430                 // Is this layout already in usedLayouts?
431                 if (find(usedLayouts_.begin(), usedLayouts_.end(), layoutname)
432                     != usedLayouts_.end())
433                         return;
434
435                 Layout const & layout = tclass[layoutname];
436                 require(layout.requires());
437
438                 if (!layout.depends_on().empty()) {
439                         useLayout(layout.depends_on(), level + 1);
440                 }
441                 usedLayouts_.push_back(layoutname);
442         } else {
443                 lyxerr << "LaTeXFeatures::useLayout: layout `"
444                        << to_utf8(layoutname) << "' does not exist in this class"
445                        << endl;
446         }
447 }
448
449
450 void LaTeXFeatures::useInsetLayout(InsetLayout const & lay)
451 {
452         docstring const & lname = lay.name();
453         DocumentClass const & tclass = params_.documentClass();
454
455         // this is a default inset layout, nothing useful here
456         if (!tclass.hasInsetLayout(lname))
457                 return;
458         // Is this layout already in usedInsetLayouts?
459         if (find(usedInsetLayouts_.begin(), usedInsetLayouts_.end(), lname)
460                         != usedInsetLayouts_.end())
461                 return;
462
463         require(lay.requires());
464         usedInsetLayouts_.push_back(lname);
465 }
466
467
468 bool LaTeXFeatures::isRequired(string const & name) const
469 {
470         return features_.find(name) != features_.end();
471 }
472
473
474 bool LaTeXFeatures::isProvided(string const & name) const
475 {
476         if (params_.useNonTeXFonts)
477                 return params_.documentClass().provides(name);
478
479         bool const ot1 = (params_.font_encoding() == "default"
480                 || params_.font_encoding() == "OT1");
481         bool const complete = (params_.fonts_sans == "default")
482                 && (params_.fonts_typewriter == "default");
483         bool const nomath = (params_.fonts_math == "default");
484         return params_.documentClass().provides(name)
485                 || theLaTeXFonts().getLaTeXFont(
486                         from_ascii(params_.fonts_roman)).provides(name, ot1,
487                                                                   complete,
488                                                                   nomath)
489                 || theLaTeXFonts().getLaTeXFont(
490                         from_ascii(params_.fonts_sans)).provides(name, ot1,
491                                                                  complete,
492                                                                  nomath)
493                 || theLaTeXFonts().getLaTeXFont(
494                         from_ascii(params_.fonts_typewriter)).provides(name, ot1,
495                                                                        complete,
496                                                                        nomath)
497                 || theLaTeXFonts().getLaTeXFont(
498                         from_ascii(params_.fonts_math)).provides(name, ot1,
499                                                                        complete,
500                                                                        nomath);
501 }
502
503
504 bool LaTeXFeatures::mustProvide(string const & name) const
505 {
506         return isRequired(name) && !isProvided(name);
507 }
508
509
510 bool LaTeXFeatures::isAvailable(string const & name)
511 {
512         string::size_type const i = name.find("->");
513         if (i != string::npos) {
514                 string const from = name.substr(0,i);
515                 string const to = name.substr(i+2);
516                 //LYXERR0("from=[" << from << "] to=[" << to << "]");
517                 return theConverters().isReachable(from, to);
518         }
519         return LaTeXPackages::isAvailable(name);
520 }
521
522
523 void LaTeXFeatures::addPreambleSnippet(string const & preamble)
524 {
525         SnippetList::const_iterator begin = preamble_snippets_.begin();
526         SnippetList::const_iterator end   = preamble_snippets_.end();
527         if (find(begin, end, preamble) == end)
528                 preamble_snippets_.push_back(preamble);
529 }
530
531
532 void LaTeXFeatures::addCSSSnippet(std::string const & snippet)
533 {
534         SnippetList::const_iterator begin = css_snippets_.begin();
535         SnippetList::const_iterator end   = css_snippets_.end();
536         if (find(begin, end, snippet) == end)
537                 css_snippets_.push_back(snippet);
538 }
539
540
541 void LaTeXFeatures::useFloat(string const & name, bool subfloat)
542 {
543         if (!usedFloats_[name])
544                 usedFloats_[name] = subfloat;
545         if (subfloat)
546                 require("subfig");
547         // We only need float.sty if we use non builtin floats, or if we
548         // use the "H" modifier. This includes modified table and
549         // figure floats. (Lgb)
550         Floating const & fl = params_.documentClass().floats().getType(name);
551         if (!fl.floattype().empty() && fl.usesFloatPkg()) {
552                 require("float");
553         }
554 }
555
556
557 void LaTeXFeatures::useLanguage(Language const * lang)
558 {
559         if (!lang->babel().empty() || !lang->polyglossia().empty())
560                 UsedLanguages_.insert(lang);
561         if (!lang->requires().empty())
562                 require(lang->requires());
563         // CJK languages do not have a babel name.
564         // They use the CJK package
565         if (lang->encoding()->package() == Encoding::CJK)
566                 require("CJK");
567         // japanese package is special
568         if (lang->encoding()->package() == Encoding::japanese)
569                 require("japanese");
570 }
571
572
573 void LaTeXFeatures::includeFile(docstring const & key, string const & name)
574 {
575         IncludedFiles_[key] = name;
576 }
577
578
579 bool LaTeXFeatures::hasLanguages() const
580 {
581         return !UsedLanguages_.empty();
582 }
583
584
585 bool LaTeXFeatures::hasOnlyPolyglossiaLanguages() const
586 {
587         // first the main language
588         if (params_.language->polyglossia().empty())
589                 return false;
590         // now the secondary languages
591         LanguageList::const_iterator const begin = UsedLanguages_.begin();
592         for (LanguageList::const_iterator cit = begin;
593              cit != UsedLanguages_.end();
594              ++cit) {
595                 if ((*cit)->polyglossia().empty())
596                         return false;
597         }
598         return true;
599 }
600
601
602 bool LaTeXFeatures::hasPolyglossiaExclusiveLanguages() const
603 {
604         // first the main language
605         if (params_.language->isPolyglossiaExclusive())
606                 return true;
607         // now the secondary languages
608         LanguageList::const_iterator const begin = UsedLanguages_.begin();
609         for (LanguageList::const_iterator cit = begin;
610              cit != UsedLanguages_.end();
611              ++cit) {
612                 if ((*cit)->isPolyglossiaExclusive())
613                         return true;
614         }
615         return false;
616 }
617
618
619 string LaTeXFeatures::getBabelLanguages() const
620 {
621         ostringstream languages;
622
623         bool first = true;
624         LanguageList::const_iterator const begin = UsedLanguages_.begin();
625         for (LanguageList::const_iterator cit = begin;
626              cit != UsedLanguages_.end();
627              ++cit) {
628                 if ((*cit)->babel().empty())
629                         continue;
630                 if (!first)
631                         languages << ',';
632                 else
633                         first = false;
634                 languages << (*cit)->babel();
635         }
636         return languages.str();
637 }
638
639
640 std::map<std::string, std::string> LaTeXFeatures::getPolyglossiaLanguages() const
641 {
642         std::map<std::string, std::string> languages;
643
644         LanguageList::const_iterator const begin = UsedLanguages_.begin();
645         for (LanguageList::const_iterator cit = begin;
646              cit != UsedLanguages_.end();
647              ++cit) {
648                 languages[(*cit)->polyglossia()] = (*cit)->polyglossiaOpts();
649         }
650         return languages;
651 }
652
653
654 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
655 {
656         // This does only find encodings of languages supported by babel, but
657         // that does not matter since we don't have a language with an
658         // encoding supported by inputenc but without babel support.
659         set<string> encodings;
660         LanguageList::const_iterator it  = UsedLanguages_.begin();
661         LanguageList::const_iterator end = UsedLanguages_.end();
662         for (; it != end; ++it)
663                 if ((*it)->encoding()->latexName() != doc_encoding &&
664                     ((*it)->encoding()->package() == Encoding::inputenc
665                      || (*it)->encoding()->package() == Encoding::japanese))
666                         encodings.insert((*it)->encoding()->latexName());
667         return encodings;
668 }
669
670
671 void LaTeXFeatures::getFontEncodings(vector<string> & encodings) const
672 {
673         // these must be loaded if glyphs of this script
674         // are used (notwithstanding the language)
675         if (mustProvide("textgreek"))
676                 encodings.insert(encodings.begin(), "LGR");
677         if (mustProvide("textcyr"))
678                 encodings.insert(encodings.begin(), "T2A");
679
680         LanguageList::const_iterator it  = UsedLanguages_.begin();
681         LanguageList::const_iterator end = UsedLanguages_.end();
682         for (; it != end; ++it)
683                 if (!(*it)->fontenc().empty()
684                     && ascii_lowercase((*it)->fontenc()) != "none") {
685                         vector<string> extraencs = getVectorFromString((*it)->fontenc());
686                         vector<string>::const_iterator fit = extraencs.begin();
687                         for (; fit != extraencs.end(); ++fit) {
688                                 if (find(encodings.begin(), encodings.end(), *fit) == encodings.end())
689                                         encodings.insert(encodings.begin(), *fit);
690                         }
691                 }
692 }
693
694 namespace {
695
696 char const * simplefeatures[] = {
697 // note that the package order here will be the same in the LaTeX-output
698         "array",
699         "verbatim",
700         "longtable",
701         "rotating",
702         "latexsym",
703         "pifont",
704         // subfig is handled in BufferParams.cpp
705         "varioref",
706         "prettyref",
707         "refstyle",
708         /*For a successful cooperation of the `wrapfig' package with the
709           `float' package you should load the `wrapfig' package *after*
710           the `float' package. See the caption package documentation
711           for explanation.*/
712         "float",
713         "rotfloat",
714         "wrapfig",
715         "booktabs",
716         "dvipost",
717         "fancybox",
718         "calc",
719         "units",
720         "framed",
721         "soul",
722         "textcomp",
723         "pmboxdraw",
724         "bbding",
725         "ifsym",
726         "txfonts",
727         "pxfonts",
728         "mathdesign",
729         "mathrsfs",
730         "mathabx",
731         "mathtools",
732         // "cancel",
733         "ascii",
734         "url",
735         "covington",
736         "csquotes",
737         "enumitem",
738         "endnotes",
739         "hhline",
740         "ifthen",
741         // listings is handled in BufferParams.cpp
742         "bm",
743         "pdfpages",
744         "amscd",
745         "slashed",
746         "multicol",
747         "multirow",
748         "tfrupee",
749         "shapepar",
750         "rsphrase",
751         "hpstatement",
752         "algorithm2e",
753         "sectionbox",
754         "tcolorbox",
755         "pdfcomment",
756         "fixme",
757         "todonotes",
758         "forest"
759 };
760
761 char const * bibliofeatures[] = {
762         // Known bibliography packages (will be loaded before natbib)
763         "achicago",
764         "apacite",
765         "apalike",
766         "astron",
767         "authordate1-4",
768         "babelbib",
769         "bibgerm",
770         "chicago",
771         "chscite",
772         "harvard",
773         "mslapa",
774         "named"
775 };
776
777 int const nb_bibliofeatures = sizeof(bibliofeatures) / sizeof(char const *);
778
779 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
780
781 }
782
783
784 string const LaTeXFeatures::getColorOptions() const
785 {
786         ostringstream colors;
787
788         // Handling the color packages separately is needed to be able to load them
789         // before babel when hyperref is loaded with the colorlinks option
790         // for more info see Bufferparams.cpp
791
792         // [x]color.sty
793         if (mustProvide("color") || mustProvide("xcolor")) {
794                 string const package =
795                         (mustProvide("xcolor") ? "xcolor" : "color");
796                 if (params_.graphics_driver == "default"
797                         || params_.graphics_driver == "none")
798                         colors << "\\usepackage{" << package << "}\n";
799                 else
800                         colors << "\\usepackage["
801                                  << params_.graphics_driver
802                                  << "]{" << package << "}\n";
803         }
804
805         // pdfcolmk must be loaded after color
806         if (mustProvide("pdfcolmk"))
807                 colors << "\\usepackage{pdfcolmk}\n";
808
809         // the following 3 color commands must be set after color
810         // is loaded and before pdfpages, therefore add the command
811         // here define the set color
812         if (mustProvide("pagecolor")) {
813                 colors << "\\definecolor{page_backgroundcolor}{rgb}{";
814                 colors << outputLaTeXColor(params_.backgroundcolor) << "}\n";
815                 // set the page color
816                 colors << "\\pagecolor{page_backgroundcolor}\n";
817         }
818
819         if (mustProvide("fontcolor")) {
820                 colors << "\\definecolor{document_fontcolor}{rgb}{";
821                 colors << outputLaTeXColor(params_.fontcolor) << "}\n";
822                 // set the color
823                 colors << "\\color{document_fontcolor}\n";
824         }
825
826         if (mustProvide("lyxgreyedout")) {
827                 colors << "\\definecolor{note_fontcolor}{rgb}{";
828                 colors << outputLaTeXColor(params_.notefontcolor) << "}\n";
829                 // the color will be set together with the definition of
830                 // the lyxgreyedout environment (see lyxgreyedout_def)
831         }
832
833         // color for shaded boxes
834         if (isRequired("framed") && mustProvide("color")) {
835                 colors << "\\definecolor{shadecolor}{rgb}{";
836                 colors << outputLaTeXColor(params_.boxbgcolor) << "}\n";
837                 // this color is automatically used by the LaTeX-package "framed"
838         }
839
840         return colors.str();
841 }
842
843
844 string const LaTeXFeatures::getPackageOptions() const
845 {
846         ostringstream packageopts;
847         // Output all the package option stuff we have been asked to do.
848         map<string, string>::const_iterator it =
849                 params_.documentClass().packageOptions().begin();
850         map<string, string>::const_iterator en =
851                 params_.documentClass().packageOptions().end();
852         for (; it != en; ++it)
853                 if (mustProvide(it->first))
854                         packageopts << "\\PassOptionsToPackage{" << it->second << "}"
855                                  << "{" << it->first << "}\n";
856         return packageopts.str();
857 }
858
859
860 string const LaTeXFeatures::getPackages() const
861 {
862         ostringstream packages;
863
864         // FIXME: currently, we can only load packages and macros known
865         // to LyX.
866         // However, with the Require tag of layouts/custom insets,
867         // also unknown packages can be requested. They are silently
868         // swallowed now. We should change this eventually.
869
870         //  These are all the 'simple' includes.  i.e
871         //  packages which we just \usepackage{package}
872         for (int i = 0; i < nb_simplefeatures; ++i) {
873                 if (mustProvide(simplefeatures[i]))
874                         packages << "\\usepackage{" << simplefeatures[i] << "}\n";
875         }
876
877         // The rest of these packages are somewhat more complicated
878         // than those above.
879
880         // The tipa package and its extensions (tipx, tone) must not
881         // be loaded with non-TeX fonts, since fontspec includes the
882         // respective macros
883         if (mustProvide("tipa") && !params_.useNonTeXFonts)
884                 packages << "\\usepackage{tipa}\n";
885         if (mustProvide("tipx") && !params_.useNonTeXFonts)
886                 packages << "\\usepackage{tipx}\n";
887         if (mustProvide("tone") && !params_.useNonTeXFonts)
888                 packages << "\\usepackage{tone}\n";
889
890         // if fontspec or newtxmath is used, AMS packages have to be loaded
891         // before fontspec (in BufferParams)
892         string const amsPackages = loadAMSPackages();
893         bool const ot1 = (params_.font_encoding() == "default" || params_.font_encoding() == "OT1");
894         bool const use_newtxmath =
895                 theLaTeXFonts().getLaTeXFont(from_ascii(params_.fonts_math)).getUsedPackage(
896                         ot1, false, false) == "newtxmath";
897
898         if (!params_.useNonTeXFonts && !use_newtxmath && !amsPackages.empty())
899                 packages << amsPackages;
900
901         if (mustProvide("cancel") &&
902             params_.use_package("cancel") != BufferParams::package_off)
903                 packages << "\\usepackage{cancel}\n";
904
905         // marvosym and bbding both define the \Cross macro
906         if (mustProvide("marvosym")) {
907             if (mustProvide("bbding"))
908                 packages << "\\let\\Cross\\relax\n";
909             packages << "\\usepackage{marvosym}\n";
910         }
911
912         // accents must be loaded after amsmath
913         if (mustProvide("accents") &&
914             params_.use_package("accents") != BufferParams::package_off)
915                 packages << "\\usepackage{accents}\n";
916
917         // mathdots must be loaded after amsmath
918         if (mustProvide("mathdots") &&
919                 params_.use_package("mathdots") != BufferParams::package_off)
920                 packages << "\\usepackage{mathdots}\n";
921
922         // yhmath must be loaded after amsmath
923         if (mustProvide("yhmath") &&
924             params_.use_package("yhmath") != BufferParams::package_off)
925                 packages << "\\usepackage{yhmath}\n";
926
927         // stmaryrd must be loaded after amsmath
928         if (mustProvide("stmaryrd") &&
929             params_.use_package("stmaryrd") != BufferParams::package_off)
930                 packages << "\\usepackage{stmaryrd}\n";
931
932         if (mustProvide("stackrel") &&
933             params_.use_package("stackrel") != BufferParams::package_off)
934                 packages << "\\usepackage{stackrel}\n";
935
936         if (mustProvide("undertilde") &&
937                 params_.use_package("undertilde") != BufferParams::package_off)
938                 packages << "\\usepackage{undertilde}\n";
939
940         // [x]color and pdfcolmk are handled in getColorOptions() above
941
942         // makeidx.sty
943         if (isRequired("makeidx") || isRequired("splitidx")) {
944                 if (!isProvided("makeidx") && !isRequired("splitidx"))
945                         packages << "\\usepackage{makeidx}\n";
946                 if (mustProvide("splitidx"))
947                         packages << "\\usepackage{splitidx}\n";
948                 packages << "\\makeindex\n";
949         }
950
951         // graphicx.sty
952         if (mustProvide("graphicx") && params_.graphics_driver != "none") {
953                 if (params_.graphics_driver == "default")
954                         packages << "\\usepackage{graphicx}\n";
955                 else
956                         packages << "\\usepackage["
957                                  << params_.graphics_driver
958                                  << "]{graphicx}\n";
959         }
960
961         // lyxskak.sty --- newer chess support based on skak.sty
962         if (mustProvide("chess"))
963                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
964
965         // setspace.sty
966         if (mustProvide("setspace") && !isProvided("SetSpace"))
967                 packages << "\\usepackage{setspace}\n";
968
969         // we need to assure that mhchem is loaded before esint and every other
970         // package that redefines command of amsmath because mhchem loads amlatex
971         // (this info is from the author of mhchem from June 2013)
972         if (mustProvide("mhchem") &&
973             params_.use_package("mhchem") != BufferParams::package_off)
974                 packages << "\\PassOptionsToPackage{version=3}{mhchem}\n"
975                             "\\usepackage{mhchem}\n";
976
977         // wasysym is a simple feature, but it must be after amsmath if both
978         // are used
979         // wasysym redefines some integrals (e.g. iint) from amsmath. That
980         // leads to inconsistent integrals. We only load this package if
981         // the document does not contain integrals (then isRequired("esint")
982         // is false) or if esint is used, since esint redefines all relevant
983         // integral symbols from wasysym and amsmath.
984         // See http://www.lyx.org/trac/ticket/1942
985         if (mustProvide("wasysym") &&
986             params_.use_package("wasysym") != BufferParams::package_off &&
987             (params_.use_package("esint") != BufferParams::package_off || !isRequired("esint")))
988                 packages << "\\usepackage{wasysym}\n";
989
990         // esint must be after amsmath (and packages requiring amsmath, like mhchem)
991         // and wasysym, since it will redeclare inconsistent integral symbols
992         if (mustProvide("esint") &&
993             params_.use_package("esint") != BufferParams::package_off)
994                 packages << "\\usepackage{esint}\n";
995
996         // Known bibliography packages (simple \usepackage{package})
997         for (int i = 0; i < nb_bibliofeatures; ++i) {
998                 if (mustProvide(bibliofeatures[i]))
999                         packages << "\\usepackage{"
1000                                  << bibliofeatures[i] << "}\n";
1001         }
1002
1003         // Compatibility between achicago and natbib
1004         if (mustProvide("achicago") && mustProvide("natbib"))
1005                 packages << "\\let\\achicagobib\\thebibliography\n";
1006
1007         // natbib.sty
1008         // Some classes load natbib themselves, but still allow (or even require)
1009         // plain numeric citations (ReVTeX is such a case, see bug 5182).
1010         // This special case is indicated by the "natbib-internal" key.
1011         if (mustProvide("natbib") && !isProvided("natbib-internal")) {
1012                 packages << "\\usepackage[";
1013                 if (params_.citeEngineType() == ENGINE_TYPE_NUMERICAL)
1014                         packages << "numbers";
1015                 else
1016                         packages << "authoryear";
1017                 packages << "]{natbib}\n";
1018         }
1019
1020         // Compatibility between achicago and natbib
1021         if (mustProvide("achicago") && mustProvide("natbib")) {
1022                 packages << "\\let\\thebibliography\\achicagobib\n";
1023                 packages << "\\let\\SCcite\\astroncite\n";
1024                 packages << "\\let\\UnexpandableProtect\\protect\n";
1025         }
1026
1027         // jurabib -- we need version 0.6 at least.
1028         if (mustProvide("jurabib"))
1029                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
1030
1031         // opcit -- we pass custombst as we output \bibliographystyle ourselves
1032         if (mustProvide("opcit")) {
1033                 if (isRequired("hyperref"))
1034                         packages << "\\usepackage[custombst,hyperref]{opcit}\n";
1035                 else
1036                         packages << "\\usepackage[custombst]{opcit}\n";
1037         }
1038
1039         // xargs -- we need version 1.09 at least
1040         if (mustProvide("xargs"))
1041                 packages << "\\usepackage{xargs}[2008/03/08]\n";
1042
1043         if (mustProvide("xy"))
1044                 packages << "\\usepackage[all]{xy}\n";
1045
1046         if (mustProvide("feyn"))
1047                 packages << "\\usepackage{feyn}\n"; //Diagram
1048
1049         if (mustProvide("ulem"))
1050                 packages << "\\PassOptionsToPackage{normalem}{ulem}\n"
1051                             "\\usepackage{ulem}\n";
1052
1053         if (mustProvide("nomencl")) {
1054                 // Make it work with the new and old version of the package,
1055                 // but don't use the compatibility option since it is
1056                 // incompatible to other packages.
1057                 packages << "\\usepackage{nomencl}\n"
1058                             "% the following is useful when we have the old nomencl.sty package\n"
1059                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
1060                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
1061                             "\\makenomenclature\n";
1062         }
1063
1064         // fixltx2e provides subscript
1065         if (mustProvide("subscript") && !isRequired("fixltx2e"))
1066                 packages << "\\usepackage{subscript}\n";
1067
1068         // footmisc must be loaded after setspace
1069         // Set options here, load the package after the user preamble to
1070         // avoid problems with manual loaded footmisc.
1071         if (mustProvide("footmisc"))
1072                 packages << "\\PassOptionsToPackage{stable}{footmisc}\n";
1073
1074         return packages.str();
1075 }
1076
1077
1078 string LaTeXFeatures::getPreambleSnippets() const
1079 {
1080         ostringstream snip;
1081         SnippetList::const_iterator pit  = preamble_snippets_.begin();
1082         SnippetList::const_iterator pend = preamble_snippets_.end();
1083         for (; pit != pend; ++pit)
1084                 snip << *pit << '\n';
1085         return snip.str();
1086 }
1087
1088
1089 std::string LaTeXFeatures::getCSSSnippets() const
1090 {
1091         ostringstream snip;
1092         SnippetList::const_iterator pit  = css_snippets_.begin();
1093         SnippetList::const_iterator pend = css_snippets_.end();
1094         for (; pit != pend; ++pit)
1095                 snip << *pit << '\n';
1096         return snip.str();
1097 }
1098
1099
1100 docstring const LaTeXFeatures::getMacros() const
1101 {
1102         odocstringstream macros;
1103
1104         if (!preamble_snippets_.empty()) {
1105                 macros << '\n';
1106                 macros << from_utf8(getPreambleSnippets());
1107         }
1108
1109         if (mustProvide("papersize")) {
1110                 if (runparams_.flavor == OutputParams::LATEX)
1111                         macros << papersizedvi_def << '\n';
1112                 else
1113                         macros << papersizepdf_def << '\n';
1114         }
1115
1116         if (mustProvide("LyX")) {
1117                 if (isRequired("hyperref"))
1118                         macros << lyx_hyperref_def << '\n';
1119                 else
1120                         macros << lyx_def << '\n';
1121         }
1122
1123         if (mustProvide("noun"))
1124                 macros << noun_def << '\n';
1125
1126         if (mustProvide("lyxarrow"))
1127                 macros << lyxarrow_def << '\n';
1128
1129         if (!usePolyglossia() && mustProvide("textgreek")) {
1130                 // ensure LGR font encoding is defined also if fontenc is not loaded by LyX
1131                 if (params_.font_encoding() == "default")
1132                         macros << textgreek_LGR_def;
1133                 // Avoid a LaTeX error if times fonts are used and the grtimes
1134                 // package is installed but actual fonts are not (bug 6469).
1135                 if (params_.fonts_roman == "times")
1136                         macros << subst(textgreek_def,
1137                                         from_ascii("\\greektext #1"),
1138                                         from_ascii("%\n  \\IfFileExists"
1139                                                    "{grtm10.tfm}{}{\\fontfamily"
1140                                                    "{cmr}}\\greektext #1"))
1141                                << '\n';
1142                 else
1143                         macros << textgreek_def << '\n';
1144         }
1145
1146         if (!usePolyglossia() && mustProvide("textcyr"))
1147                 macros << textcyr_def << '\n';
1148
1149         if (mustProvide("lyxmathsym"))
1150                 macros << lyxmathsym_def << '\n';
1151
1152         if (mustProvide("cedilla"))
1153                 macros << cedilla_def << '\n';
1154
1155         if (mustProvide("subring"))
1156                 macros << subring_def << '\n';
1157
1158         if (mustProvide("subdot"))
1159                 macros << subdot_def << '\n';
1160
1161         if (mustProvide("subhat"))
1162                 macros << subhat_def << '\n';
1163
1164         if (mustProvide("subtilde"))
1165                 macros << subtilde_def << '\n';
1166
1167         if (mustProvide("dacute"))
1168                 macros << dacute_def << '\n';
1169
1170         if (mustProvide("tipasymb"))
1171                 macros << tipasymb_def << '\n';
1172
1173         if (mustProvide("dgrave"))
1174                 macros << dgrave_def << '\n';
1175
1176         if (mustProvide("rcap"))
1177                 macros << rcap_def << '\n';
1178
1179         if (mustProvide("ogonek"))
1180                 macros << ogonek_def << '\n';
1181
1182         // quotes.
1183         if (mustProvide("quotesinglbase"))
1184                 macros << quotesinglbase_def << '\n';
1185         if (mustProvide("quotedblbase"))
1186                 macros << quotedblbase_def << '\n';
1187         if (mustProvide("guilsinglleft"))
1188                 macros << guilsinglleft_def << '\n';
1189         if (mustProvide("guilsinglright"))
1190                 macros << guilsinglright_def << '\n';
1191         if (mustProvide("guillemotleft"))
1192                 macros << guillemotleft_def << '\n';
1193         if (mustProvide("guillemotright"))
1194                 macros << guillemotright_def << '\n';
1195
1196         // Math mode
1197         if (mustProvide("binom") && !isRequired("amsmath"))
1198                 macros << binom_def << '\n';
1199         if (mustProvide("mathcircumflex"))
1200                 macros << mathcircumflex_def << '\n';
1201
1202         // other
1203         if (mustProvide("ParagraphLeftIndent"))
1204                 macros << paragraphleftindent_def;
1205
1206         // some problems with tex->html converters
1207         if (mustProvide("NeedTabularnewline"))
1208                 macros << tabularnewline_def;
1209
1210         // greyed-out environment (note inset)
1211         // the color is specified in the routine
1212         // getColorOptions() to avoid LaTeX-package clashes
1213         if (mustProvide("lyxgreyedout"))
1214                 macros << lyxgreyedout_def;
1215
1216         if (mustProvide("lyxdot"))
1217                 macros << lyxdot_def << '\n';
1218
1219         // floats
1220         getFloatDefinitions(macros);
1221
1222         if (mustProvide("refstyle"))
1223                 macros << lyxref_def << '\n';
1224
1225         // change tracking
1226         if (mustProvide("ct-dvipost"))
1227                 macros << changetracking_dvipost_def;
1228
1229         if (mustProvide("ct-xcolor-ulem")) {
1230                 streamsize const prec = macros.precision(2);
1231
1232                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
1233                 macros << "\\providecolor{lyxadded}{rgb}{"
1234                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
1235
1236                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
1237                 macros << "\\providecolor{lyxdeleted}{rgb}{"
1238                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
1239
1240                 macros.precision(prec);
1241
1242                 if (isRequired("hyperref"))
1243                         macros << changetracking_xcolor_ulem_hyperref_def;
1244                 else
1245                         macros << changetracking_xcolor_ulem_def;
1246         }
1247
1248         if (mustProvide("ct-none"))
1249                 macros << changetracking_none_def;
1250
1251         if (mustProvide("rtloutputdblcol"))
1252                 macros << rtloutputdblcol_def;
1253
1254         return macros.str();
1255 }
1256
1257
1258 string const LaTeXFeatures::getBabelPresettings() const
1259 {
1260         ostringstream tmp;
1261
1262         LanguageList::const_iterator it  = UsedLanguages_.begin();
1263         LanguageList::const_iterator end = UsedLanguages_.end();
1264         for (; it != end; ++it)
1265                 if (!(*it)->babel_presettings().empty())
1266                         tmp << (*it)->babel_presettings() << '\n';
1267         if (!params_.language->babel_presettings().empty())
1268                 tmp << params_.language->babel_presettings() << '\n';
1269
1270         if (!contains(tmp.str(), '@'))
1271                 return tmp.str();
1272
1273         return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
1274 }
1275
1276
1277 string const LaTeXFeatures::getBabelPostsettings() const
1278 {
1279         ostringstream tmp;
1280
1281         LanguageList::const_iterator it  = UsedLanguages_.begin();
1282         LanguageList::const_iterator end = UsedLanguages_.end();
1283         for (; it != end; ++it)
1284                 if (!(*it)->babel_postsettings().empty())
1285                         tmp << (*it)->babel_postsettings() << '\n';
1286         if (!params_.language->babel_postsettings().empty())
1287                 tmp << params_.language->babel_postsettings() << '\n';
1288
1289         if (!contains(tmp.str(), '@'))
1290                 return tmp.str();
1291
1292         return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
1293 }
1294
1295
1296 bool LaTeXFeatures::needBabelLangOptions() const
1297 {
1298         if (!lyxrc.language_global_options || params_.language->asBabelOptions())
1299                 return true;
1300
1301         LanguageList::const_iterator it  = UsedLanguages_.begin();
1302         LanguageList::const_iterator end = UsedLanguages_.end();
1303         for (; it != end; ++it)
1304                 if ((*it)->asBabelOptions())
1305                         return true;
1306
1307         return false;
1308 }
1309
1310
1311 string const LaTeXFeatures::loadAMSPackages() const
1312 {
1313         ostringstream tmp;
1314
1315         if (mustProvide("amsmath")
1316             && params_.use_package("amsmath") != BufferParams::package_off) {
1317                 tmp << "\\usepackage{amsmath}\n";
1318         } else {
1319                 // amsbsy and amstext are already provided by amsmath
1320                 if (mustProvide("amsbsy"))
1321                         tmp << "\\usepackage{amsbsy}\n";
1322                 if (mustProvide("amstext"))
1323                         tmp << "\\usepackage{amstext}\n";
1324         }
1325
1326         if (mustProvide("amsthm"))
1327                 tmp << "\\usepackage{amsthm}\n";
1328
1329         if (mustProvide("amssymb")
1330             && params_.use_package("amssymb") != BufferParams::package_off)
1331                 tmp << "\\usepackage{amssymb}\n";
1332
1333         return tmp.str();
1334 }
1335
1336
1337 docstring const LaTeXFeatures::getTClassPreamble() const
1338 {
1339         // the text class specific preamble
1340         DocumentClass const & tclass = params_.documentClass();
1341         odocstringstream tcpreamble;
1342
1343         tcpreamble << tclass.preamble();
1344
1345         list<docstring>::const_iterator cit = usedLayouts_.begin();
1346         list<docstring>::const_iterator end = usedLayouts_.end();
1347         for (; cit != end; ++cit)
1348                 tcpreamble << tclass[*cit].preamble();
1349
1350         cit = usedInsetLayouts_.begin();
1351         end = usedInsetLayouts_.end();
1352         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1353         for (; cit != end; ++cit) {
1354                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1355                 if (it == ils.end())
1356                         continue;
1357                 tcpreamble << it->second.preamble();
1358         }
1359
1360         return tcpreamble.str();
1361 }
1362
1363
1364 docstring const LaTeXFeatures::getTClassHTMLPreamble() const
1365 {
1366         DocumentClass const & tclass = params_.documentClass();
1367         odocstringstream tcpreamble;
1368
1369         tcpreamble << tclass.htmlpreamble();
1370
1371         list<docstring>::const_iterator cit = usedLayouts_.begin();
1372         list<docstring>::const_iterator end = usedLayouts_.end();
1373         for (; cit != end; ++cit)
1374                 tcpreamble << tclass[*cit].htmlpreamble();
1375
1376         cit = usedInsetLayouts_.begin();
1377         end = usedInsetLayouts_.end();
1378         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1379         for (; cit != end; ++cit) {
1380                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1381                 if (it == ils.end())
1382                         continue;
1383                 tcpreamble << it->second.htmlpreamble();
1384         }
1385
1386         return tcpreamble.str();
1387 }
1388
1389
1390 docstring const LaTeXFeatures::getTClassHTMLStyles() const
1391 {
1392         DocumentClass const & tclass = params_.documentClass();
1393         odocstringstream tcpreamble;
1394
1395         if (mustProvide("noun"))
1396                 tcpreamble << lyxnoun_style;
1397         // this isn't exact, but it won't hurt that much if it
1398         // wasn't for this.
1399         if (mustProvide("ulem"))
1400                 tcpreamble << lyxstrikeout_style;
1401
1402         tcpreamble << tclass.htmlstyles();
1403
1404         list<docstring>::const_iterator cit = usedLayouts_.begin();
1405         list<docstring>::const_iterator end = usedLayouts_.end();
1406         for (; cit != end; ++cit)
1407                 tcpreamble << tclass[*cit].htmlstyle();
1408
1409         cit = usedInsetLayouts_.begin();
1410         end = usedInsetLayouts_.end();
1411         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1412         for (; cit != end; ++cit) {
1413                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1414                 if (it == ils.end())
1415                         continue;
1416                 tcpreamble << it->second.htmlstyle();
1417         }
1418
1419         return tcpreamble.str();
1420 }
1421
1422
1423 namespace {
1424
1425 docstring const getFloatI18nPreamble(docstring const & type,
1426                         docstring const & name, Language const * lang,
1427                         Encoding const & enc, bool const polyglossia)
1428 {
1429         // Check whether name can be encoded in the buffer encoding
1430         bool encodable = true;
1431         for (size_t i = 0; i < name.size(); ++i) {
1432                 if (!enc.encodable(name[i])) {
1433                         encodable = false;
1434                         break;
1435                 }
1436         }
1437
1438         docstring const language = polyglossia ? from_ascii(lang->polyglossia())
1439                                                : from_ascii(lang->babel());
1440         docstring const langenc = from_ascii(lang->encoding()->iconvName());
1441         docstring const texenc = from_ascii(lang->encoding()->latexName());
1442         docstring const bufenc = from_ascii(enc.iconvName());
1443         docstring const s1 = docstring(1, 0xF0000);
1444         docstring const s2 = docstring(1, 0xF0001);
1445         docstring const translated = encodable ? name
1446                 : from_ascii("\\inputencoding{") + texenc + from_ascii("}")
1447                         + s1 + langenc + s2 + name + s1 + bufenc + s2;
1448
1449         odocstringstream os;
1450         os << "\\addto\\captions" << language
1451            << "{\\renewcommand{\\" << type << "name}{" << translated << "}}\n";
1452         return os.str();
1453 }
1454
1455
1456 docstring const i18npreamble(docstring const & templ, Language const * lang,
1457                              Encoding const & enc, bool const polyglossia,
1458                              bool const need_fixedwidth)
1459 {
1460         if (templ.empty())
1461                 return templ;
1462
1463         string preamble = polyglossia ?
1464                 subst(to_utf8(templ), "$$lang", lang->polyglossia()) :
1465                 subst(to_utf8(templ), "$$lang", lang->babel());
1466
1467         string const langenc = lang->encoding()->iconvName();
1468         string const texenc = lang->encoding()->latexName();
1469         string const bufenc = enc.iconvName();
1470         Encoding const * testenc(&enc);
1471         bool lang_fallback = false;
1472         bool ascii_fallback = false;
1473         if (need_fixedwidth && !enc.hasFixedWidth()) {
1474                 if (lang->encoding()->hasFixedWidth()) {
1475                         testenc = lang->encoding();
1476                         lang_fallback = true;
1477                 } else {
1478                         // We need a fixed width encoding, but both the buffer
1479                         // encoding and the language encoding are variable
1480                         // width. As a last fallback, try to convert to pure
1481                         // ASCII using the LaTeX commands defined in unicodesymbols.
1482                         testenc = encodings.fromLyXName("ascii");
1483                         if (!testenc)
1484                                 return docstring();
1485                         ascii_fallback = true;
1486                 }
1487         }
1488         // First and second character of plane 15 (Private Use Area)
1489         string const s1 = "\xf3\xb0\x80\x80"; // U+F0000
1490         string const s2 = "\xf3\xb0\x80\x81"; // U+F0001
1491         // FIXME UNICODE
1492         // lyx::regex is not unicode-safe.
1493         // Should use QRegExp or (boost::u32regex, but that requires ICU)
1494         static regex const reg("_\\(([^\\)]+)\\)");
1495         smatch sub;
1496         while (regex_search(preamble, sub, reg)) {
1497                 string const key = sub.str(1);
1498                 docstring const name = lang->translateLayout(key);
1499                 // Check whether name can be encoded in the buffer encoding
1500                 bool encodable = true;
1501                 for (size_t i = 0; i < name.size() && encodable; ++i)
1502                         if (!testenc->encodable(name[i]))
1503                                 encodable = false;
1504                 string translated;
1505                 if (encodable && !lang_fallback)
1506                         translated = to_utf8(name);
1507                 else if (ascii_fallback)
1508                         translated = to_ascii(testenc->latexString(name).first);
1509                 else
1510                         translated = "\\inputencoding{" + texenc + "}"
1511                                 + s1 + langenc + s2 + to_utf8(name)
1512                                 + s1 + bufenc + s2;
1513                 preamble = subst(preamble, sub.str(), translated);
1514         }
1515         return from_utf8(preamble);
1516 }
1517
1518 }
1519
1520
1521 docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel, bool use_polyglossia) const
1522 {
1523         DocumentClass const & tclass = params_.documentClass();
1524         // collect preamble snippets in a set to prevent multiple identical
1525         // commands (would happen if e.g. both theorem and theorem* are used)
1526         set<docstring> snippets;
1527         typedef LanguageList::const_iterator lang_it;
1528         lang_it const lbeg = UsedLanguages_.begin();
1529         lang_it const lend =  UsedLanguages_.end();
1530         list<docstring>::const_iterator cit = usedLayouts_.begin();
1531         list<docstring>::const_iterator end = usedLayouts_.end();
1532         for (; cit != end; ++cit) {
1533                 // language dependent commands (once per document)
1534                 snippets.insert(i18npreamble(tclass[*cit].langpreamble(),
1535                                                 buffer().language(),
1536                                                 buffer().params().encoding(),
1537                                                 use_polyglossia, false));
1538                 // commands for language changing (for multilanguage documents)
1539                 if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1540                         snippets.insert(i18npreamble(
1541                                                 tclass[*cit].babelpreamble(),
1542                                                 buffer().language(),
1543                                                 buffer().params().encoding(),
1544                                                 use_polyglossia, false));
1545                         for (lang_it lit = lbeg; lit != lend; ++lit)
1546                                 snippets.insert(i18npreamble(
1547                                                 tclass[*cit].babelpreamble(),
1548                                                 *lit,
1549                                                 buffer().params().encoding(),
1550                                                 use_polyglossia, false));
1551                 }
1552         }
1553         if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1554                 FloatList const & floats = params_.documentClass().floats();
1555                 UsedFloats::const_iterator fit = usedFloats_.begin();
1556                 UsedFloats::const_iterator fend = usedFloats_.end();
1557                 for (; fit != fend; ++fit) {
1558                         Floating const & fl = floats.getType(fit->first);
1559                         // we assume builtin floats are translated
1560                         if (fl.isPredefined())
1561                                 continue;
1562                         docstring const type = from_ascii(fl.floattype());
1563                         docstring const flname = from_utf8(fl.name());
1564                         docstring name = buffer().language()->translateLayout(fl.name());
1565                         // only request translation if we have a real translation
1566                         // (that differs from the source)
1567                         if (flname != name)
1568                                 snippets.insert(getFloatI18nPreamble(
1569                                                 type, name, buffer().language(),
1570                                                 buffer().params().encoding(),
1571                                                 use_polyglossia));
1572                         for (lang_it lit = lbeg; lit != lend; ++lit) {
1573                                 string const code = (*lit)->code();
1574                                 name = (*lit)->translateLayout(fl.name());
1575                                 // we assume we have a suitable translation if
1576                                 // either the language is English (we need to
1577                                 // translate into English if English is a secondary
1578                                 // language) or if translateIfPossible returns
1579                                 // something different to the English source.
1580                                 bool const have_translation =
1581                                         (flname != name || contains(code, "en"));
1582                                 if (have_translation)
1583                                         snippets.insert(getFloatI18nPreamble(
1584                                                 type, name, *lit,
1585                                                 buffer().params().encoding(),
1586                                                 use_polyglossia));
1587                         }
1588                 }
1589         }
1590
1591         cit = usedInsetLayouts_.begin();
1592         end = usedInsetLayouts_.end();
1593         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1594         for (; cit != end; ++cit) {
1595                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1596                 if (it == ils.end())
1597                         continue;
1598                 // The listings package does not work with variable width
1599                 // encodings, only with fixed width encodings. Therefore we
1600                 // need to force a fixed width encoding for
1601                 // \lstlistlistingname and \lstlistingname (bug 9382).
1602                 // This needs to be consistent with InsetListings::latex().
1603                 bool const need_fixedwidth = !runparams_.isFullUnicode() &&
1604                                 it->second.fixedwidthpreambleencoding();
1605                 // language dependent commands (once per document)
1606                 snippets.insert(i18npreamble(it->second.langpreamble(),
1607                                                 buffer().language(),
1608                                                 buffer().params().encoding(),
1609                                                 use_polyglossia, need_fixedwidth));
1610                 // commands for language changing (for multilanguage documents)
1611                 if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
1612                         snippets.insert(i18npreamble(
1613                                                 it->second.babelpreamble(),
1614                                                 buffer().language(),
1615                                                 buffer().params().encoding(),
1616                                                 use_polyglossia, need_fixedwidth));
1617                         for (lang_it lit = lbeg; lit != lend; ++lit)
1618                                 snippets.insert(i18npreamble(
1619                                                 it->second.babelpreamble(),
1620                                                 *lit,
1621                                                 buffer().params().encoding(),
1622                                                 use_polyglossia, need_fixedwidth));
1623                 }
1624         }
1625
1626         odocstringstream tcpreamble;
1627         set<docstring>::const_iterator const send = snippets.end();
1628         set<docstring>::const_iterator it = snippets.begin();
1629         for (; it != send; ++it)
1630                 tcpreamble << *it;
1631         return tcpreamble.str();
1632 }
1633
1634
1635 docstring const LaTeXFeatures::getLyXSGMLEntities() const
1636 {
1637         // Definition of entities used in the document that are LyX related.
1638         odocstringstream entities;
1639
1640         if (mustProvide("lyxarrow")) {
1641                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
1642         }
1643
1644         return entities.str();
1645 }
1646
1647
1648 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
1649 {
1650         odocstringstream sgmlpreamble;
1651         // FIXME UNICODE
1652         docstring const basename(from_utf8(onlyPath(fname)));
1653
1654         FileMap::const_iterator end = IncludedFiles_.end();
1655         for (FileMap::const_iterator fi = IncludedFiles_.begin();
1656              fi != end; ++fi)
1657                 // FIXME UNICODE
1658                 sgmlpreamble << "\n<!ENTITY " << fi->first
1659                              << (isSGMLFileName(fi->second) ? " SYSTEM \"" : " \"")
1660                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
1661
1662         return sgmlpreamble.str();
1663 }
1664
1665
1666 void LaTeXFeatures::showStruct() const
1667 {
1668         lyxerr << "LyX needs the following commands when LaTeXing:"
1669                << "\n***** Packages:" << getPackages()
1670                << "\n***** Macros:" << to_utf8(getMacros())
1671                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
1672                << "\n***** done." << endl;
1673 }
1674
1675
1676 Buffer const & LaTeXFeatures::buffer() const
1677 {
1678         return *buffer_;
1679 }
1680
1681
1682 void LaTeXFeatures::setBuffer(Buffer const & buffer)
1683 {
1684         buffer_ = &buffer;
1685 }
1686
1687
1688 BufferParams const & LaTeXFeatures::bufferParams() const
1689 {
1690         return params_;
1691 }
1692
1693
1694 void LaTeXFeatures::getFloatDefinitions(odocstream & os) const
1695 {
1696         FloatList const & floats = params_.documentClass().floats();
1697
1698         // Here we will output the code to create the needed float styles.
1699         // We will try to do this as minimal as possible.
1700         // \floatstyle{ruled}
1701         // \newfloat{algorithm}{htbp}{loa}
1702         // \providecommand{\algorithmname}{Algorithm}
1703         // \floatname{algorithm}{\protect\algorithmname}
1704         UsedFloats::const_iterator cit = usedFloats_.begin();
1705         UsedFloats::const_iterator end = usedFloats_.end();
1706         for (; cit != end; ++cit) {
1707                 Floating const & fl = floats.getType(cit->first);
1708
1709                 // For builtin floats we do nothing.
1710                 if (fl.isPredefined())
1711                         continue;
1712
1713                 // We have to special case "table" and "figure"
1714                 if (fl.floattype() == "tabular" || fl.floattype() == "figure") {
1715                         // Output code to modify "table" or "figure"
1716                         // but only if builtin == false
1717                         // and that have to be true at this point in the
1718                         // function.
1719                         docstring const type = from_ascii(fl.floattype());
1720                         docstring const placement = from_ascii(fl.placement());
1721                         docstring const style = from_ascii(fl.style());
1722                         if (!style.empty()) {
1723                                 os << "\\floatstyle{" << style << "}\n"
1724                                    << "\\restylefloat{" << type << "}\n";
1725                         }
1726                         if (!placement.empty()) {
1727                                 os << "\\floatplacement{" << type << "}{"
1728                                    << placement << "}\n";
1729                         }
1730                 } else {
1731                         // The other non builtin floats.
1732
1733                         docstring const type = from_ascii(fl.floattype());
1734                         docstring const placement = from_ascii(fl.placement());
1735                         docstring const ext = from_ascii(fl.ext());
1736                         docstring const within = from_ascii(fl.within());
1737                         docstring const style = from_ascii(fl.style());
1738                         docstring const name =
1739                                 buffer().language()->translateLayout(fl.name());
1740                         os << "\\floatstyle{" << style << "}\n"
1741                            << "\\newfloat{" << type << "}{" << placement
1742                            << "}{" << ext << '}';
1743                         if (!within.empty())
1744                                 os << '[' << within << ']';
1745                         os << '\n'
1746                            << "\\providecommand{\\" << type << "name}{"
1747                            << name << "}\n"
1748                            << "\\floatname{" << type << "}{\\protect\\"
1749                            << type << "name}\n";
1750
1751                         // What missing here is to code to minimalize the code
1752                         // output so that the same floatstyle will not be
1753                         // used several times, when the same style is still in
1754                         // effect. (Lgb)
1755                 }
1756                 if (cit->second)
1757                         // The subfig package is loaded later
1758                         os << "\n\\AtBeginDocument{\\newsubfloat{" << from_ascii(fl.floattype()) << "}}\n";
1759         }
1760 }
1761
1762
1763 void LaTeXFeatures::resolveAlternatives()
1764 {
1765         for (Features::iterator it = features_.begin(); it != features_.end();) {
1766                 if (contains(*it, '|')) {
1767                         vector<string> const alternatives = getVectorFromString(*it, "|");
1768                         vector<string>::const_iterator const end = alternatives.end();
1769                         vector<string>::const_iterator ita = alternatives.begin();
1770                         // Is any alternative already required? => use that
1771                         for (; ita != end; ++ita) {
1772                                 if (isRequired(*ita))
1773                                         break;
1774                         }
1775                         // Is any alternative available? => use the first one
1776                         // (bug 9498)
1777                         if (ita == end) {
1778                                 for (ita = alternatives.begin(); ita != end; ++ita) {
1779                                         if (isAvailable(*ita)) {
1780                                                 require(*ita);
1781                                                 break;
1782                                         }
1783                                 }
1784                         }
1785                         // This will not work, but not requiring something
1786                         // would be more confusing
1787                         if (ita == end)
1788                                 require(alternatives.front());
1789                         features_.erase(it);
1790                         it = features_.begin();
1791                 } else
1792                         ++it;
1793         }
1794 }
1795
1796
1797 } // namespace lyx