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

« back to all changes in this revision

Viewing changes to src/gui/itemviews/qdirmodel.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 "qdirmodel.h"
 
30
#include <qfile.h>
 
31
#include <qurl.h>
 
32
#include <qmime.h>
 
33
#include <qpair.h>
 
34
#include <qvector.h>
 
35
#include <qobject.h>
 
36
#include <qdatetime.h>
 
37
#include <qstyle.h>
 
38
#include <qapplication.h>
 
39
#include <private/qabstractitemmodel_p.h>
 
40
#include <qdebug.h>
 
41
 
 
42
/*!
 
43
  \class QFileIconProvider
 
44
 
 
45
  \brief The QFileIconProvider class provides file icon for the QDirModel class.
 
46
*/
 
47
 
 
48
/*!
 
49
  \enum QFileIconProvider::IconType
 
50
  \value Computer
 
51
  \value Desktop
 
52
  \value Trashcan
 
53
  \value Network
 
54
  \value Drive
 
55
  \value Folder
 
56
  \value File
 
57
*/
 
58
 
 
59
/*!
 
60
    \enum QDirModel::Roles
 
61
    \value FileIconRole
 
62
    \value FilePathRole
 
63
    \value FileNameRole
 
64
*/
 
65
 
 
66
class QFileIconProviderPrivate
 
67
{
 
68
    Q_DECLARE_PUBLIC(QFileIconProvider)
 
69
public:
 
70
    QFileIconProviderPrivate();
 
71
 
 
72
    QIcon file;
 
73
    QIcon fileLink;
 
74
    QIcon directory;
 
75
    QIcon directoryLink;
 
76
    QIcon harddisk;
 
77
    QIcon floppy;
 
78
    QIcon cdrom;
 
79
    QIcon ram;
 
80
    QIcon network;
 
81
    QIcon computer;
 
82
    QIcon desktop;
 
83
    QIcon trashcan;
 
84
    QIcon generic;
 
85
 
 
86
    QFileIconProvider *q_ptr;
 
87
};
 
88
 
 
89
QFileIconProviderPrivate::QFileIconProviderPrivate()
 
90
{
 
91
    QStyle *style = QApplication::style();
 
92
 
 
93
    file = QIcon(style->standardPixmap(QStyle::SP_FileIcon));
 
94
    fileLink = QIcon(style->standardPixmap(QStyle::SP_FileLinkIcon));
 
95
 
 
96
    directory = QIcon(style->standardPixmap(QStyle::SP_DirClosedIcon));
 
97
    directory.addPixmap(style->standardPixmap(QStyle::SP_DirOpenIcon), QIcon::Normal, QIcon::On);
 
98
    directoryLink = QIcon(style->standardPixmap(QStyle::SP_DirLinkIcon));
 
99
 
 
100
    harddisk = QIcon(style->standardPixmap(QStyle::SP_DriveHDIcon));
 
101
    floppy = QIcon(style->standardPixmap(QStyle::SP_DriveFDIcon));
 
102
    cdrom = QIcon(style->standardPixmap(QStyle::SP_DriveCDIcon));
 
103
    generic = ram = harddisk; // FIXME
 
104
    network = QIcon(style->standardPixmap(QStyle::SP_DriveNetIcon));
 
105
    computer = QIcon(style->standardPixmap(QStyle::SP_ComputerIcon));
 
106
    desktop = QIcon(style->standardPixmap(QStyle::SP_DesktopIcon));
 
107
    trashcan = QIcon(style->standardPixmap(QStyle::SP_TrashIcon));
 
108
}
 
109
 
 
110
/*!
 
111
  Constructs a file icon provider.
 
112
*/
 
113
 
 
114
QFileIconProvider::QFileIconProvider()
 
115
    : d_ptr(new QFileIconProviderPrivate)
 
116
{
 
117
}
 
118
 
 
119
/*!
 
120
  Destroys the file icon provider.
 
121
 
 
122
*/
 
123
 
 
124
QFileIconProvider::~QFileIconProvider()
 
125
{
 
126
    delete d_ptr;
 
127
}
 
128
 
 
129
/*!
 
130
  Returns an icon set for the given \a type.
 
131
*/
 
132
 
 
133
QIcon QFileIconProvider::icon(IconType type) const
 
134
{
 
135
    switch (type) {
 
136
    case Computer:
 
137
        return d_ptr->computer;
 
138
    case Desktop:
 
139
        return d_ptr->desktop;
 
140
    case Trashcan:
 
141
        return d_ptr->trashcan;
 
142
    case Network:
 
143
        return d_ptr->network;
 
144
    case Drive:
 
145
        return d_ptr->generic;
 
146
    case Folder:
 
147
        return d_ptr->directory;
 
148
    case File:
 
149
        return d_ptr->file;
 
150
    default:
 
151
        break;
 
152
    };
 
153
    return QIcon();
 
154
}
 
155
 
 
156
/*!
 
157
  Returns an icon for the file described by \a info.
 
158
*/
 
159
 
 
160
QIcon QFileIconProvider::icon(const QFileInfo &info) const
 
161
{
 
162
 
 
163
    if (info.isRoot())
 
164
#ifdef Q_OS_WIN
 
165
    {
 
166
        uint type = DRIVE_UNKNOWN;
 
167
        QT_WA({ type = GetDriveTypeW((wchar_t *)info.absoluteFilePath().utf16()); },
 
168
        { type = GetDriveTypeA(info.absoluteFilePath().toLocal8Bit()); });
 
169
        switch (type) {
 
170
        case DRIVE_REMOVABLE:
 
171
            return d_ptr->floppy;
 
172
        case DRIVE_FIXED:
 
173
            return d_ptr->harddisk;
 
174
        case DRIVE_REMOTE:
 
175
            return d_ptr->network;
 
176
        case DRIVE_CDROM:
 
177
            return d_ptr->cdrom;
 
178
        case DRIVE_RAMDISK:
 
179
            return d_ptr->ram;
 
180
        case DRIVE_UNKNOWN:
 
181
            return d_ptr->generic;
 
182
        case DRIVE_NO_ROOT_DIR:
 
183
            return d_ptr->generic;
 
184
        }
 
185
    }
 
186
#else
 
187
  return d_ptr->generic;
 
188
#endif
 
189
  if (info.isFile())
 
190
    if (info.isSymLink())
 
191
      return d_ptr->fileLink;
 
192
    else
 
193
      return d_ptr->file;
 
194
  if (info.isDir())
 
195
    if (info.isSymLink())
 
196
      return d_ptr->directoryLink;
 
197
    else
 
198
      return d_ptr->directory;
 
199
  return QIcon();
 
200
}
 
