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