]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.C
9f6e599206e7670344635a1f209a175fb965a590
[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 #include "debug.h"
19 #include "lyx_sty.h"
20 #include "lyxrc.h"
21 #include "bufferparams.h"
22 #include "Floating.h"
23 #include "FloatList.h"
24 #include "language.h"
25 #include "encoding.h"
26 #include "LString.h"
27 #include "Lsstream.h"
28
29 #include "support/filetools.h"
30 #include "support/lstrings.h"
31
32 using namespace lyx::support;
33
34 using lyx::textclass_type;
35
36 using std::endl;
37 using std::list;
38 using std::set;
39 using std::find;
40 using std::ostream;
41
42
43 LaTeXFeatures::LaTeXFeatures(BufferParams const & p)
44         : params(p)
45 {}
46
47
48 bool LaTeXFeatures::useBabel() const
49 {
50         return lyxrc.language_use_babel ||
51                 bufferParams().language->lang() != lyxrc.default_language ||
52                 this->hasLanguages();
53 }
54
55
56 void LaTeXFeatures::require(string const & name)
57 {
58         if (isRequired(name))
59                 return;
60
61         features.push_back(name);
62 }
63
64
65 void LaTeXFeatures::useLayout(string const & layoutname)
66 {
67         // Some code to avoid loops in dependency definition
68         static int level = 0;
69         const int maxlevel = 30;
70         if (level > maxlevel) {
71                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
72                        << "recursion attained by layout "
73                        << layoutname << endl;
74                 return;
75         }
76
77         LyXTextClass const & tclass = params.getLyXTextClass();
78         if (tclass.hasLayout(layoutname)) {
79                 // Is this layout already in usedLayouts?
80                 list<string>::const_iterator cit = usedLayouts.begin();
81                 list<string>::const_iterator end = usedLayouts.end();
82                 for (; cit != end; ++cit) {
83                         if (layoutname == *cit)
84                                 return;
85                 }
86
87                 LyXLayout_ptr const & lyt = tclass[layoutname];
88                 if (!lyt->depends_on().empty()) {
89                         ++level;
90                         useLayout(lyt->depends_on());
91                         --level;
92                 }
93                 usedLayouts.push_back(layoutname);
94         } else {
95                 lyxerr << "LaTeXFeatures::useLayout: layout `"
96                        << layoutname << "' does not exist in this class"
97                        << endl;
98         }
99
100         --level;
101 }
102
103
104 bool LaTeXFeatures::isRequired(string const & name) const
105 {
106         return find(features.begin(), features.end(), name) != features.end();
107 }
108
109
110 void LaTeXFeatures::addExternalPreamble(string const & preamble)
111 {
112         FeaturesList::const_iterator begin = preamble_snippets.begin();
113         FeaturesList::const_iterator end   = preamble_snippets.end();
114         if (find(begin, end, preamble) == end)
115                 preamble_snippets.push_back(preamble);
116 }
117
118
119 void LaTeXFeatures::useFloat(string const & name)
120 {
121         usedFloats.insert(name);
122         // We only need float.sty if we use non builtin floats, or if we
123         // use the "H" modifier. This includes modified table and
124         // figure floats. (Lgb)
125         Floating const & fl = params.getLyXTextClass().floats().getType(name);
126         if (!fl.type().empty() && !fl.builtin()) {
127                 require("float");
128         }
129 }
130
131
132 void LaTeXFeatures::useLanguage(Language const * lang)
133 {
134         UsedLanguages.insert(lang);
135 }
136
137
138 void LaTeXFeatures::includeFile(string const & key, string const & name)
139 {
140         IncludedFiles[key] = name;
141 }
142
143
144 bool LaTeXFeatures::hasLanguages() const
145 {
146         return !UsedLanguages.empty();
147 }
148
149
150 string LaTeXFeatures::getLanguages() const
151 {
152         ostringstream languages;
153
154         for (LanguageList::const_iterator cit =
155                     UsedLanguages.begin();
156              cit != UsedLanguages.end();
157              ++cit)
158                 languages << (*cit)->babel() << ',';
159
160         return STRCONV(languages.str());
161 }
162
163
164 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
165 {
166         set<string> encodings;
167         for (LanguageList::const_iterator it =
168                      UsedLanguages.begin();
169              it != UsedLanguages.end(); ++it)
170                 if ((*it)->encoding()->LatexName() != doc_encoding)
171                         encodings.insert((*it)->encoding()->LatexName());
172         return encodings;
173 }
174
175 namespace {
176
177 char const * simplefeatures[] = {
178         "array",
179         "verbatim",
180         "longtable",
181         "rotating",
182         "latexsym",
183         "pifont",
184         "subfigure",
185         "floatflt",
186         "varioref",
187         "prettyref",
188         "float",
189         "wasy",
190         "dvipost"
191 };
192
193 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
194
195 }
196
197
198 string const LaTeXFeatures::getPackages() const
199 {
200         ostringstream packages;
201         LyXTextClass const & tclass = params.getLyXTextClass();
202
203         //
204         //  These are all the 'simple' includes.  i.e
205         //  packages which we just \usepackage{package}
206         //
207         for (int i = 0; i < nb_simplefeatures; ++i) {
208                 if (isRequired(simplefeatures[i]))
209                         packages << "\\usepackage{"
210                                  << simplefeatures[i] << "}\n";
211         }
212
213         //
214         // The rest of these packages are somewhat more complicated
215         // than those above.
216         //
217
218         if (isRequired("amsmath")
219             && !tclass.provides(LyXTextClass::amsmath)
220             && params.use_amsmath != BufferParams::AMS_OFF) {
221                 packages << "\\usepackage{amsmath}\n";
222         }
223
224         // color.sty
225         if (isRequired("color")) {
226                 if (params.graphicsDriver == "default")
227                         packages << "\\usepackage[usenames]{color}\n";
228                 else
229                         packages << "\\usepackage["
230                                  << params.graphicsDriver
231                                  << ",usenames"
232                                  << "]{color}\n";
233         }
234
235         // makeidx.sty
236         if (isRequired("makeidx")) {
237                 if (! tclass.provides(LyXTextClass::makeidx))
238                         packages << "\\usepackage{makeidx}\n";
239                 packages << "\\makeindex\n";
240         }
241
242         // graphicx.sty
243         if (isRequired("graphicx") && params.graphicsDriver != "none") {
244                 if (params.graphicsDriver == "default")
245                         packages << "\\usepackage{graphicx}\n";
246                 else
247                         packages << "\\usepackage["
248                                  << params.graphicsDriver
249                                  << "]{graphicx}\n";
250         }
251
252         //if (algorithm) {
253         //      packages << "\\usepackage{algorithm}\n";
254         //}
255
256         // lyxskak.sty --- newer chess support based on skak.sty
257         if (isRequired("chess")) {
258                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
259         }
260
261         // setspace.sty
262         if ((params.spacing.getSpace() != Spacing::Single
263              && !params.spacing.isDefault())
264             || isRequired("setspace")) {
265                 packages << "\\usepackage{setspace}\n";
266         }
267         switch (params.spacing.getSpace()) {
268         case Spacing::Default:
269         case Spacing::Single:
270                 // we dont use setspace.sty so dont print anything
271                 //packages += "\\singlespacing\n";
272                 break;
273         case Spacing::Onehalf:
274                 packages << "\\onehalfspacing\n";
275                 break;
276         case Spacing::Double:
277                 packages << "\\doublespacing\n";
278                 break;
279         case Spacing::Other:
280                 packages << "\\setstretch{"
281                          << params.spacing.getValue() << "}\n";
282                 break;
283         }
284
285         // amssymb.sty
286         if (isRequired("amssymb") || params.use_amsmath == BufferParams::AMS_ON)
287                 packages << "\\usepackage{amssymb}\n";
288         // url.sty
289         if (isRequired("url") && ! tclass.provides(LyXTextClass::url))
290                 packages << "\\IfFileExists{url.sty}{\\usepackage{url}}\n"
291                             "                      {\\newcommand{\\url}{\\texttt}}\n";
292
293         // float.sty
294         // natbib.sty
295         if (isRequired("natbib") && ! tclass.provides(LyXTextClass::natbib)) {
296                 packages << "\\usepackage[";
297                 if (params.use_numerical_citations) {
298                         packages << "numbers";
299                 } else {
300                         packages << "authoryear";
301                 }
302                 packages << "]{natbib}\n";
303         }
304
305         return STRCONV(packages.str());
306 }
307
308
309 string const LaTeXFeatures::getMacros() const
310 {
311         ostringstream macros;
312
313         if (!preamble_snippets.empty())
314                 macros << '\n';
315         FeaturesList::const_iterator pit  = preamble_snippets.begin();
316         FeaturesList::const_iterator pend = preamble_snippets.end();
317         for (; pit != pend; ++pit) {
318                 macros << *pit << '\n';
319         }
320
321         if (isRequired("LyX"))
322                 macros << lyx_def << '\n';
323
324         if (isRequired("lyxline"))
325                 macros << lyxline_def << '\n';
326
327         if (isRequired("noun"))
328                 macros << noun_def << '\n';
329
330         if (isRequired("lyxarrow"))
331                 macros << lyxarrow_def << '\n';
332
333         // quotes.
334         if (isRequired("quotesinglbase"))
335                 macros << quotesinglbase_def << '\n';
336         if (isRequired("quotedblbase"))
337                 macros << quotedblbase_def << '\n';
338         if (isRequired("guilsinglleft"))
339                 macros << guilsinglleft_def << '\n';
340         if (isRequired("guilsinglright"))
341                 macros << guilsinglright_def << '\n';
342         if (isRequired("guillemotleft"))
343                 macros << guillemotleft_def << '\n';
344         if (isRequired("guillemotright"))
345                 macros << guillemotright_def << '\n';
346
347         // Math mode
348         if (isRequired("boldsymbol") && !isRequired("amsmath"))
349                 macros << boldsymbol_def << '\n';
350         if (isRequired("binom") && !isRequired("amsmath"))
351                 macros << binom_def << '\n';
352         if (isRequired("mathcircumflex"))
353                 macros << mathcircumflex_def << '\n';
354
355         // other
356         if (isRequired("NeedLyXMinipageIndent"))
357                 macros << minipageindent_def;
358         if (isRequired("ParagraphLeftIndent"))
359                 macros << paragraphleftindent_def;
360         if (isRequired("NeedLyXFootnoteCode"))
361                 macros << floatingfootnote_def;
362
363         // some problems with tex->html converters
364         if (isRequired("NeedTabularnewline"))
365                 macros << tabularnewline_def;
366
367         // greyedout environment (note inset)
368         if (isRequired("lyxgreyedout"))
369                 macros << lyxgreyedout_def;
370
371         // floats
372         getFloatDefinitions(macros);
373
374         return STRCONV(macros.str());
375 }
376
377
378 string const LaTeXFeatures::getBabelOptions() const
379 {
380         ostringstream tmp;
381
382         for (LanguageList::const_iterator cit = UsedLanguages.begin();
383              cit != UsedLanguages.end(); ++cit)
384                 if (!(*cit)->latex_options().empty())
385                         tmp << (*cit)->latex_options() << '\n';
386         if (!params.language->latex_options().empty())
387                 tmp << params.language->latex_options() << '\n';
388
389         return STRCONV(tmp.str());
390 }
391
392
393 string const LaTeXFeatures::getTClassPreamble() const
394 {
395         // the text class specific preamble
396         LyXTextClass const & tclass = params.getLyXTextClass();
397         ostringstream tcpreamble;
398
399         tcpreamble << tclass.preamble();
400
401         list<string>::const_iterator cit = usedLayouts.begin();
402         list<string>::const_iterator end = usedLayouts.end();
403         for (; cit != end; ++cit) {
404                 tcpreamble << tclass[*cit]->preamble();
405         }
406
407         return STRCONV(tcpreamble.str());
408 }
409
410
411 string const LaTeXFeatures::getLyXSGMLEntities() const
412 {
413         // Definition of entities used in the document that are LyX related.
414         ostringstream entities;
415
416         if (isRequired("lyxarrow")) {
417                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
418         }
419
420         return STRCONV(entities.str());
421 }
422
423
424 string const LaTeXFeatures::getIncludedFiles(string const & fname) const
425 {
426         ostringstream sgmlpreamble;
427         string const basename = OnlyPath(fname);
428
429         FileMap::const_iterator end = IncludedFiles.end();
430         for (FileMap::const_iterator fi = IncludedFiles.begin();
431              fi != end; ++fi)
432                 sgmlpreamble << "\n<!ENTITY " << fi->first
433                              << (IsSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
434                              << MakeRelPath(fi->second, basename) << "\">";
435
436         return STRCONV(sgmlpreamble.str());
437 }
438
439
440 void LaTeXFeatures::showStruct() const {
441         lyxerr << "LyX needs the following commands when LaTeXing:"
442                << "\n***** Packages:" << getPackages()
443                << "\n***** Macros:" << getMacros()
444                << "\n***** Textclass stuff:" << getTClassPreamble()
445                << "\n***** done." << endl;
446 }
447
448
449 BufferParams const & LaTeXFeatures::bufferParams() const
450 {
451         return params;
452 }
453
454
455 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
456 {
457         FloatList const & floats = params.getLyXTextClass().floats();
458
459         // Here we will output the code to create the needed float styles.
460         // We will try to do this as minimal as possible.
461         // \floatstyle{ruled}
462         // \newfloat{algorithm}{htbp}{loa}
463         // \floatname{algorithm}{Algorithm}
464         UsedFloats::const_iterator cit = usedFloats.begin();
465         UsedFloats::const_iterator end = usedFloats.end();
466         // ostringstream floats;
467         for (; cit != end; ++cit) {
468                 Floating const & fl = floats.getType((*cit));
469
470                 // For builtin floats we do nothing.
471                 if (fl.builtin()) continue;
472
473                 // We have to special case "table" and "figure"
474                 if (fl.type() == "tabular" || fl.type() == "figure") {
475                         // Output code to modify "table" or "figure"
476                         // but only if builtin == false
477                         // and that have to be true at this point in the
478                         // function.
479                         string const type = fl.type();
480                         string const placement = fl.placement();
481                         string const style = fl.style();
482                         if (!style.empty()) {
483                                 os << "\\floatstyle{" << style << "}\n"
484                                    << "\\restylefloat{" << type << "}\n";
485                         }
486                         if (!placement.empty()) {
487                                 os << "\\floatplacement{" << type << "}{"
488                                    << placement << "}\n";
489                         }
490                 } else {
491                         // The other non builtin floats.
492
493                         string const type = fl.type();
494                         string const placement = fl.placement();
495                         string const ext = fl.ext();
496                         string const within = fl.within();
497                         string const style = fl.style();
498                         string const name = fl.name();
499                         os << "\\floatstyle{" << style << "}\n"
500                            << "\\newfloat{" << type << "}{" << placement
501                            << "}{" << ext << '}';
502                         if (!within.empty())
503                                 os << '[' << within << ']';
504                         os << '\n'
505                            << "\\floatname{" << type << "}{"
506                            << name << "}\n";
507
508                         // What missing here is to code to minimalize the code
509                         // output so that the same floatstyle will not be
510                         // used several times, when the same style is still in
511                         // effect. (Lgb)
512                 }
513         }
514 }