201
 
 
202
/*!
 
203
  Returns the type of the file described by \a info.
 
204
*/
 
205
 
 
206
QString QFileIconProvider::type(const QFileInfo &info) const
 
207
{
 
208
    if (info.isRoot())
 
209
        return QObject::tr("Drive");
 
210
    if (info.isFile())
 
211
        return info.suffix() + " " + QObject::tr("File");
 
212
    if (info.isDir())
 
213
        return QObject::tr("Directory");
 
214
    if (info.isSymLink())
 
215
        return QObject::tr("Symbolic Link");
 
216
    return QObject::tr("Unknown");
 
217
}
 
218
 
 
219
#define Q_DIRMODEL_CACHED
 
220
 
 
221
class QDirModelPrivate : public QAbstractItemModelPrivate
 
222
{
 
223
    Q_DECLARE_PUBLIC(QDirModel)
 
224
public:
 
225
    struct QDirNode
 
226
    {
 
227
        QDirNode *parent;
 
228
        QFileInfo info;
 
229
        mutable QVector<QDirNode> children;
 
230
        mutable bool populated; // have we read the children
 
231
#ifndef Q_DIRMODEL_CACHED
 
232
        inline qint64 size() const { return info.size(); }
 
233
        inline QDateTime lastModified() const { return info.lastModified(); }
 
234
#else
 
235
        inline qint64 size() const { return cached_size; }
 
236
        inline QDateTime lastModified() const { return cached_modified; }
 
237
        qint64 cached_size;
 
238
        QDateTime cached_modified;
 
239
#endif
 
240
    };
 
241
 
 
242
    QDirModelPrivate()
 
243
        : resolveSymlinks(true),
 
244
          readOnly(true),
 
245
          lazyChildCount(false),
 
246
          iconProvider(&defaultProvider) {}
 
247
 
 
248
    void init();
 
249
    QDirNode *node(int row, QDirNode *parent) const;
 
250
    QDirNode *parent(QDirNode *child) const;
 
251
    QVector<QDirNode> children(QDirNode *parent) const;
 
252
    int idx(QDirNode *node) const;
 
253
    void refresh(QDirNode *parent);
 
254
 
 
255
    void savePersistentIndexes();
 
256
    void restorePersistentIndexes();
 
257
 
 
258
    inline QIcon rootIcon() const {
 
259
        return iconProvider->icon(QFileIconProvider::Computer);
 
260
    }
 
261
 
 
262
    inline QFileInfoList entryInfoList(const QString &path) const {
 
263
        const QDir dir(path);
 
264
        QFileInfoList fil = dir.entryInfoList(nameFilters, filters, sort);
 
265
        for (int i = 0; i < fil.count(); ++i) {
 
266
            QString fn = fil.at(i).fileName();
 
267
            if (fn == "." || fn == "..")
 
268
                fil.removeAt(i--);
 
269
        }
 
270
        return fil;
 
271
    }
 
272
 
 
273
    inline QStringList entryList(const QString &path) const {
 
274
        const QDir dir(path);
 
275
        QStringList sl = dir.entryList(nameFilters, filters, sort);
 
276
        for (int i = 0; i < sl.count(); ++i) {
 
277
            QString fn = sl.at(i);
 
278
            if (fn == "." || fn == "..")
 
279
                sl.removeAt(i--);
 
280
        }
 
281
        return sl;
 
282
    }
 
283
 
 
284
    inline void populate(QDirNode *parent) const {
 
285
        Q_ASSERT(parent);
 
286
        parent->children = children(parent);
 
287
        parent->populated = true;
 
288
    }
 
289
 
 
290
    inline void clear(QDirNode *parent) const {
 
291
        Q_ASSERT(parent);
 
292
        parent->children.clear();
 
293
        parent->populated = false;
 
294
    }
 
295
 
 
296
    mutable QDirNode root;
 
297
    bool resolveSymlinks;
 
298
    bool readOnly;
 
299
    bool lazyChildCount;
 
300
 
 
301
    QDir::Filters filters;
 
302
    QDir::SortFlags sort;
 
303
    QStringList nameFilters;
 
304
 
 
305
    QFileIconProvider *iconProvider;
 
306
    QFileIconProvider defaultProvider;
 
307
 
 
308
    QList< QPair<QString,int> > saved;
 
309
};
 
310
 
 
311
/*!
 
312
  \class QDirModel qdirmodel.h
 
313
 
 
314
  \brief The QDirModel class provides a data model for the local filesystem.
 
315
 
 
316
  \ingroup model-view
 
317
 
 
318
  This class provides access to the local filesystem, providing functions
 
319
  for renaming and removing files and directories, and for creating new
 
320
  directories. In the simplest case, it can be used with a suitable display
 
321
  widget as part of a browser or filer.
 
322
 
 
323
  QDirModel does not store file information internally or cache file data.
 
324
 
 
325
  A directory model that displays the contents of a default directory
 
326
  is usually constructed with a parent object:
 
327
 
 
328
  \quotefromfile snippets/shareddirmodel/main.cpp
 
329
  \skipto QDirModel *model
 
330
  \printuntil QDirModel *model
 
331
 
 
332
  A tree view can be used to display the contents of the model
 
333
 
 
334
  \skipto QTreeView *tree
 
335
  \printuntil tree->setModel(
 
336
 
 
337
  and the contents of a particular directory can be displayed by
 
338
  setting the tree view's root index:
 
339
 
 
340
  \printuntil tree->setRootIndex(
 
341
 
 
342
  The view's root index can be used to control how much of a
 
343
  hierarchical model is displayed. QDirModel provides a convenience
 
344
  function that returns a suitable model index for a path to a
 
345
  directory within the model.
 
346
 
 
347
  QDirModel can be accessed using the standard interface provided by
 
348
  QAbstractItemModel, but it also provides some convenience functions that are
 
349
  specific to a directory model.
 
350
  The fileInfo(), isDir(), name(), and path() functions provide information
 
351
  about the underlying files and directories related to items in the model.
 
352
  Directories can be created and removed using mkdir(), rmdir(), and the
 
353
  model will be automatically updated to take the changes into account.
 
354
 
 
355
  \sa nameFilters(), setFilter(), filter(),
 
356
      \link model-view-programming.html Model/View Programming\endlink QListView QTreeView
 
357
 
 
358
*/
 
359
 
 
360
/*!
 
361
    Constructs a new directory model with the given \a parent.
 
362
    Only those files matching the \a nameFilters and the
 
363
    \a filters are included in the model. The sort order is given by the
 
364
    \a sort flags.
 
365
*/
 
