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