~dantti/apper/master

« back to all changes in this revision

Viewing changes to libapper/KpkDelegate.cpp

  • Committer: Daniel Nicoletti
  • Date: 2011-07-27 21:02:31 UTC
  • Revision ID: git-v1:2fb51b7787e2e9d70d2085cc8181a12f4277b047
The idea of libshared, was for it to be static, as
this doesn't seem too simple as putting STATIC word
I'm renaming it to libapper so we don't have such a geniric
lib installed (as pointed by Kevin Kofler

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *   Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde@gmail.com>
 
3
 *   Copyright (C) 2008 Daniel Nicoletti <dantti85-pk@yahoo.com.br>
 
4
 *
 
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
 
9
 *
 
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
 
14
 *
 
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.
 
19
 */
 
20
 
 
21
#include "KpkDelegate.h"
 
22
 
 
23
#include <KDebug>
 
24
#include <KIconLoader>
 
25
#include <KLocale>
 
26
 
 
27
#include <Package>
 
28
 
 
29
#include "KpkPackageModel.h"
 
30
#include "KpkIcons.h"
 
31
 
 
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
 
37
 
 
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")
 
51
{
 
52
    // maybe rename or copy it to package-available
 
53
    if (QApplication::isRightToLeft()) {
 
54
        setExtendPixmap(SmallIcon("arrow-left"));
 
55
    } else {
 
56
        setExtendPixmap(SmallIcon("arrow-right"));
 
57
    }
 
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();
 
61
 
 
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();
 
73
}
 
74
 
 
75
void KpkDelegate::paint(QPainter *painter,
 
76
                        const QStyleOptionViewItem &option,
 
77
                        const QModelIndex &index) const
 
78
{
 
79
    if (!index.isValid()) {
 
80
        return;
 
81
    }
 
82
    bool leftToRight = (painter->layoutDirection() == Qt::LeftToRight);
 
83
 
 
84
    QStyleOptionViewItemV4 opt(option);
 
85
    QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
 
86
    painter->save();
 
87
    style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget);
 
88
    painter->restore();
 
89
 
 
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();
 
98
    Package::Info info;
 
99
    info = static_cast<Package::Info>(index.data(KpkPackageModel::InfoRole).toUInt());
 
100
    bool    pkgInstalled  = (info == Package::InfoInstalled ||
 
101
                             info == Package::InfoCollectionInstalled);
 
102
 
 
103
    bool    pkgCollection = (info == Package::InfoCollectionInstalled ||
 
104
                             info == Package::InfoCollectionAvailable);
 
105
 
 
106
    QIcon emblemIcon;
 
107
    if (pkgCheckable) {
 
108
        // update kind icon
 
109
        emblemIcon = index.data(KpkPackageModel::IconRole).value<QIcon>();
 
110
    } else {
 
111
        emblemIcon = m_checkedIcon;
 
112
    }
 
113
 
 
114
    // pain the background (checkbox and the extender)
 
115
    if (m_extendPixmapWidth) {
 
116
        KExtendableItemDelegate::paint(painter, opt, index);
 
117
    }
 
118
 
 
119
    int leftCount;
 
120
    if (leftToRight) {
 
121
        opt.rect.setLeft(option.rect.left() + m_extendPixmapWidth + UNIVERSAL_PADDING);
 
122
        leftCount = opt.rect.left() + UNIVERSAL_PADDING;
 
123
    } else {
 
124
        opt.rect.setRight(option.rect.right() - m_extendPixmapWidth - UNIVERSAL_PADDING);
 
125
        leftCount = opt.rect.width() - (UNIVERSAL_PADDING + MAIN_ICON_SIZE);
 
126
    }
 
127
 
 
128
    int left = opt.rect.left();
 
129
    int top = opt.rect.top();
 
130
    int width = opt.rect.width();
 
131
 
 
132
    QStyleOptionButton optBt;
 
133
    optBt.rect = opt.rect;
 
134
    if (pkgCheckable) {
 
135
        optBt.rect = style->subElementRect(QStyle::SE_CheckBoxIndicator, &optBt);
 
136
        // Count the checkbox size
 
137
        if (leftToRight) {
 
138
            leftCount += optBt.rect.width();
 
139
        } else {
 
140
            leftCount -= optBt.rect.width();
 
141
        }
 
142
    } else  if ((option.state & QStyle::State_MouseOver) ||
 
143
                (option.state & QStyle::State_Selected)
 
144
    ) {
 
145
        if (leftToRight) {
 
146
            optBt.rect.setLeft(left + width - (m_buttonSize.width() + UNIVERSAL_PADDING));
 
147
            width -= m_buttonSize.width() + UNIVERSAL_PADDING;
 
148
        } else {
 
149
            optBt.rect.setLeft(left + UNIVERSAL_PADDING);
 
150
            left += m_buttonSize.width() + UNIVERSAL_PADDING;
 
151
        }
 
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) {
 
158
//                 if ()
 
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;
 
164
        }
 
165
        optBt.state |= QStyle::State_Raised | QStyle::State_Active | QStyle::State_Enabled;
 
166
        optBt.iconSize = m_buttonIconSize;
 
167
        if (pkgChecked) {
 
168
            optBt.text = m_undoString;
 
169
            optBt.icon = m_undoIcon;
 
170
        } else {
 
171
            optBt.icon = pkgInstalled ? m_removeIcon   : m_installIcon;
 
172
            optBt.text = pkgInstalled ? m_removeString : m_installString;
 
173
        }
 
174
        style->drawControl(QStyle::CE_PushButton, &optBt, painter);
 
175
    }
 
