2 #include "preferences.h"
\r
3 #include "thumbnailworker.h"
\r
5 #include "foldermodel.h"
\r
9 #include <QApplication>
\r
10 #include <QSettings>
\r
14 FolderModel* FolderModel::m_activeModel = NULL;
\r
16 ///////////////////////////////////////////////////////////////////////////////
\r
17 /// \brief FolderModel::FolderModel
\r
18 /// \param parent 親オブジェクト
\r
22 FolderModel::FolderModel(QObject *parent) :
\r
23 QAbstractTableModel(parent),
\r
32 m_pixmapCacheMutex()
\r
34 connect(&m_fsWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(fsWatcher_directoryChanged(QString)));
\r
37 ///////////////////////////////////////////////////////////////////////////////
\r
38 /// \brief FolderModel::clearPixmapCache
\r
40 /// サムネイルキャッシュをクリアします。
\r
42 void FolderModel::clearPixmapCache()
\r
45 m_pixmapCacheMutex.lock();
\r
46 m_pixmapCache.clear();
\r
47 m_pixmapCacheMutex.unlock();
\r
51 ///////////////////////////////////////////////////////////////////////////////
\r
52 /// \brief FolderModel::fileIcon
\r
53 /// \param index アイテムのインデックス
\r
54 /// \return アイコンを返します。
\r
56 QIcon FolderModel::fileIcon(const QModelIndex &index) const
\r
58 if (fileName(index) == "..") {
\r
59 return QIcon("://images/Up.png");
\r
61 return m_IconProvider.icon(fileInfo(index));
\r
64 ///////////////////////////////////////////////////////////////////////////////
\r
65 /// \brief FolderModel::isMarked
\r
66 /// \param index アイテムのインデックス
\r
67 /// \return マークされていればtrueを返します。
\r
69 bool FolderModel::isMarked(const QModelIndex &index) const
\r
71 CheckContainer::const_iterator it = m_checkStates.find(fileName(index));
\r
72 if (it != m_checkStates.end()) {
\r
73 return *it == Qt::Checked;
\r
78 ///////////////////////////////////////////////////////////////////////////////
\r
79 /// \brief FolderModel::markedItems
\r
80 /// \return マークされているアイテムのリストを返します。
\r
82 QFileInfoList FolderModel::markedItems() const
\r
85 for (int n = 0; n < rowCount(); ++n) {
\r
86 QModelIndex index = this->index(n, 0);
\r
87 if (isMarked(index)) {
\r
88 list << fileInfo(index);
\r
95 ///////////////////////////////////////////////////////////////////////////////
\r
96 /// \brief FolderModel::mkdir
\r
97 /// \param name 作成するフォルダ名
\r
98 /// \return 作成したフォルダのインデックス
\r
102 QModelIndex FolderModel::mkdir(const QString &name)
\r
104 qDebug() << "FolderModel::mkdir()" << name;
\r
106 if (!m_dir.mkdir(name)) {
\r
107 return QModelIndex();
\r
112 for (int n = 0; n < rowCount(); ++n) {
\r
113 if (m_fileInfoList[n].fileName() == name) {
\r
114 return index(n, 0);
\r
118 return QModelIndex();
\r
121 ///////////////////////////////////////////////////////////////////////////////
\r
122 /// \brief FolderModel::pixmap
\r
123 /// \param index アイテムのインデックス
\r
124 /// \param size 要求サイズ
\r
125 /// \return 画像またはアイコンを返します。
\r
127 QPixmap FolderModel::pixmap(const QModelIndex &index, const QSize &size) const
\r
130 const_cast<FolderModel*>(this)->m_pixmapCacheMutex.lock();
\r
131 if (m_pixmapCache.find(filePath(index)) != m_pixmapCache.end()) {
\r
132 pixmap = m_pixmapCache[filePath(index)];
\r
134 const_cast<FolderModel*>(this)->m_pixmapCacheMutex.unlock();
\r
136 if (!pixmap.isNull()) {
\r
140 // 別スレッドでサムネイルを生成する
\r
141 QThread *thread = new QThread();
\r
142 ThumbnailWorker *worker = new ThumbnailWorker();
\r
143 worker->setPath(filePath(index));
\r
144 worker->setSize(size);
\r
145 worker->moveToThread(thread);
\r
146 connect(worker, SIGNAL(resultReady(QString,QPixmap)), this, SLOT(thumbnail_Ready(QString,QPixmap)));
\r
147 connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
\r
148 connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
\r
149 connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
\r
150 connect(thread, SIGNAL(started()), worker, SLOT(doWork()));
\r
154 return fileIcon(index).pixmap(32, 32);
\r
157 ///////////////////////////////////////////////////////////////////////////////
\r
158 /// \brief FolderModel::search
\r
159 /// \param value 検索する文字列
\r
160 /// \param start 開始位置
\r
161 /// \param step ステップ数
\r
162 /// \return 見つかったアイテムのインデックスを返します。
\r
164 QModelIndex FolderModel::search(const QString &value, const QModelIndex &start, int step)
\r
166 qDebug() << "FolderModel::search()" << value << start << step;
\r
168 const QString searchText = value.toLower();
\r
169 for (int n = start.row() + step; 0 <= n && n < rowCount(); n += step) {
\r
170 if (m_fileInfoList[n].fileName().toLower().indexOf(searchText) != -1) {
\r
171 return index(n, 0);
\r
175 return QModelIndex();
\r
178 ///////////////////////////////////////////////////////////////////////////////
\r
179 /// \brief FolderModel::setHistoryAt
\r
180 /// \param path 設定するパス
\r
182 /// 指定したパスに履歴を移動します。
\r
184 void FolderModel::setHistoryAt(const QString &path)
\r
186 qDebug() << "FolderModel::setHistoryAt()" << path;
\r
188 for (int n = 0; n < m_history.size(); ++n) {
\r
189 if (m_history[n] == path) {
\r
191 setRootPath(path, false);
\r
197 ///////////////////////////////////////////////////////////////////////////////
\r
198 /// \brief FolderModel::setRootPath
\r
199 /// \param path 設定するパス
\r
200 /// \param addHistory 履歴に追加する場合はtrue
\r
204 void FolderModel::setRootPath(const QString &path, bool addHistory)
\r
206 qDebug() << "FolderModel::setRootPath()" << path;
\r
212 if (!QFileInfo::exists(path)) {
\r
213 throw tr("フォルダが存在しないか、利用できません:%1").arg(path);
\r
217 dir.setFilter(m_dir.filter());
\r
218 dir.setNameFilters(m_dir.nameFilters());
\r
219 dir.setSorting(m_dir.sorting());
\r
221 QFileInfoList list = dir.entryInfoList();
\r
222 if (list.isEmpty()) {
\r
223 throw tr("ファイルリストを取得できません:%1").arg(path);
\r
226 m_fileInfoList.clear();
\r
227 if (m_dir.absolutePath() != dir.absolutePath()) {
\r
228 m_fsWatcher.removePath(m_dir.absolutePath());
\r
229 m_fsWatcher.addPath(dir.absolutePath());
\r
230 m_checkStates.clear();
\r
231 m_dir.setPath(dir.absolutePath());
\r
233 m_history.resize(m_historyPos + 1);
\r
234 m_history << m_dir.absolutePath();
\r
235 m_historyPos = m_history.size() - 1;
\r
237 m_pixmapCacheMutex.lock();
\r
238 m_pixmapCache.clear();
\r
239 m_pixmapCacheMutex.unlock();
\r
242 foreach (const QFileInfo &fi, list) {
\r
243 if (fi.fileName() == "..") {
\r
244 if (!m_dir.isRoot()) {
\r
245 m_fileInfoList.push_front(fi);
\r
249 else if (!(filter() & QDir::System) &&
\r
250 Win32::hasSystemAttribute(fi.absoluteFilePath()))
\r
255 m_fileInfoList << fi;
\r
256 if (m_checkStates.find(fi.fileName()) == m_checkStates.end()) {
\r
257 m_checkStates[fi.fileName()] = Qt::Unchecked;
\r
261 catch (const QString &s) {
\r
268 ///////////////////////////////////////////////////////////////////////////////
\r
269 /// \brief FolderModel::touch
\r
270 /// \param name 作成するファイル名
\r
271 /// \return 作成したファイルのインデックス
\r
275 QModelIndex FolderModel::touch(const QString &name)
\r
277 QFile file(m_dir.absoluteFilePath(name));
\r
278 if (!file.open(QIODevice::WriteOnly)) {
\r
279 return QModelIndex();
\r
285 for (int n = 0; n < rowCount(); ++n) {
\r
286 if (m_fileInfoList[n].fileName() == name) {
\r
287 return index(n, 0);
\r
291 return QModelIndex();
\r
294 ///////////////////////////////////////////////////////////////////////////////
\r
295 /// \brief FolderModel::activeModel
\r
296 /// \return アクティブなモデルを返します。
\r
298 FolderModel *FolderModel::activeModel()
\r
300 return m_activeModel;
\r
303 ///////////////////////////////////////////////////////////////////////////////
\r
304 /// \brief FolderModel::onCdHome
\r
308 void FolderModel::onCdHome()
\r
310 setRootPath(QDir::homePath());
\r
313 ///////////////////////////////////////////////////////////////////////////////
\r
314 /// \brief FolderModel::onCdRoot
\r
318 void FolderModel::onCdRoot()
\r
320 setRootPath(QDir::rootPath());
\r
323 ///////////////////////////////////////////////////////////////////////////////
\r
324 /// \brief FolderModel::onCdUp
\r
328 void FolderModel::onCdUp()
\r
330 if (!m_dir.isRoot()) {
\r
333 setRootPath(dir.absolutePath());
\r
337 ///////////////////////////////////////////////////////////////////////////////
\r
338 /// \brief FolderModel::onHistoryBack
\r
342 void FolderModel::onHistoryBack()
\r
344 if (m_historyPos > 0) {
\r
345 setRootPath(m_history[--m_historyPos], false);
\r
349 ///////////////////////////////////////////////////////////////////////////////
\r
350 /// \brief FolderModel::onHistoryForward
\r
354 void FolderModel::onHistoryForward()
\r
356 if (m_historyPos < m_history.size() - 1) {
\r
357 setRootPath(m_history[++m_historyPos], false);
\r
361 ///////////////////////////////////////////////////////////////////////////////
\r
362 /// \brief FolderModel::onMarkAll
\r
366 void FolderModel::onMarkAll()
\r
368 CheckContainer::iterator it;
\r
369 for (it = m_checkStates.begin(); it != m_checkStates.end(); ++it) {
\r
370 it.value() = Qt::Checked;
\r
372 emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
\r
375 ///////////////////////////////////////////////////////////////////////////////
\r
376 /// \brief FolderModel::onMarkAllFiles
\r
378 /// 全てのフォルダをマークOFF、ファイルをマークONにします。
\r
380 void FolderModel::onMarkAllFiles()
\r
382 foreach (const QFileInfo &fi, m_fileInfoList) {
\r
383 if (fi.fileName() == "..") {
\r
387 m_checkStates[fi.fileName()] = Qt::Unchecked;
\r
390 m_checkStates[fi.fileName()] = Qt::Checked;
\r
393 emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
\r
396 ///////////////////////////////////////////////////////////////////////////////
\r
397 /// \brief FolderModel::onMarkAllOff
\r
399 /// 全てのマークをOFFにします。
\r
401 void FolderModel::onMarkAllOff()
\r
403 CheckContainer::iterator it;
\r
404 for (it = m_checkStates.begin(); it != m_checkStates.end(); ++it) {
\r
405 it.value() = Qt::Unchecked;
\r
407 emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
\r
410 ///////////////////////////////////////////////////////////////////////////////
\r
411 /// \brief FolderModel::onMarkInvert
\r
415 void FolderModel::onMarkInvert()
\r
417 CheckContainer::iterator it;
\r
418 for (it = m_checkStates.begin(); it != m_checkStates.end(); ++it) {
\r
419 it.value() = (it.value() == Qt::Checked) ? Qt::Unchecked : Qt::Checked;
\r
421 emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
\r
424 ///////////////////////////////////////////////////////////////////////////////
\r
425 /// \brief FolderModel::thumbnail_Ready
\r
426 /// \param path ファイルパス
\r
427 /// \param pixmap サムネイル画像
\r
429 /// サムネイルの生成終了時の処理を行います。
\r
431 void FolderModel::thumbnail_Ready(const QString &path, const QPixmap &pixmap)
\r
433 QFileInfo fi(path);
\r
434 if (fi.absolutePath() == m_dir.absolutePath()) {
\r
435 m_pixmapCacheMutex.lock();
\r
436 m_pixmapCache[path] = pixmap;
\r
437 m_pixmapCacheMutex.unlock();
\r
439 QModelIndex index = search(fi.fileName());
\r
440 if (index.isValid()) {
\r
441 emit dataChanged(index, index);
\r
446 int FolderModel::rowCount(const QModelIndex &parent) const
\r
449 return m_fileInfoList.size();
\r
452 int FolderModel::columnCount(const QModelIndex &parent) const
\r
455 return ColumnCount;
\r
458 QVariant FolderModel::data(const QModelIndex &index, int role) const
\r
460 if (!index.isValid()) {
\r
464 Preferences prefs(const_cast<FolderModel*>(this));
\r
467 case Qt::DisplayRole:
\r
468 switch (index.column()) {
\r
470 if (isDir(index) || isDotFile(index)) {
\r
471 return fileName(index);
\r
473 return fileInfo(index).completeBaseName();
\r
476 if (isDir(index) || isDotFile(index)) {
\r
479 return fileInfo(index).suffix();
\r
482 if (isDir(index)) {
\r
483 return QString("<DIR>");
\r
485 return FileSizeToString(fileInfo(index).size());
\r
487 case LastModified: // 更新日時
\r
488 return fileInfo(index).lastModified().toString("yy/MM/dd hh:mm");
\r
492 case Qt::DecorationRole:
\r
493 if (index.column() == Name) {
\r
494 return fileIcon(index);
\r
499 return prefs.getFolderViewFont();
\r
501 case Qt::TextAlignmentRole:
\r
502 switch (index.column()) {
\r
505 return Qt::AlignRight + Qt::AlignVCenter;
\r
507 return Qt::AlignLeft + Qt::AlignVCenter;
\r
509 case Qt::BackgroundRole:
\r
510 if (isMarked(index)) {
\r
511 return QBrush(prefs.folderViewMarkedBgColor(isActive()));
\r
513 return QBrush(prefs.folderViewBgColor(isActive()));
\r
515 case Qt::ForegroundRole:
\r
516 if (isMarked(index)) {
\r
517 return QBrush(prefs.folderViewMarkedFgColor(isActive()));
\r
519 if (fileName(index) != ".." && Win32::hasSystemAttribute(filePath(index))) {
\r
520 return QBrush(prefs.folderViewSystemColor(isActive()));
\r
522 if (fileName(index) != ".." && fileInfo(index).isHidden()) {
\r
523 return QBrush(prefs.folderViewHiddenColor(isActive()));
\r
525 if (fileName(index) != ".." && !fileInfo(index).isWritable()) {
\r
526 return QBrush(prefs.folderViewReadOnlyColor(isActive()));
\r
528 return QBrush(prefs.folderViewFgColor(isActive()));
\r
530 case Qt::CheckStateRole:
\r
531 if (index.column() == Name && fileName(index) != "..") {
\r
532 return isMarked(index) ? Qt::Checked : Qt::Unchecked;
\r
540 QVariant FolderModel::headerData(int section, Qt::Orientation orientation, int role) const
\r
542 if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
\r
544 case Name: return tr("名前");
\r
545 case Extension: return tr("拡張子");
\r
546 case Size: return tr("サイズ");
\r
547 case LastModified: return tr("更新日時");
\r
553 Qt::ItemFlags FolderModel::flags(const QModelIndex &index) const
\r
555 Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
\r
557 if (!index.isValid()) {
\r
558 return flags | Qt::ItemIsDropEnabled;
\r
561 if (m_fileInfoList[index.row()].fileName() != "..") {
\r
562 if (index.column() == Name) {
\r
563 flags |= Qt::ItemIsUserCheckable;
\r
565 flags |= Qt::ItemIsDropEnabled;
\r
570 bool FolderModel::setData(const QModelIndex &index, const QVariant &value, int role)
\r
572 qDebug() << "FolderModel::setData()" << index;
\r
574 if (!index.isValid()) {
\r
579 case Qt::CheckStateRole:
\r
580 if (index.column() == Name && fileName(index) != "..") {
\r
581 m_checkStates[fileName(index)] = value.toInt();
\r
582 emit dataChanged(this->index(index.row(), 0),
\r
583 this->index(index.row(), ColumnCount - 1));
\r
592 Qt::DropActions FolderModel::supportedDropActions() const
\r
594 qDebug() << "FolderModel::supportedDropActions()";
\r
596 return Qt::CopyAction;
\r
599 QStringList FolderModel::mimeTypes() const
\r
601 qDebug() << "FolderModel::mimeTypes()";
\r
605 types << "text/uri-list";
\r