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?" ),
00735          KStdGuiItem::yes(), KStdGuiItem::no(),
00736          "calendarRemoveAttachments" ) != KMessageBox::Yes ) {
00737     return;
00738   }
00739 
00740   for ( QValueList<QIconViewItem*>::iterator it( selected.begin() ), end( selected.end() );
00741         it != end ; ++it ) {
00742     if ( (*it)->nextItem() ) {
00743       (*it)->nextItem()->setSelected( true );
00744     } else if ( (*it)->prevItem() ) {
00745       (*it)->prevItem()->setSelected( true );
00746     }
00747     delete *it;
00748   }
00749   mAttachments->slotUpdate();
00750 }
00751 
00752 void KOEditorAttachments::slotShow()
00753 {
00754   for ( QIconViewItem *it = mAttachments->firstItem(); it; it = it->nextItem() ) {
00755     if ( !it->isSelected() )
00756       continue;
00757     showAttachment( it );
00758   }
00759 }
00760 
00761 void KOEditorAttachments::slotSaveAs()
00762 {
00763   for ( QIconViewItem *it = mAttachments->firstItem(); it; it = it->nextItem() ) {
00764     if ( !it->isSelected() )
00765       continue;
00766     saveAttachment( it );
00767   }
00768 }
00769 
00770 void KOEditorAttachments::setDefaults()
00771 {
00772   mAttachments->clear();
00773 }
00774 
00775 QString KOEditorAttachments::randomString(int length) const
00776 {
00777    if (length <=0 ) return QString();
00778 
00779    QString str; str.setLength( length );
00780    int i = 0;
00781    while (length--)
00782    {
00783       int r=random() % 62;
00784       r+=48;
00785       if (r>57) r+=7;
00786       if (r>90) r+=6;
00787       str[i++] =  char(r);
00788       // so what if I work backwards?
00789    }
00790    return str;
00791 }
00792 
00793 void KOEditorAttachments::addUriAttachment( const QString &uri,
00794                                             const QString &mimeType,
00795                                             const QString &label,
00796                                             bool inLine )
00797 {
00798   if ( !inLine ) {
00799     AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
00800     item->setUri( uri );
00801     item->setLabel( label );
00802     if ( mimeType.isEmpty() ) {
00803       if ( uri.startsWith( KDEPIMPROTOCOL_CONTACT ) ) {
00804         item->setMimeType( "text/directory" );
00805       } else if ( uri.startsWith( KDEPIMPROTOCOL_EMAIL ) ) {
00806         item->setMimeType( "message/rfc822" );
00807       } else if ( uri.startsWith( KDEPIMPROTOCOL_INCIDENCE ) ) {
00808         item->setMimeType( "text/calendar" );
00809       } else if ( uri.startsWith( KDEPIMPROTOCOL_NEWSARTICLE ) ) {
00810         item->setMimeType( "message/news" );
00811       } else {
00812         item->setMimeType( KMimeType::findByURL( uri )->name() );
00813       }
00814     }
00815   } else {
00816     QString tmpFile;
00817     if ( KIO::NetAccess::download( uri, tmpFile, this ) ) {
00818       QFile f( tmpFile );
00819       if ( !f.open( IO_ReadOnly ) ) {
00820         return;
00821       }
00822       const QByteArray data = f.readAll();
00823       f.close();
00824       addDataAttachment( data, mimeType, label );
00825     }
00826     KIO::NetAccess::removeTempFile( tmpFile );
00827   }
00828 }
00829 
00830 void KOEditorAttachments::addDataAttachment( const QByteArray &data,
00831                                              const QString &mimeType,
00832                                              const QString &label )
00833 {
00834   AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
00835 
00836   QString nlabel = label;
00837   if ( mimeType == "message/rfc822" ) {
00838     // mail message. try to set the label from the mail Subject:
00839     KMime::Message msg;
00840     msg.setContent( data.data() );
00841     msg.parse();
00842     nlabel = msg.subject()->asUnicodeString();
00843   }
00844 
00845   item->setData( data );
00846   item->setLabel( nlabel );
00847   if ( mimeType.isEmpty() ) {
00848     item->setMimeType( KMimeType::findByContent( data )->name() );
00849   } else {
00850     item->setMimeType( mimeType );
00851   }
00852 }
00853 
00854 void KOEditorAttachments::addAttachment( KCal::Attachment *attachment )
00855 {
00856   new AttachmentListItem( attachment, mAttachments );
00857 }
00858 
00859 void KOEditorAttachments::readIncidence( KCal::Incidence *i )
00860 {
00861   mAttachments->clear();
00862 
00863   KCal::Attachment::List attachments = i->attachments();
00864   KCal::Attachment::List::ConstIterator it;
00865   for( it = attachments.begin(); it != attachments.end(); ++it ) {
00866     addAttachment( (*it) );
00867   }
00868   if ( mAttachments->count() > 0 ) {
00869     QTimer::singleShot( 0, mAttachments, SLOT(arrangeItemsInGrid()) );
00870   }
00871 }
00872 
00873 void KOEditorAttachments::writeIncidence( KCal::Incidence *i )
00874 {
00875   i->clearAttachments();
00876 
00877   QIconViewItem *item;
00878   AttachmentListItem *attitem;
00879   for( item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00880     attitem = static_cast<AttachmentListItem*>(item);
00881     if ( attitem )
00882       i->addAttachment( new KCal::Attachment( *(attitem->attachment() ) ) );
00883   }
00884 }
00885 
00886 
00887 void KOEditorAttachments::slotCopy()
00888 {
00889     QApplication::clipboard()->setData( mAttachments->mimeData(), QClipboard::Clipboard );
00890 }
00891 
00892 void KOEditorAttachments::slotCut()
00893 {
00894     slotCopy();
00895     slotRemove();
00896 }
00897 
00898 void KOEditorAttachments::slotPaste()
00899 {
00900     handlePasteOrDrop( QApplication::clipboard()->data() );
00901 }
00902 
00903 void KOEditorAttachments::selectionChanged()
00904 {
00905   bool selected = false;
00906   for ( QIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00907     if ( item->isSelected() ) {
00908       selected = true;
00909       break;
00910     }
00911   }
00912   mRemoveBtn->setEnabled( selected );
00913 }
00914 
00915 void KOEditorAttachments::contextMenu(QIconViewItem * item, const QPoint & pos)
00916 {
00917   const bool enable = item != 0;
00918 
00919   int numSelected = 0;
00920   for ( QIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00921     if ( item->isSelected() ) {
00922       numSelected++;
00923     }
00924   }
00925 
00926   mOpenAction->setEnabled( enable );
00927   //TODO: support saving multiple attachments into a directory
00928   mSaveAsAction->setEnabled( enable && numSelected == 1 );
00929   mCopyAction->setEnabled( enable && numSelected == 1 );
00930   mCutAction->setEnabled( enable && numSelected == 1 );
00931   mDeleteAction->setEnabled( enable );
00932   mEditAction->setEnabled( enable );
00933   mContextMenu->exec( pos );
00934 }
00935 
00936 #include "koeditorattachments.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys