only include Applications by default on OS X
[ambit.git] / src / qfileinfogatherer.cpp
blobaae5067ffd9a07a4ce519803e2270603bf857a3d
1 /****************************************************************************
2 **
3 ** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.
4 **
5 ** This file is part of the QtGui module of the Qt Toolkit.
6 **
7 ** This file may be used under the terms of the GNU General Public
8 ** License version 2.0 as published by the Free Software Foundation
9 ** and appearing in the file LICENSE.GPL included in the packaging of
10 ** this file. Please review the following information to ensure GNU
11 ** General Public Licensing requirements will be met:
12 ** http://www.trolltech.com/products/qt/opensource.html
14 ** If you are unsure which license is appropriate for your use, please
15 ** review the following information:
16 ** http://www.trolltech.com/products/qt/licensing.html or contact the
17 ** sales department at sales@trolltech.com.
19 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
20 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22 ****************************************************************************/
24 #include "qfileinfogatherer_p.h"
25 #include <qdebug.h>
26 #include <qfsfileengine.h>
27 #if QT_VERSION >= 0x040300
28 #include <qdiriterator.h>
29 #endif
30 #ifndef Q_OS_WIN
31 #include <unistd.h>
32 #include <sys/types.h>
33 #endif
35 /*!
36 Creates thread
38 QFileInfoGatherer::QFileInfoGatherer(QObject *parent) : QThread(parent)
39 ,abort(false), watcher(0), m_resolveSymlinks(false), m_iconProvider(&defaultProvider)
41 #ifndef Q_OS_WIN
42 userId = getuid();
43 groupId = getuid();
44 #else
45 m_resolveSymlinks = true;
46 #endif
47 watcher = new QFileSystemWatcher(this);
48 connect(watcher, SIGNAL(directoryChanged(const QString &)), this, SLOT(list(const QString &)));
49 connect(watcher, SIGNAL(fileChanged(const QString &)), this, SLOT(updateFile(const QString &)));
50 start(LowPriority);
53 /*!
54 Distroys thread
56 QFileInfoGatherer::~QFileInfoGatherer()
58 mutex.lock();
59 abort = true;
60 mutex.unlock();
61 condition.wakeOne();
62 wait();
65 void QFileInfoGatherer::setResolveSymlinks(bool enable)
67 mutex.lock();
68 m_resolveSymlinks = enable;
69 mutex.unlock();
72 bool QFileInfoGatherer::resolveSymlinks() const
74 return m_resolveSymlinks;
77 void QFileInfoGatherer::setIconProvider(QFileIconProvider *provider)
79 mutex.lock();
80 m_iconProvider = provider;
81 mutex.unlock();
84 QFileIconProvider *QFileInfoGatherer::iconProvider() const
86 return m_iconProvider;
89 /*!
90 Fetch extended information for all \a files in \a path
92 \sa updateFile(), update(), resolvedName()
94 void QFileInfoGatherer::fetchExtendedInformation(const QString &path, const QStringList &files)
96 mutex.lock();
97 // See if we already have this dir/file in our que
98 int loc = this->path.lastIndexOf(path);
99 while (loc > 0) {
100 if (this->files.at(loc) == files) {
101 mutex.unlock();
102 return;
104 loc = this->path.lastIndexOf(path, loc - 1);
106 this->path.push(path);
107 this->files.push(files);
108 mutex.unlock();
109 condition.wakeAll();
113 Fetch extended information for all \a filePath
115 \sa fetchExtendedInformation()
117 void QFileInfoGatherer::updateFile(const QString &filePath)
119 QString dir = filePath.mid(0, filePath.lastIndexOf(QDir::separator()));
120 QString fileName = filePath.mid(dir.length() + 1);
121 fetchExtendedInformation(dir, QStringList(fileName));
125 List all files in \a directoryPath
127 \sa listed()
129 void QFileInfoGatherer::clear()
131 mutex.lock();
132 watcher->removePaths(watcher->files());
133 watcher->removePaths(watcher->directories());
134 mutex.unlock();
138 List all files in \a directoryPath
140 \sa listed()
142 void QFileInfoGatherer::list(const QString &directoryPath)
144 fetchExtendedInformation(directoryPath, QStringList());
148 Until aborted wait to fetch a directory or files
150 void QFileInfoGatherer::run()
152 forever {
153 bool updateFiles = false;
154 mutex.lock();
155 if (abort) {
156 mutex.unlock();
157 return;
159 if (this->path.isEmpty())
160 condition.wait(&mutex);
161 QString path;
162 QStringList list;
163 if (!this->path.isEmpty()) {
164 path = this->path.first();
165 list = this->files.first();
166 this->path.pop_front();
167 this->files.pop_front();
168 updateFiles = true;
170 mutex.unlock();
171 if (updateFiles) getFileInfos(path, list);
176 QFileInfo::permissions is different depending upon your platform.
178 "normalize this" so they can mean the same to us.
180 QFile::Permissions QFileInfoGatherer::translatePermissions(const QFileInfo &fileInfo) const {
181 QFile::Permissions permissions = fileInfo.permissions();
182 #ifdef Q_OS_WIN
183 return permissions;
184 #else
185 QFile::Permissions p = permissions;
186 p ^= QFile::ReadUser;
187 p ^= QFile::WriteUser;
188 p ^= QFile::ExeUser;
189 if ( permissions & QFile::ReadOther
190 || (fileInfo.ownerId() == userId && permissions & QFile::ReadOwner)
191 || (fileInfo.groupId() == groupId && permissions & QFile::ReadGroup))
192 p |= QFile::ReadUser;
194 if ( permissions & QFile::WriteOther
195 || (fileInfo.ownerId() == userId && permissions & QFile::WriteOwner)
196 || (fileInfo.groupId() == groupId && permissions & QFile::WriteGroup))
197 p |= QFile::WriteUser;
199 if ( permissions & QFile::ExeOther
200 || (fileInfo.ownerId() == userId && permissions & QFile::ExeOwner)
201 || (fileInfo.groupId() == groupId && permissions & QFile::ExeGroup))
202 p |= QFile::ExeUser;
203 return p;
204 #endif
207 QExtendedInformation QFileInfoGatherer::getInfo(const QFileInfo &fileInfo) const
209 QExtendedInformation info;
210 info.size = fileInfo.size();
211 QFSFileEngine fe(fileInfo.absoluteFilePath());
212 info.caseSensitive = fe.caseSensitive();
213 info.lastModified = fileInfo.lastModified();
214 info.permissions = translatePermissions(fileInfo);
215 info.isHidden = fileInfo.isHidden();
216 info.isSymLink = fileInfo.isSymLink();
217 info.icon = m_iconProvider->icon(fileInfo);
218 info.displayType = m_iconProvider->type(fileInfo);
219 if (fileInfo.isDir()) info.fileType = QExtendedInformation::Dir;
220 if (fileInfo.isFile()) info.fileType = QExtendedInformation::File;
222 // Enable the next two commented out lines to get updates when the file sizes change...
223 if (!fileInfo.exists() && !fileInfo.isSymLink()) {
224 info.size = -1;
225 //watcher->removePath(fileInfo.absoluteFilePath());
226 } else {
227 if (!fileInfo.absoluteFilePath().isEmpty() && fileInfo.exists() && fileInfo.isReadable()
228 && !watcher->files().contains(fileInfo.absoluteFilePath())) {
229 //watcher->addPath(fileInfo.absoluteFilePath());
233 if (fileInfo.isSymLink() && m_resolveSymlinks) {
234 QFileInfo resolvedInfo(fileInfo.symLinkTarget());
235 resolvedInfo = resolvedInfo.canonicalFilePath();
236 if (resolvedInfo.exists()) {
237 emit nameResolved(fileInfo.fileName(), resolvedInfo.fileName());
238 } else {
239 info.fileType = QExtendedInformation::System;
243 if (!fileInfo.exists() && fileInfo.isSymLink()) {
244 info.fileType = QExtendedInformation::System;
247 return info;
250 QString QFileInfoGatherer::translateDriveName(const QFileInfo &drive) const
252 QString driveName = drive.absoluteFilePath();
253 #ifdef Q_OS_WIN
254 if (driveName.startsWith(QLatin1Char('/'))) // UNC host
255 return drive.fileName();
256 if (driveName.endsWith(QLatin1Char('/')))
257 driveName.chop(1);
258 #endif
259 return driveName;
263 Get specific file info's, batch the files so update when we have 100
264 items and every 200ms after that
266 void QFileInfoGatherer::getFileInfos(const QString &path, const QStringList &files)
268 if (files.isEmpty()
269 && !watcher->directories().contains(path)
270 && !path.isEmpty()) {
271 watcher->addPath(path);
274 // List drives
275 if (path.isEmpty()) {
276 QFileInfoList infoList;
277 if (files.isEmpty()) {
278 infoList = QDir::drives();
279 } else {
280 for (int i = 0; i < files.count(); ++i)
281 infoList << QFileInfo(files.at(i));
283 for (int i = infoList.count() - 1; i >= 0; --i) {
284 QExtendedInformation info = getInfo(infoList.at(i));
285 info.isHidden = false; // windows file engine says drives are hidden, open bug
286 QString driveName = translateDriveName(infoList.at(i));
287 QList<QPair<QString,QExtendedInformation> > updatedFiles;
288 updatedFiles.append(QPair<QString,QExtendedInformation>(driveName, info));
289 emit updates(path, updatedFiles);
291 return;
294 QTime base = QTime::currentTime();
295 QFileInfo fileInfo;
296 bool firstTime = true;
297 QList<QPair<QString,QExtendedInformation> > updatedFiles;
298 QStringList filesToCheck = files;
300 #if QT_VERSION >= 0x040300
301 QString itPath = files.isEmpty() ? path : QLatin1String("");
302 QDirIterator dirIt(itPath, QDir::AllEntries | QDir::System | QDir::Hidden);
303 QStringList allFiles;
304 while(!abort && dirIt.hasNext()) {
305 dirIt.next();
306 fileInfo = dirIt.fileInfo();
307 allFiles.append(fileInfo.fileName());
308 fetch(fileInfo, base, firstTime, updatedFiles, path);
310 if (!allFiles.isEmpty())
311 emit newListOfFiles(path, allFiles);
312 #else
313 if (files.isEmpty()) {
314 QDir dir(path);
315 filesToCheck = dir.entryList(QDir::AllEntries | QDir::System | QDir::Hidden);
316 emit newListOfFiles(path, filesToCheck);
318 #endif
320 QStringList::const_iterator filesIt = filesToCheck.constBegin();
321 while(!abort && filesIt != filesToCheck.constEnd()) {
322 fileInfo.setFile(path + QDir::separator() + *filesIt);
323 ++filesIt;
324 fetch(fileInfo, base, firstTime, updatedFiles, path);
326 if (!updatedFiles.isEmpty())
327 emit updates(path, updatedFiles);
330 void QFileInfoGatherer::fetch(const QFileInfo &fileInfo, QTime &base, bool &firstTime, QList<QPair<QString,QExtendedInformation> > &updatedFiles, const QString &path) {
331 QExtendedInformation info = getInfo(fileInfo);
332 updatedFiles.append(QPair<QString,QExtendedInformation>(fileInfo.fileName(), info));
333 QTime current = QTime::currentTime();
334 if ((firstTime && updatedFiles.count() > 100) || base.msecsTo(current) > 1000) {
335 emit updates(path, updatedFiles);
336 updatedFiles.clear();
337 base = current;
338 firstTime = false;