1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich
7 * Copyright 1995-2000 The LyX Team.
9 * ====================================================== */
14 #pragma implementation
18 #include <algorithm> // sort()
20 #include "converter.h"
22 #include "support/syscall.h"
23 #include "support/path.h"
25 #include "bufferview_funcs.h"
28 #include "minibuffer.h"
29 #include "lyx_gui_misc.h"
30 #include "lyx_cb.h" // ShowMessage()
39 //////////////////////////////////////////////////////////////////////////////
41 map<string, Format> Formats::formats;
42 vector<Command> Converter::commands;
45 string add_options(string const & command, string const & options)
48 string tail = split(command, head, ' ');
49 return head + ' ' + options + ' ' + tail;
52 //////////////////////////////////////////////////////////////////////////////
54 Format::Format(string const & n)
55 : name(n), in_degree(0)
59 char const * prettyname;
64 { "ps", "PostScript" },
72 for (int i = 0; items[i].name != 0; ++i)
73 if (items[i].name == n) {
74 prettyname = items[i].prettyname;
80 void Formats::Add(string const & name)
82 if (formats.find(name) == formats.end())
83 formats[name] = Format(name);
87 void Formats::SetViewer(string const & name, string const & command)
90 string command2 = subst(command, "$$FName", "'$$FName'");
91 if (!contains(command,"$$FName"))
92 command2 += " '$$FName'";
95 GetFormat(name)->viewer = command2;
99 bool Formats::View(Buffer * buffer, string const & filename)
101 string extension = GetExtension(filename);
102 Format * format = GetFormat(extension);
103 if (!format || format->viewer.empty()) {
104 WriteAlert(_("Can not view file"),
105 _("No information for viewing ")
106 + Formats::PrettyName(extension));
110 string command = format->viewer;
112 if (extension == "dvi" &&
113 !lyxrc.view_dvi_paper_option.empty()) {
114 string options = lyxrc.view_dvi_paper_option;
115 options += " " + Converter::dvi_papersize(buffer);
116 if (buffer->params.orientation
117 == BufferParams::ORIENTATION_LANDSCAPE)
119 command = add_options(command, options);
122 string command2 = subst(command, "$$FName", OnlyFilename(filename));
123 lyxerr << "Executing command: " << command2 << endl;
124 ShowMessage(buffer, _("Executing command:"), command2);
126 command = subst(command, "$$FName", filename);
128 int res = one.startscript(Systemcalls::SystemDontWait, command);
131 WriteAlert(_("Can not view file"),
132 _("Error while executing"),
133 command.substr(0, 50));
140 Format * Formats::GetFormat(string const & name)
142 map<string, Format>::iterator it = formats.find(name);
143 if (it != formats.end())
144 return &(*it).second;
150 string const Formats::PrettyName(string const & name)
153 Converter::SplitFormat(name, format);
154 Format * f = GetFormat(format);
156 return f->prettyname;
162 //////////////////////////////////////////////////////////////////////////////
164 void Converter::Add(string const & from, string const & to,
165 string const & command, string const & flags)
167 if (command == "none")
170 bool original_dir = flags == "origdir";
172 subst(command, "$$FName", "'$$FName'");
173 command2 = subst(command2, "$$BaseName", "'$$BaseName'");
174 command2 = subst(command2, "$$OutName", "'$$OutName'");
176 for (vector<Command>::iterator it = commands.begin();
177 it != commands.end(); ++it)
178 if ((*it).from == from && (*it).to == to) {
179 *it = Command(from, to, command2, original_dir);
182 commands.push_back(Command(from, to, command2, original_dir));
185 ++Formats::GetFormat(to)->in_degree;
189 vector< pair<string,string> > const
190 Converter::GetReachable(string const & from, bool only_viewable)
192 vector< pair<string,string> > result;
193 Format * format = Formats::GetFormat(from);
198 if (!only_viewable || !format->viewer.empty()) {
199 result.push_back(pair<string,string>(from, format->prettyname));
203 queue< vector<Command>::iterator > Q;
204 for (vector<Command>::iterator it = commands.begin();
205 it != commands.end(); ++it)
206 if ((*it).from == from) {
208 (*it).visited = true;
210 (*it).visited = false;
213 vector<Command>::iterator it = Q.front();
214 format = Formats::GetFormat((*it).to);
215 string name = format->name;
216 string prettyname = format->prettyname;
217 if (format->in_degree > 1) {
218 name += ":" + (*it).from;
220 split((*it).command, tmp, ' ');
221 prettyname += _("(using ") + tmp + ")";
223 if (!only_viewable || !format->viewer.empty())
224 result.push_back(pair<string,string>(name, prettyname));
226 for (vector<Command>::iterator it2 = commands.begin();
227 it2 != commands.end(); ++it2)
228 if (!(*it2).visited && (*it).to == (*it2).from) {
230 (*it2).visited = true;
234 sort(result.begin() + sort_start, result.end());
239 bool Converter::Convert(Buffer * buffer, string const & from_file,
240 string const & to_file, string const & using_format)
242 string from_format = GetExtension(from_file);
243 string to_format = GetExtension(to_file);
244 if (from_format == to_format)
245 if (from_file != to_file)
246 return lyx::rename(from_file.c_str(), to_file.c_str());
250 queue< vector<Command>::iterator > Q;
251 for (vector<Command>::iterator it = commands.begin();
252 it != commands.end(); ++it)
253 if ((*it).from == from_format) {
255 (*it).visited = true;
256 (*it).previous = commands.end();
258 (*it).visited = false;
261 WriteAlert(_("Can not convert file"),
262 ("Unknown format ") + from_format);
267 vector<Command>::iterator it;
270 if ((*it).to == to_format &&
271 (using_format.empty() || using_format == (*it).from)) {
276 for (vector<Command>::iterator it2 = commands.begin();
277 it2 != commands.end(); ++it2)
278 if (!(*it2).visited && (*it).to == (*it2).from) {
280 (*it2).visited = true;
281 (*it2).previous = it;
286 WriteAlert(_("Can not convert file"),
287 _("No information for converting from ")
288 + Formats::PrettyName(from_format) + _(" to ")
289 + Formats::PrettyName(to_format));
293 vector< vector<Command>::iterator > S;
294 while (it != commands.end()) {
299 Path p(OnlyPath(from_file));
301 string basename = ChangeExtension(from_file, "");
302 for (vector< vector<Command>::iterator >::reverse_iterator rit =
303 S.rbegin(); rit != S.rend(); ++rit) {
305 lyxerr << "Converting from "
306 << (*it).from << " to " << (*it).to << endl;
308 if ((*it).from == "tex" &&
309 ( (*it).to == "dvi" || (*it).to == "pdf") ) {
310 lyxrc.pdf_mode = (*it).to == "pdf";
311 if (!runLaTeX(buffer, (*it).command))
314 string infile = ChangeExtension(from_file, (*it).from);
315 if (!(*it).original_dir)
316 infile = OnlyFilename(infile);
317 string outfile = ChangeExtension(infile, (*it).to);
319 string command = (*it).command;
320 command = subst(command, "$$FName", infile);
321 command = subst(command, "$$BaseName", basename);
322 command = subst(command, "$$OutName", outfile);
324 if ((*it).from == "dvi" && (*it).to == "ps")
325 command = add_options(command,
326 dvips_options(buffer));
328 lyxerr << "Calling " << command << endl;
329 ShowMessage(buffer, _("Executing command:"), command);
333 if ((*it).original_dir) {
334 Path p(buffer->filepath);
335 res = one.startscript(Systemcalls::System, command);
337 res = one.startscript(Systemcalls::System, command);
339 WriteAlert(_("Can not convert file"),
340 "Error while executing",
341 command.substr(0, 50));
347 string result_file = ChangeExtension(from_file, to_format);
348 if (result_file != to_file)
349 if ((*it).from == "tex" &&
350 ( (*it).to == "dvi" || (*it).to == "pdf") )
351 return lyx::copy(result_file.c_str(), to_file.c_str());
353 return lyx::rename(result_file.c_str(), to_file.c_str());
359 string const Converter::SplitFormat(string const & str, string & format)
361 string using_format = split(str, format, ':');
368 bool Converter::runLaTeX(Buffer * buffer, string const & command)
371 BufferView * bv = buffer->getUser();
373 if (!bv->text) return 0;
377 string name = buffer->getLatexName();
379 bv->owner()->getMiniBuffer()->Set(_("Running LaTeX..."));
381 // Remove all error insets
382 bool a = bv->removeAutoInsets();
384 // do the LaTex run(s)
386 LaTeX latex(command, name, buffer->filepath);
387 int result = latex.run(terr,
388 bv->owner()->getMiniBuffer()); // running latex
390 if ((result & LaTeX::ERRORS)) {
391 // Insert all errors as errors boxes
392 bv->insertErrors(terr);
395 // if we removed error insets before we ran LaTeX or if we inserted
396 // error insets after we ran LaTeX this must be run:
397 if (a || (result & LaTeX::ERRORS)){
400 //bv->updateScrollbar();
403 // check return value from latex.run().
404 if ((result & LaTeX::NO_LOGFILE)) {
405 WriteAlert(_("LaTeX did not work!"),
406 _("Missing log file:"), name);
407 } else if ((result & LaTeX::ERRORS)) {
408 int num_errors = latex.getNumErrors();
411 if (num_errors == 1) {
412 s = _("One error detected");
413 t = _("You should try to fix it.");
415 s = tostr(num_errors);
416 s += _(" errors detected.");
417 t = _("You should try to fix them.");
419 WriteAlert(_("There were errors during the LaTeX run."),
424 return (result & (LaTeX::NO_LOGFILE | LaTeX::ERRORS)) == 0;
429 string Converter::dvi_papersize(Buffer * buffer)
431 char real_papersize = buffer->params.papersize;
432 if (real_papersize == BufferParams::PAPER_DEFAULT)
433 real_papersize = lyxrc.default_papersize;
435 switch (real_papersize) {
436 case BufferParams::PAPER_A3PAPER:
438 case BufferParams::PAPER_A4PAPER:
440 case BufferParams::PAPER_A5PAPER:
442 case BufferParams::PAPER_B5PAPER:
444 case BufferParams::PAPER_EXECUTIVEPAPER:
446 case BufferParams::PAPER_LEGALPAPER:
448 case BufferParams::PAPER_USLETTER:
455 string Converter::dvips_options(Buffer * buffer)
458 if (buffer->params.use_geometry
459 && buffer->params.papersize2 == BufferParams::VM_PAPER_CUSTOM
460 && !lyxrc.print_paper_dimension_flag.empty()
461 && !buffer->params.paperwidth.empty()
462 && !buffer->params.paperheight.empty()) {
463 // using a custom papersize
464 result = lyxrc.print_paper_dimension_flag;
465 result += ' ' + buffer->params.paperwidth;
466 result += ',' + buffer->params.paperheight;
468 string paper_option = dvi_papersize(buffer);
469 if (paper_option != "letter" ||
470 buffer->params.orientation != BufferParams::ORIENTATION_LANDSCAPE) {
471 // dvips won't accept -t letter -t landscape. In all other
472 // cases, include the paper size explicitly.
473 result = lyxrc.print_paper_flag;
474 result += ' ' + paper_option;
477 if (buffer->params.orientation == BufferParams::ORIENTATION_LANDSCAPE)
478 result += ' ' + lyxrc.print_landscape_flag;