OSDN Git Service

3e9c41e09a8f22a434cfec5f578d9c14b0bd5922
[gefu/Gefu.git] / folderview.cpp
1 #include "common.h"
2 #include "folderview.h"
3
4 #include <QDebug>
5 #include <QHeaderView>
6 #include <QKeyEvent>
7 #include <QSettings>
8 #include <QMimeData>
9 #include <QApplication>
10 #include <QDrag>
11 #include <QMenu>
12
13 QString FilesizeToString(quint64 size)
14 {
15     if (size >= 1024 * 1024 * 1024) {
16         return QString("%1GB").arg(int(10 * size / (1024 * 1024 * 1024)) / 10);
17     }
18     if (size >= 1024 * 1024) {
19         return QString("%1MB").arg(int(10 * size / (1024 * 1024)) / 10);
20     }
21     if (size >= 1024) {
22         return QString("%1KB").arg(int(10 * size / (1024)) / 10);
23     }
24     return QString("%1B").arg(size);
25 }
26
27 FolderView::FolderView(QWidget *parent) :
28     QTableView(parent),
29     m_model(),
30     m_dragStartPos(),
31     m_dragging(false)
32 {
33     setModel(&m_model);
34     connect(&m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(dataChanged(QModelIndex,QModelIndex)));
35
36     setDragEnabled(true);
37     setAcceptDrops(true);
38     setDropIndicatorShown(true);
39
40     setContextMenuPolicy(Qt::DefaultContextMenu);
41 }
42
43 QString FolderView::side() const
44 {
45     if (this->objectName() == "folderView1") {
46         return QString("Left");
47     }
48     else {
49         Q_ASSERT(this->objectName() == "folderView2");
50         return QString("Right");
51     }
52 }
53
54 void FolderView::initialize()
55 {
56     qDebug() << side() << "initialize";
57
58     setColumnWidth(0, 30);
59
60     // 前回終了時のパスを開く
61     QSettings settings;
62     setPath(settings.value(side() + slash + IniKey_Dir).toString(), true);
63
64     // 色とフォントを設定する
65     updateAppearance();
66
67     // 列のリサイズモードを設定する
68     QHeaderView *header;
69     header = horizontalHeader();
70     header->setSectionResizeMode(0, QHeaderView::Fixed);
71     header->setSectionResizeMode(1, QHeaderView::Stretch);
72     header->setSectionResizeMode(2, QHeaderView::ResizeToContents);
73     header->setSectionResizeMode(3, QHeaderView::ResizeToContents);
74     header->setSectionResizeMode(4, QHeaderView::ResizeToContents);
75 }
76
77 void FolderView::updateAppearance()
78 {
79     qDebug() << side() << "updateAppearance";
80     m_model.updateAppearance();
81
82     QSettings settings;
83     QPalette pal = palette();
84     pal.setColor(QPalette::Base, settings.value(IniKey_ViewColorBgNormal).value<QColor>());
85     setPalette(pal);
86
87     // 行の高さを設定する
88     QHeaderView *header = verticalHeader();
89     header->setDefaultSectionSize(QFontMetrics(m_model.font()).height() * 1.5);
90
91     // 列の幅を設定する
92     header = horizontalHeader();
93     header->setSectionResizeMode(0, QHeaderView::Fixed);
94     header->setSectionResizeMode(1, QHeaderView::Stretch);
95     header->setSectionResizeMode(2, QHeaderView::ResizeToContents);
96     header->setSectionResizeMode(3, QHeaderView::ResizeToContents);
97     header->setSectionResizeMode(4, QHeaderView::ResizeToContents);
98
99     repaint();
100 }
101
102 void FolderView::refresh()
103 {
104     qDebug() << side() << "refresh";
105
106     int row = currentIndex().row();
107
108     setPath(m_model.absolutePath(), false);
109
110     if (row < 0) {
111         row = 0;
112     }
113     else if (row >= m_model.rowCount()) {
114         row = m_model.rowCount() - 1;
115     }
116     setCurrentIndex(m_model.index(row, 0));
117     selectRow(row);
118 }
119
120 void FolderView::searchItem(const QString &text)
121 {
122     qDebug() << "FolderView::searchItem" << text;
123
124     for (int row = 0; row < m_model.rowCount(); row++) {
125         QModelIndex index = m_model.index(row, 0);
126         QString name = m_model.fileInfo(index).fileName().toLower();
127         if (name.indexOf(text.toLower()) != -1) {
128             setCurrentIndex(index);
129             emit itemFound();
130             return;
131         }
132     }
133
134     emit itemNotFound();
135 }
136
137 void FolderView::searchNext(const QString &text)
138 {
139     qDebug() << "FolderView::searchNext" << text;
140
141     for (int row = currentIndex().row() + 1; row < m_model.rowCount(); row++) {
142         QModelIndex index = m_model.index(row, 0);
143         QString name = m_model.fileInfo(index).fileName().toLower();
144         if (name.indexOf(text.toLower()) != -1) {
145             setCurrentIndex(index);
146             emit itemFound();
147             return;
148         }
149     }
150
151     emit itemNotFound();
152 }
153
154 void FolderView::searchPrev(const QString &text)
155 {
156     qDebug() << side() << "searchPrev" << text;
157
158     for (int row = currentIndex().row() - 1; row >= 0; row--) {
159         QModelIndex index = m_model.index(row, 0);
160         QString name = m_model.fileInfo(index).fileName().toLower();
161         if (name.indexOf(text.toLower()) != -1) {
162             setCurrentIndex(index);
163             emit itemFound();
164             return;
165         }
166     }
167
168     emit itemNotFound();
169 }
170
171 void FolderView::setCheckStateAll(bool checked)
172 {
173     qDebug() << side() << "markAll();";
174
175     QModelIndex current = currentIndex();
176
177     setUpdatesEnabled(false);
178     m_model.setCheckStateAll(checked ? Qt::Checked : Qt::Unchecked);
179     setUpdatesEnabled(true);
180
181     setCurrentIndex(current);
182 }
183
184 void FolderView::setCheckStateAllFiles()
185 {
186     qDebug() << side() << "markAllFiles();";
187
188     QModelIndex current = currentIndex();
189
190     setUpdatesEnabled(false);
191     for (int n = 0; n < m_model.rowCount(); n++) {
192         QModelIndex index = m_model.index(n, 0);
193         QFileInfo info = m_model.fileInfo(index);
194         if (info.isDir()) {
195             m_model.setCheckState(index, Qt::Unchecked);
196         }
197         else {
198             m_model.setCheckState(index, Qt::Checked);
199         }
200     }
201     setUpdatesEnabled(true);
202
203     setCurrentIndex(current);
204 }
205
206 void FolderView::invertCheckState()
207 {
208     qDebug() << side() << "invertCheckState();";
209
210     QModelIndex current = currentIndex();
211
212     setUpdatesEnabled(false);
213     for (int n = 0; n < m_model.rowCount(); n++) {
214         QModelIndex index = m_model.index(n, 0);
215         if (m_model.checkState(index) == Qt::Checked) {
216             m_model.setCheckState(index, Qt::Unchecked);
217         }
218         else {
219             m_model.setCheckState(index, Qt::Checked);
220         }
221     }
222     setUpdatesEnabled(true);
223
224     setCurrentIndex(current);
225 }
226
227 void FolderView::toggleCheckState(const QModelIndex &index)
228 {
229     QFileInfo info = m_model.fileInfo(index);
230     if (info.fileName() != "..") {
231         if (m_model.checkState(index) == Qt::Checked) {
232             m_model.setCheckState(index, Qt::Unchecked);
233         }
234         else {
235             m_model.setCheckState(index, Qt::Checked);
236         }
237     }
238     // 最終行でなければ、次のアイテムに移動する
239     if (index.row() == m_model.rowCount() - 1) {
240         setCurrentIndex(index);
241     }
242     else if (index.row() < m_model.rowCount() - 1) {
243         setCurrentIndex(m_model.index(index.row() + 1, 1));
244     }
245 }
246
247 bool FolderView::historyBack()
248 {
249     if (!m_history.isBegin()) {
250         setPath(m_history.back(), false);
251         return true;
252     }
253     return false;
254 }
255
256 bool FolderView::historyForward()
257 {
258     if (!m_history.isEnd()) {
259         setPath(m_history.forward(), false);
260         return true;
261     }
262     return false;
263 }
264
265 QFileInfo FolderView::currentItem() const
266 {
267     qDebug() << "FolderView::currentItem";
268
269     Q_ASSERT(currentIndex().isValid());
270
271     return m_model.fileInfo(currentIndex());
272 }
273
274 QFileInfoList FolderView::checkedItems() const
275 {
276     qDebug() << side() << "checkedItems()";
277
278     return m_model.checkedItems();
279 }
280
281 QFileInfoList FolderView::selectedItems() const
282 {
283     qDebug() << side() << "selectedItems";
284
285     // マークされているアイテムを取得する
286     QFileInfoList list = m_model.checkedItems();
287
288     // 一つもマークされていなければ、カーソル位置のアイテムを取得する
289     if (list.isEmpty()) {
290         list << currentItem();
291     }
292
293     return list;
294 }
295
296 void FolderView::setPath(const QString &path, bool addHistory)
297 {
298     qDebug() << side() << "setPath" << path << addHistory;
299
300     Q_ASSERT(QFileInfo(path).isDir());
301
302     emit retrieveStarted(path);
303
304     setUpdatesEnabled(false);
305     m_model.setPath(path);
306     setCurrentIndex(m_model.index(0, 0));
307     setUpdatesEnabled(true);
308
309     if (addHistory) {
310         m_history.add(path);
311     }
312
313     emit retrieveFinished();
314 }
315
316 void FolderView::setFilter(QDir::Filters filter, bool enable)
317 {
318     qDebug() << side() << "setFilter" << enable;
319
320     if (enable) {
321         m_model.setFilter(m_model.filter() | filter);
322     }
323     else {
324         m_model.setFilter(m_model.filter() ^ filter);
325     }
326 }
327
328 void FolderView::setHistoryIndexAt(int index)
329 {
330     m_history.setAt(index);
331     setPath(m_history.current(), false);
332 }
333
334 void FolderView::setNameFilters(const QStringList &list)
335 {
336     m_model.setNameFilters(list);
337     refresh();
338 }
339
340 void FolderView::setSorting(QDir::SortFlags flags)
341 {
342     m_model.setSorting(flags);
343     refresh();
344 }
345
346 void FolderView::keyPressEvent(QKeyEvent *event)
347 {
348     qDebug() << side() << "keyPressEvent";
349
350     emit keyPressed(event);
351
352     if (!event->isAccepted()) {
353         QTableView::keyPressEvent(event);
354     }
355     else {
356         qDebug() << "KeyEvent accepted.";
357     }
358 }
359
360 void FolderView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
361 {
362     emit dataChanged();
363
364     QTableView::dataChanged(topLeft, bottomRight, roles);
365 }
366
367 void FolderView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
368 {
369     emit currentChanged(m_model.fileInfo(current));
370
371     QTableView::currentChanged(current, previous);
372 }
373
374 void FolderView::mousePressEvent(QMouseEvent *event)
375 {
376     if ((event->buttons() & Qt::LeftButton) || (event->buttons() & Qt::RightButton))
377     {
378         m_dragStartPos = event->pos();
379     }
380
381     QTableView::mousePressEvent(event);
382 }
383
384 void FolderView::mouseMoveEvent(QMouseEvent *event)
385 {
386     if (!(event->buttons() & Qt::LeftButton) &&
387             !(event->buttons() & Qt::RightButton))
388     {
389         QTableView::mouseMoveEvent(event);
390         return;
391     }
392     if ((event->pos() - m_dragStartPos).manhattanLength()
393             < QApplication::startDragDistance())
394     {
395         QTableView::mouseMoveEvent(event);
396         return;
397     }
398
399     QFileInfoList list = selectedItems();
400     if (list.isEmpty()) {
401         QTableView::mousePressEvent(event);
402         return;
403     }
404
405     QList<QUrl> urls;
406     foreach (const QFileInfo &info, list) {
407         urls << QUrl::fromLocalFile(info.absoluteFilePath());
408     }
409
410     QDrag *drag = new QDrag(this);
411     QMimeData *mimeData = new QMimeData;
412     mimeData->setUrls(urls);
413     drag->setMimeData(mimeData);
414
415     m_dragging = true;
416     if (event->buttons() & Qt::RightButton) {
417         drag->exec(Qt::CopyAction | Qt::MoveAction);
418     }
419     else {
420         drag->exec(Qt::CopyAction);
421     }
422     m_dragging = false;
423 }
424
425 void FolderView::dragEnterEvent(QDragEnterEvent *event)
426 {
427     if (event->mimeData()->hasUrls()) {
428         event->acceptProposedAction();
429         return;
430     }
431
432     QTableView::dragEnterEvent(event);
433 }
434
435 void FolderView::dropEvent(QDropEvent *event)
436 {
437     qDebug() << side() << "dropEvent();";
438
439     if (m_dragging) {
440         event->ignore();
441         return;
442     }
443
444     QFileInfoList list;
445     foreach (const QUrl &url, event->mimeData()->urls()) {
446         QString path = QFileInfo(url.toLocalFile()).canonicalFilePath();
447         if (!path.isEmpty()) {
448             list << path;
449         }
450         else {
451             qDebug() << "path is empty." << url;
452         }
453     }
454
455     if (list.isEmpty()) {
456         event->ignore();
457         return;
458     }
459
460     event->acceptProposedAction();
461
462     emit dropAccepted(list);
463 }
464
465
466 void FolderView::contextMenuEvent(QContextMenuEvent *event)
467 {
468     qDebug() << side() << "contextMenuEvent();";
469
470     emit requestContextMenu(event);
471 }