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