]> git.lyx.org Git - lyx.git/blob - src/format.C
Fix bug 2195: Slowness in rendering inside insets, especially on the Mac
[lyx.git] / src / format.C
1 /**
2  * \file format.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Dekel Tsur
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "format.h"
14 #include "buffer.h"
15 #include "bufferparams.h"
16 #include "lyxrc.h"
17 #include "debug.h"
18 #include "gettext.h"
19 #include "lyxsocket.h"
20
21 #include "frontends/Alert.h" //to be removed?
22
23 #include "support/filetools.h"
24 #include "support/path.h"
25 #include "support/systemcall.h"
26
27 using lyx::support::bformat;
28 using lyx::support::compare_ascii_no_case;
29 using lyx::support::contains;
30 using lyx::support::LibScriptSearch;
31 using lyx::support::MakeDisplayPath;
32 using lyx::support::OnlyFilename;
33 using lyx::support::OnlyPath;
34 using lyx::support::Path;
35 using lyx::support::QuoteName;
36 using lyx::support::subst;
37 using lyx::support::Systemcall;
38
39 using std::string;
40 using std::distance;
41
42 extern LyXServerSocket * lyxsocket;
43
44 namespace {
45
46 string const token_from("$$i");
47 string const token_path("$$p");
48 string const token_socket("$$a");
49
50
51 class FormatNamesEqual : public std::unary_function<Format, bool> {
52 public:
53         FormatNamesEqual(string const & name)
54                 : name_(name) {}
55         bool operator()(Format const & f) const
56         {
57                 return f.name() == name_;
58         }
59 private:
60         string name_;
61 };
62
63
64 class FormatExtensionsEqual : public std::unary_function<Format, bool> {
65 public:
66         FormatExtensionsEqual(string const & extension)
67                 : extension_(extension) {}
68         bool operator()(Format const & f) const
69         {
70                 return f.extension() == extension_;
71         }
72 private:
73         string extension_;
74 };
75
76 } //namespace anon
77
78 bool operator<(Format const & a, Format const & b)
79 {
80         // use the compare_ascii_no_case instead of compare_no_case,
81         // because in turkish, 'i' is not the lowercase version of 'I',
82         // and thus turkish locale breaks parsing of tags.
83
84         return compare_ascii_no_case(a.prettyname(), b.prettyname()) < 0;
85 }
86
87 Format::Format(string const & n, string const & e, string const & p,
88                string const & s, string const & v, string const & ed)
89         : name_(n), extension_(e), prettyname_(p), shortcut_(s), viewer_(v), editor_(ed)
90 {}
91
92
93 bool Format::dummy() const
94 {
95         return extension().empty();
96 }
97
98
99 bool Format::isChildFormat() const
100 {
101         if (name_.empty())
102                 return false;
103         return isdigit(name_[name_.length() - 1]);
104 }
105
106
107 string const Format::parentFormat() const
108 {
109         return name_.substr(0, name_.length() - 1);
110 }
111
112
113 // This method should return a reference, and throw an exception
114 // if the format named name cannot be found (Lgb)
115 Format const * Formats::getFormat(string const & name) const
116 {
117         FormatList::const_iterator cit =
118                 find_if(formatlist.begin(), formatlist.end(),
119                         FormatNamesEqual(name));
120         if (cit != formatlist.end())
121                 return &(*cit);
122         else
123                 return 0;
124 }
125
126
127 string Formats::getFormatFromFile(string const & filename) const
128 {
129         if (filename.empty())
130                 return string();
131
132         string const format = lyx::support::getFormatFromContents(filename);
133         if (!format.empty())
134                 return format;
135
136         // try to find a format from the file extension.
137         string const ext(lyx::support::GetExtension(filename));
138         if (!ext.empty()) {
139                 // this is ambigous if two formats have the same extension,
140                 // but better than nothing
141                 Formats::const_iterator cit =
142                         find_if(formatlist.begin(), formatlist.end(),
143                                 FormatExtensionsEqual(ext));
144                 if (cit != formats.end()) {
145                         lyxerr[Debug::GRAPHICS]
146                                 << "\twill guess format from file extension: "
147                                 << ext << " -> " << cit->name() << std::endl;
148                         return cit->name();
149                 }
150         }
151         return string();
152 }
153
154
155 int Formats::getNumber(string const & name) const
156 {
157         FormatList::const_iterator cit =
158                 find_if(formatlist.begin(), formatlist.end(),
159                         FormatNamesEqual(name));
160         if (cit != formatlist.end())
161                 return distance(formatlist.begin(), cit);
162         else
163                 return -1;
164 }
165
166
167 void Formats::add(string const & name)
168 {
169         if (!getFormat(name))
170                 add(name, name, name, string(), string(), string());
171 }
172
173
174 void Formats::add(string const & name, string const & extension,
175                   string const & prettyname, string const & shortcut,
176                   string const & viewer, string const & editor)
177 {
178         FormatList::iterator it =
179                 find_if(formatlist.begin(), formatlist.end(),
180                         FormatNamesEqual(name));
181         if (it == formatlist.end())
182                 formatlist.push_back(Format(name, extension, prettyname,
183                                             shortcut, viewer, editor));
184         else
185                 *it = Format(name, extension, prettyname, shortcut, viewer, editor);
186 }
187
188
189 void Formats::erase(string const & name)
190 {
191         FormatList::iterator it =
192                 find_if(formatlist.begin(), formatlist.end(),
193                         FormatNamesEqual(name));
194         if (it != formatlist.end())
195                 formatlist.erase(it);
196 }
197
198
199 void Formats::sort()
200 {
201         std::sort(formatlist.begin(), formatlist.end());
202 }
203
204
205 void Formats::setViewer(string const & name, string const & command)
206 {
207         add(name);
208         FormatList::iterator it =
209                 find_if(formatlist.begin(), formatlist.end(),
210                         FormatNamesEqual(name));
211         if (it != formatlist.end())
212                 it->setViewer(command);
213 }
214
215
216 bool Formats::view(Buffer const & buffer, string const & filename,
217                    string const & format_name) const
218 {
219         if (filename.empty())
220                 return false;
221
222         Format const * format = getFormat(format_name);
223         if (format && format->viewer().empty() &&
224             format->isChildFormat())
225                 format = getFormat(format->parentFormat());
226         if (!format || format->viewer().empty()) {
227 // I believe this is the wrong place to show alerts, it should be done by
228 // the caller (this should be "utility" code)
229                 Alert::error(_("Cannot view file"),
230                         bformat(_("No information for viewing %1$s"),
231                                 prettyName(format_name)));
232                 return false;
233         }
234
235         string command = LibScriptSearch(format->viewer());
236
237         if (format_name == "dvi" &&
238             !lyxrc.view_dvi_paper_option.empty()) {
239                 command += ' ' + lyxrc.view_dvi_paper_option;
240                 string paper_size = buffer.params().paperSizeName();
241                 if (paper_size == "letter")
242                         paper_size = "us";
243                 command += ' ' + paper_size;
244                 if (buffer.params().orientation == ORIENTATION_LANDSCAPE)
245                         command += 'r';
246         }
247
248         if (!contains(command, token_from))
249                 command += ' ' + token_from;
250
251         command = subst(command, token_from,
252                         QuoteName(OnlyFilename(filename)));
253         command = subst(command, token_path, QuoteName(OnlyPath(filename)));
254         command = subst(command, token_socket, QuoteName(lyxsocket->address()));
255         lyxerr[Debug::FILES] << "Executing command: " << command << std::endl;
256         buffer.message(_("Executing command: ") + command);
257
258         Path p(OnlyPath(filename));
259         Systemcall one;
260         int const res = one.startscript(Systemcall::DontWait, command);
261
262         if (res) {
263                 Alert::error(_("Cannot view file"),
264                              bformat(_("An error occurred whilst running %1$s"),
265                                MakeDisplayPath(command, 50)));
266                 return false;
267         }
268         return true;
269 }
270
271
272 bool Formats::edit(Buffer const & buffer, string const & filename,
273                          string const & format_name) const
274 {
275         if (filename.empty())
276                 return false;
277
278         Format const * format = getFormat(format_name);
279         if (format && format->editor().empty() &&
280             format->isChildFormat())
281                 format = getFormat(format->parentFormat());
282         if (!format || format->editor().empty()) {
283 // I believe this is the wrong place to show alerts, it should be done by
284 // the caller (this should be "utility" code)
285                 Alert::error(_("Cannot edit file"),
286                         bformat(_("No information for editing %1$s"),
287                                 prettyName(format_name)));
288                 return false;
289         }
290
291         string command = format->editor();
292
293         if (!contains(command, token_from))
294                 command += ' ' + token_from;
295
296         command = subst(command, token_from,
297                         QuoteName(OnlyFilename(filename)));
298         command = subst(command, token_path, QuoteName(OnlyPath(filename)));
299         command = subst(command, token_socket, QuoteName(lyxsocket->address()));
300         lyxerr[Debug::FILES] << "Executing command: " << command << std::endl;
301         buffer.message(_("Executing command: ") + command);
302
303         Path p(OnlyPath(filename));
304         Systemcall one;
305         int const res = one.startscript(Systemcall::DontWait, command);
306
307         if (res) {
308                 Alert::error(_("Cannot edit file"),
309                              bformat(_("An error occurred whilst running %1$s"),
310                                MakeDisplayPath(command, 50)));
311                 return false;
312         }
313         return true;
314 }
315
316
317 string const Formats::prettyName(string const & name) const
318 {
319         Format const * format = getFormat(name);
320         if (format)
321                 return format->prettyname();
322         else
323                 return name;
324 }
325
326
327 string const Formats::extension(string const & name) const
328 {
329         Format const * format = getFormat(name);
330         if (format)
331                 return format->extension();
332         else
333                 return name;
334 }
335
336
337
338
339 Formats formats;
340
341 Formats system_formats;