]> git.lyx.org Git - lyx.git/blob - src/LaTeXFonts.cpp
GuiTabular.cpp: don't hardcode decimal align combobox item
[lyx.git] / src / LaTeXFonts.cpp
1 /**
2  * \file LaTeXFonts.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Jürgen Spitzmüller
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "LaTeXFonts.h"
14
15 #include "LaTeXFeatures.h"
16 #include "Lexer.h"
17
18 #include "frontends/alert.h"
19
20 #include "support/convert.h"
21 #include "support/debug.h"
22 #include "support/FileName.h"
23 #include "support/filetools.h"
24 #include "support/gettext.h"
25 #include "support/lstrings.h"
26
27
28 using namespace std;
29 using namespace lyx::support;
30
31
32 namespace lyx {
33
34 LaTeXFonts latexfonts;
35
36
37 bool LaTeXFont::available(bool ot1) const
38 {
39         return ot1 ? available_ot1_ : available_;
40 }
41
42
43 bool LaTeXFont::providesOSF(bool ot1) const
44 {
45         if (!osfpackage_.empty())
46                 return LaTeXFeatures::isAvailable(to_ascii(osfpackage_));
47
48         if (ot1 && !ot1package_.empty() && ot1package_ != "none")
49                 return false;
50
51         if (!package_.empty() && !LaTeXFeatures::isAvailable(to_ascii(package_)))
52                 return false;
53
54         return (!osfoption_.empty() || !osfscoption_.empty());
55 }
56
57
58 bool LaTeXFont::providesSC(bool ot1) const
59 {
60         if (ot1 && !ot1package_.empty() && ot1package_ != "none")
61                 return false;
62
63         if (!package_.empty() && !LaTeXFeatures::isAvailable(to_ascii(package_)))
64                 return false;
65
66         return (!scoption_.empty() || !osfscoption_.empty());
67 }
68
69
70 bool LaTeXFont::providesScale(bool ot1) const
71 {
72         if (ot1 && !ot1package_.empty() && ot1package_ != "none")
73                 return false;
74
75         if (!package_.empty() && !LaTeXFeatures::isAvailable(to_ascii(package_)))
76                 return false;
77
78         return (!scaleoption_.empty());
79 }
80
81
82 string const LaTeXFont::getAvailablePackage(bool dryrun, bool ot1, bool complete, bool & alt)
83 {
84         if (ot1 && !ot1package_.empty()) {
85                 if (ot1package_ != "none"
86                     && (LaTeXFeatures::isAvailable(to_ascii(ot1package_)) || dryrun))
87                         return to_ascii(ot1package_);
88                 if (!dryrun && ot1package_ != "none")
89                         frontend::Alert::warning(_("Font not available"),
90                                         bformat(_("The LaTeX package `%1$s' needed for the font `%2$s'\n"
91                                                   "is not available on your system. LyX will fall back to the default font."),
92                                                 ot1package_, guiname_), true);
93                 return string();
94         }
95         if (family_ == "rm" && complete && !completepackage_.empty()) {
96                 if (LaTeXFeatures::isAvailable(to_ascii(completepackage_)) || dryrun)
97                         return to_ascii(completepackage_);
98         }
99         if (!package_.empty()) {
100                 if (!requires_.empty() && LaTeXFeatures::isAvailable(to_ascii(requires_)))
101                         return to_ascii(package_);
102                 if (LaTeXFeatures::isAvailable(to_ascii(package_)))
103                         return to_ascii(package_);
104                 else if (!altpackages_.empty()) {
105                         for (size_t i = 0; i < altpackages_.size(); ++i) {
106                                 if (LaTeXFeatures::isAvailable(to_ascii(altpackages_[i]))) {
107                                         alt = true;
108                                         return to_ascii(altpackages_[i]);
109                                 }
110                         }
111                 }
112                 // Output unavailable packages in source preview
113                 if (dryrun)
114                         return to_ascii(package_);
115                 docstring const req = requires_.empty() ? package_ : requires_;
116                         frontend::Alert::warning(_("Font not available"),
117                                         bformat(_("The LaTeX package `%1$s' needed for the font `%2$s'\n"
118                                                   "is not available on your system. LyX will fall back to the default font."),
119                                                 req, guiname_), true);
120         }
121         return string();
122 }
123
124
125 string const LaTeXFont::getPackageOptions(bool ot1, bool sc, bool osf, int scale)
126 {
127         if (ot1 && !ot1package_.empty())
128                 return string();
129
130         ostringstream os;
131         if (!packageoption_.empty())
132                 os << to_ascii(packageoption_);
133         if (sc && osf && providesOSF() && providesSC()) {
134                 if (!os.str().empty())
135                         os << ',';
136                 if (!osfscoption_.empty())
137                         os << to_ascii(osfscoption_);
138                 else
139                         os << to_ascii(osfoption_) << ',' << to_ascii(scoption_);
140         } else if (osf && providesOSF()) {
141                 if (!os.str().empty())
142                         os << ',';
143                 os << to_ascii(osfoption_);
144         } else if (sc && providesSC()) {
145                 if (!os.str().empty())
146                         os << ',';
147                 os << to_ascii(scoption_);
148         }
149         if (scale != 100 && !scaleoption_.empty()) {
150                 if (!os.str().empty())
151                         os << ',';
152                 os << subst(to_ascii(scaleoption_), "$$val",
153                             convert<std::string>(float(scale) / 100));
154         }
155         return os.str();
156 }
157
158
159 string const LaTeXFont::getLaTeXCode(bool dryrun, bool ot1, bool complete, bool sc,
160                                      bool osf, int const & scale)
161 {
162         ostringstream os;
163
164         if (switchdefault_) {
165                 if (family_.empty()) {
166                         LYXERR0("Error: Font `" << name_ << "' has no family defined!");
167                         return string();
168                 }
169                 if (available(ot1) || dryrun)
170                         os << "\\renewcommand{\\" << to_ascii(family_) << "default}{"
171                         << to_ascii(name_) << "}\n";
172                 else
173                         frontend::Alert::warning(_("Font not available"),
174                                         bformat(_("The LaTeX package `%1$s' needed for the font `%2$s'\n"
175                                                   "is not available on your system. LyX will fall back to the default font."),
176                                                 requires_, guiname_), true);
177         } else {
178                 bool alt = false;
179                 string const package =
180                         getAvailablePackage(dryrun, ot1, complete, alt);
181                 // Package options are not for alternative packages
182                 string const packageopts = alt ? string() : getPackageOptions(ot1, sc, osf, scale);
183                 if (packageopts.empty() && !package.empty())
184                         os << "\\usepackage{" << package << "}\n";
185                 else if (!packageopts.empty() && !package.empty())
186                         os << "\\usepackage[" << packageopts << "]{" << package << "}\n";
187         }
188         if (osf && providesOSF(ot1) && !osfpackage_.empty())
189                 os << "\\usepackage{" << to_ascii(osfpackage_) << "}\n";
190
191         return os.str();
192 }
193
194
195 bool LaTeXFont::readFont(Lexer & lex)
196 {
197         enum LaTeXFontTags {
198                 LF_ALT_PACKAGES = 1,
199                 LF_COMPLETE_PACKAGE,
200                 LF_END,
201                 LF_FAMILY,
202                 LF_GUINAME,
203                 LF_OSFOPTION,
204                 LF_OSFPACKAGE,
205                 LF_OSFSCOPTION,
206                 LF_OT1_PACKAGE,
207                 LF_PACKAGE,
208                 LF_PACKAGEOPTION,
209                 LF_REQUIRES,
210                 LF_SCALEOPTION,
211                 LF_SCOPTION,
212                 LF_SWITCHDEFAULT
213         };
214
215         // Keep these sorted alphabetically!
216         LexerKeyword latexFontTags[] = {
217                 { "altpackages",          LF_ALT_PACKAGES },
218                 { "completepackage",      LF_COMPLETE_PACKAGE },
219                 { "endfont",              LF_END },
220                 { "family",               LF_FAMILY },
221                 { "guiname",              LF_GUINAME },
222                 { "osfoption",            LF_OSFOPTION },
223                 { "osfpackage",           LF_OSFPACKAGE },
224                 { "osfscoption",          LF_OSFSCOPTION },
225                 { "ot1package",           LF_OT1_PACKAGE },
226                 { "package",              LF_PACKAGE },
227                 { "packageoption",        LF_PACKAGEOPTION },
228                 { "requires",             LF_REQUIRES },
229                 { "scaleoption",          LF_SCALEOPTION },
230                 { "scoption",             LF_SCOPTION },
231                 { "switchdefault",        LF_SWITCHDEFAULT }
232         };
233
234         bool error = false;
235         bool finished = false;
236         lex.pushTable(latexFontTags);
237         // parse style section
238         while (!finished && lex.isOK() && !error) {
239                 int le = lex.lex();
240                 // See comment in LyXRC.cpp.
241                 switch (le) {
242                 case Lexer::LEX_FEOF:
243                         continue;
244
245                 case Lexer::LEX_UNDEF: // parse error
246                         lex.printError("Unknown LaTeXFont tag `$$Token'");
247                         error = true;
248                         continue;
249
250                 default: 
251                         break;
252                 }
253                 switch (static_cast<LaTeXFontTags>(le)) {
254                 case LF_END: // end of structure
255                         finished = true;
256                         break;
257                 case LF_ALT_PACKAGES: {
258                         docstring altp;
259                         lex >> altp;
260                         altpackages_ = getVectorFromString(altp);
261                         break;
262                 }
263                 case LF_COMPLETE_PACKAGE:
264                         lex >> completepackage_;
265                         break;
266                 case LF_FAMILY:
267                         lex >> family_;
268                         break;
269                 case LF_GUINAME:
270                         lex >> guiname_;
271                         break;
272                 case LF_OSFOPTION:
273                         lex >> osfoption_;
274                         break;
275                 case LF_OSFPACKAGE:
276                         lex >> osfpackage_;
277                         break;
278                 case LF_OSFSCOPTION:
279                         lex >> osfscoption_;
280                         break;
281                 case LF_OT1_PACKAGE:
282                         lex >> ot1package_;
283                         break;
284                 case LF_PACKAGE:
285                         lex >> package_;
286                         break;
287                 case LF_PACKAGEOPTION:
288                         lex >> packageoption_;
289                         break;
290                 case LF_REQUIRES:
291                         lex >> requires_;
292                         break;
293                 case LF_SCALEOPTION:
294                         lex >> scaleoption_;
295                         break;
296                 case LF_SCOPTION:
297                         lex >> scoption_;
298                         break;
299                 case LF_SWITCHDEFAULT:
300                         lex >> switchdefault_;
301                         break;
302                 }
303         }
304         if (!finished) {
305                 lex.printError("No End tag found for LaTeXFont tag `$$Token'");
306                 return false;
307         }
308         lex.popTable();
309         return finished && !error;
310 }
311
312
313 bool LaTeXFont::read(Lexer & lex)
314 {
315         switchdefault_ = 0;
316
317         if (!lex.next()) {
318                 lex.printError("No name given for LaTeX font: `$$Token'.");
319                 return false;
320         }
321
322         name_ = lex.getDocString();
323         LYXERR(Debug::INFO, "Reading LaTeX font " << name_);
324         if (!readFont(lex)) {
325                 LYXERR0("Error parsing LaTeX font `" << name_ << '\'');
326                 return false;
327         }
328
329         bool available = true;
330         if (!requires_.empty())
331                 available = LaTeXFeatures::isAvailable(to_ascii(requires_));
332         else if (!package_.empty()) {
333                 available = LaTeXFeatures::isAvailable(to_ascii(package_));
334                 if (!available && !altpackages_.empty()) {
335                         for (size_t i = 0; i < altpackages_.size(); ++i) {
336                                 available = LaTeXFeatures::isAvailable(to_ascii(altpackages_[i]));
337                                 if (available)
338                                         break;
339                         }
340                 }
341         }
342         available_ = available;
343
344         if (!ot1package_.empty() && ot1package_ != "none")
345                 available_ot1_ = LaTeXFeatures::isAvailable(to_ascii(ot1package_));
346         else
347                 available_ot1_ = available;
348
349         return true;
350 }
351
352
353 void LaTeXFonts::readLaTeXFonts()
354 {
355         // Read latexfonts file
356         FileName filename = libFileSearch(string(), "latexfonts");
357         if (filename.empty()) {
358                 LYXERR0("Error: latexfonts file not found!");
359                 return;
360         }
361         Lexer lex;
362         lex.setFile(filename);
363         lex.setContext("LaTeXFeatures::readLaTeXFonts");
364         while (lex.isOK()) {
365                 int le = lex.lex();
366                 switch (le) {
367                 case Lexer::LEX_FEOF:
368                         continue;
369
370                 default:
371                         break;
372                 }
373                 if (lex.getString() != "Font") {
374                         lex.printError("Unknown LaTeXFont tag `$$Token'");
375                         continue;
376                 }
377                 LaTeXFont f;
378                 f.read(lex);
379                 if (!lex)
380                         break;
381
382                 texfontmap_[f.name()] = f;
383         }
384 }
385
386
387 LaTeXFonts::TexFontMap LaTeXFonts::getLaTeXFonts()
388 {
389         if (texfontmap_.empty())
390                 readLaTeXFonts();
391         return texfontmap_;
392 }
393
394
395 LaTeXFont LaTeXFonts::getLaTeXFont(docstring const & name)
396 {
397         if (name == "default")
398                 return LaTeXFont();
399         if (texfontmap_.empty())
400                 readLaTeXFonts();
401         if (texfontmap_.find(name) == texfontmap_.end()) {
402                 LYXERR0("LaTeXFonts::getLaTeXFont: font '" << name << "' not found!");
403                 return LaTeXFont();
404         }
405         return texfontmap_[name];
406 }
407
408
409 } // namespace lyx