~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/gui/itemviews/qstandarditemmodel.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
 
4
**
 
5
** This file is part of the item views module of the Qt Toolkit.
 
6
**
 
7
** This file may be distributed under the terms of the Q Public License
 
8
** as defined by Trolltech AS of Norway and appearing in the file
 
9
** LICENSE.QPL included in the packaging of this file.
 
10
**
 
11
** This file may be distributed and/or modified under the terms of the
 
12
** GNU General Public License version 2 as published by the Free Software
 
13
** Foundation and appearing in the file LICENSE.GPL included in the
 
14
** packaging of this file.
 
15
**
 
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
 
17
**   information about Qt Commercial License Agreements.
 
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
 
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
 
20
**
 
21
** Contact info@trolltech.com if any conditions of this licensing are
 
22
** not clear to you.
 
23
**
 
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
26
**
 
27
****************************************************************************/
 
28
 
 
29
#include "qstandarditemmodel.h"
 
30
#include <qpair.h>
 
31
#include <qvariant.h>
 
32
#include <qvector.h>
 
33
 
 
34
#include <private/qstandarditemmodel_p.h>
 
35
#include <qdebug.h>
 
36
 
 
37
/*!
 
38
    \class QStandardItemModel
 
39
    \brief The QStandardItemModel class provides a generic model for storing custom data.
 
40
 
 
41
    QStandardItemModel provides a model that that can be used as a repository
 
42
    for standard Qt data types. Data is written to the model and read back using
 
43
    the standard QAbstractItemModel interface. The way each item of information
 
44
    is referenced depends on how the data is inserted into the model.
 
45
 
 
46
    For performance and flexibility, you may want to subclass QAbstractItemModel
 
47
    to provide support for different kinds of repositories. For example, the
 
48
    QDirModel provides a model interface to the underlying file system, and does
 
49
    not actually store file information internally.
 
50
 
 
51
    \sa \link model-view-programming.html Model/View Programming\endlink QAbstractItemModel
 
52
 
 
53
*/
 
54
 
 
55
/*!
 
56
    Creates an empty model that contains no rows or columns with the given
 
57
    \a parent.
 
58
*/
 
59
QStandardItemModel::QStandardItemModel(QObject *parent)
 
60
    : QAbstractItemModel(*new QStandardItemModelPrivate(0, 0), parent)
 
61
{
 
62
    // nothing
 
63
}
 
64
 
 
65
/*!
 
66
    Creates a model with \a rows number of rows and \a columns number of columns.
 
67
*/
 
68
QStandardItemModel::QStandardItemModel(int rows, int columns, QObject *parent)
 
69
    : QAbstractItemModel(*new QStandardItemModelPrivate(rows, columns), parent)
 
70
{
 
71
    // nothing
 
72
}
 
73
 
 
74
 
 
75
/*!
 
76
    Destroys the model.
 
77
*/
 
78
QStandardItemModel::~QStandardItemModel()
 
79
{
 
80
}
 
81
 
 
82
/*!
 
83
    Returns a model index for the given \a row, \a column, and \a parent.
 
84
*/
 
85
QModelIndex QStandardItemModel::index(int row, int column, const QModelIndex &parent) const
 
86
{
 
87
    Q_D(const QStandardItemModel);
 
88
    if (hasIndex(row, column, parent)) {
 
89
        if (parent.isValid()) {
 
90
            QStdModelRow *parentRow = d->containedRow(parent, false);
 
91
            return createIndex(row, column, parentRow);
 
92
        } else {
 
93
            return createIndex(row, column, 0);
 
94
        }
 
95
    }
 
96
    return QModelIndex();
 
97
}
 
98
 
 
99
/*!
 
100
    Returns a model index for the parent of the \a child item.
 
101
*/
 
102
QModelIndex QStandardItemModel::parent(const QModelIndex &child) const
 
