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.
 
 
 

397 lines
12 KiB

/******************************************************************************
*
* KMail Folder Selection Tree Widget
*
* Copyright (c) 1997-1998 Stefan Taferner <taferner@kde.org>
* Copyright (c) 2004-2005 Carsten Burghardt <burghardt@kde.org>
* Copyright (c) 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 "folderselectiontreewidget.h"
#include "mainfolderview.h"
#include "kmfolder.h"
#include "kmfoldermgr.h"
#include "util.h"
#include <kmenu.h>
#include <kiconloader.h>
#include <kconfiggroup.h>
using namespace KMail::Util;
namespace KMail {
class FolderSelectionTreeWidgetItem : public KPIM::FolderTreeWidgetItem
{
public:
FolderSelectionTreeWidgetItem(
KPIM::FolderTreeWidget * listView,
const FolderViewItem * srcItem
)
: KPIM::FolderTreeWidgetItem(
listView, srcItem->labelText(),
srcItem->protocol(), srcItem->folderType()
), mFolder( 0 ) {};
FolderSelectionTreeWidgetItem(
KPIM::FolderTreeWidgetItem * listViewItem,
const FolderViewItem * srcItem
)
: KPIM::FolderTreeWidgetItem(
listViewItem, srcItem->labelText(),
srcItem->protocol(), srcItem->folderType()
), mFolder( 0 ) {};
public:
void setFolder( KMFolder * folder )
{ mFolder = folder; };
KMFolder * folder() const
{ return mFolder; };
private:
KMFolder * mFolder;
};
FolderSelectionTreeWidget::FolderSelectionTreeWidget( QWidget * parent, ::KMail::MainFolderView * folderTree )
: KPIM::FolderTreeWidget( parent ), mFolderTree( folderTree )
{
setSelectionMode( QTreeWidget::SingleSelection );
mNameColumnIndex = addColumn( i18n( "Folder" ) );
mPathColumnIndex = addColumn( i18n( "Path" ) );
setContextMenuPolicy( Qt::CustomContextMenu );
connect( this, SIGNAL( customContextMenuRequested( const QPoint & ) ),
this, SLOT( slotContextMenuRequested( const QPoint & ) ) );
}
void FolderSelectionTreeWidget::recursiveReload( FolderViewItem *fti, FolderSelectionTreeWidgetItem *parent )
{
// search folders are never shown
if ( fti->protocol() == KPIM::FolderTreeWidgetItem::Search )
return;
// imap folders?
if ( fti->protocol() == KPIM::FolderTreeWidgetItem::Imap && !mLastShowImapFolders )
return;
// the outbox?
if ( fti->folderType() == KPIM::FolderTreeWidgetItem::Outbox && !mLastShowOutbox )
return;
// top level
FolderSelectionTreeWidgetItem *item = parent ? new FolderSelectionTreeWidgetItem( parent, fti )
: new FolderSelectionTreeWidgetItem( this, fti );
item->setText( mNameColumnIndex, fti->labelText() );
// Build the path (ParentItemPath/CurrentItemName)
QString path;
if( parent )
path = parent->text( mPathColumnIndex ) + '/';
path += fti->labelText();
item->setText( mPathColumnIndex, path );
QPixmap pix = fti->normalIcon();
item->setIcon( mNameColumnIndex, pix.isNull() ? SmallIcon( "folder" ) : QIcon( pix ) );
// Make items without folders and readonly items unselectable
// if we're told so
if ( mLastMustBeReadWrite && ( !fti->folder() || fti->folder()->isReadOnly() ) ) {
item->setFlags( item->flags() & ~Qt::ItemIsSelectable );
} else {
item->setFolder( fti->folder() );
}
int cc = fti->childCount();
int i = 0;
while ( i < cc )
{
FolderViewItem *child = dynamic_cast<FolderViewItem *>( ( ( QTreeWidgetItem * )fti)->child( i ) );
if ( child )
recursiveReload( child, item );
i++;
}
}
void FolderSelectionTreeWidget::reload( bool mustBeReadWrite, bool showOutbox,
bool showImapFolders, const QString& preSelection )
{
mLastMustBeReadWrite = mustBeReadWrite;
mLastShowOutbox = showOutbox;
mLastShowImapFolders = showImapFolders;
clear();
QString selected = preSelection;
if ( selected.isEmpty() && folder() )
selected = folder()->idString();
mFilter.clear();
int cc = mFolderTree->topLevelItemCount();
int i = 0;
// Calling setUpdatesEnabled() here causes weird effects (including crashes)
// in the folder requester (used by the filtering dialog).
// So disable it for now, this makes the folderselection dialog appear much
// slower though :(
//setUpdatesEnabled( false );
while ( i < cc )
{
FolderViewItem *child = dynamic_cast<FolderViewItem *>( mFolderTree->topLevelItem( i ) );
if ( child )
recursiveReload( child, 0 );
i++;
}
// we do this here in one go after all items have been created, as that is
// faster than expanding each item, which triggers a lot of updates
expandAll();
if ( !preSelection.isEmpty() )
setFolder( preSelection );
}
KMFolder * FolderSelectionTreeWidget::folder() const
{
QTreeWidgetItem * item = currentItem();
if ( item ) {
if ( item->flags() & Qt::ItemIsSelectable )
return static_cast<FolderSelectionTreeWidgetItem *>( item )->folder();
}
return 0;
}
void FolderSelectionTreeWidget::setFolder( KMFolder *folder )
{
for ( QTreeWidgetItemIterator it( this ) ; *it ; ++it )
{
const KMFolder *fld = static_cast<FolderSelectionTreeWidgetItem *>( *it )->folder();
if ( fld == folder )
{
( *it )->setSelected( true );
scrollToItem( *it );
setCurrentItem( *it );
return;
}
}
}
void FolderSelectionTreeWidget::setFolder( const QString& idString )
{
setFolder( kmkernel->findFolderById( idString ) );
}
void FolderSelectionTreeWidget::addChildFolder()
{
const KMFolder *fld = folder();
if ( fld ) {
reconnectSignalSlotPair( kmkernel->folderMgr(), SIGNAL( folderAdded(KMFolder*) ),
this, SLOT( slotFolderAdded(KMFolder*) ) );
reconnectSignalSlotPair( kmkernel->imapFolderMgr(), SIGNAL( folderAdded(KMFolder*) ),
this, SLOT( slotFolderAdded(KMFolder*) ) );
reconnectSignalSlotPair( kmkernel->dimapFolderMgr(), SIGNAL( folderAdded(KMFolder*) ),
this, SLOT( slotFolderAdded(KMFolder*) ) );
mFolderTree->addChildFolder( (KMFolder *) fld, parentWidget() );
}
}
void FolderSelectionTreeWidget::slotContextMenuRequested( const QPoint &p )
{
QTreeWidgetItem * lvi = itemAt( p );
if ( !lvi )
return;
setCurrentItem( lvi );
lvi->setSelected( true );
const KMFolder * folder = static_cast<FolderSelectionTreeWidgetItem *>( lvi )->folder();
if ( !folder || folder->noContent() || folder->noChildren() )
return;
KMenu *folderMenu = new KMenu;
folderMenu->addTitle( folder->label() );
folderMenu->addSeparator();
folderMenu->addAction( KIcon("folder-new"),
i18n("&New Subfolder..."), this,
SLOT(addChildFolder()) );
kmkernel->setContextMenuShown( true );
folderMenu->exec ( viewport()->mapToGlobal( p ), 0);
kmkernel->setContextMenuShown( false );
delete folderMenu;
folderMenu = 0;
}
void FolderSelectionTreeWidget::slotFolderAdded( KMFolder *addedFolder )
{
reload( mLastMustBeReadWrite, mLastShowOutbox, mLastShowImapFolders );
setFolder( addedFolder );
disconnect( kmkernel->folderMgr(), SIGNAL( folderAdded(KMFolder*) ),
this, SLOT( slotFolderAdded(KMFolder*) ) );
disconnect( kmkernel->imapFolderMgr(), SIGNAL( folderAdded(KMFolder*) ),
this, SLOT( slotFolderAdded(KMFolder*) ) );
disconnect( kmkernel->dimapFolderMgr(), SIGNAL( folderAdded(KMFolder*) ),
this, SLOT( slotFolderAdded(KMFolder*) ) );
}
void FolderSelectionTreeWidget::applyFilter( const QString& filter )
{
// We would like to set items that do not match the filter to disabled,
// but that also disables all the children of that item (qt bug 181410,
// closed as WONTFIX).
// So instead, we mark the items as not selectable. That unfortunalty does not
// give us visual feedback, though.
// In keyPressEvent(), we change the behavior of the up/down arrow to skip
// non-selectable items.
if ( filter.isEmpty() )
{
// Empty filter:
// reset all items to enabled, visible, expanded and not selected
QTreeWidgetItemIterator clean( this );
while ( QTreeWidgetItem *item = *clean )
{
item->setHidden( false );
item->setSelected( false );
item->setFlags( item->flags() | Qt::ItemIsSelectable );
++clean;
}
setColumnText( mPathColumnIndex, i18n("Path") );
return;
}
// Not empty filter.
// Reset all items to disabled, hidden, closed and not selected
QTreeWidgetItemIterator clean( this );
while ( QTreeWidgetItem *item = *clean )
{
item->setHidden( true );
item->setSelected( false );
item->setFlags( item->flags() & ~Qt::ItemIsSelectable );
++clean;
}
// Now search...
QList<QTreeWidgetItem *> lItems = findItems( mFilter, Qt::MatchContains | Qt::MatchRecursive, mPathColumnIndex );
for( QList<QTreeWidgetItem *>::Iterator it = lItems.begin(); it != lItems.end(); ++it )
{
( *it )->setFlags( ( *it )->flags() | Qt::ItemIsSelectable );
( *it )->setHidden( false );
// Open all the parents up to this item
QTreeWidgetItem * p = ( *it )->parent();
while( p )
{
p->setHidden( false );
p = p->parent();
}
}
// Iterate through the list to find the first selectable item
QTreeWidgetItemIterator first( this );
while ( FolderSelectionTreeWidgetItem * item = static_cast< FolderSelectionTreeWidgetItem* >( *first ) )
{
if ( ( !item->isHidden() ) && ( !item->isDisabled() ) &&
( item->flags() & Qt::ItemIsSelectable ) )
{
item->setSelected( true );
setCurrentItem( item );
scrollToItem( item );
break;
}
++first;
}
// Display and save the current filter
if ( filter.length() > 0 )
setColumnText( mPathColumnIndex, i18n("Path") + " ( " + filter + " )" );
else
setColumnText( mPathColumnIndex, i18n("Path") );
}
void FolderSelectionTreeWidget::keyPressEvent( QKeyEvent *e )
{
// Handle keyboard filtering.
// Each key with text is appended to our search filter (which gets displayed
// in the header for the Path column). Backpace removes text from the filter
// while the del button clears the filter completely.
switch( e->key() )
{
case Qt::Key_Backspace:
if ( mFilter.length() > 0 )
mFilter.truncate( mFilter.length()-1 );
applyFilter( mFilter );
return;
break;
case Qt::Key_Delete:
mFilter = "";
applyFilter( mFilter);
return;
break;
// Reimplement up/down arrow handling to skip non-selectable items
case Qt::Key_Up:
{
QTreeWidgetItem *newCurrent = currentItem();
do {
newCurrent = itemAbove( newCurrent );
} while ( newCurrent && !( newCurrent->flags() & Qt::ItemIsSelectable ) );
if ( newCurrent )
setCurrentItem( newCurrent );
return;
}
break;
case Qt::Key_Down:
{
QTreeWidgetItem *newCurrent = currentItem();
do {
newCurrent = itemBelow( newCurrent );
} while ( newCurrent && !( newCurrent->flags() & Qt::ItemIsSelectable ) );
if ( newCurrent )
setCurrentItem( newCurrent );
return;
}
break;
default:
{
QString s = e->text();
if ( !s.isEmpty() && s.at( 0 ).isPrint() ) {
mFilter += s;
applyFilter( mFilter );
return;
}
}
break;
}
KPIM::FolderTreeWidget::keyPressEvent( e );
}
} // namespace KMail
#include "folderselectiontreewidget.moc"