X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2Finsetgraphics.C;h=bb4a0cdfd0e749ca75136b3f5a35ffd1296e098b;hb=357a3741c0655e174ad48ded68cca90b09a158e6;hp=782b954033aed0a16c9bd0b28c11a6ab36996587;hpb=ba01e80b7cd9ff3dd59e268206603e6be6cecfd9;p=lyx.git diff --git a/src/insets/insetgraphics.C b/src/insets/insetgraphics.C index 782b954033..bb4a0cdfd0 100644 --- a/src/insets/insetgraphics.C +++ b/src/insets/insetgraphics.C @@ -4,9 +4,9 @@ * Licence details can be found in the file COPYING. * * \author Baruch Even - * \author Herbert Voss + * \author Herbert Voß * - * Full author contact details are available in file CREDITS + * Full author contact details are available in file CREDITS. */ /* @@ -53,40 +53,62 @@ TODO #include #include "insets/insetgraphics.h" -#include "insets/insetgraphicsParams.h" -#include "insets/renderers.h" +#include "insets/render_graphic.h" #include "buffer.h" #include "BufferView.h" #include "converter.h" +#include "cursor.h" #include "debug.h" +#include "dispatchresult.h" #include "format.h" #include "funcrequest.h" #include "gettext.h" #include "LaTeXFeatures.h" -#include "latexrunparams.h" -#include "Lsstream.h" +#include "lyx_main.h" #include "lyxlex.h" #include "lyxrc.h" +#include "metricsinfo.h" +#include "outputparams.h" #include "frontends/Alert.h" -#include "frontends/Dialogs.h" +#include "frontends/LyXView.h" #include "support/filetools.h" #include "support/lyxalgo.h" // lyx::count #include "support/lyxlib.h" // float_equal -#include "support/tostr.h" +#include "support/os.h" #include "support/systemcall.h" +#include "support/tostr.h" +#include "support/std_sstream.h" #include +#include + +namespace support = lyx::support; +using lyx::support::AbsolutePath; +using lyx::support::bformat; +using lyx::support::ChangeExtension; +using lyx::support::contains; +using lyx::support::FileName; +using lyx::support::float_equal; +using lyx::support::GetExtension; +using lyx::support::getExtFromContents; +using lyx::support::IsFileReadable; +using lyx::support::LibFileSearch; +using lyx::support::rtrim; +using lyx::support::Systemcall; +using lyx::support::unzipFile; +using lyx::support::unzippedFileName; + +namespace os = lyx::support::os; -#include // For the std::max - -extern string system_tempdir; -// set by Exporters - -using std::ostream; using std::endl; +using std::string; +using std::auto_ptr; +using std::istringstream; +using std::ostream; +using std::ostringstream; namespace { @@ -111,11 +133,11 @@ string const uniqueID() } -string findTargetFormat(string const & suffix, LatexRunParams const & runparams) +string findTargetFormat(string const & suffix, OutputParams const & runparams) { // Are we using latex or pdflatex). - if (runparams.flavor == LatexRunParams::PDFLATEX) { - lyxerr[Debug::GRAPHICS] << "findTargetFormat: PDF mode\n"; + if (runparams.flavor == OutputParams::PDFLATEX) { + lyxerr[Debug::GRAPHICS] << "findTargetFormat: PDF mode" << endl; if (contains(suffix, "ps") || suffix == "pdf") return "pdf"; if (suffix == "jpg") // pdflatex can use jpeg @@ -123,7 +145,7 @@ string findTargetFormat(string const & suffix, LatexRunParams const & runparams) return "png"; // and also png } // If it's postscript, we always do eps. - lyxerr[Debug::GRAPHICS] << "findTargetFormat: PostScript mode\n"; + lyxerr[Debug::GRAPHICS] << "findTargetFormat: PostScript mode" << endl; if (suffix != "ps") // any other than ps return "eps"; // is changed to eps return suffix; // let ps untouched @@ -134,26 +156,26 @@ string findTargetFormat(string const & suffix, LatexRunParams const & runparams) InsetGraphics::InsetGraphics() : graphic_label(uniqueID()), - graphic_(new GraphicRenderer) + graphic_(new RenderGraphic) { graphic_->connect(boost::bind(&InsetGraphics::statusChanged, this)); } InsetGraphics::InsetGraphics(InsetGraphics const & ig) - : Inset(ig), + : InsetOld(ig), boost::signals::trackable(), graphic_label(uniqueID()), - graphic_(new GraphicRenderer(*ig.graphic_)) + graphic_(new RenderGraphic(*ig.graphic_)) { graphic_->connect(boost::bind(&InsetGraphics::statusChanged, this)); setParams(ig.params()); } -Inset * InsetGraphics::clone() const +auto_ptr InsetGraphics::clone() const { - return new InsetGraphics(*this); + return auto_ptr(new InsetGraphics(*this)); } @@ -163,75 +185,82 @@ InsetGraphics::~InsetGraphics() } -void InsetGraphics::statusChanged() +void InsetGraphics::statusChanged() const { - BufferView * bv = graphic_->view(); - if (bv) - bv->updateInset(this); + LyX::cref().updateInset(this); } - -dispatch_result InsetGraphics::localDispatch(FuncRequest const & cmd) + +void InsetGraphics::priv_dispatch(LCursor & cur, FuncRequest const & cmd) { switch (cmd.action) { case LFUN_INSET_MODIFY: { + Buffer const & buffer = *cur.bv().buffer(); InsetGraphicsParams p; - InsetGraphicsMailer::string2params(cmd.argument, p); + InsetGraphicsMailer::string2params(cmd.argument, buffer, p); if (!p.filename.empty()) { setParams(p); - cmd.view()->updateInset(this); + cur.bv().update(); } - return DISPATCHED; + break; } case LFUN_INSET_DIALOG_UPDATE: - InsetGraphicsMailer(*this).updateDialog(cmd.view()); - return DISPATCHED; + InsetGraphicsMailer(*this).updateDialog(&cur.bv()); + break; - case LFUN_INSET_EDIT: case LFUN_MOUSE_RELEASE: - InsetGraphicsMailer(*this).showDialog(cmd.view()); - return DISPATCHED; + InsetGraphicsMailer(*this).showDialog(&cur.bv()); + break; default: - return Inset::localDispatch(cmd); + InsetOld::priv_dispatch(cur, cmd); + break; } } +void InsetGraphics::edit(LCursor & cur, bool) +{ + InsetGraphicsMailer(*this).showDialog(&cur.bv()); +} + + void InsetGraphics::metrics(MetricsInfo & mi, Dimension & dim) const { graphic_->metrics(mi, dim); + dim_ = dim; } void InsetGraphics::draw(PainterInfo & pi, int x, int y) const { + setPosCache(pi, x, y); graphic_->draw(pi, x, y); } -Inset::EDITABLE InsetGraphics::editable() const +InsetOld::EDITABLE InsetGraphics::editable() const { return IS_EDITABLE; } -void InsetGraphics::write(Buffer const * buf, ostream & os) const +void InsetGraphics::write(Buffer const & buf, ostream & os) const { os << "Graphics\n"; - params().Write(os, buf->filePath()); + params().Write(os, buf.filePath()); } -void InsetGraphics::read(Buffer const * buf, LyXLex & lex) +void InsetGraphics::read(Buffer const & buf, LyXLex & lex) { string const token = lex.getString(); if (token == "Graphics") - readInsetGraphics(lex, buf->filePath()); + readInsetGraphics(lex, buf.filePath()); else - lyxerr[Debug::GRAPHICS] << "Not a Graphics inset!\n"; + lyxerr[Debug::GRAPHICS] << "Not a Graphics inset!" << endl; graphic_->update(params().as_grfxParams()); } @@ -246,7 +275,7 @@ void InsetGraphics::readInsetGraphics(LyXLex & lex, string const & bufpath) string const token = lex.getString(); lyxerr[Debug::GRAPHICS] << "Token: '" << token << '\'' - << std::endl; + << endl; if (token.empty()) { continue; @@ -260,7 +289,7 @@ void InsetGraphics::readInsetGraphics(LyXLex & lex, string const & bufpath) << "This document was created with a newer Graphics widget" ", You should use a newer version of LyX to read this" " file." - << std::endl; + << endl; // TODO: Possibly open up a dialog? } else { @@ -284,8 +313,8 @@ string const InsetGraphics::createLatexOptions() const options << " draft,\n"; if (params().clip) options << " clip,\n"; - if (!lyx::float_equal(params().scale, 0.0, 0.05)) { - if (!lyx::float_equal(params().scale, 100.0, 0.05)) + if (!float_equal(params().scale, 0.0, 0.05)) { + if (!float_equal(params().scale, 100.0, 0.05)) options << " scale=" << params().scale / 100.0 << ",\n"; } else { @@ -299,7 +328,7 @@ string const InsetGraphics::createLatexOptions() const // Make sure rotation angle is not very close to zero; // a float can be effectively zero but not exactly zero. - if (!lyx::float_equal(params().rotateAngle, 0, 0.001)) { + if (!float_equal(params().rotateAngle, 0, 0.001)) { options << " angle=" << params().rotateAngle << ",\n"; if (!params().rotateOrigin.empty()) { options << " origin=" << params().rotateOrigin[0]; @@ -316,20 +345,85 @@ string const InsetGraphics::createLatexOptions() const if (!params().special.empty()) options << params().special << ",\n"; - string opts = STRCONV(options.str()); + string opts = options.str(); // delete last ",\n" return opts.substr(0, opts.size() - 2); } -string const InsetGraphics::prepareFile(Buffer const * buf, - LatexRunParams const & runparams) const +namespace { + +enum CopyStatus { + SUCCESS, + FAILURE, + IDENTICAL_PATHS, + IDENTICAL_CONTENTS +}; + + +std::pair const +copyToDirIfNeeded(string const & file_in, string const & dir) +{ + using support::rtrim; + + BOOST_ASSERT(AbsolutePath(file_in)); + + string const only_path = support::OnlyPath(file_in); + if (rtrim(support::OnlyPath(file_in) , "/") == rtrim(dir, "/")) + return std::make_pair(IDENTICAL_PATHS, file_in); + + string mangled; + if (support::zippedFile(file_in)) { + string const ext = GetExtension(file_in); + string const unzipped = support::unzippedFileName(file_in); + mangled = FileName(unzipped).mangledFilename(); + mangled += "." + ext; + } else + mangled = FileName(file_in).mangledFilename(); + + string const file_out = support::MakeAbsPath(mangled, dir); + + unsigned long const checksum_in = support::sum(file_in); + unsigned long const checksum_out = support::sum(file_out); + + if (checksum_in == checksum_out) + // Nothing to do... + return std::make_pair(IDENTICAL_CONTENTS, file_out); + + bool const success = support::copy(file_in, file_out); + if (!success) { + lyxerr[Debug::GRAPHICS] + << support::bformat(_("Could not copy the file\n%1$s\n" + "into the temporary directory."), + file_in) + << std::endl; + } + + CopyStatus status = success ? SUCCESS : FAILURE; + return std::make_pair(status, file_out); +} + + +string const stripExtensionIfPossible(string const & file, string const & to) +{ + // No conversion is needed. LaTeX can handle the graphic file as is. + // This is true even if the orig_file is compressed. + if (formats.getFormat(to)->extension() == GetExtension(file)) + return RemoveExtension(file); + return file; +} + +} // namespace anon + + +string const InsetGraphics::prepareFile(Buffer const & buf, + OutputParams const & runparams) const { + string orig_file = params().filename.absFilename(); + string const rel_file = params().filename.relFilename(buf.filePath()); + // LaTeX can cope if the graphics file doesn't exist, so just return the // filename. - string orig_file = params().filename; - string const rel_file = MakeRelPath(orig_file, buf->filePath()); - if (!IsFileReadable(orig_file)) { lyxerr[Debug::GRAPHICS] << "InsetGraphics::prepareFile\n" @@ -337,11 +431,11 @@ string const InsetGraphics::prepareFile(Buffer const * buf, return rel_file; } - bool const zipped = zippedFile(orig_file); - // If the file is compressed and we have specified that it // should not be uncompressed, then just return its name and // let LaTeX do the rest! + bool const zipped = params().filename.isZipped(); + if (zipped && params().noUnzip) { lyxerr[Debug::GRAPHICS] << "\tpass zipped file to LaTeX but with full path.\n"; @@ -355,25 +449,19 @@ string const InsetGraphics::prepareFile(Buffer const * buf, string temp_file = orig_file; if (zipped) { - // Uncompress the file if necessary. - // If it has been uncompressed in a previous call to - // prepareFile, do nothing. - temp_file = MakeAbsPath(OnlyFilename(temp_file), buf->tmppath); - lyxerr[Debug::GRAPHICS] - << "\ttemp_file: " << temp_file << endl; - if (graphic_->hasFileChanged() || !IsFileReadable(temp_file)) { - bool const success = lyx::copy(orig_file, temp_file); - lyxerr[Debug::GRAPHICS] - << "\tCopying zipped file from " - << orig_file << " to " << temp_file - << (success ? " succeeded\n" : " failed\n"); - } else + CopyStatus status; + boost::tie(status, temp_file) = + copyToDirIfNeeded(orig_file, buf.temppath()); + + if (status == FAILURE) + return orig_file; + + orig_file = unzippedFileName(temp_file); + if (!IsFileReadable(orig_file)) { + unzipFile(temp_file); lyxerr[Debug::GRAPHICS] - << "\tzipped file " << temp_file - << " exists! Maybe no tempdir ...\n"; - orig_file = unzipFile(temp_file); - lyxerr[Debug::GRAPHICS] - << "\tunzipped to " << orig_file << endl; + << "\tunzipped to " << orig_file << endl; + } } string const from = getExtFromContents(orig_file); @@ -381,69 +469,65 @@ string const InsetGraphics::prepareFile(Buffer const * buf, lyxerr[Debug::GRAPHICS] << "\t we have: from " << from << " to " << to << '\n'; - if (from == to && !lyxrc.use_tempdir) { - // No conversion is needed. LaTeX can handle the - // graphic file as is. - // This is true even if the orig_file is compressed. - if (formats.getFormat(to)->extension() == GetExtension(orig_file)) - return RemoveExtension(orig_file); - return orig_file; - } + if (from == to && !lyxrc.use_tempdir) + return stripExtensionIfPossible(orig_file, to); // We're going to be running the exported buffer through the LaTeX // compiler, so must ensure that LaTeX can cope with the graphics // file format. - // Perform all these manipulations on a temporary file if possible. - // If we are not using a temp dir, then temp_file contains the - // original file. - // to allow files with the same name in different dirs - // we manipulate the original file "any.dir/file.ext" - // to "any_dir_file.ext"! changing the dots in the - // dirname is important for the use of ChangeExtension lyxerr[Debug::GRAPHICS] << "\tthe orig file is: " << orig_file << endl; + bool conversion_needed = true; if (lyxrc.use_tempdir) { - temp_file = copyFileToDir(buf->tmppath, orig_file); - if (temp_file.empty()) { - string str = bformat(_("Could not copy the file\n%1$s\n" - "into the temporary directory."), - orig_file); - Alert::error(_("Graphics display failed"), str); + CopyStatus status; + boost::tie(status, temp_file) = + copyToDirIfNeeded(orig_file, buf.temppath()); + + if (status == FAILURE) return orig_file; - } - - if (from == to) { - // No conversion is needed. LaTeX can handle the - // graphic file as is. - if (formats.getFormat(to)->extension() == GetExtension(orig_file)) - return RemoveExtension(temp_file); - return temp_file; - } + else if (status == IDENTICAL_CONTENTS) + conversion_needed = false; + } + + if (from == to) + return stripExtensionIfPossible(temp_file, to); + + string const to_file_base = RemoveExtension(temp_file); + string const to_file = ChangeExtension(to_file_base, to); + + // Do we need to perform the conversion? + // Yes if to_file does not exist or if temp_file is newer than to_file + if (!conversion_needed || + support::compare_timestamps(temp_file, to_file) < 0) { + lyxerr[Debug::GRAPHICS] + << bformat(_("No conversion of %1$s is needed after all"), + rel_file) + << std::endl; + return to_file_base; } - string const outfile_base = RemoveExtension(temp_file); lyxerr[Debug::GRAPHICS] << "\tThe original file is " << orig_file << "\n" << "\tA copy has been made and convert is to be called with:\n" << "\tfile to convert = " << temp_file << '\n' - << "\toutfile_base = " << outfile_base << '\n' + << "\tto_file_base = " << to_file_base << '\n' << "\t from " << from << " to " << to << '\n'; // if no special converter defined, than we take the default one // from ImageMagic: convert from:inname.from to:outname.to - if (!converters.convert(buf, temp_file, outfile_base, from, to)) { + if (!converters.convert(&buf, temp_file, to_file_base, from, to)) { string const command = - LibFileSearch("scripts", "convertDefault.sh") + + "sh " + LibFileSearch("scripts", "convertDefault.sh") + ' ' + from + ':' + temp_file + ' ' + - to + ':' + outfile_base + '.' + to; + to + ':' + to_file_base + '.' + to; lyxerr[Debug::GRAPHICS] << "No converter defined! I use convertDefault.sh:\n\t" << command << endl; Systemcall one; one.startscript(Systemcall::Wait, command); - if (!IsFileReadable(ChangeExtension(outfile_base, to))) { + if (!IsFileReadable(ChangeExtension(to_file_base, to))) { string str = bformat(_("No information for converting %1$s " "format files to %2$s.\n" "Try defining a convertor in the preferences."), from, to); @@ -451,25 +535,26 @@ string const InsetGraphics::prepareFile(Buffer const * buf, } } - return RemoveExtension(temp_file); + return to_file_base; } -int InsetGraphics::latex(Buffer const * buf, ostream & os, - LatexRunParams const & runparams) const +int InsetGraphics::latex(Buffer const & buf, ostream & os, + OutputParams const & runparams) const { // If there is no file specified or not existing, // just output a message about it in the latex output. lyxerr[Debug::GRAPHICS] << "insetgraphics::latex: Filename = " - << params().filename << endl; + << params().filename.absFilename() << endl; - string const relative_file = MakeRelPath(params().filename, buf->filePath()); + string const relative_file = + params().filename.relFilename(buf.filePath()); // A missing (e)ps-extension is no problem for LaTeX, so // we have to test three different cases #warning uh, but can our cache handle it ? no. - string const file_ = params().filename; + string const file_ = params().filename.absFilename(); bool const file_exists = !file_.empty() && (IsFileReadable(file_) || // original @@ -532,21 +617,29 @@ int InsetGraphics::latex(Buffer const * buf, ostream & os, } -int InsetGraphics::ascii(Buffer const *, ostream & os, int) const +int InsetGraphics::plaintext(Buffer const &, ostream & os, + OutputParams const &) const { // No graphics in ascii output. Possible to use gifscii to convert // images to ascii approximation. // 1. Convert file to ascii using gifscii // 2. Read ascii output file and add it to the output stream. // at least we send the filename - os << '<' << bformat(_("Graphics file: %1$s"), params().filename) << ">\n"; + os << '<' << bformat(_("Graphics file: %1$s"), + params().filename.absFilename()) << ">\n"; return 0; } -int InsetGraphics::linuxdoc(Buffer const *, ostream &) const +int InsetGraphics::linuxdoc(Buffer const & buf, ostream & os, + OutputParams const & runparams) const { - // No graphics in LinuxDoc output. Should check how/what to add. + string const file_name = runparams.nice ? + params().filename.relFilename(buf.filePath()): + params().filename.absFilename(); + + os << "\n"; + os << ""; return 0; } @@ -554,8 +647,8 @@ int InsetGraphics::linuxdoc(Buffer const *, ostream &) const // For explanation on inserting graphics into DocBook checkout: // http://en.tldp.org/LDP/LDP-Author-Guide/inserting-pictures.html // See also the docbook guide at http://www.docbook.org/ -int InsetGraphics::docbook(Buffer const *, ostream & os, - bool /*mixcont*/) const +int InsetGraphics::docbook(Buffer const &, ostream & os, + OutputParams const &) const { // In DocBook v5.0, the graphic tag will be eliminated from DocBook, will // need to switch to MediaObject. However, for now this is sufficient and @@ -571,7 +664,8 @@ void InsetGraphics::validate(LaTeXFeatures & features) const if (params().filename.empty()) return; - features.includeFile(graphic_label, RemoveExtension(params().filename)); + features.includeFile(graphic_label, + RemoveExtension(params().filename.absFilename())); features.require("graphicx"); @@ -589,8 +683,8 @@ bool InsetGraphics::setParams(InsetGraphicsParams const & p) // Copy the new parameters. params_ = p; - // Update the display using the new parameters. - graphic_->update(params().as_grfxParams()); + // Update the display using the new parameters. + graphic_->update(params().as_grfxParams()); // We have changed data, report it. return true; @@ -610,47 +704,42 @@ InsetGraphicsMailer::InsetGraphicsMailer(InsetGraphics & inset) {} -string const InsetGraphicsMailer::inset2string() const +string const InsetGraphicsMailer::inset2string(Buffer const & buffer) const { - return params2string(inset_.params()); + return params2string(inset_.params(), buffer); } void InsetGraphicsMailer::string2params(string const & in, + Buffer const & buffer, InsetGraphicsParams & params) { params = InsetGraphicsParams(); - if (in.empty()) return; - istringstream data(STRCONV(in)); + istringstream data(in); LyXLex lex(0,0); lex.setStream(data); - if (lex.isOK()) { - lex.next(); - string const token = lex.getString(); - if (token != name_) - return; - } + string name; + lex >> name; + if (!lex || name != name_) + return print_mailer_error("InsetGraphicsMailer", in, 1, name_); - if (lex.isOK()) { - InsetGraphics inset; -#warning FIXME not setting bufpath is dubious - inset.readInsetGraphics(lex, string()); - params = inset.params(); - } + InsetGraphics inset; + inset.readInsetGraphics(lex, buffer.filePath()); + params = inset.params(); } string const -InsetGraphicsMailer::params2string(InsetGraphicsParams const & params) +InsetGraphicsMailer::params2string(InsetGraphicsParams const & params, + Buffer const & buffer) { ostringstream data; data << name_ << ' '; -#warning FIXME not setting bufpath is dubious - params.Write(data, string()); + params.Write(data, buffer.filePath()); data << "\\end_inset\n"; - return STRCONV(data.str()); + return data.str(); }