You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

940 lines
25 KiB

/******************************************************************************
*
* Copyright 2008 Szymon Tomasz Stefanek <pragma@kvirc.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*******************************************************************************/
#include "messagelistview/widget.h"
#include "messagelistview/pane.h"
#include "messagelistview/storagemodel.h"
#include "messagelistview/core/view.h"
#include "messagelistview/core/messageitem.h"
#include "kmmessage.h"
#include "kmfolder.h"
#include "kmmainwidget.h"
#include "kmmessagetag.h"
#include "kmkernel.h"
#include "mainfolderview.h"
#include "messagecopyhelper.h"
#include "globalsettings.h"
#include "textsource.h"
#include "messagetree.h"
#include <QDrag>
#include <QPixmap>
#include <QTimer>
#include <QAction>
#include <QActionGroup>
#include <KAcceleratorManager>
#include <KActionMenu>
#include <KApplication>
#include <KConfigGroup>
#include <KIconEffect>
#include <KIconLoader>
#include <KMenu>
#include <libkdepim/maillistdrag.h> // KPIM::MailList
namespace KMail
{
namespace MessageListView
{
Widget::Widget( KMMainWidget *mainWidget, Pane *pPane )
: Core::Widget( pPane ), mPane( pPane ), mMainWidget( mainWidget )
{
mLastSelectedMessage = -1;
// Behavior
{
// This is an ugly hack. I'm even not 100% sure that it's correct...
// Let's hope for the best :D
KConfigGroup config( KMKernel::config(), "Geometry" );
mReleaseMessageAfterCurrentChange = config.readEntry( "readerWindowMode", "below" ) != "hide";
}
mIconAnimationTimer = new QTimer();
QObject::connect(
mIconAnimationTimer, SIGNAL( timeout() ),
this, SLOT( animateIcon() )
);
}
Widget::~Widget()
{
delete mIconAnimationTimer;
}
void Widget::setFolder( KMFolder * fld, const QIcon &icon, Core::PreSelectionMode preSelectionMode )
{
if ( ( mLastSelectedMessage >= 0 ) && mReleaseMessageAfterCurrentChange && storageModel() )
{
static_cast< StorageModel * >( storageModel() )->releaseMessage( mLastSelectedMessage );
mLastSelectedMessage = -1;
}
mFolderIconBase = icon;
QImage base = mFolderIconBase.pixmap( 16, 16 ).toImage();
for ( int i = 0; i < BusyAnimationSteps; i++ )
{
QImage tmp = SmallIcon( QString( "overlay-busy-clock-%1.png" ).arg( i + 1 ) ).toImage();
QImage busy = base;
KIconEffect::overlay( busy, tmp );
mFolderIconBusy[ i ] = QIcon( QPixmap::fromImage( busy ) );
}
mPane->widgetIconChangeRequest( this, mFolderIconBase );
// Set the storage _after_ setting the icon so it can be overridden
// from inside setStorageModel().
setStorageModel( fld ? new StorageModel( fld ) : 0, preSelectionMode );
}
KMFolder * Widget::folder() const
{
if ( !storageModel() )
return 0;
return static_cast< StorageModel * >( storageModel() )->folder();
}
void Widget::viewMessageSelected( Core::MessageItem *msg )
{
int row = -1;
if ( msg )
row = msg->currentModelIndexRow();
if ( mLastSelectedMessage >= 0 && mReleaseMessageAfterCurrentChange &&
storageModel() ) {
bool selectedStaysSame = row != -1 && mLastSelectedMessage == row &&
msg && msg->isValid();
// No need to release the last selected message if it is the new selected
// message is going to be the same.
// This fixes a crash in KMMainWidget::slotMsgPopup(), which can activate
// an already active message in certain cirumstances. Releasing that message
// would make all the message pointers invalid.
if ( !selectedStaysSame ) {
static_cast< StorageModel * >( storageModel() )->releaseMessage( mLastSelectedMessage );
}
}
if ( !msg || !storageModel() )
{
mLastSelectedMessage = -1;
emit messageSelected( 0 );
return;
}
if ( !msg->isValid() )
{
mLastSelectedMessage = -1;
emit messageSelected( 0 );
return;
}
Q_ASSERT( row >= 0 );
KMMessage * message = static_cast< const StorageModel * >( storageModel() )->message( row );
mLastSelectedMessage = row;
emit messageSelected( message ); // this MAY be null
}
void Widget::viewMessageActivated( Core::MessageItem *msg )
{
Q_ASSERT( msg ); // must not be null
Q_ASSERT( storageModel() );
if ( !msg->isValid() )
return;
int row = msg->currentModelIndexRow();
Q_ASSERT( row >= 0 );
// The assert below may fail when quickly opening and closing a non-selected thread.
// This will actually activate the item without selecting it...
//Q_ASSERT( mLastSelectedMessage == row );
if ( mLastSelectedMessage != row )
{
// Very ugly. We are activating a non selected message.
// This is very likely a double click on the plus sign near a thread leader.
// Dealing with mLastSelectedMessage here would be expensive: it would involve releasing the last selected,
// emitting signals, handling recursion... ugly.
// We choose a very simple solution: double clicking on the plus sign near a thread leader does
// NOT activate the message (i.e open it in a toplevel window) if it isn't previously selected.
return;
}
KMMessage * message = static_cast< const StorageModel * >( storageModel() )->message( row );
emit messageActivated( message ); // this MAY be null
}
void Widget::viewMessageStatusChangeRequest( Core::MessageItem *msg, const KPIM::MessageStatus &set, const KPIM::MessageStatus &clear )
{
Q_ASSERT( msg ); // must not be null
Q_ASSERT( storageModel() );
if ( !msg->isValid() )
return;
int row = msg->currentModelIndexRow();
Q_ASSERT( row >= 0 );
KMMsgBase * msgBase = static_cast< const StorageModel * >( storageModel() )->msgBase( row );
Q_ASSERT( msgBase );
emit messageStatusChangeRequest( msgBase, set, clear );
}
Core::MessageItem * Widget::currentMessageItem() const
{
return view()->currentMessageItem();
}
Core::MessageItem * Widget::messageItemFromMessage( KMMessage * msg ) const
{
return messageItemFromMsgBase( msg );
}
KMMessage * Widget::currentMessage() const
{
if ( !storageModel() )
return 0;
Core::MessageItem * mi = currentMessageItem();
if ( !mi )
return 0;
return static_cast< StorageModel * >( storageModel() )->message( mi );
}
KMMsgBase * Widget::currentMsgBase() const
{
if ( !storageModel() )
return 0;
Core::MessageItem * mi = currentMessageItem();
if ( !mi )
return 0;
return static_cast< StorageModel * >( storageModel() )->msgBase( mi );
}
Core::MessageItem * Widget::messageItemFromMsgBase( KMMsgBase * msg ) const
{
if ( !storageModel() )
return 0;
int row = static_cast< StorageModel * >( storageModel() )->msgBaseRow( msg );
if ( row < 0 )
return 0;
return view()->model()->messageItemByStorageRow( row );
}
void Widget::activateMessageItemByMsgBase( KMMsgBase * msg )
{
// This function may be expensive since it needs to perform a linear search
// in the storage. We want to avoid that so we use some tricks.
if ( !storageModel() )
return;
Core::MessageItem * mi = 0;
// take care of current first
if ( currentMsgBase() != msg ) // this
{
mi = messageItemFromMsgBase( msg );
view()->setCurrentMessageItem( mi ); // clears the current if mi == 0
if ( !mi )
{
// aargh.. not found
view()->clearSelection();
return;
}
}
// take care of selection
// As the current selection is smaller than the whole folder and as per
// the locality principle it's likely that we're trying to activate
// and already selected item then loop through the selection first.
QList< Core::MessageItem * > selectedItems = selectionAsMessageItemList( false );
bool foundInSelection = false;
QItemSelection sel;
for ( QList< Core::MessageItem * >::Iterator it = selectedItems.begin(); it != selectedItems.end(); ++it )
{
if ( static_cast< StorageModel * >( storageModel() )->msgBase( *it ) == msg )
{
foundInSelection = true;
} else {
sel.append( QItemSelectionRange( view()->model()->index( *it, 0 ) ) );
}
}
if ( foundInSelection )
{
if ( !sel.isEmpty() )
view()->selectionModel()->select( sel, QItemSelectionModel::Deselect | QItemSelectionModel::Rows );
return;
}
// not found in selection... select as only item
if ( !mi )
{
// doh.. need a linear search :(
mi = messageItemFromMsgBase( msg );
if ( !mi )
{
// weird...
view()->clearSelection();
return;
}
}
sel.clear();
sel.append( QItemSelectionRange( view()->model()->index( mi, 0 ) ) );
view()->selectionModel()->select( sel, QItemSelectionModel::Select | QItemSelectionModel::Rows | QItemSelectionModel::Clear );
}
QList< Core::MessageItem * > Widget::selectionAsMessageItemList( bool includeCollapsedChildren ) const
{
return view()->selectionAsMessageItemList( includeCollapsedChildren );
}
QList< KMMessage * > Widget::selectionAsMessageList( bool includeCollapsedChildren ) const
{
QList< KMMessage * > ret;
if ( !storageModel() )
return ret;
QList< Core::MessageItem * > selectedItems = view()->selectionAsMessageItemList( includeCollapsedChildren );
for ( QList< Core::MessageItem * >::Iterator it = selectedItems.begin(); it != selectedItems.end(); ++it )
{
KMMessage * msg = static_cast< StorageModel * >( storageModel() )->message( *it );
Q_ASSERT( msg );
ret.append( msg );
}
return ret;
}
QList< KMMsgBase * > Widget::selectionAsMsgBaseList( bool includeCollapsedChildren ) const
{
QList< KMMsgBase * > ret;
if ( !storageModel() )
return ret;
QList< Core::MessageItem * > selectedItems = view()->selectionAsMessageItemList( includeCollapsedChildren );
for ( QList< Core::MessageItem * >::Iterator it = selectedItems.begin(); it != selectedItems.end(); ++it )
{
KMMsgBase * msg = static_cast< StorageModel * >( storageModel() )->msgBase( *it );
Q_ASSERT( msg );
ret.append( msg );
}
return ret;
}
MessageTreeCollection * Widget::itemListToMessageTreeCollection( const QList< Core::MessageItem * > &list ) const
{
if ( list.isEmpty() )
return 0;
MessageTreeCollection * collection = new MessageTreeCollection();
QHash< Core::MessageItem *, MessageTree * > messageItemsToMessageTrees;
for( QList< Core::MessageItem * >::ConstIterator it = list.begin(); it != list.end(); ++it )
{
KMMsgBase * msg = static_cast< StorageModel * >( storageModel() )->msgBase( *it );
Q_ASSERT( msg );
MessageTree * tree = new MessageTree( msg );
messageItemsToMessageTrees.insert( *it, tree );
}
for( QList< Core::MessageItem * >::ConstIterator it = list.begin(); it != list.end(); ++it )
{
MessageTree * tree = messageItemsToMessageTrees.value( *it, 0 );
Q_ASSERT( tree );
Core::Item * pParent = ( *it )->parent();
bool attached = false;
while ( pParent )
{
if ( pParent->type() != Core::Item::Message )
break;
MessageTree * parentTree = messageItemsToMessageTrees.value( static_cast< Core::MessageItem * >( pParent ), 0 );
if( parentTree )
{
parentTree->addChild( tree );
attached = true;
break;
}
pParent = pParent->parent();
}
if ( !attached )
collection->addTree( tree );
}
return collection;
}
MessageTreeCollection * Widget::selectionAsMessageTreeCollection( bool includeCollapsedChildren ) const
{
if ( !storageModel() )
return 0;
return itemListToMessageTreeCollection( view()->selectionAsMessageItemList( includeCollapsedChildren ) );
}
QList< Core::MessageItem * > Widget::currentThreadAsMessageItemList() const
{
return view()->currentThreadAsMessageItemList();
}
QList< KMMsgBase * > Widget::currentThreadAsMsgBaseList() const
{
QList< KMMsgBase * > ret;
if ( !storageModel() )
return ret;
QList< Core::MessageItem * > currentThreadItems = view()->currentThreadAsMessageItemList();
for ( QList< Core::MessageItem * >::Iterator it = currentThreadItems.begin(); it != currentThreadItems.end(); ++it )
{
KMMsgBase * msg = static_cast< StorageModel * >( storageModel() )->msgBase( *it );
Q_ASSERT( msg );
ret.append( msg );
}
return ret;
}
QList< KMMessage * > Widget::currentThreadAsMessageList() const
{
QList< KMMessage * > ret;
if ( !storageModel() )
return ret;
QList< Core::MessageItem * > currentThreadItems = view()->currentThreadAsMessageItemList();
for ( QList< Core::MessageItem * >::Iterator it = currentThreadItems.begin(); it != currentThreadItems.end(); ++it )
{
KMMessage * msg = static_cast< StorageModel * >( storageModel() )->message( *it );
Q_ASSERT( msg );
ret.append( msg );
}
return ret;
}
MessageTreeCollection * Widget::currentThreadAsMessageTreeCollection() const
{
if ( !storageModel() )
return 0;
return itemListToMessageTreeCollection( view()->currentThreadAsMessageItemList() );
}
Core::MessageItemSetReference Widget::createPersistentSetFromMessageItemList( const QList< Core::MessageItem * > &items )
{
if ( !storageModel() )
return static_cast< Core::MessageItemSetReference >( 0 ); // never exists
if ( items.isEmpty() )
return static_cast< Core::MessageItemSetReference >( 0 );
return view()->createPersistentSet( items );
}
QList< KMMsgBase * > Widget::persistentSetContentsAsMsgBaseList( Core::MessageItemSetReference ref ) const
{
QList< KMMsgBase * > ret;
if ( !storageModel() )
return ret;
QList< Core::MessageItem * > setItems = view()->persistentSetCurrentMessageItemList( ref );
if ( setItems.isEmpty() )
return ret;
for ( QList< Core::MessageItem * >::Iterator it = setItems.begin(); it != setItems.end(); ++it )
{
KMMsgBase * msg = static_cast< StorageModel * >( storageModel() )->msgBase( *it );
Q_ASSERT( msg );
ret.append( msg );
}
return ret;
}
void Widget::markPersistentSetAsAboutToBeRemoved( Core::MessageItemSetReference ref, bool bMark )
{
QList< KMMsgBase * > ret;
if ( !storageModel() )
return;
QList< Core::MessageItem * > setItems = view()->persistentSetCurrentMessageItemList( ref );
if ( setItems.isEmpty() )
return;
view()->markMessageItemsAsAboutToBeRemoved( setItems, bMark );
}
void Widget::selectPersistentSet( Core::MessageItemSetReference ref, bool clearSelectionFirst ) const
{
QList< KMMsgBase * > ret;
if ( !storageModel() )
return;
QList< Core::MessageItem * > setItems = view()->persistentSetCurrentMessageItemList( ref );
if ( setItems.isEmpty() )
return;
if ( clearSelectionFirst )
view()->clearSelection();
view()->selectMessageItems( setItems );
}
void Widget::viewSelectionChanged()
{
emit selectionChanged();
if ( !currentMessageItem() )
emit messageSelected( 0 );
}
void Widget::deletePersistentSet( Core::MessageItemSetReference ref )
{
view()->deletePersistentSet( ref );
}
bool Widget::getSelectionStats(
QList< Q_UINT32 > &selectedSernums,
QList< Q_UINT32 > &selectedVisibleSernums,
bool * allSelectedBelongToSameThread,
bool includeCollapsedChildren
) const
{
if ( !storageModel() )
return false;
selectedSernums.clear();
selectedVisibleSernums.clear();
QList< Core::MessageItem * > selected = selectionAsMessageItemList( includeCollapsedChildren );
Core::MessageItem * topmost = 0;
*allSelectedBelongToSameThread = true;
for ( QList< Core::MessageItem * >::Iterator it = selected.begin(); it != selected.end(); ++it )
{
KMMsgBase * mb = static_cast< StorageModel * >( storageModel() )->msgBase( ( *it ) );
Q_ASSERT( mb );
selectedSernums.append( mb->getMsgSerNum() );
if ( view()->isCurrentlyViewable( ( *it ) ) )
selectedVisibleSernums.append( mb->getMsgSerNum() );
if ( topmost == 0 )
topmost = ( *it )->topmostMessage();
else {
if ( topmost != ( *it )->topmostMessage() )
*allSelectedBelongToSameThread = false;
}
}
return true;
}
bool Widget::selectionEmpty() const
{
return view()->selectionEmpty();
}
void Widget::viewMessageListContextPopupRequest( const QList< Core::MessageItem * > &selectedItems, const QPoint &globalPos )
{
if ( !topLevelWidget() ) return; // safe bet
if ( selectedItems.isEmpty() ) return; // we have nothing to do
Q_ASSERT( storageModel() );
mMainWidget->updateMessageMenu();
//mMainWidget->updateMessageActions(); <-- this is called by updateMessageMenu()
KMenu menu( this );
bool out_folder = kmkernel->folderIsDraftOrOutbox( folder() );
bool tem_folder = kmkernel->folderIsTemplates( folder() );
if (tem_folder)
{
menu.addAction( mMainWidget->useAction() );
} else {
// show most used actions
if( !folder()->isSent() )
menu.addAction( mMainWidget->messageActions()->replyMenu() );
menu.addAction( mMainWidget->forwardMenu() );
if( mMainWidget->sendAgainAction()->isEnabled() )
menu.addAction( mMainWidget->sendAgainAction() );
else
menu.addAction( mMainWidget->editAction() );
}
menu.addSeparator();
menu.addAction( mMainWidget->action( "copy_to" ) );
if ( folder()->isReadOnly() )
{
QAction* act = menu.addAction( i18n( "&Move To" ) );
act->setEnabled( false );
} else {
menu.addAction( mMainWidget->action( "move_to" ) );
}
menu.addSeparator();
menu.addAction( mMainWidget->messageActions()->messageStatusMenu() ); // Mark Message menu
if ( mMainWidget->threadStatusMenu()->isEnabled() )
menu.addAction( mMainWidget->threadStatusMenu() ); // Mark Thread menu
if ( !out_folder )
{
menu.addSeparator();
menu.addAction( mMainWidget->filterMenu() ); // Create Filter menu
menu.addAction( mMainWidget->action( "apply_filter_actions" ) );
}
menu.addSeparator();
menu.addAction( mMainWidget->printAction() );
menu.addAction( mMainWidget->saveAsAction() );
menu.addAction( mMainWidget->saveAttachmentsAction() );
menu.addSeparator();
if ( folder()->isTrash() )
{
menu.addAction( mMainWidget->deleteAction() );
if ( mMainWidget->trashThreadAction()->isEnabled() )
menu.addAction( mMainWidget->deleteThreadAction() );
} else {
menu.addAction( mMainWidget->trashAction() );
if ( mMainWidget->trashThreadAction()->isEnabled() )
menu.addAction( mMainWidget->trashThreadAction() );
}
menu.addSeparator();
menu.addAction( mMainWidget->messageActions()->createTodoAction() );
KAcceleratorManager::manage( &menu );
kmkernel->setContextMenuShown( true );
menu.exec( globalPos );
kmkernel->setContextMenuShown( false );
}
void Widget::viewGroupHeaderContextPopupRequest( Core::GroupHeaderItem *ghi, const QPoint &globalPos )
{
Q_UNUSED( ghi );
KMenu menu( this );
QAction *act;
menu.addSeparator();
act = menu.addAction( i18n( "Expand All Groups" ) );
connect(
act, SIGNAL( triggered( bool ) ),
view(), SLOT( slotExpandAllGroups() )
);
act = menu.addAction( i18n( "Collapse All Groups" ) );
connect(
act, SIGNAL( triggered( bool ) ),
view(), SLOT( slotCollapseAllGroups() )
);
menu.exec( globalPos );
}
bool Widget::canAcceptDrag( const QDragMoveEvent * e )
{
KMFolder * fld = folder();
if ( !fld )
return false; // no folder here
if ( fld->isReadOnly() )
return false; // no way to drag into
if ( !e->mimeData()->hasFormat( KPIM::MailList::mimeDataType() ) )
return false; // no way to decode it
KPIM::MailList list = KPIM::MailList::fromMimeData( e->mimeData() );
if ( list.isEmpty() )
{
kWarning() << "Could not decode drag data!";
return false;
}
QList<uint> serNums = MessageCopyHelper::serNumListFromMailList( list );
KMFolder * sourceFolder = MessageCopyHelper::firstSourceFolder( serNums );
return sourceFolder != fld;
}
void Widget::viewDragEnterEvent( QDragEnterEvent *e )
{
if ( !canAcceptDrag( e ) )
{
e->ignore();
return;
}
e->accept();
}
void Widget::viewDragMoveEvent( QDragMoveEvent *e )
{
if ( !canAcceptDrag( e ) )
{
e->ignore();
return;
}
e->accept();
}
void Widget::viewStartDragRequest()
{
if ( !folder() )
return;
QList< KMMsgBase * > selectedList = selectionAsMsgBaseList();
if ( selectedList.isEmpty() )
return;
KPIM::MailList mailList;
for ( QList< KMMsgBase * >::Iterator it = selectedList.begin(); it != selectedList.end(); ++it )
{
KPIM::MailSummary mailSummary(
( *it )->getMsgSerNum(), ( *it )->msgIdMD5(),
( *it )->subject(), ( *it )->fromStrip(),
( *it )->toStrip(), ( *it )->date()
);
mailList.append( mailSummary );
}
QDrag *drag = new QDrag( view()->viewport() );
drag->setMimeData( new KPIM::MailListMimeData( new KMTextSource ) );
mailList.populateMimeData( drag->mimeData() );
// Set pixmap
QPixmap pixmap;
if( selectedList.count() == 1 )
pixmap = QPixmap( DesktopIcon("mail-message", KIconLoader::SizeSmall) );
else
pixmap = QPixmap( DesktopIcon("document-multiple", KIconLoader::SizeSmall) );
// Calculate hotspot (as in Konqueror)
if( !pixmap.isNull() )
{
drag->setHotSpot( QPoint( pixmap.width() / 2, pixmap.height() / 2 ) );
drag->setPixmap( pixmap );
}
if ( folder()->isReadOnly() )
drag->exec( Qt::CopyAction );
else
drag->exec( Qt::CopyAction | Qt::MoveAction );
}
enum DragMode
{
DragCopy,
DragMove,
DragCancel
};
void Widget::viewDropEvent( QDropEvent *e )
{
KMFolder * fld = folder();
if ( !fld || !e->mimeData()->hasFormat( KPIM::MailList::mimeDataType() ) )
{
e->ignore();
return;
}
KPIM::MailList list = KPIM::MailList::fromMimeData( e->mimeData() );
if ( list.isEmpty() )
{
kWarning() << "Could not decode drag data!";
e->ignore();
return;
}
e->accept();
QList<uint> serNums = MessageCopyHelper::serNumListFromMailList( list );
int action;
if ( MessageCopyHelper::inReadOnlyFolder( serNums ) )
action = DragCopy;
else {
action = DragCancel;
int keybstate = kapp->keyboardModifiers();
if ( keybstate & Qt::CTRL )
{
action = DragCopy;
} else if ( keybstate & Qt::SHIFT )
{
action = DragMove;
} else {
// FIXME: This code is duplicated almost exactly in FolderView... shouldn't we share ?
// FIXME: anybody sets this option to false ?
if ( GlobalSettings::self()->showPopupAfterDnD() )
{
KMenu menu;
QAction *moveAction = menu.addAction( KIcon( "go-jump"), i18n( "&Move Here" ) );
QAction *copyAction = menu.addAction( KIcon( "edit-copy" ), i18n( "&Copy Here" ) );
menu.addSeparator();
menu.addAction( KIcon( "dialog-cancel" ), i18n( "C&ancel" ) );
QAction *menuChoice = menu.exec( QCursor::pos() );
if ( menuChoice == moveAction )
action = DragMove;
else if ( menuChoice == copyAction )
action = DragCopy;
else
action = DragCancel;
} else {
action = DragMove;
}
}
}
if ( action == DragCopy || action == DragMove )
new MessageCopyHelper( serNums, fld, action == DragMove, this );
}
void Widget::animateIcon()
{
mPane->widgetIconChangeRequest( this, mFolderIconBusy[ mIconAnimationStep ] );
mIconAnimationStep++;
if ( mIconAnimationStep >= BusyAnimationSteps )
mIconAnimationStep = 0;
}
void Widget::viewJobBatchStarted()
{
mIconAnimationStep = 0;
animateIcon();
mIconAnimationTimer->start( 500 ); // don't waste too much time with this
}
void Widget::viewJobBatchTerminated()
{
mIconAnimationTimer->stop();
mPane->widgetIconChangeRequest( this, mFolderIconBase );
}
QActionGroup * Widget::fillMessageTagMenu( KMenu * menu )
{
// Used for sorting, go through this routine so that mMsgTagList is properly ordered
KMMessageTagList sortedTags;
QHashIterator<QString,KMMessageTagDescription*> it( *( kmkernel->msgTagMgr()->msgTagDict() ) );
while (it.hasNext())
{
it.next();
sortedTags.append( it.value()->label() );
}
if ( sortedTags.isEmpty() )
return 0;
sortedTags.prioritySort();
QActionGroup * grp = new QActionGroup( menu );
QAction * act;
QString currentTagId = currentFilterTagId();
for ( KMMessageTagList::Iterator itl = sortedTags.begin(); itl != sortedTags.end(); ++itl )
{
const KMMessageTagDescription *description = kmkernel->msgTagMgr()->find( *itl );
if ( description )
{
act = menu->addAction( description->name() );
act->setIcon( SmallIcon( description->toolbarIconName() ) );
act->setCheckable( true );
act->setChecked( description->label() == currentTagId );
act->setData( QVariant( description->label() ) );
grp->addAction( act );
}
}
return grp;
}
} // namespace MessageListView
} // namespace KMail