~ubuntu-branches/ubuntu/precise/gwenview/precise-proposed

« back to all changes in this revision

Viewing changes to lib/thumbnailview/previewitemdelegate.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2011-12-15 14:17:54 UTC
  • mto: This revision was merged to the branch mainline in revision 12.
  • Revision ID: package-import@ubuntu.com-20111215141754-z043hyx69dulbggf
Tags: upstream-4.7.90
ImportĀ upstreamĀ versionĀ 4.7.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// vim: set tabstop=4 shiftwidth=4 noexpandtab:
 
1
// vim: set tabstop=4 shiftwidth=4 expandtab:
2
2
/*
3
3
Gwenview: an image viewer
4
4
Copyright 2008 AurĆ©lien GĆ¢teau <agateau@kde.org>
65
65
#include <QSettings>
66
66
#endif
67
67
 
68
 
namespace Gwenview {
 
68
namespace Gwenview
 
69
{
69
70
 
70
71
/**
71
72
 * Space between the item outer rect and the content, and between the
88
89
/** How many pixels around the thumbnail are shadowed */
89
90
const int SHADOW_SIZE = 4;
90
91
 
91
 
 
92
 
static KFileItem fileItemForIndex(const QModelIndex& index) {
93
 
        Q_ASSERT(index.isValid());
94
 
        QVariant data = index.data(KDirModel::FileItemRole);
95
 
        return qvariant_cast<KFileItem>(data);
96
 
}
97
 
 
98
 
 
99
 
static KUrl urlForIndex(const QModelIndex& index) {
100
 
        KFileItem item = fileItemForIndex(index);
101
 
        return item.url();
102
 
}
103
 
 
 
92
static KFileItem fileItemForIndex(const QModelIndex& index)
 
93
{
 
94
    Q_ASSERT(index.isValid());
 
95
    QVariant data = index.data(KDirModel::FileItemRole);
 
96
    return qvariant_cast<KFileItem>(data);
 
97
}
 
98
 
 
99
static KUrl urlForIndex(const QModelIndex& index)
 
100
{
 
101
    KFileItem item = fileItemForIndex(index);
 
102
    return item.url();
 
103
}
104
104
 
105
105
struct PreviewItemDelegatePrivate {
106
 
        /**
107
 
         * Maps full text to elided text.
108
 
         */
109
 
        mutable QHash<QString, QString> mElidedTextCache;
110
 
 
111
 
        // Key is height * 1000 + width
112
 
        typedef QHash<int, QPixmap> ShadowCache;
113
 
        mutable ShadowCache mShadowCache;
114
 
 
115
 
        PreviewItemDelegate* that;
116
 
        ThumbnailView* mView;
117
 
        QWidget* mContextBar;
118
 
        QToolButton* mSaveButton;
119
 
        QPixmap mSaveButtonPixmap;
120
 
 
121
 
        QToolButton* mToggleSelectionButton;
122
 
        QToolButton* mFullScreenButton;
123
 
        QToolButton* mRotateLeftButton;
124
 
        QToolButton* mRotateRightButton;
125
 
#ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
126
 
        KRatingPainter mRatingPainter;
127
 
#endif
128
 
 
129
 
        QModelIndex mIndexUnderCursor;
130
 
        int mThumbnailSize;
131
 
        PreviewItemDelegate::ThumbnailDetails mDetails;
132
 
        PreviewItemDelegate::ContextBarMode mContextBarMode;
133
 
        Qt::TextElideMode mTextElideMode;
134
 
 
135
 
        QPointer<ToolTipWidget> mToolTip;
136
 
        QScopedPointer<QAbstractAnimation> mToolTipAnimation;
137
 
 
138
 
 
139
 
        void initSaveButtonPixmap() {
140
 
                if (!mSaveButtonPixmap.isNull()) {
141
 
                        return;
142
 
                }
143
 
                // Necessary otherwise we won't see the save button itself
144
 
                mSaveButton->adjustSize();
145
 
 
146
 
                mSaveButtonPixmap = QPixmap(mSaveButton->sizeHint());
147
 
                mSaveButtonPixmap.fill(Qt::transparent);
148
 
                mSaveButton->render(&mSaveButtonPixmap, QPoint(), QRegion(), QWidget::DrawChildren);
149
 
        }
150
 
 
151
 
 
152
 
        void showContextBar(const QRect& rect, const QPixmap& thumbnailPix) {
153
 
                if (mContextBarMode == PreviewItemDelegate::NoContextBar) {
154
 
                        return;
155
 
                }
156
 
                mContextBar->adjustSize();
157
 
                // Center bar in FullContextBar mode, left align in
158
 
                // SelectionOnlyContextBar mode
159
 
                const int posX = mContextBarMode == PreviewItemDelegate::FullContextBar
160
 
                        ? (rect.width() - mContextBar->width()) / 2
161
 
                        : 0;
162
 
                const int posY = qMax(CONTEXTBAR_MARGIN, mThumbnailSize - thumbnailPix.height() - mContextBar->height());
163
 
                mContextBar->move(rect.topLeft() + QPoint(posX, posY));
164
 
                mContextBar->show();
165
 
        }
166
 
 
167
 
 
168
 
        void initToolTip() {
169
 
                mToolTip = new ToolTipWidget(mView->viewport());
170
 
                mToolTip->setOpacity(0);
171
 
                mToolTip->show();
172
 
        }
173
 
 
174
 
 
175
 
        bool hoverEventFilter(QHoverEvent* event) {
176
 
                QModelIndex index = mView->indexAt(event->pos());
177
 
                if (index != mIndexUnderCursor) {
178
 
                        updateHoverUi(index);
179
 
                } else {
180
 
                        // Same index, nothing to do, but repaint anyway in case we are
181
 
                        // over the rating row
182
 
                        mView->update(mIndexUnderCursor);
183
 
                }
184
 
                return false;
185
 
        }
186
 
 
187
 
 
188
 
        void updateHoverUi(const QModelIndex& index) {
189
 
                QModelIndex oldIndex = mIndexUnderCursor;
190
 
                mIndexUnderCursor = index;
191
 
                mView->update(oldIndex);
192
 
 
193
 
                if (KGlobalSettings::singleClick() && KGlobalSettings::changeCursorOverIcon()) {
194
 
                        mView->setCursor(mIndexUnderCursor.isValid() ? Qt::PointingHandCursor : Qt::ArrowCursor);
195
 
                }
196
 
 
197
 
                if (mIndexUnderCursor.isValid()) {
198
 
                        updateToggleSelectionButton();
199
 
                        updateImageButtons();
200
 
 
201
 
                        const QRect rect = mView->visualRect(mIndexUnderCursor);
202
 
                        const QPixmap thumbnailPix = mView->thumbnailForIndex(index);
203
 
                        showContextBar(rect, thumbnailPix);
204
 
                        if (mView->isModified(mIndexUnderCursor)) {
205
 
                                showSaveButton(rect);
206
 
                        } else {
207
 
                                mSaveButton->hide();
208
 
                        }
209
 
 
210
 
                        showToolTip(index);
211
 
                        mView->update(mIndexUnderCursor);
212
 
 
213
 
                } else {
214
 
                        mContextBar->hide();
215
 
                        mSaveButton->hide();
216
 
                        hideToolTip();
217
 
                }
218
 
        }
219
 
 
220
 
        QRect ratingRectFromIndexRect(const QRect& rect) const {
221
 
                return QRect(
222
 
                        rect.left(),
223
 
                        rect.bottom() - ratingRowHeight() - ITEM_MARGIN,
224
 
                        rect.width(),
225
 
                        ratingRowHeight());
226
 
        }
227
 
 
228
 
#ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
229
 
        int ratingFromCursorPosition(const QRect& ratingRect) const {
230
 
                const QPoint pos = mView->viewport()->mapFromGlobal(QCursor::pos());
231
 
                return mRatingPainter.ratingFromPosition(ratingRect, pos);
232
 
        }
233
 
#endif
234
 
 
235
 
        bool mouseButtonEventFilter(QEvent::Type type) {
236
 
        #ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
237
 
                const QRect rect = ratingRectFromIndexRect(mView->visualRect(mIndexUnderCursor));
238
 
                const int rating = ratingFromCursorPosition(rect);
239
 
                if (rating == -1) {
240
 
                        return false;
241
 
                }
242
 
                if (type == QEvent::MouseButtonRelease) {
243
 
                        that->setDocumentRatingRequested(urlForIndex(mIndexUnderCursor) , rating);
244
 
                }
245
 
                return true;
246
 
        #else
247
 
                return false;
248
 
        #endif
249
 
        }
250
 
 
251
 
 
252
 
        QPoint saveButtonPosition(const QRect& itemRect) const {
253
 
                QSize buttonSize = mSaveButton->sizeHint();
254
 
                int posX = itemRect.right() - buttonSize.width();
255
 
                int posY = itemRect.top() + mThumbnailSize + 2 * ITEM_MARGIN - buttonSize.height();
256
 
 
257
 
                return QPoint(posX, posY);
258
 
        }
259
 
 
260
 
 
261
 
        void showSaveButton(const QRect& itemRect) const {
262
 
                mSaveButton->move(saveButtonPosition(itemRect));
263
 
                mSaveButton->show();
264
 
        }
265
 
 
266
 
 
267
 
