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