]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.C
More unicode fixes for docbook.
[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         return packages.str();
387 }
388
389
390 string const LaTeXFeatures::getMacros() const
391 {
392         ostringstream macros;
393
394         if (!preamble_snippets_.empty())
395                 macros << '\n';
396         FeaturesList::const_iterator pit  = preamble_snippets_.begin();
397         FeaturesList::const_iterator pend = preamble_snippets_.end();
398         for (; pit != pend; ++pit) {
399                 macros << *pit << '\n';
400         }
401
402         if (isRequired("LyX"))
403                 macros << lyx_def << '\n';
404
405         if (isRequired("lyxline"))
406                 macros << lyxline_def << '\n';
407
408         if (isRequired("noun"))
409                 macros << noun_def << '\n';
410
411         if (isRequired("lyxarrow"))
412                 macros << lyxarrow_def << '\n';
413
414         // quotes.
415         if (isRequired("quotesinglbase"))
416                 macros << quotesinglbase_def << '\n';
417         if (isRequired("quotedblbase"))
418                 macros << quotedblbase_def << '\n';
419         if (isRequired("guilsinglleft"))
420                 macros << guilsinglleft_def << '\n';
421         if (isRequired("guilsinglright"))
422                 macros << guilsinglright_def << '\n';
423         if (isRequired("guillemotleft"))
424                 macros << guillemotleft_def << '\n';
425         if (isRequired("guillemotright"))
426                 macros << guillemotright_def << '\n';
427
428         // Math mode
429         if (isRequired("boldsymbol") && !isRequired("amsmath"))
430                 macros << boldsymbol_def << '\n';
431         if (isRequired("binom") && !isRequired("amsmath"))
432                 macros << binom_def << '\n';
433         if (isRequired("mathcircumflex"))
434                 macros << mathcircumflex_def << '\n';
435
436         // other
437         if (isRequired("ParagraphLeftIndent"))
438                 macros << paragraphleftindent_def;
439         if (isRequired("NeedLyXFootnoteCode"))
440                 macros << floatingfootnote_def;
441
442         // some problems with tex->html converters
443         if (isRequired("NeedTabularnewline"))
444                 macros << tabularnewline_def;
445
446         // greyedout environment (note inset)
447         if (isRequired("lyxgreyedout"))
448                 macros << lyxgreyedout_def;
449
450         if (isRequired("lyxdot"))
451                 macros << lyxdot_def << '\n';
452
453         // floats
454         getFloatDefinitions(macros);
455
456         return macros.str();
457 }
458
459
460 string const LaTeXFeatures::getBabelOptions() const
461 {
462         ostringstream tmp;
463
464         LanguageList::const_iterator it  = UsedLanguages_.begin();
465         LanguageList::const_iterator end =  UsedLanguages_.end();
466         for (; it != end; ++it)
467                 if (!(*it)->latex_options().empty())
468                         tmp << (*it)->latex_options() << '\n';
469         if (!params_.language->latex_options().empty())
470                 tmp << params_.language->latex_options() << '\n';
471
472         return tmp.str();
473 }
474
475
476 string const LaTeXFeatures::getTClassPreamble() const
477 {
478         // the text class specific preamble
479         LyXTextClass const & tclass = params_.getLyXTextClass();
480         ostringstream tcpreamble;
481
482         tcpreamble << tclass.preamble();
483
484         list<string>::const_iterator cit = usedLayouts_.begin();
485         list<string>::const_iterator end = usedLayouts_.end();
486         for (; cit != end; ++cit) {
487                 tcpreamble << tclass[*cit]->preamble();
488         }
489
490         CharStyles::iterator cs = tclass.charstyles().begin();
491         CharStyles::iterator csend = tclass.charstyles().end();
492         for (; cs != csend; ++cs) {
493                 if (isRequired(cs->name))
494                         tcpreamble << cs->preamble;
495         }
496
497         return tcpreamble.str();
498 }
499
500
501 docstring const LaTeXFeatures::getLyXSGMLEntities() const
502 {
503         // Definition of entities used in the document that are LyX related.
504         odocstringstream entities;
505
506         if (isRequired("lyxarrow")) {
507                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
508         }
509
510         return entities.str();
511 }
512
513
514 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
515 {
516         odocstringstream sgmlpreamble;
517         string const basename = onlyPath(fname);
518
519         FileMap::const_iterator end = IncludedFiles_.end();
520         for (FileMap::const_iterator fi = IncludedFiles_.begin();
521              fi != end; ++fi)
522                 sgmlpreamble << "\n<!ENTITY " << fi->first
523                              << (isSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
524                              << from_ascii(makeRelPath(fi->second, basename)) << "\">";
525
526         return sgmlpreamble.str();
527 }
528
529
530 void LaTeXFeatures::showStruct() const {
531         lyxerr << "LyX needs the following commands when LaTeXing:"
532                << "\n***** Packages:" << getPackages()
533                << "\n***** Macros:" << getMacros()
534                << "\n***** Textclass stuff:" << getTClassPreamble()
535                << "\n***** done." << endl;
536 }
537
538
539 Buffer const & LaTeXFeatures::buffer() const
540 {
541         return *buffer_;
542 }
543
544
545 void LaTeXFeatures::setBuffer(Buffer const & buffer)
546 {
547         buffer_ = &buffer;
548 }
549
550
551 BufferParams const & LaTeXFeatures::bufferParams() const
552 {
553         return params_;
554 }
555
556
557 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
558 {
559         FloatList const & floats = params_.getLyXTextClass().floats();
560
561         // Here we will output the code to create the needed float styles.
562         // We will try to do this as minimal as possible.
563         // \floatstyle{ruled}
564         // \newfloat{algorithm}{htbp}{loa}
565         // \floatname{algorithm}{Algorithm}
566         UsedFloats::const_iterator cit = usedFloats_.begin();
567         UsedFloats::const_iterator end = usedFloats_.end();
568         // ostringstream floats;
569         for (; cit != end; ++cit) {
570                 Floating const & fl = floats.getType((*cit));
571
572                 // For builtin floats we do nothing.
573                 if (fl.builtin()) continue;
574
575                 // We have to special case "table" and "figure"
576                 if (fl.type() == "tabular" || fl.type() == "figure") {
577                         // Output code to modify "table" or "figure"
578                         // but only if builtin == false
579                         // and that have to be true at this point in the
580                         // function.
581                         string const type = fl.type();
582                         string const placement = fl.placement();
583                         string const style = fl.style();
584                         if (!style.empty()) {
585                                 os << "\\floatstyle{" << style << "}\n"
586                                    << "\\restylefloat{" << type << "}\n";
587                         }
588                         if (!placement.empty()) {
589                                 os << "\\floatplacement{" << type << "}{"
590                                    << placement << "}\n";
591                         }
592                 } else {
593                         // The other non builtin floats.
594
595                         string const type = fl.type();
596                         string const placement = fl.placement();
597                         string const ext = fl.ext();
598                         string const within = fl.within();
599                         string const style = fl.style();
600                         string const name = fl.name();
601                         os << "\\floatstyle{" << style << "}\n"
602                            << "\\newfloat{" << type << "}{" << placement
603                            << "}{" << ext << '}';
604                         if (!within.empty())
605                                 os << '[' << within << ']';
606                         os << '\n'
607                            << "\\floatname{" << type << "}{"
608                            << name << "}\n";
609
610                         // What missing here is to code to minimalize the code
611                         // output so that the same floatstyle will not be
612                         // used several times, when the same style is still in
613                         // effect. (Lgb)
614                 }
615         }
616 }
617
618
619 } // namespace lyx