]> gitweb.stoutner.com Git - PrivacyBrowserPC.git/blob - src/widgets/DraggableTreeView.cpp
Fix moving a bookmark to a specific location in a different folder. https://redmine...
[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> previousParentFolderIdList;
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             // Get the new parent folder ID.
68             double newParentFolderId = dropModelIndex.siblingAtColumn(BookmarksDialog::FOLDER_ID_COLUMN).data().toDouble();
69
70             // Get a list of all the items in the target folder except those selected.
71             QList<BookmarkStruct> *itemsInFolderExceptSelectedListPointer = BookmarksDatabase::getBookmarksInFolderExcept(newParentFolderId, selectedDatabaseIdsListPointer);
72
73             // Initialize a new display order tracker.
74             int newDisplayOrder = 0;
75
76             // Move all the items to the top of the target folder.
77             for (const int databaseId : *rootSelectedDatabaseIdsListPointer)
78             {
79                 // Get the item's current parent folder ID.
80                 double currentParentFolderId = BookmarksDatabase::getParentFolderId(databaseId);
81
82                 // Add the parent folder ID to the list of previous parent folders if the item is from a different folder.
83                 if (currentParentFolderId != newParentFolderId)
84                     previousParentFolderIdList.push_back(currentParentFolderId);
85
86                 // Update the parent folder and display order for each bookmark.
87                 BookmarksDatabase::updateParentFolderAndDisplayOrder(databaseId, newParentFolderId, newDisplayOrder);
88
89                 // Increment the new display order.
90                 ++newDisplayOrder;
91             }
92
93             // Update the display order of the existing items in the folder.
94             for (const BookmarkStruct &bookmarkStruct : *itemsInFolderExceptSelectedListPointer)
95             {
96                 // Set the bookmark's display order if it has changed.
97                 if (bookmarkStruct.displayOrder != newDisplayOrder)
98                     BookmarksDatabase::updateDisplayOrder(bookmarkStruct.databaseId, newDisplayOrder);
99
100                 // Increment the new display order.
101                 ++newDisplayOrder;
102             }
103             break;
104         }
105
106         case QAbstractItemView::AboveItem:
107         {
108             // Get the drop display order.
109             int dropDisplayOrder = dropModelIndex.siblingAtColumn(BookmarksDialog::DISPLAY_ORDER_COLUMN).data().toInt();
110
111             // Get the drop parent folder ID.
112             double dropParentFolderId = dropModelIndex.parent().siblingAtColumn(BookmarksDialog::FOLDER_ID_COLUMN).data().toDouble();
113
114             // Get a list of all the items in the target folder except those selected.
115             QList<BookmarkStruct> *itemsInFolderExceptSelectedListPointer = BookmarksDatabase::getBookmarksInFolderExcept(dropParentFolderId, selectedDatabaseIdsListPointer);
116
117             // Initialize a new display order tracker.
118             int newDisplayOrder = 0;
119
120             // Process all the items in the target folder, moving in the new ones.
121             for (const BookmarkStruct &bookmarkStruct : *itemsInFolderExceptSelectedListPointer)
122             {
123                 // Check to see if this is the drop display order.
124                 if (bookmarkStruct.displayOrder == dropDisplayOrder)
125                 {
126                     // Add all of the bookmarks being moved to this point.
127                     for (const int databaseId : *rootSelectedDatabaseIdsListPointer)
128                     {
129                         // Get the item's current parent folder ID.
130                         double currentParentFolderId = BookmarksDatabase::getParentFolderId(databaseId);
131
132                         // Add the parent folder ID to the list of previous parent folders if the item is from a different folder.
133                         if (currentParentFolderId != dropParentFolderId)
134                             previousParentFolderIdList.push_back(currentParentFolderId);
135
136                         // Update the parent folder and display order for each bookmark.
137                         BookmarksDatabase::updateParentFolderAndDisplayOrder(databaseId, dropParentFolderId, newDisplayOrder);
138
139                         // Increment the new display order.
140                         ++newDisplayOrder;
141                     }
142                 }
143
144                 // Set the bookmark's display order if it has changed.
145                 if (bookmarkStruct.displayOrder != newDisplayOrder)
146                     BookmarksDatabase::updateDisplayOrder(bookmarkStruct.databaseId, newDisplayOrder);
147
148                 // Increment the new display order.
149                 ++newDisplayOrder;
150             }
151             break;
152         }
153
154         case QAbstractItemView::BelowItem:
155         {
156             // Get the drop display order.
157             int dropDisplayOrder = dropModelIndex.siblingAtColumn(BookmarksDialog::DISPLAY_ORDER_COLUMN).data().toInt();
158
159             // Get the drop parent folder ID.
160             double dropParentFolderId = dropModelIndex.parent().siblingAtColumn(BookmarksDialog::FOLDER_ID_COLUMN).data().toDouble();
161
162             // Get a list of all the items in the target folder except those selected.
163             QList<BookmarkStruct> *itemsInFolderExceptSelectedListPointer = BookmarksDatabase::getBookmarksInFolderExcept(dropParentFolderId, selectedDatabaseIdsListPointer);
164
165             // Initialize a new display order tracker.
166             int newDisplayOrder = 0;
167
168             // Process all the items in the target folder, moving in the new ones.
169             for (const BookmarkStruct &bookmarkStruct : *itemsInFolderExceptSelectedListPointer)
170             {
171                 // Set the bookmark's display order if it has changed.
172                 if (bookmarkStruct.displayOrder != newDisplayOrder)
173                     BookmarksDatabase::updateDisplayOrder(bookmarkStruct.databaseId, newDisplayOrder);
174
175                 // Increment the new display order.
176                 ++newDisplayOrder;
177
178                 // Check to see if this is the drop display order.
179                 if (bookmarkStruct.displayOrder == dropDisplayOrder)
180                 {
181                     // Add all of the bookmarks being moved to this point.
182                     for (const int databaseId : *rootSelectedDatabaseIdsListPointer)
183                     {
184                         // Get the item's current parent folder ID.
185                         double currentParentFolderId = BookmarksDatabase::getParentFolderId(databaseId);
186
187                         // Add the parent folder ID to the list of previous parent folders if the item is from a different folder.
188                         if (currentParentFolderId != dropParentFolderId)
189                             previousParentFolderIdList.push_back(currentParentFolderId);
190
191                         // Update the parent folder and display order for each bookmark.
192                         BookmarksDatabase::updateParentFolderAndDisplayOrder(databaseId, dropParentFolderId, newDisplayOrder);
193
194                         // Increment the new display order.
195                         ++newDisplayOrder;
196                     }
197                 }
198             }
199             break;
200         }
201
202         case QAbstractItemView::OnViewport:
203         {
204             // Get the drop parent folder ID.
205             double dropParentFolderId = 0;
206
207             // Get a list of all the items in the root folder except those selected.
208             QList<BookmarkStruct> *itemsInFolderExceptSelectedListPointer = BookmarksDatabase::getBookmarksInFolderExcept(dropParentFolderId, selectedDatabaseIdsListPointer);
209
210             // Initialize a new display order tracker.
211             int newDisplayOrder = 0;
212
213             // Update the display order of the existing items in the folder.
214             for (const BookmarkStruct &bookmarkStruct : *itemsInFolderExceptSelectedListPointer)
215             {
216                 // Set the bookmark's display order if it has changed.
217                 if (bookmarkStruct.displayOrder != newDisplayOrder)
218                     BookmarksDatabase::updateDisplayOrder(bookmarkStruct.databaseId, newDisplayOrder);
219
220                 // Increment the new display order.
221                 ++newDisplayOrder;
222             }
223
224             // Add all of the bookmarks being moved to the end of the list.
225             for (const int databaseId : *rootSelectedDatabaseIdsListPointer)
226             {
227                 // Get the item's current parent folder ID.
228                 double currentParentFolderId = BookmarksDatabase::getParentFolderId(databaseId);
229
230                 // Add the parent folder ID to the list of previous parent folders if the item is from a different folder.
231                 if (currentParentFolderId != dropParentFolderId)
232                     previousParentFolderIdList.push_back(currentParentFolderId);
233
234                 // Update the parent folder and display order for each bookmark.
235                 BookmarksDatabase::updateParentFolderAndDisplayOrder(databaseId, dropParentFolderId, newDisplayOrder);
236
237                 // Increment the new display order.
238                 ++newDisplayOrder;
239             }
240             break;
241         }
242     }
243
244     // Sort the previous parent folder ID list.
245     previousParentFolderIdList.sort();
246
247     // Remove duplicates from the parent folder ID list.
248     previousParentFolderIdList.unique();
249
250     // Update the folder contents display order for each previous parent folder.
251     for (const double parentFolderId : previousParentFolderIdList)
252         BookmarksDatabase::updateFolderContentsDisplayOrder(parentFolderId);
253
254     // Emit the bookmarks moved signal.
255     emit bookmarksMoved();
256 }
257
258 QList<int>* DraggableTreeView::getRootSelectedDatabaseIds(QList<int> *selectedDatabaseIdsPointer) const
259 {
260     // Create a list of the database IDs of the contents of each selected folder.
261     QList<int> selectedFoldersContentsDatabaseIds;
262
263     // Populate the list of the database IDs of the contents of each selected folder.
264     for (const int databaseId : *selectedDatabaseIdsPointer)
265     {
266         // If this is not the root item and is a folder, get the database IDs of the contents.
267         if ((databaseId != -1) && BookmarksDatabase::isFolder(databaseId))
268             selectedFoldersContentsDatabaseIds.append(*BookmarksDatabase::getFolderContentsDatabaseIds(BookmarksDatabase::getFolderId(databaseId)));
269     }
270
271     // Create a root selected database IDs list.
272     QList<int>* rootSelectedDatabaseIdsListPointer = new QList<int>;
273
274     // Populate the root selected database IDs list.
275     for (const int databaseId : *selectedDatabaseIdsPointer)
276     {
277         // 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.
278         if ((databaseId != -1) && !selectedFoldersContentsDatabaseIds.contains(databaseId))
279             rootSelectedDatabaseIdsListPointer->append(databaseId);
280     }
281
282     // Return the root selected database IDs list.
283     return rootSelectedDatabaseIdsListPointer;
284 }