103
{
 
104
    Q_D(const QStandardItemModel);
 
105
    if (child.isValid() && child.internalPointer()) {
 
106
        QStdModelRow *parentRow = static_cast<QStdModelRow*>(child.internalPointer());
 
107
        QStdModelRow *grandParentRow = parentRow ? parentRow->p : 0;
 
108
        QVector<QStdModelRow*> grandParentChildren = d->topLevelRows;
 
109
        if (grandParentRow)
 
110
            grandParentChildren = grandParentRow->childrenRows;
 
111
        // ### slow, use ptr trick
 
112
        int row = grandParentChildren.indexOf(parentRow);
 
113
        return createIndex(row, 0, grandParentRow);
 
114
    }
 
115
    return QModelIndex();
 
116
}
 
117
 
 
118
/*!
 
119
    Returns the number of rows in the model that contain items with the given
 
120
    \a parent.
 
121
 
 
122
*/
 
123
int QStandardItemModel::rowCount(const QModelIndex &parent) const
 
124
{
 
125
    Q_D(const QStandardItemModel);
 
126
    QStdModelRow *modelRow = d->containedRow(parent, true);
 
127
    if (modelRow)
 
128
        return modelRow->childrenRows.count();
 
129
 
 
130
    return d->topLevelRows.count();
 
131
}
 
132
 
 
133
/*!
 
134
    Returns the number of columns in the model that contain items with the given
 
135
    \a parent.
 
136
*/
 
137
int QStandardItemModel::columnCount(const QModelIndex &parent) const
 
138
{
 
139
    Q_D(const QStandardItemModel);
 
140
    QStdModelRow *modelRow = d->containedRow(parent, true);
 
141
    if (modelRow)
 
142
        return modelRow->childrenColumns;
 
143
 
 
144
    return d->topLevelColumns;
 
145
}
 
146
 
 
147
/*!
 
148
    Returns true if the \a parent model index has child items; otherwise returns
 
149
    false.
 
150
*/
 
151
bool QStandardItemModel::hasChildren(const QModelIndex &parent) const
 
152
{
 
153
    Q_D(const QStandardItemModel);
 
154
    if (parent.isValid()) {
 
155
        QStdModelRow *modelRow = d->containedRow(parent, true);
 
156
        if (modelRow)
 
157
            return modelRow->childrenRows.count() && modelRow->childrenColumns;
 
158
    } else {
 
159
        return !d->topLevelRows.isEmpty() && d->topLevelColumns;
 
160
    }
 
161
    return false;
 
162
}
 
163
 
 
164
/*!
 
165
    Returns the data for the given \a index and \a role.
 
166
*/
 
167
QVariant QStandardItemModel::data(const QModelIndex &index, int role) const
 
168
{
 
169
    Q_D(const QStandardItemModel);
 
170
    role = (role == Qt::EditRole ? Qt::DisplayRole : role);
 
171
    if (index.isValid()) {
 
172
        QStdModelRow *modelRow = d->containedRow(index, false);
 
173
        if (modelRow && modelRow->items.count() > index.column()) {
 
174
            QStdModelItem *item = modelRow->items.at(index.column());
 
175
            if (item)
 
176
                return item->value(role);
 
177
        }
 
178
    }
 
179
    return QVariant();
 
180
}
 
181
 
 
182
/*!
 
183
    Sets the data for the given \a index and \a role to the \a value specified.
 
184
*/
 
185
bool QStandardItemModel::setData(const QModelIndex &index, const QVariant &value, int role)
 
186
{
 
187
    Q_D(const QStandardItemModel);
 
188
    role = (role == Qt::EditRole ? Qt::DisplayRole : role);
 
189
    if (index.isValid()) {
 
190
        QStdModelRow *modelRow = d->containedRow(index, true);
 
191
        int count = modelRow->items.count();
 
192
        // make room for enough items
 
193
        if (count <= index.column())
 
194
            modelRow->items.insert(count, index.column() + 1 - count, 0);
 
195
        // make sure we have a QStdModelItem at the position
 
196
        if (!modelRow->items.at(index.column()))
 
197
            modelRow->items[index.column()] = new QStdModelItem();
 
198
        modelRow->items.at(index.column())->setValue(role, value);
 
199
        emit dataChanged(index, index);
 
200
        return true;
 
201
    }
 
202
    return false;
 
203
}
 
