From f67b8df3ebdba2d398b9cce686b7c644adffff08 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Sat, 7 May 2011 00:02:01 +0200 Subject: library split --- src/widgets/dialogs/qfileinfogatherer.cpp | 355 ++++++++++++++++++++++++++++++ 1 file changed, 355 insertions(+) create mode 100644 src/widgets/dialogs/qfileinfogatherer.cpp (limited to 'src/widgets/dialogs/qfileinfogatherer.cpp') diff --git a/src/widgets/dialogs/qfileinfogatherer.cpp b/src/widgets/dialogs/qfileinfogatherer.cpp new file mode 100644 index 0000000000..b36b21e63d --- /dev/null +++ b/src/widgets/dialogs/qfileinfogatherer.cpp @@ -0,0 +1,355 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfileinfogatherer_p.h" +#include +#include +#include +#ifndef Q_OS_WIN +# include +# include +#endif +#if defined(Q_OS_VXWORKS) +# include "qplatformdefs.h" +#endif + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_FILESYSTEMMODEL + +#ifdef QT_BUILD_INTERNAL +static bool fetchedRoot = false; +Q_AUTOTEST_EXPORT void qt_test_resetFetchedRoot() +{ + fetchedRoot = false; +} + +Q_AUTOTEST_EXPORT bool qt_test_isFetchedRoot() +{ + return fetchedRoot; +} +#endif + +/*! + Creates thread +*/ +QFileInfoGatherer::QFileInfoGatherer(QObject *parent) + : QThread(parent), abort(false), +#ifndef QT_NO_FILESYSTEMWATCHER + watcher(0), +#endif + m_resolveSymlinks(false), m_iconProvider(&defaultProvider) +{ +#ifdef Q_OS_WIN + m_resolveSymlinks = true; +#elif !defined(Q_OS_INTEGRITY) + userId = getuid(); + groupId = getgid(); +#endif +#ifndef QT_NO_FILESYSTEMWATCHER + watcher = new QFileSystemWatcher(this); + connect(watcher, SIGNAL(directoryChanged(QString)), this, SLOT(list(QString))); + connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(updateFile(QString))); +#endif + start(LowPriority); +} + +/*! + Destroys thread +*/ +QFileInfoGatherer::~QFileInfoGatherer() +{ + QMutexLocker locker(&mutex); + abort = true; + condition.wakeOne(); + locker.unlock(); + wait(); +} + +void QFileInfoGatherer::setResolveSymlinks(bool enable) +{ + Q_UNUSED(enable); +#ifdef Q_OS_WIN + QMutexLocker locker(&mutex); + m_resolveSymlinks = enable; +#endif +} + +bool QFileInfoGatherer::resolveSymlinks() const +{ + return m_resolveSymlinks; +} + +void QFileInfoGatherer::setIconProvider(QFileIconProvider *provider) +{ + QMutexLocker locker(&mutex); + m_iconProvider = provider; +} + +QFileIconProvider *QFileInfoGatherer::iconProvider() const +{ + return m_iconProvider; +} + +/*! + Fetch extended information for all \a files in \a path + + \sa updateFile(), update(), resolvedName() +*/ +void QFileInfoGatherer::fetchExtendedInformation(const QString &path, const QStringList &files) +{ + QMutexLocker locker(&mutex); + // See if we already have this dir/file in our que + int loc = this->path.lastIndexOf(path); + while (loc > 0) { + if (this->files.at(loc) == files) { + return; + } + loc = this->path.lastIndexOf(path, loc - 1); + } + this->path.push(path); + this->files.push(files); + condition.wakeAll(); +} + +/*! + Fetch extended information for all \a filePath + + \sa fetchExtendedInformation() +*/ +void QFileInfoGatherer::updateFile(const QString &filePath) +{ + QString dir = filePath.mid(0, filePath.lastIndexOf(QDir::separator())); + QString fileName = filePath.mid(dir.length() + 1); + fetchExtendedInformation(dir, QStringList(fileName)); +} + +/* + List all files in \a directoryPath + + \sa listed() +*/ +void QFileInfoGatherer::clear() +{ +#ifndef QT_NO_FILESYSTEMWATCHER + QMutexLocker locker(&mutex); + watcher->removePaths(watcher->files()); + watcher->removePaths(watcher->directories()); +#endif +} + +/* + Remove a \a path from the watcher + + \sa listed() +*/ +void QFileInfoGatherer::removePath(const QString &path) +{ +#ifndef QT_NO_FILESYSTEMWATCHER + QMutexLocker locker(&mutex); + watcher->removePath(path); +#endif +} + +/* + List all files in \a directoryPath + + \sa listed() +*/ +void QFileInfoGatherer::list(const QString &directoryPath) +{ + fetchExtendedInformation(directoryPath, QStringList()); +} + +/* + Until aborted wait to fetch a directory or files +*/ +void QFileInfoGatherer::run() +{ + forever { + bool updateFiles = false; + QMutexLocker locker(&mutex); + if (abort) { + return; + } + if (this->path.isEmpty()) + condition.wait(&mutex); + QString path; + QStringList list; + if (!this->path.isEmpty()) { + path = this->path.first(); + list = this->files.first(); + this->path.pop_front(); + this->files.pop_front(); + updateFiles = true; + } + locker.unlock(); + if (updateFiles) + getFileInfos(path, list); + } +} + +QExtendedInformation QFileInfoGatherer::getInfo(const QFileInfo &fileInfo) const +{ + QExtendedInformation info(fileInfo); + info.icon = m_iconProvider->icon(fileInfo); + info.displayType = m_iconProvider->type(fileInfo); +#ifndef QT_NO_FILESYSTEMWATCHER + // ### Not ready to listen all modifications + #if 0 + // Enable the next two commented out lines to get updates when the file sizes change... + if (!fileInfo.exists() && !fileInfo.isSymLink()) { + info.size = -1; + //watcher->removePath(fileInfo.absoluteFilePath()); + } else { + if (!fileInfo.absoluteFilePath().isEmpty() && fileInfo.exists() && fileInfo.isReadable() + && !watcher->files().contains(fileInfo.absoluteFilePath())) { + //watcher->addPath(fileInfo.absoluteFilePath()); + } + } + #endif +#endif + + if (fileInfo.isSymLink() && m_resolveSymlinks) { + QFileInfo resolvedInfo(fileInfo.symLinkTarget()); + resolvedInfo = resolvedInfo.canonicalFilePath(); + if (resolvedInfo.exists()) { + emit nameResolved(fileInfo.filePath(), resolvedInfo.fileName()); + } + } + return info; +} + +QString QFileInfoGatherer::translateDriveName(const QFileInfo &drive) const +{ + QString driveName = drive.absoluteFilePath(); +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + if (driveName.startsWith(QLatin1Char('/'))) // UNC host + return drive.fileName(); +#endif +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) + if (driveName.endsWith(QLatin1Char('/'))) + driveName.chop(1); +#endif + return driveName; +} + +/* + Get specific file info's, batch the files so update when we have 100 + items and every 200ms after that + */ +void QFileInfoGatherer::getFileInfos(const QString &path, const QStringList &files) +{ +#ifndef QT_NO_FILESYSTEMWATCHER + if (files.isEmpty() + && !watcher->directories().contains(path) + && !path.isEmpty() + && !path.startsWith(QLatin1String("//")) /*don't watch UNC path*/) { + watcher->addPath(path); + } +#endif + + // List drives + if (path.isEmpty()) { +#ifdef QT_BUILD_INTERNAL + fetchedRoot = true; +#endif + QFileInfoList infoList; + if (files.isEmpty()) { + infoList = QDir::drives(); + } else { + for (int i = 0; i < files.count(); ++i) + infoList << QFileInfo(files.at(i)); + } + for (int i = infoList.count() - 1; i >= 0; --i) { + QString driveName = translateDriveName(infoList.at(i)); + QList > updatedFiles; + updatedFiles.append(QPair(driveName, infoList.at(i))); + emit updates(path, updatedFiles); + } + return; + } + + QElapsedTimer base; + base.start(); + QFileInfo fileInfo; + bool firstTime = true; + QList > updatedFiles; + QStringList filesToCheck = files; + + QString itPath = QDir::fromNativeSeparators(files.isEmpty() ? path : QLatin1String("")); + QDirIterator dirIt(itPath, QDir::AllEntries | QDir::System | QDir::Hidden); + QStringList allFiles; + while(!abort && dirIt.hasNext()) { + dirIt.next(); + fileInfo = dirIt.fileInfo(); + allFiles.append(fileInfo.fileName()); + fetch(fileInfo, base, firstTime, updatedFiles, path); + } + if (!allFiles.isEmpty()) + emit newListOfFiles(path, allFiles); + + QStringList::const_iterator filesIt = filesToCheck.constBegin(); + while(!abort && filesIt != filesToCheck.constEnd()) { + fileInfo.setFile(path + QDir::separator() + *filesIt); + ++filesIt; + fetch(fileInfo, base, firstTime, updatedFiles, path); + } + if (!updatedFiles.isEmpty()) + emit updates(path, updatedFiles); + emit directoryLoaded(path); +} + +void QFileInfoGatherer::fetch(const QFileInfo &fileInfo, QElapsedTimer &base, bool &firstTime, QList > &updatedFiles, const QString &path) { + updatedFiles.append(QPair(fileInfo.fileName(), fileInfo)); + QElapsedTimer current; + current.start(); + if ((firstTime && updatedFiles.count() > 100) || base.msecsTo(current) > 1000) { + emit updates(path, updatedFiles); + updatedFiles.clear(); + base = current; + firstTime = false; + } +} + +#endif // QT_NO_FILESYSTEMMODEL + +QT_END_NAMESPACE -- cgit v1.2.3