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 
00056 #include <qcheckbox.h>
00057 #include <qfile.h>
00058 #include <qlabel.h>
00059 #include <qlayout.h>
00060 #include <qlistview.h>
00061 #include <qpushbutton.h>
00062 #include <qdragobject.h>
00063 #include <qtooltip.h>
00064 #include <qwhatsthis.h>
00065 #include <qapplication.h>
00066 #include <qclipboard.h>
00067 
00068 #include <cassert>
00069 #include <cstdlib>
00070 
00071 class AttachmentListItem : public KIconViewItem
00072 {
00073   public:
00074     AttachmentListItem( KCal::Attachment*att, QIconView *parent ) :
00075         KIconViewItem( parent )
00076     {
00077       if ( att ) {
00078         mAttachment = new KCal::Attachment( *att );
00079       } else {
00080         mAttachment = new KCal::Attachment( QString::null );
00081       }
00082       readAttachment();
00083       setDragEnabled( true );
00084     }
00085     ~AttachmentListItem() { delete mAttachment; }
00086     KCal::Attachment *attachment() const { return mAttachment; }
00087 
00088     const QString uri() const
00089     {
00090       return mAttachment->uri();
00091     }
00092     void setUri( const QString &uri )
00093     {
00094       mAttachment->setUri( uri );
00095       readAttachment();
00096     }
00097     void setData( const QByteArray data )
00098     {
00099       mAttachment->setDecodedData( data );
00100       readAttachment();
00101     }
00102     const QString mimeType() const
00103     {
00104       return mAttachment->mimeType();
00105     }
00106     void setMimeType( const QString &mime )
00107     {
00108       mAttachment->setMimeType( mime );
00109       readAttachment();
00110     }
00111     const QString label() const
00112     {
00113       return mAttachment->label();
00114     }
00115     void setLabel( const QString &label )
00116     {
00117       mAttachment->setLabel( label );
00118       readAttachment();
00119     }
00120     bool isBinary() const
00121     {
00122       return mAttachment->isBinary();
00123     }
00124     QPixmap icon() const
00125     {
00126       return icon( KMimeType::mimeType( mAttachment->mimeType() ),
00127                    mAttachment->uri() );
00128     }
00129     static QPixmap icon( KMimeType::Ptr mimeType, const QString &uri )
00130     {
00131       QString iconStr = mimeType->icon( uri, false );
00132       return KGlobal::iconLoader()->loadIcon( iconStr, KIcon::Small );
00133     }
00134     void readAttachment()
00135     {
00136       if ( mAttachment->label().isEmpty() ) {
00137         if ( mAttachment->isUri() ) {
00138           setText( mAttachment->uri() );
00139         } else {
00140           setText( i18n( "[Binary data]" ) );
00141         }
00142       } else {
00143         setText( mAttachment->label() );
00144       }
00145       if ( mAttachment->mimeType().isEmpty() ||
00146            !( KMimeType::mimeType( mAttachment->mimeType() ) ) ) {
00147         KMimeType::Ptr mimeType;
00148         if ( mAttachment->isUri() ) {
00149           mimeType = KMimeType::findByURL( mAttachment->uri() );
00150         } else {
00151           mimeType = KMimeType::findByContent( mAttachment->decodedData() );
00152         }
00153         mAttachment->setMimeType( mimeType->name() );
00154       }
00155 
00156       setPixmap( icon() );
00157     }
00158 
00159   private:
00160     KCal::Attachment *mAttachment;
00161 };
00162 
00163 AttachmentEditDialog::AttachmentEditDialog( AttachmentListItem *item,
00164                                             QWidget *parent )
00165   : KDialogBase ( Plain, i18n( "Add Attachment" ), Ok|Cancel, Ok, parent, 0, false, false ),
00166     mItem( item ), mURLRequester( 0 )
00167 {
00168   QFrame *topFrame = plainPage();
00169   QVBoxLayout *vbl = new QVBoxLayout( topFrame, 0, spacingHint() );
00170 
00171   QGridLayout *grid = new QGridLayout();
00172   grid->setColStretch( 0, 0 );
00173   grid->setColStretch( 1, 0 );
00174   grid->setColStretch( 2, 1 );
00175   vbl->addLayout( grid );
00176 
00177   mIcon = new QLabel( topFrame );
00178   mIcon->setPixmap( item->icon() );
00179   grid->addWidget( mIcon, 0, 0 );
00180 
00181   mLabelEdit = new KLineEdit( topFrame );
00182   mLabelEdit->setClickMessage( i18n( "Attachment name" ) );
00183   if ( !item->uri().isEmpty() ) {
00184     KURL url( item->uri() );
00185     if ( url.isLocalFile() ) {
00186       mLabelEdit->setText( url.fileName() );
00187     } else {
00188       mLabelEdit->setText( url.url() );
00189     }
00190   }
00191   QToolTip::add( mLabelEdit, i18n( "Give the attachment a name" ) );
00192   QWhatsThis::add( mLabelEdit,
00193                    i18n( "Type any string you desire here for the name of the attachment" ) );
00194   grid->addMultiCellWidget( mLabelEdit, 0, 0, 1, 2 );
00195 
00196   KSeparator *sep = new KSeparator( Qt::Horizontal, topFrame );
00197   grid->addMultiCellWidget( sep, 1, 1, 0, 2 );
00198 
00199   QLabel *label = new QLabel( i18n( "Type:" ), topFrame );
00200   grid->addWidget( label, 2, 0 );
00201   QString typecomment = item->mimeType().isEmpty() ?
00202                         i18n( "Unknown" ) :
00203                         KMimeType::mimeType( item->mimeType() )->comment();
00204   mTypeLabel = new QLabel( typecomment, topFrame );
00205   grid->addWidget( mTypeLabel, 2, 1 );
00206   mMimeType = KMimeType::mimeType( item->mimeType() );
00207 
00208   mInline = new QCheckBox( i18n( "Store attachment inline" ), topFrame );
00209   grid->addMultiCellWidget( mInline, 3, 3, 0, 2 );
00210   mInline->setChecked( item->isBinary() );
00211   QToolTip::add( mInline, i18n( "Store the attachment file inside the calendar" ) );
00212   QWhatsThis::add(
00213     mInline,
00214     i18n( "Checking this option will cause the attachment to be stored inside "
00215           "your calendar, which can take a lot of space depending on the size "
00216           "of the attachment. If this option is not checked, then only a link "
00217           "pointing to the attachment will be stored.  Do not use a link for "
00218           "attachments that change often or may be moved (or removed) from "
00219           "their current location." ) );
00220 
00221   if ( item->attachment()->isUri() ) {
00222     label = new QLabel( i18n( "Location:" ), topFrame );
00223     grid->addWidget( label, 4, 0 );
00224     mURLRequester = new KURLRequester( item->uri(), topFrame );
00225     QToolTip::add( mURLRequester, i18n( "Provide a location for the attachment file" ) );
00226     QWhatsThis::add(
00227       mURLRequester,
00228       i18n( "Enter the path to the attachment file or use the "
00229             "file browser by pressing the adjacent button" ) );
00230     grid->addMultiCellWidget( mURLRequester, 4, 4, 1, 2 );
00231     connect( mURLRequester, SIGNAL(urlSelected(const QString &)),
00232              SLOT(urlSelected(const QString &)) );
00233     connect( mURLRequester, SIGNAL( textChanged( const QString& ) ),
00234              SLOT( urlChanged( const QString& ) ) );
00235     urlChanged( item->uri() );
00236   } else {
00237     uint size = QCString( item->attachment()->data() ).size();
00238     grid->addWidget( new QLabel( i18n( "Size:" ), topFrame ), 4, 0 );
00239     grid->addWidget( new QLabel( QString::fromLatin1( "%1 (%2)" ).
00240                                  arg( KIO::convertSize( size ) ).
00241                                  arg( KGlobal::locale()->formatNumber(
00242                                         size, 0 ) ), topFrame ), 4, 2 );
00243   }
00244   vbl->addStretch( 10 );
00245 }
00246 
00247 void AttachmentEditDialog::slotApply()
00248 {
00249   KURL url( mURLRequester->url() );
00250   if ( mLabelEdit->text().isEmpty() ) {
00251     if ( url.isLocalFile() ) {
00252       mItem->setLabel( url.fileName() );
00253     } else {
00254       mItem->setLabel( url.url() );
00255     }
00256   } else {
00257     mItem->setLabel( mLabelEdit->text() );
00258   }
00259   if ( mItem->label().isEmpty() ) {
00260     mItem->setLabel( i18n( "New attachment" ) );
00261   }
00262   mItem->setMimeType( mMimeType->name() );
00263   if ( mURLRequester ) {
00264     if ( mInline->isChecked() ) {
00265       QString tmpFile;
00266       if ( KIO::NetAccess::download( mURLRequester->url(), tmpFile, this ) ) {
00267         QFile f( tmpFile );
00268         if ( !f.open( IO_ReadOnly ) ) {
00269           return;
00270         }
00271         QByteArray data = f.readAll();
00272         f.close();
00273         mItem->setData( data );
00274       }
00275       KIO::NetAccess::removeTempFile( tmpFile );
00276     } else {
00277       mItem->setUri( url.url() );
00278     }
00279   }
00280 }
00281 
00282 void AttachmentEditDialog::accept()
00283 {
00284   slotApply();
00285   KDialog::accept();
00286 }
00287 
00288 void AttachmentEditDialog::urlChanged( const QString &url )
00289 {
00290   enableButton( Ok, !url.isEmpty() );
00291 }
00292 
00293 void AttachmentEditDialog::urlSelected( const QString &url )
00294 {
00295   KURL kurl( url );
00296   mMimeType = KMimeType::findByURL( kurl );
00297   mTypeLabel->setText( mMimeType->comment() );
00298   mIcon->setPixmap( AttachmentListItem::icon( mMimeType, kurl.path() ) );
00299 }
00300 
00301 AttachmentIconView::AttachmentIconView( KOEditorAttachments* parent )
00302   : KIconView( parent ),
00303     mParent( parent )
00304 {
00305   setSelectionMode( QIconView::Extended );
00306   setMode( KIconView::Select );
00307   setItemTextPos( QIconView::Right );
00308   setArrangement( QIconView::LeftToRight );
00309   setMaxItemWidth( QMAX(maxItemWidth(), 250) );
00310   setMinimumHeight( QMAX(fontMetrics().height(), 16) + 12 );
00311 
00312   connect( this, SIGNAL( dropped ( QDropEvent *, const QValueList<QIconDragItem> & ) ),
00313            this, SLOT( handleDrop( QDropEvent *, const QValueList<QIconDragItem> & ) ) );
00314 }
00315 
00316 KURL AttachmentIconView::tempFileForAttachment( KCal::Attachment *attachment )
00317 {
00318   if ( mTempFiles.contains( attachment ) ) {
00319     return mTempFiles[attachment];
00320   }
00321   QStringList patterns = KMimeType::mimeType( attachment->mimeType() )->patterns();
00322 
00323   KTempFile *file;
00324   if ( !patterns.empty() ) {
00325     file = new KTempFile( QString::null,
00326                           QString( patterns.first() ).remove( '*' ),0600 );
00327   } else {
00328     file = new KTempFile( QString::null, QString::null, 0600 );
00329   }
00330   file->setAutoDelete( true );
00331   file->file()->open( IO_WriteOnly );
00332   QTextStream stream( file->file() );
00333   stream << attachment->decodedData().data();
00334   KURL url( file->name() );
00335   mTempFiles.insert( attachment, url );
00336   file->close();
00337   return mTempFiles[attachment];
00338 }
00339 
00340 QDragObject *AttachmentIconView::mimeData()
00341 {
00342   // create a list of the URL:s that we want to drag
00343   KURL::List urls;
00344   QStringList labels;
00345   for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() ) {
00346     if ( it->isSelected() ) {
00347       AttachmentListItem *item = static_cast<AttachmentListItem *>( it );
00348       if ( item->isBinary() ) {
00349         urls.append( tempFileForAttachment( item->attachment() ) );
00350       } else {
00351         urls.append( item->uri() );
00352       }
00353       labels.append( KURL::encode_string( item->label() ) );
00354     }
00355   }
00356   if ( selectionMode() == QIconView::NoSelection ) {
00357     AttachmentListItem *item = static_cast<AttachmentListItem *>( currentItem() );
00358     if ( item ) {
00359       urls.append( item->uri() );
00360       labels.append( KURL::encode_string( item->label() ) );
00361     }
00362   }
00363 
00364   QMap<QString, QString> metadata;
00365   metadata["labels"] = labels.join( ":" );
00366 
00367   KURLDrag *drag = new KURLDrag( urls, metadata );
00368   return drag;
00369 }
00370 
00371 AttachmentIconView::~AttachmentIconView()
00372 {
00373   for ( std::set<KTempDir*>::iterator it = mTempDirs.begin() ; it != mTempDirs.end() ; ++it ) {
00374     delete *it;
00375   }
00376 }
00377 
00378 QDragObject * AttachmentIconView::dragObject()
00379 {
00380   KURL::List urls;
00381   for ( QIconViewItem *it = firstItem( ); it; it = it->nextItem( ) ) {
00382     if ( !it->isSelected() ) continue;
00383     AttachmentListItem * item = dynamic_cast<AttachmentListItem*>( it );
00384     if ( !item ) return 0;
00385     KCal::Attachment * att = item->attachment();
00386     assert( att );
00387     KURL url;
00388     if ( att->isUri() ) {
00389       url.setPath( att->uri() );
00390     } else {
00391       KTempDir * tempDir = new KTempDir(); // will be deleted on editor close
00392       tempDir->setAutoDelete( true );
00393       mTempDirs.insert( tempDir );
00394       QByteArray encoded;
00395       encoded.duplicate( att->data(), strlen(att->data()) );
00396       QByteArray decoded;
00397       KCodecs::base64Decode( encoded, decoded );
00398       const QString fileName = tempDir->name( ) + "/" + att->label();
00399       KPIM::kByteArrayToFile( decoded, fileName, false, false, false );
00400       url.setPath( fileName );
00401     }
00402     urls << url;
00403   }
00404   KURLDrag *drag  = new KURLDrag( urls, this );
00405   return drag;
00406 }
00407 
00408 void AttachmentIconView::handleDrop( QDropEvent *event, const QValueList<QIconDragItem> & list )
00409 {
00410   Q_UNUSED( list );
00411   mParent->handlePasteOrDrop( event );
00412 }
00413 
00414 
00415 void AttachmentIconView::dragMoveEvent( QDragMoveEvent *event )
00416 {
00417   mParent->dragMoveEvent( event );
00418 }
00419 
00420 void AttachmentIconView::contentsDragMoveEvent( QDragMoveEvent *event )
00421 {
00422   mParent->dragMoveEvent( event );
00423 }
00424 
00425 void AttachmentIconView::contentsDragEnterEvent( QDragEnterEvent *event )
00426 {
00427   mParent->dragMoveEvent( event );
00428 }
00429 
00430 void AttachmentIconView::dragEnterEvent( QDragEnterEvent *event )
00431 {
00432   mParent->dragEnterEvent( event );
00433 }
00434 
00435 KOEditorAttachments::KOEditorAttachments( int spacing, QWidget *parent,
00436                                           const char *name )
00437   : QWidget( parent, name )
00438 {
00439   QBoxLayout *topLayout = new QHBoxLayout( this );
00440   topLayout->setSpacing( spacing );
00441 
00442   QLabel *label = new QLabel( i18n("Attachments:"), this );
00443   topLayout->addWidget( label );
00444 
00445   mAttachments = new AttachmentIconView( this );
00446   QWhatsThis::add( mAttachments,
00447                    i18n("Displays a list of current items (files, mail, etc.) "
00448                         "that have been associated with this event or to-do. ") );
00449   topLayout->addWidget( mAttachments );
00450   connect( mAttachments, SIGNAL( doubleClicked( QIconViewItem * ) ),
00451            SLOT( showAttachment( QIconViewItem * ) ) );
00452   connect( mAttachments, SIGNAL(selectionChanged()),
00453            SLOT(selectionChanged()) );
00454   connect( mAttachments, SIGNAL(contextMenuRequested(QIconViewItem*,const QPoint&)),
00455            SLOT(contextMenu(QIconViewItem*,const QPoint&)) );
00456 
00457     QPushButton *addButton = new QPushButton( this );
00458   addButton->setIconSet( SmallIconSet( "add" ) );
00459   QToolTip::add( addButton, i18n( "Add an attachment" ) );
00460   QWhatsThis::add( addButton,
00461                    i18n( "Shows a dialog used to select an attachment "
00462                          "to add to this event or to-do as link or as "
00463                          "inline data." ) );
00464   topLayout->addWidget( addButton );
00465   connect( addButton, SIGNAL(clicked()), SLOT(slotAdd()) );
00466 
00467   mRemoveBtn = new QPushButton( this );
00468   mRemoveBtn->setIconSet( SmallIconSet( "remove" ) );
00469   QToolTip::add( mRemoveBtn, i18n("&Remove") );
00470   QWhatsThis::add( mRemoveBtn,
00471                    i18n("Removes the attachment selected in the list above "
00472                         "from this event or to-do.") );
00473   topLayout->addWidget( mRemoveBtn );
00474   connect( mRemoveBtn, SIGNAL(clicked()), SLOT(slotRemove()) );
00475 
00476   mContextMenu = new KPopupMenu( this );
00477 
00478   KActionCollection* ac = new KActionCollection( this, this );
00479 
00480   mOpenAction = new KAction( i18n("Open"), 0, this, SLOT(slotShow()), ac );
00481   mOpenAction->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::slotAdd()
00635 {
00636   AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
00637 
00638   AttachmentEditDialog *dlg = new AttachmentEditDialog( item, mAttachments )
00639 ;
00640   if ( dlg->exec() == KDialog::Rejected ) {
00641     delete item;
00642   }
00643   delete dlg;
00644 }
00645 
00646 void KOEditorAttachments::slotAddData()
00647 {
00648   KURL uri = KFileDialog::getOpenFileName( QString(), QString(), this, i18n("Add Attachment") );
00649   if ( !uri.isEmpty() ) {
00650     QString label = uri.fileName();
00651     if ( label.isEmpty() ) {
00652       label = uri.prettyURL();
00653     }
00654     addUriAttachment( uri.url(), QString::null, label, true );
00655   }
00656 }
00657 
00658 void KOEditorAttachments::slotEdit()
00659 {
00660   for ( QIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00661     if ( item->isSelected() ) {
00662       AttachmentListItem *attitem = static_cast<AttachmentListItem*>( item );
00663       if ( !attitem || !attitem->attachment() ) {
00664         return;
00665       }
00666 
00667       AttachmentEditDialog *dialog = new AttachmentEditDialog( attitem, mAttachments );
00668       dialog->mInline->setEnabled( false );
00669       dialog->setModal( false );
00670       connect( dialog, SIGNAL(hidden()), dialog, SLOT(delayedDestruct()) );
00671       dialog->show();
00672     }
00673   }
00674 }
00675 
00676 void KOEditorAttachments::slotRemove()
00677 {
00678     QValueList<QIconViewItem*> selected;
00679     for ( QIconViewItem *it = mAttachments->firstItem( ); it; it = it->nextItem( ) ) {
00680         if ( !it->isSelected() ) continue;
00681         selected << it;
00682     }
00683     if ( selected.isEmpty() || KMessageBox::warningContinueCancel(this,
00684                     selected.count() == 1?i18n("This item will be permanently deleted."):
00685                     i18n("The selected items will be permanently deleted."),
00686                     i18n("KOrganizer Confirmation"),KStdGuiItem::del()) != KMessageBox::Continue )
00687         return;
00688 
00689     for ( QValueList<QIconViewItem*>::iterator it( selected.begin() ), end( selected.end() ); it != end ; ++it ) {
00690         delete *it;
00691     }
00692 }
00693 
00694 void KOEditorAttachments::slotShow()
00695 {
00696   for ( QIconViewItem *it = mAttachments->firstItem(); it; it = it->nextItem() ) {
00697     if ( !it->isSelected() )
00698       continue;
00699     showAttachment( it );
00700   }
00701 }
00702 
00703 void KOEditorAttachments::setDefaults()
00704 {
00705   mAttachments->clear();
00706 }
00707 
00708 QString KOEditorAttachments::randomString(int length) const
00709 {
00710    if (length <=0 ) return QString();
00711 
00712    QString str; str.setLength( length );
00713    int i = 0;
00714    while (length--)
00715    {
00716       int r=random() % 62;
00717       r+=48;
00718       if (r>57) r+=7;
00719       if (r>90) r+=6;
00720       str[i++] =  char(r);
00721       // so what if I work backwards?
00722    }
00723    return str;
00724 }
00725 
00726 void KOEditorAttachments::addUriAttachment( const QString &uri,
00727                                             const QString &mimeType,
00728                                             const QString &label,
00729                                             bool inLine )
00730 {
00731   if ( !inLine ) {
00732     AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
00733     item->setUri( uri );
00734     item->setLabel( label );
00735     if ( mimeType.isEmpty() ) {
00736       if ( uri.startsWith( KDEPIMPROTOCOL_CONTACT ) ) {
00737         item->setMimeType( "text/directory" );
00738       } else if ( uri.startsWith( KDEPIMPROTOCOL_EMAIL ) ) {
00739         item->setMimeType( "message/rfc822" );
00740       } else if ( uri.startsWith( KDEPIMPROTOCOL_INCIDENCE ) ) {
00741         item->setMimeType( "text/calendar" );
00742       } else if ( uri.startsWith( KDEPIMPROTOCOL_NEWSARTICLE ) ) {
00743         item->setMimeType( "message/news" );
00744       } else {
00745         item->setMimeType( KMimeType::findByURL( uri )->name() );
00746       }
00747     }
00748   } else {
00749     QString tmpFile;
00750     if ( KIO::NetAccess::download( uri, tmpFile, this ) ) {
00751       QFile f( tmpFile );
00752       if ( !f.open( IO_ReadOnly ) ) {
00753         return;
00754       }
00755       const QByteArray data = f.readAll();
00756       f.close();
00757       addDataAttachment( data, mimeType, label );
00758     }
00759     KIO::NetAccess::removeTempFile( tmpFile );
00760   }
00761 }
00762 
00763 void KOEditorAttachments::addDataAttachment( const QByteArray &data,
00764                                              const QString &mimeType,
00765                                              const QString &label )
00766 {
00767   AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
00768 
00769   QString nlabel = label;
00770   if ( mimeType == "message/rfc822" ) {
00771     // mail message. try to set the label from the mail Subject:
00772     QString line( data );
00773     int index = line.find( "Subject:" );
00774     if ( index >= 0 ) {
00775       QString substr = line.mid( index, 100 );
00776       int len = substr.find( '\n' );
00777       nlabel = substr.left( len ).remove( "Subject:" ).
00778                simplifyWhiteSpace().replace( ' ', '_' ).section( '_', 0, 3 );
00779     }
00780   }
00781 
00782   item->setData( data );
00783   item->setLabel( nlabel );
00784   if ( mimeType.isEmpty() ) {
00785     item->setMimeType( KMimeType::findByContent( data )->name() );
00786   } else {
00787     item->setMimeType( mimeType );
00788   }
00789 }
00790 
00791 void KOEditorAttachments::addAttachment( KCal::Attachment *attachment )
00792 {
00793   new AttachmentListItem( attachment, mAttachments );
00794 }
00795 
00796 void KOEditorAttachments::readIncidence( KCal::Incidence *i )
00797 {
00798   mAttachments->clear();
00799 
00800   KCal::Attachment::List attachments = i->attachments();
00801   KCal::Attachment::List::ConstIterator it;
00802   for( it = attachments.begin(); it != attachments.end(); ++it ) {
00803     addAttachment( (*it) );
00804   }
00805   if ( mAttachments->count() > 0 ) {
00806     QTimer::singleShot( 0, mAttachments, SLOT(arrangeItemsInGrid()) );
00807   }
00808 }
00809 
00810 void KOEditorAttachments::writeIncidence( KCal::Incidence *i )
00811 {
00812   i->clearAttachments();
00813 
00814   QIconViewItem *item;
00815   AttachmentListItem *attitem;
00816   for( item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00817     attitem = static_cast<AttachmentListItem*>(item);
00818     if ( attitem )
00819       i->addAttachment( new KCal::Attachment( *(attitem->attachment() ) ) );
00820   }
00821 }
00822 
00823 
00824 void KOEditorAttachments::slotCopy()
00825 {
00826     QApplication::clipboard()->setData( mAttachments->mimeData(), QClipboard::Clipboard );
00827 }
00828 
00829 void KOEditorAttachments::slotCut()
00830 {
00831     slotCopy();
00832     slotRemove();
00833 }
00834 
00835 void KOEditorAttachments::slotPaste()
00836 {
00837     handlePasteOrDrop( QApplication::clipboard()->data() );
00838 }
00839 
00840 void KOEditorAttachments::selectionChanged()
00841 {
00842   bool selected = false;
00843   for ( QIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00844     if ( item->isSelected() ) {
00845       selected = true;
00846       break;
00847     }
00848   }
00849   mRemoveBtn->setEnabled( selected );
00850 }
00851 
00852 void KOEditorAttachments::contextMenu(QIconViewItem * item, const QPoint & pos)
00853 {
00854   const bool enable = item != 0;
00855   mOpenAction->setEnabled( enable );
00856   mCopyAction->setEnabled( enable );
00857   mCutAction->setEnabled( enable );
00858   mDeleteAction->setEnabled( enable );
00859   mEditAction->setEnabled( enable );
00860   mContextMenu->exec( pos );
00861 }
00862 
00863 #include "koeditorattachments.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys