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