kmail

kmmimeparttree.cpp

00001 /* -*- c++ -*-
00002     kmmimeparttree.h A MIME part tree viwer.
00003 
00004     This file is part of KMail, the KDE mail client.
00005     Copyright (c) 2002-2004 Klarälvdalens Datakonsult AB
00006 
00007     KMail is free software; you can redistribute it and/or modify it
00008     under the terms of the GNU General Public License, version 2, as
00009     published by the Free Software Foundation.
00010 
00011     KMail is distributed in the hope that it will be useful, but
00012     WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00019 
00020     In addition, as a special exception, the copyright holders give
00021     permission to link the code of this program with any edition of
00022     the Qt library by Trolltech AS, Norway (or with modified versions
00023     of Qt that use the same license as Qt), and distribute linked
00024     combinations including the two.  You must obey the GNU General
00025     Public License in all respects for all of the code used other than
00026     Qt.  If you modify this file, you may extend this exception to
00027     your version of the file, but you are not obligated to do so.  If
00028     you do not wish to do so, delete this exception statement from
00029     your version.
00030 */
00031 
00032 
00033 #include <config.h>
00034 
00035 #include "kmmimeparttree.h"
00036 
00037 #include "kmreaderwin.h"
00038 #include "partNode.h"
00039 #include "kmmsgpart.h"
00040 #include "kmkernel.h"
00041 #include "kmcommands.h"
00042 
00043 #include <kdebug.h>
00044 #include <klocale.h>
00045 #include <kfiledialog.h>
00046 #include <kmessagebox.h>
00047 #include <kiconloader.h>
00048 
00049 #include <tqclipboard.h>
00050 #include <tqheader.h>
00051 #include <tqpopupmenu.h>
00052 #include <tqstyle.h>
00053 #include <kurldrag.h>
00054 #include <kurl.h>
00055 
00056 
00057 KMMimePartTree::KMMimePartTree( KMReaderWin* readerWin,
00058                                 TQWidget* parent,
00059                                 const char* name )
00060     : KListView(  parent, name ),
00061       mReaderWin( readerWin ), mSizeColumn(0)
00062 {
00063     setStyleDependantFrameWidth();
00064     addColumn( i18n("Description") );
00065     addColumn( i18n("Type") );
00066     addColumn( i18n("Encoding") );
00067     mSizeColumn = addColumn( i18n("Size") );
00068     setColumnAlignment( 3, Qt::AlignRight );
00069 
00070     restoreLayoutIfPresent();
00071     connect( this, TQT_SIGNAL( clicked( TQListViewItem* ) ),
00072              this, TQT_SLOT( itemClicked( TQListViewItem* ) ) );
00073     connect( this, TQT_SIGNAL( contextMenuRequested( TQListViewItem*,
00074                                                  const TQPoint&, int ) ),
00075              this, TQT_SLOT( itemRightClicked( TQListViewItem*, const TQPoint& ) ) );
00076     setSelectionMode( TQListView::Extended );
00077     setRootIsDecorated( false );
00078     setAllColumnsShowFocus( true );
00079     setShowToolTips( true );
00080     setSorting(-1);
00081     setDragEnabled( true );
00082 }
00083 
00084 
00085 static const char configGroup[] = "MimePartTree";
00086 
00087 KMMimePartTree::~KMMimePartTree() {
00088   saveLayout( KMKernel::config(), configGroup );
00089 }
00090 
00091 
00092 void KMMimePartTree::restoreLayoutIfPresent() {
00093   // first column: soaks up the rest of the space:
00094   setColumnWidthMode( 0, Manual );
00095   header()->setStretchEnabled( true, 0 );
00096   // rest of the columns:
00097   if ( KMKernel::config()->hasGroup( configGroup ) ) {
00098     // there is a saved layout. use it...
00099     restoreLayout( KMKernel::config(), configGroup );
00100     // and disable Maximum mode:
00101     for ( int i = 1 ; i < 4 ; ++i )
00102       setColumnWidthMode( i, Manual );
00103   } else {
00104     // columns grow with their contents:
00105     for ( int i = 1 ; i < 4 ; ++i )
00106       setColumnWidthMode( i, Maximum );
00107   }
00108 }
00109 
00110 
00111 void KMMimePartTree::itemClicked( TQListViewItem* item )
00112 {
00113   if ( const KMMimePartTreeItem * i = dynamic_cast<KMMimePartTreeItem*>( item ) ) {
00114     if( mReaderWin->mRootNode == i->node() )
00115       mReaderWin->update( true ); // Force update
00116     else
00117       mReaderWin->setMsgPart( i->node() );
00118   } else
00119     kdWarning(5006) << "Item was not a KMMimePartTreeItem!" << endl;
00120 }
00121 
00122 
00123 void KMMimePartTree::itemRightClicked( TQListViewItem* item,
00124                                        const TQPoint& point )
00125 {
00126     // TODO: remove this member var?
00127     mCurrentContextMenuItem = dynamic_cast<KMMimePartTreeItem*>( item );
00128     if ( 0 == mCurrentContextMenuItem ) {
00129         kdDebug(5006) << "Item was not a KMMimePartTreeItem!" << endl;
00130     }
00131     else {
00132         TQPopupMenu* popup = new TQPopupMenu;
00133         if ( mCurrentContextMenuItem->node()->nodeId() > 2 &&
00134              mCurrentContextMenuItem->node()->typeString() != "Multipart" ) {
00135           popup->insertItem( SmallIcon("fileopen"), i18n("to open", "Open"), this, TQT_SLOT(slotOpen()) );
00136           popup->insertItem( i18n("Open With..."), this, TQT_SLOT(slotOpenWith()) );
00137           popup->insertItem( i18n("to view something", "View"), this, TQT_SLOT(slotView()) );
00138         }
00139         popup->insertItem( SmallIcon("filesaveas"),i18n( "Save &As..." ), this, TQT_SLOT( slotSaveAs() ) );
00140         /*
00141          * FIXME mkae optional?
00142         popup->insertItem( i18n( "Save as &Encoded..." ), this,
00143                            TQT_SLOT( slotSaveAsEncoded() ) );
00144         */
00145         popup->insertItem( i18n( "Save All Attachments..." ), this,
00146                            TQT_SLOT( slotSaveAll() ) );
00147         // edit + delete only for attachments
00148         if ( mCurrentContextMenuItem->node()->nodeId() > 2 &&
00149              mCurrentContextMenuItem->node()->typeString() != "Multipart" ) {
00150           popup->insertItem( SmallIcon("editcopy"), i18n("Copy"), this, TQT_SLOT(slotCopy()) );
00151           if ( GlobalSettings::self()->allowAttachmentDeletion() )
00152             popup->insertItem( SmallIcon("editdelete"), i18n( "Delete Attachment" ),
00153                                this, TQT_SLOT( slotDelete() ) );
00154           if ( GlobalSettings::self()->allowAttachmentEditing() )
00155             popup->insertItem( SmallIcon( "edit" ), i18n( "Edit Attachment" ),
00156                                this, TQT_SLOT( slotEdit() ) );
00157         }
00158         if ( mCurrentContextMenuItem->node()->nodeId() > 0 )
00159           popup->insertItem( i18n("Properties"), this, TQT_SLOT(slotProperties()) );
00160         popup->exec( point );
00161         delete popup;
00162         mCurrentContextMenuItem = 0;
00163     }
00164 }
00165 
00166 //-----------------------------------------------------------------------------
00167 void KMMimePartTree::slotSaveAs()
00168 {
00169   saveSelectedBodyParts( false );
00170 }
00171 
00172 //-----------------------------------------------------------------------------
00173 void KMMimePartTree::slotSaveAsEncoded()
00174 {
00175   saveSelectedBodyParts( true );
00176 }
00177 
00178 //-----------------------------------------------------------------------------
00179 void KMMimePartTree::saveSelectedBodyParts( bool encoded )
00180 {
00181   TQPtrList<TQListViewItem> selected = selectedItems();
00182 
00183   Q_ASSERT( !selected.isEmpty() );
00184   if ( selected.isEmpty() )
00185     return;
00186 
00187   TQPtrListIterator<TQListViewItem> it( selected );
00188   TQPtrList<partNode> parts;
00189   while ( it.current() ) {
00190     parts.append( static_cast<KMMimePartTreeItem *>(it.current())->node() );
00191     ++it;
00192   }
00193   mReaderWin->setUpdateAttachment();
00194   KMSaveAttachmentsCommand *command =
00195     new KMSaveAttachmentsCommand( this, parts, mReaderWin->message(), encoded );
00196   command->start();
00197 }
00198 
00199 //-----------------------------------------------------------------------------
00200 void KMMimePartTree::slotSaveAll()
00201 {
00202     if( childCount() == 0)
00203         return;
00204 
00205     mReaderWin->setUpdateAttachment();
00206     KMCommand *command =
00207       new KMSaveAttachmentsCommand( this, mReaderWin->message() );
00208     command->start();
00209 }
00210 
00211 //-----------------------------------------------------------------------------
00212 void KMMimePartTree::setStyleDependantFrameWidth()
00213 {
00214   // set the width of the frame to a reasonable value for the current GUI style
00215   int frameWidth;
00216   if( style().isA("KeramikStyle") )
00217     frameWidth = style().pixelMetric( TQStyle::PM_DefaultFrameWidth ) - 1;
00218   else
00219     frameWidth = style().pixelMetric( TQStyle::PM_DefaultFrameWidth );
00220   if ( frameWidth < 0 )
00221     frameWidth = 0;
00222   if ( frameWidth != lineWidth() )
00223     setLineWidth( frameWidth );
00224 }
00225 
00226 
00227 //-----------------------------------------------------------------------------
00228 void KMMimePartTree::styleChange( TQStyle& oldStyle )
00229 {
00230   setStyleDependantFrameWidth();
00231   KListView::styleChange( oldStyle );
00232 }
00233 
00234 //-----------------------------------------------------------------------------
00235 void KMMimePartTree::correctSize( TQListViewItem * item )
00236 {
00237   if (!item) return;
00238 
00239   KIO::filesize_t totalSize = 0;
00240   TQListViewItem * myChild = item->firstChild();
00241   while ( myChild )
00242   {
00243     totalSize += static_cast<KMMimePartTreeItem*>(myChild)->origSize();
00244     myChild = myChild->nextSibling();
00245   }
00246   if ( totalSize > static_cast<KMMimePartTreeItem*>(item)->origSize() )
00247     item->setText( mSizeColumn, KIO::convertSize(totalSize) );
00248   if ( item->parent() )
00249     correctSize( item->parent() );
00250 }
00251 
00252 void KMMimePartTree::slotDelete()
00253 {
00254   TQPtrList<TQListViewItem> selected = selectedItems();
00255   if ( selected.count() != 1 )
00256     return;
00257   mReaderWin->slotDeleteAttachment( static_cast<KMMimePartTreeItem*>( selected.first() )->node() );
00258 }
00259 
00260 void KMMimePartTree::slotEdit()
00261 {
00262   TQPtrList<TQListViewItem> selected = selectedItems();
00263   if ( selected.count() != 1 )
00264     return;
00265   mReaderWin->slotEditAttachment( static_cast<KMMimePartTreeItem*>( selected.first() )->node() );
00266 }
00267 
00268 void KMMimePartTree::slotOpen()
00269 {
00270   startHandleAttachmentCommand( KMHandleAttachmentCommand::Open );
00271 }
00272 
00273 void KMMimePartTree::slotOpenWith()
00274 {
00275   startHandleAttachmentCommand( KMHandleAttachmentCommand::OpenWith );
00276 }
00277 
00278 void KMMimePartTree::slotView()
00279 {
00280   startHandleAttachmentCommand( KMHandleAttachmentCommand::View );
00281 }
00282 
00283 void KMMimePartTree::slotProperties()
00284 {
00285   startHandleAttachmentCommand( KMHandleAttachmentCommand::Properties );
00286 }
00287 
00288 void KMMimePartTree::startHandleAttachmentCommand(int type)
00289 {
00290   TQPtrList<TQListViewItem> selected = selectedItems();
00291   if ( selected.count() != 1 )
00292     return;
00293   partNode* node = static_cast<KMMimePartTreeItem*>( selected.first() )->node();
00294   TQString name = mReaderWin->tempFileUrlFromPartNode( node ).path();
00295   KMHandleAttachmentCommand* command = new KMHandleAttachmentCommand(
00296       node, mReaderWin->message(), node->nodeId(), name,
00297       KMHandleAttachmentCommand::AttachmentAction( type ), 0, this );
00298   connect( command, TQT_SIGNAL( showAttachment( int, const TQString& ) ),
00299            mReaderWin, TQT_SLOT( slotAtmView( int, const TQString& ) ) );
00300   command->start();
00301 }
00302 
00303 void KMMimePartTree::slotCopy()
00304 {
00305   KURL::List urls;
00306   KMMimePartTreeItem *item = static_cast<KMMimePartTreeItem*>( currentItem() );
00307   if ( !item ) return;
00308   KURL url = mReaderWin->tempFileUrlFromPartNode( item->node() );
00309   if ( !url.isValid() ) return;
00310   urls.append( url );
00311   KURLDrag* drag = new KURLDrag( urls, this );
00312   TQApplication::clipboard()->setData( drag, QClipboard::Clipboard );
00313 }
00314 
00315 //=============================================================================
00316 KMMimePartTreeItem::KMMimePartTreeItem( KMMimePartTree * parent,
00317                                         partNode* node,
00318                                         const TQString & description,
00319                                         const TQString & mimetype,
00320                                         const TQString & encoding,
00321                                         KIO::filesize_t size )
00322   : TQListViewItem( parent, description,
00323            TQString::null, // set by setIconAndTextForType()
00324            encoding,
00325            KIO::convertSize( size ) ),
00326     mPartNode( node ), mOrigSize(size)
00327 {
00328   if( node )
00329     node->setMimePartTreeItem( this );
00330   setIconAndTextForType( mimetype );
00331   if ( parent )
00332     parent->correctSize(this);
00333 }
00334 
00335 KMMimePartTreeItem::KMMimePartTreeItem( KMMimePartTreeItem * parent,
00336                                         partNode* node,
00337                                         const TQString & description,
00338                                         const TQString & mimetype,
00339                                         const TQString & encoding,
00340                                         KIO::filesize_t size,
00341                                         bool revertOrder )
00342   : TQListViewItem( parent, description,
00343            TQString::null, // set by setIconAndTextForType()
00344            encoding,
00345            KIO::convertSize( size ) ),
00346     mPartNode( node ), mOrigSize(size)
00347 {
00348   if( revertOrder && nextSibling() ){
00349     TQListViewItem* sib = nextSibling();
00350     while( sib->nextSibling() )
00351       sib = sib->nextSibling();
00352     moveItem( sib );
00353   }
00354   if( node )
00355     node->setMimePartTreeItem( this );
00356   setIconAndTextForType( mimetype );
00357   if ( listView() )
00358     static_cast<KMMimePartTree*>(listView())->correctSize(this);
00359 }
00360 
00361 void KMMimePartTreeItem::setIconAndTextForType( const TQString & mime )
00362 {
00363   TQString mimetype = mime.lower();
00364   if ( mimetype.startsWith( "multipart/" ) ) {
00365     setText( 1, mimetype );
00366     setPixmap( 0, SmallIcon("folder") );
00367   } else if ( mimetype == "application/octet-stream" ) {
00368     setText( 1, i18n("Unspecified Binary Data") ); // don't show "Unknown"...
00369     setPixmap( 0, SmallIcon("unknown") );
00370   } else {
00371     KMimeType::Ptr mtp = KMimeType::mimeType( mimetype );
00372     setText( 1, (mtp && !mtp->comment().isEmpty()) ? mtp->comment() : mimetype );
00373     setPixmap( 0, mtp ? mtp->pixmap( KIcon::Small) : SmallIcon("unknown") );
00374   }
00375 }
00376 
00377 
00378 void KMMimePartTree::startDrag()
00379 {
00380     KURL::List urls;
00381     KMMimePartTreeItem *item = static_cast<KMMimePartTreeItem*>( currentItem() );
00382     if ( !item ) return;
00383     partNode *node = item->node();
00384     if ( !node ) return;
00385     KURL url = mReaderWin->tempFileUrlFromPartNode( node );
00386     if (!url.isValid() ) return;
00387     urls.append( url );
00388     KURLDrag* drag = new KURLDrag( urls, this );
00389     drag->drag();
00390 }
00391 
00392 #include "kmmimeparttree.moc"
00393