kmail

kmmimeparttree.cpp

Go to the documentation of this file.
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 <qclipboard.h>
00050 #include <qheader.h>
00051 #include <qpopupmenu.h>
00052 #include <qstyle.h>
00053 #include <kurldrag.h>
00054 #include <kurl.h>
00055 
00056 
00057 KMMimePartTree::KMMimePartTree( KMReaderWin* readerWin,
00058                                 QWidget* 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, SIGNAL( clicked( QListViewItem* ) ),
00072              this, SLOT( itemClicked( QListViewItem* ) ) );
00073     connect( this, SIGNAL( contextMenuRequested( QListViewItem*,
00074                                                  const QPoint&, int ) ),
00075              this, SLOT( itemRightClicked( QListViewItem*, const QPoint& ) ) );
00076     setSelectionMode( QListView::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( QListViewItem* 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( QListViewItem* item,
00124                                        const QPoint& 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         kdDebug(5006) << "\n**\n** KMMimePartTree::itemRightClicked() **\n**" << endl;
00133 
00134         QPopupMenu* popup = new QPopupMenu;
00135         if ( mCurrentContextMenuItem->node()->nodeId() > 2 &&
00136              mCurrentContextMenuItem->node()->typeString() != "Multipart" ) {
00137           popup->insertItem( SmallIcon("fileopen"), i18n("to open", "Open"), this, SLOT(slotOpen()) );
00138           popup->insertItem( i18n("Open With..."), this, SLOT(slotOpenWith()) );
00139           popup->insertItem( i18n("to view something", "View"), this, SLOT(slotView()) );
00140         }
00141         popup->insertItem( SmallIcon("filesaveas"),i18n( "Save &As..." ), this, SLOT( slotSaveAs() ) );
00142         /*
00143          * FIXME mkae optional?
00144         popup->insertItem( i18n( "Save as &Encoded..." ), this,
00145                            SLOT( slotSaveAsEncoded() ) );
00146         */
00147         popup->insertItem( i18n( "Save All Attachments..." ), this,
00148                            SLOT( slotSaveAll() ) );
00149         // edit + delete only for attachments
00150         if ( mCurrentContextMenuItem->node()->nodeId() > 2 &&
00151              mCurrentContextMenuItem->node()->typeString() != "Multipart" ) {
00152           popup->insertItem( SmallIcon("editcopy"), i18n("Copy"), this, SLOT(slotCopy()) );
00153           if ( GlobalSettings::self()->allowAttachmentDeletion() )
00154             popup->insertItem( SmallIcon("editdelete"), i18n( "Delete Attachment" ),
00155                                this, SLOT( slotDelete() ) );
00156           if ( GlobalSettings::self()->allowAttachmentEditing() )
00157             popup->insertItem( SmallIcon( "edit" ), i18n( "Edit Attachment" ),
00158                                this, SLOT( slotEdit() ) );
00159         }
00160         if ( mCurrentContextMenuItem->node()->nodeId() > 0 )
00161           popup->insertItem( i18n("Properties"), this, SLOT(slotProperties()) );
00162         popup->exec( point );
00163         delete popup;
00164         mCurrentContextMenuItem = 0;
00165     }
00166 }
00167 
00168 //-----------------------------------------------------------------------------
00169 void KMMimePartTree::slotSaveAs()
00170 {
00171   saveSelectedBodyParts( false );
00172 }
00173 
00174 //-----------------------------------------------------------------------------
00175 void KMMimePartTree::slotSaveAsEncoded()
00176 {
00177   saveSelectedBodyParts( true );
00178 }
00179 
00180 //-----------------------------------------------------------------------------
00181 void KMMimePartTree::saveSelectedBodyParts( bool encoded )
00182 {
00183   QPtrList<QListViewItem> selected = selectedItems();
00184 
00185   Q_ASSERT( !selected.isEmpty() );
00186   if ( selected.isEmpty() )
00187     return;
00188 
00189   QPtrListIterator<QListViewItem> it( selected );
00190   QPtrList<partNode> parts;
00191   while ( it.current() ) {
00192     parts.append( static_cast<KMMimePartTreeItem *>(it.current())->node() );
00193     ++it;
00194   }
00195   mReaderWin->setUpdateAttachment();
00196   KMSaveAttachmentsCommand *command =
00197     new KMSaveAttachmentsCommand( this, parts, mReaderWin->message(), encoded );
00198   command->start();
00199 }
00200 
00201 //-----------------------------------------------------------------------------
00202 void KMMimePartTree::slotSaveAll()
00203 {
00204     if( childCount() == 0)
00205         return;
00206 
00207     mReaderWin->setUpdateAttachment();
00208     KMCommand *command =
00209       new KMSaveAttachmentsCommand( this, mReaderWin->message() );
00210     command->start();
00211 }
00212 
00213 //-----------------------------------------------------------------------------
00214 void KMMimePartTree::setStyleDependantFrameWidth()
00215 {
00216   // set the width of the frame to a reasonable value for the current GUI style
00217   int frameWidth;
00218   if( style().isA("KeramikStyle") )
00219     frameWidth = style().pixelMetric( QStyle::PM_DefaultFrameWidth ) - 1;
00220   else
00221     frameWidth = style().pixelMetric( QStyle::PM_DefaultFrameWidth );
00222   if ( frameWidth < 0 )
00223     frameWidth = 0;
00224   if ( frameWidth != lineWidth() )
00225     setLineWidth( frameWidth );
00226 }
00227 
00228 
00229 //-----------------------------------------------------------------------------
00230 void KMMimePartTree::styleChange( QStyle& oldStyle )
00231 {
00232   setStyleDependantFrameWidth();
00233   KListView::styleChange( oldStyle );
00234 }
00235 
00236 //-----------------------------------------------------------------------------
00237 void KMMimePartTree::correctSize( QListViewItem * item )
00238 {
00239   if (!item) return;
00240 
00241   KIO::filesize_t totalSize = 0;
00242   QListViewItem * myChild = item->firstChild();
00243   while ( myChild )
00244   {
00245     totalSize += static_cast<KMMimePartTreeItem*>(myChild)->origSize();
00246     myChild = myChild->nextSibling();
00247   }
00248   if ( totalSize > static_cast<KMMimePartTreeItem*>(item)->origSize() )
00249     item->setText( mSizeColumn, KIO::convertSize(totalSize) );
00250   if ( item->parent() )
00251     correctSize( item->parent() );
00252 }
00253 
00254 void KMMimePartTree::slotDelete()
00255 {
00256   QPtrList<QListViewItem> selected = selectedItems();
00257   if ( selected.count() != 1 )
00258     return;
00259   mReaderWin->slotDeleteAttachment( static_cast<KMMimePartTreeItem*>( selected.first() )->node() );
00260 }
00261 
00262 void KMMimePartTree::slotEdit()
00263 {
00264   QPtrList<QListViewItem> selected = selectedItems();
00265   if ( selected.count() != 1 )
00266     return;
00267   mReaderWin->slotEditAttachment( static_cast<KMMimePartTreeItem*>( selected.first() )->node() );
00268 }
00269 
00270 void KMMimePartTree::slotOpen()
00271 {
00272   startHandleAttachmentCommand( KMHandleAttachmentCommand::Open );
00273 }
00274 
00275 void KMMimePartTree::slotOpenWith()
00276 {
00277   startHandleAttachmentCommand( KMHandleAttachmentCommand::OpenWith );
00278 }
00279 
00280 void KMMimePartTree::slotView()
00281 {
00282   startHandleAttachmentCommand( KMHandleAttachmentCommand::View );
00283 }
00284 
00285 void KMMimePartTree::slotProperties()
00286 {
00287   startHandleAttachmentCommand( KMHandleAttachmentCommand::Properties );
00288 }
00289 
00290 void KMMimePartTree::startHandleAttachmentCommand(int type)
00291 {
00292   QPtrList<QListViewItem> selected = selectedItems();
00293   if ( selected.count() != 1 )
00294     return;
00295   partNode* node = static_cast<KMMimePartTreeItem*>( selected.first() )->node();
00296   QString name = mReaderWin->tempFileUrlFromPartNode( node ).path();
00297   KMHandleAttachmentCommand* command = new KMHandleAttachmentCommand(
00298       node, mReaderWin->message(), node->nodeId(), name,
00299       KMHandleAttachmentCommand::AttachmentAction( type ), 0, this );
00300   connect( command, SIGNAL( showAttachment( int, const QString& ) ),
00301            mReaderWin, SLOT( slotAtmView( int, const QString& ) ) );
00302   command->start();
00303 }
00304 
00305 void KMMimePartTree::slotCopy()
00306 {
00307   KURL::List urls;
00308   KMMimePartTreeItem *item = static_cast<KMMimePartTreeItem*>( currentItem() );
00309   if ( !item ) return;
00310   KURL url = mReaderWin->tempFileUrlFromPartNode( item->node() );
00311   if ( !url.isValid() ) return;
00312   urls.append( url );
00313   KURLDrag* drag = new KURLDrag( urls, this );
00314   QApplication::clipboard()->setData( drag, QClipboard::Clipboard );
00315 }
00316 
00317 //=============================================================================
00318 KMMimePartTreeItem::KMMimePartTreeItem( KMMimePartTree * parent,
00319                                         partNode* node,
00320                                         const QString & description,
00321                                         const QString & mimetype,
00322                                         const QString & encoding,
00323                                         KIO::filesize_t size )
00324   : QListViewItem( parent, description,
00325            QString::null, // set by setIconAndTextForType()
00326            encoding,
00327            KIO::convertSize( size ) ),
00328     mPartNode( node ), mOrigSize(size)
00329 {
00330   if( node )
00331     node->setMimePartTreeItem( this );
00332   setIconAndTextForType( mimetype );
00333   if ( parent )
00334     parent->correctSize(this);
00335 }
00336 
00337 KMMimePartTreeItem::KMMimePartTreeItem( KMMimePartTreeItem * parent,
00338                                         partNode* node,
00339                                         const QString & description,
00340                                         const QString & mimetype,
00341                                         const QString & encoding,
00342                                         KIO::filesize_t size,
00343                                         bool revertOrder )
00344   : QListViewItem( parent, description,
00345            QString::null, // set by setIconAndTextForType()
00346            encoding,
00347            KIO::convertSize( size ) ),
00348     mPartNode( node ), mOrigSize(size)
00349 {
00350   if( revertOrder && nextSibling() ){
00351     QListViewItem* sib = nextSibling();
00352     while( sib->nextSibling() )
00353       sib = sib->nextSibling();
00354     moveItem( sib );
00355   }
00356   if( node )
00357     node->setMimePartTreeItem( this );
00358   setIconAndTextForType( mimetype );
00359   if ( listView() )
00360     static_cast<KMMimePartTree*>(listView())->correctSize(this);
00361 }
00362 
00363 void KMMimePartTreeItem::setIconAndTextForType( const QString & mime )
00364 {
00365   QString mimetype = mime.lower();
00366   if ( mimetype.startsWith( "multipart/" ) ) {
00367     setText( 1, mimetype );
00368     setPixmap( 0, SmallIcon("folder") );
00369   } else if ( mimetype == "application/octet-stream" ) {
00370     setText( 1, i18n("Unspecified Binary Data") ); // don't show "Unknown"...
00371     setPixmap( 0, SmallIcon("unknown") );
00372   } else {
00373     KMimeType::Ptr mtp = KMimeType::mimeType( mimetype );
00374     setText( 1, (mtp && !mtp->comment().isEmpty()) ? mtp->comment() : mimetype );
00375     setPixmap( 0, mtp ? mtp->pixmap( KIcon::Small) : SmallIcon("unknown") );
00376   }
00377 }
00378 
00379 
00380 void KMMimePartTree::startDrag()
00381 {
00382     KURL::List urls;
00383     KMMimePartTreeItem *item = static_cast<KMMimePartTreeItem*>( currentItem() );
00384     if ( !item ) return;
00385     partNode *node = item->node();
00386     if ( !node ) return;
00387     KURL url = mReaderWin->tempFileUrlFromPartNode( node );
00388     if (!url.isValid() ) return;
00389     urls.append( url );
00390     KURLDrag* drag = new KURLDrag( urls, this );
00391     drag->drag();
00392 }
00393 
00394 #include "kmmimeparttree.moc"
00395