OSDN Git Service

サムネイル生成を別スレッド化
authorMasayuki Satoh <miyabi.satoh@gmail.com>
Sun, 14 Sep 2014 13:29:03 +0000 (22:29 +0900)
committerMasayuki Satoh <miyabi.satoh@gmail.com>
Sun, 14 Sep 2014 13:29:03 +0000 (22:29 +0900)
Gefu.pro
README.md
foldermodel.cpp
foldermodel.h
folderpanel.ui
thumbnaildelegate.cpp
thumbnailworker.cpp [new file with mode: 0644]
thumbnailworker.h [new file with mode: 0644]

index 4476cbb..d62af24 100644 (file)
--- a/Gefu.pro
+++ b/Gefu.pro
@@ -37,7 +37,8 @@ SOURCES += main.cpp\
     global.cpp \
     win32.cpp \
     thumbnailview.cpp \
-    thumbnaildelegate.cpp
+    thumbnaildelegate.cpp \
+    thumbnailworker.cpp
 
 HEADERS  += mainwindow.h \
     renamesingledialog.h \
@@ -65,7 +66,8 @@ HEADERS  += mainwindow.h \
     abstractview.h \
     abstractrenamedialog.h \
     thumbnailview.h \
-    thumbnaildelegate.h
+    thumbnaildelegate.h \
+    thumbnailworker.h
 
 FORMS    += mainwindow.ui \
     renamesingledialog.ui \
index 996dc97..19ecaf7 100644 (file)
--- a/README.md
+++ b/README.md
@@ -9,6 +9,8 @@ Gefu is an Experimental File Utility.
   * 画像ビューアの画質を向上。
   * アイコンを変更。
   * フォルダビューの列ヘッダーを削除。
+  * 単画面モードを実装。
+  * サムネイルモードを実装。
 
 #### 2014/08/31 Ver0.20
   * ウィンドウ自体が非アクティブになったとき、両パネルとも暗くなっていたのを修正。
index 9d881ef..4f7fbec 100644 (file)
@@ -1,5 +1,6 @@
 #include "global.h"\r
 #include "preferences.h"\r
+#include "thumbnailworker.h"\r
 #include "win32.h"\r
 #include "foldermodel.h"\r
 \r
@@ -8,6 +9,7 @@
 #include <QApplication>\r
 #include <QSettings>\r
 #include <QPalette>\r
+#include <QThread>\r
 \r
 FolderModel* FolderModel::m_activeModel = NULL;\r
 \r
@@ -25,7 +27,9 @@ FolderModel::FolderModel(QObject *parent) :
     m_IconProvider(),\r
     m_fsWatcher(this),\r
     m_history(),\r
-    m_historyPos(-1)\r
+    m_historyPos(-1),\r
+    m_pixmapCache(),\r
+    m_pixmapCacheMutex()\r
 {\r
     connect(&m_fsWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(fsWatcher_directoryChanged(QString)));\r
 }\r
@@ -101,6 +105,42 @@ QModelIndex FolderModel::mkdir(const QString &name)
 }\r
 \r
 ///////////////////////////////////////////////////////////////////////////////\r
+/// \brief FolderModel::pixmap\r
+/// \param index    アイテムのインデックス\r
+/// \param size     要求サイズ\r
+/// \return 画像またはアイコンを返します。\r
+///\r
+QPixmap FolderModel::pixmap(const QModelIndex &index, const QSize &size) const\r
+{\r
+    QPixmap pixmap;\r
+    const_cast<FolderModel*>(this)->m_pixmapCacheMutex.lock();\r
+    if (m_pixmapCache.find(filePath(index)) != m_pixmapCache.end()) {\r
+        pixmap = m_pixmapCache[filePath(index)];\r
+    }\r
+    const_cast<FolderModel*>(this)->m_pixmapCacheMutex.unlock();\r
+\r
+    if (!pixmap.isNull()) {\r
+        return pixmap;\r
+    }\r
+\r
+    // 別スレッドでサムネイルを生成する\r
+    QThread *thread = new QThread();\r
+    ThumbnailWorker *worker = new ThumbnailWorker();\r
+    worker->setPath(filePath(index));\r
+    worker->setSize(size);\r
+    worker->moveToThread(thread);\r
+    connect(worker, SIGNAL(resultReady(QString,QPixmap)), this, SLOT(thumbnail_Ready(QString,QPixmap)));\r
+    connect(worker, SIGNAL(finished()), thread, SLOT(quit()));\r
+    connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));\r
+    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));\r
+    connect(thread, SIGNAL(started()), worker, SLOT(doWork()));\r
+    thread->start();\r
+\r
+    // とりあえずアイコンを返す。\r
+    return fileIcon(index).pixmap(32, 32);\r
+}\r
+\r
+///////////////////////////////////////////////////////////////////////////////\r
 /// \brief FolderModel::search\r
 /// \param value    検索する文字列\r
 /// \param start    開始位置\r
