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