00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "koeditorattachments.h"
00027
00028 #include <libkcal/incidence.h>
00029 #include <libkdepim/kpimurlrequesterdlg.h>
00030 #include <libkdepim/kfileio.h>
00031
00032 #include <klocale.h>
00033 #include <kdebug.h>
00034 #include <kmdcodec.h>
00035 #include <kmessagebox.h>
00036 #include <krun.h>
00037 #include <kurldrag.h>
00038 #include <ktempfile.h>
00039 #include <ktempdir.h>
00040 #include <kio/netaccess.h>
00041 #include <kmimetype.h>
00042 #include <kiconloader.h>
00043 #include <kfiledialog.h>
00044 #include <kstdaction.h>
00045 #include <kactioncollection.h>
00046 #include <kpopupmenu.h>
00047
00048 #include <qfile.h>
00049 #include <qlabel.h>
00050 #include <qlayout.h>
00051 #include <qlistview.h>
00052 #include <qpushbutton.h>
00053 #include <qdragobject.h>
00054 #include <qtooltip.h>
00055 #include <qwhatsthis.h>
00056 #include <qapplication.h>
00057 #include <qclipboard.h>
00058
00059 #include <cassert>
00060
00061 class AttachmentListItem : public KIconViewItem
00062 {
00063 public:
00064 AttachmentListItem( KCal::Attachment*att, QIconView *parent ) :
00065 KIconViewItem( parent )
00066 {
00067 if ( att ) {
00068 mAttachment = new KCal::Attachment( *att );
00069 } else {
00070 mAttachment = new KCal::Attachment( QString::null );
00071 }
00072 readAttachment();
00073 setDragEnabled( true );
00074 }
00075 ~AttachmentListItem() { delete mAttachment; }
00076 KCal::Attachment *attachment() const { return mAttachment; }
00077
00078 void setUri( const QString &uri )
00079 {
00080 mAttachment->setUri( uri );
00081 readAttachment();
00082 }
00083 void setData( const char *base64 )
00084 {
00085 mAttachment->setData( base64 );
00086 readAttachment();
00087 }
00088 void setMimeType( const QString &mime )
00089 {
00090 mAttachment->setMimeType( mime );
00091 readAttachment();
00092 }
00093 void setLabel( const QString &label )
00094 {
00095 mAttachment->setLabel( label );
00096 readAttachment();
00097 }
00098
00099 void readAttachment()
00100 {
00101 if ( mAttachment->isUri() )
00102 setText( mAttachment->uri() );
00103 else {
00104 if ( mAttachment->label().isEmpty() )
00105 setText( i18n("[Binary data]") );
00106 else
00107 setText( mAttachment->label() );
00108 }
00109 KMimeType::Ptr mt = KMimeType::mimeType( mAttachment->mimeType() );
00110 if ( mt ) {
00111 const QString iconName( mt->icon( QString(), false ) );
00112 QPixmap pix = KGlobal::iconLoader( )->loadIcon( iconName, KIcon::Small );
00113 if ( pix.isNull() )
00114 pix = KGlobal::iconLoader( )->loadIcon( "unknown", KIcon::Small );
00115 if ( !pix.isNull() )
00116 setPixmap( pix );
00117 }
00118 }
00119
00120 private:
00121 KCal::Attachment *mAttachment;
00122 };
00123
00124 AttachmentIconView::AttachmentIconView( KOEditorAttachments* parent )
00125 : KIconView( parent ),
00126 mParent( parent )
00127 {
00128 setSelectionMode( QIconView::Extended );
00129 setMode( KIconView::Select );
00130 setItemTextPos( QIconView::Right );
00131 setArrangement( QIconView::LeftToRight );
00132 setMaxItemWidth( QMAX(maxItemWidth(), 250) );
00133 setMinimumHeight( QMAX(fontMetrics().height(), 16) + 12 );
00134
00135 connect( this, SIGNAL( dropped ( QDropEvent *, const QValueList<QIconDragItem> & ) ),
00136 this, SLOT( handleDrop( QDropEvent *, const QValueList<QIconDragItem> & ) ) );
00137 }
00138
00139 AttachmentIconView::~AttachmentIconView()
00140 {
00141 for ( std::set<KTempDir*>::iterator it = mTempDirs.begin() ; it != mTempDirs.end() ; ++it ) {
00142 delete *it;
00143 }
00144 }
00145
00146 QDragObject * AttachmentIconView::dragObject()
00147 {
00148 KURL::List urls;
00149 for ( QIconViewItem *it = firstItem( ); it; it = it->nextItem( ) ) {
00150 if ( !it->isSelected() ) continue;
00151 AttachmentListItem * item = dynamic_cast<AttachmentListItem*>( it );
00152 if ( !item ) return 0;
00153 KCal::Attachment * att = item->attachment();
00154 assert( att );
00155 KURL url;
00156 if ( att->isUri() ) {
00157 url.setPath( att->uri() );
00158 } else {
00159 KTempDir * tempDir = new KTempDir();
00160 tempDir->setAutoDelete( true );
00161 mTempDirs.insert( tempDir );
00162 QByteArray encoded;
00163 encoded.duplicate( att->data(), strlen(att->data()) );
00164 QByteArray decoded;
00165 KCodecs::base64Decode( encoded, decoded );
00166 const QString fileName = tempDir->name( ) + "/" + att->label();
00167 KPIM::kByteArrayToFile( decoded, fileName, false, false, false );
00168 url.setPath( fileName );
00169 }
00170 urls << url;
00171 }
00172 KURLDrag *drag = new KURLDrag( urls, this );
00173 return drag;
00174 }
00175
00176 void AttachmentIconView::handleDrop( QDropEvent *event, const QValueList<QIconDragItem> & list )
00177 {
00178 Q_UNUSED( list );
00179 mParent->handlePasteOrDrop( event );
00180 }
00181
00182
00183 void AttachmentIconView::dragMoveEvent( QDragMoveEvent *event )
00184 {
00185 mParent->dragMoveEvent( event );
00186 }
00187
00188 void AttachmentIconView::contentsDragMoveEvent( QDragMoveEvent *event )
00189 {
00190 mParent->dragMoveEvent( event );
00191 }
00192
00193 void AttachmentIconView::contentsDragEnterEvent( QDragEnterEvent *event )
00194 {
00195 mParent->dragMoveEvent( event );
00196 }
00197
00198 void AttachmentIconView::dragEnterEvent( QDragEnterEvent *event )
00199 {
00200 mParent->dragEnterEvent( event );
00201 }
00202
00203 KOEditorAttachments::KOEditorAttachments( int spacing, QWidget *parent,
00204 const char *name )
00205 : QWidget( parent, name )
00206 {
00207 QBoxLayout *topLayout = new QHBoxLayout( this );
00208 topLayout->setSpacing( spacing );
00209
00210 QLabel *label = new QLabel( i18n("Attachments:"), this );
00211 topLayout->addWidget( label );
00212
00213 mAttachments = new AttachmentIconView( this );
00214 QWhatsThis::add( mAttachments,
00215 i18n("Displays a list of current items (files, mail, etc.) "
00216 "that have been associated with this event or to-do. ") );
00217 topLayout->addWidget( mAttachments );
00218 connect( mAttachments, SIGNAL( doubleClicked( QIconViewItem * ) ),
00219 SLOT( showAttachment( QIconViewItem * ) ) );
00220 connect( mAttachments, SIGNAL(selectionChanged()),
00221 SLOT(selectionChanged()) );
00222 connect( mAttachments, SIGNAL(contextMenuRequested(QIconViewItem*,const QPoint&)),
00223 SLOT(contextMenu(QIconViewItem*,const QPoint&)) );
00224
00225 mAddMenu = new KPopupMenu( this );
00226 mContextMenu = new KPopupMenu( this );
00227
00228 KActionCollection* ac = new KActionCollection( this, this );
00229
00230 mOpenAction = new KAction( i18n("View"), 0, this, SLOT(slotShow()), ac );
00231 mOpenAction->plug( mContextMenu );
00232 mContextMenu->insertSeparator();
00233
00234 mCopyAction = KStdAction::copy(this, SLOT(slotCopy( ) ), ac );
00235 mCopyAction->plug( mContextMenu );
00236 mCutAction = KStdAction::cut(this, SLOT(slotCut( ) ), ac );
00237 mCutAction->plug( mContextMenu );
00238 KAction *action = KStdAction::paste(this, SLOT(slotPaste( ) ), ac );
00239 action->plug( mContextMenu );
00240
00241 action = new KAction( i18n("&Attach File..."), 0, this, SLOT(slotAddData()), ac );
00242 action->setWhatsThis( i18n("Shows a dialog used to select an attachment "
00243 "to add to this event or to-do as link as inline data.") );
00244 action->plug( mAddMenu );
00245 action = new KAction( i18n("Attach &Link..."), 0, this, SLOT(slotAdd()), ac );
00246 action->setWhatsThis( i18n("Shows a dialog used to select an attachment "
00247 "to add to this event or to-do as link.") );
00248 action->plug( mAddMenu );
00249
00250 QPushButton *addButton = new QPushButton( this );
00251 addButton->setIconSet( SmallIconSet( "add" ) );
00252 addButton->setPopup( mAddMenu );
00253 topLayout->addWidget( addButton );
00254
00255 mRemoveBtn = new QPushButton( this );
00256 mRemoveBtn->setIconSet( SmallIconSet( "remove" ) );
00257 QToolTip::add( mRemoveBtn, i18n("&Remove") );
00258 QWhatsThis::add( mRemoveBtn,
00259 i18n("Removes the attachment selected in the list above "
00260 "from this event or to-do.") );
00261 topLayout->addWidget( mRemoveBtn );
00262 connect( mRemoveBtn, SIGNAL( clicked() ), SLOT( slotRemove() ) );
00263
00264 selectionChanged();
00265 setAcceptDrops( true );
00266 }
00267
00268 KOEditorAttachments::~KOEditorAttachments()
00269 {
00270 }
00271
00272 bool KOEditorAttachments::hasAttachments()
00273 {
00274 return mAttachments->count() != 0;
00275 }
00276
00277 void KOEditorAttachments::dragMoveEvent( QDragMoveEvent *event )
00278 {
00279 event->accept( KURLDrag::canDecode( event ) || QTextDrag::canDecode( event ) );
00280 }
00281
00282 void KOEditorAttachments::dragEnterEvent( QDragEnterEvent* event )
00283 {
00284 dragMoveEvent( event );
00285 }
00286
00287 void KOEditorAttachments::handlePasteOrDrop( QMimeSource* source )
00288 {
00289 KURL::List urls;
00290 QString text;
00291 if ( KURLDrag::decode( source, urls ) ) {
00292 const bool asUri = KMessageBox::questionYesNo( this,
00293 i18n("Do you want to link to the attachments, or include them in the event?"),
00294 i18n("Attach as link?"), i18n("As Link"), i18n("As File") ) == KMessageBox::Yes;
00295 for ( KURL::List::ConstIterator it = urls.begin(); it != urls.end(); ++it ) {
00296 addAttachment( (*it).url(), QString::null, asUri );
00297 }
00298 } else if ( QTextDrag::decode( source, text ) ) {
00299 QStringList lst = QStringList::split( '\n', text );
00300 for ( QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it ) {
00301 addAttachment( (*it) );
00302 }
00303 }
00304 }
00305
00306 void KOEditorAttachments::dropEvent( QDropEvent* event )
00307 {
00308 handlePasteOrDrop( event );
00309 }
00310
00311 void KOEditorAttachments::showAttachment( QIconViewItem *item )
00312 {
00313 AttachmentListItem *attitem = static_cast<AttachmentListItem*>(item);
00314 if ( !attitem || !attitem->attachment() ) return;
00315
00316 KCal::Attachment *att = attitem->attachment();
00317 if ( att->isUri() ) {
00318 emit openURL( att->uri() );
00319 } else {
00320 KTempFile f;
00321 if ( !f.file() )
00322 return;
00323 QByteArray encoded;
00324 encoded.duplicate( att->data(), strlen(att->data()) );
00325 QByteArray decoded;
00326 KCodecs::base64Decode( encoded, decoded );
00327 f.file()->writeBlock( decoded );
00328 f.file()->close();
00329 KRun::runURL( f.name(), att->mimeType(), true, false );
00330 }
00331 }
00332
00333 void KOEditorAttachments::slotAdd()
00334 {
00335 KURL uri = KPimURLRequesterDlg::getURL( QString::null, i18n(
00336 "URL (e.g. a web page) or file to be attached (only "
00337 "the link will be attached, not the file itself):"), this,
00338 i18n("Add Attachment") );
00339 if ( !uri.isEmpty() ) {
00340 addAttachment( uri );
00341 }
00342 }
00343
00344 void KOEditorAttachments::slotAddData()
00345 {
00346 KURL uri = KFileDialog::getOpenFileName( QString(), QString(), this, i18n("Add Attachment") );
00347 if ( !uri.isEmpty() ) {
00348 addAttachment( uri, QString::null, false );
00349 }
00350 }
00351
00352 void KOEditorAttachments::slotEdit()
00353 {
00354 QIconViewItem *item = mAttachments->currentItem();
00355 AttachmentListItem *attitem = static_cast<AttachmentListItem*>(item);
00356 if ( !attitem || !attitem->attachment() ) return;
00357
00358 KCal::Attachment *att = attitem->attachment();
00359 if ( att->isUri() ) {
00360 KURL uri = KPimURLRequesterDlg::getURL( att->uri(), i18n(
00361 "URL (e.g. a web page) or file to be attached (only "
00362 "the link will be attached, not the file itself):"), this,
00363 i18n("Edit Attachment") );
00364
00365 if ( !uri.isEmpty() )
00366 attitem->setUri( uri.url() );
00367 } else {
00368 KURL uri = KPimURLRequesterDlg::getURL( QString::null, i18n(
00369 "File to be attached:"), this, i18n("Add Attachment") );
00370 if ( !uri.isEmpty() ) {
00371 QString tmpFile;
00372 if ( KIO::NetAccess::download( uri, tmpFile, this ) ) {
00373 QFile f( tmpFile );
00374 if ( !f.open( IO_ReadOnly ) )
00375 return;
00376 QByteArray data = f.readAll();
00377 f.close();
00378 attitem->setData( KCodecs::base64Encode( data ) );
00379 attitem->setMimeType( KIO::NetAccess::mimetype( uri, this ) );
00380 QString label = uri.fileName();
00381 if ( label.isEmpty() )
00382 label = uri.prettyURL();
00383 attitem->setLabel( label );
00384 KIO::NetAccess::removeTempFile( tmpFile );
00385 }
00386 }
00387 }
00388 }
00389
00390 void KOEditorAttachments::slotRemove()
00391 {
00392 QValueList<QIconViewItem*> selected;
00393 for ( QIconViewItem *it = mAttachments->firstItem( ); it; it = it->nextItem( ) ) {
00394 if ( !it->isSelected() ) continue;
00395 selected << it;
00396 }
00397 if ( selected.isEmpty() || KMessageBox::warningContinueCancel(this,
00398 selected.count() == 1?i18n("This item will be permanently deleted."):
00399 i18n("The selected items will be permanently deleted."),
00400 i18n("KOrganizer Confirmation"),KStdGuiItem::del()) != KMessageBox::Continue )
00401 return;
00402
00403 for ( QValueList<QIconViewItem*>::iterator it( selected.begin() ), end( selected.end() ); it != end ; ++it ) {
00404 delete *it;
00405 }
00406 }
00407
00408 void KOEditorAttachments::slotShow()
00409 {
00410 for ( QIconViewItem *it = mAttachments->firstItem(); it; it = it->nextItem() ) {
00411 if ( !it->isSelected() )
00412 continue;
00413 showAttachment( it );
00414 }
00415 }
00416
00417 void KOEditorAttachments::setDefaults()
00418 {
00419 mAttachments->clear();
00420 }
00421
00422 void KOEditorAttachments::addAttachment( const KURL &uri,
00423 const QString &mimeType, bool asUri )
00424 {
00425 AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
00426 if ( asUri ) {
00427 item->setUri( uri.url() );
00428 if ( !mimeType.isEmpty() ) item->setMimeType( mimeType );
00429 } else {
00430 QString tmpFile;
00431 if ( KIO::NetAccess::download( uri, tmpFile, this ) ) {
00432 QFile f( tmpFile );
00433 if ( !f.open( IO_ReadOnly ) )
00434 return;
00435 QByteArray data = f.readAll();
00436 f.close();
00437 item->setData( KCodecs::base64Encode( data ) );
00438 if ( !mimeType.isEmpty() )
00439 item->setMimeType( mimeType );
00440 else
00441 item->setMimeType( KIO::NetAccess::mimetype( uri, this ) );
00442 QString label = uri.fileName();
00443 if ( label.isEmpty() )
00444 label = uri.prettyURL();
00445 item->setLabel( label );
00446 KIO::NetAccess::removeTempFile( tmpFile );
00447 }
00448 }
00449 }
00450
00451
00452 void KOEditorAttachments::addAttachment( KCal::Attachment *attachment )
00453 {
00454 new AttachmentListItem( attachment, mAttachments );
00455 }
00456
00457 void KOEditorAttachments::readIncidence( KCal::Incidence *i )
00458 {
00459 mAttachments->clear();
00460
00461 KCal::Attachment::List attachments = i->attachments();
00462 KCal::Attachment::List::ConstIterator it;
00463 for( it = attachments.begin(); it != attachments.end(); ++it ) {
00464 addAttachment( (*it) );
00465 }
00466 if ( mAttachments->count() > 0 ) {
00467 QTimer::singleShot( 0, mAttachments, SLOT(arrangeItemsInGrid()) );
00468 }
00469 }
00470
00471 void KOEditorAttachments::writeIncidence( KCal::Incidence *i )
00472 {
00473 i->clearAttachments();
00474
00475 QIconViewItem *item;
00476 AttachmentListItem *attitem;
00477 for( item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00478 attitem = static_cast<AttachmentListItem*>(item);
00479 if ( attitem )
00480 i->addAttachment( new KCal::Attachment( *(attitem->attachment() ) ) );
00481 }
00482 }
00483
00484
00485 void KOEditorAttachments::slotCopy()
00486 {
00487 QApplication::clipboard()->setData( mAttachments->dragObject(), QClipboard::Clipboard );
00488 }
00489
00490 void KOEditorAttachments::slotCut()
00491 {
00492 slotCopy();
00493 slotRemove();
00494 }
00495
00496 void KOEditorAttachments::slotPaste()
00497 {
00498 handlePasteOrDrop( QApplication::clipboard()->data() );
00499 }
00500
00501 void KOEditorAttachments::selectionChanged()
00502 {
00503 bool selected = false;
00504 for ( QIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00505 if ( item->isSelected() ) {
00506 selected = true;
00507 break;
00508 }
00509 }
00510 mRemoveBtn->setEnabled( selected );
00511 }
00512
00513 void KOEditorAttachments::contextMenu(QIconViewItem * item, const QPoint & pos)
00514 {
00515 const bool enable = item != 0;
00516 mOpenAction->setEnabled( enable );
00517 mCopyAction->setEnabled( enable );
00518 mCutAction->setEnabled( enable );
00519 mContextMenu->exec( pos );
00520 }
00521
00522 #include "koeditorattachments.moc"