366
 
 
367
QDirModel::QDirModel(const QStringList &nameFilters,
 
368
                     QDir::Filters filters,
 
369
                     QDir::SortFlags sort,
 
370
                     QObject *parent)
 
371
    : QAbstractItemModel(*new QDirModelPrivate, parent)
 
372
{
 
373
    Q_D(QDirModel);
 
374
    // we always start with QDir::drives()
 
375
    d->nameFilters = nameFilters.isEmpty() ? QStringList("*") : nameFilters;
 
376
    d->filters = filters;
 
377
    d->sort = sort;
 
378
    d->root.parent = 0;
 
379
    d->root.info = QFileInfo();
 
380
    d->clear(&d->root);
 
381
}
 
382
 
 
383
/*!
 
384
  Constructs a directory model with the given \a parent.
 
385
*/
 
386
 
 
387
QDirModel::QDirModel(QObject *parent)
 
388
    : QAbstractItemModel(*new QDirModelPrivate, parent)
 
389
{
 
390
    Q_D(QDirModel);
 
391
    d->init();
 
392
}
 
393
 
 
394
/*!
 
395
    \internal
 
396
*/
 
397
QDirModel::QDirModel(QDirModelPrivate &dd, QObject *parent)
 
398
    : QAbstractItemModel(dd, parent)
 
399
{
 
400
    Q_D(QDirModel);
 
401
    d->init();
 
402
}
 
403
 
 
404
/*!
 
405
  Destroys this directory model.
 
406
*/
 
407
 
 
408
QDirModel::~QDirModel()
 
409
{
 
410
 
 
411
}
 
412
 
 
413
/*!
 
414
  Returns the model item index for the item in the \a parent with the
 
415
  given \a row and \a column.
 
416
 
 
417
*/
 
418
 
 
419
QModelIndex QDirModel::index(int row, int column, const QModelIndex &parent) const
 
420
{
 
421
    Q_D(const QDirModel);
 
422
    if (column < 0 || column >= 4 || row < 0 || row >= rowCount(parent)) // does lazy population
 
423
        return QModelIndex();
 
424
 
 
425
    QDirModelPrivate::QDirNode *p =
 
426
        static_cast<QDirModelPrivate::QDirNode*>(parent.internalPointer());
 
427
    QDirModelPrivate::QDirNode *n = d->node(row, p);
 
428
    Q_ASSERT(n);
 
429
 
 
430
    return createIndex(row, column, n);
 
431
}
 
432
 
 
433
/*!
 
434
  Return the parent of the given \a child model item.
 
435
*/
 
436
 
 
437
QModelIndex QDirModel::parent(const QModelIndex &child) const
 
438
{
 
439
    Q_D(const QDirModel);
 
440
    if (!child.isValid())
 
441
        return QModelIndex();
 
442
 
 
443
    QDirModelPrivate::QDirNode *node =
 
444
        static_cast<QDirModelPrivate::QDirNode*>(child.internalPointer());
 
445
    Q_ASSERT(node);
 
446
 
 
447
    QDirModelPrivate::QDirNode *par = d->parent(node);
 
448
    if (!par)
 
449
        return QModelIndex(); // parent is the root node
 
450
 
 
451
    int r = d->idx(par);
 
452
    Q_ASSERT(r >= 0);
 
453
    return createIndex(r, 0, par);
 
454
}
 
455
 
 
456
/*!
 
457
  Returns the number of rows in the \a parent model item.
 
458
 
 
459
*/
 
460
 
 
461
int QDirModel::rowCount(const QModelIndex &parent) const
 
462
{
 
463
    Q_D(const QDirModel);
 
464
    QDirModelPrivate::QDirNode *p =
 
465
        static_cast<QDirModelPrivate::QDirNode*>(parent.internalPointer());
 
466
 
 
467
    bool isDir = !p || p->info.isDir(); // no node pointer means that it is the root
 
468
    if (!p) p = &(d->root);
 
469
    if (isDir && !p->populated) // lazy population
 
470
        d->populate(p);
 
471
    return p->children.count();
 
472
}
 
473
 
 
474
/*!
 
475
  Returns the number of columns in the \a parent model item.
 
476
 
 
477
*/
 
478
 
 
479
int QDirModel::columnCount(const QModelIndex &) const
 
480
{
 
481
    return 4;
 
482
}
 
483
 
 
484
/*!
 
485
  Returns the data for the model item \a index with the given \a role.
 
486
 
 
487
*/
 
488
 
 
489
QVariant QDirModel::data(const QModelIndex &index, int role) const
 
490
{
 
491
    Q_D(const QDirModel);
 
492
    if (!index.isValid())
 
493
        return QVariant();
 
494
 
 
495
    QDirModelPrivate::QDirNode *node =
 
496
        static_cast<QDirModelPrivate::QDirNode*>(index.internalPointer());
 
497
    Q_ASSERT(node);
 
498
 
 
499
    if (role == Qt::DisplayRole || role == Qt::EditRole) {
 
500
        switch (index.column()) {
 
501
            case 0:
 
502
                if (node->info.isRoot()) {
 
503
                    QString name = node->info.absoluteFilePath();
 
504
#ifdef Q_OS_WIN
 
505
                    if (name.at(0) == '/') // UNC host
 
506
                        return node->info.fileName();
 
507
                    if (name.at(name.length() - 1) == '/')
 
508
                        name.chop(1);
 
509
#endif
 
510
                    return name;
 
511
                }
 
512
                return node->info.fileName();
 
513
        case 1: return node->size();
 
514
        case 2: return d->iconProvider->type(node->info);
 
515
        case 3: return node->lastModified();
 
516
        default:
 
517
            qWarning("data: invalid display value column %d", index.column());
 
518
            return QVariant();
 
519
        }
 
520
    }
 
521
 
 
522
    if (index.column() == 0) {
 
523
        if (role == FileIconRole)
 
524
            return fileIcon(index);
 
525
        if (role == FilePathRole)
 
526
            return filePath(index);
 
527
        if (role == FileNameRole)
 
528
            return fileName(index);
 
529
    }
 
530
    return QVariant();
 
531
}
 
532
 
 
533
/*!
 
534
  Sets the data for the model item \a index with the given \a role to
 
535
  the data referenced by the \a value. Returns true if successful;
 
536
  otherwise returns false.
 
537
 
 
538
*/
 
539
 
 
540
bool QDirModel::setData(const QModelIndex &index, const QVariant &value, int role)
 
