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