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( "" );
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 
165 AttachmentEditDialog::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 
242 void 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 
287 void AttachmentEditDialog::accept()
288 {
289  slotApply();
290  KDialog::accept();
291 }
292 
293 void AttachmentEditDialog::urlChanged( const TQString &url )
294 {
295  enableButton( Ok, !url.isEmpty() );
296 }
297 
298 void 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 
306 AttachmentIconView::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 
321 KURL 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 
345 TQDragObject *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 
376 AttachmentIconView::~AttachmentIconView()
377 {
378  for ( std::set<KTempDir*>::iterator it = mTempDirs.begin() ; it != mTempDirs.end() ; ++it ) {
379  delete *it;
380  }
381 }
382 
383 TQDragObject * 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 
413 void AttachmentIconView::handleDrop( TQDropEvent *event, const TQValueList<TQIconDragItem> & list )
414 {
415  Q_UNUSED( list );
416  mParent->handlePasteOrDrop( event );
417 }
418 
419 
420 void AttachmentIconView::dragMoveEvent( TQDragMoveEvent *event )
421 {
422  mParent->dragMoveEvent( event );
423 }
424 
425 void AttachmentIconView::contentsDragMoveEvent( TQDragMoveEvent *event )
426 {
427  mParent->dragMoveEvent( event );
428 }
429 
430 void AttachmentIconView::contentsDragEnterEvent( TQDragEnterEvent *event )
431 {
432  mParent->dragMoveEvent( event );
433 }
434 
435 void AttachmentIconView::dragEnterEvent( TQDragEnterEvent *event )
436 {
437  mParent->dragEnterEvent( event );
438 }
439 
440 KOEditorAttachments::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 
512 KOEditorAttachments::~KOEditorAttachments()
513 {
514 }
515 
516 bool KOEditorAttachments::hasAttachments()
517 {
518  return mAttachments->count() != 0;
519 }
520 
521 void 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 
529 void KOEditorAttachments::dragEnterEvent( TQDragEnterEvent* event )
530 {
531  dragMoveEvent( event );
532 }
533 
534 void 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 
625 void KOEditorAttachments::dropEvent( TQDropEvent* event )
626 {
627  handlePasteOrDrop( event );
628 }
629 
630 void 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();
636  KCal::AttachmentHandler::view( this, att );
637 }
638 
639 void 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();
645  KCal::AttachmentHandler::saveAs( this, att );
646 }
647 
648 void 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 
660 void 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 
672 void 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 
690 void 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 
730 void 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 
739 void 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 
748 void KOEditorAttachments::setDefaults()
749 {
750  mAttachments->clear();
751 }
752 
753 TQString 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 
771 void 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 
808 void 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 
832 void KOEditorAttachments::addAttachment( KCal::Attachment *attachment )
833 {
834  new AttachmentListItem( attachment, mAttachments );
835 }
836 
837 void 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 
851 void 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 
865 void KOEditorAttachments::slotCopy()
866 {
867  TQApplication::clipboard()->setData( mAttachments->mimeData(), TQClipboard::Clipboard );
868 }
869 
870 void KOEditorAttachments::slotCut()
871 {
872  slotCopy();
873  slotRemove();
874 }
875 
876 void KOEditorAttachments::slotPaste()
877 {
878  handlePasteOrDrop( TQApplication::clipboard()->data() );
879 }
880 
881 void 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 
893 void 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"
bool saveAs(TQWidget *parent, Attachment *attachment)
bool view(TQWidget *parent, Attachment *attachment)