        void drawBackground(QPainter* painter, const QRect& rect, const QColor& bgColor, const QColor& borderColor) const {
268
 
                int bgH, bgS, bgV;
269
 
                int borderH, borderS, borderV, borderMargin;
270
 
        #ifdef FINETUNE_SELECTION_BACKGROUND
271
 
                QSettings settings(QDir::homePath() + "/colors.ini", QSettings::IniFormat);
272
 
                bgH = settings.value("bg/h").toInt();
273
 
                bgS = settings.value("bg/s").toInt();
274
 
                bgV = settings.value("bg/v").toInt();
275
 
                borderH = settings.value("border/h").toInt();
276
 
                borderS = settings.value("border/s").toInt();
277
 
                borderV = settings.value("border/v").toInt();
278
 
                borderMargin = settings.value("border/margin").toInt();
279
 
        #else
280
 
                bgH = 0;
281
 
                bgS = -20;
282
 
                bgV = 43;
283
 
                borderH = 0;
284
 
                borderS = -100;
285
 
                borderV = 60;
286
 
                borderMargin = 1;
287
 
        #endif
288
 
                painter->setRenderHint(QPainter::Antialiasing);
289
 
 
290
 
                QRectF rectF = QRectF(rect).adjusted(0.5, 0.5, -0.5, -0.5);
291
 
 
292
 
                QPainterPath path = PaintUtils::roundedRectangle(rectF, SELECTION_RADIUS);
293
 
 
294
 
                QLinearGradient gradient(rectF.topLeft(), rectF.bottomLeft());
295
 
                gradient.setColorAt(0, PaintUtils::adjustedHsv(bgColor, bgH, bgS, bgV));
296
 
                gradient.setColorAt(1, bgColor);
297
 
                painter->fillPath(path, gradient);
298
 
 
299
 
                painter->setPen(borderColor);
300
 
                painter->drawPath(path);
301
 
 
302
 
                painter->setPen(PaintUtils::adjustedHsv(borderColor, borderH, borderS, borderV));
303
 
                rectF = rectF.adjusted(borderMargin, borderMargin, -borderMargin, -borderMargin);
304
 
                path = PaintUtils::roundedRectangle(rectF, SELECTION_RADIUS);
305
 
                painter->drawPath(path);
306
 
        }
307
 
 
308
 
 
309
 
        void drawShadow(QPainter* painter, const QRect& rect) const {
310
 
                const QPoint shadowOffset(-SHADOW_SIZE, -SHADOW_SIZE + 1);
311
 
 
312
 
                int key = rect.height() * 1000 + rect.width();
313
 
 
314
 
                ShadowCache::Iterator it = mShadowCache.find(key);
315
 
                if (it == mShadowCache.end()) {
316
 
                        QSize size = QSize(rect.width() + 2*SHADOW_SIZE, rect.height() + 2*SHADOW_SIZE);
317
 
                        QColor color(0, 0, 0, SHADOW_STRENGTH);
318
 
                        QPixmap shadow = PaintUtils::generateFuzzyRect(size, color, SHADOW_SIZE);
319
 
                        it = mShadowCache.insert(key, shadow);
320
 
                }
321
 
                painter->drawPixmap(rect.topLeft() + shadowOffset, it.value());
322
 
        }
323
 
 
324
 
 
325
 
        void drawText(QPainter* painter, const QRect& rect, const QColor& fgColor, const QString& fullText) const {
326
 
                QFontMetrics fm = mView->fontMetrics();
327
 
 
328
 
                // Elide text
329
 
                QString text;
330
 
                QHash<QString, QString>::const_iterator it = mElidedTextCache.constFind(fullText);
331
 
                if (it == mElidedTextCache.constEnd()) {
332
 
                        text = fm.elidedText(fullText, mTextElideMode, rect.width());
333
 
                        mElidedTextCache[fullText] = text;
334
 
                } else {
335
 
                        text = it.value();
336
 
                }
337
 
 
338
 
                // Compute x pos
339
 
                int posX;
340
 
                if (text.length() == fullText.length()) {
341
 
                        // Not elided, center text
342
 
                        posX = (rect.width() - fm.width(text)) / 2;
343
 
                } else {
344
 
                        // Elided, left align
345
 
                        posX = 0;
346
 
                }
347
 
 
348
 
                // Draw text
349
 
                painter->setPen(fgColor);
350
 
                painter->drawText(rect.left() + posX, rect.top() + fm.ascent(), text);
351
 
        }
352
 
 
353
 
 
354
 
        void drawRating(QPainter* painter, const QRect& rect, const QVariant& value) {
355
 
        #ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
356
 
                const int rating = value.toInt();
357
 
                const QRect ratingRect = ratingRectFromIndexRect(rect);
358
 
                const int hoverRating = ratingFromCursorPosition(ratingRect);
359
 
                mRatingPainter.paint(painter, ratingRect, rating, hoverRating);
360
 
        #endif
361
 
        }
362
 
 
363
 
 
364
 
        bool isTextElided(const QString& text) const {
365
 
                QHash<QString, QString>::const_iterator it = mElidedTextCache.constFind(text);
366
 
                if (it == mElidedTextCache.constEnd()) {
367
 
                        return false;
368
 
                }
369
 
                return it.value().length() < text.length();
370
 
        }
371
 
 
372
 
 
373
 
        /**
374
 
         * Show a tooltip only if the item has been elided.
375
 
         * This function places the tooltip over the item text.
376
 
         */
377
 
        void showToolTip(const QModelIndex& index) {
378
 
                if (mDetails == 0 || mDetails == PreviewItemDelegate::RatingDetail) {
379
 
                        // No text to display
380
 
                        return;
381
 
                }
382
 
 
383
 
                // Gather tip text
384
 
                QStringList textList;
385
 
                bool elided = false;
386
 
                if (mDetails & PreviewItemDelegate::FileNameDetail) {
387
 
                        const QString text = index.data().toString();
388
 
                        elided |= isTextElided(text);
389
 
                        textList << text;
390
 
                }
391
 
 
392
 
                // FIXME: Duplicated from drawText
393
 
                const KFileItem fileItem = fileItemForIndex(index);
394
 
                const bool isDirOrArchive = ArchiveUtils::fileItemIsDirOrArchive(fileItem);
395
 
                if (mDetails & PreviewItemDelegate::DateDetail) {
396
 
                        if (!ArchiveUtils::fileItemIsDirOrArchive(fileItem)) {
397
 
                                const KDateTime dt = TimeUtils::dateTimeForFileItem(fileItem);
398
 
                                const QString text = KGlobal::locale()->formatDateTime(dt);
399
 
                                elided |= isTextElided(text);
400
 
                                textList << text;
401
 
                        }
402
 
                }
403
 
 
404
 
                if (!isDirOrArchive && (mDetails & PreviewItemDelegate::ImageSizeDetail)) {
405
 
                        QSize fullSize;
406
 
                        QPixmap thumbnailPix = mView->thumbnailForIndex(index, &fullSize);
407
 
                        if (fullSize.isValid()) {
408
 
                                const QString text = QString("%1x%2").arg(fullSize.width()).arg(fullSize.height());
409
 
                                elided |= isTextElided(text);
410
 
                                textList << text;
411
 
                        }
412
 
                }
413
 
 
414
 
                if (!isDirOrArchive && (mDetails & PreviewItemDelegate::FileSizeDetail)) {
415
 
                        const KIO::filesize_t size = fileItem.size();
416
 
                        if (size > 0) {
417
 
                                const QString text = KIO::convertSize(size);
418
 
                                elided |= isTextElided(text);
419
 
                                textList << text;
420
 
                        }
421
 
                }
422
 
 
423
 
                if (!elided) {
424
 
                        hideToolTip();
425
 
                        return;
426
 
                }
427
 
 
428
 
                bool newTipLabel = !mToolTip;
429
 
                if (!mToolTip) {
430
 
                        initToolTip();
431
 
                }
432
 
                mToolTip->setText(textList.join("\n"));
433
 
                QSize tipSize = mToolTip->sizeHint();
434
 
 
435
 
                // Compute tip position
436
 
                QRect rect = mView->visualRect(index);
437
 
                const int textY = ITEM_MARGIN + mThumbnailSize + ITEM_MARGIN;
438
 
                const int spacing = 1;
439
 
                QRect geometry(
440
 
                        QPoint(rect.topLeft() + QPoint((rect.width() - tipSize.width()) / 2, textY + spacing)),
441
 
                        tipSize
442
 
                        );
443
 
                if (geometry.left() < 0) {
444
 
                        geometry.moveLeft(0);
445
 
                } else if (geometry.right() > mView->viewport()->width()) {
446
 
                        geometry.moveRight(mView->viewport()->width());
447
 
                }
448
 
 
449
 
                // Show tip
450
 
                QParallelAnimationGroup* anim = new QParallelAnimationGroup();
451
 
                QPropertyAnimation* fadeIn = new QPropertyAnimation(mToolTip, "opacity");
452
 
                fadeIn->setStartValue(mToolTip->opacity());
453
 
                fadeIn->setEndValue(1.);
454
 
                anim->addAnimation(fadeIn);
455
 
 
456
 
                if (newTipLabel) {
457
 
                        mToolTip->setGeometry(geometry);
458
 
                } else {
459
 
                        QPropertyAnimation* move = new QPropertyAnimation(mToolTip, "geometry");
460
 
                        move->setStartValue(mToolTip->geometry());
461
 
                        move->setEndValue(geometry);
462
 
                        anim->addAnimation(move);
463
 
                }
464
 
 
465
 
                mToolTipAnimation.reset(anim);
466
 
                mToolTipAnimation->start();
467
 
        }
468
 
 
469
 
        void hideToolTip() {
470
 
                if (!mToolTip) {
471
 
                        return;
472
 
                }
473
 
                QSequentialAnimationGroup* anim = new QSequentialAnimationGroup();
474
 
                anim->addPause(500);
475
 
                QPropertyAnimation* fadeOut = new QPropertyAnimation(mToolTip, "opacity");
476
 
                fadeOut->setStartValue(mToolTip->opacity());
477
 
                fadeOut->setEndValue(0.);
478
 
                anim->addAnimation(fadeOut);
479
 
                mToolTipAnimation.reset(anim);
480
 
                mToolTipAnimation->start();
481
 
                QObject::connect(anim, SIGNAL(finished()), mToolTip, SLOT(deleteLater()));
482
 
        }
483
 
 
484
 
