Version v4.05 is released!
[LameXP.git] / src / Model_FileSystem.cpp
blob3c71e7d824aa6260d371fdaad097b80da6fea678
1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2012 LoRd_MuldeR <MuldeR2@GMX.de>
4 //
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.
9 //
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"
23 #include "Global.h"
25 #include <QApplication>
26 #include <QFileIconProvider>
27 #include <QDesktopServices>
28 #include <QLibrary>
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
41 public:
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; }
47 private:
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_heartIcon;
59 const QIcon m_emptyIcon;
60 const QString m_folderType;
61 const QString m_emptyType;
62 const QString m_homeDir;
63 const QString m_desktopDir;
64 const QString m_musicDir;
65 const QString m_moviesDir;
66 const QString m_picturesDir;
67 const QString m_installDir;
70 QFileIconProviderEx::QFileIconProviderEx()
72 m_folderIcon(":/icons/folder.png"),
73 m_driveIcon(":/icons/drive.png"),
74 m_cdromIcon(":/icons/drive_cd.png"),
75 m_networkIcon(":/icons/drive_link.png"),
76 m_floppyIcon(":/icons/drive_disk.png"),
77 m_homeIcon(":/icons/house.png"),
78 m_desktopIcon(":/icons/monitor.png"),
79 m_musicIcon(":/icons/music.png"),
80 m_moviesIcon(":/icons/film.png"),
81 m_picturesIcon(":/icons/picture.png"),
82 m_heartIcon(":/icons/heart.png"),
83 m_homeDir(QDir::fromNativeSeparators(QDesktopServices::storageLocation(QDesktopServices::HomeLocation))),
84 m_desktopDir(QDir::fromNativeSeparators(QDesktopServices::storageLocation(QDesktopServices::DesktopLocation))),
85 m_musicDir(QDir::fromNativeSeparators(QDesktopServices::storageLocation(QDesktopServices::MusicLocation))),
86 m_moviesDir(QDir::fromNativeSeparators(QDesktopServices::storageLocation(QDesktopServices::MoviesLocation))),
87 m_picturesDir(QDir::fromNativeSeparators(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation))),
88 m_installDir(QDir::fromNativeSeparators(qApp->applicationDirPath())),
89 m_folderType("Folder")
91 /* Nothing to do! */
94 QIcon QFileIconProviderEx::icon(const QFileInfo &info) const
96 if(info.isFile())
98 return m_emptyIcon;
100 else if(info.isRoot())
102 switch(GetDriveType(QWCHAR(QDir::toNativeSeparators(info.absoluteFilePath()))))
104 case DRIVE_CDROM:
105 return m_cdromIcon;
106 break;
107 case DRIVE_REMOVABLE:
108 return m_floppyIcon;
109 break;
110 case DRIVE_REMOTE:
111 return m_networkIcon;
112 break;
113 default:
114 return m_driveIcon;
115 break;
118 else
120 const QString filePath = info.filePath();
121 if(m_homeDir.compare(filePath, Qt::CaseInsensitive) == 0)
123 return m_homeIcon;
125 else if(m_desktopDir.compare(filePath, Qt::CaseInsensitive) == 0)
127 return m_desktopIcon;
129 else if(m_musicDir.compare(filePath, Qt::CaseInsensitive) == 0)
131 return m_musicIcon;
133 else if(m_moviesDir.compare(filePath, Qt::CaseInsensitive) == 0)
135 return m_moviesIcon;
137 else if(m_picturesDir.compare(filePath, Qt::CaseInsensitive) == 0)
139 return m_picturesIcon;
141 else if(m_installDir.compare(filePath, Qt::CaseInsensitive) == 0)
143 return m_heartIcon;
145 else
147 return m_folderIcon;
152 ///////////////////////////////////////////////////////////////////////////////
153 // Modified QFileSystemModel class
154 ///////////////////////////////////////////////////////////////////////////////
156 QFileSystemModelEx::QFileSystemModelEx()
158 QFileSystemModel()
160 this->m_myIconProvider = new QFileIconProviderEx();
161 this->setIconProvider(m_myIconProvider);
162 this->setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
163 this->setNameFilterDisables(false);
166 QFileSystemModelEx::~QFileSystemModelEx()
168 removeAllFromCache();
169 LAMEXP_DELETE(m_myIconProvider);
172 bool QFileSystemModelEx::hasChildren(const QModelIndex &parent) const
174 if(parent.isValid())
176 return hasSubfoldersCached(filePath(parent).toLower()); //return (QDir(QFileSystemModel::filePath(parent)).entryList(QDir::Dirs | QDir::NoDotAndDotDot).count() > 0);
178 return true;
181 void QFileSystemModelEx::fetchMore(const QModelIndex &parent)
183 if(parent.isValid())
185 removeFromCache(filePath(parent).toLower());
188 QFileSystemModel::fetchMore(parent);
191 QModelIndex QFileSystemModelEx::index(const QString &path, int column) const
193 QFileInfo info(path);
194 if(info.exists() && info.isDir())
196 QString fullPath = QDir::fromNativeSeparators(info.canonicalFilePath());
197 QStringList parts = fullPath.split('/', QString::SkipEmptyParts);
198 for(int i = 2; i <= parts.count(); i++)
200 QFileInfo currentPath(((QStringList) parts.mid(0, i)).join("/"));
201 if((!currentPath.exists()) || (!currentPath.isDir()) || currentPath.isHidden())
203 return QModelIndex();
206 QModelIndex index = QFileSystemModel::index(fullPath, column);
207 if(index.isValid())
209 QModelIndex temp = index;
210 while(temp.isValid())
212 removeFromCache(filePath(temp).toLower());
213 temp = temp.parent();
215 return index;
218 return QModelIndex();
221 void QFileSystemModelEx::flushCache(void)
223 removeAllFromCache();
226 /* ------------------------ */
227 /* STATIC FUNCTIONS BELOW */
228 /* ------------------------ */
230 QHash<const QString, bool> QFileSystemModelEx::s_hasSubfolderCache;
231 QMutex QFileSystemModelEx::s_hasSubfolderMutex;
233 void *QFileSystemModelEx::FindFirstFileExPtr = NULL;
234 bool QFileSystemModelEx::FindFirstFileExInitialized = false;
235 bool QFileSystemModelEx::FindFirstFileExInfoBasicOK = false;
237 bool QFileSystemModelEx::hasSubfoldersCached(const QString &path)
239 QMutexLocker lock(&s_hasSubfolderMutex);
241 if(s_hasSubfolderCache.contains(path))
243 return s_hasSubfolderCache.value(path);
246 bool bChildren = hasSubfolders(path);
247 s_hasSubfolderCache.insert(path, bChildren);
248 return bChildren;
251 void QFileSystemModelEx::removeFromCache(const QString &path)
253 QMutexLocker lock(&s_hasSubfolderMutex);
254 s_hasSubfolderCache.remove(path);
257 void QFileSystemModelEx::removeAllFromCache(void)
259 QMutexLocker lock(&s_hasSubfolderMutex);
260 s_hasSubfolderCache.clear();
263 bool QFileSystemModelEx::hasSubfolders(const QString &path)
265 if(!FindFirstFileExInitialized)
267 QLibrary kernel32Lib("kernel32.dll");
268 if(kernel32Lib.load())
270 FindFirstFileExPtr = kernel32Lib.resolve("FindFirstFileExW");
271 DWORD osVersionNo = lamexp_get_os_version();
272 FindFirstFileExInfoBasicOK = LAMEXP_MIN_OS_VER(osVersionNo, 6, 1);
274 FindFirstFileExInitialized = true;
277 WIN32_FIND_DATAW findData;
278 bool bChildren = false;
280 HANDLE h = (FindFirstFileExPtr)
281 ? reinterpret_cast<FindFirstFileExFun>(FindFirstFileExPtr)(QWCHAR(QDir::toNativeSeparators(path + "/*")), (FindFirstFileExInfoBasicOK ? FindExInfoBasic : FindExInfoStandard), &findData, FindExSearchLimitToDirectories, NULL, 0)
282 : FindFirstFileW(QWCHAR(QDir::toNativeSeparators(path + "/*")), &findData);
284 if(h != INVALID_HANDLE_VALUE)
286 if(NO_DOT_OR_DOTDOT(findData.cFileName))
288 bChildren = IS_DIR(findData.dwFileAttributes);
290 while((!bChildren) && FindNextFile(h, &findData))
292 if(NO_DOT_OR_DOTDOT(findData.cFileName))
294 bChildren = IS_DIR(findData.dwFileAttributes);
297 FindClose(h);
299 else
301 DWORD err = GetLastError();
302 if((err == ERROR_NOT_SUPPORTED) || (err == ERROR_INVALID_PARAMETER))
304 qWarning("%s failed with error code #%u", FindFirstFileExPtr ? "FindFirstFileEx" : "FindFirstFile", err);
308 return bChildren;