2 * Copyright 2023-2024 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc>.
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.
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.
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/>.
20 // Application headers.
21 #include "DraggableTreeView.h"
22 #include "databases/BookmarksDatabase.h"
23 #include "dialogs/BookmarksDialog.h"
25 // Qt toolkit headers.
30 // Construct the class.
31 DraggableTreeView::DraggableTreeView(QWidget *parentWidget) : QTreeView(parentWidget) {}
33 // Handle drop events.
34 void DraggableTreeView::dropEvent(QDropEvent *dropEvent)
36 // Get the list of currently selected items that are moving.
37 QList<QModelIndex> indexesMovingList = selectedIndexes();
39 // Create a list of selected database IDs.
40 QList<int> *selectedDatabaseIdsListPointer = new QList<int>;
42 // Populate the list of selected database IDs.
43 for (const QModelIndex &modelIndex : indexesMovingList)
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());
50 // Get a list of root selected database IDs.
51 QList<int> *rootSelectedDatabaseIdsListPointer = getRootSelectedDatabaseIds(selectedDatabaseIdsListPointer);
53 // Get the drop position.
54 int dropPosition = dropIndicatorPosition();
56 // Get the drop model index.
57 QModelIndex dropModelIndex = indexAt(dropEvent->pos());
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;
62 // Process the move according to the drop position.
65 case QAbstractItemView::OnItem: // This will only ever be called for folders as `BookmarksDialog::populateSubfolders` creates bookmarks without `setDropEnabled`.
67 // Get the new parent folder ID.
68 double newParentFolderId = dropModelIndex.siblingAtColumn(BookmarksDialog::FOLDER_ID_COLUMN).data().toDouble();
70 // Get a list of all the items in the target folder except those selected.
71 QList<BookmarkStruct> *itemsInFolderExceptSelectedListPointer = BookmarksDatabase::getBookmarksInFolderExcept(newParentFolderId, selectedDatabaseIdsListPointer);
73 // Initialize a new display order tracker.
74 int newDisplayOrder = 0;
76 // Move all the items to the top of the target folder.
77 for (const int databaseId : *rootSelectedDatabaseIdsListPointer)
79 // Get the item's current parent folder ID.
80 double currentParentFolderId = BookmarksDatabase::getParentFolderId(databaseId);
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);
86 // Update the parent folder and display order for each bookmark.
87 BookmarksDatabase::updateParentFolderAndDisplayOrder(databaseId, newParentFolderId, newDisplayOrder);
89 // Increment the new display order.
93 // Update the display order of the existing items in the folder.
94 for (const BookmarkStruct &bookmarkStruct : *itemsInFolderExceptSelectedListPointer)
96 // Set the bookmark's display order if it has changed.
97 if (bookmarkStruct.displayOrder != newDisplayOrder)
98 BookmarksDatabase::updateDisplayOrder(bookmarkStruct.databaseId, newDisplayOrder);
100 // Increment the new display order.
106 case QAbstractItemView::AboveItem:
108 // Get the drop display order.
109 int dropDisplayOrder = dropModelIndex.siblingAtColumn(BookmarksDialog::DISPLAY_ORDER_COLUMN).data().toInt();
111 // Get the drop parent folder ID.
112 double dropParentFolderId = dropModelIndex.parent().siblingAtColumn(BookmarksDialog::FOLDER_ID_COLUMN).data().toDouble();
114 // Get a list of all the items in the target folder except those selected.
115 QList<BookmarkStruct> *itemsInFolderExceptSelectedListPointer = BookmarksDatabase::getBookmarksInFolderExcept(dropParentFolderId, selectedDatabaseIdsListPointer);
117 // Initialize a new display order tracker.
118 int newDisplayOrder = 0;
120 // Process all the items in the target folder, moving in the new ones.
121 for (const BookmarkStruct &bookmarkStruct : *itemsInFolderExceptSelectedListPointer)
123 // Check to see if this is the drop display order.
124 if (bookmarkStruct.displayOrder == dropDisplayOrder)
126 // Add all of the bookmarks being moved to this point.
127 for (const int databaseId : *rootSelectedDatabaseIdsListPointer)
129 // Get the item's current parent folder ID.
130 double currentParentFolderId = BookmarksDatabase::getParentFolderId(databaseId);
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);
136 // Update the parent folder and display order for each bookmark.
137 BookmarksDatabase::updateParentFolderAndDisplayOrder(databaseId, dropParentFolderId, newDisplayOrder);
139 // Increment the new display order.
144 // Set the bookmark's display order if it has changed.
145 if (bookmarkStruct.displayOrder != newDisplayOrder)
146 BookmarksDatabase::updateDisplayOrder(bookmarkStruct.databaseId, newDisplayOrder);
148 // Increment the new display order.
154 case QAbstractItemView::BelowItem:
156 // Get the drop display order.
157 int dropDisplayOrder = dropModelIndex.siblingAtColumn(BookmarksDialog::DISPLAY_ORDER_COLUMN).data().toInt();
159 // Get the drop parent folder ID.
160 double dropParentFolderId = dropModelIndex.parent().siblingAtColumn(BookmarksDialog::FOLDER_ID_COLUMN).data().toDouble();
162 // Get a list of all the items in the target folder except those selected.
163 QList<BookmarkStruct> *itemsInFolderExceptSelectedListPointer = BookmarksDatabase::getBookmarksInFolderExcept(dropParentFolderId, selectedDatabaseIdsListPointer);
165 // Initialize a new display order tracker.
166 int newDisplayOrder = 0;
168 // Process all the items in the target folder, moving in the new ones.
169 for (const BookmarkStruct &bookmarkStruct : *itemsInFolderExceptSelectedListPointer)
171 // Set the bookmark's display order if it has changed.
172 if (bookmarkStruct.displayOrder != newDisplayOrder)
173 BookmarksDatabase::updateDisplayOrder(bookmarkStruct.databaseId, newDisplayOrder);
175 // Increment the new display order.
178 // Check to see if this is the drop display order.
179 if (bookmarkStruct.displayOrder == dropDisplayOrder)
181 // Add all of the bookmarks being moved to this point.
182 for (const int databaseId : *rootSelectedDatabaseIdsListPointer)
184 // Get the item's current parent folder ID.
185 double currentParentFolderId = BookmarksDatabase::getParentFolderId(databaseId);
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);
191 // Update the parent folder and display order for each bookmark.
192 BookmarksDatabase::updateParentFolderAndDisplayOrder(databaseId, dropParentFolderId, newDisplayOrder);
194 // Increment the new display order.
202 case QAbstractItemView::OnViewport:
204 // Get the drop parent folder ID.
205 double dropParentFolderId = 0;
207 // Get a list of all the items in the root folder except those selected.
208 QList<BookmarkStruct> *itemsInFolderExceptSelectedListPointer = BookmarksDatabase::getBookmarksInFolderExcept(dropParentFolderId, selectedDatabaseIdsListPointer);
210 // Initialize a new display order tracker.
211 int newDisplayOrder = 0;
213 // Update the display order of the existing items in the folder.
214 for (const BookmarkStruct &bookmarkStruct : *itemsInFolderExceptSelectedListPointer)
216 // Set the bookmark's display order if it has changed.
217 if (bookmarkStruct.displayOrder != newDisplayOrder)
218 BookmarksDatabase::updateDisplayOrder(bookmarkStruct.databaseId, newDisplayOrder);
220 // Increment the new display order.
224 // Add all of the bookmarks being moved to the end of the list.
225 for (const int databaseId : *rootSelectedDatabaseIdsListPointer)
227 // Get the item's current parent folder ID.
228 double currentParentFolderId = BookmarksDatabase::getParentFolderId(databaseId);
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);
234 // Update the parent folder and display order for each bookmark.
235 BookmarksDatabase::updateParentFolderAndDisplayOrder(databaseId, dropParentFolderId, newDisplayOrder);
237 // Increment the new display order.
244 // Sort the previous parent folder ID list.
245 previousParentFolderIdList.sort();
247 // Remove duplicates from the parent folder ID list.
248 previousParentFolderIdList.unique();
250 // Update the folder contents display order for each previous parent folder.
251 for (const double parentFolderId : previousParentFolderIdList)
252 BookmarksDatabase::updateFolderContentsDisplayOrder(parentFolderId);
254 // Emit the bookmarks moved signal.
255 emit bookmarksMoved();
258 QList<int>* DraggableTreeView::getRootSelectedDatabaseIds(QList<int> *selectedDatabaseIdsPointer) const
260 // Create a list of the database IDs of the contents of each selected folder.
261 QList<int> selectedFoldersContentsDatabaseIds;
263 // Populate the list of the database IDs of the contents of each selected folder.
264 for (const int databaseId : *selectedDatabaseIdsPointer)
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)));
271 // Create a root selected database IDs list.
272 QList<int>* rootSelectedDatabaseIdsListPointer = new QList<int>;
274 // Populate the root selected database IDs list.
275 for (const int databaseId : *selectedDatabaseIdsPointer)
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);
282 // Return the root selected database IDs list.
283 return rootSelectedDatabaseIdsListPointer;