204
 
 
205
 
 
206
/*!
 
207
  \reimp
 
208
*/
 
209
QVariant QStandardItemModel::headerData(int section, Qt::Orientation orientation, int role) const
 
210
{
 
211
    Q_D(const QStandardItemModel);
 
212
    if (section < 0
 
213
        || (orientation == Qt::Horizontal && section >= columnCount())
 
214
        || (orientation == Qt::Vertical && section >= rowCount()))
 
215
        return QVariant();
 
216
 
 
217
    const QStdModelItem *headerItem = 0;
 
218
    const QVector<QStdModelItem*> &header = (orientation == Qt::Horizontal
 
219
                                             ? d->horizontalHeader : d->verticalHeader);
 
220
    role = (role == Qt::EditRole ? Qt::DisplayRole : role);
 
221
    if (header.size() > section)
 
222
        headerItem = header.at(section);
 
223
 
 
224
    if (headerItem)
 
225
        return headerItem->value(role);
 
226
 
 
227
    return QAbstractItemModel::headerData(section, orientation, role);
 
228
}
 
229
 
 
230
/*!
 
231
  \reimp
 
232
*/
 
233
bool QStandardItemModel::setHeaderData(int section, Qt::Orientation orientation,
 
234
                                       const QVariant &value, int role)
 
235
{
 
236
    Q_D(QStandardItemModel);
 
237
    if (section < 0
 
238
        || (orientation == Qt::Horizontal && section >= columnCount())
 
239
        || (orientation == Qt::Vertical && section >= rowCount()))
 
240
        return false;
 
241
 
 
242
    QStdModelItem *headerItem = 0;
 
243
    QVector<QStdModelItem*> &header = (orientation == Qt::Horizontal
 
244
                                       ? d->horizontalHeader : d->verticalHeader);
 
245
    role = (role == Qt::EditRole ? Qt::DisplayRole : role);
 
246
    if (header.size() <= section)
 
247
        header.resize(section + 1);
 
248
    headerItem = header[section];
 
249
    if (!headerItem) {
 
250
        headerItem = new QStdModelItem();
 
251
        header.replace(section, headerItem);
 
252
    }
 
253
 
 
254
    headerItem->setValue(role, value);
 
255
    emit  headerDataChanged(orientation, section, section);
 
256
    return true;
 
257
}
 
258
 
 
259
 
 
260
/*!
 
261
Inserts \a count rows into the model, creating new items as children of
 
262
the given \a parent. The new rows are inserted before the \a row specified.
 
263
 
 
264
If \a row is 0, the rows are prepended to any existing rows in the parent.
 
265
If \a row is rowCount(), the rows are appended to any existing rows in
 
266
the parent.
 
267
If \a parent has no children, a single column with \a count rows is inserted.
 
268
 
 
269
Returns true if the rows were successfully inserted; otherwise returns false.
 
270
*/
 
271
bool QStandardItemModel::insertRows(int row, int count, const QModelIndex &parent)
 
272
{
 
273
    Q_D(QStandardItemModel);
 
274
    if (count < 1)
 
275
        return false;
 
276
 
 
277
    QVector<QStdModelRow*> &rows = (parent.isValid()) ? d->containedRow(parent, true)->childrenRows
 
278
                               : d->topLevelRows;
 
279
 
 
280
    if (row < 0)
 
281
        row = 0;
 
282
    else if (row > rows.count())
 
283
        row = rows.count();
 
284
 
 
285
    if (!parent.isValid() && d->verticalHeader.size() > row)
 
286
        d->verticalHeader.insert(row, count, 0);
 
287
 
 
288
    beginInsertRows(parent, row, row + count - 1);
 
289
 
 
290
    rows.insert(row, count, 0);
 
291
 
 
292
    endInsertRows();
 
293
 
 
294
    return true;
 
295
}
 
