]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.C
use \usepackage instead of \RequirePackage for jurabib
[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
164         return languages.str();
165 }
166
167
168 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
169 {
170         set<string> encodings;
171         LanguageList::const_iterator it  = UsedLanguages_.begin();
172         LanguageList::const_iterator end = UsedLanguages_.end();
173         for (; it != end; ++it)
174                 if ((*it)->encoding()->LatexName() != doc_encoding)
175                         encodings.insert((*it)->encoding()->LatexName());
176         return encodings;
177 }
178
179 namespace {
180
181 char const * simplefeatures[] = {
182         "array",
183         "verbatim",
184         "longtable",
185         "rotating",
186         "latexsym",
187         "pifont",
188         "subfigure",
189         "floatflt",
190         "varioref",
191         "prettyref",
192         "float",
193         "wasy",
194         "dvipost",
195         "fancybox",
196         "calc",
197 };
198
199 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
200
201 }
202
203
204 string const LaTeXFeatures::getPackages() const
205 {
206         ostringstream packages;
207         LyXTextClass const & tclass = params_.getLyXTextClass();
208
209         //
210         //  These are all the 'simple' includes.  i.e
211         //  packages which we just \usepackage{package}
212         //
213         for (int i = 0; i < nb_simplefeatures; ++i) {
214                 if (isRequired(simplefeatures[i]))
215                         packages << "\\usepackage{"
216                                  << simplefeatures[i] << "}\n";
217         }
218
219         //
220         // The rest of these packages are somewhat more complicated
221         // than those above.
222         //
223
224         if (isRequired("amsmath")
225             && !tclass.provides(LyXTextClass::amsmath)
226             && params_.use_amsmath != BufferParams::AMS_OFF) {
227                 packages << "\\usepackage{amsmath}\n";
228         }
229
230         // color.sty
231         if (isRequired("color")) {
232                 if (params_.graphicsDriver == "default")
233                         packages << "\\usepackage[usenames]{color}\n";
234                 else
235                         packages << "\\usepackage["
236                                  << params_.graphicsDriver
237                                  << ",usenames"
238                                  << "]{color}\n";
239         }
240
241         // makeidx.sty
242         if (isRequired("makeidx")) {
243                 if (! tclass.provides(LyXTextClass::makeidx))
244                         packages << "\\usepackage{makeidx}\n";
245                 packages << "\\makeindex\n";
246         }
247
248         // graphicx.sty
249         if (isRequired("graphicx") && params_.graphicsDriver != "none") {
250                 if (params_.graphicsDriver == "default")
251                         packages << "\\usepackage{graphicx}\n";
252                 else
253                         packages << "\\usepackage["
254                                  << params_.graphicsDriver
255                                  << "]{graphicx}\n";
256         }
257
258         //if (algorithm) {
259         //      packages << "\\usepackage{algorithm}\n";
260         //}
261
262         // lyxskak.sty --- newer chess support based on skak.sty
263         if (isRequired("chess")) {
264                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
265         }
266
267         // setspace.sty
268         if ((params_.spacing().getSpace() != Spacing::Single
269              && !params_.spacing().isDefault())
270             || isRequired("setspace")) {
271                 packages << "\\usepackage{setspace}\n";
272         }
273         switch (params_.spacing().getSpace()) {
274         case Spacing::Default:
275         case Spacing::Single:
276                 // we dont use setspace.sty so dont print anything
277                 //packages += "\\singlespacing\n";
278                 break;
279         case Spacing::Onehalf:
280                 packages << "\\onehalfspacing\n";
281                 break;
282         case Spacing::Double:
283                 packages << "\\doublespacing\n";
284                 break;
285         case Spacing::Other:
286                 packages << "\\setstretch{"
287                          << params_.spacing().getValue() << "}\n";
288                 break;
289         }
290
291         // amssymb.sty
292         if (isRequired("amssymb") || params_.use_amsmath == BufferParams::AMS_ON)
293                 packages << "\\usepackage{amssymb}\n";
294         // url.sty
295         if (isRequired("url") && ! tclass.provides(LyXTextClass::url))
296                 packages << "\\IfFileExists{url.sty}{\\usepackage{url}}\n"
297                             "                      {\\newcommand{\\url}{\\texttt}}\n";
298
299         // float.sty
300         // natbib.sty
301         if (isRequired("natbib") && ! tclass.provides(LyXTextClass::natbib)) {
302                 packages << "\\usepackage[";
303                 if (params_.cite_engine == biblio::ENGINE_NATBIB_NUMERICAL) {
304                         packages << "numbers";
305                 } else {
306                         packages << "authoryear";
307                 }
308                 packages << "]{natbib}\n";
309         }
310
311         // jurabib -- we need version 0.6 at least.
312         if (isRequired("jurabib")) {
313                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
314         }
315
316         // bibtopic -- the dot provides the aux file naming which
317         // LyX can detect.
318         if (isRequired("bibtopic")) {
319                 packages << "\\usepackage[dot]{bibtopic}\n";
320         }
321
322         return packages.str();
323 }
324
325
326 string const LaTeXFeatures::getMacros() const
327 {
328         ostringstream macros;
329
330         if (!preamble_snippets_.empty())
331                 macros << '\n';
332         FeaturesList::const_iterator pit  = preamble_snippets_.begin();
333         FeaturesList::const_iterator pend = preamble_snippets_.end();
334         for (; pit != pend; ++pit) {
335                 macros << *pit << '\n';
336         }
337
338         if (isRequired("LyX"))
339                 macros << lyx_def << '\n';
340
341         if (isRequired("lyxline"))
342                 macros << lyxline_def << '\n';
343
344         if (isRequired("noun"))
345                 macros << noun_def << '\n';
346
347         if (isRequired("lyxarrow"))
348                 macros << lyxarrow_def << '\n';
349
350         // quotes.
351         if (isRequired("quotesinglbase"))
352                 macros << quotesinglbase_def << '\n';
353         if (isRequired("quotedblbase"))
354                 macros << quotedblbase_def << '\n';
355         if (isRequired("guilsinglleft"))
356                 macros << guilsinglleft_def << '\n';
357         if (isRequired("guilsinglright"))
358                 macros << guilsinglright_def << '\n';
359         if (isRequired("guillemotleft"))
360                 macros << guillemotleft_def << '\n';
361         if (isRequired("guillemotright"))
362                 macros << guillemotright_def << '\n';
363
364         // Math mode
365         if (isRequired("boldsymbol") && !isRequired("amsmath"))
366                 macros << boldsymbol_def << '\n';
367         if (isRequired("binom") && !isRequired("amsmath"))
368                 macros << binom_def << '\n';
369         if (isRequired("mathcircumflex"))
370                 macros << mathcircumflex_def << '\n';
371
372         // other
373         if (isRequired("ParagraphLeftIndent"))
374                 macros << paragraphleftindent_def;
375         if (isRequired("NeedLyXFootnoteCode"))
376                 macros << floatingfootnote_def;
377
378         // some problems with tex->html converters
379         if (isRequired("NeedTabularnewline"))
380                 macros << tabularnewline_def;
381
382         // greyedout environment (note inset)
383         if (isRequired("lyxgreyedout"))
384                 macros << lyxgreyedout_def;
385
386         if (isRequired("lyxdot"))
387                 macros << lyxdot_def << '\n';
388
389         // floats
390         getFloatDefinitions(macros);
391
392         return macros.str();
393 }
394
395
396 string const LaTeXFeatures::getBabelOptions() const
397 {
398         ostringstream tmp;
399
400         LanguageList::const_iterator it  = UsedLanguages_.begin();
401         LanguageList::const_iterator end =  UsedLanguages_.end();
402         for (; it != end; ++it)
403                 if (!(*it)->latex_options().empty())
404                         tmp << (*it)->latex_options() << '\n';
405         if (!params_.language->latex_options().empty())
406                 tmp << params_.language->latex_options() << '\n';
407
408         return tmp.str();
409 }
410
411
412 string const LaTeXFeatures::getTClassPreamble() const
413 {
414         // the text class specific preamble
415         LyXTextClass const & tclass = params_.getLyXTextClass();
416         ostringstream tcpreamble;
417
418         tcpreamble << tclass.preamble();
419
420         list<string>::const_iterator cit = usedLayouts_.begin();
421         list<string>::const_iterator end = usedLayouts_.end();
422         for (; cit != end; ++cit) {
423                 tcpreamble << tclass[*cit]->preamble();
424         }
425
426         CharStyles::iterator cs = tclass.charstyles().begin();
427         CharStyles::iterator csend = tclass.charstyles().end();
428         for (; cs != csend; ++cs) {
429                 if (isRequired(cs->name))
430                         tcpreamble << cs->preamble;
431         }
432
433         return tcpreamble.str();
434 }
435
436
437 string const LaTeXFeatures::getLyXSGMLEntities() const
438 {
439         // Definition of entities used in the document that are LyX related.
440         ostringstream entities;
441
442         if (isRequired("lyxarrow")) {
443                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
444         }
445
446         return entities.str();
447 }
448
449
450 string const LaTeXFeatures::getIncludedFiles(string const & fname) const
451 {
452         ostringstream sgmlpreamble;
453         string const basename = OnlyPath(fname);
454
455         FileMap::const_iterator end = IncludedFiles_.end();
456         for (FileMap::const_iterator fi = IncludedFiles_.begin();
457              fi != end; ++fi)
458                 sgmlpreamble << "\n<!ENTITY " << fi->first
459                              << (IsSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
460                              << MakeRelPath(fi->second, basename) << "\">";
461
462         return sgmlpreamble.str();
463 }
464
465
466 void LaTeXFeatures::showStruct() const {
467         lyxerr << "LyX needs the following commands when LaTeXing:"
468                << "\n***** Packages:" << getPackages()
469                << "\n***** Macros:" << getMacros()
470                << "\n***** Textclass stuff:" << getTClassPreamble()
471                << "\n***** done." << endl;
472 }
473
474
475 Buffer const & LaTeXFeatures::buffer() const
476 {
477         return *buffer_;
478 }
479
480
481 void LaTeXFeatures::setBuffer(Buffer const & buffer)
482 {
483         buffer_ = &buffer;
484 }
485
486
487 BufferParams const & LaTeXFeatures::bufferParams() const
488 {
489         return params_;
490 }
491
492
493 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
494 {
495         FloatList const & floats = params_.getLyXTextClass().floats();
496
497         // Here we will output the code to create the needed float styles.
498         // We will try to do this as minimal as possible.
499         // \floatstyle{ruled}
500         // \newfloat{algorithm}{htbp}{loa}
501         // \floatname{algorithm}{Algorithm}
502         UsedFloats::const_iterator cit = usedFloats_.begin();
503         UsedFloats::const_iterator end = usedFloats_.end();
504         // ostringstream floats;
505         for (; cit != end; ++cit) {
506                 Floating const & fl = floats.getType((*cit));
507
508                 // For builtin floats we do nothing.
509                 if (fl.builtin()) continue;
510
511                 // We have to special case "table" and "figure"
512                 if (fl.type() == "tabular" || fl.type() == "figure") {
513                         // Output code to modify "table" or "figure"
514                         // but only if builtin == false
515                         // and that have to be true at this point in the
516                         // function.
517                         string const type = fl.type();
518                         string const placement = fl.placement();
519                         string const style = fl.style();
520                         if (!style.empty()) {
521                                 os << "\\floatstyle{" << style << "}\n"
522                                    << "\\restylefloat{" << type << "}\n";
523                         }
524                         if (!placement.empty()) {
525                                 os << "\\floatplacement{" << type << "}{"
526                                    << placement << "}\n";
527                         }
528                 } else {
529                         // The other non builtin floats.
530
531                         string const type = fl.type();
532                         string const placement = fl.placement();
533                         string const ext = fl.ext();
534                         string const within = fl.within();
535                         string const style = fl.style();
536                         string const name = fl.name();
537                         os << "\\floatstyle{" << style << "}\n"
538                            << "\\newfloat{" << type << "}{" << placement
539                            << "}{" << ext << '}';
540                         if (!within.empty())
541                                 os << '[' << within << ']';
542                         os << '\n'
543                            << "\\floatname{" << type << "}{"
544                            << name << "}\n";
545
546                         // What missing here is to code to minimalize the code
547                         // output so that the same floatstyle will not be
548                         // used several times, when the same style is still in
549                         // effect. (Lgb)
550                 }
551         }
552 }