X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fgraphics%2FGraphicsConverter.C;h=5d08e460d56f8b9e80b52ab1d45fbc22cc2376e5;hb=f643df79a890ec4bc2eb05a3fd3d349ba3994f96;hp=ca347ade672881f212396323b483e4604541b8c6;hpb=b49f5ac419b81c6dbbc3e9d802b5a7bc9bbed71d;p=lyx.git diff --git a/src/graphics/GraphicsConverter.C b/src/graphics/GraphicsConverter.C index ca347ade67..5d08e460d5 100644 --- a/src/graphics/GraphicsConverter.C +++ b/src/graphics/GraphicsConverter.C @@ -1,9 +1,9 @@ -/* - * \file GraphicsConverter.C - * Copyright 2002 the LyX Team - * Read the file COPYING +/** + * \file GraphicsConverter.C + * Copyright 2002 the LyX Team + * Read the file COPYING * - * \author Angus Leeming + * \author Angus Leeming */ #include @@ -16,151 +16,240 @@ #include "converter.h" #include "debug.h" -#include "gettext.h" - -#include "frontends/Alert.h" #include "support/filetools.h" #include "support/forkedcall.h" -#include "support/path.h" +#include "support/lyxlib.h" + +#include +#include +#include "Lsstream.h" #include +#include // needed for pid_t -namespace { +extern string system_lyxdir; -string const move_file(string const & from_file, string const & to_file) -{ - if (from_file == to_file) - return string(); +using std::endl; - ostringstream command; - command << "fromfile=" << from_file << "\n" - << "tofile=" << to_file << "\n\n" - << "'mv' -f ${fromfile} ${tofile}\n" - << "if [ $? -ne 0 ]; then\n" - << "\t'cp' -f ${fromfile} ${tofile}\n" - << "\tif [ $? -ne 0 ]; then\n" - << "\t\texit 1\n" - << "\tfi\n" - << "\t'rm' -f ${fromfile}\n" - << "fi\n"; +namespace grfx { - return command.str().c_str(); +struct Converter::Impl : public boost::signals::trackable { + /// + Impl(string const &, string const &, string const &, string const &); + + /// + void startConversion(); + + /** This method is connected to a signal passed to the forked call + * class, passing control back here when the conversion is completed. + * Cleans-up the temporary files, emits the finishedConversion + * signal and removes the Converter from the list of all processes. + */ + void converted(string const & cmd, pid_t pid, int retval); + + /** At the end of the conversion process inform the outside world + * by emitting a signal. + */ + typedef boost::signal1 SignalType; + /// + SignalType finishedConversion; + + /// + string script_command_; + /// + string script_file_; + /// + string to_file_; + /// + bool valid_process_; + /// + bool finished_; +}; + + +bool Converter::isReachable(string const & from_format_name, + string const & to_format_name) +{ + return converters.isReachable(from_format_name, to_format_name); } -} // namespace anon - -namespace grfx { +Converter::Converter(string const & from_file, string const & to_file_base, + string const & from_format, string const & to_format) + : pimpl_(new Impl(from_file, to_file_base, from_format, to_format)) +{} + + +Converter::~Converter() +{} -GConverter & GConverter::get() + +void Converter::startConversion() const { - static GConverter singleton; - return singleton; + pimpl_->startConversion(); } - -bool GConverter::isReachable(string const & from_format_name, - string const & to_format_name) const + +boost::signals::connection Converter::connect(slot_type const & slot) const { - return converters.isReachable(from_format_name, to_format_name); + return pimpl_->finishedConversion.connect(slot); +} + + +string const & Converter::convertedFile() const +{ + static string const empty; + return pimpl_->finished_ ? pimpl_->to_file_ : empty; } +} // namespace grfx + +//------------------------------ +// Implementation details follow +//------------------------------ + +namespace { + +/** Build the conversion script, returning true if able to build it. + * The script is output to the ostringstream 'script'. + */ +bool build_script(string const & from_file, string const & to_file_base, + string const & from_format, string const & to_format, + ostringstream & script); -void GConverter::convert(string const & from_file, string const & to_file_base, - string const & from_format, string const & to_format, - SignalTypePtr on_finish) +} // namespace anon + + +namespace grfx { + +Converter::Impl::Impl(string const & from_file, string const & to_file_base, + string const & from_format, string const & to_format) + : valid_process_(false), finished_(false) { + lyxerr[Debug::GRAPHICS] << "Converter c-tor:\n" + << "\tfrom_file: " << from_file + << "\n\tto_file_base: " << to_file_base + << "\n\tfrom_format: " << from_format + << "\n\tto_format: " << to_format << endl; + // The conversion commands are stored in a stringstream ostringstream script; script << "#!/bin/sh\n"; - bool const success = build_script(from_file, to_file_base, from_format, to_format, script); - if (!success) { - lyxerr[Debug::GRAPHICS] - << "Unable to build the conversion script" << std::endl; - on_finish->emit(string()); + if (!success) return; - } - lyxerr[Debug::GRAPHICS] << "Conversion script:\n\n" - << script.str().c_str() << "\n" << std::endl; + lyxerr[Debug::GRAPHICS] << "\tConversion script:" + << "\n--------------------------------------\n" + << script.str().c_str() + << "\n--------------------------------------\n"; // Output the script to file. static int counter = 0; - string const script_file = OnlyPath(to_file_base) + "lyxconvert" + - tostr(counter++) + ".sh"; + script_file_ = OnlyPath(to_file_base) + "lyxconvert" + + tostr(counter++) + ".sh"; - std::ofstream fs(script_file.c_str()); - if (!fs.good()) { - // Unable to output the conversion script to file. - on_finish->emit(string()); + std::ofstream fs(script_file_.c_str()); + if (!fs.good()) return; - } - + fs << script.str().c_str(); fs.close(); - // Create a dummy command for ease of understanding of the + // The converted image is to be stored in this file + // We do not use ChangeExtension here because this is a + // basename, which may nevertheless contain a dot + to_file_ = to_file_base + '.' + formats.extension(to_format); + + // The command needed to run the conversion process + // We create a dummy command for ease of understanding of the // list of forked processes. // Note that 'sh ' is absolutely essential, or execvp will fail. - string const script_command = - "sh " + script_file + " " + - OnlyFilename(from_file) + " " + to_format; - - string const to_file = - ChangeExtension(to_file_base, formats.extension(to_format)); - - // Launch the conversion process. - ConvProcessPtr shared_ptr; - shared_ptr.reset(new ConvProcess(script_file, script_command, - to_file, on_finish)); - all_processes_.push_back(shared_ptr); + script_command_ = "sh " + script_file_ + " " + + OnlyFilename(from_file) + " " + to_format; + + // All is ready to go + valid_process_ = true; } -namespace { +void Converter::Impl::startConversion() +{ + if (!valid_process_) { + converted(string(), 0, 1); + return; + } -typedef boost::shared_ptr ConvProcessPtr; - -class Find_Ptr { -public: - Find_Ptr(ConvProcess * ptr) : ptr_(ptr) {} + // Initiate the conversion + Forkedcall::SignalTypePtr convert_ptr; + convert_ptr.reset(new Forkedcall::SignalType); - bool operator()(ConvProcessPtr const & ptr) - { - return ptr.get() == ptr_; - } + convert_ptr->connect( + boost::bind(&Impl::converted, this, _1, _2, _3)); -private: - ConvProcess * ptr_; -}; + Forkedcall call; + int retval = call.startscript(script_command_, convert_ptr); + if (retval > 0) { + // Unable to even start the script, so clean-up the mess! + converted(string(), 0, 1); + } +} -} // namespace anon - -void GConverter::erase(ConvProcess * process) +void Converter::Impl::converted(string const & /* cmd */, + pid_t /* pid */, int retval) { - std::list::iterator begin = all_processes_.begin(); - std::list::iterator end = all_processes_.end(); - std::list::iterator it = - std::find_if(begin, end, Find_Ptr(process)); - - if (it == end) + if (finished_) + // We're done already! return; - all_processes_.erase(it); + finished_ = true; + // Clean-up behind ourselves + lyx::unlink(script_file_); + + if (retval > 0) { + lyx::unlink(to_file_); + to_file_.erase(); + finishedConversion(false); + } else { + finishedConversion(true); + } } +} // namespace grfx + +namespace { + +string const move_file(string const & from_file, string const & to_file) +{ + if (from_file == to_file) + return string(); + + ostringstream command; + command << "fromfile=" << from_file << "\n" + << "tofile=" << to_file << "\n\n" + << "'mv' -f ${fromfile} ${tofile}\n" + << "if [ $? -ne 0 ]; then\n" + << "\t'cp' -f ${fromfile} ${tofile}\n" + << "\tif [ $? -ne 0 ]; then\n" + << "\t\texit 1\n" + << "\tfi\n" + << "\t'rm' -f ${fromfile}\n" + << "fi\n"; + + return command.str().c_str(); +} -bool GConverter::build_script(string const & from_file, - string const & to_file_base, - string const & from_format, - string const & to_format, - ostringstream & script) const +bool build_script(string const & from_file, + string const & to_file_base, + string const & from_format, + string const & to_format, + ostringstream & script) { + lyxerr[Debug::GRAPHICS] << "build_script ... "; typedef Converters::EdgePath EdgePath; string const to_file = ChangeExtension(to_file_base, @@ -168,16 +257,14 @@ bool GConverter::build_script(string const & from_file, if (from_format == to_format) { script << move_file(QuoteName(from_file), QuoteName(to_file)); + lyxerr[Debug::GRAPHICS] << "ready (from == to)" << endl; return true; } EdgePath edgepath = converters.getPath(from_format, to_format); if (edgepath.empty()) { - Alert::alert(_("Cannot convert file"), - _("No information for converting from ") - + formats.prettyName(from_format) + _(" to ") - + formats.prettyName(to_format)); + lyxerr[Debug::GRAPHICS] << "ready (edgepath.empty())" << endl; return false; } @@ -195,11 +282,13 @@ bool GConverter::build_script(string const & from_file, string const token_from("$$i"); string const token_base("$$b"); string const token_to("$$o"); + string const token_lib("$$s"); EdgePath::const_iterator it = edgepath.begin(); EdgePath::const_iterator end = edgepath.end(); + for (; it != end; ++it) { - Converter const & conv = converters.get(*it); + ::Converter const & conv = converters.get(*it); // Build the conversion command string const infile = outfile; @@ -215,11 +304,12 @@ bool GConverter::build_script(string const & from_file, command = subst(command, token_from, "${infile}"); command = subst(command, token_base, "${infile_base}"); command = subst(command, token_to, "${outfile}"); + command = subst(command, token_lib, system_lyxdir + "scripts"); // Store in the shell script script << "\n" << command << "\n\n"; - // Test that this was successful. If not, remove + // Test that this was successful. If not, remove // ${outfile} and exit the shell script script << "if [ $? -ne 0 ]; then\n" << "\t'rm' -f ${outfile}\n" @@ -248,47 +338,9 @@ bool GConverter::build_script(string const & from_file, // Move the final outfile to to_file script << move_file("${outfile}", QuoteName(to_file)); + lyxerr[Debug::GRAPHICS] << "ready!" << endl; return true; } - -ConvProcess::ConvProcess(string const & script_file, - string const & script_command, - string const & to_file, SignalTypePtr on_finish) - : script_file_(script_file), to_file_(to_file), on_finish_(on_finish) -{ - Forkedcall::SignalTypePtr convert_ptr; - convert_ptr.reset(new Forkedcall::SignalType); - - convert_ptr->connect(SigC::slot(this, &ConvProcess::converted)); - - Forkedcall call; - int retval = call.startscript(script_command, convert_ptr); - if (retval > 0) { - // Unable to even start the script, so clean-up the mess! - converted(string(), 0, 1); - } -} - - -void ConvProcess::converted(string const &/* cmd */, - pid_t /* pid */, int retval) -{ - // Clean-up behind ourselves - lyx::unlink(script_file_); - - if (retval > 0) { - lyx::unlink(to_file_); - to_file_.erase(); - } - - if (on_finish_.get()) { - on_finish_->emit(to_file_); - } - - grfx::GConverter::get().erase(this); -} - - -} // namespace grfx +} // namespace anon