replace most &dquot;...&dquot; by <...>
[lyx.git] / src / LaTeXFeatures.C
blob67fcb20535e824dbc1fa4f2820f6573341b2b0b6
1 /**
2  * \file LaTeXFeatures.C
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  */
15 #include <config.h>
17 #include "LaTeXFeatures.h"
19 #include "bufferparams.h"
20 #include "debug.h"
21 #include "encoding.h"
22 #include "Floating.h"
23 #include "FloatList.h"
24 #include "language.h"
25 #include "lyx_sty.h"
26 #include "lyxrc.h"
28 #include "support/filetools.h"
30 #include <sstream>
32 using lyx::support::IsSGMLFilename;
33 using lyx::support::MakeRelPath;
34 using lyx::support::OnlyPath;
36 using std::endl;
37 using std::find;
38 using std::string;
39 using std::list;
40 using std::ostream;
41 using std::ostringstream;
42 using std::set;
44 namespace biblio = lyx::biblio;
47 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p, bool n)
48         : buffer_(&b), params_(p), nice_(n)
52 bool LaTeXFeatures::useBabel() const
54         return lyxrc.language_use_babel ||
55                 bufferParams().language->lang() != lyxrc.default_language ||
56                 this->hasLanguages();
60 void LaTeXFeatures::require(string const & name)
62         if (isRequired(name))
63                 return;
65         features_.push_back(name);
69 void LaTeXFeatures::useLayout(string const & layoutname)
71         // Some code to avoid loops in dependency definition
72         static int level = 0;
73         const int maxlevel = 30;
74         if (level > maxlevel) {
75                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
76                        << "recursion attained by layout "
77                        << layoutname << endl;
78                 return;
79         }
81         LyXTextClass const & tclass = params_.getLyXTextClass();
82         if (tclass.hasLayout(layoutname)) {
83                 // Is this layout already in usedLayouts?
84                 list<string>::const_iterator cit = usedLayouts_.begin();
85                 list<string>::const_iterator end = usedLayouts_.end();
86                 for (; cit != end; ++cit) {
87                         if (layoutname == *cit)
88                                 return;
89                 }
91                 LyXLayout_ptr const & lyt = tclass[layoutname];
92                 if (!lyt->depends_on().empty()) {
93                         ++level;
94                         useLayout(lyt->depends_on());
95                         --level;
96                 }
97                 usedLayouts_.push_back(layoutname);
98         } else {
99                 lyxerr << "LaTeXFeatures::useLayout: layout `"
100                        << layoutname << "' does not exist in this class"
101                        << endl;
102         }
104         --level;
108 bool LaTeXFeatures::isRequired(string const & name) const
110         return find(features_.begin(), features_.end(), name) != features_.end();
114 void LaTeXFeatures::addExternalPreamble(string const & preamble)
116         FeaturesList::const_iterator begin = preamble_snippets_.begin();
117         FeaturesList::const_iterator end   = preamble_snippets_.end();
118         if (find(begin, end, preamble) == end)
119                 preamble_snippets_.push_back(preamble);
123 void LaTeXFeatures::useFloat(string const & name)
125         usedFloats_.insert(name);
126         // We only need float.sty if we use non builtin floats, or if we
127         // use the "H" modifier. This includes modified table and
128         // figure floats. (Lgb)
129         Floating const & fl = params_.getLyXTextClass().floats().getType(name);
130         if (!fl.type().empty() && !fl.builtin()) {
131                 require("float");
132         }
136 void LaTeXFeatures::useLanguage(Language const * lang)
138         UsedLanguages_.insert(lang);
142 void LaTeXFeatures::includeFile(string const & key, string const & name)
144         IncludedFiles_[key] = name;
148 bool LaTeXFeatures::hasLanguages() const
150         return !UsedLanguages_.empty();
154 string LaTeXFeatures::getLanguages() const
156         ostringstream languages;
158         for (LanguageList::const_iterator cit =
159                     UsedLanguages_.begin();
160              cit != UsedLanguages_.end();
161              ++cit)
162                 languages << (*cit)->babel() << ',';
164         return languages.str();
168 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
170         set<string> encodings;
171         LanguageList::const_iterator it  = UsedLanguages_.begin();
172         LanguageList::const_iterator end = UsedLanguages_.end();
173         for (; it != end; ++it)
174                 if ((*it)->encoding()->LatexName() != doc_encoding)
175                         encodings.insert((*it)->encoding()->LatexName());
176         return encodings;
179 namespace {
181 char const * simplefeatures[] = {
182         "array",
183         "verbatim",
184         "longtable",
185         "rotating",
186         "latexsym",
187         "pifont",
188         "subfigure",
189         "floatflt",
190         "varioref",
191         "prettyref",
192         "float",
193         "wasy",
194         "dvipost",
195         "fancybox",
196         "calc",
199 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
204 string const LaTeXFeatures::getPackages() const
206         ostringstream packages;
207         LyXTextClass const & tclass = params_.getLyXTextClass();
209         //
210         //  These are all the 'simple' includes.  i.e
211         //  packages which we just \usepackage{package}
212         //
213         for (int i = 0; i < nb_simplefeatures; ++i) {
214                 if (isRequired(simplefeatures[i]))
215                         packages << "\\usepackage{"
216                                  << simplefeatures[i] << "}\n";
217         }
219         //
220         // The rest of these packages are somewhat more complicated
221         // than those above.
222         //
224         if (isRequired("amsmath")
225             && !tclass.provides(LyXTextClass::amsmath)
226             && params_.use_amsmath != BufferParams::AMS_OFF) {
227                 packages << "\\usepackage{amsmath}\n";
228         }
230         // color.sty
231         if (isRequired("color")) {
232                 if (params_.graphicsDriver == "default")
233                         packages << "\\usepackage[usenames]{color}\n";
234                 else
235                         packages << "\\usepackage["
236                                  << params_.graphicsDriver
237                                  << ",usenames"
238                                  << "]{color}\n";
239         }
241         // makeidx.sty
242         if (isRequired("makeidx")) {
243                 if (! tclass.provides(LyXTextClass::makeidx))
244                         packages << "\\usepackage{makeidx}\n";
245                 packages << "\\makeindex\n";
246         }
248         // graphicx.sty
249         if (isRequired("graphicx") && params_.graphicsDriver != "none") {
250                 if (params_.graphicsDriver == "default")
251                         packages << "\\usepackage{graphicx}\n";
252                 else
253                         packages << "\\usepackage["
254                                  << params_.graphicsDriver
255                                  << "]{graphicx}\n";
256         }
258         //if (algorithm) {
259         //      packages << "\\usepackage{algorithm}\n";
260         //}
262         // lyxskak.sty --- newer chess support based on skak.sty
263         if (isRequired("chess")) {
264                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
265         }
267         // setspace.sty
268         if ((params_.spacing().getSpace() != Spacing::Single
269              && !params_.spacing().isDefault())
270             || isRequired("setspace")) {
271                 packages << "\\usepackage{setspace}\n";
272         }
273         switch (params_.spacing().getSpace()) {
274         case Spacing::Default:
275         case Spacing::Single:
276                 // we dont use setspace.sty so dont print anything
277                 //packages += "\\singlespacing\n";
278                 break;
279         case Spacing::Onehalf:
280                 packages << "\\onehalfspacing\n";
281                 break;
282         case Spacing::Double:
283                 packages << "\\doublespacing\n";
284                 break;
285         case Spacing::Other:
286                 packages << "\\setstretch{"
287                          << params_.spacing().getValue() << "}\n";
288                 break;
289         }
291         // amssymb.sty
292         if (isRequired("amssymb") || params_.use_amsmath == BufferParams::AMS_ON)
293                 packages << "\\usepackage{amssymb}\n";
294         // url.sty
295         if (isRequired("url") && ! tclass.provides(LyXTextClass::url))
296                 packages << "\\IfFileExists{url.sty}{\\usepackage{url}}\n"
297                             "                      {\\newcommand{\\url}{\\texttt}}\n";
299         // float.sty
300         // natbib.sty
301         if (isRequired("natbib") && ! tclass.provides(LyXTextClass::natbib)) {
302                 packages << "\\usepackage[";
303                 if (params_.cite_engine == biblio::ENGINE_NATBIB_NUMERICAL) {
304                         packages << "numbers";
305                 } else {
306                         packages << "authoryear";
307                 }
308                 packages << "]{natbib}\n";
309         }
311         // jurabib -- we need version 0.6 at least.
312         if (isRequired("jurabib")) {
313                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
314         }
316         // bibtopic -- the dot provides the aux file naming which
317         // LyX can detect.
318         if (isRequired("bibtopic")) {
319                 packages << "\\usepackage[dot]{bibtopic}\n";
320         }
322         return packages.str();
326 string const LaTeXFeatures::getMacros() const
328         ostringstream macros;
330         if (!preamble_snippets_.empty())
331                 macros << '\n';
332         FeaturesList::const_iterator pit  = preamble_snippets_.begin();
333         FeaturesList::const_iterator pend = preamble_snippets_.end();
334         for (; pit != pend; ++pit) {
335                 macros << *pit << '\n';
336         }
338         if (isRequired("LyX"))
339                 macros << lyx_def << '\n';
341         if (isRequired("lyxline"))
342                 macros << lyxline_def << '\n';
344         if (isRequired("noun"))
345                 macros << noun_def << '\n';
347         if (isRequired("lyxarrow"))
348                 macros << lyxarrow_def << '\n';
350         // quotes.
351         if (isRequired("quotesinglbase"))
352                 macros << quotesinglbase_def << '\n';
353         if (isRequired("quotedblbase"))
354                 macros << quotedblbase_def << '\n';
355         if (isRequired("guilsinglleft"))
356                 macros << guilsinglleft_def << '\n';
357         if (isRequired("guilsinglright"))
358                 macros << guilsinglright_def << '\n';
359         if (isRequired("guillemotleft"))
360                 macros << guillemotleft_def << '\n';
361         if (isRequired("guillemotright"))
362                 macros << guillemotright_def << '\n';
364         // Math mode
365         if (isRequired("boldsymbol") && !isRequired("amsmath"))
366                 macros << boldsymbol_def << '\n';
367         if (isRequired("binom") && !isRequired("amsmath"))
368                 macros << binom_def << '\n';
369         if (isRequired("mathcircumflex"))
370                 macros << mathcircumflex_def << '\n';
372         // other
373         if (isRequired("ParagraphLeftIndent"))
374                 macros << paragraphleftindent_def;
375         if (isRequired("NeedLyXFootnoteCode"))
376                 macros << floatingfootnote_def;
378         // some problems with tex->html converters
379         if (isRequired("NeedTabularnewline"))
380                 macros << tabularnewline_def;
382         // greyedout environment (note inset)
383         if (isRequired("lyxgreyedout"))
384                 macros << lyxgreyedout_def;
386         if (isRequired("lyxdot"))
387                 macros << lyxdot_def << '\n';
389         // floats
390         getFloatDefinitions(macros);
392         return macros.str();
396 string const LaTeXFeatures::getBabelOptions() const
398         ostringstream tmp;
400         LanguageList::const_iterator it  = UsedLanguages_.begin();
401         LanguageList::const_iterator end =  UsedLanguages_.end();
402         for (; it != end; ++it)
403                 if (!(*it)->latex_options().empty())
404                         tmp << (*it)->latex_options() << '\n';
405         if (!params_.language->latex_options().empty())
406                 tmp << params_.language->latex_options() << '\n';
408         return tmp.str();
412 string const LaTeXFeatures::getTClassPreamble() const
414         // the text class specific preamble
415         LyXTextClass const & tclass = params_.getLyXTextClass();
416         ostringstream tcpreamble;
418         tcpreamble << tclass.preamble();
420         list<string>::const_iterator cit = usedLayouts_.begin();
421         list<string>::const_iterator end = usedLayouts_.end();
422         for (; cit != end; ++cit) {
423                 tcpreamble << tclass[*cit]->preamble();
424         }
426         CharStyles::iterator cs = tclass.charstyles().begin();
427         CharStyles::iterator csend = tclass.charstyles().end();
428         for (; cs != csend; ++cs) {
429                 if (isRequired(cs->name))
430                         tcpreamble << cs->preamble;
431         }
433         return tcpreamble.str();
437 string const LaTeXFeatures::getLyXSGMLEntities() const
439         // Definition of entities used in the document that are LyX related.
440         ostringstream entities;
442         if (isRequired("lyxarrow")) {
443                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
444         }
446         return entities.str();
450 string const LaTeXFeatures::getIncludedFiles(string const & fname) const
452         ostringstream sgmlpreamble;
453         string const basename = OnlyPath(fname);
455         FileMap::const_iterator end = IncludedFiles_.end();
456         for (FileMap::const_iterator fi = IncludedFiles_.begin();
457              fi != end; ++fi)
458                 sgmlpreamble << "\n<!ENTITY " << fi->first
459                              << (IsSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
460                              << MakeRelPath(fi->second, basename) << "\">";
462         return sgmlpreamble.str();
466 void LaTeXFeatures::showStruct() const {
467         lyxerr << "LyX needs the following commands when LaTeXing:"
468                << "\n***** Packages:" << getPackages()
469                << "\n***** Macros:" << getMacros()
470                << "\n***** Textclass stuff:" << getTClassPreamble()
471                << "\n***** done." << endl;
475 Buffer const & LaTeXFeatures::buffer() const
477         return *buffer_;
481 void LaTeXFeatures::setBuffer(Buffer const & buffer)
483         buffer_ = &buffer;
487 BufferParams const & LaTeXFeatures::bufferParams() const
489         return params_;
493 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
495         FloatList const & floats = params_.getLyXTextClass().floats();
497         // Here we will output the code to create the needed float styles.
498         // We will try to do this as minimal as possible.
499         // \floatstyle{ruled}
500         // \newfloat{algorithm}{htbp}{loa}
501         // \floatname{algorithm}{Algorithm}
502         UsedFloats::const_iterator cit = usedFloats_.begin();
503         UsedFloats::const_iterator end = usedFloats_.end();
504         // ostringstream floats;
505         for (; cit != end; ++cit) {
506                 Floating const & fl = floats.getType((*cit));
508                 // For builtin floats we do nothing.
509                 if (fl.builtin()) continue;
511                 // We have to special case "table" and "figure"
512                 if (fl.type() == "tabular" || fl.type() == "figure") {
513                         // Output code to modify "table" or "figure"
514                         // but only if builtin == false
515                         // and that have to be true at this point in the
516                         // function.
517                         string const type = fl.type();
518                         string const placement = fl.placement();
519                         string const style = fl.style();
520                         if (!style.empty()) {
521                                 os << "\\floatstyle{" << style << "}\n"
522                                    << "\\restylefloat{" << type << "}\n";
523                         }
524                         if (!placement.empty()) {
525                                 os << "\\floatplacement{" << type << "}{"
526                                    << placement << "}\n";
527                         }
528                 } else {
529                         // The other non builtin floats.
531                         string const type = fl.type();
532                         string const placement = fl.placement();
533                         string const ext = fl.ext();
534                         string const within = fl.within();
535                         string const style = fl.style();
536                         string const name = fl.name();
537                         os << "\\floatstyle{" << style << "}\n"
538                            << "\\newfloat{" << type << "}{" << placement
539                            << "}{" << ext << '}';
540                         if (!within.empty())
541                                 os << '[' << within << ']';
542                         os << '\n'
543                            << "\\floatname{" << type << "}{"
544                            << name << "}\n";
546                         // What missing here is to code to minimalize the code
547                         // output so that the same floatstyle will not be
548                         // used several times, when the same style is still in
549                         // effect. (Lgb)
550                 }
551         }