1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2017 LoRd_MuldeR <MuldeR2@GMX.de>
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version, but always including the *additional*
9 // restrictions defined in the "License.txt" file.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License along
17 // with this program; if not, write to the Free Software Foundation, Inc.,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 // http://www.gnu.org/licenses/gpl-2.0.txt
21 ///////////////////////////////////////////////////////////////////////////////
23 #include "Model_FileSystem.h"
29 #include <MUtils/Global.h>
30 #include <MUtils/OSSupport.h>
33 #include <QApplication>
34 #include <QFileIconProvider>
35 #include <QDesktopServices>
39 #define WIN32_LEAN_AND_MEAN
42 #define IS_DIR(ATTR) (((ATTR) & FILE_ATTRIBUTE_DIRECTORY) && (!((ATTR) & FILE_ATTRIBUTE_HIDDEN)))
43 #define NO_DOT_OR_DOTDOT(STR) (wcscmp((STR), L".") && wcscmp((STR), L".."))
45 ///////////////////////////////////////////////////////////////////////////////
46 // Dummy QFileIconProvider class
47 ///////////////////////////////////////////////////////////////////////////////
49 class QFileIconProviderEx
: public QFileIconProvider
52 QFileIconProviderEx();
53 virtual QIcon
icon(IconType type
) const { return (type
== Drive
) ? m_driveIcon
: m_folderIcon
; }
54 virtual QIcon
icon(const QFileInfo
&info
) const;
55 virtual QString
type (const QFileInfo
&info
) const { return info
.isDir() ? m_folderType
: m_emptyType
; }
58 const QIcon m_driveIcon
;
59 const QIcon m_cdromIcon
;
60 const QIcon m_networkIcon
;
61 const QIcon m_floppyIcon
;
62 const QIcon m_folderIcon
;
63 const QIcon m_homeIcon
;
64 const QIcon m_desktopIcon
;
65 const QIcon m_musicIcon
;
66 const QIcon m_moviesIcon
;
67 const QIcon m_picturesIcon
;
68 const QIcon m_heartIcon
;
69 const QIcon m_emptyIcon
;
70 const QString m_folderType
;
71 const QString m_emptyType
;
72 const QString m_homeDir
;
73 const QString m_desktopDir
;
74 const QString m_musicDir
;
75 const QString m_moviesDir
;
76 const QString m_picturesDir
;
77 const QString m_installDir
;
80 QFileIconProviderEx::QFileIconProviderEx()
82 m_folderIcon(":/icons/folder.png"),
83 m_driveIcon(":/icons/drive.png"),
84 m_cdromIcon(":/icons/drive_cd.png"),
85 m_networkIcon(":/icons/drive_link.png"),
86 m_floppyIcon(":/icons/drive_disk.png"),
87 m_homeIcon(":/icons/house.png"),
88 m_desktopIcon(":/icons/monitor.png"),
89 m_musicIcon(":/icons/music.png"),
90 m_moviesIcon(":/icons/film.png"),
91 m_picturesIcon(":/icons/picture.png"),
92 m_heartIcon(":/icons/heart.png"),
93 m_homeDir(QDir::fromNativeSeparators(QDesktopServices::storageLocation(QDesktopServices::HomeLocation
))),
94 m_desktopDir(QDir::fromNativeSeparators(QDesktopServices::storageLocation(QDesktopServices::DesktopLocation
))),
95 m_musicDir(QDir::fromNativeSeparators(QDesktopServices::storageLocation(QDesktopServices::MusicLocation
))),
96 m_moviesDir(QDir::fromNativeSeparators(QDesktopServices::storageLocation(QDesktopServices::MoviesLocation
))),
97 m_picturesDir(QDir::fromNativeSeparators(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation
))),
98 m_installDir(QDir::fromNativeSeparators(qApp
->applicationDirPath())),
99 m_folderType("Folder")
104 QIcon
QFileIconProviderEx::icon(const QFileInfo
&info
) const
110 else if(info
.isRoot())
112 switch(GetDriveType(MUTILS_WCHR(QDir::toNativeSeparators(info
.absoluteFilePath()))))
117 case DRIVE_REMOVABLE
:
121 return m_networkIcon
;
130 const QString filePath
= info
.filePath();
131 if(m_homeDir
.compare(filePath
, Qt::CaseInsensitive
) == 0)
135 else if(m_desktopDir
.compare(filePath
, Qt::CaseInsensitive
) == 0)
137 return m_desktopIcon
;
139 else if(m_musicDir
.compare(filePath
, Qt::CaseInsensitive
) == 0)
143 else if(m_moviesDir
.compare(filePath
, Qt::CaseInsensitive
) == 0)
147 else if(m_picturesDir
.compare(filePath
, Qt::CaseInsensitive
) == 0)
149 return m_picturesIcon
;
151 else if(m_installDir
.compare(filePath
, Qt::CaseInsensitive
) == 0)
162 ///////////////////////////////////////////////////////////////////////////////
163 // Modified QFileSystemModel class
164 ///////////////////////////////////////////////////////////////////////////////
166 QFileSystemModelEx::QFileSystemModelEx()
170 this->m_myIconProvider
= new QFileIconProviderEx();
171 this->setIconProvider(m_myIconProvider
);
172 this->setFilter(QDir::Dirs
| QDir::NoDotAndDotDot
);
173 this->setNameFilterDisables(false);
176 QFileSystemModelEx::~QFileSystemModelEx()
178 removeAllFromCache();
179 MUTILS_DELETE(m_myIconProvider
);
182 bool QFileSystemModelEx::hasChildren(const QModelIndex
&parent
) const
186 return hasSubfoldersCached(filePath(parent
).toLower()); //return (QDir(QFileSystemModel::filePath(parent)).entryList(QDir::Dirs | QDir::NoDotAndDotDot).count() > 0);
191 void QFileSystemModelEx::fetchMore(const QModelIndex
&parent
)
195 removeFromCache(filePath(parent
).toLower());
198 QFileSystemModel::fetchMore(parent
);
201 QModelIndex
QFileSystemModelEx::index(const QString
&path
, int column
) const
203 QFileInfo
info(path
);
204 if(info
.exists() && info
.isDir())
206 QString fullPath
= QDir::fromNativeSeparators(info
.canonicalFilePath());
207 QStringList parts
= fullPath
.split('/', QString::SkipEmptyParts
);
208 for(int i
= 2; i
<= parts
.count(); i
++)
210 QFileInfo
currentPath(((QStringList
) parts
.mid(0, i
)).join("/"));
211 if((!currentPath
.exists()) || (!currentPath
.isDir()) || currentPath
.isHidden())
213 return QModelIndex();
216 QModelIndex index
= QFileSystemModel::index(fullPath
, column
);
219 QModelIndex temp
= index
;
220 while(temp
.isValid())
222 removeFromCache(filePath(temp
).toLower());
223 temp
= temp
.parent();
228 return QModelIndex();
231 void QFileSystemModelEx::flushCache(void)
233 removeAllFromCache();
236 /* ------------------------ */
237 /* STATIC FUNCTIONS BELOW */
238 /* ------------------------ */
240 QHash
<const QString
, bool> QFileSystemModelEx::s_hasSubfolderCache
;
241 QMutex
QFileSystemModelEx::s_hasSubfolderMutex
;
242 int QFileSystemModelEx::s_findFirstFileExInfoLevel
= INT_MAX
;
244 bool QFileSystemModelEx::hasSubfoldersCached(const QString
&path
)
246 QMutexLocker
lock(&s_hasSubfolderMutex
);
248 if(s_hasSubfolderCache
.contains(path
))
250 return s_hasSubfolderCache
.value(path
);
253 bool bChildren
= hasSubfolders(path
);
254 s_hasSubfolderCache
.insert(path
, bChildren
);
258 void QFileSystemModelEx::removeFromCache(const QString
&path
)
260 QMutexLocker
lock(&s_hasSubfolderMutex
);
261 s_hasSubfolderCache
.remove(path
);
264 void QFileSystemModelEx::removeAllFromCache(void)
266 QMutexLocker
lock(&s_hasSubfolderMutex
);
267 s_hasSubfolderCache
.clear();
270 bool QFileSystemModelEx::hasSubfolders(const QString
&path
)
272 if(s_findFirstFileExInfoLevel
== INT_MAX
)
274 const MUtils::OS::Version::os_version_t
&osVersion
= MUtils::OS::os_version();
275 s_findFirstFileExInfoLevel
= (osVersion
>= MUtils::OS::Version::WINDOWS_WIN70
) ? FindExInfoBasic
: FindExInfoStandard
;
278 WIN32_FIND_DATAW findData
;
279 bool bChildren
= false;
281 HANDLE h
= FindFirstFileEx(MUTILS_WCHR(QDir::toNativeSeparators(path
+ "/*")), ((FINDEX_INFO_LEVELS
)s_findFirstFileExInfoLevel
), &findData
, FindExSearchLimitToDirectories
, NULL
, 0);
283 if(h
!= INVALID_HANDLE_VALUE
)
285 if(NO_DOT_OR_DOTDOT(findData
.cFileName
))
287 bChildren
= IS_DIR(findData
.dwFileAttributes
);
289 while((!bChildren
) && FindNextFile(h
, &findData
))
291 if(NO_DOT_OR_DOTDOT(findData
.cFileName
))
293 bChildren
= IS_DIR(findData
.dwFileAttributes
);
300 DWORD err
= GetLastError();
301 if((err
== ERROR_NOT_SUPPORTED
) || (err
== ERROR_INVALID_PARAMETER
))
303 qWarning("FindFirstFileEx failed with error code #%u", err
);