| Summary: | GwenView refuses to save animated GIFs | ||
|---|---|---|---|
| Product: | [Applications] gwenview | Reporter: | Stephan Sokolow <kde_bugzilla_2> |
| Component: | general | Assignee: | Gwenview Bugs <gwenview-bugs-null> |
| Status: | RESOLVED FIXED | ||
| Severity: | normal | ||
| Priority: | NOR | ||
| Version First Reported In: | unspecified | ||
| Target Milestone: | --- | ||
| Platform: | Compiled Sources | ||
| OS: | Linux | ||
| Latest Commit: | Version Fixed/Implemented In: | ||
| Sentry Crash Report: | |||
|
Description
Stephan Sokolow
2006-08-04 08:52:29 UTC
SVN commit 606305 by gateau:
Instead of "re-saving" the image, do a copy of the data if possible.
BUG: 131833
M +3 -0 NEWS
M +116 -3 gvimagepart/gvimagepart.cpp
M +24 -0 gvimagepart/gvimagepart.h
--- trunk/extragear/graphics/gwenview/NEWS #606304:606305
@@ -22,6 +22,9 @@
(Bug 126218).
- In KPart, do not loose selection when starting a drag.
- Fixed behavior of the middle-mouse button (Bug 134590).
+ - Saving in KPart now does a copy of the image instead of recompressing it,
+ unless the user rotated the image, this ensures the KPart won't fail to
+ save certain files (Bug 131833).
2006.09.16 - v1.4.0
- Fixes:
--- trunk/extragear/graphics/gwenview/gvimagepart/gvimagepart.cpp #606304:606305
@@ -20,6 +20,7 @@
#include <qapplication.h>
#include <qcursor.h>
+#include <qfile.h>
#include <qpoint.h>
#include <kaction.h>
@@ -27,13 +28,16 @@
#include <kconfig.h>
#include <kdebug.h>
#include <kdirlister.h>
+#include <kfiledialog.h>
#include <kiconloader.h>
#include <klocale.h>
+#include <kmessagebox.h>
#include <kmimetype.h>
#include <kparts/genericfactory.h>
#include <gvcore/cache.h>
#include <gvcore/document.h>
+#include <gvcore/fileoperation.h>
#include <gvcore/printdialog.h>
#include <gvcore/imageview.h>
#include <gvcore/imageloader.h>
@@ -47,7 +51,7 @@
#undef ENABLE_LOG
#undef LOG
-//#define ENABLE_LOG
+#define ENABLE_LOG
#ifdef ENABLE_LOG
#define LOG(x) kdDebug() << k_funcinfo << x << endl
#else
@@ -55,6 +59,18 @@
#endif
+static bool storeData(QWidget* parent, QFile* file, const QByteArray& data) {
+ uint sizeWritten = file->writeBlock(data);
+ if (sizeWritten != data.size()) {
+ KMessageBox::error(
+ parent,
+ i18n("Could not save image to a temporary file"));
+ return false;
+ }
+ return true;
+}
+
+
//Factory Code
typedef KParts::GenericFactory<GVImagePart> GVImageFactory;
K_EXPORT_COMPONENT_FACTORY( libgvimagepart /*library name*/, GVImageFactory )
@@ -98,7 +114,7 @@
this,SLOT(slotSelectNext()), actionCollection(), "next");
updateNextPrevious();
- KStdAction::saveAs( mDocument, SLOT(saveAs()), actionCollection(), "saveAs" );
+ KStdAction::saveAs( this, SLOT(saveAs()), actionCollection(), "saveAs" );
new KAction(i18n("Rotate &Left"), "rotate_ccw", CTRL + Key_L, this, SLOT(rotateLeft()), actionCollection(), "rotate_left");
new KAction(i18n("Rotate &Right"), "rotate_cw", CTRL + Key_R, this, SLOT(rotateRight()), actionCollection(), "rotate_right");
@@ -288,6 +304,103 @@
}
+void GVImagePart::saveAs() {
+ if (!mDocument->isModified()) {
+ saveOriginalAs();
+ return;
+ }
+
+ if (mDocument->canBeSaved()) {
+ mDocument->saveAs();
+ return;
+ }
+
+ KGuiItem saveItem(i18n("&Save Original"), "filesaveas");
+ int result = KMessageBox::warningContinueCancel(
+ widget(),
+ i18n("Gwenview KPart can't save the modifications you made. Do you want to save the original image?"),
+ i18n("Warning"),
+ saveItem);
+
+ if (result == KMessageBox::Cancel) return;
+
+ saveOriginalAs();
+}
+
+
+void GVImagePart::showJobError(KIO::Job* job) {
+ if (job->error() != 0) {
+ job->showErrorDialog(widget());
+ }
+}
+
+
+void GVImagePart::saveOriginalAs() {
+ KURL srcURL = mDocument->url();
+ KURL dstURL = KFileDialog::getSaveURL(
+ srcURL.fileName(),
+ QString::null,
+ widget());
+ if (!dstURL.isValid()) return;
+
+ // Try to get data from the cache to avoid downloading the image again.
+ QByteArray data = Cache::instance()->file(srcURL);
+
+ if (data.size() == 0) {
+ // We need to read the image again. Let KIO::copy do the work.
+ KIO::Job* job = KIO::copy(srcURL, dstURL);
+ job->setWindow(widget());
+ connect(job, SIGNAL(result(KIO::Job*)),
+ this, SLOT(showJobError(KIO::Job*)) );
+ return;
+ }
+
+ if (dstURL.isLocalFile()) {
+ // Destination is a local file, store it ourself
+ QString path = dstURL.path();
+ QFile file(path);
+ if (!file.open(IO_WriteOnly)) {
+ KMessageBox::error(
+ widget(),
+ i18n("Could not open '%1' for writing.").arg(path));
+ return;
+ }
+ storeData(widget(), &file, data);
+ return;
+ }
+
+ // We need to send the data to a remote location
+ new DataUploader(widget(), data, dstURL);
+}
+
+
+DataUploader::DataUploader(QWidget* dialogParent, const QByteArray& data, const KURL& dstURL)
+: mDialogParent(dialogParent)
+{
+ mTempFile.setAutoDelete(true);
+
+ // Store it in a temp file
+ if (! storeData(dialogParent, mTempFile.file(), data) ) return;
+
+ // Now upload it
+ KURL tmpURL;
+ tmpURL.setPath(mTempFile.name());
+ KIO::Job* job = KIO::copy(tmpURL, dstURL);
+ job->setWindow(dialogParent);
+ connect(job, SIGNAL(result(KIO::Job*)),
+ this, SLOT(slotJobFinished(KIO::Job*)) );
+}
+
+
+void DataUploader::slotJobFinished(KIO::Job* job) {
+ if (job->error() != 0) {
+ job->showErrorDialog(mDialogParent);
+ }
+
+ delete this;
+}
+
+
/**
* Overload KXMLGUIClient so that we can call setXML
*/
@@ -304,7 +417,7 @@
QString doc = KXMLGUIFactory::readConfigFile( "gvimagepartpopup.rc", true, instance() );
PopupGUIClient guiClient(instance(), doc);
- KStdAction::saveAs( mDocument, SLOT(saveAs()), guiClient.actionCollection(), "saveAs" );
+ KStdAction::saveAs( this, SLOT(saveAs()), guiClient.actionCollection(), "saveAs" );
KParts::URLArgs urlArgs;
urlArgs.serviceType = mDocument->mimeType();
--- trunk/extragear/graphics/gwenview/gvimagepart/gvimagepart.h #606304:606305
@@ -21,8 +21,10 @@
#include <kparts/part.h>
#include <kparts/browserextension.h>
+#include <ktempfile.h>
// Forward declarations
+class QFile;
class QPoint;
class KAboutData;
@@ -118,11 +120,16 @@
void openContextMenu(const QPoint&);
+ void saveAs();
+
+ void showJobError(KIO::Job* job);
+
private:
void updateNextPrevious();
KURL nextURL() const;
KURL previousURL() const;
+ void saveOriginalAs();
/**
* The component's widget
@@ -153,5 +160,22 @@
LastDirection mLastDirection; // used for prefetching
};
+
+/**
+ * This simple helper class uploads data to a remote URL asynchronously
+ */
+class DataUploader : public QObject {
+ Q_OBJECT
+public:
+ DataUploader(QWidget* dialogParent, const QByteArray& data, const KURL& destURL);
+
+private slots:
+ void slotJobFinished(KIO::Job*);
+
+private:
+ KTempFile mTempFile;
+ QWidget* mDialogParent;
+};
+
} // namespace
#endif
|