296
 
 
297
/*!
 
298
    Inserts \a count columns into the model, creating new items as children of
 
299
    the given \a parent. The new columns are inserted before the \a column
 
300
    specified.
 
301
 
 
302
    If \a column is 0, the columns are prepended to any existing columns in the
 
303
    parent.
 
304
    If \a column is columnCount(), the columns are appended to any existing
 
305
    columns in the parent.
 
306
    If \a parent has no children, a single row with \a count columns is inserted.
 
307
 
 
308
    Returns true if the columns were successfully inserted; otherwise returns
 
309
    false.
 
310
*/
 
311
bool QStandardItemModel::insertColumns(int column, int count, const QModelIndex &parent)
 
312
{
 
313
    Q_D(QStandardItemModel);
 
314
    if (count < 1)
 
315
        return false;
 
316
 
 
317
    if (column < 0)
 
318
        column = 0;
 
319
    else if (column > columnCount(parent))
 
320
        column = columnCount(parent);
 
321
 
 
322
    beginInsertColumns(parent, column, column + count - 1);
 
323
 
 
324
    QVector<QStdModelRow*> *rows = &d->topLevelRows;
 
325
    // update the column counters
 
326
    if (parent.isValid()) {
 
327
        QStdModelRow *modelRow = d->containedRow(parent, true);
 
328
        modelRow->childrenColumns += count;
 
329
        rows = &modelRow->childrenRows;
 
330
    } else {
 
331
        d->topLevelColumns += count;
 
332
        if (d->horizontalHeader.size() > column)
 
333
            d->horizontalHeader.insert(column, count, 0);
 
334
    }
 
335
 
 
336
    // update any item vectors if needed
 
337
    for (int i=0; i<rows->count(); ++i) {
 
338
        QStdModelRow *modelRow = rows->at(i);
 
339
        // only insert if there is a QStdModelRow and QStdModelItems in it
 
340
        if (modelRow && modelRow->items.count()
 
341
              && modelRow->items.count() > column)
 
342
            modelRow->items.insert(column, count, 0);
 
343
    }
 
344
 
 
345
    endInsertColumns();
 
346
 
 
347
    return true;
 
348
}
 
349
 
 
350
/*!
 
351
    Removes \a count rows from the model, starting with the given
 
352
    \a row.
 
353
    The items removed are children of the item represented by the \a parent
 
354
    model index.
 
355
 
 
356
    Returns true if the rows were successfully removed; otherwise returns
 
357
    false.
 
358
*/
 
359
bool QStandardItemModel::removeRows(int row, int count, const QModelIndex &parent)
 
360
{
 
361
    Q_D(QStandardItemModel);
 
362
    if (count < 1 || row < 0 || (row + count) > rowCount(parent))
 
363
        return false;
 
364
 
 
365
    beginRemoveRows(parent, row, row + count - 1);
 
366
 
 
367
    QVector<QStdModelRow*> &rows = (parent.isValid()) ? d->containedRow(parent, true)->childrenRows
 
368
                               : d->topLevelRows;
 
369
 
 
370
    if (!parent.isValid() && d->verticalHeader.count() > row) {
 
371
        int headerCount = qMin(d->verticalHeader.count() - row, count);
 
372
        for (int i=row; i < (row+headerCount); ++i)
 
373
            delete d->verticalHeader.at(i);
 
374
        d->verticalHeader.remove(row, headerCount);
 
375
    }
 
376
 
 
377
    // delete QStdModelRows
 
378
    for (int i=row; i<(row+count); ++i)
 
379
        delete rows.at(i);
 
380
    // resize row vector
 
381
    rows.remove(row, count);
 
382
 
 
383
    endRemoveRows();
 
384
 
 
385
    return true;
 
386
}
 
387
 
 
388
/*!
 
389
    Removes \a count columns from the model, starting with the given
 
390
    \a column.
 
391
    The items removed are children of the item represented by the \a parent
 
392
    model index.
 
393
 
 
394
    Returns true if the columns were successfully removed; otherwise returns
 
395
    false.
 
396
*/
 
397
bool QStandardItemModel::removeColumns(int column, int count, const QModelIndex &parent)
 
