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 TQt, and distribute the resulting executable,
00023     without including the source code for TQt in the source distribution.
00024 */
00025 
00026 #include "koeditorattachments.h"
00027 
00028 #include <libkcal/attachmenthandler.h>
00029 #include <libkcal/incidence.h>
00030 #include <libtdepim/kpimurlrequesterdlg.h>
00031 #include <libtdepim/tdefileio.h>
00032 #include <libtdepim/tdepimprotocols.h>
00033 #include <libtdepim/maillistdrag.h>
00034 #include <libtdepim/kvcarddrag.h>
00035 #include <libtdepim/tdepimprotocols.h>
00036 
00037 #include <tdelocale.h>
00038 #include <kdebug.h>
00039 #include <kmdcodec.h>
00040 #include <tdemessagebox.h>
00041 #include <krun.h>
00042 #include <kurldrag.h>
00043 #include <tdetempfile.h>
00044 #include <ktempdir.h>
00045 #include <tdeio/netaccess.h>
00046 #include <kmimetype.h>
00047 #include <kiconloader.h>
00048 #include <tdefiledialog.h>
00049 #include <kstdaction.h>
00050 #include <tdeactioncollection.h>
00051 #include <tdepopupmenu.h>
00052 #include <kprotocolinfo.h>
00053 #include <klineedit.h>
00054 #include <kseparator.h>
00055 #include <kurlrequester.h>
00056 #include <libkmime/kmime_message.h>
00057 
00058 #include <tqcheckbox.h>
00059 #include <tqfile.h>
00060 #include <tqlabel.h>
00061 #include <tqlayout.h>
00062 #include <tqlistview.h>
00063 #include <tqpushbutton.h>
00064 #include <tqdragobject.h>
00065 #include <tqtooltip.h>
00066 #include <tqwhatsthis.h>
00067 #include <tqapplication.h>
00068 #include <tqclipboard.h>
00069 
00070 #include <cassert>
00071 #include <cstdlib>
00072 
00073 class AttachmentListItem : public TDEIconViewItem
00074 {
00075   public:
00076     AttachmentListItem( KCal::Attachment*att, TQIconView *parent ) :
00077         TDEIconViewItem( parent )
00078     {
00079       if ( att ) {
00080         mAttachment = new KCal::Attachment( *att );
00081       } else {
00082         mAttachment = new KCal::Attachment( TQChar('\0') ); //use the non-uri constructor
00083                                                     //as we want inline by default
00084       }
00085       readAttachment();
00086       setDragEnabled( true );
00087     }
00088     ~AttachmentListItem() { delete mAttachment; }
00089     KCal::Attachment *attachment() const { return mAttachment; }
00090 
00091     const TQString uri() const
00092     {
00093       return mAttachment->uri();
00094     }
00095     void setUri( const TQString &uri )
00096     {
00097       mAttachment->setUri( uri );
00098       readAttachment();
00099     }
00100     void setData( const TQByteArray data )
00101     {
00102       mAttachment->setDecodedData( data );
00103       readAttachment();
00104     }
00105     const TQString mimeType() const
00106     {
00107       return mAttachment->mimeType();
00108     }
00109     void setMimeType( const TQString &mime )
00110     {
00111       mAttachment->setMimeType( mime );
00112       readAttachment();
00113     }
00114     const TQString label() const
00115     {
00116       return mAttachment->label();
00117     }
00118     void setLabel( const TQString &label )
00119     {
00120       mAttachment->setLabel( label );
00121       readAttachment();
00122     }
00123     bool isBinary() const
00124     {
00125       return mAttachment->isBinary();
00126     }
00127     TQPixmap icon() const
00128     {
00129       return icon( KMimeType::mimeType( mAttachment->mimeType() ),
00130                    mAttachment->uri() );
00131     }
00132     static TQPixmap icon( KMimeType::Ptr mimeType, const TQString &uri )
00133     {
00134       TQString iconStr = mimeType->icon( uri, false );
00135       return TDEGlobal::iconLoader()->loadIcon( iconStr, TDEIcon::Small );
00136     }
00137     void readAttachment()
00138     {
00139       if ( mAttachment->label().isEmpty() ) {
00140         if ( mAttachment->isUri() ) {
00141           setText( mAttachment->uri() );
00142         } else {
00143           setText( i18n( "[Binary data]" ) );
00144         }
00145       } else {
00146         setText( mAttachment->label() );
00147       }
00148       if ( mAttachment->mimeType().isEmpty() ||
00149            !( KMimeType::mimeType( mAttachment->mimeType() ) ) ) {
00150         KMimeType::Ptr mimeType;
00151         if ( mAttachment->isUri() ) {
00152           mimeType = KMimeType::findByURL( mAttachment->uri() );
00153         } else {
00154           mimeType = KMimeType::findByContent( mAttachment->decodedData() );
00155         }
00156         mAttachment->setMimeType( mimeType->name() );
00157       }
00158 
00159       setPixmap( icon() );
00160     }
00161 
00162   private:
00163     KCal::Attachment *mAttachment;
00164 };
00165 
00166 AttachmentEditDialog::AttachmentEditDialog( AttachmentListItem *item,
00167                                             TQWidget *parent )
00168   : KDialogBase ( Plain, i18n( "Add Attachment" ), Ok|Cancel, Ok, parent, 0, false, false ),
00169     mItem( item ), mURLRequester( 0 )
00170 {
00171   TQFrame *topFrame = plainPage();
00172   TQVBoxLayout *vbl = new TQVBoxLayout( topFrame, 0, spacingHint() );
00173 
00174   TQGridLayout *grid = new TQGridLayout();
00175   grid->setColStretch( 0, 0 );
00176   grid->setColStretch( 1, 0 );
00177   grid->setColStretch( 2, 1 );
00178   vbl->addLayout( grid );
00179 
00180   mIcon = new TQLabel( topFrame );
00181   mIcon->setPixmap( item->icon() );
00182   grid->addWidget( mIcon, 0, 0 );
00183 
00184   mLabelEdit = new KLineEdit( topFrame );
00185   mLabelEdit->setText( item->label().isEmpty() ? item->uri() : item->label() );
00186   mLabelEdit->setClickMessage( i18n( "Attachment name" ) );
00187   TQToolTip::add( mLabelEdit, i18n( "Give the attachment a name" ) );
00188   TQWhatsThis::add( mLabelEdit,
00189                    i18n( "Type any string you desire here for the name of the attachment" ) );
00190   grid->addMultiCellWidget( mLabelEdit, 0, 0, 1, 2 );
00191 
00192   KSeparator *sep = new KSeparator( Qt::Horizontal, topFrame );
00193   grid->addMultiCellWidget( sep, 1, 1, 0, 2 );
00194 
00195   TQLabel *label = new TQLabel( i18n( "Type:" ), topFrame );
00196   grid->addWidget( label, 2, 0 );
00197   TQString typecomment = item->mimeType().isEmpty() ?
00198                         i18n( "Unknown" ) :
00199                         KMimeType::mimeType( item->mimeType() )->comment();
00200   mTypeLabel = new TQLabel( typecomment, topFrame );
00201   grid->addWidget( mTypeLabel, 2, 1 );
00202   mMimeType = KMimeType::mimeType( item->mimeType() );
00203 
00204   mInline = new TQCheckBox( i18n( "Store attachment inline" ), topFrame );
00205   grid->addMultiCellWidget( mInline, 3, 3, 0, 2 );
00206   mInline->setChecked( item->isBinary() );
00207   TQToolTip::add( mInline, i18n( "Store the attachment file inside the calendar" ) );
00208   TQWhatsThis::add(
00209     mInline,
00210     i18n( "Checking this option will cause the attachment to be stored inside "
00211           "your calendar, which can take a lot of space depending on the size "
00212           "of the attachment. If this option is not checked, then only a link "
00213           "pointing to the attachment will be stored.  Do not use a link for "
00214           "attachments that change often or may be moved (or removed) from "
00215           "their current location." ) );
00216 
00217   if ( item->attachment()->isUri() || !item->attachment()->data() ) {
00218     label = new TQLabel( i18n( "Location:" ), topFrame );
00219     grid->addWidget( label, 4, 0 );
00220     mURLRequester = new KURLRequester( item->uri(), topFrame );
00221     TQToolTip::add( mURLRequester, i18n( "Provide a location for the attachment file" ) );
00222     TQWhatsThis::add(
00223       mURLRequester,
00224       i18n( "Enter the path to the attachment file or use the "
00225             "file browser by pressing the adjacent button" ) );
00226     grid->addMultiCellWidget( mURLRequester, 4, 4, 1, 2 );
00227     connect( mURLRequester, TQT_SIGNAL(urlSelected(const TQString &)),
00228              TQT_SLOT(urlSelected(const TQString &)) );
00229     connect( mURLRequester, TQT_SIGNAL( textChanged( const TQString& ) ),
00230              TQT_SLOT( urlChanged( const TQString& ) ) );
00231     urlChanged( item->uri() );
00232   } else {
00233     uint size = item->attachment()->size();
00234     grid->addWidget( new TQLabel( i18n( "Size:" ), topFrame ), 4, 0 );
00235     grid->addWidget( new TQLabel( TQString::fromLatin1( "%1 (%2)" ).
00236                                  arg( TDEIO::convertSize( size ) ).
00237                                  arg( TDEGlobal::locale()->formatNumber(
00238                                         size, 0 ) ), topFrame ), 4, 2 );
00239   }
00240   vbl->addStretch( 10 );
00241 }
00242 
00243 void AttachmentEditDialog::slotApply()
00244 {
00245   if ( !mLabelEdit->text().isEmpty() ) {
00246     mItem->setLabel( mLabelEdit->text() );
00247   } else {
00248     if ( mURLRequester ) {
00249       KURL url( mURLRequester->url() );
00250       if ( url.isLocalFile() ) {
00251         mItem->setLabel( url.fileName() );
00252       } else {
00253         mItem->setLabel( url.url() );
00254       }
00255     }
00256   }
00257   if ( mItem->label().isEmpty() ) {
00258     mItem->setLabel( i18n( "New attachment" ) );
00259   }
00260   mItem->setMimeType( mMimeType->name() );
00261   if ( mURLRequester ) {
00262     KURL url( mURLRequester->url() );
00263 
00264     TQString correctedUrl = mURLRequester->url();
00265     if ( !url.isValid() ) {
00266       // If the user used KURLRequester's KURLCompletion
00267       // (used the line edit instead of the file dialog)
00268       // the returned url is not absolute and is always relative
00269       // to the home directory (not pwd), so we must prepend home
00270 
00271       correctedUrl = TQDir::home().filePath( mURLRequester->url() );
00272       url = KURL( correctedUrl );
00273       if ( url.isValid() ) {
00274         urlSelected( correctedUrl );
00275         mItem->setMimeType( mMimeType->name() );
00276       }
00277     }
00278 
00279     if ( mInline->isChecked() ) {
00280       TQString tmpFile;
00281       if ( TDEIO::NetAccess::download( correctedUrl, tmpFile, this ) ) {
00282         TQFile f( tmpFile );
00283         if ( !f.open( IO_ReadOnly ) ) {
00284           return;
00285         }
00286         TQByteArray data = f.readAll();
00287         f.close();
00288         mItem->setData( data );
00289       }
00290       TDEIO::NetAccess::removeTempFile( tmpFile );
00291     } else {
00292       mItem->setUri( url.url() );
00293     }
00294   }
00295 }
00296 
00297 void AttachmentEditDialog::accept()
00298 {
00299   slotApply();
00300   KDialog::accept();
00301 }
00302 
00303 void AttachmentEditDialog::urlChanged( const TQString &url )
00304 {
00305   enableButton( Ok, !url.isEmpty() );
00306 }
00307 
00308 void AttachmentEditDialog::urlSelected( const TQString &url )
00309 {
00310   KURL kurl( url );
00311   mMimeType = KMimeType::findByURL( kurl );
00312   mTypeLabel->setText( mMimeType->comment() );
00313   mIcon->setPixmap( AttachmentListItem::icon( mMimeType, kurl.path() ) );
00314 }
00315 
00316 AttachmentIconView::AttachmentIconView( KOEditorAttachments* parent )
00317   : TDEIconView( parent ),
00318     mParent( parent )
00319 {
00320   setSelectionMode( TQIconView::Extended );
00321   setMode( TDEIconView::Select );
00322   setItemTextPos( TQIconView::Right );
00323   setArrangement( TQIconView::LeftToRight );
00324   setMaxItemWidth( TQMAX(maxItemWidth(), 250) );
00325   setMinimumHeight( TQMAX(fontMetrics().height(), 16) + 12 );
00326 
00327   connect( this, TQT_SIGNAL( dropped ( TQDropEvent *, const TQValueList<TQIconDragItem> & ) ),
00328            this, TQT_SLOT( handleDrop( TQDropEvent *, const TQValueList<TQIconDragItem> & ) ) );
00329 }
00330 
00331 KURL AttachmentIconView::tempFileForAttachment( KCal::Attachment *attachment )
00332 {
00333   if ( mTempFiles.contains( attachment ) ) {
00334     return mTempFiles[attachment];
00335   }
00336   TQStringList patterns = KMimeType::mimeType( attachment->mimeType() )->patterns();
00337 
00338   KTempFile *file;
00339   if ( !patterns.empty() ) {
00340     file = new KTempFile( TQString(),
00341                           TQString( patterns.first() ).remove( '*' ),0600 );
00342   } else {
00343     file = new KTempFile( TQString(), TQString(), 0600 );
00344   }
00345   file->setAutoDelete( true );
00346   file->file()->open( IO_WriteOnly );
00347   TQTextStream stream( file->file() );
00348   stream.writeRawBytes( attachment->decodedData().data(), attachment->size() );
00349   KURL url( file->name() );
00350   mTempFiles.insert( attachment, url );
00351   file->close();
00352   return mTempFiles[attachment];
00353 }
00354 
00355 TQDragObject *AttachmentIconView::mimeData()
00356 {
00357   // create a list of the URL:s that we want to drag
00358   KURL::List urls;
00359   TQStringList labels;
00360   for ( TQIconViewItem *it = firstItem(); it; it = it->nextItem() ) {
00361     if ( it->isSelected() ) {
00362       AttachmentListItem *item = static_cast<AttachmentListItem *>( it );
00363       if ( item->isBinary() ) {
00364         urls.append( tempFileForAttachment( item->attachment() ) );
00365       } else {
00366         urls.append( item->uri() );
00367       }
00368       labels.append( KURL::encode_string( item->label() ) );
00369     }
00370   }
00371   if ( selectionMode() == TQIconView::NoSelection ) {
00372     AttachmentListItem *item = static_cast<AttachmentListItem *>( currentItem() );
00373     if ( item ) {
00374       urls.append( item->uri() );
00375       labels.append( KURL::encode_string( item->label() ) );
00376     }
00377   }
00378 
00379   TQMap<TQString, TQString> metadata;
00380   metadata["labels"] = labels.join( ":" );
00381 
00382   KURLDrag *drag = new KURLDrag( urls, metadata );
00383   return drag;
00384 }
00385 
00386 AttachmentIconView::~AttachmentIconView()
00387 {
00388   for ( std::set<KTempDir*>::iterator it = mTempDirs.begin() ; it != mTempDirs.end() ; ++it ) {
00389     delete *it;
00390   }
00391 }
00392 
00393 TQDragObject * AttachmentIconView::dragObject()
00394 {
00395   KURL::List urls;
00396   for ( TQIconViewItem *it = firstItem( ); it; it = it->nextItem( ) ) {
00397     if ( !it->isSelected() ) continue;
00398     AttachmentListItem * item = dynamic_cast<AttachmentListItem*>( it );
00399     if ( !item ) return 0;
00400     KCal::Attachment * att = item->attachment();
00401     assert( att );
00402     KURL url;
00403     if ( att->isUri() ) {
00404       url.setPath( att->uri() );
00405     } else {
00406       KTempDir *tempDir = new KTempDir(); // will be deleted on editor close
00407       tempDir->setAutoDelete( true );
00408       mTempDirs.insert( tempDir );
00409       TQByteArray encoded;
00410       encoded.duplicate( att->data(), strlen( att->data() ) );
00411       TQByteArray decoded;
00412       KCodecs::base64Decode( encoded, decoded );
00413       const TQString fileName = tempDir->name( ) + '/' + att->label();
00414       KPIM::kByteArrayToFile( decoded, fileName, false, false, false );
00415       url.setPath( fileName );
00416     }
00417     urls << url;
00418   }
00419   KURLDrag *drag  = new KURLDrag( urls, this );
00420   return drag;
00421 }
00422 
00423 void AttachmentIconView::handleDrop( TQDropEvent *event, const TQValueList<TQIconDragItem> & list )
00424 {
00425   Q_UNUSED( list );
00426   mParent->handlePasteOrDrop( event );
00427 }
00428 
00429 
00430 void AttachmentIconView::dragMoveEvent( TQDragMoveEvent *event )
00431 {
00432   mParent->dragMoveEvent( event );
00433 }
00434 
00435 void AttachmentIconView::contentsDragMoveEvent( TQDragMoveEvent *event )
00436 {
00437   mParent->dragMoveEvent( event );
00438 }
00439 
00440 void AttachmentIconView::contentsDragEnterEvent( TQDragEnterEvent *event )
00441 {
00442   mParent->dragMoveEvent( event );
00443 }
00444 
00445 void AttachmentIconView::dragEnterEvent( TQDragEnterEvent *event )
00446 {
00447   mParent->dragEnterEvent( event );
00448 }
00449 
00450 KOEditorAttachments::KOEditorAttachments( int spacing, TQWidget *parent,
00451                                           const char *name )
00452   : TQWidget( parent, name )
00453 {
00454   TQBoxLayout *topLayout = new TQHBoxLayout( this );
00455   topLayout->setSpacing( spacing );
00456 
00457   TQLabel *label = new TQLabel( i18n("Attachments:"), this );
00458   topLayout->addWidget( label );
00459 
00460   mAttachments = new AttachmentIconView( this );
00461   TQWhatsThis::add( mAttachments,
00462                    i18n("Displays a list of current items (files, mail, etc.) "
00463                         "that have been associated with this event or to-do. ") );
00464   topLayout->addWidget( mAttachments );
00465   connect( mAttachments, TQT_SIGNAL( doubleClicked( TQIconViewItem * ) ),
00466            TQT_SLOT( showAttachment( TQIconViewItem * ) ) );
00467   connect( mAttachments, TQT_SIGNAL(selectionChanged()),
00468            TQT_SLOT(selectionChanged()) );
00469   connect( mAttachments, TQT_SIGNAL(contextMenuRequested(TQIconViewItem*,const TQPoint&)),
00470            TQT_SLOT(contextMenu(TQIconViewItem*,const TQPoint&)) );
00471 
00472     TQPushButton *addButton = new TQPushButton( this );
00473   addButton->setIconSet( SmallIconSet( "add" ) );
00474   TQToolTip::add( addButton, i18n( "Add an attachment" ) );
00475   TQWhatsThis::add( addButton,
00476                    i18n( "Shows a dialog used to select an attachment "
00477                          "to add to this event or to-do as link or as "
00478                          "inline data." ) );
00479   topLayout->addWidget( addButton );
00480   connect( addButton, TQT_SIGNAL(clicked()), TQT_SLOT(slotAdd()) );
00481 
00482   mRemoveBtn = new TQPushButton( this );
00483   mRemoveBtn->setIconSet( SmallIconSet( "remove" ) );
00484   TQToolTip::add( mRemoveBtn, i18n("&Remove") );
00485   TQWhatsThis::add( mRemoveBtn,
00486                    i18n("Removes the attachment selected in the list above "
00487                         "from this event or to-do.") );
00488   topLayout->addWidget( mRemoveBtn );
00489   connect( mRemoveBtn, TQT_SIGNAL(clicked()), TQT_SLOT(slotRemove()) );
00490 
00491   mContextMenu = new TDEPopupMenu( this );
00492 
00493   TDEActionCollection* ac = new TDEActionCollection( TQT_TQWIDGET(this), TQT_TQOBJECT(this) );
00494 
00495   mOpenAction = new TDEAction( i18n("Open"), 0, TQT_TQOBJECT(this), TQT_SLOT(slotShow()), ac );
00496   mOpenAction->plug( mContextMenu );
00497 
00498   mSaveAsAction = new TDEAction( i18n( "Save As..." ), 0, TQT_TQOBJECT(this), TQT_SLOT(slotSaveAs()), ac );
00499   mSaveAsAction->plug( mContextMenu );
00500   mContextMenu->insertSeparator();
00501 
00502   mCopyAction = KStdAction::copy(TQT_TQOBJECT(this), TQT_SLOT(slotCopy()), ac );
00503   mCopyAction->plug( mContextMenu );
00504   mCutAction = KStdAction::cut(TQT_TQOBJECT(this), TQT_SLOT(slotCut()), ac );
00505   mCutAction->plug( mContextMenu );
00506   TDEAction *action = KStdAction::paste(TQT_TQOBJECT(this), TQT_SLOT(slotPaste()), ac );
00507   action->plug( mContextMenu );
00508   mContextMenu->insertSeparator();
00509 
00510   mDeleteAction = new TDEAction( i18n( "&Remove" ), 0, TQT_TQOBJECT(this), TQT_SLOT(slotRemove()),  ac );
00511   mDeleteAction->plug( mContextMenu );
00512   mDeleteAction->setShortcut( Key_Delete );
00513   mContextMenu->insertSeparator();
00514 
00515   mEditAction = new TDEAction( i18n( "&Properties..." ), 0, TQT_TQOBJECT(this), TQT_SLOT(slotEdit()), ac );
00516   mEditAction->plug( mContextMenu );
00517 
00518   selectionChanged();
00519   setAcceptDrops( true );
00520 }
00521 
00522 KOEditorAttachments::~KOEditorAttachments()
00523 {
00524 }
00525 
00526 bool KOEditorAttachments::hasAttachments()
00527 {
00528   return mAttachments->count() != 0;
00529 }
00530 
00531 void KOEditorAttachments::dragMoveEvent( TQDragMoveEvent *event )
00532 {
00533   event->accept( KURLDrag::canDecode( event ) ||
00534                  TQTextDrag::canDecode( event ) ||
00535                  KPIM::MailListDrag::canDecode( event ) ||
00536                  KVCardDrag::canDecode( event ) );
00537 }
00538 
00539 void KOEditorAttachments::dragEnterEvent( TQDragEnterEvent* event )
00540 {
00541   dragMoveEvent( event );
00542 }
00543 
00544 void KOEditorAttachments::handlePasteOrDrop( TQMimeSource* source )
00545 {
00546   KURL::List urls;
00547   bool probablyWeHaveUris = false;
00548   bool weCanCopy = true;
00549   TQStringList labels;
00550 
00551   if ( KVCardDrag::canDecode( source ) ) {
00552     TDEABC::Addressee::List addressees;
00553     KVCardDrag::decode( source, addressees );
00554     for ( TDEABC::Addressee::List::ConstIterator it = addressees.constBegin();
00555           it != addressees.constEnd(); ++it ) {
00556       urls.append( TDEPIMPROTOCOL_CONTACT + ( *it ).uid() );
00557       // there is some weirdness about realName(), hence fromUtf8
00558       labels.append( TQString::fromUtf8( ( *it ).realName().latin1() ) );
00559     }
00560     probablyWeHaveUris = true;
00561   } else if ( KURLDrag::canDecode( source ) ) {
00562     TQMap<TQString,TQString> metadata;
00563     if ( KURLDrag::decode( source, urls, metadata ) ) {
00564       probablyWeHaveUris = true;
00565       labels = TQStringList::split( ':', metadata["labels"], FALSE );
00566       for ( TQStringList::Iterator it = labels.begin(); it != labels.end(); ++it ) {
00567         *it = KURL::decode_string( (*it).latin1() );
00568       }
00569 
00570     }
00571   } else if ( TQTextDrag::canDecode( source ) ) {
00572     TQString text;
00573     TQTextDrag::decode( source, text );
00574     TQStringList lst = TQStringList::split( '\n', text, FALSE );
00575     for ( TQStringList::ConstIterator it = lst.constBegin(); it != lst.constEnd(); ++it ) {
00576       urls.append( *it );
00577       labels.append( TQString() );
00578     }
00579     probablyWeHaveUris = true;
00580   }
00581 
00582   TDEPopupMenu menu;
00583   int items=0;
00584   if ( probablyWeHaveUris ) {
00585     menu.insertItem( i18n( "&Link here" ), DRAG_LINK, items++ );
00586     // we need to check if we can reasonably expect to copy the objects
00587     for ( KURL::List::ConstIterator it = urls.constBegin(); it != urls.constEnd(); ++it ) {
00588       if ( !( weCanCopy = KProtocolInfo::supportsReading( *it ) ) ) {
00589         break; // either we can copy them all, or no copying at all
00590       }
00591     }
00592     if ( weCanCopy ) {
00593       menu.insertItem( SmallIcon( "edit-copy" ), i18n( "&Copy Here" ), DRAG_COPY, items++ );
00594     }
00595   } else {
00596       menu.insertItem( SmallIcon( "edit-copy" ), i18n( "&Copy Here" ), DRAG_COPY, items++ );
00597   }
00598 
00599   menu.insertSeparator();
00600   items++;
00601   menu.insertItem( SmallIcon( "cancel" ), i18n( "C&ancel" ), DRAG_CANCEL, items );
00602   int action = menu.exec( TQCursor::pos(), 0 );
00603 
00604   if ( action == DRAG_LINK ) {
00605     TQStringList::ConstIterator jt = labels.constBegin();
00606     for ( KURL::List::ConstIterator it = urls.constBegin();
00607           it != urls.constEnd(); ++it ) {
00608       TQString label = (*jt++);
00609       if ( mAttachments->findItem( label ) ) {
00610         label += '~' + randomString( 3 );
00611       }
00612       addUriAttachment( (*it).url(), TQString(), label, true );
00613     }
00614   } else if ( action != DRAG_CANCEL ) {
00615     if ( probablyWeHaveUris ) {
00616       for ( KURL::List::ConstIterator it = urls.constBegin();
00617             it != urls.constEnd(); ++it ) {
00618         TQString label = (*it).fileName();
00619         if ( label.isEmpty() ) {
00620           label = (*it).prettyURL();
00621         }
00622         if ( mAttachments->findItem( label ) ) {
00623           label += '~' + randomString( 3 );
00624         }
00625         addUriAttachment( (*it).url(), TQString(), label, true );
00626       }
00627     } else { // we take anything
00628       addDataAttachment( source->encodedData( source->format() ),
00629                          source->format(),
00630                          KMimeType::mimeType( source->format() )->name() );
00631     }
00632   }
00633 }
00634 
00635 void KOEditorAttachments::dropEvent( TQDropEvent* event )
00636 {
00637     handlePasteOrDrop( event );
00638 }
00639 
00640 void KOEditorAttachments::showAttachment( TQIconViewItem *item )
00641 {
00642   AttachmentListItem *attitem = static_cast<AttachmentListItem*>(item);
00643   if ( !attitem || !attitem->attachment() ) return;
00644 
00645   KCal::Attachment *att = attitem->attachment();
00646   KCal::AttachmentHandler::view( this, att );
00647 }
00648 
00649 void KOEditorAttachments::saveAttachment( TQIconViewItem *item )
00650 {
00651   AttachmentListItem *attitem = static_cast<AttachmentListItem*>(item);
00652   if ( !attitem || !attitem->attachment() ) return;
00653 
00654   KCal::Attachment *att = attitem->attachment();
00655   KCal::AttachmentHandler::saveAs( this, att );
00656 }
00657 
00658 void KOEditorAttachments::slotAdd()
00659 {
00660   AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
00661 
00662   AttachmentEditDialog *dlg = new AttachmentEditDialog( item, mAttachments )
00663 ;
00664   if ( dlg->exec() == KDialog::Rejected ) {
00665     delete item;
00666   }
00667   delete dlg;
00668 }
00669 
00670 void KOEditorAttachments::slotAddData()
00671 {
00672   KURL uri = KFileDialog::getOpenFileName( TQString(), TQString(), this, i18n("Add Attachment") );
00673   if ( !uri.isEmpty() ) {
00674     TQString label = uri.fileName();
00675     if ( label.isEmpty() ) {
00676       label = uri.prettyURL();
00677     }
00678     addUriAttachment( uri.url(), TQString(), label, true );
00679   }
00680 }
00681 
00682 void KOEditorAttachments::slotEdit()
00683 {
00684   for ( TQIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00685     if ( item->isSelected() ) {
00686       AttachmentListItem *attitem = static_cast<AttachmentListItem*>( item );
00687       if ( !attitem || !attitem->attachment() ) {
00688         return;
00689       }
00690 
00691       AttachmentEditDialog *dialog = new AttachmentEditDialog( attitem, mAttachments );
00692       dialog->mInline->setEnabled( false );
00693       dialog->setModal( false );
00694       connect( dialog, TQT_SIGNAL(hidden()), dialog, TQT_SLOT(delayedDestruct()) );
00695       dialog->show();
00696     }
00697   }
00698 }
00699 
00700 void KOEditorAttachments::slotRemove()
00701 {
00702   TQValueList<TQIconViewItem*> selected;
00703   TQStringList labels;
00704   for ( TQIconViewItem *it = mAttachments->firstItem( ); it; it = it->nextItem( ) ) {
00705     if ( !it->isSelected() ) continue;
00706     selected << it;
00707 
00708     AttachmentListItem *attitem = static_cast<AttachmentListItem*>(it);
00709     KCal::Attachment *att = attitem->attachment();
00710     labels << att->label();
00711   }
00712 
00713   if ( selected.isEmpty() ) {
00714     return;
00715   }
00716 
00717   TQString labelsStr = labels.join( "<br>" );
00718 
00719   if ( KMessageBox::questionYesNo(
00720          this,
00721          i18n( "<qt>Do you really want to remove these attachments?<p>%1</qt>" ).arg( labelsStr ),
00722          i18n( "Remove Attachment?" ),
00723          KStdGuiItem::yes(), KStdGuiItem::no(),
00724          "calendarRemoveAttachments" ) != KMessageBox::Yes ) {
00725     return;
00726   }
00727 
00728   for ( TQValueList<TQIconViewItem*>::iterator it( selected.begin() ), end( selected.end() );
00729         it != end ; ++it ) {
00730     if ( (*it)->nextItem() ) {
00731       (*it)->nextItem()->setSelected( true );
00732     } else if ( (*it)->prevItem() ) {
00733       (*it)->prevItem()->setSelected( true );
00734     }
00735     delete *it;
00736   }
00737   mAttachments->slotUpdate();
00738 }
00739 
00740 void KOEditorAttachments::slotShow()
00741 {
00742   for ( TQIconViewItem *it = mAttachments->firstItem(); it; it = it->nextItem() ) {
00743     if ( !it->isSelected() )
00744       continue;
00745     showAttachment( it );
00746   }
00747 }
00748 
00749 void KOEditorAttachments::slotSaveAs()
00750 {
00751   for ( TQIconViewItem *it = mAttachments->firstItem(); it; it = it->nextItem() ) {
00752     if ( !it->isSelected() )
00753       continue;
00754     saveAttachment( it );
00755   }
00756 }
00757 
00758 void KOEditorAttachments::setDefaults()
00759 {
00760   mAttachments->clear();
00761 }
00762 
00763 TQString KOEditorAttachments::randomString(int length) const
00764 {
00765    if (length <=0 ) return TQString();
00766 
00767    TQString str; str.setLength( length );
00768    int i = 0;
00769    while (length--)
00770    {
00771       int r=random() % 62;
00772       r+=48;
00773       if (r>57) r+=7;
00774       if (r>90) r+=6;
00775       str[i++] =  char(r);
00776       // so what if I work backwards?
00777    }
00778    return str;
00779 }
00780 
00781 void KOEditorAttachments::addUriAttachment( const TQString &uri,
00782                                             const TQString &mimeType,
00783                                             const TQString &label,
00784                                             bool inLine )
00785 {
00786   if ( !inLine ) {
00787     AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
00788     item->setUri( uri );
00789     item->setLabel( label );
00790     if ( mimeType.isEmpty() ) {
00791       if ( uri.startsWith( TDEPIMPROTOCOL_CONTACT ) ) {
00792         item->setMimeType( "text/directory" );
00793       } else if ( uri.startsWith( TDEPIMPROTOCOL_EMAIL ) ) {
00794         item->setMimeType( "message/rfc822" );
00795       } else if ( uri.startsWith( TDEPIMPROTOCOL_INCIDENCE ) ) {
00796         item->setMimeType( "text/calendar" );
00797       } else if ( uri.startsWith( TDEPIMPROTOCOL_NEWSARTICLE ) ) {
00798         item->setMimeType( "message/news" );
00799       } else {
00800         item->setMimeType( KMimeType::findByURL( uri )->name() );
00801       }
00802     }
00803   } else {
00804     TQString tmpFile;
00805     if ( TDEIO::NetAccess::download( uri, tmpFile, this ) ) {
00806       TQFile f( tmpFile );
00807       if ( !f.open( IO_ReadOnly ) ) {
00808         return;
00809       }
00810       const TQByteArray data = f.readAll();
00811       f.close();
00812       addDataAttachment( data, mimeType, label );
00813     }
00814     TDEIO::NetAccess::removeTempFile( tmpFile );
00815   }
00816 }
00817 
00818 void KOEditorAttachments::addDataAttachment( const TQByteArray &data,
00819                                              const TQString &mimeType,
00820                                              const TQString &label )
00821 {
00822   AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
00823 
00824   TQString nlabel = label;
00825   if ( mimeType == "message/rfc822" ) {
00826     // mail message. try to set the label from the mail Subject:
00827     KMime::Message msg;
00828     msg.setContent( data.data() );
00829     msg.parse();
00830     nlabel = msg.subject()->asUnicodeString();
00831   }
00832 
00833   item->setData( data );
00834   item->setLabel( nlabel );
00835   if ( mimeType.isEmpty() ) {
00836     item->setMimeType( KMimeType::findByContent( data )->name() );
00837   } else {
00838     item->setMimeType( mimeType );
00839   }
00840 }
00841 
00842 void KOEditorAttachments::addAttachment( KCal::Attachment *attachment )
00843 {
00844   new AttachmentListItem( attachment, mAttachments );
00845 }
00846 
00847 void KOEditorAttachments::readIncidence( KCal::Incidence *i )
00848 {
00849   mAttachments->clear();
00850 
00851   KCal::Attachment::List attachments = i->attachments();
00852   KCal::Attachment::List::ConstIterator it;
00853   for( it = attachments.begin(); it != attachments.end(); ++it ) {
00854     addAttachment( (*it) );
00855   }
00856   if ( mAttachments->count() > 0 ) {
00857     TQTimer::singleShot( 0, mAttachments, TQT_SLOT(arrangeItemsInGrid()) );
00858   }
00859 }
00860 
00861 void KOEditorAttachments::writeIncidence( KCal::Incidence *i )
00862 {
00863   i->clearAttachments();
00864 
00865   TQIconViewItem *item;
00866   AttachmentListItem *attitem;
00867   for( item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00868     attitem = static_cast<AttachmentListItem*>(item);
00869     if ( attitem )
00870       i->addAttachment( new KCal::Attachment( *(attitem->attachment() ) ) );
00871   }
00872 }
00873 
00874 
00875 void KOEditorAttachments::slotCopy()
00876 {
00877     TQApplication::clipboard()->setData( mAttachments->mimeData(), TQClipboard::Clipboard );
00878 }
00879 
00880 void KOEditorAttachments::slotCut()
00881 {
00882     slotCopy();
00883     slotRemove();
00884 }
00885 
00886 void KOEditorAttachments::slotPaste()
00887 {
00888     handlePasteOrDrop( TQApplication::clipboard()->data() );
00889 }
00890 
00891 void KOEditorAttachments::selectionChanged()
00892 {
00893   bool selected = false;
00894   for ( TQIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00895     if ( item->isSelected() ) {
00896       selected = true;
00897       break;
00898     }
00899   }
00900   mRemoveBtn->setEnabled( selected );
00901 }
00902 
00903 void KOEditorAttachments::contextMenu(TQIconViewItem * item, const TQPoint & pos)
00904 {
00905   const bool enable = item != 0;
00906 
00907   int numSelected = 0;
00908   for ( TQIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) {
00909     if ( item->isSelected() ) {
00910       numSelected++;
00911     }
00912   }
00913 
00914   mOpenAction->setEnabled( enable );
00915   //TODO: support saving multiple attachments into a directory
00916   mSaveAsAction->setEnabled( enable && numSelected == 1 );
00917   mCopyAction->setEnabled( enable && numSelected == 1 );
00918   mCutAction->setEnabled( enable && numSelected == 1 );
00919   mDeleteAction->setEnabled( enable );
00920   mEditAction->setEnabled( enable );
00921   mContextMenu->exec( pos );
00922 }
00923 
00924 #include "koeditorattachments.moc"