modified model-view
authorpavelpa <pavelpa@localhost>
Tue, 12 Jan 2010 08:15:42 +0000 (08:15 +0000)
committerpavelpa <pavelpa@localhost>
Tue, 12 Jan 2010 08:15:42 +0000 (08:15 +0000)
 - created own delegate to display TreeView items
   - contains also 'controls' - which are clickable (handled in TreeView)
 - created own TreeView inherited from QTreeView
   - to handle control-clicks of the Delegate
 - minor modifications to MainWindow UI
   - QTreeView replaced by own TreeView
   - autoresizing of TreeView
 - icons added

15 files changed:
src/app/app.pro
src/gui/mainwindow.cpp
src/gui/mainwindow.ui
src/icons.qrc [new file with mode: 0644]
src/icons/alarm-off.png [new file with mode: 0644]
src/icons/alarm-on.png [new file with mode: 0644]
src/icons/collapse.png [new file with mode: 0644]
src/icons/expand.png [new file with mode: 0644]
src/icons/favourite-off.png [new file with mode: 0644]
src/icons/favourite-on.png [new file with mode: 0644]
src/model/delegate.cpp [new file with mode: 0644]
src/model/delegate.h [new file with mode: 0644]
src/model/model.pro
src/model/treeview.cpp [new file with mode: 0644]
src/model/treeview.h [new file with mode: 0644]

index 48d12f6..c14f1e6 100644 (file)
@@ -11,3 +11,5 @@ TARGETDEPS += $$DESTDIR/libmodel.a $$DESTDIR/libgui.a
 
 SOURCES += main.cpp
 
+RESOURCES += ../icons.qrc
+
index bf48d91..b2f091c 100644 (file)
@@ -4,6 +4,7 @@
 #include <QDirModel>
 
 #include <eventmodel.h>
+#include <delegate.h>
 
 MainWindow::MainWindow(QWidget *parent)
     : QMainWindow(parent)
@@ -15,6 +16,11 @@ MainWindow::MainWindow(QWidget *parent)
 
     setupUi(this);
     //TODO Palo: continue
-    //treeView->setModel(new QDirModel);
+    treeView->setHeaderHidden(true);
+    treeView->setRootIsDecorated(false);
+    treeView->setIndentation(0);
+    treeView->setAnimated(true);
     treeView->setModel(new EventModel());
+    treeView->setItemDelegate(new Delegate(treeView));
 }
+
index bdce5c7..5447986 100644 (file)
@@ -5,60 +5,69 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>800</width>
-    <height>600</height>
+    <width>856</width>
+    <height>558</height>
    </rect>
   </property>
   <property name="windowTitle" >
    <string>MainWindow</string>
   </property>
   <widget class="QWidget" name="centralwidget" >
-   <widget class="QTabWidget" name="tabWidget" >
-    <property name="geometry" >
-     <rect>
-      <x>0</x>
-      <y>0</y>
-      <width>791</width>
-      <height>551</height>
-     </rect>
-    </property>
-    <property name="currentIndex" >
-     <number>0</number>
-    </property>
-    <widget class="QWidget" name="tab" >
-     <attribute name="title" >
-      <string>Tab 1</string>
-     </attribute>
-     <widget class="QTreeView" name="treeView" >
-      <property name="geometry" >
-       <rect>
-        <x>0</x>
-        <y>0</y>
-        <width>781</width>
-        <height>521</height>
-       </rect>
+   <layout class="QGridLayout" name="gridLayout" >
+    <item row="0" column="0" >
+     <widget class="QTabWidget" name="tabWidget" >
+      <property name="currentIndex" >
+       <number>0</number>
       </property>
+      <widget class="QWidget" name="tab" >
+       <attribute name="title" >
+        <string>Tab 1</string>
+       </attribute>
+       <layout class="QGridLayout" name="gridLayout_2" >
+        <item row="0" column="0" >
+         <layout class="QVBoxLayout" name="verticalLayout" >
+          <item>
+           <widget class="TreeView" name="treeView" >
+            <property name="maximumSize" >
+             <size>
+              <width>16777215</width>
+              <height>16777215</height>
+             </size>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+       </layout>
+      </widget>
+      <widget class="QWidget" name="tab_2" >
+       <attribute name="title" >
+        <string>Tab 2</string>
+       </attribute>
+      </widget>
      </widget>
