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> *previousParentFolderIdListPointer = new std::list<double>;
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 // Move everything to the beginning of the folder.
68 moveToBeginningOfFolder(dropModelIndex, selectedDatabaseIdsListPointer, rootSelectedDatabaseIdsListPointer, previousParentFolderIdListPointer);
73 case QAbstractItemView::AboveItem:
75 // Get the drop display order.
76 int dropDisplayOrder = dropModelIndex.siblingAtColumn(BookmarksDialog::DISPLAY_ORDER_COLUMN).data().toInt();
78 // Get the drop parent folder ID.
79 double dropParentFolderId = dropModelIndex.parent().siblingAtColumn(BookmarksDialog::FOLDER_ID_COLUMN).data().toDouble();
81 // Get a list of all the items in the target folder except those selected.
82 QList<BookmarkStruct> *itemsInFolderExceptSelectedListPointer = BookmarksDatabase::getBookmarksInFolderExcept(dropParentFolderId, selectedDatabaseIdsListPointer);
84 // Initialize a new display order tracker.
85 int newDisplayOrder = 0;
87 // Process all the items in the target folder, moving in the new ones.
88 for (const BookmarkStruct &bookmarkStruct : *itemsInFolderExceptSelectedListPointer)
90 // Check to see if this is the drop display order.
91 if (bookmarkStruct.displayOrder == dropDisplayOrder)
93 // Add all of the bookmarks being moved to this point.
94 for (const int databaseId : *rootSelectedDatabaseIdsListPointer)
96 // Get the item's current parent folder ID.
97 double currentParentFolderId = BookmarksDatabase::getParentFolderId(databaseId);
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);
103 // Update the parent folder and display order for each bookmark.
104 BookmarksDatabase::updateParentFolderAndDisplayOrder(databaseId, dropParentFolderId, newDisplayOrder);
106 // Increment the new display order.
111 // Set the bookmark's display order if it has changed.
112 if (bookmarkStruct.displayOrder != newDisplayOrder)
113 BookmarksDatabase::updateDisplayOrder(bookmarkStruct.databaseId, newDisplayOrder);
115 // Increment the new display order.
121 case QAbstractItemView::BelowItem:
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.
126 // Move everything to the beginning of the folder.
127 moveToBeginningOfFolder(dropModelIndex, selectedDatabaseIdsListPointer, rootSelectedDatabaseIdsListPointer, previousParentFolderIdListPointer);
129 else // The drop model index is not an expanded folder.
131 // Get the drop display order.
132 int dropDisplayOrder = dropModelIndex.siblingAtColumn(BookmarksDialog::DISPLAY_ORDER_COLUMN).data().toInt();
134 // Get the drop parent folder ID.
135 double dropParentFolderId = dropModelIndex.parent().siblingAtColumn(BookmarksDialog::FOLDER_ID_COLUMN).data().toDouble();
137 // Get a list of all the items in the target folder except those selected.
138 QList<BookmarkStruct> *itemsInFolderExceptSelectedListPointer = BookmarksDatabase::getBookmarksInFolderExcept(dropParentFolderId, selectedDatabaseIdsListPointer);
140 // Initialize a new display order tracker.
141 int newDisplayOrder = 0;
143 // Process all the items in the target folder, moving in the new ones.
144 for (const BookmarkStruct &bookmarkStruct : *itemsInFolderExceptSelectedListPointer)
146 // Set the bookmark's display order if it has changed.
147 if (bookmarkStruct.displayOrder != newDisplayOrder)
148 BookmarksDatabase::updateDisplayOrder(bookmarkStruct.databaseId, newDisplayOrder);
150 // Increment the new display order.
153 // Check to see if this is the drop display order.
154 if (bookmarkStruct.displayOrder == dropDisplayOrder)
156 // Add all of the bookmarks being moved to this point.
157 for (const int databaseId : *rootSelectedDatabaseIdsListPointer)
159 // Get the item's current parent folder ID.
160 double currentParentFolderId = BookmarksDatabase::getParentFolderId(databaseId);
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);
166 // Update the parent folder and display order for each bookmark.
167 BookmarksDatabase::updateParentFolderAndDisplayOrder(databaseId, dropParentFolderId, newDisplayOrder);
169 // Increment the new display order.
178 case QAbstractItemView::OnViewport:
180 // Get the drop parent folder ID.
181 double dropParentFolderId = 0;
183 // Get a list of all the items in the root folder except those selected.
184 QList<BookmarkStruct> *itemsInFolderExceptSelectedListPointer = BookmarksDatabase::getBookmarksInFolderExcept(dropParentFolderId, selectedDatabaseIdsListPointer);
186 // Initialize a new display order tracker.
187 int newDisplayOrder = 0;
189 // Update the display order of the existing items in the folder.
190 for (const BookmarkStruct &bookmarkStruct : *itemsInFolderExceptSelectedListPointer)
192 // Set the bookmark's display order if it has changed.
193 if (bookmarkStruct.displayOrder != newDisplayOrder)
194 BookmarksDatabase::updateDisplayOrder(bookmarkStruct.databaseId, newDisplayOrder);
196 // Increment the new display order.
200 // Add all of the bookmarks being moved to the end of the list.
201 for (const int databaseId : *rootSelectedDatabaseIdsListPointer)
203 // Get the item's current parent folder ID.
204 double currentParentFolderId = BookmarksDatabase::getParentFolderId(databaseId);
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);
210 // Update the parent folder and display order for each bookmark.
211 BookmarksDatabase::updateParentFolderAndDisplayOrder(databaseId, dropParentFolderId, newDisplayOrder);
213 // Increment the new display order.
220 // Sort the previous parent folder ID list.
221 previousParentFolderIdListPointer->sort();
223 // Remove duplicates from the parent folder ID list.
224 previousParentFolderIdListPointer->unique();
226 // Update the folder contents display order for each previous parent folder.
227 for (const double parentFolderId : *previousParentFolderIdListPointer)
228 BookmarksDatabase::updateFolderContentsDisplayOrder(parentFolderId);
230 // Emit the bookmarks moved signal.
231 emit bookmarksMoved();
234 QList<int>* DraggableTreeView::getRootSelectedDatabaseIds(QList<int> *selectedDatabaseIdsPointer) const
236 // Create a list of the database IDs of the contents of each selected folder.
237 QList<int> selectedFoldersContentsDatabaseIds;
239 // Populate the list of the database IDs of the contents of each selected folder.
240 for (const int databaseId : *selectedDatabaseIdsPointer)
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)));
247 // Create a root selected database IDs list.
248 QList<int>* rootSelectedDatabaseIdsListPointer = new QList<int>;
250 // Populate the root selected database IDs list.
251 for (const int databaseId : *selectedDatabaseIdsPointer)
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);
258 // Return the root selected database IDs list.
259 return rootSelectedDatabaseIdsListPointer;
262 void DraggableTreeView::moveToBeginningOfFolder(const QModelIndex &dropModelIndex, QList<int> *selectedDatabaseIdsListPointer, QList<int> *rootSelectedDatabaseIdsListPointer,
263 std::list<double> *previousParentFolderIdListPointer) const
265 // Get the new parent folder ID.
266 double newParentFolderId = dropModelIndex.siblingAtColumn(BookmarksDialog::FOLDER_ID_COLUMN).data().toDouble();
268 // Get a list of all the items in the target folder except those selected.
269 QList<BookmarkStruct> *itemsInFolderExceptSelectedListPointer = BookmarksDatabase::getBookmarksInFolderExcept(newParentFolderId, selectedDatabaseIdsListPointer);
271 // Initialize a new display order tracker.
272 int newDisplayOrder = 0;
274 // Move all the items to the top of the target folder.
275 for (const int databaseId : *rootSelectedDatabaseIdsListPointer)
277 // Get the item's current parent folder ID.
278 double currentParentFolderId = BookmarksDatabase::getParentFolderId(databaseId);
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);
284 // Update the parent folder and display order for each bookmark.
285 BookmarksDatabase::updateParentFolderAndDisplayOrder(databaseId, newParentFolderId, newDisplayOrder);
287 // Increment the new display order.
291 // Update the display order of the existing items in the folder.
292 for (const BookmarkStruct &bookmarkStruct : *itemsInFolderExceptSelectedListPointer)
294 // Set the bookmark's display order if it has changed.
295 if (bookmarkStruct.displayOrder != newDisplayOrder)
296 BookmarksDatabase::updateDisplayOrder(bookmarkStruct.databaseId, newDisplayOrder);
298 // Increment the new display order.