1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2012 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.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 // http://www.gnu.org/licenses/gpl-2.0.txt
20 ///////////////////////////////////////////////////////////////////////////////
22 #include "Model_FileSystem.h"
25 #include <QApplication>
26 #include <QFileIconProvider>
27 #include <QDesktopServices>
30 #define IS_DIR(ATTR) (((ATTR) & FILE_ATTRIBUTE_DIRECTORY) && (!((ATTR) & FILE_ATTRIBUTE_HIDDEN)))
31 #define NO_DOT_OR_DOTDOT(STR) (wcscmp((STR), L".") && wcscmp((STR), L".."))
33 typedef HANDLE (WINAPI
*FindFirstFileExFun
)(LPCWSTR lpFileName
, FINDEX_INFO_LEVELS fInfoLevelId
, LPVOID lpFindFileData
, FINDEX_SEARCH_OPS fSearchOp
, LPVOID lpSearchFilter
, DWORD dwAdditionalFlags
);
35 ///////////////////////////////////////////////////////////////////////////////
36 // Dummy QFileIconProvider class
37 ///////////////////////////////////////////////////////////////////////////////
39 class QFileIconProviderEx
: public QFileIconProvider
42 QFileIconProviderEx();
43 virtual QIcon
icon(IconType type
) const { return (type
== Drive
) ? m_driveIcon
: m_folderIcon
; }
44 virtual QIcon
icon(const QFileInfo
&info
) const;
45 virtual QString
type (const QFileInfo
&info
) const { return info
.isDir() ? m_folderType
: m_emptyType
; }
48 const QIcon m_driveIcon
;
49 const QIcon m_cdromIcon
;
50 const QIcon m_networkIcon
;
51 const QIcon m_floppyIcon
;
52 const QIcon m_folderIcon
;
53 const QIcon m_homeIcon
;
54 const QIcon m_desktopIcon
;
55 const QIcon m_musicIcon
;
56 const QIcon m_moviesIcon
;
57 const QIcon m_picturesIcon
;
58 const QIcon m_emptyIcon
;
59 const QString m_folderType
;
60 const QString m_emptyType
;
61 const QString m_homeDir
;
62 const QString m_desktopDir
;
63 const QString m_musicDir
;
64 const QString m_moviesDir
;
65 const QString m_picturesDir
;
68 QFileIconProviderEx::QFileIconProviderEx()
70 m_folderIcon(":/icons/folder.png"),
71 m_driveIcon(":/icons/drive.png"),
72 m_cdromIcon(":/icons/drive_cd.png"),
73 m_networkIcon(":/icons/drive_link.png"),
74 m_floppyIcon(":/icons/drive_disk.png"),
75 m_homeIcon(":/icons/house.png"),
76 m_desktopIcon(":/icons/monitor.png"),
77 m_musicIcon(":/icons/music.png"),
78 m_moviesIcon(":/icons/film.png"),
79 m_picturesIcon(":/icons/picture.png"),
80 m_homeDir(QDir::fromNativeSeparators(QDesktopServices::storageLocation(QDesktopServices::HomeLocation
))),
81 m_desktopDir(QDir::fromNativeSeparators(QDesktopServices::storageLocation(QDesktopServices::DesktopLocation
))),
82 m_musicDir(QDir::fromNativeSeparators(QDesktopServices::storageLocation(QDesktopServices::MusicLocation
))),
83 m_moviesDir(QDir::fromNativeSeparators(QDesktopServices::storageLocation(QDesktopServices::MoviesLocation
))),
84 m_picturesDir(QDir::fromNativeSeparators(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation
))),
85 m_folderType("Folder")
90 QIcon
QFileIconProviderEx::icon(const QFileInfo
&info
) const
96 else if(info
.isRoot())
98 switch(GetDriveType(QWCHAR(QDir::toNativeSeparators(info
.absoluteFilePath()))))
103 case DRIVE_REMOVABLE
:
107 return m_networkIcon
;
114 else if(!info
.filePath().compare(m_homeDir
, Qt::CaseInsensitive
))
118 else if(!info
.filePath().compare(m_desktopDir
, Qt::CaseInsensitive
))
120 return m_desktopIcon
;
122 else if(!info
.filePath().compare(m_musicDir
, Qt::CaseInsensitive
))
126 else if(!info
.filePath().compare(m_moviesDir
, Qt::CaseInsensitive
))
130 else if(!info
.filePath().compare(m_picturesDir
, Qt::CaseInsensitive
))
132 return m_picturesIcon
;
140 ///////////////////////////////////////////////////////////////////////////////
141 // Modified QFileSystemModel class
142 ///////////////////////////////////////////////////////////////////////////////
144 QFileSystemModelEx::QFileSystemModelEx()
148 this->m_myIconProvider
= new QFileIconProviderEx();
149 this->setIconProvider(m_myIconProvider
);
150 this->setFilter(QDir::Dirs
| QDir::NoDotAndDotDot
);
151 this->setNameFilterDisables(false);
154 QFileSystemModelEx::~QFileSystemModelEx()
156 removeAllFromCache();
157 LAMEXP_DELETE(m_myIconProvider
);
160 bool QFileSystemModelEx::hasChildren(const QModelIndex
&parent
) const
164 return hasSubfoldersCached(filePath(parent
).toLower()); //return (QDir(QFileSystemModel::filePath(parent)).entryList(QDir::Dirs | QDir::NoDotAndDotDot).count() > 0);
169 void QFileSystemModelEx::fetchMore(const QModelIndex
&parent
)
173 removeFromCache(filePath(parent
).toLower());
176 QFileSystemModel::fetchMore(parent
);
179 QModelIndex
QFileSystemModelEx::index(const QString
&path
, int column
) const
181 QFileInfo
info(path
);
182 if(info
.exists() && info
.isDir())
184 QString fullPath
= QDir::fromNativeSeparators(info
.canonicalFilePath());
185 QStringList parts
= fullPath
.split('/', QString::SkipEmptyParts
);
186 for(int i
= 2; i
<= parts
.count(); i
++)
188 QFileInfo
currentPath(((QStringList
) parts
.mid(0, i
)).join("/"));
189 if((!currentPath
.exists()) || (!currentPath
.isDir()) || currentPath
.isHidden())
191 return QModelIndex();
194 QModelIndex index
= QFileSystemModel::index(fullPath
, column
);
197 QModelIndex temp
= index
;
198 while(temp
.isValid())
200 removeFromCache(filePath(temp
).toLower());
201 temp
= temp
.parent();
206 return QModelIndex();
209 void QFileSystemModelEx::flushCache(void)
211 removeAllFromCache();
214 /* ------------------------ */
215 /* STATIC FUNCTIONS BELOW */
216 /* ------------------------ */
218 QHash
<const QString
, bool> QFileSystemModelEx::s_hasSubfolderCache
;
219 QMutex
QFileSystemModelEx::s_hasSubfolderMutex
;
221 void *QFileSystemModelEx::FindFirstFileExPtr
= NULL
;
222 bool QFileSystemModelEx::FindFirstFileExInitialized
= false;
223 bool QFileSystemModelEx::FindFirstFileExInfoBasicOK
= false;
225 bool QFileSystemModelEx::hasSubfoldersCached(const QString
&path
)
227 QMutexLocker
lock(&s_hasSubfolderMutex
);
229 if(s_hasSubfolderCache
.contains(path
))
231 return s_hasSubfolderCache
.value(path
);
234 bool bChildren
= hasSubfolders(path
);
235 s_hasSubfolderCache
.insert(path
, bChildren
);
239 void QFileSystemModelEx::removeFromCache(const QString
&path
)
241 QMutexLocker
lock(&s_hasSubfolderMutex
);
242 s_hasSubfolderCache
.remove(path
);
245 void QFileSystemModelEx::removeAllFromCache(void)
247 QMutexLocker
lock(&s_hasSubfolderMutex
);
248 s_hasSubfolderCache
.clear();
251 bool QFileSystemModelEx::hasSubfolders(const QString
&path
)
253 if(!FindFirstFileExInitialized
)
255 QLibrary
kernel32Lib("kernel32.dll");
256 if(kernel32Lib
.load())
258 FindFirstFileExPtr
= kernel32Lib
.resolve("FindFirstFileExW");
259 DWORD osVersionNo
= lamexp_get_os_version();
260 FindFirstFileExInfoBasicOK
= LAMEXP_MIN_OS_VER(osVersionNo
, 6, 1);
262 FindFirstFileExInitialized
= true;
265 WIN32_FIND_DATAW findData
;
266 bool bChildren
= false;
268 HANDLE h
= (FindFirstFileExPtr
)
269 ? reinterpret_cast<FindFirstFileExFun
>(FindFirstFileExPtr
)(QWCHAR(QDir::toNativeSeparators(path
+ "/*")), (FindFirstFileExInfoBasicOK
? FindExInfoBasic
: FindExInfoStandard
), &findData
, FindExSearchLimitToDirectories
, NULL
, 0)
270 : FindFirstFileW(QWCHAR(QDir::toNativeSeparators(path
+ "/*")), &findData
);
272 if(h
!= INVALID_HANDLE_VALUE
)
274 if(NO_DOT_OR_DOTDOT(findData
.cFileName
))
276 bChildren
= IS_DIR(findData
.dwFileAttributes
);
278 while((!bChildren
) && FindNextFile(h
, &findData
))
280 if(NO_DOT_OR_DOTDOT(findData
.cFileName
))
282 bChildren
= IS_DIR(findData
.dwFileAttributes
);
289 DWORD err
= GetLastError();
290 if((err
== ERROR_NOT_SUPPORTED
) || (err
== ERROR_INVALID_PARAMETER
))
292 qWarning("%s failed with error code #%u", FindFirstFileExPtr
? "FindFirstFileEx" : "FindFirstFile", err
);