2
* Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde@gmail.com>
3
* Copyright (C) 2008 Daniel Nicoletti <dantti85-pk@yahoo.com.br>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU Library/Lesser General Public License
7
* version 2, or (at your option) any later version, as published by the
8
* Free Software Foundation
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details
15
* You should have received a copy of the GNU Library/Lesser General Public
16
* License along with this program; if not, write to the
17
* Free Software Foundation, Inc.,
18
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21
#include "KpkDelegate.h"
24
#include <KIconLoader>
29
#include "KpkPackageModel.h"
32
#define FAV_ICON_SIZE 24
33
#define EMBLEM_ICON_SIZE 8
34
#define UNIVERSAL_PADDING 4
35
#define FADE_LENGTH 16
36
#define MAIN_ICON_SIZE 32
38
KpkDelegate::KpkDelegate(QAbstractItemView *parent)
39
: KExtendableItemDelegate(parent),
40
m_viewport(parent->viewport()),
41
// loads it here to be faster when displaying items
42
m_packageIcon("package"),
43
m_collectionIcon("package-orign"),
44
m_installIcon("go-down"),
45
m_installString(i18n("Install")),
46
m_removeIcon("edit-delete"),
47
m_removeString(i18n("Remove")),
48
m_undoIcon("edit-undo"),
49
m_undoString(i18n("Deselect")),
50
m_checkedIcon("dialog-ok-apply")
52
// maybe rename or copy it to package-available
53
if (QApplication::isRightToLeft()) {
54
setExtendPixmap(SmallIcon("arrow-left"));
56
setExtendPixmap(SmallIcon("arrow-right"));
58
setContractPixmap(SmallIcon("arrow-down"));
59
// store the size of the extend pixmap to know how much we should move
60
m_extendPixmapWidth = SmallIcon("arrow-right").size().width();
62
QPushButton button, button2;
63
button.setText(m_installString);
64
button.setIcon(m_installIcon);
65
button2.setText(m_removeString);
66
button2.setIcon(m_removeIcon);
67
m_buttonSize = button.sizeHint();
68
int width = qMax(button.sizeHint().width(), button2.sizeHint().width());
69
button.setText(m_undoString);
70
width = qMax(width, button2.sizeHint().width());
71
m_buttonSize.setWidth(width);
72
m_buttonIconSize = button.iconSize();
75
void KpkDelegate::paint(QPainter *painter,
76
const QStyleOptionViewItem &option,
77
const QModelIndex &index) const
79
if (!index.isValid()) {
82
bool leftToRight = (painter->layoutDirection() == Qt::LeftToRight);
84
QStyleOptionViewItemV4 opt(option);
85
QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
87
style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget);
90
//grab the package from the index pointer
91
QString pkgName = index.data(KpkPackageModel::NameRole).toString();
92
QString pkgSummary = index.data(KpkPackageModel::SummaryRole).toString();
93
QString pkgVersion = index.data(KpkPackageModel::VersionRole).toString();
94
QString pkgArch = index.data(KpkPackageModel::ArchRole).toString();
95
// QString pkgIconPath = index.data(KpkPackageModel::IconPathRole).toString();
96
bool pkgChecked = index.data(KpkPackageModel::CheckStateRole).toBool();
97
bool pkgCheckable = !index.data(Qt::CheckStateRole).isNull();
99
info = static_cast<Package::Info>(index.data(KpkPackageModel::InfoRole).toUInt());
100
bool pkgInstalled = (info == Package::InfoInstalled ||
101
info == Package::InfoCollectionInstalled);
103
bool pkgCollection = (info == Package::InfoCollectionInstalled ||
104
info == Package::InfoCollectionAvailable);
109
emblemIcon = index.data(KpkPackageModel::IconRole).value<QIcon>();
111
emblemIcon = m_checkedIcon;
114
// pain the background (checkbox and the extender)
115
if (m_extendPixmapWidth) {
116
KExtendableItemDelegate::paint(painter, opt, index);
121
opt.rect.setLeft(option.rect.left() + m_extendPixmapWidth + UNIVERSAL_PADDING);
122
leftCount = opt.rect.left() + UNIVERSAL_PADDING;
124
opt.rect.setRight(option.rect.right() - m_extendPixmapWidth - UNIVERSAL_PADDING);
125
leftCount = opt.rect.width() - (UNIVERSAL_PADDING + MAIN_ICON_SIZE);
128
int left = opt.rect.left();
129
int top = opt.rect.top();
130
int width = opt.rect.width();
132
QStyleOptionButton optBt;
133
optBt.rect = opt.rect;
135
optBt.rect = style->subElementRect(QStyle::SE_CheckBoxIndicator, &optBt);
136
// Count the checkbox size
138
leftCount += optBt.rect.width();
140
leftCount -= optBt.rect.width();
142
} else if ((option.state & QStyle::State_MouseOver) ||
143
(option.state & QStyle::State_Selected)
146
optBt.rect.setLeft(left + width - (m_buttonSize.width() + UNIVERSAL_PADDING));
147
width -= m_buttonSize.width() + UNIVERSAL_PADDING;
149
optBt.rect.setLeft(left + UNIVERSAL_PADDING);
150
left += m_buttonSize.width() + UNIVERSAL_PADDING;
152
// Calculate the top of the button which is the item height - the button height size divided by 2
153
// this give us a little value which is the top and bottom margin
154
optBt.rect.setTop(optBt.rect.top() + ((calcItemHeight(option) - m_buttonSize.height()) / 2));
155
optBt.rect.setSize(m_buttonSize); // the width and height sizes of the button
156
optBt.features = QStyleOptionButton::Flat;
157
if (option.state & QStyle::State_MouseOver) {
159
// QAbstractItemView *view = qobject_cast<QAbstractItemView*>(parent());
160
// QPoint pos = view->viewport()->mapFromGlobal(QCursor::pos());
161
// kDebug() << optBt.rect << pos << insideButton(optBt.rect, pos);
162
// insideCheckBox(rect, pos);
163
optBt.state |= QStyle::State_MouseOver;
165
optBt.state |= QStyle::State_Raised | QStyle::State_Active | QStyle::State_Enabled;
166
optBt.iconSize = m_buttonIconSize;
168
optBt.text = m_undoString;
169
optBt.icon = m_undoIcon;
171
optBt.icon = pkgInstalled ? m_removeIcon : m_installIcon;
172
optBt.text = pkgInstalled ? m_removeString : m_installString;
174
style->drawControl(QStyle::CE_PushButton, &optBt, painter);
177
// QAbstractItemView *view = qobject_cast<QAbstractItemView*>(parent());
178
// QPoint pos = view->viewport()->mapFromGlobal(QCursor::pos());
182
// selects the mode to paint the icon based on the info field
183
QIcon::Mode iconMode = QIcon::Normal;
184
if (option.state & QStyle::State_MouseOver) {
185
iconMode = QIcon::Active;
188
QColor foregroundColor = (option.state.testFlag(QStyle::State_Selected))?
189
option.palette.color(QPalette::HighlightedText):option.palette.color(QPalette::Text);
191
// Painting main column
192
QStyleOptionViewItem local_option_title(option);
193
QStyleOptionViewItem local_option_normal(option);
195
local_option_normal.font.setPointSize(local_option_normal.font.pointSize() - 1);
197
QPixmap pixmap(option.rect.size());
198
pixmap.fill(Qt::transparent);
200
p.translate(-option.rect.topLeft());
204
// if (pkgIconPath.isEmpty()) {
205
icon = pkgCollection ? m_collectionIcon : m_packageIcon;
207
// icon = KpkIcons::getIcon(pkgIconPath, "package");
210
int iconSize = calcItemHeight(option) - 2 * UNIVERSAL_PADDING;
213
top + UNIVERSAL_PADDING,
222
leftCount += iconSize + UNIVERSAL_PADDING;
223
textWidth = width - (leftCount - left);
225
leftCount -= UNIVERSAL_PADDING;
226
textWidth = leftCount - left;
234
const int itemHeight = calcItemHeight(option);
236
p.setPen(foregroundColor);
237
// compose the top line
238
// Collections does not have version and arch
239
if (option.state & QStyle::State_MouseOver && !pkgCollection) {
240
pkgName = pkgName + " - " + pkgVersion + (pkgArch.isNull() ? NULL : " (" + pkgArch + ')');
243
int topTextHeight = QFontInfo(local_option_title.font).pixelSize();
244
p.setFont(local_option_title.font);
245
p.drawText(leftCount,
248
topTextHeight + UNIVERSAL_PADDING,
249
Qt::AlignVCenter | Qt::AlignLeft,
252
// draw the bottom line
253
iconSize = topTextHeight + UNIVERSAL_PADDING;
254
if (pkgCheckable || pkgInstalled) {
256
leftToRight ? leftCount : (textWidth + left) - iconSize,
257
top + topTextHeight + UNIVERSAL_PADDING,
260
Qt::AlignVCenter | Qt::AlignHCenter,
264
// store the original opacity
265
qreal opa = p.opacity();
266
if (!(option.state & QStyle::State_MouseOver) && !(option.state & QStyle::State_Selected)) {
267
p.setOpacity(opa / 2.5);
270
p.setFont(local_option_normal.font);
271
p.drawText(leftToRight ? leftCount + iconSize + UNIVERSAL_PADDING : left - UNIVERSAL_PADDING,
272
top + itemHeight / 2,
273
textWidth - iconSize,
274
QFontInfo(local_option_normal.font).pixelSize() + UNIVERSAL_PADDING,
275
Qt::AlignTop | Qt::AlignLeft,
279
QLinearGradient gradient;
280
// Gradient part of the background - fading of the text at the end
282
gradient = QLinearGradient(left + width - UNIVERSAL_PADDING - FADE_LENGTH,
284
left + width - UNIVERSAL_PADDING,
286
gradient.setColorAt(0, Qt::white);
287
gradient.setColorAt(1, Qt::transparent);
289
gradient = QLinearGradient(left + UNIVERSAL_PADDING,
291
left + UNIVERSAL_PADDING + FADE_LENGTH,
293
gradient.setColorAt(0, Qt::transparent);
294
gradient.setColorAt(1, Qt::white);
297
QRect paintRect = option.rect;
298
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
299
p.fillRect(paintRect, gradient);
302
gradient.setStart(left + width
303
- (UNIVERSAL_PADDING + EMBLEM_ICON_SIZE) - FADE_LENGTH, 0);
304
gradient.setFinalStop(left + width
305
- (UNIVERSAL_PADDING + EMBLEM_ICON_SIZE), 0);
307
gradient.setStart(left + UNIVERSAL_PADDING
308
+ (UNIVERSAL_PADDING + EMBLEM_ICON_SIZE), 0);
309
gradient.setFinalStop(left + UNIVERSAL_PADDING
310
+ (UNIVERSAL_PADDING + EMBLEM_ICON_SIZE) + FADE_LENGTH, 0);
312
paintRect.setHeight(UNIVERSAL_PADDING + MAIN_ICON_SIZE / 2);
313
p.fillRect(paintRect, gradient);
314
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
317
painter->drawPixmap(option.rect.topLeft(), pixmap);
320
int KpkDelegate::calcItemHeight(const QStyleOptionViewItem &option) const
322
// Painting main column
323
QStyleOptionViewItem local_option_title(option);
324
QStyleOptionViewItem local_option_normal(option);
326
local_option_normal.font.setPointSize(local_option_normal.font.pointSize() - 1);
328
int textHeight = QFontInfo(local_option_title.font).pixelSize() + QFontInfo(local_option_normal.font).pixelSize();
329
return textHeight + 3 * UNIVERSAL_PADDING;
332
bool KpkDelegate::insideButton(const QRect &rect, const QPoint &pos) const
334
// kDebug() << rect << pos;
335
if ((pos.x() >= rect.x() && (pos.x() <= rect.x() + rect.width())) &&
336
(pos.y() >= rect.y() && (pos.y() <= rect.y() + rect.height()))) {
342
bool KpkDelegate::editorEvent(QEvent *event,
343
QAbstractItemModel *model,
344
const QStyleOptionViewItem &option,
345
const QModelIndex &index)
349
if (event->type() == QEvent::MouseButtonRelease) {
350
QAbstractItemView *view = qobject_cast<QAbstractItemView*>(parent());
351
QPoint point = m_viewport->mapFromGlobal(QCursor::pos());
352
QTreeView *tree = qobject_cast<QTreeView*>(parent());
354
point.ry() -= tree->header()->size().height();
357
bool leftToRight = QApplication::isLeftToRight();
358
QStyleOptionButton optBt;
359
optBt.rect = option.rect;
361
optBt.rect.setLeft(option.rect.left() + option.rect.width() - (m_buttonSize.width() + UNIVERSAL_PADDING));
363
optBt.rect.setLeft(option.rect.left() + UNIVERSAL_PADDING);
365
// Calculate the top of the button which is the item height - the button height size divided by 2
366
// this give us a little value which is the top and bottom margin
367
optBt.rect.setTop(optBt.rect.top() + ((calcItemHeight(option) - m_buttonSize.height()) / 2));
368
optBt.rect.setSize(m_buttonSize);
370
kDebug() << point << option.rect.left() << option << insideButton(optBt.rect, point);
371
// kDebug() << view->visualRect(index);
372
if (insideButton(optBt.rect, point)) {
373
return model->setData(index,
374
!index.data(KpkPackageModel::CheckStateRole).toBool(),
377
QRect rect = view->visualRect(index);
378
if (QApplication::isRightToLeft()) {
379
if ((rect.width() - point.x()) <= m_extendPixmapWidth) {
380
emit showExtendItem(index);
382
} else if (point.x() <= m_extendPixmapWidth) {
383
emit showExtendItem(index);
387
// We need move the option rect left because KExtendableItemDelegate
388
// drew the extendPixmap
389
QStyleOptionViewItemV4 opt(option);
390
if (QApplication::isRightToLeft()) {
391
opt.rect.setRight(option.rect.right() - m_extendPixmapWidth);
393
opt.rect.setLeft(option.rect.left() + m_extendPixmapWidth);
395
// When the exterder is shown the height get compromised,
396
// this makes sure the check box is always known
397
opt.rect.setHeight(calcItemHeight(option));
398
return KExtendableItemDelegate::editorEvent(event, model, opt, index);
401
void KpkDelegate::setExtendPixmapWidth(int width)
403
m_extendPixmapWidth = width;
406
void KpkDelegate::setViewport(QWidget *viewport)
408
m_viewport = viewport;
411
QSize KpkDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index ) const
413
int width = (index.column() == 0) ? index.data(Qt::SizeHintRole).toSize().width() : FAV_ICON_SIZE + 2 * UNIVERSAL_PADDING;
414
QSize ret(KExtendableItemDelegate::sizeHint(option, index));
415
// remove the default size of the index
416
ret -= QStyledItemDelegate::sizeHint(option, index);
418
ret.rheight() += calcItemHeight(option);
419
ret.rwidth() += width;
424
#include "KpkDelegate.moc"