        int itemWidth() const {
485
 
                return mThumbnailSize + 2 * ITEM_MARGIN;
486
 
        }
487
 
 
488
 
        int ratingRowHeight() const {
489
 
#ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
490
 
                return mView->fontMetrics().ascent();
491
 
#endif
492
 
                return 0;
493
 
        }
494
 
 
495
 
        int itemHeight() const {
496
 
                const int lineHeight = mView->fontMetrics().height();
497
 
                int textHeight = 0;
498
 
                if (mDetails & PreviewItemDelegate::FileNameDetail) {
499
 
                        textHeight += lineHeight;
500
 
                }
501
 
                if (mDetails & PreviewItemDelegate::DateDetail) {
502
 
                        textHeight += lineHeight;
503
 
                }
504
 
                if (mDetails & PreviewItemDelegate::ImageSizeDetail) {
505
 
                        textHeight += lineHeight;
506
 
                }
507
 
                if (mDetails & PreviewItemDelegate::FileSizeDetail) {
508
 
                        textHeight += lineHeight;
509
 
                }
510
 
                if (mDetails & PreviewItemDelegate::RatingDetail) {
511
 
                        textHeight += ratingRowHeight();
512
 
                }
513
 
                if (textHeight == 0) {
514
 
                        // Keep at least one row of text, so that we can show folder names
515
 
                        textHeight = lineHeight;
516
 
                }
517
 
                return mThumbnailSize + textHeight + 3*ITEM_MARGIN;
518
 
        }
519
 
 
520
 
        void selectIndexUnderCursorIfNoMultiSelection() {
521
 
                if (mView->selectionModel()->selectedIndexes().size() <= 1) {
522
 
                        mView->setCurrentIndex(mIndexUnderCursor);
523
 
                }
524
 
        }
525
 
 
526
 
        void updateToggleSelectionButton() {
527
 
                mToggleSelectionButton->setIcon(SmallIcon(
528
 
                        mView->selectionModel()->isSelected(mIndexUnderCursor) ? "list-remove" : "list-add"
529
 
                        ));
530
 
        }
531
 
 
532
 
        void updateImageButtons() {
533
 
                const KFileItem item = fileItemForIndex(mIndexUnderCursor);
534
 
                const bool isImage = !ArchiveUtils::fileItemIsDirOrArchive(item);
535
 
                mFullScreenButton->setEnabled(isImage);
536
 
                mRotateLeftButton->setEnabled(isImage);
537
 
                mRotateRightButton->setEnabled(isImage);
538
 
        }
539
 
 
540
 
        void updateContextBar() {
541
 
                if (mContextBarMode == PreviewItemDelegate::NoContextBar) {
542
 
                        mContextBar->hide();
543
 
                        return;
544
 
                }
545
 
                const int width = itemWidth();
546
 
                const int buttonWidth = mRotateRightButton->sizeHint().width();
547
 
                bool full = mContextBarMode == PreviewItemDelegate::FullContextBar;
548
 
                mFullScreenButton->setVisible(full);
549
 
                mRotateLeftButton->setVisible(full && width >= 3 * buttonWidth);
550
 
                mRotateRightButton->setVisible(full && width >= 4 * buttonWidth);
551
 
                mContextBar->adjustSize();
552
 
        }
553
 
 
554
 
