src/gui/dialogs/qfilesystemmodel.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 "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::copy(path, to + QFileInfo(path).fileName())
       
  1227                       && QFile::remove(path) && success;
       
  1228         }
       
  1229         break;
       
  1230     default:
       
  1231         return false;
       
  1232     }
       
  1233 
       
  1234     return success;
       
  1235 }
       
  1236 
       
  1237 /*!
       
  1238     \reimp
       
  1239 */
       
  1240 Qt::DropActions QFileSystemModel::supportedDropActions() const
       
  1241 {
       
  1242     return Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
       
  1243 }
       
  1244 
       
  1245 /*!
       
  1246     Returns the path of the item stored in the model under the
       
  1247     \a index given.
       
  1248 */
       
  1249 QString QFileSystemModel::filePath(const QModelIndex &index) const
       
  1250 {
       
  1251     Q_D(const QFileSystemModel);
       
  1252     QString fullPath = d->filePath(index);
       
  1253     QFileSystemModelPrivate::QFileSystemNode *dirNode = d->node(index);
       
  1254     if (dirNode->isSymLink() && d->fileInfoGatherer.resolveSymlinks()
       
  1255         && d->resolvedSymLinks.contains(fullPath)
       
  1256         && dirNode->isDir()) {
       
  1257         QFileInfo resolvedInfo(fullPath);
       
  1258         resolvedInfo = resolvedInfo.canonicalFilePath();
       
  1259         if (resolvedInfo.exists())
       
  1260             return resolvedInfo.filePath();
       
  1261     }
       
  1262     return fullPath;
       
  1263 }
       
  1264 
       
  1265 QString QFileSystemModelPrivate::filePath(const QModelIndex &index) const
       
  1266 {
       
  1267     Q_Q(const QFileSystemModel);
       
  1268     Q_UNUSED(q);
       
  1269     if (!index.isValid())
       
  1270         return QString();
       
  1271     Q_ASSERT(index.model() == q);
       
  1272 
       
  1273     QStringList path;
       
  1274     QModelIndex idx = index;
       
  1275     while (idx.isValid()) {
       
  1276         QFileSystemModelPrivate::QFileSystemNode *dirNode = node(idx);
       
  1277         if (dirNode)
       
  1278             path.prepend(dirNode->fileName);
       
  1279         idx = idx.parent();
       
  1280     }
       
  1281     QString fullPath = QDir::fromNativeSeparators(path.join(QDir::separator()));
       
  1282 #if !defined(Q_OS_WIN) || defined(Q_OS_WINCE)
       
  1283     if ((fullPath.length() > 2) && fullPath[0] == QLatin1Char('/') && fullPath[1] == QLatin1Char('/'))
       
  1284         fullPath = fullPath.mid(1);
       
  1285 #endif
       
  1286     return fullPath;
       
  1287 }
       
  1288 
       
  1289 /*!
       
  1290     Create a directory with the \a name in the \a parent model index.
       
  1291 */
       
  1292 QModelIndex QFileSystemModel::mkdir(const QModelIndex &parent, const QString &name)
       
  1293 {
       
  1294     Q_D(QFileSystemModel);
       
  1295     if (!parent.isValid())
       
  1296         return parent;
       
  1297 
       
  1298     QDir dir(filePath(parent));
       
  1299     if (!dir.mkdir(name))
       
  1300         return QModelIndex();
       
  1301     QFileSystemModelPrivate::QFileSystemNode *parentNode = d->node(parent);
       
  1302     d->addNode(parentNode, name, QFileInfo());
       
  1303     Q_ASSERT(parentNode->children.contains(name));
       
  1304     QFileSystemModelPrivate::QFileSystemNode *node = parentNode->children[name];
       
  1305     node->populate(d->fileInfoGatherer.getInfo(QFileInfo(dir.absolutePath() + QDir::separator() + name)));
       
  1306     d->addVisibleFiles(parentNode, QStringList(name));
       
  1307     return d->index(node);
       
  1308 }
       
  1309 
       
  1310 /*!
       
  1311     Returns the complete OR-ed together combination of QFile::Permission for the \a index.
       
  1312  */
       
  1313 QFile::Permissions QFileSystemModel::permissions(const QModelIndex &index) const
       
  1314 {
       
  1315     Q_D(const QFileSystemModel);
       
  1316     QFile::Permissions p = d->node(index)->permissions();
       
  1317     if (d->readOnly) {
       
  1318         p ^= (QFile::WriteOwner | QFile::WriteUser
       
  1319             | QFile::WriteGroup | QFile::WriteOther);
       
  1320     }
       
  1321     return p;
       
  1322 }
       
  1323 
       
  1324 /*!
       
  1325     Sets the directory that is being watched by the model to \a newPath by
       
  1326     installing a \l{QFileSystemWatcher}{file system watcher} on it. Any
       
  1327     changes to files and directories within this directory will be
       
  1328     reflected in the model.
       
  1329 
       
  1330     If the path is changed, the rootPathChanged() signal will be emitted.
       
  1331 
       
  1332     \note This function does not change the structure of the model or
       
  1333     modify the data available to views. In other words, the "root" of
       
  1334     the model is \e not changed to include only files and directories
       
  1335     within the directory specified by \a newPath in the file system.
       
  1336   */
       
  1337 QModelIndex QFileSystemModel::setRootPath(const QString &newPath)
       
  1338 {
       
  1339     Q_D(QFileSystemModel);
       
  1340 #ifdef Q_OS_WIN
       
  1341     QString longNewPath = QDir::fromNativeSeparators(qt_GetLongPathName(newPath));
       
  1342 #else
       
  1343     QString longNewPath = newPath;
       
  1344 #endif
       
  1345     QDir newPathDir(longNewPath);
       
  1346     //we remove .. and . from the given path if exist
       
  1347     if (!newPath.isEmpty()) {
       
  1348         longNewPath = QDir::cleanPath(longNewPath);
       
  1349         newPathDir.setPath(longNewPath);
       
  1350     }
       
  1351 
       
  1352     d->setRootPath = true;
       
  1353 
       
  1354     //user don't ask for the root path ("") but the conversion failed
       
  1355     if (!newPath.isEmpty() && longNewPath.isEmpty())
       
  1356         return d->index(rootPath());
       
  1357 
       
  1358     if (d->rootDir.path() == longNewPath)
       
  1359         return d->index(rootPath());
       
  1360 
       
  1361     bool showDrives = (longNewPath.isEmpty() || longNewPath == d->myComputer());
       
  1362     if (!showDrives && !newPathDir.exists())
       
  1363         return d->index(rootPath());
       
  1364 
       
  1365     // We have a new valid root path
       
  1366     d->rootDir = newPathDir;
       
  1367     QModelIndex newRootIndex;
       
  1368     if (showDrives) {
       
  1369         // otherwise dir will become '.'
       
  1370         d->rootDir.setPath(QLatin1String(""));
       
  1371     } else {
       
  1372         newRootIndex = d->index(newPathDir.path());
       
  1373     }
       
  1374     fetchMore(newRootIndex);
       
  1375     emit rootPathChanged(longNewPath);
       
  1376     d->forceSort = true;
       
  1377     d->delayedSort();
       
  1378     return newRootIndex;
       
  1379 }
       
  1380 
       
  1381 /*!
       
  1382     The currently set root path
       
  1383 
       
  1384     \sa rootDirectory()
       
  1385 */
       
  1386 QString QFileSystemModel::rootPath() const
       
  1387 {
       
  1388     Q_D(const QFileSystemModel);
       
  1389     return d->rootDir.path();
       
  1390 }
       
  1391 
       
  1392 /*!
       
  1393     The currently set directory
       
  1394 
       
  1395     \sa rootPath()
       
  1396 */
       
  1397 QDir QFileSystemModel::rootDirectory() const
       
  1398 {
       
  1399     Q_D(const QFileSystemModel);
       
  1400     QDir dir(d->rootDir);
       
  1401     dir.setNameFilters(nameFilters());
       
  1402     dir.setFilter(filter());
       
  1403     return dir;
       
  1404 }
       
  1405 
       
  1406 /*!
       
  1407     Sets the \a provider of file icons for the directory model.
       
  1408 */
       
  1409 void QFileSystemModel::setIconProvider(QFileIconProvider *provider)
       
  1410 {
       
  1411     Q_D(QFileSystemModel);
       
  1412     d->fileInfoGatherer.setIconProvider(provider);
       
  1413     QApplication::processEvents();
       
  1414     d->root.updateIcon(provider, QString());
       
  1415 }
       
  1416 
       
  1417 /*!
       
  1418     Returns the file icon provider for this directory model.
       
  1419 */
       
  1420 QFileIconProvider *QFileSystemModel::iconProvider() const
       
  1421 {
       
  1422     Q_D(const QFileSystemModel);
       
  1423     return d->fileInfoGatherer.iconProvider();
       
  1424 }
       
  1425 
       
  1426 /*!
       
  1427     Sets the directory model's filter to that specified by \a filters.
       
  1428 
       
  1429     Note that the filter you set should always include the QDir::AllDirs enum value,
       
  1430     otherwise QFileSystemModel won't be able to read the directory structure.
       
  1431 
       
  1432     \sa QDir::Filters
       
  1433 */
       
  1434 void QFileSystemModel::setFilter(QDir::Filters filters)
       
  1435 {
       
  1436     Q_D(QFileSystemModel);
       
  1437     if (d->filters == filters)
       
  1438         return;
       
  1439     d->filters = filters;
       
  1440     // CaseSensitivity might have changed
       
  1441     setNameFilters(nameFilters());
       
  1442     d->forceSort = true;
       
  1443     d->delayedSort();
       
  1444 }
       
  1445 
       
  1446 /*!
       
  1447     Returns the filter specified for the directory model.
       
  1448 
       
  1449     If a filter has not been set, the default filter is QDir::AllEntries |
       
  1450     QDir::NoDotAndDotDot | QDir::AllDirs.
       
  1451 
       
  1452     \sa QDir::Filters
       
  1453 */
       
  1454 QDir::Filters QFileSystemModel::filter() const
       
  1455 {
       
  1456     Q_D(const QFileSystemModel);
       
  1457     return d->filters;
       
  1458 }
       
  1459 
       
  1460 /*!
       
  1461     \property QFileSystemModel::resolveSymlinks
       
  1462     \brief Whether the directory model should resolve symbolic links
       
  1463 
       
  1464     This is only relevant on operating systems that support symbolic links.
       
  1465 
       
  1466     By default, this property is false.
       
  1467 */
       
  1468 void QFileSystemModel::setResolveSymlinks(bool enable)
       
  1469 {
       
  1470     Q_D(QFileSystemModel);
       
  1471     d->fileInfoGatherer.setResolveSymlinks(enable);
       
  1472 }
       
  1473 
       
  1474 bool QFileSystemModel::resolveSymlinks() const
       
  1475 {
       
  1476     Q_D(const QFileSystemModel);
       
  1477     return d->fileInfoGatherer.resolveSymlinks();
       
  1478 }
       
  1479 
       
  1480 /*!
       
  1481     \property QFileSystemModel::readOnly
       
  1482     \brief Whether the directory model allows writing to the file system
       
  1483 
       
  1484     If this property is set to false, the directory model will allow renaming, copying
       
  1485     and deleting of files and directories.
       
  1486 
       
  1487     This property is true by default
       
  1488 */
       
  1489 void QFileSystemModel::setReadOnly(bool enable)
       
  1490 {
       
  1491     Q_D(QFileSystemModel);
       
  1492     d->readOnly = enable;
       
  1493 }
       
  1494 
       
  1495 bool QFileSystemModel::isReadOnly() const
       
  1496 {
       
  1497     Q_D(const QFileSystemModel);
       
  1498     return d->readOnly;
       
  1499 }
       
  1500 
       
  1501 /*!
       
  1502     \property QFileSystemModel::nameFilterDisables
       
  1503     \brief Whether files that don't pass the name filter are hidden or disabled
       
  1504 
       
  1505     This property is true by default
       
  1506 */
       
  1507 void QFileSystemModel::setNameFilterDisables(bool enable)
       
  1508 {
       
  1509     Q_D(QFileSystemModel);
       
  1510     if (d->nameFilterDisables == enable)
       
  1511         return;
       
  1512     d->nameFilterDisables = enable;
       
  1513     d->forceSort = true;
       
  1514     d->delayedSort();
       
  1515 }
       
  1516 
       
  1517 bool QFileSystemModel::nameFilterDisables() const
       
  1518 {
       
  1519     Q_D(const QFileSystemModel);
       
  1520     return d->nameFilterDisables;
       
  1521 }
       
  1522 
       
  1523 /*!
       
  1524     Sets the name \a filters to apply against the existing files.
       
  1525 */
       
  1526 void QFileSystemModel::setNameFilters(const QStringList &filters)
       
  1527 {
       
  1528     // Prep the regexp's ahead of time
       
  1529 #ifndef QT_NO_REGEXP
       
  1530     Q_D(QFileSystemModel);
       
  1531 
       
  1532     if (!d->bypassFilters.isEmpty()) {
       
  1533         // update the bypass filter to only bypass the stuff that must be kept around
       
  1534         d->bypassFilters.clear();
       
  1535         // We guarantee that rootPath will stick around
       
  1536         QPersistentModelIndex root(index(rootPath()));
       
  1537         QModelIndexList persistantList = persistentIndexList();
       
  1538         for (int i = 0; i < persistantList.count(); ++i) {
       
  1539             QFileSystemModelPrivate::QFileSystemNode *node;
       
  1540             node = d->node(persistantList.at(i));
       
  1541             while (node) {
       
  1542                 if (d->bypassFilters.contains(node))
       
  1543                     break;
       
  1544                 if (node->isDir())
       
  1545                     d->bypassFilters[node] = true;
       
  1546                 node = node->parent;
       
  1547             }
       
  1548         }
       
  1549     }
       
  1550 
       
  1551     d->nameFilters.clear();
       
  1552     const Qt::CaseSensitivity caseSensitive =
       
  1553         (filter() & QDir::CaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive;
       
  1554     for (int i = 0; i < filters.size(); ++i) {
       
  1555         d->nameFilters << QRegExp(filters.at(i), caseSensitive, QRegExp::Wildcard);
       
  1556     }
       
  1557     d->forceSort = true;
       
  1558     d->delayedSort();
       
  1559 #endif
       
  1560 }
       
  1561 
       
  1562 /*!
       
  1563     Returns a list of filters applied to the names in the model.
       
  1564 */
       
  1565 QStringList QFileSystemModel::nameFilters() const
       
  1566 {
       
  1567     Q_D(const QFileSystemModel);
       
  1568     QStringList filters;
       
  1569 #ifndef QT_NO_REGEXP
       
  1570     for (int i = 0; i < d->nameFilters.size(); ++i) {
       
  1571          filters << d->nameFilters.at(i).pattern();
       
  1572     }
       
  1573 #endif
       
  1574     return filters;
       
  1575 }
       
  1576 
       
  1577 /*!
       
  1578     \reimp
       
  1579 */
       
  1580 bool QFileSystemModel::event(QEvent *event)
       
  1581 {
       
  1582     Q_D(QFileSystemModel);
       
  1583     if (event->type() == QEvent::LanguageChange) {
       
  1584         d->root.retranslateStrings(d->fileInfoGatherer.iconProvider(), QString());
       
  1585         return true;
       
  1586     }
       
  1587     return QAbstractItemModel::event(event);
       
  1588 }
       
  1589 
       
  1590 /*!
       
  1591      \internal
       
  1592 
       
  1593     Performed quick listing and see if any files have been added or removed,
       
  1594     then fetch more information on visible files.
       
  1595  */
       
  1596 void QFileSystemModelPrivate::_q_directoryChanged(const QString &directory, const QStringList &files)
       
  1597 {
       
  1598     QFileSystemModelPrivate::QFileSystemNode *parentNode = node(directory, false);
       
  1599     if (parentNode->children.count() == 0)
       
  1600         return;
       
  1601     QStringList toRemove;
       
  1602 #if defined(Q_OS_SYMBIAN)
       
  1603     // Filename case must be exact in qBinaryFind below, so create a list of all lowercase names.
       
  1604     QStringList newFiles;
       
  1605     for(int i = 0; i < files.size(); i++) {
       
  1606         newFiles << files.at(i).toLower();
       
  1607     }
       
  1608 #else
       
  1609     QStringList newFiles = files;
       
  1610 #endif
       
  1611     qSort(newFiles.begin(), newFiles.end());
       
  1612     QHash<QString, QFileSystemNode*>::const_iterator i = parentNode->children.constBegin();
       
  1613     while (i != parentNode->children.constEnd()) {
       
  1614         QStringList::iterator iterator;
       
  1615         iterator = qBinaryFind(newFiles.begin(), newFiles.end(),
       
  1616 #if defined(Q_OS_SYMBIAN)
       
  1617                     i.value()->fileName.toLower());
       
  1618 #else
       
  1619                     i.value()->fileName);
       
  1620 #endif
       
  1621         if (iterator == newFiles.end()) {
       
  1622             toRemove.append(i.value()->fileName);
       
  1623         }
       
  1624         ++i;
       
  1625     }
       
  1626     for (int i = 0 ; i < toRemove.count() ; ++i )
       
  1627         removeNode(parentNode, toRemove[i]);
       
  1628 }
       
  1629 
       
  1630 /*!
       
  1631     \internal
       
  1632 
       
  1633     Adds a new file to the children of parentNode
       
  1634 
       
  1635     *WARNING* this will change the count of children
       
  1636 */
       
  1637 QFileSystemModelPrivate::QFileSystemNode* QFileSystemModelPrivate::addNode(QFileSystemNode *parentNode, const QString &fileName, const QFileInfo& info)
       
  1638 {
       
  1639     // In the common case, itemLocation == count() so check there first
       
  1640     QFileSystemModelPrivate::QFileSystemNode *node = new QFileSystemModelPrivate::QFileSystemNode(fileName, parentNode);
       
  1641 #ifndef QT_NO_FILESYSTEMWATCHER
       
  1642     node->populate(info);
       
  1643 #endif
       
  1644     parentNode->children.insert(fileName, node);
       
  1645     return node;
       
  1646 }
       
  1647 
       
  1648 /*!
       
  1649     \internal
       
  1650 
       
  1651     File at parentNode->children(itemLocation) has been removed, remove from the lists
       
  1652     and emit signals if necessary
       
  1653 
       
  1654     *WARNING* this will change the count of children and could change visibleChildren
       
  1655  */
       
  1656 void QFileSystemModelPrivate::removeNode(QFileSystemModelPrivate::QFileSystemNode *parentNode, const QString& name)
       
  1657 {
       
  1658     Q_Q(QFileSystemModel);
       
  1659     QModelIndex parent = index(parentNode);
       
  1660     bool indexHidden = isHiddenByFilter(parentNode, parent);
       
  1661 
       
  1662     int vLocation = parentNode->visibleLocation(name);
       
  1663     if (vLocation >= 0 && !indexHidden)
       
  1664         q->beginRemoveRows(parent, translateVisibleLocation(parentNode, vLocation),
       
  1665                                        translateVisibleLocation(parentNode, vLocation));
       
  1666     QFileSystemNode * node = parentNode->children.take(name);
       
  1667     delete node;
       
  1668     // cleanup sort files after removing rather then re-sorting which is O(n)
       
  1669     if (vLocation >= 0)
       
  1670         parentNode->visibleChildren.removeAt(vLocation);
       
  1671     if (vLocation >= 0 && !indexHidden)
       
  1672         q->endRemoveRows();
       
  1673 }
       
  1674 
       
  1675 /*
       
  1676     \internal
       
  1677     Helper functor used by addVisibleFiles()
       
  1678 */
       
  1679 class QFileSystemModelVisibleFinder
       
  1680 {
       
  1681 public:
       
  1682     inline QFileSystemModelVisibleFinder(QFileSystemModelPrivate::QFileSystemNode *node, QFileSystemModelSorter *sorter) : parentNode(node), sorter(sorter) {}
       
  1683 
       
  1684     bool operator()(const QString &, QString r) const
       
  1685     {
       
  1686         return sorter->compareNodes(parentNode->children.value(name), parentNode->children.value(r));
       
  1687     }
       
  1688 
       
  1689     QString name;
       
  1690 private:
       
  1691     QFileSystemModelPrivate::QFileSystemNode *parentNode;
       
  1692     QFileSystemModelSorter *sorter;
       
  1693 };
       
  1694 
       
  1695 /*!
       
  1696     \internal
       
  1697 
       
  1698     File at parentNode->children(itemLocation) was not visible before, but now should be
       
  1699     and emit signals if necessary.
       
  1700 
       
  1701     *WARNING* this will change the visible count
       
  1702  */
       
  1703 void QFileSystemModelPrivate::addVisibleFiles(QFileSystemNode *parentNode, const QStringList &newFiles)
       
  1704 {
       
  1705     Q_Q(QFileSystemModel);
       
  1706     QModelIndex parent = index(parentNode);
       
  1707     bool indexHidden = isHiddenByFilter(parentNode, parent);
       
  1708     if (!indexHidden) {
       
  1709         q->beginInsertRows(parent, parentNode->visibleChildren.count() , parentNode->visibleChildren.count() + newFiles.count() - 1);
       
  1710     }
       
  1711 
       
  1712     if (parentNode->dirtyChildrenIndex == -1)
       
  1713         parentNode->dirtyChildrenIndex = parentNode->visibleChildren.count();
       
  1714 
       
  1715     for (int i = 0; i < newFiles.count(); ++i) {
       
  1716             parentNode->visibleChildren.append(newFiles.at(i));
       
  1717             parentNode->children[newFiles.at(i)]->isVisible = true;
       
  1718         }
       
  1719     if (!indexHidden)
       
  1720       q->endInsertRows();
       
  1721 }
       
  1722 
       
  1723 /*!
       
  1724     \internal
       
  1725 
       
  1726     File was visible before, but now should NOT be
       
  1727 
       
  1728     *WARNING* this will change the visible count
       
  1729  */
       
  1730 void QFileSystemModelPrivate::removeVisibleFile(QFileSystemNode *parentNode, int vLocation)
       
  1731 {
       
  1732     Q_Q(QFileSystemModel);
       
  1733     if (vLocation == -1)
       
  1734         return;
       
  1735     QModelIndex parent = index(parentNode);
       
  1736     bool indexHidden = isHiddenByFilter(parentNode, parent);
       
  1737     if (!indexHidden)
       
  1738         q->beginRemoveRows(parent, translateVisibleLocation(parentNode, vLocation),
       
  1739                                        translateVisibleLocation(parentNode, vLocation));
       
  1740     parentNode->children[parentNode->visibleChildren.at(vLocation)]->isVisible = false;
       
  1741     parentNode->visibleChildren.removeAt(vLocation);
       
  1742     if (!indexHidden)
       
  1743         q->endRemoveRows();
       
  1744 }
       
  1745 
       
  1746 /*!
       
  1747     \internal
       
  1748 
       
  1749     The thread has received new information about files,
       
  1750     update and emit dataChanged if it has actually changed.
       
  1751  */
       
  1752 void QFileSystemModelPrivate::_q_fileSystemChanged(const QString &path, const QList<QPair<QString, QFileInfo> > &updates)
       
  1753 {
       
  1754     Q_Q(QFileSystemModel);
       
  1755     QVector<QString> rowsToUpdate;
       
  1756     QStringList newFiles;
       
  1757     QFileSystemModelPrivate::QFileSystemNode *parentNode = node(path, false);
       
  1758     QModelIndex parentIndex = index(parentNode);
       
  1759     for (int i = 0; i < updates.count(); ++i) {
       
  1760         QString fileName = updates.at(i).first;
       
  1761         Q_ASSERT(!fileName.isEmpty());
       
  1762         QExtendedInformation info = fileInfoGatherer.getInfo(updates.at(i).second);
       
  1763         bool previouslyHere = parentNode->children.contains(fileName);
       
  1764         if (!previouslyHere) {
       
  1765             addNode(parentNode, fileName, info.fileInfo());
       
  1766         }
       
  1767         QFileSystemModelPrivate::QFileSystemNode * node = parentNode->children.value(fileName);
       
  1768         bool isCaseSensitive = parentNode->caseSensitive();
       
  1769         if (isCaseSensitive) {
       
  1770             if (node->fileName != fileName)
       
  1771                 continue;
       
  1772         } else {
       
  1773             if (QString::compare(node->fileName,fileName,Qt::CaseInsensitive) != 0)
       
  1774                 continue;
       
  1775         }
       
  1776         if (isCaseSensitive) {
       
  1777             Q_ASSERT(node->fileName == fileName);
       
  1778         } else {
       
  1779             node->fileName = fileName;
       
  1780         }
       
  1781 
       
  1782         if (info.size() == -1) {
       
  1783             removeNode(parentNode, fileName);
       
  1784             continue;
       
  1785         }
       
  1786         if (*node != info ) {
       
  1787             node->populate(info);
       
  1788             bypassFilters.remove(node);
       
  1789             // brand new information.
       
  1790             if (filtersAcceptsNode(node)) {
       
  1791                 if (!node->isVisible) {
       
  1792                     newFiles.append(fileName);
       
  1793                 } else {
       
  1794                     rowsToUpdate.append(fileName);
       
  1795                 }
       
  1796             } else {
       
  1797                 if (node->isVisible) {
       
  1798                     int visibleLocation = parentNode->visibleLocation(fileName);
       
  1799                     removeVisibleFile(parentNode, visibleLocation);
       
  1800                 } else {
       
  1801                     // The file is not visible, don't do anything
       
  1802                 }
       
  1803             }
       
  1804         }
       
  1805     }
       
  1806 
       
  1807     // bundle up all of the changed signals into as few as possible.
       
  1808     qSort(rowsToUpdate.begin(), rowsToUpdate.end());
       
  1809     QString min;
       
  1810     QString max;
       
  1811     for (int i = 0; i < rowsToUpdate.count(); ++i) {
       
  1812         QString value = rowsToUpdate.at(i);
       
  1813         //##TODO is there a way to bundle signals with QString as the content of the list?
       
  1814         /*if (min.isEmpty()) {
       
  1815             min = value;
       
  1816             if (i != rowsToUpdate.count() - 1)
       
  1817                 continue;
       
  1818         }
       
  1819         if (i != rowsToUpdate.count() - 1) {
       
  1820             if ((value == min + 1 && max.isEmpty()) || value == max + 1) {
       
  1821                 max = value;
       
  1822                 continue;
       
  1823             }
       
  1824         }*/
       
  1825         max = value;
       
  1826         min = value;
       
  1827         int visibleMin = parentNode->visibleLocation(min);
       
  1828         int visibleMax = parentNode->visibleLocation(max);
       
  1829         if (visibleMin >= 0
       
  1830             && visibleMin < parentNode->visibleChildren.count()
       
  1831             && parentNode->visibleChildren.at(visibleMin) == min
       
  1832             && visibleMax >= 0) {
       
  1833             QModelIndex bottom = q->index(translateVisibleLocation(parentNode, visibleMin), 0, parentIndex);
       
  1834             QModelIndex top = q->index(translateVisibleLocation(parentNode, visibleMax), 3, parentIndex);
       
  1835             emit q->dataChanged(bottom, top);
       
  1836         }
       
  1837 
       
  1838         /*min = QString();
       
  1839         max = QString();*/
       
  1840     }
       
  1841 
       
  1842     if (newFiles.count() > 0) {
       
  1843         addVisibleFiles(parentNode, newFiles);
       
  1844     }
       
  1845 
       
  1846     if (newFiles.count() > 0 || (sortColumn != 0 && rowsToUpdate.count() > 0)) {
       
  1847         forceSort = true;
       
  1848         delayedSort();
       
  1849     }
       
  1850 }
       
  1851 
       
  1852 /*!
       
  1853     \internal
       
  1854 */
       
  1855 void QFileSystemModelPrivate::_q_resolvedName(const QString &fileName, const QString &resolvedName)
       
  1856 {
       
  1857     resolvedSymLinks[fileName] = resolvedName;
       
  1858 }
       
  1859 
       
  1860 /*!
       
  1861     \internal
       
  1862 */
       
  1863 void QFileSystemModelPrivate::init()
       
  1864 {
       
  1865     Q_Q(QFileSystemModel);
       
  1866     qRegisterMetaType<QList<QPair<QString,QFileInfo> > >("QList<QPair<QString,QFileInfo> >");
       
  1867     q->connect(&fileInfoGatherer, SIGNAL(newListOfFiles(const QString &, const QStringList &)),
       
  1868                q, SLOT(_q_directoryChanged(const QString &, const QStringList &)));
       
  1869     q->connect(&fileInfoGatherer, SIGNAL(updates(const QString &, const QList<QPair<QString, QFileInfo> > &)),
       
  1870             q, SLOT(_q_fileSystemChanged(const QString &, const QList<QPair<QString, QFileInfo> > &)));
       
  1871     q->connect(&fileInfoGatherer, SIGNAL(nameResolved(const QString &, const QString &)),
       
  1872             q, SLOT(_q_resolvedName(const QString &, const QString &)));
       
  1873     q->connect(&delayedSortTimer, SIGNAL(timeout()), q, SLOT(_q_performDelayedSort()), Qt::QueuedConnection);
       
  1874 }
       
  1875 
       
  1876 /*!
       
  1877     \internal
       
  1878 
       
  1879     Returns false if node doesn't pass the filters otherwise true
       
  1880 
       
  1881     QDir::Modified is not supported
       
  1882     QDir::Drives is not supported
       
  1883 */
       
  1884 bool QFileSystemModelPrivate::filtersAcceptsNode(const QFileSystemNode *node) const
       
  1885 {
       
  1886     // always accept drives
       
  1887     if (node->parent == &root || bypassFilters.contains(node))
       
  1888         return true;
       
  1889 
       
  1890     // If we don't know anything yet don't accept it
       
  1891     if (!node->hasInformation())
       
  1892         return false;
       
  1893 
       
  1894     const bool filterPermissions = ((filters & QDir::PermissionMask)
       
  1895                                    && (filters & QDir::PermissionMask) != QDir::PermissionMask);
       
  1896     const bool hideDirs          = !(filters & (QDir::Dirs | QDir::AllDirs));
       
  1897     const bool hideFiles         = !(filters & QDir::Files);
       
  1898     const bool hideReadable      = !(!filterPermissions || (filters & QDir::Readable));
       
  1899     const bool hideWritable      = !(!filterPermissions || (filters & QDir::Writable));
       
  1900     const bool hideExecutable    = !(!filterPermissions || (filters & QDir::Executable));
       
  1901     const bool hideHidden        = !(filters & QDir::Hidden);
       
  1902     const bool hideSystem        = !(filters & QDir::System);
       
  1903     const bool hideSymlinks      = (filters & QDir::NoSymLinks);
       
  1904     const bool hideDotAndDotDot  = (filters & QDir::NoDotAndDotDot);
       
  1905 
       
  1906     // Note that we match the behavior of entryList and not QFileInfo on this and this
       
  1907     // incompatibility won't be fixed until Qt 5 at least
       
  1908     bool isDotOrDot = (  (node->fileName == QLatin1String(".")
       
  1909                        || node->fileName == QLatin1String("..")));
       
  1910     if (   (hideHidden && (!isDotOrDot && node->isHidden()))
       
  1911         || (hideSystem && node->isSystem())
       
  1912         || (hideDirs && node->isDir())
       
  1913         || (hideFiles && node->isFile())
       
  1914         || (hideSymlinks && node->isSymLink())
       
  1915         || (hideReadable && node->isReadable())
       
  1916         || (hideWritable && node->isWritable())
       
  1917         || (hideExecutable && node->isExecutable())
       
  1918         || (hideDotAndDotDot && isDotOrDot))
       
  1919         return false;
       
  1920 
       
  1921     return nameFilterDisables || passNameFilters(node);
       
  1922 }
       
  1923 
       
  1924 /*
       
  1925     \internal
       
  1926 
       
  1927     Returns true if node passes the name filters and should be visible.
       
  1928  */
       
  1929 bool QFileSystemModelPrivate::passNameFilters(const QFileSystemNode *node) const
       
  1930 {
       
  1931 #ifndef QT_NO_REGEXP
       
  1932     if (nameFilters.isEmpty())
       
  1933         return true;
       
  1934 
       
  1935     // Check the name regularexpression filters
       
  1936     if (!(node->isDir() && (filters & QDir::AllDirs))) {
       
  1937         for (int i = 0; i < nameFilters.size(); ++i) {
       
  1938             if (nameFilters.at(i).exactMatch(node->fileName))
       
  1939                 return true;
       
  1940         }
       
  1941         return false;
       
  1942     }
       
  1943 #endif
       
  1944     return true;
       
  1945 }
       
  1946 
       
  1947 QT_END_NAMESPACE
       
  1948 
       
  1949 #include "moc_qfilesystemmodel.cpp"
       
  1950 
       
  1951 #endif // QT_NO_FILESYSTEMMODEL