kmail

kmmimeparttree.cpp
1 /*
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, TQ_SIGNAL( clicked( TQListViewItem* ) ),
72  this, TQ_SLOT( itemClicked( TQListViewItem* ) ) );
73  connect( this, TQ_SIGNAL( contextMenuRequested( TQListViewItem*,
74  const TQPoint&, int ) ),
75  this, TQ_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  mCurrentContextMenuItem->node()->subTypeString() == "HTML" ) {
136  popup->insertItem( SmallIcon("document-open"), i18n("to open", "Open"), this, TQ_SLOT(slotOpen()) );
137  popup->insertItem( i18n("Open With..."), this, TQ_SLOT(slotOpenWith()) );
138  popup->insertItem( i18n("to view something", "View"), this, TQ_SLOT(slotView()) );
139  }
140  popup->insertItem( SmallIcon("document-save-as"),i18n( "Save &As..." ), this, TQ_SLOT( slotSaveAs() ) );
141  /*
142  * FIXME mkae optional?
143  popup->insertItem( i18n( "Save as &Encoded..." ), this,
144  TQ_SLOT( slotSaveAsEncoded() ) );
145  */
146  popup->insertItem( i18n( "Save All Attachments..." ), this,
147  TQ_SLOT( slotSaveAll() ) );
148  // edit + delete only for attachments
149  if ( mCurrentContextMenuItem->node()->nodeId() > 2 &&
150  mCurrentContextMenuItem->node()->typeString() != "Multipart" ) {
151  popup->insertItem( SmallIcon("edit-copy"), i18n("Copy"), this, TQ_SLOT(slotCopy()) );
152  if ( GlobalSettings::self()->allowAttachmentDeletion() )
153  popup->insertItem( SmallIcon("edit-delete"), i18n( "Delete Attachment" ),
154  this, TQ_SLOT( slotDelete() ) );
155  if ( GlobalSettings::self()->allowAttachmentEditing() )
156  popup->insertItem( SmallIcon( "edit" ), i18n( "Edit Attachment" ),
157  this, TQ_SLOT( slotEdit() ) );
158  }
159  if ( mCurrentContextMenuItem->node()->nodeId() > 0 )
160  popup->insertItem( i18n("Properties"), this, TQ_SLOT(slotProperties()) );
161  popup->exec( point );
162  delete popup;
163  mCurrentContextMenuItem = 0;
164  }
165 }
166 
167 //-----------------------------------------------------------------------------
168 void KMMimePartTree::slotSaveAs()
169 {
170  saveSelectedBodyParts( false );
171 }
172 
173 //-----------------------------------------------------------------------------
174 void KMMimePartTree::slotSaveAsEncoded()
175 {
176  saveSelectedBodyParts( true );
177 }
178 
179 //-----------------------------------------------------------------------------
180 void KMMimePartTree::saveSelectedBodyParts( bool encoded )
181 {
182  TQPtrList<TQListViewItem> selected = selectedItems();
183 
184  Q_ASSERT( !selected.isEmpty() );
185  if ( selected.isEmpty() )
186  return;
187 
188  TQPtrListIterator<TQListViewItem> it( selected );
189  TQPtrList<partNode> parts;
190  while ( it.current() ) {
191  parts.append( static_cast<KMMimePartTreeItem *>(it.current())->node() );
192  ++it;
193  }
194  mReaderWin->setUpdateAttachment();
195  KMSaveAttachmentsCommand *command =
196  new KMSaveAttachmentsCommand( this, parts, mReaderWin->message(), encoded );
197  command->start();
198 }
199 
200 //-----------------------------------------------------------------------------
201 void KMMimePartTree::slotSaveAll()
202 {
203  if( childCount() == 0)
204  return;
205 
206  mReaderWin->setUpdateAttachment();
207  KMCommand *command =
208  new KMSaveAttachmentsCommand( this, mReaderWin->message() );
209  command->start();
210 }
211 
212 //-----------------------------------------------------------------------------
213 void KMMimePartTree::setStyleDependantFrameWidth()
214 {
215  // set the width of the frame to a reasonable value for the current GUI style
216  int frameWidth;
217  if( style().isA("KeramikStyle") )
218  frameWidth = style().pixelMetric( TQStyle::PM_DefaultFrameWidth ) - 1;
219  else
220  frameWidth = style().pixelMetric( TQStyle::PM_DefaultFrameWidth );
221  if ( frameWidth < 0 )
222  frameWidth = 0;
223  if ( frameWidth != lineWidth() )
224  setLineWidth( frameWidth );
225 }
226 
227 
228 //-----------------------------------------------------------------------------
229 void KMMimePartTree::styleChange( TQStyle& oldStyle )
230 {
231  setStyleDependantFrameWidth();
232  TDEListView::styleChange( oldStyle );
233 }
234 
235 //-----------------------------------------------------------------------------
236 void KMMimePartTree::correctSize( TQListViewItem * item )
237 {
238  if (!item) return;
239 
240  TDEIO::filesize_t totalSize = 0;
241  TQListViewItem * myChild = item->firstChild();
242  while ( myChild )
243  {
244  totalSize += static_cast<KMMimePartTreeItem*>(myChild)->origSize();
245  myChild = myChild->nextSibling();
246  }
247  if ( totalSize > static_cast<KMMimePartTreeItem*>(item)->origSize() )
248  item->setText( mSizeColumn, TDEIO::convertSize(totalSize) );
249  if ( item->parent() )
250  correctSize( item->parent() );
251 }
252 
253 void KMMimePartTree::slotDelete()
254 {
255  TQPtrList<TQListViewItem> selected = selectedItems();
256  if ( selected.count() != 1 )
257  return;
258  mReaderWin->slotDeleteAttachment( static_cast<KMMimePartTreeItem*>( selected.first() )->node() );
259 }
260 
261 void KMMimePartTree::slotEdit()
262 {
263  TQPtrList<TQListViewItem> selected = selectedItems();
264  if ( selected.count() != 1 )
265  return;
266  mReaderWin->slotEditAttachment( static_cast<KMMimePartTreeItem*>( selected.first() )->node() );
267 }
268 
269 void KMMimePartTree::slotOpen()
270 {
271  startHandleAttachmentCommand( KMHandleAttachmentCommand::Open );
272 }
273 
274 void KMMimePartTree::slotOpenWith()
275 {
276  startHandleAttachmentCommand( KMHandleAttachmentCommand::OpenWith );
277 }
278 
279 void KMMimePartTree::slotView()
280 {
281  startHandleAttachmentCommand( KMHandleAttachmentCommand::View );
282 }
283 
284 void KMMimePartTree::slotProperties()
285 {
286  startHandleAttachmentCommand( KMHandleAttachmentCommand::Properties );
287 }
288 
289 void KMMimePartTree::startHandleAttachmentCommand(int type)
290 {
291  TQPtrList<TQListViewItem> selected = selectedItems();
292  if ( selected.count() != 1 )
293  return;
294  partNode* node = static_cast<KMMimePartTreeItem*>( selected.first() )->node();
295  TQString name = mReaderWin->tempFileUrlFromPartNode( node ).path();
296  KMHandleAttachmentCommand* command = new KMHandleAttachmentCommand(
297  node, mReaderWin->message(), node->nodeId(), name,
298  KMHandleAttachmentCommand::AttachmentAction( type ), 0, this );
299  connect( command, TQ_SIGNAL( showAttachment( int, const TQString& ) ),
300  mReaderWin, TQ_SLOT( slotAtmView( int, const TQString& ) ) );
301  command->start();
302 }
303 
304 void KMMimePartTree::slotCopy()
305 {
306  KURL::List urls;
307  KMMimePartTreeItem *item = static_cast<KMMimePartTreeItem*>( currentItem() );
308  if ( !item ) return;
309  KURL url = mReaderWin->tempFileUrlFromPartNode( item->node() );
310  if ( !url.isValid() ) return;
311  urls.append( url );
312  KURLDrag* drag = new KURLDrag( urls, this );
313  TQApplication::clipboard()->setData( drag, TQClipboard::Clipboard );
314 }
315 
316 //=============================================================================
317 KMMimePartTreeItem::KMMimePartTreeItem( KMMimePartTree * parent,
318  partNode* node,
319  const TQString & description,
320  const TQString & mimetype,
321  const TQString & encoding,
322  TDEIO::filesize_t size )
323  : TQListViewItem( parent, description,
324  TQString(), // set by setIconAndTextForType()
325  encoding,
326  TDEIO::convertSize( size ) ),
327  mPartNode( node ), mOrigSize(size)
328 {
329  if( node )
330  node->setMimePartTreeItem( this );
331  setIconAndTextForType( mimetype );
332  if ( parent )
333  parent->correctSize(this);
334 }
335 
336 KMMimePartTreeItem::KMMimePartTreeItem( KMMimePartTreeItem * parent,
337  partNode* node,
338  const TQString & description,
339  const TQString & mimetype,
340  const TQString & encoding,
341  TDEIO::filesize_t size,
342  bool revertOrder )
343  : TQListViewItem( parent, description,
344  TQString(), // set by setIconAndTextForType()
345  encoding,
346  TDEIO::convertSize( size ) ),
347  mPartNode( node ), mOrigSize(size)
348 {
349  if( revertOrder && nextSibling() ){
350  TQListViewItem* sib = nextSibling();
351  while( sib->nextSibling() )
352  sib = sib->nextSibling();
353  moveItem( sib );
354  }
355  if( node )
356  node->setMimePartTreeItem( this );
357  setIconAndTextForType( mimetype );
358  if ( listView() )
359  static_cast<KMMimePartTree*>(listView())->correctSize(this);
360 }
361 
362 void KMMimePartTreeItem::setIconAndTextForType( const TQString & mime )
363 {
364  TQString mimetype = mime.lower();
365  if ( mimetype.startsWith( "multipart/" ) ) {
366  setText( 1, mimetype );
367  setPixmap( 0, SmallIcon("folder") );
368  } else if ( mimetype == "application/octet-stream" ) {
369  setText( 1, i18n("Unspecified Binary Data") ); // don't show "Unknown"...
370  setPixmap( 0, SmallIcon("unknown") );
371  } else {
372  KMimeType::Ptr mtp = KMimeType::mimeType( mimetype );
373  setText( 1, (mtp && !mtp->comment().isEmpty()) ? mtp->comment() : mimetype );
374  setPixmap( 0, mtp ? mtp->pixmap( TDEIcon::Small) : SmallIcon("unknown") );
375  }
376 }
377 
378 
379 void KMMimePartTree::startDrag()
380 {
381  KURL::List urls;
382  KMMimePartTreeItem *item = static_cast<KMMimePartTreeItem*>( currentItem() );
383  if ( !item ) return;
384  partNode *node = item->node();
385  if ( !node ) return;
386  KURL url = mReaderWin->tempFileUrlFromPartNode( node );
387  if (!url.isValid() ) return;
388  urls.append( url );
389  KURLDrag* drag = new KURLDrag( urls, this );
390  drag->drag();
391 }
392 
393 #include "kmmimeparttree.moc"
394 
This class implements a "reader window", that is a window used for reading or viewing messages.
Definition: kmreaderwin.h:75