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