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