        void updateViewGridSize() {
555
 
                mView->setGridSize(QSize(itemWidth(), itemHeight()));
556
 
        }
 
106
    /**
 
107
     * Maps full text to elided text.
 
108
     */
 
109
    mutable QHash<QString, QString> mElidedTextCache;
 
110
 
 
111
    // Key is height * 1000 + width
 
112
    typedef QHash<int, QPixmap> ShadowCache;
 
113
    mutable ShadowCache mShadowCache;
 
114
 
 
115
    PreviewItemDelegate* q;
 
116
    ThumbnailView* mView;
 
117
    QWidget* mContextBar;
 
118
    QToolButton* mSaveButton;
 
119
    QPixmap mSaveButtonPixmap;
 
120
 
 
121
    QToolButton* mToggleSelectionButton;
 
122
    QToolButton* mFullScreenButton;
 
123
    QToolButton* mRotateLeftButton;
 
124
    QToolButton* mRotateRightButton;
 
125
#ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
 
126
    KRatingPainter mRatingPainter;
 
127
#endif
 
128
 
 
129
    QModelIndex mIndexUnderCursor;
 
130
    int mThumbnailSize;
 
131
    PreviewItemDelegate::ThumbnailDetails mDetails;
 
132
    PreviewItemDelegate::ContextBarMode mContextBarMode;
 
133
    Qt::TextElideMode mTextElideMode;
 
134
 
 
135
    QPointer<ToolTipWidget> mToolTip;
 
136
    QScopedPointer<QAbstractAnimation> mToolTipAnimation;
 
137
 
 
138
    void initSaveButtonPixmap()
 
139
    {
 
140
        if (!mSaveButtonPixmap.isNull()) {
 
141
            return;
 
142
        }
 
143
        // Necessary otherwise we won't see the save button itself
 
144
        mSaveButton->adjustSize();
 
145
 
 
146
        mSaveButtonPixmap = QPixmap(mSaveButton->sizeHint());
 
147
        mSaveButtonPixmap.fill(Qt::transparent);
 
148
        mSaveButton->render(&mSaveButtonPixmap, QPoint(), QRegion(), QWidget::DrawChildren);
 
149
    }
 
150
 
 
151
    void showContextBar(const QRect& rect, const QPixmap& thumbnailPix)
 
152
    {
 
153
        if (mContextBarMode == PreviewItemDelegate::NoContextBar) {
 
154
            return;
 
155
        }
 
156
        mContextBar->adjustSize();
 
157
        // Center bar in FullContextBar mode, left align in
 
158
        // SelectionOnlyContextBar mode
 
159
        const int posX = mContextBarMode == PreviewItemDelegate::FullContextBar
 
160
                         ? (rect.width() - mContextBar->width()) / 2
 
161
                         : 0;
 
162
        const int posY = qMax(CONTEXTBAR_MARGIN, mThumbnailSize - thumbnailPix.height() - mContextBar->height());
 
163
        mContextBar->move(rect.topLeft() + QPoint(posX, posY));
 
164
        mContextBar->show();
 
165
    }
 
166
 
 
167
    void initToolTip()
 
168
    {
 
169
        mToolTip = new ToolTipWidget(mView->viewport());
 
170
        mToolTip->setOpacity(0);
 
171
        mToolTip->show();
 
172
    }
 
173
 
 
174
    bool hoverEventFilter(QHoverEvent* event)
 
175
    {
 
176
        QModelIndex index = mView->indexAt(event->pos());
 
177
        if (index != mIndexUnderCursor) {
 
178
            updateHoverUi(index);
 
179
        } else {
 
180
            // Same index, nothing to do, but repaint anyway in case we are
 
181
            // over the rating row
 
182
            mView->update(mIndexUnderCursor);
 
183
        }
 
184
        return false;
 
185
    }
 
186
 
 
187
    void updateHoverUi(const QModelIndex& index)
 
188
    {
 
189
        QModelIndex oldIndex = mIndexUnderCursor;
 
190
        mIndexUnderCursor = index;
 
191
        mView->update(oldIndex);
 
192
 
 
193
        if (KGlobalSettings::singleClick() && KGlobalSettings::changeCursorOverIcon()) {
 
194
            mView->setCursor(mIndexUnderCursor.isValid() ? Qt::PointingHandCursor : Qt::ArrowCursor);
 
195
        }
 
196
 
 
197
        if (mIndexUnderCursor.isValid()) {
 
198
            updateToggleSelectionButton();
 
199
            updateImageButtons();
 
200
 
 
201
            const QRect rect = mView->visualRect(mIndexUnderCursor);
 
202
            const QPixmap thumbnailPix = mView->thumbnailForIndex(index);
 
203
            showContextBar(rect, thumbnailPix);
 
204
            if (mView->isModified(mIndexUnderCursor)) {
 
205
                showSaveButton(rect);
 
206
            } else {
 
207
                mSaveButton->hide();
 
208
            }
 
209
 
 
210
            showToolTip(index);
 
211
            mView->update(mIndexUnderCursor);
 
212
 
 
213
        } else {
 
214
            mContextBar->hide();
 
215
            mSaveButton->hide();
 
216
            hideToolTip();
 
217
        }
 
218
    }
 
219
 
 
220
    QRect ratingRectFromIndexRect(const QRect& rect) const {
 
221
        return QRect(
 
222
                   rect.left(),
 
223
                   rect.bottom() - ratingRowHeight() - ITEM_MARGIN,
 
224
                   rect.width(),
 
225
                   ratingRowHeight());
 
226
    }
 
227
 
 
228
#ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
 
229
    int ratingFromCursorPosition(const QRect& ratingRect) const {
 
230
        const QPoint pos = mView->viewport()->mapFromGlobal(QCursor::pos());
 
231
        return mRatingPainter.ratingFromPosition(ratingRect, pos);
 
232
    }
 
233
#endif
 
234
 
 
235
    bool mouseButtonEventFilter(QEvent::Type type)
 
236
    {
 
237
#ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
 
238
        const QRect rect = ratingRectFromIndexRect(mView->visualRect(mIndexUnderCursor));
 
239
        const int rating = ratingFromCursorPosition(rect);
 
240
        if (rating == -1) {
 
241
            return false;
 
242
        }
 
243
        if (type == QEvent::MouseButtonRelease) {
 
244
            q->setDocumentRatingRequested(urlForIndex(mIndexUnderCursor) , rating);
 
245
        }
 
246
        return true;
 
247
#else
 
248
        return false;
 
249
#endif
 
250
    }
 
251
 
 
252
    QPoint saveButtonPosition(const QRect& itemRect) const {
 
253
        QSize buttonSize = mSaveButton->sizeHint();
 
254
        int posX = itemRect.right() - buttonSize.width();
 
255
        int posY = itemRect.top() + mThumbnailSize + 2 * ITEM_MARGIN - buttonSize.height();
 
256
 
 
257
        return QPoint(posX, posY);
 
258
    }
 
259
 
 
260
    void showSaveButton(const QRect& itemRect) const
 
261
    {
 
262
        mSaveButton->move(saveButtonPosition(itemRect));
 
263
        mSaveButton->show();
 
264
    }
 
265
 
 
266
    void drawBackground(QPainter* painter, const QRect& rect, const QColor& bgColor, const QColor& borderColor) const
 
267
    {
 
268
        int bgH, bgS, bgV;
 
269
        int borderH, borderS, borderV, borderMargin;
 
270
#ifdef FINETUNE_SELECTION_BACKGROUND
 
271
        QSettings settings(QDir::homePath() + "/colors.ini", QSettings::IniFormat);
 
272
        bgH = settings.value("bg/h").toInt();
 
273
        bgS = settings.value("bg/s").toInt();
 
274
        bgV = settings.value("bg/v").toInt();
 
275
        borderH = settings.value("border/h").toInt();
 
276
        borderS = settings.value("border/s").toInt();
 
277
        borderV = settings.value("border/v").toInt();
 
278
        borderMargin = settings.value("border/margin").toInt();
 
279
#else
 
280
        bgH = 0;
 
281
        bgS = -20;
 
282
        bgV = 43;
 
283
        borderH = 0;
 
284
        borderS = -100;
 
285
        borderV = 60;
 
286
        borderMargin = 1;
 
287
#endif
 
288
        painter->setRenderHint(QPainter::Antialiasing);
 
289
 
 
290
        QRectF rectF = QRectF(rect).adjusted(0.5, 0.5, -0.5, -0.5);
 
291
 
 
292
        QPainterPath path = PaintUtils::roundedRectangle(rectF, SELECTION_RADIUS);
 
293
 
 
294
        QLinearGradient gradient(rectF.topLeft(), rectF.bottomLeft());
 
295
        gradient.setColorAt(0, PaintUtils::adjustedHsv(bgColor, bgH, bgS, bgV));
 
296
        gradient.setColorAt(1, bgColor);
 
297
        painter->fillPath(path, gradient);
 
298
 
 
299
        painter->setPen(borderColor);
 
300
        painter->drawPath(path);
 
301
 
 
302
        painter->setPen(PaintUtils::adjustedHsv(borderColor, borderH, borderS, borderV));
 
303
        rectF = rectF.adjusted(borderMargin, borderMargin, -borderMargin, -borderMargin);
 
304
        path = PaintUtils::roundedRectangle(rectF, SELECTION_RADIUS);
 
305
        painter->drawPath(path);
 
306
    }
 
307
 
 
308
    void drawShadow(QPainter* painter, const QRect& rect) const
 
309
    {
 
310
        const QPoint shadowOffset(-SHADOW_SIZE, -SHADOW_SIZE + 1);
 
311
 
 
312
        int key = rect.height() * 1000 + rect.width();
 
313
 
 
314
        ShadowCache::Iterator it = mShadowCache.find(key);
 
315
        if (it == mShadowCache.end()) {
 
316
            QSize size = QSize(rect.width() + 2 * SHADOW_SIZE, rect.height() + 2 * SHADOW_SIZE);
 
317
            QColor color(0, 0, 0, SHADOW_STRENGTH);
 
318
            QPixmap shadow = PaintUtils::generateFuzzyRect(size, color, SHADOW_SIZE);
 
319
            it = mShadowCache.insert(key, shadow);
 
320
        }
 
321
        painter->drawPixmap(rect.topLeft() + shadowOffset, it.value());
 
322
    }
 
323
 
 
324
    void drawText(QPainter* painter, const QRect& rect, const QColor& fgColor, const QString& fullText) const
 
325
    {
 
326
        QFontMetrics fm = mView->fontMetrics();
 
327
 
 
328
        // Elide text
 
329
        QString text;
 
330
        QHash<QString, QString>::const_iterator it = mElidedTextCache.constFind(fullText);
 
331
        if (it == mElidedTextCache.constEnd()) {
 
332
            text = fm.elidedText(fullText, mTextElideMode, rect.width());
 
333
            mElidedTextCache[fullText] = text;
 
334
        } else {
 
335
            text = it.value();
 
336
        }
 
337
 
 
338
        // Compute x pos
 
339
        int posX;
 
340
        if (text.length() == fullText.length()) {
 
341
            // Not elided, center text
 
342
            posX = (rect.width() - fm.width(text)) / 2;
 
343
        } else {
 
344
            // Elided, left align
 
345
            posX = 0;
 
346
        }
 
347
 
 
348
        // Draw text
 
349
        painter->setPen(fgColor);
 
350
        painter->drawText(rect.left() + posX, rect.top() + fm.ascent(), text);
 
351
    }
 
352
 
 
353
    void drawRating(QPainter* painter, const QRect& rect, const QVariant& value)
 
354
    {
 
355
#ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
 
356
        const int rating = value.toInt();
 
357
        const QRect ratingRect = ratingRectFromIndexRect(rect);
 
358
        const int hoverRating = ratingFromCursorPosition(ratingRect);
 
359
        mRatingPainter.paint(painter, ratingRect, rating, hoverRating);
 
360
#endif
 
361
    }
 
362
 
 
363
    bool isTextElided(const QString& text) const {
 
364
        QHash<QString, QString>::const_iterator it = mElidedTextCache.constFind(text);
 
365
        if (it == mElidedTextCache.constEnd()) {
 
366
            return false;
 
367
        }
 
368
        return it.value().length() < text.length();
 
369
    }
 
370
 
 
371
    /**
 
372
     * Show a tooltip only if the item has been elided.
 
373
     * This function places the tooltip over the item text.
 
374
     */
 
375
    void showToolTip(const QModelIndex& index)
 
376
    {
 
377
        if (mDetails == 0 || mDetails == PreviewItemDelegate::RatingDetail) {
 
378
            // No text to display
 
379
            return;
 
380
        }
 
381
 
 
382
        // Gather tip text
 
383
        QStringList textList;
 
384
        bool elided = false;
 
385
        if (mDetails & PreviewItemDelegate::FileNameDetail) {
 
386
            const QString text = index.data().toString();
 
387
            elided |= isTextElided(text);
 
388
            textList << text;
 
389
        }
 
390
 
 
391
        // FIXME: Duplicated from drawText
 
392
        const KFileItem fileItem = fileItemForIndex(index);
 
393
        const bool isDirOrArchive = ArchiveUtils::fileItemIsDirOrArchive(fileItem);
 
394
        if (mDetails & PreviewItemDelegate::DateDetail) {
 
395
            if (!ArchiveUtils::fileItemIsDirOrArchive(fileItem)) {
 
396
                const KDateTime dt = TimeUtils::dateTimeForFileItem(fileItem);
 
397
                const QString text = KGlobal::locale()->formatDateTime(dt);
 
398
                elided |= isTextElided(text);
 
399
                textList << text;
 
400
            }
 
401
        }
 
402
 
 
403
        if (!isDirOrArchive && (mDetails & PreviewItemDelegate::ImageSizeDetail)) {
 
404
            QSize fullSize;
 
405
            QPixmap thumbnailPix = mView->thumbnailForIndex(index, &fullSize);
 
406
            if (fullSize.isValid()) {
 
407
                const QString text = QString("%1x%2").arg(fullSize.width()).arg(fullSize.height());
 
408
                elided |= isTextElided(text);
 
409
                textList << text;
 
410
            }
 
411
        }
 
412
 
 
413
        if (!isDirOrArchive && (mDetails & PreviewItemDelegate::FileSizeDetail)) {
 
414
            const KIO::filesize_t size = fileItem.size();
 
415
            if (size > 0) {
 
416
                const QString text = KIO::convertSize(size);
 
417
                elided |= isTextElided(text);
 
418
                textList << text;
 
419
            }
 
420
        }
 
421
 
 
422
        if (!elided) {
 
423
            hideToolTip();
 
424
            return;
 
425
        }
 
426
 
 
427
        bool newTipLabel = !mToolTip;
 
428
        if (!mToolTip) {
 
429
            initToolTip();
 
430
        }
 
431
        mToolTip->setText(textList.join("\n"));
 
432
        QSize tipSize = mToolTip->sizeHint();
 
433
 
 
434
        // Compute tip position
 
435
        QRect rect = mView->visualRect(index);
 
436
        const int textY = ITEM_MARGIN + mThumbnailSize + ITEM_MARGIN;
 
437
        const int spacing = 1;
 
438
        QRect geometry(
 
439
            QPoint(rect.topLeft() + QPoint((rect.width() - tipSize.width()) / 2, textY + spacing)),
 
440
            tipSize
 
441
        );
 
442
        if (geometry.left() < 0) {
 
443
            geometry.moveLeft(0);
 
444
        } else if (geometry.right() > mView->viewport()->width()) {
 
445
            geometry.moveRight(mView->viewport()->width());
 
446
        }
 
447
 
 
448
        // Show tip
 
449
        QParallelAnimationGroup* anim = new QParallelAnimationGroup();
 
450
        QPropertyAnimation* fadeIn = new QPropertyAnimation(mToolTip, "opacity");
 
451
        fadeIn->setStartValue(mToolTip->opacity());
 
452
        fadeIn->setEndValue(1.);
 
453
        anim->addAnimation(fadeIn);
 
454
 
 
455
        if (newTipLabel) {
 
456
            mToolTip->setGeometry(geometry);
 
457
        } else {
 
458
            QPropertyAnimation* move = new QPropertyAnimation(mToolTip, "geometry");
 
459
            move->setStartValue(mToolTip->geometry());
 
460
            move->setEndValue(geometry);
 
461
            anim->addAnimation(move);
 
462
        }
 
463
 
 
464
        mToolTipAnimation.reset(anim);
 
465
        mToolTipAnimation->start();
 
466
    }
 
467
 
 
468
    void hideToolTip()
 
469
    {
 
470
        if (!mToolTip) {
 
471
            return;
 
472
        }
 
473
        QSequentialAnimationGroup* anim = new QSequentialAnimationGroup();
 
474
        anim->addPause(500);
 
475
        QPropertyAnimation* fadeOut = new QPropertyAnimation(mToolTip, "opacity");
 
476
        fadeOut->setStartValue(mToolTip->opacity());
 
477
        fadeOut->setEndValue(0.);
 
478
        anim->addAnimation(fadeOut);
 
479
        mToolTipAnimation.reset(anim);
 
480
        mToolTipAnimation->start();
 
481
        QObject::connect(anim, SIGNAL(finished()), mToolTip, SLOT(deleteLater()));
 
482
    }
 
483
 
 
484
    int itemWidth() const {
 
485
        return mThumbnailSize + 2 * ITEM_MARGIN;
 
486
    }
 
487
 
 
488
    int ratingRowHeight() const {
 
489
#ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
 
490
        return mView->fontMetrics().ascent();
 
491
#endif
 
492
        return 0;
 
493
    }
 
494
 
 
495
    int itemHeight() const {
 
496
        const int lineHeight = mView->fontMetrics().height();
 
497
        int textHeight = 0;
 
498
        if (mDetails & PreviewItemDelegate::FileNameDetail) {
 
499
            textHeight += lineHeight;
 
500
        }
 
501
        if (mDetails & PreviewItemDelegate::DateDetail) {
 
502
            textHeight += lineHeight;
 
503
        }
 
504
        if (mDetails & PreviewItemDelegate::ImageSizeDetail) {
 
505
            textHeight += lineHeight;
 
506
        }
 
507
        if (mDetails & PreviewItemDelegate::FileSizeDetail) {
 
508
            textHeight += lineHeight;
 
509
        }
 
510
        if (mDetails & PreviewItemDelegate::RatingDetail) {
 
511
            textHeight += ratingRowHeight();
 
512
        }
 
513
        if (textHeight == 0) {
 
514
            // Keep at least one row of text, so that we can show folder names
 
515
            textHeight = lineHeight;
 
516
        }
 
517
        return mThumbnailSize + textHeight + 3 * ITEM_MARGIN;
 
518
    }
 
519
 
 
520
    void selectIndexUnderCursorIfNoMultiSelection()
 
521
    {
 
522
        if (mView->selectionModel()->selectedIndexes().size() <= 1) {
 
523
            mView->setCurrentIndex(mIndexUnderCursor);
 
524
        }
 
525
    }
 
526
 
 
527
    void updateToggleSelectionButton()
 
528
    {
 
529
        mToggleSelectionButton->setIcon(SmallIcon(
 
530
                                            mView->selectionModel()->isSelected(mIndexUnderCursor) ? "list-remove" : "list-add"
 
531
                                        ));
 
532
    }
 
533
 
 
534
    void updateImageButtons()
 
535
    {
 
536
        const KFileItem item = fileItemForIndex(mIndexUnderCursor);
 
537
        const bool isImage = !ArchiveUtils::fileItemIsDirOrArchive(item);
 
538
        mFullScreenButton->setEnabled(isImage);
 
539
        mRotateLeftButton->setEnabled(isImage);
 
540
        mRotateRightButton->setEnabled(isImage);
 
541
    }
 
542
 
 
543
    void updateContextBar()
 
544
    {
 
545
        if (mContextBarMode == PreviewItemDelegate::NoContextBar) {
 
546
            mContextBar->hide();
 
547
            return;
 
548
        }
 
549
        const int width = itemWidth();
 
550
        const int buttonWidth = mRotateRightButton->sizeHint().width();
 
551
        bool full = mContextBarMode == PreviewItemDelegate::FullContextBar;
 
552
        mFullScreenButton->setVisible(full);
 
553
        mRotateLeftButton->setVisible(full && width >= 3 * buttonWidth);
 
554
        mRotateRightButton->setVisible(full && width >= 4 * buttonWidth);
 
555
        mContextBar->adjustSize();
 
556
    }
 
557
 
 
558
    void updateViewGridSize()
 
559
    {
 
560
        mView->setGridSize(QSize(itemWidth(), itemHeight()));
 
561
    }
557
562
};
558
563
 
