/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qfilesystemmodel_p.h"
#include "qfilesystemmodel.h"
#include <qlocale.h>
#include <qmime.h>
#include <qurl.h>
#include <qdebug.h>
#include <qmessagebox.h>
#include <qapplication.h>
#ifdef Q_OS_WIN
#include <qt_windows.h>
#endif
QT_BEGIN_NAMESPACE
#ifndef QT_NO_FILESYSTEMMODEL
/*!
\enum QFileSystemModel::Roles
\value FileIconRole
\value FilePathRole
\value FileNameRole
\value FilePermissions
*/
/*!
\class QFileSystemModel
\since 4.4
\brief The QFileSystemModel class provides a data model for the local filesystem.
\ingroup model-view
This class provides access to the local filesystem, providing functions
for renaming and removing files and directories, and for creating new
directories. In the simplest case, it can be used with a suitable display
widget as part of a browser or filter.
QFileSystemModel will not fetch any files or directories until setRootPath
is called. This will prevent any unnecessary querying on the file system
until that point such as listing the drives on Windows.
Unlike the QDirModel, QFileSystemModel uses a separate thread to populate
itself so it will not cause the main thread to hang as the file system
is being queried. Calls to rowCount() will return 0 until the model
populates a directory.
QFileSystemModel keeps a cache with file information. The cache is
automatically kept up to date using the QFileSystemWatcher.
QFileSystemModel can be accessed using the standard interface provided by
QAbstractItemModel, but it also provides some convenience functions that are
specific to a directory model.
The fileInfo(), isDir(), name(), and path() functions provide information
about the underlying files and directories related to items in the model.
Directories can be created and removed using mkdir(), rmdir().
\note QFileSystemModel requires an instance of a GUI application.
\sa {Model Classes}
*/
/*!
\fn bool QFileSystemModel::rmdir(const QModelIndex &index) const
Removes the directory corresponding to the model item \a index in the
file system model and \bold{deletes the corresponding directory from the
file system}, returning true if successful. If the directory cannot be
removed, false is returned.
\warning This function deletes directories from the file system; it does
\bold{not} move them to a location where they can be recovered.
\sa remove()
*/
/*!
\fn QIcon QFileSystemModel::fileName(const QModelIndex &index) const
Returns the file name for the item stored in the model under the given
\a index.
*/
/*!
\fn QIcon QFileSystemModel::fileIcon(const QModelIndex &index) const
Returns the icon for the item stored in the model under the given
\a index.
*/
/*!
\fn QFileInfo QFileSystemModel::fileInfo(const QModelIndex &index) const
Returns the QFileInfo for the item stored in the model under the given
\a index.
*/
/*!
\fn void QFileSystemModel::rootPathChanged(const QString &newPath);
This signal is emitted whenever the root path has been changed to a \a newPath.
*/
/*!
\fn void QFileSystemModel::fileRenamed(const QString &path, const QString &oldName, const QString &newName)
This signal is emitted whenever a file with the \a oldName is successfully
renamed to \a newName. The file is located in in the directory \a path.
*/
/*!
\fn bool QFileSystemModel::remove(const QModelIndex &index) const
Removes the model item \a index from the file system model and \bold{deletes the
corresponding file from the file system}, returning true if successful. If the
item cannot be removed, false is returned.
\warning This function deletes files from the file system; it does \bold{not}
move them to a location where they can be recovered.
\sa rmdir()
*/
bool QFileSystemModel::remove(const QModelIndex &aindex) const
{
//### TODO optim
QString path = filePath(aindex);
QFileSystemModelPrivate * d = const_cast<QFileSystemModelPrivate*>(d_func());
d->fileInfoGatherer.removePath(path);
QDirIterator it(path,
QDir::AllDirs | QDir:: Files | QDir::NoDotAndDotDot,
QDirIterator::Subdirectories);
QStringList children;
while (it.hasNext())
children.prepend(it.next());
children.append(path);
bool error = false;
for (int i = 0; i < children.count(); ++i) {
QFileInfo info(children.at(i));
QModelIndex modelIndex = index(children.at(i));
if (info.isDir()) {
QDir dir;
if (children.at(i) != path)
error |= remove(modelIndex);
error |= rmdir(modelIndex);
} else {
error |= QFile::remove(filePath(modelIndex));
}
}
return error;
}
/*!
Constructs a file system model with the given \a parent.
*/
QFileSystemModel::QFileSystemModel(QObject *parent)
: QAbstractItemModel(*new QFileSystemModelPrivate, parent)
{
Q_D(QFileSystemModel);
d->init();
}
/*!
\internal
*/
QFileSystemModel::QFileSystemModel(QFileSystemModelPrivate &dd, QObject *parent)
: QAbstractItemModel(dd, parent)
{
Q_D(QFileSystemModel);
d->init();
}
/*!
Destroys this file system model.
*/
QFileSystemModel::~QFileSystemModel()
{
}
/*!
\reimp
*/
QModelIndex QFileSystemModel::index(int row, int column, const QModelIndex &parent) const
{
Q_D(const QFileSystemModel);
if (row < 0 || column < 0 || row >= rowCount(parent) || column >= columnCount(parent))
return QModelIndex();
// get the parent node
QFileSystemModelPrivate::QFileSystemNode *parentNode = (d->indexValid(parent) ? d->node(parent) :
const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&d->root));
Q_ASSERT(parentNode);
// now get the internal pointer for the index
QString childName = parentNode->visibleChildren[d->translateVisibleLocation(parentNode, row)];
const QFileSystemModelPrivate::QFileSystemNode *indexNode = parentNode->children.value(childName);
Q_ASSERT(indexNode);
return createIndex(row, column, const_cast<QFileSystemModelPrivate::QFileSystemNode*>(indexNode));
}
/*!
\overload
Returns the model item index for the given \a path and \a column.
*/
QModelIndex QFileSystemModel::index(const QString &path, int column) const
{
Q_D(const QFileSystemModel);
QFileSystemModelPrivate::QFileSystemNode *node = d->node(path, false);
QModelIndex idx = d->index(node);
if (idx.column() != column)
idx = idx.sibling(idx.row(), column);
return idx;
}
/*!
\internal
Return the QFileSystemNode that goes to index.
*/
QFileSystemModelPrivate::QFileSystemNode *QFileSystemModelPrivate::node(const QModelIndex &index) const
{
if (!index.isValid())
return const_cast<QFileSystemNode*>(&root);
QFileSystemModelPrivate::QFileSystemNode *indexNode = static_cast<QFileSystemModelPrivate::QFileSystemNode*>(index.internalPointer());
Q_ASSERT(indexNode);
return indexNode;
}
#ifdef Q_OS_WIN
static QString qt_GetLongPathName(const QString &strShortPath)
{
QString longPath;
int i = 0;
if (strShortPath == QLatin1String(".")
|| (strShortPath.startsWith(QLatin1String("//")))
|| (strShortPath.startsWith(QLatin1String("\\\\")))) // unc
return strShortPath;
QString::const_iterator it = strShortPath.constBegin();
QString::const_iterator constEnd = strShortPath.constEnd();
do {
bool isSep = (*it == QLatin1Char('\\') || *it == QLatin1Char('/'));
if (isSep || it == constEnd) {
QString section = (it == constEnd ? strShortPath : strShortPath.left(i));
// FindFirstFile does not handle volumes ("C:"), so we have to catch that ourselves.
|