mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-25 19:32:54 +00:00
307 lines
11 KiB
C++
307 lines
11 KiB
C++
/*
|
|
* Copyright 2009 Andrew Stromme <astromme@chatonka.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU Library General Public License as
|
|
* published by the Free Software Foundation; either version 2, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this program; if not, write to the
|
|
* Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "taskitemdelegate.h"
|
|
|
|
#include "taskeditor.h"
|
|
|
|
#include <QApplication>
|
|
|
|
#include <Plasma/Theme>
|
|
#include <Plasma/Svg>
|
|
|
|
#include <QColor>
|
|
#include <QLinearGradient>
|
|
#include <QCheckBox>
|
|
|
|
#include <KDebug>
|
|
|
|
const qreal TaskItemDelegate::MARGIN = 1.0;
|
|
const qreal TaskItemDelegate::MARGINH = 6.0;
|
|
const qreal TaskItemDelegate::COLORTAB = MARGIN*6;
|
|
|
|
// These colors are hardcoded because they represent priorities and need to be the same for visual recognition purposes.
|
|
const QColor TaskItemDelegate::priority1 = QColor(255, 123, 0); // reddish-orange
|
|
const QColor TaskItemDelegate::priority2 = QColor(0, 132, 255); // Darker blue
|
|
const QColor TaskItemDelegate::priority3 = QColor(53, 201, 255); // Ligher Blue
|
|
const QColor TaskItemDelegate::priorityNone = QColor(241, 241, 241); // Almost white
|
|
|
|
const QString TaskItemDelegate::tagsPrefix = i18n("Tags: ");
|
|
|
|
TaskItemDelegate::TaskItemDelegate(QObject *parent)
|
|
: QStyledItemDelegate(parent),
|
|
dragging(false)
|
|
{
|
|
setSmallTasks(false);
|
|
}
|
|
|
|
void TaskItemDelegate::setSmallTasks(bool small)
|
|
{
|
|
smallTasks = small;
|
|
leftMargin = small ? 0 : MARGIN;
|
|
}
|
|
|
|
|
|
bool TaskItemDelegate::eventFilter(QObject* object, QEvent* event) {
|
|
if (event->type() == QEvent::DragMove)
|
|
dragging = true;
|
|
if (event->type() == QEvent::Drop || QEvent::DragLeave)
|
|
dragging = false;
|
|
return QStyledItemDelegate::eventFilter(object, event);
|
|
}
|
|
|
|
QColor TaskItemDelegate::itemPriorityColor(const QModelIndex &index) const
|
|
{
|
|
switch (index.data(Qt::RTMPriorityRole).toInt()) { // Set color based on priority
|
|
case 1:
|
|
return priority1;
|
|
case 2:
|
|
return priority2;
|
|
case 3:
|
|
return priority3;
|
|
case 4:
|
|
return priorityNone;
|
|
}
|
|
return QColor();
|
|
}
|
|
|
|
void TaskItemDelegate::paintDueHeader(QPainter* painter, const QRectF& rect, const QModelIndex &index) const
|
|
{
|
|
painter->save();
|
|
|
|
QFontMetrics fm = QApplication::fontMetrics();
|
|
QString dueString = index.data(Qt::DisplayRole).toString();
|
|
|
|
QLinearGradient gradient(rect.bottomLeft(), rect.bottomRight());
|
|
gradient.setColorAt(0, Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
|
|
gradient.setColorAt((qreal)(0.9*fm.width(dueString)+2*MARGIN)/rect.width(), Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
|
|
gradient.setColorAt((qreal)(1.3*fm.width(dueString)+2*MARGIN)/rect.width(), Qt::transparent);
|
|
painter->setBrush(Qt::NoBrush);
|
|
painter->setPen(QPen(QBrush(gradient), 1));
|
|
painter->drawLine(rect.bottomLeft()+QPoint(0, -MARGIN), rect.bottomRight()+QPoint(0, -MARGIN));
|
|
|
|
painter->setPen(Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
|
|
painter->drawText(rect.bottomLeft()+QPoint(MARGIN, -2*MARGIN) ,dueString);
|
|
|
|
painter->restore();
|
|
}
|
|
|
|
void TaskItemDelegate::paintPriorityHeader(QPainter* painter, const QRectF& rect, const QModelIndex &index) const
|
|
{
|
|
painter->save();
|
|
|
|
//Draw colored gradient as priority background
|
|
QLinearGradient gradient(rect.topLeft(), rect.bottomRight());
|
|
gradient.setColorAt(0, itemPriorityColor(index));
|
|
gradient.setColorAt(1, Qt::transparent);
|
|
|
|
int h = QApplication::fontMetrics().height();
|
|
QPainterPath path;
|
|
path.moveTo(rect.bottomLeft());
|
|
path.quadTo(rect.bottomLeft()+QPointF(0, -h), rect.bottomLeft()+QPointF(2, -h));
|
|
path.lineTo(rect.bottomRight()-QPointF(2, h));
|
|
path.quadTo(rect.bottomRight()+QPointF(0, -h), rect.bottomRight());
|
|
painter->setBrush(Qt::NoBrush);
|
|
QPen thickPen(itemPriorityColor(index));
|
|
thickPen.setWidth(2);
|
|
painter->setPen(thickPen);
|
|
painter->drawPath(path);
|
|
|
|
// Draw priority text
|
|
QString priority = index.data(Qt::DisplayRole).toString();
|
|
painter->setPen(Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
|
|
painter->setBrush(Qt::NoBrush);
|
|
painter->drawText(rect.bottomLeft()+QPoint(MARGIN, -2*MARGIN) ,priority);
|
|
|
|
painter->restore();
|
|
}
|
|
|
|
void TaskItemDelegate::paintTask(QPainter* painter, const QStyleOptionViewItem &option, const QModelIndex& index) const
|
|
{
|
|
QRect rect = option.rect;
|
|
QFontMetrics fm = QApplication::fontMetrics();
|
|
|
|
// Painting Order:
|
|
// Background wash
|
|
// Mouseover highlight
|
|
// Priority Tab on left
|
|
// Bounding Box
|
|
// Task name
|
|
// If not small, other task information
|
|
|
|
painter->save();
|
|
if (smallTasks) { // Paint the background for a small task
|
|
painter->save();
|
|
painter->setOpacity(0.5);
|
|
painter->setBrush(Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor));
|
|
painter->setPen(Qt::NoPen);
|
|
painter->drawRoundedRect(rect.adjusted(leftMargin, MARGIN, -MARGIN, -MARGIN), 3, 3);
|
|
painter->restore();
|
|
}
|
|
else { // Paint the background for a two row task
|
|
painter->save();
|
|
painter->setOpacity(0.5);
|
|
painter->setBrush(Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor));
|
|
painter->drawRect(option.rect.adjusted(leftMargin, MARGIN, -MARGIN, -MARGIN));
|
|
|
|
painter->restore();
|
|
painter->drawRect(QRectF(option.rect.topLeft()+QPointF(leftMargin, MARGIN), option.rect.bottomLeft()+QPointF(COLORTAB, -MARGIN)));
|
|
}
|
|
|
|
if (option.state & QStyle::State_MouseOver) {
|
|
painter->save();
|
|
painter->setBrush(Plasma::Theme::defaultTheme()->color(Plasma::Theme::HighlightColor));
|
|
painter->setPen(Qt::NoPen);
|
|
if (smallTasks)
|
|
painter->drawRoundedRect(rect.adjusted(leftMargin, MARGIN, -MARGIN, -MARGIN), 3, 3);
|
|
else
|
|
painter->drawRect(rect.adjusted(leftMargin, MARGIN, -MARGIN, -MARGIN));
|
|
painter->restore();
|
|
}
|
|
|
|
//Paint Priority tab on the left
|
|
painter->setPen(Qt::NoPen);
|
|
painter->setBrush(itemPriorityColor(index));
|
|
painter->drawRoundedRect(QRectF(option.rect.topLeft()+QPointF(leftMargin, MARGIN), option.rect.bottomLeft()+QPointF(COLORTAB, 0)), 3, 3);
|
|
|
|
|
|
// Draw Bounding rect/box
|
|
painter->save();
|
|
painter->setOpacity(.5);
|
|
painter->setPen(Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
|
|
painter->setBrush(Qt::NoBrush);
|
|
if (smallTasks)
|
|
painter->drawRoundedRect(option.rect.adjusted(leftMargin, MARGIN, -MARGIN, -MARGIN), 3, 3);
|
|
else
|
|
painter->drawRect(option.rect.adjusted(leftMargin, MARGIN, -MARGIN, -MARGIN));
|
|
painter->restore();
|
|
|
|
|
|
// Draw Task information
|
|
painter->setPen(Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
|
|
|
|
QString task = index.data(Qt::RTMNameRole).toString();
|
|
QString due = index.data(Qt::RTMDueRole).toDate().toString("MMM d");
|
|
QString tags = index.data(Qt::RTMTagsRole).toStringList().join(", ");
|
|
if (!tags.isEmpty())
|
|
tags.prepend(tagsPrefix);
|
|
|
|
QFont font = painter->font();
|
|
font.setPointSize(font.pointSize());
|
|
QFontMetrics largerFM(font);
|
|
|
|
QDate date = index.data(Qt::RTMDueRole).toDate();
|
|
|
|
if (smallTasks && date.isValid() && date < QDate::currentDate()) {
|
|
// Elide (text with dots like th...) if wider than view and draw
|
|
font.setBold(true);
|
|
QFontMetrics boldLargerFM(font);
|
|
due = due.append(" "); // So that we have a space after the date before the task name
|
|
task = largerFM.elidedText(task, Qt::ElideRight, option.rect.width()-COLORTAB-3*MARGIN - boldLargerFM.width(due));
|
|
painter->setFont(font);
|
|
painter->drawText(option.rect.topLeft()+QPoint(COLORTAB+MARGIN,largerFM.height()),due);
|
|
|
|
font.setBold(false);
|
|
painter->setFont(font);
|
|
painter->drawText(option.rect.topLeft()+QPoint(COLORTAB+3*MARGIN + boldLargerFM.width(due),boldLargerFM.height()),task);
|
|
}
|
|
else {
|
|
// Elide (text with dots like th...) if wider than view and draw
|
|
task = largerFM.elidedText(task, Qt::ElideRight, option.rect.width()-COLORTAB-3*MARGIN);
|
|
painter->setFont(font);
|
|
painter->drawText(option.rect.topLeft()+QPoint(COLORTAB+MARGIN,largerFM.height()),task);
|
|
}
|
|
|
|
if (smallTasks) {
|
|
painter->restore();
|
|
return;
|
|
}
|
|
|
|
// Set our smaller attributes and blue hue for additional text
|
|
font.setPointSize(font.pointSize()-1);
|
|
font.setItalic(true);
|
|
painter->setFont(font);
|
|
fm = QFontMetrics(font);
|
|
QColor moreText(Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
|
|
|
|
qreal red = moreText.redF();
|
|
qreal green = moreText.greenF();
|
|
qreal blue = moreText.blueF();
|
|
qreal colorChangeMult = 0.85;
|
|
if (blue < colorChangeMult)
|
|
blue /= colorChangeMult;
|
|
else {
|
|
red *= colorChangeMult;
|
|
green *= colorChangeMult;
|
|
}
|
|
moreText.setRgbF(red, green, blue);
|
|
painter->setPen(moreText);
|
|
|
|
// Elide the due from the front because "Due on" isn't necessary
|
|
due = fm.elidedText(due, Qt::ElideLeft, option.rect.width() - COLORTAB+3*MARGIN - fm.width(tags));
|
|
painter->drawText(option.rect.bottomLeft()+QPoint(COLORTAB+MARGIN, -MARGINH), tags);
|
|
painter->drawText(option.rect.bottomRight()+QPoint(-COLORTAB+MARGIN-fm.width(due), -MARGINH), due);
|
|
|
|
painter->restore();
|
|
}
|
|
|
|
void TaskItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
|
const QModelIndex &index) const
|
|
{
|
|
switch (index.data(Qt::RTMItemType).toInt()) {
|
|
case RTMPriorityHeader:
|
|
paintPriorityHeader(painter, option.rect, index);
|
|
break;
|
|
case RTMDateHeader:
|
|
paintDueHeader(painter, option.rect, index);
|
|
break;
|
|
case RTMTaskItem:
|
|
paintTask(painter, option, index);
|
|
break;
|
|
}
|
|
}
|
|
|
|
QSize TaskItemDelegate::sizeHint(const QStyleOptionViewItem &option,
|
|
const QModelIndex &index) const
|
|
{
|
|
Q_UNUSED(option)
|
|
if (smallTasks || index.data(Qt::RTMItemType).toInt() != RTMTaskItem) {
|
|
QString priority = index.data(Qt::DisplayRole).toString();
|
|
QSize size;
|
|
if (index.data(Qt::RTMItemType).toInt() == RTMDateHeader)
|
|
size.setHeight(QApplication::fontMetrics().height()+MARGINH*1.5);
|
|
else
|
|
size.setHeight(QApplication::fontMetrics().height()+MARGINH);
|
|
size.setWidth(QApplication::fontMetrics().width(priority));
|
|
return size;
|
|
}
|
|
else {
|
|
QString task = index.data(Qt::RTMNameRole).toString();
|
|
QString due = index.data(Qt::RTMDueRole).toDate().toString("MMM d");
|
|
QString tags = index.data(Qt::RTMTagsRole).toStringList().join(", ");
|
|
if (!tags.isEmpty())
|
|
tags.prepend(tagsPrefix);
|
|
|
|
//QSize size = QStyledItemDelegate::sizeHint(option, index);
|
|
QSize size;
|
|
size.setHeight(MARGINH + MARGINH + QApplication::fontMetrics().height()*2);
|
|
size.setWidth(MARGIN + MARGIN + QApplication::fontMetrics().width(task+due));
|
|
return size;
|
|
}
|
|
}
|