559
 
 
560
564
PreviewItemDelegate::PreviewItemDelegate(ThumbnailView* view)
561
565
: QItemDelegate(view)
562
 
, d(new PreviewItemDelegatePrivate) {
563
 
        d->that = this;
564
 
        d->mView = view;
565
 
        view->viewport()->installEventFilter(this);
566
 
        d->mThumbnailSize = view->thumbnailSize();
567
 
        d->mDetails = FileNameDetail;
568
 
        d->mContextBarMode = FullContextBar;
569
 
        d->mTextElideMode = Qt::ElideRight;
 
566
, d(new PreviewItemDelegatePrivate)
 
567
{
 
568
    d->q = this;
 
569
    d->mView = view;
 
570
    view->viewport()->installEventFilter(this);
 
571
    d->mThumbnailSize = view->thumbnailSize();
 
572
    d->mDetails = FileNameDetail;
 
573
    d->mContextBarMode = FullContextBar;
 
574
    d->mTextElideMode = Qt::ElideRight;
570
575
 
571
 
        connect(view, SIGNAL(rowsRemovedSignal(const QModelIndex&, int, int)),
572
 
                SLOT(slotRowsChanged()));
573
 
        connect(view, SIGNAL(rowsInsertedSignal(const QModelIndex&, int, int)),
574
 
                SLOT(slotRowsChanged()));
 
576
    connect(view, SIGNAL(rowsRemovedSignal(QModelIndex, int, int)),
 
577
            SLOT(slotRowsChanged()));
 
578
    connect(view, SIGNAL(rowsInsertedSignal(QModelIndex, int, int)),
 
579
            SLOT(slotRowsChanged()));
575
580
 
576
581
#ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
577
 
        d->mRatingPainter.setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
578
 
        d->mRatingPainter.setLayoutDirection(view->layoutDirection());
579
 
        d->mRatingPainter.setMaxRating(10);
 
582
    d->mRatingPainter.setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
 
583
    d->mRatingPainter.setLayoutDirection(view->layoutDirection());
 
584
    d->mRatingPainter.setMaxRating(10);
580
585
#endif
581
586
 
582
 
        connect(view, SIGNAL(thumbnailSizeChanged(int)),
583
 
                SLOT(setThumbnailSize(int)) );
584
 
 
585
 
        // Button frame
586
 
        d->mContextBar = new QWidget(d->mView->viewport());
587
 
        d->mContextBar->hide();
588
 
 
589
 
        d->mToggleSelectionButton = new ContextBarButton("list-add");
590
 
        connect(d->mToggleSelectionButton, SIGNAL(clicked()),
591
 
                SLOT(slotToggleSelectionClicked()));
592
 
 
593
 
        d->mFullScreenButton = new ContextBarButton("view-fullscreen");
594
 
        connect(d->mFullScreenButton, SIGNAL(clicked()),
595
 
                SLOT(slotFullScreenClicked()) );
596
 
 
597
 
        d->mRotateLeftButton = new ContextBarButton("object-rotate-left");
598
 
        connect(d->mRotateLeftButton, SIGNAL(clicked()),
599
 
                SLOT(slotRotateLeftClicked()) );
600
 
 
601
 
        d->mRotateRightButton = new ContextBarButton("object-rotate-right");
602
 
        connect(d->mRotateRightButton, SIGNAL(clicked()),
603
 
                SLOT(slotRotateRightClicked()) );
604
 
 
605
 
        QHBoxLayout* layout = new QHBoxLayout(d->mContextBar);
606
 
        layout->setMargin(2);
607
 
        layout->setSpacing(2);
608
 
        layout->addWidget(d->mToggleSelectionButton);
609
 
        layout->addWidget(d->mFullScreenButton);
610
 
        layout->addWidget(d->mRotateLeftButton);
611
 
        layout->addWidget(d->mRotateRightButton);
612
 
 
613
 
        // Save button
614
 
        d->mSaveButton = new ContextBarButton("document-save", d->mView->viewport());
615
 
        d->mSaveButton->hide();
616
 
        connect(d->mSaveButton, SIGNAL(clicked()),
617
 
                SLOT(slotSaveClicked()) );
618
 
}
619
 
 
620
 
 
621
 
PreviewItemDelegate::~PreviewItemDelegate() {
622
 
        delete d;
623
 
}
624
 
 
625
 
 
626
 
QSize PreviewItemDelegate::sizeHint( const QStyleOptionViewItem & /*option*/, const QModelIndex & /*index*/ ) const {
627
 
        return d->mView->gridSize();
628
 
}
629
 
 
630
 
 
631
 
bool PreviewItemDelegate::eventFilter(QObject* object, QEvent* event) {
632
 
        if (object == d->mView->viewport()) {
633
 
                switch (event->type()) {
634
 
                case QEvent::ToolTip:
635
 
                        return true;
636
 
 
637
 
                case QEvent::HoverMove:
638
 
                case QEvent::HoverLeave:
639
 
                        return d->hoverEventFilter(static_cast<QHoverEvent*>(event));
640
 
 
641
 
                case QEvent::MouseButtonPress:
642
 
                case QEvent::MouseButtonRelease:
643
 
                        return d->mouseButtonEventFilter(event->type());
644
 
 
645
 
                default:
646
 
                        return false;
647
 
                }
648
 
        } else {
649
 
                // Necessary for the item editor to work correctly (especially closing
650
 
                // the editor with the Escape key)
651
 
                return QItemDelegate::eventFilter(object, event);
652
 
        }
653
 
}
654
 
 
655
 
 
656
 
void PreviewItemDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const {
657
 
        int thumbnailSize = d->mThumbnailSize;
658
 
        QSize fullSize;
659
 
        QPixmap thumbnailPix = d->mView->thumbnailForIndex(index, &fullSize);
660
 
        const KFileItem fileItem = fileItemForIndex(index);
661
 
        const bool opaque = !thumbnailPix.hasAlphaChannel();
662
 
        const bool isDirOrArchive = ArchiveUtils::fileItemIsDirOrArchive(fileItem);
663
 
        QRect rect = option.rect;
664
 
        const bool selected = option.state & QStyle::State_Selected;
665
 
        const bool underMouse = option.state & QStyle::State_MouseOver;
666
 
        const QWidget* viewport = d->mView->viewport();
 
587
    connect(view, SIGNAL(thumbnailSizeChanged(int)),
 
588
            SLOT(setThumbnailSize(int)));
 
589
 
 
590
    // Button frame
 
591
    d->mContextBar = new QWidget(d->mView->viewport());
 
592
    d->mContextBar->hide();
 
593
 
 
594
    d->mToggleSelectionButton = new ContextBarButton("list-add");
 
595
    connect(d->mToggleSelectionButton, SIGNAL(clicked()),
 
596
            SLOT(slotToggleSelectionClicked()));
 
597
 
 
598
    d->mFullScreenButton = new ContextBarButton("view-fullscreen");
 
599
    connect(d->mFullScreenButton, SIGNAL(clicked()),
 
600
            SLOT(slotFullScreenClicked()));
 
601
 
 
602
    d->mRotateLeftButton = new ContextBarButton("object-rotate-left");
 
603
    connect(d->mRotateLeftButton, SIGNAL(clicked()),
 
604
            SLOT(slotRotateLeftClicked()));
 
605
 
 
606
    d->mRotateRightButton = new ContextBarButton("object-rotate-right");
 
607
    connect(d->mRotateRightButton, SIGNAL(clicked()),
 
608
            SLOT(slotRotateRightClicked()));
 
609
 
 
610
    QHBoxLayout* layout = new QHBoxLayout(d->mContextBar);
 
611
    layout->setMargin(2);
 
612
    layout->setSpacing(2);
 
613
    layout->addWidget(d->mToggleSelectionButton);
 
614
    layout->addWidget(d->mFullScreenButton);
 
615
    layout->addWidget(d->mRotateLeftButton);
 
616
    layout->addWidget(d->mRotateRightButton);
 
617
 
 
618
    // Save button
 
619
    d->mSaveButton = new ContextBarButton("document-save", d->mView->viewport());
 
620
    d->mSaveButton->hide();
 
621
    connect(d->mSaveButton, SIGNAL(clicked()),
 
622
            SLOT(slotSaveClicked()));
 
623
}
 
624
 
 
625
PreviewItemDelegate::~PreviewItemDelegate()
 
626
{
 
627
    delete d;
 
628
}
 
629
 
 
630
QSize PreviewItemDelegate::sizeHint(const QStyleOptionViewItem & /*option*/, const QModelIndex & /*index*/) const
 
631
{
 
632
    return d->mView->gridSize();
 
633
}
 
634
 
 
635
bool PreviewItemDelegate::eventFilter(QObject* object, QEvent* event)
 
636
{
 
637
    if (object == d->mView->viewport()) {
 
638
        switch (event->type()) {
 
639
        case QEvent::ToolTip:
 
640
            return true;
 
641
 
 
642
        case QEvent::HoverMove:
 
643
        case QEvent::HoverLeave:
 
644
            return d->hoverEventFilter(static_cast<QHoverEvent*>(event));
 
645
 
 
646
        case QEvent::MouseButtonPress:
 
647
        case QEvent::MouseButtonRelease:
 
648
            return d->mouseButtonEventFilter(event->type());
 
649
 
 
650
        default:
 
651
            return false;
 
652
        }
 
653
    } else {
 
654
        // Necessary for the item editor to work correctly (especially closing
 
655
        // the editor with the Escape key)
 
656
        return QItemDelegate::eventFilter(object, event);
 
657
    }
 
658
}
 
659
 
 
660
void PreviewItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
 
661
{
 
662
    int thumbnailSize = d->mThumbnailSize;
 
663
    QSize fullSize;
 
664
    QPixmap thumbnailPix = d->mView->thumbnailForIndex(index, &fullSize);
 
665
    const KFileItem fileItem = fileItemForIndex(index);
 
666
    const bool opaque = !thumbnailPix.hasAlphaChannel();
 
667
    const bool isDirOrArchive = ArchiveUtils::fileItemIsDirOrArchive(fileItem);
 
668
    QRect rect = option.rect;
 
669
    const bool selected = option.state & QStyle::State_Selected;
 
670
    const bool underMouse = option.state & QStyle::State_MouseOver;
 
671
    const QWidget* viewport = d->mView->viewport();
667
672
 
668
673
#ifdef DEBUG_RECT
669
 
        painter->setPen(Qt::red);
670
 
        painter->setBrush(Qt::NoBrush);
671
 
        painter->drawRect(rect);
 
674
    painter->setPen(Qt::red);
 
675
    painter->setBrush(Qt::NoBrush);
 
676
    painter->drawRect(rect);
672
677
#endif
673
678
 
674
 
        // Select color group
675
 
        QPalette::ColorGroup cg;
676
 
 
677
 
        if ( (option.state & QStyle::State_Enabled) && (option.state & QStyle::State_Active) ) {
678
 
                cg = QPalette::Normal;
679
 
        } else if ( (option.state & QStyle::State_Enabled)) {
680
 
                cg = QPalette::Inactive;
681
 
        } else {
682
 
                cg = QPalette::Disabled;
683
 
        }
684
 
 
685
 
        // Select colors
686
 
        QColor bgColor, borderColor, fgColor;
687
 
        if (selected || underMouse) {
688
 
                bgColor = option.palette.color(cg, QPalette::Highlight);
689
 
                borderColor = bgColor.dark(SELECTION_BORDER_DARKNESS);
690
 
        } else {
691
 
                bgColor = viewport->palette().color(viewport->backgroundRole());
692
 
                borderColor = bgColor.light(200);
693
 
        }
694
 
        fgColor = viewport->palette().color(viewport->foregroundRole());
695
 
 
696
 
        // Compute thumbnailRect
697
 
        QRect thumbnailRect = QRect(
698
 
                rect.left() + (rect.width() - thumbnailPix.width())/2,
699
 
                rect.top() + (thumbnailSize - thumbnailPix.height()) + ITEM_MARGIN,
700
 
                thumbnailPix.width(),
701
 
                thumbnailPix.height());
702
 
 
703
 
        // Draw background
704
 
        const QRect backgroundRect = thumbnailRect.adjusted(-ITEM_MARGIN, -ITEM_MARGIN, ITEM_MARGIN, ITEM_MARGIN);
705
 
        if (selected) {
706
 
                d->drawBackground(painter, backgroundRect, bgColor, borderColor);
707
 
        } else if (underMouse) {
708
 
                painter->setOpacity(0.2);
709
 
                d->drawBackground(painter, backgroundRect, bgColor, borderColor);
710
 
                painter->setOpacity(1.);
711
 
        } else if (opaque) {
712
 
                d->drawShadow(painter, thumbnailRect);
713
 
        }
714
 
 
715
 
        // Draw thumbnail
716
 
        if (opaque) {
717
 
                painter->setPen(borderColor);
718
 
                painter->setRenderHint(QPainter::Antialiasing, false);
719
 
                QRect borderRect = thumbnailRect.adjusted(-1, -1, 0, 0);
720
 
                painter->drawRect(borderRect);
721
 
        }
722
 
        painter->drawPixmap(thumbnailRect.left(), thumbnailRect.top(), thumbnailPix);
723
 
 
724
 
        // Draw modified indicator
725
 
        bool isModified = d->mView->isModified(index);
726
 
        if (isModified) {
727
 
                // Draws a pixmap of the save button frame, as an indicator that
728
 
                // the image has been modified
729
 
                QPoint framePosition = d->saveButtonPosition(rect);
730
 
                d->initSaveButtonPixmap();
731
 
                painter->drawPixmap(framePosition, d->mSaveButtonPixmap);
732
 
        }
733
 
 
734
 
        // Draw busy indicator
735
 
        if (d->mView->isBusy(index)) {
736
 
                QPixmap pix = d->mView->busySequenceCurrentPixmap();
737
 
                painter->drawPixmap(
738
 
                        thumbnailRect.left() + (thumbnailRect.width() - pix.width()) / 2,
739
 
                        thumbnailRect.top() + (thumbnailRect.height() - pix.height()) / 2,
740
 
                        pix);
741
 
        }
742
 
 
743
 
        if (index == d->mIndexUnderCursor) {
744
 
                // Show bar again: if the thumbnail has changed, we may need to update
745
 
                // its position. Don't do it if we are over rotate buttons, though: it
746
 
                // would not be nice to move the button now, the user may want to
747
 
                // rotate the image one more time.
748
 
                // The button will get moved when the mouse leaves.
749
 
                if (!d->mRotateLeftButton->underMouse() && !d->mRotateRightButton->underMouse()) {
750
 
                        d->showContextBar(rect, thumbnailPix);
751
 
                }
752
 
                if (isModified) {
753
 
                        // If we just rotated the image with the buttons from the
754
 
                        // button frame, we need to show the save button frame right now.
755
 
                        d->showSaveButton(rect);
756
 
                } else {
757
 
                        d->mSaveButton->hide();
758
 
                }
759
 
        }
760
 
 
761
 
        QRect textRect(
762
 
                rect.left() + ITEM_MARGIN,
763
 
                rect.top() + 2 * ITEM_MARGIN + thumbnailSize,
764
 
                rect.width() - 2 * ITEM_MARGIN,
765
 
                d->mView->fontMetrics().height());
766
 
        if (isDirOrArchive || (d->mDetails & PreviewItemDelegate::FileNameDetail)) {
767
 
                d->drawText(painter, textRect, fgColor, index.data().toString());
768
 
                textRect.moveTop(textRect.bottom());
769
 
        }
770
 
 
771
 
        if (!isDirOrArchive && (d->mDetails & PreviewItemDelegate::DateDetail)) {
772
 
                const KDateTime dt = TimeUtils::dateTimeForFileItem(fileItem);
773
 
                d->drawText(painter, textRect, fgColor, KGlobal::locale()->formatDateTime(dt));
774
 
                textRect.moveTop(textRect.bottom());
775
 
        }
776
 
 
777
 
        if (!isDirOrArchive && (d->mDetails & PreviewItemDelegate::ImageSizeDetail)) {
778
 
                if (fullSize.isValid()) {
779
 
                        const QString text = QString("%1x%2").arg(fullSize.width()).arg(fullSize.height());
780
 
                        d->drawText(painter, textRect, fgColor, text);
781
 
                        textRect.moveTop(textRect.bottom());
782
 
                }
783
 
        }
784
 
 
785
 
        if (!isDirOrArchive && (d->mDetails & PreviewItemDelegate::FileSizeDetail)) {
786
 
                const KIO::filesize_t size = fileItem.size();
787
 
                if (size > 0) {
788
 
                        const QString st = KIO::convertSize(size);
789
 
                        d->drawText(painter, textRect, fgColor, st);
790
 
                        textRect.moveTop(textRect.bottom());
791
 
                }
792
 
        }
793
 
 
794
 
        if (!isDirOrArchive && (d->mDetails & PreviewItemDelegate::RatingDetail)) {
 
679
    // Select color group
 
680
    QPalette::ColorGroup cg;
 
681
 
 
682
    if ((option.state & QStyle::State_Enabled) && (option.state & QStyle::State_Active)) {
 
683
        cg = QPalette::Normal;
 
684
    } else if ((option.state & QStyle::State_Enabled)) {
 
685
        cg = QPalette::Inactive;
 
686
    } else {
 
687
        cg = QPalette::Disabled;
 
688
    }
 
689
 
 
690
    // Select colors
 
691
    QColor bgColor, borderColor, fgColor;
 
692
    if (selected || underMouse) {
 
693
        bgColor = option.palette.color(cg, QPalette::Highlight);
 
694
        borderColor = bgColor.dark(SELECTION_BORDER_DARKNESS);
 
695
    } else {
 
696
        bgColor = viewport->palette().color(viewport->backgroundRole());
 
697
        borderColor = bgColor.light(200);
 
698
    }
 
699
    fgColor = viewport->palette().color(viewport->foregroundRole());
 
700
 
 
701
    // Compute thumbnailRect
 
702
    QRect thumbnailRect = QRect(
 
703
                              rect.left() + (rect.width() - thumbnailPix.width()) / 2,
 
704
                              rect.top() + (thumbnailSize - thumbnailPix.height()) + ITEM_MARGIN,
 
705
                              thumbnailPix.width(),
 
706
                              thumbnailPix.height());
 
707
 
 
708
    // Draw background
 
709
    const QRect backgroundRect = thumbnailRect.adjusted(-ITEM_MARGIN, -ITEM_MARGIN, ITEM_MARGIN, ITEM_MARGIN);
 
710
    if (selected) {
 
711
        d->drawBackground(painter, backgroundRect, bgColor, borderColor);
 
712
    } else if (underMouse) {
 
713
        painter->setOpacity(0.2);
 
714
        d->drawBackground(painter, backgroundRect, bgColor, borderColor);
 
715
        painter->setOpacity(1.);
 
716
    } else if (opaque) {
 
717
        d->drawShadow(painter, thumbnailRect);
 
718
    }
 
719
 
 
720
    // Draw thumbnail
 
721
    if (opaque) {
 
722
        painter->setPen(borderColor);
 
723
        painter->setRenderHint(QPainter::Antialiasing, false);
 
724
        QRect borderRect = thumbnailRect.adjusted(-1, -1, 0, 0);
 
725
        painter->drawRect(borderRect);
 
726
    }
 
727
    painter->drawPixmap(thumbnailRect.left(), thumbnailRect.top(), thumbnailPix);
 
728
 
 
729
    // Draw modified indicator
 
730
    bool isModified = d->mView->isModified(index);
 
731
    if (isModified) {
 
732
        // Draws a pixmap of the save button frame, as an indicator that
 
733
        // the image has been modified
 
734
        QPoint framePosition = d->saveButtonPosition(rect);
 
735
        d->initSaveButtonPixmap();
 
736
        painter->drawPixmap(framePosition, d->mSaveButtonPixmap);
 
737
    }
 
738
 
 
739
    // Draw busy indicator
 
740
    if (d->mView->isBusy(index)) {
 
741
        QPixmap pix = d->mView->busySequenceCurrentPixmap();
 
742
        painter->drawPixmap(
 
743
            thumbnailRect.left() + (thumbnailRect.width() - pix.width()) / 2,
 
744
            thumbnailRect.top() + (thumbnailRect.height() - pix.height()) / 2,
 
745
            pix);
 
746
    }
 
747
 
 
748
    if (index == d->mIndexUnderCursor) {
 
749
        // Show bar again: if the thumbnail has changed, we may need to update
 
750
        // its position. Don't do it if we are over rotate buttons, though: it
 
751
        // would not be nice to move the button now, the user may want to
 
752
        // rotate the image one more time.
 
753
        // The button will get moved when the mouse leaves.
 
754
        if (!d->mRotateLeftButton->underMouse() && !d->mRotateRightButton->underMouse()) {
 
755
            d->showContextBar(rect, thumbnailPix);
 
756
        }
 
757
        if (isModified) {
 
758
            // If we just rotated the image with the buttons from the
 
759
            // button frame, we need to show the save button frame right now.
 
760
            d->showSaveButton(rect);
 
761
        } else {
 
762
            d->mSaveButton->hide();
 
763
        }
 
764
    }
 
765
 
 
766
    QRect textRect(
 
767
        rect.left() + ITEM_MARGIN,
 
768
        rect.top() + 2 * ITEM_MARGIN + thumbnailSize,
 
769
        rect.width() - 2 * ITEM_MARGIN,
 
770
        d->mView->fontMetrics().height());
 
771
    if (isDirOrArchive || (d->mDetails & PreviewItemDelegate::FileNameDetail)) {
 
772
        d->drawText(painter, textRect, fgColor, index.data().toString());
 
773
        textRect.moveTop(textRect.bottom());
 
774
    }
 
775
 
 
776
    if (!isDirOrArchive && (d->mDetails & PreviewItemDelegate::DateDetail)) {
 
777
        const KDateTime dt = TimeUtils::dateTimeForFileItem(fileItem);
 
778
        d->drawText(painter, textRect, fgColor, KGlobal::locale()->formatDateTime(dt));
 
779
        textRect.moveTop(textRect.bottom());
 
780
    }
 
781
 
 
782
    if (!isDirOrArchive && (d->mDetails & PreviewItemDelegate::ImageSizeDetail)) {
 
783
        if (fullSize.isValid()) {
 
784
            const QString text = QString("%1x%2").arg(fullSize.width()).arg(fullSize.height());
 
785
            d->drawText(painter, textRect, fgColor, text);
 
786
            textRect.moveTop(textRect.bottom());
 
787
        }
 
788
    }
 
789
 
 
790
    if (!isDirOrArchive && (d->mDetails & PreviewItemDelegate::FileSizeDetail)) {
 
791
        const KIO::filesize_t size = fileItem.size();
 
792
        if (size > 0) {
 
793
            const QString st = KIO::convertSize(size);
 
794
            d->drawText(painter, textRect, fgColor, st);
 
795
            textRect.moveTop(textRect.bottom());
 
796
        }
 
797
    }
 
798
 
 
799
    if (!isDirOrArchive && (d->mDetails & PreviewItemDelegate::RatingDetail)) {
795
800
#ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
796
 
                d->drawRating(painter, rect, index.data(SemanticInfoDirModel::RatingRole));
 
801
        d->drawRating(painter, rect, index.data(SemanticInfoDirModel::RatingRole));
797
802
#endif
798
 
        }
799
 
}
800
 
 
801
 
 
802
 
void PreviewItemDelegate::setThumbnailSize(int value) {
803
 
        d->mThumbnailSize = value;
804
 
        d->updateViewGridSize();
805
 
        d->updateContextBar();
806
 
        d->mElidedTextCache.clear();
807
 
}
808
 
 
809
 
 
810
 
void PreviewItemDelegate::slotSaveClicked() {
811
 
        saveDocumentRequested(urlForIndex(d->mIndexUnderCursor));
812
 
}
813
 
 
814
 
 
815
 
void PreviewItemDelegate::slotRotateLeftClicked() {
816
 
        d->selectIndexUnderCursorIfNoMultiSelection();
817
 
        rotateDocumentLeftRequested(urlForIndex(d->mIndexUnderCursor));
818
 
}
819
 
 
820
 
 
821
 
void PreviewItemDelegate::slotRotateRightClicked() {
822
 
        d->selectIndexUnderCursorIfNoMultiSelection();
823
 
        rotateDocumentRightRequested(urlForIndex(d->mIndexUnderCursor));
824
 
}
825
 
 
826
 
 
827
 
void PreviewItemDelegate::slotFullScreenClicked() {
828
 
        showDocumentInFullScreenRequested(urlForIndex(d->mIndexUnderCursor));
829
 
}
830
 
 
831
 
 
832
 
void PreviewItemDelegate::slotToggleSelectionClicked() {
833
 
        d->mView->selectionModel()->select(d->mIndexUnderCursor, QItemSelectionModel::Toggle);
834
 
        d->updateToggleSelectionButton();
835
 
}
836
 
 
837
 
 
838
 
PreviewItemDelegate::ThumbnailDetails PreviewItemDelegate::thumbnailDetails() const {
839
 
        return d->mDetails;
840
 
}
841
 
 
842
 
 
843
 
void PreviewItemDelegate::setThumbnailDetails(PreviewItemDelegate::ThumbnailDetails details) {
844
 
        d->mDetails = details;
845
 
        d->updateViewGridSize();
846
 
        d->mView->scheduleDelayedItemsLayout();
847
 
}
848
 
 
849
 
 
850
 
PreviewItemDelegate::ContextBarMode PreviewItemDelegate::contextBarMode() const {
851
 
        return d->mContextBarMode;
852
 
}
853
 
 
854
 
 
855
 
void PreviewItemDelegate::setContextBarMode(PreviewItemDelegate::ContextBarMode mode) {
856
 
        d->mContextBarMode = mode;
857
 
        d->updateContextBar();
858
 
}
859
 
 
860
 
 
861
 
Qt::TextElideMode PreviewItemDelegate::textElideMode() const {
862
 
        return d->mTextElideMode;
863
 
}
864
 
 
865
 
 
866
 
void PreviewItemDelegate::setTextElideMode(Qt::TextElideMode mode) {
867
 
        if (d->mTextElideMode == mode) {
868
 
                return;
869
 
        }
870
 
        d->mTextElideMode = mode;
871
 
        d->mElidedTextCache.clear();
872
 
        d->mView->viewport()->update();
873
 
}
874
 
 
875
 
 
876
 
void PreviewItemDelegate::slotRowsChanged() {
877
 
        // We need to update hover ui because the current index may have
878
 
        // disappeared: for example if the current image is removed with "del".
879
 
        QPoint pos = d->mView->viewport()->mapFromGlobal(QCursor::pos());
880
 
        QModelIndex index = d->mView->indexAt(pos);
881
 
        d->updateHoverUi(index);
882
 
}
883
 
 
884
 
 
885
 
QWidget * PreviewItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/) const {
886
 
        return new ItemEditor(parent);
887
 
}
888
 
 
889
 
 
890
 
void PreviewItemDelegate::setEditorData(QWidget* widget, const QModelIndex& index) const {
891
 
        ItemEditor* edit = qobject_cast<ItemEditor*>(widget);
892
 
        if (!edit) {
893
 
                return;
894
 
        }
895
 
        edit->setText(index.data().toString());
896
 
}
897
 
 
898
 
 
899
 
void PreviewItemDelegate::updateEditorGeometry(QWidget* widget, const QStyleOptionViewItem& option, const QModelIndex& index) const {
900
 
        ItemEditor* edit = qobject_cast<ItemEditor*>(widget);
901
 
        if (!edit) {
902
 
                return;
903
 
        }
904
 
        QString text = index.data().toString();
905
 
        int textWidth = edit->fontMetrics().width("  " + text + "  ");
906
 
        QRect textRect(
907
 
                option.rect.left() + (option.rect.width() - textWidth) / 2,
908
 
                option.rect.top() + 2 * ITEM_MARGIN + d->mThumbnailSize,
909
 
                textWidth,
910
 
                edit->sizeHint().height());
911
 
 
912
 
        edit->setGeometry(textRect);
913
 
}
914
 
 
915
 
 
916
 
void PreviewItemDelegate::setModelData(QWidget* widget, QAbstractItemModel* model, const QModelIndex& index) const {
917
 
        ItemEditor* edit = qobject_cast<ItemEditor*>(widget);
918
 
        if (!edit) {
919
 
                return;
920
 
        }
921
 
        if (index.data().toString() != edit->text()) {
922
 
                model->setData(index, edit->text(), Qt::EditRole);
923
 
        }
 
803
    }
 
804
}
 
