]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.C
9cbbc3288c564c9e76c60aa34443f15740d92782
[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_.cite_engine == biblio::ENGINE_NATBIB_NUMERICAL) {
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         if (isRequired("lyxdot"))
381                 macros << lyxdot_def << '\n';
382
383         // floats
384         getFloatDefinitions(macros);
385
386         return macros.str();
387 }
388
389
390 string const LaTeXFeatures::getBabelOptions() const
391 {
392         ostringstream tmp;
393
394         LanguageList::const_iterator it  = UsedLanguages_.begin();
395         LanguageList::const_iterator end =  UsedLanguages_.end();
396         for (; it != end; ++it)
397                 if (!(*it)->latex_options().empty())
398                         tmp << (*it)->latex_options() << '\n';
399         if (!params_.language->latex_options().empty())
400                 tmp << params_.language->latex_options() << '\n';
401
402         return tmp.str();
403 }
404
405
406 string const LaTeXFeatures::getTClassPreamble() const
407 {
408         // the text class specific preamble
409         LyXTextClass const & tclass = params_.getLyXTextClass();
410         ostringstream tcpreamble;
411
412         tcpreamble << tclass.preamble();
413
414         list<string>::const_iterator cit = usedLayouts_.begin();
415         list<string>::const_iterator end = usedLayouts_.end();
416         for (; cit != end; ++cit) {
417                 tcpreamble << tclass[*cit]->preamble();
418         }
419
420         CharStyles::iterator cs = tclass.charstyles().begin();
421         CharStyles::iterator csend = tclass.charstyles().end();
422         for (; cs != csend; ++cs) {
423                 if (isRequired(cs->name))
424                         tcpreamble << cs->preamble;
425         }
426
427         return tcpreamble.str();
428 }
429
430
431 string const LaTeXFeatures::getLyXSGMLEntities() const
432 {
433         // Definition of entities used in the document that are LyX related.
434         ostringstream entities;
435
436         if (isRequired("lyxarrow")) {
437                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
438         }
439
440         return entities.str();
441 }
442
443
444 string const LaTeXFeatures::getIncludedFiles(string const & fname) const
445 {
446         ostringstream sgmlpreamble;
447         string const basename = OnlyPath(fname);
448
449         FileMap::const_iterator end = IncludedFiles_.end();
450         for (FileMap::const_iterator fi = IncludedFiles_.begin();
451              fi != end; ++fi)
452                 sgmlpreamble << "\n<!ENTITY " << fi->first
453                              << (IsSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
454                              << MakeRelPath(fi->second, basename) << "\">";
455
456         return sgmlpreamble.str();
457 }
458
459
460 void LaTeXFeatures::showStruct() const {
461         lyxerr << "LyX needs the following commands when LaTeXing:"
462                << "\n***** Packages:" << getPackages()
463                << "\n***** Macros:" << getMacros()
464                << "\n***** Textclass stuff:" << getTClassPreamble()
465                << "\n***** done." << endl;
466 }
467
468
469 Buffer const & LaTeXFeatures::buffer() const
470 {
471         return *buffer_;
472 }
473
474
475 void LaTeXFeatures::setBuffer(Buffer const & buffer)
476 {
477         buffer_ = &buffer;
478 }
479
480
481 BufferParams const & LaTeXFeatures::bufferParams() const
482 {
483         return params_;
484 }
485
486
487 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
488 {
489         FloatList const & floats = params_.getLyXTextClass().floats();
490
491         // Here we will output the code to create the needed float styles.
492         // We will try to do this as minimal as possible.
493         // \floatstyle{ruled}
494         // \newfloat{algorithm}{htbp}{loa}
495         // \floatname{algorithm}{Algorithm}
496         UsedFloats::const_iterator cit = usedFloats_.begin();
497         UsedFloats::const_iterator end = usedFloats_.end();
498         // ostringstream floats;
499         for (; cit != end; ++cit) {
500                 Floating const & fl = floats.getType((*cit));
501
502                 // For builtin floats we do nothing.
503                 if (fl.builtin()) continue;
504
505                 // We have to special case "table" and "figure"
506                 if (fl.type() == "tabular" || fl.type() == "figure") {
507                         // Output code to modify "table" or "figure"
508                         // but only if builtin == false
509                         // and that have to be true at this point in the
510                         // function.
511                         string const type = fl.type();
512                         string const placement = fl.placement();
513                         string const style = fl.style();
514                         if (!style.empty()) {
515                                 os << "\\floatstyle{" << style << "}\n"
516                                    << "\\restylefloat{" << type << "}\n";
517                         }
518                         if (!placement.empty()) {
519                                 os << "\\floatplacement{" << type << "}{"
520                                    << placement << "}\n";
521                         }
522                 } else {
523                         // The other non builtin floats.
524
525                         string const type = fl.type();
526                         string const placement = fl.placement();
527                         string const ext = fl.ext();
528                         string const within = fl.within();
529                         string const style = fl.style();
530                         string const name = fl.name();
531                         os << "\\floatstyle{" << style << "}\n"
532                            << "\\newfloat{" << type << "}{" << placement
533                            << "}{" << ext << '}';
534                         if (!within.empty())
535                                 os << '[' << within << ']';
536                         os << '\n'
537                            << "\\floatname{" << type << "}{"
538                            << name << "}\n";
539
540                         // What missing here is to code to minimalize the code
541                         // output so that the same floatstyle will not be
542                         // used several times, when the same style is still in
543                         // effect. (Lgb)
544                 }
545         }
546 }