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 = (scaleX > scaleY) ? scaleY : scaleX;
\r
164 return pixmap.scaled(pixmap.size() * scaleFactor,
\r
165 Qt::IgnoreAspectRatio,
\r
166 Qt::SmoothTransformation);
\r
170 return fileIcon(index).pixmap(32, 32);
\r
173 ///////////////////////////////////////////////////////////////////////////////
\r
174 /// \brief FolderModel::search
\r
175 /// \param value 検索する文字列
\r
176 /// \param start 開始位置
\r
177 /// \param step ステップ数
\r
178 /// \return 見つかったアイテムのインデックスを返します。
\r
180 QModelIndex FolderModel::search(const QString &value, const QModelIndex &start, int step)
\r
182 qDebug() << "FolderModel::search()" << value << start << step;
\r
184 const QString searchText = value.toLower();
\r
185 for (int n = start.row() + step; 0 <= n && n < rowCount(); n += step) {
\r
186 if (m_fileInfoList[n].fileName().toLower().indexOf(searchText) != -1) {
\r
187 return index(n, 0);
\r
191 return QModelIndex();
\r
194 ///////////////////////////////////////////////////////////////////////////////
\r
195 /// \brief FolderModel::setHistoryAt
\r
196 /// \param path 設定するパス
\r
198 /// 指定したパスに履歴を移動します。
\r
200 void FolderModel::setHistoryAt(const QString &path)
\r
202 qDebug() << "FolderModel::setHistoryAt()" << path;
\r
204 for (int n = 0; n < m_history.size(); ++n) {
\r
205 if (m_history[n] == path) {
\r
207 setRootPath(path, false);
\r
213 ///////////////////////////////////////////////////////////////////////////////
\r
214 /// \brief FolderModel::setRootPath
\r
215 /// \param path 設定するパス
\r
216 /// \param addHistory 履歴に追加する場合はtrue
\r
220 void FolderModel::setRootPath(const QString &path, bool addHistory)
\r
222 qDebug() << "FolderModel::setRootPath()" << path;
\r
228 if (!QFileInfo::exists(path)) {
\r
229 throw tr("フォルダが存在しないか、利用できません:%1").arg(path);
\r
233 dir.setFilter(m_dir.filter());
\r
234 dir.setNameFilters(m_dir.nameFilters());
\r
235 dir.setSorting(m_dir.sorting());
\r
237 QFileInfoList list = dir.entryInfoList();
\r
238 if (list.isEmpty()) {
\r
239 throw tr("ファイルリストを取得できません:%1").arg(path);
\r
242 m_fileInfoList.clear();
\r
243 if (m_dir.absolutePath() != dir.absolutePath()) {
\r
244 m_fsWatcher.removePath(m_dir.absolutePath());
\r
245 m_fsWatcher.addPath(dir.absolutePath());
\r
246 m_checkStates.clear();
\r
247 m_dir.setPath(dir.absolutePath());
\r
249 m_history.resize(m_historyPos + 1);
\r
250 m_history << m_dir.absolutePath();
\r
251 m_historyPos = m_history.size() - 1;
\r
253 m_worker->clearPath();
\r
254 m_pixmapCacheMutex.lock();
\r
255 m_pixmapCache.clear();
\r
256 m_pixmapCacheMutex.unlock();
\r
257 m_lastModifiedCache.clear();
\r
260 foreach (const QFileInfo &fi, list) {
\r
261 if (fi.fileName() == "..") {
\r
262 if (!m_dir.isRoot()) {
\r
263 m_fileInfoList.push_front(fi);
\r
267 else if (!(filter() & QDir::System) &&
\r
268 Win32::hasSystemAttribute(fi.absoluteFilePath()))
\r
273 m_fileInfoList << fi;
\r
274 if (m_checkStates.find(fi.fileName()) == m_checkStates.end()) {
\r
275 m_checkStates[fi.fileName()] = Qt::Unchecked;
\r
277 if (m_lastModifiedCache.find(fi.fileName()) == m_lastModifiedCache.end() ||
\r
278 m_lastModifiedCache[fi.fileName()] != fi.lastModified())
\r
280 m_lastModifiedCache[fi.fileName()] = fi.lastModified();
\r
281 m_worker->addPath(fi.absoluteFilePath());
\r
285 catch (const QString &s) {
\r
292 ///////////////////////////////////////////////////////////////////////////////
\r
293 /// \brief FolderModel::touch
\r
294 /// \param name 作成するファイル名
\r
295 /// \return 作成したファイルのインデックス
\r
299 QModelIndex FolderModel::touch(const QString &name)
\r
301 QFile file(m_dir.absoluteFilePath(name));
\r
302 if (!file.open(QIODevice::WriteOnly)) {
\r
303 return QModelIndex();
\r
309 for (int n = 0; n < rowCount(); ++n) {
\r
310 if (m_fileInfoList[n].fileName() == name) {
\r
311 return index(n, 0);
\r
315 return QModelIndex();
\r
318 ///////////////////////////////////////////////////////////////////////////////
\r
319 /// \brief FolderModel::updateAppearance
\r
323 void FolderModel::updateAppearance(const Preferences &prefs)
\r
325 qDebug() << "FolderModel::updateAppearance()";
\r
327 m_font = prefs.getFolderViewFont();
\r
328 m_Palette.setColor(QPalette::Base, prefs.folderViewBgColor(isActive()));
\r
329 m_Palette.setColor(QPalette::Text, prefs.folderViewFgColor(isActive()));
\r
330 m_Palette.setColor(QPalette::Highlight, prefs.folderViewMarkedBgColor(isActive()));
\r
331 m_Palette.setColor(QPalette::HighlightedText, prefs.folderViewMarkedFgColor(isActive()));
\r
332 m_Palette.setColor(QPalette::Dark, prefs.folderViewHiddenColor(isActive()));
\r
333 m_Palette.setColor(QPalette::Light, prefs.folderViewReadOnlyColor(isActive()));
\r
334 m_Palette.setColor(QPalette::Mid, prefs.folderViewSystemColor(isActive()));
\r
337 ///////////////////////////////////////////////////////////////////////////////
\r
338 /// \brief FolderModel::activeModel
\r
339 /// \return アクティブなモデルを返します。
\r
341 FolderModel *FolderModel::activeModel()
\r
343 return m_activeModel;
\r
346 ///////////////////////////////////////////////////////////////////////////////
\r
347 /// \brief FolderModel::onCdHome
\r
351 void FolderModel::onCdHome()
\r
353 setRootPath(QDir::homePath());
\r
356 ///////////////////////////////////////////////////////////////////////////////
\r
357 /// \brief FolderModel::onCdRoot
\r
361 void FolderModel::onCdRoot()
\r
363 setRootPath(QDir::rootPath());
\r
366 ///////////////////////////////////////////////////////////////////////////////
\r
367 /// \brief FolderModel::onCdUp
\r
371 void FolderModel::onCdUp()
\r
373 if (!m_dir.isRoot()) {
\r
376 setRootPath(dir.absolutePath());
\r
380 ///////////////////////////////////////////////////////////////////////////////
\r
381 /// \brief FolderModel::onHistoryBack
\r
385 void FolderModel::onHistoryBack()
\r
387 if (m_historyPos > 0) {
\r
388 setRootPath(m_history[--m_historyPos], false);
\r
392 ///////////////////////////////////////////////////////////////////////////////
\r
393 /// \brief FolderModel::onHistoryForward
\r
397 void FolderModel::onHistoryForward()
\r
399 if (m_historyPos < m_history.size() - 1) {
\r
400 setRootPath(m_history[++m_historyPos], false);
\r
404 ///////////////////////////////////////////////////////////////////////////////
\r
405 /// \brief FolderModel::onMarkAll
\r
409 void FolderModel::onMarkAll()
\r
411 CheckContainer::iterator it;
\r
412 for (it = m_checkStates.begin(); it != m_checkStates.end(); ++it) {
\r
413 it.value() = Qt::Checked;
\r
415 emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
\r
418 ///////////////////////////////////////////////////////////////////////////////
\r
419 /// \brief FolderModel::onMarkAllFiles
\r
421 /// 全てのフォルダをマークOFF、ファイルをマークONにします。
\r
423 void FolderModel::onMarkAllFiles()
\r
425 foreach (const QFileInfo &fi, m_fileInfoList) {
\r
426 if (fi.fileName() == "..") {
\r
430 m_checkStates[fi.fileName()] = Qt::Unchecked;
\r
433 m_checkStates[fi.fileName()] = Qt::Checked;
\r
436 emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
\r
439 ///////////////////////////////////////////////////////////////////////////////
\r
440 /// \brief FolderModel::onMarkAllOff
\r
442 /// 全てのマークをOFFにします。
\r
444 void FolderModel::onMarkAllOff()
\r
446 CheckContainer::iterator it;
\r
447 for (it = m_checkStates.begin(); it != m_checkStates.end(); ++it) {
\r
448 it.value() = Qt::Unchecked;
\r
450 emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
\r
453 ///////////////////////////////////////////////////////////////////////////////
\r
454 /// \brief FolderModel::onMarkInvert
\r
458 void FolderModel::onMarkInvert()
\r
460 CheckContainer::iterator it;
\r
461 for (it = m_checkStates.begin(); it != m_checkStates.end(); ++it) {
\r
462 it.value() = (it.value() == Qt::Checked) ? Qt::Unchecked : Qt::Checked;
\r
464 emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
\r
467 ///////////////////////////////////////////////////////////////////////////////
\r
468 /// \brief FolderModel::thumbnail_Ready
\r
469 /// \param path ファイルパス
\r
470 /// \param pixmap サムネイル画像
\r
472 /// サムネイルの生成終了時の処理を行います。
\r
474 void FolderModel::thumbnail_Ready(const QString &path, const QPixmap &pixmap)
\r
476 QFileInfo fi(path);
\r
477 if (fi.absolutePath() == m_dir.absolutePath()) {
\r
478 m_pixmapCacheMutex.lock();
\r
479 m_pixmapCache[path] = pixmap;
\r
480 m_pixmapCacheMutex.unlock();
\r
482 QModelIndex index = search(fi.fileName());
\r
483 if (index.isValid()) {
\r
484 emit dataChanged(index, index);
\r
489 int FolderModel::rowCount(const QModelIndex &parent) const
\r
492 return m_fileInfoList.size();
\r
495 int FolderModel::columnCount(const QModelIndex &parent) const
\r
498 return ColumnCount;
\r
501 QVariant FolderModel::data(const QModelIndex &index, int role) const
\r
503 if (!index.isValid()) {
\r
508 case Qt::DisplayRole:
\r
509 switch (index.column()) {
\r
511 if (isDir(index) || isDotFile(index)) {
\r
512 return fileName(index);
\r
514 return fileInfo(index).completeBaseName();
\r
517 if (isDir(index) || isDotFile(index)) {
\r
520 return fileInfo(index).suffix();
\r
523 if (isDir(index)) {
\r
524 return QString("<DIR>");
\r
526 return FileSizeToString(fileInfo(index).size());
\r
528 case LastModified: // 更新日時
\r
529 return fileInfo(index).lastModified().toString("yy/MM/dd hh:mm");
\r
533 case Qt::DecorationRole:
\r
534 if (index.column() == Name) {
\r
535 return fileIcon(index);
\r
542 case Qt::TextAlignmentRole:
\r
543 switch (index.column()) {
\r
546 return Qt::AlignRight + Qt::AlignVCenter;
\r
548 return Qt::AlignLeft + Qt::AlignVCenter;
\r
550 case Qt::BackgroundRole:
\r
551 if (isMarked(index)) {
\r
556 case Qt::ForegroundRole:
\r
557 if (isMarked(index)) {
\r
558 return markedText();
\r
560 if (fileName(index) != ".." && Win32::hasSystemAttribute(filePath(index))) {
\r
563 if (fileName(index) != ".." && fileInfo(index).isHidden()) {
\r
566 if (fileName(index) != ".." && !fileInfo(index).isWritable()) {
\r
571 case Qt::CheckStateRole:
\r
572 if (index.column() == Name && fileName(index) != "..") {
\r
573 return isMarked(index) ? Qt::Checked : Qt::Unchecked;
\r
581 QVariant FolderModel::headerData(int section, Qt::Orientation orientation, int role) const
\r
583 if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
\r
585 case Name: return tr("名前");
\r
586 case Extension: return tr("拡張子");
\r
587 case Size: return tr("サイズ");
\r
588 case LastModified: return tr("更新日時");
\r
594 Qt::ItemFlags FolderModel::flags(const QModelIndex &index) const
\r
596 Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
\r
598 if (!index.isValid()) {
\r
599 return flags | Qt::ItemIsDropEnabled;
\r
602 if (m_fileInfoList[index.row()].fileName() != "..") {
\r
603 if (index.column() == Name) {
\r
604 flags |= Qt::ItemIsUserCheckable;
\r
606 flags |= Qt::ItemIsDropEnabled;
\r
611 bool FolderModel::setData(const QModelIndex &index, const QVariant &value, int role)
\r
613 qDebug() << "FolderModel::setData()" << index;
\r
615 if (!index.isValid()) {
\r
620 case Qt::CheckStateRole:
\r
621 if (index.column() == Name && fileName(index) != "..") {
\r
622 m_checkStates[fileName(index)] = value.toInt();
\r
623 emit dataChanged(this->index(index.row(), 0),
\r
624 this->index(index.row(), ColumnCount - 1));
\r
633 Qt::DropActions FolderModel::supportedDropActions() const
\r
635 qDebug() << "FolderModel::supportedDropActions()";
\r
637 return Qt::CopyAction;
\r
640 QStringList FolderModel::mimeTypes() const
\r
642 qDebug() << "FolderModel::mimeTypes()";
\r
646 types << "text/uri-list";
\r