805
 
 
806
void PreviewItemDelegate::setThumbnailSize(int value)
 
807
{
 
808
    d->mThumbnailSize = value;
 
809
    d->updateViewGridSize();
 
810
    d->updateContextBar();
 
811
    d->mElidedTextCache.clear();
 
812
}
 
813
 
 
814
void PreviewItemDelegate::slotSaveClicked()
 
815
{
 
816
    saveDocumentRequested(urlForIndex(d->mIndexUnderCursor));
 
817
}
 
818
 
 
819
void PreviewItemDelegate::slotRotateLeftClicked()
 
820
{
 
821
    d->selectIndexUnderCursorIfNoMultiSelection();
 
822
    rotateDocumentLeftRequested(urlForIndex(d->mIndexUnderCursor));
 
823
}
 
824
 
 
825
void PreviewItemDelegate::slotRotateRightClicked()
 
826
{
 
827
    d->selectIndexUnderCursorIfNoMultiSelection();
 
828
    rotateDocumentRightRequested(urlForIndex(d->mIndexUnderCursor));
 
829
}
 
830
 
 
831
void PreviewItemDelegate::slotFullScreenClicked()
 
832
{
 
833
    showDocumentInFullScreenRequested(urlForIndex(d->mIndexUnderCursor));
 
834
}
 