@@ -180,6 +220,10 @@ void FolderModel::setRootPath(const QString &path, bool addHistory)
                 m_history << m_dir.absolutePath();\r
                 m_historyPos = m_history.size() - 1;\r
             }\r
+\r
+            m_pixmapCacheMutex.lock();\r
+            m_pixmapCache.clear();\r
+            m_pixmapCacheMutex.unlock();\r
         }\r
 \r
         foreach (const QFileInfo &fi, list) {\r
@@ -364,6 +408,28 @@ void FolderModel::onMarkInvert()
     emit dataChanged(index(0, 0), index(rowCount(), columnCount()));\r
 }\r
 \r
+///////////////////////////////////////////////////////////////////////////////\r
+/// \brief FolderModel::thumbnail_Ready\r
+/// \param path     ファイルパス\r
+/// \param pixmap   サムネイル画像\r
+///\r
+/// サムネイルの生成終了時の処理を行います。\r
+///\r
+void FolderModel::thumbnail_Ready(const QString &path, const QPixmap &pixmap)\r
+{\r
+    QFileInfo fi(path);\r
+    if (fi.absolutePath() == m_dir.absolutePath()) {\r
+        m_pixmapCacheMutex.lock();\r
+        m_pixmapCache[path] = pixmap;\r
+        m_pixmapCacheMutex.unlock();\r
+\r
+        QModelIndex index = search(fi.fileName());\r
+        if (index.isValid()) {\r
+            emit dataChanged(index, index);\r
+        }\r
+    }\r
+}\r
+\r
 int FolderModel::rowCount(const QModelIndex &parent) const\r
 {\r
     Q_UNUSED(parent);\r
index 15b0e56..1e36bbf 100644 (file)
@@ -38,6 +38,7 @@ public:
     QFileInfoList   markedItems() const;\r
     QModelIndex     mkdir(const QString &name);\r
     QStringList     nameFilters() const;\r
+    QPixmap         pixmap(const QModelIndex &index, const QSize &size) const;\r
     QString         rootPath() const;\r
     QModelIndex     search(const QString &value, const QModelIndex &start = QModelIndex(), int step = 1);\r
     void            setActive();\r
@@ -54,6 +55,7 @@ public:
 signals:\r
 \r
 public slots:\r
+    void    fsWatcher_directoryChanged(const QString &path);\r
     void    onCdHome();\r
     void    onCdRoot();\r
     void    onCdUp();\r
@@ -64,14 +66,13 @@ public slots:
     void    onMarkAllOff();\r
     void    onMarkInvert();\r
     void    refresh();\r
-\r
-private slots:\r
-    void    fsWatcher_directoryChanged(const QString &path);\r
+    void    thumbnail_Ready(const QString &path, const QPixmap &pixmap);\r
 \r
 private:\r
     static FolderModel* m_activeModel;\r
 \r
     typedef QMap<QString, int> CheckContainer;\r
+    typedef QMap<QString, QPixmap> PixmapContainer;\r
 \r
     QString             m_error;\r
     QDir                m_dir;\r
@@ -81,6 +82,8 @@ private:
     QFileSystemWatcher  m_fsWatcher;\r
     History             m_history;\r
     int                 m_historyPos;\r
+    PixmapContainer     m_pixmapCache;\r
+    QMutex              m_pixmapCacheMutex;\r
 \r
     bool    isDotFile(const QModelIndex &index) const;\r
     void    setError(const QString &error = QString());\r
index d58c939..4c21d0d 100644 (file)
      <property name="textElideMode">
       <enum>Qt::ElideMiddle</enum>
      </property>
+     <property name="movement">
+      <enum>QListView::Snap</enum>
+     </property>
+     <property name="resizeMode">
+      <enum>QListView::Adjust</enum>
+     </property>
      <property name="viewMode">
       <enum>QListView::IconMode</enum>
      </property>
+     <property name="selectionRectVisible">
+      <bool>false</bool>
+     </property>
     </widget>
    </item>
    <item>
index fcb79c6..17ae692 100644 (file)
@@ -14,6 +14,8 @@ ThumbnailDelegate::ThumbnailDelegate(QObject *parent) :
 
 void ThumbnailDelegate::model_Reset()
 {
+    qDebug() << "ThumbnailDelegate::model_Reset()";
+
     m_pixmapCache.clear();
 }
 
@@ -55,28 +57,11 @@ void ThumbnailDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opt
     // アイコンまたは画像
     QSize size(option.rect.size());
     size -= padding;
-    if (m_pixmapCache.find(model->fileName(index)) == m_pixmapCache.end()) {
-        QPixmap pixmap(model->filePath(index));
-        if (pixmap.isNull()) {
-            pixmap = model->fileIcon(index).pixmap(32, 32);
-        }
-        if (pixmap.width() > size.width() || pixmap.height() > size.height()) {
-            double scaleX = 1.0 * size.width() / pixmap.width();
-            double scaleY = 1.0 * size.height() / pixmap.height();
-            double scaleFactor = (scaleX > scaleY) ? scaleY : scaleX;
-            pixmap = pixmap.scaled(pixmap.size() * scaleFactor,
-                                   Qt::IgnoreAspectRatio,
-                                   Qt::SmoothTransformation);
-        }
-        const_cast<ThumbnailDelegate*>(this)->m_pixmapCache[model->fileName(index)] = pixmap;
-    }
-    const QPixmap &pixmap = m_pixmapCache[model->fileName(index)];
-
+    QPixmap pixmap = model->pixmap(index, size);
     painter->drawPixmap(padding.width() + option.rect.left() + (size.width() - pixmap.width()) / 2,
                         option.rect.top() + (size.height() - pixmap.height()) / 2,
                         pixmap);
 
-    //QStyledItemDelegate::paint(painter, option, index);
 }
 
 QSize ThumbnailDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
