X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fgraphics%2FGraphicsConverter.C;h=5d08e460d56f8b9e80b52ab1d45fbc22cc2376e5;hb=f643df79a890ec4bc2eb05a3fd3d349ba3994f96;hp=fbf5f6759e1b049366e7eb1e8ae2d906371fc9e5;hpb=fff706a2485ddb331152747c137acb374e436ba0;p=lyx.git diff --git a/src/graphics/GraphicsConverter.C b/src/graphics/GraphicsConverter.C index fbf5f6759e..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,170 +16,240 @@ #include "converter.h" #include "debug.h" -#include "gettext.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 + +extern string system_lyxdir; using std::endl; +namespace grfx { -namespace { +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_; +}; -string const move_file(string const & from_file, string const & to_file) + +bool Converter::isReachable(string const & from_format_name, + string const & to_format_name) { - if (from_file == to_file) - return string(); + return converters.isReachable(from_format_name, to_format_name); +} - 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(); -} +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)) +{} -} // namespace anon +Converter::~Converter() +{} -namespace grfx { -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); } -void GConverter::convert(string const & from_file, string const & to_file_base, - string const & from_format, string const & to_format, - SignalTypePtr on_finish) +string const & Converter::convertedFile() const { - lyxerr[Debug::GRAPHICS] << "[GraphicsConverter::convert]\n" - << "\tfrom_file: " << from_file + 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); + +} // 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"; - string script_command; - string script_file; - - bool success = build_script(from_file, to_file_base, - from_format, to_format, script); - - if (success) { - lyxerr[Debug::GRAPHICS] << "\tConversion script:\n" - << "--------------------------------------\n" - << script.str().c_str() - << "\n--------------------------------------\n"; - - // Output the script to file. - static int counter = 0; - 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. - success = false; - } else { - - fs << script.str().c_str(); - fs.close(); - - // Create a dummy command for ease of understanding of the - // list of forked processes. - // Note that 'sh ' is absolutely essential, or execvp will fail. - script_command = - "sh " + script_file + " " + - OnlyFilename(from_file) + " " + to_format; - } - } + bool const success = build_script(from_file, to_file_base, + from_format, to_format, script); - string const to_file = - ChangeExtension(to_file_base, formats.extension(to_format)); - - if (!success) { - script_file = string(); - script_command = - "convert -depth 8 " + - from_format + ':' + from_file + ' ' + - to_format + ':' + to_file; - lyxerr[Debug::GRAPHICS] - << "\tNo converter defined! I use convert from ImageMagic:\n\t" - << script_command << endl; - } - - // 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); -} + if (!success) + return; + lyxerr[Debug::GRAPHICS] << "\tConversion script:" + << "\n--------------------------------------\n" + << script.str().c_str() + << "\n--------------------------------------\n"; -namespace { + // Output the script to file. + static int counter = 0; + script_file_ = OnlyPath(to_file_base) + "lyxconvert" + + tostr(counter++) + ".sh"; -typedef boost::shared_ptr ConvProcessPtr; + std::ofstream fs(script_file_.c_str()); + if (!fs.good()) + return; -class Find_Ptr { -public: - Find_Ptr(ConvProcess * ptr) : ptr_(ptr) {} + fs << script.str().c_str(); + fs.close(); - bool operator()(ConvProcessPtr const & ptr) - { - return ptr.get() == ptr_; - } + // 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); -private: - ConvProcess * ptr_; -}; + // 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. + script_command_ = "sh " + script_file_ + " " + + OnlyFilename(from_file) + " " + to_format; -} // namespace anon + // All is ready to go + valid_process_ = true; +} -void GConverter::erase(ConvProcess * process) +void Converter::Impl::startConversion() { - 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 (!valid_process_) { + converted(string(), 0, 1); + return; + } + + // Initiate the conversion + Forkedcall::SignalTypePtr convert_ptr; + convert_ptr.reset(new Forkedcall::SignalType); + + convert_ptr->connect( + boost::bind(&Impl::converted, this, _1, _2, _3)); + + 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); + } +} + - if (it == end) +void Converter::Impl::converted(string const & /* cmd */, + pid_t /* pid */, int retval) +{ + 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 { -bool GConverter::build_script(string const & from_file, - string const & to_file_base, - string const & from_format, - string const & to_format, - ostringstream & script) const +string const move_file(string const & from_file, string const & to_file) { - lyxerr[Debug::GRAPHICS] << "[GraphicsConverter::build_script] ... "; + 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 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, @@ -212,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; @@ -232,6 +304,7 @@ 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"; @@ -270,43 +343,4 @@ bool GConverter::build_script(string const & from_file, 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(boost::bind(&ConvProcess::converted, this, _1, _2, _3)); - - 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_->operator()(to_file_); - } - - grfx::GConverter::get().erase(this); -} - - -} // namespace grfx +} // namespace anon