835
 
 
836
void PreviewItemDelegate::slotToggleSelectionClicked()
 
837
{
 
838
    d->mView->selectionModel()->select(d->mIndexUnderCursor, QItemSelectionModel::Toggle);
 
839
    d->updateToggleSelectionButton();
 
840
}
 
841
 
 
842
PreviewItemDelegate::ThumbnailDetails PreviewItemDelegate::thumbnailDetails() const
 
843
{
 
844
    return d->mDetails;
 
845
}
 
846
 
 
847
void PreviewItemDelegate::setThumbnailDetails(PreviewItemDelegate::ThumbnailDetails details)
 
848
{
 
849
    d->mDetails = details;
 
850
    d->updateViewGridSize();
 
851
    d->mView->scheduleDelayedItemsLayout();
 
852
}
 
853
 
 
854
PreviewItemDelegate::ContextBarMode PreviewItemDelegate::contextBarMode() const
 
855
{
 
856
    return d->mContextBarMode;
 
857
}
 
858
 
 
859
void PreviewItemDelegate::setContextBarMode(PreviewItemDelegate::ContextBarMode mode)
 
860
{
 
861
    d->mContextBarMode = mode;
 
862
    d->updateContextBar();
 
863
}
 
864
 
 
865
Qt::TextElideMode PreviewItemDelegate::textElideMode() const
 
