]> gitweb.stoutner.com Git - PrivacyBrowserPC.git/blob - src/widgets/DraggableTreeView.cpp
Add a default folder icon to the edit folder dialog. https://redmine.stoutner.com...
[PrivacyBrowserPC.git] / src / widgets / DraggableTreeView.cpp
1 /*
2  * Copyright 2023-2024 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 "DraggableTreeView.h"
22 #include "databases/BookmarksDatabase.h"
23 #include "dialogs/BookmarksDialog.h"
24
25 // Qt toolkit headers.
26 #include <QDebug>
27 #include <QDropEvent>
28 #include <QList>
29
30 // Construct the class.
31 DraggableTreeView::DraggableTreeView(QWidget *parentWidget) : QTreeView(parentWidget) {}
32
33 // Handle drop events.
34 void DraggableTreeView::dropEvent(QDropEvent *dropEvent)
35 {
36     // Get the list of currently selected items that are moving.
37     QList<QModelIndex> indexesMovingList = selectedIndexes();
38
39     // Create a list of selected database IDs.
40     QList<int> *selectedDatabaseIdsListPointer = new QList<int>;
41
42     // Populate the list of selected database IDs.
43     for (const QModelIndex &modelIndex : indexesMovingList)
44     {
45         // Only process model indexes from the bookmark name column (by default, there will be model indexes from all the visible columns in the list).
46         if (modelIndex.column() == BookmarksDialog::NAME_COLUMN)
47             selectedDatabaseIdsListPointer->append(modelIndex.siblingAtColumn(BookmarksDialog::DATABASE_ID_COLUMN).data().toInt());
48     }
49
50     // Get a list of root selected database IDs.
51     QList<int> *rootSelectedDatabaseIdsListPointer = getRootSelectedDatabaseIds(selectedDatabaseIdsListPointer);
52
53     // Get the drop position.
54     int dropPosition = dropIndicatorPosition();
55
56     // Get the drop model index.
57     QModelIndex dropModelIndex = indexAt(dropEvent->pos());
58
59     // Create a previous parent folder ID standard C++ list (which can be sorted and from which duplicates can be removed).
60     std::list<double> *previousParentFolderIdListPointer = new std::list<double>;
61
62     // Process the move according to the drop position.
63     switch (dropPosition)
64     {
65         case QAbstractItemView::OnItem:  // This will only ever be called for folders as `BookmarksDialog::populateSubfolders` creates bookmarks without `setDropEnabled`.
66         {
67             // Move everything to the beginning of the folder.
68             moveToBeginningOfFolder(dropModelIndex, selectedDatabaseIdsListPointer, rootSelectedDatabaseIdsListPointer, previousParentFolderIdListPointer);
69
70             break;
71         }
72
73         case QAbstractItemView::AboveItem:
74         {
75             // Get the drop display order.
76             int dropDisplayOrder = dropModelIndex.siblingAtColumn(BookmarksDialog::DISPLAY_ORDER_COLUMN).data().toInt();
77
78             // Get the drop parent folder ID.
79             double dropParentFolderId = dropModelIndex.parent().siblingAtColumn(BookmarksDialog::FOLDER_ID_COLUMN).data().toDouble();
80
81             // Get a list of all the items in the target folder except those selected.
82             QList<BookmarkStruct> *itemsInFolderExceptSelectedListPointer = BookmarksDatabase::getBookmarksInFolderExcept(dropParentFolderId, selectedDatabaseIdsListPointer);
83
84             // Initialize a new display order tracker.
85             int newDisplayOrder = 0;
86
87             // Process all the items in the target folder, moving in the new ones.
88             for (const BookmarkStruct &bookmarkStruct : *itemsInFolderExceptSelectedListPointer)
89             {
90                 // Check to see if this is the drop display order.
91                 if (bookmarkStruct.displayOrder == dropDisplayOrder)
92                 {
93                     // Add all of the bookmarks being moved to this point.
94                     for (const int databaseId : *rootSelectedDatabaseIdsListPointer)
95                     {
96                         // Get the item's current parent folder ID.
97                         double currentParentFolderId = BookmarksDatabase::getParentFolderId(databaseId);
98
99                         // Add the parent folder ID to the list of previous parent folders if the item is from a different folder.
100                         if (currentParentFolderId != dropParentFolderId)
101                             previousParentFolderIdListPointer->push_back(currentParentFolderId);
102
103                         // Update the parent folder and display order for each bookmark.
104                         BookmarksDatabase::updateParentFolderAndDisplayOrder(databaseId, dropParentFolderId, newDisplayOrder);
105
106                         // Increment the new display order.
107                         ++newDisplayOrder;
108                     }
109                 }
110
111                 // Set the bookmark's display order if it has changed.
112                 if (bookmarkStruct.displayOrder != newDisplayOrder)
113                     BookmarksDatabase::updateDisplayOrder(bookmarkStruct.databaseId, newDisplayOrder);
114
115                 // Increment the new display order.
116                 ++newDisplayOrder;
117             }
118             break;
119         }
120
121         case QAbstractItemView::BelowItem:
122         {
123             // Check to see if the drop model index is an expanded folder.
124             if (dropModelIndex.siblingAtColumn(BookmarksDialog::IS_FOLDER_COLUMN).data().toBool() && isExpanded(dropModelIndex))  // The drop model index is an expanded folder.
125             {
126                 // Move everything to the beginning of the folder.
127                 moveToBeginningOfFolder(dropModelIndex, selectedDatabaseIdsListPointer, rootSelectedDatabaseIdsListPointer, previousParentFolderIdListPointer);
128             }
129             else  // The drop model index is not an expanded folder.
130             {
131                 // Get the drop display order.
132                 int dropDisplayOrder = dropModelIndex.siblingAtColumn(BookmarksDialog::DISPLAY_ORDER_COLUMN).data().toInt();
133
134                 // Get the drop parent folder ID.
135                 double dropParentFolderId = dropModelIndex.parent().siblingAtColumn(BookmarksDialog::FOLDER_ID_COLUMN).data().toDouble();
136
137                 // Get a list of all the items in the target folder except those selected.
138                 QList<BookmarkStruct> *itemsInFolderExceptSelectedListPointer = BookmarksDatabase::getBookmarksInFolderExcept(dropParentFolderId, selectedDatabaseIdsListPointer);
139
140                 // Initialize a new display order tracker.
141                 int newDisplayOrder = 0;
142
143                 // Process all the items in the target folder, moving in the new ones.
144                 for (const BookmarkStruct &bookmarkStruct : *itemsInFolderExceptSelectedListPointer)
145                 {
146                     // Set the bookmark's display order if it has changed.
147                     if (bookmarkStruct.displayOrder != newDisplayOrder)
148                         BookmarksDatabase::updateDisplayOrder(bookmarkStruct.databaseId, newDisplayOrder);
149
150                     // Increment the new display order.
151                     ++newDisplayOrder;
152
153                     // Check to see if this is the drop display order.
154                     if (bookmarkStruct.displayOrder == dropDisplayOrder)
155                     {
156                         // Add all of the bookmarks being moved to this point.
157                         for (const int databaseId : *rootSelectedDatabaseIdsListPointer)
158                         {
159                             // Get the item's current parent folder ID.
160                             double currentParentFolderId = BookmarksDatabase::getParentFolderId(databaseId);
161
162                             // Add the parent folder ID to the list of previous parent folders if the item is from a different folder.
163                             if (currentParentFolderId != dropParentFolderId)
164                                 previousParentFolderIdListPointer->push_back(currentParentFolderId);
165
166                             // Update the parent folder and display order for each bookmark.
167                             BookmarksDatabase::updateParentFolderAndDisplayOrder(databaseId, dropParentFolderId, newDisplayOrder);
168
169                             // Increment the new display order.
170                             ++newDisplayOrder;
171                         }
172                     }
173                 }
174             }
175             break;
176         }
177
178         case QAbstractItemView::OnViewport:
179         {
180             // Get the drop parent folder ID.
181             double dropParentFolderId = 0;
182
183             // Get a list of all the items in the root folder except those selected.
184             QList<BookmarkStruct> *itemsInFolderExceptSelectedListPointer = BookmarksDatabase::getBookmarksInFolderExcept(dropParentFolderId, selectedDatabaseIdsListPointer);
185
186             // Initialize a new display order tracker.
187             int newDisplayOrder = 0;
188
189             // Update the display order of the existing items in the folder.
190             for (const BookmarkStruct &bookmarkStruct : *itemsInFolderExceptSelectedListPointer)
191             {
192                 // Set the bookmark's display order if it has changed.
193                 if (bookmarkStruct.displayOrder != newDisplayOrder)
194                     BookmarksDatabase::updateDisplayOrder(bookmarkStruct.databaseId, newDisplayOrder);
195
196                 // Increment the new display order.
197                 ++newDisplayOrder;
198             }
199
200             // Add all of the bookmarks being moved to the end of the list.
201             for (const int databaseId : *rootSelectedDatabaseIdsListPointer)
202             {
203                 // Get the item's current parent folder ID.
204                 double currentParentFolderId = BookmarksDatabase::getParentFolderId(databaseId);
205
206                 // Add the parent folder ID to the list of previous parent folders if the item is from a different folder.
207                 if (currentParentFolderId != dropParentFolderId)
208                     previousParentFolderIdListPointer->push_back(currentParentFolderId);
209
210                 // Update the parent folder and display order for each bookmark.
211                 BookmarksDatabase::updateParentFolderAndDisplayOrder(databaseId, dropParentFolderId, newDisplayOrder);
212
213                 // Increment the new display order.
214                 ++newDisplayOrder;
215             }
216             break;
217         }
218     }
219
220     // Sort the previous parent folder ID list.
221     previousParentFolderIdListPointer->sort();
222
223     // Remove duplicates from the parent folder ID list.
224     previousParentFolderIdListPointer->unique();
225
226     // Update the folder contents display order for each previous parent folder.
227     for (const double parentFolderId : *previousParentFolderIdListPointer)
228         BookmarksDatabase::updateFolderContentsDisplayOrder(parentFolderId);
229
230     // Emit the bookmarks moved signal.
231     emit bookmarksMoved();
232 }
233
234 QList<int>* DraggableTreeView::getRootSelectedDatabaseIds(QList<int> *selectedDatabaseIdsPointer) const
235 {
236     // Create a list of the database IDs of the contents of each selected folder.
237     QList<int> selectedFoldersContentsDatabaseIds;
238
239     // Populate the list of the database IDs of the contents of each selected folder.
240     for (const int databaseId : *selectedDatabaseIdsPointer)
241     {
242         // If this is not the root item and is a folder, get the database IDs of the contents.
243         if ((databaseId != -1) && BookmarksDatabase::isFolder(databaseId))
244             selectedFoldersContentsDatabaseIds.append(*BookmarksDatabase::getFolderContentsDatabaseIds(BookmarksDatabase::getFolderId(databaseId)));
245     }
246
247     // Create a root selected database IDs list.
248     QList<int>* rootSelectedDatabaseIdsListPointer = new QList<int>;
249
250     // Populate the root selected database IDs list.
251     for (const int databaseId : *selectedDatabaseIdsPointer)
252     {
253         // Add the database ID to the root selected database IDs list if it isn't the root item and it isn't contained in the selected folder contents database IDs list.
254         if ((databaseId != -1) && !selectedFoldersContentsDatabaseIds.contains(databaseId))
255             rootSelectedDatabaseIdsListPointer->append(databaseId);
256     }
257
258     // Return the root selected database IDs list.
259     return rootSelectedDatabaseIdsListPointer;
260 }
261
262 void DraggableTreeView::moveToBeginningOfFolder(const QModelIndex &dropModelIndex, QList<int> *selectedDatabaseIdsListPointer, QList<int> *rootSelectedDatabaseIdsListPointer,
263                                                 std::list<double> *previousParentFolderIdListPointer) const
264 {
265     // Get the new parent folder ID.
266     double newParentFolderId = dropModelIndex.siblingAtColumn(BookmarksDialog::FOLDER_ID_COLUMN).data().toDouble();
267
268     // Get a list of all the items in the target folder except those selected.
269     QList<BookmarkStruct> *itemsInFolderExceptSelectedListPointer = BookmarksDatabase::getBookmarksInFolderExcept(newParentFolderId, selectedDatabaseIdsListPointer);
270
271     // Initialize a new display order tracker.
272     int newDisplayOrder = 0;
273
274     // Move all the items to the top of the target folder.
275     for (const int databaseId : *rootSelectedDatabaseIdsListPointer)
276     {
277         // Get the item's current parent folder ID.
278         double currentParentFolderId = BookmarksDatabase::getParentFolderId(databaseId);
279
280         // Add the parent folder ID to the list of previous parent folders if the item is from a different folder.
281         if (currentParentFolderId != newParentFolderId)
282             previousParentFolderIdListPointer->push_back(currentParentFolderId);
283
284                 // Update the parent folder and display order for each bookmark.
285                 BookmarksDatabase::updateParentFolderAndDisplayOrder(databaseId, newParentFolderId, newDisplayOrder);
286
287                 // Increment the new display order.
288                 ++newDisplayOrder;
289             }
290
291             // Update the display order of the existing items in the folder.
292             for (const BookmarkStruct &bookmarkStruct : *itemsInFolderExceptSelectedListPointer)
293             {
294                 // Set the bookmark's display order if it has changed.
295                 if (bookmarkStruct.displayOrder != newDisplayOrder)
296                     BookmarksDatabase::updateDisplayOrder(bookmarkStruct.databaseId, newDisplayOrder);
297
298                 // Increment the new display order.
299                 ++newDisplayOrder;
300             }
301 }