-    </widget>
-    <widget class="QWidget" name="tab_2" >
-     <attribute name="title" >
-      <string>Tab 2</string>
-     </attribute>
-    </widget>
-   </widget>
+    </item>
+   </layout>
   </widget>
   <widget class="QMenuBar" name="menubar" >
    <property name="geometry" >
     <rect>
      <x>0</x>
      <y>0</y>
-     <width>800</width>
-     <height>25</height>
+     <width>856</width>
+     <height>22</height>
     </rect>
    </property>
   </widget>
   <widget class="QStatusBar" name="statusbar" />
  </widget>
+ <customwidgets>
+  <customwidget>
+   <class>TreeView</class>
+   <extends>QTreeView</extends>
+   <header>../model/treeview.h</header>
+  </customwidget>
+ </customwidgets>
  <resources/>
  <connections/>
 </ui>
diff --git a/src/icons.qrc b/src/icons.qrc
new file mode 100644 (file)
index 0000000..3579279
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+    <file>icons/favourite-on.png</file>
+    <file>icons/favourite-off.png</file>
+    <file>icons/alarm-on.png</file>
+    <file>icons/alarm-off.png</file>
+    <file>icons/expand.png</file>
+    <file>icons/collapse.png</file>
+</qresource>
+</RCC>
diff --git a/src/icons/alarm-off.png b/src/icons/alarm-off.png
new file mode 100644 (file)
index 0000000..acb7b5c
Binary files /dev/null and b/src/icons/alarm-off.png differ
diff --git a/src/icons/alarm-on.png b/src/icons/alarm-on.png
new file mode 100644 (file)
index 0000000..4ecff7b
Binary files /dev/null and b/src/icons/alarm-on.png differ
diff --git a/src/icons/collapse.png b/src/icons/collapse.png
new file mode 100644 (file)
index 0000000..b3a0825
Binary files /dev/null and b/src/icons/collapse.png differ
diff --git a/src/icons/expand.png b/src/icons/expand.png
new file mode 100644 (file)
index 0000000..4dfcdc6
Binary files /dev/null and b/src/icons/expand.png differ
diff --git a/src/icons/favourite-off.png b/src/icons/favourite-off.png
new file mode 100644 (file)
index 0000000..1b42daf
Binary files /dev/null and b/src/icons/favourite-off.png differ
diff --git a/src/icons/favourite-on.png b/src/icons/favourite-on.png
new file mode 100644 (file)
index 0000000..4b569ce
Binary files /dev/null and b/src/icons/favourite-on.png differ
diff --git a/src/model/delegate.cpp b/src/model/delegate.cpp
new file mode 100644 (file)
index 0000000..95ab7b1
--- /dev/null
@@ -0,0 +1,220 @@
+#include "delegate.h"
+#include "eventmodel.h"
+
+#include <QDebug>
+#include <QPainter>
+
+const int RADIUS = 10;
+const int SPACER = RADIUS;
+
+Delegate::Delegate(QTreeView *aParent)
+    : QItemDelegate(aParent)
+    , mViewPtr(aParent)
+{
+    mControls.clear();
+    defineControls();
+}
+
+Delegate::~Delegate()
+{
+    QListIterator<ControlId> i(mControls.keys());
+    while (i.hasNext())
+    {
+        delete mControls[i.next()]->image();
+    }
+}
+
+void Delegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+    if(!mViewPtr)
+        return;
+
+    painter->save();
+
+    QColor bkgrColor = Qt::cyan;
+    QPen borderPen(bkgrColor.darker());
+    if(hasParent(index))
+    {
+        if(isLast(index))
+        {
+            QLinearGradient lastGradient(option.rect.topLeft(), option.rect.bottomLeft());
+            lastGradient.setColorAt(0.0, Qt::white);
+            lastGradient.setColorAt(0.5, bkgrColor);
+            lastGradient.setColorAt(1.0, Qt::white);
+
+            QPainterPath endPath;
+            endPath.moveTo(option.rect.topLeft());
+            endPath.lineTo(option.rect.bottomLeft()-QPoint(0, RADIUS));
+            endPath.arcTo(option.rect.left(), option.rect.bottom()-2*RADIUS, 2*RADIUS, 2*RADIUS, 180, 90);
+            endPath.lineTo(option.rect.bottomRight()-QPoint(RADIUS, 0));
+            endPath.arcTo(option.rect.right()-2*RADIUS, option.rect.bottom()-2*RADIUS, 2*RADIUS, 2*RADIUS, 270, 90);
+            endPath.lineTo(option.rect.topRight());
+
+            //painter->setBrush( bkgrColor );
+            painter->setBrush(lastGradient);
+            painter->setPen(borderPen);
+            painter->drawPath(endPath);
+
+            painter->setFont(option.font);
+        }
+        else // middle elements
+        {
+
+            QLinearGradient middleGradient(option.rect.topLeft(), option.rect.bottomLeft());
+            middleGradient.setColorAt(0.0, Qt::white);
+            middleGradient.setColorAt(0.25, bkgrColor);
+            middleGradient.setColorAt(0.5, Qt::white);
+            middleGradient.setColorAt(0.75, bkgrColor);
+            middleGradient.setColorAt(1.0, Qt::white);
+
+            //painter->setBrush( bkgrColor );
+            painter->setBrush(middleGradient);
+            painter->setPen(Qt::NoPen);
+            painter->drawRect(option.rect);
+
+            painter->setPen(borderPen);
+            // vertical lines
+            painter->drawLine(option.rect.topLeft(), option.rect.bottomLeft());
+            painter->drawLine(option.rect.topRight(), option.rect.bottomRight());
+            // horizontal lines
+            painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
+
+            painter->setFont(option.font);
+        }
+
+        // draw Controls
+        painter->drawImage(mControls[FavouriteControl]->drawPoint(option.rect),*mControls[FavouriteControl]->image());
+        painter->drawImage(mControls[AlarmControl]->drawPoint(option.rect),*mControls[AlarmControl]->image());
+    }
+    else // doesn't have parent - time-groups' elements (top items)
+    {
+        QLinearGradient titleGradient(option.rect.topLeft(), option.rect.topRight());
+        //titleGradient.setColorAt(0.0, Qt::white);
+        titleGradient.setColorAt(0.0, bkgrColor);
+        titleGradient.setColorAt(0.5, Qt::white);
+        titleGradient.setColorAt(1.0, bkgrColor);
+
+        QPainterPath titlePath;
+        if(isExpanded(index))
+        {
+            titlePath.moveTo(option.rect.bottomLeft());
+            titlePath.lineTo(option.rect.topLeft()+QPoint(0, RADIUS));
+            titlePath.arcTo(option.rect.left(), option.rect.top(), 2*RADIUS, 2*RADIUS, 180, -90);
+            titlePath.lineTo(option.rect.topRight()-QPoint(RADIUS, 0));
+            titlePath.arcTo(option.rect.right()-2*RADIUS, option.rect.top(), 2*RADIUS, 2*RADIUS, 90, -90);
+            titlePath.lineTo(option.rect.bottomRight());
+            titlePath.closeSubpath();
+        }
+        else
+        {
+            titlePath.lineTo(option.rect.topLeft()+QPoint(0, RADIUS));
+            titlePath.arcTo(option.rect.left(), option.rect.top(), 2*RADIUS, 2*RADIUS, 180, -90);
+            titlePath.lineTo(option.rect.topRight()-QPoint(RADIUS, 0));
+            titlePath.arcTo(option.rect.right()-2*RADIUS, option.rect.top(), 2*RADIUS, 2*RADIUS, 90, -90);
+            titlePath.lineTo(option.rect.bottomRight()-QPoint(0, RADIUS));
+            titlePath.arcTo(option.rect.right()-2*RADIUS, option.rect.bottom()-2*RADIUS, 2*RADIUS, 2*RADIUS, 0, -90);
+            titlePath.lineTo(option.rect.bottomLeft()+QPoint(RADIUS, 0));
+            titlePath.arcTo(option.rect.left(), option.rect.bottom()-2*RADIUS, 2*RADIUS, 2*RADIUS, 270, -90);      
+            titlePath.closeSubpath();
+        }
+
+        painter->setBrush(titleGradient);
+        painter->setPen(borderPen);
+        painter->drawPath(titlePath);
+
+        QFont font = option.font;
+        font.setBold(true);
+        painter->setFont(font);
+    }
+
+    //// HIGHLIGHTING SELECTED ITEM
+    //if (option.state & QStyle::State_Selected)
+        //painter->fillRect(option.rect, option.palette.highlight());
+
+    // draw title
+    QPointF titlePointF(option.rect.x(),option.rect.y()+option.rect.height()-10);
+    QString text = qVariantValue<QString>(index.data());
+    painter->drawText(titlePointF,text);
+
+    painter->restore();
+}
+
+QSize Delegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+    Q_UNUSED(option)
+
+    if (index.internalId() == 0) // time group
+    {
+        return QSize(30,30);
+    }
+    else // event
+    {
+        return QSize(100,100);
+    }
+}
+
+bool Delegate::hasParent( const QModelIndex &index ) const
+{
+    if( index.parent().isValid() )
+        return true;
+    else
+        return false;
+}
+  
+bool Delegate::isLast( const QModelIndex &index ) const
+{
+    if(!hasParent(index))
+        return false; // what should be returned here?
+
+    if(index.row() >= (index.model()->rowCount(index.parent())-1))
+        return true;
+    else
+        return false;
+}
+
+bool Delegate::isExpanded( const QModelIndex &index ) const
+{
+    if( !mViewPtr )
+        return false;
+    else
+        return mViewPtr->isExpanded( index );
+}
+
+Delegate::ControlId Delegate::whichControlClicked(const QModelIndex &aIndex, const QPoint &aPoint) const
+{
+    if(!hasParent(aIndex)) // time-group item (root item)
+        return ControlNone;
+
+    QListIterator<ControlId> i(mControls.keys());
+    while (i.hasNext())
+    {
+        ControlId id = i.next();
+        if(mControls[id]->drawRect(static_cast<QTreeView*>(parent())->visualRect(aIndex)).contains(aPoint))
+            return id;
+    }
+
+    return ControlNone;
+}
+
+void Delegate::defineControls()
+{
+    Control *control;
+    // FAVOURITE ICON
+    control = new Control(FavouriteControl,QString(":icons/favourite-on.png"));
+    control->setDrawPoint(QPoint(-control->image()->width()-SPACER,SPACER));
+    mControls.insert(FavouriteControl,control);
+
+    // ALARM ICON
+    control = new Control(AlarmControl,QString(":icons/alarm-on.png"));
+    control->setDrawPoint(QPoint(-mControls[FavouriteControl]->image()->width()-control->image()->width()-2*SPACER,SPACER));
+    mControls.insert(AlarmControl,control);
+}
+
+bool Delegate::isPointFromRect(const QPoint &aPoint, const QRect &aRect) const
+{
+    if( (aPoint.x()>=aRect.left() && aPoint.x()<=aRect.right()) && (aPoint.y()>=aRect.top() && aPoint.y()<=aRect.bottom()) )
+        return true;
+
+    return false;
+}
+
diff --git a/src/model/delegate.h b/src/model/delegate.h
new file mode 100644 (file)
index 0000000..657994d
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef DELEGATE_H
+#define DELEGATE_H
+
+#include <QItemDelegate>
+#include <QTreeView>
+#include <QPointer>
+
+class Delegate : public QItemDelegate
+{
+    Q_OBJECT
+
+    public:
+
+        enum ControlId
+        {
+            ControlNone = 0,
+            FavouriteControl,
+            AlarmControl
+        };
+
+        class Control
+        {
+            public:
+                Control(ControlId aControlId, const QString &aImageName)
+                    : mId(aControlId)
+                    , mImage(new QImage(aImageName))
+                    , mDrawPoint(QPoint(0,0))
+                { }
+                inline QImage *image() const { return mImage; }
+                inline void setDrawPoint(const QPoint &aPoint) { mDrawPoint = aPoint; }
+                inline QPoint drawPoint(const QRect &aRect) const // for painter to draw Control
+                {
+                    return QPoint(aRect.x()+aRect.width(),aRect.y()) + mDrawPoint;
+                }
+                inline QRect drawRect(const QRect &aRect) const // helper for determining if Control was clicked
+                {
+                    return QRect(drawPoint(aRect), drawPoint(aRect)+QPoint(mImage->size().width(),mImage->size().height()));
+                }
+            private:
+                ControlId mId;
+                QImage *mImage;
+                QPoint mDrawPoint; // relative 'start-drawing' position (may hold negative values)
+        };
+
+        Delegate(QTreeView *aParent); // the delegate 'owner' has to be specified in the constructor - it's used to obtain visualRect of selected item/index
+        ~Delegate();
+
+        void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+        QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
+        //
+        Delegate::ControlId whichControlClicked(const QModelIndex &aIndex, const QPoint &aPoint) const;
+        bool isPointFromRect(const QPoint &aPoint, const QRect &aRect) const;
+
+    private:
+        bool hasParent( const QModelIndex &index ) const;
+        bool isLast( const QModelIndex &index ) const;
+        bool isExpanded( const QModelIndex &index ) const;
+        void defineControls();
+
+    private:
+        QPointer<QTreeView> mViewPtr;
+        QMap<ControlId,Control*> mControls;
+};
+
+#endif /* DELEGATE_H */
+
index c8e0b62..1a80365 100644 (file)
@@ -12,8 +12,12 @@ TARGETDEPS += $$DESTDIR/liborm.a
 
 HEADERS += \
     event.h \
