[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [zanshin] src/widgets: Expand the row when selected and show more information
From:       Kevin Ottens <ervin () kde ! org>
Date:       2016-11-23 8:23:15
Message-ID: E1c9Spn-00066t-93 () code ! kde ! org
[Download RAW message or body]

Git commit 100214bebd2f7a855ee6034e4ac85b835a6995bf by Kevin Ottens.
Committed on 23/11/2016 at 08:23.
Pushed by ervin into branch 'master'.

Expand the row when selected and show more information

Summary:
Added some more information to display in the item delegate of the
central view. Now we display the due date right aligned if available and
also we show the first few lines of the artifact text when the item is
the current item (requiring a higher row).

It led to a massive refactoring of the delegate.

Reviewers: bensi, dfaure, franckarrecot

Reviewed By: franckarrecot

Differential Revision: https://phabricator.kde.org/D2738

M  +141  -40   src/widgets/itemdelegate.cpp
M  +8    -0    src/widgets/itemdelegate.h
M  +4    -0    src/widgets/pageview.cpp

https://commits.kde.org/zanshin/100214bebd2f7a855ee6034e4ac85b835a6995bf

diff --git a/src/widgets/itemdelegate.cpp b/src/widgets/itemdelegate.cpp
index 48e9933..54100e0 100644
--- a/src/widgets/itemdelegate.cpp
+++ b/src/widgets/itemdelegate.cpp
@@ -1,6 +1,6 @@
 /* This file is part of Zanshin
 
-   Copyright 2014 Kevin Ottens <ervin@kde.org>
+   Copyright 2014-2016 Kevin Ottens <ervin@kde.org>
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -25,6 +25,7 @@
 #include "itemdelegate.h"
 
 #include <QApplication>
+#include <QPainter>
 #include <QStyleOptionViewItemV4>
 
 #include "domain/note.h"
@@ -33,18 +34,37 @@
 
 using namespace Widgets;
 
+namespace {
+    const int SELECTED_FACTOR = 3;
+}
+
 ItemDelegate::ItemDelegate(QObject *parent)
     : QStyledItemDelegate(parent)
 {
 }
 
+void ItemDelegate::setCurrentIndex(const QModelIndex &current)
+{
+    if (m_currentIndex.isValid())
+        emit sizeHintChanged(m_currentIndex);
+
+    m_currentIndex = current;
+
+    if (m_currentIndex.isValid())
+        emit sizeHintChanged(m_currentIndex);
+}
+
 QSize ItemDelegate::sizeHint(const QStyleOptionViewItem &option,
-                                   const QModelIndex &index) const
+                             const QModelIndex &index) const
 {
     // Make sure they all get the height needed for a check indicator
     QStyleOptionViewItemV4 opt = option;
+    initStyleOption(&opt, index);
     opt.features = QStyleOptionViewItemV4::HasCheckIndicator;
+    opt.text += ' ' + QLocale().dateFormat(QLocale::ShortFormat).toUpper() \
+ ' ';  QSize res = QStyledItemDelegate::sizeHint(opt, index);
+    if (m_currentIndex == index)
+        res.setHeight(res.height() * SELECTED_FACTOR);
     return res;
 }
 
@@ -52,57 +72,138 @@ void ItemDelegate::paint(QPainter *painter,
                          const QStyleOptionViewItem &option,
                          const QModelIndex &index) const
 {
-    QStyleOptionViewItemV4 opt = option;
-    initStyleOption(&opt, index);
+    const auto data = \
index.data(Presentation::QueryTreeModelBase::ObjectRole);  
-    Domain::Task::Ptr task;
-    Domain::Note::Ptr note;
-
-    QVariant data = \
index.data(Presentation::QueryTreeModelBase::ObjectRole); +    auto task = \
Domain::Task::Ptr();  auto artifact = data.value<Domain::Artifact::Ptr>();
     if (artifact) {
         task = artifact.dynamicCast<Domain::Task>();
-        note = artifact.dynamicCast<Domain::Note>();
     } else {
         task = data.value<Domain::Task::Ptr>();
-        note = data.value<Domain::Note::Ptr>();
+        auto note = data.value<Domain::Note::Ptr>();
+        artifact = task ? task.staticCast<Domain::Artifact>()
+                        : note.staticCast<Domain::Artifact>();
     }
 
+    auto opt = QStyleOptionViewItemV4(option);
+    initStyleOption(&opt, index);
+    const auto widget = opt.widget;
+    const auto style = widget ? widget->style() : QApplication::style();
+
+    const auto isDone = task ? task->isDone() : false;
+    const auto isEnabled = (opt.state & QStyle::State_Enabled);
+    const auto isActive = (opt.state & QStyle::State_Active);
+    const auto isCurrent = (m_currentIndex == index);
+    const auto isSelected = (opt.state & QStyle::State_Selected);
+    const auto isEditing = (opt.state & QStyle::State_Editing);
+
+    const auto startDate = task ? task->startDate() : QDateTime();
+    const auto dueDate = task ? task->dueDate() : QDateTime();
+
+    const auto onStartDate = startDate.isValid() && startDate.date() <= \
QDate::currentDate(); +    const auto pastDueDate = dueDate.isValid() && \
dueDate.date() < QDate::currentDate(); +    const auto onDueDate = \
dueDate.isValid() && dueDate.date() == QDate::currentDate(); +
+    const auto baseFont = opt.font;
+    const auto summaryFont = [=] {
+        auto font = baseFont;
+        font.setStrikeOut(isDone);
+        font.setBold(!isDone && (onStartDate || onDueDate || \
pastDueDate)); +        return font;
+    }();
+    const auto summaryMetrics = QFontMetrics(summaryFont);
+
+    const auto colorGroup = (isEnabled && !isActive) ? QPalette::Inactive
+                          : isEnabled ? QPalette::Normal
+                          : QPalette::Disabled;
+    const auto colorRole = (isSelected && !isEditing) ? \
QPalette::HighlightedText : QPalette::Text; +
+    const auto baseColor = opt.palette.color(colorGroup, colorRole);
+    const auto summaryColor = isDone ? baseColor
+                            : pastDueDate ? QColor(Qt::red)
+                            : onDueDate ? QColor("orange")
+                            : baseColor;
+
+    const auto hasDelegate = task && task->delegate().isValid();
+    const auto summaryText = hasDelegate ? tr("(%1) \
%2").arg(task->delegate().display(), opt.text) : opt.text; +    const auto \
dueDateText = dueDate.isValid() ? QLocale().toString(dueDate.date(), \
QLocale::ShortFormat) +                                               : \
QString(); +
+    const auto textMargin = \
style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, widget) + 1; +    const \
auto dueDateWidth = dueDate.isValid() ? (summaryMetrics.width(dueDateText) \
+ 2 * textMargin) : 0; +
+
+    if (isCurrent)
+        opt.rect.setHeight(opt.rect.height() / SELECTED_FACTOR);
+
+    const auto checkRect = \
style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &opt, widget); \
+    const auto summaryRect = \
style->subElementRect(QStyle::SE_ItemViewItemText, &opt, widget) +          \
.adjusted(textMargin, 0, -dueDateWidth - textMargin, 0); +    const auto \
dueDateRect = opt.rect.adjusted(opt.rect.width() - dueDateWidth, 0, 0, 0); \
+ +    if (isCurrent)
+        opt.rect.setHeight(opt.rect.height() * SELECTED_FACTOR);
+
+
+    // Draw background
+    style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, \
widget); +
+    // Draw the check box
     if (task) {
-        if (task->isDone()) {
-            opt.font.setStrikeOut(true);
-        } else {
-            if (task->startDate().isValid()
-             && task->startDate().date() <= QDate::currentDate()) {
-                opt.font.setBold(true);
-            }
-
-            if (task->dueDate().isValid()) {
-                if (task->dueDate().date() < QDate::currentDate()) {
-                    opt.font.setBold(true);
-                    opt.palette.setColor(QPalette::Text, QColor(Qt::red));
-                    opt.palette.setColor(QPalette::HighlightedText, \
                QColor(Qt::red));
-
-                } else if (task->dueDate().date() == QDate::currentDate()) \
                {
-                    opt.font.setBold(true);
-                    opt.palette.setColor(QPalette::Text, \
                QColor("orange"));
-                    opt.palette.setColor(QPalette::HighlightedText, \
                QColor("orange"));
-                }
-            }
-        }
-
-        if (task->delegate().isValid()) {
-            opt.text = tr("(%1) %2").arg(task->delegate().display(), \
                opt.text);
-            opt.font.setItalic(true);
-        }
+        auto checkOption = opt;
+        checkOption.rect = checkRect;
+        checkOption.state = option.state & ~QStyle::State_HasFocus;
+        checkOption.state |= isDone ? QStyle::State_On : \
QStyle::State_Off; +        \
style->drawPrimitive(QStyle::PE_IndicatorViewItemCheck, &checkOption, \
painter, widget); +    }
+
+    // Draw the summary
+    if (!summaryText.isEmpty()) {
+        painter->setPen(summaryColor);
+        painter->setFont(summaryFont);
+        painter->drawText(summaryRect, Qt::AlignVCenter,
+                          summaryMetrics.elidedText(opt.text, \
Qt::ElideRight, summaryRect.width()));  }
 
-    if (note) {
-        opt.features |= QStyleOptionViewItemV4::HasDecoration;
-        opt.icon = QIcon::fromTheme(QStringLiteral("text-plain"));
+    // Draw the due date
+    if (!dueDateText.isEmpty()) {
+        painter->drawText(dueDateRect, Qt::AlignCenter, dueDateText);
     }
 
+    // Draw the extra text
+    const auto extraText = [artifact] {
+        auto text = artifact ? artifact->text() : QString();
+        while (text.startsWith('\n'))
+            text.remove(0, 1);
+        return text;
+    }();
+
+    if (isCurrent && !extraText.isEmpty()) {
+        const auto extraTextRect = opt.rect.adjusted(summaryRect.left(),
+                                                     opt.rect.height() / \
SELECTED_FACTOR, +                                                     0, \
0); +
+        auto gradient = QLinearGradient(extraTextRect.topLeft(), \
extraTextRect.bottomLeft()); +        gradient.setColorAt(0.0, baseColor);
+        gradient.setColorAt(0.75, baseColor);
+        gradient.setColorAt(1.0, Qt::transparent);
+
+        painter->setPen(QPen(QBrush(gradient), 0.0));
+        painter->setFont(baseFont);
+        painter->drawText(extraTextRect, Qt::AlignTop | Qt::TextWordWrap, \
extraText); +    }
+}
+
+void ItemDelegate::updateEditorGeometry(QWidget *editor, const \
QStyleOptionViewItem &option, const QModelIndex &index) const +{
+    QStyleOptionViewItemV4 opt = option;
+    initStyleOption(&opt, index);
+
     const QWidget *widget = opt.widget;
     QStyle *style = widget ? widget->style() : QApplication::style();
-    style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget);
+
+    if (m_currentIndex == index)
+        opt.rect.setHeight(option.rect.height() / SELECTED_FACTOR);
+    const auto textRect = \
style->subElementRect(QStyle::SE_ItemViewItemText, &opt, widget); +    \
editor->setGeometry(textRect);  }
diff --git a/src/widgets/itemdelegate.h b/src/widgets/itemdelegate.h
index c0eda2c..baabd31 100644
--- a/src/widgets/itemdelegate.h
+++ b/src/widgets/itemdelegate.h
@@ -35,11 +35,19 @@ class ItemDelegate : public QStyledItemDelegate
 public:
     explicit ItemDelegate(QObject *parent = Q_NULLPTR);
 
+    void setCurrentIndex(const QModelIndex &current);
+
     QSize sizeHint(const QStyleOptionViewItem &option,
                    const QModelIndex &index) const Q_DECL_OVERRIDE;
     void paint(QPainter *painter,
                const QStyleOptionViewItem &option,
                const QModelIndex &index) const Q_DECL_OVERRIDE;
+    void updateEditorGeometry(QWidget *editor,
+                              const QStyleOptionViewItem &option,
+                              const QModelIndex &index) const \
Q_DECL_OVERRIDE; +
+private:
+    QPersistentModelIndex m_currentIndex;
 };
 
 }
diff --git a/src/widgets/pageview.cpp b/src/widgets/pageview.cpp
index 34ee513..0cf6f89 100644
--- a/src/widgets/pageview.cpp
+++ b/src/widgets/pageview.cpp
@@ -367,6 +367,10 @@ void PageView::onFilterToggled(bool show)
 
 void PageView::onCurrentChanged(const QModelIndex &current)
 {
+    auto delegate = \
qobject_cast<ItemDelegate*>(m_centralView->itemDelegate()); +    if \
(delegate) +        delegate->setCurrentIndex(current);
+
     auto data = current.data(Presentation::QueryTreeModelBase::ObjectRole);
  if (!data.isValid())
         return;


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic