X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/c8072005fada01d772595ec64adca449134f421e..7eeb8dba6aeba09aa3dfa7fa5f0b00840d4d8317:/src/dolphincategorydrawer.cpp diff --git a/src/dolphincategorydrawer.cpp b/src/dolphincategorydrawer.cpp index 2479f2755..59743b7f5 100644 --- a/src/dolphincategorydrawer.cpp +++ b/src/dolphincategorydrawer.cpp @@ -1,6 +1,6 @@ -/** +/* * This file is part of the KDE project - * Copyright (C) 2007 Rafael Fernández López + * Copyright (C) 2007 Rafael Fernández López * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -20,26 +20,39 @@ #include "dolphincategorydrawer.h" +#include + #include #include #include +#include +#include + +#ifdef HAVE_NEPOMUK +#include +#endif #include +#include #include -#include +#include #include - -#include -#ifdef HAVE_NEPOMUK -#include -#include -#include -#endif +#include #include "dolphinview.h" #include "dolphinmodel.h" -DolphinCategoryDrawer::DolphinCategoryDrawer() +#define HORIZONTAL_HINT 3 + +DolphinCategoryDrawer::DolphinCategoryDrawer(KCategorizedView *view) + : KCategoryDrawerV3(view) + , hotSpotPressed(NoneHotSpot) + , selectAll(KIconLoader::global()->loadIcon("list-add", KIconLoader::Desktop, 16)) + , selectAllHovered(KIconLoader::global()->iconEffect()->apply(selectAll, KIconLoader::Desktop, KIconLoader::ActiveState)) + , selectAllDisabled(KIconLoader::global()->iconEffect()->apply(selectAll, KIconLoader::Desktop, KIconLoader::DisabledState)) + , unselectAll(KIconLoader::global()->loadIcon("list-remove", KIconLoader::Desktop, 16)) + , unselectAllHovered(KIconLoader::global()->iconEffect()->apply(unselectAll, KIconLoader::Desktop, KIconLoader::ActiveState)) + , unselectAllDisabled(KIconLoader::global()->iconEffect()->apply(unselectAll, KIconLoader::Desktop, KIconLoader::DisabledState)) { } @@ -47,256 +60,319 @@ DolphinCategoryDrawer::~DolphinCategoryDrawer() { } +bool DolphinCategoryDrawer::allCategorySelected(const QString &category) const +{ + const QModelIndexList list = view()->block(category); + foreach (const QModelIndex &index, list) { + if (!view()->selectionModel()->isSelected(index)) { + return false; + } + } + return true; +} + +bool DolphinCategoryDrawer::someCategorySelected(const QString &category) const +{ + const QModelIndexList list = view()->block(category); + foreach (const QModelIndex &index, list) { + if (view()->selectionModel()->isSelected(index)) { + return true; + } + } + return false; +} + void DolphinCategoryDrawer::drawCategory(const QModelIndex &index, int sortRole, const QStyleOption &option, QPainter *painter) const { - QRect starRect = option.rect; - - int iconSize = KIconLoader::global()->currentSize(K3Icon::Small); - QVariant categoryVariant = index.model()->data(index, KCategorizedSortFilterProxyModel::CategoryRole); + Q_UNUSED(sortRole); + painter->setRenderHint(QPainter::Antialiasing); - if (!categoryVariant.isValid()) - { + if (!index.isValid()) { return; } - const QString category = categoryVariant.toString(); - - QColor color = option.palette.color(QPalette::Text); - - painter->save(); - painter->setRenderHint(QPainter::Antialiasing); + const QString category = index.model()->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); + const QRect optRect = option.rect; + QFont font(QApplication::font()); + font.setBold(true); + const QFontMetrics fontMetrics = QFontMetrics(font); - QStyleOptionButton opt; + QColor outlineColor = option.palette.text().color(); + outlineColor.setAlphaF(0.35); - opt.rect = option.rect; - opt.palette = option.palette; - opt.direction = option.direction; - opt.text = category; - - if (option.state & QStyle::State_MouseOver) + //BEGIN: top left corner { - QColor hover = option.palette.color(QPalette::Highlight).light(); - hover.setAlpha(88); - - QLinearGradient gradient(option.rect.topLeft(), - option.rect.bottomRight()); - gradient.setColorAt(option.direction == Qt::LeftToRight ? 0 - : 1, hover); - gradient.setColorAt(option.direction == Qt::LeftToRight ? 1 - : 0, Qt::transparent); - - painter->fillRect(option.rect, gradient); + painter->save(); + painter->setPen(outlineColor); + const QPointF topLeft(optRect.topLeft()); + QRectF arc(topLeft, QSizeF(4, 4)); + arc.translate(0.5, 0.5); + painter->drawArc(arc, 1440, 1440); + painter->restore(); } + //END: top left corner - QFont painterFont = painter->font(); - painterFont.setWeight(QFont::Bold); - QFontMetrics metrics(painterFont); - painter->setFont(painterFont); - - QPainterPath path; - path.addRect(option.rect.left(), - option.rect.bottom() - 2, - option.rect.width(), - 2); - - QLinearGradient gradient(option.rect.topLeft(), - option.rect.bottomRight()); - gradient.setColorAt(option.direction == Qt::LeftToRight ? 0 - : 1, color); - gradient.setColorAt(option.direction == Qt::LeftToRight ? 1 - : 0, Qt::transparent); - - painter->setBrush(gradient); - painter->fillPath(path, gradient); - - if (option.direction == Qt::LeftToRight) + //BEGIN: left vertical line { - opt.rect.setLeft(opt.rect.left() + (iconSize / 4)); - starRect.setLeft(starRect.left() + (iconSize / 4)); - starRect.setRight(starRect.right() + (iconSize / 4)); + QPoint start(optRect.topLeft()); + start.ry() += 3; + QPoint verticalGradBottom(optRect.topLeft()); + verticalGradBottom.ry() += fontMetrics.height() + 5; + QLinearGradient gradient(start, verticalGradBottom); + gradient.setColorAt(0, outlineColor); + gradient.setColorAt(1, Qt::transparent); + painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient); } - else + //END: left vertical line + + //BEGIN: horizontal line { - opt.rect.setRight(opt.rect.width() - (iconSize / 4)); - starRect.setLeft(starRect.width() - iconSize); - starRect.setRight(starRect.width() - (iconSize / 4)); + QPoint start(optRect.topLeft()); + start.rx() += 3; + QPoint horizontalGradTop(optRect.topLeft()); + horizontalGradTop.rx() += optRect.width() - 6; + painter->fillRect(QRect(start, QSize(optRect.width() - 6, 1)), outlineColor); } + //END: horizontal line - bool paintIcon = true; - bool paintText = true; - - QPixmap icon; - switch (index.column()) { - case KDirModel::Name: - paintIcon = false; - break; - - case KDirModel::Size: - paintIcon = false; - break; - - case KDirModel::ModifiedTime: - paintIcon = false; - break; - - case KDirModel::Permissions: - paintIcon = false; // TODO: let's think about how to represent permissions - break; - - case KDirModel::Owner: { - opt.rect.setTop(option.rect.top() + (iconSize / 4)); - KUser user(category); - if (QFile::exists(user.homeDir() + QDir::separator() + ".face.icon")) - { - icon = QPixmap::fromImage(QImage(user.homeDir() + QDir::separator() + ".face.icon")).scaled(iconSize, iconSize); - } - else - { - icon = KIconLoader::global()->loadIcon("user", K3Icon::Small); - } - break; - } - - case KDirModel::Group: - paintIcon = false; - break; - - case KDirModel::Type: { - opt.rect.setTop(option.rect.top() + (option.rect.height() / 2) - (iconSize / 2)); - const KCategorizedSortFilterProxyModel *proxyModel = static_cast(index.model()); - const DolphinModel *model = static_cast(proxyModel->sourceModel()); - KFileItem item = model->itemForIndex(proxyModel->mapToSource(index)); - // This is the only way of getting the icon right. Others will fail on corner - // cases like the item representing this group has been set a different icon, - // so the group icon drawn is that one particularly. This way assures the drawn - // icon is the one of the mimetype of the group itself. (ereslibre) - icon = KIconLoader::global()->loadMimeTypeIcon(item.mimeTypePtr()->iconName(), - K3Icon::Small); - break; - } - -#ifdef HAVE_NEPOMUK - case DolphinModel::Rating: { - paintText = false; - paintIcon = false; - - starRect.setTop(option.rect.top() + (option.rect.height() / 2) - (iconSize / 2)); - starRect.setSize(QSize(iconSize, iconSize)); - - QPixmap pixmap = KIconLoader::global()->loadIcon("rating", K3Icon::Small); - QPixmap smallPixmap = KIconLoader::global()->loadIcon("rating", K3Icon::NoGroup, iconSize / 2); - QPixmap disabledPixmap = KIconLoader::global()->loadIcon("rating", K3Icon::Small); - - KPixmapEffect::toGray(disabledPixmap, false); - - int rating = category.toInt(); - - for (int i = 0; i < rating - (rating % 2); i += 2) { - painter->drawPixmap(starRect, pixmap); - - if (option.direction == Qt::LeftToRight) - { - starRect.setLeft(starRect.left() + iconSize + (iconSize / 4) /* separator between stars */); - starRect.setRight(starRect.right() + iconSize + (iconSize / 4) /* separator between stars */); - } - else - { - starRect.setLeft(starRect.left() - iconSize - (iconSize / 4) /* separator between stars */); - starRect.setRight(starRect.right() - iconSize - (iconSize / 4) /* separator between stars */); - } - } - - if (rating && rating % 2) { - if (option.direction == Qt::RightToLeft) - { - starRect.setLeft(starRect.left() + (iconSize / 2) /* separator between stars */); - //starRect.setRight(starRect.right() + (iconSize / 2) /* separator between stars */); - } + //BEGIN: top right corner + { + painter->save(); + painter->setPen(outlineColor); + QPointF topRight(optRect.topRight()); + topRight.rx() -= 4; + QRectF arc(topRight, QSizeF(4, 4)); + arc.translate(0.5, 0.5); + painter->drawArc(arc, 0, 1440); + painter->restore(); + } + //END: top right corner - starRect.setTop(option.rect.top() + (option.rect.height() / 2) - (iconSize / 4)); - starRect.setSize(QSize(iconSize / 2, iconSize / 2)); - painter->drawPixmap(starRect, smallPixmap); - starRect.setTop(opt.rect.top() + (option.rect.height() / 2) - (iconSize / 2)); - //starRect.setSize(QSize(iconSize / 2, iconSize / 2)); + //BEGIN: right vertical line + { + QPoint start(optRect.topRight()); + start.ry() += 3; + QPoint verticalGradBottom(optRect.topRight()); + verticalGradBottom.ry() += fontMetrics.height() + 5; + QLinearGradient gradient(start, verticalGradBottom); + gradient.setColorAt(0, outlineColor); + gradient.setColorAt(1, Qt::transparent); + painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient); + } + //END: right vertical line - if (option.direction == Qt::LeftToRight) - { - starRect.setLeft(starRect.left() + (iconSize / 2) + (iconSize / 4)); - starRect.setRight(starRect.right() + (iconSize / 2) + (iconSize / 4)); - } - else - { - starRect.setLeft(starRect.left() - (iconSize / 2) - (iconSize / 4)); - starRect.setRight(starRect.right() - (iconSize / 2) - (iconSize / 4)); - } + const int iconSize = KIconLoader::global()->currentSize(KIconLoader::Small); - if (option.direction == Qt::RightToLeft) - { - starRect.setLeft(starRect.left() - (iconSize / 2)); - starRect.setRight(starRect.right() - (iconSize / 2)); + //BEGIN: select/unselect all + { + if (this->category == category) { + QRect iconAllRect(option.rect); + iconAllRect.setTop(iconAllRect.top() + 4); + iconAllRect.setLeft(iconAllRect.right() - 16 - 7); + iconAllRect.setSize(QSize(iconSize, iconSize)); + if (!allCategorySelected(category)) { + if (iconAllRect.contains(pos)) { + painter->drawPixmap(iconAllRect, selectAllHovered); + } else { + painter->drawPixmap(iconAllRect, selectAll); } - - starRect.setSize(QSize(iconSize, iconSize)); + } else { + painter->drawPixmap(iconAllRect, selectAllDisabled); } - - for (int i = rating; i < 9; i += 2) { - painter->drawPixmap(starRect, disabledPixmap); - - if (option.direction == Qt::LeftToRight) - { - starRect.setLeft(starRect.left() + iconSize + (iconSize / 4)); - starRect.setRight(starRect.right() + iconSize + (iconSize / 4)); - } - else - { - starRect.setLeft(starRect.left() - iconSize - (iconSize / 4)); - starRect.setRight(starRect.right() - iconSize - (iconSize / 4)); + QRect iconNoneRect(option.rect); + iconNoneRect.setTop(iconNoneRect.top() + 4); + iconNoneRect.setLeft(iconNoneRect.right() - 16 * 2 - 7 * 2); + iconNoneRect.setSize(QSize(iconSize, iconSize)); + if (someCategorySelected(category)) { + if (iconNoneRect.contains(pos)) { + painter->drawPixmap(iconNoneRect, unselectAllHovered); + } else { + painter->drawPixmap(iconNoneRect, unselectAll); } + } else { + painter->drawPixmap(iconNoneRect, unselectAllDisabled); } - - break; } - - case DolphinModel::Tags: - paintIcon = false; - break; -#endif } + //END: select/unselect all - if (paintIcon) { - painter->drawPixmap(QRect(option.direction == Qt::LeftToRight ? opt.rect.left() - : opt.rect.right() - iconSize, opt.rect.top(), iconSize, iconSize), icon); + //BEGIN: category information + { + bool paintIcon; + QPixmap icon; + switch (index.column()) { + case KDirModel::Owner: { + paintIcon = true; + KUser user(category); + const QString faceIconPath = user.faceIconPath(); + if (faceIconPath.isEmpty()) { + icon = KIconLoader::global()->loadIcon("user-identity", KIconLoader::NoGroup, iconSize); + } else { + icon = QPixmap::fromImage(QImage(faceIconPath).scaledToHeight(iconSize, Qt::SmoothTransformation)); + } + } + break; + case KDirModel::Type: { + paintIcon = true; + const KCategorizedSortFilterProxyModel *proxyModel = static_cast(index.model()); + const DolphinModel *model = static_cast(proxyModel->sourceModel()); + KFileItem item = model->itemForIndex(proxyModel->mapToSource(index)); + // This is the only way of getting the icon right. Others will fail on corner + // cases like the item representing this group has been set a different icon, + // so the group icon drawn is that one particularly. This way assures the drawn + // icon is the one of the mimetype of the group itself. (ereslibre) + icon = KIconLoader::global()->loadMimeTypeIcon(item.mimeTypePtr()->iconName(), KIconLoader::NoGroup, iconSize); + } + break; + default: + paintIcon = false; + } + + if (paintIcon) { + QRect iconRect(option.rect); + iconRect.setTop(iconRect.top() + 4); + iconRect.setLeft(iconRect.left() + 7); + iconRect.setSize(QSize(iconSize, iconSize)); + + painter->drawPixmap(iconRect, icon); + } - if (option.direction == Qt::LeftToRight) + //BEGIN: text { - opt.rect.setLeft(opt.rect.left() + iconSize + (iconSize / 4)); + QRect textRect(option.rect); + textRect.setTop(textRect.top() + 7); + textRect.setLeft(textRect.left() + 7 + (paintIcon ? (iconSize + 6) : 0)); + textRect.setHeight(qMax(fontMetrics.height(), iconSize)); + textRect.setRight(textRect.right() - 7); + textRect.setBottom(textRect.bottom() - 5); // only one pixel separation here (no gradient) + + painter->save(); + painter->setFont(font); + QColor penColor(option.palette.text().color()); + penColor.setAlphaF(0.6); + painter->setPen(penColor); + painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, category); + painter->restore(); } + //END: text } + //BEGIN: category information +} - if (paintText) { - opt.rect.setTop(option.rect.top() + (iconSize / 4)); - opt.rect.setBottom(opt.rect.bottom() - 2); - painter->setPen(color); +int DolphinCategoryDrawer::categoryHeight(const QModelIndex &index, const QStyleOption &) const +{ + int iconSize = KIconLoader::global()->currentSize(KIconLoader::Small); + QFont font(QApplication::font()); + font.setBold(true); + const QFontMetrics fontMetrics = QFontMetrics(font); + int heightWithoutIcon = fontMetrics.height() + (iconSize / 4) * 2 + 1; /* 1 pixel-width gradient */ + bool paintIcon; - QRect textRect = opt.rect; + switch (index.column()) { + case KDirModel::Owner: + case KDirModel::Type: + paintIcon = true; + break; + default: + paintIcon = false; + } - if (option.direction == Qt::RightToLeft) - { - textRect.setWidth(textRect.width() - (paintIcon ? iconSize + (iconSize / 4) - : (iconSize / 4))); - } + if (paintIcon) { + return qMax(heightWithoutIcon + 5, iconSize + 1 /* 1 pixel-width gradient */ + + 5 /* top and bottom separation */); + } + + return heightWithoutIcon + 5; +} - painter->drawText(textRect, Qt::AlignVCenter | Qt::AlignLeft, - metrics.elidedText(category, Qt::ElideRight, textRect.width())); +void DolphinCategoryDrawer::mouseButtonPressed(const QModelIndex &index, const QRect &blockRect, QMouseEvent *event) +{ + if (!index.isValid()) { + event->ignore(); + return; + } + const QString category = index.model()->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); + int iconSize = KIconLoader::global()->currentSize(KIconLoader::Small); + if (this->category == category) { + QRect iconAllRect(blockRect); + iconAllRect.setTop(iconAllRect.top() + 4); + iconAllRect.setLeft(iconAllRect.right() - 16 - 7); + iconAllRect.setSize(QSize(iconSize, iconSize)); + if (iconAllRect.contains(pos)) { + event->accept(); + hotSpotPressed = SelectAllHotSpot; + categoryPressed = index; + return; + } + QRect iconNoneRect(blockRect); + iconNoneRect.setTop(iconNoneRect.top() + 4); + iconNoneRect.setLeft(iconNoneRect.right() - 16 * 2 - 7 * 2); + iconNoneRect.setSize(QSize(iconSize, iconSize)); + if (iconNoneRect.contains(pos)) { + event->accept(); + hotSpotPressed = UnselectAllHotSpot; + categoryPressed = index; + return; + } } + event->ignore(); +} - painter->restore(); +void DolphinCategoryDrawer::mouseButtonReleased(const QModelIndex &index, const QRect &blockRect, QMouseEvent *event) +{ + if (!index.isValid() || hotSpotPressed == NoneHotSpot || categoryPressed != index) { + event->ignore(); + return; + } + categoryPressed = QModelIndex(); + const QString category = index.model()->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); + int iconSize = KIconLoader::global()->currentSize(KIconLoader::Small); + if (this->category == category) { + QRect iconAllRect(blockRect); + iconAllRect.setTop(iconAllRect.top() + 4); + iconAllRect.setLeft(iconAllRect.right() - 16 - 7); + iconAllRect.setSize(QSize(iconSize, iconSize)); + if (iconAllRect.contains(pos)) { + if (hotSpotPressed == SelectAllHotSpot) { + event->accept(); + emit actionRequested(SelectAll, index); + } else { + event->ignore(); + hotSpotPressed = NoneHotSpot; + } + return; + } + QRect iconNoneRect(blockRect); + iconNoneRect.setTop(iconNoneRect.top() + 4); + iconNoneRect.setLeft(iconNoneRect.right() - 16 * 2 - 7 * 2); + iconNoneRect.setSize(QSize(iconSize, iconSize)); + if (iconNoneRect.contains(pos)) { + if (hotSpotPressed == UnselectAllHotSpot) { + event->accept(); + emit actionRequested(UnselectAll, index); + } else { + event->ignore(); + hotSpotPressed = NoneHotSpot; + } + return; + } + } + event->ignore(); } -int DolphinCategoryDrawer::categoryHeight(const QStyleOption &option) const +void DolphinCategoryDrawer::mouseMoved(const QModelIndex &index, const QRect &, QMouseEvent *event) { - int iconSize = KIconLoader::global()->currentSize(K3Icon::Small); + event->ignore(); + if (!index.isValid()) { + return; + } + pos = event->pos(); + category = index.model()->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); +} - return qMax(option.fontMetrics.height() + (iconSize / 4) * 2 + 2, iconSize + (iconSize / 4) * 2 + 2) /* 2 gradient */; +void DolphinCategoryDrawer::mouseLeft(const QModelIndex &, const QRect &) +{ + pos = QPoint(); + category = QString(); }