mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-23 10:22:50 +00:00
1136 lines
34 KiB
C++
1136 lines
34 KiB
C++
/*
|
|
Copyright (c) 2009 Kevin Ottens <ervin@kde.org>
|
|
|
|
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 "pane.h"
|
|
|
|
#include <KDE/KActionCollection>
|
|
#include <KDE/KActionMenu>
|
|
#include <KDE/KIcon>
|
|
#include <KDE/KLocale>
|
|
#include <KDE/KMenu>
|
|
#include <KDE/KXMLGUIClient>
|
|
|
|
#include <KToggleAction>
|
|
|
|
#include <QtCore/QAbstractItemModel>
|
|
#include <QAbstractProxyModel>
|
|
#include <QItemSelectionModel>
|
|
#include <QTabBar>
|
|
#include <QToolButton>
|
|
#include <QMouseEvent>
|
|
#include <QHeaderView>
|
|
|
|
#include <akonadi/etmviewstatesaver.h>
|
|
|
|
#include "storagemodel.h"
|
|
#include "widget.h"
|
|
#include "core/settings.h"
|
|
#include "core/manager.h"
|
|
#include <akonadi/kmime/messagestatus.h>
|
|
#include "core/model.h"
|
|
|
|
namespace MessageList
|
|
{
|
|
|
|
class Pane::Private
|
|
{
|
|
public:
|
|
Private( Pane *owner )
|
|
: q( owner ),
|
|
mXmlGuiClient( 0 ),
|
|
mActionMenu( 0 ),
|
|
mModel( 0 ),
|
|
mSelectionModel( 0 ),
|
|
mPreSelectionMode( Core::PreSelectLastSelected ),
|
|
mNewTabButton( 0 ),
|
|
mCloseTabButton( 0 ),
|
|
mCloseTabAction( 0 ),
|
|
mActivateNextTabAction( 0 ),
|
|
mActivatePreviousTabAction( 0 ),
|
|
mMoveTabLeftAction( 0 ),
|
|
mMoveTabRightAction( 0 ),
|
|
mPreferEmptyTab( false ),
|
|
mMaxTabCreated( 0 )
|
|
{ }
|
|
|
|
void onSelectionChanged( const QItemSelection &selected, const QItemSelection &deselected );
|
|
void onNewTabClicked();
|
|
void onCloseTabClicked();
|
|
void activateTab();
|
|
void closeTab( QWidget * );
|
|
void onCurrentTabChanged();
|
|
void onTabContextMenuRequest( const QPoint &pos );
|
|
void activateNextTab();
|
|
void activatePreviousTab();
|
|
void moveTabLeft();
|
|
void moveTabRight();
|
|
void moveTabBackward();
|
|
void moveTabForward();
|
|
void changeQuicksearchVisibility(bool);
|
|
void addActivateTabAction(int i);
|
|
QItemSelection mapSelectionToSource( const QItemSelection &selection ) const;
|
|
QItemSelection mapSelectionFromSource( const QItemSelection &selection ) const;
|
|
void updateTabControls();
|
|
|
|
Pane * const q;
|
|
|
|
KXMLGUIClient *mXmlGuiClient;
|
|
KActionMenu *mActionMenu;
|
|
|
|
QAbstractItemModel *mModel;
|
|
QItemSelectionModel *mSelectionModel;
|
|
Core::PreSelectionMode mPreSelectionMode;
|
|
|
|
QHash<Widget*, QItemSelectionModel*> mWidgetSelectionHash;
|
|
QList<const QAbstractProxyModel*> mProxyStack;
|
|
|
|
QToolButton *mNewTabButton;
|
|
QToolButton *mCloseTabButton;
|
|
KAction *mCloseTabAction;
|
|
KAction *mActivateNextTabAction;
|
|
KAction *mActivatePreviousTabAction;
|
|
KAction *mMoveTabLeftAction;
|
|
KAction *mMoveTabRightAction;
|
|
bool mPreferEmptyTab;
|
|
int mMaxTabCreated;
|
|
};
|
|
|
|
} // namespace MessageList
|
|
|
|
using namespace Akonadi;
|
|
using namespace MessageList;
|
|
|
|
|
|
Pane::Pane( bool restoreSession, QAbstractItemModel *model, QItemSelectionModel *selectionModel, QWidget *parent )
|
|
: KTabWidget( parent ), d( new Private( this ) )
|
|
{
|
|
setDocumentMode( true );
|
|
d->mModel = model;
|
|
d->mSelectionModel = selectionModel;
|
|
|
|
// Build the proxy stack
|
|
const QAbstractProxyModel *proxyModel = qobject_cast<const QAbstractProxyModel*>( d->mSelectionModel->model() );
|
|
|
|
while (proxyModel) {
|
|
if (static_cast<const QAbstractItemModel*>(proxyModel) == d->mModel) {
|
|
break;
|
|
}
|
|
|
|
d->mProxyStack << proxyModel;
|
|
const QAbstractProxyModel *nextProxyModel = qobject_cast<const QAbstractProxyModel*>(proxyModel->sourceModel());
|
|
|
|
if (!nextProxyModel) {
|
|
// It's the final model in the chain, so it is necessarily the sourceModel.
|
|
Q_ASSERT(qobject_cast<const QAbstractItemModel*>(proxyModel->sourceModel()) == d->mModel);
|
|
break;
|
|
}
|
|
proxyModel = nextProxyModel;
|
|
} // Proxy stack done
|
|
|
|
d->mNewTabButton = new QToolButton( this );
|
|
d->mNewTabButton->setIcon( KIcon( QLatin1String( "tab-new" ) ) );
|
|
d->mNewTabButton->adjustSize();
|
|
d->mNewTabButton->setToolTip( i18nc("@info:tooltip", "Open a new tab"));
|
|
#ifndef QT_NO_ACCESSIBILITY
|
|
d->mNewTabButton->setAccessibleName( i18n( "New tab" ) );
|
|
#endif
|
|
setCornerWidget( d->mNewTabButton, Qt::TopLeftCorner );
|
|
connect( d->mNewTabButton, SIGNAL(clicked()),
|
|
SLOT(onNewTabClicked()) );
|
|
|
|
d->mCloseTabButton = new QToolButton( this );
|
|
d->mCloseTabButton->setIcon( KIcon( QLatin1String( "tab-close" ) ) );
|
|
d->mCloseTabButton->adjustSize();
|
|
d->mCloseTabButton->setToolTip( i18nc("@info:tooltip", "Close the current tab"));
|
|
#ifndef QT_NO_ACCESSIBILITY
|
|
d->mCloseTabButton->setAccessibleName( i18n( "Close tab" ) );
|
|
#endif
|
|
setCornerWidget( d->mCloseTabButton, Qt::TopRightCorner );
|
|
connect( d->mCloseTabButton, SIGNAL(clicked()),
|
|
SLOT(onCloseTabClicked()) );
|
|
|
|
setTabsClosable( Core::Settings::self()->tabsHaveCloseButton() );
|
|
connect( this, SIGNAL(closeRequest(QWidget*)), SLOT(closeTab(QWidget*)) );
|
|
|
|
readConfig(restoreSession);
|
|
setMovable( true );
|
|
|
|
connect( d->mSelectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
|
|
this, SLOT(onSelectionChanged(QItemSelection,QItemSelection)) );
|
|
connect( this, SIGNAL(currentChanged(int)),
|
|
this, SLOT(onCurrentTabChanged()) );
|
|
|
|
setContextMenuPolicy( Qt::CustomContextMenu );
|
|
connect( this, SIGNAL(customContextMenuRequested(QPoint)),
|
|
this, SLOT(onTabContextMenuRequest(QPoint)) );
|
|
|
|
connect( Core::Settings::self(), SIGNAL(configChanged()),
|
|
this, SLOT(updateTabControls()) );
|
|
|
|
connect( this, SIGNAL(mouseDoubleClick()),
|
|
this, SLOT(createNewTab()) );
|
|
|
|
connect( this, SIGNAL(mouseMiddleClick(QWidget*)),
|
|
this, SLOT(closeTab(QWidget*)) );
|
|
tabBar()->installEventFilter( this );
|
|
}
|
|
|
|
Pane::~Pane()
|
|
{
|
|
writeConfig(true);
|
|
delete d;
|
|
}
|
|
|
|
void Pane::Private::addActivateTabAction(int i)
|
|
{
|
|
QString actionname;
|
|
actionname.sprintf("activate_tab_%02d", i);
|
|
KAction *action = new KAction( i18n("Activate Tab %1", i), q);
|
|
action->setShortcut( QKeySequence( QString::fromLatin1( "Alt+%1" ).arg( i ) ) );
|
|
mXmlGuiClient->actionCollection()->addAction( actionname, action );
|
|
connect( action, SIGNAL(triggered(bool)),q, SLOT(activateTab()) );
|
|
}
|
|
|
|
|
|
|
|
void Pane::setXmlGuiClient( KXMLGUIClient *xmlGuiClient )
|
|
{
|
|
d->mXmlGuiClient = xmlGuiClient;
|
|
|
|
KToggleAction * const showHideQuicksearch = new KToggleAction( i18n( "Show Quick Search Bar" ), this );
|
|
showHideQuicksearch->setShortcut( Qt::CTRL + Qt::Key_H );
|
|
showHideQuicksearch->setChecked( Core::Settings::showQuickSearch() );
|
|
|
|
d->mXmlGuiClient->actionCollection()->addAction( QLatin1String( "show_quick_search" ), showHideQuicksearch );
|
|
connect( showHideQuicksearch, SIGNAL(triggered(bool)), this, SLOT(changeQuicksearchVisibility(bool)) );
|
|
|
|
|
|
for ( int i=0; i<count(); ++i ) {
|
|
Widget *w = qobject_cast<Widget *>( widget( i ) );
|
|
w->setXmlGuiClient( d->mXmlGuiClient );
|
|
}
|
|
|
|
// Setup "View->Message List" actions.
|
|
if ( xmlGuiClient ) {
|
|
if ( d->mActionMenu ) {
|
|
d->mXmlGuiClient->actionCollection()->removeAction( d->mActionMenu );
|
|
}
|
|
d->mActionMenu = new KActionMenu( KIcon(), i18n( "Message List" ), this );
|
|
d->mXmlGuiClient->actionCollection()->addAction( QLatin1String( "view_message_list" ), d->mActionMenu );
|
|
MessageList::Util::fillViewMenu( d->mActionMenu->menu(), this );
|
|
|
|
d->mActionMenu->addSeparator();
|
|
|
|
KAction *action = new KAction( i18n("Create New Tab"), this );
|
|
action->setShortcut( QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_O ) );
|
|
d->mXmlGuiClient->actionCollection()->addAction( QLatin1String( "create_new_tab" ), action );
|
|
connect( action, SIGNAL(triggered(bool)), SLOT(onNewTabClicked()) );
|
|
d->mActionMenu->addAction( action );
|
|
|
|
d->mMaxTabCreated = count();
|
|
for (int i=1;i<10 && i<=count();++i) {
|
|
d->addActivateTabAction(i);
|
|
}
|
|
|
|
|
|
d->mCloseTabAction = new KAction( i18n("Close Tab"), this );
|
|
d->mCloseTabAction->setShortcut( QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_W ) );
|
|
d->mXmlGuiClient->actionCollection()->addAction( QLatin1String( "close_current_tab" ), d->mCloseTabAction );
|
|
connect( d->mCloseTabAction, SIGNAL(triggered(bool)), SLOT(onCloseTabClicked()) );
|
|
d->mActionMenu->addAction( d->mCloseTabAction );
|
|
d->mCloseTabAction->setEnabled( false );
|
|
|
|
d->mActivateNextTabAction = new KAction( i18n("Activate Next Tab"),this );
|
|
d->mXmlGuiClient->actionCollection()->addAction( QLatin1String( "activate_next_tab" ), d->mActivateNextTabAction );
|
|
d->mActivateNextTabAction->setEnabled( false );
|
|
connect( d->mActivateNextTabAction, SIGNAL(triggered(bool)), SLOT(activateNextTab()) );
|
|
|
|
d->mActivatePreviousTabAction = new KAction( i18n("Activate Previous Tab"),this );
|
|
d->mXmlGuiClient->actionCollection()->addAction( QLatin1String( "activate_previous_tab" ), d->mActivatePreviousTabAction );
|
|
d->mActivatePreviousTabAction->setEnabled( false );
|
|
connect( d->mActivatePreviousTabAction, SIGNAL(triggered(bool)), SLOT(activatePreviousTab()) );
|
|
|
|
|
|
d->mMoveTabLeftAction = new KAction( i18n("Move Tab Left"),this );
|
|
d->mXmlGuiClient->actionCollection()->addAction( QLatin1String( "move_tab_left" ), d->mMoveTabLeftAction );
|
|
d->mMoveTabLeftAction->setEnabled( false );
|
|
connect( d->mMoveTabLeftAction, SIGNAL(triggered(bool)), SLOT(moveTabLeft()) );
|
|
|
|
d->mMoveTabRightAction = new KAction( i18n("Move Tab Right"),this );
|
|
d->mXmlGuiClient->actionCollection()->addAction( QLatin1String( "move_tab_right" ), d->mMoveTabRightAction );
|
|
d->mMoveTabRightAction->setEnabled( false );
|
|
connect( d->mMoveTabRightAction, SIGNAL(triggered(bool)), SLOT(moveTabRight()) );
|
|
}
|
|
}
|
|
|
|
bool Pane::selectNextMessageItem( MessageList::Core::MessageTypeFilter messageTypeFilter,
|
|
MessageList::Core::ExistingSelectionBehaviour existingSelectionBehaviour,
|
|
bool centerItem,
|
|
bool loop )
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
|
|
if ( w ) {
|
|
if ( w->view()->model()->isLoading() )
|
|
return true;
|
|
|
|
return w->selectNextMessageItem( messageTypeFilter, existingSelectionBehaviour, centerItem, loop );
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Pane::selectPreviousMessageItem( MessageList::Core::MessageTypeFilter messageTypeFilter,
|
|
MessageList::Core::ExistingSelectionBehaviour existingSelectionBehaviour,
|
|
bool centerItem,
|
|
bool loop )
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
|
|
if ( w ) {
|
|
if ( w->view()->model()->isLoading() )
|
|
return true;
|
|
|
|
return w->selectPreviousMessageItem( messageTypeFilter, existingSelectionBehaviour, centerItem, loop );
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Pane::focusNextMessageItem( MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem, bool loop )
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
|
|
if ( w ) {
|
|
if ( w->view()->model()->isLoading() )
|
|
return true;
|
|
|
|
return w->focusNextMessageItem( messageTypeFilter, centerItem, loop );
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Pane::focusPreviousMessageItem( MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem, bool loop )
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
|
|
if ( w ) {
|
|
if ( w->view()->model()->isLoading() )
|
|
return true;
|
|
|
|
return w->focusPreviousMessageItem( messageTypeFilter, centerItem, loop );
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void Pane::selectFocusedMessageItem( bool centerItem )
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
|
|
if ( w ) {
|
|
if ( w->view()->model()->isLoading() )
|
|
return;
|
|
|
|
w->selectFocusedMessageItem( centerItem );
|
|
}
|
|
}
|
|
|
|
bool Pane::selectFirstMessageItem( MessageList::Core::MessageTypeFilter messageTypeFilter, bool centerItem )
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
|
|
if ( w ) {
|
|
if ( w->view()->model()->isLoading() )
|
|
return true;
|
|
|
|
return w->selectFirstMessageItem( messageTypeFilter, centerItem );
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Pane::selectLastMessageItem(Core::MessageTypeFilter messageTypeFilter, bool centerItem)
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
|
|
if ( w ) {
|
|
if ( w->view()->model()->isLoading() )
|
|
return true;
|
|
|
|
return w->selectLastMessageItem( messageTypeFilter, centerItem );
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void Pane::selectAll()
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
|
|
if ( w ) {
|
|
if ( w->view()->model()->isLoading() )
|
|
return;
|
|
|
|
w->selectAll();
|
|
}
|
|
}
|
|
|
|
|
|
void Pane::setCurrentThreadExpanded( bool expand )
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
|
|
if ( w ) {
|
|
if ( w->view()->model()->isLoading() )
|
|
return;
|
|
|
|
w->setCurrentThreadExpanded(expand );
|
|
}
|
|
}
|
|
|
|
void Pane::setAllThreadsExpanded( bool expand )
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
|
|
if ( w ) {
|
|
if ( w->view()->model()->isLoading() )
|
|
return;
|
|
|
|
w->setAllThreadsExpanded( expand );
|
|
}
|
|
}
|
|
|
|
void Pane::setAllGroupsExpanded( bool expand )
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
|
|
if ( w ) {
|
|
if ( w->view()->model()->isLoading() )
|
|
return;
|
|
|
|
w->setAllGroupsExpanded(expand);
|
|
}
|
|
}
|
|
|
|
void Pane::focusQuickSearch(const QString &selectedText)
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
|
|
if ( w ) {
|
|
w->focusQuickSearch(selectedText);
|
|
}
|
|
}
|
|
|
|
void Pane::setQuickSearchClickMessage(const QString &msg)
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
|
|
if ( w ) {
|
|
w->setQuickSearchClickMessage(msg);
|
|
}
|
|
}
|
|
|
|
|
|
void Pane::Private::onSelectionChanged( const QItemSelection &selected, const QItemSelection &deselected )
|
|
{
|
|
if ( mPreferEmptyTab ) {
|
|
q->createNewTab();
|
|
}
|
|
|
|
Widget *w = static_cast<Widget*>( q->currentWidget() );
|
|
QItemSelectionModel * s = mWidgetSelectionHash[w];
|
|
|
|
w->saveCurrentSelection();
|
|
|
|
// Deselect old before we select new - so that the messagelist can clear first.
|
|
s->select( mapSelectionToSource( deselected ), QItemSelectionModel::Deselect );
|
|
if ( s->selection().isEmpty() ) {
|
|
w->view()->model()->setPreSelectionMode( mPreSelectionMode );
|
|
}
|
|
s->select( mapSelectionToSource( selected ), QItemSelectionModel::Select );
|
|
|
|
QString label;
|
|
QIcon icon;
|
|
QString toolTip;
|
|
foreach ( const QModelIndex &index, s->selectedRows() ) {
|
|
label+= index.data( Qt::DisplayRole ).toString()+QLatin1String( ", " );
|
|
}
|
|
label.chop( 2 );
|
|
|
|
if ( label.isEmpty() ) {
|
|
label = i18nc( "@title:tab Empty messagelist", "Empty" );
|
|
icon = QIcon();
|
|
} else if ( s->selectedRows().size()==1 ) {
|
|
icon = s->selectedRows().first().data( Qt::DecorationRole ).value<QIcon>();
|
|
QModelIndex idx = s->selectedRows().first().parent();
|
|
toolTip = label;
|
|
while ( idx != QModelIndex() ) {
|
|
toolTip = idx.data().toString() + QLatin1Char( '/' ) + toolTip;
|
|
idx = idx.parent();
|
|
}
|
|
} else {
|
|
icon = KIcon( QLatin1String( "folder" ) );
|
|
}
|
|
|
|
const int index = q->indexOf( w );
|
|
q->setTabText( index, label );
|
|
q->setTabIcon( index, icon );
|
|
q->setTabToolTip( index, toolTip);
|
|
if ( mPreferEmptyTab ) {
|
|
disconnect( mSelectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
|
|
q, SLOT(onSelectionChanged(QItemSelection,QItemSelection)) );
|
|
|
|
mSelectionModel->select( mapSelectionFromSource( s->selection() ),
|
|
QItemSelectionModel::ClearAndSelect );
|
|
|
|
connect( mSelectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
|
|
q, SLOT(onSelectionChanged(QItemSelection,QItemSelection)) );
|
|
|
|
}
|
|
}
|
|
|
|
void Pane::Private::activateTab()
|
|
{
|
|
q->tabBar()->setCurrentIndex( q->sender()->objectName().right( 2 ).toInt() -1 );
|
|
}
|
|
|
|
void Pane::Private::moveTabRight()
|
|
{
|
|
const int numberOfTab = q->tabBar()->count();
|
|
if( numberOfTab == 1 )
|
|
return;
|
|
if ( QApplication::isRightToLeft() )
|
|
moveTabForward();
|
|
else
|
|
moveTabBackward();
|
|
|
|
}
|
|
|
|
void Pane::Private::moveTabLeft()
|
|
{
|
|
const int numberOfTab = q->tabBar()->count();
|
|
if( numberOfTab == 1 )
|
|
return;
|
|
if ( QApplication::isRightToLeft() )
|
|
moveTabBackward();
|
|
else
|
|
moveTabForward();
|
|
|
|
}
|
|
|
|
void Pane::Private::moveTabForward()
|
|
{
|
|
const int currentIndex = q->tabBar()->currentIndex();
|
|
if ( currentIndex == q->tabBar()->count()-1 )
|
|
return;
|
|
q->tabBar()->moveTab( currentIndex, currentIndex+1 );
|
|
}
|
|
|
|
void Pane::Private::moveTabBackward()
|
|
{
|
|
const int currentIndex = q->tabBar()->currentIndex();
|
|
if ( currentIndex == 0 )
|
|
return;
|
|
q->tabBar()->moveTab( currentIndex, currentIndex-1 );
|
|
}
|
|
|
|
void Pane::Private::activateNextTab()
|
|
{
|
|
const int numberOfTab = q->tabBar()->count();
|
|
if( numberOfTab == 1 )
|
|
return;
|
|
|
|
int indexTab = ( q->tabBar()->currentIndex() + 1 );
|
|
|
|
if( indexTab == numberOfTab )
|
|
indexTab = 0;
|
|
|
|
q->tabBar()->setCurrentIndex( indexTab );
|
|
}
|
|
|
|
void Pane::Private::activatePreviousTab()
|
|
{
|
|
const int numberOfTab = q->tabBar()->count();
|
|
if( numberOfTab == 1 )
|
|
return;
|
|
|
|
int indexTab = ( q->tabBar()->currentIndex() - 1 );
|
|
|
|
if( indexTab == -1 )
|
|
indexTab = numberOfTab - 1;
|
|
|
|
q->tabBar()->setCurrentIndex( indexTab );
|
|
}
|
|
|
|
void Pane::Private::onNewTabClicked()
|
|
{
|
|
q->createNewTab();
|
|
}
|
|
|
|
void Pane::Private::onCloseTabClicked()
|
|
{
|
|
closeTab( q->currentWidget() );
|
|
}
|
|
|
|
void Pane::Private::closeTab( QWidget *w )
|
|
{
|
|
if ( !w || (q->count() < 2) ) {
|
|
return;
|
|
}
|
|
|
|
delete w;
|
|
updateTabControls();
|
|
}
|
|
|
|
|
|
void Pane::Private::changeQuicksearchVisibility(bool show)
|
|
{
|
|
for ( int i=0; i<q->count(); ++i ) {
|
|
Widget *w = qobject_cast<Widget *>( q->widget( i ) );
|
|
w->changeQuicksearchVisibility(show);
|
|
}
|
|
}
|
|
|
|
|
|
bool Pane::eventFilter( QObject *object, QEvent *event )
|
|
{
|
|
if ( event->type() == QEvent::MouseButtonPress ) {
|
|
QMouseEvent * const mouseEvent = static_cast<QMouseEvent *>( event );
|
|
if ( mouseEvent->button() == Qt::MidButton ) {
|
|
return true;
|
|
}
|
|
}
|
|
return KTabWidget::eventFilter( object, event );
|
|
}
|
|
|
|
void Pane::Private::onCurrentTabChanged()
|
|
{
|
|
emit q->currentTabChanged();
|
|
|
|
Widget *w = static_cast<Widget*>( q->currentWidget() );
|
|
|
|
QItemSelectionModel *s = mWidgetSelectionHash[w];
|
|
|
|
disconnect( mSelectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
|
|
q, SLOT(onSelectionChanged(QItemSelection,QItemSelection)) );
|
|
|
|
mSelectionModel->select( mapSelectionFromSource( s->selection() ),
|
|
QItemSelectionModel::ClearAndSelect );
|
|
|
|
connect( mSelectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
|
|
q, SLOT(onSelectionChanged(QItemSelection,QItemSelection)) );
|
|
}
|
|
|
|
void Pane::Private::onTabContextMenuRequest( const QPoint &pos )
|
|
{
|
|
QTabBar *bar = q->tabBar();
|
|
if ( q->count() <= 1 ) return;
|
|
|
|
const int indexBar = bar->tabAt( bar->mapFrom( q, pos ) );
|
|
if ( indexBar == -1 ) return;
|
|
|
|
Widget *w = qobject_cast<Widget *>( q->widget( indexBar ) );
|
|
if ( !w ) return;
|
|
|
|
KMenu menu( q );
|
|
|
|
|
|
QAction *closeTabAction = menu.addAction( i18nc( "@action:inmenu", "Close Tab" ) );
|
|
closeTabAction->setIcon( KIcon( QLatin1String( "tab-close" ) ) );
|
|
|
|
QAction *allOther = menu.addAction( i18nc("@action:inmenu", "Close All Other Tabs" ) );
|
|
allOther->setIcon( KIcon( QLatin1String( "tab-close-other" ) ) );
|
|
|
|
QAction *action = menu.exec( q->mapToGlobal( pos ) );
|
|
|
|
if ( action == allOther ) { // Close all other tabs
|
|
QList<Widget *> widgets;
|
|
const int index = q->indexOf( w );
|
|
|
|
for ( int i=0; i<q->count(); ++i ) {
|
|
if ( i==index) continue; // Skip the current one
|
|
|
|
Widget *other = qobject_cast<Widget *>( q->widget( i ) );
|
|
widgets << other;
|
|
}
|
|
|
|
foreach ( Widget *other, widgets ) {
|
|
delete other;
|
|
}
|
|
|
|
updateTabControls();
|
|
} else if (action == closeTabAction) {
|
|
closeTab(q->widget(indexBar));
|
|
}
|
|
}
|
|
|
|
MessageList::StorageModel *Pane::createStorageModel( QAbstractItemModel *model, QItemSelectionModel *selectionModel, QObject *parent )
|
|
{
|
|
return new MessageList::StorageModel( model, selectionModel, parent );
|
|
}
|
|
|
|
void Pane::setCurrentFolder( const Akonadi::Collection &collection, bool, Core::PreSelectionMode preSelectionMode, const QString &overrideLabel )
|
|
{
|
|
d->mPreSelectionMode = preSelectionMode;
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
if ( w ) {
|
|
w->setCurrentFolder( collection );
|
|
QItemSelectionModel *s = d->mWidgetSelectionHash[w];
|
|
MessageList::StorageModel *m = createStorageModel( d->mModel, s, w );
|
|
w->setStorageModel( m, preSelectionMode );
|
|
if ( !overrideLabel.isEmpty() ) {
|
|
int index = indexOf( w );
|
|
setTabText( index, overrideLabel );
|
|
}
|
|
}
|
|
}
|
|
|
|
void Pane::updateTabIconText( const Akonadi::Collection &collection, const QString&label, const QIcon& icon )
|
|
{
|
|
for ( int i=0; i<count(); ++i ) {
|
|
Widget *w = qobject_cast<Widget *>( widget( i ) );
|
|
if ( w->currentCollection() == collection )
|
|
{
|
|
const int index = indexOf( w );
|
|
setTabText( index, label );
|
|
setTabIcon( index, icon );
|
|
}
|
|
}
|
|
}
|
|
|
|
QItemSelectionModel *Pane::createNewTab()
|
|
{
|
|
Widget * w = new Widget( this );
|
|
w->setXmlGuiClient( d->mXmlGuiClient );
|
|
|
|
addTab( w, i18nc( "@title:tab Empty messagelist", "Empty" ) );
|
|
|
|
if(d->mXmlGuiClient && count() < 10) {
|
|
if(d->mMaxTabCreated < count() ) {
|
|
d->mMaxTabCreated = count();
|
|
d->addActivateTabAction(d->mMaxTabCreated);
|
|
}
|
|
}
|
|
|
|
QItemSelectionModel *s = new QItemSelectionModel( d->mModel, w );
|
|
MessageList::StorageModel *m = createStorageModel( d->mModel, s, w );
|
|
w->setStorageModel( m );
|
|
|
|
d->mWidgetSelectionHash[w] = s;
|
|
|
|
connect( w, SIGNAL(messageSelected(Akonadi::Item)),
|
|
this, SIGNAL(messageSelected(Akonadi::Item)) );
|
|
connect( w, SIGNAL(messageActivated(Akonadi::Item)),
|
|
this, SIGNAL(messageActivated(Akonadi::Item)) );
|
|
connect( w, SIGNAL(selectionChanged()),
|
|
this, SIGNAL(selectionChanged()) );
|
|
connect( w, SIGNAL(messageStatusChangeRequest(Akonadi::Item,Akonadi::MessageStatus,Akonadi::MessageStatus)),
|
|
this, SIGNAL(messageStatusChangeRequest(Akonadi::Item,Akonadi::MessageStatus,Akonadi::MessageStatus)) );
|
|
|
|
connect( w, SIGNAL(statusMessage(QString)),
|
|
this, SIGNAL(statusMessage(QString)) );
|
|
|
|
d->updateTabControls();
|
|
setCurrentWidget( w );
|
|
return s;
|
|
}
|
|
|
|
QItemSelection Pane::Private::mapSelectionToSource( const QItemSelection &selection ) const
|
|
{
|
|
QItemSelection result = selection;
|
|
|
|
foreach ( const QAbstractProxyModel *proxy, mProxyStack ) {
|
|
result = proxy->mapSelectionToSource( result );
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
QItemSelection Pane::Private::mapSelectionFromSource( const QItemSelection &selection ) const
|
|
{
|
|
QItemSelection result = selection;
|
|
|
|
typedef QList<const QAbstractProxyModel*>::ConstIterator Iterator;
|
|
|
|
for ( Iterator it = mProxyStack.end()-1; it!=mProxyStack.begin(); --it ) {
|
|
result = (*it)->mapSelectionFromSource( result );
|
|
}
|
|
result = mProxyStack.first()->mapSelectionFromSource( result );
|
|
|
|
return result;
|
|
}
|
|
|
|
void Pane::Private::updateTabControls()
|
|
{
|
|
const bool enableAction = ( q->count()>1 );
|
|
if (mCloseTabButton)
|
|
mCloseTabButton->setEnabled( enableAction );
|
|
if ( mCloseTabAction )
|
|
mCloseTabAction->setEnabled( enableAction );
|
|
if ( mActivatePreviousTabAction )
|
|
mActivatePreviousTabAction->setEnabled( enableAction );
|
|
if ( mActivateNextTabAction )
|
|
mActivateNextTabAction->setEnabled( enableAction );
|
|
if ( mMoveTabRightAction )
|
|
mMoveTabRightAction->setEnabled( enableAction );
|
|
if ( mMoveTabLeftAction )
|
|
mMoveTabLeftAction->setEnabled( enableAction );
|
|
|
|
if ( Core::Settings::self()->autoHideTabBarWithSingleTab() ) {
|
|
q->tabBar()->setVisible( enableAction );
|
|
} else {
|
|
q->tabBar()->setVisible( true );
|
|
}
|
|
|
|
const bool hasCloseButton(Core::Settings::self()->tabsHaveCloseButton());
|
|
q->setTabsClosable( hasCloseButton );
|
|
if( hasCloseButton ) {
|
|
const int numberOfTab(q->count());
|
|
if( numberOfTab ==1) {
|
|
q->tabBar()->tabButton(0, QTabBar::RightSide)->setEnabled(false);
|
|
} else if(numberOfTab > 1) {
|
|
q->tabBar()->tabButton(0, QTabBar::RightSide)->setEnabled(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
Item Pane::currentItem() const
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
|
|
if ( w == 0 ) {
|
|
return Item();
|
|
}
|
|
|
|
return w->currentItem();
|
|
}
|
|
|
|
KMime::Message::Ptr Pane::currentMessage() const
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
|
|
if ( w == 0 ) {
|
|
return KMime::Message::Ptr();
|
|
}
|
|
|
|
return w->currentMessage();
|
|
}
|
|
|
|
QList<KMime::Message::Ptr > Pane::selectionAsMessageList( bool includeCollapsedChildren ) const
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
if ( w == 0 ) {
|
|
return QList<KMime::Message::Ptr>();
|
|
}
|
|
return w->selectionAsMessageList( includeCollapsedChildren );
|
|
}
|
|
|
|
QList<Akonadi::Item> Pane::selectionAsMessageItemList( bool includeCollapsedChildren ) const
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
if ( w == 0 ) {
|
|
return QList<Akonadi::Item>();
|
|
}
|
|
return w->selectionAsMessageItemList( includeCollapsedChildren );
|
|
}
|
|
|
|
QList<Akonadi::Item::Id> Pane::selectionAsListMessageId( bool includeCollapsedChildren ) const
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
if ( w == 0 ) {
|
|
return QList<Akonadi::Item::Id>();
|
|
}
|
|
return w->selectionAsListMessageId( includeCollapsedChildren );
|
|
}
|
|
|
|
|
|
QVector<qlonglong> Pane::selectionAsMessageItemListId( bool includeCollapsedChildren ) const
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
if ( w == 0 ) {
|
|
return QVector<qlonglong>();
|
|
}
|
|
return w->selectionAsMessageItemListId( includeCollapsedChildren );
|
|
}
|
|
|
|
|
|
QList<Akonadi::Item> Pane::currentThreadAsMessageList() const
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
if ( w == 0 ) {
|
|
return QList<Akonadi::Item>();
|
|
}
|
|
return w->currentThreadAsMessageList();
|
|
}
|
|
|
|
QList<Akonadi::Item> Pane::itemListFromPersistentSet( MessageList::Core::MessageItemSetReference ref )
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
if ( w ) {
|
|
return w->itemListFromPersistentSet(ref);
|
|
}
|
|
return QList<Akonadi::Item>();
|
|
}
|
|
|
|
void Pane::deletePersistentSet( MessageList::Core::MessageItemSetReference ref )
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
if ( w ) {
|
|
w->deletePersistentSet( ref );
|
|
}
|
|
}
|
|
|
|
void Pane::markMessageItemsAsAboutToBeRemoved( MessageList::Core::MessageItemSetReference ref, bool bMark )
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
if ( w ) {
|
|
w->markMessageItemsAsAboutToBeRemoved( ref, bMark );
|
|
}
|
|
}
|
|
|
|
QList<Akonadi::MessageStatus> Pane::currentFilterStatus() const
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
if ( w == 0 ) {
|
|
return QList<Akonadi::MessageStatus>();
|
|
}
|
|
return w->currentFilterStatus();
|
|
}
|
|
|
|
QString Pane::currentFilterSearchString() const
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
if ( w ) {
|
|
return w->currentFilterSearchString();
|
|
}
|
|
return QString();
|
|
}
|
|
|
|
bool Pane::isThreaded() const
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
if ( w ) {
|
|
return w->isThreaded();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Pane::selectionEmpty() const
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
if ( w ) {
|
|
return w->selectionEmpty();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Pane::getSelectionStats( Akonadi::Item::List &selectedItems,
|
|
Akonadi::Item::List &selectedVisibleItems,
|
|
bool * allSelectedBelongToSameThread,
|
|
bool includeCollapsedChildren ) const
|
|
{
|
|
Widget * w = static_cast<Widget*>( currentWidget() );
|
|
if ( w == 0 ) {
|
|
return false;
|
|
}
|
|
|
|
return w->getSelectionStats(
|
|
selectedItems, selectedVisibleItems,
|
|
allSelectedBelongToSameThread, includeCollapsedChildren
|
|
);
|
|
}
|
|
|
|
MessageList::Core::MessageItemSetReference Pane::selectionAsPersistentSet( bool includeCollapsedChildren ) const
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
if ( w )
|
|
return w->selectionAsPersistentSet( includeCollapsedChildren );
|
|
return -1;
|
|
}
|
|
|
|
MessageList::Core::MessageItemSetReference Pane::currentThreadAsPersistentSet() const
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
if ( w )
|
|
return w->currentThreadAsPersistentSet();
|
|
return -1;
|
|
}
|
|
|
|
void Pane::focusView()
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
if ( w ) {
|
|
QWidget *view = w->view();
|
|
if ( view )
|
|
view->setFocus();
|
|
}
|
|
}
|
|
|
|
void Pane::reloadGlobalConfiguration()
|
|
{
|
|
d->updateTabControls();
|
|
}
|
|
|
|
QItemSelectionModel* Pane::currentItemSelectionModel()
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
if ( w )
|
|
return w->view()->selectionModel();
|
|
return 0;
|
|
}
|
|
|
|
void Pane::resetModelStorage()
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
if ( w ) {
|
|
MessageList::StorageModel *m = static_cast<MessageList::StorageModel*>( w->storageModel() );
|
|
if ( m )
|
|
m->resetModelStorage();
|
|
}
|
|
}
|
|
|
|
void Pane::setPreferEmptyTab( bool emptyTab )
|
|
{
|
|
d->mPreferEmptyTab = emptyTab;
|
|
}
|
|
|
|
void Pane::saveCurrentSelection()
|
|
{
|
|
for ( int i=0; i<count(); ++i ) {
|
|
Widget *w = qobject_cast<Widget *>( widget( i ) );
|
|
w->saveCurrentSelection();
|
|
}
|
|
}
|
|
|
|
void Pane::updateTagComboBox()
|
|
{
|
|
for ( int i=0; i<count(); ++i ) {
|
|
Widget *w = qobject_cast<Widget *>( widget( i ) );
|
|
w->populateStatusFilterCombo();
|
|
}
|
|
}
|
|
|
|
void Pane::writeConfig(bool restoreSession)
|
|
{
|
|
KConfigGroup conf( MessageList::Core::Settings::self()->config(),"MessageListPane");
|
|
|
|
// Delete list before
|
|
const QStringList list = MessageList::Core::Settings::self()->config()->groupList().filter( QRegExp( QLatin1String("MessageListTab\\d+") ) );
|
|
foreach ( const QString &group, list ) {
|
|
MessageList::Core::Settings::self()->config()->deleteGroup( group );
|
|
}
|
|
|
|
if (restoreSession) {
|
|
conf.writeEntry(QLatin1String("currentIndex"),currentIndex());
|
|
conf.writeEntry(QLatin1String("tabNumber"),count());
|
|
|
|
for ( int i=0; i<count(); ++i ) {
|
|
Widget *w = qobject_cast<Widget *>( widget( i ) );
|
|
KConfigGroup grp(MessageList::Core::Settings::self()->config(),QString::fromLatin1("MessageListTab%1").arg(i));
|
|
grp.writeEntry(QLatin1String("collectionId"),w->currentCollection().id());
|
|
grp.writeEntry(QLatin1String("HeaderState"), w->view()->header()->saveState());
|
|
}
|
|
}
|
|
conf.sync();
|
|
}
|
|
|
|
|
|
void Pane::readConfig(bool restoreSession)
|
|
{
|
|
if(restoreSession && MessageList::Core::Settings::self()->config()->hasGroup(QLatin1String("MessageListPane"))) {
|
|
KConfigGroup conf( MessageList::Core::Settings::self()->config(),"MessageListPane");
|
|
const int numberOfTab = conf.readEntry(QLatin1String("tabNumber"),0);
|
|
if(numberOfTab == 0) {
|
|
createNewTab();
|
|
} else {
|
|
for(int i = 0; i<numberOfTab; ++i) {
|
|
KConfigGroup grp(MessageList::Core::Settings::self()->config(),QString::fromLatin1("MessageListTab%1").arg(i));
|
|
QItemSelectionModel *selectionModel = createNewTab();
|
|
#if 0
|
|
Akonadi::Collection::Id id = grp.readEntry(QLatin1String("collectionId"),-1);
|
|
ETMViewStateSaver *saver = new ETMViewStateSaver;
|
|
saver->setSelectionModel(selectionModel);
|
|
|
|
if(id != -1) {
|
|
ETMViewStateSaver *saver = new ETMViewStateSaver;
|
|
saver->setSelectionModel(selectionModel);
|
|
saver->restoreState( grp );
|
|
saver->selectCollections(Akonadi::Collection::List()<<Akonadi::Collection(id));
|
|
saver->restoreCurrentItem( QString::fromLatin1("c%1").arg(id) );
|
|
}
|
|
#else
|
|
Q_UNUSED( selectionModel );
|
|
#endif
|
|
Widget *w = qobject_cast<Widget *>( widget( i ) );
|
|
w->view()->header()->restoreState(grp.readEntry(QLatin1String("HeaderState"),QByteArray()));
|
|
}
|
|
setCurrentIndex(conf.readEntry(QLatin1String("currentIndex"),0));
|
|
}
|
|
} else {
|
|
createNewTab();
|
|
}
|
|
}
|
|
|
|
|
|
bool Pane::searchEditHasFocus() const
|
|
{
|
|
Widget *w = static_cast<Widget*>( currentWidget() );
|
|
if ( w )
|
|
return w->searchEditHasFocus();
|
|
return false;
|
|
}
|
|
|
|
|
|
void Pane::sortOrderMenuAboutToShow()
|
|
{
|
|
KMenu * menu = dynamic_cast< KMenu * >( sender() );
|
|
if ( !menu )
|
|
return;
|
|
const Widget * const w = static_cast<Widget*>( currentWidget() );
|
|
w->view()->sortOrderMenuAboutToShow(menu);
|
|
}
|
|
|
|
void Pane::aggregationMenuAboutToShow()
|
|
{
|
|
KMenu * menu = dynamic_cast< KMenu * >( sender() );
|
|
if ( !menu )
|
|
return;
|
|
const Widget * const w = static_cast<Widget*>( currentWidget() );
|
|
w->view()->aggregationMenuAboutToShow(menu);
|
|
}
|
|
|
|
void Pane::themeMenuAboutToShow()
|
|
{
|
|
KMenu * menu = dynamic_cast< KMenu * >( sender() );
|
|
if ( !menu )
|
|
return;
|
|
const Widget * const w = static_cast<Widget*>( currentWidget() );
|
|
w->view()->themeMenuAboutToShow(menu);
|
|
}
|
|
|
|
void Pane::populateStatusFilterCombo()
|
|
{
|
|
for ( int i=0; i<count(); ++i ) {
|
|
Widget *w = qobject_cast<Widget *>( widget( i ) );
|
|
w->populateStatusFilterCombo();
|
|
}
|
|
}
|
|
|
|
#include "moc_pane.cpp"
|