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