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