1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 |
3 | #include "bookmarkmanagerwidget.h" |
4 | #include "bookmarkitem.h" |
5 | #include "bookmarkmodel.h" |
6 | #include "tracer.h" |
7 | #include "xbelsupport.h" |
8 | |
9 | #include <QtWidgets/QFileDialog> |
10 | #include <QtWidgets/QMessageBox> |
11 | |
12 | #include <QtGui/QCloseEvent> |
13 | #include <QtGui/QKeySequence> |
14 | #include <QtGui/QShortcut> |
15 | |
16 | #include <QtCore/QCoreApplication> |
17 | #include <QtCore/QFile> |
18 | #include <QtCore/QUrl> |
19 | |
20 | QT_BEGIN_NAMESPACE |
21 | |
22 | BookmarkManagerWidget::BookmarkManagerWidget(BookmarkModel *sourceModel, |
23 | QWidget *parent) |
24 | : QWidget(parent) |
25 | , bookmarkModel(sourceModel) |
26 | { |
27 | TRACE_OBJ |
28 | ui.setupUi(this); |
29 | |
30 | ui.treeView->setModel(bookmarkModel); |
31 | |
32 | ui.treeView->expandAll(); |
33 | ui.treeView->installEventFilter(this); |
34 | ui.treeView->viewport()->installEventFilter(this); |
35 | ui.treeView->setContextMenuPolicy(Qt::CustomContextMenu); |
36 | |
37 | connect(ui.treeView, &QWidget::customContextMenuRequested, |
38 | this, &BookmarkManagerWidget::customContextMenuRequested); |
39 | |
40 | connect(ui.remove, &QAbstractButton::clicked, |
41 | this, [this]() { removeItem(); }); |
42 | connect(ui.lineEdit, &QLineEdit::textChanged, |
43 | this, &BookmarkManagerWidget::textChanged); |
44 | QShortcut *shortcut = new QShortcut(QKeySequence::Find, ui.lineEdit); |
45 | connect(shortcut, &QShortcut::activated, |
46 | ui.lineEdit, QOverload<>::of(&QWidget::setFocus)); |
47 | |
48 | importExportMenu.addAction(text: tr(s: "Import..." ), args: this, |
49 | args: &BookmarkManagerWidget::importBookmarks); |
50 | importExportMenu.addAction(text: tr(s: "Export..." ), args: this, |
51 | args: &BookmarkManagerWidget::exportBookmarks); |
52 | ui.importExport->setMenu(&importExportMenu); |
53 | |
54 | shortcut = new QShortcut(QKeySequence::FindNext, this); |
55 | connect(shortcut, &QShortcut::activated, |
56 | this, &BookmarkManagerWidget::findNext); |
57 | shortcut = new QShortcut(QKeySequence::FindPrevious, this); |
58 | connect(shortcut, &QShortcut::activated, |
59 | this, &BookmarkManagerWidget::findPrevious); |
60 | |
61 | connect(bookmarkModel, &QAbstractItemModel::rowsRemoved, |
62 | this, &BookmarkManagerWidget::refeshBookmarkCache); |
63 | connect(bookmarkModel, &QAbstractItemModel::rowsInserted, |
64 | this, &BookmarkManagerWidget::refeshBookmarkCache); |
65 | connect(bookmarkModel, &QAbstractItemModel::dataChanged, |
66 | this, &BookmarkManagerWidget::refeshBookmarkCache); |
67 | |
68 | ui.treeView->setCurrentIndex(ui.treeView->indexAt(QPoint(2, 2))); |
69 | } |
70 | |
71 | BookmarkManagerWidget::~BookmarkManagerWidget() |
72 | { |
73 | TRACE_OBJ |
74 | } |
75 | |
76 | void BookmarkManagerWidget::closeEvent(QCloseEvent *event) |
77 | { |
78 | TRACE_OBJ |
79 | event->accept(); |
80 | emit managerWidgetAboutToClose(); |
81 | } |
82 | |
83 | void BookmarkManagerWidget::renameItem(const QModelIndex &index) |
84 | { |
85 | TRACE_OBJ |
86 | // check if we should rename the "Bookmarks Menu", bail |
87 | if (!bookmarkModel->parent(index).isValid()) |
88 | return; |
89 | |
90 | bookmarkModel->setItemsEditable(true); |
91 | ui.treeView->edit(index); |
92 | bookmarkModel->setItemsEditable(false); |
93 | } |
94 | |
95 | static int nextIndex(int current, int count, bool forward) |
96 | { |
97 | TRACE_OBJ |
98 | if (current >= 0) |
99 | return (forward ? (current + 1) : ((current - 1) + count)) % count; |
100 | return 0; |
101 | } |
102 | |
103 | void BookmarkManagerWidget::selectNextIndex(bool direction) const |
104 | { |
105 | QModelIndex current = ui.treeView->currentIndex(); |
106 | if (current.isValid() && !cache.isEmpty()) { |
107 | current = cache.at(i: nextIndex(current: cache.indexOf(t: current), count: cache.size(), |
108 | forward: direction)); |
109 | } |
110 | ui.treeView->setCurrentIndex(current); |
111 | } |
112 | |
113 | bool BookmarkManagerWidget::eventFilter(QObject *object, QEvent *event) |
114 | { |
115 | TRACE_OBJ |
116 | if (object != ui.treeView && object != ui.treeView->viewport()) |
117 | return QWidget::eventFilter(object, event); |
118 | |
119 | if (event->type() == QEvent::KeyPress) { |
120 | QKeyEvent *ke = static_cast<QKeyEvent*>(event); |
121 | switch (ke->key()) { |
122 | case Qt::Key_F2: |
123 | renameItem(ui.treeView->currentIndex()); |
124 | break; |
125 | |
126 | case Qt::Key_Delete: |
127 | removeItem(ui.treeView->currentIndex()); |
128 | break; |
129 | |
130 | default: break; |
131 | } |
132 | } |
133 | |
134 | if (event->type() == QEvent::MouseButtonRelease) { |
135 | QMouseEvent *me = static_cast<QMouseEvent*>(event); |
136 | switch (me->button()) { |
137 | case Qt::LeftButton: |
138 | if (me->modifiers() & Qt::ControlModifier) |
139 | setSourceFromIndex(ui.treeView->currentIndex(), true); |
140 | break; |
141 | |
142 | case Qt::MiddleButton: |
143 | setSourceFromIndex(ui.treeView->currentIndex(), true); |
144 | break; |
145 | |
146 | default: break; |
147 | } |
148 | } |
149 | return QObject::eventFilter(object, event); |
150 | } |
151 | |
152 | void BookmarkManagerWidget::findNext() |
153 | { |
154 | TRACE_OBJ |
155 | selectNextIndex(direction: true); |
156 | } |
157 | |
158 | void BookmarkManagerWidget::findPrevious() |
159 | { |
160 | TRACE_OBJ |
161 | selectNextIndex(direction: false); |
162 | } |
163 | |
164 | void BookmarkManagerWidget::importBookmarks() |
165 | { |
166 | TRACE_OBJ |
167 | const QString &fileName = QFileDialog::getOpenFileName(parent: nullptr, caption: tr(s: "Open File" ), |
168 | dir: QDir::currentPath(), filter: tr(s: "Files (*.xbel)" )); |
169 | |
170 | if (fileName.isEmpty()) |
171 | return; |
172 | |
173 | QFile file(fileName); |
174 | if (file.open(flags: QIODevice::ReadOnly)) { |
175 | XbelReader reader(bookmarkModel); |
176 | reader.readFromFile(device: &file); |
177 | } |
178 | } |
179 | |
180 | void BookmarkManagerWidget::exportBookmarks() |
181 | { |
182 | TRACE_OBJ |
183 | QString fileName = QFileDialog::getSaveFileName(parent: nullptr, caption: tr(s: "Save File" ), |
184 | dir: QLatin1String("untitled.xbel" ), filter: tr(s: "Files (*.xbel)" )); |
185 | |
186 | const QLatin1String suffix(".xbel" ); |
187 | if (!fileName.endsWith(s: suffix)) |
188 | fileName.append(s: suffix); |
189 | |
190 | QFile file(fileName); |
191 | if (file.open(flags: QIODevice::WriteOnly)) { |
192 | XbelWriter writer(bookmarkModel); |
193 | writer.writeToFile(device: &file); |
194 | } else { |
195 | QMessageBox::information(this, tr(s: "Qt Assistant" ), |
196 | tr(s: "Unable to save bookmarks." ), QMessageBox::Ok); |
197 | } |
198 | } |
199 | |
200 | void BookmarkManagerWidget::refeshBookmarkCache() |
201 | { |
202 | TRACE_OBJ |
203 | cache.clear(); |
204 | |
205 | const QString &text = ui.lineEdit->text(); |
206 | if (!text.isEmpty()) |
207 | cache = bookmarkModel->indexListFor(label: text); |
208 | } |
209 | |
210 | void BookmarkManagerWidget::textChanged(const QString &/*text*/) |
211 | { |
212 | TRACE_OBJ |
213 | refeshBookmarkCache(); |
214 | if (!cache.isEmpty()) |
215 | ui.treeView->setCurrentIndex(cache.at(0)); |
216 | } |
217 | |
218 | void BookmarkManagerWidget::removeItem(const QModelIndex &index) |
219 | { |
220 | TRACE_OBJ |
221 | QModelIndex current = index.isValid() ? index : ui.treeView->currentIndex(); |
222 | if (!current.parent().isValid() && current.row() < 2) |
223 | return; // check if we should delete the "Bookmarks Menu", bail |
224 | |
225 | if (bookmarkModel->hasChildren(parent: current)) { |
226 | int value = QMessageBox::question(this, tr(s: "Remove" ), tr(s: "You are going" |
227 | "to delete a Folder, this will also<br> remove it's content. Are " |
228 | "you sure to continue?" ), |
229 | QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel); |
230 | if (value == QMessageBox::Cancel) |
231 | return; |
232 | } |
233 | bookmarkModel->removeItem(index: current); |
234 | } |
235 | |
236 | void BookmarkManagerWidget::(const QPoint &point) |
237 | { |
238 | TRACE_OBJ |
239 | const QModelIndex &index = ui.treeView->indexAt(point); |
240 | if (!index.isValid()) |
241 | return; |
242 | |
243 | // check if we should open the menu on "Bookmarks Menu", bail |
244 | if (!bookmarkModel->parent(index).isValid()) |
245 | return; |
246 | |
247 | QAction *remove = nullptr; |
248 | QAction *rename = nullptr; |
249 | QAction *showItem = nullptr; |
250 | QAction *showItemInNewTab = nullptr; |
251 | |
252 | QMenu ; |
253 | if (bookmarkModel->data(index, role: UserRoleFolder).toBool()) { |
254 | remove = menu.addAction(text: tr(s: "Delete Folder" )); |
255 | rename = menu.addAction(text: tr(s: "Rename Folder" )); |
256 | } else { |
257 | showItem = menu.addAction(text: tr(s: "Show Bookmark" )); |
258 | showItemInNewTab = menu.addAction(text: tr(s: "Show Bookmark in New Tab" )); |
259 | menu.addSeparator(); |
260 | remove = menu.addAction(text: tr(s: "Delete Bookmark" )); |
261 | rename = menu.addAction(text: tr(s: "Rename Bookmark" )); |
262 | } |
263 | |
264 | QAction *pickedAction = menu.exec(ui.treeView->mapToGlobal(point)); |
265 | if (pickedAction == rename) |
266 | renameItem(index); |
267 | else if (pickedAction == remove) |
268 | removeItem(index); |
269 | else if (pickedAction == showItem || pickedAction == showItemInNewTab) |
270 | setSourceFromIndex(index, newTab: pickedAction == showItemInNewTab); |
271 | } |
272 | |
273 | void |
274 | BookmarkManagerWidget::setSourceFromIndex(const QModelIndex &index, bool newTab) |
275 | { |
276 | TRACE_OBJ |
277 | if (bookmarkModel->data(index, role: UserRoleFolder).toBool()) |
278 | return; |
279 | |
280 | const QVariant &data = bookmarkModel->data(index, role: UserRoleUrl); |
281 | if (data.canConvert<QUrl>()) { |
282 | if (newTab) |
283 | emit setSourceInNewTab(data.toUrl()); |
284 | else |
285 | emit setSource(data.toUrl()); |
286 | } |
287 | } |
288 | |
289 | QT_END_NAMESPACE |
290 | |