]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.C
ws changes only
[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         return tcpreamble.str();
413 }
414
415
416 string const LaTeXFeatures::getLyXSGMLEntities() const
417 {
418         // Definition of entities used in the document that are LyX related.
419         ostringstream entities;
420
421         if (isRequired("lyxarrow")) {
422                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
423         }
424
425         return entities.str();
426 }
427
428
429 string const LaTeXFeatures::getIncludedFiles(string const & fname) const
430 {
431         ostringstream sgmlpreamble;
432         string const basename = OnlyPath(fname);
433
434         FileMap::const_iterator end = IncludedFiles_.end();
435         for (FileMap::const_iterator fi = IncludedFiles_.begin();
436              fi != end; ++fi)
437                 sgmlpreamble << "\n<!ENTITY " << fi->first
438                              << (IsSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
439                              << MakeRelPath(fi->second, basename) << "\">";
440
441         return sgmlpreamble.str();
442 }
443
444
445 void LaTeXFeatures::showStruct() const {
446         lyxerr << "LyX needs the following commands when LaTeXing:"
447                << "\n***** Packages:" << getPackages()
448                << "\n***** Macros:" << getMacros()
449                << "\n***** Textclass stuff:" << getTClassPreamble()
450                << "\n***** done." << endl;
451 }
452
453
454 Buffer const & LaTeXFeatures::buffer() const
455 {
456         return buffer_;
457 }
458
459
460 BufferParams const & LaTeXFeatures::bufferParams() const
461 {
462         return params_;
463 }
464
465
466 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
467 {
468         FloatList const & floats = params_.getLyXTextClass().floats();
469
470         // Here we will output the code to create the needed float styles.
471         // We will try to do this as minimal as possible.
472         // \floatstyle{ruled}
473         // \newfloat{algorithm}{htbp}{loa}
474         // \floatname{algorithm}{Algorithm}
475         UsedFloats::const_iterator cit = usedFloats_.begin();
476         UsedFloats::const_iterator end = usedFloats_.end();
477         // ostringstream floats;
478         for (; cit != end; ++cit) {
479                 Floating const & fl = floats.getType((*cit));
480
481                 // For builtin floats we do nothing.
482                 if (fl.builtin()) continue;
483
484                 // We have to special case "table" and "figure"
485                 if (fl.type() == "tabular" || fl.type() == "figure") {
486                         // Output code to modify "table" or "figure"
487                         // but only if builtin == false
488                         // and that have to be true at this point in the
489                         // function.
490                         string const type = fl.type();
491                         string const placement = fl.placement();
492                         string const style = fl.style();
493                         if (!style.empty()) {
494                                 os << "\\floatstyle{" << style << "}\n"
495                                    << "\\restylefloat{" << type << "}\n";
496                         }
497                         if (!placement.empty()) {
498                                 os << "\\floatplacement{" << type << "}{"
499                                    << placement << "}\n";
500                         }
501                 } else {
502                         // The other non builtin floats.
503
504                         string const type = fl.type();
505                         string const placement = fl.placement();
506                         string const ext = fl.ext();
507                         string const within = fl.within();
508                         string const style = fl.style();
509                         string const name = fl.name();
510                         os << "\\floatstyle{" << style << "}\n"
511                            << "\\newfloat{" << type << "}{" << placement
512                            << "}{" << ext << '}';
513                         if (!within.empty())
514                                 os << '[' << within << ']';
515                         os << '\n'
516                            << "\\floatname{" << type << "}{"
517                            << name << "}\n";
518
519                         // What missing here is to code to minimalize the code
520                         // output so that the same floatstyle will not be
521                         // used several times, when the same style is still in
522                         // effect. (Lgb)
523                 }
524         }
525 }