176
 
 
177
// QAbstractItemView *view = qobject_cast<QAbstractItemView*>(parent());
 
178
//             QPoint pos = view->viewport()->mapFromGlobal(QCursor::pos());
 
179
//     kDebug() << pos;
 
180
 
 
181
 
 
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;
 
186
    }
 
187
 
 
188
    QColor foregroundColor = (option.state.testFlag(QStyle::State_Selected))?
 
189
    option.palette.color(QPalette::HighlightedText):option.palette.color(QPalette::Text);
 
190
 
 
191
    // Painting main column
 
192
    QStyleOptionViewItem local_option_title(option);
 
193
    QStyleOptionViewItem local_option_normal(option);
 
194
 
 
195
    local_option_normal.font.setPointSize(local_option_normal.font.pointSize() - 1);
 
196
 
 
197
    QPixmap pixmap(option.rect.size());
 
198
    pixmap.fill(Qt::transparent);
 
199
    QPainter p(&pixmap);
 
200
    p.translate(-option.rect.topLeft());
 
201
 
 
202
    // Main icon
 
203
    QIcon icon;
 
204
//     if (pkgIconPath.isEmpty()) {
 
205
        icon = pkgCollection ? m_collectionIcon : m_packageIcon;
 
206
//     } else {
 
207
//         icon = KpkIcons::getIcon(pkgIconPath, "package");
 
208
//     }
 
209
 
 
210
    int iconSize = calcItemHeight(option) - 2 * UNIVERSAL_PADDING;
 
211
    icon.paint(&p,
 
212
               leftCount,
 
213
               top + UNIVERSAL_PADDING,
 
214
               iconSize,
 
215
               iconSize,
 
216
               Qt::AlignCenter,
 
217
               iconMode);
 
218
 
 
219
    int textWidth;
 
220
    if (leftToRight) {
 
221
        // add the main icon
 
222
        leftCount += iconSize + UNIVERSAL_PADDING;
 
223
        textWidth = width - (leftCount - left);
 
224
    } else {
 
225
        leftCount -= UNIVERSAL_PADDING;
 
226
        textWidth = leftCount - left;
 
227
        leftCount = left;
 
228
    }
 
229
 
 
230
 
 
231
    // Painting
 
232
 
 
233
    // Text
 
234
    const int itemHeight = calcItemHeight(option);
 
235
 
 
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 + ')');
 
241
    }
 
242
    // draw the top line
 
243
    int topTextHeight = QFontInfo(local_option_title.font).pixelSize();
 
244
    p.setFont(local_option_title.font);
 
245
    p.drawText(leftCount,
 
246
               top,
 
247
               textWidth,
 
248
               topTextHeight + UNIVERSAL_PADDING,
 
249
               Qt::AlignVCenter | Qt::AlignLeft,
 
250
               pkgName);
 
251
 
 
252
    // draw the bottom line
 
253
    iconSize = topTextHeight + UNIVERSAL_PADDING;
 
254
    if (pkgCheckable || pkgInstalled) {
 
255
        emblemIcon.paint(&p,
 
256
                         leftToRight ? leftCount : (textWidth + left) - iconSize,
 
257
                         top + topTextHeight + UNIVERSAL_PADDING,
 
258
                         iconSize,
 
259
                         iconSize,
 
260
                         Qt::AlignVCenter | Qt::AlignHCenter,
 
261
                         iconMode);
 
262
    }
 
263
 
 
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);
 
268
    }
 
269
 
 
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,
 
276
               pkgSummary);
 
277
    p.setOpacity(opa);
 
278
 
 
279
    QLinearGradient gradient;
 