541
{
 
542
    Q_D(QDirModel);
 
543
    if (!index.isValid() || index.column() != 0
 
544
        || (flags(index) & Qt::ItemIsEditable) == 0 || role != Qt::EditRole)
 
545
        return false;
 
546
 
 
547
    QDirModelPrivate::QDirNode *node =
 
548
        static_cast<QDirModelPrivate::QDirNode*>(index.internalPointer());
 
549
    Q_ASSERT(node);
 
550
    QDir dir = node->info.dir();
 
551
    if (dir.rename(node->info.fileName(), value.toString())) {
 
552
        QModelIndex par = parent(index);
 
553
        QDirModelPrivate::QDirNode *p =
 
554
            static_cast<QDirModelPrivate::QDirNode*>(par.internalPointer());
 
555
        d->refresh(p);
 
556
        QModelIndex topLeft = this->index(0, 0, par);
 
557
        int rc = rowCount(par);
 
558
        int cc = columnCount(par);
 
559
        QModelIndex bottomRight = this->index(rc, cc, par);
 
560
        emit dataChanged(topLeft, bottomRight);
 
561
        return true;
 
562
    }
 
563
 
 
564
    return false;
 
565
}
 
566
 
 
567
/*!
 
568
  Returns the data stored under the given \a role for the specified \a section
 
569
  of the header with the given \a orientation.
 
570
*/
 
571
 
 
572
QVariant QDirModel::headerData(int section, Qt::Orientation orientation, int role) const
 
573
{
 
574
    if (orientation == Qt::Horizontal) {
 
575
        if (role != Qt::DisplayRole)
 
576
            return QVariant();
 
577
        switch (section) {
 
578
        case 0: return tr("Name");
 
579
        case 1: return tr("Size");
 
580
        case 2: return tr("Type");
 
581
        case 3: return tr("Modified");
 
582
        default: return QVariant();
 
583
        }
 
584
    }
 
585
    return QAbstractItemModel::headerData(section, orientation, role);
 
586
}
 
587
 
 
588
/*!
 
589
  Returns true if the \a parent model item has children; otherwise
 
590
  returns false.
 
591
*/
 
592
 
 
593
bool QDirModel::hasChildren(const QModelIndex &parent) const
 
594
{
 
595
    Q_D(const QDirModel);
 
596
    if (!parent.isValid()) // the invalid index is the "My Computer" item
 
597
        return true; // the drives
 
598
    QDirModelPrivate::QDirNode *p =
 
599
        static_cast<QDirModelPrivate::QDirNode*>(parent.internalPointer());
 
600
    Q_ASSERT(p);
 
601
    if (d->lazyChildCount) { // optimization that only checks for children if the node has been populated
 
602
        if (p->populated)
 
603
            return rowCount(parent) > 0; // rowCount will lazily populate if needed
 
604
        return p->info.isDir();
 
605
    }
 
606
    return p->info.isDir() && rowCount(parent) > 0;
 
607
}
 
608
 
 
609
/*!
 
610
  Returns the item flags for the given \a index in the model.
 
611
 
 
612
  \sa Qt::ItemFlags
 
613
*/
 
614
Qt::ItemFlags QDirModel::flags(const QModelIndex &index) const
 
615
{
 
616
    Q_D(const QDirModel);
 
617
    Qt::ItemFlags flags = QAbstractItemModel::flags(index);
 
618
    if (!index.isValid())
 
619
        return flags;
 
620
    flags |= Qt::ItemIsDragEnabled;
 
621
    if (d->readOnly)
 
622
        return flags;
 
623
    QDirModelPrivate::QDirNode *node =
 
624
        static_cast<QDirModelPrivate::QDirNode*>(index.internalPointer());
 
625
    Q_ASSERT(node);
 
626
    if ((index.column() == 0) && node->info.isWritable()) {
 
627
        flags |= Qt::ItemIsEditable;
 
628
        if (fileInfo(index).isDir()) // is directory and is editable
 
629
            flags |= Qt::ItemIsDropEnabled;
 
630
    }
 
631
    return flags;
 
632
}
 
633
 
 
634
/*!
 
635
  Sort the model items in the \a column using the \a order given.
 
636
  The order is a value defined in \l Qt::SortOrder.
 
637
*/
 
638
 
 
639
void QDirModel::sort(int column, Qt::SortOrder order)
 
640
{
 
641
    QDir::SortFlags sort = 0;
 
642
    if (order == Qt::DescendingOrder)
 
643
        sort |= QDir::Reversed;
 
644
 
 
645
    switch (column) {
 
646
    case 0:
 
647
        sort |= QDir::Name;
 
648
        break;
 
649
    case 1:
 
650
        sort |= QDir::Size;
 
651
        break;
 
652
    case 2:
 
653
        // FIXME: we should sort on the type string
 
654
        sort |= QDir::DirsFirst;
 
655
        break;
 
656
    case 3:
 
657
        sort |= QDir::Time;
 
658
        break;
 
659
    default:
 
660
        break;
 
661
    }
 
662
 
 
663
    setSorting(sort);
 
664
}
 
665
 
 
666
/*!
 
667
    Returns a list of MIME types that can be used to describe a list of items
 
668
    in the model.
 
669
*/
 
670
 
 
671
QStringList QDirModel::mimeTypes() const
 
672
{
 
673
    return QStringList("text/uri-list");
 
674
}
 
675
 
 
676
/*!
 
677
    Returns an object that contains a serialized description of the specified
 
678
    \a indexes. The format used to describe the items corresponding to the
 
679
    indexes is obtained from the mimeTypes() function.
 
680
 
 
681
    If the list of indexes is empty, 0 is returned rather than a serialized
 
682
    empty list.
 
683
*/
 
684
 
 
685
QMimeData *QDirModel::mimeData(const QModelIndexList &indexes) const
 
686
{
 
687
    QList<QUrl> urls;
 
688
    QList<QModelIndex>::const_iterator it = indexes.begin();
 
689
    for (; it != indexes.end(); ++it)
 
690
        if ((*it).column() == 0)
 
691
            urls << QUrl::fromLocalFile(filePath(*it));
 
692
    QMimeData *data = new QMimeData();
 
693
    data->setUrls(urls);
 
694
    return data;
 
695
}
 
696
 
 
697
/*!
 
698
    Handles the \a data supplied by a drag and drop operation that ended with
 
699
    the given \a action over the row in the model specified by the \a row and
 
700
    \a column and by the \a parent index.
 
701
 
 
702
    \sa supportedDropActions()
 
703
*/
 
704
 
 
705
bool QDirModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
 
