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