OSDN Git Service

Made getLogFile() function "const" and made sure that we will return a const referenc...
[lamexp/LameXP.git] / src / Model_FileSystem.cpp
index 9e694d0..e42dfde 100644 (file)
@@ -1,6 +1,6 @@
 ///////////////////////////////////////////////////////////////////////////////
 // LameXP - Audio Encoder Front-End
-// Copyright (C) 2004-2010 LoRd_MuldeR <MuldeR2@GMX.de>
+// Copyright (C) 2004-2012 LoRd_MuldeR <MuldeR2@GMX.de>
 //
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License as published by
 ///////////////////////////////////////////////////////////////////////////////
 
 #include "Model_FileSystem.h"
+#include "Global.h"
 
 #include <QApplication>
+#include <QFileIconProvider>
+#include <QDesktopServices>
+#include <QLibrary>
+
+#define IS_DIR(ATTR) (((ATTR) & FILE_ATTRIBUTE_DIRECTORY) && (!((ATTR) & FILE_ATTRIBUTE_HIDDEN)))
+#define NO_DOT_OR_DOTDOT(STR) (wcscmp((STR), L".") && wcscmp((STR), L".."))
+
+typedef HANDLE (WINAPI *FindFirstFileExFun)(LPCWSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags);
+
+///////////////////////////////////////////////////////////////////////////////
+// Dummy QFileIconProvider class
+///////////////////////////////////////////////////////////////////////////////
+
+class QFileIconProviderEx : public QFileIconProvider
+{
+public:
+       QFileIconProviderEx();
+       virtual QIcon icon(IconType type) const { return (type == Drive) ? m_driveIcon : m_folderIcon; }
+       virtual QIcon icon(const QFileInfo &info) const;
+       virtual QString type (const QFileInfo &info) const { return info.isDir() ? m_folderType : m_emptyType; }
+
+private:
+       const QIcon m_driveIcon;
+       const QIcon m_cdromIcon;
+       const QIcon m_networkIcon;
+       const QIcon m_floppyIcon;
+       const QIcon m_folderIcon;
+       const QIcon m_homeIcon;
+       const QIcon m_desktopIcon;
+       const QIcon m_musicIcon;
+       const QIcon m_moviesIcon;
+       const QIcon m_picturesIcon;
+       const QIcon m_heartIcon;
+       const QIcon m_emptyIcon;
+       const QString m_folderType;
+       const QString m_emptyType;
+       const QString m_homeDir;
+       const QString m_desktopDir;
+       const QString m_musicDir;
+       const QString m_moviesDir;
+       const QString m_picturesDir;
+       const QString m_installDir;
+};
+
+QFileIconProviderEx::QFileIconProviderEx()
+:
+       m_folderIcon(":/icons/folder.png"),
+       m_driveIcon(":/icons/drive.png"),
+       m_cdromIcon(":/icons/drive_cd.png"),
+       m_networkIcon(":/icons/drive_link.png"),
+       m_floppyIcon(":/icons/drive_disk.png"),
+       m_homeIcon(":/icons/house.png"),
+       m_desktopIcon(":/icons/monitor.png"),
+       m_musicIcon(":/icons/music.png"),
+       m_moviesIcon(":/icons/film.png"),
+       m_picturesIcon(":/icons/picture.png"),
+       m_heartIcon(":/icons/heart.png"),
+       m_homeDir(QDir::fromNativeSeparators(QDesktopServices::storageLocation(QDesktopServices::HomeLocation))),
+       m_desktopDir(QDir::fromNativeSeparators(QDesktopServices::storageLocation(QDesktopServices::DesktopLocation))),
+       m_musicDir(QDir::fromNativeSeparators(QDesktopServices::storageLocation(QDesktopServices::MusicLocation))),
+       m_moviesDir(QDir::fromNativeSeparators(QDesktopServices::storageLocation(QDesktopServices::MoviesLocation))),
+       m_picturesDir(QDir::fromNativeSeparators(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation))),
+       m_installDir(QDir::fromNativeSeparators(qApp->applicationDirPath())),
+       m_folderType("Folder")
+{
+       /* Nothing to do! */
+}
+
+QIcon QFileIconProviderEx::icon(const QFileInfo &info) const
+{
+       if(info.isFile())
+       {
+               return m_emptyIcon;
+       }
+       else if(info.isRoot())
+       {
+               switch(GetDriveType(QWCHAR(QDir::toNativeSeparators(info.absoluteFilePath()))))
+               {
+               case DRIVE_CDROM:
+                       return m_cdromIcon;
+                       break;
+               case DRIVE_REMOVABLE:
+                       return m_floppyIcon;
+                       break;
+               case DRIVE_REMOTE:
+                       return m_networkIcon;
+                       break;
+               default:
+                       return m_driveIcon;
+                       break;
+               }
+       }
+       else
+       {
+               const QString filePath = info.filePath();
+               if(m_homeDir.compare(filePath, Qt::CaseInsensitive) == 0)
+               {
+                       return m_homeIcon;
+               }
+               else if(m_desktopDir.compare(filePath, Qt::CaseInsensitive) == 0)
+               {
+                       return m_desktopIcon;
+               }
+               else if(m_musicDir.compare(filePath, Qt::CaseInsensitive) == 0)
+               {
+                       return m_musicIcon;
+               }
+               else if(m_moviesDir.compare(filePath, Qt::CaseInsensitive) == 0)
+               {
+                       return m_moviesIcon;
+               }
+               else if(m_picturesDir.compare(filePath, Qt::CaseInsensitive) == 0)
+               {
+                       return m_picturesIcon;
+               }
+               else if(m_installDir.compare(filePath, Qt::CaseInsensitive) == 0)
+               {
+                       return m_heartIcon;
+               }
+               else
+               {
+                       return  m_folderIcon;
+               }
+       }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Modified QFileSystemModel class
+///////////////////////////////////////////////////////////////////////////////
 
 QFileSystemModelEx::QFileSystemModelEx()
 :
        QFileSystemModel()
 {
+       this->m_myIconProvider = new QFileIconProviderEx();
+       this->setIconProvider(m_myIconProvider);
        this->setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
+       this->setNameFilterDisables(false);
+}
+
+QFileSystemModelEx::~QFileSystemModelEx()
+{
+       removeAllFromCache();
+       LAMEXP_DELETE(m_myIconProvider);
 }
 
 bool QFileSystemModelEx::hasChildren(const QModelIndex &parent) const
 {
-       bool result = QFileSystemModel::hasChildren(parent);
+       if(parent.isValid())
+       {
+               return hasSubfoldersCached(filePath(parent).toLower()); //return (QDir(QFileSystemModel::filePath(parent)).entryList(QDir::Dirs | QDir::NoDotAndDotDot).count() > 0);
+       }
+       return true;
+}
+
+void QFileSystemModelEx::fetchMore(const QModelIndex &parent)
+{
+       if(parent.isValid())
+       {
+               removeFromCache(filePath(parent).toLower());
+       }
 
-       if(parent.isValid() && result)
+       QFileSystemModel::fetchMore(parent);
+}
+
+QModelIndex QFileSystemModelEx::index(const QString &path, int column) const
+{
+       QFileInfo info(path);
+       if(info.exists() && info.isDir())
        {
-               QFileInfo fileInfo = QFileSystemModel::fileInfo(parent);
-               if(fileInfo.isDir())
+               QString fullPath = QDir::fromNativeSeparators(info.canonicalFilePath());
+               QStringList parts = fullPath.split('/', QString::SkipEmptyParts);
+               for(int i = 2; i <= parts.count(); i++)
                {
-                       result = (QDir(fileInfo.absoluteFilePath()).entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot).count() > 0);
+                       QFileInfo currentPath(((QStringList) parts.mid(0, i)).join("/"));
+                       if((!currentPath.exists()) || (!currentPath.isDir()) || currentPath.isHidden())
+                       {
+                               return QModelIndex();
+                       }
                }
+               QModelIndex index = QFileSystemModel::index(fullPath, column);
+               if(index.isValid())
+               {
+                       QModelIndex temp = index;
+                       while(temp.isValid())
+                       {
+                               removeFromCache(filePath(temp).toLower());
+                               temp = temp.parent();
+                       }
+                       return index;
+               }
+       }
+       return QModelIndex();
+}
+
+void QFileSystemModelEx::flushCache(void)
+{
+       removeAllFromCache();
+}
+
+/* ------------------------ */
+/*  STATIC FUNCTIONS BELOW  */
+/* ------------------------ */
+
+QHash<const QString, bool> QFileSystemModelEx::s_hasSubfolderCache;
+QMutex QFileSystemModelEx::s_hasSubfolderMutex;
+
+void *QFileSystemModelEx::FindFirstFileExPtr = NULL;
+bool QFileSystemModelEx::FindFirstFileExInitialized = false;
+bool QFileSystemModelEx::FindFirstFileExInfoBasicOK = false;
+
+bool QFileSystemModelEx::hasSubfoldersCached(const QString &path)
+{
+       QMutexLocker lock(&s_hasSubfolderMutex);
+
+       if(s_hasSubfolderCache.contains(path))
+       {
+               return s_hasSubfolderCache.value(path);
        }
        
-       return result;
+       bool bChildren = hasSubfolders(path);
+       s_hasSubfolderCache.insert(path, bChildren);
+       return bChildren;
+}
+
+void QFileSystemModelEx::removeFromCache(const QString &path)
+{
+       QMutexLocker lock(&s_hasSubfolderMutex);
+       s_hasSubfolderCache.remove(path);
+}
+
+void QFileSystemModelEx::removeAllFromCache(void)
+{
+       QMutexLocker lock(&s_hasSubfolderMutex);
+       s_hasSubfolderCache.clear();
+}
+
+bool QFileSystemModelEx::hasSubfolders(const QString &path)
+{
+       if(!FindFirstFileExInitialized)
+       {
+               QLibrary kernel32Lib("kernel32.dll");
+               if(kernel32Lib.load())
+               {
+                       FindFirstFileExPtr = kernel32Lib.resolve("FindFirstFileExW");
+                       const lamexp_os_version_t *osVersionNo = lamexp_get_os_version();
+                       FindFirstFileExInfoBasicOK = LAMEXP_MIN_OS_VER(osVersionNo, 6, 1);
+               }
+               FindFirstFileExInitialized = true;
+       }
+
+       WIN32_FIND_DATAW findData;
+       bool bChildren = false;
+
+       HANDLE h = (FindFirstFileExPtr)
+               ? reinterpret_cast<FindFirstFileExFun>(FindFirstFileExPtr)(QWCHAR(QDir::toNativeSeparators(path + "/*")), (FindFirstFileExInfoBasicOK ? FindExInfoBasic : FindExInfoStandard), &findData, FindExSearchLimitToDirectories, NULL, 0)
+               : FindFirstFileW(QWCHAR(QDir::toNativeSeparators(path + "/*")), &findData);
+
+       if(h != INVALID_HANDLE_VALUE)
+       {
+               if(NO_DOT_OR_DOTDOT(findData.cFileName))
+               {
+                       bChildren = IS_DIR(findData.dwFileAttributes);
+               }
+               while((!bChildren) && FindNextFile(h, &findData))
+               {
+                       if(NO_DOT_OR_DOTDOT(findData.cFileName))
+                       {
+                               bChildren = IS_DIR(findData.dwFileAttributes);
+                       }
+               }
+               FindClose(h);
+       }
+       else
+       {
+               DWORD err = GetLastError();
+               if((err == ERROR_NOT_SUPPORTED) || (err == ERROR_INVALID_PARAMETER))
+               {
+                       qWarning("%s failed with error code #%u", FindFirstFileExPtr ? "FindFirstFileEx" : "FindFirstFile", err);
+               }
+       }
+
+       return bChildren;
 }