-    eventmodel.h
+    delegate.h \
+    eventmodel.h \
+    treeview.h
 SOURCES += \
     event.cpp \
-    eventmodel.cpp
+    delegate.cpp \
+    eventmodel.cpp \
+    treeview.cpp
 
diff --git a/src/model/treeview.cpp b/src/model/treeview.cpp
new file mode 100644 (file)
index 0000000..80fbd28
--- /dev/null
@@ -0,0 +1,52 @@
+#include <QMouseEvent>
+
+#include "treeview.h"
+#include "delegate.h"
+
+#include <QDebug>
+
+TreeView::TreeView(QWidget *aParent)
+    : QTreeView(aParent)
+{
+}
+
+void TreeView::mouseReleaseEvent(QMouseEvent *aEvent)
+{
+    QModelIndex index = currentIndex();
+    QPoint point = aEvent->pos();
+
+    testForControlClicked(index,point);
+
+    // pass the event to the Base class, so item clicks/events are handled correctly
+    QTreeView::mouseReleaseEvent(aEvent);
+}
+
+void TreeView::testForControlClicked(const QModelIndex &aIndex, const QPoint &aPoint) 
+{
+    if(!aIndex.isValid())
+        return;
+
+    QRect rect = visualRect(aIndex); // visual QRect of selected/clicked item in the list
+    Delegate *delegate = static_cast<Delegate*>(itemDelegate(aIndex));
+    switch(delegate->whichControlClicked(aIndex,aPoint))
+    {
+        case Delegate::FavouriteControl:
+            {
+                // handle Favourite Control clicked
+                qDebug() << "FAVOURITE CLICKED: " << qVariantValue<QString>(aIndex.data());
+            }
+            break;
+        case Delegate::AlarmControl:
+            {
+                // handle Alarm Control clicked
+                qDebug() << "ALARM CLICKED: " << qVariantValue<QString>(aIndex.data());
+            }
+            break;
+        case Delegate::ControlNone:
+        default:
+            {
+                // item was clicked, but not a control
+            }
+    };
+}
+
diff --git a/src/model/treeview.h b/src/model/treeview.h
new file mode 100644 (file)
index 0000000..2a81907
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef TREEVIEW_H
+#define TREEVIEW_H
+
+#include <QTreeView>
+
+class TreeView : public QTreeView
+{
+public:
+    TreeView(QWidget *aParent = NULL);
+    ~TreeView() {}
+private:
+    void mouseReleaseEvent(QMouseEvent *aEvent);
+    void testForControlClicked(const QModelIndex &aIndex, const QPoint &aPoint);
+};
+
+#endif /* TREEVIEW_H */
+