OSDN Git Service

3fcdebe17afb1ae31010359ddd860bb486346695
[gefu/Gefu.git] / filetableview.cpp
1 #include "common.h"\r
2 #include "copymoveworker.h"\r
3 #include "deleteworker.h"\r
4 #include "filetablemodel.h"\r
5 #include "filetableview.h"\r
6 #include "historydialog.h"\r
7 #include "mainwindow.h"\r
8 #include "operationdialog.h"\r
9 #include "overwritedialog.h"\r
10 #include "renamemultidialog.h"\r
11 #include "renamesingledialog.h"\r
12 #include "renameworker.h"\r
13 #include "sortdialog.h"\r
14 \r
15 #include <QDebug>\r
16 #include <QDesktopServices>\r
17 #include <QInputDialog>\r
18 #include <QMessageBox>\r
19 #include <QProcess>\r
20 #include <QUrl>\r
21 #include <QAction>\r
22 #include <QSettings>\r
23 #include <QFileDialog>\r
24 #include <QKeyEvent>\r
25 #include <QStatusBar>\r
26 #include <QMimeData>\r
27 #include <QDrag>\r
28 #include <QApplication>\r
29 \r
30 #define CHECK_FOCUS {                   \\r
31         if (!hasFocus()) { return; }    \\r
32     }\r
33 \r
34 #define MENU_TRRIGGERED(x) \\r
35     getMainWnd()->findChild<QAction*>(#x), SIGNAL(triggered())\r
36 #define MENU_TOGGLED(x) \\r
37     getMainWnd()->findChild<QAction*>(#x), SIGNAL(toggled(bool))\r
38 \r
39 FileTableView::FileTableView(QWidget *parent) :\r
40     QTableView(parent),\r
41     m_side(),\r
42     m_history(),\r
43     m_dragStartPos(),\r
44     m_dragging(false)\r
45 {\r
46     // シグナル/スロットを設定する\r
47     connect(MENU_TRRIGGERED(action_Open), this, SLOT(setPath()));\r
48     connect(MENU_TRRIGGERED(action_Exec), this, SLOT(openUrl()));\r
49     connect(MENU_TRRIGGERED(action_OpenEditor), this, SLOT(openEditor()));\r
50     connect(MENU_TRRIGGERED(action_OpenTerminal), this, SLOT(openTerminal()));\r
51     connect(MENU_TRRIGGERED(action_Command), this, SLOT(kickProcess()));\r
52 \r
53     connect(MENU_TRRIGGERED(mark_Toggle), this, SLOT(toggleChecked()));\r
54     connect(MENU_TRRIGGERED(mark_All), this, SLOT(checkAllItems()));\r
55     connect(MENU_TRRIGGERED(mark_AllFiles), this, SLOT(checkAllFiles()));\r
56     connect(MENU_TRRIGGERED(mark_AllOff), this, SLOT(uncheckAllItems()));\r
57     connect(MENU_TRRIGGERED(mark_Invert), this, SLOT(invertAllChecked()));\r
58 \r
59     connect(MENU_TRRIGGERED(view_FromOther), this, SLOT(setPathFromOther()));\r
60     connect(MENU_TRRIGGERED(view_ToOther), this, SLOT(setPathToOther()));\r
61     connect(MENU_TRRIGGERED(view_Swap), this, SLOT(swapPath()));\r
62     connect(MENU_TRRIGGERED(view_Sort), this, SLOT(setSort()));\r
63     connect(MENU_TRRIGGERED(view_Refresh), this, SLOT(refresh()));\r
64     connect(MENU_TRRIGGERED(view_Filter), this, SLOT(setFilter()));\r
65 \r
66     connect(MENU_TRRIGGERED(move_Back), this, SLOT(back()));\r
67     connect(MENU_TRRIGGERED(move_Forward), this, SLOT(forward()));\r
68     connect(MENU_TRRIGGERED(move_History), this, SLOT(showHidtory()));\r
69     connect(MENU_TRRIGGERED(move_Home), this, SLOT(jumpToHome()));\r
70     connect(MENU_TRRIGGERED(move_Parent), this, SLOT(jumpToParent()));\r
71     connect(MENU_TRRIGGERED(move_Root), this, SLOT(jumpToRoot()));\r
72     connect(MENU_TRRIGGERED(move_Jump), this, SLOT(jumpTo()));\r
73     connect(MENU_TRRIGGERED(move_Down), this, SLOT(cursorDown()));\r
74     connect(MENU_TRRIGGERED(move_Up), this, SLOT(cursorUp()));\r
75     connect(MENU_TRRIGGERED(move_Begin), this, SLOT(cursorToBegin()));\r
76     connect(MENU_TRRIGGERED(move_End), this, SLOT(cursorToEnd()));\r
77 \r
78     connect(MENU_TRRIGGERED(cmd_Copy), this, SLOT(cmdCopy()));\r
79     connect(MENU_TRRIGGERED(cmd_Move), this, SLOT(cmdMove()));\r
80     connect(MENU_TRRIGGERED(cmd_Delete), this, SLOT(cmdDelete()));\r
81     connect(MENU_TRRIGGERED(cmd_Rename), this, SLOT(cmdRename()));\r
82     connect(MENU_TRRIGGERED(cmd_NewFile), this, SLOT(newFile()));\r
83     connect(MENU_TRRIGGERED(cmd_NewFolder), this, SLOT(newFolder()));\r
84 \r
85     connect(getMainWnd(), SIGNAL(showHiddenFiles(bool)),\r
86             this, SLOT(showHiddenFiles(bool)));\r
87     connect(getMainWnd(), SIGNAL(showSystemFiles(bool)),\r
88             this, SLOT(showSystemFiles(bool)));\r
89 \r
90     connect(this, SIGNAL(doubleClicked(QModelIndex)),\r
91             this, SLOT(onDoubleClick(QModelIndex)));\r
92 \r
93     // Drag & Drop\r
94     setDragEnabled(true);\r
95     setAcceptDrops(true);\r
96     setDropIndicatorShown(true);\r
97 }\r
98 \r
99 FileTableView::~FileTableView()\r
100 {\r
101     QSettings settings;\r
102     FileTableModel *m = static_cast<FileTableModel*>(model());\r
103 \r
104     settings.setValue(side() + slash + IniKey_Dir, m->absolutePath());\r
105 }\r
106 \r
107 QString FileTableView::side() const\r
108 {\r
109     return m_side;\r
110 }\r
111 \r
112 void FileTableView::setSide(const QString &side)\r
113 {\r
114     m_side = side;\r
115 \r
116     // コンストラクタではステータスバーが生成されていないため\r
117     // このタイミングでconnectする\r
118     connect(this, SIGNAL(indexChanged(QString)),\r
119             getMainWnd()->statusBar(), SLOT(showMessage(QString)));\r
120 }\r
121 \r
122 void FileTableView::setRootPath(const QString &path, bool addHistory)\r
123 {\r
124     FileTableModel *m = static_cast<FileTableModel*>(model());\r
125     QFileInfo info(path);\r
126 \r
127     if (info.isDir()) {\r
128         getMainWnd()->statusBar()->showMessage(tr("ファイルリストの取得中..."));\r
129 \r
130         setUpdatesEnabled(false);\r
131         m->setPath(info.absoluteFilePath());\r
132         setUpdatesEnabled(true);\r
133 \r
134         if (addHistory) {\r
135             m_history.add(info.absoluteFilePath());\r
136         }\r
137         updateMenu();\r
138 \r
139         selectRow(0);\r
140         getMainWnd()->statusBar()->showMessage(tr("レディ"), 5000);\r
141     }\r
142 }\r
143 \r
144 QFileInfoList FileTableView::selectedItems() const\r
145 {\r
146     FileTableModel *m = static_cast<FileTableModel*>(model());\r
147     QFileInfoList list = m->checkedItems();\r
148     if (list.isEmpty()) {\r
149         QFileInfo info = m->fileInfo(currentIndex());\r
150         if (info.fileName() != "..") {\r
151             list.append(info);\r
152         }\r
153     }\r
154 \r
155     return list;\r
156 }\r
157 \r
158 void FileTableView::updateMenu()\r
159 {\r
160     if (m_history.isEmpty()) {\r
161         getMainWnd()->findChild<QAction*>("move_Back")->setEnabled(false);\r
162         getMainWnd()->findChild<QAction*>("move_Forward")->setEnabled(false);\r
163 \r
164     }\r
165     else {\r
166         getMainWnd()->findChild<QAction*>("move_Back")\r
167                 ->setEnabled(!m_history.isBegin());\r
168         getMainWnd()->findChild<QAction*>("move_Forward")\r
169                 ->setEnabled(!m_history.isEnd());\r
170     }\r
171 }\r
172 \r
173 void FileTableView::setPath()\r
174 {\r
175     CHECK_FOCUS;\r
176 \r
177     setRootIndex(currentIndex());\r
178 }\r
179 \r
180 void FileTableView::openUrl(const QModelIndex &index)\r
181 {\r
182     CHECK_FOCUS;\r
183 \r
184     if (index.isValid()) {\r
185         FileTableModel *m = static_cast<FileTableModel*>(model());\r
186         QString path = QDir::toNativeSeparators(m->absoluteFilePath(index));\r
187         QDesktopServices::openUrl(QUrl("file:///" + path));\r
188     }\r
189     else {\r
190         QFileInfoList list = selectedItems();\r
191         foreach (const QFileInfo &info, list) {\r
192             QString path = QDir::toNativeSeparators(info.absoluteFilePath());\r
193             QDesktopServices::openUrl(QUrl("file:///" + path));\r
194         }\r
195     }\r
196 }\r
197 \r
198 void FileTableView::openEditor(const QString &path)\r
199 {\r
200     CHECK_FOCUS;\r
201 \r
202     QSettings settings;\r
203     if (settings.value(IniKey_EditorPath).toString().isEmpty()) {\r
204         QMessageBox::critical(\r
205                     this, tr("エラー"),\r
206                     tr("外部エディタのパスが未定義です。"));\r
207         return;\r
208     }\r
209 \r
210     QFileInfo info;\r
211     if (path.isEmpty()) {\r
212         FileTableModel *m = static_cast<FileTableModel*>(model());\r
213         info.setFile(m->absoluteFilePath(currentIndex()));\r
214     }\r
215     else {\r
216         info.setFile(path);\r
217     }\r
218 \r
219     QString exe = settings.value(IniKey_EditorPath).toString();\r
220     QString opt = settings.value(IniKey_EditorOption).toString();\r
221     opt.replace("$B", info.completeBaseName());\r
222     opt.replace("$E", info.suffix());\r
223     opt.replace("$F", info.fileName());\r
224     opt.replace("$D", info.absolutePath());\r
225     opt.replace("$P", info.absoluteFilePath());\r
226 \r
227     QString command;\r
228 #ifdef Q_OS_MAC\r
229     command = "open -a " + exe + " " + opt;\r
230 #else\r
231     command = QQ(exe) + " " + opt;\r
232 #endif\r
233     qDebug() << command;\r
234     QProcess process(this);\r
235     process.setWorkingDirectory(info.absolutePath());\r
236     if (!process.startDetached(command)) {\r
237         QMessageBox::critical(\r
238                     this, tr("エラー"),\r
239                     tr("外部エディタの起動に失敗しました。<br/>")\r
240                     + command);\r
241     }\r
242 }\r
243 \r
244 void FileTableView::openTerminal(const QString &path)\r
245 {\r
246     CHECK_FOCUS;\r
247 \r
248     QSettings settings;\r
249     if (settings.value(IniKey_TerminalPath).toString().isEmpty()) {\r
250         QMessageBox::critical(\r
251                     this, tr("エラー"),\r
252                     tr("ターミナルのパスが未定義です。"));\r
253         return;\r
254     }\r
255 \r
256     QFileInfo info;\r
257     if (path.isEmpty()) {\r
258         FileTableModel *m = static_cast<FileTableModel*>(model());\r
259         info.setFile(m->absoluteFilePath(currentIndex()));\r
260     }\r
261     else {\r
262         info.setFile(path);\r
263     }\r
264 \r
265     QString exe = settings.value(IniKey_TerminalPath).toString();\r
266     QString opt = settings.value(IniKey_TerminalOption).toString();\r
267     opt.replace("$B", info.completeBaseName());\r
268     opt.replace("$E", info.suffix());\r
269     opt.replace("$F", info.fileName());\r
270     if (info.isDir()) {\r
271         opt.replace("$D", info.absoluteFilePath());\r
272     }\r
273     else {\r
274         opt.replace("$D", info.absolutePath());\r
275     }\r
276     opt.replace("$P", info.absoluteFilePath());\r
277 \r
278     QString command;\r
279 #ifdef Q_OS_MAC\r
280     command = "open -a " + exe + " --args " + opt;\r
281 #else\r
282     command = QQ(exe) + " " + opt;\r
283 #endif\r
284     qDebug() << command;\r
285     QProcess process(this);\r
286     process.setWorkingDirectory(info.absolutePath());\r
287     if (!process.startDetached(command)) {\r
288         QMessageBox::critical(\r
289                     this, tr("エラー"),\r
290                     tr("ターミナルの起動に失敗しました。<br/>")\r
291                     + command);\r
292     }\r
293 }\r
294 \r
295 void FileTableView::kickProcess()\r
296 {\r
297     CHECK_FOCUS;\r
298 \r
299     QFileInfoList list = selectedItems();\r
300     QString command = QString::null;\r
301     foreach (const QFileInfo &info, list) {\r
302         if (info.isExecutable()) {\r
303             command = QQ(info.fileName()) + " " + command;\r
304         }\r
305         else {\r
306             command += " " + QQ(info.fileName());\r
307         }\r
308     }\r
309 \r
310     QInputDialog dlg(this);\r
311     dlg.setInputMode(QInputDialog::TextInput);\r
312     dlg.setWindowTitle(tr("コマンドを実行"));\r
313     dlg.setLabelText(tr("コマンド:"));\r
314     dlg.setTextValue(command);\r
315     dlg.resize(getMainWnd()->width() * 0.8, dlg.height());\r
316 \r
317     int ret = dlg.exec();\r
318     command = dlg.textValue();\r
319     if (ret == QDialog::Accepted && !command.isEmpty()) {\r
320         FileTableModel *m = static_cast<FileTableModel*>(model());\r
321         QProcess process(this);\r
322         process.setWorkingDirectory(m->absolutePath());\r
323         if (!process.startDetached(command)) {\r
324             QMessageBox::critical(\r
325                         this, tr("エラー"),\r
326                         tr("コマンドの実行に失敗しました。<br/>") + command);\r
327         }\r
328     }\r
329 }\r
330 \r
331 void FileTableView::toggleChecked()\r
332 {\r
333     CHECK_FOCUS;\r
334 \r
335     FileTableModel *m = static_cast<FileTableModel*>(model());\r
336 \r
337     QModelIndex index = currentIndex();\r
338 \r
339     QFileInfo info = m->fileInfo(index);\r
340     if (info.fileName() != "..") {\r
341         if (m->checkState(index) == Qt::Checked) {\r
342             m->setCheckState(index, Qt::Unchecked);\r
343         }\r
344         else {\r
345             m->setCheckState(index, Qt::Checked);\r
346         }\r
347     }\r
348     // 最終行でなければ、次のアイテムに移動する\r
349     if (index.row() == m->rowCount() - 1) {\r
350         setCurrentIndex(index);\r
351     }\r
352     else if (index.row() < m->rowCount() - 1) {\r
353         setCurrentIndex(m->index(index.row() + 1, 1));\r
354     }\r
355 }\r
356 \r
357 void FileTableView::checkAllItems()\r
358 {\r
359     CHECK_FOCUS;\r
360 \r
361     QModelIndex index = currentIndex();\r
362     FileTableModel *m = static_cast<FileTableModel*>(model());\r
363     setUpdatesEnabled(false);\r
364     m->setCheckStateAll(Qt::Checked);\r
365     setUpdatesEnabled(true);\r
366     setCurrentIndex(index);\r
367 }\r
368 \r
369 void FileTableView::checkAllFiles()\r
370 {\r
371     CHECK_FOCUS;\r
372 \r
373     QModelIndex index = currentIndex();\r
374     FileTableModel *m = static_cast<FileTableModel*>(model());\r
375     setUpdatesEnabled(false);\r
376     for (int n = 0; n < m->rowCount(); n++) {\r
377         QModelIndex index = m->index(n, 0);\r
378         QFileInfo info = m->fileInfo(index);\r
379         if (info.isDir()) {\r
380             m->setCheckState(index, Qt::Unchecked);\r
381         }\r
382         else {\r
383             m->setCheckState(index, Qt::Checked);\r
384         }\r
385         update(index);\r
386     }\r
387     setUpdatesEnabled(true);\r
388     setCurrentIndex(index);\r
389 }\r
390 \r
391 void FileTableView::uncheckAllItems()\r
392 {\r
393     CHECK_FOCUS;\r
394 \r
395     QModelIndex index = currentIndex();\r
396     FileTableModel *m = static_cast<FileTableModel*>(model());\r
397     setUpdatesEnabled(false);\r
398     m->setCheckStateAll(Qt::Unchecked);\r
399     setUpdatesEnabled(true);\r
400     setCurrentIndex(index);\r
401 }\r
402 \r
403 void FileTableView::invertAllChecked()\r
404 {\r
405     CHECK_FOCUS;\r
406 \r
407     QModelIndex index = currentIndex();\r
408     FileTableModel *m = static_cast<FileTableModel*>(model());\r
409     setUpdatesEnabled(false);\r
410     for (int n = 0; n < m->rowCount(); n++) {\r
411         QModelIndex index = m->index(n, 0);\r
412         if (m->checkState(index) == Qt::Checked) {\r
413             m->setCheckState(index, Qt::Unchecked);\r
414         }\r
415         else {\r
416             m->setCheckState(index, Qt::Checked);\r
417         }\r
418         update(index);\r
419     }\r
420     setUpdatesEnabled(true);\r
421     setCurrentIndex(index);\r
422 }\r
423 \r
424 void FileTableView::setPathFromOther()\r
425 {\r
426     CHECK_FOCUS;\r
427 \r
428     FileTableView *other = getMainWnd()->otherSideView(this);\r
429     if (other == NULL) {\r
430         return;\r
431     }\r
432 \r
433     FileTableModel *mOther = static_cast<FileTableModel*>(other->model());\r
434 \r
435     setRootPath(mOther->absolutePath(), true);\r
436 }\r
437 \r
438 void FileTableView::setPathToOther()\r
439 {\r
440     CHECK_FOCUS;\r
441 \r
442     FileTableView *other = getMainWnd()->otherSideView(this);\r
443     if (other == NULL) {\r
444         return;\r
445     }\r
446 \r
447     FileTableModel *m = static_cast<FileTableModel*>(model());\r
448 \r
449     other->setRootPath(m->absolutePath(), true);\r
450 }\r
451 \r
452 void FileTableView::swapPath()\r
453 {\r
454     CHECK_FOCUS;\r
455 \r
456     FileTableView *other = getMainWnd()->otherSideView(this);\r
457     if (other == NULL) {\r
458         return;\r
459     }\r
460 \r
461     FileTableModel *m = static_cast<FileTableModel*>(model());\r
462     FileTableModel *mOther = static_cast<FileTableModel*>(other->model());\r
463 \r
464     QString path = m->absolutePath();\r
465     QString pathOther = mOther->absolutePath();\r
466 \r
467     setRootPath(pathOther, true);\r
468     other->setRootPath(path, true);\r
469 }\r
470 \r
471 void FileTableView::showHiddenFiles(bool show)\r
472 {\r
473     FileTableModel *m = static_cast<FileTableModel*>(model());\r
474     if (show) {\r
475         m->setFilter(m->filter() | QDir::Hidden);\r
476     }\r
477     else {\r
478         m->setFilter(m->filter() ^ QDir::Hidden);\r
479     }\r
480 \r
481     setUpdatesEnabled(false);\r
482     refresh();\r
483     setUpdatesEnabled(true);\r
484 }\r
485 \r
486 void FileTableView::showSystemFiles(bool show)\r
487 {\r
488     FileTableModel *m = static_cast<FileTableModel*>(model());\r
489     if (show) {\r
490         m->setFilter(m->filter() | QDir::System);\r
491     }\r
492     else {\r
493         m->setFilter(m->filter() ^ QDir::System);\r
494     }\r
495 \r
496     setUpdatesEnabled(false);\r
497     refresh();\r
498     setUpdatesEnabled(true);\r
499 }\r
500 \r
501 void FileTableView::setSort()\r
502 {\r
503     CHECK_FOCUS;\r
504 \r
505     SortDialog dlg(this);\r
506     dlg.setRightOrLeft(side());\r
507     if (dlg.exec() == QDialog::Accepted) {\r
508         QSettings settings;\r
509         FileTableModel *m = static_cast<FileTableModel*>(model());\r
510         m->setSorting(QDir::Name);  // 0\r
511 \r
512         int sortBy = settings.value(side() + slash + IniKey_SortBy).toInt();\r
513         switch (sortBy) {\r
514         case SortByDate:    m->setSorting(m->sorting() | QDir::Time); break;\r
515         case SortBySize:    m->setSorting(m->sorting() | QDir::Size); break;\r
516         case SortByType:    m->setSorting(m->sorting() | QDir::Type); break;\r
517         default:            m->setSorting(m->sorting() | QDir::Name); break;\r
518         }\r
519 \r
520         // デフォルトだと文字列は昇順で、数値は降順…orz\r
521         int orderBy = settings.value(side() + slash + IniKey_OrderBy).toInt();\r
522         if (((sortBy == SortByName || sortBy == SortByType) && orderBy == OrderByDesc) ||\r
523             ((sortBy == SortByDate || sortBy == SortBySize) && orderBy == OrderByAsc))\r
524         {\r
525             m->setSorting(m->sorting() | QDir::Reversed);\r
526         }\r
527 \r
528         switch (settings.value(side() + slash + IniKey_PutDirs).toInt()) {\r
529         case PutDirsFirst:  m->setSorting(m->sorting() | QDir::DirsFirst); break;\r
530         case PutDirsLast:   m->setSorting(m->sorting() | QDir::DirsLast); break;\r
531         }\r
532 \r
533         if (settings.value(side() + slash + IniKey_IgnoreCase).toBool()) {\r
534             m->setSorting(m->sorting() | QDir::IgnoreCase);\r
535         }\r
536 \r
537         setUpdatesEnabled(false);\r
538         refresh();\r
539         setUpdatesEnabled(true);\r
540     }\r
541 }\r
542 \r
543 void FileTableView::refresh()\r
544 {\r
545     FileTableModel *m = static_cast<FileTableModel*>(model());\r
546     int row = currentIndex().row();\r
547     setRootPath(m->absolutePath(), false);\r
548     if (m->rowCount() <= row) {\r
549         row = m->rowCount() - 1;\r
550     }\r
551     setCurrentIndex(m->index(row, 0));\r
552     selectRow(row);\r
553 }\r
554 \r
555 void FileTableView::setFilter()\r
556 {\r
557     CHECK_FOCUS;\r
558 \r
559     QString filters = QString::null;\r
560     FileTableModel *m = static_cast<FileTableModel*>(model());\r
561     foreach (const QString &filter, m->nameFilters()) {\r
562         filters += filter + " ";\r
563     }\r
564 \r
565     QInputDialog dlg(this);\r
566     dlg.setInputMode(QInputDialog::TextInput);\r
567     dlg.setWindowTitle(tr("フィルタを設定"));\r
568     dlg.setLabelText(tr("フィルタ:"));\r
569     dlg.setTextValue(filters);\r
570     dlg.resize(getMainWnd()->width() * 0.8, dlg.height());\r
571 \r
572     if (dlg.exec() == QDialog::Accepted) {\r
573         filters = dlg.textValue();\r
574         if (filters.isEmpty()) {\r
575             filters = "*";\r
576         }\r
577         m->setNameFilters(filters.split(" ", QString::SkipEmptyParts));\r
578         refresh();\r
579         emit filterChanged();\r
580     }\r
581 }\r
582 \r
583 void FileTableView::back()\r
584 {\r
585     CHECK_FOCUS;\r
586 \r
587     if (!m_history.isBegin()) {\r
588         const QString &path = m_history.back();\r
589         setRootPath(path, false);\r
590 \r
591         updateMenu();\r
592     }\r
593 }\r
594 \r
595 void FileTableView::forward()\r
596 {\r
597     CHECK_FOCUS;\r
598 \r
599     if (!m_history.isEnd()) {\r
600         const QString &path = m_history.forward();\r
601         setRootPath(path, false);\r
602 \r
603         updateMenu();\r
604     }\r
605 }\r
606 \r
607 void FileTableView::showHidtory()\r
608 {\r
609     CHECK_FOCUS;\r
610 \r
611     FileTableView *other = getMainWnd()->otherSideView(this);\r
612 \r
613     HistoryDialog dlg(this);\r
614     if (side() == "Left") {\r
615         dlg.setDefaultLeft(true);\r
616         dlg.setHistory(&m_history, other->history());\r
617     }\r
618     else {\r
619         dlg.setDefaultLeft(false);\r
620         dlg.setHistory(other->history(), &m_history);\r
621     }\r
622 \r
623     if (dlg.exec() == QDialog::Accepted) {\r
624         if (side() == dlg.selectedSide()) {\r
625             m_history.setAt(dlg.selectedIndex());\r
626             setRootPath(m_history.current(), false);\r
627         }\r
628         else {\r
629             setRootPath(other->history()->at(dlg.selectedIndex()), true);\r
630         }\r
631         updateMenu();\r
632     }\r
633 }\r
634 \r
635 void FileTableView::jumpToHome()\r
636 {\r
637     CHECK_FOCUS;\r
638 \r
639     setRootPath(QDir::homePath(), true);\r
640 }\r
641 \r
642 void FileTableView::jumpToParent()\r
643 {\r
644     CHECK_FOCUS;\r
645 \r
646     FileTableModel *m = static_cast<FileTableModel*>(model());\r
647     QDir dir(m->absolutePath());\r
648     dir.cdUp();\r
649 \r
650     setRootPath(dir.absolutePath(), true);\r
651 }\r
652 \r
653 void FileTableView::jumpToRoot()\r
654 {\r
655     CHECK_FOCUS;\r
656 \r
657     setRootPath(QDir::rootPath(), true);\r
658 }\r
659 \r
660 void FileTableView::jumpTo()\r
661 {\r
662     CHECK_FOCUS;\r
663 \r
664     FileTableModel *m = static_cast<FileTableModel*>(model());\r
665     QString path = QFileDialog::getExistingDirectory(\r
666                 this, tr("フォルダを選択"), m->absolutePath());\r
667     if (!path.isEmpty()) {\r
668         setRootPath(path, true);\r
669     }\r
670 }\r
671 \r
672 void FileTableView::cursorDown()\r
673 {\r
674     CHECK_FOCUS;\r
675 \r
676     int row = currentIndex().row();\r
677     if (row < model()->rowCount() - 1) {\r
678         setCurrentIndex(model()->index(row + 1, 1));\r
679     }\r
680 }\r
681 \r
682 void FileTableView::cursorUp()\r
683 {\r
684     CHECK_FOCUS;\r
685 \r
686     int row = currentIndex().row();\r
687     if (row > 0) {\r
688         setCurrentIndex(model()->index(row - 1, 1));\r
689     }\r
690 }\r
691 \r
692 void FileTableView::cursorToBegin()\r
693 {\r
694     CHECK_FOCUS;\r
695 \r
696     setCurrentIndex(model()->index(0, 1));\r
697 }\r
698 \r
699 void FileTableView::cursorToEnd()\r
700 {\r
701     CHECK_FOCUS;\r
702 \r
703     setCurrentIndex(model()->index(model()->rowCount() - 1, 1));\r
704 }\r
705 \r
706 void FileTableView::cmdCopy()\r
707 {\r
708     CHECK_FOCUS;\r
709 \r
710     QFileInfoList list = selectedItems();\r
711     if (list.isEmpty()) {\r
712         return;\r
713     }\r
714 \r
715     QSettings settings;\r
716     if (settings.value(IniKey_ConfirmCopy).toBool()) {\r
717         int ret = QMessageBox::question(this, tr("確認"),\r
718                                         tr("コピーを実行しますか?"));\r
719         if (ret != QMessageBox::Yes) {\r
720             return;\r
721         }\r
722     }\r
723 \r
724     FileTableView *other = getMainWnd()->otherSideView(this);\r
725     FileTableModel *mOther = static_cast<FileTableModel*>(other->model());\r
726     CopyMoveWorker *worker = new CopyMoveWorker();\r
727     connect(worker, SIGNAL(askOverWrite(bool*,int*,int*,QString*,QString,QString)),\r
728             this, SLOT(askOverWrite(bool*,int*,int*,QString*,QString,QString)));\r
729     worker->setCopyList(&list);\r
730     worker->setTargetDir(mOther->absolutePath());\r
731     worker->setMoveMode(false);\r
732 \r
733     OperationDialog opDlg(this);\r
734     opDlg.setWindowTitle(tr("コピー"));\r
735     opDlg.setWorker(worker);\r
736     opDlg.setAutoClose(settings.value(IniKey_AutoCloseCopy).toBool());\r
737 \r
738     opDlg.exec();\r
739 \r
740     settings.setValue(IniKey_AutoCloseCopy, opDlg.autoClose());\r
741 }\r
742 \r
743 void FileTableView::cmdMove()\r
744 {\r
745     CHECK_FOCUS;\r
746 \r
747     QFileInfoList list = selectedItems();\r
748     if (list.isEmpty()) {\r
749         return;\r
750     }\r
751 \r
752     QSettings settings;\r
753     if (settings.value(IniKey_ConfirmMove).toBool()) {\r
754         int ret = QMessageBox::question(this, tr("確認"),\r
755                                         tr("移動を実行しますか?"));\r
756         if (ret != QMessageBox::Yes) {\r
757             return;\r
758         }\r
759     }\r
760 \r
761     FileTableView *other = getMainWnd()->otherSideView(this);\r
762     FileTableModel *mOther = static_cast<FileTableModel*>(other->model());\r
763     CopyMoveWorker *worker = new CopyMoveWorker();\r
764     connect(worker, SIGNAL(askOverWrite(bool*,int*,int*,QString*,QString,QString)),\r
765             this, SLOT(askOverWrite(bool*,int*,int*,QString*,QString,QString)));\r
766     worker->setCopyList(&list);\r
767     worker->setTargetDir(mOther->absolutePath());\r
768     worker->setMoveMode(true);\r
769 \r
770     OperationDialog opDlg(this);\r
771     opDlg.setWindowTitle(tr("移動"));\r
772     opDlg.setWorker(worker);\r
773     opDlg.setAutoClose(settings.value(IniKey_AutoCloseMove).toBool());\r
774 \r
775     opDlg.exec();\r
776 \r
777     settings.setValue(IniKey_AutoCloseMove, opDlg.autoClose());\r
778 }\r
779 \r
780 void FileTableView::cmdDelete()\r
781 {\r
782     CHECK_FOCUS;\r
783 \r
784     QFileInfoList list = selectedItems();\r
785     if (list.isEmpty()) {\r
786         return;\r
787     }\r
788 \r
789     QSettings settings;\r
790     if (settings.value(IniKey_ConfirmDelete).toBool()) {\r
791         QString msg;\r
792         if (list.size() == 1) {\r
793             msg = list[0].fileName();\r
794         }\r
795         else {\r
796             msg = tr("%1個のアイテム").arg(list.size());\r
797         }\r
798         int ret = QMessageBox::question(\r
799                     this, tr("確認"),\r
800                     msg + tr("を削除しますか?"));\r
801         if (ret != QMessageBox::Yes) {\r
802             return;\r
803         }\r
804     }\r
805     DeleteWorker *worker = new DeleteWorker();\r
806     worker->setDeleteList(&list);\r
807 \r
808     OperationDialog opDlg(this);\r
809     opDlg.setWindowTitle(tr("削除"));\r
810     opDlg.setWorker(worker);\r
811     opDlg.setAutoClose(settings.value(IniKey_AutoCloseDelete).toBool());\r
812 \r
813     opDlg.exec();\r
814 \r
815     settings.setValue(IniKey_AutoCloseDelete, opDlg.autoClose());\r
816 }\r
817 \r
818 void FileTableView::cmdRename()\r
819 {\r
820     CHECK_FOCUS;\r
821 \r
822     QFileInfoList list = selectedItems();\r
823     if (list.isEmpty()) {\r
824         return;\r
825     }\r
826 \r
827     IRenameDialog *dlg;\r
828     if (list.size() == 1) {\r
829         dlg = new RenameSingleDialog(this);\r
830     }\r
831     else {\r
832         dlg = new RenameMultiDialog(this);\r
833     }\r
834     FileTableModel *m = static_cast<FileTableModel*>(model());\r
835     dlg->setWorkingDirectory(m->absolutePath());\r
836     dlg->setNames(list);\r
837     int dlgResult = dlg->exec();\r
838     if (dlgResult == QDialog::Accepted && !dlg->renameMap().isEmpty()) {\r
839         QSettings settings;\r
840         if (settings.value(IniKey_ConfirmRename).toBool()) {\r
841             int ret = QMessageBox::question(this, tr("確認"),\r
842                                             tr("名前の変更を実行しますか?"));\r
843             if (ret != QMessageBox::Yes) {\r
844                 return;\r
845             }\r
846         }\r
847 \r
848         RenameWorker *worker = new RenameWorker();\r
849         worker->setRenameMap(&dlg->renameMap());\r
850 \r
851         OperationDialog opDlg(this);\r
852         opDlg.setWindowTitle(tr("名前を変更"));\r
853         opDlg.setWorker(worker);\r
854         opDlg.setAutoClose(settings.value(IniKey_AutoCloseRename).toBool());\r
855 \r
856         opDlg.exec();\r
857 \r
858         settings.setValue(IniKey_AutoCloseRename, opDlg.autoClose());\r
859     }\r
860 }\r
861 \r
862 void FileTableView::newFile()\r
863 {\r
864     CHECK_FOCUS;\r
865 \r
866     bool bOk;\r
867     QString name = QInputDialog::getText(\r
868                 this, tr("ファイルを作成"), tr("ファイル名:"),\r
869                 QLineEdit::Normal, "", &bOk);\r
870     if (bOk && !name.isEmpty()) {\r
871         FileTableModel *m = static_cast<FileTableModel*>(model());\r
872         QDir dir(m->absolutePath());\r
873         QFile file(dir.absoluteFilePath(name));\r
874         if (!file.open(QIODevice::WriteOnly)) {\r
875             QMessageBox::critical(\r
876                         this, tr("エラー"),\r
877                         tr("ファイルの作成に失敗しました。"));\r
878         }\r
879         else {\r
880             file.close();\r
881 \r
882             QSettings settings;\r
883             if (settings.value(IniKey_OpenAfterCreateFile).toBool()) {\r
884                 openEditor(dir.absoluteFilePath(name));\r
885             }\r
886         }\r
887     }\r
888 }\r
889 \r
890 void FileTableView::newFolder()\r
891 {\r
892     CHECK_FOCUS;\r
893 \r
894     bool bOk;\r
895     QString name = QInputDialog::getText(\r
896                 this, tr("フォルダを作成"), tr("フォルダ名:"),\r
897                 QLineEdit::Normal, "", &bOk);\r
898     if (bOk && !name.isEmpty()) {\r
899         FileTableModel *m = static_cast<FileTableModel*>(model());\r
900         QDir dir(m->absolutePath());\r
901         if (!dir.mkpath(name)) {\r
902             QMessageBox::critical(\r
903                         this, tr("エラー"),\r
904                         tr("フォルダの作成に失敗しました。"));\r
905         }\r
906         else {\r
907             QSettings settings;\r
908             if (settings.value(IniKey_MoveAfterCreateFolder).toBool()) {\r
909                 setRootPath(dir.absoluteFilePath(name), true);\r
910             }\r
911         }\r
912     }\r
913 }\r
914 \r
915 void FileTableView::XXX()\r
916 {\r
917     CHECK_FOCUS;\r
918 \r
919     qDebug() << sender()->objectName() << "に対するスロットは未実装です。";\r
920 }\r
921 \r
922 void FileTableView::askOverWrite(bool *bOk, int *prevCopyMethod, int *copyMethod,\r
923                                  QString *alias, const QString &srcPath,\r
924                                  const QString &tgtPath)\r
925  {\r
926      OverWriteDialog dlg;\r
927      if (*prevCopyMethod == OverWriteDialog::Undefined) {\r
928          QSettings settings;\r
929          QString method = settings.value(IniKey_DefaultOnCopy).toString();\r
930          if (method == "owDefOverWrite") {\r
931              *prevCopyMethod = OverWriteDialog::OverWrite;\r
932          }\r
933          else if (method == "owDefSkip") {\r
934              *prevCopyMethod = OverWriteDialog::Skip;\r
935          }\r
936          else if (method == "owDefAppendNumber") {\r
937              *prevCopyMethod = OverWriteDialog::AppendNumber;\r
938          }\r
939          else if (method == "owDefRename") {\r
940              *prevCopyMethod = OverWriteDialog::Rename;\r
941          }\r
942          else {\r
943              *prevCopyMethod = OverWriteDialog::OverWriteIfNew;\r
944          }\r
945      }\r
946      dlg.setCopyMethod(*prevCopyMethod);\r
947      dlg.setSameMethodChecked(*copyMethod != OverWriteDialog::Undefined);\r
948      dlg.setFileInfo(srcPath, tgtPath);\r
949      if (dlg.exec() == QDialog::Rejected) {\r
950          *bOk = false;\r
951      }\r
952      else {\r
953          *prevCopyMethod = dlg.copyMethod();\r
954          if (dlg.isSameMethodChecked()) {\r
955              *copyMethod = *prevCopyMethod;\r
956          }\r
957          *alias = dlg.alias();\r
958          *bOk = true;\r
959      }\r
960      CopyMoveWorker *worker = static_cast<CopyMoveWorker*>(sender());\r
961      worker->endAsking();\r
962 }\r
963 \r
964 void FileTableView::onDoubleClick(const QModelIndex &index)\r
965 {\r
966     if (!index.isValid()) {\r
967         return;\r
968     }\r
969 \r
970     FileTableModel *m = static_cast<FileTableModel*>(model());\r
971 \r
972     if (m->isDir(index)) {\r
973         if (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier)) {\r
974             openTerminal(m->absoluteFilePath(index));\r
975         }\r
976         else {\r
977             setRootPath(m->absoluteFilePath(index), true);\r
978         }\r
979     }\r
980     else if (QApplication::keyboardModifiers().testFlag(Qt::ShiftModifier)){\r
981         openEditor(m->absoluteFilePath(index));\r
982     }\r
983     else {\r
984         openUrl(index);\r
985     }\r
986 \r
987 }\r
988 \r
989 void FileTableView::setRootIndex(const QModelIndex &index)\r
990 {\r
991     if (!index.isValid()) {\r
992         return;\r
993     }\r
994 \r
995     FileTableModel *m = static_cast<FileTableModel*>(model());\r
996 \r
997     if (m->isDir(index)) {\r
998         setRootPath(m->absoluteFilePath(index), true);\r
999     }\r
1000 }\r
1001 \r
1002 void FileTableView::keyPressEvent(QKeyEvent *event)\r
1003 {\r
1004     // Macでアクションが処理されないケースがあるため、\r
1005     // キーイベントを拾ってアクションシグナルを起動する\r
1006     QString modifier = QString::null;\r
1007     if (event->modifiers() & Qt::ShiftModifier)     { modifier += "Shift+"; }\r
1008     if (event->modifiers() & Qt::ControlModifier)   { modifier += "Ctrl+"; }\r
1009     if (event->modifiers() & Qt::AltModifier)       { modifier += "Alt+"; }\r
1010     if (event->modifiers() & Qt::MetaModifier)      { modifier += "Meta+"; }\r
1011 \r
1012     QString key = QKeySequence(event->key()).toString();\r
1013     QString ksq = QKeySequence(modifier + key).toString();\r
1014 \r
1015     if (!ksq.isEmpty()) {\r
1016         foreach (QObject *obj, getMainWnd()->children()) {\r
1017             QAction *action = qobject_cast<QAction*>(obj);\r
1018             if (action) {\r
1019                 foreach (const QKeySequence &keySeq, action->shortcuts()) {\r
1020                     if (ksq == keySeq.toString()) {\r
1021                         qDebug() << "emit " << ksq << " " << action->objectName();\r
1022                         emit action->triggered();\r
1023                         event->accept();\r
1024                         return;\r
1025                     }\r
1026                 }\r
1027             }\r
1028         }\r
1029     }\r
1030 \r
1031     if (!ksq.isEmpty() && ksq != "Down" && ksq != "Up") {\r
1032         qDebug() << ksq;\r
1033     }\r
1034     QTableView::keyPressEvent(event);\r
1035 }\r
1036 \r
1037 void FileTableView::focusInEvent(QFocusEvent *event)\r
1038 {\r
1039     qDebug() << "focusInEvent();";\r
1040     if (!currentIndex().isValid()) {\r
1041         FileTableModel *m = static_cast<FileTableModel*>(model());\r
1042         if (m) {\r
1043             setCurrentIndex(m->index(0, 0));\r
1044         }\r
1045     }\r
1046 \r
1047     updateMenu();\r
1048 \r
1049     QTableView::focusInEvent(event);\r
1050 }\r
1051 \r
1052 void FileTableView::currentChanged(const QModelIndex &current, const QModelIndex &previous)\r
1053 {\r
1054     Q_UNUSED(previous);\r
1055 \r
1056     FileTableModel *m = static_cast<FileTableModel*>(model());\r
1057     emit indexChanged(m->absoluteFilePath(current));\r
1058 \r
1059     QTableView::currentChanged(current, previous);\r
1060 }\r
1061 \r
1062 \r
1063 void FileTableView::dropEvent(QDropEvent *event)\r
1064 {\r
1065     if (m_dragging) {\r
1066         event->ignore();\r
1067         return;\r
1068     }\r
1069 \r
1070     QFileInfoList list;\r
1071     foreach (const QUrl &url, event->mimeData()->urls()) {\r
1072         QFileInfo info(url.toLocalFile());\r
1073         QString path = info.canonicalFilePath();\r
1074         if (!path.isEmpty()) {\r
1075             list << path;\r
1076         }\r
1077         else {\r
1078             qDebug() << "path is empty.";\r
1079         }\r
1080     }\r
1081 \r
1082     if (list.isEmpty()) {\r
1083         event->ignore();\r
1084         return;\r
1085     }\r
1086     event->acceptProposedAction();\r
1087 \r
1088     FileTableModel *m = static_cast<FileTableModel*>(model());\r
1089     CopyMoveWorker *worker = new CopyMoveWorker();\r
1090     connect(worker, SIGNAL(askOverWrite(bool*,int*,int*,QString*,QString,QString)),\r
1091             this, SLOT(askOverWrite(bool*,int*,int*,QString*,QString,QString)));\r
1092     worker->setCopyList(&list);\r
1093     worker->setTargetDir(m->absolutePath());\r
1094     worker->setMoveMode(false);\r
1095 \r
1096     OperationDialog opDlg(this);\r
1097     opDlg.setWindowTitle(tr("コピー"));\r
1098     opDlg.setWorker(worker);\r
1099 \r
1100     opDlg.exec();\r
1101 }\r
1102 \r
1103 \r
1104 void FileTableView::dragEnterEvent(QDragEnterEvent *event)\r
1105 {\r
1106     if (event->mimeData()->hasUrls()) {\r
1107         event->acceptProposedAction();\r
1108         return;\r
1109     }\r
1110 \r
1111     QTableView::dragEnterEvent(event);\r
1112 }\r
1113 \r
1114 void FileTableView::mousePressEvent(QMouseEvent *event)\r
1115 {\r
1116     if ((event->buttons() & Qt::LeftButton) || (event->buttons() & Qt::RightButton))\r
1117     {\r
1118         m_dragStartPos = event->pos();\r
1119     }\r
1120 \r
1121     QTableView::mousePressEvent(event);\r
1122 }\r
1123 \r
1124 void FileTableView::mouseMoveEvent(QMouseEvent *event)\r
1125 {\r
1126     if (!(event->buttons() & Qt::LeftButton) &&\r
1127         !(event->buttons() & Qt::RightButton))\r
1128     {\r
1129         QTableView::mouseMoveEvent(event);\r
1130         return;\r
1131     }\r
1132     if ((event->pos() - m_dragStartPos).manhattanLength()\r
1133             < QApplication::startDragDistance())\r
1134     {\r
1135         QTableView::mouseMoveEvent(event);\r
1136         return;\r
1137     }\r
1138 \r
1139     QFileInfoList list = selectedItems();\r
1140     if (list.isEmpty()) {\r
1141         QTableView::mousePressEvent(event);\r
1142         return;\r
1143     }\r
1144 \r
1145     QList<QUrl> urls;\r
1146     foreach (const QFileInfo &info, list) {\r
1147         urls << QUrl::fromLocalFile(info.absoluteFilePath());\r
1148     }\r
1149 \r
1150     QDrag *drag = new QDrag(this);\r
1151     QMimeData *mimeData = new QMimeData;\r
1152     mimeData->setUrls(urls);\r
1153     drag->setMimeData(mimeData);\r
1154 \r
1155     m_dragging = true;\r
1156     if (event->buttons() & Qt::RightButton) {\r
1157         drag->exec(Qt::CopyAction | Qt::MoveAction);\r
1158     }\r
1159     else {\r
1160         drag->exec(Qt::CopyAction);\r
1161     }\r
1162     m_dragging = false;\r
1163 }\r