diff --git a/akonadi/agenttypemodel.cpp b/akonadi/agenttypemodel.cpp index 00fae3c0f..25ec9815c 100644 --- a/akonadi/agenttypemodel.cpp +++ b/akonadi/agenttypemodel.cpp @@ -1,144 +1,158 @@ /* Copyright (c) 2006 Tobias Koenig This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "agenttypemodel.h" #include "agenttype.h" #include "agentmanager.h" #include #include using namespace Akonadi; /** * @internal */ class AgentTypeModel::Private { public: Private( AgentTypeModel *parent ) : mParent( parent ) { mTypes = AgentManager::self()->types(); } AgentTypeModel *mParent; AgentType::List mTypes; void typeAdded( const AgentType &agentType ); void typeRemoved( const AgentType &agentType ); }; void AgentTypeModel::Private::typeAdded( const AgentType &agentType ) { mTypes.append( agentType ); emit mParent->layoutChanged(); } void AgentTypeModel::Private::typeRemoved( const AgentType &agentType ) { mTypes.removeAll( agentType ); emit mParent->layoutChanged(); } AgentTypeModel::AgentTypeModel( QObject *parent ) : QAbstractItemModel( parent ), d( new Private( this ) ) { connect( AgentManager::self(), SIGNAL( typeAdded( const Akonadi::AgentType& ) ), this, SLOT( typeAdded( const Akonadi::AgentType& ) ) ); connect( AgentManager::self(), SIGNAL( typeRemoved( const Akonadi::AgentType& ) ), this, SLOT( typeRemoved( const Akonadi::AgentType& ) ) ); } AgentTypeModel::~AgentTypeModel() { delete d; } int AgentTypeModel::columnCount( const QModelIndex& ) const { return 1; } int AgentTypeModel::rowCount( const QModelIndex& ) const { return d->mTypes.count(); } QVariant AgentTypeModel::data( const QModelIndex &index, int role ) const { if ( !index.isValid() ) return QVariant(); if ( index.row() < 0 || index.row() >= d->mTypes.count() ) return QVariant(); const AgentType &type = d->mTypes[ index.row() ]; switch ( role ) { case Qt::DisplayRole: return type.name(); break; case Qt::DecorationRole: return type.icon(); break; case TypeRole: { QVariant var; var.setValue( type ); return var; } break; case IdentifierRole: return type.identifier(); break; case DescriptionRole: return type.description(); break; case MimeTypesRole: return type.mimeTypes(); break; case CapabilitiesRole: return type.capabilities(); break; default: break; } return QVariant(); } QModelIndex AgentTypeModel::index( int row, int column, const QModelIndex& ) const { if ( row < 0 || row >= d->mTypes.count() ) return QModelIndex(); if ( column != 0 ) return QModelIndex(); return createIndex( row, column, 0 ); } QModelIndex AgentTypeModel::parent( const QModelIndex& ) const { return QModelIndex(); } +Qt::ItemFlags AgentTypeModel::flags(const QModelIndex& index) const +{ + if ( !index.isValid() || index.row() < 0 || index.row() >= d->mTypes.count() ) + return QAbstractItemModel::flags( index ); + + const AgentType &type = d->mTypes[ index.row() ]; + if ( type.capabilities().contains( QLatin1String( "Unique" ) ) && + AgentManager::self()->instance( type.identifier() ).isValid() ) + { + return QAbstractItemModel::flags( index ) & ~(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + } + return QAbstractItemModel::flags(index); +} + #include "agenttypemodel.moc" diff --git a/akonadi/agenttypemodel.h b/akonadi/agenttypemodel.h index 9c070c76a..41f1dff24 100644 --- a/akonadi/agenttypemodel.h +++ b/akonadi/agenttypemodel.h @@ -1,96 +1,97 @@ /* Copyright (c) 2006-2008 Tobias Koenig This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef AKONADI_AGENTTYPEMODEL_H #define AKONADI_AGENTTYPEMODEL_H #include "akonadi_export.h" #include namespace Akonadi { /** * @short Provides a data model for agent types. * * This class provides the interface of a QAbstractItemModel to * access all available agent types: their name, identifier, * supported mimetypes and capabilities. * * @code * * Akonadi::AgentTypeModel *model = new Akonadi::AgentTypeModel( this ); * * QListView *view = new QListView( this ); * view->setModel( model ); * * @endcode * * To show only agent types that match a given mime type or special * capabilities, use the AgentFilterProxyModel on top of this model. * * @author Tobias Koenig */ class AKONADI_EXPORT AgentTypeModel : public QAbstractItemModel { Q_OBJECT public: /** * Describes the roles of this model. */ enum Roles { TypeRole = Qt::UserRole + 1, ///< The agent type itself IdentifierRole, ///< The identifier of the agent type DescriptionRole, ///< A description of the agent type MimeTypesRole, ///< A list of supported mimetypes CapabilitiesRole, ///< A list of supported capabilities UserRole = Qt::UserRole + 42 ///< Role for user extensions }; /** * Creates a new agent type model. */ explicit AgentTypeModel( QObject *parent = 0 ); /** * Destroys the agent type model. */ virtual ~AgentTypeModel(); virtual int columnCount( const QModelIndex &parent = QModelIndex() ) const; virtual int rowCount( const QModelIndex &parent = QModelIndex() ) const; virtual QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const; virtual QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const; virtual QModelIndex parent( const QModelIndex &index ) const; + virtual Qt::ItemFlags flags(const QModelIndex& index) const; private: //@cond PRIVATE class Private; Private* const d; Q_PRIVATE_SLOT( d, void typeAdded( const Akonadi::AgentType& ) ) Q_PRIVATE_SLOT( d, void typeRemoved( const Akonadi::AgentType& ) ) //@endcond }; } #endif diff --git a/akonadi/agenttypewidget.cpp b/akonadi/agenttypewidget.cpp index e0afe1631..6dac70c41 100644 --- a/akonadi/agenttypewidget.cpp +++ b/akonadi/agenttypewidget.cpp @@ -1,250 +1,258 @@ /* Copyright (c) 2006-2008 Tobias Koenig This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "agenttypewidget.h" +#include + #include #include #include #include #include "agentfilterproxymodel.h" #include "agenttype.h" #include "agenttypemodel.h" using namespace Akonadi; /** * @internal */ class AgentTypeWidgetDelegate : public QAbstractItemDelegate { public: AgentTypeWidgetDelegate( QObject *parent = 0 ); virtual void paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const; virtual QSize sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const; private: void drawFocus( QPainter*, const QStyleOptionViewItem&, const QRect& ) const; }; /** * @internal */ class AgentTypeWidget::Private { public: Private( AgentTypeWidget *parent ) : mParent( parent ) { } void currentAgentTypeChanged( const QModelIndex&, const QModelIndex& ); + void typeActivated( const QModelIndex &index ) + { + if ( index.flags() & (Qt::ItemIsSelectable | Qt::ItemIsEnabled) ) + emit mParent->activated(); + } + AgentTypeWidget *mParent; QListView *mView; AgentTypeModel *mModel; AgentFilterProxyModel *proxyModel; }; void AgentTypeWidget::Private::currentAgentTypeChanged( const QModelIndex ¤tIndex, const QModelIndex &previousIndex ) { AgentType currentType; if ( currentIndex.isValid() ) currentType = currentIndex.data( AgentTypeModel::TypeRole ).value(); AgentType previousType; if ( previousIndex.isValid() ) previousType = previousIndex.data( AgentTypeModel::TypeRole ).value(); emit mParent->currentChanged( currentType, previousType ); } AgentTypeWidget::AgentTypeWidget( QWidget *parent ) : QWidget( parent ), d( new Private( this ) ) { QHBoxLayout *layout = new QHBoxLayout( this ); layout->setMargin( 0 ); d->mView = new QListView( this ); d->mView->setItemDelegate( new AgentTypeWidgetDelegate( d->mView ) ); d->mView->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel ); d->mView->setAlternatingRowColors( true ); layout->addWidget( d->mView ); d->mModel = new AgentTypeModel( d->mView ); d->proxyModel = new AgentFilterProxyModel( this ); d->proxyModel->setSourceModel( d->mModel ); d->proxyModel->sort( 0 ); d->mView->setModel( d->proxyModel ); d->mView->selectionModel()->setCurrentIndex( d->mView->model()->index( 0, 0 ), QItemSelectionModel::Select ); d->mView->scrollTo( d->mView->model()->index( 0, 0 ) ); connect( d->mView->selectionModel(), SIGNAL( currentChanged( const QModelIndex&, const QModelIndex& ) ), this, SLOT( currentAgentTypeChanged( const QModelIndex&, const QModelIndex& ) ) ); connect( d->mView, SIGNAL( activated( const QModelIndex& ) ), - SIGNAL( activated() ) ); + SLOT( typeActivated(QModelIndex) ) ); } AgentTypeWidget::~AgentTypeWidget() { delete d; } AgentType AgentTypeWidget::currentAgentType() const { QItemSelectionModel *selectionModel = d->mView->selectionModel(); if ( !selectionModel ) return AgentType(); QModelIndex index = selectionModel->currentIndex(); if ( !index.isValid() ) return AgentType(); return index.data( AgentTypeModel::TypeRole ).value(); } AgentFilterProxyModel* AgentTypeWidget::agentFilterProxyModel() const { return d->proxyModel; } /** * AgentTypeWidgetDelegate */ AgentTypeWidgetDelegate::AgentTypeWidgetDelegate( QObject *parent ) : QAbstractItemDelegate( parent ) { } void AgentTypeWidgetDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const { if ( !index.isValid() ) return; painter->setRenderHint( QPainter::Antialiasing ); const QString name = index.model()->data( index, Qt::DisplayRole ).toString(); const QString comment = index.model()->data( index, AgentTypeModel::DescriptionRole ).toString(); const QVariant data = index.model()->data( index, Qt::DecorationRole ); QPixmap pixmap; if ( data.isValid() && data.type() == QVariant::Icon ) pixmap = qvariant_cast( data ).pixmap( 64, 64 ); const QFont oldFont = painter->font(); QFont boldFont( oldFont ); boldFont.setBold( true ); painter->setFont( boldFont ); QFontMetrics fm = painter->fontMetrics(); int hn = fm.boundingRect( 0, 0, 0, 0, Qt::AlignLeft, name ).height(); int wn = fm.boundingRect( 0, 0, 0, 0, Qt::AlignLeft, name ).width(); painter->setFont( oldFont ); fm = painter->fontMetrics(); int hc = fm.boundingRect( 0, 0, 0, 0, Qt::AlignLeft, comment ).height(); int wc = fm.boundingRect( 0, 0, 0, 0, Qt::AlignLeft, comment ).width(); int wp = pixmap.width(); QStyleOptionViewItemV4 opt(option); opt.showDecorationSelected = true; QApplication::style()->drawPrimitive( QStyle::PE_PanelItemViewItem, &opt, painter ); QPen pen = painter->pen(); QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; if (cg == QPalette::Normal && !(option.state & QStyle::State_Active)) cg = QPalette::Inactive; if (option.state & QStyle::State_Selected) { painter->setPen(option.palette.color(cg, QPalette::HighlightedText)); } else { painter->setPen(option.palette.color(cg, QPalette::Text)); } QFont font = painter->font(); painter->setFont(option.font); painter->drawPixmap( option.rect.x() + 5, option.rect.y() + 5, pixmap ); painter->setFont(boldFont); if ( !name.isEmpty() ) painter->drawText( option.rect.x() + 5 + wp + 5, option.rect.y() + 7, wn, hn, Qt::AlignLeft, name ); painter->setFont(oldFont); if ( !comment.isEmpty() ) painter->drawText( option.rect.x() + 5 + wp + 5, option.rect.y() + 7 + hn, wc, hc, Qt::AlignLeft, comment ); painter->setPen(pen); drawFocus( painter, option, option.rect ); } QSize AgentTypeWidgetDelegate::sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const { if ( !index.isValid() ) return QSize( 0, 0 ); const QString name = index.model()->data( index, Qt::DisplayRole ).toString(); const QString comment = index.model()->data( index, AgentTypeModel::DescriptionRole ).toString(); QFontMetrics fm = option.fontMetrics; int hn = fm.boundingRect( 0, 0, 0, 0, Qt::AlignLeft, name ).height(); int wn = fm.boundingRect( 0, 0, 0, 0, Qt::AlignLeft, name ).width(); int hc = fm.boundingRect( 0, 0, 0, 0, Qt::AlignLeft, comment ).height(); int wc = fm.boundingRect( 0, 0, 0, 0, Qt::AlignLeft, comment ).width(); int width = 0; int height = 0; if ( !name.isEmpty() ) { height += hn; width = qMax( width, wn ); } if ( !comment.isEmpty() ) { height += hc; width = qMax( width, wc ); } height = qMax( height, 64 ) + 10; width += 64 + 15; return QSize( width, height ); } void AgentTypeWidgetDelegate::drawFocus( QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect ) const { if (option.state & QStyle::State_HasFocus) { QStyleOptionFocusRect o; o.QStyleOption::operator=(option); o.rect = rect; o.state |= QStyle::State_KeyboardFocusChange; QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled) ? QPalette::Normal : QPalette::Disabled; o.backgroundColor = option.palette.color(cg, (option.state & QStyle::State_Selected) ? QPalette::Highlight : QPalette::Background); QApplication::style()->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter); } } #include "agenttypewidget.moc" diff --git a/akonadi/agenttypewidget.h b/akonadi/agenttypewidget.h index 54aed9c42..390f82a16 100644 --- a/akonadi/agenttypewidget.h +++ b/akonadi/agenttypewidget.h @@ -1,107 +1,108 @@ /* Copyright (c) 2006-2008 Tobias Koenig This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef AKONADI_AGENTTYPEWIDGET_H #define AKONADI_AGENTTYPEWIDGET_H #include "akonadi_export.h" #include namespace Akonadi { class AgentFilterProxyModel; class AgentType; /** * @short Provides a widget that lists all available agent types. * * The widget is listening on the dbus for changes, so the * widget is updated automatically as soon as new agent types * are added to or removed from the system. * * @code * * Akonadi::AgentTypeWidget *widget = new Akonadi::AgentTypeWidget( this ); * * // only list agent types that provide contacts * widget->agentFilterProxyModel()->addMimeTypeFilter( "text/directory" ); * * @endcode * * If you want a dialog, you can use the Akonadi::AgentTypeDialog. * * @author Tobias Koenig */ class AKONADI_EXPORT AgentTypeWidget : public QWidget { Q_OBJECT public: /** * Creates a new agent type widget. * * @param parent The parent widget. */ explicit AgentTypeWidget( QWidget *parent = 0 ); /** * Destroys the agent type widget. */ ~AgentTypeWidget(); /** * Returns the current agent type or an invalid agent type * if no agent type is selected. */ AgentType currentAgentType() const; /** * Returns the agent filter proxy model, use this to filter by * agent mimetype or capabilities. */ AgentFilterProxyModel* agentFilterProxyModel() const; Q_SIGNALS: /** * This signal is emitted whenever the current agent type changes. * * @param current The current agent type. * @param previous The previous agent type. */ void currentChanged( const Akonadi::AgentType ¤t, const Akonadi::AgentType &previous ); /** * This signal is emitted whenever the user activates an agent. * @since 4.2 */ void activated(); private: //@cond PRIVATE class Private; Private* const d; Q_PRIVATE_SLOT( d, void currentAgentTypeChanged( const QModelIndex&, const QModelIndex& ) ) + Q_PRIVATE_SLOT( d, void typeActivated( const QModelIndex &index ) ) //@endcond }; } #endif