1 | // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. |
2 | // |
3 | // SPDX-License-Identifier: GPL-3.0-or-later |
4 | |
5 | #include "treeview.h" |
6 | #include "transceiver/sendevents.h" |
7 | |
8 | #include "common/common.h" |
9 | |
10 | #include <QHeaderView> |
11 | #include <QMenu> |
12 | #include <QDebug> |
13 | #include <QContextMenuEvent> |
14 | #include <QFileSystemModel> |
15 | #include <QStack> |
16 | |
17 | const QString NEW_DOCUMENT_NAME = "NewDocument.txt" ; |
18 | const QString NEW_FOLDER_NAME = "NewFolder" ; |
19 | const QString DELETE_MESSAGE_TEXT {QTreeView::tr("The delete operation will be removed from" |
20 | "the disk and will not be recoverable " |
21 | "after this operation.\nDelete anyway?" )}; |
22 | |
23 | const QString DELETE_WINDOW_TEXT {QTreeView::tr("Delete Warning" )}; |
24 | |
25 | class TreeViewPrivate |
26 | { |
27 | friend class TreeView; |
28 | QFileSystemModel *model {nullptr}; |
29 | QMenu* {nullptr}; |
30 | QStack<QStringList> moveToTrashStack; |
31 | dpfservice::ProjectInfo proInfo; |
32 | }; |
33 | |
34 | TreeView::TreeView(QWidget *parent) |
35 | : QTreeView (parent) |
36 | , d (new TreeViewPrivate) |
37 | { |
38 | d->model = new QFileSystemModel(this); |
39 | d->menu = new QMenu(this); |
40 | setModel(d->model); |
41 | header()->setSectionResizeMode(QHeaderView::ResizeMode::ResizeToContents); |
42 | QObject::connect(this, &QTreeView::doubleClicked, this, &TreeView::doDoubleClicked); |
43 | } |
44 | |
45 | TreeView::~TreeView() |
46 | { |
47 | if (d) { |
48 | delete d; |
49 | } |
50 | } |
51 | |
52 | void TreeView::setProjectInfo(const dpfservice::ProjectInfo &proInfo) |
53 | { |
54 | d->proInfo = proInfo; |
55 | d->model->setRootPath(proInfo.workspaceFolder()); |
56 | auto index = d->model->index(proInfo.workspaceFolder()); |
57 | QTreeView::expand(index); |
58 | QTreeView::setRootIndex(index); |
59 | emit rootPathChanged(proInfo.workspaceFolder()); |
60 | } |
61 | |
62 | void TreeView::selOpen() |
63 | { |
64 | QModelIndexList indexs = selectedIndexes(); |
65 | QSet<QString> countPaths; |
66 | for (auto index : indexs) { |
67 | countPaths << d->model->filePath(index); |
68 | } |
69 | |
70 | for (auto path : countPaths) { |
71 | if (QFileInfo(path).isFile()) |
72 | editor.openFile(path); |
73 | } |
74 | } |
75 | |
76 | void TreeView::selMoveToTrash() |
77 | { |
78 | QModelIndexList indexs = selectedIndexes(); |
79 | QSet<QString> countPaths; |
80 | for (auto index : indexs) { |
81 | countPaths << d->model->filePath(index); |
82 | } |
83 | |
84 | QStringList errFilePaths; |
85 | QStringList okFilePaths; |
86 | bool hasError = false; |
87 | for (auto path : countPaths) { |
88 | bool currErr = !FileOperation::doMoveMoveToTrash(path); |
89 | if (currErr){ |
90 | errFilePaths << path; |
91 | hasError = true; |
92 | } else { |
93 | okFilePaths << path; |
94 | } |
95 | } |
96 | |
97 | if (!hasError) { |
98 | d->moveToTrashStack.push(okFilePaths); |
99 | } else { |
100 | QString errMess; |
101 | for (auto errFilePath : errFilePaths) { |
102 | errMess = QTreeView::tr("Error, Can't move to trash: " ) + "\n" |
103 | + errFilePath + "\n" ; |
104 | } |
105 | ContextDialog::ok(errMess); |
106 | } |
107 | } |
108 | |
109 | void TreeView::selRemove() |
110 | { |
111 | QModelIndexList indexs = selectedIndexes(); |
112 | QSet<QString> countPaths; |
113 | for (auto index : indexs) { |
114 | countPaths << d->model->filePath(index); |
115 | } |
116 | |
117 | bool doDeleta = false; |
118 | auto okCallBack = [&](bool checked) { |
119 | Q_UNUSED(checked); |
120 | doDeleta = true; |
121 | }; |
122 | |
123 | QString mess = DELETE_MESSAGE_TEXT + "\n" ; |
124 | for (auto path : countPaths) { |
125 | mess += path + "\n" ; |
126 | } |
127 | |
128 | ContextDialog::okCancel(mess, |
129 | DELETE_WINDOW_TEXT, |
130 | QMessageBox::Warning, |
131 | okCallBack, |
132 | nullptr); |
133 | |
134 | if (!doDeleta) |
135 | return; |
136 | |
137 | bool hasError = false; |
138 | QStringList errFilePaths; |
139 | for (auto currPath : countPaths){ |
140 | bool currErr = !FileOperation::doRemove(currPath); |
141 | if (currErr){ |
142 | errFilePaths << currPath; |
143 | hasError = true; |
144 | } |
145 | } |
146 | |
147 | if (hasError) { |
148 | QString errMess; |
149 | for (auto errFilePath : errFilePaths) { |
150 | errMess = QTreeView::tr("Error, Can't move to trash: " ) + "\n" |
151 | + errFilePath + "\n" ; |
152 | } |
153 | ContextDialog::ok(errMess); |
154 | } |
155 | } |
156 | |
157 | void TreeView::selNewDocument() |
158 | { |
159 | QModelIndexList indexs = selectedIndexes(); |
160 | bool hasErr = false; |
161 | QString errString; |
162 | if (indexs.size() == 1) { |
163 | QString filePath = d->model->filePath(indexs[0]); |
164 | QFileInfo info(filePath); |
165 | if (info.isDir()) { |
166 | hasErr = !FileOperation::doNewDocument(filePath, NEW_DOCUMENT_NAME); |
167 | if (hasErr) |
168 | errString = QTreeView::tr("Error: Can't create New Document" ); |
169 | } else { |
170 | hasErr = true; |
171 | errString = QTreeView::tr("Error: Create New Document, parent not's dir" ); |
172 | } |
173 | } |
174 | |
175 | if (hasErr) |
176 | ContextDialog::ok(errString); |
177 | } |
178 | |
179 | void TreeView::selNewFolder() |
180 | { |
181 | QModelIndexList indexs = selectedIndexes(); |
182 | bool hasErr = false; |
183 | QString errString; |
184 | if (indexs.size() > 0) { |
185 | QString filePath = d->model->filePath(indexs[0]); |
186 | QFileInfo info(filePath); |
187 | if (info.isDir()) { |
188 | hasErr = !FileOperation::doNewFolder(filePath, NEW_FOLDER_NAME); |
189 | if (hasErr) |
190 | errString = QTreeView::tr("Error: Can't create new folder" ); |
191 | } else { |
192 | hasErr = true; |
193 | errString = QTreeView::tr("Error: Create new folder, parent not's dir" ); |
194 | } |
195 | } |
196 | |
197 | if (hasErr) |
198 | ContextDialog::ok(errString); |
199 | } |
200 | |
201 | void TreeView::recoverFromTrash() |
202 | { |
203 | if (!d->moveToTrashStack.isEmpty()) { |
204 | auto filePaths = d->moveToTrashStack.pop(); |
205 | for (auto filePath : filePaths) { |
206 | FileOperation::doRecoverFromTrash(filePath); |
207 | } |
208 | } |
209 | } |
210 | |
211 | void TreeView::doDoubleClicked(const QModelIndex &index) |
212 | { |
213 | QString filePath = d->model->filePath(index); |
214 | if (QFileInfo(filePath).isFile()) |
215 | editor.openFile(filePath); |
216 | } |
217 | |
218 | void TreeView::(QContextMenuEvent *event) |
219 | { |
220 | QModelIndex index = QTreeView::indexAt(event->pos()); |
221 | if (index.isValid()) { |
222 | d->menu = createContextMenu(selectedIndexes()); |
223 | } else { |
224 | d->menu = createEmptyMenu(); |
225 | } |
226 | d->menu->exec(viewport()->mapToGlobal(event->pos())); |
227 | } |
228 | |
229 | QMenu *TreeView::(const QModelIndexList &indexs) |
230 | { |
231 | QMenu * = new QMenu(); |
232 | bool hasDir = false; |
233 | bool selOne = indexs.size() == 0; |
234 | for (auto index: indexs) { |
235 | if (d->model->isDir(index)) |
236 | hasDir = true; |
237 | } |
238 | |
239 | QAction *openAction = new QAction(QAction::tr("Open" )); |
240 | QObject::connect(openAction, &QAction::triggered, this, &TreeView::selOpen); |
241 | menu->addAction(openAction); |
242 | if (hasDir) { |
243 | openAction->setEnabled(false); |
244 | } |
245 | |
246 | if (selOne || hasDir) { |
247 | QAction *newFolderAction = new QAction(QAction::tr("New Folder" )); |
248 | QAction *newDocumentAction = new QAction(QAction::tr("New Document" )); |
249 | |
250 | QObject::connect(newFolderAction, &QAction::triggered, this, &TreeView::selNewFolder); |
251 | QObject::connect(newDocumentAction, &QAction::triggered, this, &TreeView::selNewDocument); |
252 | menu->addSeparator(); |
253 | menu->addAction(newFolderAction); |
254 | menu->addAction(newDocumentAction); |
255 | } |
256 | |
257 | QAction *moveToTrashAction = new QAction(QAction::tr("Move To Trash" )); |
258 | QAction *removeAction = new QAction(QAction::tr("Remove" )); |
259 | QObject::connect(moveToTrashAction, &QAction::triggered, this, &TreeView::selMoveToTrash); |
260 | QObject::connect(removeAction, &QAction::triggered, this, &TreeView::selRemove); |
261 | |
262 | menu->addSeparator(); |
263 | menu->addAction(moveToTrashAction); |
264 | menu->addAction(removeAction); |
265 | return menu; |
266 | } |
267 | |
268 | QMenu *TreeView::() |
269 | { |
270 | QMenu * = new QMenu(); |
271 | QAction *recoverFromTrashAction = new QAction(QAction::tr("Recover From Trash" )); |
272 | QObject::connect(recoverFromTrashAction, &QAction::triggered, |
273 | this, &TreeView::recoverFromTrash); |
274 | menu->addAction(recoverFromTrashAction); |
275 | return menu; |
276 | } |
277 | |