OSDN Git Service

da31c82c0ec5dce042b25d06abaf90f6027cb39b
[gefu/Gefu.git] / filetablemodel.cpp
1 #include "common.h"\r
2 #include "filetablemodel.h"\r
3 \r
4 #include <QDateTime>\r
5 #include <QDebug>\r
6 #include <QApplication>\r
7 #include <QSettings>\r
8 #include <QPalette>\r
9 #ifdef Q_OS_WIN32\r
10     #include <windows.h>\r
11 #endif\r
12 \r
13 FileTableModel::FileTableModel(QObject *parent) :\r
14     QAbstractTableModel(parent),\r
15     m_dir(),\r
16     m_fileInfoList(),\r
17     m_checkStates(),\r
18     m_IconFactory(),\r
19     m_fsWatcher(NULL),\r
20     m_font(),\r
21     m_NormalBrush(),\r
22     m_NormalTextBrush(),\r
23     m_MarkBrush(),\r
24     m_MarkTextBrush(),\r
25     m_SystemBrush(),\r
26     m_HiddenBrush(),\r
27     m_ReadonlyBrush()\r
28 {\r
29     m_fsWatcher = new QFileSystemWatcher(this);\r
30 \r
31     // デフォルトフィルタを設定する\r
32     setFilter(QDir::NoDot | QDir::AllDirs | QDir::Files);\r
33 }\r
34 \r
35 bool FileTableModel::setPath(const QString &path)\r
36 {\r
37     qDebug() << "FileTableModel::setPath" << path;\r
38 \r
39     if (!QFileInfo::exists(path)) {\r
40         qDebug() << "パスが存在しません";\r
41         qDebug() << path;\r
42         return false;\r
43     }\r
44     QFileInfo info(path);\r
45     if (!info.isDir()) {\r
46         qDebug() << "フォルダではありません";\r
47         qDebug() << path;\r
48         return false;\r
49     }\r
50 \r
51     beginResetModel();\r
52 \r
53     m_dir.setPath(path);\r
54     m_fileInfoList = m_dir.entryInfoList();\r
55     m_checkStates.clear();\r
56 \r
57     if (m_fileInfoList.isEmpty()) {\r
58         qDebug() << "ファイルリストを取得できません";\r
59         qDebug() << path;\r
60     }\r
61     else {\r
62         QFileInfoList::iterator it;\r
63         for (it = m_fileInfoList.begin(); it != m_fileInfoList.end(); ) {\r
64 #ifdef Q_OS_WIN32\r
65             if (!(filter() & QDir::System)){\r
66                 DWORD dwFlags = ::GetFileAttributes(\r
67                             it->absoluteFilePath().toStdWString().c_str());\r
68                 if (dwFlags != DWORD(-1) && it->fileName() != ".." &&\r
69                     ((dwFlags & FILE_ATTRIBUTE_SYSTEM) == FILE_ATTRIBUTE_SYSTEM))\r
70                 {\r
71                     qDebug() << it->fileName() << " is system file.";\r
72                     it = m_fileInfoList.erase(it);\r
73                     continue;\r
74                 }\r
75             }\r
76 #endif\r
77             if (it->fileName() == "..") {\r
78                 if (m_dir.isRoot()) {\r
79                     qDebug() << m_dir.absolutePath() << " is root.";\r
80                     it = m_fileInfoList.erase(it);\r
81                     continue;\r
82                 }\r
83             }\r
84             it++;\r
85         }\r
86         // ソート方法によらず、".."は必ず先頭にする\r
87         QFileInfoList::iterator itRoot = m_fileInfoList.end();\r
88         for (it = m_fileInfoList.begin(); it != m_fileInfoList.end(); it++) {\r
89             if (it->fileName() == "..") {\r
90                 itRoot = it;\r
91                 break;\r
92             }\r
93         }\r
94         if (itRoot != m_fileInfoList.end()) {\r
95             QFileInfo info(*itRoot);\r
96             m_fileInfoList.erase(itRoot);\r
97             m_fileInfoList.push_front(info);\r
98         }\r
99     }\r
100 \r
101     m_checkStates.resize(m_fileInfoList.size());\r
102     m_checkStates.fill(Qt::Unchecked);\r
103 \r
104     m_fsWatcher->addPath(path);\r
105     connect(m_fsWatcher, SIGNAL(directoryChanged(QString)),\r
106             this, SLOT(directoryChange(QString)));\r
107 \r
108     endResetModel();\r
109 \r
110     emit dataChanged(QModelIndex(), QModelIndex());\r
111 \r
112     return !m_fileInfoList.isEmpty();\r
113 }\r
114 \r
115 Qt::CheckState FileTableModel::checkState(const QModelIndex &index) const\r
116 {\r
117     return m_checkStates[index.row()];\r
118 }\r
119 \r
120 void FileTableModel::setCheckState(const QModelIndex &index, Qt::CheckState state)\r
121 {\r
122     qDebug() << "FileTableModel::setCheckState();";\r
123 \r
124     beginResetModel();\r
125     m_checkStates[index.row()] = state;\r
126     if (state == Qt::Checked && index.row() == 0 &&\r
127         m_fileInfoList[0].fileName() == "..")\r
128     {\r
129         m_checkStates[0] = Qt::Unchecked;\r
130     }\r
131     endResetModel();;\r
132     emit dataChanged(index, this->index(index.row(), 3));\r
133 }\r
134 \r
135 void FileTableModel::setCheckStateAll(Qt::CheckState state)\r
136 {\r
137     qDebug() << "FileTableModel::setCheckStateAll();";\r
138 \r
139     beginResetModel();\r
140     m_checkStates.fill(state);\r
141     if (state == Qt::Checked && m_fileInfoList.size() > 1 &&\r
142         m_fileInfoList[0].fileName() == "..")\r
143     {\r
144         m_checkStates[0] = Qt::Unchecked;\r
145     }\r
146     endResetModel();\r
147     emit dataChanged(QModelIndex(), QModelIndex());\r
148 }\r
149 \r
150 QFileInfo FileTableModel::fileInfo(const QModelIndex &index) const\r
151 {\r
152     if (!index.isValid()) {\r
153         qDebug() << "fileInfo() : index is invalid.";\r
154         return QFileInfo();\r
155     }\r
156     return m_fileInfoList[index.row()];\r
157 }\r
158 \r
159 void FileTableModel::updateAppearance(bool darker)\r
160 {\r
161     QSettings settings;\r
162     int darkness = 100;\r
163     if (darker && settings.value(IniKey_EnableDarker).toBool()) {\r
164         darkness += settings.value(IniKey_Darkness).toInt();\r
165     }\r
166     m_font = settings.value(IniKey_ViewFont).value<QFont>();\r
167 \r
168     m_NormalBrush = QBrush(settings.value(IniKey_ViewColorBgNormal).value<QColor>().darker(darkness));\r
169     m_NormalTextBrush = QBrush(settings.value(IniKey_ViewColorFgNormal).value<QColor>().darker(darkness));\r
170     m_MarkBrush = QBrush(settings.value(IniKey_ViewColorBgMark).value<QColor>().darker(darkness));\r
171     m_MarkTextBrush = QBrush(settings.value(IniKey_ViewColorFgMark).value<QColor>().darker(darkness));\r
172     m_SystemBrush = QBrush(settings.value(IniKey_ViewColorFgSystem).value<QColor>().darker(darkness));\r
173     m_HiddenBrush = QBrush(settings.value(IniKey_ViewColorFgHidden).value<QColor>().darker(darkness));\r
174     m_ReadonlyBrush = QBrush(settings.value(IniKey_ViewColorFgReadonly).value<QColor>().darker(darkness));\r
175     m_ReadonlyBrush = QBrush(settings.value(IniKey_ViewColorFgReadonly).value<QColor>().darker(darkness));\r
176 }\r
177 \r
178 void FileTableModel::directoryChange(const QString &path)\r
179 {\r
180     qDebug() << "FileTableModel::directoryChange";\r
181 \r
182     m_fsWatcher->removePath(m_dir.absolutePath());\r
183     setPath(path);\r
184 }\r
185 \r
186 QFileInfoList FileTableModel::checkedItems() const\r
187 {\r
188     QFileInfoList list;\r
189     for (int n = 0; n < m_checkStates.size(); n++) {\r
190         if (m_fileInfoList[n].fileName() != ".." &&\r
191             m_checkStates[n] == Qt::Checked)\r
192         {\r
193             list.append(m_fileInfoList[n]);\r
194         }\r
195     }\r
196     return list;\r
197 }\r
198 \r
199 int FileTableModel::rowCount(const QModelIndex &parent) const\r
200 {\r
201     Q_UNUSED(parent);\r
202     return m_fileInfoList.size();\r
203 }\r
204 \r
205 int FileTableModel::columnCount(const QModelIndex &parent) const\r
206 {\r
207     Q_UNUSED(parent);\r
208     return 5;\r
209 }\r
210 \r
211 QVariant FileTableModel::data(const QModelIndex &index, int role) const\r
212 {\r
213     if (!index.isValid()) {\r
214         return QVariant();\r
215     }\r
216 \r
217     const QFileInfo &info = m_fileInfoList.at(index.row());\r
218     int checked = m_checkStates.at(index.row());\r
219 \r
220     switch (role) {\r
221     case Qt::DisplayRole:\r
222         switch (index.column()) {\r
223         case 0: // チェックボックス\r
224             return QString("");\r
225         case 1: // ファイル名\r
226             if (info.isDir()) {\r
227                 return info.fileName();\r
228             }\r
229             if (info.fileName().left(1) == ".") {   // "."で始まるファイル\r
230                 int pos = info.fileName().lastIndexOf(".");\r
231                 if (pos == 0) {\r
232                     return info.fileName();\r
233                 }\r
234             }\r
235             return info.completeBaseName();\r
236 \r
237         case 2: // 拡張子\r
238             if (info.isDir()) {\r
239                 return QString();\r
240             }\r
241             if (info.fileName().left(1) == ".") {   // "."で始まるファイル\r
242                 int pos = info.fileName().lastIndexOf(".");\r
243                 if (pos == 0) {\r
244                     return QString();\r
245                 }\r
246             }\r
247             return info.suffix();\r
248 \r
249         case 3: // サイズ\r
250             if (info.isDir()) {\r
251                 return QString("<DIR>");\r
252             }\r
253             else {\r
254                 return FilesizeToString(info.size());\r
255             }\r
256             break;\r
257 \r
258         case 4: // 更新日時\r
259             return info.lastModified().toString("yy/MM/dd hh:mm");\r
260         }\r
261         break;\r
262 \r
263     case Qt::DecorationRole:\r
264         if (index.column() == 1) {\r
265             if (info.fileName() == "..") {\r
266                 return QIcon(":/images/Up.png");\r
267             }\r
268             else {\r
269                 // infoを使うと、正しいアイコンが取れない場合がある…なぜ?\r
270                 return m_IconFactory.icon(QFileInfo(info.absoluteFilePath()));\r
271             }\r
272         }\r
273         break;\r
274 \r
275     case Qt::FontRole:\r
276         return m_font;\r
277 \r
278     case Qt::TextAlignmentRole:\r
279         switch (index.column()) {\r
280         case 3:\r
281         case 4:\r
282             return Qt::AlignRight + Qt::AlignVCenter;\r
283         default:\r
284             return Qt::AlignLeft + Qt::AlignVCenter;\r
285         }\r
286         break;\r
287 \r
288     case Qt::BackgroundRole:\r
289         if (checked) {\r
290             return m_MarkBrush;\r
291         }\r
292         return m_NormalBrush;\r
293 \r
294     case Qt::ForegroundRole:\r
295         if (checked) {\r
296             return m_MarkTextBrush;\r
297         }\r
298 #ifdef Q_OS_WIN32\r
299         {\r
300             DWORD dwFlags = ::GetFileAttributes(\r
301                         info.absoluteFilePath().toStdWString().c_str());\r
302             if (dwFlags != DWORD(-1) && (dwFlags & FILE_ATTRIBUTE_SYSTEM) == FILE_ATTRIBUTE_SYSTEM)\r
303             {\r
304                 return m_SystemBrush;\r
305             }\r
306         }\r
307 #endif\r
308         if (info.isHidden() && info.fileName() != "..") {\r
309             return m_HiddenBrush;\r
310         }\r
311         if (!info.isWritable()) {\r
312             return m_ReadonlyBrush;\r
313         }\r
314         return m_NormalTextBrush;\r
315 \r
316     case Qt::CheckStateRole:\r
317         if (index.column() == 0 && info.fileName() != "..") {\r
318             return checked;\r
319         }\r
320         break;\r
321     }\r
322 \r
323     return QVariant();\r
324 }\r
325 \r
326 QVariant FileTableModel::headerData(int section, Qt::Orientation orientation, int role) const\r
327 {\r
328     if (role == Qt::DisplayRole) {\r
329         if (orientation == Qt::Horizontal) {\r
330             switch (section) {\r
331             case 0: return QString("");\r
332             case 1: return tr("名前");\r
333             case 2: return tr("拡張子");\r
334             case 3: return tr("サイズ");\r
335             case 4: return tr("更新日時");\r
336             }\r
337         }\r
338     }\r
339     return QVariant();\r
340 }\r
341 \r
342 Qt::ItemFlags FileTableModel::flags(const QModelIndex &index) const\r
343 {\r
344     Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;\r
345     if (!index.isValid()) {\r
346         flags |= Qt::ItemIsDropEnabled;\r
347     }\r
348     else if (m_fileInfoList[index.row()].fileName() != "..") {\r
349         if (index.column() == 0) {\r
350             flags |= Qt::ItemIsUserCheckable;\r
351         }\r
352         flags |= Qt::ItemIsDropEnabled;\r
353     }\r
354     return flags;\r
355 }\r
356 \r
357 bool FileTableModel::setData(const QModelIndex &index, const QVariant &value, int role)\r
358 {\r
359     qDebug() << "FileTableModel::setData()";\r
360 \r
361     if (!index.isValid()) {\r
362         return false;\r
363     }\r
364 \r
365     switch (role) {\r
366     case Qt::CheckStateRole:\r
367         if (index.column() == 0) {\r
368             m_checkStates[index.row()] = static_cast<Qt::CheckState>(value.toInt());\r
369             emit dataChanged(index, this->index(index.row(), 3));\r
370             return true;\r
371         }\r
372         break;\r
373     }\r
374 \r
375     return false;\r
376 }\r
377 \r
378 Qt::DropActions FileTableModel::supportedDropActions() const\r
379 {\r
380     return Qt::CopyAction | Qt::MoveAction;\r
381 }\r
382 \r
383 QStringList FileTableModel::mimeTypes() const\r
384 {\r
385     QStringList types;\r
386 \r
387     types << "text/uri-list";\r
388 \r
389     return types;\r
390 }\r