korganizer

koeditorattachments.cpp
1/*
2 This file is part of KOrganizer.
3
4 Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
5 Copyright (c) 2005 Reinhold Kainhofer <reinhold@kainhofer.com>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
21 As a special exception, permission is given to link this program
22 with any edition of TQt, and distribute the resulting executable,
23 without including the source code for TQt in the source distribution.
24*/
25
26#include "koeditorattachments.h"
27
29#include <libkcal/incidence.h>
30#include <libtdepim/kpimurlrequesterdlg.h>
31#include <libtdepim/tdefileio.h>
32#include <libtdepim/tdepimprotocols.h>
33#include <libtdepim/maillistdrag.h>
34#include <libtdepim/kvcarddrag.h>
35#include <libtdepim/tdepimprotocols.h>
36
37#include <tdelocale.h>
38#include <kdebug.h>
39#include <kmdcodec.h>
40#include <tdemessagebox.h>
41#include <krun.h>
42#include <kurldrag.h>
43#include <tdetempfile.h>
44#include <ktempdir.h>
45#include <tdeio/netaccess.h>
46#include <kmimetype.h>
47#include <kiconloader.h>
48#include <tdefiledialog.h>
49#include <kstdaction.h>
50#include <tdeactioncollection.h>
51#include <tdepopupmenu.h>
52#include <kprotocolinfo.h>
53#include <klineedit.h>
54#include <kseparator.h>
55#include <kurlrequester.h>
56#include <libkmime/kmime_message.h>
57
58#include <tqcheckbox.h>
59#include <tqfile.h>
60#include <tqlabel.h>
61#include <tqlayout.h>
62#include <tqlistview.h>
63#include <tqpushbutton.h>
64#include <tqdragobject.h>
65#include <tqtooltip.h>
66#include <tqwhatsthis.h>
67#include <tqapplication.h>
68#include <tqclipboard.h>
69
70#include <cassert>
71#include <cstdlib>
72
73class AttachmentListItem : public TDEIconViewItem
74{
75 public:
76 AttachmentListItem( KCal::Attachment*att, TQIconView *parent ) :
77 TDEIconViewItem( parent )
78 {
79 if ( att ) {
80 mAttachment = new KCal::Attachment( *att );
81 } else {
82 mAttachment = new KCal::Attachment( nullptr );
83 }
84 readAttachment();
85 setDragEnabled( true );
86 }
87 ~AttachmentListItem() { delete mAttachment; }
88 KCal::Attachment *attachment() const { return mAttachment; }
89
90 const TQString uri() const
91 {
92 return mAttachment->uri();
93 }
94 void setUri( const TQString &uri )
95 {
96 mAttachment->setUri( uri );
97 readAttachment();
98 }
99 void setData( const TQByteArray data )
100 {
101 mAttachment->setDecodedData( data );
102 readAttachment();
103 }
104 const TQString mimeType() const
105 {
106 return mAttachment->mimeType();
107 }
108 void setMimeType( const TQString &mime )
109 {
110 mAttachment->setMimeType( mime );
111 readAttachment();
112 }
113 const TQString label() const
114 {
115 return mAttachment->label();
116 }
117 void setLabel( const TQString &label )
118 {
119 mAttachment->setLabel( label );
120 readAttachment();
121 }
122 bool isBinary() const
123 {
124 return mAttachment->isBinary();
125 }
126 TQPixmap icon() const
127 {
128 return icon( KMimeType::mimeType( mAttachment->mimeType() ),
129 mAttachment->uri() );
130 }
131 static TQPixmap icon( KMimeType::Ptr mimeType, const TQString &uri )
132 {
133 TQString iconStr = mimeType->icon( uri, false );
134 return TDEGlobal::iconLoader()->loadIcon( iconStr, TDEIcon::Small );
135 }
136 void readAttachment()
137 {
138 if ( mAttachment->label().isEmpty() ) {
139 if ( mAttachment->isUri() ) {
140 setText( mAttachment->uri() );
141 } else {
142 setText( i18n( "[Binary data]" ) );
143 }
144 } else {
145 setText( mAttachment->label() );
146 }
147 if ( mAttachment->mimeType().isEmpty() ||
148 !( KMimeType::mimeType( mAttachment->mimeType() ) ) ) {
149 KMimeType::Ptr mimeType;
150 if ( mAttachment->isUri() ) {
151 mimeType = KMimeType::findByURL( mAttachment->uri() );
152 } else {
153 mimeType = KMimeType::findByContent( mAttachment->decodedData() );
154 }
155 mAttachment->setMimeType( mimeType->name() );
156 }
157
158 setPixmap( icon() );
159 }
160
161 private:
162 KCal::Attachment *mAttachment;
163};
164
165AttachmentEditDialog::AttachmentEditDialog( AttachmentListItem *item,
166 TQWidget *parent )
167 : KDialogBase ( Plain, i18n( "Add Attachment" ), Ok|Cancel, Ok, parent, 0, false, false ),
168 mItem( item ), mURLRequester( 0 )
169{
170 TQFrame *topFrame = plainPage();
171 TQVBoxLayout *vbl = new TQVBoxLayout( topFrame, 0, spacingHint() );
172
173 TQGridLayout *grid = new TQGridLayout();
174 grid->setColStretch( 0, 0 );
175 grid->setColStretch( 1, 0 );
176 grid->setColStretch( 2, 1 );
177 vbl->addLayout( grid );
178
179 mIcon = new TQLabel( topFrame );
180 mIcon->setPixmap( item->icon() );
181 grid->addWidget( mIcon, 0, 0 );
182
183 mLabelEdit = new KLineEdit( topFrame );
184 mLabelEdit->setText( item->label().isEmpty() ? item->uri() : item->label() );
185 mLabelEdit->setClickMessage( i18n( "Attachment name" ) );
186 TQToolTip::add( mLabelEdit, i18n( "Give the attachment a name" ) );
187 TQWhatsThis::add( mLabelEdit,
188 i18n( "Type any string you desire here for the name of the attachment" ) );
189 grid->addMultiCellWidget( mLabelEdit, 0, 0, 1, 2 );
190
191 KSeparator *sep = new KSeparator( TQt::Horizontal, topFrame );
192 grid->addMultiCellWidget( sep, 1, 1, 0, 2 );
193
194 TQLabel *label = new TQLabel( i18n( "Type:" ), topFrame );
195 grid->addWidget( label, 2, 0 );
196 TQString typecomment = item->mimeType().isEmpty() ?
197 i18n( "Unknown" ) :
198 KMimeType::mimeType( item->mimeType() )->comment();
199 mTypeLabel = new TQLabel( typecomment, topFrame );
200 grid->addWidget( mTypeLabel, 2, 1 );
201 mMimeType = KMimeType::mimeType( item->mimeType() );
202
203 mInline = new TQCheckBox( i18n( "Store attachment inline" ), topFrame );
204 grid->addMultiCellWidget( mInline, 3, 3, 0, 2 );
205 mInline->setChecked( item->isBinary() || item->label().isEmpty() );
206 TQToolTip::add( mInline, i18n( "Store the attachment file inside the calendar" ) );
207 TQWhatsThis::add(
208 mInline,
209 i18n( "Checking this option will cause the attachment to be stored inside "
210 "your calendar, which can take a lot of space depending on the size "
211 "of the attachment. If this option is not checked, then only a link "
212 "pointing to the attachment will be stored. Do not use a link for "
213 "attachments that change often or may be moved (or removed) from "
214 "their current location." ) );
215
216 if ( item->attachment()->isUri() || item->label().isEmpty() || !item->attachment()->data() ) {
217 label = new TQLabel( i18n( "Location:" ), topFrame );
218 grid->addWidget( label, 4, 0 );
219 mURLRequester = new KURLRequester( item->uri(), topFrame );
220 TQToolTip::add( mURLRequester, i18n( "Provide a location for the attachment file" ) );
221 TQWhatsThis::add(
222 mURLRequester,
223 i18n( "Enter the path to the attachment file or use the "
224 "file browser by pressing the adjacent button" ) );
225 grid->addMultiCellWidget( mURLRequester, 4, 4, 1, 2 );
226 connect( mURLRequester, TQ_SIGNAL(urlSelected(const TQString &)),
227 TQ_SLOT(urlSelected(const TQString &)) );
228 connect( mURLRequester, TQ_SIGNAL( textChanged( const TQString& ) ),
229 TQ_SLOT( urlChanged( const TQString& ) ) );
230 urlChanged( item->uri() );
231 } else {
232 uint size = item->attachment()->size();
233 grid->addWidget( new TQLabel( i18n( "Size:" ), topFrame ), 4, 0 );
234 grid->addWidget( new TQLabel( TQString::fromLatin1( "%1 (%2)" ).
235 arg( TDEIO::convertSize( size ) ).
236 arg( TDEGlobal::locale()->formatNumber(
237 size, 0 ) ), topFrame ), 4, 2 );
238 }
239 vbl->addStretch( 10 );
240}
241
242void AttachmentEditDialog::slotApply()
243{
244 if ( !mLabelEdit->text().isEmpty() ) {
245 mItem->setLabel( mLabelEdit->text() );
246 } else if ( mURLRequester && !mURLRequester->url().isEmpty() ) {
247 KURL url = KURL::fromPathOrURL( mURLRequester->url() );
248 mItem->setLabel( url.isLocalFile() ? url.fileName() : url.url() );
249 } else {
250 mItem->setLabel( i18n( "New attachment" ) );
251 }
252 mItem->setMimeType( mMimeType->name() );
253 if ( mURLRequester ) {
254 KURL url = KURL::fromPathOrURL( mURLRequester->url() );
255
256 TQString correctedUrl = mURLRequester->url();
257 if ( !url.isValid() ) {
258 // If the user used KURLRequester's KURLCompletion
259 // (used the line edit instead of the file dialog)
260 // the returned url is not absolute and is always relative
261 // to the home directory (not pwd), so we must prepend home
262
263 correctedUrl = TQDir::home().filePath( mURLRequester->url() );
264 url = KURL::fromPathOrURL( correctedUrl );
265 if ( url.isValid() ) {
266 urlSelected( correctedUrl );
267 mItem->setMimeType( mMimeType->name() );
268 }
269 }
270
271 if ( mInline->isChecked() ) {
272 TQString tmpFile;
273 if ( TDEIO::NetAccess::download( url, tmpFile, this ) ) {
274 TQFile f( tmpFile );
275 if ( !f.open( IO_ReadOnly ) ) {
276 return;
277 }
278 TQByteArray data = f.readAll();
279 f.close();
280 mItem->setData( data );
281 }
282 TDEIO::NetAccess::removeTempFile( tmpFile );
283 } else {
284 mItem->setUri( url.url() );
285 }
286 }
287}
288
289void AttachmentEditDialog::accept()
290{
291 slotApply();
292 KDialog::accept();
293}
294
295void AttachmentEditDialog::urlChanged( const TQString &url )
296{
297 enableButton( Ok, !url.isEmpty() );
298}
299
300void AttachmentEditDialog::urlSelected( const TQString &url )
301{
302 KURL kurl = KURL::fromPathOrURL( url );
303 mMimeType = KMimeType::findByURL( kurl );
304 mTypeLabel->setText( mMimeType->comment() );
305 mIcon->setPixmap( AttachmentListItem::icon( mMimeType, kurl.path() ) );
306}
307
308AttachmentIconView::AttachmentIconView( KOEditorAttachments* parent )
309 : TDEIconView( parent ),
310 mParent( parent )
311{
312 setSelectionMode( TQIconView::Extended );
313 setMode( TDEIconView::Select );
314 setItemTextPos( TQIconView::Right );
315 setArrangement( TQIconView::LeftToRight );
316 setMaxItemWidth( TQMAX(maxItemWidth(), 250) );
317 setMinimumHeight( TQMAX(fontMetrics().height(), 16) + 12 );
318
319 connect( this, TQ_SIGNAL( dropped ( TQDropEvent *, const TQValueList<TQIconDragItem> & ) ),
320 this, TQ_SLOT( handleDrop( TQDropEvent *, const TQValueList<TQIconDragItem> & ) ) );
321}
322
323KURL AttachmentIconView::tempFileForAttachment( KCal::Attachment *attachment )
324{
325 if ( mTempFiles.contains( attachment ) ) {
326 return mTempFiles[attachment];
327 }
328 TQStringList patterns = KMimeType::mimeType( attachment->mimeType() )->patterns();
329
330 KTempFile *file;
331 if ( !patterns.empty() ) {
332 file = new KTempFile( TQString(),
333 TQString( patterns.first() ).remove( '*' ),0600 );
334 } else {
335 file = new KTempFile( TQString(), TQString(), 0600 );
336 }
337 file->setAutoDelete( true );
338 file->file()->open( IO_WriteOnly );
339 TQTextStream stream( file->file() );
340 stream.writeRawBytes( attachment->decodedData().data(), attachment->size() );
341 KURL url( file->name() );
342 mTempFiles.insert( attachment, url );
343 file->close();
344 return mTempFiles[attachment];
345}
346
347TQDragObject *AttachmentIconView::mimeData()
348{
349 // create a list of the URL:s that we want to drag
350 KURL::List urls;
351 TQStringList labels;
352 for ( TQIconViewItem *it = firstItem(); it; it = it->nextItem() ) {
353 if ( it->isSelected() ) {
354 AttachmentListItem *item = static_cast<AttachmentListItem *>( it );
355 if ( item->isBinary() ) {
356 urls.append( tempFileForAttachment( item->attachment() ) );
357 } else {
358 urls.append( item->uri() );
359 }
360 labels.append( KURL::encode_string( item->label() ) );
361 }
362 }
363 if ( selectionMode() == TQIconView::NoSelection ) {
364 AttachmentListItem *item = static_cast<AttachmentListItem *>( currentItem() );
365 if ( item ) {
366 urls.append( item->uri() );
367 labels.append( KURL::encode_string( item->label() ) );
368 }
369 }
370
371 TQMap<TQString, TQString> metadata;
372 metadata["labels"] = labels.join( ":" );
373
374 KURLDrag *drag = new KURLDrag( urls, metadata );
375 return drag;
376}
377
378AttachmentIconView::~AttachmentIconView()
379{
380 for ( std::set<KTempDir*>::iterator it = mTempDirs.begin() ; it != mTempDirs.end() ; ++it ) {
381 delete *it;
382 }
383}
384
385TQDragObject * AttachmentIconView::dragObject()
386{
387 KURL::List urls;
388 for ( TQIconViewItem *it = firstItem( ); it; it = it->nextItem( ) ) {
389 if ( !it->isSelected() ) continue;
390 AttachmentListItem * item = dynamic_cast<AttachmentListItem*>( it );
391 if ( !item ) return 0;
392 KCal::Attachment * att = item->attachment();
393 assert( att );
394 KURL url;
395 if ( att->isUri() ) {
396 url.setPath( att->uri() );
397 } else {
398 KTempDir *tempDir = new KTempDir(); // will be deleted on editor close
399 tempDir->setAutoDelete( true );
400 mTempDirs.insert( tempDir );
401 TQByteArray encoded;
402 encoded.duplicate( att->data(), strlen( att->data() ) );
403 TQByteArray decoded;
404 KCodecs::base64Decode( encoded, decoded );
405 const TQString fileName = tempDir->name( ) + '/' + att->label();
406 KPIM::kByteArrayToFile( decoded, fileName, false, false, false );
407 url.setPath( fileName );
408 }
409 urls << url;
410 }
411 KURLDrag *drag = new KURLDrag( urls, this );
412 return drag;
413}
414
415void AttachmentIconView::handleDrop( TQDropEvent *event, const TQValueList<TQIconDragItem> & list )
416{
417 Q_UNUSED( list );
418 mParent->handlePasteOrDrop( event );
419}
420
421
422void AttachmentIconView::dragMoveEvent( TQDragMoveEvent *event )
423{
424 mParent->dragMoveEvent( event );
425}
426
427void AttachmentIconView::contentsDragMoveEvent( TQDragMoveEvent *event )
428{
429 mParent->dragMoveEvent( event );
430}
431
432void AttachmentIconView::contentsDragEnterEvent( TQDragEnterEvent *event )
433{
434 mParent->dragMoveEvent( event );
435}
436
437void AttachmentIconView::dragEnterEvent( TQDragEnterEvent *event )
438{
439 mParent->dragEnterEvent( event );
440}
441
442KOEditorAttachments::KOEditorAttachments( int spacing, TQWidget *parent,
443 const char *name )
444 : TQWidget( parent, name )
445{
446 TQBoxLayout *topLayout = new TQHBoxLayout( this );
447 topLayout->setSpacing( spacing );
448
449 TQLabel *label = new TQLabel( i18n("Attachments:"), this );
450 topLayout->addWidget( label );
451
452 mAttachments = new AttachmentIconView( this );
453 TQWhatsThis::add( mAttachments,
454 i18n("Displays a list of current items (files, mail, etc.) "
455 "that have been associated with this event or to-do. ") );
456 topLayout->addWidget( mAttachments );
457 connect( mAttachments, TQ_SIGNAL( doubleClicked( TQIconViewItem * ) ),
458 TQ_SLOT( showAttachment( TQIconViewItem * ) ) );
459 connect( mAttachments, TQ_SIGNAL(selectionChanged()),
460 TQ_SLOT(selectionChanged()) );
461 connect( mAttachments, TQ_SIGNAL(contextMenuRequested(TQIconViewItem*,const TQPoint&)),
462 TQ_SLOT(contextMenu(TQIconViewItem*,const TQPoint&)) );
463
464 TQPushButton *addButton = new TQPushButton( this );
465 addButton->setIconSet( SmallIconSet( "add" ) );
466 TQToolTip::add( addButton, i18n( "Add an attachment" ) );
467 TQWhatsThis::add( addButton,
468 i18n( "Shows a dialog used to select an attachment "
469 "to add to this event or to-do as link or as "
470 "inline data." ) );
471 topLayout->addWidget( addButton );
472 connect( addButton, TQ_SIGNAL(clicked()), TQ_SLOT(slotAdd()) );
473
474 mRemoveBtn = new TQPushButton( this );
475 mRemoveBtn->setIconSet( SmallIconSet( "remove" ) );
476 TQToolTip::add( mRemoveBtn, i18n("&Remove") );
477 TQWhatsThis::add( mRemoveBtn,
478 i18n("Removes the attachment selected in the list above "
479 "from this event or to-do.") );
480 topLayout->addWidget( mRemoveBtn );
481 connect( mRemoveBtn, TQ_SIGNAL(clicked()), TQ_SLOT(slotRemove()) );
482
483 mContextMenu = new TDEPopupMenu( this );
484
485 TDEActionCollection* ac = new TDEActionCollection( this, this );
486
487 mOpenAction = new TDEAction( i18n("Open"), 0, this, TQ_SLOT(slotShow()), ac );
488 mOpenAction->plug( mContextMenu );
489
490 mSaveAsAction = new TDEAction( i18n( "Save As..." ), 0, this, TQ_SLOT(slotSaveAs()), ac );
491 mSaveAsAction->plug( mContextMenu );
492 mContextMenu->insertSeparator();
493
494 mCopyAction = KStdAction::copy(this, TQ_SLOT(slotCopy()), ac );
495 mCopyAction->plug( mContextMenu );
496 mCutAction = KStdAction::cut(this, TQ_SLOT(slotCut()), ac );
497 mCutAction->plug( mContextMenu );
498 TDEAction *action = KStdAction::paste(this, TQ_SLOT(slotPaste()), ac );
499 action->plug( mContextMenu );
500 mContextMenu->insertSeparator();
501
502 mDeleteAction = new TDEAction( i18n( "&Remove" ), 0, this, TQ_SLOT(slotRemove()), ac );
503 mDeleteAction->plug( mContextMenu );
504 mDeleteAction->setShortcut( Key_Delete );
505 mContextMenu->insertSeparator();
506
507 mEditAction = new TDEAction( i18n( "&Properties..." ), 0, this, TQ_SLOT(slotEdit()), ac );
508 mEditAction->plug( mContextMenu );
509
510 selectionChanged();
511 setAcceptDrops( true );
512}
513
514KOEditorAttachments::~KOEditorAttachments()
515{
516}
517
518bool KOEditorAttachments::hasAttachments()
519{
520 return mAttachments->count() != 0;
521}
522
523void KOEditorAttachments::dragMoveEvent( TQDragMoveEvent *event )
524{
525 event->accept( KURLDrag::canDecode( event ) ||
526 TQTextDrag::canDecode( event ) ||
527 KPIM::MailListDrag::canDecode( event ) ||
528 KVCardDrag::canDecode( event ) );
529}
530
531void KOEditorAttachments::dragEnterEvent( TQDragEnterEvent* event )
532{
533 dragMoveEvent( event );
534}
535
536void KOEditorAttachments::handlePasteOrDrop( TQMimeSource* source )
537{
538 KURL::List urls;
539 bool probablyWeHaveUris = false;
540 bool weCanCopy = true;
541 TQStringList labels;
542
543 if ( KVCardDrag::canDecode( source ) ) {
544 TDEABC::Addressee::List addressees;
545 KVCardDrag::decode( source, addressees );
546 for ( TDEABC::Addressee::List::ConstIterator it = addressees.constBegin();
547 it != addressees.constEnd(); ++it ) {
548 urls.append( TDEPIMPROTOCOL_CONTACT + ( *it ).uid() );
549 // there is some weirdness about realName(), hence fromUtf8
550 labels.append( TQString::fromUtf8( ( *it ).realName().latin1() ) );
551 }
552 probablyWeHaveUris = true;
553 } else if ( KURLDrag::canDecode( source ) ) {
554 TQMap<TQString,TQString> metadata;
555 if ( KURLDrag::decode( source, urls, metadata ) ) {
556 probablyWeHaveUris = true;
557 labels = TQStringList::split( ':', metadata["labels"], false );
558 for ( TQStringList::Iterator it = labels.begin(); it != labels.end(); ++it ) {
559 *it = KURL::decode_string( (*it).latin1() );
560 }
561
562 }
563 } else if ( TQTextDrag::canDecode( source ) ) {
564 TQString text;
565 TQTextDrag::decode( source, text );
566 TQStringList lst = TQStringList::split( '\n', text, false );
567 for ( TQStringList::ConstIterator it = lst.constBegin(); it != lst.constEnd(); ++it ) {
568 urls.append( *it );
569 labels.append( TQString() );
570 }
571 probablyWeHaveUris = true;
572 }
573
574 TDEPopupMenu menu;
575 int items=0;
576 if ( probablyWeHaveUris ) {
577 menu.insertItem( i18n( "&Link here" ), DRAG_LINK, items++ );
578 // we need to check if we can reasonably expect to copy the objects
579 for ( KURL::List::ConstIterator it = urls.constBegin(); it != urls.constEnd(); ++it ) {
580 if ( !( weCanCopy = KProtocolInfo::supportsReading( *it ) ) ) {
581 break; // either we can copy them all, or no copying at all
582 }
583 }
584 if ( weCanCopy ) {
585 menu.insertItem( SmallIcon( "edit-copy" ), i18n( "&Copy Here" ), DRAG_COPY, items++ );
586 }
587 } else {
588 menu.insertItem( SmallIcon( "edit-copy" ), i18n( "&Copy Here" ), DRAG_COPY, items++ );
589 }
590
591 menu.insertSeparator();
592 items++;
593 menu.insertItem( SmallIcon( "cancel" ), i18n( "C&ancel" ), DRAG_CANCEL, items );
594 int action = menu.exec( TQCursor::pos(), 0 );
595
596 if ( action == DRAG_LINK ) {
597 TQStringList::ConstIterator jt = labels.constBegin();
598 for ( KURL::List::ConstIterator it = urls.constBegin();
599 it != urls.constEnd(); ++it ) {
600 TQString label = (*jt++);
601 if ( mAttachments->findItem( label ) ) {
602 label += '~' + randomString( 3 );
603 }
604 addUriAttachment( (*it).url(), TQString(), label, true );
605 }
606 } else if ( action != DRAG_CANCEL ) {
607 if ( probablyWeHaveUris ) {
608 for ( KURL::List::ConstIterator it = urls.constBegin();
609 it != urls.constEnd(); ++it ) {
610 TQString label = (*it).fileName();
611 if ( label.isEmpty() ) {
612 label = (*it).prettyURL();
613 }
614 if ( mAttachments->findItem( label ) ) {
615 label += '~' + randomString( 3 );
616 }
617 addUriAttachment( (*it).url(), TQString(), label, true );
618 }
619 } else { // we take anything
620 addDataAttachment( source->encodedData( source->format() ),
621 source->format(),
622 KMimeType::mimeType( source->format() )->name() );
623 }
624 }
625}
626
627void KOEditorAttachments::dropEvent( TQDropEvent* event )
628{
629 handlePasteOrDrop( event );
630}
631
632void KOEditorAttachments::showAttachment( TQIconViewItem *item )
633{
634 AttachmentListItem *attitem = static_cast<AttachmentListItem*>(item);
635 if ( !attitem || !attitem->attachment() ) return;
636
637 KCal::Attachment *att = attitem->attachment();
639}
640
641void KOEditorAttachments::saveAttachment( TQIconViewItem *item )
642{
643 AttachmentListItem *attitem = static_cast<AttachmentListItem*>(item);
644 if ( !attitem || !attitem->attachment() ) return;
645
646 KCal::Attachment *att = attitem->attachment();
648}
649
650void KOEditorAttachments::slotAdd()
651{
652 AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
653
654 AttachmentEditDialog *dlg = new AttachmentEditDialog( item, mAttachments )
655;
656 if ( dlg->exec() == KDialog::Rejected ) {
657 delete item;
658 }
659 delete dlg;
660}
661
662void KOEditorAttachments::slotAddData()
663{
664 KURL uri = KFileDialog::getOpenFileName( TQString(), TQString(), this, i18n("Add Attachment") );
665 if ( !uri.isEmpty() ) {
666 TQString label = uri.fileName();
667 if ( label.isEmpty() ) {
668 label = uri.prettyURL();
669 }
670 addUriAttachment( uri.url(), TQString(), label, true );
671 }
672}
673
674void KOEditorAttachments::slotEdit()
675{
676 for ( TQIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) {
677 if ( item->isSelected() ) {
678 AttachmentListItem *attitem = static_cast<AttachmentListItem*>( item );
679 if ( !attitem || !attitem->attachment() ) {
680 return;
681 }
682
683 AttachmentEditDialog *dialog = new AttachmentEditDialog( attitem, mAttachments );
684 dialog->mInline->setEnabled( false );
685 dialog->setModal( false );
686 connect( dialog, TQ_SIGNAL(hidden()), dialog, TQ_SLOT(delayedDestruct()) );
687 dialog->show();
688 }
689 }
690}
691
692void KOEditorAttachments::slotRemove()
693{
694 TQValueList<TQIconViewItem*> selected;
695 TQStringList labels;
696 for ( TQIconViewItem *it = mAttachments->firstItem( ); it; it = it->nextItem( ) ) {
697 if ( !it->isSelected() ) continue;
698 selected << it;
699
700 AttachmentListItem *attitem = static_cast<AttachmentListItem*>(it);
701 KCal::Attachment *att = attitem->attachment();
702 labels << att->label();
703 }
704
705 if ( selected.isEmpty() ) {
706 return;
707 }
708
709 TQString labelsStr = labels.join( "<br>" );
710
711 if ( KMessageBox::questionYesNo(
712 this,
713 i18n( "<qt>Do you really want to remove these attachments?<p>%1</qt>" ).arg( labelsStr ),
714 i18n( "Remove Attachment?" ),
715 KStdGuiItem::yes(), KStdGuiItem::no(),
716 "calendarRemoveAttachments" ) != KMessageBox::Yes ) {
717 return;
718 }
719
720 for ( TQValueList<TQIconViewItem*>::iterator it( selected.begin() ), end( selected.end() );
721 it != end ; ++it ) {
722 if ( (*it)->nextItem() ) {
723 (*it)->nextItem()->setSelected( true );
724 } else if ( (*it)->prevItem() ) {
725 (*it)->prevItem()->setSelected( true );
726 }
727 delete *it;
728 }
729 mAttachments->slotUpdate();
730}
731
732void KOEditorAttachments::slotShow()
733{
734 for ( TQIconViewItem *it = mAttachments->firstItem(); it; it = it->nextItem() ) {
735 if ( !it->isSelected() )
736 continue;
737 showAttachment( it );
738 }
739}
740
741void KOEditorAttachments::slotSaveAs()
742{
743 for ( TQIconViewItem *it = mAttachments->firstItem(); it; it = it->nextItem() ) {
744 if ( !it->isSelected() )
745 continue;
746 saveAttachment( it );
747 }
748}
749
750void KOEditorAttachments::setDefaults()
751{
752 mAttachments->clear();
753}
754
755TQString KOEditorAttachments::randomString(int length) const
756{
757 if (length <=0 ) return TQString();
758
759 TQString str; str.setLength( length );
760 int i = 0;
761 while (length--)
762 {
763 int r=random() % 62;
764 r+=48;
765 if (r>57) r+=7;
766 if (r>90) r+=6;
767 str[i++] = char(r);
768 // so what if I work backwards?
769 }
770 return str;
771}
772
773void KOEditorAttachments::addUriAttachment( const TQString &uri,
774 const TQString &mimeType,
775 const TQString &label,
776 bool inLine )
777{
778 if ( !inLine ) {
779 AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
780 item->setUri( uri );
781 item->setLabel( label );
782 if ( mimeType.isEmpty() ) {
783 if ( uri.startsWith( TDEPIMPROTOCOL_CONTACT ) ) {
784 item->setMimeType( "text/directory" );
785 } else if ( uri.startsWith( TDEPIMPROTOCOL_EMAIL ) ) {
786 item->setMimeType( "message/rfc822" );
787 } else if ( uri.startsWith( TDEPIMPROTOCOL_INCIDENCE ) ) {
788 item->setMimeType( "text/calendar" );
789 } else if ( uri.startsWith( TDEPIMPROTOCOL_NEWSARTICLE ) ) {
790 item->setMimeType( "message/news" );
791 } else {
792 item->setMimeType( KMimeType::findByURL( uri )->name() );
793 }
794 }
795 } else {
796 TQString tmpFile;
797 if ( TDEIO::NetAccess::download( uri, tmpFile, this ) ) {
798 TQFile f( tmpFile );
799 if ( !f.open( IO_ReadOnly ) ) {
800 return;
801 }
802 const TQByteArray data = f.readAll();
803 f.close();
804 addDataAttachment( data, mimeType, label );
805 }
806 TDEIO::NetAccess::removeTempFile( tmpFile );
807 }
808}
809
810void KOEditorAttachments::addDataAttachment( const TQByteArray &data,
811 const TQString &mimeType,
812 const TQString &label )
813{
814 AttachmentListItem *item = new AttachmentListItem( 0, mAttachments );
815
816 TQString nlabel = label;
817 if ( mimeType == "message/rfc822" ) {
818 // mail message. try to set the label from the mail Subject:
819 KMime::Message msg;
820 msg.setContent( data.data() );
821 msg.parse();
822 nlabel = msg.subject()->asUnicodeString();
823 }
824
825 item->setData( data );
826 item->setLabel( nlabel );
827 if ( mimeType.isEmpty() ) {
828 item->setMimeType( KMimeType::findByContent( data )->name() );
829 } else {
830 item->setMimeType( mimeType );
831 }
832}
833
834void KOEditorAttachments::addAttachment( KCal::Attachment *attachment )
835{
836 new AttachmentListItem( attachment, mAttachments );
837}
838
839void KOEditorAttachments::readIncidence( KCal::Incidence *i )
840{
841 mAttachments->clear();
842
843 KCal::Attachment::List attachments = i->attachments();
844 KCal::Attachment::List::ConstIterator it;
845 for( it = attachments.begin(); it != attachments.end(); ++it ) {
846 addAttachment( (*it) );
847 }
848 if ( mAttachments->count() > 0 ) {
849 TQTimer::singleShot( 0, mAttachments, TQ_SLOT(arrangeItemsInGrid()) );
850 }
851}
852
853void KOEditorAttachments::writeIncidence( KCal::Incidence *i )
854{
855 i->clearAttachments();
856
857 TQIconViewItem *item;
858 AttachmentListItem *attitem;
859 for( item = mAttachments->firstItem(); item; item = item->nextItem() ) {
860 attitem = static_cast<AttachmentListItem*>(item);
861 if ( attitem )
862 i->addAttachment( new KCal::Attachment( *(attitem->attachment() ) ) );
863 }
864}
865
866
867void KOEditorAttachments::slotCopy()
868{
869 TQApplication::clipboard()->setData( mAttachments->mimeData(), TQClipboard::Clipboard );
870}
871
872void KOEditorAttachments::slotCut()
873{
874 slotCopy();
875 slotRemove();
876}
877
878void KOEditorAttachments::slotPaste()
879{
880 handlePasteOrDrop( TQApplication::clipboard()->data() );
881}
882
883void KOEditorAttachments::selectionChanged()
884{
885 bool selected = false;
886 for ( TQIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) {
887 if ( item->isSelected() ) {
888 selected = true;
889 break;
890 }
891 }
892 mRemoveBtn->setEnabled( selected );
893}
894
895void KOEditorAttachments::contextMenu(TQIconViewItem * item, const TQPoint & pos)
896{
897 const bool enable = item != 0;
898
899 int numSelected = 0;
900 for ( TQIconViewItem *item = mAttachments->firstItem(); item; item = item->nextItem() ) {
901 if ( item->isSelected() ) {
902 numSelected++;
903 }
904 }
905
906 mOpenAction->setEnabled( enable );
907 //TODO: support saving multiple attachments into a directory
908 mSaveAsAction->setEnabled( enable && numSelected == 1 );
909 mCopyAction->setEnabled( enable && numSelected == 1 );
910 mCutAction->setEnabled( enable && numSelected == 1 );
911 mDeleteAction->setEnabled( enable );
912 mEditAction->setEnabled( enable );
913 mContextMenu->exec( pos );
914}
915
916#include "koeditorattachments.moc"
void addAttachment(Attachment *attachment)
void clearAttachments()
Attachment::List attachments() const
bool view(TQWidget *parent, Attachment *attachment)
bool saveAs(TQWidget *parent, Attachment *attachment)