@@ -86,5 +71,5 @@ QSize ThumbnailDelegate::sizeHint(const QStyleOptionViewItem &option, const QMod
     const FolderModel *model = static_cast<const FolderModel*>(index.model());
     int pointSize = model->data(index, Qt::FontRole).value<QFont>().pointSize();
 
-    return QSize(pointSize * 10, pointSize * 10 * 11 / 16);
+    return QSize(pointSize * 10, pointSize * 10 * 3 / 4);
 }
diff --git a/thumbnailworker.cpp b/thumbnailworker.cpp
new file mode 100644 (file)
index 0000000..497577b
--- /dev/null
@@ -0,0 +1,28 @@
+#include "thumbnailworker.h"
+
+ThumbnailWorker::ThumbnailWorker(QObject *parent) :
+    QObject(parent)
+{
+}
+
+void ThumbnailWorker::doWork()
+{
+    QPixmap pixmap(m_path);
+    if (pixmap.isNull()) {
+        emit finished();
+        return;
+    }
+
+    if (pixmap.width() > m_size.width() || pixmap.height() > m_size.height()) {
+        double scaleX = 1.0 * m_size.width() / pixmap.width();
+        double scaleY = 1.0 * m_size.height() / pixmap.height();
+        double scaleFactor = (scaleX > scaleY) ? scaleY : scaleX;
+
+        pixmap = pixmap.scaled(pixmap.size() * scaleFactor,
+                               Qt::IgnoreAspectRatio,
+                               Qt::SmoothTransformation);
+    }
+
+    emit resultReady(m_path, pixmap);
+    emit finished();
+}
diff --git a/thumbnailworker.h b/thumbnailworker.h
new file mode 100644 (file)
index 0000000..2f1e813
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef THUMBNAILWORKER_H
+#define THUMBNAILWORKER_H
+
+#include <QObject>
+#include <QSize>
+#include <QPixmap>
+
+class ThumbnailWorker : public QObject
+{
+    Q_OBJECT
+public:
+    explicit ThumbnailWorker(QObject *parent = 0);
+
+    void    setPath(const QString &path) { m_path = path; }
+    void    setSize(const QSize &size) { m_size = size; }
+
+private:
+    QString m_path;
+    QSize m_size;
+
+signals:
+    void    finished();
+    void    resultReady(const QString &path, const QPixmap &pixmap);
+
+public slots:
+    void    doWork();
+};
+
+#endif // THUMBNAILWORKER_H