diff options
Diffstat (limited to 'src/gvimagepart/gvimagepart.cpp')
-rw-r--r-- | src/gvimagepart/gvimagepart.cpp | 450 |
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 <jr@jriddell.org> + +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 <jr@jriddell.org>"); + 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 |