706
                             int row, int /* column */, const QModelIndex &parent)
 
707
{
 
708
    Q_D(QDirModel);
 
709
    if (!parent.isValid() || isReadOnly())
 
710
        return false;
 
711
 
 
712
    QDirModelPrivate::QDirNode *p =
 
713
        static_cast<QDirModelPrivate::QDirNode*>(parent.internalPointer());
 
714
    Q_ASSERT(p);
 
715
 
 
716
    bool success = true;
 
717
    QString to = filePath(parent) + QDir::separator();
 
718
 
 
719
    QList<QUrl> urls = data->urls();
 
720
    QList<QUrl>::const_iterator it = urls.begin();
 
721
 
 
722
    int last = row + urls.count() - 1;
 
723
    beginInsertRows(parent, row, last);
 
724
 
 
725
    switch (action) {
 
726
    case Qt::CopyAction:
 
727
        for (; it != urls.end(); ++it) {
 
728
            QString path = (*it).toLocalFile();
 
729
            success = QFile::copy(path, to + QFileInfo(path).fileName()) && success;
 
730
        }
 
731
        break;
 
732
    case Qt::LinkAction:
 
733
        for (; it != urls.end(); ++it) {
 
734
            QString path = (*it).toLocalFile();
 
735
            success = QFile::link(path, to + QFileInfo(path).fileName()) && success;
 
736
        }
 
737
        break;
 
738
    case Qt::MoveAction:
 
739
        for (; it != urls.end(); ++it) {
 
740
            QString path = (*it).toLocalFile();
 
741
            success = QFile::copy(path, to + QFileInfo(path).fileName())
 
742
                      && QFile::remove(path) && success;
 
743
        }
 
744
        break;
 
745
    default:
 
746
        return false;
 
747
    }
 
748
 
 
749
    d->populate(p);
 
750
    endInsertRows();
 
751
 
 
752
    return success;
 
753
}
 
754
 
 
755
/*!
 
756
  Returns the drop actions supported by this model.
 
757
 
 
758
  \sa Qt::DropActions
 
759
*/
 
760
 
 
761
Qt::DropActions QDirModel::supportedDropActions() const
 
762
{
 
763
    return Qt::CopyAction | Qt::MoveAction; // FIXME: LinkAction is not supported yet
 
764
}
 
765
 
 
766
/*!
 
767
  Sets the \a provider of file icons for the directory model.
 
768
 
 
769
*/
 
770
 
 
771
void QDirModel::setIconProvider(QFileIconProvider *provider)
 
772
{
 
773
    Q_D(QDirModel);
 
774
    d->iconProvider = provider;
 
775
}
 
776
 
 
777
/*!
 
778
  Returns the file icon provider for this directory model.
 
779
*/
 
780
 
 
781
QFileIconProvider *QDirModel::iconProvider() const
 
782
{
 
783
    Q_D(const QDirModel);
 
784
    return d->iconProvider;
 
785
}
 
786
 
 
787
/*!
 
788
  Sets the name \a filters for the directory model.
 
789
*/
 
790
 
 
791
void QDirModel::setNameFilters(const QStringList &filters)
 
792
{
 
793
    Q_D(QDirModel);
 
794
 
 
795
    d->savePersistentIndexes();
 
796
    beginRemoveRows(QModelIndex(), 0, rowCount(QModelIndex()) - 1);
 
797
    
 
798
    d->nameFilters = filters;
 
799
    d->clear(&d->root); // clear model
 
800
 
 
801
    endRemoveRows();
 
802
    d->restorePersistentIndexes();
 
803
}
 
804
 
 
805
/*!
 
806
  Returns a list of filters applied to the names in the model.
 
807
*/
 
808
 
 
809
QStringList QDirModel::nameFilters() const
 
810
{
 
811
    Q_D(const QDirModel);
 
812
    return d->nameFilters;
 
813
}
 
814
 
 
815
/*!
 
816
  Sets the directory model's filter to that specified by \a filters.
 
817
 
 
818
  \sa QDir::Filters
 
819
*/
 
820
 
 
821
void QDirModel::setFilter(QDir::Filters filters)
 
822
{
 
823
    Q_D(QDirModel);
 
824
    
 
825
    d->savePersistentIndexes();
 
826
    beginRemoveRows(QModelIndex(), 0, rowCount(QModelIndex()) - 1);
 
827
 
 
828
    d->filters = filters;
 
829
    d->clear(&d->root); // clear model
 
830
 
 
831
    endRemoveRows();
 
832
    d->restorePersistentIndexes();
 
833
}
 
834
 
 
835
/*!
 
836
  Returns the filter specification for the directory model.
 
837
 
 
838
  \sa QDir::Filters
 
839
*/
 
840
 
 
841
QDir::Filters QDirModel::filter() const
 
842
{
 
843
    Q_D(const QDirModel);
 
844
    return d->filters;
 
845
}
 
846
 
 
847
/*!
 
848
  Sets the directory model's sorting order to that specified by \a sort.
 
849
 
 
850
  \sa QDir::SortFlags
 
851
*/
 
852
 
 
853
void QDirModel::setSorting(QDir::SortFlags sort)
 
854
{
 
855
    Q_D(QDirModel);
 
856
 
 
857
    d->savePersistentIndexes();
 
858
    beginRemoveRows(QModelIndex(), 0, rowCount(QModelIndex()) - 1);
 
859
 
 
860
    d->sort = sort;
 
861
    d->clear(&d->root); // clear model
 
862
 
 
863
    endRemoveRows();
 
864
    d->restorePersistentIndexes();
 
865
}
 
866
 
 
867
/*!
 
868
  Returns the sorting method used for the directory model.
 
869
 
 
870
  \sa QDir::SortFlags */
 
871
 
 
872
QDir::SortFlags QDirModel::sorting() const
 
873
{
 
874
    Q_D(const QDirModel);
 
875
    return d->sort;
 
876
}
 
877
 
 
878
/*!
 
879
    \property QDirModel::resolveSymlinks
 
880
    \brief Whether the directory model should resolve symbolic links
 
881
 
 
882
    This is only relevant on operating systems that support symbolic
 
883
    links.
 
884
*/
 
885
void QDirModel::setResolveSymlinks(bool enable)
 
886
{
 
887
    Q_D(QDirModel);
 
888
    d->resolveSymlinks = enable;
 
889
}
 
890
 
 
891
bool QDirModel::resolveSymlinks() const
 
892
{
 
893
    Q_D(const QDirModel);
 
894
    return d->resolveSymlinks;
 
895
}
 
