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