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 #include <libkdepim/kdepimprotocols.h>
00032 #include <libkdepim/maillistdrag.h>
00033 #include <libkdepim/kvcarddrag.h>
00034 #include <libkdepim/kdepimprotocols.h>
00035 
00036 #include <klocale.h>
00037 #include <kdebug.h>
00038 #include <kmdcodec.h>
00039 #include <kmessagebox.h>
00040 #include <krun.h>
00041 #include <kurldrag.h>
00042 #include <ktempfile.h>
00043 #include <ktempdir.h>
00044 #include <kio/netaccess.h>
00045 #include <kmimetype.h>
00046 #include <kiconloader.h>
00047 #include <kfiledialog.h>
00048 #include <kstdaction.h>
00049 #include <kactioncollection.h>
00050 #include <kpopupmenu.h>
00051 #include <kprotocolinfo.h>
00052 #include <klineedit.h>
00053 #include <kseparator.h>
00054 #include <kurlrequester.h>
00055 #include <libkmime/kmime_message.h>
00056 
00057 #include <qcheckbox.h>
00058 #include <qfile.h>
00059 #include <qlabel.h>
00060 #include <qlayout.h>
00061 #include <qlistview.h>
00062 #include <qpushbutton.h>
00063 #include <qdragobject.h>
00064 #include <qtooltip.h>
00065 #include <qwhatsthis.h>
00066 #include <qapplication.h>
00067 #include <qclipboard.h>
00068 
00069 #include <cassert>
00070 #include <cstdlib>
00071 
00072 class AttachmentListItem : public KIconViewItem
00073 {
00074   public:
00075     AttachmentListItem( KCal::Attachment*att, QIconView *parent ) :
00076         KIconViewItem( parent )
00077     {
00078       if ( att ) {
00079         mAttachment = new KCal::Attachment( *att );
00080       } else {
00081         mAttachment = new KCal::Attachment( '\0' ); //use the non-uri constructor
00082                                                     //as we want inline by default
00083       }
00084       readAttachment();
00085       setDragEnabled( true );
00086     }
00087     ~AttachmentListItem() { delete mAttachment; }
00088     KCal::Attachment *attachment() const { return mAttachment; }
00089 
00090     const QString uri() const
00091     {
00092       return mAttachment->uri();
00093     }
00094     void setUri( const QString &uri )
00095     {
00096       mAttachment->setUri( uri );
00097       readAttachment();
00098     }
00099     void setData( const QByteArray data )
00100     {
00101       mAttachment->setDecodedData( data );
00102       readAttachment();
00103     }
00104     const QString mimeType() const
00105     {
00106       return mAttachment->mimeType();
00107     }
00108     void setMimeType( const QString &mime )
00109     {
00110       mAttachment->setMimeType( mime );
00111       readAttachment();
00112     }
00113     const QString label() const
00114     {
00115       return mAttachment->label();
00116     }
00117     void setLabel( const QString &label )
00118     {
00119       mAttachment->setLabel( label );
00120       readAttachment();
00121     }
00122     bool isBinary() const
00123     {
00124       return mAttachment->isBinary();
00125     }
00126     QPixmap icon() const
00127     {
00128       return icon( KMimeType::mimeType( mAttachment->mimeType() ),
00129                    mAttachment->uri() );
00130     }
00131     static QPixmap icon( KMimeType::Ptr mimeType, const QString &uri )
00132     {
00133       QString iconStr = mimeType->icon( uri, false );
00134       return KGlobal::iconLoader()->loadIcon( iconStr, KIcon::Small );
00135     }
00136     void readAttachment()
00137     {
00138       if ( mAttachment->label().isEmpty() ) {
00139         if ( mAttachment->isUri() ) {
00140           setText( mAttachment->uri() );
00141         } else {
00142           setText( i18n( "[Binary data]" ) );
00143         }
00144       } else {
00145         setText( mAttachment->label() );
00146       }
00147       if ( mAttachment->mimeType().isEmpty() ||
00148            !( KMimeType::mimeType( mAttachment->mimeType() ) ) ) {
00149         KMimeType::Ptr mimeType;
00150         if ( mAttachment->isUri() ) {
00151           mimeType = KMimeType::findByURL( mAttachment->uri() );
00152         } else {
00153           mimeType = KMimeType::findByContent( mAttachment->decodedData() );
00154         }
00155         mAttachment->setMimeType( mimeType->name() );
00156       }
00157 
00158       setPixmap( icon() );
00159     }
00160 
00161   private:
00162     KCal::Attachment *mAttachment;
00163 };
00164 
00165 AttachmentEditDialog::AttachmentEditDialog( AttachmentListItem *item,
00166                                             QWidget *parent )
00167   : KDialogBase ( Plain, i18n( "Add Attachment" ), Ok|Cancel, Ok, parent, 0, false, false ),
00168     mItem( item ), mURLRequester( 0 )
00169 {
00170   QFrame *topFrame = plainPage();
00171   QVBoxLayout *vbl = new QVBoxLayout( topFrame, 0, spacingHint() );
00172 
00173   QGridLayout *grid = new QGridLayout();
00174   grid->setColStretch( 0, 0 );
00175   grid->setColStretch( 1, 0 );
00176   grid->setColStretch( 2, 1 );
00177   vbl->addLayout( grid );
00178 
00179   mIcon = new QLabel( topFrame );
00180   mIcon->setPixmap( item->icon() );
00181   grid->addWidget( mIcon, 0, 0 );
00182 
00183   mLabelEdit = new KLineEdit( topFrame );
00184   mLabelEdit->setText( item->label().isEmpty() ? item->uri() : item->label() );
00185   mLabelEdit->setClickMessage( i18n( "Attachment name" ) );
00186   QToolTip::add( mLabelEdit, i18n( "Give the attachment a name" ) );
00187   QWhatsThis::add( mLabelEdit,
00188                    i18n( "Type any string you desire here for the name of the attachment" ) );
00189   grid->addMultiCellWidget( mLabelEdit, 0, 0, 1, 2 );
00190 
00191   KSeparator *sep = new KSeparator( Qt::Horizontal, topFrame );
00192   grid->addMultiCellWidget( sep, 1, 1, 0, 2 );
00193 
00194   QLabel *label = new QLabel( i18n( "Type:" ), topFrame );
00195   grid->addWidget( label, 2, 0 );
00196   QString typecomment = item->mimeType().isEmpty() ?
00197                         i18n( "Unknown" ) :
00198                         KMimeType::mimeType( item->mimeType() )->comment();
00199   mTypeLabel = new QLabel( typecomment, topFrame );
00200   grid->addWidget( mTypeLabel, 2, 1 );
00201   mMimeType = KMimeType::mimeType( item->mimeType() );
00202 
00203   mInline = new QCheckBox( i18n( "Store attachment inline" ), topFrame );
00204   grid->addMultiCellWidget( mInline, 3, 3, 0, 2 );
00205   mInline->setChecked( item->isBinary() );
00206   QToolTip::add( mInline, i18n( "Store the attachment file inside the calendar" ) );
00207   QWhatsThis::add(
00208     mInline,
00209     i18n( "Checking this option will cause the attachment to be stored inside "
00210           "your calendar, which can take a lot of space depending on the size "
00211           "of the attachment. If this option is not checked, then only a link "
00212           "pointing to the attachment will be stored.  Do not use a link for "
00213           "attachments that change often or may be moved (or removed) from "
00214           "their current location." ) );
00215 
00216   if ( item->attachment()->isUri() || !item->attachment()->data() ) {
00217     label = new QLabel( i18n( "Location:" ), topFrame );
00218     grid->addWidget( label, 4, 0 );
00219     mURLRequester = new KURLRequester( item->uri(), topFrame );
00220     QToolTip::add( mURLRequester, i18n( "Provide a location for the attachment file" ) );
00221     QWhatsThis::add(
00222       mURLRequester,
00223       i18n( "Enter the path to the attachment file or use the "
00224             "file browser by pressing the adjacent button" ) );
00225     grid->addMultiCellWidget( mURLRequester, 4, 4, 1, 2 );
00226     connect( mURLRequester, SIGNAL(urlSelected(const QString &)),
00227              SLOT(urlSelected(const QString &)) );
00228     connect( mURLRequester, SIGNAL( textChanged( const QString& ) ),
00229              SLOT( urlChanged( const QString& ) ) );
00230     urlChanged( item->uri() );
00231   } else {
00232     uint size = item->attachment()->size();
00233     grid->addWidget( new QLabel( i18n( "Size:" ), topFrame ), 4, 0 );
00234     grid->addWidget( new QLabel( QString::fromLatin1( "%1 (%2)" ).
00235                                  arg( KIO::convertSize( size ) ).
00236                                  arg( KGlobal::locale()->formatNumber(
00237                                         size, 0 ) ), topFrame ), 4, 2 );
00238   }
00239   vbl->addStretch( 10 );
00240 }
00241 
00242 void AttachmentEditDialog::slotApply()
00243 {
00244   if ( !mLabelEdit->text().isEmpty() ) {
00245     mItem->setLabel( mLabelEdit->text() );
00246   } else {
00247     if ( mURLRequester ) {
00248       KURL url( mURLRequester->url() );
00249       if ( url.isLocalFile() ) {
00250         mItem->setLabel( url.fileName() );
00251       } else {
00252         mItem->setLabel( url.url() );
00253       }
00254     }
00255   }
00256   if ( mItem->label().isEmpty() ) {
00257     mItem->setLabel( i18n( "New attachment" ) );
00258   }
00259   mItem->setMimeType( mMimeType->name() );
00260   if ( mURLRequester ) {
00261     KURL url( mURLRequester->url() );
00262     if ( mInline->isChecked() ) {
00263       QString tmpFile;
00264       if ( KIO::NetAccess::download( mURLRequester->url(), tmpFile, this ) ) {
00265         QFile f( tmpFile );
00266         if ( !f.open( IO_ReadOnly ) ) {
00267           return;
00268         }
00269         QByteArray data = f.readAll();
00270         f.close();
00271         mItem->setData( data );
00272       }
00273       KIO::NetAccess::removeTempFile( tmpFile );
00274     } else {
00275       mItem->setUri( url.url() );
00276     }
00277   }
00278 }
00279 
00280 void AttachmentEditDialog::accept()
00281 {
00282   slotApply();
00283   KDialog::accept();
00284 }
00285 
00286 void AttachmentEditDialog::urlChanged( const QString &url )
00287 {
00288   enableButton( Ok, !url.isEmpty() );
00289 }
00290 
00291 void AttachmentEditDialog::urlSelected( const QString &url )
00292 {
00293   KURL kurl( url );
00294   mMimeType = KMimeType::findByURL( kurl );
00295   mTypeLabel->setText( mMimeType->comment() );
00296   mIcon->setPixmap( AttachmentListItem::icon( mMimeType, kurl.path() ) );
00297 }
00298 
00299 AttachmentIconView::AttachmentIconView( KOEditorAttachments* parent )
00300   : KIconView( parent ),
00301     mParent( parent )
00302 {
00303   setSelectionMode( QIconView::Extended );
00304   setMode( KIconView::Select );
00305   setItemTextPos( QIconView::Right );
00306   setArrangement( QIconView::LeftToRight );
00307   setMaxItemWidth( QMAX(maxItemWidth(), 250) );
00308   setMinimumHeight( QMAX(fontMetrics().height(), 16) + 12 );
00309 
00310   connect( this, SIGNAL( dropped ( QDropEvent *, const QValueList<QIconDragItem> & ) ),
00311            this, SLOT( handleDrop( QDropEvent *, const QValueList<QIconDragItem> & ) ) );
00312 }
00313 
00314 KURL AttachmentIconView::tempFileForAttachment( KCal::Attachment *attachment )
00315 {
00316   if ( mTempFiles.contains( attachment ) ) {
00317     return mTempFiles[attachment];
00318   }
00319   QStringList patterns = KMimeType::mimeType( attachment->mimeType() )->patterns();
00320 
00321   KTempFile *file;
00322   if ( !patterns.empty() ) {
00323     file = new KTempFile( QString::null,
00324                           QString( patterns.first() ).remove( '*' ),0600 );
00325   } else {
00326     file = new KTempFile( QString::null, QString::null, 0600 );
00327   }
00328   file->setAutoDelete( true );
00329   file->file()->open( IO_WriteOnly );
00330   QTextStream stream( file->file() );
00331   stream.writeRawBytes( attachment->decodedData().data(), attachment->size() );
00332   KURL url( file->name() );
00333   mTempFiles.insert( attachment, url );
00334   file->close();
00335   return mTempFiles[attachment];
00336 }
00337 
00338 QDragObject *AttachmentIconView::mimeData()
00339 {
00340   // create a list of the URL:s that we want to drag
00341   KURL::List urls;
00342   QStringList labels;
00343   for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() ) {
00344     if ( it->isSelected() ) {
00345       AttachmentListItem *item = static_cast<AttachmentListItem *>( it );
00346       if ( item->isBinary() ) {
00347         urls.append( tempFileForAttachment( item->attachment() ) );
00348       } else {
00349         urls.append( item->uri() );
00350       }
00351       labels.append( KURL::encode_string( item->label() ) );
00352     }
00353   }
00354   if ( selectionMode() == QIconView::NoSelection ) {
00355     AttachmentListItem *item = static_cast<AttachmentListItem *>( currentItem() );
00356     if ( item ) {
00357       urls.append( item->uri() );
00358       labels.append( KURL::encode_string( item->label() ) );
00359     }
00360   }
00361 
00362   QMap<QString, QString> metadata;
00363   metadata["labels"] = labels.join( ":" );
00364 
00365   KURLDrag *drag = new KURLDrag( urls, metadata );
00366   return drag;
00367 }
00368 
00369 AttachmentIconView::~AttachmentIconView()
00370 {
00371   for ( std::set<KTempDir*>::iterator it = mTempDirs.begin() ; it != mTempDirs.end() ; ++it ) {
00372     delete *it;
00373   }
00374 }
00375 
00376 QDragObject * AttachmentIconView::dragObject()
00377 {
00378   KURL::List urls;
00379   for ( QIconViewItem *it = firstItem( ); it; it = it->nextItem( ) ) {
00380     if ( !it->isSelected() ) continue;
00381     AttachmentListItem * item = dynamic_cast<AttachmentListItem*>( it );
00382     if ( !item ) return 0;
00383     KCal::Attachment * att = item->attachment();
00384     assert( att );
00385     KURL url;
00386     if ( att->isUri() ) {
00387       url.setPath( att->uri() );
00388     } else {
00389       KTempDir * tempDir = new KTempDir(); // will be deleted on editor close
00390       tempDir->setAutoDelete( true );
00391       mTempDirs.insert( tempDir );
00392       QByteArray encoded;
00393       encoded.duplicate( att->data(), strlen(att->data()) );
00394       QByteArray decoded;
00395       KCodecs::base64Decode( encoded, decoded );
00396       const QString fileName = tempDir->name( ) + "/" + att->label();
00397       KPIM::kByteArrayToFile( decoded, fileName, false, false, false );
00398       url.setPath( fileName );
00399     }
00400     urls << url;
00401   }
00402   KURLDrag *drag  = new KURLDrag( urls, this );
00403   return drag;
00404 }
00405 
00406 void AttachmentIconView::handleDrop( QDropEvent *event, const QValueList<QIconDragItem> & list )
00407 {
00408   Q_UNUSED( list );
00409   mParent->handlePasteOrDrop( event );
00410 }
00411 
00412 
00413 void AttachmentIconView::dragMoveEvent( QDragMoveEvent *event )
00414 {
00415   mParent->dragMoveEvent( event );
00416 }
00417 
00418 void AttachmentIconView::contentsDragMoveEvent( QDragMoveEvent *event )
00419 {
00420   mParent->dragMoveEvent( event );
00421 }
00422 
00423 void AttachmentIconView::contentsDragEnterEvent( QDragEnterEvent *event )
00424 {
00425   mParent->dragMoveEvent( event );
00426 }
00427 
00428 void AttachmentIconView::dragEnterEvent( QDragEnterEvent *event )
00429 {
00430   mParent->dragEnterEvent( event );
00431 }
00432 
00433 KOEditorAttachments::KOEditorAttachments( int spacing, QWidget *parent,
00434                                           const char *name )
00435   : QWidget( parent, name )
00436 {
00437   QBoxLayout *topLayout = new QHBoxLayout( this );
00438   topLayout->setSpacing( spacing );
00439 
00440   QLabel *label = new QLabel( i18n("Attachments:"), this );
00441   topLayout->addWidget( label );
00442 
00443   mAttachments = new AttachmentIconView( this );
00444   QWhatsThis::add( mAttachments,
00445                    i18n("Displays a list of current items (files, mail, etc.) "
00446                         "that have been associated with this event or to-do. ") );
00447   topLayout->addWidget( mAttachments );
00448   connect( mAttachments, SIGNAL( doubleClicked( QIconViewItem * ) ),
00449            SLOT( showAttachment( QIconViewItem * ) ) );
00450   connect( mAttachments, SIGNAL(selectionChanged()),
00451            SLOT(selectionChanged()) );
00452   connect( mAttachments, SIGNAL(contextMenuRequested(QIconViewItem*,const QPoint&)),
00453            SLOT(contextMenu(QIconViewItem*,const QPoint&)) );
00454 
00455     QPushButton *addButton = new QPushButton( this );
00456   addButton->setIconSet( SmallIconSet( "add" ) );
00457   QToolTip::add( addButton, i18n( "Add an attachment" ) );
00458   QWhatsThis::add( addButton,
00459                    i18n( "Shows a dialog used to select an attachment "
00460                          "to add to this event or to-do as link or as "
00461                          "inline data." ) );
00462   topLayout->addWidget( addButton );
00463   connect( addButton, SIGNAL(clicked()), SLOT(slotAdd()) );
00464 
00465   mRemoveBtn = new QPushButton( this );
00466   mRemoveBtn->setIconSet( SmallIconSet( "remove" ) );
00467   QToolTip::add( mRemoveBtn, i18n("&Remove") );
00468   QWhatsThis::add( mRemoveBtn,
00469                    i18n("Removes the attachment selected in the list above "
00470                         "from this event or to-do.") );
00471   topLayout->addWidget( mRemoveBtn );
00472   connect( mRemoveBtn, SIGNAL(clicked()), SLOT(slotRemove()) );
00473 
00474   mContextMenu = new KPopupMenu( this );
00475 
00476   KActionCollection* ac = new KActionCollection( this, this );
00477 
00478   mOpenAction = new KAction( i18n("Open"), 0, this, SLOT(slotShow()), ac );
00479   mOpenAction->plug( mContextMenu );
00480 
00481   mSaveAsAction = new KAction( i18n( "Save As..." ), 0, this, SLOT(slotSaveAs()), ac );
00482   mSaveAsAction->plug( mContextMenu );
00483   mContextMenu->insertSeparator();
00484 
00485   mCopyAction = KStdAction::copy(this, SLOT(slotCopy()), ac );
00486   mCopyAction->plug( mContextMenu );
00487   mCutAction = KStdAction::cut(this, SLOT(slotCut()), ac );
00488   mCutAction->plug( mContextMenu );
00489   KAction *action = KStdAction::paste(this, SLOT(slotPaste()), ac );
00490   action->plug( mContextMenu );
00491   mContextMenu->insertSeparator();
00492 
00493   mDeleteAction = new KAction( i18n( "&Remove" ), 0, this, SLOT(slotRemove()),  ac );
00494   mDeleteAction->plug( mContextMenu );
00495   mDeleteAction->setShortcut( Key_Delete );
00496   mContextMenu->insertSeparator();
00497 
00498   mEditAction = new KAction( i18n( "&Properties..." ), 0, this, SLOT(slotEdit()), ac );
00499   mEditAction->plug( mContextMenu );
00500 
00501   selectionChanged();
00502   setAcceptDrops( true );
00503 }
00504 
00505 KOEditorAttachments::~KOEditorAttachments()
00506 {
00507 }
00508 
00509 bool KOEditorAttachments::hasAttachments()
00510 {
00511   return mAttachments->count() != 0;
00512 }
00513 
00514 void KOEditorAttachments::dragMoveEvent( QDragMoveEvent *event )
00515 {
00516   event->accept( KURLDrag::canDecode( event ) ||
00517                  QTextDrag::canDecode( event ) ||
00518                  KPIM::MailListDrag::canDecode( event ) ||
00519                  KVCardDrag::canDecode( event ) );
00520 }
00521 
00522 void KOEditorAttachments::dragEnterEvent( QDragEnterEvent* event )
00523 {
00524   dragMoveEvent( event );
00525 }
00526 
00527 void KOEditorAttachments::handlePasteOrDrop( QMimeSource* source )
00528 {
00529   KURL::List urls;
00530   bool probablyWeHaveUris = false;
00531   bool weCanCopy = true;
00532   QStringList labels;
00533 
00534   if ( KVCardDrag::canDecode( source ) ) {
00535     KABC::Addressee::List addressees;
00536     KVCardDrag::decode( source, addressees );
00537     for ( KABC::Addressee::List::ConstIterator it = addressees.constBegin();
00538           it != addressees.constEnd(); ++it ) {
00539       urls.append( KDEPIMPROTOCOL_CONTACT + ( *it ).uid() );
00540       // there is some weirdness about realName(), hence fromUtf8
00541       labels.append( QString::fromUtf8( ( *it ).realName().latin1() ) );
00542     }
00543     probablyWeHaveUris = true;
00544   } else if ( KURLDrag::canDecode( source ) ) {
00545     QMap<QString,QString> metadata;
00546     if ( KURLDrag::decode( source, urls, metadata ) ) {
00547       probablyWeHaveUris = true;
00548       labels = QStringList::split( ':', metadata["labels"], FALSE );
00549       for ( QStringList::Iterator it = labels.begin(); it != labels.end(); ++it ) {
00550         *it = KURL::decode_string( (*it).latin1() );
00551       }
00552 
00553     }
00554   } else if ( QTextDrag::canDecode( source ) ) {
00555     QString text;
00556     QTextDrag::decode( source, text );
00557     QStringList lst = QStringList::split( '\n', text, FALSE );
00558     for ( QStringList::ConstIterator it = lst.constBegin(); it != lst.constEnd(); ++it ) {
00559       urls.append( *it );
00560       labels.append( QString::null );
00561     }
00562     probablyWeHaveUris = true;
00563   }
00564 
00565   KPopupMenu menu;
00566   int items=0;
00567   if ( probablyWeHaveUris ) {
00568     menu.insertItem( i18n( "&Link here" ), DRAG_LINK, items++ );
00569     // we need to check if we can reasonably expect to copy the objects
00570     for ( KURL::List::ConstIterator it = urls.constBegin(); it != urls.constEnd(); ++it ) {
00571       if ( !( weCanCopy = KProtocolInfo::supportsReading( *it ) ) ) {
00572         break; // either we can copy them all, or no copying at all
00573       }
00574     }
00575     if ( weCanCopy ) {
00576       menu.insertItem( SmallIcon( "editcopy" ), i18n( "&Copy Here" ), DRAG_COPY, items++ );
00577     }
00578   } else {
00579       menu.insertItem( SmallIcon( "editcopy" ), i18n( "&Copy Here" ), DRAG_COPY, items++ );
00580   }
00581 
00582   menu.insertSeparator();
00583   items++;
00584   menu.insertItem( SmallIcon( "cancel" ), i18n( "C&ancel" ), DRAG_CANCEL, items );
00585   int action = menu.exec( QCursor::pos(), 0 );
00586 
00587   if ( action == DRAG_LINK ) {
00588     QStringList::ConstIterator jt = labels.constBegin();
00589     for ( KURL::List::ConstIterator it = urls.constBegin();
00590           it != urls.constEnd(); ++it ) {
00591       QString label = (*jt++);
00592       if ( mAttachments->findItem( label ) ) {
00593         label += '~' + randomString( 3 );
00594       }
00595       addUriAttachment( (*it).url(), QString::null, label, true );
00596     }
00597   } else if ( action != DRAG_CANCEL ) {
00598     if ( probablyWeHaveUris ) {
00599       for ( KURL::List::ConstIterator it = urls.constBegin();
00600             it != urls.constEnd(); ++it ) {
00601         QString label = (*it).fileName();
00602         if ( label.isEmpty() ) {
00603           label = (*it).prettyURL();
00604         }
00605         if ( mAttachments->findItem( label ) ) {
00606           label += '~' + randomString( 3 );
00607         }
00608         addUriAttachment( (*it).url(), QString::null, label, true );
00609       }
00610     } else { // we take anything
00611       addDataAttachment( source->encodedData( source->format() ),
00612                          source->format(),
00613                          KMimeType::mimeType( source->format() )->name() );
00614     }
00615   }
00616 }
00617 
00618 void KOEditorAttachments::dropEvent( QDropEvent* event )
00619 {
00620     handlePasteOrDrop( event );
00621 }
00622 
00623 void KOEditorAttachments::showAttachment( QIconViewItem *item )
00624 {
00625   AttachmentListItem *attitem = static_cast<AttachmentListItem*>(item);
00626   if ( !attitem || !attitem->attachment() ) return;
00627 
00628   KCal::Attachment *att = attitem->attachment();
00629   if ( att->isUri() ) {
00630     emit openURL( att->uri() );
00631   } else {
00632     KRun::runURL( mAttachments->tempFileForAttachment( att ), att->mimeType(), 0, true );
00633   }
00634 }
00635 
00636 void KOEditorAttachments::saveAttachment( QIconViewItem *item )
00637 {
00638   AttachmentListItem *attitem = static_cast<AttachmentListItem*>(item);
00639   if ( !attitem || !attitem->attachment() ) return;
00640 
00641   KCal::Attachment *att = attitem->attachment();
00642 
00643   // get the saveas file name
00644   QString saveAsFile =
00645     KFileDialog::getSaveFileName( att->label(),
00646                                   QString::null, 0,
00647                                   i18n( "Save  Attachment" ) );
00648   if ( saveAsFile.isEmpty() ||
00649        ( QFile( saveAsFile ).exists() &&
00650          ( KMessageBox::warningYesNo(
00651            0,
00652            i18n( "%1 already exists. Do you want to overwrite it?").
00653            arg( saveAsFile ) ) == KMessageBox::No ) ) ) {
00654     return;
00655   }
00656 
00657   KURL sourceUrl;
00658   if ( att->isUri() ) {
00659     sourceUrl = att->uri();
00660   } else {
00661     sourceUrl = mAttachments->tempFileForAttachment( att );
00662   }
00663   // save the attachment url
00664   if ( !KIO::NetAccess::file_copy( sourceUrl, KURL( saveAsFile ), -1, true ) &&
00665        KIO::NetAccess::lastError() ) {
00666     KMessageBox::error( this, KIO::NetAccess::lastErrorString() );
00667   }
00668 }
00669 
00670 void KOEditorAttachments::slotAdd()
00671 {
00672   AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
00673 
00674   AttachmentEditDialog *dlg = new AttachmentEditDialog( item, mAttachments )
00675 ;
00676   if ( dlg->exec() == KDialog::Rejected ) {
00677     delete item;
00678   }
00679   delete dlg;
00680 }
00681 
00682 void KOEditorAttachments::slotAddData()
00683 {
00684   KURL uri = KFileDialog::getOpenFileName( QString(), QString(), this, i18n("Add Attachment") );
00685   if ( !uri.isEmpty() ) {
00686     QString label = uri.fileName();
00687     if ( label.isEmpty() ) {
00688       label = uri.prettyURL();
00689     }
00690     addUriAttachment( uri.url(), QString::null, label, true );
00691   }
00692 }
00693 
00694 void KOEditorAttachments::slotEdit()
00695 {
00696   for ( QIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00697     if ( item->isSelected() ) {
00698       AttachmentListItem *attitem = static_cast<AttachmentListItem*>( item );
00699       if ( !attitem || !attitem->attachment() ) {
00700         return;
00701       }
00702 
00703       AttachmentEditDialog *dialog = new AttachmentEditDialog( attitem, mAttachments );
00704       dialog->mInline->setEnabled( false );
00705       dialog->setModal( false );
00706       connect( dialog, SIGNAL(hidden()), dialog, SLOT(delayedDestruct()) );
00707       dialog->show();
00708     }
00709   }
00710 }
00711 
00712 void KOEditorAttachments::slotRemove()
00713 {
00714   QValueList<QIconViewItem*> selected;
00715   QStringList labels;
00716   for ( QIconViewItem *it = mAttachments->firstItem( ); it; it = it->nextItem( ) ) {
00717     if ( !it->isSelected() ) continue;
00718     selected << it;
00719 
00720     AttachmentListItem *attitem = static_cast<AttachmentListItem*>(it);
00721     KCal::Attachment *att = attitem->attachment();
00722     labels << att->label();
00723   }
00724 
00725   if ( selected.isEmpty() ) {
00726     return;
00727   }
00728 
00729   QString labelsStr = labels.join( "<br>" );
00730 
00731   if ( KMessageBox::questionYesNo(
00732          this,
00733          i18n( "<qt>Do you really want to remove these attachments?<p>%1</qt>" ).arg( labelsStr ),
00734          i18n( "Remove Attachment?" ) ) != KMessageBox::Yes ) {
00735     return;
00736   }
00737 
00738   for ( QValueList<QIconViewItem*>::iterator it( selected.begin() ), end( selected.end() );
00739         it != end ; ++it ) {
00740     delete *it;
00741   }
00742 }
00743 
00744 void KOEditorAttachments::slotShow()
00745 {
00746   for ( QIconViewItem *it = mAttachments->firstItem(); it; it = it->nextItem() ) {
00747     if ( !it->isSelected() )
00748       continue;
00749     showAttachment( it );
00750   }
00751 }
00752 
00753 void KOEditorAttachments::slotSaveAs()
00754 {
00755   for ( QIconViewItem *it = mAttachments->firstItem(); it; it = it->nextItem() ) {
00756     if ( !it->isSelected() )
00757       continue;
00758     saveAttachment( it );
00759   }
00760 }
00761 
00762 void KOEditorAttachments::setDefaults()
00763 {
00764   mAttachments->clear();
00765 }
00766 
00767 QString KOEditorAttachments::randomString(int length) const
00768 {
00769    if (length <=0 ) return QString();
00770 
00771    QString str; str.setLength( length );
00772    int i = 0;
00773    while (length--)
00774    {
00775       int r=random() % 62;
00776       r+=48;
00777       if (r>57) r+=7;
00778       if (r>90) r+=6;
00779       str[i++] =  char(r);
00780       // so what if I work backwards?
00781    }
00782    return str;
00783 }
00784 
00785 void KOEditorAttachments::addUriAttachment( const QString &uri,
00786                                             const QString &mimeType,
00787                                             const QString &label,
00788                                             bool inLine )
00789 {
00790   if ( !inLine ) {
00791     AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
00792     item->setUri( uri );
00793     item->setLabel( label );
00794     if ( mimeType.isEmpty() ) {
00795       if ( uri.startsWith( KDEPIMPROTOCOL_CONTACT ) ) {
00796         item->setMimeType( "text/directory" );
00797       } else if ( uri.startsWith( KDEPIMPROTOCOL_EMAIL ) ) {
00798         item->setMimeType( "message/rfc822" );
00799       } else if ( uri.startsWith( KDEPIMPROTOCOL_INCIDENCE ) ) {
00800         item->setMimeType( "text/calendar" );
00801       } else if ( uri.startsWith( KDEPIMPROTOCOL_NEWSARTICLE ) ) {
00802         item->setMimeType( "message/news" );
00803       } else {
00804         item->setMimeType( KMimeType::findByURL( uri )->name() );
00805       }
00806     }
00807   } else {
00808     QString tmpFile;
00809     if ( KIO::NetAccess::download( uri, tmpFile, this ) ) {
00810       QFile f( tmpFile );
00811       if ( !f.open( IO_ReadOnly ) ) {
00812         return;
00813       }
00814       const QByteArray data = f.readAll();
00815       f.close();
00816       addDataAttachment( data, mimeType, label );
00817     }
00818     KIO::NetAccess::removeTempFile( tmpFile );
00819   }
00820 }
00821 
00822 void KOEditorAttachments::addDataAttachment( const QByteArray &data,
00823                                              const QString &mimeType,
00824                                              const QString &label )
00825 {
00826   AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
00827 
00828   QString nlabel = label;
00829   if ( mimeType == "message/rfc822" ) {
00830     // mail message. try to set the label from the mail Subject:
00831     KMime::Message msg;
00832     msg.setContent( data.data() );
00833     msg.parse();
00834     nlabel = msg.subject()->asUnicodeString();
00835   }
00836 
00837   item->setData( data );
00838   item->setLabel( nlabel );
00839   if ( mimeType.isEmpty() ) {
00840     item->setMimeType( KMimeType::findByContent( data )->name() );
00841   } else {
00842     item->setMimeType( mimeType );
00843   }
00844 }
00845 
00846 void KOEditorAttachments::addAttachment( KCal::Attachment *attachment )
00847 {
00848   new AttachmentListItem( attachment, mAttachments );
00849 }
00850 
00851 void KOEditorAttachments::readIncidence( KCal::Incidence *i )
00852 {
00853   mAttachments->clear();
00854 
00855   KCal::Attachment::List attachments = i->attachments();
00856   KCal::Attachment::List::ConstIterator it;
00857   for( it = attachments.begin(); it != attachments.end(); ++it ) {
00858     addAttachment( (*it) );
00859   }
00860   if ( mAttachments->count() > 0 ) {
00861     QTimer::singleShot( 0, mAttachments, SLOT(arrangeItemsInGrid()) );
00862   }
00863 }
00864 
00865 void KOEditorAttachments::writeIncidence( KCal::Incidence *i )
00866 {
00867   i->clearAttachments();
00868 
00869   QIconViewItem *item;
00870   AttachmentListItem *attitem;
00871   for( item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00872     attitem = static_cast<AttachmentListItem*>(item);
00873     if ( attitem )
00874       i->addAttachment( new KCal::Attachment( *(attitem->attachment() ) ) );
00875   }
00876 }
00877 
00878 
00879 void KOEditorAttachments::slotCopy()
00880 {
00881     QApplication::clipboard()->setData( mAttachments->mimeData(), QClipboard::Clipboard );
00882 }
00883 
00884 void KOEditorAttachments::slotCut()
00885 {
00886     slotCopy();
00887     slotRemove();
00888 }
00889 
00890 void KOEditorAttachments::slotPaste()
00891 {
00892     handlePasteOrDrop( QApplication::clipboard()->data() );
00893 }
00894 
00895 void KOEditorAttachments::selectionChanged()
00896 {
00897   bool selected = false;
00898   for ( QIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00899     if ( item->isSelected() ) {
00900       selected = true;
00901       break;
00902     }
00903   }
00904   mRemoveBtn->setEnabled( selected );
00905 }
00906 
00907 void KOEditorAttachments::contextMenu(QIconViewItem * item, const QPoint & pos)
00908 {
00909   const bool enable = item != 0;
00910 
00911   int numSelected = 0;
00912   for ( QIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00913     if ( item->isSelected() ) {
00914       numSelected++;
00915     }
00916   }
00917 
00918   mOpenAction->setEnabled( enable );
00919   //TODO: support saving multiple attachments into a directory
00920   mSaveAsAction->setEnabled( enable && numSelected == 1 );
00921   mCopyAction->setEnabled( enable && numSelected == 1 );
00922   mCutAction->setEnabled( enable && numSelected == 1 );
00923   mDeleteAction->setEnabled( enable );
00924   mEditAction->setEnabled( enable );
00925   mContextMenu->exec( pos );
00926 }
00927 
00928 #include "koeditorattachments.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys