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