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