2 #include "preferences.h"
\r
3 #include "thumbnailworker.h"
\r
5 #include "foldermodel.h"
\r
7 #include <QApplication>
\r
13 FolderModel* FolderModel::m_activeModel = NULL;
\r
15 ///////////////////////////////////////////////////////////////////////////////
\r
16 /// \brief FolderModel::FolderModel
\r
17 /// \param parent 親オブジェクト
\r
21 FolderModel::FolderModel(QObject *parent) :
\r
22 QAbstractTableModel(parent),
\r
32 m_lastModifiedCache(),
\r
33 m_pixmapCacheMutex(),
\r
37 // サムネイル生成用スレッドを初期化する
\r
38 QThread *thread = new QThread();
\r
39 m_worker = new ThumbnailWorker();
\r
40 m_worker->moveToThread(thread);
\r
41 connect(m_worker, SIGNAL(resultReady(QString,QPixmap)), this, SLOT(thumbnail_Ready(QString,QPixmap)));
\r
42 connect(m_worker, SIGNAL(finished()), thread, SLOT(quit()));
\r
43 connect(thread, SIGNAL(started()), m_worker, SLOT(doWork()));
\r
46 connect(&m_fsWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(fsWatcher_directoryChanged(QString)));
\r
49 ///////////////////////////////////////////////////////////////////////////////
\r
50 /// \brief FolderModel::~FolderModel
\r
54 FolderModel::~FolderModel()
\r
57 m_worker->thread()->quit();
\r
58 m_worker->thread()->wait();
\r
61 ///////////////////////////////////////////////////////////////////////////////
\r
62 /// \brief FolderModel::clearPixmapCache
\r
64 /// サムネイルキャッシュをクリアしたように見せかけます。
\r
66 void FolderModel::clearPixmapCache()
\r
69 // m_pixmapCacheMutex.lock();
\r
70 // m_pixmapCache.clear();
\r
71 // m_pixmapCacheMutex.unlock();
\r
75 ///////////////////////////////////////////////////////////////////////////////
\r
76 /// \brief FolderModel::fileIcon
\r
77 /// \param index アイテムのインデックス
\r
78 /// \return アイコンを返します。
\r
80 QIcon FolderModel::fileIcon(const QModelIndex &index) const
\r
82 if (fileName(index) == "..") {
\r
83 return QIcon("://images/Up.png");
\r
85 return m_IconProvider.icon(fileInfo(index));
\r
88 ///////////////////////////////////////////////////////////////////////////////
\r
89 /// \brief FolderModel::isMarked
\r
90 /// \param index アイテムのインデックス
\r
91 /// \return マークされていればtrueを返します。
\r
93 bool FolderModel::isMarked(const QModelIndex &index) const
\r
95 CheckContainer::const_iterator it = m_checkStates.find(fileName(index));
\r
96 if (it != m_checkStates.end()) {
\r
97 return *it == Qt::Checked;
\r
102 ///////////////////////////////////////////////////////////////////////////////
\r
103 /// \brief FolderModel::markedItems
\r
104 /// \return マークされているアイテムのリストを返します。
\r
106 QFileInfoList FolderModel::markedItems() const
\r
108 QFileInfoList list;
\r
109 for (int n = 0; n < rowCount(); ++n) {
\r
110 QModelIndex index = this->index(n, 0);
\r
111 if (isMarked(index)) {
\r
112 list << fileInfo(index);
\r
119 ///////////////////////////////////////////////////////////////////////////////
\r
120 /// \brief FolderModel::mkdir
\r
121 /// \param name 作成するフォルダ名
\r
122 /// \return 作成したフォルダのインデックス
\r
126 QModelIndex FolderModel::mkdir(const QString &name)
\r
128 qDebug() << "FolderModel::mkdir()" << name;
\r
130 if (!m_dir.mkdir(name)) {
\r
131 return QModelIndex();
\r
136 for (int n = 0; n < rowCount(); ++n) {
\r
137 if (m_fileInfoList[n].fileName() == name) {
\r
138 return index(n, 0);
\r
142 return QModelIndex();
\r
145 ///////////////////////////////////////////////////////////////////////////////
\r
146 /// \brief FolderModel::pixmap
\r
147 /// \param index アイテムのインデックス
\r
148 /// \param size 要求サイズ
\r
149 /// \return 画像またはアイコンを返します。
\r
151 QPixmap FolderModel::pixmap(const QModelIndex &index, const QSize &size) const
\r
154 const_cast<FolderModel*>(this)->m_pixmapCacheMutex.lock();
\r
155 if (m_pixmapCache.find(filePath(index)) != m_pixmapCache.end()) {
\r
156 pixmap = m_pixmapCache[filePath(index)];
\r
158 const_cast<FolderModel*>(this)->m_pixmapCacheMutex.unlock();
\r
160 if (!pixmap.isNull()) {
\r
161 double scaleX = 1.0 * size.width() / pixmap.width();
\r
162 double scaleY = 1.0 * size.height() / pixmap.height();
\r
163 double scaleFactor = qMin(scaleX, scaleY);
\r
164 if (scaleFactor > 1) {
\r
167 return pixmap.scaled(pixmap.size() * scaleFactor,
\r
168 Qt::IgnoreAspectRatio,
\r
169 Qt::SmoothTransformation);
\r
173 return fileIcon(index).pixmap(32, 32);
\r
176 ///////////////////////////////////////////////////////////////////////////////
\r
177 /// \brief FolderModel::search
\r
178 /// \param value 検索する文字列
\r
179 /// \param start 開始位置
\r
180 /// \param step ステップ数
\r
181 /// \return 見つかったアイテムのインデックスを返します。
\r
183 QModelIndex FolderModel::search(const QString &value, const QModelIndex &start, int step)
\r
185 qDebug() << "FolderModel::search()" << value << start << step;
\r
187 const QString searchText = value.toLower();
\r
188 for (int n = start.row() + step; 0 <= n && n < rowCount(); n += step) {
\r
189 if (m_fileInfoList[n].fileName().toLower().indexOf(searchText) != -1) {
\r
190 return index(n, 0);
\r
194 return QModelIndex();
\r
197 ///////////////////////////////////////////////////////////////////////////////
\r
198 /// \brief FolderModel::setHistoryAt
\r
199 /// \param path 設定するパス
\r
201 /// 指定したパスに履歴を移動します。
\r
203 void FolderModel::setHistoryAt(const QString &path)
\r
205 qDebug() << "FolderModel::setHistoryAt()" << path;
\r
207 for (int n = 0; n < m_history.size(); ++n) {
\r
208 if (m_history[n] == path) {
\r
210 setRootPath(path, false);
\r
216 ///////////////////////////////////////////////////////////////////////////////
\r
217 /// \brief FolderModel::setRootPath
\r
218 /// \param path 設定するパス
\r
219 /// \param addHistory 履歴に追加する場合はtrue
\r
223 void FolderModel::setRootPath(const QString &path, bool addHistory)
\r
225 qDebug() << "FolderModel::setRootPath()" << path;
\r
231 if (!QFileInfo::exists(path)) {
\r
232 throw tr("フォルダが存在しないか、利用できません:%1").arg(path);
\r
236 dir.setFilter(m_dir.filter());
\r
237 dir.setNameFilters(m_dir.nameFilters());
\r
238 dir.setSorting(m_dir.sorting());
\r
240 QFileInfoList list = dir.entryInfoList();
\r
241 if (list.isEmpty()) {
\r
242 throw tr("ファイルリストを取得できません:%1").arg(path);
\r
245 m_fileInfoList.clear();
\r
246 if (m_dir.absolutePath() != dir.absolutePath()) {
\r
247 m_fsWatcher.removePath(m_dir.absolutePath());
\r
248 m_fsWatcher.addPath(dir.absolutePath());
\r
249 m_checkStates.clear();
\r
250 m_dir.setPath(dir.absolutePath());
\r
252 m_history.resize(m_historyPos + 1);
\r
253 m_history << m_dir.absolutePath();
\r
254 m_historyPos = m_history.size() - 1;
\r
256 m_worker->clearPath();
\r
257 m_pixmapCacheMutex.lock();
\r
258 m_pixmapCache.clear();
\r
259 m_pixmapCacheMutex.unlock();
\r
260 m_lastModifiedCache.clear();
\r
263 foreach (const QFileInfo &fi, list) {
\r
264 if (fi.fileName() == "..") {
\r
265 if (!m_dir.isRoot()) {
\r
266 m_fileInfoList.push_front(fi);
\r
270 else if (!(filter() & QDir::System) &&
\r
271 Win32::hasSystemAttribute(fi.absoluteFilePath()))
\r
276 m_fileInfoList << fi;
\r
277 if (m_checkStates.find(fi.fileName()) == m_checkStates.end()) {
\r
278 m_checkStates[fi.fileName()] = Qt::Unchecked;
\r
280 if (m_lastModifiedCache.find(fi.fileName()) == m_lastModifiedCache.end() ||
\r
281 m_lastModifiedCache[fi.fileName()] != fi.lastModified())
\r
283 m_lastModifiedCache[fi.fileName()] = fi.lastModified();
\r
284 m_worker->addPath(fi.absoluteFilePath());
\r
288 catch (const QString &s) {
\r
295 ///////////////////////////////////////////////////////////////////////////////
\r
296 /// \brief FolderModel::touch
\r
297 /// \param name 作成するファイル名
\r
298 /// \return 作成したファイルのインデックス
\r
302 QModelIndex FolderModel::touch(const QString &name)
\r
304 QFile file(m_dir.absoluteFilePath(name));
\r
305 if (!file.open(QIODevice::WriteOnly)) {
\r
306 return QModelIndex();
\r
312 for (int n = 0; n < rowCount(); ++n) {
\r
313 if (m_fileInfoList[n].fileName() == name) {
\r
314 return index(n, 0);
\r
318 return QModelIndex();
\r
321 ///////////////////////////////////////////////////////////////////////////////
\r
322 /// \brief FolderModel::updateAppearance
\r
326 void FolderModel::updateAppearance(const Preferences &prefs)
\r
328 qDebug() << "FolderModel::updateAppearance()";
\r
330 m_font = prefs.getFolderViewFont();
\r
331 m_Palette.setColor(QPalette::Base, prefs.folderViewBgColor(isActive()));
\r
332 m_Palette.setColor(QPalette::Text, prefs.folderViewFgColor(isActive()));
\r
333 m_Palette.setColor(QPalette::Highlight, prefs.folderViewMarkedBgColor(isActive()));
\r
334 m_Palette.setColor(QPalette::HighlightedText, prefs.folderViewMarkedFgColor(isActive()));
\r
335 m_Palette.setColor(QPalette::Dark, prefs.folderViewHiddenColor(isActive()));
\r
336 m_Palette.setColor(QPalette::Light, prefs.folderViewReadOnlyColor(isActive()));
\r
337 m_Palette.setColor(QPalette::Mid, prefs.folderViewSystemColor(isActive()));
\r
340 ///////////////////////////////////////////////////////////////////////////////
\r
341 /// \brief FolderModel::activeModel
\r
342 /// \return アクティブなモデルを返します。
\r
344 FolderModel *FolderModel::activeModel()
\r
346 return m_activeModel;
\r
349 ///////////////////////////////////////////////////////////////////////////////
\r
350 /// \brief FolderModel::onCdHome
\r
354 void FolderModel::onCdHome()
\r
356 setRootPath(QDir::homePath());
\r
359 ///////////////////////////////////////////////////////////////////////////////
\r
360 /// \brief FolderModel::onCdRoot
\r
364 void FolderModel::onCdRoot()
\r
366 setRootPath(QDir::rootPath());
\r
369 ///////////////////////////////////////////////////////////////////////////////
\r
370 /// \brief FolderModel::onCdUp
\r
374 void FolderModel::onCdUp()
\r
376 if (!m_dir.isRoot()) {
\r
379 setRootPath(dir.absolutePath());
\r
383 ///////////////////////////////////////////////////////////////////////////////
\r
384 /// \brief FolderModel::onHistoryBack
\r
388 void FolderModel::onHistoryBack()
\r
390 if (m_historyPos > 0) {
\r
391 setRootPath(m_history[--m_historyPos], false);
\r
395 ///////////////////////////////////////////////////////////////////////////////
\r
396 /// \brief FolderModel::onHistoryForward
\r
400 void FolderModel::onHistoryForward()
\r
402 if (m_historyPos < m_history.size() - 1) {
\r
403 setRootPath(m_history[++m_historyPos], false);
\r
407 ///////////////////////////////////////////////////////////////////////////////
\r
408 /// \brief FolderModel::onMarkAll
\r
412 void FolderModel::onMarkAll()
\r
414 CheckContainer::iterator it;
\r
415 for (it = m_checkStates.begin(); it != m_checkStates.end(); ++it) {
\r
416 it.value() = Qt::Checked;
\r
418 emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
\r
421 ///////////////////////////////////////////////////////////////////////////////
\r
422 /// \brief FolderModel::onMarkAllFiles
\r
424 /// 全てのフォルダをマークOFF、ファイルをマークONにします。
\r
426 void FolderModel::onMarkAllFiles()
\r
428 foreach (const QFileInfo &fi, m_fileInfoList) {
\r
429 if (fi.fileName() == "..") {
\r
433 m_checkStates[fi.fileName()] = Qt::Unchecked;
\r
436 m_checkStates[fi.fileName()] = Qt::Checked;
\r
439 emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
\r
442 ///////////////////////////////////////////////////////////////////////////////
\r
443 /// \brief FolderModel::onMarkAllOff
\r
445 /// 全てのマークをOFFにします。
\r
447 void FolderModel::onMarkAllOff()
\r
449 CheckContainer::iterator it;
\r
450 for (it = m_checkStates.begin(); it != m_checkStates.end(); ++it) {
\r
451 it.value() = Qt::Unchecked;
\r
453 emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
\r
456 ///////////////////////////////////////////////////////////////////////////////
\r
457 /// \brief FolderModel::onMarkInvert
\r
461 void FolderModel::onMarkInvert()
\r
463 CheckContainer::iterator it;
\r
464 for (it = m_checkStates.begin(); it != m_checkStates.end(); ++it) {
\r
465 it.value() = (it.value() == Qt::Checked) ? Qt::Unchecked : Qt::Checked;
\r
467 emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
\r
470 ///////////////////////////////////////////////////////////////////////////////
\r
471 /// \brief FolderModel::thumbnail_Ready
\r
472 /// \param path ファイルパス
\r
473 /// \param pixmap サムネイル画像
\r
475 /// サムネイルの生成終了時の処理を行います。
\r
477 void FolderModel::thumbnail_Ready(const QString &path, const QPixmap &pixmap)
\r
479 QFileInfo fi(path);
\r
480 if (fi.absolutePath() == m_dir.absolutePath()) {
\r
481 m_pixmapCacheMutex.lock();
\r
482 m_pixmapCache[path] = pixmap;
\r
483 m_pixmapCacheMutex.unlock();
\r
485 QModelIndex index = search(fi.fileName());
\r
486 if (index.isValid()) {
\r
487 emit dataChanged(index, index);
\r
492 int FolderModel::rowCount(const QModelIndex &parent) const
\r
495 return m_fileInfoList.size();
\r
498 int FolderModel::columnCount(const QModelIndex &parent) const
\r
501 return ColumnCount;
\r
504 QVariant FolderModel::data(const QModelIndex &index, int role) const
\r
506 if (!index.isValid()) {
\r
511 case Qt::DisplayRole:
\r
512 switch (index.column()) {
\r
514 if (isDir(index) || isDotFile(index)) {
\r
515 return fileName(index);
\r
517 return fileInfo(index).completeBaseName();
\r
520 if (isDir(index) || isDotFile(index)) {
\r
523 return fileInfo(index).suffix();
\r
526 if (isDir(index)) {
\r
527 return QString("<DIR>");
\r
529 return FileSizeToString(fileInfo(index).size());
\r
531 case LastModified: // 更新日時
\r
532 return fileInfo(index).lastModified().toString("yy/MM/dd hh:mm");
\r
536 case Qt::DecorationRole:
\r
537 if (index.column() == Name) {
\r
538 return fileIcon(index);
\r
545 case Qt::TextAlignmentRole:
\r
546 switch (index.column()) {
\r
549 return Qt::AlignRight + Qt::AlignVCenter;
\r
551 return Qt::AlignLeft + Qt::AlignVCenter;
\r
553 case Qt::BackgroundRole:
\r
554 if (isMarked(index)) {
\r
559 case Qt::ForegroundRole:
\r
560 if (isMarked(index)) {
\r
561 return markedText();
\r
563 if (fileName(index) != ".." && Win32::hasSystemAttribute(filePath(index))) {
\r
566 if (fileName(index) != ".." && fileInfo(index).isHidden()) {
\r
569 if (fileName(index) != ".." && !fileInfo(index).isWritable()) {
\r
574 case Qt::CheckStateRole:
\r
575 if (index.column() == Name && fileName(index) != "..") {
\r
576 return isMarked(index) ? Qt::Checked : Qt::Unchecked;
\r
584 QVariant FolderModel::headerData(int section, Qt::Orientation orientation, int role) const
\r
586 if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
\r
588 case Name: return tr("名前");
\r
589 case Extension: return tr("拡張子");
\r
590 case Size: return tr("サイズ");
\r
591 case LastModified: return tr("更新日時");
\r
597 Qt::ItemFlags FolderModel::flags(const QModelIndex &index) const
\r
599 Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
\r
601 if (!index.isValid()) {
\r
602 return flags | Qt::ItemIsDropEnabled;
\r
605 if (m_fileInfoList[index.row()].fileName() != "..") {
\r
606 if (index.column() == Name) {
\r
607 flags |= Qt::ItemIsUserCheckable;
\r
609 flags |= Qt::ItemIsDropEnabled;
\r
614 bool FolderModel::setData(const QModelIndex &index, const QVariant &value, int role)
\r
616 qDebug() << "FolderModel::setData()" << index;
\r
618 if (!index.isValid()) {
\r
623 case Qt::CheckStateRole:
\r
624 if (index.column() == Name && fileName(index) != "..") {
\r
625 m_checkStates[fileName(index)] = value.toInt();
\r
626 emit dataChanged(this->index(index.row(), 0),
\r
627 this->index(index.row(), ColumnCount - 1));
\r
636 Qt::DropActions FolderModel::supportedDropActions() const
\r
638 qDebug() << "FolderModel::supportedDropActions()";
\r
640 return Qt::CopyAction;
\r
643 QStringList FolderModel::mimeTypes() const
\r
645 qDebug() << "FolderModel::mimeTypes()";
\r
649 types << "text/uri-list";
\r