]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.C
compile fix
[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 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 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 = floatList.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 languages.str().c_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 };
179
180 const int nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
181
182 }
183
184 string const LaTeXFeatures::getPackages() const
185 {
186         ostringstream packages;
187         LyXTextClass const & tclass = params.getLyXTextClass();
188
189
190         //
191         //  These are all the 'simple' includes.  i.e
192         //  packages which we just \usepackage{package}
193         //
194         for (int i = 0; i < nb_simplefeatures; ++i) {
195                 if (isRequired(simplefeatures[i]))
196                         packages << "\\usepackage{"
197                                  << simplefeatures[i] << "}\n";
198         }
199
200         //
201         // The rest of these packages are somewhat more complicated
202         // than those above.
203         //
204
205         if (isRequired("amsmath")
206             && ! tclass.provides(LyXTextClass::amsmath)) {
207                 packages << "\\usepackage{amsmath}\n";
208         }
209
210         // color.sty
211         if (isRequired("color")) {
212                 if (params.graphicsDriver == "default")
213                         packages << "\\usepackage{color}\n";
214                 else
215                         packages << "\\usepackage["
216                                  << params.graphicsDriver
217                                  << "]{color}\n";
218         }
219
220         // makeidx.sty
221         if (isRequired("makeidx")) {
222                 if (! tclass.provides(LyXTextClass::makeidx))
223                         packages << "\\usepackage{makeidx}\n";
224                 packages << "\\makeindex\n";
225         }
226
227         // graphicx.sty
228         if (isRequired("graphicx") && params.graphicsDriver != "none") {
229                 if (params.graphicsDriver == "default")
230                         packages << "\\usepackage{graphicx}\n";
231                 else
232                         packages << "\\usepackage["
233                                  << params.graphicsDriver
234                                  << "]{graphicx}\n";
235         }
236
237         //if (algorithm) {
238         //      packages << "\\usepackage{algorithm}\n";
239         //}
240
241         // lyxskak.sty --- newer chess support based on skak.sty
242         if (isRequired("chess")) {
243                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
244         }
245
246         // setspace.sty
247         if ((params.spacing.getSpace() != Spacing::Single
248              && !params.spacing.isDefault())
249             || isRequired("setspace")) {
250                 packages << "\\usepackage{setspace}\n";
251         }
252         switch (params.spacing.getSpace()) {
253         case Spacing::Default:
254         case Spacing::Single:
255                 // we dont use setspace.sty so dont print anything
256                 //packages += "\\singlespacing\n";
257                 break;
258         case Spacing::Onehalf:
259                 packages << "\\onehalfspacing\n";
260                 break;
261         case Spacing::Double:
262                 packages << "\\doublespacing\n";
263                 break;
264         case Spacing::Other:
265                 packages << "\\setstretch{"
266                          << params.spacing.getValue() << "}\n";
267                 break;
268         }
269
270         // amssymb.sty
271         if (isRequired("amssymb") || params.use_amsmath)
272                 packages << "\\usepackage{amssymb}\n";
273         // url.sty
274         if (isRequired("url") && ! tclass.provides(LyXTextClass::url))
275                 packages << "\\IfFileExists{url.sty}{\\usepackage{url}}\n"
276                             "                      {\\newcommand{\\url}{\\texttt}}\n";
277
278         // float.sty
279         // natbib.sty
280         if (isRequired("natbib") && ! tclass.provides(LyXTextClass::natbib)) {
281                 packages << "\\usepackage[";
282                 if (params.use_numerical_citations) {
283                         packages << "numbers";
284                 } else {
285                         packages << "authoryear";
286                 }
287                 packages << "]{natbib}\n";
288         }
289
290         packages << externalPreambles;
291
292         return packages.str().c_str();
293 }
294
295
296 string const LaTeXFeatures::getMacros() const
297 {
298         ostringstream macros;
299
300         if (isRequired("LyX"))
301                 macros << lyx_def << '\n';
302
303         if (isRequired("lyxline"))
304                 macros << lyxline_def << '\n';
305
306         if (isRequired("noun"))
307                 macros << noun_def << '\n';
308
309         if (isRequired("lyxarrow"))
310                 macros << lyxarrow_def << '\n';
311
312         // quotes.
313         if (isRequired("quotesinglbase"))
314                 macros << quotesinglbase_def << '\n';
315         if (isRequired("quotedblbase"))
316                 macros << quotedblbase_def << '\n';
317         if (isRequired("guilsinglleft"))
318                 macros << guilsinglleft_def << '\n';
319         if (isRequired("guilsinglright"))
320                 macros << guilsinglright_def << '\n';
321         if (isRequired("guillemotleft"))
322                 macros << guillemotleft_def << '\n';
323         if (isRequired("guillemotright"))
324                 macros << guillemotright_def << '\n';
325
326         // Math mode
327         if (isRequired("boldsymbol") && !isRequired("amsmath"))
328                 macros << boldsymbol_def << '\n';
329         if (isRequired("binom") && !isRequired("amsmath"))
330                 macros << binom_def << '\n';
331         if (isRequired("mathcircumflex"))
332                 macros << mathcircumflex_def << '\n';
333
334         // other
335         if (isRequired("NeedLyXMinipageIndent"))
336                 macros << minipageindent_def;
337         if (isRequired("ParagraphLeftIndent"))
338                 macros << paragraphleftindent_def;
339         if (isRequired("NeedLyXFootnoteCode"))
340                 macros << floatingfootnote_def;
341
342         // floats
343         getFloatDefinitions(macros);
344
345         return macros.str().c_str();
346 }
347
348
349 string const LaTeXFeatures::getBabelOptions() const
350 {
351         ostringstream tmp;
352
353         for (LanguageList::const_iterator cit = UsedLanguages.begin();
354              cit != UsedLanguages.end(); ++cit)
355                 if (!(*cit)->latex_options().empty())
356                         tmp << (*cit)->latex_options() << '\n';
357         if (!params.language->latex_options().empty())
358                 tmp << params.language->latex_options() << '\n';
359
360         return tmp.str().c_str();
361 }
362
363
364 string const LaTeXFeatures::getTClassPreamble() const
365 {
366         // the text class specific preamble
367         LyXTextClass const & tclass = params.getLyXTextClass();
368         ostringstream tcpreamble;
369
370         tcpreamble << tclass.preamble();
371
372         list<string>::const_iterator cit = usedLayouts.begin();
373         list<string>::const_iterator end = usedLayouts.end();
374         for (; cit != end; ++cit) {
375                 tcpreamble << tclass[*cit]->preamble();
376         }
377
378         return tcpreamble.str().c_str();
379 }
380
381
382 string const LaTeXFeatures::getLyXSGMLEntities() const
383 {
384         // Definition of entities used in the document that are LyX related.
385         ostringstream entities;
386
387         if (isRequired("lyxarrow")) {
388                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
389         }
390
391         return entities.str().c_str();
392 }
393
394
395 string const LaTeXFeatures::getIncludedFiles(string const & fname) const
396 {
397         ostringstream sgmlpreamble;
398         string const basename = OnlyPath(fname);
399
400         FileMap::const_iterator end = IncludedFiles.end();
401         for (FileMap::const_iterator fi = IncludedFiles.begin();
402              fi != end; ++fi)
403                 sgmlpreamble << "\n<!ENTITY " << fi->first
404                              << (IsSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
405                              << MakeRelPath(fi->second, basename) << "\">";
406
407         return sgmlpreamble.str().c_str();
408 }
409
410
411 void LaTeXFeatures::showStruct() const {
412         lyxerr << "LyX needs the following commands when LaTeXing:"
413                << "\n***** Packages:" << getPackages()
414                << "\n***** Macros:" << getMacros()
415                << "\n***** Textclass stuff:" << getTClassPreamble()
416                << "\n***** done." << endl;
417 }
418
419
420 BufferParams const & LaTeXFeatures::bufferParams() const
421 {
422         return params;
423 }
424
425
426 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
427 {
428         // Here we will output the code to create the needed float styles.
429         // We will try to do this as minimal as possible.
430         // \floatstyle{ruled}
431         // \newfloat{algorithm}{htbp}{loa}
432         // \floatname{algorithm}{Algorithm}
433         UsedFloats::const_iterator cit = usedFloats.begin();
434         UsedFloats::const_iterator end = usedFloats.end();
435         // ostringstream floats;
436         for (; cit != end; ++cit) {
437                 Floating const & fl = floatList.getType((*cit));
438
439                 // For builtin floats we do nothing.
440                 if (fl.builtin()) continue;
441
442                 // We have to special case "table" and "figure"
443                 if (fl.type() == "tabular" || fl.type() == "figure") {
444                         // Output code to modify "table" or "figure"
445                         // but only if builtin == false
446                         // and that have to be true at this point in the
447                         // function.
448                         string const type = fl.type();
449                         string const placement = fl.placement();
450                         string const style = fl.style();
451                         if (!style.empty()) {
452                                 os << "\\floatstyle{" << style << "}\n"
453                                    << "\\restylefloat{" << type << "}\n";
454                         }
455                         if (!placement.empty()) {
456                                 os << "\\floatplacement{" << type << "}{"
457                                    << placement << "}\n";
458                         }
459                 } else {
460                         // The other non builtin floats.
461
462                         string const type = fl.type();
463                         string const placement = fl.placement();
464                         string const ext = fl.ext();
465                         string const within = fl.within();
466                         string const style = fl.style();
467                         string const name = fl.name();
468                         os << "\\floatstyle{" << style << "}\n"
469                            << "\\newfloat{" << type << "}{" << placement
470                            << "}{" << ext << "}";
471                         if (!within.empty())
472                                 os << "[" << within << "]";
473                         os << "\n"
474                            << "\\floatname{" << type << "}{"
475                            << name << "}\n";
476
477                         // What missing here is to code to minimalize the code
478                         // output so that the same floatstyle will not be
479                         // used several times, when the same style is still in
480                         // effect. (Lgb)
481                 }
482         }
483 }