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 
00263     QString correctedUrl = mURLRequester->url();
00264     if ( !url.isValid() ) {
00265       // If the user used KURLRequester's KURLCompletion
00266       // (used the line edit instead of the file dialog)
00267       // the returned url is not absolute and is always relative
00268       // to the home directory (not pwd), so we must prepend home
00269 
00270       correctedUrl = QDir::home().filePath( mURLRequester->url() );
00271       url = KURL( correctedUrl );
00272       if ( url.isValid() ) {
00273         urlSelected( correctedUrl );
00274         mItem->setMimeType( mMimeType->name() );
00275       }
00276     }
00277 
00278     if ( mInline->isChecked() ) {
00279       QString tmpFile;
00280       if ( KIO::NetAccess::download( correctedUrl, tmpFile, this ) ) {
00281         QFile f( tmpFile );
00282         if ( !f.open( IO_ReadOnly ) ) {
00283           return;
00284         }
00285         QByteArray data = f.readAll();
00286         f.close();
00287         mItem->setData( data );
00288       }
00289       KIO::NetAccess::removeTempFile( tmpFile );
00290     } else {
00291       mItem->setUri( url.url() );
00292     }
00293   }
00294 }
00295 
00296 void AttachmentEditDialog::accept()
00297 {
00298   slotApply();
00299   KDialog::accept();
00300 }
00301 
00302 void AttachmentEditDialog::urlChanged( const QString &url )
00303 {
00304   enableButton( Ok, !url.isEmpty() );
00305 }
00306 
00307 void AttachmentEditDialog::urlSelected( const QString &url )
00308 {
00309   KURL kurl( url );
00310   mMimeType = KMimeType::findByURL( kurl );
00311   mTypeLabel->setText( mMimeType->comment() );
00312   mIcon->setPixmap( AttachmentListItem::icon( mMimeType, kurl.path() ) );
00313 }
00314 
00315 AttachmentIconView::AttachmentIconView( KOEditorAttachments* parent )
00316   : KIconView( parent ),
00317     mParent( parent )
00318 {
00319   setSelectionMode( QIconView::Extended );
00320   setMode( KIconView::Select );
00321   setItemTextPos( QIconView::Right );
00322   setArrangement( QIconView::LeftToRight );
00323   setMaxItemWidth( QMAX(maxItemWidth(), 250) );
00324   setMinimumHeight( QMAX(fontMetrics().height(), 16) + 12 );
00325 
00326   connect( this, SIGNAL( dropped ( QDropEvent *, const QValueList<QIconDragItem> & ) ),
00327            this, SLOT( handleDrop( QDropEvent *, const QValueList<QIconDragItem> & ) ) );
00328 }
00329 
00330 KURL AttachmentIconView::tempFileForAttachment( KCal::Attachment *attachment )
00331 {
00332   if ( mTempFiles.contains( attachment ) ) {
00333     return mTempFiles[attachment];
00334   }
00335   QStringList patterns = KMimeType::mimeType( attachment->mimeType() )->patterns();
00336 
00337   KTempFile *file;
00338   if ( !patterns.empty() ) {
00339     file = new KTempFile( QString::null,
00340                           QString( patterns.first() ).remove( '*' ),0600 );
00341   } else {
00342     file = new KTempFile( QString::null, QString::null, 0600 );
00343   }
00344   file->setAutoDelete( true );
00345   file->file()->open( IO_WriteOnly );
00346   QTextStream stream( file->file() );
00347   stream.writeRawBytes( attachment->decodedData().data(), attachment->size() );
00348   KURL url( file->name() );
00349   mTempFiles.insert( attachment, url );
00350   file->close();
00351   return mTempFiles[attachment];
00352 }
00353 
00354 QDragObject *AttachmentIconView::mimeData()
00355 {
00356   // create a list of the URL:s that we want to drag
00357   KURL::List urls;
00358   QStringList labels;
00359   for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() ) {
00360     if ( it->isSelected() ) {
00361       AttachmentListItem *item = static_cast<AttachmentListItem *>( it );
00362       if ( item->isBinary() ) {
00363         urls.append( tempFileForAttachment( item->attachment() ) );
00364       } else {
00365         urls.append( item->uri() );
00366       }
00367       labels.append( KURL::encode_string( item->label() ) );
00368     }
00369   }
00370   if ( selectionMode() == QIconView::NoSelection ) {
00371     AttachmentListItem *item = static_cast<AttachmentListItem *>( currentItem() );
00372     if ( item ) {
00373       urls.append( item->uri() );
00374       labels.append( KURL::encode_string( item->label() ) );
00375     }
00376   }
00377 
00378   QMap<QString, QString> metadata;
00379   metadata["labels"] = labels.join( ":" );
00380 
00381   KURLDrag *drag = new KURLDrag( urls, metadata );
00382   return drag;
00383 }
00384 
00385 AttachmentIconView::~AttachmentIconView()
00386 {
00387   for ( std::set<KTempDir*>::iterator it = mTempDirs.begin() ; it != mTempDirs.end() ; ++it ) {
00388     delete *it;
00389   }
00390 }
00391 
00392 QDragObject * AttachmentIconView::dragObject()
00393 {
00394   KURL::List urls;
00395   for ( QIconViewItem *it = firstItem( ); it; it = it->nextItem( ) ) {
00396     if ( !it->isSelected() ) continue;
00397     AttachmentListItem * item = dynamic_cast<AttachmentListItem*>( it );
00398     if ( !item ) return 0;
00399     KCal::Attachment * att = item->attachment();
00400     assert( att );
00401     KURL url;
00402     if ( att->isUri() ) {
00403       url.setPath( att->uri() );
00404     } else {
00405       KTempDir *tempDir = new KTempDir(); // will be deleted on editor close
00406       tempDir->setAutoDelete( true );
00407       mTempDirs.insert( tempDir );
00408       QByteArray encoded;
00409       encoded.duplicate( att->data(), strlen( att->data() ) );
00410       QByteArray decoded;
00411       KCodecs::base64Decode( encoded, decoded );
00412       const QString fileName = tempDir->name( ) + '/' + att->label();
00413       KPIM::kByteArrayToFile( decoded, fileName, false, false, false );
00414       url.setPath( fileName );
00415     }
00416     urls << url;
00417   }
00418   KURLDrag *drag  = new KURLDrag( urls, this );
00419   return drag;
00420 }
00421 
00422 void AttachmentIconView::handleDrop( QDropEvent *event, const QValueList<QIconDragItem> & list )
00423 {
00424   Q_UNUSED( list );
00425   mParent->handlePasteOrDrop( event );
00426 }
00427 
00428 
00429 void AttachmentIconView::dragMoveEvent( QDragMoveEvent *event )
00430 {
00431   mParent->dragMoveEvent( event );
00432 }
00433 
00434 void AttachmentIconView::contentsDragMoveEvent( QDragMoveEvent *event )
00435 {
00436   mParent->dragMoveEvent( event );
00437 }
00438 
00439 void AttachmentIconView::contentsDragEnterEvent( QDragEnterEvent *event )
00440 {
00441   mParent->dragMoveEvent( event );
00442 }
00443 
00444 void AttachmentIconView::dragEnterEvent( QDragEnterEvent *event )
00445 {
00446   mParent->dragEnterEvent( event );
00447 }
00448 
00449 KOEditorAttachments::KOEditorAttachments( int spacing, QWidget *parent,
00450                                           const char *name )
00451   : QWidget( parent, name )
00452 {
00453   QBoxLayout *topLayout = new QHBoxLayout( this );
00454   topLayout->setSpacing( spacing );
00455 
00456   QLabel *label = new QLabel( i18n("Attachments:"), this );
00457   topLayout->addWidget( label );
00458 
00459   mAttachments = new AttachmentIconView( this );
00460   QWhatsThis::add( mAttachments,
00461                    i18n("Displays a list of current items (files, mail, etc.) "
00462                         "that have been associated with this event or to-do. ") );
00463   topLayout->addWidget( mAttachments );
00464   connect( mAttachments, SIGNAL( doubleClicked( QIconViewItem * ) ),
00465            SLOT( showAttachment( QIconViewItem * ) ) );
00466   connect( mAttachments, SIGNAL(selectionChanged()),
00467            SLOT(selectionChanged()) );
00468   connect( mAttachments, SIGNAL(contextMenuRequested(QIconViewItem*,const QPoint&)),
00469            SLOT(contextMenu(QIconViewItem*,const QPoint&)) );
00470 
00471     QPushButton *addButton = new QPushButton( this );
00472   addButton->setIconSet( SmallIconSet( "add" ) );
00473   QToolTip::add( addButton, i18n( "Add an attachment" ) );
00474   QWhatsThis::add( addButton,
00475                    i18n( "Shows a dialog used to select an attachment "
00476                          "to add to this event or to-do as link or as "
00477                          "inline data." ) );
00478   topLayout->addWidget( addButton );
00479   connect( addButton, SIGNAL(clicked()), SLOT(slotAdd()) );
00480 
00481   mRemoveBtn = new QPushButton( this );
00482   mRemoveBtn->setIconSet( SmallIconSet( "remove" ) );
00483   QToolTip::add( mRemoveBtn, i18n("&Remove") );
00484   QWhatsThis::add( mRemoveBtn,
00485                    i18n("Removes the attachment selected in the list above "
00486                         "from this event or to-do.") );
00487   topLayout->addWidget( mRemoveBtn );
00488   connect( mRemoveBtn, SIGNAL(clicked()), SLOT(slotRemove()) );
00489 
00490   mContextMenu = new KPopupMenu( this );
00491 
00492   KActionCollection* ac = new KActionCollection( this, this );
00493 
00494   mOpenAction = new KAction( i18n("Open"), 0, this, SLOT(slotShow()), ac );
00495   mOpenAction->plug( mContextMenu );
00496 
00497   mSaveAsAction = new KAction( i18n( "Save As..." ), 0, this, SLOT(slotSaveAs()), ac );
00498   mSaveAsAction->plug( mContextMenu );
00499   mContextMenu->insertSeparator();
00500 
00501   mCopyAction = KStdAction::copy(this, SLOT(slotCopy()), ac );
00502   mCopyAction->plug( mContextMenu );
00503   mCutAction = KStdAction::cut(this, SLOT(slotCut()), ac );
00504   mCutAction->plug( mContextMenu );
00505   KAction *action = KStdAction::paste(this, SLOT(slotPaste()), ac );
00506   action->plug( mContextMenu );
00507   mContextMenu->insertSeparator();
00508 
00509   mDeleteAction = new KAction( i18n( "&Remove" ), 0, this, SLOT(slotRemove()),  ac );
00510   mDeleteAction->plug( mContextMenu );
00511   mDeleteAction->setShortcut( Key_Delete );
00512   mContextMenu->insertSeparator();
00513 
00514   mEditAction = new KAction( i18n( "&Properties..." ), 0, this, SLOT(slotEdit()), ac );
00515   mEditAction->plug( mContextMenu );
00516 
00517   selectionChanged();
00518   setAcceptDrops( true );
00519 }
00520 
00521 KOEditorAttachments::~KOEditorAttachments()
00522 {
00523 }
00524 
00525 bool KOEditorAttachments::hasAttachments()
00526 {
00527   return mAttachments->count() != 0;
00528 }
00529 
00530 void KOEditorAttachments::dragMoveEvent( QDragMoveEvent *event )
00531 {
00532   event->accept( KURLDrag::canDecode( event ) ||
00533                  QTextDrag::canDecode( event ) ||
00534                  KPIM::MailListDrag::canDecode( event ) ||
00535                  KVCardDrag::canDecode( event ) );
00536 }
00537 
00538 void KOEditorAttachments::dragEnterEvent( QDragEnterEvent* event )
00539 {
00540   dragMoveEvent( event );
00541 }
00542 
00543 void KOEditorAttachments::handlePasteOrDrop( QMimeSource* source )
00544 {
00545   KURL::List urls;
00546   bool probablyWeHaveUris = false;
00547   bool weCanCopy = true;
00548   QStringList labels;
00549 
00550   if ( KVCardDrag::canDecode( source ) ) {
00551     KABC::Addressee::List addressees;
00552     KVCardDrag::decode( source, addressees );
00553     for ( KABC::Addressee::List::ConstIterator it = addressees.constBegin();
00554           it != addressees.constEnd(); ++it ) {
00555       urls.append( KDEPIMPROTOCOL_CONTACT + ( *it ).uid() );
00556       // there is some weirdness about realName(), hence fromUtf8
00557       labels.append( QString::fromUtf8( ( *it ).realName().latin1() ) );
00558     }
00559     probablyWeHaveUris = true;
00560   } else if ( KURLDrag::canDecode( source ) ) {
00561     QMap<QString,QString> metadata;
00562     if ( KURLDrag::decode( source, urls, metadata ) ) {
00563       probablyWeHaveUris = true;
00564       labels = QStringList::split( ':', metadata["labels"], FALSE );
00565       for ( QStringList::Iterator it = labels.begin(); it != labels.end(); ++it ) {
00566         *it = KURL::decode_string( (*it).latin1() );
00567       }
00568 
00569     }
00570   } else if ( QTextDrag::canDecode( source ) ) {
00571     QString text;
00572     QTextDrag::decode( source, text );
00573     QStringList lst = QStringList::split( '\n', text, FALSE );
00574     for ( QStringList::ConstIterator it = lst.constBegin(); it != lst.constEnd(); ++it ) {
00575       urls.append( *it );
00576       labels.append( QString::null );
00577     }
00578     probablyWeHaveUris = true;
00579   }
00580 
00581   KPopupMenu menu;
00582   int items=0;
00583   if ( probablyWeHaveUris ) {
00584     menu.insertItem( i18n( "&Link here" ), DRAG_LINK, items++ );
00585     // we need to check if we can reasonably expect to copy the objects
00586     for ( KURL::List::ConstIterator it = urls.constBegin(); it != urls.constEnd(); ++it ) {
00587       if ( !( weCanCopy = KProtocolInfo::supportsReading( *it ) ) ) {
00588         break; // either we can copy them all, or no copying at all
00589       }
00590     }
00591     if ( weCanCopy ) {
00592       menu.insertItem( SmallIcon( "editcopy" ), i18n( "&Copy Here" ), DRAG_COPY, items++ );
00593     }
00594   } else {
00595       menu.insertItem( SmallIcon( "editcopy" ), i18n( "&Copy Here" ), DRAG_COPY, items++ );
00596   }
00597 
00598   menu.insertSeparator();
00599   items++;
00600   menu.insertItem( SmallIcon( "cancel" ), i18n( "C&ancel" ), DRAG_CANCEL, items );
00601   int action = menu.exec( QCursor::pos(), 0 );
00602 
00603   if ( action == DRAG_LINK ) {
00604     QStringList::ConstIterator jt = labels.constBegin();
00605     for ( KURL::List::ConstIterator it = urls.constBegin();
00606           it != urls.constEnd(); ++it ) {
00607       QString label = (*jt++);
00608       if ( mAttachments->findItem( label ) ) {
00609         label += '~' + randomString( 3 );
00610       }
00611       addUriAttachment( (*it).url(), QString::null, label, true );
00612     }
00613   } else if ( action != DRAG_CANCEL ) {
00614     if ( probablyWeHaveUris ) {
00615       for ( KURL::List::ConstIterator it = urls.constBegin();
00616             it != urls.constEnd(); ++it ) {
00617         QString label = (*it).fileName();
00618         if ( label.isEmpty() ) {
00619           label = (*it).prettyURL();
00620         }
00621         if ( mAttachments->findItem( label ) ) {
00622           label += '~' + randomString( 3 );
00623         }
00624         addUriAttachment( (*it).url(), QString::null, label, true );
00625       }
00626     } else { // we take anything
00627       addDataAttachment( source->encodedData( source->format() ),
00628                          source->format(),
00629                          KMimeType::mimeType( source->format() )->name() );
00630     }
00631   }
00632 }
00633 
00634 void KOEditorAttachments::dropEvent( QDropEvent* event )
00635 {
00636     handlePasteOrDrop( event );
00637 }
00638 
00639 void KOEditorAttachments::showAttachment( QIconViewItem *item )
00640 {
00641   AttachmentListItem *attitem = static_cast<AttachmentListItem*>(item);
00642   if ( !attitem || !attitem->attachment() ) return;
00643 
00644   KCal::Attachment *att = attitem->attachment();
00645   if ( att->isUri() ) {
00646     emit openURL( att->uri() );
00647   } else {
00648     KRun::runURL( mAttachments->tempFileForAttachment( att ), att->mimeType(), 0, true );
00649   }
00650 }
00651 
00652 void KOEditorAttachments::saveAttachment( QIconViewItem *item )
00653 {
00654   AttachmentListItem *attitem = static_cast<AttachmentListItem*>(item);
00655   if ( !attitem || !attitem->attachment() ) return;
00656 
00657   KCal::Attachment *att = attitem->attachment();
00658 
00659   // get the saveas file name
00660   QString saveAsFile =
00661     KFileDialog::getSaveFileName( att->label(),
00662                                   QString::null, 0,
00663                                   i18n( "Save  Attachment" ) );
00664   if ( saveAsFile.isEmpty() ||
00665        ( QFile( saveAsFile ).exists() &&
00666          ( KMessageBox::warningYesNo(
00667            0,
00668            i18n( "%1 already exists. Do you want to overwrite it?").
00669            arg( saveAsFile ) ) == KMessageBox::No ) ) ) {
00670     return;
00671   }
00672 
00673   KURL sourceUrl;
00674   if ( att->isUri() ) {
00675     sourceUrl = att->uri();
00676   } else {
00677     sourceUrl = mAttachments->tempFileForAttachment( att );
00678   }
00679   // save the attachment url
00680   if ( !KIO::NetAccess::file_copy( sourceUrl, KURL( saveAsFile ), -1, true ) &&
00681        KIO::NetAccess::lastError() ) {
00682     KMessageBox::error( this, KIO::NetAccess::lastErrorString() );
00683   }
00684 }
00685 
00686 void KOEditorAttachments::slotAdd()
00687 {
00688   AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
00689 
00690   AttachmentEditDialog *dlg = new AttachmentEditDialog( item, mAttachments )
00691 ;
00692   if ( dlg->exec() == KDialog::Rejected ) {
00693     delete item;
00694   }
00695   delete dlg;
00696 }
00697 
00698 void KOEditorAttachments::slotAddData()
00699 {
00700   KURL uri = KFileDialog::getOpenFileName( QString(), QString(), this, i18n("Add Attachment") );
00701   if ( !uri.isEmpty() ) {
00702     QString label = uri.fileName();
00703     if ( label.isEmpty() ) {
00704       label = uri.prettyURL();
00705     }
00706     addUriAttachment( uri.url(), QString::null, label, true );
00707   }
00708 }
00709 
00710 void KOEditorAttachments::slotEdit()
00711 {
00712   for ( QIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00713     if ( item->isSelected() ) {
00714       AttachmentListItem *attitem = static_cast<AttachmentListItem*>( item );
00715       if ( !attitem || !attitem->attachment() ) {
00716         return;
00717       }
00718 
00719       AttachmentEditDialog *dialog = new AttachmentEditDialog( attitem, mAttachments );
00720       dialog->mInline->setEnabled( false );
00721       dialog->setModal( false );
00722       connect( dialog, SIGNAL(hidden()), dialog, SLOT(delayedDestruct()) );
00723       dialog->show();
00724     }
00725   }
00726 }
00727 
00728 void KOEditorAttachments::slotRemove()
00729 {
00730   QValueList<QIconViewItem*> selected;
00731   QStringList labels;
00732   for ( QIconViewItem *it = mAttachments->firstItem( ); it; it = it->nextItem( ) ) {
00733     if ( !it->isSelected() ) continue;
00734     selected << it;
00735 
00736     AttachmentListItem *attitem = static_cast<AttachmentListItem*>(it);
00737     KCal::Attachment *att = attitem->attachment();
00738     labels << att->label();
00739   }
00740 
00741   if ( selected.isEmpty() ) {
00742     return;
00743   }
00744 
00745   QString labelsStr = labels.join( "<br>" );
00746 
00747   if ( KMessageBox::questionYesNo(
00748          this,
00749          i18n( "<qt>Do you really want to remove these attachments?<p>%1</qt>" ).arg( labelsStr ),
00750          i18n( "Remove Attachment?" ),
00751          KStdGuiItem::yes(), KStdGuiItem::no(),
00752          "calendarRemoveAttachments" ) != KMessageBox::Yes ) {
00753     return;
00754   }
00755 
00756   for ( QValueList<QIconViewItem*>::iterator it( selected.begin() ), end( selected.end() );
00757         it != end ; ++it ) {
00758     if ( (*it)->nextItem() ) {
00759       (*it)->nextItem()->setSelected( true );
00760     } else if ( (*it)->prevItem() ) {
00761       (*it)->prevItem()->setSelected( true );
00762     }
00763     delete *it;
00764   }
00765   mAttachments->slotUpdate();
00766 }
00767 
00768 void KOEditorAttachments::slotShow()
00769 {
00770   for ( QIconViewItem *it = mAttachments->firstItem(); it; it = it->nextItem() ) {
00771     if ( !it->isSelected() )
00772       continue;
00773     showAttachment( it );
00774   }
00775 }
00776 
00777 void KOEditorAttachments::slotSaveAs()
00778 {
00779   for ( QIconViewItem *it = mAttachments->firstItem(); it; it = it->nextItem() ) {
00780     if ( !it->isSelected() )
00781       continue;
00782     saveAttachment( it );
00783   }
00784 }
00785 
00786 void KOEditorAttachments::setDefaults()
00787 {
00788   mAttachments->clear();
00789 }
00790 
00791 QString KOEditorAttachments::randomString(int length) const
00792 {
00793    if (length <=0 ) return QString();
00794 
00795    QString str; str.setLength( length );
00796    int i = 0;
00797    while (length--)
00798    {
00799       int r=random() % 62;
00800       r+=48;
00801       if (r>57) r+=7;
00802       if (r>90) r+=6;
00803       str[i++] =  char(r);
00804       // so what if I work backwards?
00805    }
00806    return str;
00807 }
00808 
00809 void KOEditorAttachments::addUriAttachment( const QString &uri,
00810                                             const QString &mimeType,
00811                                             const QString &label,
00812                                             bool inLine )
00813 {
00814   if ( !inLine ) {
00815     AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
00816     item->setUri( uri );
00817     item->setLabel( label );
00818     if ( mimeType.isEmpty() ) {
00819       if ( uri.startsWith( KDEPIMPROTOCOL_CONTACT ) ) {
00820         item->setMimeType( "text/directory" );
00821       } else if ( uri.startsWith( KDEPIMPROTOCOL_EMAIL ) ) {
00822         item->setMimeType( "message/rfc822" );
00823       } else if ( uri.startsWith( KDEPIMPROTOCOL_INCIDENCE ) ) {
00824         item->setMimeType( "text/calendar" );
00825       } else if ( uri.startsWith( KDEPIMPROTOCOL_NEWSARTICLE ) ) {
00826         item->setMimeType( "message/news" );
00827       } else {
00828         item->setMimeType( KMimeType::findByURL( uri )->name() );
00829       }
00830     }
00831   } else {
00832     QString tmpFile;
00833     if ( KIO::NetAccess::download( uri, tmpFile, this ) ) {
00834       QFile f( tmpFile );
00835       if ( !f.open( IO_ReadOnly ) ) {
00836         return;
00837       }
00838       const QByteArray data = f.readAll();
00839       f.close();
00840       addDataAttachment( data, mimeType, label );
00841     }
00842     KIO::NetAccess::removeTempFile( tmpFile );
00843   }
00844 }
00845 
00846 void KOEditorAttachments::addDataAttachment( const QByteArray &data,
00847                                              const QString &mimeType,
00848                                              const QString &label )
00849 {
00850   AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
00851 
00852   QString nlabel = label;
00853   if ( mimeType == "message/rfc822" ) {
00854     // mail message. try to set the label from the mail Subject:
00855     KMime::Message msg;
00856     msg.setContent( data.data() );
00857     msg.parse();
00858     nlabel = msg.subject()->asUnicodeString();
00859   }
00860 
00861   item->setData( data );
00862   item->setLabel( nlabel );
00863   if ( mimeType.isEmpty() ) {
00864     item->setMimeType( KMimeType::findByContent( data )->name() );
00865   } else {
00866     item->setMimeType( mimeType );
00867   }
00868 }
00869 
00870 void KOEditorAttachments::addAttachment( KCal::Attachment *attachment )
00871 {
00872   new AttachmentListItem( attachment, mAttachments );
00873 }
00874 
00875 void KOEditorAttachments::readIncidence( KCal::Incidence *i )
00876 {
00877   mAttachments->clear();
00878 
00879   KCal::Attachment::List attachments = i->attachments();
00880   KCal::Attachment::List::ConstIterator it;
00881   for( it = attachments.begin(); it != attachments.end(); ++it ) {
00882     addAttachment( (*it) );
00883   }
00884   if ( mAttachments->count() > 0 ) {
00885     QTimer::singleShot( 0, mAttachments, SLOT(arrangeItemsInGrid()) );
00886   }
00887 }
00888 
00889 void KOEditorAttachments::writeIncidence( KCal::Incidence *i )
00890 {
00891   i->clearAttachments();
00892 
00893   QIconViewItem *item;
00894   AttachmentListItem *attitem;
00895   for( item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00896     attitem = static_cast<AttachmentListItem*>(item);
00897     if ( attitem )
00898       i->addAttachment( new KCal::Attachment( *(attitem->attachment() ) ) );
00899   }
00900 }
00901 
00902 
00903 void KOEditorAttachments::slotCopy()
00904 {
00905     QApplication::clipboard()->setData( mAttachments->mimeData(), QClipboard::Clipboard );
00906 }
00907 
00908 void KOEditorAttachments::slotCut()
00909 {
00910     slotCopy();
00911     slotRemove();
00912 }
00913 
00914 void KOEditorAttachments::slotPaste()
00915 {
00916     handlePasteOrDrop( QApplication::clipboard()->data() );
00917 }
00918 
00919 void KOEditorAttachments::selectionChanged()
00920 {
00921   bool selected = false;
00922   for ( QIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00923     if ( item->isSelected() ) {
00924       selected = true;
00925       break;
00926     }
00927   }
00928   mRemoveBtn->setEnabled( selected );
00929 }
00930 
00931 void KOEditorAttachments::contextMenu(QIconViewItem * item, const QPoint & pos)
00932 {
00933   const bool enable = item != 0;
00934 
00935   int numSelected = 0;
00936   for ( QIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00937     if ( item->isSelected() ) {
00938       numSelected++;
00939     }
00940   }
00941 
00942   mOpenAction->setEnabled( enable );
00943   //TODO: support saving multiple attachments into a directory
00944   mSaveAsAction->setEnabled( enable && numSelected == 1 );
00945   mCopyAction->setEnabled( enable && numSelected == 1 );
00946   mCutAction->setEnabled( enable && numSelected == 1 );
00947   mDeleteAction->setEnabled( enable );
00948   mEditAction->setEnabled( enable );
00949   mContextMenu->exec( pos );
00950 }
00951 
00952 #include "koeditorattachments.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys