You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
884 lines
27 KiB
884 lines
27 KiB
/* This file is part of the KDE project
|
|
|
|
Copyright (C) 1999 Simon Hausmann <hausmann@kde.org>
|
|
2001-2003 Matthias Kretz <kretz@kde.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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
#include "kviewviewer.h"
|
|
#include "kimageviewer/canvas.h"
|
|
#include "version.h"
|
|
|
|
#include <ksettings/dispatcher.h>
|
|
|
|
#include <unistd.h>
|
|
#include <assert.h>
|
|
|
|
#include <tqbuffer.h>
|
|
#include <tqlayout.h>
|
|
#include <tqvbox.h>
|
|
#include <tqlabel.h>
|
|
#include <tqregexp.h>
|
|
|
|
#include <kpushbutton.h>
|
|
#include <kpassivepopup.h>
|
|
#include <kdebug.h>
|
|
#include <kio/job.h>
|
|
#include <kxmlguifactory.h>
|
|
#include <kfiledialog.h>
|
|
#include <kparts/genericfactory.h>
|
|
#include <kparts/componentfactory.h>
|
|
#include <kparts/plugin.h>
|
|
#include <kmessagebox.h>
|
|
#include <ktempfile.h>
|
|
#include <kapplication.h>
|
|
#include <kimageio.h>
|
|
#include <kstdaccel.h>
|
|
#include <kdirwatch.h>
|
|
#include <kurldrag.h>
|
|
#include <krecentdocument.h>
|
|
|
|
typedef KParts::GenericFactory<KViewViewer> KViewViewerFactory;
|
|
K_EXPORT_COMPONENT_FACTORY( libkviewviewer, KViewViewerFactory )
|
|
|
|
KViewViewer::KViewViewer( TQWidget *parentWidget, const char * /*widgetName*/,
|
|
TQObject *parent, const char *name, const TQStringList & )
|
|
: KImageViewer::Viewer( parent, name )
|
|
, m_pParentWidget( parentWidget )
|
|
, m_pJob( 0 )
|
|
, m_pExtension( 0 )
|
|
, m_pCanvas( 0 )
|
|
, m_pTempFile( 0 )
|
|
, m_pBuffer( 0 )
|
|
, m_pFileWatch( new KDirWatch( this ) )
|
|
{
|
|
KImageIO::registerFormats();
|
|
|
|
TQWidget * widget = KParts::ComponentFactory::createInstanceFromQuery<TQWidget>(
|
|
"KImageViewer/Canvas", TQString(), TQT_TQOBJECT(m_pParentWidget) );
|
|
m_pCanvas = static_cast<KImageViewer::Canvas *>( widget->qt_cast( "KImageViewer::Canvas" ) );
|
|
kdDebug( 4610 ) << "KImageViewer::Canvas at " << m_pCanvas << endl;
|
|
if( ! ( widget && m_pCanvas ) )
|
|
{
|
|
if( ! widget )
|
|
KMessageBox::error( m_pParentWidget, i18n( "Unable to find a suitable Image Canvas. This probably means that KView was not installed properly." ) );
|
|
else
|
|
KMessageBox::error( m_pParentWidget, i18n( "Accessing the KImageViewer interface of the Image Canvas failed. Something in your setup is broken (a component claims to be a KImageViewer::Canvas but it is not)." ) );
|
|
}
|
|
else
|
|
{
|
|
// create the extension before the plugins are loaded, because plugins might want to use it
|
|
m_pExtension = new KViewKonqExtension( m_pCanvas, this );
|
|
|
|
setPluginLoadingMode( LoadPluginsIfEnabled );
|
|
setInstance( KViewViewerFactory::instance() );
|
|
|
|
// m_url isn't set from ReadOnlyPart so we set it here to the CWD
|
|
m_url = TQDir::currentDirPath() + "/";
|
|
m_sCaption = i18n( "Title caption when no image loaded", "no image loaded" );
|
|
|
|
setWidget( widget );
|
|
|
|
// Drag and Drop for the Canvas
|
|
widget->setAcceptDrops( true );
|
|
widget->installEventFilter( this );
|
|
|
|
setupActions();
|
|
|
|
if( isReadWrite() )
|
|
setXMLFile( "kviewviewer.rc" );
|
|
else
|
|
setXMLFile( "kviewviewer_ro.rc" );
|
|
|
|
connect( widget, TQT_SIGNAL( contextPress( const TQPoint & ) ),
|
|
this, TQT_SLOT( slotPopupMenu( const TQPoint & ) ) );
|
|
connect( widget, TQT_SIGNAL( zoomChanged( double ) ),
|
|
this, TQT_SLOT( zoomChanged( double ) ) );
|
|
connect( widget, TQT_SIGNAL( showingImageDone() ),
|
|
this, TQT_SLOT( switchBlendEffect() ) );
|
|
connect( widget, TQT_SIGNAL( hasImage( bool ) ),
|
|
this, TQT_SLOT( hasImage( bool ) ) );
|
|
connect( widget, TQT_SIGNAL( imageChanged() ),
|
|
this, TQT_SLOT( setModified() ) );
|
|
|
|
connect( m_pFileWatch, TQT_SIGNAL( dirty( const TQString & ) ),
|
|
this, TQT_SLOT( slotFileDirty( const TQString & ) ) );
|
|
|
|
KSettings::Dispatcher::self()->registerInstance( instance(), this, TQT_SLOT( readSettings() ) );
|
|
|
|
// by default disable progress info (so it won't open the dialog in Konqueror)
|
|
setProgressInfoEnabled( false );
|
|
|
|
m_popupDoc = KXMLGUIFactory::readConfigFile( "kviewpopup.rc", true, instance() );
|
|
|
|
KConfigGroup cfgGroup( instance()->config(), "Settings" );
|
|
bool hideBars = cfgGroup.readBoolEntry( "hideScrollbars", false );
|
|
m_pCanvas->hideScrollbars( hideBars );
|
|
m_paShowScrollbars->setChecked( ! hideBars );
|
|
m_vEffects.resize( m_pCanvas->numOfBlendEffects() );
|
|
|
|
readSettings();
|
|
}
|
|
}
|
|
|
|
KViewViewer::~KViewViewer()
|
|
{
|
|
kdDebug( 4610 ) << k_funcinfo << endl;
|
|
|
|
writeSettings();
|
|
instance()->config()->sync();
|
|
|
|
/*abortLoad(); //just in case
|
|
if( isModified() && isReadWrite() )
|
|
{
|
|
int res = m_url.isEmpty() ?
|
|
KMessageBox::warningYesNo( widget(),
|
|
i18n( "This is a new document.\nDo you want to save it ?" ),
|
|
TQString(), KStdGuiItem::saveAs(), KStdGuiItem::discard() ):
|
|
KMessageBox::warningYesNo( widget(),
|
|
i18n( "The document has been modified.\nDo you want to save it ?" ),
|
|
TQString(), KStdGuiItem::saveAs(), KStdGuiItem::dontSave() );
|
|
|
|
if( res == KMessageBox::Yes )
|
|
{
|
|
KURL url = KFileDialog::getSaveURL();
|
|
if( ! url.isEmpty() )
|
|
saveAs( url );
|
|
}
|
|
}
|
|
ReadOnlyPart::closeURL();*/
|
|
|
|
abortLoad();
|
|
delete m_pTempFile;
|
|
delete m_pBuffer;
|
|
}
|
|
|
|
KAboutData * KViewViewer::createAboutData()
|
|
{
|
|
KAboutData * aboutData = new KAboutData( "kviewviewer", I18N_NOOP( "KView" ),
|
|
KVIEW_VERSION, I18N_NOOP( "KDE Image Viewer Part" ),
|
|
KAboutData::License_GPL,
|
|
I18N_NOOP("(c) 1997-2002, The KView Developers") );
|
|
aboutData->addAuthor( "Matthias Kretz", I18N_NOOP( "Maintainer" ), "kretz@kde.org" );
|
|
aboutData->addAuthor( "Sirtaj Singh Kang", I18N_NOOP( "started it all" ), "taj@kde.org" );
|
|
aboutData->addAuthor( "Simon Hausmann", 0, "hausmann@kde.org" );
|
|
return aboutData;
|
|
}
|
|
|
|
void KViewViewer::setReadWrite( bool readwrite )
|
|
{
|
|
KImageViewer::Viewer::setReadWrite( readwrite );
|
|
if( readwrite )
|
|
setXMLFile( "kviewviewer.rc" );
|
|
else
|
|
setXMLFile( "kviewviewer_ro.rc" );
|
|
}
|
|
|
|
bool KViewViewer::saveAs( const KURL & kurl )
|
|
{
|
|
kdDebug( 4610 ) << k_funcinfo << endl;
|
|
if( !kurl.isValid() )
|
|
return KParts::ReadWritePart::saveAs( kurl ); // sets m_bClosing = false
|
|
|
|
// if the image wasn't modified and should be saved in the same format we just copy the file - no need
|
|
// to lose some quality or information by calling TQImage::save()
|
|
if( ! ( isModified() && isReadWrite() ) && m_mimeType == m_newMimeType )
|
|
{
|
|
kdDebug( 4610 ) << "copy image from " << m_file << " to " << kurl.prettyURL() << endl;
|
|
|
|
KIO::Job * job = KIO::copy( KURL( m_file ), kurl, isProgressInfoEnabled() );
|
|
emit started( job );
|
|
connect( job, TQT_SIGNAL( result( KIO::Job * ) ),
|
|
this, TQT_SLOT( slotResultSaveAs( KIO::Job * ) ) );
|
|
return true;
|
|
}
|
|
kdDebug( 4610 ) << "call KParts::ReadWritePart::saveAs( " << kurl.prettyURL() << " )" << endl;
|
|
|
|
bool ret = KParts::ReadWritePart::saveAs( kurl );
|
|
if( ret == false )
|
|
KMessageBox::error( m_pParentWidget, i18n( "The image could not be saved to disk. A possible causes is that you don't have permission to write to that file." ) );
|
|
return ret;
|
|
}
|
|
|
|
void KViewViewer::setModified( bool modified )
|
|
{
|
|
m_paSave->setEnabled( modified );
|
|
KImageViewer::Viewer::setModified( modified );
|
|
}
|
|
|
|
bool KViewViewer::openURL( const KURL & url )
|
|
{
|
|
kdDebug( 4610 ) << k_funcinfo << endl;
|
|
if ( !url.isValid() )
|
|
{
|
|
kdWarning( 4610 ) << "malformed URL " << url.prettyURL() << endl;
|
|
return false;
|
|
}
|
|
if ( !closeURL() )
|
|
{
|
|
kdDebug( 4610 ) << "closeURL didn't work out" << endl;
|
|
return false;
|
|
}
|
|
setModified( false );
|
|
m_url = url;
|
|
m_mimeType = m_pExtension->urlArgs().serviceType; // if this fails to
|
|
// find the right mime type it'll be determined in openFile()
|
|
if ( m_url.isLocalFile() )
|
|
{
|
|
emit started( 0 );
|
|
m_file = m_url.path();
|
|
kdDebug( 4610 ) << "open local file " << m_file << endl;
|
|
bool ret = openFile();
|
|
if( ret )
|
|
{
|
|
m_sCaption = m_url.prettyURL();
|
|
emit setWindowCaption( m_sCaption );
|
|
emit completed();
|
|
}
|
|
return ret;
|
|
}
|
|
else
|
|
{
|
|
m_sCaption = m_url.prettyURL();
|
|
emit setWindowCaption( m_sCaption );
|
|
m_bTemp = true;
|
|
// Use same extension as remote file. This is important for mimetype-determination (e.g. koffice)
|
|
TQString extension;
|
|
TQString fileName = url.fileName();
|
|
int extensionPos = fileName.findRev( '.' );
|
|
if ( extensionPos != -1 )
|
|
extension = fileName.mid( extensionPos ); // keep the '.'
|
|
delete m_pTempFile;
|
|
m_pTempFile = new KTempFile( TQString(), extension );
|
|
m_file = m_pTempFile->name();
|
|
|
|
m_pJob = KIO::get( m_url, m_pExtension->urlArgs().reload, isProgressInfoEnabled() );
|
|
emit started( m_pJob );
|
|
connect( m_pJob, TQT_SIGNAL( result( KIO::Job * ) ), TQT_SLOT( slotJobFinished ( KIO::Job * ) ) );
|
|
connect( m_pJob, TQT_SIGNAL( data( KIO::Job *, const TQByteArray & ) ), TQT_SLOT( slotData( KIO::Job *, const TQByteArray & ) ) );
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool KViewViewer::closeURL()
|
|
{
|
|
kdDebug( 4610 ) << k_funcinfo << endl;
|
|
abortLoad();
|
|
TQString file = m_file;
|
|
bool ret = KParts::ReadWritePart::closeURL();
|
|
if( ret )
|
|
if( ! file.isEmpty() )
|
|
{
|
|
kdDebug( 4610 ) << "remove " << file << " from KDirWatch\n";
|
|
m_pFileWatch->removeFile( file );
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void KViewViewer::newImage( const TQImage & newimg )
|
|
{
|
|
if( closeURL() )
|
|
{
|
|
m_url = "";
|
|
m_file = TQString();
|
|
m_sCaption = i18n( "Title caption when new image selected", "new image" );
|
|
m_pCanvas->setImage( newimg );
|
|
if( isReadWrite() )
|
|
setModified( true );
|
|
}
|
|
}
|
|
|
|
void KViewViewer::reload()
|
|
{
|
|
kdDebug( 4610 ) << k_funcinfo << endl;
|
|
|
|
if( isReadWrite() && isModified() )
|
|
if( ! queryClose() )
|
|
return;
|
|
|
|
//load from file
|
|
TQImage image( m_file );
|
|
m_pCanvas->setImage( image );
|
|
setModified( false );
|
|
}
|
|
|
|
bool KViewViewer::eventFilter( TQObject * o, TQEvent * e )
|
|
{
|
|
KImageViewer::Canvas * canvas = static_cast<KImageViewer::Canvas*>( o->qt_cast( "KImageViewer::Canvas" ) );
|
|
if( canvas )
|
|
{
|
|
// intercept drops onto the Canvas
|
|
switch( e->type() )
|
|
{
|
|
case TQEvent::DragEnter:
|
|
{
|
|
TQDragEnterEvent * ev = static_cast<TQDragEnterEvent*>( e );
|
|
kdDebug( 4610 ) << "DragEnter Event in the Canvas: " << endl;
|
|
for( int i = 0; ev->format( i ); ++i )
|
|
kdDebug( 4610 ) << " - " << ev->format( i ) << endl;
|
|
ev->accept( KURLDrag::canDecode( ev ) || TQImageDrag::canDecode( ev ) );
|
|
return true;
|
|
}
|
|
case TQEvent::Drop:
|
|
{
|
|
TQDropEvent * ev = static_cast<TQDropEvent*>( e );
|
|
kdDebug( 4610 ) << "Drop Event in the Canvas" << endl;
|
|
TQStringList l;
|
|
TQImage image;
|
|
if( KURLDrag::decodeToUnicodeUris( ev, l ) )
|
|
openURL( KURL( l.first() ) );
|
|
else if( TQImageDrag::decode( ev, image ) )
|
|
newImage( image );
|
|
return true;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return KImageViewer::Viewer::eventFilter( o, e );
|
|
}
|
|
|
|
void KViewViewer::abortLoad()
|
|
{
|
|
if ( m_pJob )
|
|
{
|
|
m_pJob->kill();
|
|
m_pJob = 0;
|
|
}
|
|
}
|
|
|
|
bool KViewViewer::openFile()
|
|
{
|
|
//m_pCanvas->setMaximumImageSize( TQSize( widget()->width(), widget()->height() ) );
|
|
if( m_pBuffer )
|
|
{
|
|
kdDebug( 4610 ) << k_funcinfo << " load from buffer\n";
|
|
//load from buffer
|
|
m_pBuffer->close();
|
|
if( m_pTempFile )
|
|
{
|
|
m_pTempFile->dataStream()->writeRawBytes( m_pBuffer->buffer().data(), m_pBuffer->buffer().size() );
|
|
m_pTempFile->close();
|
|
}
|
|
|
|
// determine Mime Type
|
|
if( m_mimeType.isNull() )
|
|
{
|
|
m_mimeType = KImageIO::mimeType( m_url.fileName() );
|
|
kdDebug( 4610 ) << "MimeType: " << m_mimeType << endl;
|
|
if( m_mimeType.isNull() )
|
|
{
|
|
m_mimeType = KMimeType::findByContent( m_pBuffer->buffer() )->name();
|
|
kdDebug( 4610 ) << "MimeType: " << m_mimeType << endl;
|
|
}
|
|
}
|
|
|
|
TQImage image( m_pBuffer->buffer() );
|
|
delete m_pBuffer;
|
|
m_pBuffer = 0;
|
|
if( ! image.isNull() )
|
|
{
|
|
TQSize size = image.size();
|
|
m_pCanvas->setImage( image, size );
|
|
}
|
|
else
|
|
{
|
|
emit setStatusBarText( i18n( "Unknown image format: %1" ).arg( m_url.prettyURL() ) );
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{ //load from local file
|
|
kdDebug( 4610 ) << k_funcinfo << " load from file: " << m_file << endl;
|
|
if( ! TQFile::exists( m_file ) )
|
|
{
|
|
emit setStatusBarText( i18n( "No such file: %1" ).arg( m_file ) );
|
|
return false;
|
|
}
|
|
if( TQImage::imageFormat( m_file ) == 0 )
|
|
{
|
|
emit setStatusBarText( i18n( "Unknown image format: %1" ).arg( m_file ) );
|
|
return false;
|
|
}
|
|
// determine Mime Type
|
|
if( m_mimeType.isNull() )
|
|
{
|
|
m_mimeType = KImageIO::mimeType( m_file );
|
|
kdDebug( 4610 ) << "MimeType: " << m_mimeType << endl;
|
|
}
|
|
|
|
//load from file
|
|
TQImage image( m_file );
|
|
TQSize size = image.size();
|
|
m_pCanvas->setImage( image, size );
|
|
}
|
|
m_pFileWatch->addFile( m_file );
|
|
emit imageOpened( m_url );
|
|
return true;
|
|
}
|
|
|
|
bool KViewViewer::saveFile()
|
|
{
|
|
kdDebug( 4610 ) << k_funcinfo << endl;
|
|
// two possibilities:
|
|
//
|
|
// 1. The image should be saved as an exact copy of the loaded one (this
|
|
// is useful if you downloaded an image from the net and want to save it
|
|
// locally) - this can happen only in saveAs() so only 2. applies here:
|
|
//
|
|
// 2. The image should be saved in a different format or was modified, so
|
|
// that copying isn't possible anymore.
|
|
|
|
const TQImage * image = m_pCanvas->image();
|
|
if( ! image )
|
|
return false;
|
|
|
|
if( ! m_newMimeType.isNull() )
|
|
{
|
|
m_mimeType = m_newMimeType;
|
|
m_newMimeType = TQString();
|
|
}
|
|
TQString type = KImageIO::typeForMime( m_mimeType );
|
|
kdDebug( 4610 ) << "save m_pCanvas->image() to " << m_file << " as " << type << endl;
|
|
int quality = 100; // TODO: ask user for quality. Keep it at 100 so that our
|
|
// users don't lose quality when working with KView.
|
|
|
|
m_pFileWatch->removeFile( m_file );
|
|
bool ret = image->save( m_file, type.latin1(), quality );
|
|
m_pFileWatch->addFile( m_file );
|
|
return ret;
|
|
}
|
|
|
|
void KViewViewer::setupActions()
|
|
{
|
|
m_paZoomIn = new KAction( i18n( "Zoom In" ), "viewmag+", KStdAccel::shortcut( KStdAccel::ZoomIn ), this,
|
|
TQT_SLOT( slotZoomIn() ), actionCollection(), "zoomin" );
|
|
m_paZoomOut = new KAction( i18n( "Zoom Out" ), "viewmag-", KStdAccel::shortcut( KStdAccel::ZoomOut ), this,
|
|
TQT_SLOT( slotZoomOut() ), actionCollection(), "zoomout" );
|
|
|
|
m_paZoom = new KSelectAction( i18n( "Zoom" ), "viewmag", 0, actionCollection(), "view_zoom" );
|
|
connect( m_paZoom, TQT_SIGNAL( activated( const TQString & ) ), this, TQT_SLOT( setZoom( const TQString & ) ) );
|
|
m_paZoom->setEditable( true );
|
|
m_paZoom->clear();
|
|
m_paZoom->setItems( TQStringList::split( '|', "20%|25%|33%|50%|75%|100%|125%|150%|200%|250%|300%|350%|400%|450%|500%" ) );
|
|
m_paZoom->setCurrentItem( 5 );
|
|
|
|
m_paFlipMenu = new KActionMenu( i18n( "&Flip" ), actionCollection(), "flip" );
|
|
m_paFlipV = new KAction( i18n( "&Vertical" ), Key_V, this, TQT_SLOT( slotFlipV() ), actionCollection(), "flip_vertical" );
|
|
m_paFlipH = new KAction( i18n( "&Horizontal" ), Key_H, this, TQT_SLOT( slotFlipH() ), actionCollection(), "flip_horizontal" );
|
|
m_paFlipMenu->insert( m_paFlipV );
|
|
m_paFlipMenu->insert( m_paFlipH );
|
|
|
|
m_paRotateCCW = new KAction( i18n( "Ro&tate Counter-Clockwise" ), "rotate_ccw", 0, this,
|
|
TQT_SLOT( slotRotateCCW() ), actionCollection(), "rotateCCW" );
|
|
m_paRotateCW = new KAction( i18n( "Rotate Clockwise" ), "rotate_cw", 0, this,
|
|
TQT_SLOT( slotRotateCW() ), actionCollection(), "rotateCW" );
|
|
m_paSave = KStdAction::save( this, TQT_SLOT( slotSave() ), actionCollection() );
|
|
m_paSave->setEnabled( false );
|
|
m_paSaveAs = KStdAction::saveAs( this, TQT_SLOT( slotSaveAs() ), actionCollection() );
|
|
|
|
m_paFitToWin = new KAction( i18n( "Fit Image to Window" ), 0, 0, this,
|
|
TQT_SLOT( slotFitToWin() ), actionCollection(), "fittowin" );
|
|
m_paZoomIn->setEnabled( false );
|
|
m_paZoomOut->setEnabled( false );
|
|
m_paZoom->setEnabled( false );
|
|
m_paRotateCCW->setEnabled( false );
|
|
m_paRotateCW->setEnabled( false );
|
|
m_paSaveAs->setEnabled( false );
|
|
m_paFitToWin->setEnabled( false );
|
|
m_paFlipMenu->setEnabled( false );
|
|
m_paFlipV->setEnabled( false );
|
|
m_paFlipH->setEnabled( false );
|
|
connect( widget(), TQT_SIGNAL( hasImage( bool ) ), m_paZoomIn, TQT_SLOT( setEnabled( bool ) ) );
|
|
connect( widget(), TQT_SIGNAL( hasImage( bool ) ), m_paZoomOut, TQT_SLOT( setEnabled( bool ) ) );
|
|
connect( widget(), TQT_SIGNAL( hasImage( bool ) ), m_paZoom, TQT_SLOT( setEnabled( bool ) ) );
|
|
connect( widget(), TQT_SIGNAL( hasImage( bool ) ), m_paRotateCCW, TQT_SLOT( setEnabled( bool ) ) );
|
|
connect( widget(), TQT_SIGNAL( hasImage( bool ) ), m_paRotateCW, TQT_SLOT( setEnabled( bool ) ) );
|
|
connect( widget(), TQT_SIGNAL( hasImage( bool ) ), m_paSaveAs, TQT_SLOT( setEnabled( bool ) ) );
|
|
connect( widget(), TQT_SIGNAL( hasImage( bool ) ), m_paFitToWin, TQT_SLOT( setEnabled( bool ) ) );
|
|
connect( widget(), TQT_SIGNAL( hasImage( bool ) ), m_paFlipMenu, TQT_SLOT( setEnabled( bool ) ) );
|
|
connect( widget(), TQT_SIGNAL( hasImage( bool ) ), m_paFlipV, TQT_SLOT( setEnabled( bool ) ) );
|
|
connect( widget(), TQT_SIGNAL( hasImage( bool ) ), m_paFlipH, TQT_SLOT( setEnabled( bool ) ) );
|
|
|
|
m_paShowScrollbars = new KToggleAction( i18n( "Show Scrollbars" ), 0, this, TQT_SLOT( slotToggleScrollbars() ),
|
|
actionCollection(), "show_scrollbars" );
|
|
m_paShowScrollbars->setCheckedState(i18n("Hide Scrollbars"));
|
|
}
|
|
|
|
void KViewViewer::guiActivateEvent( KParts::GUIActivateEvent * event )
|
|
{
|
|
ReadWritePart::guiActivateEvent( event );
|
|
bool enabled = m_pCanvas->image() ? true : false;
|
|
emit m_pExtension->enableAction( "del", enabled );
|
|
emit m_pExtension->enableAction( "print", enabled );
|
|
if( ! enabled )
|
|
{
|
|
m_sCaption = i18n( "Title caption when no image loaded", "no image loaded" );
|
|
emit setWindowCaption( m_sCaption );
|
|
}
|
|
}
|
|
|
|
void KViewViewer::readSettings()
|
|
{
|
|
KConfigGroup cfgGroup( instance()->config(), "Settings" );
|
|
m_pCanvas->setFastScale( ! cfgGroup.readBoolEntry( "Smooth Scaling", ! m_pCanvas->fastScale() ) );
|
|
m_pCanvas->setKeepAspectRatio( cfgGroup.readBoolEntry( "Keep Aspect Ratio", m_pCanvas->keepAspectRatio() ) );
|
|
m_pCanvas->setCentered( cfgGroup.readBoolEntry( "Center Image", m_pCanvas->centered() ) );
|
|
|
|
m_pCanvas->setBgColor( cfgGroup.readColorEntry( "Background Color", &m_pCanvas->bgColor() ) );
|
|
|
|
m_pCanvas->setMinimumImageSize( TQSize( cfgGroup.readNumEntry( "Minimum Width", m_pCanvas->minimumImageSize().width() ),
|
|
cfgGroup.readNumEntry( "Minimum Height", m_pCanvas->minimumImageSize().height() ) ) );
|
|
m_pCanvas->setMaximumImageSize( TQSize( cfgGroup.readNumEntry( "Maximum Width", m_pCanvas->maximumImageSize().width() ),
|
|
cfgGroup.readNumEntry( "Maximum Height", m_pCanvas->maximumImageSize().height() ) ) );
|
|
|
|
KConfigGroup blendConfig( instance()->config(), "Blend Effects" );
|
|
m_vEffects.clear();
|
|
for( unsigned int i = 1; i <= m_pCanvas->numOfBlendEffects(); ++i )
|
|
{
|
|
if( blendConfig.readBoolEntry( TQString::number( i ), false ) )
|
|
m_vEffects.push_back( i );
|
|
}
|
|
// and now tell the canvas what blend effect to use
|
|
switchBlendEffect();
|
|
loadPlugins();
|
|
}
|
|
|
|
void KViewViewer::writeSettings()
|
|
{
|
|
KConfigGroup cfgGroup( instance()->config(), "Settings" );
|
|
cfgGroup.writeEntry( "hideScrollbars", ! m_paShowScrollbars->isChecked() );
|
|
}
|
|
|
|
void KViewViewer::zoomChanged( double zoom )
|
|
{
|
|
kdDebug( 4610 ) << k_funcinfo << endl;
|
|
emit setWindowCaption( m_sCaption + TQString( " (%1%)" ).arg( zoom * 100, 0, 'f', 0 ) );
|
|
updateZoomMenu( zoom );
|
|
}
|
|
|
|
void KViewViewer::slotJobFinished( KIO::Job * job )
|
|
{
|
|
assert( job == m_pJob );
|
|
m_pJob = 0;
|
|
if (job->error())
|
|
emit canceled( job->errorString() );
|
|
else
|
|
{
|
|
openFile();
|
|
emit completed();
|
|
}
|
|
}
|
|
|
|
void KViewViewer::slotData( KIO::Job *, const TQByteArray & data )
|
|
{
|
|
if( ! m_pBuffer )
|
|
{
|
|
m_pBuffer = new TQBuffer();
|
|
m_pBuffer->open( IO_ReadWrite );
|
|
}
|
|
m_pBuffer->writeBlock( data.data(), data.size() );
|
|
|
|
//show partial image XXX: is this really the way to do it?
|
|
//No. :) It takes forever like this.
|
|
//OK. So I really have to look at khtml...
|
|
//later...
|
|
//m_pCanvas->setImage( TQImage( m_pBuffer->buffer() ) );
|
|
}
|
|
|
|
void KViewViewer::slotSave()
|
|
{
|
|
kdDebug( 4610 ) << k_funcinfo << endl;
|
|
if( ! save() )
|
|
KMessageBox::error( m_pParentWidget, i18n( "The image could not be saved to disk. A possible causes is that you don't have permission to write to that file." ) );
|
|
}
|
|
|
|
void KViewViewer::slotSaveAs()
|
|
{
|
|
kdDebug( 4610 ) << k_funcinfo << endl;
|
|
KFileDialog dlg( TQString(), TQString(), widget(), "filedialog", true );
|
|
dlg.setMimeFilter( KImageIO::mimeTypes( KImageIO::Writing ) );
|
|
dlg.setSelection( m_url.fileName() );
|
|
dlg.setCaption( i18n( "Save As" ) );
|
|
dlg.setOperationMode( KFileDialog::Saving );
|
|
dlg.exec();
|
|
KURL url = dlg.selectedURL();
|
|
m_newMimeType = dlg.currentMimeFilter();
|
|
if( m_newMimeType.isEmpty() )
|
|
m_newMimeType = KImageIO::mimeType( url.path() );
|
|
kdDebug( 4610 ) << k_funcinfo << "m_newMimeType = " << m_newMimeType << endl;
|
|
if( url.isValid() )
|
|
KRecentDocument::add( url );
|
|
saveAs( url );
|
|
}
|
|
|
|
void KViewViewer::slotZoomIn()
|
|
{
|
|
double zoom = m_pCanvas->zoom() * 1.1;
|
|
if (zoom < 0.01) zoom=0.01 ;
|
|
m_pCanvas->setZoom( zoom );
|
|
}
|
|
|
|
void KViewViewer::slotZoomOut()
|
|
{
|
|
double zoom = m_pCanvas->zoom() / 1.1;
|
|
if (zoom < 0.01) zoom=0.01 ;
|
|
m_pCanvas->setZoom( zoom );
|
|
}
|
|
|
|
void KViewViewer::setZoom( const TQString & newZoom )
|
|
{
|
|
kdDebug( 4610 ) << k_funcinfo << newZoom << endl;
|
|
double zoom;
|
|
TQString z = newZoom;
|
|
z.remove( z.find( '%' ), 1 );
|
|
if( newZoom == "33%" )
|
|
zoom = 1.0 / 3.0;
|
|
else
|
|
zoom = KGlobal::locale()->readNumber( z ) / 100;
|
|
|
|
m_pCanvas->setZoom( zoom );
|
|
}
|
|
|
|
void KViewViewer::updateZoomMenu( double zoom )
|
|
{
|
|
TQStringList lst;
|
|
if( zoom > 0.0 )
|
|
{
|
|
//lst << i18n( "Maxpect" );
|
|
TQValueList<int> list;
|
|
TQString z;
|
|
int val;
|
|
bool ok;
|
|
TQStringList itemsList = m_paZoom->items();
|
|
for( TQStringList::Iterator it = itemsList.begin(); it != itemsList.end(); ++it )
|
|
{
|
|
z = ( *it ).replace( TQRegExp( "%" ), "" );
|
|
z = z.simplifyWhiteSpace();
|
|
val = z.toInt( &ok );
|
|
if( ok && val > 0 && list.contains( val ) == 0 )
|
|
list << val;
|
|
}
|
|
val = TQString::number( zoom * 100, 'f', 0 ).toInt(); // round/lround from math.h doesn't work - dunno
|
|
if( list.contains( val ) == 0 )
|
|
list.append( val );
|
|
|
|
qHeapSort( list );
|
|
|
|
for( TQValueList<int>::Iterator it = list.begin(); it != list.end(); ++it )
|
|
lst << TQString::number( *it ) + '%';
|
|
m_paZoom->setItems( lst );
|
|
}
|
|
|
|
// first look if it's a new value (not in the list yet)
|
|
TQString z = TQString( "%1%" ).arg( zoom * 100, 0, 'f', 0 );
|
|
TQStringList items = m_paZoom->items();
|
|
int idx = items.findIndex( z );
|
|
if( -1 == idx )
|
|
{
|
|
// not found XXX: remove when done
|
|
kdDebug( 4610 ) << "zoom value not in the list: " << z << endl;
|
|
kdDebug( 4610 ) << "here's the list:\n- " << items.join( "\n- " ) << endl;
|
|
}
|
|
else
|
|
{
|
|
// already in the list
|
|
kdDebug( 4610 ) << "zoom value already in the list: " << z << endl;
|
|
// make that one selected
|
|
m_paZoom->setCurrentItem( idx );
|
|
}
|
|
}
|
|
|
|
void KViewViewer::slotFlipH()
|
|
{
|
|
m_pCanvas->flipVertical( isReadWrite() );
|
|
}
|
|
|
|
void KViewViewer::slotFlipV()
|
|
{
|
|
m_pCanvas->flipHorizontal( isReadWrite() );
|
|
}
|
|
|
|
void KViewViewer::slotRotateCCW()
|
|
{
|
|
m_pCanvas->rotate( -90.0, isReadWrite() );
|
|
}
|
|
|
|
void KViewViewer::slotRotateCW()
|
|
{
|
|
m_pCanvas->rotate( 90.0, isReadWrite() );
|
|
}
|
|
|
|
void KViewViewer::slotFitToWin()
|
|
{
|
|
m_pCanvas->boundImageTo( widget()->size() );
|
|
}
|
|
|
|
void KViewViewer::slotDel()
|
|
{
|
|
//just in case m_url get's modified while closing
|
|
KURL urltodel = m_url;
|
|
if( closeURL() )
|
|
{
|
|
setModified( false );
|
|
KIO::file_delete( urltodel );
|
|
m_pCanvas->clear();
|
|
}
|
|
}
|
|
|
|
class PopupGUIClient : public KXMLGUIClient
|
|
{
|
|
public:
|
|
PopupGUIClient( KInstance *inst, const TQString &doc )
|
|
{
|
|
setInstance( inst );
|
|
setXML( doc );
|
|
}
|
|
};
|
|
|
|
void KViewViewer::slotPopupMenu( const TQPoint &pos )
|
|
{
|
|
KXMLGUIClient *popupGUIClient = new PopupGUIClient( instance(), m_popupDoc );
|
|
|
|
(void) new KAction( i18n( "Save Image As..." ), 0, this, TQT_SLOT( slotSaveAs() ),
|
|
popupGUIClient->actionCollection(), "saveimageas" );
|
|
|
|
// ### HACK treat the image as dir to get the back/fwd/reload buttons (Simon)
|
|
emit m_pExtension->popupMenu( popupGUIClient, pos, m_url, m_mimeType, S_IFDIR );
|
|
|
|
delete popupGUIClient;
|
|
}
|
|
|
|
void KViewViewer::slotResultSaveAs( KIO::Job *job )
|
|
{
|
|
if ( job->error() )
|
|
{
|
|
emit canceled( job->errorString() );
|
|
//job->showErrorDialog( widget() );
|
|
}
|
|
else
|
|
{
|
|
emit completed();
|
|
KIO::CopyJob * cjob = ::tqqt_cast<KIO::CopyJob*>( job );
|
|
if( cjob )
|
|
{
|
|
m_url = cjob->destURL();
|
|
m_sCaption = m_url.prettyURL();
|
|
}
|
|
else
|
|
m_sCaption = "";
|
|
emit setWindowCaption( m_sCaption );
|
|
}
|
|
|
|
// Now we have to delete the tempfile if it exists and if the current
|
|
// image position is on the local HD. If it's somewhere else we keep the
|
|
// tempfile in case the user calls saveAs() again.
|
|
if( m_url.isLocalFile() )
|
|
{
|
|
if( m_bTemp )
|
|
{
|
|
unlink( TQFile::encodeName( m_file ) );
|
|
m_bTemp = false;
|
|
}
|
|
m_file = m_url.path();
|
|
}
|
|
}
|
|
|
|
void KViewViewer::slotFileDirty( const TQString & )
|
|
{
|
|
if( isModified() && isReadWrite() )
|
|
{
|
|
KPassivePopup * pop = new KPassivePopup( m_pParentWidget );
|
|
TQVBox * vb = pop->standardView( i18n( "Load changed image? - %1" ).arg( kapp->aboutData()->programName() ),
|
|
TQString(), kapp->miniIcon() );
|
|
( void )new TQLabel( i18n( "The image %1 which you have modified has changed on disk.\n"
|
|
"Do you want to reload the file and lose your changes?\n"
|
|
"If you don't and subsequently save the image, you will lose the\n"
|
|
"changes that have already been saved." ).arg( url().fileName() ), vb );
|
|
TQWidget * hb = new TQWidget( vb );
|
|
TQHBoxLayout * layout = new TQHBoxLayout( hb );
|
|
layout->addItem( new TQSpacerItem( 0, 0, TQSizePolicy::Minimum, TQSizePolicy::Minimum ) );
|
|
KPushButton * yes = new KPushButton( i18n("Reload"), hb );
|
|
layout->addWidget( yes );
|
|
layout->addItem( new TQSpacerItem( 0, 0, TQSizePolicy::Minimum, TQSizePolicy::Minimum ) );
|
|
KPushButton * no = new KPushButton( i18n("Do Not Reload"), hb );
|
|
layout->addWidget( no );
|
|
layout->addItem( new TQSpacerItem( 0, 0, TQSizePolicy::Minimum, TQSizePolicy::Minimum ) );
|
|
connect( yes, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotReloadUnmodified() ) );
|
|
connect( yes, TQT_SIGNAL( clicked() ), pop, TQT_SLOT( hide() ) );
|
|
connect( no, TQT_SIGNAL( clicked() ), pop, TQT_SLOT( hide() ) );
|
|
pop->setView( vb );
|
|
pop->setTimeout( 0 );
|
|
pop->setAutoDelete( true );
|
|
pop->show();
|
|
kdDebug( 4610 ) << "popup returned\n";
|
|
}
|
|
else
|
|
reload();
|
|
}
|
|
|
|
void KViewViewer::slotReloadUnmodified()
|
|
{
|
|
setModified( false );
|
|
reload();
|
|
kdDebug( 4610 ) << "reload done\n";
|
|
}
|
|
|
|
void KViewViewer::slotToggleScrollbars()
|
|
{
|
|
m_pCanvas->hideScrollbars( ! m_paShowScrollbars->isChecked() );
|
|
}
|
|
|
|
void KViewViewer::loadPlugins()
|
|
{
|
|
KImageViewer::Viewer::loadPlugins( this, this, instance() );
|
|
if( factory() )
|
|
{
|
|
TQPtrList<KParts::Plugin> plugins = KParts::Plugin::pluginObjects( this );
|
|
KParts::Plugin * plugin;
|
|
for( plugin = plugins.first(); plugin; plugin = plugins.next() )
|
|
factory()->addClient( plugin );
|
|
}
|
|
}
|
|
|
|
void KViewViewer::switchBlendEffect()
|
|
{
|
|
if( m_vEffects.empty() )
|
|
m_pCanvas->setBlendEffect( 0 );
|
|
else
|
|
{
|
|
unsigned int num = KApplication::random() % m_vEffects.size();
|
|
m_pCanvas->setBlendEffect( m_vEffects[ num ] );
|
|
}
|
|
}
|
|
|
|
void KViewViewer::hasImage( bool b )
|
|
{
|
|
emit m_pExtension->enableAction( "del", b );
|
|
emit m_pExtension->enableAction( "print", b );
|
|
if( ! b )
|
|
{
|
|
m_sCaption = i18n( "Title caption when no image loaded", "No Image Loaded" );
|
|
emit setWindowCaption( m_sCaption );
|
|
}
|
|
}
|
|
|
|
// vim:sw=4:ts=4
|
|
|
|
#include "kviewviewer.moc"
|
|
|