-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathqtwidgetlistview.cpp
150 lines (124 loc) · 5.34 KB
/
qtwidgetlistview.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
* Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
* Copyright (C) 2010 Robin Burchell <[email protected]>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <QStyledItemDelegate>
#include <QEvent>
#include "qtwidgetlistview.h"
#include "qtmodelwidget.h"
class QtWidgetListDelegate : public QStyledItemDelegate
{
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
// Remove selected state
QStyleOptionViewItemV4 opt(option);
initStyleOption(&opt, index);
opt.state &= ~QStyle::State_Selected;
QStyledItemDelegate::paint(painter, opt, index);
}
};
QtWidgetListView::QtWidgetListView(QWidget *parent) :
QListWidget(parent),
m_metaObject(0)
{
setItemDelegate(new QtWidgetListDelegate);
}
void QtWidgetListView::setMetaObject(const QMetaObject *metaObject)
{
m_metaObject = metaObject;
}
void QtWidgetListView::setModel(QAbstractItemModel *model)
{
// TODO: disconnect signals from old model
// connect signals to new model
connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(onDataChanged(QModelIndex,QModelIndex)));
connect(model, SIGNAL(layoutChanged()), this, SLOT(populateModel())); // cheat: just redo the whole view if layout changes
connect(model, SIGNAL(modelReset()), this, SLOT(populateModel())); // not sure precisely what this is supposed to do; so we cheat
connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(populateModel())); // this won't perform great. we should do it properly.
connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(populateModel())); // this won't perform great. we should do it properly.
m_model = model;
populateModel();
}
void QtWidgetListView::populateModel()
{
// clear old widget list
while (!m_widgets.empty())
m_widgets.takeFirst()->deleteLater();
// remove all rows from the view
clear();
for (int i = 0; i != m_model->rowCount(); ++i) {
QtModelWidget *widget = static_cast<QtModelWidget *>(m_metaObject->newInstance
(
Q_ARG(QAbstractItemModel*, m_model),
Q_ARG(QModelIndex, m_model->index(i, 0))
));
// if this asserts, you either:
// 1) have the wrong constructor arguments
// 2) forgot to mark it Q_INVOKABLE.
Q_ASSERT(widget);
// parenting for layout changes
widget->setParent(this);
m_widgets.append(widget);
QListWidgetItem *item = new QListWidgetItem(this);
insertItem(i, item);
setItemWidget(item, widget);
}
// Populate the UI for the first time
if (m_widgets.count())
onDataChanged(m_model->index(0, 0), m_model->index(m_widgets.count() - 1, 0));
}
void QtWidgetListView::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
// send notifications to all the widgets that their data changed
int bottomRow = bottomRight.row() + 1;
for (int i = topLeft.row(); i != bottomRow; ++i) {
QtModelWidget *widget = m_widgets.at(i);
// tell it its data changed so it can reposition UI
widget->dataChanged();
// get the new sizehint from it
QSize size = widget->sizeHint();
// cap at our own width
if (size.width() > viewport()->geometry().width())
size.setWidth(viewport()->geometry().width());
// change sizehint on the item.
item(i)->setSizeHint(size);
}
}
bool QtWidgetListView::event(QEvent *event)
{
if (event->type() == QEvent::LayoutRequest) {
// one of our children has changed size.
// as a result, we need to force relayout of everything.
//
// NOTE: be careful what you do here. you can cause a (sort of) infinite loop
// if you do anything which results in changed data on the widget.
// this is why it specifically *does not* call onDataChanged().
if (m_widgets.count()) {
// iterate over all widgets
for (int i = 0; i != m_widgets.count(); ++i) {
// fetch sizehint
QSize size = m_widgets.at(i)->sizeHint();
// cap to avoid it spilling out of the listview
if (size.width() > viewport()->geometry().width())
size.setWidth(viewport()->geometry().width());
// resize the item row
item(i)->setSizeHint(size);
}
}
}
// and give QListView the chance to interpret the event as needed.
return QListView::event(event);
}