diff options
Diffstat (limited to 'korganizer/koeditorattachments.cpp')
-rw-r--r-- | korganizer/koeditorattachments.cpp | 831 |
1 files changed, 627 insertions, 204 deletions
diff --git a/korganizer/koeditorattachments.cpp b/korganizer/koeditorattachments.cpp index adcd871e6..99d775e69 100644 --- a/korganizer/koeditorattachments.cpp +++ b/korganizer/koeditorattachments.cpp @@ -25,15 +25,19 @@ #include "koeditorattachments.h" +#include <libkcal/attachmenthandler.h> #include <libkcal/incidence.h> #include <libkdepim/kpimurlrequesterdlg.h> #include <libkdepim/kfileio.h> +#include <libkdepim/kdepimprotocols.h> +#include <libkdepim/maillistdrag.h> +#include <libkdepim/kvcarddrag.h> +#include <libkdepim/kdepimprotocols.h> #include <klocale.h> #include <kdebug.h> #include <kmdcodec.h> #include <kmessagebox.h> -#include <kiconview.h> #include <krun.h> #include <kurldrag.h> #include <ktempfile.h> @@ -45,7 +49,13 @@ #include <kstdaction.h> #include <kactioncollection.h> #include <kpopupmenu.h> +#include <kprotocolinfo.h> +#include <klineedit.h> +#include <kseparator.h> +#include <kurlrequester.h> +#include <libkmime/kmime_message.h> +#include <tqcheckbox.h> #include <tqfile.h> #include <tqlabel.h> #include <tqlayout.h> @@ -58,7 +68,7 @@ #include <tqclipboard.h> #include <cassert> -#include <set> +#include <cstdlib> class AttachmentListItem : public KIconViewItem { @@ -69,7 +79,8 @@ class AttachmentListItem : public KIconViewItem if ( att ) { mAttachment = new KCal::Attachment( *att ); } else { - mAttachment = new KCal::Attachment( TQString::null ); + mAttachment = new KCal::Attachment( '\0' ); //use the non-uri constructor + //as we want inline by default } readAttachment(); setDragEnabled( true ); @@ -77,112 +88,364 @@ class AttachmentListItem : public KIconViewItem ~AttachmentListItem() { delete mAttachment; } KCal::Attachment *attachment() const { return mAttachment; } + const TQString uri() const + { + return mAttachment->uri(); + } void setUri( const TQString &uri ) { mAttachment->setUri( uri ); readAttachment(); } - void setData( const char *base64 ) + void setData( const TQByteArray data ) { - mAttachment->setData( base64 ); + mAttachment->setDecodedData( data ); readAttachment(); } + const TQString mimeType() const + { + return mAttachment->mimeType(); + } void setMimeType( const TQString &mime ) { mAttachment->setMimeType( mime ); readAttachment(); } + const TQString label() const + { + return mAttachment->label(); + } void setLabel( const TQString &label ) { mAttachment->setLabel( label ); readAttachment(); } - + bool isBinary() const + { + return mAttachment->isBinary(); + } + TQPixmap icon() const + { + return icon( KMimeType::mimeType( mAttachment->mimeType() ), + mAttachment->uri() ); + } + static TQPixmap icon( KMimeType::Ptr mimeType, const TQString &uri ) + { + TQString iconStr = mimeType->icon( uri, false ); + return KGlobal::iconLoader()->loadIcon( iconStr, KIcon::Small ); + } void readAttachment() { - if ( mAttachment->isUri() ) - setText( mAttachment->uri() ); - else { - if ( mAttachment->label().isEmpty() ) - setText( i18n("[Binary data]") ); - else - setText( mAttachment->label() ); + if ( mAttachment->label().isEmpty() ) { + if ( mAttachment->isUri() ) { + setText( mAttachment->uri() ); + } else { + setText( i18n( "[Binary data]" ) ); + } + } else { + setText( mAttachment->label() ); } - KMimeType::Ptr mt = KMimeType::mimeType( mAttachment->mimeType() ); - if ( mt ) { - const TQString iconName( mt->icon( TQString(), false ) ); - TQPixmap pix = KGlobal::iconLoader( )->loadIcon( iconName, KIcon::Small ); - if ( pix.isNull() ) - pix = KGlobal::iconLoader( )->loadIcon( "unknown", KIcon::Small ); - if ( !pix.isNull() ) - setPixmap( pix ); + if ( mAttachment->mimeType().isEmpty() || + !( KMimeType::mimeType( mAttachment->mimeType() ) ) ) { + KMimeType::Ptr mimeType; + if ( mAttachment->isUri() ) { + mimeType = KMimeType::findByURL( mAttachment->uri() ); + } else { + mimeType = KMimeType::findByContent( mAttachment->decodedData() ); + } + mAttachment->setMimeType( mimeType->name() ); } + + setPixmap( icon() ); } private: KCal::Attachment *mAttachment; }; -class AttachmentIconView : public KIconView -{ - friend class KOEditorAttachments; - public: - AttachmentIconView( KOEditorAttachments* parent=0 ) - :KIconView( parent ), - mParent( parent ) - { - setAcceptDrops( true ); - setSelectionMode( TQIconView::Extended ); - setMode( KIconView::Select ); - setItemTextPos( TQIconView::Right ); - setArrangement( TQIconView::LeftToRight ); - setMaxItemWidth( QMAX(maxItemWidth(), 250) ); - setMinimumHeight( QMAX(fontMetrics().height(), 16) + 12 ); - } - ~AttachmentIconView() - { - for ( std::set<KTempDir*>::iterator it = mTempDirs.begin() ; it != mTempDirs.end() ; ++it ) { - delete *it; - } - } - protected: - TQDragObject * dragObject() - { - KURL::List urls; - for ( TQIconViewItem *it = firstItem( ); it; it = it->nextItem( ) ) { - if ( !it->isSelected() ) continue; - AttachmentListItem * item = dynamic_cast<AttachmentListItem*>( it ); - if ( !item ) return 0; - KCal::Attachment * att = item->attachment(); - assert( att ); - KURL url; - if ( att->isUri() ) { - url.setPath( att->uri() ); - } else { - KTempDir * tempDir = new KTempDir(); // will be deleted on editor close - tempDir->setAutoDelete( true ); - mTempDirs.insert( tempDir ); - TQByteArray encoded; - encoded.duplicate( att->data(), strlen(att->data()) ); - TQByteArray decoded; - KCodecs::base64Decode( encoded, decoded ); - const TQString fileName = tempDir->name( ) + "/" + att->label(); - KPIM::kByteArrayToFile( decoded, fileName, false, false, false ); - url.setPath( fileName ); - } - urls << url; - } - KURLDrag *drag = new KURLDrag( urls, this ); - return drag; - } - void contentsDropEvent( TQDropEvent* event ) - { - mParent->handlePasteOrDrop( event ); +AttachmentEditDialog::AttachmentEditDialog( AttachmentListItem *item, + TQWidget *parent ) + : KDialogBase ( Plain, i18n( "Add Attachment" ), Ok|Cancel, Ok, parent, 0, false, false ), + mItem( item ), mURLRequester( 0 ) +{ + TQFrame *topFrame = plainPage(); + TQVBoxLayout *vbl = new TQVBoxLayout( topFrame, 0, spacingHint() ); + + TQGridLayout *grid = new TQGridLayout(); + grid->setColStretch( 0, 0 ); + grid->setColStretch( 1, 0 ); + grid->setColStretch( 2, 1 ); + vbl->addLayout( grid ); + + mIcon = new TQLabel( topFrame ); + mIcon->setPixmap( item->icon() ); + grid->addWidget( mIcon, 0, 0 ); + + mLabelEdit = new KLineEdit( topFrame ); + mLabelEdit->setText( item->label().isEmpty() ? item->uri() : item->label() ); + mLabelEdit->setClickMessage( i18n( "Attachment name" ) ); + TQToolTip::add( mLabelEdit, i18n( "Give the attachment a name" ) ); + TQWhatsThis::add( mLabelEdit, + i18n( "Type any string you desire here for the name of the attachment" ) ); + grid->addMultiCellWidget( mLabelEdit, 0, 0, 1, 2 ); + + KSeparator *sep = new KSeparator( TQt::Horizontal, topFrame ); + grid->addMultiCellWidget( sep, 1, 1, 0, 2 ); + + TQLabel *label = new TQLabel( i18n( "Type:" ), topFrame ); + grid->addWidget( label, 2, 0 ); + TQString typecomment = item->mimeType().isEmpty() ? + i18n( "Unknown" ) : + KMimeType::mimeType( item->mimeType() )->comment(); + mTypeLabel = new TQLabel( typecomment, topFrame ); + grid->addWidget( mTypeLabel, 2, 1 ); + mMimeType = KMimeType::mimeType( item->mimeType() ); + + mInline = new TQCheckBox( i18n( "Store attachment inline" ), topFrame ); + grid->addMultiCellWidget( mInline, 3, 3, 0, 2 ); + mInline->setChecked( item->isBinary() ); + TQToolTip::add( mInline, i18n( "Store the attachment file inside the calendar" ) ); + TQWhatsThis::add( + mInline, + i18n( "Checking this option will cause the attachment to be stored inside " + "your calendar, which can take a lot of space depending on the size " + "of the attachment. If this option is not checked, then only a link " + "pointing to the attachment will be stored. Do not use a link for " + "attachments that change often or may be moved (or removed) from " + "their current location." ) ); + + if ( item->attachment()->isUri() || !item->attachment()->data() ) { + label = new TQLabel( i18n( "Location:" ), topFrame ); + grid->addWidget( label, 4, 0 ); + mURLRequester = new KURLRequester( item->uri(), topFrame ); + TQToolTip::add( mURLRequester, i18n( "Provide a location for the attachment file" ) ); + TQWhatsThis::add( + mURLRequester, + i18n( "Enter the path to the attachment file or use the " + "file browser by pressing the adjacent button" ) ); + grid->addMultiCellWidget( mURLRequester, 4, 4, 1, 2 ); + connect( mURLRequester, TQT_SIGNAL(urlSelected(const TQString &)), + TQT_SLOT(urlSelected(const TQString &)) ); + connect( mURLRequester, TQT_SIGNAL( textChanged( const TQString& ) ), + TQT_SLOT( urlChanged( const TQString& ) ) ); + urlChanged( item->uri() ); + } else { + uint size = item->attachment()->size(); + grid->addWidget( new TQLabel( i18n( "Size:" ), topFrame ), 4, 0 ); + grid->addWidget( new TQLabel( TQString::fromLatin1( "%1 (%2)" ). + arg( KIO::convertSize( size ) ). + arg( KGlobal::locale()->formatNumber( + size, 0 ) ), topFrame ), 4, 2 ); + } + vbl->addStretch( 10 ); +} + +void AttachmentEditDialog::slotApply() +{ + if ( !mLabelEdit->text().isEmpty() ) { + mItem->setLabel( mLabelEdit->text() ); + } else { + if ( mURLRequester ) { + KURL url( mURLRequester->url() ); + if ( url.isLocalFile() ) { + mItem->setLabel( url.fileName() ); + } else { + mItem->setLabel( url.url() ); + } + } + } + if ( mItem->label().isEmpty() ) { + mItem->setLabel( i18n( "New attachment" ) ); + } + mItem->setMimeType( mMimeType->name() ); + if ( mURLRequester ) { + KURL url( mURLRequester->url() ); + + TQString correctedUrl = mURLRequester->url(); + if ( !url.isValid() ) { + // If the user used KURLRequester's KURLCompletion + // (used the line edit instead of the file dialog) + // the returned url is not absolute and is always relative + // to the home directory (not pwd), so we must prepend home + + correctedUrl = TQDir::home().filePath( mURLRequester->url() ); + url = KURL( correctedUrl ); + if ( url.isValid() ) { + urlSelected( correctedUrl ); + mItem->setMimeType( mMimeType->name() ); + } + } + + if ( mInline->isChecked() ) { + TQString tmpFile; + if ( KIO::NetAccess::download( correctedUrl, tmpFile, this ) ) { + TQFile f( tmpFile ); + if ( !f.open( IO_ReadOnly ) ) { + return; } - private: - std::set<KTempDir*> mTempDirs; - KOEditorAttachments* mParent; -}; + TQByteArray data = f.readAll(); + f.close(); + mItem->setData( data ); + } + KIO::NetAccess::removeTempFile( tmpFile ); + } else { + mItem->setUri( url.url() ); + } + } +} + +void AttachmentEditDialog::accept() +{ + slotApply(); + KDialog::accept(); +} + +void AttachmentEditDialog::urlChanged( const TQString &url ) +{ + enableButton( Ok, !url.isEmpty() ); +} + +void AttachmentEditDialog::urlSelected( const TQString &url ) +{ + KURL kurl( url ); + mMimeType = KMimeType::findByURL( kurl ); + mTypeLabel->setText( mMimeType->comment() ); + mIcon->setPixmap( AttachmentListItem::icon( mMimeType, kurl.path() ) ); +} + +AttachmentIconView::AttachmentIconView( KOEditorAttachments* parent ) + : KIconView( parent ), + mParent( parent ) +{ + setSelectionMode( TQIconView::Extended ); + setMode( KIconView::Select ); + setItemTextPos( TQIconView::Right ); + setArrangement( TQIconView::LeftToRight ); + setMaxItemWidth( QMAX(maxItemWidth(), 250) ); + setMinimumHeight( QMAX(fontMetrics().height(), 16) + 12 ); + + connect( this, TQT_SIGNAL( dropped ( TQDropEvent *, const TQValueList<TQIconDragItem> & ) ), + this, TQT_SLOT( handleDrop( TQDropEvent *, const TQValueList<TQIconDragItem> & ) ) ); +} + +KURL AttachmentIconView::tempFileForAttachment( KCal::Attachment *attachment ) +{ + if ( mTempFiles.contains( attachment ) ) { + return mTempFiles[attachment]; + } + TQStringList patterns = KMimeType::mimeType( attachment->mimeType() )->patterns(); + + KTempFile *file; + if ( !patterns.empty() ) { + file = new KTempFile( TQString::null, + TQString( patterns.first() ).remove( '*' ),0600 ); + } else { + file = new KTempFile( TQString::null, TQString::null, 0600 ); + } + file->setAutoDelete( true ); + file->file()->open( IO_WriteOnly ); + TQTextStream stream( file->file() ); + stream.writeRawBytes( attachment->decodedData().data(), attachment->size() ); + KURL url( file->name() ); + mTempFiles.insert( attachment, url ); + file->close(); + return mTempFiles[attachment]; +} + +TQDragObject *AttachmentIconView::mimeData() +{ + // create a list of the URL:s that we want to drag + KURL::List urls; + TQStringList labels; + for ( TQIconViewItem *it = firstItem(); it; it = it->nextItem() ) { + if ( it->isSelected() ) { + AttachmentListItem *item = static_cast<AttachmentListItem *>( it ); + if ( item->isBinary() ) { + urls.append( tempFileForAttachment( item->attachment() ) ); + } else { + urls.append( item->uri() ); + } + labels.append( KURL::encode_string( item->label() ) ); + } + } + if ( selectionMode() == TQIconView::NoSelection ) { + AttachmentListItem *item = static_cast<AttachmentListItem *>( currentItem() ); + if ( item ) { + urls.append( item->uri() ); + labels.append( KURL::encode_string( item->label() ) ); + } + } + + TQMap<TQString, TQString> metadata; + metadata["labels"] = labels.join( ":" ); + + KURLDrag *drag = new KURLDrag( urls, metadata ); + return drag; +} + +AttachmentIconView::~AttachmentIconView() +{ + for ( std::set<KTempDir*>::iterator it = mTempDirs.begin() ; it != mTempDirs.end() ; ++it ) { + delete *it; + } +} + +TQDragObject * AttachmentIconView::dragObject() +{ + KURL::List urls; + for ( TQIconViewItem *it = firstItem( ); it; it = it->nextItem( ) ) { + if ( !it->isSelected() ) continue; + AttachmentListItem * item = dynamic_cast<AttachmentListItem*>( it ); + if ( !item ) return 0; + KCal::Attachment * att = item->attachment(); + assert( att ); + KURL url; + if ( att->isUri() ) { + url.setPath( att->uri() ); + } else { + KTempDir *tempDir = new KTempDir(); // will be deleted on editor close + tempDir->setAutoDelete( true ); + mTempDirs.insert( tempDir ); + TQByteArray encoded; + encoded.duplicate( att->data(), strlen( att->data() ) ); + TQByteArray decoded; + KCodecs::base64Decode( encoded, decoded ); + const TQString fileName = tempDir->name( ) + '/' + att->label(); + KPIM::kByteArrayToFile( decoded, fileName, false, false, false ); + url.setPath( fileName ); + } + urls << url; + } + KURLDrag *drag = new KURLDrag( urls, this ); + return drag; +} + +void AttachmentIconView::handleDrop( TQDropEvent *event, const TQValueList<TQIconDragItem> & list ) +{ + Q_UNUSED( list ); + mParent->handlePasteOrDrop( event ); +} + + +void AttachmentIconView::dragMoveEvent( TQDragMoveEvent *event ) +{ + mParent->dragMoveEvent( event ); +} + +void AttachmentIconView::contentsDragMoveEvent( TQDragMoveEvent *event ) +{ + mParent->dragMoveEvent( event ); +} + +void AttachmentIconView::contentsDragEnterEvent( TQDragEnterEvent *event ) +{ + mParent->dragMoveEvent( event ); +} + +void AttachmentIconView::dragEnterEvent( TQDragEnterEvent *event ) +{ + mParent->dragEnterEvent( event ); +} KOEditorAttachments::KOEditorAttachments( int spacing, TQWidget *parent, const char *name ) @@ -206,44 +469,51 @@ KOEditorAttachments::KOEditorAttachments( int spacing, TQWidget *parent, connect( mAttachments, TQT_SIGNAL(contextMenuRequested(TQIconViewItem*,const TQPoint&)), TQT_SLOT(contextMenu(TQIconViewItem*,const TQPoint&)) ); - mAddMenu = new KPopupMenu( this ); + TQPushButton *addButton = new TQPushButton( this ); + addButton->setIconSet( SmallIconSet( "add" ) ); + TQToolTip::add( addButton, i18n( "Add an attachment" ) ); + TQWhatsThis::add( addButton, + i18n( "Shows a dialog used to select an attachment " + "to add to this event or to-do as link or as " + "inline data." ) ); + topLayout->addWidget( addButton ); + connect( addButton, TQT_SIGNAL(clicked()), TQT_SLOT(slotAdd()) ); + + mRemoveBtn = new TQPushButton( this ); + mRemoveBtn->setIconSet( SmallIconSet( "remove" ) ); + TQToolTip::add( mRemoveBtn, i18n("&Remove") ); + TQWhatsThis::add( mRemoveBtn, + i18n("Removes the attachment selected in the list above " + "from this event or to-do.") ); + topLayout->addWidget( mRemoveBtn ); + connect( mRemoveBtn, TQT_SIGNAL(clicked()), TQT_SLOT(slotRemove()) ); + mContextMenu = new KPopupMenu( this ); KActionCollection* ac = new KActionCollection( this, this ); - mOpenAction = new KAction( i18n("View"), 0, this, TQT_SLOT(slotShow()), ac ); + mOpenAction = new KAction( i18n("Open"), 0, this, TQT_SLOT(slotShow()), ac ); mOpenAction->plug( mContextMenu ); + + mSaveAsAction = new KAction( i18n( "Save As..." ), 0, this, TQT_SLOT(slotSaveAs()), ac ); + mSaveAsAction->plug( mContextMenu ); mContextMenu->insertSeparator(); - mCopyAction = KStdAction::copy(this, TQT_SLOT(slotCopy( ) ), ac ); + mCopyAction = KStdAction::copy(this, TQT_SLOT(slotCopy()), ac ); mCopyAction->plug( mContextMenu ); - mCutAction = KStdAction::cut(this, TQT_SLOT(slotCut( ) ), ac ); + mCutAction = KStdAction::cut(this, TQT_SLOT(slotCut()), ac ); mCutAction->plug( mContextMenu ); - KAction *action = KStdAction::paste(this, TQT_SLOT(slotPaste( ) ), ac ); + KAction *action = KStdAction::paste(this, TQT_SLOT(slotPaste()), ac ); action->plug( mContextMenu ); + mContextMenu->insertSeparator(); - action = new KAction( i18n("&Attach File..."), 0, this, TQT_SLOT(slotAddData()), ac ); - action->setWhatsThis( i18n("Shows a dialog used to select an attachment " - "to add to this event or to-do as link as inline data.") ); - action->plug( mAddMenu ); - action = new KAction( i18n("Attach &Link..."), 0, this, TQT_SLOT(slotAdd()), ac ); - action->setWhatsThis( i18n("Shows a dialog used to select an attachment " - "to add to this event or to-do as link.") ); - action->plug( mAddMenu ); + mDeleteAction = new KAction( i18n( "&Remove" ), 0, this, TQT_SLOT(slotRemove()), ac ); + mDeleteAction->plug( mContextMenu ); + mDeleteAction->setShortcut( Key_Delete ); + mContextMenu->insertSeparator(); - TQPushButton *addButton = new TQPushButton( this ); - addButton->setIconSet( SmallIconSet( "add" ) ); - addButton->setPopup( mAddMenu ); - topLayout->addWidget( addButton ); - - mRemoveBtn = new TQPushButton( this ); - mRemoveBtn->setIconSet( SmallIconSet( "remove" ) ); - TQToolTip::add( mRemoveBtn, i18n("&Remove") ); - TQWhatsThis::add( mRemoveBtn, - i18n("Removes the attachment selected in the list above " - "from this event or to-do.") ); - topLayout->addWidget( mRemoveBtn ); - connect( mRemoveBtn, TQT_SIGNAL( clicked() ), TQT_SLOT( slotRemove() ) ); + mEditAction = new KAction( i18n( "&Properties..." ), 0, this, TQT_SLOT(slotEdit()), ac ); + mEditAction->plug( mContextMenu ); selectionChanged(); setAcceptDrops( true ); @@ -258,26 +528,106 @@ bool KOEditorAttachments::hasAttachments() return mAttachments->count() != 0; } +void KOEditorAttachments::dragMoveEvent( TQDragMoveEvent *event ) +{ + event->accept( KURLDrag::canDecode( event ) || + TQTextDrag::canDecode( event ) || + KPIM::MailListDrag::canDecode( event ) || + KVCardDrag::canDecode( event ) ); +} + void KOEditorAttachments::dragEnterEvent( TQDragEnterEvent* event ) { - event->accept( KURLDrag::canDecode( event ) | TQTextDrag::canDecode( event ) ); + dragMoveEvent( event ); } void KOEditorAttachments::handlePasteOrDrop( TQMimeSource* source ) { KURL::List urls; - TQString text; - if ( KURLDrag::decode( source, urls ) ) { - const bool asUri = KMessageBox::questionYesNo( this, - i18n("Do you want to link to the attachments, or include them in the event?"), - i18n("Attach as link?"), i18n("As Link"), i18n("As File") ) == KMessageBox::Yes; - for ( KURL::List::ConstIterator it = urls.begin(); it != urls.end(); ++it ) { - addAttachment( (*it).url(), TQString::null, asUri ); - } - } else if ( TQTextDrag::decode( source, text ) ) { - TQStringList lst = TQStringList::split( '\n', text ); - for ( TQStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it ) { - addAttachment( (*it) ); + bool probablyWeHaveUris = false; + bool weCanCopy = true; + TQStringList labels; + + if ( KVCardDrag::canDecode( source ) ) { + KABC::Addressee::List addressees; + KVCardDrag::decode( source, addressees ); + for ( KABC::Addressee::List::ConstIterator it = addressees.constBegin(); + it != addressees.constEnd(); ++it ) { + urls.append( KDEPIMPROTOCOL_CONTACT + ( *it ).uid() ); + // there is some weirdness about realName(), hence fromUtf8 + labels.append( TQString::fromUtf8( ( *it ).realName().latin1() ) ); + } + probablyWeHaveUris = true; + } else if ( KURLDrag::canDecode( source ) ) { + TQMap<TQString,TQString> metadata; + if ( KURLDrag::decode( source, urls, metadata ) ) { + probablyWeHaveUris = true; + labels = TQStringList::split( ':', metadata["labels"], FALSE ); + for ( TQStringList::Iterator it = labels.begin(); it != labels.end(); ++it ) { + *it = KURL::decode_string( (*it).latin1() ); + } + + } + } else if ( TQTextDrag::canDecode( source ) ) { + TQString text; + TQTextDrag::decode( source, text ); + TQStringList lst = TQStringList::split( '\n', text, FALSE ); + for ( TQStringList::ConstIterator it = lst.constBegin(); it != lst.constEnd(); ++it ) { + urls.append( *it ); + labels.append( TQString::null ); + } + probablyWeHaveUris = true; + } + + KPopupMenu menu; + int items=0; + if ( probablyWeHaveUris ) { + menu.insertItem( i18n( "&Link here" ), DRAG_LINK, items++ ); + // we need to check if we can reasonably expect to copy the objects + for ( KURL::List::ConstIterator it = urls.constBegin(); it != urls.constEnd(); ++it ) { + if ( !( weCanCopy = KProtocolInfo::supportsReading( *it ) ) ) { + break; // either we can copy them all, or no copying at all + } + } + if ( weCanCopy ) { + menu.insertItem( SmallIcon( "editcopy" ), i18n( "&Copy Here" ), DRAG_COPY, items++ ); + } + } else { + menu.insertItem( SmallIcon( "editcopy" ), i18n( "&Copy Here" ), DRAG_COPY, items++ ); + } + + menu.insertSeparator(); + items++; + menu.insertItem( SmallIcon( "cancel" ), i18n( "C&ancel" ), DRAG_CANCEL, items ); + int action = menu.exec( TQCursor::pos(), 0 ); + + if ( action == DRAG_LINK ) { + TQStringList::ConstIterator jt = labels.constBegin(); + for ( KURL::List::ConstIterator it = urls.constBegin(); + it != urls.constEnd(); ++it ) { + TQString label = (*jt++); + if ( mAttachments->findItem( label ) ) { + label += '~' + randomString( 3 ); + } + addUriAttachment( (*it).url(), TQString::null, label, true ); + } + } else if ( action != DRAG_CANCEL ) { + if ( probablyWeHaveUris ) { + for ( KURL::List::ConstIterator it = urls.constBegin(); + it != urls.constEnd(); ++it ) { + TQString label = (*it).fileName(); + if ( label.isEmpty() ) { + label = (*it).prettyURL(); + } + if ( mAttachments->findItem( label ) ) { + label += '~' + randomString( 3 ); + } + addUriAttachment( (*it).url(), TQString::null, label, true ); + } + } else { // we take anything + addDataAttachment( source->encodedData( source->format() ), + source->format(), + KMimeType::mimeType( source->format() )->name() ); } } } @@ -293,95 +643,98 @@ void KOEditorAttachments::showAttachment( TQIconViewItem *item ) if ( !attitem || !attitem->attachment() ) return; KCal::Attachment *att = attitem->attachment(); - if ( att->isUri() ) { - emit openURL( att->uri() ); - } else { - KTempFile f; - if ( !f.file() ) - return; - TQByteArray encoded; - encoded.duplicate( att->data(), strlen(att->data()) ); - TQByteArray decoded; - KCodecs::base64Decode( encoded, decoded ); - f.file()->writeBlock( decoded ); - f.file()->close(); - KRun::runURL( f.name(), att->mimeType(), true, false ); - } + KCal::AttachmentHandler::view( this, att ); +} + +void KOEditorAttachments::saveAttachment( TQIconViewItem *item ) +{ + AttachmentListItem *attitem = static_cast<AttachmentListItem*>(item); + if ( !attitem || !attitem->attachment() ) return; + + KCal::Attachment *att = attitem->attachment(); + KCal::AttachmentHandler::saveAs( this, att ); } void KOEditorAttachments::slotAdd() { - KURL uri = KPimURLRequesterDlg::getURL( TQString::null, i18n( - "URL (e.g. a web page) or file to be attached (only " - "the link will be attached, not the file itself):"), this, - i18n("Add Attachment") ); - if ( !uri.isEmpty() ) { - addAttachment( uri ); + AttachmentListItem *item = new AttachmentListItem( 0, mAttachments ); + + AttachmentEditDialog *dlg = new AttachmentEditDialog( item, mAttachments ) +; + if ( dlg->exec() == KDialog::Rejected ) { + delete item; } + delete dlg; } void KOEditorAttachments::slotAddData() { KURL uri = KFileDialog::getOpenFileName( TQString(), TQString(), this, i18n("Add Attachment") ); if ( !uri.isEmpty() ) { - addAttachment( uri, TQString::null, false ); + TQString label = uri.fileName(); + if ( label.isEmpty() ) { + label = uri.prettyURL(); + } + addUriAttachment( uri.url(), TQString::null, label, true ); } } void KOEditorAttachments::slotEdit() { - TQIconViewItem *item = mAttachments->currentItem(); - AttachmentListItem *attitem = static_cast<AttachmentListItem*>(item); - if ( !attitem || !attitem->attachment() ) return; - - KCal::Attachment *att = attitem->attachment(); - if ( att->isUri() ) { - KURL uri = KPimURLRequesterDlg::getURL( att->uri(), i18n( - "URL (e.g. a web page) or file to be attached (only " - "the link will be attached, not the file itself):"), this, - i18n("Edit Attachment") ); - - if ( !uri.isEmpty() ) - attitem->setUri( uri.url() ); - } else { - KURL uri = KPimURLRequesterDlg::getURL( TQString::null, i18n( - "File to be attached:"), this, i18n("Add Attachment") ); - if ( !uri.isEmpty() ) { - TQString tmpFile; - if ( KIO::NetAccess::download( uri, tmpFile, this ) ) { - TQFile f( tmpFile ); - if ( !f.open( IO_ReadOnly ) ) - return; - TQByteArray data = f.readAll(); - f.close(); - attitem->setData( KCodecs::base64Encode( data ) ); - attitem->setMimeType( KIO::NetAccess::mimetype( uri, this ) ); - TQString label = uri.fileName(); - if ( label.isEmpty() ) - label = uri.prettyURL(); - attitem->setLabel( label ); - KIO::NetAccess::removeTempFile( tmpFile ); + for ( TQIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) { + if ( item->isSelected() ) { + AttachmentListItem *attitem = static_cast<AttachmentListItem*>( item ); + if ( !attitem || !attitem->attachment() ) { + return; } + + AttachmentEditDialog *dialog = new AttachmentEditDialog( attitem, mAttachments ); + dialog->mInline->setEnabled( false ); + dialog->setModal( false ); + connect( dialog, TQT_SIGNAL(hidden()), dialog, TQT_SLOT(delayedDestruct()) ); + dialog->show(); } } } void KOEditorAttachments::slotRemove() { - TQValueList<TQIconViewItem*> selected; - for ( TQIconViewItem *it = mAttachments->firstItem( ); it; it = it->nextItem( ) ) { - if ( !it->isSelected() ) continue; - selected << it; - } - if ( selected.isEmpty() || KMessageBox::warningContinueCancel(this, - selected.count() == 1?i18n("This item will be permanently deleted."): - i18n("The selected items will be permanently deleted."), - i18n("KOrganizer Confirmation"),KStdGuiItem::del()) != KMessageBox::Continue ) - return; + TQValueList<TQIconViewItem*> selected; + TQStringList labels; + for ( TQIconViewItem *it = mAttachments->firstItem( ); it; it = it->nextItem( ) ) { + if ( !it->isSelected() ) continue; + selected << it; + + AttachmentListItem *attitem = static_cast<AttachmentListItem*>(it); + KCal::Attachment *att = attitem->attachment(); + labels << att->label(); + } - for ( TQValueList<TQIconViewItem*>::iterator it( selected.begin() ), end( selected.end() ); it != end ; ++it ) { - delete *it; + if ( selected.isEmpty() ) { + return; + } + + TQString labelsStr = labels.join( "<br>" ); + + if ( KMessageBox::questionYesNo( + this, + i18n( "<qt>Do you really want to remove these attachments?<p>%1</qt>" ).arg( labelsStr ), + i18n( "Remove Attachment?" ), + KStdGuiItem::yes(), KStdGuiItem::no(), + "calendarRemoveAttachments" ) != KMessageBox::Yes ) { + return; + } + + for ( TQValueList<TQIconViewItem*>::iterator it( selected.begin() ), end( selected.end() ); + it != end ; ++it ) { + if ( (*it)->nextItem() ) { + (*it)->nextItem()->setSelected( true ); + } else if ( (*it)->prevItem() ) { + (*it)->prevItem()->setSelected( true ); } + delete *it; + } + mAttachments->slotUpdate(); } void KOEditorAttachments::slotShow() @@ -393,40 +746,98 @@ void KOEditorAttachments::slotShow() } } +void KOEditorAttachments::slotSaveAs() +{ + for ( TQIconViewItem *it = mAttachments->firstItem(); it; it = it->nextItem() ) { + if ( !it->isSelected() ) + continue; + saveAttachment( it ); + } +} + void KOEditorAttachments::setDefaults() { mAttachments->clear(); } -void KOEditorAttachments::addAttachment( const KURL &uri, - const TQString &mimeType, bool asUri ) +TQString KOEditorAttachments::randomString(int length) const { - AttachmentListItem *item = new AttachmentListItem( 0, mAttachments ); - if ( asUri ) { - item->setUri( uri.url() ); - if ( !mimeType.isEmpty() ) item->setMimeType( mimeType ); + if (length <=0 ) return TQString(); + + TQString str; str.setLength( length ); + int i = 0; + while (length--) + { + int r=random() % 62; + r+=48; + if (r>57) r+=7; + if (r>90) r+=6; + str[i++] = char(r); + // so what if I work backwards? + } + return str; +} + +void KOEditorAttachments::addUriAttachment( const TQString &uri, + const TQString &mimeType, + const TQString &label, + bool inLine ) +{ + if ( !inLine ) { + AttachmentListItem *item = new AttachmentListItem( 0, mAttachments ); + item->setUri( uri ); + item->setLabel( label ); + if ( mimeType.isEmpty() ) { + if ( uri.startsWith( KDEPIMPROTOCOL_CONTACT ) ) { + item->setMimeType( "text/directory" ); + } else if ( uri.startsWith( KDEPIMPROTOCOL_EMAIL ) ) { + item->setMimeType( "message/rfc822" ); + } else if ( uri.startsWith( KDEPIMPROTOCOL_INCIDENCE ) ) { + item->setMimeType( "text/calendar" ); + } else if ( uri.startsWith( KDEPIMPROTOCOL_NEWSARTICLE ) ) { + item->setMimeType( "message/news" ); + } else { + item->setMimeType( KMimeType::findByURL( uri )->name() ); + } + } } else { TQString tmpFile; if ( KIO::NetAccess::download( uri, tmpFile, this ) ) { TQFile f( tmpFile ); - if ( !f.open( IO_ReadOnly ) ) + if ( !f.open( IO_ReadOnly ) ) { return; - TQByteArray data = f.readAll(); + } + const TQByteArray data = f.readAll(); f.close(); - item->setData( KCodecs::base64Encode( data ) ); - if ( !mimeType.isEmpty() ) - item->setMimeType( mimeType ); - else - item->setMimeType( KIO::NetAccess::mimetype( uri, this ) ); - TQString label = uri.fileName(); - if ( label.isEmpty() ) - label = uri.prettyURL(); - item->setLabel( label ); - KIO::NetAccess::removeTempFile( tmpFile ); + addDataAttachment( data, mimeType, label ); } + KIO::NetAccess::removeTempFile( tmpFile ); } } +void KOEditorAttachments::addDataAttachment( const TQByteArray &data, + const TQString &mimeType, + const TQString &label ) +{ + AttachmentListItem *item = new AttachmentListItem( 0, mAttachments ); + + TQString nlabel = label; + if ( mimeType == "message/rfc822" ) { + // mail message. try to set the label from the mail Subject: + KMime::Message msg; + msg.setContent( data.data() ); + msg.parse(); + nlabel = msg.subject()->asUnicodeString(); + } + + item->setData( data ); + item->setLabel( nlabel ); + if ( mimeType.isEmpty() ) { + item->setMimeType( KMimeType::findByContent( data )->name() ); + } else { + item->setMimeType( mimeType ); + } +} void KOEditorAttachments::addAttachment( KCal::Attachment *attachment ) { @@ -463,7 +874,7 @@ void KOEditorAttachments::writeIncidence( KCal::Incidence *i ) void KOEditorAttachments::slotCopy() { - TQApplication::clipboard()->setData( mAttachments->dragObject(), QClipboard::Clipboard ); + TQApplication::clipboard()->setData( mAttachments->mimeData(), QClipboard::Clipboard ); } void KOEditorAttachments::slotCut() @@ -492,9 +903,21 @@ void KOEditorAttachments::selectionChanged() void KOEditorAttachments::contextMenu(TQIconViewItem * item, const TQPoint & pos) { const bool enable = item != 0; + + int numSelected = 0; + for ( TQIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) { + if ( item->isSelected() ) { + numSelected++; + } + } + mOpenAction->setEnabled( enable ); - mCopyAction->setEnabled( enable ); - mCutAction->setEnabled( enable ); + //TODO: support saving multiple attachments into a directory + mSaveAsAction->setEnabled( enable && numSelected == 1 ); + mCopyAction->setEnabled( enable && numSelected == 1 ); + mCutAction->setEnabled( enable && numSelected == 1 ); + mDeleteAction->setEnabled( enable ); + mEditAction->setEnabled( enable ); mContextMenu->exec( pos ); } |