[PATCH] Add dive list view to main window

Lubomir I. Ivanov neolit123 at gmail.com
Thu Apr 11 09:27:13 PDT 2013


On 11 April 2013 19:06,  <amit.k.chaudhuri at gmail.com> wrote:
> From: Amit Chaudhuri <amit.k.chaudhuri at gmail.com>
>
> Add files for dive list model/view implementation. Replace TableView
> with the custom list view.  Amendments to makefile to match.
>
> Note: we don't yet handle trips and may want to add additional columns
> to describe the dive.
>
> A single, dummy dive is added to show how this works (get root; item is
> child of root). Purely to illustrate - needs proper integration etc.
>
> Signed-off-by: Amit Chaudhuri <amit.k.chaudhuri at gmail.com>
> ---
>  Makefile                |    2 +-
>  qt-ui/divelistview.cpp  |    5 ++
>  qt-ui/divelistview.h    |   19 +++++++
>  qt-ui/divetripmodel.cpp |  139 +++++++++++++++++++++++++++++++++++++++++++++++
>  qt-ui/divetripmodel.h   |   80 +++++++++++++++++++++++++++
>  qt-ui/mainwindow.cpp    |    9 +++
>  qt-ui/mainwindow.h      |    2 +
>  qt-ui/mainwindow.ui     |    7 ++-
>  8 files changed, 261 insertions(+), 2 deletions(-)
>  create mode 100644 qt-ui/divelistview.cpp
>  create mode 100644 qt-ui/divelistview.h
>  create mode 100644 qt-ui/divetripmodel.cpp
>  create mode 100644 qt-ui/divetripmodel.h
>
> diff --git a/Makefile b/Makefile
> index c89816d..9e8e69b 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -183,7 +183,7 @@ MSGLANGS=$(notdir $(wildcard po/*.po))
>  MSGOBJS=$(addprefix share/locale/,$(MSGLANGS:.po=.UTF-8/LC_MESSAGES/subsurface.mo))
>
>
> -QTOBJS = qt-ui/maintab.o  qt-ui/mainwindow.o  qt-ui/plotareascene.o
> +QTOBJS = qt-ui/maintab.o  qt-ui/mainwindow.o  qt-ui/plotareascene.o qt-ui/divelistview.o qt-ui/divetripmodel.o
>
>  OBJS = main.o dive.o time.o profile.o info.o equipment.o divelist.o divelist-gtk.o deco.o \
>         planner.o planner-gtk.o \
> diff --git a/qt-ui/divelistview.cpp b/qt-ui/divelistview.cpp
> new file mode 100644
> index 0000000..eafbdd3
> --- /dev/null
> +++ b/qt-ui/divelistview.cpp
> @@ -0,0 +1,5 @@
> +#include "divelistview.h"
> +
> +DiveListView::DiveListView(QWidget *parent) : QTreeView(parent)
> +{
> +}
> diff --git a/qt-ui/divelistview.h b/qt-ui/divelistview.h
> new file mode 100644
> index 0000000..75ad2e0
> --- /dev/null
> +++ b/qt-ui/divelistview.h
> @@ -0,0 +1,19 @@
> +#ifndef DIVELISTVIEW_H
> +#define DIVELISTVIEW_H
> +
> +/*! A view subclass for use with dives
> +
> +  Note: calling this a list view might be misleading?
> +
> +
> +*/
> +
> +#include <QTreeView>
> +
> +class DiveListView : public QTreeView
> +{
> +public:
> +    DiveListView(QWidget * parent = 0);
> +};
> +
> +#endif // DIVELISTVIEW_H
> diff --git a/qt-ui/divetripmodel.cpp b/qt-ui/divetripmodel.cpp
> new file mode 100644
> index 0000000..6ccf31b
> --- /dev/null
> +++ b/qt-ui/divetripmodel.cpp
> @@ -0,0 +1,139 @@
> +#include "divetripmodel.h"
> +
> +
> +DiveItem::DiveItem(int num, QString dt, float dur, float dep, QString loc, DiveItem *p):
> +    m_number(num), m_dateTime(dt), m_duration(dur), m_depth(dep), m_location(loc), m_parent(p)
> +{
> +    if (m_parent)
> +        m_parent->addChild(this);
> +}
> +
> +
> +DiveTripModel::DiveTripModel(const QString &filename, QObject *parent) : QAbstractItemModel(parent), m_Filename(filename)
> +{
> +    m_RootItem = new DiveItem;
> +}
> +
> +
> +Qt::ItemFlags DiveTripModel::flags(const QModelIndex &index) const
> +{
> +    Qt::ItemFlags diveFlags = QAbstractItemModel::flags(index);
> +    if(index.isValid()){
> +        diveFlags |= Qt::ItemIsSelectable|Qt::ItemIsEnabled;
> +    }
> +    return diveFlags;
> +}
> +
> +
> +QVariant DiveTripModel::data(const QModelIndex &index, int role) const
> +{
> +    if (!index.isValid())
> +        return QVariant();
> +
> +    if (role != Qt::DisplayRole)
> +        return QVariant();
> +
> +    DiveItem *item = static_cast<DiveItem*>(index.internalPointer());
> +
> +    QVariant retVal;
> +    switch( index.column())
> +    {
> +    case DIVE_NUMBER:
> +        retVal = QVariant(item->diveNumber());
> +        break;
> +    case DIVE_DATE_TIME:
> +        retVal = QVariant(item->dateTime());
> +        break;
> +    case DIVE_DURATION:
> +        retVal = QVariant(item->duration());
> +        break;
> +    case DIVE_DEPTH:
> +        retVal = QVariant(item->depth());
> +        break;
> +    case DIVE_LOCATION:
> +        retVal = QVariant(item->location());
> +        break;
> +    default:
> +        return QVariant();
> +    };
> +    return retVal;
> +}
> +
> +
> +QVariant DiveTripModel::headerData(int section, Qt::Orientation orientation, int role) const
> +{
> +    if(orientation == Qt::Horizontal && role == Qt::DisplayRole){
> +        if( section == DIVE_NUMBER){
> +            return tr("Dive number");
> +        } else if (section == DIVE_DATE_TIME) {
> +            return tr("Date");
> +        } else if (section == DIVE_DURATION) {
> +            return tr("Duration");
> +        } else if (section == DIVE_DEPTH) {
> +            return tr("Depth");
> +        } else if (section == DIVE_LOCATION){
> +            return tr("Location");
> +        }
> +    }
> +    return QVariant();
> +}
> +
> +int DiveTripModel::rowCount(const QModelIndex &parent) const
> +{
> +    /* only allow kids in column 0 */
> +    if (parent.isValid() && parent.column() > 0){
> +        return 0;
> +    }
> +    DiveItem * item = itemForIndex(parent);
> +    return item ? item->childCount() : 0;
> +}
> +
> +
> +
> +int DiveTripModel::columnCount(const QModelIndex &parent) const
> +{
> +    return parent.isValid() && parent.column() != 0 ? 0 : COLUMNS;
> +
> +}
> +
> +
> +QModelIndex DiveTripModel::index(int row, int column, const QModelIndex &parent) const
> +{
> +
> +    if (!m_RootItem || row < 0 || column < 0 || column >= COLUMNS
> +            || ( parent.isValid() && parent.column() != 0) )
> +        return QModelIndex();
> +
> +    DiveItem *parentItem = itemForIndex(parent);
> +    Q_ASSERT(parentItem);
> +    if ( DiveItem *item = parentItem->childAt(row) ){
> +        return createIndex(row, column, item);
> +    }
> +    return QModelIndex();
> +
> +}
> +
> +
> +QModelIndex DiveTripModel::parent(const QModelIndex &childIndex) const
> +{
> +    if (!childIndex.isValid())
> +        return QModelIndex();
> +
> +    DiveItem *child = static_cast<DiveItem*>(childIndex.internalPointer());
> +    DiveItem *parent = child->parent();
> +
> +    if (parent == m_RootItem)
> +        return QModelIndex();
> +
> +    return createIndex(parent->rowOfChild(child), 0, parent);
> +}
> +
> +
> +DiveItem * DiveTripModel::itemForIndex(const QModelIndex &index) const
> +{
> +    if (index.isValid()) {
> +        DiveItem * item = static_cast<DiveItem*>(index.internalPointer());
> +        return item;
> +    }
> +    return m_RootItem;
> +}
> diff --git a/qt-ui/divetripmodel.h b/qt-ui/divetripmodel.h
> new file mode 100644
> index 0000000..b80591b
> --- /dev/null
> +++ b/qt-ui/divetripmodel.h
> @@ -0,0 +1,80 @@
> +#ifndef DIVETRIPMODEL_H
> +#define DIVETRIPMODEL_H
> +
> +#include <QAbstractItemModel>
> +
> +/*! A DiveItem for use with a DiveTripModel
> + *
> + * A simple class which wraps basic stats for a dive (e.g. duration, depth) and
> + * tidies up after it's children. This is done manually as we don't inherit from
> + * QObject.
> + *
> +*/
> +class DiveItem
> +{
> +public:
> +    explicit DiveItem(): m_number(0), m_dateTime(QString()), m_duration(0.0), m_depth(0.0), m_location(QString()) {m_parent = 0;}
> +    explicit DiveItem(int num, QString dt, float, float, QString loc, DiveItem *parent = 0);
> +    ~DiveItem() { qDeleteAll(m_children); }
> +
> +    int diveNumber() const {return m_number;}
> +    QString dateTime() const {return m_dateTime;}
> +    float duration() const {return m_duration;}
> +    float depth() const {return m_depth;}
> +    QString location() const {return m_location;}
> +
> +    DiveItem *parent() const {return m_parent;}
> +    DiveItem *childAt(int row) const {return m_children.value(row);}
> +    int rowOfChild(DiveItem *child) const {return m_children.indexOf(child);}
> +    int childCount() const {return m_children.count();}
> +    bool hasChildren() const {return !m_children.isEmpty();}
> +    QList<DiveItem *> children() const {return m_children;}
> +    void addChild(DiveItem*item) {item->m_parent = this; m_children << item;} /* parent = self */
> +
> +
> +private:
> +
> +    int m_number;
> +    QString m_dateTime;
> +    float m_duration;
> +    float m_depth;
> +    QString m_location;
> +
> +    DiveItem *m_parent;
> +    QList <DiveItem*> m_children;
> +
> +};
> +
> +
> +enum Column {DIVE_NUMBER, DIVE_DATE_TIME, DIVE_DURATION, DIVE_DEPTH, DIVE_LOCATION, COLUMNS};
> +
> +
> +/*! An AbstractItemModel for recording dive trip information such as a list of dives.
> + *
> +*/
> +class DiveTripModel : public QAbstractItemModel
> +{
> +public:
> +
> +    DiveTripModel(const QString &filename, QObject *parent = 0);
> +
> +    Qt::ItemFlags flags(const QModelIndex &index) const;
> +    QVariant data(const QModelIndex &index, int role) const;
> +    QVariant headerData(int section, Qt::Orientation orientation, int role) const;
> +    int rowCount(const QModelIndex &parent) const;
> +
> +    int columnCount(const QModelIndex &parent = QModelIndex()) const;
> +    virtual QModelIndex index(int row, int column,
> +                              const QModelIndex &parent = QModelIndex()) const;
> +    virtual QModelIndex parent(const QModelIndex &child) const;
> +
> +    DiveItem * itemForIndex(const QModelIndex &) const;
> +
> +private:
> +
> +    DiveItem * m_RootItem;
> +    QString m_Filename;
> +
> +};
> +
> +#endif // DIVETRIPMODEL_H
> diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp
> index 56c3901..f41bb0d 100644
> --- a/qt-ui/mainwindow.cpp
> +++ b/qt-ui/mainwindow.cpp
> @@ -4,9 +4,18 @@
>  #include <QVBoxLayout>
>  #include <QtDebug>
>
> +#include "divelistview.h"
> +#include "divetripmodel.h"
> +
>  MainWindow::MainWindow() : ui(new Ui::MainWindow())
>  {
>         ui->setupUi(this);
> +
> +       mModel = new DiveTripModel("",this);
> +       if(mModel){
> +               ui->ListWidget->setModel(mModel);
> +       }
> +
>  }
>
>  void MainWindow::on_actionNew_triggered()
> diff --git a/qt-ui/mainwindow.h b/qt-ui/mainwindow.h
> index 51b428c..a6894ad 100644
> --- a/qt-ui/mainwindow.h
> +++ b/qt-ui/mainwindow.h
> @@ -3,6 +3,7 @@
>
>  #include <QMainWindow>
>
> +class DiveTripModel;
>
>  namespace Ui
>  {
> @@ -60,6 +61,7 @@ private Q_SLOTS:
>
>  private:
>         Ui::MainWindow *ui;
> +       DiveTripModel *mModel;
>  };
>
>  #endif
> diff --git a/qt-ui/mainwindow.ui b/qt-ui/mainwindow.ui
> index 65b18c7..6ece13f 100644
> --- a/qt-ui/mainwindow.ui
> +++ b/qt-ui/mainwindow.ui
> @@ -27,7 +27,7 @@
>         <widget class="MainTab" name="InfoWidget" native="true"/>
>         <widget class="QGraphicsView" name="ProfileWidget"/>
>        </widget>
> -      <widget class="QTableView" name="ListWidget"/>
> +      <widget class="DiveListView" name="ListWidget"/>
>       </widget>
>      </item>
>      <item>
> @@ -291,6 +291,11 @@
>     <header>maintab.h</header>
>     <container>1</container>
>    </customwidget>
> +  <customwidget>
> +   <class>DiveListView</class>
> +   <extends>QTreeView</extends>
> +   <header>divelistview.h</header>
> +  </customwidget>
>   </customwidgets>
>   <resources/>
>   <connections/>
> --


hello amit, and thank you for this implementation and pushing the Qt port.

sorry to be too observant, but you could you revise usage of the
following (coding style semantics follow):
+        if( section == DIVE_NUMBER){

and similar. spacing should be:
+        if (section == DIVE_NUMBER) {


from:
+    DiveItem * itemForIndex(const QModelIndex &) const;
to:
+    DiveItem *itemForIndex(const QModelIndex &) const;

perhaps sticking the * to function or variable name for consistency.

something else is usage of C++ pointers:
const QString &filename
i would use C pointers here. other's opinions?

> +DiveItem::DiveItem(int num, QString dt, float dur, float dep, QString loc, DiveItem *p):
> +    m_number(num), m_dateTime(dt), m_duration(dur), m_depth(dep), m_location(loc), m_parent(p)
in another thread i pointed out that m_name or m_Name for members is
not preferable over mName. perhaps others could comment here as well.

on this:
+        DiveItem * item = static_cast<DiveItem*>(index.internalPointer());
not sure on the final word on C++ casts as well, but at least we can
try keeping the * with the following spacing:
+        DiveItem *item = static_cast<DiveItem *>(index.internalPointer());

pm this:
+    switch( index.column())
+    {
we should rather have it as:
+    switch(index.column()) {


on this:
> +    DiveItem *parent() const {return m_parent;}
i think there should be spaces inside {}
> +    DiveItem *parent() const { return m_parent; }


i know that this is very annoying, but if we don't have a coding
style, essentially more patches have to contribute later to SNR
statistics until the codebase its cleaned up.

lubomir
--


More information about the subsurface mailing list