korganizer

koeditorattachments.cpp

00001 /*
00002     This file is part of KOrganizer.
00003 
00004     Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
00005     Copyright (c) 2005 Reinhold Kainhofer <reinhold@kainhofer.com>
00006 
00007     This program is free software; you can redistribute it and/or modify
00008     it under the terms of the GNU General Public License as published by
00009     the Free Software Foundation; either version 2 of the License, or
00010     (at your option) any later version.
00011 
00012     This program is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00015     GNU General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program; if not, write to the Free Software
00019     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020 
00021     As a special exception, permission is given to link this program
00022     with any edition of Qt, and distribute the resulting executable,
00023     without including the source code for Qt in the source distribution.
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(); // will be deleted on editor close
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"
KDE Home | KDE Accessibility Home | Description of Access Keys