896
 
 
897
/*!
 
898
  \property QDirModel::readOnly
 
899
  \brief Whether the directory model allows writing to the file system
 
900
 
 
901
  If this property is set to false, the directory model will allow renaming, copying
 
902
  and deleting of files and directories.
 
903
 
 
904
  This property is true by default
 
905
*/
 
906
 
 
907
void QDirModel::setReadOnly(bool enable)
 
908
{
 
909
    Q_D(QDirModel);
 
910
    d->readOnly = enable;
 
911
}
 
912
 
 
913
bool QDirModel::isReadOnly() const
 
914
{
 
915
    Q_D(const QDirModel);
 
916
    return d->readOnly;
 
917
}
 
918
 
 
919
/*!
 
920
  \property QDirModel::lazyChildCount
 
921
  \brief Whether the directory model optimizes the hasChildren function
 
922
  to only check if the item is a directory.
 
923
 
 
924
  If this property is set to true, the directory model will make sure that a directory
 
925
  actually containes any files before reporting that it has children.
 
926
  Otherwise the directory model will report that an item has children if the item
 
927
  is a directory.
 
928
 
 
929
  This property is false by default
 
930
*/
 
931
 
 
932
void QDirModel::setLazyChildCount(bool enable)
 
933
{
 
934
    Q_D(QDirModel);
 
935
    d->lazyChildCount = enable;
 
936
}
 
937
 
 
938
bool QDirModel::lazyChildCount() const
 
939
{
 
940
    Q_D(const QDirModel);
 
941
    return d->lazyChildCount;
 
942
}
 
943
 
 
944
/*!
 
945
  Refreshes (rereads) the children of \a parent.
 
946
*/
 
947
 
 
948
void QDirModel::refresh(const QModelIndex &parent)
 
949
{
 
950
    Q_D(QDirModel);
 
951
 
 
952
    QDirModelPrivate::QDirNode *p =
 
953
        static_cast<QDirModelPrivate::QDirNode*>(parent.internalPointer());
 
954
    QDirModelPrivate::QDirNode *n = (p ? p : &(d->root));
 
955
 
 
956
    d->savePersistentIndexes();
 
957
    beginRemoveRows(parent, 0, n->children.count() - 1);
 
958
 
 
959
    d->refresh(p); // if (p == 0) it reads the drives
 
960
 
 
961
    endRemoveRows();
 
962
    d->restorePersistentIndexes();
 
963
}
 
964
 
 
965
/*!
 
966
    \overload
 
967
 
 
968
    Returns the model item index for the given \a path.
 
969
*/
 
970
 
 
971
QModelIndex QDirModel::index(const QString &path, int column) const
 
972
{
 
973
    Q_D(const QDirModel);
 
974
 
 
975
    if (path.isEmpty() || path == QObject::tr("My Computer"))
 
976
        return QModelIndex();
 
977
 
 
978
    QString absolutePath = QDir(path).absolutePath();
 
979
    QStringList pathElements = absolutePath.split(QChar('/'), QString::SkipEmptyParts);
 
980
    if ((pathElements.isEmpty() || !QFileInfo(path).exists())
 
981
#ifndef Q_OS_WIN
 
982
        && path != "/"
 
983
#endif
 
984
        )
 
985
        return QModelIndex();
 
986
 
 
987
    QModelIndex idx; // start with "My Computer"
 
988
    if (!d->root.populated) // make sure the root is populated
 
989
        d->populate(&d->root);
 
990
    
 
991
#ifdef Q_OS_WIN
 
992
    if (absolutePath.startsWith("//")) { // UNC path
 
993
        QString host = pathElements.first();
 
994
        int r = 0;
 
995
        for (; r < d->root.children.count(); ++r) {
 
996
            if (d->root.children.at(r).info.fileName() == host)
 
997
                break;
 
998
        }
 
999
        if (r >= d->root.children.count()) {
 
1000
            QFileInfo info("//" + host);
 
1001
            QDirModelPrivate::QDirNode node;
 
1002
            node.parent = 0;
 
1003
            node.info = info; 
 
1004
            node.populated = false;
 
1005
#ifdef Q_DIRMODEL_CACHED
 
1006
            node.cached_size = info.size();
 
1007
            node.cached_modified = info.lastModified();
 
1008
#endif
 
1009
            d->root.children.append(node);
 
1010
        }
 
1011
        idx = index(r, 0, QModelIndex());
 
1012
        pathElements.pop_front();
 
1013
    } else if (pathElements.at(0).endsWith(":")) {
 
1014
        pathElements[0] += "/";
 
1015
    }
 
1016
#else
 
1017
    // add the "/" item, since it is a valid path element on unix
 
1018
    pathElements.prepend("/");
 
1019
#endif
 
1020
    for (int i = 0; i < pathElements.count(); ++i) {
 
1021
        QStringList entries;
 
1022
        Q_ASSERT(!pathElements.at(i).isEmpty()); // we don't allow empty elements
 
1023
        // get the list of children of the current path element
 
1024
        if (idx.isValid()) {
 
1025
            QDirModelPrivate::QDirNode *node =
 
1026
                static_cast<QDirModelPrivate::QDirNode*>(idx.internalPointer());
 
1027
            Q_ASSERT(node);
 
1028
            entries = d->entryList(node->info.absoluteFilePath());
 
1029
        } else { // parent is "My Computer"
 
1030
            for (int j = 0; j < d->root.children.count(); ++j)
 
1031
                entries << QDir::cleanPath(d->root.children.at(j).info.absoluteFilePath());
 
1032
        }
 
1033
 
 
1034
        // find the row of the current path element in the list of children
 
1035
        int row = entries.indexOf(pathElements.at(i));
 
1036
        idx = index(row, column, idx); // will check row and lazily populate
 
1037
        // hit an invalid element (could be hidden or just not found)
 
1038
        if (!idx.isValid()) {
 
1039
            qWarning() << "The file or directory" << pathElements.at(i)
 
1040
                       << "in the path" << path << "could not be found.";
 
1041
            break; // return an invalid index
 
1042
        }
 
1043
    }
 
1044
 
 
1045
    return idx;
 
1046
}
 
1047
 
 
1048
/*!
 
1049
  Returns true if the model item \a index represents a directory;
 
1050
  otherwise returns false.
 
1051
*/
 
1052
 
 
1053
bool QDirModel::isDir(const QModelIndex &index) const
 
1054
{
 
1055
    Q_ASSERT(index.isValid());
 
1056
    QDirModelPrivate::QDirNode *node =
 
1057
        static_cast<QDirModelPrivate::QDirNode*>(index.internalPointer());
 
1058
    Q_ASSERT(node);
 
1059
    return node->info.isDir();
 
1060
}
 
