]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.C
get rid of broken_header.h and some unneeded tests
[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 <sstream>
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 namespace biblio = lyx::biblio;
45
46
47 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p, bool n)
48         : buffer_(&b), params_(p), nice_(n)
49 {}
50
51
52 bool LaTeXFeatures::useBabel() const
53 {
54         return lyxrc.language_use_babel ||
55                 bufferParams().language->lang() != lyxrc.default_language ||
56                 this->hasLanguages();
57 }
58
59
60 void LaTeXFeatures::require(string const & name)
61 {
62         if (isRequired(name))
63                 return;
64
65         features_.push_back(name);
66 }
67
68
69 void LaTeXFeatures::useLayout(string const & layoutname)
70 {
71         // Some code to avoid loops in dependency definition
72         static int level = 0;
73         const int maxlevel = 30;
74         if (level > maxlevel) {
75                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
76                        << "recursion attained by layout "
77                        << layoutname << endl;
78                 return;
79         }
80
81         LyXTextClass const & tclass = params_.getLyXTextClass();
82         if (tclass.hasLayout(layoutname)) {
83                 // Is this layout already in usedLayouts?
84                 list<string>::const_iterator cit = usedLayouts_.begin();
85                 list<string>::const_iterator end = usedLayouts_.end();
86                 for (; cit != end; ++cit) {
87                         if (layoutname == *cit)
88                                 return;
89                 }
90
91                 LyXLayout_ptr const & lyt = tclass[layoutname];
92                 if (!lyt->depends_on().empty()) {
93                         ++level;
94                         useLayout(lyt->depends_on());
95                         --level;
96                 }
97                 usedLayouts_.push_back(layoutname);
98         } else {
99                 lyxerr << "LaTeXFeatures::useLayout: layout `"
100                        << layoutname << "' does not exist in this class"
101                        << endl;
102         }
103
104         --level;
105 }
106
107
108 bool LaTeXFeatures::isRequired(string const & name) const
109 {
110         return find(features_.begin(), features_.end(), name) != features_.end();
111 }
112
113
114 void LaTeXFeatures::addExternalPreamble(string const & preamble)
115 {
116         FeaturesList::const_iterator begin = preamble_snippets_.begin();
117         FeaturesList::const_iterator end   = preamble_snippets_.end();
118         if (find(begin, end, preamble) == end)
119                 preamble_snippets_.push_back(preamble);
120 }
121
122
123 void LaTeXFeatures::useFloat(string const & name)
124 {
125         usedFloats_.insert(name);
126         // We only need float.sty if we use non builtin floats, or if we
127         // use the "H" modifier. This includes modified table and
128         // figure floats. (Lgb)
129         Floating const & fl = params_.getLyXTextClass().floats().getType(name);
130         if (!fl.type().empty() && !fl.builtin()) {
131                 require("float");
132         }
133 }
134
135
136 void LaTeXFeatures::useLanguage(Language const * lang)
137 {
138         UsedLanguages_.insert(lang);
139 }
140
141
142 void LaTeXFeatures::includeFile(string const & key, string const & name)
143 {
144         IncludedFiles_[key] = name;
145 }
146
147
148 bool LaTeXFeatures::hasLanguages() const
149 {
150         return !UsedLanguages_.empty();
151 }
152
153
154 string LaTeXFeatures::getLanguages() const
155 {
156         ostringstream languages;
157
158         for (LanguageList::const_iterator cit =
159                     UsedLanguages_.begin();
160              cit != UsedLanguages_.end();
161              ++cit)
162                 languages << (*cit)->babel() << ',';
163         return languages.str();
164 }
165
166
167 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
168 {
169         set<string> encodings;
170         LanguageList::const_iterator it  = UsedLanguages_.begin();
171         LanguageList::const_iterator end = UsedLanguages_.end();
172         for (; it != end; ++it)
173                 if ((*it)->encoding()->LatexName() != doc_encoding)
174                         encodings.insert((*it)->encoding()->LatexName());
175         return encodings;
176 }
177
178 namespace {
179
180 char const * simplefeatures[] = {
181         "array",
182         "verbatim",
183         "longtable",
184         "rotating",
185         "latexsym",
186         "pifont",
187         "subfigure",
188         "floatflt",
189         "varioref",
190         "prettyref",
191         "float",
192         "wasy",
193         "dvipost",
194         "fancybox",
195         "calc",
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_.cite_engine == biblio::ENGINE_NATBIB_NUMERICAL) {
303                         packages << "numbers";
304                 } else {
305                         packages << "authoryear";
306                 }
307                 packages << "]{natbib}\n";
308         }
309
310         // jurabib -- we need version 0.6 at least.
311         if (isRequired("jurabib")) {
312                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
313         }
314
315         // bibtopic -- the dot provides the aux file naming which
316         // LyX can detect.
317         if (isRequired("bibtopic")) {
318                 packages << "\\usepackage[dot]{bibtopic}\n";
319         }
320
321         return packages.str();
322 }
323
324
325 string const LaTeXFeatures::getMacros() const
326 {
327         ostringstream macros;
328
329         if (!preamble_snippets_.empty())
330                 macros << '\n';
331         FeaturesList::const_iterator pit  = preamble_snippets_.begin();
332         FeaturesList::const_iterator pend = preamble_snippets_.end();
333         for (; pit != pend; ++pit) {
334                 macros << *pit << '\n';
335         }
336
337         if (isRequired("LyX"))
338                 macros << lyx_def << '\n';
339
340         if (isRequired("lyxline"))
341                 macros << lyxline_def << '\n';
342
343         if (isRequired("noun"))
344                 macros << noun_def << '\n';
345
346         if (isRequired("lyxarrow"))
347                 macros << lyxarrow_def << '\n';
348
349         // quotes.
350         if (isRequired("quotesinglbase"))
351                 macros << quotesinglbase_def << '\n';
352         if (isRequired("quotedblbase"))
353                 macros << quotedblbase_def << '\n';
354         if (isRequired("guilsinglleft"))
355                 macros << guilsinglleft_def << '\n';
356         if (isRequired("guilsinglright"))
357                 macros << guilsinglright_def << '\n';
358         if (isRequired("guillemotleft"))
359                 macros << guillemotleft_def << '\n';
360         if (isRequired("guillemotright"))
361                 macros << guillemotright_def << '\n';
362
363         // Math mode
364         if (isRequired("boldsymbol") && !isRequired("amsmath"))
365                 macros << boldsymbol_def << '\n';
366         if (isRequired("binom") && !isRequired("amsmath"))
367                 macros << binom_def << '\n';
368         if (isRequired("mathcircumflex"))
369                 macros << mathcircumflex_def << '\n';
370
371         // other
372         if (isRequired("ParagraphLeftIndent"))
373                 macros << paragraphleftindent_def;
374         if (isRequired("NeedLyXFootnoteCode"))
375                 macros << floatingfootnote_def;
376
377         // some problems with tex->html converters
378         if (isRequired("NeedTabularnewline"))
379                 macros << tabularnewline_def;
380
381         // greyedout environment (note inset)
382         if (isRequired("lyxgreyedout"))
383                 macros << lyxgreyedout_def;
384
385         if (isRequired("lyxdot"))
386                 macros << lyxdot_def << '\n';
387
388         // floats
389         getFloatDefinitions(macros);
390
391         return macros.str();
392 }
393
394
395 string const LaTeXFeatures::getBabelOptions() const
396 {
397         ostringstream tmp;
398
399         LanguageList::const_iterator it  = UsedLanguages_.begin();
400         LanguageList::const_iterator end =  UsedLanguages_.end();
401         for (; it != end; ++it)
402                 if (!(*it)->latex_options().empty())
403                         tmp << (*it)->latex_options() << '\n';
404         if (!params_.language->latex_options().empty())
405                 tmp << params_.language->latex_options() << '\n';
406
407         return tmp.str();
408 }
409
410
411 string const LaTeXFeatures::getTClassPreamble() const
412 {
413         // the text class specific preamble
414         LyXTextClass const & tclass = params_.getLyXTextClass();
415         ostringstream tcpreamble;
416
417         tcpreamble << tclass.preamble();
418
419         list<string>::const_iterator cit = usedLayouts_.begin();
420         list<string>::const_iterator end = usedLayouts_.end();
421         for (; cit != end; ++cit) {
422                 tcpreamble << tclass[*cit]->preamble();
423         }
424
425         CharStyles::iterator cs = tclass.charstyles().begin();
426         CharStyles::iterator csend = tclass.charstyles().end();
427         for (; cs != csend; ++cs) {
428                 if (isRequired(cs->name))
429                         tcpreamble << cs->preamble;
430         }
431
432         return tcpreamble.str();
433 }
434
435
436 string const LaTeXFeatures::getLyXSGMLEntities() const
437 {
438         // Definition of entities used in the document that are LyX related.
439         ostringstream entities;
440
441         if (isRequired("lyxarrow")) {
442                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
443         }
444
445         return entities.str();
446 }
447
448
449 string const LaTeXFeatures::getIncludedFiles(string const & fname) const
450 {
451         ostringstream sgmlpreamble;
452         string const basename = OnlyPath(fname);
453
454         FileMap::const_iterator end = IncludedFiles_.end();
455         for (FileMap::const_iterator fi = IncludedFiles_.begin();
456              fi != end; ++fi)
457                 sgmlpreamble << "\n<!ENTITY " << fi->first
458                              << (IsSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
459                              << MakeRelPath(fi->second, basename) << "\">";
460
461         return sgmlpreamble.str();
462 }
463
464
465 void LaTeXFeatures::showStruct() const {
466         lyxerr << "LyX needs the following commands when LaTeXing:"
467                << "\n***** Packages:" << getPackages()
468                << "\n***** Macros:" << getMacros()
469                << "\n***** Textclass stuff:" << getTClassPreamble()
470                << "\n***** done." << endl;
471 }
472
473
474 Buffer const & LaTeXFeatures::buffer() const
475 {
476         return *buffer_;
477 }
478
479
480 void LaTeXFeatures::setBuffer(Buffer const & buffer)
481 {
482         buffer_ = &buffer;
483 }
484
485
486 BufferParams const & LaTeXFeatures::bufferParams() const
487 {
488         return params_;
489 }
490
491
492 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
493 {
494         FloatList const & floats = params_.getLyXTextClass().floats();
495
496         // Here we will output the code to create the needed float styles.
497         // We will try to do this as minimal as possible.
498         // \floatstyle{ruled}
499         // \newfloat{algorithm}{htbp}{loa}
500         // \floatname{algorithm}{Algorithm}
501         UsedFloats::const_iterator cit = usedFloats_.begin();
502         UsedFloats::const_iterator end = usedFloats_.end();
503         // ostringstream floats;
504         for (; cit != end; ++cit) {
505                 Floating const & fl = floats.getType((*cit));
506
507                 // For builtin floats we do nothing.
508                 if (fl.builtin()) continue;
509
510                 // We have to special case "table" and "figure"
511                 if (fl.type() == "tabular" || fl.type() == "figure") {
512                         // Output code to modify "table" or "figure"
513                         // but only if builtin == false
514                         // and that have to be true at this point in the
515                         // function.
516                         string const type = fl.type();
517                         string const placement = fl.placement();
518                         string const style = fl.style();
519                         if (!style.empty()) {
520                                 os << "\\floatstyle{" << style << "}\n"
521                                    << "\\restylefloat{" << type << "}\n";
522                         }
523                         if (!placement.empty()) {
524                                 os << "\\floatplacement{" << type << "}{"
525                                    << placement << "}\n";
526                         }
527                 } else {
528                         // The other non builtin floats.
529
530                         string const type = fl.type();
531                         string const placement = fl.placement();
532                         string const ext = fl.ext();
533                         string const within = fl.within();
534                         string const style = fl.style();
535                         string const name = fl.name();
536                         os << "\\floatstyle{" << style << "}\n"
537                            << "\\newfloat{" << type << "}{" << placement
538                            << "}{" << ext << '}';
539                         if (!within.empty())
540                                 os << '[' << within << ']';
541                         os << '\n'
542                            << "\\floatname{" << type << "}{"
543                            << name << "}\n";
544
545                         // What missing here is to code to minimalize the code
546                         // output so that the same floatstyle will not be
547                         // used several times, when the same style is still in
548                         // effect. (Lgb)
549                 }
550         }
551 }