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