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.
tdepim/korganizer/koeditorattachments.cpp

502 lines
16 KiB

/*
This file is part of KOrganizer.
Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
Copyright (c) 2005 Reinhold Kainhofer <reinhold@kainhofer.com>
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.
As a special exception, permission is given to link this program
with any edition of Qt, and distribute the resulting executable,
without including the source code for Qt in the source distribution.
*/
#include "koeditorattachments.h"
#include <libkcal/incidence.h>
#include <libkdepim/kpimurlrequesterdlg.h>
#include <libkdepim/kfileio.h>
#include <klocale.h>
#include <kdebug.h>
#include <kmdcodec.h>
#include <kmessagebox.h>
#include <kiconview.h>
#include <krun.h>
#include <kurldrag.h>
#include <ktempfile.h>
#include <ktempdir.h>
#include <kio/netaccess.h>
#include <kmimetype.h>
#include <kiconloader.h>
#include <kfiledialog.h>
#include <kstdaction.h>
#include <kactioncollection.h>
#include <kpopupmenu.h>
#include <qfile.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qlistview.h>
#include <qpushbutton.h>
#include <qdragobject.h>
#include <qtooltip.h>
#include <qwhatsthis.h>
#include <qapplication.h>
#include <qclipboard.h>
#include <cassert>
#include <set>
class AttachmentListItem : public KIconViewItem
{
public:
AttachmentListItem( KCal::Attachment*att, QIconView *parent ) :
KIconViewItem( parent )
{
if ( att ) {
mAttachment = new KCal::Attachment( *att );
} else {
mAttachment = new KCal::Attachment( QString::null );
}
readAttachment();
setDragEnabled( true );
}
~AttachmentListItem() { delete mAttachment; }
KCal::Attachment *attachment() const { return mAttachment; }
void setUri( const QString &uri )
{
mAttachment->setUri( uri );
readAttachment();
}
void setData( const char *base64 )
{
mAttachment->setData( base64 );
readAttachment();
}
void setMimeType( const QString &mime )
{
mAttachment->setMimeType( mime );
readAttachment();
}
void setLabel( const QString &label )
{
mAttachment->setLabel( label );
readAttachment();
}
void readAttachment()
{
if ( mAttachment->isUri() )
setText( mAttachment->uri() );
else {
if ( mAttachment->label().isEmpty() )
setText( i18n("[Binary data]") );
else
setText( mAttachment->label() );
}
KMimeType::Ptr mt = KMimeType::mimeType( mAttachment->mimeType() );
if ( mt ) {
const QString iconName( mt->icon( QString(), false ) );
QPixmap pix = KGlobal::iconLoader( )->loadIcon( iconName, KIcon::Small );
if ( pix.isNull() )
pix = KGlobal::iconLoader( )->loadIcon( "unknown", KIcon::Small );
if ( !pix.isNull() )
setPixmap( pix );
}
}
private:
KCal::Attachment *mAttachment;
};
class AttachmentIconView : public KIconView
{
friend class KOEditorAttachments;
public:
AttachmentIconView( KOEditorAttachments* parent=0 )
:KIconView( parent ),
mParent( parent )
{
setAcceptDrops( true );
setSelectionMode( QIconView::Extended );
setMode( KIconView::Select );
setItemTextPos( QIconView::Right );
setArrangement( QIconView::LeftToRight );
setMaxItemWidth( QMAX(maxItemWidth(), 250) );
setMinimumHeight( QMAX(fontMetrics().height(), 16) + 12 );
}
~AttachmentIconView()
{
for ( std::set<KTempDir*>::iterator it = mTempDirs.begin() ; it != mTempDirs.end() ; ++it ) {
delete *it;
}
}
protected:
QDragObject * dragObject()
{
KURL::List urls;
for ( QIconViewItem *it = firstItem( ); it; it = it->nextItem( ) ) {
if ( !it->isSelected() ) continue;
AttachmentListItem * item = dynamic_cast<AttachmentListItem*>( it );
if ( !item ) return 0;
KCal::Attachment * att = item->attachment();
assert( att );
KURL url;
if ( att->isUri() ) {
url.setPath( att->uri() );
} else {
KTempDir * tempDir = new KTempDir(); // will be deleted on editor close
tempDir->setAutoDelete( true );
mTempDirs.insert( tempDir );
QByteArray encoded;
encoded.duplicate( att->data(), strlen(att->data()) );
QByteArray decoded;
KCodecs::base64Decode( encoded, decoded );
const QString fileName = tempDir->name( ) + "/" + att->label();
KPIM::kByteArrayToFile( decoded, fileName, false, false, false );
url.setPath( fileName );
}
urls << url;
}
KURLDrag *drag = new KURLDrag( urls, this );
return drag;
}
void contentsDropEvent( QDropEvent* event )
{
mParent->handlePasteOrDrop( event );
}
private:
std::set<KTempDir*> mTempDirs;
KOEditorAttachments* mParent;
};
KOEditorAttachments::KOEditorAttachments( int spacing, QWidget *parent,
const char *name )
: QWidget( parent, name )
{
QBoxLayout *topLayout = new QHBoxLayout( this );
topLayout->setSpacing( spacing );
QLabel *label = new QLabel( i18n("Attachments:"), this );
topLayout->addWidget( label );
mAttachments = new AttachmentIconView( this );
QWhatsThis::add( mAttachments,
i18n("Displays a list of current items (files, mail, etc.) "
"that have been associated with this event or to-do. ") );
topLayout->addWidget( mAttachments );
connect( mAttachments, SIGNAL( doubleClicked( QIconViewItem * ) ),
SLOT( showAttachment( QIconViewItem * ) ) );
connect( mAttachments, SIGNAL(selectionChanged()),
SLOT(selectionChanged()) );
connect( mAttachments, SIGNAL(contextMenuRequested(QIconViewItem*,const QPoint&)),
SLOT(contextMenu(QIconViewItem*,const QPoint&)) );
mAddMenu = new KPopupMenu( this );
mContextMenu = new KPopupMenu( this );
KActionCollection* ac = new KActionCollection( this, this );
mOpenAction = new KAction( i18n("View"), 0, this, SLOT(slotShow()), ac );
mOpenAction->plug( mContextMenu );
mContextMenu->insertSeparator();
mCopyAction = KStdAction::copy(this, SLOT(slotCopy( ) ), ac );
mCopyAction->plug( mContextMenu );
mCutAction = KStdAction::cut(this, SLOT(slotCut( ) ), ac );
mCutAction->plug( mContextMenu );
KAction *action = KStdAction::paste(this, SLOT(slotPaste( ) ), ac );
action->plug( mContextMenu );
action = new KAction( i18n("&Attach File..."), 0, this, SLOT(slotAddData()), ac );
action->setWhatsThis( i18n("Shows a dialog used to select an attachment "
"to add to this event or to-do as link as inline data.") );
action->plug( mAddMenu );
action = new KAction( i18n("Attach &Link..."), 0, this, SLOT(slotAdd()), ac );
action->setWhatsThis( i18n("Shows a dialog used to select an attachment "
"to add to this event or to-do as link.") );
action->plug( mAddMenu );
QPushButton *addButton = new QPushButton( this );
addButton->setIconSet( SmallIconSet( "add" ) );
addButton->setPopup( mAddMenu );
topLayout->addWidget( addButton );
mRemoveBtn = new QPushButton( this );
mRemoveBtn->setIconSet( SmallIconSet( "remove" ) );
QToolTip::add( mRemoveBtn, i18n("&Remove") );
QWhatsThis::add( mRemoveBtn,
i18n("Removes the attachment selected in the list above "
"from this event or to-do.") );
topLayout->addWidget( mRemoveBtn );
connect( mRemoveBtn, SIGNAL( clicked() ), SLOT( slotRemove() ) );
selectionChanged();
setAcceptDrops( true );
}
KOEditorAttachments::~KOEditorAttachments()
{
}
bool KOEditorAttachments::hasAttachments()
{
return mAttachments->count() != 0;
}
void KOEditorAttachments::dragEnterEvent( QDragEnterEvent* event )
{
event->accept( KURLDrag::canDecode( event ) | QTextDrag::canDecode( event ) );
}
void KOEditorAttachments::handlePasteOrDrop( QMimeSource* source )
{
KURL::List urls;
QString text;
if ( KURLDrag::decode( source, urls ) ) {
const bool asUri = KMessageBox::questionYesNo( this,
i18n("Do you want to link to the attachments, or include them in the event?"),
i18n("Attach as link?"), i18n("As Link"), i18n("As File") ) == KMessageBox::Yes;
for ( KURL::List::ConstIterator it = urls.begin(); it != urls.end(); ++it ) {
addAttachment( (*it).url(), QString::null, asUri );
}
} else if ( QTextDrag::decode( source, text ) ) {
QStringList lst = QStringList::split( '\n', text );
for ( QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it ) {
addAttachment( (*it) );
}
}
}
void KOEditorAttachments::dropEvent( QDropEvent* event )
{
handlePasteOrDrop( event );
}
void KOEditorAttachments::showAttachment( QIconViewItem *item )
{
AttachmentListItem *attitem = static_cast<AttachmentListItem*>(item);
if ( !attitem || !attitem->attachment() ) return;
KCal::Attachment *att = attitem->attachment();
if ( att->isUri() ) {
emit openURL( att->uri() );
} else {
KTempFile f;
if ( !f.file() )
return;
QByteArray encoded;
encoded.duplicate( att->data(), strlen(att->data()) );
QByteArray decoded;
KCodecs::base64Decode( encoded, decoded );
f.file()->writeBlock( decoded );
f.file()->close();
KRun::runURL( f.name(), att->mimeType(), true, false );
}
}
void KOEditorAttachments::slotAdd()
{
KURL uri = KPimURLRequesterDlg::getURL( QString::null, i18n(
"URL (e.g. a web page) or file to be attached (only "
"the link will be attached, not the file itself):"), this,
i18n("Add Attachment") );
if ( !uri.isEmpty() ) {
addAttachment( uri );
}
}
void KOEditorAttachments::slotAddData()
{
KURL uri = KFileDialog::getOpenFileName( QString(), QString(), this, i18n("Add Attachment") );
if ( !uri.isEmpty() ) {
addAttachment( uri, QString::null, false );
}
}
void KOEditorAttachments::slotEdit()
{
QIconViewItem *item = mAttachments->currentItem();
AttachmentListItem *attitem = static_cast<AttachmentListItem*>(item);
if ( !attitem || !attitem->attachment() ) return;
KCal::Attachment *att = attitem->attachment();
if ( att->isUri() ) {
KURL uri = KPimURLRequesterDlg::getURL( att->uri(), i18n(
"URL (e.g. a web page) or file to be attached (only "
"the link will be attached, not the file itself):"), this,
i18n("Edit Attachment") );
if ( !uri.isEmpty() )
attitem->setUri( uri.url() );
} else {
KURL uri = KPimURLRequesterDlg::getURL( QString::null, i18n(
"File to be attached:"), this, i18n("Add Attachment") );
if ( !uri.isEmpty() ) {
QString tmpFile;
if ( KIO::NetAccess::download( uri, tmpFile, this ) ) {
QFile f( tmpFile );
if ( !f.open( IO_ReadOnly ) )
return;
QByteArray data = f.readAll();
f.close();
attitem->setData( KCodecs::base64Encode( data ) );
attitem->setMimeType( KIO::NetAccess::mimetype( uri, this ) );
QString label = uri.fileName();
if ( label.isEmpty() )
label = uri.prettyURL();
attitem->setLabel( label );
KIO::NetAccess::removeTempFile( tmpFile );
}
}
}
}
void KOEditorAttachments::slotRemove()
{
QValueList<QIconViewItem*> selected;
for ( QIconViewItem *it = mAttachments->firstItem( ); it; it = it->nextItem( ) ) {
if ( !it->isSelected() ) continue;
selected << it;
}
if ( selected.isEmpty() || KMessageBox::warningContinueCancel(this,
selected.count() == 1?i18n("This item will be permanently deleted."):
i18n("The selected items will be permanently deleted."),
i18n("KOrganizer Confirmation"),KStdGuiItem::del()) != KMessageBox::Continue )
return;
for ( QValueList<QIconViewItem*>::iterator it( selected.begin() ), end( selected.end() ); it != end ; ++it ) {
delete *it;
}
}
void KOEditorAttachments::slotShow()
{
for ( QIconViewItem *it = mAttachments->firstItem(); it; it = it->nextItem() ) {
if ( !it->isSelected() )
continue;
showAttachment( it );
}
}
void KOEditorAttachments::setDefaults()
{
mAttachments->clear();
}
void KOEditorAttachments::addAttachment( const KURL &uri,
const QString &mimeType, bool asUri )
{
AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
if ( asUri ) {
item->setUri( uri.url() );
if ( !mimeType.isEmpty() ) item->setMimeType( mimeType );
} else {
QString tmpFile;
if ( KIO::NetAccess::download( uri, tmpFile, this ) ) {
QFile f( tmpFile );
if ( !f.open( IO_ReadOnly ) )
return;
QByteArray data = f.readAll();
f.close();
item->setData( KCodecs::base64Encode( data ) );
if ( !mimeType.isEmpty() )
item->setMimeType( mimeType );
else
item->setMimeType( KIO::NetAccess::mimetype( uri, this ) );
QString label = uri.fileName();
if ( label.isEmpty() )
label = uri.prettyURL();
item->setLabel( label );
KIO::NetAccess::removeTempFile( tmpFile );
}
}
}
void KOEditorAttachments::addAttachment( KCal::Attachment *attachment )
{
new AttachmentListItem( attachment, mAttachments );
}
void KOEditorAttachments::readIncidence( KCal::Incidence *i )
{
mAttachments->clear();
KCal::Attachment::List attachments = i->attachments();
KCal::Attachment::List::ConstIterator it;
for( it = attachments.begin(); it != attachments.end(); ++it ) {
addAttachment( (*it) );
}
if ( mAttachments->count() > 0 ) {
QTimer::singleShot( 0, mAttachments, SLOT(arrangeItemsInGrid()) );
}
}
void KOEditorAttachments::writeIncidence( KCal::Incidence *i )
{
i->clearAttachments();
QIconViewItem *item;
AttachmentListItem *attitem;
for( item = mAttachments->firstItem(); item; item = item->nextItem() ) {
attitem = static_cast<AttachmentListItem*>(item);
if ( attitem )
i->addAttachment( new KCal::Attachment( *(attitem->attachment() ) ) );
}
}
void KOEditorAttachments::slotCopy()
{
QApplication::clipboard()->setData( mAttachments->dragObject(), QClipboard::Clipboard );
}
void KOEditorAttachments::slotCut()
{
slotCopy();
slotRemove();
}
void KOEditorAttachments::slotPaste()
{
handlePasteOrDrop( QApplication::clipboard()->data() );
}
void KOEditorAttachments::selectionChanged()
{
bool selected = false;
for ( QIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) {
if ( item->isSelected() ) {
selected = true;
break;
}
}
mRemoveBtn->setEnabled( selected );
}
void KOEditorAttachments::contextMenu(QIconViewItem * item, const QPoint & pos)
{
const bool enable = item != 0;
mOpenAction->setEnabled( enable );
mCopyAction->setEnabled( enable );
mCutAction->setEnabled( enable );
mContextMenu->exec( pos );
}
#include "koeditorattachments.moc"