src/gui/itemviews/qdirmodel.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qdirmodel.h"
       
    43 
       
    44 #ifndef QT_NO_DIRMODEL
       
    45 #include <qstack.h>
       
    46 #include <qfile.h>
       
    47 #include <qfilesystemmodel.h>
       
    48 #include <qurl.h>
       
    49 #include <qmime.h>
       
    50 #include <qpair.h>
       
    51 #include <qvector.h>
       
    52 #include <qobject.h>
       
    53 #include <qdatetime.h>
       
    54 #include <qlocale.h>
       
    55 #include <qstyle.h>
       
    56 #include <qapplication.h>
       
    57 #include <private/qabstractitemmodel_p.h>
       
    58 #include <qdebug.h>
       
    59 
       
    60 /*!
       
    61     \enum QDirModel::Roles
       
    62     \value FileIconRole
       
    63     \value FilePathRole
       
    64     \value FileNameRole
       
    65 */
       
    66 
       
    67 QT_BEGIN_NAMESPACE
       
    68 
       
    69 class QDirModelPrivate : public QAbstractItemModelPrivate
       
    70 {
       
    71     Q_DECLARE_PUBLIC(QDirModel)
       
    72 
       
    73 public:
       
    74     struct QDirNode
       
    75     {
       
    76         QDirNode() : parent(0), populated(false), stat(false) {}
       
    77         ~QDirNode() { children.clear(); }
       
    78         QDirNode *parent;
       
    79         QFileInfo info;
       
    80         QIcon icon; // cache the icon
       
    81         mutable QVector<QDirNode> children;
       
    82         mutable bool populated; // have we read the children
       
    83         mutable bool stat;
       
    84     };
       
    85 
       
    86     QDirModelPrivate()
       
    87         : resolveSymlinks(true),
       
    88           readOnly(true),
       
    89           lazyChildCount(false),
       
    90           allowAppendChild(true),
       
    91           iconProvider(&defaultProvider),
       
    92           shouldStat(true) // ### This is set to false by QFileDialog
       
    93     { }
       
    94 
       
    95     void init();
       
    96     QDirNode *node(int row, QDirNode *parent) const;
       
    97     QVector<QDirNode> children(QDirNode *parent, bool stat) const;
       
    98 
       
    99     void _q_refresh();
       
   100 
       
   101     void savePersistentIndexes();
       
   102     void restorePersistentIndexes();
       
   103 
       
   104     QFileInfoList entryInfoList(const QString &path) const;
       
   105     QStringList entryList(const QString &path) const;
       
   106 
       
   107     QString name(const QModelIndex &index) const;
       
   108     QString size(const QModelIndex &index) const;
       
   109     QString type(const QModelIndex &index) const;
       
   110     QString time(const QModelIndex &index) const;
       
   111 
       
   112     void appendChild(QDirModelPrivate::QDirNode *parent, const QString &path) const;
       
   113     static QFileInfo resolvedInfo(QFileInfo info);
       
   114 
       
   115     inline QDirNode *node(const QModelIndex &index) const;
       
   116     inline void populate(QDirNode *parent) const;
       
   117     inline void clear(QDirNode *parent) const;
       
   118 
       
   119     void invalidate();
       
   120 
       
   121     mutable QDirNode root;
       
   122     bool resolveSymlinks;
       
   123     bool readOnly;
       
   124     bool lazyChildCount;
       
   125     bool allowAppendChild;
       
   126 
       
   127     QDir::Filters filters;
       
   128     QDir::SortFlags sort;
       
   129     QStringList nameFilters;
       
   130 
       
   131     QFileIconProvider *iconProvider;
       
   132     QFileIconProvider defaultProvider;
       
   133 
       
   134     struct SavedPersistent {
       
   135         QString path;
       
   136         int column;
       
   137         QPersistentModelIndexData *data;
       
   138         QPersistentModelIndex index;
       
   139     };
       
   140     QList<SavedPersistent> savedPersistent;
       
   141     QPersistentModelIndex toBeRefreshed;
       
   142 
       
   143     bool shouldStat; // use the "carefull not to stat directories" mode
       
   144 };
       
   145 
       
   146 void qt_setDirModelShouldNotStat(QDirModelPrivate *modelPrivate)
       
   147 {
       
   148     modelPrivate->shouldStat = false;
       
   149 }
       
   150 
       
   151 QDirModelPrivate::QDirNode *QDirModelPrivate::node(const QModelIndex &index) const
       
   152 {
       
   153     QDirModelPrivate::QDirNode *n =
       
   154         static_cast<QDirModelPrivate::QDirNode*>(index.internalPointer());
       
   155     Q_ASSERT(n);
       
   156     return n;
       
   157 }
       
   158 
       
   159 void QDirModelPrivate::populate(QDirNode *parent) const
       
   160 {
       
   161     Q_ASSERT(parent);
       
   162     parent->children = children(parent, parent->stat);
       
   163     parent->populated = true;
       
   164 }
       
   165 
       
   166 void QDirModelPrivate::clear(QDirNode *parent) const
       
   167 {
       
   168      Q_ASSERT(parent);
       
   169      parent->children.clear();
       
   170      parent->populated = false;
       
   171 }
       
   172 
       
   173 void QDirModelPrivate::invalidate()
       
   174 {
       
   175     QStack<const QDirNode*> nodes;
       
   176     nodes.push(&root);
       
   177     while (!nodes.empty()) {
       
   178         const QDirNode *current = nodes.pop();
       
   179         current->stat = false;
       
   180         const QVector<QDirNode> children = current->children;
       
   181         for (int i = 0; i < children.count(); ++i)
       
   182             nodes.push(&children.at(i));
       
   183     }
       
   184 }
       
   185 
       
   186 /*!
       
   187     \class QDirModel
       
   188 
       
   189     \brief The QDirModel class provides a data model for the local filesystem.
       
   190 
       
   191     \ingroup model-view
       
   192 
       
   193     \note The usage of QDirModel is not recommended anymore. The
       
   194     QFileSystemModel class is a more performant alternative.
       
   195 
       
   196     This class provides access to the local filesystem, providing functions
       
   197     for renaming and removing files and directories, and for creating new
       
   198     directories. In the simplest case, it can be used with a suitable display
       
   199     widget as part of a browser or filer.
       
   200 
       
   201     QDirModel keeps a cache with file information. The cache needs to be
       
   202     updated with refresh().
       
   203 
       
   204     A directory model that displays the contents of a default directory
       
   205     is usually constructed with a parent object:
       
   206 
       
   207     \snippet doc/src/snippets/shareddirmodel/main.cpp 2
       
   208 
       
   209     A tree view can be used to display the contents of the model
       
   210 
       
   211     \snippet doc/src/snippets/shareddirmodel/main.cpp 4
       
   212 
       
   213     and the contents of a particular directory can be displayed by
       
   214     setting the tree view's root index:
       
   215 
       
   216     \snippet doc/src/snippets/shareddirmodel/main.cpp 7
       
   217 
       
   218     The view's root index can be used to control how much of a
       
   219     hierarchical model is displayed. QDirModel provides a convenience
       
   220     function that returns a suitable model index for a path to a
       
   221     directory within the model.
       
   222 
       
   223     QDirModel can be accessed using the standard interface provided by
       
   224     QAbstractItemModel, but it also provides some convenience functions
       
   225     that are specific to a directory model. The fileInfo() and isDir()
       
   226     functions provide information about the underlying files and directories
       
   227     related to items in the model.
       
   228 
       
   229     Directories can be created and removed using mkdir(), rmdir(), and the
       
   230     model will be automatically updated to take the changes into account.
       
   231 
       
   232     \note QDirModel requires an instance of a GUI application.
       
   233 
       
   234     \sa nameFilters(), setFilter(), filter(), QListView, QTreeView, QFileSystemModel,
       
   235     {Dir View Example}, {Model Classes}
       
   236 */
       
   237 
       
   238 /*!
       
   239     Constructs a new directory model with the given \a parent.
       
   240     Only those files matching the \a nameFilters and the
       
   241     \a filters are included in the model. The sort order is given by the
       
   242     \a sort flags.
       
   243 */
       
   244 
       
   245 QDirModel::QDirModel(const QStringList &nameFilters,
       
   246                      QDir::Filters filters,
       
   247                      QDir::SortFlags sort,
       
   248                      QObject *parent)
       
   249     : QAbstractItemModel(*new QDirModelPrivate, parent)
       
   250 {
       
   251     Q_D(QDirModel);
       
   252     // we always start with QDir::drives()
       
   253     d->nameFilters = nameFilters.isEmpty() ? QStringList(QLatin1String("*")) : nameFilters;
       
   254     d->filters = filters;
       
   255     d->sort = sort;
       
   256     d->root.parent = 0;
       
   257     d->root.info = QFileInfo();
       
   258     d->clear(&d->root);
       
   259 }
       
   260 
       
   261 /*!
       
   262   Constructs a directory model with the given \a parent.
       
   263 */
       
   264 
       
   265 QDirModel::QDirModel(QObject *parent)
       
   266     : QAbstractItemModel(*new QDirModelPrivate, parent)
       
   267 {
       
   268     Q_D(QDirModel);
       
   269     d->init();
       
   270 }
       
   271 
       
   272 /*!
       
   273     \internal
       
   274 */
       
   275 QDirModel::QDirModel(QDirModelPrivate &dd, QObject *parent)
       
   276     : QAbstractItemModel(dd, parent)
       
   277 {
       
   278     Q_D(QDirModel);
       
   279     d->init();
       
   280 }
       
   281 
       
   282 /*!
       
   283   Destroys this directory model.
       
   284 */
       
   285 
       
   286 QDirModel::~QDirModel()
       
   287 {
       
   288 
       
   289 }
       
   290 
       
   291 /*!
       
   292   Returns the model item index for the item in the \a parent with the
       
   293   given \a row and \a column.
       
   294 
       
   295 */
       
   296 
       
   297 QModelIndex QDirModel::index(int row, int column, const QModelIndex &parent) const
       
   298 {
       
   299     Q_D(const QDirModel);
       
   300     // note that rowCount does lazy population
       
   301     if (column < 0 || column >= columnCount(parent) || row < 0 || parent.column() > 0)
       
   302         return QModelIndex();
       
   303     // make sure the list of children is up to date
       
   304     QDirModelPrivate::QDirNode *p = (d->indexValid(parent) ? d->node(parent) : &d->root);
       
   305     Q_ASSERT(p);
       
   306     if (!p->populated)
       
   307         d->populate(p); // populate without stat'ing
       
   308     if (row >= p->children.count())
       
   309         return QModelIndex();
       
   310     // now get the internal pointer for the index
       
   311     QDirModelPrivate::QDirNode *n = d->node(row, d->indexValid(parent) ? p : 0);
       
   312     Q_ASSERT(n);
       
   313 
       
   314     return createIndex(row, column, n);
       
   315 }
       
   316 
       
   317 /*!
       
   318   Return the parent of the given \a child model item.
       
   319 */
       
   320 
       
   321 QModelIndex QDirModel::parent(const QModelIndex &child) const
       
   322 {
       
   323     Q_D(const QDirModel);
       
   324 
       
   325     if (!d->indexValid(child))
       
   326 	return QModelIndex();
       
   327     QDirModelPrivate::QDirNode *node = d->node(child);
       
   328     QDirModelPrivate::QDirNode *par = (node ? node->parent : 0);
       
   329     if (par == 0) // parent is the root node
       
   330 	return QModelIndex();
       
   331 
       
   332     // get the parent's row
       
   333     const QVector<QDirModelPrivate::QDirNode> children =
       
   334         par->parent ? par->parent->children : d->root.children;
       
   335     Q_ASSERT(children.count() > 0);
       
   336     int row = (par - &(children.at(0)));
       
   337     Q_ASSERT(row >= 0);
       
   338 
       
   339     return createIndex(row, 0, par);
       
   340 }
       
   341 
       
   342 /*!
       
   343   Returns the number of rows in the \a parent model item.
       
   344 
       
   345 */
       
   346 
       
   347 int QDirModel::rowCount(const QModelIndex &parent) const
       
   348 {
       
   349     Q_D(const QDirModel);
       
   350     if (parent.column() > 0)
       
   351         return 0;
       
   352 
       
   353     if (!parent.isValid()) {
       
   354         if (!d->root.populated) // lazy population
       
   355             d->populate(&d->root);
       
   356         return d->root.children.count();
       
   357     }
       
   358     if (parent.model() != this)
       
   359         return 0;
       
   360     QDirModelPrivate::QDirNode *p = d->node(parent);
       
   361     if (p->info.isDir() && !p->populated) // lazy population
       
   362         d->populate(p);
       
   363     return p->children.count();
       
   364 }
       
   365 
       
   366 /*!
       
   367   Returns the number of columns in the \a parent model item.
       
   368 
       
   369 */
       
   370 
       
   371 int QDirModel::columnCount(const QModelIndex &parent) const
       
   372 {
       
   373     if (parent.column() > 0)
       
   374         return 0;
       
   375     return 4;
       
   376 }
       
   377 
       
   378 /*!
       
   379   Returns the data for the model item \a index with the given \a role.
       
   380 */
       
   381 QVariant QDirModel::data(const QModelIndex &index, int role) const
       
   382 {
       
   383     Q_D(const QDirModel);
       
   384     if (!d->indexValid(index))
       
   385         return QVariant();
       
   386 
       
   387     if (role == Qt::DisplayRole || role == Qt::EditRole) {
       
   388         switch (index.column()) {
       
   389         case 0: return d->name(index);
       
   390         case 1: return d->size(index);
       
   391         case 2: return d->type(index);
       
   392         case 3: return d->time(index);
       
   393         default:
       
   394             qWarning("data: invalid display value column %d", index.column());
       
   395             return QVariant();
       
   396         }
       
   397     }
       
   398 
       
   399     if (index.column() == 0) {
       
   400         if (role == FileIconRole)
       
   401             return fileIcon(index);
       
   402         if (role == FilePathRole)
       
   403             return filePath(index);
       
   404         if (role == FileNameRole)
       
   405             return fileName(index);
       
   406     }
       
   407 
       
   408     if (index.column() == 1 && Qt::TextAlignmentRole == role) {
       
   409         return Qt::AlignRight;
       
   410     }
       
   411     return QVariant();
       
   412 }
       
   413 
       
   414 /*!
       
   415   Sets the data for the model item \a index with the given \a role to
       
   416   the data referenced by the \a value. Returns true if successful;
       
   417   otherwise returns false.
       
   418 
       
   419   \sa Qt::ItemDataRole
       
   420 */
       
   421 
       
   422 bool QDirModel::setData(const QModelIndex &index, const QVariant &value, int role)
       
   423 {
       
   424     Q_D(QDirModel);
       
   425     if (!d->indexValid(index) || index.column() != 0
       
   426         || (flags(index) & Qt::ItemIsEditable) == 0 || role != Qt::EditRole)
       
   427         return false;
       
   428 
       
   429     QDirModelPrivate::QDirNode *node = d->node(index);
       
   430     QDir dir = node->info.dir();
       
   431     QString name = value.toString();
       
   432     if (dir.rename(node->info.fileName(), name)) {
       
   433         node->info = QFileInfo(dir, name);
       
   434         QModelIndex sibling = index.sibling(index.row(), 3);
       
   435         emit dataChanged(index, sibling);
       
   436 
       
   437         d->toBeRefreshed = index.parent();
       
   438         QMetaObject::invokeMethod(this, "_q_refresh", Qt::QueuedConnection);
       
   439 
       
   440         return true;
       
   441     }
       
   442 
       
   443     return false;
       
   444 }
       
   445 
       
   446 /*!
       
   447   Returns the data stored under the given \a role for the specified \a section
       
   448   of the header with the given \a orientation.
       
   449 */
       
   450 
       
   451 QVariant QDirModel::headerData(int section, Qt::Orientation orientation, int role) const
       
   452 {
       
   453     if (orientation == Qt::Horizontal) {
       
   454         if (role != Qt::DisplayRole)
       
   455             return QVariant();
       
   456 	switch (section) {
       
   457         case 0: return tr("Name");
       
   458         case 1: return tr("Size");
       
   459         case 2: return
       
   460 #ifdef Q_OS_MAC
       
   461                        tr("Kind", "Match OS X Finder");
       
   462 #else
       
   463                        tr("Type", "All other platforms");
       
   464 #endif
       
   465         // Windows   - Type
       
   466         // OS X      - Kind
       
   467         // Konqueror - File Type
       
   468         // Nautilus  - Type
       
   469         case 3: return tr("Date Modified");
       
   470         default: return QVariant();
       
   471         }
       
   472     }
       
   473     return QAbstractItemModel::headerData(section, orientation, role);
       
   474 }
       
   475 
       
   476 /*!
       
   477   Returns true if the \a parent model item has children; otherwise
       
   478   returns false.
       
   479 */
       
   480 
       
   481 bool QDirModel::hasChildren(const QModelIndex &parent) const
       
   482 {
       
   483     Q_D(const QDirModel);
       
   484     if (parent.column() > 0)
       
   485         return false;
       
   486 
       
   487     if (!parent.isValid()) // the invalid index is the "My Computer" item
       
   488         return true; // the drives
       
   489     QDirModelPrivate::QDirNode *p = d->node(parent);
       
   490     Q_ASSERT(p);
       
   491 
       
   492     if (d->lazyChildCount) // optimization that only checks for children if the node has been populated
       
   493         return p->info.isDir();
       
   494     return p->info.isDir() && rowCount(parent) > 0;
       
   495 }
       
   496 
       
   497 /*!
       
   498   Returns the item flags for the given \a index in the model.
       
   499 
       
   500   \sa Qt::ItemFlags
       
   501 */
       
   502 Qt::ItemFlags QDirModel::flags(const QModelIndex &index) const
       
   503 {
       
   504     Q_D(const QDirModel);
       
   505     Qt::ItemFlags flags = QAbstractItemModel::flags(index);
       
   506     if (!d->indexValid(index))
       
   507         return flags;
       
   508     flags |= Qt::ItemIsDragEnabled;
       
   509     if (d->readOnly)
       
   510         return flags;
       
   511     QDirModelPrivate::QDirNode *node = d->node(index);
       
   512     if ((index.column() == 0) && node->info.isWritable()) {
       
   513         flags |= Qt::ItemIsEditable;
       
   514         if (fileInfo(index).isDir()) // is directory and is editable
       
   515             flags |= Qt::ItemIsDropEnabled;
       
   516     }
       
   517     return flags;
       
   518 }
       
   519 
       
   520 /*!
       
   521   Sort the model items in the \a column using the \a order given.
       
   522   The order is a value defined in \l Qt::SortOrder.
       
   523 */
       
   524 
       
   525 void QDirModel::sort(int column, Qt::SortOrder order)
       
   526 {
       
   527     QDir::SortFlags sort = QDir::DirsFirst | QDir::IgnoreCase;
       
   528     if (order == Qt::DescendingOrder)
       
   529         sort |= QDir::Reversed;
       
   530 
       
   531     switch (column) {
       
   532     case 0:
       
   533         sort |= QDir::Name;
       
   534         break;
       
   535     case 1:
       
   536         sort |= QDir::Size;
       
   537         break;
       
   538     case 2:
       
   539         sort |= QDir::Type;
       
   540         break;
       
   541     case 3:
       
   542         sort |= QDir::Time;
       
   543         break;
       
   544     default:
       
   545         break;
       
   546     }
       
   547 
       
   548     setSorting(sort);
       
   549 }
       
   550 
       
   551 /*!
       
   552     Returns a list of MIME types that can be used to describe a list of items
       
   553     in the model.
       
   554 */
       
   555 
       
   556 QStringList QDirModel::mimeTypes() const
       
   557 {
       
   558     return QStringList(QLatin1String("text/uri-list"));
       
   559 }
       
   560 
       
   561 /*!
       
   562     Returns an object that contains a serialized description of the specified
       
   563     \a indexes. The format used to describe the items corresponding to the
       
   564     indexes is obtained from the mimeTypes() function.
       
   565 
       
   566     If the list of indexes is empty, 0 is returned rather than a serialized
       
   567     empty list.
       
   568 */
       
   569 
       
   570 QMimeData *QDirModel::mimeData(const QModelIndexList &indexes) const
       
   571 {
       
   572     QList<QUrl> urls;
       
   573     QList<QModelIndex>::const_iterator it = indexes.begin();
       
   574     for (; it != indexes.end(); ++it)
       
   575         if ((*it).column() == 0)
       
   576             urls << QUrl::fromLocalFile(filePath(*it));
       
   577     QMimeData *data = new QMimeData();
       
   578     data->setUrls(urls);
       
   579     return data;
       
   580 }
       
   581 
       
   582 /*!
       
   583     Handles the \a data supplied by a drag and drop operation that ended with
       
   584     the given \a action over the row in the model specified by the \a row and
       
   585     \a column and by the \a parent index.
       
   586 
       
   587     \sa supportedDropActions()
       
   588 */
       
   589 
       
   590 bool QDirModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
       
   591                              int /* row */, int /* column */, const QModelIndex &parent)
       
   592 {
       
   593     Q_D(QDirModel);
       
   594     if (!d->indexValid(parent) || isReadOnly())
       
   595         return false;
       
   596 
       
   597     bool success = true;
       
   598     QString to = filePath(parent) + QDir::separator();
       
   599     QModelIndex _parent = parent;
       
   600 
       
   601     QList<QUrl> urls = data->urls();
       
   602     QList<QUrl>::const_iterator it = urls.constBegin();
       
   603 
       
   604     switch (action) {
       
   605     case Qt::CopyAction:
       
   606         for (; it != urls.constEnd(); ++it) {
       
   607             QString path = (*it).toLocalFile();
       
   608             success = QFile::copy(path, to + QFileInfo(path).fileName()) && success;
       
   609         }
       
   610         break;
       
   611     case Qt::LinkAction:
       
   612         for (; it != urls.constEnd(); ++it) {
       
   613             QString path = (*it).toLocalFile();
       
   614             success = QFile::link(path, to + QFileInfo(path).fileName()) && success;
       
   615         }
       
   616         break;
       
   617     case Qt::MoveAction:
       
   618         for (; it != urls.constEnd(); ++it) {
       
   619             QString path = (*it).toLocalFile();
       
   620             if (QFile::copy(path, to + QFileInfo(path).fileName())
       
   621                && QFile::remove(path)) {
       
   622                 QModelIndex idx=index(QFileInfo(path).path());
       
   623                 if (idx.isValid()) {
       
   624                     refresh(idx);
       
   625                     //the previous call to refresh may invalidate the _parent. so recreate a new QModelIndex
       
   626                     _parent = index(to);
       
   627                 }
       
   628             } else {
       
   629                 success = false;
       
   630             }
       
   631         }
       
   632         break;
       
   633     default:
       
   634         return false;
       
   635     }
       
   636 
       
   637     if (success)
       
   638         refresh(_parent);
       
   639 
       
   640     return success;
       
   641 }
       
   642 
       
   643 /*!
       
   644   Returns the drop actions supported by this model.
       
   645 
       
   646   \sa Qt::DropActions
       
   647 */
       
   648 
       
   649 Qt::DropActions QDirModel::supportedDropActions() const
       
   650 {
       
   651     return Qt::CopyAction | Qt::MoveAction; // FIXME: LinkAction is not supported yet
       
   652 }
       
   653 
       
   654 /*!
       
   655   Sets the \a provider of file icons for the directory model.
       
   656 
       
   657 */
       
   658 
       
   659 void QDirModel::setIconProvider(QFileIconProvider *provider)
       
   660 {
       
   661     Q_D(QDirModel);
       
   662     d->iconProvider = provider;
       
   663 }
       
   664 
       
   665 /*!
       
   666   Returns the file icon provider for this directory model.
       
   667 */
       
   668 
       
   669 QFileIconProvider *QDirModel::iconProvider() const
       
   670 {
       
   671     Q_D(const QDirModel);
       
   672     return d->iconProvider;
       
   673 }
       
   674 
       
   675 /*!
       
   676   Sets the name \a filters for the directory model.
       
   677 */
       
   678 
       
   679 void QDirModel::setNameFilters(const QStringList &filters)
       
   680 {
       
   681     Q_D(QDirModel);
       
   682     d->nameFilters = filters;
       
   683     emit layoutAboutToBeChanged();
       
   684     if (d->shouldStat)
       
   685        refresh(QModelIndex());
       
   686     else
       
   687         d->invalidate();
       
   688     emit layoutChanged();
       
   689 }
       
   690 
       
   691 /*!
       
   692   Returns a list of filters applied to the names in the model.
       
   693 */
       
   694 
       
   695 QStringList QDirModel::nameFilters() const
       
   696 {
       
   697     Q_D(const QDirModel);
       
   698     return d->nameFilters;
       
   699 }
       
   700 
       
   701 /*!
       
   702   Sets the directory model's filter to that specified by \a filters.
       
   703 
       
   704   Note that the filter you set should always include the QDir::AllDirs enum value,
       
   705   otherwise QDirModel won't be able to read the directory structure.
       
   706 
       
   707   \sa QDir::Filters
       
   708 */
       
   709 
       
   710 void QDirModel::setFilter(QDir::Filters filters)
       
   711 {
       
   712     Q_D(QDirModel);
       
   713     d->filters = filters;
       
   714     emit layoutAboutToBeChanged();
       
   715     if (d->shouldStat)
       
   716         refresh(QModelIndex());
       
   717     else
       
   718         d->invalidate();
       
   719     emit layoutChanged();
       
   720 }
       
   721 
       
   722 /*!
       
   723   Returns the filter specification for the directory model.
       
   724 
       
   725   \sa QDir::Filters
       
   726 */
       
   727 
       
   728 QDir::Filters QDirModel::filter() const
       
   729 {
       
   730     Q_D(const QDirModel);
       
   731     return d->filters;
       
   732 }
       
   733 
       
   734 /*!
       
   735   Sets the directory model's sorting order to that specified by \a sort.
       
   736 
       
   737   \sa QDir::SortFlags
       
   738 */
       
   739 
       
   740 void QDirModel::setSorting(QDir::SortFlags sort)
       
   741 {
       
   742     Q_D(QDirModel);
       
   743     d->sort = sort;
       
   744     emit layoutAboutToBeChanged();
       
   745     if (d->shouldStat)
       
   746         refresh(QModelIndex());
       
   747     else
       
   748         d->invalidate();
       
   749     emit layoutChanged();
       
   750 }
       
   751 
       
   752 /*!
       
   753   Returns the sorting method used for the directory model.
       
   754 
       
   755   \sa QDir::SortFlags */
       
   756 
       
   757 QDir::SortFlags QDirModel::sorting() const
       
   758 {
       
   759     Q_D(const QDirModel);
       
   760     return d->sort;
       
   761 }
       
   762 
       
   763 /*!
       
   764     \property QDirModel::resolveSymlinks
       
   765     \brief Whether the directory model should resolve symbolic links
       
   766 
       
   767     This is only relevant on operating systems that support symbolic
       
   768     links.
       
   769 */
       
   770 void QDirModel::setResolveSymlinks(bool enable)
       
   771 {
       
   772     Q_D(QDirModel);
       
   773     d->resolveSymlinks = enable;
       
   774 }
       
   775 
       
   776 bool QDirModel::resolveSymlinks() const
       
   777 {
       
   778     Q_D(const QDirModel);
       
   779     return d->resolveSymlinks;
       
   780 }
       
   781 
       
   782 /*!
       
   783   \property QDirModel::readOnly
       
   784   \brief Whether the directory model allows writing to the file system
       
   785 
       
   786   If this property is set to false, the directory model will allow renaming, copying
       
   787   and deleting of files and directories.
       
   788 
       
   789   This property is true by default
       
   790 */
       
   791 
       
   792 void QDirModel::setReadOnly(bool enable)
       
   793 {
       
   794     Q_D(QDirModel);
       
   795     d->readOnly = enable;
       
   796 }
       
   797 
       
   798 bool QDirModel::isReadOnly() const
       
   799 {
       
   800     Q_D(const QDirModel);
       
   801     return d->readOnly;
       
   802 }
       
   803 
       
   804 /*!
       
   805   \property QDirModel::lazyChildCount
       
   806   \brief Whether the directory model optimizes the hasChildren function
       
   807   to only check if the item is a directory.
       
   808 
       
   809   If this property is set to false, the directory model will make sure that a directory
       
   810   actually containes any files before reporting that it has children.
       
   811   Otherwise the directory model will report that an item has children if the item
       
   812   is a directory.
       
   813 
       
   814   This property is false by default
       
   815 */
       
   816 
       
   817 void QDirModel::setLazyChildCount(bool enable)
       
   818 {
       
   819     Q_D(QDirModel);
       
   820     d->lazyChildCount = enable;
       
   821 }
       
   822 
       
   823 bool QDirModel::lazyChildCount() const
       
   824 {
       
   825     Q_D(const QDirModel);
       
   826     return d->lazyChildCount;
       
   827 }
       
   828 
       
   829 /*!
       
   830   QDirModel caches file information. This function updates the
       
   831   cache. The \a parent parameter is the directory from which the
       
   832   model is updated; the default value will update the model from
       
   833   root directory of the file system (the entire model).
       
   834 */
       
   835 
       
   836 void QDirModel::refresh(const QModelIndex &parent)
       
   837 {
       
   838     Q_D(QDirModel);
       
   839 
       
   840     QDirModelPrivate::QDirNode *n = d->indexValid(parent) ? d->node(parent) : &(d->root);
       
   841 
       
   842     int rows = n->children.count();
       
   843     if (rows == 0) {
       
   844         emit layoutAboutToBeChanged();
       
   845         n->stat = true; // make sure that next time we read all the info
       
   846         n->populated = false;
       
   847         emit layoutChanged();
       
   848         return;
       
   849     }
       
   850 
       
   851     emit layoutAboutToBeChanged();
       
   852     d->savePersistentIndexes();
       
   853     d->rowsAboutToBeRemoved(parent, 0, rows - 1);
       
   854     n->stat = true; // make sure that next time we read all the info
       
   855     d->clear(n);
       
   856     d->rowsRemoved(parent, 0, rows - 1);
       
   857     d->restorePersistentIndexes();
       
   858     emit layoutChanged();
       
   859 }
       
   860 
       
   861 /*!
       
   862     \overload
       
   863 
       
   864     Returns the model item index for the given \a path.
       
   865 */
       
   866 
       
   867 QModelIndex QDirModel::index(const QString &path, int column) const
       
   868 {
       
   869     Q_D(const QDirModel);
       
   870 
       
   871     if (path.isEmpty() || path == QCoreApplication::translate("QFileDialog", "My Computer"))
       
   872         return QModelIndex();
       
   873 
       
   874     QString absolutePath = QDir(path).absolutePath();
       
   875 #if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN)
       
   876     absolutePath = absolutePath.toLower();
       
   877 #endif
       
   878 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
       
   879     // On Windows, "filename......." and "filename" are equivalent
       
   880     if (absolutePath.endsWith(QLatin1Char('.'))) {
       
   881         int i;
       
   882         for (i = absolutePath.count() - 1; i >= 0; --i) {
       
   883             if (absolutePath.at(i) != QLatin1Char('.'))
       
   884                 break;
       
   885         }
       
   886         absolutePath = absolutePath.left(i+1);
       
   887     }
       
   888 #endif
       
   889 
       
   890     QStringList pathElements = absolutePath.split(QLatin1Char('/'), QString::SkipEmptyParts);
       
   891     if ((pathElements.isEmpty() || !QFileInfo(path).exists())
       
   892 #if !defined(Q_OS_WIN) || defined(Q_OS_WINCE)
       
   893         && path != QLatin1String("/")
       
   894 #endif
       
   895         )
       
   896         return QModelIndex();
       
   897 
       
   898     QModelIndex idx; // start with "My Computer"
       
   899     if (!d->root.populated) // make sure the root is populated
       
   900         d->populate(&d->root);
       
   901 
       
   902 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
       
   903     if (absolutePath.startsWith(QLatin1String("//"))) { // UNC path
       
   904         QString host = pathElements.first();
       
   905         int r = 0;
       
   906         for (; r < d->root.children.count(); ++r)
       
   907             if (d->root.children.at(r).info.fileName() == host)
       
   908                 break;
       
   909         bool childAppended = false;
       
   910         if (r >= d->root.children.count() && d->allowAppendChild) {
       
   911             d->appendChild(&d->root, QLatin1String("//") + host);
       
   912             childAppended = true;
       
   913         }
       
   914         idx = index(r, 0, QModelIndex());
       
   915         pathElements.pop_front();
       
   916         if (childAppended)
       
   917             emit const_cast<QDirModel*>(this)->layoutChanged();
       
   918     } else 
       
   919 #endif
       
   920 #if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN)
       
   921     if (pathElements.at(0).endsWith(QLatin1Char(':'))) {
       
   922         pathElements[0] += QLatin1Char('/');
       
   923     }
       
   924 #else
       
   925     // add the "/" item, since it is a valid path element on unix
       
   926     pathElements.prepend(QLatin1String("/"));
       
   927 #endif
       
   928 
       
   929     for (int i = 0; i < pathElements.count(); ++i) {
       
   930         Q_ASSERT(!pathElements.at(i).isEmpty());
       
   931         QString element = pathElements.at(i);
       
   932         QDirModelPrivate::QDirNode *parent = (idx.isValid() ? d->node(idx) : &d->root);
       
   933 
       
   934         Q_ASSERT(parent);
       
   935         if (!parent->populated)
       
   936             d->populate(parent);
       
   937 
       
   938         // search for the element in the child nodes first
       
   939         int row = -1;
       
   940         for (int j = parent->children.count() - 1; j >= 0; --j) {
       
   941             const QFileInfo& fi = parent->children.at(j).info;
       
   942             QString childFileName;
       
   943             childFileName = idx.isValid() ? fi.fileName() : fi.absoluteFilePath();
       
   944 #if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN)
       
   945             childFileName = childFileName.toLower();
       
   946 #endif
       
   947             if (childFileName == element) {
       
   948                 if (i == pathElements.count() - 1)
       
   949                     parent->children[j].stat = true;
       
   950                 row = j;
       
   951                 break;
       
   952             }
       
   953         }
       
   954 
       
   955         // we couldn't find the path element, we create a new node since we _know_ that the path is valid
       
   956         if (row == -1) {
       
   957 #if defined(Q_OS_WINCE)
       
   958             QString newPath;
       
   959             if (parent->info.isRoot())
       
   960                 newPath = parent->info.absoluteFilePath() + element;
       
   961             else
       
   962                 newPath = parent->info.absoluteFilePath() + QLatin1Char('/') + element;
       
   963 #else
       
   964             QString newPath = parent->info.absoluteFilePath() + QLatin1Char('/') + element;
       
   965 #endif
       
   966             if (!d->allowAppendChild || !QFileInfo(newPath).isDir())
       
   967                 return QModelIndex();
       
   968             d->appendChild(parent, newPath);
       
   969             row = parent->children.count() - 1;
       
   970             if (i == pathElements.count() - 1) // always stat children of  the last element
       
   971                 parent->children[row].stat = true;
       
   972             emit const_cast<QDirModel*>(this)->layoutChanged();
       
   973         }
       
   974 
       
   975         Q_ASSERT(row >= 0);
       
   976         idx = createIndex(row, 0, static_cast<void*>(&parent->children[row]));
       
   977         Q_ASSERT(idx.isValid());
       
   978     }
       
   979 
       
   980     if (column != 0)
       
   981         return idx.sibling(idx.row(), column);
       
   982     return idx;
       
   983 }
       
   984 
       
   985 /*!
       
   986   Returns true if the model item \a index represents a directory;
       
   987   otherwise returns false.
       
   988 */
       
   989 
       
   990 bool QDirModel::isDir(const QModelIndex &index) const
       
   991 {
       
   992     Q_D(const QDirModel);
       
   993     Q_ASSERT(d->indexValid(index));
       
   994     QDirModelPrivate::QDirNode *node = d->node(index);
       
   995     return node->info.isDir();
       
   996 }
       
   997 
       
   998 /*!
       
   999   Create a directory with the \a name in the \a parent model item.
       
  1000 */
       
  1001 
       
  1002 QModelIndex QDirModel::mkdir(const QModelIndex &parent, const QString &name)
       
  1003 {
       
  1004     Q_D(QDirModel);
       
  1005     if (!d->indexValid(parent) || isReadOnly())
       
  1006         return QModelIndex();
       
  1007 
       
  1008     QDirModelPrivate::QDirNode *p = d->node(parent);
       
  1009     QString path = p->info.absoluteFilePath();
       
  1010     // For the indexOf() method to work, the new directory has to be a direct child of
       
  1011     // the parent directory.
       
  1012 
       
  1013     QDir newDir(name);
       
  1014     QDir dir(path);
       
  1015     if (newDir.isRelative())
       
  1016         newDir = QDir(path + QLatin1Char('/') + name);
       
  1017     QString childName = newDir.dirName(); // Get the singular name of the directory
       
  1018     newDir.cdUp();
       
  1019 
       
  1020     if (newDir.absolutePath() != dir.absolutePath() || !dir.mkdir(name))
       
  1021         return QModelIndex(); // nothing happened
       
  1022 
       
  1023     refresh(parent);
       
  1024 
       
  1025     QStringList entryList = d->entryList(path);
       
  1026     int r = entryList.indexOf(childName);
       
  1027     QModelIndex i = index(r, 0, parent); // return an invalid index
       
  1028 
       
  1029     return i;
       
  1030 }
       
  1031 
       
  1032 /*!
       
  1033   Removes the directory corresponding to the model item \a index in the
       
  1034   directory model and \bold{deletes the corresponding directory from the
       
  1035   file system}, returning true if successful. If the directory cannot be
       
  1036   removed, false is returned.
       
  1037 
       
  1038   \warning This function deletes directories from the file system; it does
       
  1039   \bold{not} move them to a location where they can be recovered.
       
  1040 
       
  1041   \sa remove()
       
  1042 */
       
  1043 
       
  1044 bool QDirModel::rmdir(const QModelIndex &index)
       
  1045 {
       
  1046     Q_D(QDirModel);
       
  1047     if (!d->indexValid(index) || isReadOnly())
       
  1048         return false;
       
  1049 
       
  1050     QDirModelPrivate::QDirNode *n = d_func()->node(index);
       
  1051     if (!n->info.isDir()) {
       
  1052         qWarning("rmdir: the node is not a directory");
       
  1053         return false;
       
  1054     }
       
  1055 
       
  1056     QModelIndex par = parent(index);
       
  1057     QDirModelPrivate::QDirNode *p = d_func()->node(par);
       
  1058     QDir dir = p->info.dir(); // parent dir
       
  1059     QString path = n->info.absoluteFilePath();
       
  1060     if (!dir.rmdir(path))
       
  1061         return false;
       
  1062 
       
  1063     refresh(par);
       
  1064 
       
  1065     return true;
       
  1066 }
       
  1067 
       
  1068 /*!
       
  1069   Removes the model item \a index from the directory model and \bold{deletes the
       
  1070   corresponding file from the file system}, returning true if successful. If the
       
  1071   item cannot be removed, false is returned.
       
  1072 
       
  1073   \warning This function deletes files from the file system; it does \bold{not}
       
  1074   move them to a location where they can be recovered.
       
  1075 
       
  1076   \sa rmdir()
       
  1077 */
       
  1078 
       
  1079 bool QDirModel::remove(const QModelIndex &index)
       
  1080 {
       
  1081     Q_D(QDirModel);
       
  1082     if (!d->indexValid(index) || isReadOnly())
       
  1083         return false;
       
  1084 
       
  1085     QDirModelPrivate::QDirNode *n = d_func()->node(index);
       
  1086     if (n->info.isDir())
       
  1087         return false;
       
  1088 
       
  1089     QModelIndex par = parent(index);
       
  1090     QDirModelPrivate::QDirNode *p = d_func()->node(par);
       
  1091     QDir dir = p->info.dir(); // parent dir
       
  1092     QString path = n->info.absoluteFilePath();
       
  1093     if (!dir.remove(path))
       
  1094         return false;
       
  1095 
       
  1096     refresh(par);
       
  1097 
       
  1098     return true;
       
  1099 }
       
  1100 
       
  1101 /*!
       
  1102   Returns the path of the item stored in the model under the
       
  1103   \a index given.
       
  1104 
       
  1105 */
       
  1106 
       
  1107 QString QDirModel::filePath(const QModelIndex &index) const
       
  1108 {
       
  1109     Q_D(const QDirModel);
       
  1110     if (d->indexValid(index)) {
       
  1111         QFileInfo fi = fileInfo(index);
       
  1112         if (d->resolveSymlinks && fi.isSymLink())
       
  1113             fi = d->resolvedInfo(fi);
       
  1114         return QDir::cleanPath(fi.absoluteFilePath());
       
  1115     }
       
  1116     return QString(); // root path
       
  1117 }
       
  1118 
       
  1119 /*!
       
  1120   Returns the name of the item stored in the model under the
       
  1121   \a index given.
       
  1122 
       
  1123 */
       
  1124 
       
  1125 QString QDirModel::fileName(const QModelIndex &index) const
       
  1126 {
       
  1127     Q_D(const QDirModel);
       
  1128     if (!d->indexValid(index))
       
  1129         return QString();
       
  1130     QFileInfo info = fileInfo(index);
       
  1131     if (info.isRoot())
       
  1132         return info.absoluteFilePath();
       
  1133     if (d->resolveSymlinks && info.isSymLink())
       
  1134         info = d->resolvedInfo(info);
       
  1135     return info.fileName();
       
  1136 }
       
  1137 
       
  1138 /*!
       
  1139   Returns the icons for the item stored in the model under the given
       
  1140   \a index.
       
  1141 */
       
  1142 
       
  1143 QIcon QDirModel::fileIcon(const QModelIndex &index) const
       
  1144 {
       
  1145     Q_D(const QDirModel);
       
  1146     if (!d->indexValid(index))
       
  1147         return d->iconProvider->icon(QFileIconProvider::Computer);
       
  1148     QDirModelPrivate::QDirNode *node = d->node(index);
       
  1149     if (node->icon.isNull())
       
  1150         node->icon = d->iconProvider->icon(node->info);
       
  1151     return node->icon;
       
  1152 }
       
  1153 
       
  1154 /*!
       
  1155   Returns the file information for the specified model \a index.
       
  1156 
       
  1157   \bold{Note:} If the model index represents a symbolic link in the
       
  1158   underlying filing system, the file information returned will contain
       
  1159   information about the symbolic link itself, regardless of whether
       
  1160   resolveSymlinks is enabled or not.
       
  1161 
       
  1162   \sa QFileInfo::symLinkTarget()
       
  1163 */
       
  1164 
       
  1165 QFileInfo QDirModel::fileInfo(const QModelIndex &index) const
       
  1166 {
       
  1167     Q_D(const QDirModel);
       
  1168     Q_ASSERT(d->indexValid(index));
       
  1169 
       
  1170     QDirModelPrivate::QDirNode *node = d->node(index);
       
  1171     return node->info;
       
  1172 }
       
  1173 
       
  1174 /*!
       
  1175   \fn QObject *QDirModel::parent() const
       
  1176   \internal
       
  1177 */
       
  1178 
       
  1179 /*
       
  1180   The root node is never seen outside the model.
       
  1181 */
       
  1182 
       
  1183 void QDirModelPrivate::init()
       
  1184 {
       
  1185     filters = QDir::AllEntries | QDir::NoDotAndDotDot;
       
  1186     sort = QDir::Name;
       
  1187     nameFilters << QLatin1String("*");
       
  1188     root.parent = 0;
       
  1189     root.info = QFileInfo();
       
  1190     clear(&root);
       
  1191 }
       
  1192 
       
  1193 QDirModelPrivate::QDirNode *QDirModelPrivate::node(int row, QDirNode *parent) const
       
  1194 {
       
  1195     if (row < 0)
       
  1196 	return 0;
       
  1197 
       
  1198     bool isDir = !parent || parent->info.isDir();
       
  1199     QDirNode *p = (parent ? parent : &root);
       
  1200     if (isDir && !p->populated)
       
  1201         populate(p); // will also resolve symlinks
       
  1202 
       
  1203     if (row >= p->children.count()) {
       
  1204         qWarning("node: the row does not exist");
       
  1205         return 0;
       
  1206     }
       
  1207 
       
  1208     return const_cast<QDirNode*>(&p->children.at(row));
       
  1209 }
       
  1210 
       
  1211 QVector<QDirModelPrivate::QDirNode> QDirModelPrivate::children(QDirNode *parent, bool stat) const
       
  1212 {
       
  1213     Q_ASSERT(parent);
       
  1214     QFileInfoList infoList;
       
  1215     if (parent == &root) {
       
  1216         parent = 0;
       
  1217         infoList = QDir::drives();
       
  1218     } else if (parent->info.isDir()) {
       
  1219         //resolve directory links only if requested.
       
  1220         if (parent->info.isSymLink() && resolveSymlinks) {
       
  1221             QString link = parent->info.symLinkTarget();
       
  1222             if (link.size() > 1 && link.at(link.size() - 1) == QDir::separator())
       
  1223                 link.chop(1);
       
  1224             if (stat)
       
  1225                 infoList = entryInfoList(link);
       
  1226             else
       
  1227                 infoList = QDir(link).entryInfoList(nameFilters, QDir::AllEntries | QDir::System);
       
  1228         } else {
       
  1229             if (stat)
       
  1230                 infoList = entryInfoList(parent->info.absoluteFilePath());
       
  1231             else
       
  1232                 infoList = QDir(parent->info.absoluteFilePath()).entryInfoList(nameFilters, QDir::AllEntries | QDir::System);
       
  1233         }
       
  1234     }
       
  1235 
       
  1236     QVector<QDirNode> nodes(infoList.count());
       
  1237     for (int i = 0; i < infoList.count(); ++i) {
       
  1238         QDirNode &node = nodes[i];
       
  1239         node.parent = parent;
       
  1240         node.info = infoList.at(i);
       
  1241         node.populated = false;
       
  1242         node.stat = shouldStat;
       
  1243     }
       
  1244 
       
  1245     return nodes;
       
  1246 }
       
  1247 
       
  1248 void QDirModelPrivate::_q_refresh()
       
  1249 {
       
  1250     Q_Q(QDirModel);
       
  1251     q->refresh(toBeRefreshed);
       
  1252     toBeRefreshed = QModelIndex();
       
  1253 }
       
  1254 
       
  1255 void QDirModelPrivate::savePersistentIndexes()
       
  1256 {
       
  1257     Q_Q(QDirModel);
       
  1258     savedPersistent.clear();
       
  1259     foreach (QPersistentModelIndexData *data, persistent.indexes) {
       
  1260         SavedPersistent saved;
       
  1261         QModelIndex index = data->index;
       
  1262         saved.path = q->filePath(index);
       
  1263         saved.column = index.column();
       
  1264         saved.data = data;
       
  1265         saved.index = index;
       
  1266         savedPersistent.append(saved);
       
  1267     }
       
  1268 }
       
  1269 
       
  1270 void QDirModelPrivate::restorePersistentIndexes()
       
  1271 {
       
  1272     Q_Q(QDirModel);
       
  1273     bool allow = allowAppendChild;
       
  1274     allowAppendChild = false;
       
  1275     for (int i = 0; i < savedPersistent.count(); ++i) {
       
  1276         QPersistentModelIndexData *data = savedPersistent.at(i).data;
       
  1277         QString path = savedPersistent.at(i).path;
       
  1278         int column = savedPersistent.at(i).column;
       
  1279         QModelIndex idx = q->index(path, column);
       
  1280         if (idx != data->index || data->model == 0) {
       
  1281             //data->model may be equal to 0 if the model is getting destroyed
       
  1282             persistent.indexes.remove(data->index);
       
  1283             data->index = idx;
       
  1284             data->model = q;
       
  1285             if (idx.isValid())
       
  1286                 persistent.indexes.insert(idx, data);
       
  1287         }
       
  1288     }
       
  1289     savedPersistent.clear();
       
  1290     allowAppendChild = allow;
       
  1291 }
       
  1292 
       
  1293 QFileInfoList QDirModelPrivate::entryInfoList(const QString &path) const
       
  1294 {
       
  1295     const QDir dir(path);
       
  1296     return dir.entryInfoList(nameFilters, filters, sort);
       
  1297 }
       
  1298 
       
  1299 QStringList QDirModelPrivate::entryList(const QString &path) const
       
  1300 {
       
  1301     const QDir dir(path);
       
  1302     return dir.entryList(nameFilters, filters, sort);
       
  1303 }
       
  1304 
       
  1305 QString QDirModelPrivate::name(const QModelIndex &index) const
       
  1306 {
       
  1307     const QDirNode *n = node(index);
       
  1308     const QFileInfo info = n->info;
       
  1309     if (info.isRoot()) {
       
  1310         QString name = info.absoluteFilePath();
       
  1311 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
       
  1312         if (name.startsWith(QLatin1Char('/'))) // UNC host
       
  1313             return info.fileName();
       
  1314 #endif        
       
  1315 #if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN)
       
  1316         if (name.endsWith(QLatin1Char('/')))
       
  1317             name.chop(1);
       
  1318 #endif
       
  1319         return name;
       
  1320     }
       
  1321     return info.fileName();
       
  1322 }
       
  1323 
       
  1324 QString QDirModelPrivate::size(const QModelIndex &index) const
       
  1325 {
       
  1326     const QDirNode *n = node(index);
       
  1327     if (n->info.isDir()) {
       
  1328 #ifdef Q_OS_MAC
       
  1329         return QLatin1String("--");
       
  1330 #else
       
  1331         return QLatin1String("");
       
  1332 #endif
       
  1333     // Windows   - ""
       
  1334     // OS X      - "--"
       
  1335     // Konqueror - "4 KB"
       
  1336     // Nautilus  - "9 items" (the number of children)
       
  1337     }
       
  1338 
       
  1339     // According to the Si standard KB is 1000 bytes, KiB is 1024
       
  1340     // but on windows sizes are calulated by dividing by 1024 so we do what they do.
       
  1341     const quint64 kb = 1024;
       
  1342     const quint64 mb = 1024 * kb;
       
  1343     const quint64 gb = 1024 * mb;
       
  1344     const quint64 tb = 1024 * gb;
       
  1345     quint64 bytes = n->info.size();
       
  1346     if (bytes >= tb)
       
  1347         return QFileSystemModel::tr("%1 TB").arg(QLocale().toString(qreal(bytes) / tb, 'f', 3));
       
  1348     if (bytes >= gb)
       
  1349         return QFileSystemModel::tr("%1 GB").arg(QLocale().toString(qreal(bytes) / gb, 'f', 2));
       
  1350     if (bytes >= mb)
       
  1351         return QFileSystemModel::tr("%1 MB").arg(QLocale().toString(qreal(bytes) / mb, 'f', 1));
       
  1352     if (bytes >= kb)
       
  1353         return QFileSystemModel::tr("%1 KB").arg(QLocale().toString(bytes / kb));
       
  1354     return QFileSystemModel::tr("%1 bytes").arg(QLocale().toString(bytes));
       
  1355 }
       
  1356 
       
  1357 QString QDirModelPrivate::type(const QModelIndex &index) const
       
  1358 {
       
  1359     return iconProvider->type(node(index)->info);
       
  1360 }
       
  1361 
       
  1362 QString QDirModelPrivate::time(const QModelIndex &index) const
       
  1363 {
       
  1364 #ifndef QT_NO_DATESTRING
       
  1365     return node(index)->info.lastModified().toString(Qt::LocalDate);
       
  1366 #else
       
  1367     Q_UNUSED(index);
       
  1368     return QString();
       
  1369 #endif
       
  1370 }
       
  1371 
       
  1372 void QDirModelPrivate::appendChild(QDirModelPrivate::QDirNode *parent, const QString &path) const
       
  1373 {
       
  1374     QDirModelPrivate::QDirNode node;
       
  1375     node.populated = false;
       
  1376     node.stat = shouldStat;
       
  1377     node.parent = (parent == &root ? 0 : parent);
       
  1378     node.info = QFileInfo(path);
       
  1379     node.info.setCaching(true);
       
  1380 
       
  1381     // The following append(node) may reallocate the vector, thus
       
  1382     // we need to update the pointers to the childnodes parent.
       
  1383     QDirModelPrivate *that = const_cast<QDirModelPrivate *>(this);
       
  1384     that->savePersistentIndexes();
       
  1385     parent->children.append(node);
       
  1386     for (int i = 0; i < parent->children.count(); ++i) {
       
  1387         QDirNode *childNode = &parent->children[i];
       
  1388         for (int j = 0; j < childNode->children.count(); ++j)
       
  1389             childNode->children[j].parent = childNode;
       
  1390     }
       
  1391     that->restorePersistentIndexes();
       
  1392 }
       
  1393 
       
  1394 QFileInfo QDirModelPrivate::resolvedInfo(QFileInfo info)
       
  1395 {
       
  1396 #ifdef Q_OS_WIN
       
  1397     // On windows, we cannot create a shortcut to a shortcut.
       
  1398     return QFileInfo(info.symLinkTarget());
       
  1399 #else
       
  1400     QStringList paths;
       
  1401     do {
       
  1402         QFileInfo link(info.symLinkTarget());
       
  1403         if (link.isRelative())
       
  1404             info.setFile(info.absolutePath(), link.filePath());
       
  1405         else
       
  1406             info = link;
       
  1407         if (paths.contains(info.absoluteFilePath()))
       
  1408             return QFileInfo();
       
  1409         paths.append(info.absoluteFilePath());
       
  1410     } while (info.isSymLink());
       
  1411     return info;
       
  1412 #endif
       
  1413 }
       
  1414 
       
  1415 QT_END_NAMESPACE
       
  1416 
       
  1417 #include "moc_qdirmodel.cpp"
       
  1418 
       
  1419 #endif // QT_NO_DIRMODEL