Akonadi

agentinstancewidget.cpp
1/*
2 SPDX-FileCopyrightText: 2006-2008 Tobias Koenig <tokoe@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "agentinstancewidget.h"
8
9#include "agentinstance.h"
10#include "agentinstancefilterproxymodel.h"
11#include "agentinstancemodel.h"
12
13#include <KLocalizedString>
14
15#include <QApplication>
16#include <QHBoxLayout>
17#include <QIcon>
18#include <QListView>
19#include <QPainter>
20#include <QStyle>
21
22namespace Akonadi
23{
24namespace Internal
25{
26static void iconsEarlyCleanup();
27
28struct Icons {
29 Icons()
30 : readyPixmap(QIcon::fromTheme(QStringLiteral("user-online")).pixmap(QSize(16, 16)))
31 , syncPixmap(QIcon::fromTheme(QStringLiteral("network-connect")).pixmap(QSize(16, 16)))
32 , errorPixmap(QIcon::fromTheme(QStringLiteral("dialog-error")).pixmap(QSize(16, 16)))
33 , offlinePixmap(QIcon::fromTheme(QStringLiteral("network-disconnect")).pixmap(QSize(16, 16)))
34 {
35 qAddPostRoutine(iconsEarlyCleanup);
36 }
37 QPixmap readyPixmap, syncPixmap, errorPixmap, offlinePixmap;
38};
39
40Q_GLOBAL_STATIC(Icons, s_icons) // NOLINT(readability-redundant-member-init)
41
42// called as a Qt post routine, to prevent pixmap leaking
43void iconsEarlyCleanup()
44{
45 Icons *const ic = s_icons;
46 ic->readyPixmap = ic->syncPixmap = ic->errorPixmap = ic->offlinePixmap = QPixmap();
47}
48
49static const int s_delegatePaddingSize = 7;
50
51/**
52 * @internal
53 */
54
55class AgentInstanceWidgetDelegate : public QAbstractItemDelegate
56{
58public:
59 explicit AgentInstanceWidgetDelegate(QObject *parent = nullptr);
60
61 void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
62 QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
63};
64
65} // namespace Internal
66
67using Akonadi::Internal::AgentInstanceWidgetDelegate;
68
69/**
70 * @internal
71 */
72class AgentInstanceWidgetPrivate
73{
74public:
75 explicit AgentInstanceWidgetPrivate(AgentInstanceWidget *parent)
76 : mParent(parent)
77 {
78 }
79
80 void currentAgentInstanceChanged(const QModelIndex &currentIndex, const QModelIndex &previousIndex);
81 void currentAgentInstanceDoubleClicked(const QModelIndex &currentIndex);
82 void currentAgentInstanceClicked(const QModelIndex &currentIndex);
83
84 AgentInstanceWidget *const mParent;
85 QListView *mView = nullptr;
86 AgentInstanceModel *mModel = nullptr;
87 AgentInstanceFilterProxyModel *proxy = nullptr;
88};
89
90void AgentInstanceWidgetPrivate::currentAgentInstanceChanged(const QModelIndex &currentIndex, const QModelIndex &previousIndex)
91{
92 AgentInstance currentInstance;
93 if (currentIndex.isValid()) {
94 currentInstance = currentIndex.data(AgentInstanceModel::InstanceRole).value<AgentInstance>();
95 }
96
97 AgentInstance previousInstance;
98 if (previousIndex.isValid()) {
99 previousInstance = previousIndex.data(AgentInstanceModel::InstanceRole).value<AgentInstance>();
100 }
101
102 Q_EMIT mParent->currentChanged(currentInstance, previousInstance);
103}
104
105void AgentInstanceWidgetPrivate::currentAgentInstanceDoubleClicked(const QModelIndex &currentIndex)
106{
107 AgentInstance currentInstance;
108 if (currentIndex.isValid()) {
109 currentInstance = currentIndex.data(AgentInstanceModel::InstanceRole).value<AgentInstance>();
110 }
111
112 Q_EMIT mParent->doubleClicked(currentInstance);
113}
114
115void AgentInstanceWidgetPrivate::currentAgentInstanceClicked(const QModelIndex &currentIndex)
116{
117 AgentInstance currentInstance;
118 if (currentIndex.isValid()) {
119 currentInstance = currentIndex.data(AgentInstanceModel::InstanceRole).value<AgentInstance>();
120 }
121
122 Q_EMIT mParent->clicked(currentInstance);
123}
124
126 : QWidget(parent)
127 , d(new AgentInstanceWidgetPrivate(this))
128{
129 auto layout = new QHBoxLayout(this);
131
132 d->mView = new QListView(this);
133 d->mView->setContextMenuPolicy(Qt::NoContextMenu);
134 d->mView->setItemDelegate(new Internal::AgentInstanceWidgetDelegate(d->mView));
135 d->mView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
136 d->mView->setAlternatingRowColors(true);
137 d->mView->setSelectionMode(QAbstractItemView::ExtendedSelection);
138 layout->addWidget(d->mView);
139
140 d->mModel = new AgentInstanceModel(this);
141
142 d->proxy = new AgentInstanceFilterProxyModel(this);
143 d->proxy->sort(0);
144 d->proxy->setSortCaseSensitivity(Qt::CaseInsensitive);
145 d->proxy->setSourceModel(d->mModel);
146 d->mView->setModel(d->proxy);
147
148 d->mView->selectionModel()->setCurrentIndex(d->mView->model()->index(0, 0), QItemSelectionModel::Select);
149 d->mView->scrollTo(d->mView->model()->index(0, 0));
150
151 connect(d->mView->selectionModel(), &QItemSelectionModel::currentChanged, this, [this](const auto &tl, const auto &br) {
152 d->currentAgentInstanceChanged(tl, br);
153 });
154 connect(d->mView, &QListView::doubleClicked, this, [this](const QModelIndex &currentIndex) {
155 d->currentAgentInstanceDoubleClicked(currentIndex);
156 });
157 connect(d->mView, &QListView::clicked, this, [this](const auto &mi) {
158 d->currentAgentInstanceClicked(mi);
159 });
160}
161
163
165{
166 QItemSelectionModel *selectionModel = d->mView->selectionModel();
167 if (!selectionModel) {
168 return AgentInstance();
169 }
170
171 QModelIndex index = selectionModel->currentIndex();
172 if (!index.isValid()) {
173 return AgentInstance();
174 }
175
177}
178
180{
182 QItemSelectionModel *selectionModel = d->mView->selectionModel();
183 if (!selectionModel) {
184 return list;
185 }
186
187 const QModelIndexList indexes = selectionModel->selection().indexes();
188 list.reserve(indexes.count());
189 for (const QModelIndex &index : indexes) {
190 list.append(index.data(AgentInstanceModel::InstanceRole).value<AgentInstance>());
191 }
192
193 return list;
194}
195
197{
198 return d->mView;
199}
200
205
206bool AgentInstanceWidget::enablePlasmaActivities() const
207{
208 return d->proxy->enablePlasmaActivities();
209}
210
211void AgentInstanceWidget::setEnablePlasmaActivities(bool newEnablePlasmaActivities)
212{
213 d->proxy->setEnablePlasmaActivities(newEnablePlasmaActivities);
214}
215
216AccountActivitiesAbstract *AgentInstanceWidget::accountActivitiesAbstract() const
217{
218 return d->proxy->accountActivitiesAbstract();
219}
220
221void AgentInstanceWidget::setAccountActivitiesAbstract(AccountActivitiesAbstract *abstract)
222{
223 d->proxy->setAccountActivitiesAbstract(abstract);
224}
225
226AgentInstanceWidgetDelegate::AgentInstanceWidgetDelegate(QObject *parent)
227 : QAbstractItemDelegate(parent)
228{
229}
230
231void AgentInstanceWidgetDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
232{
233 if (!index.isValid()) {
234 return;
235 }
236
237 QStyle *style = QApplication::style();
238 style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, nullptr);
239
240 auto icon = index.data(Qt::DecorationRole).value<QIcon>();
241 const QString name = index.model()->data(index, Qt::DisplayRole).toString();
242 int status = index.model()->data(index, AgentInstanceModel::StatusRole).toInt();
243 uint progress = index.model()->data(index, AgentInstanceModel::ProgressRole).toUInt();
244 QString statusMessage = index.model()->data(index, AgentInstanceModel::StatusMessageRole).toString();
245
246 QPixmap statusPixmap;
247
249 statusPixmap = s_icons->offlinePixmap;
250 } else if (status == AgentInstance::Idle) {
251 statusPixmap = s_icons->readyPixmap;
252 } else if (status == AgentInstance::Running) {
253 statusPixmap = s_icons->syncPixmap;
254 } else {
255 statusPixmap = s_icons->errorPixmap;
256 }
257
258 if (status == 1) {
259 statusMessage.append(QStringLiteral(" ") + i18nc("Status percent value", "(%1%)", progress));
260 }
261
262 const QPixmap iconPixmap = icon.pixmap(style->pixelMetric(QStyle::PM_MessageBoxIconSize));
263 QRect innerRect = option.rect.adjusted(s_delegatePaddingSize,
264 s_delegatePaddingSize,
265 -s_delegatePaddingSize,
266 -s_delegatePaddingSize); // add some padding round entire delegate
267
268 const QSize decorationSize = iconPixmap.size();
269 const QSize statusIconSize = statusPixmap.size(); //= KIconLoader::global()->currentSize(KIconLoader::Small);
270
271 QFont nameFont = option.font;
272 nameFont.setBold(true);
273
274 QFont statusTextFont = option.font;
275 const QRect decorationRect(innerRect.left(), innerRect.top(), decorationSize.width(), innerRect.height());
276 const QRect nameTextRect(decorationRect.topRight() + QPoint(4, 0), innerRect.topRight() + QPoint(0, innerRect.height() / 2));
277 const QRect statusTextRect(decorationRect.bottomRight() + QPoint(4, -innerRect.height() / 2), innerRect.bottomRight());
278
279 QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled) ? QPalette::Normal : QPalette::Disabled;
280 if (cg == QPalette::Normal && !(option.state & QStyle::State_Active)) {
282 }
283
284 if (option.state & QStyle::State_Selected) {
285 painter->setPen(option.palette.color(cg, QPalette::HighlightedText));
286 } else {
287 painter->setPen(option.palette.color(cg, QPalette::Text));
288 }
289
290 painter->drawPixmap(style->itemPixmapRect(decorationRect, Qt::AlignCenter, iconPixmap), iconPixmap);
291
292 painter->setFont(nameFont);
293 painter->drawText(nameTextRect, Qt::AlignVCenter | Qt::AlignLeft, name);
294
295 painter->setFont(statusTextFont);
296 painter->drawText(statusTextRect.adjusted(statusIconSize.width() + 4, 0, 0, 0), Qt::AlignVCenter | Qt::AlignLeft, statusMessage);
297 painter->drawPixmap(style->itemPixmapRect(statusTextRect, Qt::AlignVCenter | Qt::AlignLeft, statusPixmap), statusPixmap);
298}
299
300QSize AgentInstanceWidgetDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
301{
302 Q_UNUSED(index)
303
304 const int iconHeight = QApplication::style()->pixelMetric(QStyle::PM_MessageBoxIconSize) + (s_delegatePaddingSize * 2); // icon height + padding either side
305 const int textHeight =
306 option.fontMetrics.height() + qMax(option.fontMetrics.height(), 16) + (s_delegatePaddingSize * 2); // height of text + icon/text + padding either side
307
308 return QSize(1, qMax(iconHeight, textHeight)); // any width,the view will give us the whole thing in list mode
309}
310
311} // namespace Akonadi
312
313#include "agentinstancewidget.moc"
314
315#include "moc_agentinstancewidget.cpp"
Represents one agent instance and takes care of communication with it.
A proxy model for filtering AgentType or AgentInstance.
Provides a data model for agent instances.
@ StatusMessageRole
A textual presentation of the current status.
@ OnlineRole
The current online/offline status.
@ StatusRole
The current status (numerical) of the instance.
@ InstanceRole
The agent instance itself.
@ ProgressRole
The current progress (numerical in percent) of an operation.
void doubleClicked(const Akonadi::AgentInstance &current)
This signal is emitted whenever there is a double click on an agent instance.
QList< AgentInstance > selectedAgentInstances() const
Returns the selected agent instances.
void clicked(const Akonadi::AgentInstance &current)
This signal is emitted whenever there is a click on an agent instance.
Akonadi::AgentInstanceFilterProxyModel * agentInstanceFilterProxyModel() const
Returns the agent filter proxy model, use this to filter by agent mimetype or capabilities.
~AgentInstanceWidget() override
Destroys the agent instance widget.
AgentInstance currentAgentInstance() const
Returns the current agent instance or an invalid agent instance if no agent instance is selected.
QAbstractItemView * view() const
Returns the view used in the widget.
void currentChanged(const Akonadi::AgentInstance &current, const Akonadi::AgentInstance &previous)
This signal is emitted whenever the current agent instance changes.
AgentInstanceWidget(QWidget *parent=nullptr)
Creates a new agent instance widget.
A representation of an agent instance.
@ Running
The agent instance is working on something.
@ Idle
The agent instance does currently nothing.
Q_SCRIPTABLE CaptureState status()
QString i18nc(const char *context, const char *text, const TYPE &arg...)
Helper integration between Akonadi and Qt.
QString name(StandardAction id)
virtual QVariant data(const QModelIndex &index, int role) const const=0
void clicked(const QModelIndex &index)
void doubleClicked(const QModelIndex &index)
QStyle * style()
void setBold(bool enable)
QModelIndexList indexes() const const
void currentChanged(const QModelIndex &current, const QModelIndex &previous)
QModelIndex currentIndex() const const
const QItemSelection selection() const const
void addWidget(QWidget *w)
void setContentsMargins(const QMargins &margins)
void append(QList< T > &&value)
void reserve(qsizetype size)
QVariant data(int role) const const
bool isValid() const const
const QAbstractItemModel * model() const const
Q_OBJECTQ_OBJECT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QObject * parent() const const
void drawPixmap(const QPoint &point, const QPixmap &pixmap)
void drawText(const QPoint &position, const QString &text)
void setFont(const QFont &font)
void setPen(Qt::PenStyle style)
QSize size() const const
QPoint bottomRight() const const
int height() const const
int left() const const
int top() const const
QPoint topRight() const const
int width() const const
QString & append(QChar ch)
PM_MessageBoxIconSize
PE_PanelItemViewItem
virtual void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const const=0
virtual QRect itemPixmapRect(const QRect &rectangle, int alignment, const QPixmap &pixmap) const const
virtual int pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const const=0
AlignCenter
CaseInsensitive
NoContextMenu
DecorationRole
bool toBool() const const
int toInt(bool *ok) const const
QString toString() const const
uint toUInt(bool *ok) const const
T value() const const
QLayout * layout() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Oct 11 2024 12:11:39 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.