280
    // Gradient part of the background - fading of the text at the end
 
281
    if (leftToRight) {
 
282
        gradient = QLinearGradient(left + width - UNIVERSAL_PADDING - FADE_LENGTH,
 
283
                                   0,
 
284
                                   left + width - UNIVERSAL_PADDING,
 
285
                                   0);
 
286
        gradient.setColorAt(0, Qt::white);
 
287
        gradient.setColorAt(1, Qt::transparent);
 
288
    } else {
 
289
        gradient = QLinearGradient(left + UNIVERSAL_PADDING,
 
290
                                   0,
 
291
                                   left + UNIVERSAL_PADDING + FADE_LENGTH,
 
292
                                   0);
 
293
        gradient.setColorAt(0, Qt::transparent);
 
294
        gradient.setColorAt(1, Qt::white);
 
295
    }
 
296
 
 
297
    QRect paintRect = option.rect;
 
298
    p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
 
299
    p.fillRect(paintRect, gradient);
 
300
 
 
301
    if (leftToRight) {
 
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);
 
306
    } else {
 
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);
 
311
    }
 
312
    paintRect.setHeight(UNIVERSAL_PADDING + MAIN_ICON_SIZE / 2);
 
313
    p.fillRect(paintRect, gradient);
 
314
    p.setCompositionMode(QPainter::CompositionMode_SourceOver);
 
315
    p.end();
 
316
 
 
317
    painter->drawPixmap(option.rect.topLeft(), pixmap);
 
318
}
 
319
 
 
320
int KpkDelegate::calcItemHeight(const QStyleOptionViewItem &option) const
 
321
{
 
322
    // Painting main column
 
323
    QStyleOptionViewItem local_option_title(option);
 
324
    QStyleOptionViewItem local_option_normal(option);
 
325
 
 
326
    local_option_normal.font.setPointSize(local_option_normal.font.pointSize() - 1);
 
327
 
 
328
    int textHeight = QFontInfo(local_option_title.font).pixelSize() + QFontInfo(local_option_normal.font).pixelSize();
 
329
    return textHeight + 3 * UNIVERSAL_PADDING;
 
330
}
 
331
 
 
332
bool KpkDelegate::insideButton(const QRect &rect, const QPoint &pos) const
 
333
{
 
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()))) {
 
337
        return true;
 
338
    }
 
339
    return false;
 
340
}
 
341
 
 
342
bool KpkDelegate::editorEvent(QEvent *event,
 
343
                                    QAbstractItemModel *model,
 
344
                                    const QStyleOptionViewItem &option,
 
345
                                    const QModelIndex &index)
 
346
{
 
347
    Q_UNUSED(option)
 
348
 
 
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());
 
353
        if (tree) {
 
354
            point.ry() -= tree->header()->size().height();
 
355
        }
 
356
 
 
357
        bool leftToRight = QApplication::isLeftToRight();
 
358
        QStyleOptionButton optBt;
 
359
        optBt.rect = option.rect;
 
360
        if (leftToRight) {
 
361
            optBt.rect.setLeft(option.rect.left() + option.rect.width() - (m_buttonSize.width() + UNIVERSAL_PADDING));
 
362
        } else {
 
363
            optBt.rect.setLeft(option.rect.left() + UNIVERSAL_PADDING);
 
364
        }
 
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);
 
369
 
 
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(),
 
375
                                  Qt::CheckStateRole);
 
376
        }
 
377
        QRect rect = view->visualRect(index);
 
378
        if (QApplication::isRightToLeft()) {
 
379
            if ((rect.width() - point.x()) <= m_extendPixmapWidth) {
 
380
                emit showExtendItem(index);
 
381
            }
 
382
        } else if (point.x() <= m_extendPixmapWidth) {
 
383
            emit showExtendItem(index);
 
384
        }
 
385
    }
 
386
 
 
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);
 
392
    } else {
 
393
        opt.rect.setLeft(option.rect.left() + m_extendPixmapWidth);
 
394
    }
 
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);
 
399
}
 
400
 
 
401
void KpkDelegate::setExtendPixmapWidth(int width)
 
402
{
 
403
    m_extendPixmapWidth = width;
 
404
}
 
405
 
 
406
void KpkDelegate::setViewport(QWidget *viewport)
 
407
{
 
408
    m_viewport = viewport;
 
409
}
 
410
 
 
411
QSize KpkDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index ) const
 
412
{
 
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);
 
417
 
 
418
    ret.rheight() += calcItemHeight(option);
 
419
    ret.rwidth()  += width;
 
420
 
 
421
    return ret;
 
422
}
 
423
 
 
424
#include "KpkDelegate.moc"