398
{
 
399
    Q_D(QStandardItemModel);
 
400
    if (count < 1 || column < 0 || (column + count) > columnCount(parent))
 
401
        return false;
 
402
 
 
403
    beginRemoveColumns(parent, column, column + count - 1);
 
404
 
 
405
    QVector<QStdModelRow*> *rows = &d->topLevelRows;
 
406
    // update the column counters
 
407
    if (parent.isValid()) {
 
408
        QStdModelRow *modelRow = d->containedRow(parent, true);
 
409
        modelRow->childrenColumns -= count;
 
410
        rows = &modelRow->childrenRows;
 
411
    } else {
 
412
        d->topLevelColumns -= count;
 
413
        if (d->horizontalHeader.count() > column) {
 
414
            int headerCount = qMin(d->horizontalHeader.size() - column, count);
 
415
            for (int i=column; i < (column+headerCount); ++i)
 
416
                delete d->horizontalHeader.at(i);
 
417
            d->horizontalHeader.remove(column, headerCount);
 
418
        }
 
419
    }
 
420
 
 
421
    // iterate over all child rows and remove if needed
 
422
    for (int i=0; i<rows->count(); ++i) {
 
423
        QStdModelRow *modelRow = rows->at(i);
 
424
        if (modelRow && column < modelRow->items.count()) {
 
425
            // delete the QStdModelItem if any
 
426
            for (int j=column; j<(column+count) && j<modelRow->items.count(); ++j)
 
427
                delete modelRow->items.at(j);
 
428
            // resize item vector
 
429
            modelRow->items.remove(column, qMin(count, modelRow->items.count() - column));
 
430
        }
 
431
    }
 
432
 
 
433
    endRemoveColumns();
 
434
 
 
435
    return true;
 
436
}
 
437
 
 
438
/*!
 
439
    Returns the item flags for the given \a index.
 
440
 
 
441
    This model returns returns a combination of flags that
 
442
    enables the item (Qt::ItemIsEnabled), allows it to be
 
443
    selected (Qt::ItemIsSelectable) and edited (Qt::ItemIsEditable).
 
444
*/
 
445
Qt::ItemFlags QStandardItemModel::flags(const QModelIndex &index) const
 
446
{
 
447
    return QAbstractItemModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
 
448
}
 
449
 
 
450
/*!
 
451
    Clears the model, removing all items.
 
452
*/
 
453
void QStandardItemModel::clear()
 
454
{
 
455
    Q_D(QStandardItemModel);
 
456
 
 
457
    d->clear();
 
458
    reset();
 
459
}
 
460
 
 
461
/*!
 
462
    \internal
 
463
*/
 
464
QStandardItemModelPrivate::~QStandardItemModelPrivate()
 
465
{
 
466
    clear();
 
467
}
 
468
 
 
469
/*!
 
470
    \internal
 
471
*/
 
472
QStdModelRow *QStandardItemModelPrivate::containedRow(const QModelIndex &index,
 
473
                                                  bool createIfMissing) const
 
474
{
 
475
    if (!index.isValid())
 
476
        return 0;
 
477
 
 
478
    QStdModelRow *parentRow = static_cast<QStdModelRow*>(index.internalPointer());
 
479
    QVector<QStdModelRow*> *rowList = const_cast<QVector<QStdModelRow*> *>(&topLevelRows);
 
480
    if (parentRow) {
 
481
        rowList = const_cast<QVector<QStdModelRow*> *>(&parentRow->childrenRows);
 
482
    }
 
483
 
 
484
    if (createIfMissing && !rowList->at(index.row()))
 
485
        rowList->replace(index.row() , new QStdModelRow(parentRow));
 
486
    return rowList->at(index.row());
 
487
}
 
488
 
 
489
/*!
 
490
    \internal
 
491
*/
 
492
void QStandardItemModelPrivate::clear()
 
493
{
 
494
    qDeleteAll(topLevelRows);
 
495
    topLevelRows.clear();
 
496
    qDeleteAll(horizontalHeader);
 
497
    horizontalHeader.clear();
 
498
    qDeleteAll(verticalHeader);
 
499
    verticalHeader.clear();
 
500
}
 
501