866
{
 
867
    return d->mTextElideMode;
 
868
}
 
869
 
 
870
void PreviewItemDelegate::setTextElideMode(Qt::TextElideMode mode)
 
871
{
 
872
    if (d->mTextElideMode == mode) {
 
873
        return;
 
874
    }
 
875
    d->mTextElideMode = mode;
 
876
    d->mElidedTextCache.clear();
 
877
    d->mView->viewport()->update();
 
878
}
 
879
 
 
880
void PreviewItemDelegate::slotRowsChanged()
 
881
{
 
882
    // We need to update hover ui because the current index may have
 
883
    // disappeared: for example if the current image is removed with "del".
 
884
    QPoint pos = d->mView->viewport()->mapFromGlobal(QCursor::pos());
 
885
    QModelIndex index = d->mView->indexAt(pos);
 
886
    d->updateHoverUi(index);
 
887
}
 
888
 
 
889
QWidget * PreviewItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/) const
 
890
{
 
891
    return new ItemEditor(parent);
 
892
}
 
893
 
 
894
void PreviewItemDelegate::setEditorData(QWidget* widget, const QModelIndex& index) const
 
895
{
 
896
    ItemEditor* edit = qobject_cast<ItemEditor*>(widget);
 
897
    if (!edit) {
 
898
        return;
 
899
    }
 
900
    edit->setText(index.data().toString());
 
901
}
 
902
 
 
903
void PreviewItemDelegate::updateEditorGeometry(QWidget* widget, const QStyleOptionViewItem& option, const QModelIndex& index) const
 
904
{
 
905
    ItemEditor* edit = qobject_cast<ItemEditor*>(widget);
 
906
    if (!edit) {
 
907
        return;
 
908
    }
 
909
    QString text = index.data().toString();
 
910
    int textWidth = edit->fontMetrics().width("  " + text + "  ");
 
911
    QRect textRect(
 
912
        option.rect.left() + (option.rect.width() - textWidth) / 2,
 
913
        option.rect.top() + 2 * ITEM_MARGIN + d->mThumbnailSize,
 
914
        textWidth,
 
915
        edit->sizeHint().height());
 
916
 
 
917
    edit->setGeometry(textRect);
 
918
}
 
919
 
 
920
void PreviewItemDelegate::setModelData(QWidget* widget, QAbstractItemModel* model, const QModelIndex& index) const
 
921
{
 
922
    ItemEditor* edit = qobject_cast<ItemEditor*>(widget);
 
923
    if (!edit) {
 
924
        return;
 
925
    }
 
926
    if (index.data().toString() != edit->text()) {
 
927
        model->setData(index, edit->text(), Qt::EditRole);
 
928
    }
924
929
}
925
930
 
926
931
} // namespace