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 
73 class 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 
166 AttachmentEditDialog::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 
243 void 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 
297 void AttachmentEditDialog::accept()
298 {
299  slotApply();
300  KDialog::accept();
301 }
302 
303 void AttachmentEditDialog::urlChanged( const TQString &url )
304 {
305  enableButton( Ok, !url.isEmpty() );
306 }
307 
308 void 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 
316 AttachmentIconView::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 
331 KURL 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 
355 TQDragObject *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 
386 AttachmentIconView::~AttachmentIconView()
387 {
388  for ( std::set<KTempDir*>::iterator it = mTempDirs.begin() ; it != mTempDirs.end() ; ++it ) {
389  delete *it;
390  }
391 }
392 
393 TQDragObject * 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 
423 void AttachmentIconView::handleDrop( TQDropEvent *event, const TQValueList<TQIconDragItem> & list )
424 {
425  Q_UNUSED( list );
426  mParent->handlePasteOrDrop( event );
427 }
428 
429 
430 void AttachmentIconView::dragMoveEvent( TQDragMoveEvent *event )
431 {
432  mParent->dragMoveEvent( event );
433 }
434 
435 void AttachmentIconView::contentsDragMoveEvent( TQDragMoveEvent *event )
436 {
437  mParent->dragMoveEvent( event );
438 }
439 
440 void AttachmentIconView::contentsDragEnterEvent( TQDragEnterEvent *event )
441 {
442  mParent->dragMoveEvent( event );
443 }
444 
445 void AttachmentIconView::dragEnterEvent( TQDragEnterEvent *event )
446 {
447  mParent->dragEnterEvent( event );
448 }
449 
450 KOEditorAttachments::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 
522 KOEditorAttachments::~KOEditorAttachments()
523 {
524 }
525 
526 bool KOEditorAttachments::hasAttachments()
527 {
528  return mAttachments->count() != 0;
529 }
530 
531 void 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 
539 void KOEditorAttachments::dragEnterEvent( TQDragEnterEvent* event )
540 {
541  dragMoveEvent( event );
542 }
543 
544 void 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 
635 void KOEditorAttachments::dropEvent( TQDropEvent* event )
636 {
637  handlePasteOrDrop( event );
638 }
639 
640 void 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();
646  KCal::AttachmentHandler::view( this, att );
647 }
648 
649 void 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();
655  KCal::AttachmentHandler::saveAs( this, att );
656 }
657 
658 void 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 
670 void 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 
682 void 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 
700 void 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 
740 void 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 
749 void 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 
758 void KOEditorAttachments::setDefaults()
759 {
760  mAttachments->clear();
761 }
762 
763 TQString 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 
781 void 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 
818 void 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 
842 void KOEditorAttachments::addAttachment( KCal::Attachment *attachment )
843 {
844  new AttachmentListItem( attachment, mAttachments );
845 }
846 
847 void 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 
861 void 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 
875 void KOEditorAttachments::slotCopy()
876 {
877  TQApplication::clipboard()->setData( mAttachments->mimeData(), TQClipboard::Clipboard );
878 }
879 
880 void KOEditorAttachments::slotCut()
881 {
882  slotCopy();
883  slotRemove();
884 }
885 
886 void KOEditorAttachments::slotPaste()
887 {
888  handlePasteOrDrop( TQApplication::clipboard()->data() );
889 }
890 
891 void 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 
903 void 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)