Akonadi

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

KDE's Doxygen guidelines are available online.