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