1061
 
 
1062
/*!
 
1063
  Create a directory with the \a name in the \a parent model item.
 
1064
*/
 
1065
 
 
1066
QModelIndex QDirModel::mkdir(const QModelIndex &parent, const QString &name)
 
1067
{
 
1068
    Q_D(QDirModel);
 
1069
    if (!parent.isValid())
 
1070
        return QModelIndex();
 
1071
 
 
1072
    QDirModelPrivate::QDirNode *p =
 
1073
        static_cast<QDirModelPrivate::QDirNode*>(parent.internalPointer());
 
1074
    Q_ASSERT(p);
 
1075
    QString path = p->info.absoluteFilePath();
 
1076
    // For the indexOf() method to work, the new directory has to be a direct child of
 
1077
    // the parent directory.
 
1078
 
 
1079
    QDir newDir(name); 
 
1080
    QDir dir(path);
 
1081
    if (newDir.isRelative())
 
1082
        newDir = QDir(path + "/" + name); 
 
1083
    QString childName = newDir.dirName(); // Get the singular name of the directory
 
1084
    newDir.cdUp();
 
1085
 
 
1086
    if (newDir.absolutePath() != dir.absolutePath() || !dir.mkdir(name))
 
1087
        return QModelIndex(); // nothing happened
 
1088
 
 
1089
    refresh(parent);
 
1090
 
 
1091
    QStringList entryList = d->entryList(path);
 
1092
    int r = entryList.indexOf(childName);
 
1093
    QModelIndex i = index(r, 0, parent); // return an invalid index
 
1094
 
 
1095
    return i;
 
1096
}
 
1097
 
 
1098
/*!
 
1099
  Removes the directory corresponding to the model item \a index in the
 
1100
  directory model, returning true if successful. If the directory
 
1101
  cannot be removed, false is returned.
 
1102
 
 
1103
*/
 
1104
 
 
1105
bool QDirModel::rmdir(const QModelIndex &index)
 
1106
{
 
1107
    if (!index.isValid())
 
1108
        return false;
 
1109
 
 
1110
    QDirModelPrivate::QDirNode *n =
 
1111
        static_cast<QDirModelPrivate::QDirNode*>(index.internalPointer());
 
1112
    Q_ASSERT(n);
 
1113
 
 
1114
    if (!n->info.isDir()) {
 
1115
        qWarning("rmdir: the node is not a directory");
 
1116
        return false;
 
1117
    }
 
1118
 
 
1119
    QModelIndex par = parent(index);
 
1120
    QDirModelPrivate::QDirNode *p =
 
1121
        static_cast<QDirModelPrivate::QDirNode*>(par.internalPointer());
 
1122
    Q_ASSERT(p);
 
1123
 
 
1124
    QDir dir = p->info.dir(); // parent dir
 
1125
    QString path = n->info.absoluteFilePath();
 
1126
    if (!dir.rmdir(path))
 
1127
        return false;
 
1128
 
 
1129
    refresh(par);
 
1130
 
 
1131
    return true;
 
1132
}
 
1133
 
 
1134
/*!
 
1135
  Removes the model item \a index from the directory model, returning
 
1136
  true if successful. If the item cannot be removed, false is returned.
 
1137
 
 
1138
 */
 
1139
 
 
1140
bool QDirModel::remove(const QModelIndex &index)
 
1141
{
 
1142
    if (!index.isValid())
 
1143
        return false;
 
1144
 
 
1145
    QDirModelPrivate::QDirNode *n =
 
1146
        static_cast<QDirModelPrivate::QDirNode*>(index.internalPointer());
 
1147
    Q_ASSERT(n);
 
1148
 
 
1149
    if (n->info.isDir())
 
1150
        return false;
 
1151
 
 
1152
    QModelIndex par = parent(index);
 
1153
    QDirModelPrivate::QDirNode *p =
 
1154
        static_cast<QDirModelPrivate::QDirNode*>(par.internalPointer());
 
1155
    Q_ASSERT(p);
 
1156
 
 
1157
    QDir dir = p->info.dir(); // parent dir
 
1158
    QString path = n->info.absoluteFilePath();
 
1159
    if (!dir.remove(path))
 
1160
        return false;
 
1161
 
 
1162
    refresh(par);
 
1163
    
 
1164
    return true;
 
1165
}
 
1166
 
 
1167
/*!
 
1168
  Returns the path of the item stored in the model under the
 
1169
  \a index given.
 
1170
 
 
1171
*/
 
1172
 
 
1173
QString QDirModel::filePath(const QModelIndex &index) const
 
1174
{
 
1175
    Q_D(const QDirModel);
 
1176
    if (index.isValid()) {
 
1177
        QFileInfo fi = fileInfo(index);
 
1178
        if (d->resolveSymlinks && fi.isSymLink()) {
 
1179
            QString link = fi.readLink();
 
1180
            if (link.at(link.size() - 1) == QDir::separator())
 
1181
                link.chop(1);
 
1182
            return QDir::cleanPath(link);
 
1183
        }
 
1184
        return QDir::cleanPath(fi.absoluteFilePath());
 
1185
    }
 
1186
    return QString(); // root path
 
1187
}
 
1188
 
 
1189
/*!
 
1190
  Returns the name of the item stored in the model under the
 
1191
  \a index given.
 
1192
 
 
1193
*/
 
1194
 
 
1195
QString QDirModel::fileName(const QModelIndex &index) const
 
1196
{
 
1197
    if (!index.isValid())
 
1198
        return QObject::tr("My Computer");
 
1199
    QFileInfo info = fileInfo(index);
 
1200
    if (info.isRoot())
 
1201
        return info.absoluteFilePath();
 
1202
    return info.fileName();
 
1203
}
 
1204
 
 
1205
/*!
 
1206
  Returns the icons for the item stored in the model under the given
 
1207
  \a index.
 
1208
*/
 
1209
 
 
1210
QIcon QDirModel::fileIcon(const QModelIndex &index) const
 
1211
{
 
1212
    Q_D(const QDirModel);
 
1213
    if (!index.isValid())
 
1214
        return d->rootIcon();
 
1215
    return d->iconProvider->icon(fileInfo(index));
 
1216
}
 
1217
 
 
1218
/*!
 
1219
  Returns the file information for the model item \a index.
 
1220
 
 
1221
*/
 
1222
 
 
1223
QFileInfo QDirModel::fileInfo(const QModelIndex &index) const
 
