]> gitweb.stoutner.com Git - PrivacyBrowserPC.git/blob - src/dialogs/BookmarksDialog.cpp
Add dragging and dropping of bookmarks.
[PrivacyBrowserPC.git] / src / dialogs / BookmarksDialog.cpp
1 /*
2  * Copyright 2023 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
5  *
6  * Privacy Browser PC is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Privacy Browser PC is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Privacy Browser PC.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 // Application headers.
21 #include "BookmarksDialog.h"
22 #include "ui_BookmarksDialog.h"
23 #include "databases/BookmarksDatabase.h"
24 #include "dialogs/AddBookmarkDialog.h"
25 #include "dialogs/EditBookmarkDialog.h"
26
27 // KDE Frameworks headers.
28 #include <KLocalizedString>
29
30 // Qt toolkit headers.
31 #include <QDebug>
32 #include <QStandardItemModel>
33
34 // Construct the class.
35 BookmarksDialog::BookmarksDialog(QIcon currentWebsiteFavorieIcon) : QDialog(nullptr), websiteFavoriteIcon(currentWebsiteFavorieIcon)
36 {
37     // Set the dialog window title.
38     setWindowTitle(i18nc("The bookmarks dialog window title", "Bookmarks"));
39
40     // Set the window modality.
41     setWindowModality(Qt::WindowModality::ApplicationModal);
42
43     // Instantiate the bookmarks settings dialog UI.
44     Ui::BookmarksDialog bookmarksDialogUi;
45
46     // Setup the UI.
47     bookmarksDialogUi.setupUi(this);
48
49     // Get a handle for the draggable tree view.
50     draggableTreeViewPointer = bookmarksDialogUi.draggableTreeView;
51
52     // Initialize the tree model.
53     treeModelPointer = new QStandardItemModel();
54
55     // Auto resize the headers.
56     draggableTreeViewPointer->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
57
58     // Indicate that all the rows are the same height, which improves performance.
59     draggableTreeViewPointer->setUniformRowHeights(true);
60
61     // Set the selection mode to allow multiple rows to be selected at once.
62     draggableTreeViewPointer->setSelectionMode(QAbstractItemView::ExtendedSelection);
63
64     // Allow dragging of bookmarks to reorder.
65     draggableTreeViewPointer->setDragDropMode(QAbstractItemView::InternalMove);
66
67     // Set the tree model.
68     draggableTreeViewPointer->setModel(treeModelPointer);
69
70     // Get a handle for the tree selection model.
71     treeSelectionModelPointer = draggableTreeViewPointer->selectionModel();
72
73     // Listen for selection changes.
74     connect(treeSelectionModelPointer, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(updateUi()));
75
76     // Repopulate the bookmarks when they are moved.
77     connect(draggableTreeViewPointer, SIGNAL(bookmarksMoved()), this, SLOT(refreshBookmarks()));
78
79     // Get handles for the buttons.
80     QPushButton *addBookmarkButtonPointer = bookmarksDialogUi.addBookmarkButton;
81     editButtonPointer = bookmarksDialogUi.editButton;
82     deleteItemsButtonPointer = bookmarksDialogUi.deleteItemsButton;
83     QDialogButtonBox *dialogButtonBoxPointer = bookmarksDialogUi.dialogButtonBox;
84     QPushButton *closeButtonPointer = dialogButtonBoxPointer->button(QDialogButtonBox::Close);
85
86     // Connect the buttons.
87     connect(addBookmarkButtonPointer, SIGNAL(clicked()), this, SLOT(showAddBookmarkDialog()));
88     connect(editButtonPointer, SIGNAL(clicked()), this, SLOT(showEditDialog()));
89     connect(deleteItemsButtonPointer, SIGNAL(clicked()), this, SLOT(deleteItems()));
90     connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(reject()));
91
92     // Set the close button to be the default.
93     closeButtonPointer->setDefault(true);
94
95     // Monitor editing of data in the tree model.
96     connect(treeModelPointer, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(updateBookmarkFromTree(QStandardItem*)));
97
98     // Populate the bookmarks.
99     populateBookmarks();
100 }
101
102 void BookmarksDialog::deleteItems() const
103 {
104     // Get the list of selected model indexes.
105     QList<QModelIndex> selectedModelIndexList = treeSelectionModelPointer->selectedRows(DATABASE_ID_COLUMN);
106
107     // Delete each of the bookmarks.
108     for (const QModelIndex &modelIndex : selectedModelIndexList)
109     {
110         // Delete the bookmark.
111         BookmarksDatabase::deleteBookmark(modelIndex.data().toInt());
112     }
113
114     // Repopulate the bookmarks in this dialog
115     populateBookmarks();
116
117     // Emit the bookmark updated signal to redraw the bookmarks in the menu and toolbar.
118     emit bookmarkUpdated();
119 }
120
121 void BookmarksDialog::populateBookmarks() const
122 {
123     // Clear the current contents of the tree model.
124     treeModelPointer->clear();
125
126     // Set the column count.
127     treeModelPointer->setColumnCount(4);
128
129     // Set the tree header data.  The last column is the database ID, which is not displayed.
130     treeModelPointer->setHeaderData(BOOKMARK_NAME_COLUMN, Qt::Horizontal, i18nc("The bookmark Name header.", "Name"));
131     treeModelPointer->setHeaderData(BOOKMARK_URL_COLUMN, Qt::Horizontal, i18nc("The bookmark URL header.", "URL"));
132
133     // Hide the backend columns.
134     draggableTreeViewPointer->setColumnHidden(DATABASE_ID_COLUMN, true);
135     draggableTreeViewPointer->setColumnHidden(DISPLAY_ORDER, true);
136
137     // Get the list of bookmarks.
138     std::list<BookmarkStruct> *bookmarksListPointer = BookmarksDatabase::getBookmarks();
139
140     // Populate the bookmarks tree view.
141     for (const BookmarkStruct &bookmarkStruct : *bookmarksListPointer)
142     {
143         // Create a list for the bookmark items.
144         QList<QStandardItem*> bookmarkItemList;
145
146         // Create the bookmark items.
147         QStandardItem *nameItemPointer = new QStandardItem(bookmarkStruct.favoriteIcon, bookmarkStruct.bookmarkName);
148         QStandardItem *urlItemPointer = new QStandardItem(bookmarkStruct.bookmarkUrl);
149         QStandardItem *idItemPointer = new QStandardItem(QString::number(bookmarkStruct.id));
150         QStandardItem *displayOrderPointer = new QStandardItem(QString::number(bookmarkStruct.displayOrder));
151
152         nameItemPointer->setDragEnabled(true);
153         nameItemPointer->setDropEnabled(true);
154
155         // Disable dragging the URL.
156         urlItemPointer->setDragEnabled(false);
157
158         // Disable dropping on the URL.  For some reason this doesn't work.
159         urlItemPointer->setDropEnabled(false);
160
161         // Disable selecting the URL.
162         urlItemPointer->setSelectable(false);
163
164         // Populate the bookmark item list.
165         bookmarkItemList.append(nameItemPointer);
166         bookmarkItemList.append(urlItemPointer);
167         bookmarkItemList.append(idItemPointer);
168         bookmarkItemList.append(displayOrderPointer);
169
170         // Add the bookmark to the tree.
171         treeModelPointer->appendRow(bookmarkItemList);
172     }
173
174     // Update the UI.
175     updateUi();
176 }
177
178 void BookmarksDialog::refreshBookmarks() const
179 {
180     // Repopulate the bookmarks in this dialog
181     populateBookmarks();
182
183     // Emit the bookmark updated signal to redraw the bookmarks in the menu and toolbar.
184     emit bookmarkUpdated();
185 }
186
187 void BookmarksDialog::showAddBookmarkDialog() const
188 {
189     // Instantiate an add bookmark dialog.
190     AddBookmarkDialog *addBookmarkDialogPointer = new AddBookmarkDialog(QLatin1String(""), QLatin1String(""), websiteFavoriteIcon);
191
192     // Update the displayed bookmarks when a new one is added.
193     connect(addBookmarkDialogPointer, SIGNAL(bookmarkAdded()), this, SLOT(refreshBookmarks()));
194
195     // Show the dialog.
196     addBookmarkDialogPointer->show();
197 }
198
199 void BookmarksDialog::showEditDialog()
200 {
201     // Get the current model index.
202     QModelIndex currentIndex = treeSelectionModelPointer->currentIndex();
203
204     // Instantiate an edit bookmark dialog.
205     QDialog *editBookmarkDialogPointer = new EditBookmarkDialog(currentIndex.siblingAtColumn(DATABASE_ID_COLUMN).data().toInt(), websiteFavoriteIcon);
206
207     // Show the dialog.
208     editBookmarkDialogPointer->show();
209
210     // Process bookmark events.
211     connect(editBookmarkDialogPointer, SIGNAL(bookmarkSaved()), this, SLOT(refreshBookmarks()));
212 }
213
214 void BookmarksDialog::updateBookmarkFromTree(QStandardItem *modifiedStandardItem)
215 {
216     // Get the model index of the modified item.
217     QModelIndex modifiedItemModelIndex = modifiedStandardItem->index();
218
219     // Get the model index of the database ID.
220     QModelIndex databaseIdModelIndex = modifiedItemModelIndex.siblingAtColumn(DATABASE_ID_COLUMN);
221
222     // Get the database ID.
223     int databaseId = databaseIdModelIndex.data().toInt();
224
225     // Check to see if the bookmark name or the URL was edited.
226     if (modifiedStandardItem->column() == BOOKMARK_NAME_COLUMN)  // The bookmark name was edited.
227     {
228         // Update the bookmark name.
229         BookmarksDatabase::updateBookmarkName(databaseId, modifiedStandardItem->text());
230     }
231     else  // The bookmark URL was edited.
232     {
233         // Update the bookmark URL.
234         BookmarksDatabase::updateBookmarkUrl(databaseId, modifiedStandardItem->text());
235     }
236
237     // Emit the bookmark updated signal.
238     emit bookmarkUpdated();
239 }
240
241 void BookmarksDialog::updateUi() const
242 {
243     // Set the status of the buttons.
244     if (treeSelectionModelPointer->hasSelection())  // A bookmark or folder is selected.
245     {
246         // Enabled the buttons.
247         editButtonPointer->setEnabled(true);
248         deleteItemsButtonPointer->setEnabled(true);
249
250         // Update the delete items button text.
251         deleteItemsButtonPointer->setText(i18ncp("Delete items button populated text.", "Delete %1 item", "Delete %1 items", treeSelectionModelPointer->selectedRows().count()));
252     }
253     else  // Nothing is selected.
254     {
255         // Disable the buttons.
256         editButtonPointer->setEnabled(false);
257         deleteItemsButtonPointer->setEnabled(false);
258
259         // Update the delete items button text.
260         deleteItemsButtonPointer->setText(i18nc("Delete items button default text", "Delete items"));
261     }
262 }