]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.C
e7f52c7954a5a5f9efe912c85a8b65d85d9a0167
[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         // bibtopic -- the dot provides the aux file naming which
311         // LyX can detect.
312         if (isRequired("bibtopic")) {
313                 packages << "\\usepackage[dot]{bibtopic}\n";
314         }
315
316         return packages.str();
317 }
318
319
320 string const LaTeXFeatures::getMacros() const
321 {
322         ostringstream macros;
323
324         if (!preamble_snippets_.empty())
325                 macros << '\n';
326         FeaturesList::const_iterator pit  = preamble_snippets_.begin();
327         FeaturesList::const_iterator pend = preamble_snippets_.end();
328         for (; pit != pend; ++pit) {
329                 macros << *pit << '\n';
330         }
331
332         if (isRequired("LyX"))
333                 macros << lyx_def << '\n';
334
335         if (isRequired("lyxline"))
336                 macros << lyxline_def << '\n';
337
338         if (isRequired("noun"))
339                 macros << noun_def << '\n';
340
341         if (isRequired("lyxarrow"))
342                 macros << lyxarrow_def << '\n';
343
344         // quotes.
345         if (isRequired("quotesinglbase"))
346                 macros << quotesinglbase_def << '\n';
347         if (isRequired("quotedblbase"))
348                 macros << quotedblbase_def << '\n';
349         if (isRequired("guilsinglleft"))
350                 macros << guilsinglleft_def << '\n';
351         if (isRequired("guilsinglright"))
352                 macros << guilsinglright_def << '\n';
353         if (isRequired("guillemotleft"))
354                 macros << guillemotleft_def << '\n';
355         if (isRequired("guillemotright"))
356                 macros << guillemotright_def << '\n';
357
358         // Math mode
359         if (isRequired("boldsymbol") && !isRequired("amsmath"))
360                 macros << boldsymbol_def << '\n';
361         if (isRequired("binom") && !isRequired("amsmath"))
362                 macros << binom_def << '\n';
363         if (isRequired("mathcircumflex"))
364                 macros << mathcircumflex_def << '\n';
365
366         // other
367         if (isRequired("ParagraphLeftIndent"))
368                 macros << paragraphleftindent_def;
369         if (isRequired("NeedLyXFootnoteCode"))
370                 macros << floatingfootnote_def;
371
372         // some problems with tex->html converters
373         if (isRequired("NeedTabularnewline"))
374                 macros << tabularnewline_def;
375
376         // greyedout environment (note inset)
377         if (isRequired("lyxgreyedout"))
378                 macros << lyxgreyedout_def;
379
380         // floats
381         getFloatDefinitions(macros);
382
383         return macros.str();
384 }
385
386
387 string const LaTeXFeatures::getBabelOptions() const
388 {
389         ostringstream tmp;
390
391         LanguageList::const_iterator it  = UsedLanguages_.begin();
392         LanguageList::const_iterator end =  UsedLanguages_.end();
393         for (; it != end; ++it)
394                 if (!(*it)->latex_options().empty())
395                         tmp << (*it)->latex_options() << '\n';
396         if (!params_.language->latex_options().empty())
397                 tmp << params_.language->latex_options() << '\n';
398
399         return tmp.str();
400 }
401
402
403 string const LaTeXFeatures::getTClassPreamble() const
404 {
405         // the text class specific preamble
406         LyXTextClass const & tclass = params_.getLyXTextClass();
407         ostringstream tcpreamble;
408
409         tcpreamble << tclass.preamble();
410
411         list<string>::const_iterator cit = usedLayouts_.begin();
412         list<string>::const_iterator end = usedLayouts_.end();
413         for (; cit != end; ++cit) {
414                 tcpreamble << tclass[*cit]->preamble();
415         }
416
417         CharStyles::iterator cs = tclass.charstyles().begin();
418         CharStyles::iterator csend = tclass.charstyles().end();
419         for (; cs != csend; ++cs) {
420                 if (isRequired(cs->name))
421                         tcpreamble << cs->preamble;
422         }
423
424         return tcpreamble.str();
425 }
426
427
428 string const LaTeXFeatures::getLyXSGMLEntities() const
429 {
430         // Definition of entities used in the document that are LyX related.
431         ostringstream entities;
432
433         if (isRequired("lyxarrow")) {
434                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
435         }
436
437         return entities.str();
438 }
439
440
441 string const LaTeXFeatures::getIncludedFiles(string const & fname) const
442 {
443         ostringstream sgmlpreamble;
444         string const basename = OnlyPath(fname);
445
446         FileMap::const_iterator end = IncludedFiles_.end();
447         for (FileMap::const_iterator fi = IncludedFiles_.begin();
448              fi != end; ++fi)
449                 sgmlpreamble << "\n<!ENTITY " << fi->first
450                              << (IsSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
451                              << MakeRelPath(fi->second, basename) << "\">";
452
453         return sgmlpreamble.str();
454 }
455
456
457 void LaTeXFeatures::showStruct() const {
458         lyxerr << "LyX needs the following commands when LaTeXing:"
459                << "\n***** Packages:" << getPackages()
460                << "\n***** Macros:" << getMacros()
461                << "\n***** Textclass stuff:" << getTClassPreamble()
462                << "\n***** done." << endl;
463 }
464
465
466 Buffer const & LaTeXFeatures::buffer() const
467 {
468         return buffer_;
469 }
470
471
472 BufferParams const & LaTeXFeatures::bufferParams() const
473 {
474         return params_;
475 }
476
477
478 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
479 {
480         FloatList const & floats = params_.getLyXTextClass().floats();
481
482         // Here we will output the code to create the needed float styles.
483         // We will try to do this as minimal as possible.
484         // \floatstyle{ruled}
485         // \newfloat{algorithm}{htbp}{loa}
486         // \floatname{algorithm}{Algorithm}
487         UsedFloats::const_iterator cit = usedFloats_.begin();
488         UsedFloats::const_iterator end = usedFloats_.end();
489         // ostringstream floats;
490         for (; cit != end; ++cit) {
491                 Floating const & fl = floats.getType((*cit));
492
493                 // For builtin floats we do nothing.
494                 if (fl.builtin()) continue;
495
496                 // We have to special case "table" and "figure"
497                 if (fl.type() == "tabular" || fl.type() == "figure") {
498                         // Output code to modify "table" or "figure"
499                         // but only if builtin == false
500                         // and that have to be true at this point in the
501                         // function.
502                         string const type = fl.type();
503                         string const placement = fl.placement();
504                         string const style = fl.style();
505                         if (!style.empty()) {
506                                 os << "\\floatstyle{" << style << "}\n"
507                                    << "\\restylefloat{" << type << "}\n";
508                         }
509                         if (!placement.empty()) {
510                                 os << "\\floatplacement{" << type << "}{"
511                                    << placement << "}\n";
512                         }
513                 } else {
514                         // The other non builtin floats.
515
516                         string const type = fl.type();
517                         string const placement = fl.placement();
518                         string const ext = fl.ext();
519                         string const within = fl.within();
520                         string const style = fl.style();
521                         string const name = fl.name();
522                         os << "\\floatstyle{" << style << "}\n"
523                            << "\\newfloat{" << type << "}{" << placement
524                            << "}{" << ext << '}';
525                         if (!within.empty())
526                                 os << '[' << within << ']';
527                         os << '\n'
528                            << "\\floatname{" << type << "}{"
529                            << name << "}\n";
530
531                         // What missing here is to code to minimalize the code
532                         // output so that the same floatstyle will not be
533                         // used several times, when the same style is still in
534                         // effect. (Lgb)
535                 }
536         }
537 }