1224
{
 
1225
    Q_ASSERT(index.isValid());
 
1226
 
 
1227
    QDirModelPrivate::QDirNode *node =
 
1228
        static_cast<QDirModelPrivate::QDirNode*>(index.internalPointer());
 
1229
    Q_ASSERT(node);
 
1230
 
 
1231
    return node->info;
 
1232
}
 
1233
 
 
1234
/*
 
1235
  The root node is never seen outside the model.
 
1236
*/
 
1237
 
 
1238
void QDirModelPrivate::init()
 
1239
{
 
1240
    filters = QDir::TypeMask;
 
1241
    sort = QDir::Name;
 
1242
    nameFilters << "*";
 
1243
    root.parent = 0;
 
1244
    root.info = QFileInfo();
 
1245
    clear(&root);
 
1246
}
 
1247
 
 
1248
QDirModelPrivate::QDirNode *QDirModelPrivate::node(int row, QDirNode *parent) const
 
1249
{
 
1250
    if (row < 0)
 
1251
        return 0;
 
1252
 
 
1253
    bool isDir =  !parent || parent->info.isDir();
 
1254
    QDirNode *p = (parent ? parent : &root);
 
1255
    if (isDir && !p->populated)
 
1256
        populate(p); // will also resolve symlinks
 
1257
 
 
1258
    if (row >= p->children.count()) {
 
1259
        qWarning("node: the row does not exist");
 
1260
        return 0;
 
1261
    }
 
1262
 
 
1263
    return const_cast<QDirNode*>(&p->children.at(row));
 
1264
}
 
1265
 
 
1266
QDirModelPrivate::QDirNode *QDirModelPrivate::parent(QDirNode *child) const
 
1267
{
 
1268
    return child ? child->parent : 0;
 
1269
}
 
1270
 
 
1271
QVector<QDirModelPrivate::QDirNode> QDirModelPrivate::children(QDirNode *parent) const
 
1272
{
 
1273
    Q_ASSERT(parent);
 
1274
    QFileInfoList info;
 
1275
    if (parent == &root) {
 
1276
        parent = 0;
 
1277
        info = QDir::drives();
 
1278
    } else if (parent->info.isDir()) {
 
1279
        if (resolveSymlinks && parent->info.isSymLink()) {
 
1280
            QString link = parent->info.readLink();
 
1281
            if (link.at(link.size() - 1) == QDir::separator())
 
1282
                link.chop(1);
 
1283
            info = entryInfoList(link);
 
1284
        } else {
 
1285
            info = entryInfoList(parent->info.filePath());
 
1286
        }
 
1287
    }
 
1288
 
 
1289
    QVector<QDirNode> nodes(info.count());
 
1290
    for (int i = 0; i < info.count(); ++i) {
 
1291
        nodes[i].parent = parent;
 
1292
        nodes[i].info = info.at(i);
 
1293
        nodes[i].populated = false;
 
1294
#ifdef Q_DIRMODEL_CACHED
 
1295
        nodes[i].cached_size = info.at(i).size();
 
1296
        nodes[i].cached_modified = info.at(i).lastModified();
 
1297
#endif
 
1298
    }
 
1299
 
 
1300
    return nodes;
 
1301
}
 
1302
 
 
1303
int QDirModelPrivate::idx(QDirNode *node) const
 
1304
{
 
1305
    Q_ASSERT(node);
 
1306
 
 
1307
    if (node == &root)
 
1308
        return 0;
 
1309
 
 
1310
    const QVector<QDirNode> children = node->parent ? node->parent->children : root.children;
 
1311
    Q_ASSERT(children.count() > 0);
 
1312
 
 
1313
    const QDirNode *first = &(children.at(0));
 
1314
    return (node - first);
 
1315
}
 
1316
 
 
1317
void QDirModelPrivate::refresh(QDirNode *parent)
 
1318
{
 
1319
    QFileInfoList info;
 
1320
    if (!parent)
 
1321
        info = QDir::drives(); 
 
1322
    else if (parent->info.isDir())
 
1323
        info = entryInfoList(parent->info.filePath());
 
1324
 
 
1325
    QVector<QDirNode> *nodes = parent ? &(parent->children) : &(root.children);
 
1326
    if (nodes->count() != info.count())
 
1327
        nodes->resize(info.count());
 
1328
 
 
1329
    for (int i = 0; i < (int)info.count(); ++i) {
 
1330
        (*nodes)[i].parent = parent;
 
1331
        if (resolveSymlinks && info.at(i).isSymLink()) {
 
1332
            QString link = info.at(i).readLink();
 
1333
            if (link.at(link.size() - 1) == QDir::separator())
 
1334
                link.chop(1);
 
1335
            (*nodes)[i].info = QFileInfo(link);
 
1336
        } else {
 
1337
            (*nodes)[i].info = info.at(i);
 
1338
        }
 
1339
        if (nodes->at(i).children.count() > 0)
 
1340
            refresh(&(*nodes)[i]);
 
1341
    }
 
1342
}
 
1343
 
 
1344
void QDirModelPrivate::savePersistentIndexes()
 
1345
{
 
1346
    Q_Q(QDirModel);
 
1347
    saved.clear();
 
1348
    const QList<QPersistentModelIndexData*> indexes = persistent.indexes;
 
1349
    for (int i = 0; i < indexes.count(); ++i) {
 
1350
        QModelIndex idx = indexes.at(i)->index;
 
1351
        QString path = q->filePath(idx);
 
1352
        saved.append(qMakePair(path, idx.column()));
 
1353
        persistent.indexes.at(i)->ref.ref(); // save
 
1354
        persistent.indexes[i]->index = QModelIndex(); // invalidated
 
1355
    }
 
1356
}
 
1357
 
 
1358
void QDirModelPrivate::restorePersistentIndexes()
 
1359
{
 
1360
    Q_Q(QDirModel);
 
1361
    const QList<QPersistentModelIndexData*> indexes = persistent.indexes;
 
1362
    QList<QPersistentModelIndexData*> deleteList;
 
1363
    for (int i = 0; i < indexes.count(); ++i) {
 
1364
        persistent.indexes[i]->index = q->index(saved.at(i).first, saved.at(i).second);
 
1365
        if (!persistent.indexes.at(i)->ref.deref()) // if we have no other references
 
1366
            deleteList.append(indexes.at(i)); // make sure we delete it
 
1367
    }
 
1368
    saved.clear();
 
1369
    while (!deleteList.isEmpty()) {
 
1370
        QPersistentModelIndexData::destroy(deleteList.last());
 
1371
        deleteList.removeLast();
 
1372
    }
 
1373
}
 
1374