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