kde-playground/kdepimlibs/akonadi/agentinstancewidget.cpp
2015-04-14 21:49:29 +00:00

302 lines
10 KiB
C++

/*
Copyright (c) 2006-2008 Tobias Koenig <tokoe@kde.org>
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 "agentinstancewidget.h"
#include "agentfilterproxymodel.h"
#include "agentinstance.h"
#include "agentinstancemodel.h"
#include <KIcon>
#include <KIconLoader>
#include <QtCore/QUrl>
#include <QApplication>
#include <QHBoxLayout>
#include <QListView>
#include <QPainter>
namespace Akonadi {
namespace Internal {
static void iconsEarlyCleanup();
struct Icons
{
Icons()
: readyPixmap(KIcon(QLatin1String("user-online")).pixmap(QSize(16, 16)))
, syncPixmap(KIcon(QLatin1String("network-connect")).pixmap(QSize(16, 16)))
, errorPixmap(KIcon(QLatin1String("dialog-error")).pixmap(QSize(16, 16)))
, offlinePixmap(KIcon(QLatin1String("network-disconnect")).pixmap(QSize(16, 16)))
{
qAddPostRoutine(iconsEarlyCleanup);
}
QPixmap readyPixmap, syncPixmap, errorPixmap, offlinePixmap;
};
K_GLOBAL_STATIC(Icons, s_icons)
// called as a Qt post routine, to prevent pixmap leaking
void iconsEarlyCleanup() {
Icons *const ic = s_icons;
ic->readyPixmap = ic->syncPixmap = ic->errorPixmap = ic->offlinePixmap = QPixmap();
}
static const int s_delegatePaddingSize = 7;
/**
* @internal
*/
class AgentInstanceWidgetDelegate : public QAbstractItemDelegate
{
public:
AgentInstanceWidgetDelegate(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;
};
}
using Akonadi::Internal::AgentInstanceWidgetDelegate;
/**
* @internal
*/
class AgentInstanceWidget::Private
{
public:
Private(AgentInstanceWidget *parent)
: mParent(parent)
, mView(0)
, mModel(0)
, proxy(0)
{
}
void currentAgentInstanceChanged(const QModelIndex &, const QModelIndex &);
void currentAgentInstanceDoubleClicked(const QModelIndex &);
void currentAgentInstanceClicked(const QModelIndex &currentIndex);
AgentInstanceWidget *mParent;
QListView *mView;
AgentInstanceModel *mModel;
AgentFilterProxyModel *proxy;
};
void AgentInstanceWidget::Private::currentAgentInstanceChanged(const QModelIndex &currentIndex, const QModelIndex &previousIndex)
{
AgentInstance currentInstance;
if (currentIndex.isValid()) {
currentInstance = currentIndex.data(AgentInstanceModel::InstanceRole).value<AgentInstance>();
}
AgentInstance previousInstance;
if (previousIndex.isValid()) {
previousInstance = previousIndex.data(AgentInstanceModel::InstanceRole).value<AgentInstance>();
}
emit mParent->currentChanged(currentInstance, previousInstance);
}
void AgentInstanceWidget::Private::currentAgentInstanceDoubleClicked(const QModelIndex &currentIndex)
{
AgentInstance currentInstance;
if (currentIndex.isValid()) {
currentInstance = currentIndex.data(AgentInstanceModel::InstanceRole).value<AgentInstance>();
}
emit mParent->doubleClicked(currentInstance);
}
void AgentInstanceWidget::Private::currentAgentInstanceClicked(const QModelIndex &currentIndex)
{
AgentInstance currentInstance;
if (currentIndex.isValid()) {
currentInstance = currentIndex.data(AgentInstanceModel::InstanceRole).value<AgentInstance>();
}
emit mParent->clicked(currentInstance);
}
AgentInstanceWidget::AgentInstanceWidget(QWidget *parent)
: QWidget(parent)
, d(new Private(this))
{
QHBoxLayout *layout = new QHBoxLayout(this);
layout->setMargin(0);
d->mView = new QListView(this);
d->mView->setContextMenuPolicy(Qt::NoContextMenu);
d->mView->setItemDelegate(new Internal::AgentInstanceWidgetDelegate(d->mView));
d->mView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
d->mView->setAlternatingRowColors(true);
d->mView->setSelectionMode(QAbstractItemView::ExtendedSelection);
layout->addWidget(d->mView);
d->mModel = new AgentInstanceModel(this);
d->proxy = new AgentFilterProxyModel(this);
d->proxy->setSourceModel(d->mModel);
d->mView->setModel(d->proxy);
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(QModelIndex,QModelIndex)),
this, SLOT(currentAgentInstanceChanged(QModelIndex,QModelIndex)));
connect(d->mView, SIGNAL(doubleClicked(QModelIndex)),
this, SLOT(currentAgentInstanceDoubleClicked(QModelIndex)));
connect(d->mView, SIGNAL(clicked(QModelIndex)),
this, SLOT(currentAgentInstanceClicked(QModelIndex)));
}
AgentInstanceWidget::~AgentInstanceWidget()
{
delete d;
}
AgentInstance AgentInstanceWidget::currentAgentInstance() const
{
QItemSelectionModel *selectionModel = d->mView->selectionModel();
if (!selectionModel) {
return AgentInstance();
}
QModelIndex index = selectionModel->currentIndex();
if (!index.isValid()) {
return AgentInstance();
}
return index.data(AgentInstanceModel::InstanceRole).value<AgentInstance>();
}
QList<AgentInstance> AgentInstanceWidget::selectedAgentInstances() const
{
QList<AgentInstance> list;
QItemSelectionModel *selectionModel = d->mView->selectionModel();
if (!selectionModel) {
return list;
}
const QModelIndexList indexes = selectionModel->selection().indexes();
foreach (const QModelIndex &index, indexes) {
list.append(index.data(AgentInstanceModel::InstanceRole).value<AgentInstance>());
}
return list;
}
QAbstractItemView *AgentInstanceWidget::view() const
{
return d->mView;
}
AgentFilterProxyModel *AgentInstanceWidget::agentFilterProxyModel() const
{
return d->proxy;
}
AgentInstanceWidgetDelegate::AgentInstanceWidgetDelegate(QObject *parent)
: QAbstractItemDelegate(parent)
{
}
void AgentInstanceWidgetDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if (!index.isValid()) {
return;
}
QStyle *style = QApplication::style();
style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, 0);
QIcon icon = index.data(Qt::DecorationRole).value<QIcon>();
const QString name = index.model()->data(index, Qt::DisplayRole).toString();
int status = index.model()->data(index, AgentInstanceModel::StatusRole).toInt();
uint progress = index.model()->data(index, AgentInstanceModel::ProgressRole).toUInt();
QString statusMessage = index.model()->data(index, AgentInstanceModel::StatusMessageRole).toString();
QPixmap statusPixmap;
if (!index.data(AgentInstanceModel::OnlineRole).toBool()) {
statusPixmap = s_icons->offlinePixmap;
} else if (status == AgentInstance::Idle) {
statusPixmap = s_icons->readyPixmap;
} else if (status == AgentInstance::Running) {
statusPixmap = s_icons->syncPixmap;
} else {
statusPixmap = s_icons->errorPixmap;
}
if (status == 1) {
statusMessage.append(QString::fromLatin1(" (%1%)").arg(progress));
}
QRect innerRect = option.rect.adjusted(s_delegatePaddingSize, s_delegatePaddingSize, -s_delegatePaddingSize, -s_delegatePaddingSize); //add some padding round entire delegate
const QSize decorationSize(KIconLoader::global()->currentSize(KIconLoader::Desktop), KIconLoader::global()->currentSize(KIconLoader::Desktop));
const QSize statusIconSize = QSize(16, 16); //= KIconLoader::global()->currentSize(KIconLoader::Small);
QFont nameFont = option.font;
nameFont.setBold(true);
QFont statusTextFont = option.font;
const QRect decorationRect(innerRect.left(), innerRect.top(), decorationSize.width(), innerRect.height());
const QRect nameTextRect(decorationRect.topRight() + QPoint(4, 0), innerRect.topRight() + QPoint(0, innerRect.height() / 2));
const QRect statusTextRect(decorationRect.bottomRight() + QPoint(4, - innerRect.height() / 2), innerRect.bottomRight());
const QPixmap iconPixmap = icon.pixmap(decorationSize);
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));
}
painter->drawPixmap(style->itemPixmapRect(decorationRect, Qt::AlignCenter, iconPixmap), iconPixmap);
painter->setFont(nameFont);
painter->drawText(nameTextRect, Qt::AlignVCenter | Qt::AlignLeft, name);
painter->setFont(statusTextFont);
painter->drawText(statusTextRect.adjusted(statusIconSize.width() + 4, 0, 0, 0), Qt::AlignVCenter | Qt::AlignLeft, statusMessage);
painter->drawPixmap(style->itemPixmapRect(statusTextRect, Qt::AlignVCenter | Qt::AlignLeft, statusPixmap), statusPixmap);
}
QSize AgentInstanceWidgetDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(index);
const int iconHeight = KIconLoader::global()->currentSize(KIconLoader::Desktop) + (s_delegatePaddingSize * 2); //icon height + padding either side
const int textHeight = option.fontMetrics.height() + qMax(option.fontMetrics.height(), 16) + (s_delegatePaddingSize * 2); //height of text + icon/text + padding either side
return QSize(1, qMax(iconHeight, textHeight)); //any width,the view will give us the whole thing in list mode
}
}
#include "moc_agentinstancewidget.cpp"