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 m_worker = new ThumbnailWorker();
\r
39 connect(m_worker, SIGNAL(resultReady(QString,QPixmap)), this, SLOT(thumbnail_Ready(QString,QPixmap)));
\r
42 connect(&m_fsWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(fsWatcher_directoryChanged(QString)));
\r
45 ///////////////////////////////////////////////////////////////////////////////
\r
46 /// \brief FolderModel::~FolderModel
\r
50 FolderModel::~FolderModel()
\r
55 ///////////////////////////////////////////////////////////////////////////////
\r
56 /// \brief FolderModel::clearPixmapCache
\r
58 /// サムネイルキャッシュをクリアしたように見せかけます。
\r
60 void FolderModel::clearPixmapCache()
\r
66 ///////////////////////////////////////////////////////////////////////////////
\r
67 /// \brief FolderModel::fileIcon
\r
68 /// \param index アイテムのインデックス
\r
69 /// \return アイコンを返します。
\r
71 QIcon FolderModel::fileIcon(const QModelIndex &index) const
\r
73 if (fileName(index) == "..") {
\r
74 return QIcon("://images/Up.png");
\r
76 return m_IconProvider.icon(fileInfo(index));
\r
79 ///////////////////////////////////////////////////////////////////////////////
\r
80 /// \brief FolderModel::isMarked
\r
81 /// \param index アイテムのインデックス
\r
82 /// \return マークされていればtrueを返します。
\r
84 bool FolderModel::isMarked(const QModelIndex &index) const
\r
86 CheckContainer::const_iterator it = m_checkStates.find(fileName(index));
\r
87 if (it != m_checkStates.end()) {
\r
88 return *it == Qt::Checked;
\r
93 ///////////////////////////////////////////////////////////////////////////////
\r
94 /// \brief FolderModel::markedItems
\r
95 /// \return マークされているアイテムのリストを返します。
\r
97 QFileInfoList FolderModel::markedItems() const
\r
100 for (int n = 0; n < rowCount(); ++n) {
\r
101 QModelIndex index = this->index(n, 0);
\r
102 if (isMarked(index)) {
\r
103 list << fileInfo(index);
\r
110 ///////////////////////////////////////////////////////////////////////////////
\r
111 /// \brief FolderModel::mkdir
\r
112 /// \param name 作成するフォルダ名
\r
113 /// \return 作成したフォルダのインデックス
\r
117 QModelIndex FolderModel::mkdir(const QString &name)
\r
119 qDebug() << "FolderModel::mkdir()" << name;
\r
121 if (!m_dir.mkdir(name)) {
\r
122 return QModelIndex();
\r
127 for (int n = 0; n < rowCount(); ++n) {
\r
128 if (m_fileInfoList[n].fileName() == name) {
\r
129 return index(n, 0);
\r
133 return QModelIndex();
\r
136 ///////////////////////////////////////////////////////////////////////////////
\r
137 /// \brief FolderModel::pixmap
\r
138 /// \param index アイテムのインデックス
\r
139 /// \param size 要求サイズ
\r
140 /// \return 画像またはアイコンを返します。
\r
142 QPixmap FolderModel::pixmap(const QModelIndex &index, const QSize &size) const
\r
145 const_cast<FolderModel*>(this)->m_pixmapCacheMutex.lock();
\r
146 if (m_pixmapCache.find(filePath(index)) != m_pixmapCache.end()) {
\r
147 pixmap = m_pixmapCache[filePath(index)];
\r
149 const_cast<FolderModel*>(this)->m_pixmapCacheMutex.unlock();
\r
151 if (!pixmap.isNull()) {
\r
152 double scaleX = 1.0 * size.width() / pixmap.width();
\r
153 double scaleY = 1.0 * size.height() / pixmap.height();
\r
154 double scaleFactor = qMin(scaleX, scaleY);
\r
155 if (scaleFactor > 1) {
\r
158 return pixmap.scaled(pixmap.size() * scaleFactor,
\r
159 Qt::IgnoreAspectRatio,
\r
160 Qt::SmoothTransformation);
\r
164 return fileIcon(index).pixmap(32, 32);
\r
167 ///////////////////////////////////////////////////////////////////////////////
\r
168 /// \brief FolderModel::search
\r
169 /// \param value 検索する文字列
\r
170 /// \param start 開始位置
\r
171 /// \param step ステップ数
\r
172 /// \return 見つかったアイテムのインデックスを返します。
\r
174 QModelIndex FolderModel::search(const QString &value, const QModelIndex &start, int step)
\r
176 qDebug() << "FolderModel::search()" << value << start << step;
\r
178 const QString searchText = value.toLower();
\r
179 for (int n = start.row() + step; 0 <= n && n < rowCount(); n += step) {
\r
180 if (m_fileInfoList[n].fileName().toLower().indexOf(searchText) != -1) {
\r
181 return index(n, 0);
\r
185 return QModelIndex();
\r
188 ///////////////////////////////////////////////////////////////////////////////
\r
189 /// \brief FolderModel::setHistoryAt
\r
190 /// \param path 設定するパス
\r
192 /// 指定したパスに履歴を移動します。
\r
194 void FolderModel::setHistoryAt(const QString &path)
\r
196 qDebug() << "FolderModel::setHistoryAt()" << path;
\r
198 for (int n = 0; n < m_history.size(); ++n) {
\r
199 if (m_history[n] == path) {
\r
201 setRootPath(path, false);
\r
207 ///////////////////////////////////////////////////////////////////////////////
\r
208 /// \brief FolderModel::setRootPath
\r
209 /// \param path 設定するパス
\r
210 /// \param addHistory 履歴に追加する場合はtrue
\r
214 void FolderModel::setRootPath(const QString &path, bool addHistory)
\r
216 qDebug() << "FolderModel::setRootPath()" << path;
\r
222 if (!QFileInfo::exists(path)) {
\r
223 throw tr("フォルダが存在しないか、利用できません:%1").arg(path);
\r
227 dir.setFilter(m_dir.filter());
\r
228 dir.setNameFilters(m_dir.nameFilters());
\r
229 dir.setSorting(m_dir.sorting());
\r
231 QFileInfoList list = dir.entryInfoList();
\r
232 if (list.isEmpty()) {
\r
233 throw tr("ファイルリストを取得できません:%1").arg(path);
\r
236 m_fileInfoList.clear();
\r
237 if (m_dir.absolutePath() != dir.absolutePath()) {
\r
238 m_fsWatcher.removePath(m_dir.absolutePath());
\r
239 m_fsWatcher.addPath(dir.absolutePath());
\r
240 m_checkStates.clear();
\r
241 m_dir.setPath(dir.absolutePath());
\r
243 m_history.resize(m_historyPos + 1);
\r
244 m_history << m_dir.absolutePath();
\r
245 m_historyPos = m_history.size() - 1;
\r
247 m_worker->clearPath();
\r
248 m_pixmapCacheMutex.lock();
\r
249 m_pixmapCache.clear();
\r
250 m_pixmapCacheMutex.unlock();
\r
251 m_lastModifiedCache.clear();
\r
254 foreach (const QFileInfo &fi, list) {
\r
255 if (fi.fileName() == "..") {
\r
256 if (!m_dir.isRoot()) {
\r
257 m_fileInfoList.push_front(fi);
\r
261 else if (!(filter() & QDir::System) &&
\r
262 Win32::hasSystemAttribute(fi.absoluteFilePath()))
\r
267 m_fileInfoList << fi;
\r
268 if (m_checkStates.find(fi.fileName()) == m_checkStates.end()) {
\r
269 m_checkStates[fi.fileName()] = Qt::Unchecked;
\r
271 if (m_lastModifiedCache.find(fi.fileName()) == m_lastModifiedCache.end() ||
\r
272 m_lastModifiedCache[fi.fileName()] != fi.lastModified())
\r
274 m_lastModifiedCache[fi.fileName()] = fi.lastModified();
\r
275 m_worker->addPath(fi.absoluteFilePath());
\r
279 catch (const QString &s) {
\r
286 ///////////////////////////////////////////////////////////////////////////////
\r
287 /// \brief FolderModel::touch
\r
288 /// \param name 作成するファイル名
\r
289 /// \return 作成したファイルのインデックス
\r
293 QModelIndex FolderModel::touch(const QString &name)
\r
295 QFile file(m_dir.absoluteFilePath(name));
\r
296 if (!file.open(QIODevice::WriteOnly)) {
\r
297 return QModelIndex();
\r
303 for (int n = 0; n < rowCount(); ++n) {
\r
304 if (m_fileInfoList[n].fileName() == name) {
\r
305 return index(n, 0);
\r
309 return QModelIndex();
\r
312 ///////////////////////////////////////////////////////////////////////////////
\r
313 /// \brief FolderModel::updateAppearance
\r
317 void FolderModel::updateAppearance(const Preferences &prefs)
\r
319 qDebug() << "FolderModel::updateAppearance()";
\r
321 m_font = prefs.getFolderViewFont();
\r
322 m_Palette.setColor(QPalette::Base, prefs.folderViewBgColor(isActive()));
\r
323 m_Palette.setColor(QPalette::Text, prefs.folderViewFgColor(isActive()));
\r
324 m_Palette.setColor(QPalette::Highlight, prefs.folderViewMarkedBgColor(isActive()));
\r
325 m_Palette.setColor(QPalette::HighlightedText, prefs.folderViewMarkedFgColor(isActive()));
\r
326 m_Palette.setColor(QPalette::Dark, prefs.folderViewHiddenColor(isActive()));
\r
327 m_Palette.setColor(QPalette::Light, prefs.folderViewReadOnlyColor(isActive()));
\r
328 m_Palette.setColor(QPalette::Mid, prefs.folderViewSystemColor(isActive()));
\r
331 ///////////////////////////////////////////////////////////////////////////////
\r
332 /// \brief FolderModel::activeModel
\r
333 /// \return アクティブなモデルを返します。
\r
335 FolderModel *FolderModel::activeModel()
\r
337 return m_activeModel;
\r
340 ///////////////////////////////////////////////////////////////////////////////
\r
341 /// \brief FolderModel::onCdHome
\r
345 void FolderModel::onCdHome()
\r
347 setRootPath(QDir::homePath());
\r
350 ///////////////////////////////////////////////////////////////////////////////
\r
351 /// \brief FolderModel::onCdRoot
\r
355 void FolderModel::onCdRoot()
\r
357 setRootPath(QDir::rootPath());
\r
360 ///////////////////////////////////////////////////////////////////////////////
\r
361 /// \brief FolderModel::onCdUp
\r
365 void FolderModel::onCdUp()
\r
367 if (!m_dir.isRoot()) {
\r
370 setRootPath(dir.absolutePath());
\r
374 ///////////////////////////////////////////////////////////////////////////////
\r
375 /// \brief FolderModel::onHistoryBack
\r
379 void FolderModel::onHistoryBack()
\r
381 if (m_historyPos > 0) {
\r
382 setRootPath(m_history[--m_historyPos], false);
\r
386 ///////////////////////////////////////////////////////////////////////////////
\r
387 /// \brief FolderModel::onHistoryForward
\r
391 void FolderModel::onHistoryForward()
\r
393 if (m_historyPos < m_history.size() - 1) {
\r
394 setRootPath(m_history[++m_historyPos], false);
\r
398 ///////////////////////////////////////////////////////////////////////////////
\r
399 /// \brief FolderModel::onMarkAll
\r
403 void FolderModel::onMarkAll()
\r
405 CheckContainer::iterator it;
\r
406 for (it = m_checkStates.begin(); it != m_checkStates.end(); ++it) {
\r
407 it.value() = Qt::Checked;
\r
409 emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
\r
412 ///////////////////////////////////////////////////////////////////////////////
\r
413 /// \brief FolderModel::onMarkAllFiles
\r
415 /// 全てのフォルダをマークOFF、ファイルをマークONにします。
\r
417 void FolderModel::onMarkAllFiles()
\r
419 foreach (const QFileInfo &fi, m_fileInfoList) {
\r
420 if (fi.fileName() == "..") {
\r
424 m_checkStates[fi.fileName()] = Qt::Unchecked;
\r
427 m_checkStates[fi.fileName()] = Qt::Checked;
\r
430 emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
\r
433 ///////////////////////////////////////////////////////////////////////////////
\r
434 /// \brief FolderModel::onMarkAllOff
\r
436 /// 全てのマークをOFFにします。
\r
438 void FolderModel::onMarkAllOff()
\r
440 CheckContainer::iterator it;
\r
441 for (it = m_checkStates.begin(); it != m_checkStates.end(); ++it) {
\r
442 it.value() = Qt::Unchecked;
\r
444 emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
\r
447 ///////////////////////////////////////////////////////////////////////////////
\r
448 /// \brief FolderModel::onMarkInvert
\r
452 void FolderModel::onMarkInvert()
\r
454 CheckContainer::iterator it;
\r
455 for (it = m_checkStates.begin(); it != m_checkStates.end(); ++it) {
\r
456 it.value() = (it.value() == Qt::Checked) ? Qt::Unchecked : Qt::Checked;
\r
458 emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
\r
461 ///////////////////////////////////////////////////////////////////////////////
\r
462 /// \brief FolderModel::thumbnail_Ready
\r
463 /// \param path ファイルパス
\r
464 /// \param pixmap サムネイル画像
\r
466 /// サムネイルの生成終了時の処理を行います。
\r
468 void FolderModel::thumbnail_Ready(const QString &path, const QPixmap &pixmap)
\r
470 qDebug() << "FolderModel::thumbnail_Ready()" << path;
\r
471 QFileInfo fi(path);
\r
472 if (fi.absolutePath() == m_dir.absolutePath()) {
\r
473 m_pixmapCacheMutex.lock();
\r
474 m_pixmapCache[path] = pixmap;
\r
475 m_pixmapCacheMutex.unlock();
\r
477 QModelIndex index = search(fi.fileName());
\r
478 if (index.isValid()) {
\r
479 emit dataChanged(index, index);
\r
484 ///////////////////////////////////////////////////////////////////////////////
\r
485 /// \brief FolderModel::rowCount
\r
486 /// \param parent (使用しません)
\r
487 /// \return 行数を返します。
\r
489 int FolderModel::rowCount(const QModelIndex &parent) const
\r
492 return m_fileInfoList.size();
\r
495 ///////////////////////////////////////////////////////////////////////////////
\r
496 /// \brief FolderModel::columnCount
\r
497 /// \param parent (使用しません)
\r
498 /// \return 列数を返します。
\r
500 int FolderModel::columnCount(const QModelIndex &parent) const
\r
503 return ColumnCount;
\r
506 ///////////////////////////////////////////////////////////////////////////////
\r
507 /// \brief FolderModel::data
\r
508 /// \param index インデックス
\r
509 /// \param role ロール
\r
510 /// \return 該当のデータを返します。
\r
512 QVariant FolderModel::data(const QModelIndex &index, int role) const
\r
514 if (!index.isValid()) {
\r
519 case Qt::DisplayRole:
\r
520 switch (index.column()) {
\r
522 if (isDir(index) || isDotFile(index)) {
\r
523 return fileName(index);
\r
525 return fileInfo(index).completeBaseName();
\r
528 if (isDir(index) || isDotFile(index)) {
\r
531 return fileInfo(index).suffix();
\r
534 if (isDir(index)) {
\r
535 return QString("<DIR>");
\r
537 return fileSizeToString(fileInfo(index).size());
\r
539 case LastModified: // 更新日時
\r
540 return fileInfo(index).lastModified().toString("yy/MM/dd hh:mm");
\r
544 case Qt::DecorationRole:
\r
545 if (index.column() == Name) {
\r
546 return fileIcon(index);
\r
553 case Qt::TextAlignmentRole:
\r
554 switch (index.column()) {
\r
557 return Qt::AlignRight + Qt::AlignVCenter;
\r
559 return Qt::AlignLeft + Qt::AlignVCenter;
\r
561 case Qt::BackgroundRole:
\r
562 if (isMarked(index)) {
\r
567 case Qt::ForegroundRole:
\r
568 if (isMarked(index)) {
\r
569 return markedText();
\r
571 if (fileName(index) != ".." && Win32::hasSystemAttribute(filePath(index))) {
\r
574 if (fileName(index) != ".." && fileInfo(index).isHidden()) {
\r
577 if (fileName(index) != ".." && !fileInfo(index).isWritable()) {
\r
582 case Qt::CheckStateRole:
\r
583 if (index.column() == Name && fileName(index) != "..") {
\r
584 return isMarked(index) ? Qt::Checked : Qt::Unchecked;
\r
592 ///////////////////////////////////////////////////////////////////////////////
\r
593 /// \brief FolderModel::flags
\r
594 /// \param index インデックス
\r
595 /// \return フラグを返します。
\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 ///////////////////////////////////////////////////////////////////////////////
\r
615 /// \brief FolderModel::setData
\r
616 /// \param index インデックス
\r
618 /// \param role ロール
\r
619 /// \return 値を設定した場合はtrueを返します。
\r
621 bool FolderModel::setData(const QModelIndex &index, const QVariant &value, int role)
\r
623 qDebug() << "FolderModel::setData()" << index;
\r
625 if (!index.isValid()) {
\r
630 case Qt::CheckStateRole:
\r
631 if (index.column() == Name && fileName(index) != "..") {
\r
632 m_checkStates[fileName(index)] = value.toInt();
\r
633 emit dataChanged(this->index(index.row(), 0),
\r
634 this->index(index.row(), ColumnCount - 1));
\r
643 ///////////////////////////////////////////////////////////////////////////////
\r
644 /// \brief FolderModel::supportedDropActions
\r
645 /// \return Qt::CopyActionを返します。
\r
647 Qt::DropActions FolderModel::supportedDropActions() const
\r
649 qDebug() << "FolderModel::supportedDropActions()";
\r
651 return Qt::CopyAction;
\r
654 ///////////////////////////////////////////////////////////////////////////////
\r
655 /// \brief FolderModel::mimeTypes
\r
656 /// \return MIMEタイプのリストを返します。
\r
658 QStringList FolderModel::mimeTypes() const
\r
660 qDebug() << "FolderModel::mimeTypes()";
\r
664 types << "text/uri-list";
\r