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"