]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.C
Move #includes out of header files.
[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 "lyxrc.h"
21 #include "bufferparams.h"
22 #include "Floating.h"
23 #include "FloatList.h"
24 #include "language.h"
25 #include "encoding.h"
26 #include "LString.h"
27 #include "Lsstream.h"
28
29 #include "support/filetools.h"
30 #include "support/lstrings.h"
31
32 using namespace lyx::support;
33
34 using lyx::textclass_type;
35
36 using std::endl;
37 using std::list;
38 using std::set;
39 using std::find;
40 using std::ostream;
41
42
43 LaTeXFeatures::LaTeXFeatures(BufferParams const & p)
44         : params(p)
45 {}
46
47
48 bool LaTeXFeatures::useBabel() const
49 {
50         return lyxrc.language_use_babel ||
51                 bufferParams().language->lang() != lyxrc.default_language ||
52                 this->hasLanguages();
53 }
54
55
56 void LaTeXFeatures::require(string const & name)
57 {
58         if (isRequired(name))
59                 return;
60
61         features.push_back(name);
62 }
63
64
65 void LaTeXFeatures::useLayout(string const & layoutname)
66 {
67         // Some code to avoid loops in dependency definition
68         static int level = 0;
69         const int maxlevel = 30;
70         if (level > maxlevel) {
71                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
72                        << "recursion attained by layout "
73                        << layoutname << endl;
74                 return;
75         }
76
77         LyXTextClass const & tclass = params.getLyXTextClass();
78         if (tclass.hasLayout(layoutname)) {
79                 // Is this layout already in usedLayouts?
80                 list<string>::const_iterator cit = usedLayouts.begin();
81                 list<string>::const_iterator end = usedLayouts.end();
82                 for (; cit != end; ++cit) {
83                         if (layoutname == *cit)
84                                 return;
85                 }
86
87                 LyXLayout_ptr const & lyt = tclass[layoutname];
88                 if (!lyt->depends_on().empty()) {
89                         ++level;
90                         useLayout(lyt->depends_on());
91                         --level;
92                 }
93                 usedLayouts.push_back(layoutname);
94         } else {
95                 lyxerr << "LaTeXFeatures::useLayout: layout `"
96                        << layoutname << "' does not exist in this class"
97                        << endl;
98         }
99
100         --level;
101 }
102
103
104 bool LaTeXFeatures::isRequired(string const & name) const
105 {
106         return find(features.begin(), features.end(), name) != features.end();
107 }
108
109
110 void LaTeXFeatures::addExternalPreamble(string const & preamble)
111 {
112         FeaturesList::const_iterator begin = preamble_snippets.begin();
113         FeaturesList::const_iterator end   = preamble_snippets.end();
114         if (find(begin, end, preamble) == end)
115                 preamble_snippets.push_back(preamble);
116 }
117
118
119 void LaTeXFeatures::useFloat(string const & name)
120 {
121         usedFloats.insert(name);
122         // We only need float.sty if we use non builtin floats, or if we
123         // use the "H" modifier. This includes modified table and
124         // figure floats. (Lgb)
125         Floating const & fl = params.getLyXTextClass().floats().getType(name);
126         if (!fl.type().empty() && !fl.builtin()) {
127                 require("float");
128         }
129 }
130
131
132 void LaTeXFeatures::useLanguage(Language const * lang)
133 {
134         UsedLanguages.insert(lang);
135 }
136
137
138 void LaTeXFeatures::includeFile(string const & key, string const & name)
139 {
140         IncludedFiles[key] = name;
141 }
142
143
144 bool LaTeXFeatures::hasLanguages() const
145 {
146         return !UsedLanguages.empty();
147 }
148
149
150 string LaTeXFeatures::getLanguages() const
151 {
152         ostringstream languages;
153
154         for (LanguageList::const_iterator cit =
155                     UsedLanguages.begin();
156              cit != UsedLanguages.end();
157              ++cit)
158                 languages << (*cit)->babel() << ',';
159
160         return STRCONV(languages.str());
161 }
162
163
164 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
165 {
166         set<string> encodings;
167         for (LanguageList::const_iterator it =
168                      UsedLanguages.begin();
169              it != UsedLanguages.end(); ++it)
170                 if ((*it)->encoding()->LatexName() != doc_encoding)
171                         encodings.insert((*it)->encoding()->LatexName());
172         return encodings;
173 }
174
175 namespace {
176
177 char const * simplefeatures[] = {
178         "array",
179         "verbatim",
180         "longtable",
181         "rotating",
182         "latexsym",
183         "pifont",
184         "subfigure",
185         "floatflt",
186         "varioref",
187         "prettyref",
188         "float",
189         "wasy",
190         "dvipost"
191 };
192
193 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
194
195 }
196
197
198 string const LaTeXFeatures::getPackages() const
199 {
200         ostringstream packages;
201         LyXTextClass const & tclass = params.getLyXTextClass();
202
203         //
204         //  These are all the 'simple' includes.  i.e
205         //  packages which we just \usepackage{package}
206         //
207         for (int i = 0; i < nb_simplefeatures; ++i) {
208                 if (isRequired(simplefeatures[i]))
209                         packages << "\\usepackage{"
210                                  << simplefeatures[i] << "}\n";
211         }
212
213         //
214         // The rest of these packages are somewhat more complicated
215         // than those above.
216         //
217
218         if (isRequired("amsmath")
219             && !tclass.provides(LyXTextClass::amsmath)
220             && params.use_amsmath != BufferParams::AMS_OFF) {
221                 packages << "\\usepackage{amsmath}\n";
222         }
223
224         // color.sty
225         if (isRequired("color")) {
226                 if (params.graphicsDriver == "default")
227                         packages << "\\usepackage[usenames]{color}\n";
228                 else
229                         packages << "\\usepackage["
230                                  << params.graphicsDriver
231                                  << ",usenames"
232                                  << "]{color}\n";
233         }
234
235         // makeidx.sty
236         if (isRequired("makeidx")) {
237                 if (! tclass.provides(LyXTextClass::makeidx))
238                         packages << "\\usepackage{makeidx}\n";
239                 packages << "\\makeindex\n";
240         }
241
242         // graphicx.sty
243         if (isRequired("graphicx") && params.graphicsDriver != "none") {
244                 if (params.graphicsDriver == "default")
245                         packages << "\\usepackage{graphicx}\n";
246                 else
247                         packages << "\\usepackage["
248                                  << params.graphicsDriver
249                                  << "]{graphicx}\n";
250         }
251
252         //if (algorithm) {
253         //      packages << "\\usepackage{algorithm}\n";
254         //}
255
256         // lyxskak.sty --- newer chess support based on skak.sty
257         if (isRequired("chess")) {
258                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
259         }
260
261         // setspace.sty
262         if ((params.spacing.getSpace() != Spacing::Single
263              && !params.spacing.isDefault())
264             || isRequired("setspace")) {
265                 packages << "\\usepackage{setspace}\n";
266         }
267         switch (params.spacing.getSpace()) {
268         case Spacing::Default:
269         case Spacing::Single:
270                 // we dont use setspace.sty so dont print anything
271                 //packages += "\\singlespacing\n";
272                 break;
273         case Spacing::Onehalf:
274                 packages << "\\onehalfspacing\n";
275                 break;
276         case Spacing::Double:
277                 packages << "\\doublespacing\n";
278                 break;
279         case Spacing::Other:
280                 packages << "\\setstretch{"
281                          << params.spacing.getValue() << "}\n";
282                 break;
283         }
284
285         // amssymb.sty
286         if (isRequired("amssymb") || params.use_amsmath == BufferParams::AMS_ON)
287                 packages << "\\usepackage{amssymb}\n";
288         // url.sty
289         if (isRequired("url") && ! tclass.provides(LyXTextClass::url))
290                 packages << "\\IfFileExists{url.sty}{\\usepackage{url}}\n"
291                             "                      {\\newcommand{\\url}{\\texttt}}\n";
292
293         // float.sty
294         // natbib.sty
295         if (isRequired("natbib") && ! tclass.provides(LyXTextClass::natbib)) {
296                 packages << "\\usepackage[";
297                 if (params.use_numerical_citations) {
298                         packages << "numbers";
299                 } else {
300                         packages << "authoryear";
301                 }
302                 packages << "]{natbib}\n";
303         }
304
305         FeaturesList::const_iterator pit  = preamble_snippets.begin();
306         FeaturesList::const_iterator pend = preamble_snippets.end();
307         for (; pit != pend; ++pit) {
308                 packages << *pit << '\n';
309         }
310
311         return STRCONV(packages.str());
312 }
313
314
315 string const LaTeXFeatures::getMacros() const
316 {
317         ostringstream macros;
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 }