1 /****************************************************************************
3 ** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.
5 ** This file is part of the QtGui module of the Qt Toolkit.
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"
26 #include <qfsfileengine.h>
27 #if QT_VERSION >= 0x040300
28 #include <qdiriterator.h>
32 #include <sys/types.h>
38 QFileInfoGatherer::QFileInfoGatherer(QObject
*parent
) : QThread(parent
)
39 ,abort(false), watcher(0), m_resolveSymlinks(false), m_iconProvider(&defaultProvider
)
45 m_resolveSymlinks
= true;
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
&)));
56 QFileInfoGatherer::~QFileInfoGatherer()
65 void QFileInfoGatherer::setResolveSymlinks(bool enable
)
68 m_resolveSymlinks
= enable
;
72 bool QFileInfoGatherer::resolveSymlinks() const
74 return m_resolveSymlinks
;
77 void QFileInfoGatherer::setIconProvider(QFileIconProvider
*provider
)
80 m_iconProvider
= provider
;
84 QFileIconProvider
*QFileInfoGatherer::iconProvider() const
86 return m_iconProvider
;
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
)
97 // See if we already have this dir/file in our que
98 int loc
= this->path
.lastIndexOf(path
);
100 if (this->files
.at(loc
) == files
) {
104 loc
= this->path
.lastIndexOf(path
, loc
- 1);
106 this->path
.push(path
);
107 this->files
.push(files
);
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
129 void QFileInfoGatherer::clear()
132 watcher
->removePaths(watcher
->files());
133 watcher
->removePaths(watcher
->directories());
138 List all files in \a directoryPath
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()
153 bool updateFiles
= false;
159 if (this->path
.isEmpty())
160 condition
.wait(&mutex
);
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();
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();
185 QFile::Permissions p
= permissions
;
186 p
^= QFile::ReadUser
;
187 p
^= QFile::WriteUser
;
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
))
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()) {
225 //watcher->removePath(fileInfo.absoluteFilePath());
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());
239 info
.fileType
= QExtendedInformation::System
;
243 if (!fileInfo
.exists() && fileInfo
.isSymLink()) {
244 info
.fileType
= QExtendedInformation::System
;
250 QString
QFileInfoGatherer::translateDriveName(const QFileInfo
&drive
) const
252 QString driveName
= drive
.absoluteFilePath();
254 if (driveName
.startsWith(QLatin1Char('/'))) // UNC host
255 return drive
.fileName();
256 if (driveName
.endsWith(QLatin1Char('/')))
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
)
269 && !watcher
->directories().contains(path
)
270 && !path
.isEmpty()) {
271 watcher
->addPath(path
);
275 if (path
.isEmpty()) {
276 QFileInfoList infoList
;
277 if (files
.isEmpty()) {
278 infoList
= QDir::drives();
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
);
294 QTime base
= QTime::currentTime();
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()) {
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
);
313 if (files
.isEmpty()) {
315 filesToCheck
= dir
.entryList(QDir::AllEntries
| QDir::System
| QDir::Hidden
);
316 emit
newListOfFiles(path
, filesToCheck
);
320 QStringList::const_iterator filesIt
= filesToCheck
.constBegin();
321 while(!abort
&& filesIt
!= filesToCheck
.constEnd()) {
322 fileInfo
.setFile(path
+ QDir::separator() + *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();