kmail

kmmimeparttree.cpp
1 /* -*- c++ -*-
2  kmmimeparttree.h A MIME part tree viwer.
3 
4  This file is part of KMail, the KDE mail client.
5  Copyright (c) 2002-2004 Klarälvdalens Datakonsult AB
6 
7  KMail is free software; you can redistribute it and/or modify it
8  under the terms of the GNU General Public License, version 2, as
9  published by the Free Software Foundation.
10 
11  KMail is distributed in the hope that it will be useful, but
12  WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 
20  In addition, as a special exception, the copyright holders give
21  permission to link the code of this program with any edition of
22  the TQt library by Trolltech AS, Norway (or with modified versions
23  of TQt that use the same license as TQt), and distribute linked
24  combinations including the two. You must obey the GNU General
25  Public License in all respects for all of the code used other than
26  TQt. If you modify this file, you may extend this exception to
27  your version of the file, but you are not obligated to do so. If
28  you do not wish to do so, delete this exception statement from
29  your version.
30 */
31 
32 
33 #include <config.h>
34 
35 #include "kmmimeparttree.h"
36 
37 #include "kmreaderwin.h"
38 #include "partNode.h"
39 #include "kmmsgpart.h"
40 #include "kmkernel.h"
41 #include "kmcommands.h"
42 
43 #include <kdebug.h>
44 #include <tdelocale.h>
45 #include <tdefiledialog.h>
46 #include <tdemessagebox.h>
47 #include <kiconloader.h>
48 
49 #include <tqclipboard.h>
50 #include <tqheader.h>
51 #include <tqpopupmenu.h>
52 #include <tqstyle.h>
53 #include <kurldrag.h>
54 #include <kurl.h>
55 
56 
57 KMMimePartTree::KMMimePartTree( KMReaderWin* readerWin,
58  TQWidget* parent,
59  const char* name )
60  : TDEListView( parent, name ),
61  mReaderWin( readerWin ), mSizeColumn(0)
62 {
63  setStyleDependantFrameWidth();
64  addColumn( i18n("Description") );
65  addColumn( i18n("Type") );
66  addColumn( i18n("Encoding") );
67  mSizeColumn = addColumn( i18n("Size") );
68  setColumnAlignment( 3, TQt::AlignRight );
69 
70  restoreLayoutIfPresent();
71  connect( this, TQT_SIGNAL( clicked( TQListViewItem* ) ),
72  this, TQT_SLOT( itemClicked( TQListViewItem* ) ) );
73  connect( this, TQT_SIGNAL( contextMenuRequested( TQListViewItem*,
74  const TQPoint&, int ) ),
75  this, TQT_SLOT( itemRightClicked( TQListViewItem*, const TQPoint& ) ) );
76  setSelectionMode( TQListView::Extended );
77  setRootIsDecorated( false );
78  setAllColumnsShowFocus( true );
79  setShowToolTips( true );
80  setSorting(-1);
81  setDragEnabled( true );
82 }
83 
84 
85 static const char configGroup[] = "MimePartTree";
86 
87 KMMimePartTree::~KMMimePartTree() {
88  saveLayout( KMKernel::config(), configGroup );
89 }
90 
91 
92 void KMMimePartTree::restoreLayoutIfPresent() {
93  // first column: soaks up the rest of the space:
94  setColumnWidthMode( 0, Manual );
95  header()->setStretchEnabled( true, 0 );
96  // rest of the columns:
97  if ( KMKernel::config()->hasGroup( configGroup ) ) {
98  // there is a saved layout. use it...
99  restoreLayout( KMKernel::config(), configGroup );
100  // and disable Maximum mode:
101  for ( int i = 1 ; i < 4 ; ++i )
102  setColumnWidthMode( i, Manual );
103  } else {
104  // columns grow with their contents:
105  for ( int i = 1 ; i < 4 ; ++i )
106  setColumnWidthMode( i, Maximum );
107  }
108 }
109 
110 
111 void KMMimePartTree::itemClicked( TQListViewItem* item )
112 {
113  if ( const KMMimePartTreeItem * i = dynamic_cast<KMMimePartTreeItem*>( item ) ) {
114  if( mReaderWin->mRootNode == i->node() )
115  mReaderWin->update( true ); // Force update
116  else
117  mReaderWin->setMsgPart( i->node() );
118  } else
119  kdWarning(5006) << "Item was not a KMMimePartTreeItem!" << endl;
120 }
121 
122 
123 void KMMimePartTree::itemRightClicked( TQListViewItem* item,
124  const TQPoint& point )
125 {
126  // TODO: remove this member var?
127  mCurrentContextMenuItem = dynamic_cast<KMMimePartTreeItem*>( item );
128  if ( 0 == mCurrentContextMenuItem ) {
129  kdDebug(5006) << "Item was not a KMMimePartTreeItem!" << endl;
130  }
131  else {
132  TQPopupMenu* popup = new TQPopupMenu;
133  if ( mCurrentContextMenuItem->node()->nodeId() > 2 &&
134  mCurrentContextMenuItem->node()->typeString() != "Multipart" ) {
135  popup->insertItem( SmallIcon("document-open"), i18n("to open", "Open"), this, TQT_SLOT(slotOpen()) );
136  popup->insertItem( i18n("Open With..."), this, TQT_SLOT(slotOpenWith()) );
137  popup->insertItem( i18n("to view something", "View"), this, TQT_SLOT(slotView()) );
138  }
139  popup->insertItem( SmallIcon("document-save-as"),i18n( "Save &As..." ), this, TQT_SLOT( slotSaveAs() ) );
140  /*
141  * FIXME mkae optional?
142  popup->insertItem( i18n( "Save as &Encoded..." ), this,
143  TQT_SLOT( slotSaveAsEncoded() ) );
144  */
145  popup->insertItem( i18n( "Save All Attachments..." ), this,
146  TQT_SLOT( slotSaveAll() ) );
147  // edit + delete only for attachments
148  if ( mCurrentContextMenuItem->node()->nodeId() > 2 &&
149  mCurrentContextMenuItem->node()->typeString() != "Multipart" ) {
150  popup->insertItem( SmallIcon("edit-copy"), i18n("Copy"), this, TQT_SLOT(slotCopy()) );
151  if ( GlobalSettings::self()->allowAttachmentDeletion() )
152  popup->insertItem( SmallIcon("edit-delete"), i18n( "Delete Attachment" ),
153  this, TQT_SLOT( slotDelete() ) );
154  if ( GlobalSettings::self()->allowAttachmentEditing() )
155  popup->insertItem( SmallIcon( "edit" ), i18n( "Edit Attachment" ),
156  this, TQT_SLOT( slotEdit() ) );
157  }
158  if ( mCurrentContextMenuItem->node()->nodeId() > 0 )
159  popup->insertItem( i18n("Properties"), this, TQT_SLOT(slotProperties()) );
160  popup->exec( point );
161  delete popup;
162  mCurrentContextMenuItem = 0;
163  }
164 }
165 
166 //-----------------------------------------------------------------------------
167 void KMMimePartTree::slotSaveAs()
168 {
169  saveSelectedBodyParts( false );
170 }
171 
172 //-----------------------------------------------------------------------------
173 void KMMimePartTree::slotSaveAsEncoded()
174 {
175  saveSelectedBodyParts( true );
176 }
177 
178 //-----------------------------------------------------------------------------
179 void KMMimePartTree::saveSelectedBodyParts( bool encoded )
180 {
181  TQPtrList<TQListViewItem> selected = selectedItems();
182 
183  Q_ASSERT( !selected.isEmpty() );
184  if ( selected.isEmpty() )
185  return;
186 
187  TQPtrListIterator<TQListViewItem> it( selected );
188  TQPtrList<partNode> parts;
189  while ( it.current() ) {
190  parts.append( static_cast<KMMimePartTreeItem *>(it.current())->node() );
191  ++it;
192  }
193  mReaderWin->setUpdateAttachment();
194  KMSaveAttachmentsCommand *command =
195  new KMSaveAttachmentsCommand( this, parts, mReaderWin->message(), encoded );
196  command->start();
197 }
198 
199 //-----------------------------------------------------------------------------
200 void KMMimePartTree::slotSaveAll()
201 {
202  if( childCount() == 0)
203  return;
204 
205  mReaderWin->setUpdateAttachment();
206  KMCommand *command =
207  new KMSaveAttachmentsCommand( this, mReaderWin->message() );
208  command->start();
209 }
210 
211 //-----------------------------------------------------------------------------
212 void KMMimePartTree::setStyleDependantFrameWidth()
213 {
214  // set the width of the frame to a reasonable value for the current GUI style
215  int frameWidth;
216  if( style().isA("KeramikStyle") )
217  frameWidth = style().pixelMetric( TQStyle::PM_DefaultFrameWidth ) - 1;
218  else
219  frameWidth = style().pixelMetric( TQStyle::PM_DefaultFrameWidth );
220  if ( frameWidth < 0 )
221  frameWidth = 0;
222  if ( frameWidth != lineWidth() )
223  setLineWidth( frameWidth );
224 }
225 
226 
227 //-----------------------------------------------------------------------------
228 void KMMimePartTree::styleChange( TQStyle& oldStyle )
229 {
230  setStyleDependantFrameWidth();
231  TDEListView::styleChange( oldStyle );
232 }
233 
234 //-----------------------------------------------------------------------------
235 void KMMimePartTree::correctSize( TQListViewItem * item )
236 {
237  if (!item) return;
238 
239  TDEIO::filesize_t totalSize = 0;
240  TQListViewItem * myChild = item->firstChild();
241  while ( myChild )
242  {
243  totalSize += static_cast<KMMimePartTreeItem*>(myChild)->origSize();
244  myChild = myChild->nextSibling();
245  }
246  if ( totalSize > static_cast<KMMimePartTreeItem*>(item)->origSize() )
247  item->setText( mSizeColumn, TDEIO::convertSize(totalSize) );
248  if ( item->parent() )
249  correctSize( item->parent() );
250 }
251 
252 void KMMimePartTree::slotDelete()
253 {
254  TQPtrList<TQListViewItem> selected = selectedItems();
255  if ( selected.count() != 1 )
256  return;
257  mReaderWin->slotDeleteAttachment( static_cast<KMMimePartTreeItem*>( selected.first() )->node() );
258 }
259 
260 void KMMimePartTree::slotEdit()
261 {
262  TQPtrList<TQListViewItem> selected = selectedItems();
263  if ( selected.count() != 1 )
264  return;
265  mReaderWin->slotEditAttachment( static_cast<KMMimePartTreeItem*>( selected.first() )->node() );
266 }
267 
268 void KMMimePartTree::slotOpen()
269 {
270  startHandleAttachmentCommand( KMHandleAttachmentCommand::Open );
271 }
272 
273 void KMMimePartTree::slotOpenWith()
274 {
275  startHandleAttachmentCommand( KMHandleAttachmentCommand::OpenWith );
276 }
277 
278 void KMMimePartTree::slotView()
279 {
280  startHandleAttachmentCommand( KMHandleAttachmentCommand::View );
281 }
282 
283 void KMMimePartTree::slotProperties()
284 {
285  startHandleAttachmentCommand( KMHandleAttachmentCommand::Properties );
286 }
287 
288 void KMMimePartTree::startHandleAttachmentCommand(int type)
289 {
290  TQPtrList<TQListViewItem> selected = selectedItems();
291  if ( selected.count() != 1 )
292  return;
293  partNode* node = static_cast<KMMimePartTreeItem*>( selected.first() )->node();
294  TQString name = mReaderWin->tempFileUrlFromPartNode( node ).path();
295  KMHandleAttachmentCommand* command = new KMHandleAttachmentCommand(
296  node, mReaderWin->message(), node->nodeId(), name,
297  KMHandleAttachmentCommand::AttachmentAction( type ), 0, this );
298  connect( command, TQT_SIGNAL( showAttachment( int, const TQString& ) ),
299  mReaderWin, TQT_SLOT( slotAtmView( int, const TQString& ) ) );
300  command->start();
301 }
302 
303 void KMMimePartTree::slotCopy()
304 {
305  KURL::List urls;
306  KMMimePartTreeItem *item = static_cast<KMMimePartTreeItem*>( currentItem() );
307  if ( !item ) return;
308  KURL url = mReaderWin->tempFileUrlFromPartNode( item->node() );
309  if ( !url.isValid() ) return;
310  urls.append( url );
311  KURLDrag* drag = new KURLDrag( urls, this );
312  TQApplication::clipboard()->setData( drag, TQClipboard::Clipboard );
313 }
314 
315 //=============================================================================
316 KMMimePartTreeItem::KMMimePartTreeItem( KMMimePartTree * parent,
317  partNode* node,
318  const TQString & description,
319  const TQString & mimetype,
320  const TQString & encoding,
321  TDEIO::filesize_t size )
322  : TQListViewItem( parent, description,
323  TQString(), // set by setIconAndTextForType()
324  encoding,
325  TDEIO::convertSize( size ) ),
326  mPartNode( node ), mOrigSize(size)
327 {
328  if( node )
329  node->setMimePartTreeItem( this );
330  setIconAndTextForType( mimetype );
331  if ( parent )
332  parent->correctSize(this);
333 }
334 
335 KMMimePartTreeItem::KMMimePartTreeItem( KMMimePartTreeItem * parent,
336  partNode* node,
337  const TQString & description,
338  const TQString & mimetype,
339  const TQString & encoding,
340  TDEIO::filesize_t size,
341  bool revertOrder )
342  : TQListViewItem( parent, description,
343  TQString(), // set by setIconAndTextForType()
344  encoding,
345  TDEIO::convertSize( size ) ),
346  mPartNode( node ), mOrigSize(size)
347 {
348  if( revertOrder && nextSibling() ){
349  TQListViewItem* sib = nextSibling();
350  while( sib->nextSibling() )
351  sib = sib->nextSibling();
352  moveItem( sib );
353  }
354  if( node )
355  node->setMimePartTreeItem( this );
356  setIconAndTextForType( mimetype );
357  if ( listView() )
358  static_cast<KMMimePartTree*>(listView())->correctSize(this);
359 }
360 
361 void KMMimePartTreeItem::setIconAndTextForType( const TQString & mime )
362 {
363  TQString mimetype = mime.lower();
364  if ( mimetype.startsWith( "multipart/" ) ) {
365  setText( 1, mimetype );
366  setPixmap( 0, SmallIcon("folder") );
367  } else if ( mimetype == "application/octet-stream" ) {
368  setText( 1, i18n("Unspecified Binary Data") ); // don't show "Unknown"...
369  setPixmap( 0, SmallIcon("unknown") );
370  } else {
371  KMimeType::Ptr mtp = KMimeType::mimeType( mimetype );
372  setText( 1, (mtp && !mtp->comment().isEmpty()) ? mtp->comment() : mimetype );
373  setPixmap( 0, mtp ? mtp->pixmap( TDEIcon::Small) : SmallIcon("unknown") );
374  }
375 }
376 
377 
378 void KMMimePartTree::startDrag()
379 {
380  KURL::List urls;
381  KMMimePartTreeItem *item = static_cast<KMMimePartTreeItem*>( currentItem() );
382  if ( !item ) return;
383  partNode *node = item->node();
384  if ( !node ) return;
385  KURL url = mReaderWin->tempFileUrlFromPartNode( node );
386  if (!url.isValid() ) return;
387  urls.append( url );
388  KURLDrag* drag = new KURLDrag( urls, this );
389  drag->drag();
390 }
391 
392 #include "kmmimeparttree.moc"
393