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
57KMMimePartTree::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
85static const char configGroup[] = "MimePartTree";
86
87KMMimePartTree::~KMMimePartTree() {
88 saveLayout( KMKernel::config(), configGroup );
89}
90
91
92void 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
111void 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
123void 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//-----------------------------------------------------------------------------
168void KMMimePartTree::slotSaveAs()
169{
170 saveSelectedBodyParts( false );
171}
172
173//-----------------------------------------------------------------------------
174void KMMimePartTree::slotSaveAsEncoded()
175{
176 saveSelectedBodyParts( true );
177}
178
179//-----------------------------------------------------------------------------
180void 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//-----------------------------------------------------------------------------
201void 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//-----------------------------------------------------------------------------
213void 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//-----------------------------------------------------------------------------
229void KMMimePartTree::styleChange( TQStyle& oldStyle )
230{
231 setStyleDependantFrameWidth();
232 TDEListView::styleChange( oldStyle );
233}
234
235//-----------------------------------------------------------------------------
236void 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
253void 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
261void 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
269void KMMimePartTree::slotOpen()
270{
271 startHandleAttachmentCommand( KMHandleAttachmentCommand::Open );
272}
273
274void KMMimePartTree::slotOpenWith()
275{
276 startHandleAttachmentCommand( KMHandleAttachmentCommand::OpenWith );
277}
278
279void KMMimePartTree::slotView()
280{
281 startHandleAttachmentCommand( KMHandleAttachmentCommand::View );
282}
283
284void KMMimePartTree::slotProperties()
285{
286 startHandleAttachmentCommand( KMHandleAttachmentCommand::Properties );
287}
288
289void 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
304void 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//=============================================================================
317KMMimePartTreeItem::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
336KMMimePartTreeItem::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
362void 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
379void 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