summaryrefslogtreecommitdiffstats
path: root/src/gvimagepart/gvimagepart.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gvimagepart/gvimagepart.cpp')
-rw-r--r--src/gvimagepart/gvimagepart.cpp450
1 files changed, 450 insertions, 0 deletions
diff --git a/src/gvimagepart/gvimagepart.cpp b/src/gvimagepart/gvimagepart.cpp
new file mode 100644
index 0000000..5750445
--- /dev/null
+++ b/src/gvimagepart/gvimagepart.cpp
@@ -0,0 +1,450 @@
+/*
+Copyright 2004 Jonathan Riddell <[email protected]>
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02111-1307, USA.
+
+*/
+#include "gvimagepart.moc"
+
+#include <qapplication.h>
+#include <qcursor.h>
+#include <qfile.h>
+#include <qpoint.h>
+
+#include <kaction.h>
+#include <kapplication.h>
+#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>
+#include <gvcore/mimetypeutils.h>
+
+#include "config.h"
+
+namespace Gwenview {
+// For now let's duplicate
+const char CONFIG_CACHE_GROUP[]="cache";
+
+#undef ENABLE_LOG
+#undef LOG
+#define ENABLE_LOG
+#ifdef ENABLE_LOG
+#define LOG(x) kdDebug() << k_funcinfo << x << endl
+#else
+#define LOG(x) ;
+#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 )
+
+GVImagePart::GVImagePart(QWidget* parentWidget, const char* /*widgetName*/, QObject* parent,
+ const char* name, const QStringList &)
+ : KParts::ReadOnlyPart( parent, name )
+ , mPrefetch( NULL )
+ , mLastDirection( DirectionUnknown ) {
+ GVImageFactory::instance()->iconLoader()->addAppDir( "gwenview");
+ setInstance( GVImageFactory::instance() );
+ KGlobal::locale()->insertCatalogue("gwenview");
+ KGlobal::locale()->setActiveCatalogue("gwenview");
+
+ mBrowserExtension = new GVImagePartBrowserExtension(this);
+
+ // Create the widgets
+ mDocument = new Document(this);
+ connect( mDocument, SIGNAL( loading()), SLOT( slotLoading()));
+ connect( mDocument, SIGNAL( loaded(const KURL&)), SLOT( slotLoaded(const KURL&)));
+ mImageView = new ImageView(parentWidget, mDocument, actionCollection());
+ connect( mImageView, SIGNAL(requestContextMenu(const QPoint&)),
+ this, SLOT(openContextMenu(const QPoint&)) );
+ setWidget(mImageView);
+
+ mDirLister = new KDirLister;
+ mDirLister->setAutoErrorHandlingEnabled( false, 0 );
+ mDirLister->setMainWindow(KApplication::kApplication()->mainWidget());
+ connect( mDirLister, SIGNAL( clear()), SLOT( dirListerClear()));
+ connect( mDirLister, SIGNAL( newItems( const KFileItemList& )),
+ SLOT( dirListerNewItems( const KFileItemList& )));
+ connect(mDirLister,SIGNAL(deleteItem(KFileItem*)),
+ SLOT(dirListerDeleteItem(KFileItem*)) );
+
+ QStringList mimeTypes=MimeTypeUtils::rasterImageMimeTypes();
+ mDirLister->setMimeFilter(mimeTypes);
+ mPreviousImage=new KAction(i18n("&Previous Image"),
+ QApplication::reverseLayout() ? "1rightarrow":"1leftarrow", Key_BackSpace,
+ this,SLOT(slotSelectPrevious()), actionCollection(), "previous");
+ mNextImage=new KAction(i18n("&Next Image"),
+ QApplication::reverseLayout() ? "1leftarrow":"1rightarrow", Key_Space,
+ this,SLOT(slotSelectNext()), actionCollection(), "next");
+ updateNextPrevious();
+
+ 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");
+
+ setXMLFile( "gvimagepart/gvimagepart.rc" );
+}
+
+GVImagePart::~GVImagePart() {
+ delete mDirLister;
+}
+
+
+void GVImagePart::partActivateEvent(KParts::PartActivateEvent* event) {
+ if (event->activated()) {
+ KConfig* config=new KConfig("gwenviewrc");
+ Cache::instance()->readConfig(config,CONFIG_CACHE_GROUP);
+ delete config;
+ }
+ KParts::ReadOnlyPart::partActivateEvent( event );
+}
+
+
+void GVImagePart::guiActivateEvent( KParts::GUIActivateEvent* event) {
+ // Stolen from KHTMLImage
+ //
+ // prevent the base implementation from emitting setWindowCaption with
+ // our url. It destroys our pretty, previously caption. Konq saves/restores
+ // the caption for us anyway.
+ if (event->activated()) {
+ return;
+ }
+ KParts::ReadOnlyPart::guiActivateEvent(event);
+}
+
+
+KAboutData* GVImagePart::createAboutData() {
+ KAboutData* aboutData = new KAboutData( "gvimagepart", I18N_NOOP("GVImagePart"),
+ "0.1", I18N_NOOP("Image Viewer"),
+ KAboutData::License_GPL,
+ "(c) 2004, Jonathan Riddell <[email protected]>");
+ return aboutData;
+}
+
+bool GVImagePart::openURL(const KURL& url) {
+ if (!url.isValid()) {
+ return false;
+ }
+ KURL oldURLDir = m_url;
+ oldURLDir.setFileName( QString::null );
+ KURL newURLDir = url;
+ newURLDir.setFileName( QString::null );
+ bool sameDir = oldURLDir == newURLDir;
+ m_url = url;
+ emit started( 0 );
+ if( mDocument->url() == url ) { // reload button in Konqy - setURL would return immediately
+ mDocument->reload();
+ } else {
+ mDocument->setURL(url);
+ }
+ if( !sameDir ) {
+ mDirLister->openURL(mDocument->dirURL());
+ mLastDirection = DirectionUnknown;
+ }
+ return true;
+}
+
+QString GVImagePart::filePath() {
+ return m_file;
+}
+
+void GVImagePart::slotLoading() {
+ emit setWindowCaption(mDocument->url().filename() + " - " + i18n("Loading..."));
+ // Set the location bar URL because we can arrive here if the user click on
+ // previous/next, which do not use openURLRequest
+ emit mBrowserExtension->setLocationBarURL(mDocument->url().pathOrURL());
+ updateNextPrevious();
+}
+
+void GVImagePart::slotLoaded(const KURL& url) {
+ QString caption = url.filename() + QString(" - %1x%2").arg(mDocument->width()).arg(mDocument->height());
+ emit setWindowCaption(caption);
+ emit completed();
+ emit setStatusBarText(i18n("Done."));
+ prefetchDone();
+ mPrefetch = ImageLoader::loader( mLastDirection == DirectionPrevious ? previousURL() : nextURL(),
+ this, BUSY_PRELOADING );
+ connect( mPrefetch, SIGNAL( imageLoaded( bool )), SLOT( prefetchDone()));
+}
+
+void GVImagePart::prefetchDone() {
+ if( mPrefetch != NULL ) {
+ mPrefetch->release( this );
+ }
+ mPrefetch = NULL;
+}
+
+void GVImagePart::print() {
+ KPrinter printer;
+
+ printer.setDocName( m_url.filename() );
+ KPrinter::addDialogPage( new PrintDialogPage( mDocument, mImageView, "GV page"));
+
+ if (printer.setup(mImageView, QString::null, true)) {
+ mDocument->print(&printer);
+ }
+}
+
+void GVImagePart::rotateLeft() {
+ mDocument->transform(ImageUtils::ROT_270);
+}
+
+void GVImagePart::rotateRight() {
+ mDocument->transform(ImageUtils::ROT_90);
+}
+
+void GVImagePart::dirListerClear() {
+ mImagesInDirectory.clear();
+ updateNextPrevious();
+}
+
+void GVImagePart::dirListerNewItems( const KFileItemList& list ) {
+ QPtrListIterator<KFileItem> it(list);
+ for( ; it.current(); ++it ) {
+ mImagesInDirectory.append( (*it)->name());
+ }
+ qHeapSort( mImagesInDirectory );
+ updateNextPrevious();
+}
+
+void GVImagePart::dirListerDeleteItem( KFileItem* item ) {
+ mImagesInDirectory.remove( item->name());
+ updateNextPrevious();
+}
+
+void GVImagePart::updateNextPrevious() {
+ QStringList::ConstIterator current = mImagesInDirectory.find( mDocument->filename());
+ if( current == mImagesInDirectory.end()) {
+ mNextImage->setEnabled( false );
+ mPreviousImage->setEnabled( false );
+ return;
+ }
+ mPreviousImage->setEnabled( current != mImagesInDirectory.begin());
+ ++current;
+ mNextImage->setEnabled( current != mImagesInDirectory.end());
+}
+
+KURL GVImagePart::nextURL() const {
+ QStringList::ConstIterator current = mImagesInDirectory.find( mDocument->filename());
+ if( current == mImagesInDirectory.end()) {
+ return KURL();
+ }
+ ++current;
+ if( current == mImagesInDirectory.end()) {
+ return KURL();
+ }
+ KURL newURL = mDocument->dirURL();
+ newURL.setFileName( *current );
+ return newURL;
+}
+
+void GVImagePart::slotSelectNext() {
+ KURL newURL = nextURL();
+ if( newURL.isEmpty()) return;
+ mLastDirection = DirectionNext;
+ // Do not use mBrowserExtension->openURLRequest to avoid switching to
+ // another KPart
+ openURL(newURL);
+ emit mBrowserExtension->openURLNotify();
+}
+
+KURL GVImagePart::previousURL() const {
+ QStringList::ConstIterator current = mImagesInDirectory.find( mDocument->filename());
+ if( current == mImagesInDirectory.end() || current == mImagesInDirectory.begin()) {
+ return KURL();
+ }
+ --current;
+ KURL newURL = mDocument->dirURL();
+ newURL.setFileName( *current );
+ return newURL;
+}
+
+void GVImagePart::slotSelectPrevious() {
+ KURL newURL = previousURL();
+ if( newURL.isEmpty()) return;
+ mLastDirection = DirectionPrevious;
+ openURL(newURL);
+ emit mBrowserExtension->openURLNotify();
+}
+
+
+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
+ */
+class PopupGUIClient : public KXMLGUIClient {
+public:
+ PopupGUIClient( KInstance *inst, const QString &doc ) {
+ setInstance( inst );
+ setXML( doc );
+ }
+};
+
+
+void GVImagePart::openContextMenu(const QPoint& pos) {
+ QString doc = KXMLGUIFactory::readConfigFile( "gvimagepartpopup.rc", true, instance() );
+ PopupGUIClient guiClient(instance(), doc);
+
+ KStdAction::saveAs( this, SLOT(saveAs()), guiClient.actionCollection(), "saveAs" );
+
+ KParts::URLArgs urlArgs;
+ urlArgs.serviceType = mDocument->mimeType();
+
+ KParts::BrowserExtension::PopupFlags flags =
+ KParts::BrowserExtension::ShowNavigationItems
+ | KParts::BrowserExtension::ShowUp
+ | KParts::BrowserExtension::ShowReload;
+
+ emit mBrowserExtension->popupMenu(&guiClient, pos, m_url, urlArgs, flags, S_IFREG);
+}
+
+
+/***** GVImagePartBrowserExtension *****/
+
+GVImagePartBrowserExtension::GVImagePartBrowserExtension(GVImagePart* viewPart, const char* name)
+ :KParts::BrowserExtension(viewPart, name) {
+ mGVImagePart = viewPart;
+ emit enableAction("print", true );
+}
+
+GVImagePartBrowserExtension::~GVImagePartBrowserExtension() {
+}
+
+void GVImagePartBrowserExtension::print() {
+ mGVImagePart->print();
+}
+
+} // namespace