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