]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.C
cf96b66de4d428db2c735047d7222d842925ff9d
[lyx.git] / src / LaTeXFeatures.C
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  */
14
15 #include <config.h>
16
17 #include "LaTeXFeatures.h"
18
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"
27
28 #include "support/filetools.h"
29
30 #include "support/std_sstream.h"
31
32 using lyx::support::IsSGMLFilename;
33 using lyx::support::MakeRelPath;
34 using lyx::support::OnlyPath;
35
36 using std::endl;
37 using std::find;
38
39 using std::list;
40 using std::ostream;
41 using std::ostringstream;
42 using std::set;
43
44
45 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p)
46         : buffer_(b), params_(p)
47 {}
48
49
50 bool LaTeXFeatures::useBabel() const
51 {
52         return lyxrc.language_use_babel ||
53                 bufferParams().language->lang() != lyxrc.default_language ||
54                 this->hasLanguages();
55 }
56
57
58 void LaTeXFeatures::require(string const & name)
59 {
60         if (isRequired(name))
61                 return;
62
63         features_.push_back(name);
64 }
65
66
67 void LaTeXFeatures::useLayout(string const & layoutname)
68 {
69         // Some code to avoid loops in dependency definition
70         static int level = 0;
71         const int maxlevel = 30;
72         if (level > maxlevel) {
73                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
74                        << "recursion attained by layout "
75                        << layoutname << endl;
76                 return;
77         }
78
79         LyXTextClass const & tclass = params_.getLyXTextClass();
80         if (tclass.hasLayout(layoutname)) {
81                 // Is this layout already in usedLayouts?
82                 list<string>::const_iterator cit = usedLayouts_.begin();
83                 list<string>::const_iterator end = usedLayouts_.end();
84                 for (; cit != end; ++cit) {
85                         if (layoutname == *cit)
86                                 return;
87                 }
88
89                 LyXLayout_ptr const & lyt = tclass[layoutname];
90                 if (!lyt->depends_on().empty()) {
91                         ++level;
92                         useLayout(lyt->depends_on());
93                         --level;
94                 }
95                 usedLayouts_.push_back(layoutname);
96         } else {
97                 lyxerr << "LaTeXFeatures::useLayout: layout `"
98                        << layoutname << "' does not exist in this class"
99                        << endl;
100         }
101
102         --level;
103 }
104
105
106 bool LaTeXFeatures::isRequired(string const & name) const
107 {
108         return find(features_.begin(), features_.end(), name) != features_.end();
109 }
110
111
112 void LaTeXFeatures::addExternalPreamble(string const & preamble)
113 {
114         FeaturesList::const_iterator begin = preamble_snippets_.begin();
115         FeaturesList::const_iterator end   = preamble_snippets_.end();
116         if (find(begin, end, preamble) == end)
117                 preamble_snippets_.push_back(preamble);
118 }
119
120
121 void LaTeXFeatures::useFloat(string const & name)
122 {
123         usedFloats_.insert(name);
124         // We only need float.sty if we use non builtin floats, or if we
125         // use the "H" modifier. This includes modified table and
126         // figure floats. (Lgb)
127         Floating const & fl = params_.getLyXTextClass().floats().getType(name);
128         if (!fl.type().empty() && !fl.builtin()) {
129                 require("float");
130         }
131 }
132
133
134 void LaTeXFeatures::useLanguage(Language const * lang)
135 {
136         UsedLanguages_.insert(lang);
137 }
138
139
140 void LaTeXFeatures::includeFile(string const & key, string const & name)
141 {
142         IncludedFiles_[key] = name;
143 }
144
145
146 bool LaTeXFeatures::hasLanguages() const
147 {
148         return !UsedLanguages_.empty();
149 }
150
151
152 string LaTeXFeatures::getLanguages() const
153 {
154         ostringstream languages;
155
156         for (LanguageList::const_iterator cit =
157                     UsedLanguages_.begin();
158              cit != UsedLanguages_.end();
159              ++cit)
160                 languages << (*cit)->babel() << ',';
161
162         return languages.str();
163 }
164
165
166 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
167 {
168         set<string> encodings;
169         LanguageList::const_iterator it  = UsedLanguages_.begin();
170         LanguageList::const_iterator end = UsedLanguages_.end();
171         for (; it != end; ++it)
172                 if ((*it)->encoding()->LatexName() != doc_encoding)
173                         encodings.insert((*it)->encoding()->LatexName());
174         return encodings;
175 }
176
177 namespace {
178
179 char const * simplefeatures[] = {
180         "array",
181         "verbatim",
182         "longtable",
183         "rotating",
184         "latexsym",
185         "pifont",
186         "subfigure",
187         "floatflt",
188         "varioref",
189         "prettyref",
190         "float",
191         "wasy",
192         "dvipost"
193 };
194
195 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
196
197 }
198
199
200 string const LaTeXFeatures::getPackages() const
201 {
202         ostringstream packages;
203         LyXTextClass const & tclass = params_.getLyXTextClass();
204
205         //
206         //  These are all the 'simple' includes.  i.e
207         //  packages which we just \usepackage{package}
208         //
209         for (int i = 0; i < nb_simplefeatures; ++i) {
210                 if (isRequired(simplefeatures[i]))
211                         packages << "\\usepackage{"
212                                  << simplefeatures[i] << "}\n";
213         }
214
215         //
216         // The rest of these packages are somewhat more complicated
217         // than those above.
218         //
219
220         if (isRequired("amsmath")
221             && !tclass.provides(LyXTextClass::amsmath)
222             && params_.use_amsmath != BufferParams::AMS_OFF) {
223                 packages << "\\usepackage{amsmath}\n";
224         }
225
226         // color.sty
227         if (isRequired("color")) {
228                 if (params_.graphicsDriver == "default")
229                         packages << "\\usepackage[usenames]{color}\n";
230                 else
231                         packages << "\\usepackage["
232                                  << params_.graphicsDriver
233                                  << ",usenames"
234                                  << "]{color}\n";
235         }
236
237         // makeidx.sty
238         if (isRequired("makeidx")) {
239                 if (! tclass.provides(LyXTextClass::makeidx))
240                         packages << "\\usepackage{makeidx}\n";
241                 packages << "\\makeindex\n";
242         }
243
244         // graphicx.sty
245         if (isRequired("graphicx") && params_.graphicsDriver != "none") {
246                 if (params_.graphicsDriver == "default")
247                         packages << "\\usepackage{graphicx}\n";
248                 else
249                         packages << "\\usepackage["
250                                  << params_.graphicsDriver
251                                  << "]{graphicx}\n";
252         }
253
254         //if (algorithm) {
255         //      packages << "\\usepackage{algorithm}\n";
256         //}
257
258         // lyxskak.sty --- newer chess support based on skak.sty
259         if (isRequired("chess")) {
260                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
261         }
262
263         // setspace.sty
264         if ((params_.spacing().getSpace() != Spacing::Single
265              && !params_.spacing().isDefault())
266             || isRequired("setspace")) {
267                 packages << "\\usepackage{setspace}\n";
268         }
269         switch (params_.spacing().getSpace()) {
270         case Spacing::Default:
271         case Spacing::Single:
272                 // we dont use setspace.sty so dont print anything
273                 //packages += "\\singlespacing\n";
274                 break;
275         case Spacing::Onehalf:
276                 packages << "\\onehalfspacing\n";
277                 break;
278         case Spacing::Double:
279                 packages << "\\doublespacing\n";
280                 break;
281         case Spacing::Other:
282                 packages << "\\setstretch{"
283                          << params_.spacing().getValue() << "}\n";
284                 break;
285         }
286
287         // amssymb.sty
288         if (isRequired("amssymb") || params_.use_amsmath == BufferParams::AMS_ON)
289                 packages << "\\usepackage{amssymb}\n";
290         // url.sty
291         if (isRequired("url") && ! tclass.provides(LyXTextClass::url))
292                 packages << "\\IfFileExists{url.sty}{\\usepackage{url}}\n"
293                             "                      {\\newcommand{\\url}{\\texttt}}\n";
294
295         // float.sty
296         // natbib.sty
297         if (isRequired("natbib") && ! tclass.provides(LyXTextClass::natbib)) {
298                 packages << "\\usepackage[";
299                 if (params_.use_numerical_citations) {
300                         packages << "numbers";
301                 } else {
302                         packages << "authoryear";
303                 }
304                 packages << "]{natbib}\n";
305         }
306
307         return packages.str();
308 }
309
310
311 string const LaTeXFeatures::getMacros() const
312 {
313         ostringstream macros;
314
315         if (!preamble_snippets_.empty())
316                 macros << '\n';
317         FeaturesList::const_iterator pit  = preamble_snippets_.begin();
318         FeaturesList::const_iterator pend = preamble_snippets_.end();
319         for (; pit != pend; ++pit) {
320                 macros << *pit << '\n';
321         }
322
323         if (isRequired("LyX"))
324                 macros << lyx_def << '\n';
325
326         if (isRequired("lyxline"))
327                 macros << lyxline_def << '\n';
328
329         if (isRequired("noun"))
330                 macros << noun_def << '\n';
331
332         if (isRequired("lyxarrow"))
333                 macros << lyxarrow_def << '\n';
334
335         // quotes.
336         if (isRequired("quotesinglbase"))
337                 macros << quotesinglbase_def << '\n';
338         if (isRequired("quotedblbase"))
339                 macros << quotedblbase_def << '\n';
340         if (isRequired("guilsinglleft"))
341                 macros << guilsinglleft_def << '\n';
342         if (isRequired("guilsinglright"))
343                 macros << guilsinglright_def << '\n';
344         if (isRequired("guillemotleft"))
345                 macros << guillemotleft_def << '\n';
346         if (isRequired("guillemotright"))
347                 macros << guillemotright_def << '\n';
348
349         // Math mode
350         if (isRequired("boldsymbol") && !isRequired("amsmath"))
351                 macros << boldsymbol_def << '\n';
352         if (isRequired("binom") && !isRequired("amsmath"))
353                 macros << binom_def << '\n';
354         if (isRequired("mathcircumflex"))
355                 macros << mathcircumflex_def << '\n';
356
357         // other
358         if (isRequired("NeedLyXMinipageIndent"))
359                 macros << minipageindent_def;
360         if (isRequired("ParagraphLeftIndent"))
361                 macros << paragraphleftindent_def;
362         if (isRequired("NeedLyXFootnoteCode"))
363                 macros << floatingfootnote_def;
364
365         // some problems with tex->html converters
366         if (isRequired("NeedTabularnewline"))
367                 macros << tabularnewline_def;
368
369         // greyedout environment (note inset)
370         if (isRequired("lyxgreyedout"))
371                 macros << lyxgreyedout_def;
372
373         // floats
374         getFloatDefinitions(macros);
375
376         return macros.str();
377 }
378
379
380 string const LaTeXFeatures::getBabelOptions() const
381 {
382         ostringstream tmp;
383
384         LanguageList::const_iterator it  = UsedLanguages_.begin();
385         LanguageList::const_iterator end =  UsedLanguages_.end();
386         for (; it != end; ++it)
387                 if (!(*it)->latex_options().empty())
388                         tmp << (*it)->latex_options() << '\n';
389         if (!params_.language->latex_options().empty())
390                 tmp << params_.language->latex_options() << '\n';
391
392         return tmp.str();
393 }
394
395
396 string const LaTeXFeatures::getTClassPreamble() const
397 {
398         // the text class specific preamble
399         LyXTextClass const & tclass = params_.getLyXTextClass();
400         ostringstream tcpreamble;
401
402         tcpreamble << tclass.preamble();
403
404         list<string>::const_iterator cit = usedLayouts_.begin();
405         list<string>::const_iterator end = usedLayouts_.end();
406         for (; cit != end; ++cit) {
407                 tcpreamble << tclass[*cit]->preamble();
408         }
409
410         return tcpreamble.str();
411 }
412
413
414 string const LaTeXFeatures::getLyXSGMLEntities() const
415 {
416         // Definition of entities used in the document that are LyX related.
417         ostringstream entities;
418
419         if (isRequired("lyxarrow")) {
420                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
421         }
422
423         return entities.str();
424 }
425
426
427 string const LaTeXFeatures::getIncludedFiles(string const & fname) const
428 {
429         ostringstream sgmlpreamble;
430         string const basename = OnlyPath(fname);
431
432         FileMap::const_iterator end = IncludedFiles_.end();
433         for (FileMap::const_iterator fi = IncludedFiles_.begin();
434              fi != end; ++fi)
435                 sgmlpreamble << "\n<!ENTITY " << fi->first
436                              << (IsSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
437                              << MakeRelPath(fi->second, basename) << "\">";
438
439         return sgmlpreamble.str();
440 }
441
442
443 void LaTeXFeatures::showStruct() const {
444         lyxerr << "LyX needs the following commands when LaTeXing:"
445                << "\n***** Packages:" << getPackages()
446                << "\n***** Macros:" << getMacros()
447                << "\n***** Textclass stuff:" << getTClassPreamble()
448                << "\n***** done." << endl;
449 }
450
451
452 Buffer const & LaTeXFeatures::buffer() const
453 {
454         return buffer_;
455 }
456
457
458 BufferParams const & LaTeXFeatures::bufferParams() const
459 {
460         return params_;
461 }
462
463
464 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
465 {
466         FloatList const & floats = params_.getLyXTextClass().floats();
467
468         // Here we will output the code to create the needed float styles.
469         // We will try to do this as minimal as possible.
470         // \floatstyle{ruled}
471         // \newfloat{algorithm}{htbp}{loa}
472         // \floatname{algorithm}{Algorithm}
473         UsedFloats::const_iterator cit = usedFloats_.begin();
474         UsedFloats::const_iterator end = usedFloats_.end();
475         // ostringstream floats;
476         for (; cit != end; ++cit) {
477                 Floating const & fl = floats.getType((*cit));
478
479                 // For builtin floats we do nothing.
480                 if (fl.builtin()) continue;
481
482                 // We have to special case "table" and "figure"
483                 if (fl.type() == "tabular" || fl.type() == "figure") {
484                         // Output code to modify "table" or "figure"
485                         // but only if builtin == false
486                         // and that have to be true at this point in the
487                         // function.
488                         string const type = fl.type();
489                         string const placement = fl.placement();
490                         string const style = fl.style();
491                         if (!style.empty()) {
492                                 os << "\\floatstyle{" << style << "}\n"
493                                    << "\\restylefloat{" << type << "}\n";
494                         }
495                         if (!placement.empty()) {
496                                 os << "\\floatplacement{" << type << "}{"
497                                    << placement << "}\n";
498                         }
499                 } else {
500                         // The other non builtin floats.
501
502                         string const type = fl.type();
503                         string const placement = fl.placement();
504                         string const ext = fl.ext();
505                         string const within = fl.within();
506                         string const style = fl.style();
507                         string const name = fl.name();
508                         os << "\\floatstyle{" << style << "}\n"
509                            << "\\newfloat{" << type << "}{" << placement
510                            << "}{" << ext << '}';
511                         if (!within.empty())
512                                 os << '[' << within << ']';
513                         os << '\n'
514                            << "\\floatname{" << type << "}{"
515                            << name << "}\n";
516
517                         // What missing here is to code to minimalize the code
518                         // output so that the same floatstyle will not be
519                         // used several times, when the same style is still in
520                         // effect. (Lgb)
521                 }
522         }
523 }