comparison libgui/languages/build_ts/octave-qt/qfilesystemmodel.cpp @ 31537:5ceb4bfcdb0f stable

add tools and files for updating the gui's language files for translation * libgui/languages/build_ts/README.md: readme for updating language files * libgui/languages/build_ts/octave-qsci: QScintilla source files for languages without translation provided by QScintilla * libgui/languages/build_ts/octave-qt: Qt source files for languages without translation provided by Qt
author Torsten Lilge <ttl-octave@mailbox.org>
date Thu, 24 Nov 2022 06:48:25 +0100
parents
children dd5ece3664ed
comparison
equal deleted inserted replaced
31535:4b80982e0af8 31537:5ceb4bfcdb0f
1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
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 #ifdef Q_OS_WIN32
55 #include <QtCore/QVarLengthArray>
56 #endif
57
58 QT_BEGIN_NAMESPACE
59
60 #ifndef QT_NO_FILESYSTEMMODEL
61
62 /*!
63 \enum QFileSystemModel::Roles
64 \value FileIconRole
65 \value FilePathRole
66 \value FileNameRole
67 \value FilePermissions
68 */
69
70 /*!
71 \class QFileSystemModel
72 \since 4.4
73
74 \brief The QFileSystemModel class provides a data model for the local filesystem.
75
76 \ingroup model-view
77
78 This class provides access to the local filesystem, providing functions
79 for renaming and removing files and directories, and for creating new
80 directories. In the simplest case, it can be used with a suitable display
81 widget as part of a browser or filter.
82
83 QFileSystemModel can be accessed using the standard interface provided by
84 QAbstractItemModel, but it also provides some convenience functions that are
85 specific to a directory model.
86 The fileInfo(), isDir(), name(), and path() functions provide information
87 about the underlying files and directories related to items in the model.
88 Directories can be created and removed using mkdir(), rmdir().
89
90 \note QFileSystemModel requires an instance of a GUI application.
91
92 \section1 Example Usage
93
94 A directory model that displays the contents of a default directory
95 is usually constructed with a parent object:
96
97 \snippet doc/src/snippets/shareddirmodel/main.cpp 2
98
99 A tree view can be used to display the contents of the model
100
101 \snippet doc/src/snippets/shareddirmodel/main.cpp 4
102
103 and the contents of a particular directory can be displayed by
104 setting the tree view's root index:
105
106 \snippet doc/src/snippets/shareddirmodel/main.cpp 7
107
108 The view's root index can be used to control how much of a
109 hierarchical model is displayed. QDirModel provides a convenience
110 function that returns a suitable model index for a path to a
111 directory within the model.
112
113 \section1 Caching and Performance
114
115 QFileSystemModel will not fetch any files or directories until setRootPath()
116 is called. This will prevent any unnecessary querying on the file system
117 until that point such as listing the drives on Windows.
118
119 Unlike QDirModel, QFileSystemModel uses a separate thread to populate
120 itself so it will not cause the main thread to hang as the file system
121 is being queried. Calls to rowCount() will return 0 until the model
122 populates a directory.
123
124 QFileSystemModel keeps a cache with file information. The cache is
125 automatically kept up to date using the QFileSystemWatcher.
126
127 \sa {Model Classes}
128 */
129
130 /*!
131 \fn bool QFileSystemModel::rmdir(const QModelIndex &index) const
132
133 Removes the directory corresponding to the model item \a index in the
134 file system model and \bold{deletes the corresponding directory from the
135 file system}, returning true if successful. If the directory cannot be
136 removed, false is returned.
137
138 \warning This function deletes directories from the file system; it does
139 \bold{not} move them to a location where they can be recovered.
140
141 \sa remove()
142 */
143
144 /*!
145 \fn QIcon QFileSystemModel::fileName(const QModelIndex &index) const
146
147 Returns the file name for the item stored in the model under the given
148 \a index.
149 */
150
151 /*!
152 \fn QIcon QFileSystemModel::fileIcon(const QModelIndex &index) const
153
154 Returns the icon for the item stored in the model under the given
155 \a index.
156 */
157
158 /*!
159 \fn QFileInfo QFileSystemModel::fileInfo(const QModelIndex &index) const
160
161 Returns the QFileInfo for the item stored in the model under the given
162 \a index.
163 */
164
165 /*!
166 \fn void QFileSystemModel::rootPathChanged(const QString &newPath);
167
168 This signal is emitted whenever the root path has been changed to a \a newPath.
169 */
170
171 /*!
172 \fn void QFileSystemModel::fileRenamed(const QString &path, const QString &oldName, const QString &newName)
173
174 This signal is emitted whenever a file with the \a oldName is successfully
175 renamed to \a newName. The file is located in in the directory \a path.
176 */
177
178 /*!
179 \since 4.7
180 \fn void QFileSystemModel::directoryLoaded(const QString &path)
181
182 This signal is emitted when the gatherer thread has finished to load the \a path.
183
184 */
185
186 /*!
187 \fn bool QFileSystemModel::remove(const QModelIndex &index) const
188
189 Removes the model item \a index from the file system model and \bold{deletes the
190 corresponding file from the file system}, returning true if successful. If the
191 item cannot be removed, false is returned.
192
193 \warning This function deletes files from the file system; it does \bold{not}
194 move them to a location where they can be recovered.
195
196 \sa rmdir()
197 */
198
199 bool QFileSystemModel::remove(const QModelIndex &aindex) const
200 {
201 //### TODO optim
202 QString path = filePath(aindex);
203 QFileSystemModelPrivate * d = const_cast<QFileSystemModelPrivate*>(d_func());
204 d->fileInfoGatherer.removePath(path);
205 QDirIterator it(path,
206 QDir::AllDirs | QDir:: Files | QDir::NoDotAndDotDot,
207 QDirIterator::Subdirectories);
208 QStringList children;
209 while (it.hasNext())
210 children.prepend(it.next());
211 children.append(path);
212
213 bool error = false;
214 for (int i = 0; i < children.count(); ++i) {
215 QFileInfo info(children.at(i));
216 QModelIndex modelIndex = index(children.at(i));
217 if (info.isDir()) {
218 QDir dir;
219 if (children.at(i) != path)
220 error |= remove(modelIndex);
221 error |= rmdir(modelIndex);
222 } else {
223 error |= QFile::remove(filePath(modelIndex));
224 }
225 }
226 return error;
227 }
228
229 /*!
230 Constructs a file system model with the given \a parent.
231 */
232 QFileSystemModel::QFileSystemModel(QObject *parent)
233 : QAbstractItemModel(*new QFileSystemModelPrivate, parent)
234 {
235 Q_D(QFileSystemModel);
236 d->init();
237 }
238
239 /*!
240 \internal
241 */
242 QFileSystemModel::QFileSystemModel(QFileSystemModelPrivate &dd, QObject *parent)
243 : QAbstractItemModel(dd, parent)
244 {
245 Q_D(QFileSystemModel);
246 d->init();
247 }
248
249 /*!
250 Destroys this file system model.
251 */
252 QFileSystemModel::~QFileSystemModel()
253 {
254 }
255
256 /*!
257 \reimp
258 */
259 QModelIndex QFileSystemModel::index(int row, int column, const QModelIndex &parent) const
260 {
261 Q_D(const QFileSystemModel);
262 if (row < 0 || column < 0 || row >= rowCount(parent) || column >= columnCount(parent))
263 return QModelIndex();
264
265 // get the parent node
266 QFileSystemModelPrivate::QFileSystemNode *parentNode = (d->indexValid(parent) ? d->node(parent) :
267 const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&d->root));
268 Q_ASSERT(parentNode);
269
270 // now get the internal pointer for the index
271 QString childName = parentNode->visibleChildren[d->translateVisibleLocation(parentNode, row)];
272 const QFileSystemModelPrivate::QFileSystemNode *indexNode = parentNode->children.value(childName);
273 Q_ASSERT(indexNode);
274
275 return createIndex(row, column, const_cast<QFileSystemModelPrivate::QFileSystemNode*>(indexNode));
276 }
277
278 /*!
279 \overload
280
281 Returns the model item index for the given \a path and \a column.
282 */
283 QModelIndex QFileSystemModel::index(const QString &path, int column) const
284 {
285 Q_D(const QFileSystemModel);
286 QFileSystemModelPrivate::QFileSystemNode *node = d->node(path, false);
287 QModelIndex idx = d->index(node);
288 if (idx.column() != column)
289 idx = idx.sibling(idx.row(), column);
290 return idx;
291 }
292
293 /*!
294 \internal
295
296 Return the QFileSystemNode that goes to index.
297 */
298 QFileSystemModelPrivate::QFileSystemNode *QFileSystemModelPrivate::node(const QModelIndex &index) const
299 {
300 if (!index.isValid())
301 return const_cast<QFileSystemNode*>(&root);
302 QFileSystemModelPrivate::QFileSystemNode *indexNode = static_cast<QFileSystemModelPrivate::QFileSystemNode*>(index.internalPointer());
303 Q_ASSERT(indexNode);
304 return indexNode;
305 }
306
307 #ifdef Q_OS_WIN32
308 static QString qt_GetLongPathName(const QString &strShortPath)
309 {
310 if (strShortPath.isEmpty()
311 || strShortPath == QLatin1String(".") || strShortPath == QLatin1String(".."))
312 return strShortPath;
313 if (strShortPath.length() == 2 && strShortPath.endsWith(QLatin1Char(':')))
314 return strShortPath.toUpper();
315 const QString absPath = QDir(strShortPath).absolutePath();
316 if (absPath.startsWith(QLatin1String("//"))
317 || absPath.startsWith(QLatin1String("\\\\"))) // unc
318 return QDir::fromNativeSeparators(absPath);
319 if (absPath.startsWith(QLatin1Char('/')))
320 return QString();
321 const QString inputString = QLatin1String("\\\\?\\") + QDir::toNativeSeparators(absPath);
322 QVarLengthArray<TCHAR, MAX_PATH> buffer(MAX_PATH);
323 DWORD result = ::GetLongPathName((wchar_t*)inputString.utf16(),
324 buffer.data(),
325 buffer.size());
326 if (result > DWORD(buffer.size())) {
327 buffer.resize(result);
328 result = ::GetLongPathName((wchar_t*)inputString.utf16(),
329 buffer.data(),
330 buffer.size());
331 }
332 if (result > 4) {
333 QString longPath = QString::fromWCharArray(buffer.data() + 4); // ignoring prefix
334 longPath[0] = longPath.at(0).toUpper(); // capital drive letters
335 return QDir::fromNativeSeparators(longPath);
336 } else {
337 return QDir::fromNativeSeparators(strShortPath);
338 }
339 }
340 #endif
341
342 /*!
343 \internal
344
345 Given a path return the matching QFileSystemNode or &root if invalid
346 */
347 QFileSystemModelPrivate::QFileSystemNode *QFileSystemModelPrivate::node(const QString &path, bool fetch) const
348 {
349 Q_Q(const QFileSystemModel);
350 Q_UNUSED(q);
351 if (path.isEmpty() || path == myComputer() || path.startsWith(QLatin1Char(':')))
352 return const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&root);
353
354 // Construct the nodes up to the new root path if they need to be built
355 QString absolutePath;
356 #ifdef Q_OS_WIN32
357 QString longPath = qt_GetLongPathName(path);
358 #else
359 QString longPath = path;
360 #endif
361 if (longPath == rootDir.path())
362 absolutePath = rootDir.absolutePath();
363 else
364 absolutePath = QDir(longPath).absolutePath();
365
366 // ### TODO can we use bool QAbstractFileEngine::caseSensitive() const?
367 QStringList pathElements = absolutePath.split(QLatin1Char('/'), QString::SkipEmptyParts);
368 if ((pathElements.isEmpty())
369 #if (!defined(Q_OS_WIN) || defined(Q_OS_WINCE)) && !defined(Q_OS_SYMBIAN)
370 && QDir::fromNativeSeparators(longPath) != QLatin1String("/")
371 #endif
372 )
373 return const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&root);
374 QModelIndex index = QModelIndex(); // start with "My Computer"
375 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
376 if (absolutePath.startsWith(QLatin1String("//"))) { // UNC path
377 QString host = QLatin1String("\\\\") + pathElements.first();
378 if (absolutePath == QDir::fromNativeSeparators(host))
379 absolutePath.append(QLatin1Char('/'));
380 if (longPath.endsWith(QLatin1Char('/')) && !absolutePath.endsWith(QLatin1Char('/')))
381 absolutePath.append(QLatin1Char('/'));
382 int r = 0;
383 QFileSystemModelPrivate::QFileSystemNode *rootNode = const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&root);
384 if (!root.children.contains(host.toLower())) {
385 if (pathElements.count() == 1 && !absolutePath.endsWith(QLatin1Char('/')))
386 return rootNode;
387 QFileInfo info(host);
388 if (!info.exists())
389 return rootNode;
390 QFileSystemModelPrivate *p = const_cast<QFileSystemModelPrivate*>(this);
391 p->addNode(rootNode, host,info);
392 p->addVisibleFiles(rootNode, QStringList(host));
393 }
394 r = rootNode->visibleLocation(host);
395 r = translateVisibleLocation(rootNode, r);
396 index = q->index(r, 0, QModelIndex());
397 pathElements.pop_front();
398 } else
399 #endif
400
401 #if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN)
402 {
403 if (!pathElements.at(0).contains(QLatin1String(":"))) {
404 // The reason we express it like this instead of with anonymous, temporary
405 // variables, is to workaround a compiler crash with Q_CC_NOKIAX86.
406 QString rootPath = QDir(longPath).rootPath();
407 pathElements.prepend(rootPath);
408 }
409 if (pathElements.at(0).endsWith(QLatin1Char('/')))
410 pathElements[0].chop(1);
411 }
412 #else
413 // add the "/" item, since it is a valid path element on Unix
414 if (absolutePath[0] == QLatin1Char('/'))
415 pathElements.prepend(QLatin1String("/"));
416 #endif
417
418 QFileSystemModelPrivate::QFileSystemNode *parent = node(index);
419
420 for (int i = 0; i < pathElements.count(); ++i) {
421 QString element = pathElements.at(i);
422 #ifdef Q_OS_WIN
423 // On Windows, "filename......." and "filename" are equivalent Task #133928
424 while (element.endsWith(QLatin1Char('.')))
425 element.chop(1);
426 #endif
427 bool alreadyExisted = parent->children.contains(element);
428
429 // we couldn't find the path element, we create a new node since we
430 // _know_ that the path is valid
431 if (alreadyExisted) {
432 if ((parent->children.count() == 0)
433 || (parent->caseSensitive()
434 && parent->children.value(element)->fileName != element)
435 || (!parent->caseSensitive()
436 && parent->children.value(element)->fileName.toLower() != element.toLower()))
437 alreadyExisted = false;
438 }
439
440 QFileSystemModelPrivate::QFileSystemNode *node;
441 if (!alreadyExisted) {
442 // Someone might call ::index("file://cookie/monster/doesn't/like/veggies"),
443 // a path that doesn't exists, I.E. don't blindly create directories.
444 QFileInfo info(absolutePath);
445 if (!info.exists())
446 return const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&root);
447 QFileSystemModelPrivate *p = const_cast<QFileSystemModelPrivate*>(this);
448 node = p->addNode(parent, element,info);
449 #ifndef QT_NO_FILESYSTEMWATCHER
450 node->populate(fileInfoGatherer.getInfo(info));
451 #endif
452 } else {
453 node = parent->children.value(element);
454 }
455
456 Q_ASSERT(node);
457 if (!node->isVisible) {
458 // It has been filtered out
459 if (alreadyExisted && node->hasInformation() && !fetch)
460 return const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&root);
461
462 QFileSystemModelPrivate *p = const_cast<QFileSystemModelPrivate*>(this);
463 p->addVisibleFiles(parent, QStringList(element));
464 if (!p->bypassFilters.contains(node))
465 p->bypassFilters[node] = 1;
466 QString dir = q->filePath(this->index(parent));
467 if (!node->hasInformation() && fetch) {
468 Fetching f;
469 f.dir = dir;
470 f.file = element;
471 f.node = node;
472 p->toFetch.append(f);
473 p->fetchingTimer.start(0, const_cast<QFileSystemModel*>(q));
474 }
475 }
476 parent = node;
477 }
478
479 return parent;
480 }
481
482 /*!
483 \reimp
484 */
485 void QFileSystemModel::timerEvent(QTimerEvent *event)
486 {
487 Q_D(QFileSystemModel);
488 if (event->timerId() == d->fetchingTimer.timerId()) {
489 d->fetchingTimer.stop();
490 #ifndef QT_NO_FILESYSTEMWATCHER
491 for (int i = 0; i < d->toFetch.count(); ++i) {
492 const QFileSystemModelPrivate::QFileSystemNode *node = d->toFetch.at(i).node;
493 if (!node->hasInformation()) {
494 d->fileInfoGatherer.fetchExtendedInformation(d->toFetch.at(i).dir,
495 QStringList(d->toFetch.at(i).file));
496 } else {
497 // qDebug() << "yah!, you saved a little gerbil soul";
498 }
499 }
500 #endif
501 d->toFetch.clear();
502 }
503 }
504
505 /*!
506 Returns true if the model item \a index represents a directory;
507 otherwise returns false.
508 */
509 bool QFileSystemModel::isDir(const QModelIndex &index) const
510 {
511 // This function is for public usage only because it could create a file info
512 Q_D(const QFileSystemModel);
513 if (!index.isValid())
514 return true;
515 QFileSystemModelPrivate::QFileSystemNode *n = d->node(index);
516 if (n->hasInformation())
517 return n->isDir();
518 return fileInfo(index).isDir();
519 }
520
521 /*!
522 Returns the size in bytes of \a index. If the file does not exist, 0 is returned.
523 */
524 qint64 QFileSystemModel::size(const QModelIndex &index) const
525 {
526 Q_D(const QFileSystemModel);
527 if (!index.isValid())
528 return 0;
529 return d->node(index)->size();
530 }
531
532 /*!
533 Returns the type of file \a index such as "Directory" or "JPEG file".
534 */
535 QString QFileSystemModel::type(const QModelIndex &index) const
536 {
537 Q_D(const QFileSystemModel);
538 if (!index.isValid())
539 return QString();
540 return d->node(index)->type();
541 }
542
543 /*!
544 Returns the date and time when \a index was last modified.
545 */
546 QDateTime QFileSystemModel::lastModified(const QModelIndex &index) const
547 {
548 Q_D(const QFileSystemModel);
549 if (!index.isValid())
550 return QDateTime();
551 return d->node(index)->lastModified();
552 }
553
554 /*!
555 \reimp
556 */
557 QModelIndex QFileSystemModel::parent(const QModelIndex &index) const
558 {
559 Q_D(const QFileSystemModel);
560 if (!d->indexValid(index))
561 return QModelIndex();
562
563 QFileSystemModelPrivate::QFileSystemNode *indexNode = d->node(index);
564 Q_ASSERT(indexNode != 0);
565 QFileSystemModelPrivate::QFileSystemNode *parentNode = (indexNode ? indexNode->parent : 0);
566 if (parentNode == 0 || parentNode == &d->root)
567 return QModelIndex();
568
569 // get the parent's row
570 QFileSystemModelPrivate::QFileSystemNode *grandParentNode = parentNode->parent;
571 Q_ASSERT(grandParentNode->children.contains(parentNode->fileName));
572 int visualRow = d->translateVisibleLocation(grandParentNode, grandParentNode->visibleLocation(grandParentNode->children.value(parentNode->fileName)->fileName));
573 if (visualRow == -1)
574 return QModelIndex();
575 return createIndex(visualRow, 0, parentNode);
576 }
577
578 /*
579 \internal
580
581 return the index for node
582 */
583 QModelIndex QFileSystemModelPrivate::index(const QFileSystemModelPrivate::QFileSystemNode *node) const
584 {
585 Q_Q(const QFileSystemModel);
586 QFileSystemModelPrivate::QFileSystemNode *parentNode = (node ? node->parent : 0);
587 if (node == &root || !parentNode)
588 return QModelIndex();
589
590 // get the parent's row
591 Q_ASSERT(node);
592 if (!node->isVisible)
593 return QModelIndex();
594
595 int visualRow = translateVisibleLocation(parentNode, parentNode->visibleLocation(node->fileName));
596 return q->createIndex(visualRow, 0, const_cast<QFileSystemNode*>(node));
597 }
598
599 /*!
600 \reimp
601 */
602 bool QFileSystemModel::hasChildren(const QModelIndex &parent) const
603 {
604 Q_D(const QFileSystemModel);
605 if (parent.column() > 0)
606 return false;
607
608 if (!parent.isValid()) // drives
609 return true;
610
611 const QFileSystemModelPrivate::QFileSystemNode *indexNode = d->node(parent);
612 Q_ASSERT(indexNode);
613 return (indexNode->isDir());
614 }
615
616 /*!
617 \reimp
618 */
619 bool QFileSystemModel::canFetchMore(const QModelIndex &parent) const
620 {
621 Q_D(const QFileSystemModel);
622 const QFileSystemModelPrivate::QFileSystemNode *indexNode = d->node(parent);
623 return (!indexNode->populatedChildren);
624 }
625
626 /*!
627 \reimp
628 */
629 void QFileSystemModel::fetchMore(const QModelIndex &parent)
630 {
631 Q_D(QFileSystemModel);
632 if (!d->setRootPath)
633 return;
634 QFileSystemModelPrivate::QFileSystemNode *indexNode = d->node(parent);
635 if (indexNode->populatedChildren)
636 return;
637 indexNode->populatedChildren = true;
638 d->fileInfoGatherer.list(filePath(parent));
639 }
640
641 /*!
642 \reimp
643 */
644 int QFileSystemModel::rowCount(const QModelIndex &parent) const
645 {
646 Q_D(const QFileSystemModel);
647 if (parent.column() > 0)
648 return 0;
649
650 if (!parent.isValid())
651 return d->root.visibleChildren.count();
652
653 const QFileSystemModelPrivate::QFileSystemNode *parentNode = d->node(parent);
654 return parentNode->visibleChildren.count();
655 }
656
657 /*!
658 \reimp
659 */
660 int QFileSystemModel::columnCount(const QModelIndex &parent) const
661 {
662 return (parent.column() > 0) ? 0 : 4;
663 }
664
665 /*!
666 Returns the data stored under the given \a role for the item "My Computer".
667
668 \sa Qt::ItemDataRole
669 */
670 QVariant QFileSystemModel::myComputer(int role) const
671 {
672 Q_D(const QFileSystemModel);
673 switch (role) {
674 case Qt::DisplayRole:
675 return d->myComputer();
676 case Qt::DecorationRole:
677 return d->fileInfoGatherer.iconProvider()->icon(QFileIconProvider::Computer);
678 }
679 return QVariant();
680 }
681
682 /*!
683 \reimp
684 */
685 QVariant QFileSystemModel::data(const QModelIndex &index, int role) const
686 {
687 Q_D(const QFileSystemModel);
688 if (!index.isValid() || index.model() != this)
689 return QVariant();
690
691 switch (role) {
692 case Qt::EditRole:
693 case Qt::DisplayRole:
694 switch (index.column()) {
695 case 0: return d->displayName(index);
696 case 1: return d->size(index);
697 case 2: return d->type(index);
698 case 3: return d->time(index);
699 default:
700 qWarning("data: invalid display value column %d", index.column());
701 break;
702 }
703 break;
704 case FilePathRole:
705 return filePath(index);
706 case FileNameRole:
707 return d->name(index);
708 case Qt::DecorationRole:
709 if (index.column() == 0) {
710 QIcon icon = d->icon(index);
711 if (icon.isNull()) {
712 if (d->node(index)->isDir())
713 icon = d->fileInfoGatherer.iconProvider()->icon(QFileIconProvider::Folder);
714 else
715 icon = d->fileInfoGatherer.iconProvider()->icon(QFileIconProvider::File);
716 }
717 return icon;
718 }
719 break;
720 case Qt::TextAlignmentRole:
721 if (index.column() == 1)
722 return Qt::AlignRight;
723 break;
724 case FilePermissions:
725 int p = permissions(index);
726 return p;
727 }
728
729 return QVariant();
730 }
731
732 /*!
733 \internal
734 */
735 QString QFileSystemModelPrivate::size(const QModelIndex &index) const
736 {
737 if (!index.isValid())
738 return QString();
739 const QFileSystemNode *n = node(index);
740 if (n->isDir()) {
741 #ifdef Q_OS_MAC
742 return QLatin1String("--");
743 #else
744 return QLatin1String("");
745 #endif
746 // Windows - ""
747 // OS X - "--"
748 // Konqueror - "4 KB"
749 // Nautilus - "9 items" (the number of children)
750 }
751 return size(n->size());
752 }
753
754 QString QFileSystemModelPrivate::size(qint64 bytes)
755 {
756 // According to the Si standard KB is 1000 bytes, KiB is 1024
757 // but on windows sizes are calculated by dividing by 1024 so we do what they do.
758 const qint64 kb = 1024;
759 const qint64 mb = 1024 * kb;
760 const qint64 gb = 1024 * mb;
761 const qint64 tb = 1024 * gb;
762 if (bytes >= tb)
763 return QFileSystemModel::tr("%1 TB").arg(QLocale().toString(qreal(bytes) / tb, 'f', 3));
764 if (bytes >= gb)
765 return QFileSystemModel::tr("%1 GB").arg(QLocale().toString(qreal(bytes) / gb, 'f', 2));
766 if (bytes >= mb)
767 return QFileSystemModel::tr("%1 MB").arg(QLocale().toString(qreal(bytes) / mb, 'f', 1));
768 if (bytes >= kb)
769 return QFileSystemModel::tr("%1 KB").arg(QLocale().toString(bytes / kb));
770 return QFileSystemModel::tr("%1 bytes").arg(QLocale().toString(bytes));
771 }
772
773 /*!
774 \internal
775 */
776 QString QFileSystemModelPrivate::time(const QModelIndex &index) const
777 {
778 if (!index.isValid())
779 return QString();
780 #ifndef QT_NO_DATESTRING
781 return node(index)->lastModified().toString(Qt::SystemLocaleDate);
782 #else
783 Q_UNUSED(index);
784 return QString();
785 #endif
786 }
787
788 /*
789 \internal
790 */
791 QString QFileSystemModelPrivate::type(const QModelIndex &index) const
792 {
793 if (!index.isValid())
794 return QString();
795 return node(index)->type();
796 }
797
798 /*!
799 \internal
800 */
801 QString QFileSystemModelPrivate::name(const QModelIndex &index) const
802 {
803 if (!index.isValid())
804 return QString();
805 QFileSystemNode *dirNode = node(index);
806 if (fileInfoGatherer.resolveSymlinks() && !resolvedSymLinks.isEmpty() &&
807 dirNode->isSymLink(/* ignoreNtfsSymLinks = */ true)) {
808 QString fullPath = QDir::fromNativeSeparators(filePath(index));
809 if (resolvedSymLinks.contains(fullPath))
810 return resolvedSymLinks[fullPath];
811 }
812 return dirNode->fileName;
813 }
814
815 /*!
816 \internal
817 */
818 QString QFileSystemModelPrivate::displayName(const QModelIndex &index) const
819 {
820 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
821 QFileSystemNode *dirNode = node(index);
822 if (!dirNode->volumeName.isNull())
823 return dirNode->volumeName + QLatin1String(" (") + name(index) + QLatin1Char(')');
824 #endif
825 return name(index);
826 }
827
828 /*!
829 \internal
830 */
831 QIcon QFileSystemModelPrivate::icon(const QModelIndex &index) const
832 {
833 if (!index.isValid())
834 return QIcon();
835 return node(index)->icon();
836 }
837
838 /*!
839 \reimp
840 */
841 bool QFileSystemModel::setData(const QModelIndex &idx, const QVariant &value, int role)
842 {
843 Q_D(QFileSystemModel);
844 if (!idx.isValid()
845 || idx.column() != 0
846 || role != Qt::EditRole
847 || (flags(idx) & Qt::ItemIsEditable) == 0) {
848 return false;
849 }
850
851 QString newName = value.toString();
852 QString oldName = idx.data().toString();
853 if (newName == idx.data().toString())
854 return true;
855
856 if (newName.isEmpty()
857 || QDir::toNativeSeparators(newName).contains(QDir::separator())
858 || !QDir(filePath(parent(idx))).rename(oldName, newName)) {
859 #ifndef QT_NO_MESSAGEBOX
860 QMessageBox::information(0, QFileSystemModel::tr("Invalid filename"),
861 QFileSystemModel::tr("<b>The name \"%1\" can not be used.</b><p>Try using another name, with fewer characters or no punctuations marks.")
862 .arg(newName),
863 QMessageBox::Ok);
864 #endif // QT_NO_MESSAGEBOX
865 return false;
866 } else {
867 /*
868 *After re-naming something we don't want the selection to change*
869 - can't remove rows and later insert
870 - can't quickly remove and insert
871 - index pointer can't change because treeview doesn't use persistant index's
872
873 - if this get any more complicated think of changing it to just
874 use layoutChanged
875 */
876
877 QFileSystemModelPrivate::QFileSystemNode *indexNode = d->node(idx);
878 QFileSystemModelPrivate::QFileSystemNode *parentNode = indexNode->parent;
879 int visibleLocation = parentNode->visibleLocation(parentNode->children.value(indexNode->fileName)->fileName);
880
881 d->addNode(parentNode, newName,indexNode->info->fileInfo());
882 parentNode->visibleChildren.removeAt(visibleLocation);
883 QFileSystemModelPrivate::QFileSystemNode * oldValue = parentNode->children.value(oldName);
884 parentNode->children[newName] = oldValue;
885 QFileInfo info(d->rootDir, newName);
886 oldValue->fileName = newName;
887 oldValue->parent = parentNode;
888 oldValue->populate(d->fileInfoGatherer.getInfo(info));
889 oldValue->isVisible = true;
890
891 parentNode->children.remove(oldName);
892 parentNode->visibleChildren.insert(visibleLocation, newName);
893
894 d->delayedSort();
895 emit fileRenamed(filePath(idx.parent()), oldName, newName);
896 }
897 return true;
898 }
899
900 /*!
901 \reimp
902 */
903 QVariant QFileSystemModel::headerData(int section, Qt::Orientation orientation, int role) const
904 {
905 switch (role) {
906 case Qt::DecorationRole:
907 if (section == 0) {
908 // ### TODO oh man this is ugly and doesn't even work all the way!
909 // it is still 2 pixels off
910 QImage pixmap(16, 1, QImage::Format_Mono);
911 pixmap.fill(0);
912 pixmap.setAlphaChannel(pixmap.createAlphaMask());
913 return pixmap;
914 }
915 break;
916 case Qt::TextAlignmentRole:
917 return Qt::AlignLeft;
918 }
919
920 if (orientation != Qt::Horizontal || role != Qt::DisplayRole)
921 return QAbstractItemModel::headerData(section, orientation, role);
922
923 QString returnValue;
924 switch (section) {
925 case 0: returnValue = tr("Name");
926 break;
927 case 1: returnValue = tr("Size");
928 break;
929 case 2: returnValue =
930 #ifdef Q_OS_MAC
931 tr("Kind", "Match OS X Finder");
932 #else
933 tr("Type", "All other platforms");
934 #endif
935 break;
936 // Windows - Type
937 // OS X - Kind
938 // Konqueror - File Type
939 // Nautilus - Type
940 case 3: returnValue = tr("Date Modified");
941 break;
942 default: return QVariant();
943 }
944 return returnValue;
945 }
946
947 /*!
948 \reimp
949 */
950 Qt::ItemFlags QFileSystemModel::flags(const QModelIndex &index) const
951 {
952 Q_D(const QFileSystemModel);
953 Qt::ItemFlags flags = QAbstractItemModel::flags(index);
954 if (!index.isValid())
955 return flags;
956
957 QFileSystemModelPrivate::QFileSystemNode *indexNode = d->node(index);
958 if (d->nameFilterDisables && !d->passNameFilters(indexNode)) {
959 flags &= ~Qt::ItemIsEnabled;
960 // ### TODO you shouldn't be able to set this as the current item, task 119433
961 return flags;
962 }
963
964 flags |= Qt::ItemIsDragEnabled;
965 if (d->readOnly)
966 return flags;
967 if ((index.column() == 0) && indexNode->permissions() & QFile::WriteUser) {
968 flags |= Qt::ItemIsEditable;
969 if (indexNode->isDir())
970 flags |= Qt::ItemIsDropEnabled;
971 }
972 return flags;
973 }
974
975 /*!
976 \internal
977 */
978 void QFileSystemModelPrivate::_q_performDelayedSort()
979 {
980 Q_Q(QFileSystemModel);
981 q->sort(sortColumn, sortOrder);
982 }
983
984 static inline QChar getNextChar(const QString &s, int location)
985 {
986 return (location < s.length()) ? s.at(location) : QChar();
987 }
988
989 /*!
990 Natural number sort, skips spaces.
991
992 Examples:
993 1, 2, 10, 55, 100
994 01.jpg, 2.jpg, 10.jpg
995
996 Note on the algorithm:
997 Only as many characters as necessary are looked at and at most they all
998 are looked at once.
999
1000 Slower then QString::compare() (of course)
1001 */
1002 int QFileSystemModelPrivate::naturalCompare(const QString &s1, const QString &s2, Qt::CaseSensitivity cs)
1003 {
1004 for (int l1 = 0, l2 = 0; l1 <= s1.count() && l2 <= s2.count(); ++l1, ++l2) {
1005 // skip spaces, tabs and 0's
1006 QChar c1 = getNextChar(s1, l1);
1007 while (c1.isSpace())
1008 c1 = getNextChar(s1, ++l1);
1009 QChar c2 = getNextChar(s2, l2);
1010 while (c2.isSpace())
1011 c2 = getNextChar(s2, ++l2);
1012
1013 if (c1.isDigit() && c2.isDigit()) {
1014 while (c1.digitValue() == 0)
1015 c1 = getNextChar(s1, ++l1);
1016 while (c2.digitValue() == 0)
1017 c2 = getNextChar(s2, ++l2);
1018
1019 int lookAheadLocation1 = l1;
1020 int lookAheadLocation2 = l2;
1021 int currentReturnValue = 0;
1022 // find the last digit, setting currentReturnValue as we go if it isn't equal
1023 for (
1024 QChar lookAhead1 = c1, lookAhead2 = c2;
1025 (lookAheadLocation1 <= s1.length() && lookAheadLocation2 <= s2.length());
1026 lookAhead1 = getNextChar(s1, ++lookAheadLocation1),
1027 lookAhead2 = getNextChar(s2, ++lookAheadLocation2)
1028 ) {
1029 bool is1ADigit = !lookAhead1.isNull() && lookAhead1.isDigit();
1030 bool is2ADigit = !lookAhead2.isNull() && lookAhead2.isDigit();
1031 if (!is1ADigit && !is2ADigit)
1032 break;
1033 if (!is1ADigit)
1034 return -1;
1035 if (!is2ADigit)
1036 return 1;
1037 if (currentReturnValue == 0) {
1038 if (lookAhead1 < lookAhead2) {
1039 currentReturnValue = -1;
1040 } else if (lookAhead1 > lookAhead2) {
1041 currentReturnValue = 1;
1042 }
1043 }
1044 }
1045 if (currentReturnValue != 0)
1046 return currentReturnValue;
1047 }
1048
1049 if (cs == Qt::CaseInsensitive) {
1050 if (!c1.isLower()) c1 = c1.toLower();
1051 if (!c2.isLower()) c2 = c2.toLower();
1052 }
1053 int r = QString::localeAwareCompare(c1, c2);
1054 if (r < 0)
1055 return -1;
1056 if (r > 0)
1057 return 1;
1058 }
1059 // The two strings are the same (02 == 2) so fall back to the normal sort
1060 return QString::compare(s1, s2, cs);
1061 }
1062
1063 /*
1064 \internal
1065 Helper functor used by sort()
1066 */
1067 class QFileSystemModelSorter
1068 {
1069 public:
1070 inline QFileSystemModelSorter(int column) : sortColumn(column) {}
1071
1072 bool compareNodes(const QFileSystemModelPrivate::QFileSystemNode *l,
1073 const QFileSystemModelPrivate::QFileSystemNode *r) const
1074 {
1075 switch (sortColumn) {
1076 case 0: {
1077 #ifndef Q_OS_MAC
1078 // place directories before files
1079 bool left = l->isDir();
1080 bool right = r->isDir();
1081 if (left ^ right)
1082 return left;
1083 #endif
1084 return QFileSystemModelPrivate::naturalCompare(l->fileName,
1085 r->fileName, Qt::CaseInsensitive) < 0;
1086 }
1087 case 1:
1088 // Directories go first
1089 if (l->isDir() && !r->isDir())
1090 return true;
1091 return l->size() < r->size();
1092 case 2:
1093 return l->type() < r->type();
1094 case 3:
1095 return l->lastModified() < r->lastModified();
1096 }
1097 Q_ASSERT(false);
1098 return false;
1099 }
1100
1101 bool operator()(const QPair<QFileSystemModelPrivate::QFileSystemNode*, int> &l,
1102 const QPair<QFileSystemModelPrivate::QFileSystemNode*, int> &r) const
1103 {
1104 return compareNodes(l.first, r.first);
1105 }
1106
1107
1108 private:
1109 int sortColumn;
1110 };
1111
1112 /*
1113 \internal
1114
1115 Sort all of the children of parent
1116 */
1117 void QFileSystemModelPrivate::sortChildren(int column, const QModelIndex &parent)
1118 {
1119 Q_Q(QFileSystemModel);
1120 QFileSystemModelPrivate::QFileSystemNode *indexNode = node(parent);
1121 if (indexNode->children.count() == 0)
1122 return;
1123
1124 QList<QPair<QFileSystemModelPrivate::QFileSystemNode*, int> > values;
1125 QHash<QString, QFileSystemNode *>::const_iterator iterator;
1126 int i = 0;
1127 for(iterator = indexNode->children.begin() ; iterator != indexNode->children.end() ; ++iterator) {
1128 if (filtersAcceptsNode(iterator.value())) {
1129 values.append(QPair<QFileSystemModelPrivate::QFileSystemNode*, int>((iterator.value()), i));
1130 } else {
1131 iterator.value()->isVisible = false;
1132 }
1133 i++;
1134 }
1135 QFileSystemModelSorter ms(column);
1136 qStableSort(values.begin(), values.end(), ms);
1137 // First update the new visible list
1138 indexNode->visibleChildren.clear();
1139 //No more dirty item we reset our internal dirty index
1140 indexNode->dirtyChildrenIndex = -1;
1141 for (int i = 0; i < values.count(); ++i) {
1142 indexNode->visibleChildren.append(values.at(i).first->fileName);
1143 values.at(i).first->isVisible = true;
1144 }
1145
1146 if (!disableRecursiveSort) {
1147 for (int i = 0; i < q->rowCount(parent); ++i) {
1148 const QModelIndex childIndex = q->index(i, 0, parent);
1149 QFileSystemModelPrivate::QFileSystemNode *indexNode = node(childIndex);
1150 //Only do a recursive sort on visible nodes
1151 if (indexNode->isVisible)
1152 sortChildren(column, childIndex);
1153 }
1154 }
1155 }
1156
1157 /*!
1158 \reimp
1159 */
1160 void QFileSystemModel::sort(int column, Qt::SortOrder order)
1161 {
1162 Q_D(QFileSystemModel);
1163 if (d->sortOrder == order && d->sortColumn == column && !d->forceSort)
1164 return;
1165
1166 emit layoutAboutToBeChanged();
1167 QModelIndexList oldList = persistentIndexList();
1168 QList<QPair<QFileSystemModelPrivate::QFileSystemNode*, int> > oldNodes;
1169 for (int i = 0; i < oldList.count(); ++i) {
1170 QPair<QFileSystemModelPrivate::QFileSystemNode*, int> pair(d->node(oldList.at(i)), oldList.at(i).column());
1171 oldNodes.append(pair);
1172 }
1173
1174 if (!(d->sortColumn == column && d->sortOrder != order && !d->forceSort)) {
1175 //we sort only from where we are, don't need to sort all the model
1176 d->sortChildren(column, index(rootPath()));
1177 d->sortColumn = column;
1178 d->forceSort = false;
1179 }
1180 d->sortOrder = order;
1181
1182 QModelIndexList newList;
1183 for (int i = 0; i < oldNodes.count(); ++i) {
1184 QModelIndex idx = d->index(oldNodes.at(i).first);
1185 idx = idx.sibling(idx.row(), oldNodes.at(i).second);
1186 newList.append(idx);
1187 }
1188 changePersistentIndexList(oldList, newList);
1189 emit layoutChanged();
1190 }
1191
1192 /*!
1193 Returns a list of MIME types that can be used to describe a list of items
1194 in the model.
1195 */
1196 QStringList QFileSystemModel::mimeTypes() const
1197 {
1198 return QStringList(QLatin1String("text/uri-list"));
1199 }
1200
1201 /*!
1202 Returns an object that contains a serialized description of the specified
1203 \a indexes. The format used to describe the items corresponding to the
1204 indexes is obtained from the mimeTypes() function.
1205
1206 If the list of indexes is empty, 0 is returned rather than a serialized
1207 empty list.
1208 */
1209 QMimeData *QFileSystemModel::mimeData(const QModelIndexList &indexes) const
1210 {
1211 QList<QUrl> urls;
1212 QList<QModelIndex>::const_iterator it = indexes.begin();
1213 for (; it != indexes.end(); ++it)
1214 if ((*it).column() == 0)
1215 urls << QUrl::fromLocalFile(filePath(*it));
1216 QMimeData *data = new QMimeData();
1217 data->setUrls(urls);
1218 return data;
1219 }
1220
1221 /*!
1222 Handles the \a data supplied by a drag and drop operation that ended with
1223 the given \a action over the row in the model specified by the \a row and
1224 \a column and by the \a parent index.
1225
1226 \sa supportedDropActions()
1227 */
1228 bool QFileSystemModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
1229 int row, int column, const QModelIndex &parent)
1230 {
1231 Q_UNUSED(row);
1232 Q_UNUSED(column);
1233 if (!parent.isValid() || isReadOnly())
1234 return false;
1235
1236 bool success = true;
1237 QString to = filePath(parent) + QDir::separator();
1238
1239 QList<QUrl> urls = data->urls();
1240 QList<QUrl>::const_iterator it = urls.constBegin();
1241
1242 switch (action) {
1243 case Qt::CopyAction:
1244 for (; it != urls.constEnd(); ++it) {
1245 QString path = (*it).toLocalFile();
1246 success = QFile::copy(path, to + QFileInfo(path).fileName()) && success;
1247 }
1248 break;
1249 case Qt::LinkAction:
1250 for (; it != urls.constEnd(); ++it) {
1251 QString path = (*it).toLocalFile();
1252 success = QFile::link(path, to + QFileInfo(path).fileName()) && success;
1253 }
1254 break;
1255 case Qt::MoveAction:
1256 for (; it != urls.constEnd(); ++it) {
1257 QString path = (*it).toLocalFile();
1258 success = QFile::rename(path, to + QFileInfo(path).fileName()) && success;
1259 }
1260 break;
1261 default:
1262 return false;
1263 }
1264
1265 return success;
1266 }
1267
1268 /*!
1269 \reimp
1270 */
1271 Qt::DropActions QFileSystemModel::supportedDropActions() const
1272 {
1273 return Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
1274 }
1275
1276 /*!
1277 Returns the path of the item stored in the model under the
1278 \a index given.
1279 */
1280 QString QFileSystemModel::filePath(const QModelIndex &index) const
1281 {
1282 Q_D(const QFileSystemModel);
1283 QString fullPath = d->filePath(index);
1284 QFileSystemModelPrivate::QFileSystemNode *dirNode = d->node(index);
1285 if (dirNode->isSymLink() && d->fileInfoGatherer.resolveSymlinks()
1286 && d->resolvedSymLinks.contains(fullPath)
1287 && dirNode->isDir()) {
1288 QFileInfo resolvedInfo(fullPath);
1289 resolvedInfo = resolvedInfo.canonicalFilePath();
1290 if (resolvedInfo.exists())
1291 return resolvedInfo.filePath();
1292 }
1293 return fullPath;
1294 }
1295
1296 QString QFileSystemModelPrivate::filePath(const QModelIndex &index) const
1297 {
1298 Q_Q(const QFileSystemModel);
1299 Q_UNUSED(q);
1300 if (!index.isValid())
1301 return QString();
1302 Q_ASSERT(index.model() == q);
1303
1304 QStringList path;
1305 QModelIndex idx = index;
1306 while (idx.isValid()) {
1307 QFileSystemModelPrivate::QFileSystemNode *dirNode = node(idx);
1308 if (dirNode)
1309 path.prepend(dirNode->fileName);
1310 idx = idx.parent();
1311 }
1312 QString fullPath = QDir::fromNativeSeparators(path.join(QDir::separator()));
1313 #if !defined(Q_OS_WIN) || defined(Q_OS_WINCE)
1314 if ((fullPath.length() > 2) && fullPath[0] == QLatin1Char('/') && fullPath[1] == QLatin1Char('/'))
1315 fullPath = fullPath.mid(1);
1316 #endif
1317 #if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
1318 if (fullPath.length() == 2 && fullPath.endsWith(QLatin1Char(':')))
1319 fullPath.append(QLatin1Char('/'));
1320 #endif
1321 return fullPath;
1322 }
1323
1324 /*!
1325 Create a directory with the \a name in the \a parent model index.
1326 */
1327 QModelIndex QFileSystemModel::mkdir(const QModelIndex &parent, const QString &name)
1328 {
1329 Q_D(QFileSystemModel);
1330 if (!parent.isValid())
1331 return parent;
1332
1333 QDir dir(filePath(parent));
1334 if (!dir.mkdir(name))
1335 return QModelIndex();
1336 QFileSystemModelPrivate::QFileSystemNode *parentNode = d->node(parent);
1337 d->addNode(parentNode, name, QFileInfo());
1338 Q_ASSERT(parentNode->children.contains(name));
1339 QFileSystemModelPrivate::QFileSystemNode *node = parentNode->children[name];
1340 node->populate(d->fileInfoGatherer.getInfo(QFileInfo(dir.absolutePath() + QDir::separator() + name)));
1341 d->addVisibleFiles(parentNode, QStringList(name));
1342 return d->index(node);
1343 }
1344
1345 /*!
1346 Returns the complete OR-ed together combination of QFile::Permission for the \a index.
1347 */
1348 QFile::Permissions QFileSystemModel::permissions(const QModelIndex &index) const
1349 {
1350 Q_D(const QFileSystemModel);
1351 QFile::Permissions p = d->node(index)->permissions();
1352 if (d->readOnly) {
1353 p ^= (QFile::WriteOwner | QFile::WriteUser
1354 | QFile::WriteGroup | QFile::WriteOther);
1355 }
1356 return p;
1357 }
1358
1359 /*!
1360 Sets the directory that is being watched by the model to \a newPath by
1361 installing a \l{QFileSystemWatcher}{file system watcher} on it. Any
1362 changes to files and directories within this directory will be
1363 reflected in the model.
1364
1365 If the path is changed, the rootPathChanged() signal will be emitted.
1366
1367 \note This function does not change the structure of the model or
1368 modify the data available to views. In other words, the "root" of
1369 the model is \e not changed to include only files and directories
1370 within the directory specified by \a newPath in the file system.
1371 */
1372 QModelIndex QFileSystemModel::setRootPath(const QString &newPath)
1373 {
1374 Q_D(QFileSystemModel);
1375 #ifdef Q_OS_WIN
1376 #ifdef Q_OS_WIN32
1377 QString longNewPath = qt_GetLongPathName(newPath);
1378 #else
1379 QString longNewPath = QDir::fromNativeSeparators(newPath);
1380 #endif
1381 #else
1382 QString longNewPath = newPath;
1383 #endif
1384 QDir newPathDir(longNewPath);
1385 //we remove .. and . from the given path if exist
1386 if (!newPath.isEmpty()) {
1387 longNewPath = QDir::cleanPath(longNewPath);
1388 newPathDir.setPath(longNewPath);
1389 }
1390
1391 d->setRootPath = true;
1392
1393 //user don't ask for the root path ("") but the conversion failed
1394 if (!newPath.isEmpty() && longNewPath.isEmpty())
1395 return d->index(rootPath());
1396
1397 if (d->rootDir.path() == longNewPath)
1398 return d->index(rootPath());
1399
1400 bool showDrives = (longNewPath.isEmpty() || longNewPath == d->myComputer());
1401 if (!showDrives && !newPathDir.exists())
1402 return d->index(rootPath());
1403
1404 //We remove the watcher on the previous path
1405 if (!rootPath().isEmpty() && rootPath() != QLatin1String(".")) {
1406 //This remove the watcher for the old rootPath
1407 d->fileInfoGatherer.removePath(rootPath());
1408 //This line "marks" the node as dirty, so the next fetchMore
1409 //call on the path will ask the gatherer to install a watcher again
1410 //But it doesn't re-fetch everything
1411 d->node(rootPath())->populatedChildren = false;
1412 }
1413
1414 // We have a new valid root path
1415 d->rootDir = newPathDir;
1416 QModelIndex newRootIndex;
1417 if (showDrives) {
1418 // otherwise dir will become '.'
1419 d->rootDir.setPath(QLatin1String(""));
1420 } else {
1421 newRootIndex = d->index(newPathDir.path());
1422 }
1423 fetchMore(newRootIndex);
1424 emit rootPathChanged(longNewPath);
1425 d->forceSort = true;
1426 d->delayedSort();
1427 return newRootIndex;
1428 }
1429
1430 /*!
1431 The currently set root path
1432
1433 \sa rootDirectory()
1434 */
1435 QString QFileSystemModel::rootPath() const
1436 {
1437 Q_D(const QFileSystemModel);
1438 return d->rootDir.path();
1439 }
1440
1441 /*!
1442 The currently set directory
1443
1444 \sa rootPath()
1445 */
1446 QDir QFileSystemModel::rootDirectory() const
1447 {
1448 Q_D(const QFileSystemModel);
1449 QDir dir(d->rootDir);
1450 dir.setNameFilters(nameFilters());
1451 dir.setFilter(filter());
1452 return dir;
1453 }
1454
1455 /*!
1456 Sets the \a provider of file icons for the directory model.
1457 */
1458 void QFileSystemModel::setIconProvider(QFileIconProvider *provider)
1459 {
1460 Q_D(QFileSystemModel);
1461 d->fileInfoGatherer.setIconProvider(provider);
1462 d->root.updateIcon(provider, QString());
1463 }
1464
1465 /*!
1466 Returns the file icon provider for this directory model.
1467 */
1468 QFileIconProvider *QFileSystemModel::iconProvider() const
1469 {
1470 Q_D(const QFileSystemModel);
1471 return d->fileInfoGatherer.iconProvider();
1472 }
1473
1474 /*!
1475 Sets the directory model's filter to that specified by \a filters.
1476
1477 Note that the filter you set should always include the QDir::AllDirs enum value,
1478 otherwise QFileSystemModel won't be able to read the directory structure.
1479
1480 \sa QDir::Filters
1481 */
1482 void QFileSystemModel::setFilter(QDir::Filters filters)
1483 {
1484 Q_D(QFileSystemModel);
1485 if (d->filters == filters)
1486 return;
1487 d->filters = filters;
1488 // CaseSensitivity might have changed
1489 setNameFilters(nameFilters());
1490 d->forceSort = true;
1491 d->delayedSort();
1492 }
1493
1494 /*!
1495 Returns the filter specified for the directory model.
1496
1497 If a filter has not been set, the default filter is QDir::AllEntries |
1498 QDir::NoDotAndDotDot | QDir::AllDirs.
1499
1500 \sa QDir::Filters
1501 */
1502 QDir::Filters QFileSystemModel::filter() const
1503 {
1504 Q_D(const QFileSystemModel);
1505 return d->filters;
1506 }
1507
1508 /*!
1509 \property QFileSystemModel::resolveSymlinks
1510 \brief Whether the directory model should resolve symbolic links
1511
1512 This is only relevant on operating systems that support symbolic links.
1513
1514 By default, this property is false.
1515 */
1516 void QFileSystemModel::setResolveSymlinks(bool enable)
1517 {
1518 Q_D(QFileSystemModel);
1519 d->fileInfoGatherer.setResolveSymlinks(enable);
1520 }
1521
1522 bool QFileSystemModel::resolveSymlinks() const
1523 {
1524 Q_D(const QFileSystemModel);
1525 return d->fileInfoGatherer.resolveSymlinks();
1526 }
1527
1528 /*!
1529 \property QFileSystemModel::readOnly
1530 \brief Whether the directory model allows writing to the file system
1531
1532 If this property is set to false, the directory model will allow renaming, copying
1533 and deleting of files and directories.
1534
1535 This property is true by default
1536 */
1537 void QFileSystemModel::setReadOnly(bool enable)
1538 {
1539 Q_D(QFileSystemModel);
1540 d->readOnly = enable;
1541 }
1542
1543 bool QFileSystemModel::isReadOnly() const
1544 {
1545 Q_D(const QFileSystemModel);
1546 return d->readOnly;
1547 }
1548
1549 /*!
1550 \property QFileSystemModel::nameFilterDisables
1551 \brief Whether files that don't pass the name filter are hidden or disabled
1552
1553 This property is true by default
1554 */
1555 void QFileSystemModel::setNameFilterDisables(bool enable)
1556 {
1557 Q_D(QFileSystemModel);
1558 if (d->nameFilterDisables == enable)
1559 return;
1560 d->nameFilterDisables = enable;
1561 d->forceSort = true;
1562 d->delayedSort();
1563 }
1564
1565 bool QFileSystemModel::nameFilterDisables() const
1566 {
1567 Q_D(const QFileSystemModel);
1568 return d->nameFilterDisables;
1569 }
1570
1571 /*!
1572 Sets the name \a filters to apply against the existing files.
1573 */
1574 void QFileSystemModel::setNameFilters(const QStringList &filters)
1575 {
1576 // Prep the regexp's ahead of time
1577 #ifndef QT_NO_REGEXP
1578 Q_D(QFileSystemModel);
1579
1580 if (!d->bypassFilters.isEmpty()) {
1581 // update the bypass filter to only bypass the stuff that must be kept around
1582 d->bypassFilters.clear();
1583 // We guarantee that rootPath will stick around
1584 QPersistentModelIndex root(index(rootPath()));
1585 QModelIndexList persistantList = persistentIndexList();
1586 for (int i = 0; i < persistantList.count(); ++i) {
1587 QFileSystemModelPrivate::QFileSystemNode *node;
1588 node = d->node(persistantList.at(i));
1589 while (node) {
1590 if (d->bypassFilters.contains(node))
1591 break;
1592 if (node->isDir())
1593 d->bypassFilters[node] = true;
1594 node = node->parent;
1595 }
1596 }
1597 }
1598
1599 d->nameFilters.clear();
1600 const Qt::CaseSensitivity caseSensitive =
1601 (filter() & QDir::CaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive;
1602 for (int i = 0; i < filters.size(); ++i) {
1603 d->nameFilters << QRegExp(filters.at(i), caseSensitive, QRegExp::Wildcard);
1604 }
1605 d->forceSort = true;
1606 d->delayedSort();
1607 #endif
1608 }
1609
1610 /*!
1611 Returns a list of filters applied to the names in the model.
1612 */
1613 QStringList QFileSystemModel::nameFilters() const
1614 {
1615 Q_D(const QFileSystemModel);
1616 QStringList filters;
1617 #ifndef QT_NO_REGEXP
1618 for (int i = 0; i < d->nameFilters.size(); ++i) {
1619 filters << d->nameFilters.at(i).pattern();
1620 }
1621 #endif
1622 return filters;
1623 }
1624
1625 /*!
1626 \reimp
1627 */
1628 bool QFileSystemModel::event(QEvent *event)
1629 {
1630 Q_D(QFileSystemModel);
1631 if (event->type() == QEvent::LanguageChange) {
1632 d->root.retranslateStrings(d->fileInfoGatherer.iconProvider(), QString());
1633 return true;
1634 }
1635 return QAbstractItemModel::event(event);
1636 }
1637
1638 bool QFileSystemModel::rmdir(const QModelIndex &aindex) const
1639 {
1640 QString path = filePath(aindex);
1641 QFileSystemModelPrivate * d = const_cast<QFileSystemModelPrivate*>(d_func());
1642 d->fileInfoGatherer.removePath(path);
1643 return QDir().rmdir(path);
1644 }
1645
1646 /*!
1647 \internal
1648
1649 Performed quick listing and see if any files have been added or removed,
1650 then fetch more information on visible files.
1651 */
1652 void QFileSystemModelPrivate::_q_directoryChanged(const QString &directory, const QStringList &files)
1653 {
1654 QFileSystemModelPrivate::QFileSystemNode *parentNode = node(directory, false);
1655 if (parentNode->children.count() == 0)
1656 return;
1657 QStringList toRemove;
1658 #if defined(Q_OS_SYMBIAN)
1659 // Filename case must be exact in qBinaryFind below, so create a list of all lowercase names.
1660 QStringList newFiles;
1661 for(int i = 0; i < files.size(); i++) {
1662 newFiles << files.at(i).toLower();
1663 }
1664 #else
1665 QStringList newFiles = files;
1666 #endif
1667 qSort(newFiles.begin(), newFiles.end());
1668 QHash<QString, QFileSystemNode*>::const_iterator i = parentNode->children.constBegin();
1669 while (i != parentNode->children.constEnd()) {
1670 QStringList::iterator iterator;
1671 iterator = qBinaryFind(newFiles.begin(), newFiles.end(),
1672 #if defined(Q_OS_SYMBIAN)
1673 i.value()->fileName.toLower());
1674 #else
1675 i.value()->fileName);
1676 #endif
1677 if (iterator == newFiles.end()) {
1678 toRemove.append(i.value()->fileName);
1679 }
1680 ++i;
1681 }
1682 for (int i = 0 ; i < toRemove.count() ; ++i )
1683 removeNode(parentNode, toRemove[i]);
1684 }
1685
1686 /*!
1687 \internal
1688
1689 Adds a new file to the children of parentNode
1690
1691 *WARNING* this will change the count of children
1692 */
1693 QFileSystemModelPrivate::QFileSystemNode* QFileSystemModelPrivate::addNode(QFileSystemNode *parentNode, const QString &fileName, const QFileInfo& info)
1694 {
1695 // In the common case, itemLocation == count() so check there first
1696 QFileSystemModelPrivate::QFileSystemNode *node = new QFileSystemModelPrivate::QFileSystemNode(fileName, parentNode);
1697 #ifndef QT_NO_FILESYSTEMWATCHER
1698 node->populate(info);
1699 #endif
1700 #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
1701 //The parentNode is "" so we are listing the drives
1702 if (parentNode->fileName.isEmpty()) {
1703 wchar_t name[MAX_PATH + 1];
1704 //GetVolumeInformation requires to add trailing backslash
1705 const QString nodeName = fileName + QLatin1String("\\");
1706 BOOL success = ::GetVolumeInformation((wchar_t *)(nodeName.utf16()),
1707 name, MAX_PATH + 1, NULL, 0, NULL, NULL, 0);
1708 if (success && name[0])
1709 node->volumeName = QString::fromWCharArray(name);
1710 }
1711 #endif
1712 parentNode->children.insert(fileName, node);
1713 return node;
1714 }
1715
1716 /*!
1717 \internal
1718
1719 File at parentNode->children(itemLocation) has been removed, remove from the lists
1720 and emit signals if necessary
1721
1722 *WARNING* this will change the count of children and could change visibleChildren
1723 */
1724 void QFileSystemModelPrivate::removeNode(QFileSystemModelPrivate::QFileSystemNode *parentNode, const QString& name)
1725 {
1726 Q_Q(QFileSystemModel);
1727 QModelIndex parent = index(parentNode);
1728 bool indexHidden = isHiddenByFilter(parentNode, parent);
1729
1730 int vLocation = parentNode->visibleLocation(name);
1731 if (vLocation >= 0 && !indexHidden)
1732 q->beginRemoveRows(parent, translateVisibleLocation(parentNode, vLocation),
1733 translateVisibleLocation(parentNode, vLocation));
1734 QFileSystemNode * node = parentNode->children.take(name);
1735 delete node;
1736 // cleanup sort files after removing rather then re-sorting which is O(n)
1737 if (vLocation >= 0)
1738 parentNode->visibleChildren.removeAt(vLocation);
1739 if (vLocation >= 0 && !indexHidden)
1740 q->endRemoveRows();
1741 }
1742
1743 /*
1744 \internal
1745 Helper functor used by addVisibleFiles()
1746 */
1747 class QFileSystemModelVisibleFinder
1748 {
1749 public:
1750 inline QFileSystemModelVisibleFinder(QFileSystemModelPrivate::QFileSystemNode *node, QFileSystemModelSorter *sorter) : parentNode(node), sorter(sorter) {}
1751
1752 bool operator()(const QString &, QString r) const
1753 {
1754 return sorter->compareNodes(parentNode->children.value(name), parentNode->children.value(r));
1755 }
1756
1757 QString name;
1758 private:
1759 QFileSystemModelPrivate::QFileSystemNode *parentNode;
1760 QFileSystemModelSorter *sorter;
1761 };
1762
1763 /*!
1764 \internal
1765
1766 File at parentNode->children(itemLocation) was not visible before, but now should be
1767 and emit signals if necessary.
1768
1769 *WARNING* this will change the visible count
1770 */
1771 void QFileSystemModelPrivate::addVisibleFiles(QFileSystemNode *parentNode, const QStringList &newFiles)
1772 {
1773 Q_Q(QFileSystemModel);
1774 QModelIndex parent = index(parentNode);
1775 bool indexHidden = isHiddenByFilter(parentNode, parent);
1776 if (!indexHidden) {
1777 q->beginInsertRows(parent, parentNode->visibleChildren.count() , parentNode->visibleChildren.count() + newFiles.count() - 1);
1778 }
1779
1780 if (parentNode->dirtyChildrenIndex == -1)
1781 parentNode->dirtyChildrenIndex = parentNode->visibleChildren.count();
1782
1783 for (int i = 0; i < newFiles.count(); ++i) {
1784 parentNode->visibleChildren.append(newFiles.at(i));
1785 parentNode->children[newFiles.at(i)]->isVisible = true;
1786 }
1787 if (!indexHidden)
1788 q->endInsertRows();
1789 }
1790
1791 /*!
1792 \internal
1793
1794 File was visible before, but now should NOT be
1795
1796 *WARNING* this will change the visible count
1797 */
1798 void QFileSystemModelPrivate::removeVisibleFile(QFileSystemNode *parentNode, int vLocation)
1799 {
1800 Q_Q(QFileSystemModel);
1801 if (vLocation == -1)
1802 return;
1803 QModelIndex parent = index(parentNode);
1804 bool indexHidden = isHiddenByFilter(parentNode, parent);
1805 if (!indexHidden)
1806 q->beginRemoveRows(parent, translateVisibleLocation(parentNode, vLocation),
1807 translateVisibleLocation(parentNode, vLocation));
1808 parentNode->children[parentNode->visibleChildren.at(vLocation)]->isVisible = false;
1809 parentNode->visibleChildren.removeAt(vLocation);
1810 if (!indexHidden)
1811 q->endRemoveRows();
1812 }
1813
1814 /*!
1815 \internal
1816
1817 The thread has received new information about files,
1818 update and emit dataChanged if it has actually changed.
1819 */
1820 void QFileSystemModelPrivate::_q_fileSystemChanged(const QString &path, const QList<QPair<QString, QFileInfo> > &updates)
1821 {
1822 Q_Q(QFileSystemModel);
1823 QVector<QString> rowsToUpdate;
1824 QStringList newFiles;
1825 QFileSystemModelPrivate::QFileSystemNode *parentNode = node(path, false);
1826 QModelIndex parentIndex = index(parentNode);
1827 for (int i = 0; i < updates.count(); ++i) {
1828 QString fileName = updates.at(i).first;
1829 Q_ASSERT(!fileName.isEmpty());
1830 QExtendedInformation info = fileInfoGatherer.getInfo(updates.at(i).second);
1831 bool previouslyHere = parentNode->children.contains(fileName);
1832 if (!previouslyHere) {
1833 addNode(parentNode, fileName, info.fileInfo());
1834 }
1835 QFileSystemModelPrivate::QFileSystemNode * node = parentNode->children.value(fileName);
1836 bool isCaseSensitive = parentNode->caseSensitive();
1837 if (isCaseSensitive) {
1838 if (node->fileName != fileName)
1839 continue;
1840 } else {
1841 if (QString::compare(node->fileName,fileName,Qt::CaseInsensitive) != 0)
1842 continue;
1843 }
1844 if (isCaseSensitive) {
1845 Q_ASSERT(node->fileName == fileName);
1846 } else {
1847 node->fileName = fileName;
1848 }
1849
1850 if (info.size() == -1 && !info.isSymLink()) {
1851 removeNode(parentNode, fileName);
1852 continue;
1853 }
1854 if (*node != info ) {
1855 node->populate(info);
1856 bypassFilters.remove(node);
1857 // brand new information.
1858 if (filtersAcceptsNode(node)) {
1859 if (!node->isVisible) {
1860 newFiles.append(fileName);
1861 } else {
1862 rowsToUpdate.append(fileName);
1863 }
1864 } else {
1865 if (node->isVisible) {
1866 int visibleLocation = parentNode->visibleLocation(fileName);
1867 removeVisibleFile(parentNode, visibleLocation);
1868 } else {
1869 // The file is not visible, don't do anything
1870 }
1871 }
1872 }
1873 }
1874
1875 // bundle up all of the changed signals into as few as possible.
1876 qSort(rowsToUpdate.begin(), rowsToUpdate.end());
1877 QString min;
1878 QString max;
1879 for (int i = 0; i < rowsToUpdate.count(); ++i) {
1880 QString value = rowsToUpdate.at(i);
1881 //##TODO is there a way to bundle signals with QString as the content of the list?
1882 /*if (min.isEmpty()) {
1883 min = value;
1884 if (i != rowsToUpdate.count() - 1)
1885 continue;
1886 }
1887 if (i != rowsToUpdate.count() - 1) {
1888 if ((value == min + 1 && max.isEmpty()) || value == max + 1) {
1889 max = value;
1890 continue;
1891 }
1892 }*/
1893 max = value;
1894 min = value;
1895 int visibleMin = parentNode->visibleLocation(min);
1896 int visibleMax = parentNode->visibleLocation(max);
1897 if (visibleMin >= 0
1898 && visibleMin < parentNode->visibleChildren.count()
1899 && parentNode->visibleChildren.at(visibleMin) == min
1900 && visibleMax >= 0) {
1901 QModelIndex bottom = q->index(translateVisibleLocation(parentNode, visibleMin), 0, parentIndex);
1902 QModelIndex top = q->index(translateVisibleLocation(parentNode, visibleMax), 3, parentIndex);
1903 emit q->dataChanged(bottom, top);
1904 }
1905
1906 /*min = QString();
1907 max = QString();*/
1908 }
1909
1910 if (newFiles.count() > 0) {
1911 addVisibleFiles(parentNode, newFiles);
1912 }
1913
1914 if (newFiles.count() > 0 || (sortColumn != 0 && rowsToUpdate.count() > 0)) {
1915 forceSort = true;
1916 delayedSort();
1917 }
1918 }
1919
1920 /*!
1921 \internal
1922 */
1923 void QFileSystemModelPrivate::_q_resolvedName(const QString &fileName, const QString &resolvedName)
1924 {
1925 resolvedSymLinks[fileName] = resolvedName;
1926 }
1927
1928 /*!
1929 \internal
1930 */
1931 void QFileSystemModelPrivate::init()
1932 {
1933 Q_Q(QFileSystemModel);
1934 qRegisterMetaType<QList<QPair<QString,QFileInfo> > >("QList<QPair<QString,QFileInfo> >");
1935 q->connect(&fileInfoGatherer, SIGNAL(newListOfFiles(QString,QStringList)),
1936 q, SLOT(_q_directoryChanged(QString,QStringList)));
1937 q->connect(&fileInfoGatherer, SIGNAL(updates(QString,QList<QPair<QString,QFileInfo> >)),
1938 q, SLOT(_q_fileSystemChanged(QString,QList<QPair<QString,QFileInfo> >)));
1939 q->connect(&fileInfoGatherer, SIGNAL(nameResolved(QString,QString)),
1940 q, SLOT(_q_resolvedName(QString,QString)));
1941 q->connect(&fileInfoGatherer, SIGNAL(directoryLoaded(QString)),
1942 q, SIGNAL(directoryLoaded(QString)));
1943 q->connect(&delayedSortTimer, SIGNAL(timeout()), q, SLOT(_q_performDelayedSort()), Qt::QueuedConnection);
1944
1945 QHash<int, QByteArray> roles = q->roleNames();
1946 roles.insertMulti(QFileSystemModel::FileIconRole, "fileIcon"); // == Qt::decoration
1947 roles.insert(QFileSystemModel::FilePathRole, "filePath");
1948 roles.insert(QFileSystemModel::FileNameRole, "fileName");
1949 roles.insert(QFileSystemModel::FilePermissions, "filePermissions");
1950 q->setRoleNames(roles);
1951 }
1952
1953 /*!
1954 \internal
1955
1956 Returns false if node doesn't pass the filters otherwise true
1957
1958 QDir::Modified is not supported
1959 QDir::Drives is not supported
1960 */
1961 bool QFileSystemModelPrivate::filtersAcceptsNode(const QFileSystemNode *node) const
1962 {
1963 // always accept drives
1964 if (node->parent == &root || bypassFilters.contains(node))
1965 return true;
1966
1967 // If we don't know anything yet don't accept it
1968 if (!node->hasInformation())
1969 return false;
1970
1971 const bool filterPermissions = ((filters & QDir::PermissionMask)
1972 && (filters & QDir::PermissionMask) != QDir::PermissionMask);
1973 const bool hideDirs = !(filters & (QDir::Dirs | QDir::AllDirs));
1974 const bool hideFiles = !(filters & QDir::Files);
1975 const bool hideReadable = !(!filterPermissions || (filters & QDir::Readable));
1976 const bool hideWritable = !(!filterPermissions || (filters & QDir::Writable));
1977 const bool hideExecutable = !(!filterPermissions || (filters & QDir::Executable));
1978 const bool hideHidden = !(filters & QDir::Hidden);
1979 const bool hideSystem = !(filters & QDir::System);
1980 const bool hideSymlinks = (filters & QDir::NoSymLinks);
1981 const bool hideDot = (filters & QDir::NoDot) || (filters & QDir::NoDotAndDotDot); // ### Qt5: simplify (because NoDotAndDotDot=NoDot|NoDotDot)
1982 const bool hideDotDot = (filters & QDir::NoDotDot) || (filters & QDir::NoDotAndDotDot); // ### Qt5: simplify (because NoDotAndDotDot=NoDot|NoDotDot)
1983
1984 // Note that we match the behavior of entryList and not QFileInfo on this and this
1985 // incompatibility won't be fixed until Qt 5 at least
1986 bool isDot = (node->fileName == QLatin1String("."));
1987 bool isDotDot = (node->fileName == QLatin1String(".."));
1988 if ( (hideHidden && !(isDot || isDotDot) && node->isHidden())
1989 || (hideSystem && node->isSystem())
1990 || (hideDirs && node->isDir())
1991 || (hideFiles && node->isFile())
1992 || (hideSymlinks && node->isSymLink())
1993 || (hideReadable && node->isReadable())
1994 || (hideWritable && node->isWritable())
1995 || (hideExecutable && node->isExecutable())
1996 || (hideDot && isDot)
1997 || (hideDotDot && isDotDot))
1998 return false;
1999
2000 return nameFilterDisables || passNameFilters(node);
2001 }
2002
2003 /*
2004 \internal
2005
2006 Returns true if node passes the name filters and should be visible.
2007 */
2008 bool QFileSystemModelPrivate::passNameFilters(const QFileSystemNode *node) const
2009 {
2010 #ifndef QT_NO_REGEXP
2011 if (nameFilters.isEmpty())
2012 return true;
2013
2014 // Check the name regularexpression filters
2015 if (!(node->isDir() && (filters & QDir::AllDirs))) {
2016 for (int i = 0; i < nameFilters.size(); ++i) {
2017 if (nameFilters.at(i).exactMatch(node->fileName))
2018 return true;
2019 }
2020 return false;
2021 }
2022 #endif
2023 return true;
2024 }
2025
2026 QT_END_NAMESPACE
2027
2028 #include "moc_qfilesystemmodel.cpp"
2029
2030 #endif // QT_NO_FILESYSTEMMODEL