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 = item->attachment()->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.writeRawBytes( attachment->decodedData().data(), attachment->size() );
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 
00480   mSaveAsAction = new KAction( i18n( "Save As..." ), 0, this, SLOT(slotSaveAs()), ac );
00481   mSaveAsAction->plug( mContextMenu );
00482   mContextMenu->insertSeparator();
00483 
00484   mCopyAction = KStdAction::copy(this, SLOT(slotCopy()), ac );
00485   mCopyAction->plug( mContextMenu );
00486   mCutAction = KStdAction::cut(this, SLOT(slotCut()), ac );
00487   mCutAction->plug( mContextMenu );
00488   KAction *action = KStdAction::paste(this, SLOT(slotPaste()), ac );
00489   action->plug( mContextMenu );
00490   mContextMenu->insertSeparator();
00491 
00492   mDeleteAction = new KAction( i18n( "&Remove" ), 0, this, SLOT(slotRemove()),  ac );
00493   mDeleteAction->plug( mContextMenu );
00494   mContextMenu->insertSeparator();
00495 
00496   mEditAction = new KAction( i18n( "&Properties..." ), 0, this, SLOT(slotEdit()), ac );
00497   mEditAction->plug( mContextMenu );
00498 
00499   selectionChanged();
00500   setAcceptDrops( true );
00501 }
00502 
00503 KOEditorAttachments::~KOEditorAttachments()
00504 {
00505 }
00506 
00507 bool KOEditorAttachments::hasAttachments()
00508 {
00509   return mAttachments->count() != 0;
00510 }
00511 
00512 void KOEditorAttachments::dragMoveEvent( QDragMoveEvent *event )
00513 {
00514   event->accept( KURLDrag::canDecode( event ) ||
00515                  QTextDrag::canDecode( event ) ||
00516                  KPIM::MailListDrag::canDecode( event ) ||
00517                  KVCardDrag::canDecode( event ) );
00518 }
00519 
00520 void KOEditorAttachments::dragEnterEvent( QDragEnterEvent* event )
00521 {
00522   dragMoveEvent( event );
00523 }
00524 
00525 void KOEditorAttachments::handlePasteOrDrop( QMimeSource* source )
00526 {
00527   KURL::List urls;
00528   bool probablyWeHaveUris = false;
00529   bool weCanCopy = true;
00530   QStringList labels;
00531 
00532   if ( KVCardDrag::canDecode( source ) ) {
00533     KABC::Addressee::List addressees;
00534     KVCardDrag::decode( source, addressees );
00535     for ( KABC::Addressee::List::ConstIterator it = addressees.constBegin();
00536           it != addressees.constEnd(); ++it ) {
00537       urls.append( KDEPIMPROTOCOL_CONTACT + ( *it ).uid() );
00538       // there is some weirdness about realName(), hence fromUtf8
00539       labels.append( QString::fromUtf8( ( *it ).realName().latin1() ) );
00540     }
00541     probablyWeHaveUris = true;
00542   } else if ( KURLDrag::canDecode( source ) ) {
00543     QMap<QString,QString> metadata;
00544     if ( KURLDrag::decode( source, urls, metadata ) ) {
00545       probablyWeHaveUris = true;
00546       labels = QStringList::split( ':', metadata["labels"], FALSE );
00547       for ( QStringList::Iterator it = labels.begin(); it != labels.end(); ++it ) {
00548         *it = KURL::decode_string( (*it).latin1() );
00549       }
00550 
00551     }
00552   } else if ( QTextDrag::canDecode( source ) ) {
00553     QString text;
00554     QTextDrag::decode( source, text );
00555     QStringList lst = QStringList::split( '\n', text, FALSE );
00556     for ( QStringList::ConstIterator it = lst.constBegin(); it != lst.constEnd(); ++it ) {
00557       urls.append( *it );
00558       labels.append( QString::null );
00559     }
00560     probablyWeHaveUris = true;
00561   }
00562 
00563   KPopupMenu menu;
00564   int items=0;
00565   if ( probablyWeHaveUris ) {
00566     menu.insertItem( i18n( "&Link here" ), DRAG_LINK, items++ );
00567     // we need to check if we can reasonably expect to copy the objects
00568     for ( KURL::List::ConstIterator it = urls.constBegin(); it != urls.constEnd(); ++it ) {
00569       if ( !( weCanCopy = KProtocolInfo::supportsReading( *it ) ) ) {
00570         break; // either we can copy them all, or no copying at all
00571       }
00572     }
00573     if ( weCanCopy ) {
00574       menu.insertItem( SmallIcon( "editcopy" ), i18n( "&Copy Here" ), DRAG_COPY, items++ );
00575     }
00576   } else {
00577       menu.insertItem( SmallIcon( "editcopy" ), i18n( "&Copy Here" ), DRAG_COPY, items++ );
00578   }
00579 
00580   menu.insertSeparator();
00581   items++;
00582   menu.insertItem( SmallIcon( "cancel" ), i18n( "C&ancel" ), DRAG_CANCEL, items );
00583   int action = menu.exec( QCursor::pos(), 0 );
00584 
00585   if ( action == DRAG_LINK ) {
00586     QStringList::ConstIterator jt = labels.constBegin();
00587     for ( KURL::List::ConstIterator it = urls.constBegin();
00588           it != urls.constEnd(); ++it ) {
00589       QString label = (*jt++);
00590       if ( mAttachments->findItem( label ) ) {
00591         label += '~' + randomString( 3 );
00592       }
00593       addUriAttachment( (*it).url(), QString::null, label, true );
00594     }
00595   } else if ( action != DRAG_CANCEL ) {
00596     if ( probablyWeHaveUris ) {
00597       for ( KURL::List::ConstIterator it = urls.constBegin();
00598             it != urls.constEnd(); ++it ) {
00599         QString label = (*it).fileName();
00600         if ( label.isEmpty() ) {
00601           label = (*it).prettyURL();
00602         }
00603         if ( mAttachments->findItem( label ) ) {
00604           label += '~' + randomString( 3 );
00605         }
00606         addUriAttachment( (*it).url(), QString::null, label, true );
00607       }
00608     } else { // we take anything
00609       addDataAttachment( source->encodedData( source->format() ),
00610                          source->format(),
00611                          KMimeType::mimeType( source->format() )->name() );
00612     }
00613   }
00614 }
00615 
00616 void KOEditorAttachments::dropEvent( QDropEvent* event )
00617 {
00618     handlePasteOrDrop( event );
00619 }
00620 
00621 void KOEditorAttachments::showAttachment( QIconViewItem *item )
00622 {
00623   AttachmentListItem *attitem = static_cast<AttachmentListItem*>(item);
00624   if ( !attitem || !attitem->attachment() ) return;
00625 
00626   KCal::Attachment *att = attitem->attachment();
00627   if ( att->isUri() ) {
00628     emit openURL( att->uri() );
00629   } else {
00630     KRun::runURL( mAttachments->tempFileForAttachment( att ), att->mimeType(), 0, true );
00631   }
00632 }
00633 
00634 void KOEditorAttachments::saveAttachment( QIconViewItem *item )
00635 {
00636   AttachmentListItem *attitem = static_cast<AttachmentListItem*>(item);
00637   if ( !attitem || !attitem->attachment() ) return;
00638 
00639   KCal::Attachment *att = attitem->attachment();
00640 
00641   // get the saveas file name
00642   QString saveAsFile =
00643     KFileDialog::getSaveFileName( att->label(),
00644                                   QString::null, 0,
00645                                   i18n( "Save  Attachment" ) );
00646   if ( saveAsFile.isEmpty() ||
00647        ( QFile( saveAsFile ).exists() &&
00648          ( KMessageBox::warningYesNo(
00649            0,
00650            i18n( "%1 already exists. Do you want to overwrite it?").
00651            arg( saveAsFile ) ) == KMessageBox::No ) ) ) {
00652     return;
00653   }
00654 
00655   KURL sourceUrl;
00656   if ( att->isUri() ) {
00657     sourceUrl = att->uri();
00658   } else {
00659     sourceUrl = mAttachments->tempFileForAttachment( att );
00660   }
00661   // save the attachment url
00662   if ( !KIO::NetAccess::file_copy( sourceUrl, KURL( saveAsFile ), -1, true ) &&
00663        KIO::NetAccess::lastError() ) {
00664     KMessageBox::error( this, KIO::NetAccess::lastErrorString() );
00665   }
00666 }
00667 
00668 void KOEditorAttachments::slotAdd()
00669 {
00670   AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
00671 
00672   AttachmentEditDialog *dlg = new AttachmentEditDialog( item, mAttachments )
00673 ;
00674   if ( dlg->exec() == KDialog::Rejected ) {
00675     delete item;
00676   }
00677   delete dlg;
00678 }
00679 
00680 void KOEditorAttachments::slotAddData()
00681 {
00682   KURL uri = KFileDialog::getOpenFileName( QString(), QString(), this, i18n("Add Attachment") );
00683   if ( !uri.isEmpty() ) {
00684     QString label = uri.fileName();
00685     if ( label.isEmpty() ) {
00686       label = uri.prettyURL();
00687     }
00688     addUriAttachment( uri.url(), QString::null, label, true );
00689   }
00690 }
00691 
00692 void KOEditorAttachments::slotEdit()
00693 {
00694   for ( QIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00695     if ( item->isSelected() ) {
00696       AttachmentListItem *attitem = static_cast<AttachmentListItem*>( item );
00697       if ( !attitem || !attitem->attachment() ) {
00698         return;
00699       }
00700 
00701       AttachmentEditDialog *dialog = new AttachmentEditDialog( attitem, mAttachments );
00702       dialog->mInline->setEnabled( false );
00703       dialog->setModal( false );
00704       connect( dialog, SIGNAL(hidden()), dialog, SLOT(delayedDestruct()) );
00705       dialog->show();
00706     }
00707   }
00708 }
00709 
00710 void KOEditorAttachments::slotRemove()
00711 {
00712     QValueList<QIconViewItem*> selected;
00713     for ( QIconViewItem *it = mAttachments->firstItem( ); it; it = it->nextItem( ) ) {
00714         if ( !it->isSelected() ) continue;
00715         selected << it;
00716     }
00717     if ( selected.isEmpty() || KMessageBox::warningContinueCancel(this,
00718                     selected.count() == 1?i18n("This item will be permanently deleted."):
00719                     i18n("The selected items will be permanently deleted."),
00720                     i18n("KOrganizer Confirmation"),KStdGuiItem::del()) != KMessageBox::Continue )
00721         return;
00722 
00723     for ( QValueList<QIconViewItem*>::iterator it( selected.begin() ), end( selected.end() ); it != end ; ++it ) {
00724         delete *it;
00725     }
00726 }
00727 
00728 void KOEditorAttachments::slotShow()
00729 {
00730   for ( QIconViewItem *it = mAttachments->firstItem(); it; it = it->nextItem() ) {
00731     if ( !it->isSelected() )
00732       continue;
00733     showAttachment( it );
00734   }
00735 }
00736 
00737 void KOEditorAttachments::slotSaveAs()
00738 {
00739   for ( QIconViewItem *it = mAttachments->firstItem(); it; it = it->nextItem() ) {
00740     if ( !it->isSelected() )
00741       continue;
00742     saveAttachment( it );
00743   }
00744 }
00745 
00746 void KOEditorAttachments::setDefaults()
00747 {
00748   mAttachments->clear();
00749 }
00750 
00751 QString KOEditorAttachments::randomString(int length) const
00752 {
00753    if (length <=0 ) return QString();
00754 
00755    QString str; str.setLength( length );
00756    int i = 0;
00757    while (length--)
00758    {
00759       int r=random() % 62;
00760       r+=48;
00761       if (r>57) r+=7;
00762       if (r>90) r+=6;
00763       str[i++] =  char(r);
00764       // so what if I work backwards?
00765    }
00766    return str;
00767 }
00768 
00769 void KOEditorAttachments::addUriAttachment( const QString &uri,
00770                                             const QString &mimeType,
00771                                             const QString &label,
00772                                             bool inLine )
00773 {
00774   if ( !inLine ) {
00775     AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
00776     item->setUri( uri );
00777     item->setLabel( label );
00778     if ( mimeType.isEmpty() ) {
00779       if ( uri.startsWith( KDEPIMPROTOCOL_CONTACT ) ) {
00780         item->setMimeType( "text/directory" );
00781       } else if ( uri.startsWith( KDEPIMPROTOCOL_EMAIL ) ) {
00782         item->setMimeType( "message/rfc822" );
00783       } else if ( uri.startsWith( KDEPIMPROTOCOL_INCIDENCE ) ) {
00784         item->setMimeType( "text/calendar" );
00785       } else if ( uri.startsWith( KDEPIMPROTOCOL_NEWSARTICLE ) ) {
00786         item->setMimeType( "message/news" );
00787       } else {
00788         item->setMimeType( KMimeType::findByURL( uri )->name() );
00789       }
00790     }
00791   } else {
00792     QString tmpFile;
00793     if ( KIO::NetAccess::download( uri, tmpFile, this ) ) {
00794       QFile f( tmpFile );
00795       if ( !f.open( IO_ReadOnly ) ) {
00796         return;
00797       }
00798       const QByteArray data = f.readAll();
00799       f.close();
00800       addDataAttachment( data, mimeType, label );
00801     }
00802     KIO::NetAccess::removeTempFile( tmpFile );
00803   }
00804 }
00805 
00806 void KOEditorAttachments::addDataAttachment( const QByteArray &data,
00807                                              const QString &mimeType,
00808                                              const QString &label )
00809 {
00810   AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
00811 
00812   QString nlabel = label;
00813   if ( mimeType == "message/rfc822" ) {
00814     // mail message. try to set the label from the mail Subject:
00815     KMime::Message msg;
00816     msg.setContent( data.data() );
00817     msg.parse();
00818     nlabel = msg.subject()->asUnicodeString();
00819   }
00820 
00821   item->setData( data );
00822   item->setLabel( nlabel );
00823   if ( mimeType.isEmpty() ) {
00824     item->setMimeType( KMimeType::findByContent( data )->name() );
00825   } else {
00826     item->setMimeType( mimeType );
00827   }
00828 }
00829 
00830 void KOEditorAttachments::addAttachment( KCal::Attachment *attachment )
00831 {
00832   new AttachmentListItem( attachment, mAttachments );
00833 }
00834 
00835 void KOEditorAttachments::readIncidence( KCal::Incidence *i )
00836 {
00837   mAttachments->clear();
00838 
00839   KCal::Attachment::List attachments = i->attachments();
00840   KCal::Attachment::List::ConstIterator it;
00841   for( it = attachments.begin(); it != attachments.end(); ++it ) {
00842     addAttachment( (*it) );
00843   }
00844   if ( mAttachments->count() > 0 ) {
00845     QTimer::singleShot( 0, mAttachments, SLOT(arrangeItemsInGrid()) );
00846   }
00847 }
00848 
00849 void KOEditorAttachments::writeIncidence( KCal::Incidence *i )
00850 {
00851   i->clearAttachments();
00852 
00853   QIconViewItem *item;
00854   AttachmentListItem *attitem;
00855   for( item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00856     attitem = static_cast<AttachmentListItem*>(item);
00857     if ( attitem )
00858       i->addAttachment( new KCal::Attachment( *(attitem->attachment() ) ) );
00859   }
00860 }
00861 
00862 
00863 void KOEditorAttachments::slotCopy()
00864 {
00865     QApplication::clipboard()->setData( mAttachments->mimeData(), QClipboard::Clipboard );
00866 }
00867 
00868 void KOEditorAttachments::slotCut()
00869 {
00870     slotCopy();
00871     slotRemove();
00872 }
00873 
00874 void KOEditorAttachments::slotPaste()
00875 {
00876     handlePasteOrDrop( QApplication::clipboard()->data() );
00877 }
00878 
00879 void KOEditorAttachments::selectionChanged()
00880 {
00881   bool selected = false;
00882   for ( QIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00883     if ( item->isSelected() ) {
00884       selected = true;
00885       break;
00886     }
00887   }
00888   mRemoveBtn->setEnabled( selected );
00889 }
00890 
00891 void KOEditorAttachments::contextMenu(QIconViewItem * item, const QPoint & pos)
00892 {
00893   const bool enable = item != 0;
00894 
00895   int numSelected = 0;
00896   for ( QIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00897     if ( item->isSelected() ) {
00898       numSelected++;
00899     }
00900   }
00901 
00902   mOpenAction->setEnabled( enable );
00903   //TODO: support saving multiple attachments into a directory
00904   mSaveAsAction->setEnabled( enable && numSelected == 1 );
00905   mCopyAction->setEnabled( enable && numSelected == 1 );
00906   mCutAction->setEnabled( enable && numSelected == 1 );
00907   mDeleteAction->setEnabled( enable );
00908   mEditAction->setEnabled( enable );
00909   mContextMenu->exec( pos );
00910 }
00911 
00912 #include "koeditorattachments.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys