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 "agentfilterproxymodel.h"
10#include "agentinstance.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 AgentFilterProxyModel *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 AgentFilterProxyModel(this);
143 d->proxy->setDynamicSortFilter(true);
144 d->proxy->sort(0);
145 d->proxy->setSortCaseSensitivity(Qt::CaseInsensitive);
146 d->proxy->setSourceModel(d->mModel);
147 d->mView->setModel(d->proxy);
148
149 d->mView->selectionModel()->setCurrentIndex(d->mView->model()->index(0, 0), QItemSelectionModel::Select);
150 d->mView->scrollTo(d->mView->model()->index(0, 0));
151
152 connect(d->mView->selectionModel(), &QItemSelectionModel::currentChanged, this, [this](const auto &tl, const auto &br) {
153 d->currentAgentInstanceChanged(tl, br);
154 });
155 connect(d->mView, &QListView::doubleClicked, this, [this](const QModelIndex &currentIndex) {
156 d->currentAgentInstanceDoubleClicked(currentIndex);
157 });
158 connect(d->mView, &QListView::clicked, this, [this](const auto &mi) {
159 d->currentAgentInstanceClicked(mi);
160 });
161}
162
164
166{
167 QItemSelectionModel *selectionModel = d->mView->selectionModel();
168 if (!selectionModel) {
169 return AgentInstance();
170 }
171
172 QModelIndex index = selectionModel->currentIndex();
173 if (!index.isValid()) {
174 return AgentInstance();
175 }
176
178}
179
181{
183 QItemSelectionModel *selectionModel = d->mView->selectionModel();
184 if (!selectionModel) {
185 return list;
186 }
187
188 const QModelIndexList indexes = selectionModel->selection().indexes();
189 list.reserve(indexes.count());
190 for (const QModelIndex &index : indexes) {
191 list.append(index.data(AgentInstanceModel::InstanceRole).value<AgentInstance>());
192 }
193
194 return list;
195}
196
198{
199 return d->mView;
200}
201
206
207AgentInstanceWidgetDelegate::AgentInstanceWidgetDelegate(QObject *parent)
208 : QAbstractItemDelegate(parent)
209{
210}
211
212void AgentInstanceWidgetDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
213{
214 if (!index.isValid()) {
215 return;
216 }
217
218 QStyle *style = QApplication::style();
219 style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, nullptr);
220
221 auto icon = index.data(Qt::DecorationRole).value<QIcon>();
222 const QString name = index.model()->data(index, Qt::DisplayRole).toString();
223 int status = index.model()->data(index, AgentInstanceModel::StatusRole).toInt();
224 uint progress = index.model()->data(index, AgentInstanceModel::ProgressRole).toUInt();
225 QString statusMessage = index.model()->data(index, AgentInstanceModel::StatusMessageRole).toString();
226
228
230 statusPixmap = s_icons->offlinePixmap;
231 } else if (status == AgentInstance::Idle) {
232 statusPixmap = s_icons->readyPixmap;
233 } else if (status == AgentInstance::Running) {
234 statusPixmap = s_icons->syncPixmap;
235 } else {
236 statusPixmap = s_icons->errorPixmap;
237 }
238
239 if (status == 1) {
240 statusMessage.append(QStringLiteral(" ") + i18nc("Status percent value", "(%1%)", progress));
241 }
242
243 const QPixmap iconPixmap = icon.pixmap(style->pixelMetric(QStyle::PM_MessageBoxIconSize));
244 QRect innerRect = option.rect.adjusted(s_delegatePaddingSize,
245 s_delegatePaddingSize,
246 -s_delegatePaddingSize,
247 -s_delegatePaddingSize); // add some padding round entire delegate
248
249 const QSize decorationSize = iconPixmap.size();
250 const QSize statusIconSize = statusPixmap.size(); //= KIconLoader::global()->currentSize(KIconLoader::Small);
251
252 QFont nameFont = option.font;
253 nameFont.setBold(true);
254
255 QFont statusTextFont = option.font;
256 const QRect decorationRect(innerRect.left(), innerRect.top(), decorationSize.width(), innerRect.height());
257 const QRect nameTextRect(decorationRect.topRight() + QPoint(4, 0), innerRect.topRight() + QPoint(0, innerRect.height() / 2));
258 const QRect statusTextRect(decorationRect.bottomRight() + QPoint(4, -innerRect.height() / 2), innerRect.bottomRight());
259
261 if (cg == QPalette::Normal && !(option.state & QStyle::State_Active)) {
263 }
264
265 if (option.state & QStyle::State_Selected) {
266 painter->setPen(option.palette.color(cg, QPalette::HighlightedText));
267 } else {
268 painter->setPen(option.palette.color(cg, QPalette::Text));
269 }
270
271 painter->drawPixmap(style->itemPixmapRect(decorationRect, Qt::AlignCenter, iconPixmap), iconPixmap);
272
273 painter->setFont(nameFont);
275
276 painter->setFont(statusTextFont);
277 painter->drawText(statusTextRect.adjusted(statusIconSize.width() + 4, 0, 0, 0), Qt::AlignVCenter | Qt::AlignLeft, statusMessage);
279}
280
281QSize AgentInstanceWidgetDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
282{
283 Q_UNUSED(index)
284
285 const int iconHeight = QApplication::style()->pixelMetric(QStyle::PM_MessageBoxIconSize) + (s_delegatePaddingSize * 2); // icon height + padding either side
286 const int textHeight =
287 option.fontMetrics.height() + qMax(option.fontMetrics.height(), 16) + (s_delegatePaddingSize * 2); // height of text + icon/text + padding either side
288
289 return QSize(1, qMax(iconHeight, textHeight)); // any width,the view will give us the whole thing in list mode
290}
291
292} // namespace Akonadi
293
294#include "agentinstancewidget.moc"
295
296#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.
~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.
AgentFilterProxyModel * agentFilterProxyModel() const
Returns the agent filter proxy model, use this to filter by agent mimetype or capabilities.
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(StandardShortcut 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
T qobject_cast(QObject *object)
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 Tue Mar 26 2024 11:13:38 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.