-/**
+/*
* This file is part of the KDE project
* Copyright (C) 2007 Rafael Fernández López <ereslibre@kde.org>
*
*/
#include "dolphincategorydrawer.h"
-#include "ratingpainter.h"
+
+#include <config-nepomuk.h>
+
#include <QPainter>
#include <QFile>
#include <QDir>
+#include <QApplication>
+#include <QStyleOption>
+
+#ifdef HAVE_NEPOMUK
+#include <nepomuk/kratingpainter.h>
+#endif
#include <kiconloader.h>
+#include <kiconeffect.h>
#include <kcategorizedsortfilterproxymodel.h>
#include <qimageblitz.h>
#include <kuser.h>
-
-#include <config-nepomuk.h>
-#ifdef HAVE_NEPOMUK
-#include <nepomuk/global.h>
-#include <nepomuk/resource.h>
-#include <nepomuk/tag.h>
-#endif
+#include <kcategorizedview.h>
#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))
{
}
{
}
+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(KIconLoader::Small);
- QVariant categoryVariant = index.model()->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole);
+ Q_UNUSED(sortRole);
+ painter->setRenderHint(QPainter::Antialiasing);
- if (!categoryVariant.isValid())
- {
+ if (!index.isValid()) {
return;
}
- const QString category = categoryVariant.toString();
+ 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);
- QColor color;
+ QColor outlineColor = option.palette.text().color();
+ outlineColor.setAlphaF(0.35);
- if (option.state & QStyle::State_Selected)
- {
- color = option.palette.color(QPalette::HighlightedText);
- }
- else
+ //BEGIN: top left corner
{
- color = option.palette.color(QPalette::Text);
+ 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
- painter->save();
- painter->setRenderHint(QPainter::Antialiasing);
-
- QStyleOptionButton opt;
-
- opt.rect = option.rect;
- opt.palette = option.palette;
- opt.direction = option.direction;
- opt.text = category;
-
- if (option.state & QStyle::State_Selected)
+ //BEGIN: left vertical line
{
- QColor selected = option.palette.color(QPalette::Highlight);
-
- QLinearGradient gradient(option.rect.topLeft(),
- option.rect.bottomRight());
- gradient.setColorAt(option.direction == Qt::LeftToRight ? 0
- : 1, selected);
- gradient.setColorAt(option.direction == Qt::LeftToRight ? 1
- : 0, Qt::transparent);
-
- painter->fillRect(option.rect, gradient);
+ 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 if (option.state & QStyle::State_MouseOver)
- {
- QColor hover = option.palette.color(QPalette::Highlight);
- 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);
+ //END: left vertical line
- painter->fillRect(option.rect, gradient);
+ //BEGIN: horizontal line
+ {
+ 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
- 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: top right corner
{
- opt.rect.setLeft(opt.rect.left() + (iconSize / 4));
- starRect.setLeft(starRect.left() + (iconSize / 4));
- starRect.setRight(starRect.right() + (iconSize / 4));
+ 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();
}
- else
+ //END: top right corner
+
+ //BEGIN: right vertical line
{
- opt.rect.setRight(opt.rect.width() - (iconSize / 4));
- starRect.setLeft(starRect.width() - iconSize);
- starRect.setRight(starRect.width() - (iconSize / 4));
+ 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
- bool paintIcon = true;
- bool paintText = true;
+ const int iconSize = KIconLoader::global()->currentSize(KIconLoader::Small);
- 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.bottom() - (iconSize / 4));
- KUser user(category);
- QString faceIconPath = user.faceIconPath();
-
- if (!faceIconPath.isEmpty())
- {
- icon = QPixmap::fromImage(QImage(faceIconPath).scaledToHeight(option.fontMetrics.height(), Qt::SmoothTransformation));
+ //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);
+ }
+ } else {
+ painter->drawPixmap(iconAllRect, selectAllDisabled);
}
- else
- {
- icon = KIconLoader::global()->loadIcon("user", KIconLoader::NoGroup, option.fontMetrics.height());
+ 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);
}
-
- opt.rect.setTop(opt.rect.top() - icon.height());
-
- break;
}
+ }
+ //END: select/unselect all
- case KDirModel::Group:
- paintIcon = false;
- break;
-
- case KDirModel::Type: {
- opt.rect.setTop(option.rect.bottom() - (iconSize / 4));
- const KCategorizedSortFilterProxyModel *proxyModel = static_cast<const KCategorizedSortFilterProxyModel*>(index.model());
- const DolphinModel *model = static_cast<const DolphinModel*>(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, option.fontMetrics.height());
-
- opt.rect.setTop(opt.rect.top() - icon.height());
-
- break;
+ //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<const KCategorizedSortFilterProxyModel*>(index.model());
+ const DolphinModel *model = static_cast<const DolphinModel*>(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);
}
-#ifdef HAVE_NEPOMUK
- case DolphinModel::Rating: {
- paintText = false;
- paintIcon = false;
-
- painter->setLayoutDirection( option.direction );
- QRect ratingRect( option.rect );
- ratingRect.setTop(option.rect.top() + (option.rect.height() / 2) - (iconSize / 2));
- ratingRect.setHeight( iconSize );
- Nepomuk::RatingPainter::drawRating( painter, ratingRect, Qt::AlignLeft, category.toInt() );
- break;
+ //BEGIN: text
+ {
+ 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
+}
- case DolphinModel::Tags:
- paintIcon = false;
- break;
-#endif
+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;
+
+ switch (index.column()) {
+ case KDirModel::Owner:
+ case KDirModel::Type:
+ paintIcon = true;
+ break;
+ default:
+ paintIcon = false;
}
if (paintIcon) {
- painter->drawPixmap(QRect(option.direction == Qt::LeftToRight ? opt.rect.left()
- : opt.rect.right() - icon.width() + (iconSize / 4), opt.rect.top(), icon.width(), icon.height()), icon);
+ return qMax(heightWithoutIcon + 5, iconSize + 1 /* 1 pixel-width gradient */
+ + 5 /* top and bottom separation */);
+ }
- if (option.direction == Qt::LeftToRight)
- {
- opt.rect.setLeft(opt.rect.left() + icon.width() + (iconSize / 4));
+ return heightWithoutIcon + 5;
+}
+
+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;
}
- else
- {
- opt.rect.setRight(opt.rect.right() + (iconSize / 4));
+ 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();
+}
- if (paintText) {
- opt.rect.setTop(option.rect.top() + (iconSize / 4));
- opt.rect.setBottom(opt.rect.bottom() - 2);
- painter->setPen(color);
-
- QRect textRect = opt.rect;
-
- if (option.direction == Qt::RightToLeft)
- {
- textRect.setWidth(textRect.width() - (paintIcon ? icon.width() + (iconSize / 2)
- : -(iconSize / 4)));
+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;
}
-
- painter->drawText(textRect, Qt::AlignVCenter | Qt::AlignLeft,
- metrics.elidedText(category, Qt::ElideRight, textRect.width()));
}
-
- painter->restore();
+ event->ignore();
}
-int DolphinCategoryDrawer::categoryHeight(const QStyleOption &option) const
+void DolphinCategoryDrawer::mouseMoved(const QModelIndex &index, const QRect &, QMouseEvent *event)
{
- int iconSize = KIconLoader::global()->currentSize(KIconLoader::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();
}