util/src/gui/dialogs/qfilesystemmodel.cpp
changeset 7 f7bc934e204c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 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 "qfilesystemmodel_p.h"
       
    43 #include "qfilesystemmodel.h"
       
    44 #include <qlocale.h>
       
    45 #include <qmime.h>
       
    46 #include <qurl.h>
       
    47 #include <qdebug.h>
       
    48 #include <qmessagebox.h>
       
    49 #include <qapplication.h>
       
    50 
       
    51 #ifdef Q_OS_WIN
       
    52 #include <qt_windows.h>
       
    53 #endif
       
    54 
       
    55 QT_BEGIN_NAMESPACE
       
    56 
       
    57 #ifndef QT_NO_FILESYSTEMMODEL
       
    58 
       
    59 /*!
       
    60     \enum QFileSystemModel::Roles
       
    61     \value FileIconRole
       
    62     \value FilePathRole
       
    63     \value FileNameRole
       
    64     \value FilePermissions
       
    65 */
       
    66 
       
    67 /*!
       
    68     \class QFileSystemModel
       
    69     \since 4.4
       
    70 
       
    71     \brief The QFileSystemModel class provides a data model for the local filesystem.
       
    72 
       
    73     \ingroup model-view
       
    74 
       
    75     This class provides access to the local filesystem, providing functions
       
    76     for renaming and removing files and directories, and for creating new
       
    77     directories. In the simplest case, it can be used with a suitable display
       
    78     widget as part of a browser or filter.
       
    79 
       
    80     QFileSystemModel will not fetch any files or directories until setRootPath
       
    81     is called.  This will prevent any unnecessary querying on the file system
       
    82     until that point such as listing the drives on Windows.
       
    83 
       
    84     Unlike the QDirModel, QFileSystemModel uses a separate thread to populate
       
    85     itself so it will not cause the main thread to hang as the file system
       
    86     is being queried.  Calls to rowCount() will return 0 until the model
       
    87     populates a directory.
       
    88 
       
    89     QFileSystemModel keeps a cache with file information. The cache is
       
    90     automatically kept up to date using the QFileSystemWatcher.
       
    91 
       
    92     QFileSystemModel can be accessed using the standard interface provided by
       
    93     QAbstractItemModel, but it also provides some convenience functions that are
       
    94     specific to a directory model.
       
    95     The fileInfo(), isDir(), name(), and path() functions provide information
       
    96     about the underlying files and directories related to items in the model.
       
    97     Directories can be created and removed using mkdir(), rmdir().
       
    98 
       
    99     \note QFileSystemModel requires an instance of a GUI application.
       
   100 
       
   101     \sa {Model Classes}
       
   102 */
       
   103 
       
   104 /*!
       
   105     \fn bool QFileSystemModel::rmdir(const QModelIndex &index) const
       
   106 
       
   107     Removes the directory corresponding to the model item \a index in the
       
   108     file system model and \bold{deletes the corresponding directory from the
       
   109     file system}, returning true if successful. If the directory cannot be
       
   110     removed, false is returned.
       
   111 
       
   112     \warning This function deletes directories from the file system; it does
       
   113     \bold{not} move them to a location where they can be recovered.
       
   114 
       
   115     \sa remove()
       
   116 */
       
   117 
       
   118 /*!
       
   119     \fn QIcon QFileSystemModel::fileName(const QModelIndex &index) const
       
   120 
       
   121     Returns the file name for the item stored in the model under the given
       
   122     \a index.
       
   123 */
       
   124 
       
   125 /*!
       
   126     \fn QIcon QFileSystemModel::fileIcon(const QModelIndex &index) const
       
   127 
       
   128     Returns the icon for the item stored in the model under the given
       
   129     \a index.
       
   130 */
       
   131 
       
   132 /*!
       
   133     \fn QFileInfo QFileSystemModel::fileInfo(const QModelIndex &index) const
       
   134 
       
   135     Returns the QFileInfo for the item stored in the model under the given
       
   136     \a index.
       
   137 */
       
   138 
       
   139 /*!
       
   140     \fn void QFileSystemModel::rootPathChanged(const QString &newPath);
       
   141 
       
   142     This signal is emitted whenever the root path has been changed to a \a newPath.
       
   143 */
       
   144 
       
   145 /*!
       
   146     \fn void QFileSystemModel::fileRenamed(const QString &path, const QString &oldName, const QString &newName)
       
   147 
       
   148     This signal is emitted whenever a file with the \a oldName is successfully
       
   149     renamed to \a newName.  The file is located in in the directory \a path.
       
   150 */
       
   151 
       
   152 /*!
       
   153     \fn bool QFileSystemModel::remove(const QModelIndex &index) const
       
   154 
       
   155     Removes the model item \a index from the file system model and \bold{deletes the
       
   156     corresponding file from the file system}, returning true if successful. If the
       
   157     item cannot be removed, false is returned.
       
   158 
       
   159     \warning This function deletes files from the file system; it does \bold{not}
       
   160     move them to a location where they can be recovered.
       
   161 
       
   162     \sa rmdir()
       
   163 */
       
   164 
       
   165 bool QFileSystemModel::remove(const QModelIndex &aindex) const
       
   166 {
       
   167     //### TODO optim
       
   168     QString path = filePath(aindex);
       
   169     QFileSystemModelPrivate * d = const_cast<QFileSystemModelPrivate*>(d_func());
       
   170     d->fileInfoGatherer.removePath(path);
       
   171     QDirIterator it(path,
       
   172             QDir::AllDirs | QDir:: Files | QDir::NoDotAndDotDot,
       
   173             QDirIterator::Subdirectories);
       
   174     QStringList children;
       
   175     while (it.hasNext())
       
   176         children.prepend(it.next());
       
   177     children.append(path);
       
   178 
       
   179     bool error = false;
       
   180     for (int i = 0; i < children.count(); ++i) {
       
   181         QFileInfo info(children.at(i));
       
   182         QModelIndex modelIndex = index(children.at(i));
       
   183         if (info.isDir()) {
       
   184             QDir dir;
       
   185             if (children.at(i) != path)
       
   186                 error |= remove(modelIndex);
       
   187             error |= rmdir(modelIndex);
       
   188         } else {
       
   189             error |= QFile::remove(filePath(modelIndex));
       
   190         }
       
   191     }
       
   192     return error;
       
   193 }
       
   194 
       
   195 /*!
       
   196   Constructs a file system model with the given \a parent.
       
   197 */
       
   198 QFileSystemModel::QFileSystemModel(QObject *parent)
       
   199     : QAbstractItemModel(*new QFileSystemModelPrivate, parent)
       
   200 {
       
   201     Q_D(QFileSystemModel);
       
   202     d->init();
       
   203 }
       
   204 
       
   205 /*!
       
   206     \internal
       
   207 */
       
   208 QFileSystemModel::QFileSystemModel(QFileSystemModelPrivate &dd, QObject *parent)
       
   209     : QAbstractItemModel(dd, parent)
       
   210 {
       
   211     Q_D(QFileSystemModel);
       
   212     d->init();
       
   213 }
       
   214 
       
   215 /*!
       
   216   Destroys this file system model.
       
   217 */
       
   218 QFileSystemModel::~QFileSystemModel()
       
   219 {
       
   220 }
       
   221 
       
   222 /*!
       
   223     \reimp
       
   224 */
       
   225 QModelIndex QFileSystemModel::index(int row, int column, const QModelIndex &parent) const
       
   226 {
       
   227     Q_D(const QFileSystemModel);
       
   228     if (row < 0 || column < 0 || row >= rowCount(parent) || column >= columnCount(parent))
       
   229         return QModelIndex();
       
   230 
       
   231     // get the parent node
       
   232     QFileSystemModelPrivate::QFileSystemNode *parentNode = (d->indexValid(parent) ? d->node(parent) :
       
   233                                                    const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&d->root));
       
   234     Q_ASSERT(parentNode);
       
   235 
       
   236     // now get the internal pointer for the index
       
   237     QString childName = parentNode->visibleChildren[d->translateVisibleLocation(parentNode, row)];
       
   238     const QFileSystemModelPrivate::QFileSystemNode *indexNode = parentNode->children.value(childName);
       
   239     Q_ASSERT(indexNode);
       
   240 
       
   241     return createIndex(row, column, const_cast<QFileSystemModelPrivate::QFileSystemNode*>(indexNode));
       
   242 }
       
   243 
       
   244 /*!
       
   245     \overload
       
   246 
       
   247     Returns the model item index for the given \a path and \a column.
       
   248 */
       
   249 QModelIndex QFileSystemModel::index(const QString &path, int column) const
       
   250 {
       
   251     Q_D(const QFileSystemModel);
       
   252     QFileSystemModelPrivate::QFileSystemNode *node = d->node(path, false);
       
   253     QModelIndex idx = d->index(node);
       
   254     if (idx.column() != column)
       
   255         idx = idx.sibling(idx.row(), column);
       
   256     return idx;
       
   257 }
       
   258 
       
   259 /*!
       
   260     \internal
       
   261 
       
   262     Return the QFileSystemNode that goes to index.
       
   263   */
       
   264 QFileSystemModelPrivate::QFileSystemNode *QFileSystemModelPrivate::node(const QModelIndex &index) const
       
   265 {
       
   266     if (!index.isValid())
       
   267         return const_cast<QFileSystemNode*>(&root);
       
   268     QFileSystemModelPrivate::QFileSystemNode *indexNode = static_cast<QFileSystemModelPrivate::QFileSystemNode*>(index.internalPointer());
       
   269     Q_ASSERT(indexNode);
       
   270     return indexNode;
       
   271 }
       
   272 
       
   273 #ifdef Q_OS_WIN
       
   274 static QString qt_GetLongPathName(const QString &strShortPath)
       
   275 {
       
   276     QString longPath;
       
   277     int i = 0;
       
   278     if (strShortPath == QLatin1String(".")
       
   279         || (strShortPath.startsWith(QLatin1String("//")))
       
   280         || (strShortPath.startsWith(QLatin1String("\\\\")))) // unc
       
   281         return strShortPath;
       
   282     QString::const_iterator it = strShortPath.constBegin();
       
   283     QString::const_iterator constEnd = strShortPath.constEnd();
       
   284     do {
       
   285         bool isSep = (*it == QLatin1Char('\\') || *it == QLatin1Char('/'));
       
   286         if (isSep || it == constEnd) {
       
   287             QString section = (it == constEnd ? strShortPath : strShortPath.left(i));
       
   288             // FindFirstFile does not handle volumes ("C:"), so we have to catch that ourselves.
       
   289             if (section.endsWith(QLatin1Char(':'))) {
       
   290                 longPath.append(section.toUpper());
       
   291             } else {
       
   292                 HANDLE h;
       
   293 #ifndef Q_OS_WINCE
       
   294                 //We add the extend length prefix to handle long path
       
   295                 QString longSection = QLatin1String("\\\\?\\")+QDir::toNativeSeparators(section);
       
   296 #else
       
   297                 QString longSection = QDir::toNativeSeparators(section);
       
   298 #endif
       
   299                 WIN32_FIND_DATA findData;
       
   300                 h = ::FindFirstFile((wchar_t*)longSection.utf16(), &findData);
       
   301                 if (h != INVALID_HANDLE_VALUE) {
       
   302                     longPath.append(QString::fromWCharArray(findData.cFileName));
       
   303                     ::FindClose(h);
       
   304                 } else {
       
   305                     longPath.append(section);
       
   306                     break;
       
   307                 }
       
   308             }
       
   309             if (it != constEnd)
       
   310                 longPath.append(*it);
       
   311             else
       
   312                 break;
       
   313         }
       
   314         ++it;
       
   315         if (isSep && it == constEnd)    // break out if the last character is a separator
       
   316             break;
       
   317         ++i;
       
   318     } while (true);
       
   319     return longPath;
       
   320 }
       
   321 #endif
       
   322 
       
   323 /*!
       
   324     \internal
       
   325 
       
   326     Given a path return the matching QFileSystemNode or &root if invalid
       
   327 */
       
   328 QFileSystemModelPrivate::QFileSystemNode *QFileSystemModelPrivate::node(const QString &path, bool fetch) const
       
   329 {
       
   330     Q_Q(const QFileSystemModel);
       
   331     Q_UNUSED(q);
       
   332     if (path.isEmpty() || path == myComputer() || path.startsWith(QLatin1Char(':')))
       
   333         return const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&root);
       
   334 
       
   335     // Construct the nodes up to the new root path if they need to be built
       
   336     QString absolutePath;
       
   337 #ifdef Q_OS_WIN
       
   338     QString longPath = qt_GetLongPathName(path);
       
   339 #else
       
   340     QString longPath = path;
       
   341 #endif
       
   342     if (longPath == rootDir.path())
       
   343         absolutePath = rootDir.absolutePath();
       
   344     else
       
   345         absolutePath = QDir(longPath).absolutePath();
       
   346 
       
   347     // ### TODO can we use bool QAbstractFileEngine::caseSensitive() const?
       
   348     QStringList pathElements = absolutePath.split(QLatin1Char('/'), QString::SkipEmptyParts);
       
   349     if ((pathElements.isEmpty())
       
   350 #if (!defined(Q_OS_WIN) || defined(Q_OS_WINCE)) && !defined(Q_OS_SYMBIAN)
       
   351         && QDir::fromNativeSeparators(longPath) != QLatin1String("/")
       
   352 #endif
       
   353         )
       
   354         return const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&root);
       
   355     QModelIndex index = QModelIndex(); // start with "My Computer"
       
   356 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
       
   357     if (absolutePath.startsWith(QLatin1String("//"))) { // UNC path
       
   358         QString host = QLatin1String("\\\\") + pathElements.first();
       
   359         if (absolutePath == QDir::fromNativeSeparators(host))
       
   360             absolutePath.append(QLatin1Char('/'));
       
   361         if (longPath.endsWith(QLatin1Char('/')) && !absolutePath.endsWith(QLatin1Char('/')))
       
   362             absolutePath.append(QLatin1Char('/'));
       
   363         int r = 0;
       
   364         QFileSystemModelPrivate::QFileSystemNode *rootNode = const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&root);
       
   365         if (!root.children.contains(host.toLower())) {
       
   366             if (pathElements.count() == 1 && !absolutePath.endsWith(QLatin1Char('/')))
       
   367                 return rootNode;
       
   368             QFileInfo info(host);
       
   369             if (!info.exists())
       
   370                 return rootNode;
       
   371             QFileSystemModelPrivate *p = const_cast<QFileSystemModelPrivate*>(this);
       
   372             p->addNode(rootNode, host,info);
       
   373             p->addVisibleFiles(rootNode, QStringList(host));
       
   374         }
       
   375         r = rootNode->visibleLocation(host);
       
   376         r = translateVisibleLocation(rootNode, r);
       
   377         index = q->index(r, 0, QModelIndex());
       
   378         pathElements.pop_front();
       
   379     } else
       
   380 #endif
       
   381 
       
   382 #if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN)
       
   383     {
       
   384         if (!pathElements.at(0).contains(QLatin1String(":"))) {
       
   385             // The reason we express it like this instead of with anonymous, temporary
       
   386             // variables, is to workaround a compiler crash with Q_CC_NOKIAX86.
       
   387             QString rootPath = QDir(longPath).rootPath();
       
   388             pathElements.prepend(rootPath);
       
   389         }
       
   390         if (pathElements.at(0).endsWith(QLatin1Char('/')))
       
   391             pathElements[0].chop(1);
       
   392     }
       
   393 #else
       
   394     // add the "/" item, since it is a valid path element on Unix
       
   395     if (absolutePath[0] == QLatin1Char('/'))
       
   396         pathElements.prepend(QLatin1String("/"));
       
   397 #endif
       
   398 
       
   399     QFileSystemModelPrivate::QFileSystemNode *parent = node(index);
       
   400 
       
   401     for (int i = 0; i < pathElements.count(); ++i) {
       
   402         QString element = pathElements.at(i);
       
   403 #ifdef Q_OS_WIN
       
   404         // On Windows, "filename......." and "filename" are equivalent Task #133928
       
   405         while (element.endsWith(QLatin1Char('.')))
       
   406             element.chop(1);
       
   407 #endif
       
   408         bool alreadyExisted = parent->children.contains(element);
       
   409 
       
   410         // we couldn't find the path element, we create a new node since we
       
   411         // _know_ that the path is valid
       
   412         if (alreadyExisted) {
       
   413             if ((parent->children.count() == 0)
       
   414                 || (parent->caseSensitive()
       
   415                     && parent->children.value(element)->fileName != element)
       
   416                 || (!parent->caseSensitive()
       
   417                     && parent->children.value(element)->fileName.toLower() != element.toLower()))
       
   418                 alreadyExisted = false;
       
   419         }
       
   420 
       
   421         QFileSystemModelPrivate::QFileSystemNode *node;
       
   422         if (!alreadyExisted) {
       
   423             // Someone might call ::index("file://cookie/monster/doesn't/like/veggies"),
       
   424             // a path that doesn't exists, I.E. don't blindly create directories.
       
   425             QFileInfo info(absolutePath);
       
   426             if (!info.exists())
       
   427                 return const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&root);
       
   428             QFileSystemModelPrivate *p = const_cast<QFileSystemModelPrivate*>(this);
       
   429             node = p->addNode(parent, element,info);
       
   430 #ifndef QT_NO_FILESYSTEMWATCHER
       
   431             node->populate(fileInfoGatherer.getInfo(info));
       
   432 #endif
       
   433         } else {
       
   434             node = parent->children.value(element);
       
   435         }
       
   436 
       
   437         Q_ASSERT(node);
       
   438         if (!node->isVisible) {
       
   439             // It has been filtered out
       
   440             if (alreadyExisted && node->hasInformation() && !fetch)
       
   441                 return const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&root);
       
   442 
       
   443             QFileSystemModelPrivate *p = const_cast<QFileSystemModelPrivate*>(this);
       
   444             p->addVisibleFiles(parent, QStringList(element));
       
   445             if (!p->bypassFilters.contains(node))
       
   446                 p->bypassFilters[node] = 1;
       
   447             QString dir = q->filePath(this->index(parent));
       
   448             if (!node->hasInformation() && fetch) {
       
   449                 Fetching f;
       
   450                 f.dir = dir;
       
   451                 f.file = element;
       
   452                 f.node = node;
       
   453                 p->toFetch.append(f);
       
   454                 p->fetchingTimer.start(0, const_cast<QFileSystemModel*>(q));
       
   455             }
       
   456         }
       
   457         parent = node;
       
   458     }
       
   459 
       
   460     return parent;
       
   461 }
       
   462 
       
   463 /*!
       
   464     \reimp
       
   465 */
       
   466 void QFileSystemModel::timerEvent(QTimerEvent *event)
       
   467 {
       
   468     Q_D(QFileSystemModel);
       
   469     if (event->timerId() == d->fetchingTimer.timerId()) {
       
   470         d->fetchingTimer.stop();
       
   471 #ifndef QT_NO_FILESYSTEMWATCHER
       
   472         for (int i = 0; i < d->toFetch.count(); ++i) {
       
   473             const QFileSystemModelPrivate::QFileSystemNode *node = d->toFetch.at(i).node;
       
   474             if (!node->hasInformation()) {
       
   475                 d->fileInfoGatherer.fetchExtendedInformation(d->toFetch.at(i).dir,
       
   476                                                  QStringList(d->toFetch.at(i).file));
       
   477             } else {
       
   478                 // qDebug() << "yah!, you saved a little gerbil soul";
       
   479             }
       
   480         }
       
   481 #endif
       
   482         d->toFetch.clear();
       
   483     }
       
   484 }
       
   485 
       
   486 /*!
       
   487     Returns true if the model item \a index represents a directory;
       
   488     otherwise returns false.
       
   489 */
       
   490 bool QFileSystemModel::isDir(const QModelIndex &index) const
       
   491 {
       
   492     // This function is for public usage only because it could create a file info
       
   493     Q_D(const QFileSystemModel);
       
   494     if (!index.isValid())
       
   495         return true;
       
   496     QFileSystemModelPrivate::QFileSystemNode *n = d->node(index);
       
   497     if (n->hasInformation())
       
   498         return n->isDir();
       
   499     return fileInfo(index).isDir();
       
   500 }
       
   501 
       
   502 /*!
       
   503     Returns the size in bytes of \a index. If the file does not exist, 0 is returned.
       
   504   */
       
   505 qint64 QFileSystemModel::size(const QModelIndex &index) const
       
   506 {
       
   507     Q_D(const QFileSystemModel);
       
   508     if (!index.isValid())
       
   509         return 0;
       
   510     return d->node(index)->size();
       
   511 }
       
   512 
       
   513 /*!
       
   514     Returns the type of file \a index such as "Directory" or "JPEG file".
       
   515   */
       
   516 QString QFileSystemModel::type(const QModelIndex &index) const
       
   517 {
       
   518     Q_D(const QFileSystemModel);
       
   519     if (!index.isValid())
       
   520         return QString();
       
   521     return d->node(index)->type();
       
   522 }
       
   523 
       
   524 /*!
       
   525     Returns the date and time when \a index was last modified.
       
   526  */
       
   527 QDateTime QFileSystemModel::lastModified(const QModelIndex &index) const
       
   528 {
       
   529     Q_D(const QFileSystemModel);
       
   530     if (!index.isValid())
       
   531         return QDateTime();
       
   532     return d->node(index)->lastModified();
       
   533 }
       
   534 
       
   535 /*!
       
   536     \reimp
       
   537 */
       
   538 QModelIndex QFileSystemModel::parent(const QModelIndex &index) const
       
   539 {
       
   540     Q_D(const QFileSystemModel);
       
   541     if (!d->indexValid(index))
       
   542         return QModelIndex();
       
   543 
       
   544     QFileSystemModelPrivate::QFileSystemNode *indexNode = d->node(index);
       
   545     Q_ASSERT(indexNode != 0);
       
   546     QFileSystemModelPrivate::QFileSystemNode *parentNode = (indexNode ? indexNode->parent : 0);
       
   547     if (parentNode == 0 || parentNode == &d->root)
       
   548         return QModelIndex();
       
   549 
       
   550     // get the parent's row
       
   551     QFileSystemModelPrivate::QFileSystemNode *grandParentNode = parentNode->parent;
       
   552     Q_ASSERT(grandParentNode->children.contains(parentNode->fileName));
       
   553     int visualRow = d->translateVisibleLocation(grandParentNode, grandParentNode->visibleLocation(grandParentNode->children.value(parentNode->fileName)->fileName));
       
   554     if (visualRow == -1)
       
   555         return QModelIndex();
       
   556     return createIndex(visualRow, 0, parentNode);
       
   557 }
       
   558 
       
   559 /*
       
   560     \internal
       
   561 
       
   562     return the index for node
       
   563 */
       
   564 QModelIndex QFileSystemModelPrivate::index(const QFileSystemModelPrivate::QFileSystemNode *node) const
       
   565 {
       
   566     Q_Q(const QFileSystemModel);
       
   567     QFileSystemModelPrivate::QFileSystemNode *parentNode = (node ? node->parent : 0);
       
   568     if (node == &root || !parentNode)
       
   569         return QModelIndex();
       
   570 
       
   571     // get the parent's row
       
   572     Q_ASSERT(node);
       
   573     if (!node->isVisible)
       
   574         return QModelIndex();
       
   575 
       
   576     int visualRow = translateVisibleLocation(parentNode, parentNode->visibleLocation(node->fileName));
       
   577     return q->createIndex(visualRow, 0, const_cast<QFileSystemNode*>(node));
       
   578 }
       
   579 
       
   580 /*!
       
   581     \reimp
       
   582 */
       
   583 bool QFileSystemModel::hasChildren(const QModelIndex &parent) const
       
   584 {
       
   585     Q_D(const QFileSystemModel);
       
   586     if (parent.column() > 0)
       
   587         return false;
       
   588 
       
   589     if (!parent.isValid()) // drives
       
   590         return true;
       
   591 
       
   592     const QFileSystemModelPrivate::QFileSystemNode *indexNode = d->node(parent);
       
   593     Q_ASSERT(indexNode);
       
   594     return (indexNode->isDir());
       
   595 }
       
   596 
       
   597 /*!
       
   598     \reimp
       
   599  */
       
   600 bool QFileSystemModel::canFetchMore(const QModelIndex &parent) const
       
   601 {
       
   602     Q_D(const QFileSystemModel);
       
   603     const QFileSystemModelPrivate::QFileSystemNode *indexNode = d->node(parent);
       
   604     return (!indexNode->populatedChildren);
       
   605 }
       
   606 
       
   607 /*!
       
   608     \reimp
       
   609  */
       
   610 void QFileSystemModel::fetchMore(const QModelIndex &parent)
       
   611 {
       
   612     Q_D(QFileSystemModel);
       
   613     if (!d->setRootPath)
       
   614         return;
       
   615     QFileSystemModelPrivate::QFileSystemNode *indexNode = d->node(parent);
       
   616     if (indexNode->populatedChildren)
       
   617         return;
       
   618     indexNode->populatedChildren = true;
       
   619     d->fileInfoGatherer.list(filePath(parent));
       
   620 }
       
   621 
       
   622 /*!
       
   623     \reimp
       
   624 */
       
   625 int QFileSystemModel::rowCount(const QModelIndex &parent) const
       
   626 {
       
   627     Q_D(const QFileSystemModel);
       
   628     if (parent.column() > 0)
       
   629         return 0;
       
   630 
       
   631     if (!parent.isValid())
       
   632         return d->root.visibleChildren.count();
       
   633 
       
   634     const QFileSystemModelPrivate::QFileSystemNode *parentNode = d->node(parent);
       
   635     return parentNode->visibleChildren.count();
       
   636 }
       
   637 
       
   638 /*!
       
   639     \reimp
       
   640 */
       
   641 int QFileSystemModel::columnCount(const QModelIndex &parent) const
       
   642 {
       
   643     return (parent.column() > 0) ? 0 : 4;
       
   644 }
       
   645 
       
   646 /*!
       
   647     Returns the data stored under the given \a role for the item "My Computer".
       
   648 
       
   649     \sa Qt::ItemDataRole
       
   650  */
       
   651 QVariant QFileSystemModel::myComputer(int role) const
       
   652 {
       
   653     Q_D(const QFileSystemModel);
       
   654     switch (role) {
       
   655     case Qt::DisplayRole:
       
   656         return d->myComputer();
       
   657     case Qt::DecorationRole:
       
   658         return d->fileInfoGatherer.iconProvider()->icon(QFileIconProvider::Computer);
       
   659     }
       
   660     return QVariant();
       
   661 }
       
   662 
       
   663 /*!
       
   664     \reimp
       
   665 */
       
   666 QVariant QFileSystemModel::data(const QModelIndex &index, int role) const
       
   667 {
       
   668     Q_D(const QFileSystemModel);
       
   669     if (!index.isValid() || index.model() != this)
       
   670         return QVariant();
       
   671 
       
   672     switch (role) {
       
   673     case Qt::EditRole:
       
   674     case Qt::DisplayRole:
       
   675         switch (index.column()) {
       
   676         case 0: return d->name(index);
       
   677         case 1: return d->size(index);
       
   678         case 2: return d->type(index);
       
   679         case 3: return d->time(index);
       
   680         default:
       
   681             qWarning("data: invalid display value column %d", index.column());
       
   682             break;
       
   683         }
       
   684         break;
       
   685     case FilePathRole:
       
   686         return filePath(index);
       
   687     case FileNameRole:
       
   688         return d->name(index);
       
   689     case Qt::DecorationRole:
       
   690         if (index.column() == 0) {
       
   691             QIcon icon = d->icon(index);
       
   692             if (icon.isNull()) {
       
   693                 if (d->node(index)->isDir())
       
   694                     icon = d->fileInfoGatherer.iconProvider()->icon(QFileIconProvider::Folder);
       
   695                 else
       
   696                     icon = d->fileInfoGatherer.iconProvider()->icon(QFileIconProvider::File);
       
   697             }
       
   698             return icon;
       
   699         }
       
   700         break;
       
   701     case Qt::TextAlignmentRole:
       
   702         if (index.column() == 1)
       
   703             return Qt::AlignRight;
       
   704         break;
       
   705     case FilePermissions:
       
   706         int p = permissions(index);
       
   707         return p;
       
   708     }
       
   709 
       
   710     return QVariant();
       
   711 }
       
   712 
       
   713 /*!
       
   714     \internal
       
   715 */
       
   716 QString QFileSystemModelPrivate::size(const QModelIndex &index) const
       
   717 {
       
   718     if (!index.isValid())
       
   719         return QString();
       
   720     const QFileSystemNode *n = node(index);
       
   721     if (n->isDir()) {
       
   722 #ifdef Q_OS_MAC
       
   723         return QLatin1String("--");
       
   724 #else
       
   725         return QLatin1String("");
       
   726 #endif
       
   727     // Windows   - ""
       
   728     // OS X      - "--"
       
   729     // Konqueror - "4 KB"
       
   730     // Nautilus  - "9 items" (the number of children)
       
   731     }
       
   732     return size(n->size());
       
   733 }
       
   734 
       
   735 QString QFileSystemModelPrivate::size(qint64 bytes)
       
   736 {
       
   737     // According to the Si standard KB is 1000 bytes, KiB is 1024
       
   738     // but on windows sizes are calculated by dividing by 1024 so we do what they do.
       
   739     const qint64 kb = 1024;
       
   740     const qint64 mb = 1024 * kb;
       
   741     const qint64 gb = 1024 * mb;
       
   742     const qint64 tb = 1024 * gb;
       
   743     if (bytes >= tb)
       
   744         return QFileSystemModel::tr("%1 TB").arg(QLocale().toString(qreal(bytes) / tb, 'f', 3));
       
   745     if (bytes >= gb)
       
   746         return QFileSystemModel::tr("%1 GB").arg(QLocale().toString(qreal(bytes) / gb, 'f', 2));
       
   747     if (bytes >= mb)
       
   748         return QFileSystemModel::tr("%1 MB").arg(QLocale().toString(qreal(bytes) / mb, 'f', 1));
       
   749     if (bytes >= kb)
       
   750         return QFileSystemModel::tr("%1 KB").arg(QLocale().toString(bytes / kb));
       
   751     return QFileSystemModel::tr("%1 bytes").arg(QLocale().toString(bytes));
       
   752 }
       
   753 
       
   754 /*!
       
   755     \internal
       
   756 */
       
   757 QString QFileSystemModelPrivate::time(const QModelIndex &index) const
       
   758 {
       
   759     if (!index.isValid())
       
   760         return QString();
       
   761 #ifndef QT_NO_DATESTRING
       
   762     return node(index)->lastModified().toString(Qt::SystemLocaleDate);
       
   763 #else
       
   764     Q_UNUSED(index);
       
   765     return QString();
       
   766 #endif
       
   767 }
       
   768 
       
   769 /*
       
   770     \internal
       
   771 */
       
   772 QString QFileSystemModelPrivate::type(const QModelIndex &index) const
       
   773 {
       
   774     if (!index.isValid())
       
   775         return QString();
       
   776     return node(index)->type();
       
   777 }
       
   778 
       
   779 /*!
       
   780     \internal
       
   781 */
       
   782 QString QFileSystemModelPrivate::name(const QModelIndex &index) const
       
   783 {
       
   784     if (!index.isValid())
       
   785         return QString();
       
   786     QFileSystemNode *dirNode = node(index);
       
   787     if (dirNode->isSymLink() && fileInfoGatherer.resolveSymlinks()) {
       
   788         QString fullPath = QDir::fromNativeSeparators(filePath(index));
       
   789         if (resolvedSymLinks.contains(fullPath))
       
   790             return resolvedSymLinks[fullPath];
       
   791     }
       
   792     // ### TODO it would be nice to grab the volume name if dirNode->parent == root
       
   793     return dirNode->fileName;
       
   794 }
       
   795 
       
   796 /*!
       
   797     \internal
       
   798 */
       
   799 QIcon QFileSystemModelPrivate::icon(const QModelIndex &index) const
       
   800 {
       
   801     if (!index.isValid())
       
   802         return QIcon();
       
   803     return node(index)->icon();
       
   804 }
       
   805 
       
   806 /*!
       
   807     \reimp
       
   808 */
       
   809 bool QFileSystemModel::setData(const QModelIndex &idx, const QVariant &value, int role)
       
   810 {
       
   811     Q_D(QFileSystemModel);
       
   812     if (!idx.isValid()
       
   813         || idx.column() != 0
       
   814         || role != Qt::EditRole
       
   815         || (flags(idx) & Qt::ItemIsEditable) == 0) {
       
   816         return false;
       
   817     }
       
   818 
       
   819     QString newName = value.toString();
       
   820     QString oldName = idx.data().toString();
       
   821     if (newName == idx.data().toString())
       
   822         return true;
       
   823 
       
   824     if (newName.isEmpty()
       
   825         || newName.contains(QDir::separator())
       
   826         || !QDir(filePath(parent(idx))).rename(oldName, newName)) {
       
   827 #ifndef QT_NO_MESSAGEBOX
       
   828         QMessageBox::information(0, QFileSystemModel::tr("Invalid filename"),
       
   829                                 QFileSystemModel::tr("<b>The name \"%1\" can not be used.</b><p>Try using another name, with fewer characters or no punctuations marks.")
       
   830                                 .arg(newName),
       
   831                                  QMessageBox::Ok);
       
   832 #endif // QT_NO_MESSAGEBOX
       
   833         return false;
       
   834     } else {
       
   835         /*
       
   836             *After re-naming something we don't want the selection to change*
       
   837             - can't remove rows and later insert
       
   838             - can't quickly remove and insert
       
   839             - index pointer can't change because treeview doesn't use persistant index's
       
   840 
       
   841             - if this get any more complicated think of changing it to just
       
   842               use layoutChanged
       
   843          */
       
   844 
       
   845         QFileSystemModelPrivate::QFileSystemNode *indexNode = d->node(idx);
       
   846         QFileSystemModelPrivate::QFileSystemNode *parentNode = indexNode->parent;
       
   847         int visibleLocation = parentNode->visibleLocation(parentNode->children.value(indexNode->fileName)->fileName);
       
   848 
       
   849         d->addNode(parentNode, newName,indexNode->info->fileInfo());
       
   850         parentNode->visibleChildren.removeAt(visibleLocation);
       
   851         QFileSystemModelPrivate::QFileSystemNode * oldValue = parentNode->children.value(oldName);
       
   852         parentNode->children[newName] = oldValue;
       
   853         QFileInfo info(d->rootDir, newName);
       
   854         oldValue->fileName = newName;
       
   855         oldValue->parent = parentNode;
       
   856         oldValue->populate(d->fileInfoGatherer.getInfo(info));
       
   857         oldValue->isVisible = true;
       
   858 
       
   859         parentNode->children.remove(oldName);
       
   860         parentNode->visibleChildren.insert(visibleLocation, newName);
       
   861 
       
   862         d->delayedSort();
       
   863         emit fileRenamed(filePath(idx.parent()), oldName, newName);
       
   864     }
       
   865     return true;
       
   866 }
       
   867 
       
   868 /*!
       
   869     \reimp
       
   870 */
       
   871 QVariant QFileSystemModel::headerData(int section, Qt::Orientation orientation, int role) const
       
   872 {
       
   873     switch (role) {
       
   874     case Qt::DecorationRole:
       
   875         if (section == 0) {
       
   876             // ### TODO oh man this is ugly and doesn't even work all the way!
       
   877             // it is still 2 pixels off
       
   878             QImage pixmap(16, 1, QImage::Format_Mono);
       
   879             pixmap.fill(0);
       
   880             pixmap.setAlphaChannel(pixmap.createAlphaMask());
       
   881             return pixmap;
       
   882         }
       
   883         break;
       
   884     case Qt::TextAlignmentRole:
       
   885         return Qt::AlignLeft;
       
   886     }
       
   887 
       
   888     if (orientation != Qt::Horizontal || role != Qt::DisplayRole)
       
   889         return QAbstractItemModel::headerData(section, orientation, role);
       
   890 
       
   891     QString returnValue;
       
   892     switch (section) {
       
   893     case 0: returnValue = tr("Name");
       
   894             break;
       
   895     case 1: returnValue = tr("Size");
       
   896             break;
       
   897     case 2: returnValue =
       
   898 #ifdef Q_OS_MAC
       
   899                    tr("Kind", "Match OS X Finder");
       
   900 #else
       
   901                    tr("Type", "All other platforms");
       
   902 #endif
       
   903            break;
       
   904     // Windows   - Type
       
   905     // OS X      - Kind
       
   906     // Konqueror - File Type
       
   907     // Nautilus  - Type
       
   908     case 3: returnValue = tr("Date Modified");
       
   909             break;
       
   910     default: return QVariant();
       
   911     }
       
   912     return returnValue;
       
   913 }
       
   914 
       
   915 /*!
       
   916     \reimp
       
   917 */
       
   918 Qt::ItemFlags QFileSystemModel::flags(const QModelIndex &index) const
       
   919 {
       
   920     Q_D(const QFileSystemModel);
       
   921     Qt::ItemFlags flags = QAbstractItemModel::flags(index);
       
   922     if (!index.isValid())
       
   923         return flags;
       
   924 
       
   925     QFileSystemModelPrivate::QFileSystemNode *indexNode = d->node(index);
       
   926     if (d->nameFilterDisables && !d->passNameFilters(indexNode)) {
       
   927         flags &= ~Qt::ItemIsEnabled;
       
   928         // ### TODO you shouldn't be able to set this as the current item, task 119433
       
   929         return flags;
       
   930     }
       
   931 
       
   932     flags |= Qt::ItemIsDragEnabled;
       
   933     if (d->readOnly)
       
   934         return flags;
       
   935     if ((index.column() == 0) && indexNode->permissions() & QFile::WriteUser) {
       
   936         flags |= Qt::ItemIsEditable;
       
   937         if (indexNode->isDir())
       
   938             flags |= Qt::ItemIsDropEnabled;
       
   939     }
       
   940     return flags;
       
   941 }
       
   942 
       
   943 /*!
       
   944     \internal
       
   945 */
       
   946 void QFileSystemModelPrivate::_q_performDelayedSort()
       
   947 {
       
   948     Q_Q(QFileSystemModel);
       
   949     q->sort(sortColumn, sortOrder);
       
   950 }
       
   951 
       
   952 static inline QChar getNextChar(const QString &s, int location)
       
   953 {
       
   954     return (location < s.length()) ? s.at(location) : QChar();
       
   955 }
       
   956 
       
   957 /*!
       
   958     Natural number sort, skips spaces.
       
   959 
       
   960     Examples:
       
   961     1, 2, 10, 55, 100
       
   962     01.jpg, 2.jpg, 10.jpg
       
   963 
       
   964     Note on the algorithm:
       
   965     Only as many characters as necessary are looked at and at most they all
       
   966     are looked at once.
       
   967 
       
   968     Slower then QString::compare() (of course)
       
   969   */
       
   970 int QFileSystemModelPrivate::naturalCompare(const QString &s1, const QString &s2,  Qt::CaseSensitivity cs)
       
   971 {
       
   972     for (int l1 = 0, l2 = 0; l1 <= s1.count() && l2 <= s2.count(); ++l1, ++l2) {
       
   973         // skip spaces, tabs and 0's
       
   974         QChar c1 = getNextChar(s1, l1);
       
   975         while (c1.isSpace())
       
   976             c1 = getNextChar(s1, ++l1);
       
   977         QChar c2 = getNextChar(s2, l2);
       
   978         while (c2.isSpace())
       
   979             c2 = getNextChar(s2, ++l2);
       
   980 
       
   981         if (c1.isDigit() && c2.isDigit()) {
       
   982             while (c1.digitValue() == 0)
       
   983                 c1 = getNextChar(s1, ++l1);
       
   984             while (c2.digitValue() == 0)
       
   985                 c2 = getNextChar(s2, ++l2);
       
   986 
       
   987             int lookAheadLocation1 = l1;
       
   988             int lookAheadLocation2 = l2;
       
   989             int currentReturnValue = 0;
       
   990             // find the last digit, setting currentReturnValue as we go if it isn't equal
       
   991             for (
       
   992                 QChar lookAhead1 = c1, lookAhead2 = c2;
       
   993                 (lookAheadLocation1 <= s1.length() && lookAheadLocation2 <= s2.length());
       
   994                 lookAhead1 = getNextChar(s1, ++lookAheadLocation1),
       
   995                 lookAhead2 = getNextChar(s2, ++lookAheadLocation2)
       
   996                 ) {
       
   997                 bool is1ADigit = !lookAhead1.isNull() && lookAhead1.isDigit();
       
   998                 bool is2ADigit = !lookAhead2.isNull() && lookAhead2.isDigit();
       
   999                 if (!is1ADigit && !is2ADigit)
       
  1000                     break;
       
  1001                 if (!is1ADigit)
       
  1002                     return -1;
       
  1003                 if (!is2ADigit)
       
  1004                     return 1;
       
  1005                 if (currentReturnValue == 0) {
       
  1006                     if (lookAhead1 < lookAhead2) {
       
  1007                         currentReturnValue = -1;
       
  1008                     } else if (lookAhead1 > lookAhead2) {
       
  1009                         currentReturnValue = 1;
       
  1010                     }
       
  1011                 }
       
  1012             }
       
  1013             if (currentReturnValue != 0)
       
  1014                 return currentReturnValue;
       
  1015         }
       
  1016 
       
  1017         if (cs == Qt::CaseInsensitive) {
       
  1018             if (!c1.isLower()) c1 = c1.toLower();
       
  1019             if (!c2.isLower()) c2 = c2.toLower();
       
  1020         }
       
  1021         int r = QString::localeAwareCompare(c1, c2);
       
  1022         if (r < 0)
       
  1023             return -1;
       
  1024         if (r > 0)
       
  1025             return 1;
       
  1026     }
       
  1027     // The two strings are the same (02 == 2) so fall back to the normal sort
       
  1028     return QString::compare(s1, s2, cs);
       
  1029 }
       
  1030 
       
  1031 /*
       
  1032     \internal
       
  1033     Helper functor used by sort()
       
  1034 */
       
  1035 class QFileSystemModelSorter
       
  1036 {
       
  1037 public:
       
  1038     inline QFileSystemModelSorter(int column) : sortColumn(column) {}
       
  1039 
       
  1040     bool compareNodes(const QFileSystemModelPrivate::QFileSystemNode *l,
       
  1041                     const QFileSystemModelPrivate::QFileSystemNode *r) const
       
  1042     {
       
  1043         switch (sortColumn) {
       
  1044         case 0: {
       
  1045 #ifndef Q_OS_MAC
       
  1046             // place directories before files
       
  1047             bool left = l->isDir();
       
  1048             bool right = r->isDir();
       
  1049             if (left ^ right)
       
  1050                 return left;
       
  1051 #endif
       
  1052             return QFileSystemModelPrivate::naturalCompare(l->fileName,
       
  1053                                                 r->fileName, Qt::CaseInsensitive) < 0;
       
  1054                 }
       
  1055         case 1:
       
  1056             // Directories go first
       
  1057             if (l->isDir() && !r->isDir())
       
  1058                 return true;
       
  1059             return l->size() < r->size();
       
  1060         case 2:
       
  1061             return l->type() < r->type();
       
  1062         case 3:
       
  1063             return l->lastModified() < r->lastModified();
       
  1064         }
       
  1065         Q_ASSERT(false);
       
  1066         return false;
       
  1067     }
       
  1068 
       
  1069     bool operator()(const QPair<QFileSystemModelPrivate::QFileSystemNode*, int> &l,
       
  1070                            const QPair<QFileSystemModelPrivate::QFileSystemNode*, int> &r) const
       
  1071     {
       
  1072         return compareNodes(l.first, r.first);
       
  1073     }
       
  1074 
       
  1075 
       
  1076 private:
       
  1077     int sortColumn;
       
  1078 };
       
  1079 
       
  1080 /*
       
  1081     \internal
       
  1082 
       
  1083     Sort all of the children of parent
       
  1084 */
       
  1085 void QFileSystemModelPrivate::sortChildren(int column, const QModelIndex &parent)
       
  1086 {
       
  1087     Q_Q(QFileSystemModel);
       
  1088     QFileSystemModelPrivate::QFileSystemNode *indexNode = node(parent);
       
  1089     if (indexNode->children.count() == 0)
       
  1090         return;
       
  1091 
       
  1092     QList<QPair<QFileSystemModelPrivate::QFileSystemNode*, int> > values;
       
  1093     QHash<QString, QFileSystemNode *>::const_iterator iterator;
       
  1094     int i = 0;
       
  1095     for(iterator = indexNode->children.begin() ; iterator != indexNode->children.end() ; ++iterator) {
       
  1096         if (filtersAcceptsNode(iterator.value())) {
       
  1097             values.append(QPair<QFileSystemModelPrivate::QFileSystemNode*, int>((iterator.value()), i));
       
  1098         } else {
       
  1099             iterator.value()->isVisible = false;
       
  1100         }
       
  1101         i++;
       
  1102     }
       
  1103     QFileSystemModelSorter ms(column);
       
  1104     qStableSort(values.begin(), values.end(), ms);
       
  1105     // First update the new visible list
       
  1106     indexNode->visibleChildren.clear();
       
  1107     //No more dirty item we reset our internal dirty index
       
  1108     indexNode->dirtyChildrenIndex = -1;
       
  1109     for (int i = 0; i < values.count(); ++i) {
       
  1110         indexNode->visibleChildren.append(values.at(i).first->fileName);
       
  1111         values.at(i).first->isVisible = true;
       
  1112     }
       
  1113 
       
  1114     if (!disableRecursiveSort) {
       
  1115         for (int i = 0; i < q->rowCount(parent); ++i) {
       
  1116             const QModelIndex childIndex = q->index(i, 0, parent);
       
  1117             QFileSystemModelPrivate::QFileSystemNode *indexNode = node(childIndex);
       
  1118             //Only do a recursive sort on visible nodes
       
  1119             if (indexNode->isVisible)
       
  1120                 sortChildren(column, childIndex);
       
  1121         }
       
  1122     }
       
  1123 }
       
  1124 
       
  1125 /*!
       
  1126     \reimp
       
  1127 */
       
  1128 void QFileSystemModel::sort(int column, Qt::SortOrder order)
       
  1129 {
       
  1130     Q_D(QFileSystemModel);
       
  1131     if (d->sortOrder == order && d->sortColumn == column && !d->forceSort)
       
  1132         return;
       
  1133 
       
  1134     emit layoutAboutToBeChanged();
       
  1135     QModelIndexList oldList = persistentIndexList();
       
  1136     QList<QPair<QFileSystemModelPrivate::QFileSystemNode*, int> > oldNodes;
       
  1137     for (int i = 0; i < oldList.count(); ++i) {
       
  1138         QPair<QFileSystemModelPrivate::QFileSystemNode*, int> pair(d->node(oldList.at(i)), oldList.at(i).column());
       
  1139         oldNodes.append(pair);
       
  1140     }
       
  1141 
       
  1142     if (!(d->sortColumn == column && d->sortOrder != order && !d->forceSort)) {
       
  1143         //we sort only from where we are, don't need to sort all the model
       
  1144         d->sortChildren(column, index(rootPath()));
       
  1145         d->sortColumn = column;
       
  1146         d->forceSort = false;
       
  1147     }
       
  1148     d->sortOrder = order;
       
  1149 
       
  1150     QModelIndexList newList;
       
  1151     for (int i = 0; i < oldNodes.count(); ++i) {
       
  1152         QModelIndex idx = d->index(oldNodes.at(i).first);
       
  1153         idx = idx.sibling(idx.row(), oldNodes.at(i).second);
       
  1154         newList.append(idx);
       
  1155     }
       
  1156     changePersistentIndexList(oldList, newList);
       
  1157     emit layoutChanged();
       
  1158 }
       
  1159 
       
  1160 /*!
       
  1161     Returns a list of MIME types that can be used to describe a list of items
       
  1162     in the model.
       
  1163 */
       
  1164 QStringList QFileSystemModel::mimeTypes() const
       
  1165 {
       
  1166     return QStringList(QLatin1String("text/uri-list"));
       
  1167 }
       
  1168 
       
  1169 /*!
       
  1170     Returns an object that contains a serialized description of the specified
       
  1171     \a indexes. The format used to describe the items corresponding to the
       
  1172     indexes is obtained from the mimeTypes() function.
       
  1173 
       
  1174     If the list of indexes is empty, 0 is returned rather than a serialized
       
  1175     empty list.
       
  1176 */
       
  1177 QMimeData *QFileSystemModel::mimeData(const QModelIndexList &indexes) const
       
  1178 {
       
  1179     QList<QUrl> urls;
       
  1180     QList<QModelIndex>::const_iterator it = indexes.begin();
       
  1181     for (; it != indexes.end(); ++it)
       
  1182         if ((*it).column() == 0)
       
  1183             urls << QUrl::fromLocalFile(filePath(*it));
       
  1184     QMimeData *data = new QMimeData();
       
  1185     data->setUrls(urls);
       
  1186     return data;
       
  1187 }
       
  1188 
       
  1189 /*!
       
  1190     Handles the \a data supplied by a drag and drop operation that ended with
       
  1191     the given \a action over the row in the model specified by the \a row and
       
  1192     \a column and by the \a parent index.
       
  1193 
       
  1194     \sa supportedDropActions()
       
  1195 */
       
  1196 bool QFileSystemModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
       
  1197                              int row, int column, const QModelIndex &parent)
       
  1198 {
       
  1199     Q_UNUSED(row);
       
  1200     Q_UNUSED(column);
       
  1201     if (!parent.isValid() || isReadOnly())
       
  1202         return false;
       
  1203 
       
  1204     bool success = true;
       
  1205     QString to = filePath(parent) + QDir::separator();
       
  1206 
       
  1207     QList<QUrl> urls = data->urls();
       
  1208     QList<QUrl>::const_iterator it = urls.constBegin();
       
  1209 
       
  1210     switch (action) {
       
  1211     case Qt::CopyAction:
       
  1212         for (; it != urls.constEnd(); ++it) {
       
  1213             QString path = (*it).toLocalFile();
       
  1214             success = QFile::copy(path, to + QFileInfo(path).fileName()) && success;
       
  1215         }
       
  1216         break;
       
  1217     case Qt::LinkAction:
       
  1218         for (; it != urls.constEnd(); ++it) {
       
  1219             QString path = (*it).toLocalFile();
       
  1220             success = QFile::link(path, to + QFileInfo(path).fileName()) && success;
       
  1221         }
       
  1222         break;
       
  1223     case Qt::MoveAction:
       
  1224         for (; it != urls.constEnd(); ++it) {
       
  1225             QString path = (*it).toLocalFile();
       
  1226             success = QFile::rename(path, to + QFileInfo(path).fileName()) && success;
       
  1227         }
       
  1228         break;
       
  1229     default:
       
  1230         return false;
       
  1231     }
       
  1232 
       
  1233     return success;
       
  1234 }
       
  1235 
       
  1236 /*!
       
  1237     \reimp
       
  1238 */
       
  1239 Qt::DropActions QFileSystemModel::supportedDropActions() const
       
  1240 {
       
  1241     return Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
       
  1242 }
       
  1243 
       
  1244 /*!
       
  1245     Returns the path of the item stored in the model under the
       
  1246     \a index given.
       
  1247 */
       
  1248 QString QFileSystemModel::filePath(const QModelIndex &index) const
       
  1249 {
       
  1250     Q_D(const QFileSystemModel);
       
  1251     QString fullPath = d->filePath(index);
       
  1252     QFileSystemModelPrivate::QFileSystemNode *dirNode = d->node(index);
       
  1253     if (dirNode->isSymLink() && d->fileInfoGatherer.resolveSymlinks()
       
  1254         && d->resolvedSymLinks.contains(fullPath)
       
  1255         && dirNode->isDir()) {
       
  1256         QFileInfo resolvedInfo(fullPath);
       
  1257         resolvedInfo = resolvedInfo.canonicalFilePath();
       
  1258         if (resolvedInfo.exists())
       
  1259             return resolvedInfo.filePath();
       
  1260     }
       
  1261     return fullPath;
       
  1262 }
       
  1263 
       
  1264 QString QFileSystemModelPrivate::filePath(const QModelIndex &index) const
       
  1265 {
       
  1266     Q_Q(const QFileSystemModel);
       
  1267     Q_UNUSED(q);
       
  1268     if (!index.isValid())
       
  1269         return QString();
       
  1270     Q_ASSERT(index.model() == q);
       
  1271 
       
  1272     QStringList path;
       
  1273     QModelIndex idx = index;
       
  1274     while (idx.isValid()) {
       
  1275         QFileSystemModelPrivate::QFileSystemNode *dirNode = node(idx);
       
  1276         if (dirNode)
       
  1277             path.prepend(dirNode->fileName);
       
  1278         idx = idx.parent();
       
  1279     }
       
  1280     QString fullPath = QDir::fromNativeSeparators(path.join(QDir::separator()));
       
  1281 #if !defined(Q_OS_WIN) || defined(Q_OS_WINCE)
       
  1282     if ((fullPath.length() > 2) && fullPath[0] == QLatin1Char('/') && fullPath[1] == QLatin1Char('/'))
       
  1283         fullPath = fullPath.mid(1);
       
  1284 #endif
       
  1285     return fullPath;
       
  1286 }
       
  1287 
       
  1288 /*!
       
  1289     Create a directory with the \a name in the \a parent model index.
       
  1290 */
       
  1291 QModelIndex QFileSystemModel::mkdir(const QModelIndex &parent, const QString &name)
       
  1292 {
       
  1293     Q_D(QFileSystemModel);
       
  1294     if (!parent.isValid())
       
  1295         return parent;
       
  1296 
       
  1297     QDir dir(filePath(parent));
       
  1298     if (!dir.mkdir(name))
       
  1299         return QModelIndex();
       
  1300     QFileSystemModelPrivate::QFileSystemNode *parentNode = d->node(parent);
       
  1301     d->addNode(parentNode, name, QFileInfo());
       
  1302     Q_ASSERT(parentNode->children.contains(name));
       
  1303     QFileSystemModelPrivate::QFileSystemNode *node = parentNode->children[name];
       
  1304     node->populate(d->fileInfoGatherer.getInfo(QFileInfo(dir.absolutePath() + QDir::separator() + name)));
       
  1305     d->addVisibleFiles(parentNode, QStringList(name));
       
  1306     return d->index(node);
       
  1307 }
       
  1308 
       
  1309 /*!
       
  1310     Returns the complete OR-ed together combination of QFile::Permission for the \a index.
       
  1311  */
       
  1312 QFile::Permissions QFileSystemModel::permissions(const QModelIndex &index) const
       
  1313 {
       
  1314     Q_D(const QFileSystemModel);
       
  1315     QFile::Permissions p = d->node(index)->permissions();
       
  1316     if (d->readOnly) {
       
  1317         p ^= (QFile::WriteOwner | QFile::WriteUser
       
  1318             | QFile::WriteGroup | QFile::WriteOther);
       
  1319     }
       
  1320     return p;
       
  1321 }
       
  1322 
       
  1323 /*!
       
  1324     Sets the directory that is being watched by the model to \a newPath by
       
  1325     installing a \l{QFileSystemWatcher}{file system watcher} on it. Any
       
  1326     changes to files and directories within this directory will be
       
  1327     reflected in the model.
       
  1328 
       
  1329     If the path is changed, the rootPathChanged() signal will be emitted.
       
  1330 
       
  1331     \note This function does not change the structure of the model or
       
  1332     modify the data available to views. In other words, the "root" of
       
  1333     the model is \e not changed to include only files and directories
       
  1334     within the directory specified by \a newPath in the file system.
       
  1335   */
       
  1336 QModelIndex QFileSystemModel::setRootPath(const QString &newPath)
       
  1337 {
       
  1338     Q_D(QFileSystemModel);
       
  1339 #ifdef Q_OS_WIN
       
  1340     QString longNewPath = QDir::fromNativeSeparators(qt_GetLongPathName(newPath));
       
  1341 #else
       
  1342     QString longNewPath = newPath;
       
  1343 #endif
       
  1344     QDir newPathDir(longNewPath);
       
  1345     //we remove .. and . from the given path if exist
       
  1346     if (!newPath.isEmpty()) {
       
  1347         longNewPath = QDir::cleanPath(longNewPath);
       
  1348         newPathDir.setPath(longNewPath);
       
  1349     }
       
  1350 
       
  1351     d->setRootPath = true;
       
  1352 
       
  1353     //user don't ask for the root path ("") but the conversion failed
       
  1354     if (!newPath.isEmpty() && longNewPath.isEmpty())
       
  1355         return d->index(rootPath());
       
  1356 
       
  1357     if (d->rootDir.path() == longNewPath)
       
  1358         return d->index(rootPath());
       
  1359 
       
  1360     bool showDrives = (longNewPath.isEmpty() || longNewPath == d->myComputer());
       
  1361     if (!showDrives && !newPathDir.exists())
       
  1362         return d->index(rootPath());
       
  1363 
       
  1364     // We have a new valid root path
       
  1365     d->rootDir = newPathDir;
       
  1366     QModelIndex newRootIndex;
       
  1367     if (showDrives) {
       
  1368         // otherwise dir will become '.'
       
  1369         d->rootDir.setPath(QLatin1String(""));
       
  1370     } else {
       
  1371         newRootIndex = d->index(newPathDir.path());
       
  1372     }
       
  1373     fetchMore(newRootIndex);
       
  1374     emit rootPathChanged(longNewPath);
       
  1375     d->forceSort = true;
       
  1376     d->delayedSort();
       
  1377     return newRootIndex;
       
  1378 }
       
  1379 
       
  1380 /*!
       
  1381     The currently set root path
       
  1382 
       
  1383     \sa rootDirectory()
       
  1384 */
       
  1385 QString QFileSystemModel::rootPath() const
       
  1386 {
       
  1387     Q_D(const QFileSystemModel);
       
  1388     return d->rootDir.path();
       
  1389 }
       
  1390 
       
  1391 /*!
       
  1392     The currently set directory
       
  1393 
       
  1394     \sa rootPath()
       
  1395 */
       
  1396 QDir QFileSystemModel::rootDirectory() const
       
  1397 {
       
  1398     Q_D(const QFileSystemModel);
       
  1399     QDir dir(d->rootDir);
       
  1400     dir.setNameFilters(nameFilters());
       
  1401     dir.setFilter(filter());
       
  1402     return dir;
       
  1403 }
       
  1404 
       
  1405 /*!
       
  1406     Sets the \a provider of file icons for the directory model.
       
  1407 */
       
  1408 void QFileSystemModel::setIconProvider(QFileIconProvider *provider)
       
  1409 {
       
  1410     Q_D(QFileSystemModel);
       
  1411     d->fileInfoGatherer.setIconProvider(provider);
       
  1412     QApplication::processEvents();
       
  1413     d->root.updateIcon(provider, QString());
       
  1414 }
       
  1415 
       
  1416 /*!
       
  1417     Returns the file icon provider for this directory model.
       
  1418 */
       
  1419 QFileIconProvider *QFileSystemModel::iconProvider() const
       
  1420 {
       
  1421     Q_D(const QFileSystemModel);
       
  1422     return d->fileInfoGatherer.iconProvider();
       
  1423 }
       
  1424 
       
  1425 /*!
       
  1426     Sets the directory model's filter to that specified by \a filters.
       
  1427 
       
  1428     Note that the filter you set should always include the QDir::AllDirs enum value,
       
  1429     otherwise QFileSystemModel won't be able to read the directory structure.
       
  1430 
       
  1431     \sa QDir::Filters
       
  1432 */
       
  1433 void QFileSystemModel::setFilter(QDir::Filters filters)
       
  1434 {
       
  1435     Q_D(QFileSystemModel);
       
  1436     if (d->filters == filters)
       
  1437         return;
       
  1438     d->filters = filters;
       
  1439     // CaseSensitivity might have changed
       
  1440     setNameFilters(nameFilters());
       
  1441     d->forceSort = true;
       
  1442     d->delayedSort();
       
  1443 }
       
  1444 
       
  1445 /*!
       
  1446     Returns the filter specified for the directory model.
       
  1447 
       
  1448     If a filter has not been set, the default filter is QDir::AllEntries |
       
  1449     QDir::NoDotAndDotDot | QDir::AllDirs.
       
  1450 
       
  1451     \sa QDir::Filters
       
  1452 */
       
  1453 QDir::Filters QFileSystemModel::filter() const
       
  1454 {
       
  1455     Q_D(const QFileSystemModel);
       
  1456     return d->filters;
       
  1457 }
       
  1458 
       
  1459 /*!
       
  1460     \property QFileSystemModel::resolveSymlinks
       
  1461     \brief Whether the directory model should resolve symbolic links
       
  1462 
       
  1463     This is only relevant on operating systems that support symbolic links.
       
  1464 
       
  1465     By default, this property is false.
       
  1466 */
       
  1467 void QFileSystemModel::setResolveSymlinks(bool enable)
       
  1468 {
       
  1469     Q_D(QFileSystemModel);
       
  1470     d->fileInfoGatherer.setResolveSymlinks(enable);
       
  1471 }
       
  1472 
       
  1473 bool QFileSystemModel::resolveSymlinks() const
       
  1474 {
       
  1475     Q_D(const QFileSystemModel);
       
  1476     return d->fileInfoGatherer.resolveSymlinks();
       
  1477 }
       
  1478 
       
  1479 /*!
       
  1480     \property QFileSystemModel::readOnly
       
  1481     \brief Whether the directory model allows writing to the file system
       
  1482 
       
  1483     If this property is set to false, the directory model will allow renaming, copying
       
  1484     and deleting of files and directories.
       
  1485 
       
  1486     This property is true by default
       
  1487 */
       
  1488 void QFileSystemModel::setReadOnly(bool enable)
       
  1489 {
       
  1490     Q_D(QFileSystemModel);
       
  1491     d->readOnly = enable;
       
  1492 }
       
  1493 
       
  1494 bool QFileSystemModel::isReadOnly() const
       
  1495 {
       
  1496     Q_D(const QFileSystemModel);
       
  1497     return d->readOnly;
       
  1498 }
       
  1499 
       
  1500 /*!
       
  1501     \property QFileSystemModel::nameFilterDisables
       
  1502     \brief Whether files that don't pass the name filter are hidden or disabled
       
  1503 
       
  1504     This property is true by default
       
  1505 */
       
  1506 void QFileSystemModel::setNameFilterDisables(bool enable)
       
  1507 {
       
  1508     Q_D(QFileSystemModel);
       
  1509     if (d->nameFilterDisables == enable)
       
  1510         return;
       
  1511     d->nameFilterDisables = enable;
       
  1512     d->forceSort = true;
       
  1513     d->delayedSort();
       
  1514 }
       
  1515 
       
  1516 bool QFileSystemModel::nameFilterDisables() const
       
  1517 {
       
  1518     Q_D(const QFileSystemModel);
       
  1519     return d->nameFilterDisables;
       
  1520 }
       
  1521 
       
  1522 /*!
       
  1523     Sets the name \a filters to apply against the existing files.
       
  1524 */
       
  1525 void QFileSystemModel::setNameFilters(const QStringList &filters)
       
  1526 {
       
  1527     // Prep the regexp's ahead of time
       
  1528 #ifndef QT_NO_REGEXP
       
  1529     Q_D(QFileSystemModel);
       
  1530 
       
  1531     if (!d->bypassFilters.isEmpty()) {
       
  1532         // update the bypass filter to only bypass the stuff that must be kept around
       
  1533         d->bypassFilters.clear();
       
  1534         // We guarantee that rootPath will stick around
       
  1535         QPersistentModelIndex root(index(rootPath()));
       
  1536         QModelIndexList persistantList = persistentIndexList();
       
  1537         for (int i = 0; i < persistantList.count(); ++i) {
       
  1538             QFileSystemModelPrivate::QFileSystemNode *node;
       
  1539             node = d->node(persistantList.at(i));
       
  1540             while (node) {
       
  1541                 if (d->bypassFilters.contains(node))
       
  1542                     break;
       
  1543                 if (node->isDir())
       
  1544                     d->bypassFilters[node] = true;
       
  1545                 node = node->parent;
       
  1546             }
       
  1547         }
       
  1548     }
       
  1549 
       
  1550     d->nameFilters.clear();
       
  1551     const Qt::CaseSensitivity caseSensitive =
       
  1552         (filter() & QDir::CaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive;
       
  1553     for (int i = 0; i < filters.size(); ++i) {
       
  1554         d->nameFilters << QRegExp(filters.at(i), caseSensitive, QRegExp::Wildcard);
       
  1555     }
       
  1556     d->forceSort = true;
       
  1557     d->delayedSort();
       
  1558 #endif
       
  1559 }
       
  1560 
       
  1561 /*!
       
  1562     Returns a list of filters applied to the names in the model.
       
  1563 */
       
  1564 QStringList QFileSystemModel::nameFilters() const
       
  1565 {
       
  1566     Q_D(const QFileSystemModel);
       
  1567     QStringList filters;
       
  1568 #ifndef QT_NO_REGEXP
       
  1569     for (int i = 0; i < d->nameFilters.size(); ++i) {
       
  1570          filters << d->nameFilters.at(i).pattern();
       
  1571     }
       
  1572 #endif
       
  1573     return filters;
       
  1574 }
       
  1575 
       
  1576 /*!
       
  1577     \reimp
       
  1578 */
       
  1579 bool QFileSystemModel::event(QEvent *event)
       
  1580 {
       
  1581     Q_D(QFileSystemModel);
       
  1582     if (event->type() == QEvent::LanguageChange) {
       
  1583         d->root.retranslateStrings(d->fileInfoGatherer.iconProvider(), QString());
       
  1584         return true;
       
  1585     }
       
  1586     return QAbstractItemModel::event(event);
       
  1587 }
       
  1588 
       
  1589 /*!
       
  1590      \internal
       
  1591 
       
  1592     Performed quick listing and see if any files have been added or removed,
       
  1593     then fetch more information on visible files.
       
  1594  */
       
  1595 void QFileSystemModelPrivate::_q_directoryChanged(const QString &directory, const QStringList &files)
       
  1596 {
       
  1597     QFileSystemModelPrivate::QFileSystemNode *parentNode = node(directory, false);
       
  1598     if (parentNode->children.count() == 0)
       
  1599         return;
       
  1600     QStringList toRemove;
       
  1601 #if defined(Q_OS_SYMBIAN)
       
  1602     // Filename case must be exact in qBinaryFind below, so create a list of all lowercase names.
       
  1603     QStringList newFiles;
       
  1604     for(int i = 0; i < files.size(); i++) {
       
  1605         newFiles << files.at(i).toLower();
       
  1606     }
       
  1607 #else
       
  1608     QStringList newFiles = files;
       
  1609 #endif
       
  1610     qSort(newFiles.begin(), newFiles.end());
       
  1611     QHash<QString, QFileSystemNode*>::const_iterator i = parentNode->children.constBegin();
       
  1612     while (i != parentNode->children.constEnd()) {
       
  1613         QStringList::iterator iterator;
       
  1614         iterator = qBinaryFind(newFiles.begin(), newFiles.end(),
       
  1615 #if defined(Q_OS_SYMBIAN)
       
  1616                     i.value()->fileName.toLower());
       
  1617 #else
       
  1618                     i.value()->fileName);
       
  1619 #endif
       
  1620         if (iterator == newFiles.end()) {
       
  1621             toRemove.append(i.value()->fileName);
       
  1622         }
       
  1623         ++i;
       
  1624     }
       
  1625     for (int i = 0 ; i < toRemove.count() ; ++i )
       
  1626         removeNode(parentNode, toRemove[i]);
       
  1627 }
       
  1628 
       
  1629 /*!
       
  1630     \internal
       
  1631 
       
  1632     Adds a new file to the children of parentNode
       
  1633 
       
  1634     *WARNING* this will change the count of children
       
  1635 */
       
  1636 QFileSystemModelPrivate::QFileSystemNode* QFileSystemModelPrivate::addNode(QFileSystemNode *parentNode, const QString &fileName, const QFileInfo& info)
       
  1637 {
       
  1638     // In the common case, itemLocation == count() so check there first
       
  1639     QFileSystemModelPrivate::QFileSystemNode *node = new QFileSystemModelPrivate::QFileSystemNode(fileName, parentNode);
       
  1640 #ifndef QT_NO_FILESYSTEMWATCHER
       
  1641     node->populate(info);
       
  1642 #endif
       
  1643     parentNode->children.insert(fileName, node);
       
  1644     return node;
       
  1645 }
       
  1646 
       
  1647 /*!
       
  1648     \internal
       
  1649 
       
  1650     File at parentNode->children(itemLocation) has been removed, remove from the lists
       
  1651     and emit signals if necessary
       
  1652 
       
  1653     *WARNING* this will change the count of children and could change visibleChildren
       
  1654  */
       
  1655 void QFileSystemModelPrivate::removeNode(QFileSystemModelPrivate::QFileSystemNode *parentNode, const QString& name)
       
  1656 {
       
  1657     Q_Q(QFileSystemModel);
       
  1658     QModelIndex parent = index(parentNode);
       
  1659     bool indexHidden = isHiddenByFilter(parentNode, parent);
       
  1660 
       
  1661     int vLocation = parentNode->visibleLocation(name);
       
  1662     if (vLocation >= 0 && !indexHidden)
       
  1663         q->beginRemoveRows(parent, translateVisibleLocation(parentNode, vLocation),
       
  1664                                        translateVisibleLocation(parentNode, vLocation));
       
  1665     QFileSystemNode * node = parentNode->children.take(name);
       
  1666     delete node;
       
  1667     // cleanup sort files after removing rather then re-sorting which is O(n)
       
  1668     if (vLocation >= 0)
       
  1669         parentNode->visibleChildren.removeAt(vLocation);
       
  1670     if (vLocation >= 0 && !indexHidden)
       
  1671         q->endRemoveRows();
       
  1672 }
       
  1673 
       
  1674 /*
       
  1675     \internal
       
  1676     Helper functor used by addVisibleFiles()
       
  1677 */
       
  1678 class QFileSystemModelVisibleFinder
       
  1679 {
       
  1680 public:
       
  1681     inline QFileSystemModelVisibleFinder(QFileSystemModelPrivate::QFileSystemNode *node, QFileSystemModelSorter *sorter) : parentNode(node), sorter(sorter) {}
       
  1682 
       
  1683     bool operator()(const QString &, QString r) const
       
  1684     {
       
  1685         return sorter->compareNodes(parentNode->children.value(name), parentNode->children.value(r));
       
  1686     }
       
  1687 
       
  1688     QString name;
       
  1689 private:
       
  1690     QFileSystemModelPrivate::QFileSystemNode *parentNode;
       
  1691     QFileSystemModelSorter *sorter;
       
  1692 };
       
  1693 
       
  1694 /*!
       
  1695     \internal
       
  1696 
       
  1697     File at parentNode->children(itemLocation) was not visible before, but now should be
       
  1698     and emit signals if necessary.
       
  1699 
       
  1700     *WARNING* this will change the visible count
       
  1701  */
       
  1702 void QFileSystemModelPrivate::addVisibleFiles(QFileSystemNode *parentNode, const QStringList &newFiles)
       
  1703 {
       
  1704     Q_Q(QFileSystemModel);
       
  1705     QModelIndex parent = index(parentNode);
       
  1706     bool indexHidden = isHiddenByFilter(parentNode, parent);
       
  1707     if (!indexHidden) {
       
  1708         q->beginInsertRows(parent, parentNode->visibleChildren.count() , parentNode->visibleChildren.count() + newFiles.count() - 1);
       
  1709     }
       
  1710 
       
  1711     if (parentNode->dirtyChildrenIndex == -1)
       
  1712         parentNode->dirtyChildrenIndex = parentNode->visibleChildren.count();
       
  1713 
       
  1714     for (int i = 0; i < newFiles.count(); ++i) {
       
  1715             parentNode->visibleChildren.append(newFiles.at(i));
       
  1716             parentNode->children[newFiles.at(i)]->isVisible = true;
       
  1717         }
       
  1718     if (!indexHidden)
       
  1719       q->endInsertRows();
       
  1720 }
       
  1721 
       
  1722 /*!
       
  1723     \internal
       
  1724 
       
  1725     File was visible before, but now should NOT be
       
  1726 
       
  1727     *WARNING* this will change the visible count
       
  1728  */
       
  1729 void QFileSystemModelPrivate::removeVisibleFile(QFileSystemNode *parentNode, int vLocation)
       
  1730 {
       
  1731     Q_Q(QFileSystemModel);
       
  1732     if (vLocation == -1)
       
  1733         return;
       
  1734     QModelIndex parent = index(parentNode);
       
  1735     bool indexHidden = isHiddenByFilter(parentNode, parent);
       
  1736     if (!indexHidden)
       
  1737         q->beginRemoveRows(parent, translateVisibleLocation(parentNode, vLocation),
       
  1738                                        translateVisibleLocation(parentNode, vLocation));
       
  1739     parentNode->children[parentNode->visibleChildren.at(vLocation)]->isVisible = false;
       
  1740     parentNode->visibleChildren.removeAt(vLocation);
       
  1741     if (!indexHidden)
       
  1742         q->endRemoveRows();
       
  1743 }
       
  1744 
       
  1745 /*!
       
  1746     \internal
       
  1747 
       
  1748     The thread has received new information about files,
       
  1749     update and emit dataChanged if it has actually changed.
       
  1750  */
       
  1751 void QFileSystemModelPrivate::_q_fileSystemChanged(const QString &path, const QList<QPair<QString, QFileInfo> > &updates)
       
  1752 {
       
  1753     Q_Q(QFileSystemModel);
       
  1754     QVector<QString> rowsToUpdate;
       
  1755     QStringList newFiles;
       
  1756     QFileSystemModelPrivate::QFileSystemNode *parentNode = node(path, false);
       
  1757     QModelIndex parentIndex = index(parentNode);
       
  1758     for (int i = 0; i < updates.count(); ++i) {
       
  1759         QString fileName = updates.at(i).first;
       
  1760         Q_ASSERT(!fileName.isEmpty());
       
  1761         QExtendedInformation info = fileInfoGatherer.getInfo(updates.at(i).second);
       
  1762         bool previouslyHere = parentNode->children.contains(fileName);
       
  1763         if (!previouslyHere) {
       
  1764             addNode(parentNode, fileName, info.fileInfo());
       
  1765         }
       
  1766         QFileSystemModelPrivate::QFileSystemNode * node = parentNode->children.value(fileName);
       
  1767         bool isCaseSensitive = parentNode->caseSensitive();
       
  1768         if (isCaseSensitive) {
       
  1769             if (node->fileName != fileName)
       
  1770                 continue;
       
  1771         } else {
       
  1772             if (QString::compare(node->fileName,fileName,Qt::CaseInsensitive) != 0)
       
  1773                 continue;
       
  1774         }
       
  1775         if (isCaseSensitive) {
       
  1776             Q_ASSERT(node->fileName == fileName);
       
  1777         } else {
       
  1778             node->fileName = fileName;
       
  1779         }
       
  1780 
       
  1781         if (info.size() == -1 && !info.isSymLink()) {
       
  1782             removeNode(parentNode, fileName);
       
  1783             continue;
       
  1784         }
       
  1785         if (*node != info ) {
       
  1786             node->populate(info);
       
  1787             bypassFilters.remove(node);
       
  1788             // brand new information.
       
  1789             if (filtersAcceptsNode(node)) {
       
  1790                 if (!node->isVisible) {
       
  1791                     newFiles.append(fileName);
       
  1792                 } else {
       
  1793                     rowsToUpdate.append(fileName);
       
  1794                 }
       
  1795             } else {
       
  1796                 if (node->isVisible) {
       
  1797                     int visibleLocation = parentNode->visibleLocation(fileName);
       
  1798                     removeVisibleFile(parentNode, visibleLocation);
       
  1799                 } else {
       
  1800                     // The file is not visible, don't do anything
       
  1801                 }
       
  1802             }
       
  1803         }
       
  1804     }
       
  1805 
       
  1806     // bundle up all of the changed signals into as few as possible.
       
  1807     qSort(rowsToUpdate.begin(), rowsToUpdate.end());
       
  1808     QString min;
       
  1809     QString max;
       
  1810     for (int i = 0; i < rowsToUpdate.count(); ++i) {
       
  1811         QString value = rowsToUpdate.at(i);
       
  1812         //##TODO is there a way to bundle signals with QString as the content of the list?
       
  1813         /*if (min.isEmpty()) {
       
  1814             min = value;
       
  1815             if (i != rowsToUpdate.count() - 1)
       
  1816                 continue;
       
  1817         }
       
  1818         if (i != rowsToUpdate.count() - 1) {
       
  1819             if ((value == min + 1 && max.isEmpty()) || value == max + 1) {
       
  1820                 max = value;
       
  1821                 continue;
       
  1822             }
       
  1823         }*/
       
  1824         max = value;
       
  1825         min = value;
       
  1826         int visibleMin = parentNode->visibleLocation(min);
       
  1827         int visibleMax = parentNode->visibleLocation(max);
       
  1828         if (visibleMin >= 0
       
  1829             && visibleMin < parentNode->visibleChildren.count()
       
  1830             && parentNode->visibleChildren.at(visibleMin) == min
       
  1831             && visibleMax >= 0) {
       
  1832             QModelIndex bottom = q->index(translateVisibleLocation(parentNode, visibleMin), 0, parentIndex);
       
  1833             QModelIndex top = q->index(translateVisibleLocation(parentNode, visibleMax), 3, parentIndex);
       
  1834             emit q->dataChanged(bottom, top);
       
  1835         }
       
  1836 
       
  1837         /*min = QString();
       
  1838         max = QString();*/
       
  1839     }
       
  1840 
       
  1841     if (newFiles.count() > 0) {
       
  1842         addVisibleFiles(parentNode, newFiles);
       
  1843     }
       
  1844 
       
  1845     if (newFiles.count() > 0 || (sortColumn != 0 && rowsToUpdate.count() > 0)) {
       
  1846         forceSort = true;
       
  1847         delayedSort();
       
  1848     }
       
  1849 }
       
  1850 
       
  1851 /*!
       
  1852     \internal
       
  1853 */
       
  1854 void QFileSystemModelPrivate::_q_resolvedName(const QString &fileName, const QString &resolvedName)
       
  1855 {
       
  1856     resolvedSymLinks[fileName] = resolvedName;
       
  1857 }
       
  1858 
       
  1859 /*!
       
  1860     \internal
       
  1861 */
       
  1862 void QFileSystemModelPrivate::init()
       
  1863 {
       
  1864     Q_Q(QFileSystemModel);
       
  1865     qRegisterMetaType<QList<QPair<QString,QFileInfo> > >("QList<QPair<QString,QFileInfo> >");
       
  1866     q->connect(&fileInfoGatherer, SIGNAL(newListOfFiles(QString,QStringList)),
       
  1867                q, SLOT(_q_directoryChanged(QString,QStringList)));
       
  1868     q->connect(&fileInfoGatherer, SIGNAL(updates(QString,QList<QPair<QString,QFileInfo> >)),
       
  1869             q, SLOT(_q_fileSystemChanged(QString,QList<QPair<QString,QFileInfo> >)));
       
  1870     q->connect(&fileInfoGatherer, SIGNAL(nameResolved(QString,QString)),
       
  1871             q, SLOT(_q_resolvedName(QString,QString)));
       
  1872     q->connect(&delayedSortTimer, SIGNAL(timeout()), q, SLOT(_q_performDelayedSort()), Qt::QueuedConnection);
       
  1873 }
       
  1874 
       
  1875 /*!
       
  1876     \internal
       
  1877 
       
  1878     Returns false if node doesn't pass the filters otherwise true
       
  1879 
       
  1880     QDir::Modified is not supported
       
  1881     QDir::Drives is not supported
       
  1882 */
       
  1883 bool QFileSystemModelPrivate::filtersAcceptsNode(const QFileSystemNode *node) const
       
  1884 {
       
  1885     // always accept drives
       
  1886     if (node->parent == &root || bypassFilters.contains(node))
       
  1887         return true;
       
  1888 
       
  1889     // If we don't know anything yet don't accept it
       
  1890     if (!node->hasInformation())
       
  1891         return false;
       
  1892 
       
  1893     const bool filterPermissions = ((filters & QDir::PermissionMask)
       
  1894                                    && (filters & QDir::PermissionMask) != QDir::PermissionMask);
       
  1895     const bool hideDirs          = !(filters & (QDir::Dirs | QDir::AllDirs));
       
  1896     const bool hideFiles         = !(filters & QDir::Files);
       
  1897     const bool hideReadable      = !(!filterPermissions || (filters & QDir::Readable));
       
  1898     const bool hideWritable      = !(!filterPermissions || (filters & QDir::Writable));
       
  1899     const bool hideExecutable    = !(!filterPermissions || (filters & QDir::Executable));
       
  1900     const bool hideHidden        = !(filters & QDir::Hidden);
       
  1901     const bool hideSystem        = !(filters & QDir::System);
       
  1902     const bool hideSymlinks      = (filters & QDir::NoSymLinks);
       
  1903     const bool hideDotAndDotDot  = (filters & QDir::NoDotAndDotDot);
       
  1904 
       
  1905     // Note that we match the behavior of entryList and not QFileInfo on this and this
       
  1906     // incompatibility won't be fixed until Qt 5 at least
       
  1907     bool isDotOrDot = (  (node->fileName == QLatin1String(".")
       
  1908                        || node->fileName == QLatin1String("..")));
       
  1909     if (   (hideHidden && (!isDotOrDot && node->isHidden()))
       
  1910         || (hideSystem && node->isSystem())
       
  1911         || (hideDirs && node->isDir())
       
  1912         || (hideFiles && node->isFile())
       
  1913         || (hideSymlinks && node->isSymLink())
       
  1914         || (hideReadable && node->isReadable())
       
  1915         || (hideWritable && node->isWritable())
       
  1916         || (hideExecutable && node->isExecutable())
       
  1917         || (hideDotAndDotDot && isDotOrDot))
       
  1918         return false;
       
  1919 
       
  1920     return nameFilterDisables || passNameFilters(node);
       
  1921 }
       
  1922 
       
  1923 /*
       
  1924     \internal
       
  1925 
       
  1926     Returns true if node passes the name filters and should be visible.
       
  1927  */
       
  1928 bool QFileSystemModelPrivate::passNameFilters(const QFileSystemNode *node) const
       
  1929 {
       
  1930 #ifndef QT_NO_REGEXP
       
  1931     if (nameFilters.isEmpty())
       
  1932         return true;
       
  1933 
       
  1934     // Check the name regularexpression filters
       
  1935     if (!(node->isDir() && (filters & QDir::AllDirs))) {
       
  1936         for (int i = 0; i < nameFilters.size(); ++i) {
       
  1937             if (nameFilters.at(i).exactMatch(node->fileName))
       
  1938                 return true;
       
  1939         }
       
  1940         return false;
       
  1941     }
       
  1942 #endif
       
  1943     return true;
       
  1944 }
       
  1945 
       
  1946 QT_END_NAMESPACE
       
  1947 
       
  1948 #include "moc_qfilesystemmodel.cpp"
       
  1949 
       
  1950 #endif // QT_NO_FILESYSTEMMODEL