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_pixmapCacheMutex(),
\r
36 // サムネイル生成用スレッドを初期化する
\r
37 QThread *thread = new QThread();
\r
38 m_worker = new ThumbnailWorker();
\r
39 m_worker->moveToThread(thread);
\r
40 connect(m_worker, SIGNAL(resultReady(QString,QPixmap)), this, SLOT(thumbnail_Ready(QString,QPixmap)));
\r
41 connect(m_worker, SIGNAL(finished()), thread, SLOT(quit()));
\r
42 connect(thread, SIGNAL(started()), m_worker, SLOT(doWork()));
\r
45 connect(&m_fsWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(fsWatcher_directoryChanged(QString)));
\r
48 ///////////////////////////////////////////////////////////////////////////////
\r
49 /// \brief FolderModel::~FolderModel
\r
53 FolderModel::~FolderModel()
\r
56 m_worker->thread()->quit();
\r
57 m_worker->thread()->wait();
\r
60 ///////////////////////////////////////////////////////////////////////////////
\r
61 /// \brief FolderModel::clearPixmapCache
\r
63 /// サムネイルキャッシュをクリアしたように見せかけます。
\r
65 void FolderModel::clearPixmapCache()
\r
68 // m_pixmapCacheMutex.lock();
\r
69 // m_pixmapCache.clear();
\r
70 // m_pixmapCacheMutex.unlock();
\r
74 ///////////////////////////////////////////////////////////////////////////////
\r
75 /// \brief FolderModel::fileIcon
\r
76 /// \param index アイテムのインデックス
\r
77 /// \return アイコンを返します。
\r
79 QIcon FolderModel::fileIcon(const QModelIndex &index) const
\r
81 if (fileName(index) == "..") {
\r
82 return QIcon("://images/Up.png");
\r
84 return m_IconProvider.icon(fileInfo(index));
\r
87 ///////////////////////////////////////////////////////////////////////////////
\r
88 /// \brief FolderModel::isMarked
\r
89 /// \param index アイテムのインデックス
\r
90 /// \return マークされていればtrueを返します。
\r
92 bool FolderModel::isMarked(const QModelIndex &index) const
\r
94 CheckContainer::const_iterator it = m_checkStates.find(fileName(index));
\r
95 if (it != m_checkStates.end()) {
\r
96 return *it == Qt::Checked;
\r
101 ///////////////////////////////////////////////////////////////////////////////
\r
102 /// \brief FolderModel::markedItems
\r
103 /// \return マークされているアイテムのリストを返します。
\r
105 QFileInfoList FolderModel::markedItems() const
\r
107 QFileInfoList list;
\r
108 for (int n = 0; n < rowCount(); ++n) {
\r
109 QModelIndex index = this->index(n, 0);
\r
110 if (isMarked(index)) {
\r
111 list << fileInfo(index);
\r
118 ///////////////////////////////////////////////////////////////////////////////
\r
119 /// \brief FolderModel::mkdir
\r
120 /// \param name 作成するフォルダ名
\r
121 /// \return 作成したフォルダのインデックス
\r
125 QModelIndex FolderModel::mkdir(const QString &name)
\r
127 qDebug() << "FolderModel::mkdir()" << name;
\r
129 if (!m_dir.mkdir(name)) {
\r
130 return QModelIndex();
\r
135 for (int n = 0; n < rowCount(); ++n) {
\r
136 if (m_fileInfoList[n].fileName() == name) {
\r
137 return index(n, 0);
\r
141 return QModelIndex();
\r
144 ///////////////////////////////////////////////////////////////////////////////
\r
145 /// \brief FolderModel::pixmap
\r
146 /// \param index アイテムのインデックス
\r
147 /// \param size 要求サイズ
\r
148 /// \return 画像またはアイコンを返します。
\r
150 QPixmap FolderModel::pixmap(const QModelIndex &index, const QSize &size) const
\r
153 const_cast<FolderModel*>(this)->m_pixmapCacheMutex.lock();
\r
154 if (m_pixmapCache.find(filePath(index)) != m_pixmapCache.end()) {
\r
155 pixmap = m_pixmapCache[filePath(index)];
\r
157 const_cast<FolderModel*>(this)->m_pixmapCacheMutex.unlock();
\r
159 if (!pixmap.isNull()) {
\r
160 double scaleX = 1.0 * size.width() / pixmap.width();
\r
161 double scaleY = 1.0 * size.height() / pixmap.height();
\r
162 double scaleFactor = (scaleX > scaleY) ? scaleY : scaleX;
\r
163 return pixmap.scaled(pixmap.size() * scaleFactor,
\r
164 Qt::IgnoreAspectRatio,
\r
165 Qt::SmoothTransformation);
\r
169 return fileIcon(index).pixmap(32, 32);
\r
172 ///////////////////////////////////////////////////////////////////////////////
\r
173 /// \brief FolderModel::search
\r
174 /// \param value 検索する文字列
\r
175 /// \param start 開始位置
\r
176 /// \param step ステップ数
\r
177 /// \return 見つかったアイテムのインデックスを返します。
\r
179 QModelIndex FolderModel::search(const QString &value, const QModelIndex &start, int step)
\r
181 qDebug() << "FolderModel::search()" << value << start << step;
\r
183 const QString searchText = value.toLower();
\r
184 for (int n = start.row() + step; 0 <= n && n < rowCount(); n += step) {
\r
185 if (m_fileInfoList[n].fileName().toLower().indexOf(searchText) != -1) {
\r
186 return index(n, 0);
\r
190 return QModelIndex();
\r
193 ///////////////////////////////////////////////////////////////////////////////
\r
194 /// \brief FolderModel::setHistoryAt
\r
195 /// \param path 設定するパス
\r
197 /// 指定したパスに履歴を移動します。
\r
199 void FolderModel::setHistoryAt(const QString &path)
\r
201 qDebug() << "FolderModel::setHistoryAt()" << path;
\r
203 for (int n = 0; n < m_history.size(); ++n) {
\r
204 if (m_history[n] == path) {
\r
206 setRootPath(path, false);
\r
212 ///////////////////////////////////////////////////////////////////////////////
\r
213 /// \brief FolderModel::setRootPath
\r
214 /// \param path 設定するパス
\r
215 /// \param addHistory 履歴に追加する場合はtrue
\r
219 void FolderModel::setRootPath(const QString &path, bool addHistory)
\r
221 qDebug() << "FolderModel::setRootPath()" << path;
\r
227 if (!QFileInfo::exists(path)) {
\r
228 throw tr("フォルダが存在しないか、利用できません:%1").arg(path);
\r
232 dir.setFilter(m_dir.filter());
\r
233 dir.setNameFilters(m_dir.nameFilters());
\r
234 dir.setSorting(m_dir.sorting());
\r
236 QFileInfoList list = dir.entryInfoList();
\r
237 if (list.isEmpty()) {
\r
238 throw tr("ファイルリストを取得できません:%1").arg(path);
\r
241 m_fileInfoList.clear();
\r
242 if (m_dir.absolutePath() != dir.absolutePath()) {
\r
243 m_fsWatcher.removePath(m_dir.absolutePath());
\r
244 m_fsWatcher.addPath(dir.absolutePath());
\r
245 m_checkStates.clear();
\r
246 m_dir.setPath(dir.absolutePath());
\r
248 m_history.resize(m_historyPos + 1);
\r
249 m_history << m_dir.absolutePath();
\r
250 m_historyPos = m_history.size() - 1;
\r
252 m_worker->clearPath();
\r
253 m_pixmapCacheMutex.lock();
\r
254 m_pixmapCache.clear();
\r
255 m_pixmapCacheMutex.unlock();
\r
258 foreach (const QFileInfo &fi, list) {
\r
259 if (fi.fileName() == "..") {
\r
260 if (!m_dir.isRoot()) {
\r
261 m_fileInfoList.push_front(fi);
\r
265 else if (!(filter() & QDir::System) &&
\r
266 Win32::hasSystemAttribute(fi.absoluteFilePath()))
\r
271 m_fileInfoList << fi;
\r
272 if (m_checkStates.find(fi.fileName()) == m_checkStates.end()) {
\r
273 m_checkStates[fi.fileName()] = Qt::Unchecked;
\r
274 m_worker->addPath(fi.absoluteFilePath());
\r
278 catch (const QString &s) {
\r
285 ///////////////////////////////////////////////////////////////////////////////
\r
286 /// \brief FolderModel::touch
\r
287 /// \param name 作成するファイル名
\r
288 /// \return 作成したファイルのインデックス
\r
292 QModelIndex FolderModel::touch(const QString &name)
\r
294 QFile file(m_dir.absoluteFilePath(name));
\r
295 if (!file.open(QIODevice::WriteOnly)) {
\r
296 return QModelIndex();
\r
302 for (int n = 0; n < rowCount(); ++n) {
\r
303 if (m_fileInfoList[n].fileName() == name) {
\r
304 return index(n, 0);
\r
308 return QModelIndex();
\r
311 ///////////////////////////////////////////////////////////////////////////////
\r
312 /// \brief FolderModel::updateAppearance
\r
316 void FolderModel::updateAppearance(const Preferences &prefs)
\r
318 qDebug() << "FolderModel::updateAppearance()";
\r
320 m_font = prefs.getFolderViewFont();
\r
321 m_Palette.setColor(QPalette::Base, prefs.folderViewBgColor(isActive()));
\r
322 m_Palette.setColor(QPalette::Text, prefs.folderViewFgColor(isActive()));
\r
323 m_Palette.setColor(QPalette::Highlight, prefs.folderViewMarkedBgColor(isActive()));
\r
324 m_Palette.setColor(QPalette::HighlightedText, prefs.folderViewMarkedFgColor(isActive()));
\r
325 m_Palette.setColor(QPalette::Dark, prefs.folderViewHiddenColor(isActive()));
\r
326 m_Palette.setColor(QPalette::Light, prefs.folderViewReadOnlyColor(isActive()));
\r
327 m_Palette.setColor(QPalette::Mid, prefs.folderViewSystemColor(isActive()));
\r
330 ///////////////////////////////////////////////////////////////////////////////
\r
331 /// \brief FolderModel::activeModel
\r
332 /// \return アクティブなモデルを返します。
\r
334 FolderModel *FolderModel::activeModel()
\r
336 return m_activeModel;
\r
339 ///////////////////////////////////////////////////////////////////////////////
\r
340 /// \brief FolderModel::onCdHome
\r
344 void FolderModel::onCdHome()
\r
346 setRootPath(QDir::homePath());
\r
349 ///////////////////////////////////////////////////////////////////////////////
\r
350 /// \brief FolderModel::onCdRoot
\r
354 void FolderModel::onCdRoot()
\r
356 setRootPath(QDir::rootPath());
\r
359 ///////////////////////////////////////////////////////////////////////////////
\r
360 /// \brief FolderModel::onCdUp
\r
364 void FolderModel::onCdUp()
\r
366 if (!m_dir.isRoot()) {
\r
369 setRootPath(dir.absolutePath());
\r
373 ///////////////////////////////////////////////////////////////////////////////
\r
374 /// \brief FolderModel::onHistoryBack
\r
378 void FolderModel::onHistoryBack()
\r
380 if (m_historyPos > 0) {
\r
381 setRootPath(m_history[--m_historyPos], false);
\r
385 ///////////////////////////////////////////////////////////////////////////////
\r
386 /// \brief FolderModel::onHistoryForward
\r
390 void FolderModel::onHistoryForward()
\r
392 if (m_historyPos < m_history.size() - 1) {
\r
393 setRootPath(m_history[++m_historyPos], false);
\r
397 ///////////////////////////////////////////////////////////////////////////////
\r
398 /// \brief FolderModel::onMarkAll
\r
402 void FolderModel::onMarkAll()
\r
404 CheckContainer::iterator it;
\r
405 for (it = m_checkStates.begin(); it != m_checkStates.end(); ++it) {
\r
406 it.value() = Qt::Checked;
\r
408 emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
\r
411 ///////////////////////////////////////////////////////////////////////////////
\r
412 /// \brief FolderModel::onMarkAllFiles
\r
414 /// 全てのフォルダをマークOFF、ファイルをマークONにします。
\r
416 void FolderModel::onMarkAllFiles()
\r
418 foreach (const QFileInfo &fi, m_fileInfoList) {
\r
419 if (fi.fileName() == "..") {
\r
423 m_checkStates[fi.fileName()] = Qt::Unchecked;
\r
426 m_checkStates[fi.fileName()] = Qt::Checked;
\r
429 emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
\r
432 ///////////////////////////////////////////////////////////////////////////////
\r
433 /// \brief FolderModel::onMarkAllOff
\r
435 /// 全てのマークをOFFにします。
\r
437 void FolderModel::onMarkAllOff()
\r
439 CheckContainer::iterator it;
\r
440 for (it = m_checkStates.begin(); it != m_checkStates.end(); ++it) {
\r
441 it.value() = Qt::Unchecked;
\r
443 emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
\r
446 ///////////////////////////////////////////////////////////////////////////////
\r
447 /// \brief FolderModel::onMarkInvert
\r
451 void FolderModel::onMarkInvert()
\r
453 CheckContainer::iterator it;
\r
454 for (it = m_checkStates.begin(); it != m_checkStates.end(); ++it) {
\r
455 it.value() = (it.value() == Qt::Checked) ? Qt::Unchecked : Qt::Checked;
\r
457 emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
\r
460 ///////////////////////////////////////////////////////////////////////////////
\r
461 /// \brief FolderModel::thumbnail_Ready
\r
462 /// \param path ファイルパス
\r
463 /// \param pixmap サムネイル画像
\r
465 /// サムネイルの生成終了時の処理を行います。
\r
467 void FolderModel::thumbnail_Ready(const QString &path, const QPixmap &pixmap)
\r
469 QFileInfo fi(path);
\r
470 if (fi.absolutePath() == m_dir.absolutePath()) {
\r
471 m_pixmapCacheMutex.lock();
\r
472 m_pixmapCache[path] = pixmap;
\r
473 m_pixmapCacheMutex.unlock();
\r
475 QModelIndex index = search(fi.fileName());
\r
476 if (index.isValid()) {
\r
477 emit dataChanged(index, index);
\r
482 int FolderModel::rowCount(const QModelIndex &parent) const
\r
485 return m_fileInfoList.size();
\r
488 int FolderModel::columnCount(const QModelIndex &parent) const
\r
491 return ColumnCount;
\r
494 QVariant FolderModel::data(const QModelIndex &index, int role) const
\r
496 if (!index.isValid()) {
\r
501 case Qt::DisplayRole:
\r
502 switch (index.column()) {
\r
504 if (isDir(index) || isDotFile(index)) {
\r
505 return fileName(index);
\r
507 return fileInfo(index).completeBaseName();
\r
510 if (isDir(index) || isDotFile(index)) {
\r
513 return fileInfo(index).suffix();
\r
516 if (isDir(index)) {
\r
517 return QString("<DIR>");
\r
519 return FileSizeToString(fileInfo(index).size());
\r
521 case LastModified: // 更新日時
\r
522 return fileInfo(index).lastModified().toString("yy/MM/dd hh:mm");
\r
526 case Qt::DecorationRole:
\r
527 if (index.column() == Name) {
\r
528 return fileIcon(index);
\r
535 case Qt::TextAlignmentRole:
\r
536 switch (index.column()) {
\r
539 return Qt::AlignRight + Qt::AlignVCenter;
\r
541 return Qt::AlignLeft + Qt::AlignVCenter;
\r
543 case Qt::BackgroundRole:
\r
544 if (isMarked(index)) {
\r
549 case Qt::ForegroundRole:
\r
550 if (isMarked(index)) {
\r
551 return markedText();
\r
553 if (fileName(index) != ".." && Win32::hasSystemAttribute(filePath(index))) {
\r
556 if (fileName(index) != ".." && fileInfo(index).isHidden()) {
\r
559 if (fileName(index) != ".." && !fileInfo(index).isWritable()) {
\r
564 case Qt::CheckStateRole:
\r
565 if (index.column() == Name && fileName(index) != "..") {
\r
566 return isMarked(index) ? Qt::Checked : Qt::Unchecked;
\r
574 QVariant FolderModel::headerData(int section, Qt::Orientation orientation, int role) const
\r
576 if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
\r
578 case Name: return tr("名前");
\r
579 case Extension: return tr("拡張子");
\r
580 case Size: return tr("サイズ");
\r
581 case LastModified: return tr("更新日時");
\r
587 Qt::ItemFlags FolderModel::flags(const QModelIndex &index) const
\r
589 Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
\r
591 if (!index.isValid()) {
\r
592 return flags | Qt::ItemIsDropEnabled;
\r
595 if (m_fileInfoList[index.row()].fileName() != "..") {
\r
596 if (index.column() == Name) {
\r
597 flags |= Qt::ItemIsUserCheckable;
\r
599 flags |= Qt::ItemIsDropEnabled;
\r
604 bool FolderModel::setData(const QModelIndex &index, const QVariant &value, int role)
\r
606 qDebug() << "FolderModel::setData()" << index;
\r
608 if (!index.isValid()) {
\r
613 case Qt::CheckStateRole:
\r
614 if (index.column() == Name && fileName(index) != "..") {
\r
615 m_checkStates[fileName(index)] = value.toInt();
\r
616 emit dataChanged(this->index(index.row(), 0),
\r
617 this->index(index.row(), ColumnCount - 1));
\r
626 Qt::DropActions FolderModel::supportedDropActions() const
\r
628 qDebug() << "FolderModel::supportedDropActions()";
\r
630 return Qt::CopyAction;
\r
633 QStringList FolderModel::mimeTypes() const
\r
635 qDebug() << "FolderModel::mimeTypes()";
\r
639 types << "text/uri-list";
\r