X-Git-Url: https://gitweb.stoutner.com/?a=blobdiff_plain;f=src%2Fdialogs%2FBookmarksDialog.cpp;h=0fa2b4f983f63721973139ad0b3f363d8265c789;hb=e715eca23297fb10dcf70e4c8bb2712413d16e3d;hp=509fade9f7796b3e6f240c8ac30a7b958fa1cf4a;hpb=7c6edb3608791950c6146ac242e2b6f493ca8e8c;p=PrivacyBrowserPC.git diff --git a/src/dialogs/BookmarksDialog.cpp b/src/dialogs/BookmarksDialog.cpp index 509fade..0fa2b4f 100644 --- a/src/dialogs/BookmarksDialog.cpp +++ b/src/dialogs/BookmarksDialog.cpp @@ -21,6 +21,10 @@ #include "BookmarksDialog.h" #include "ui_BookmarksDialog.h" #include "databases/BookmarksDatabase.h" +#include "dialogs/AddBookmarkDialog.h" +#include "dialogs/AddFolderDialog.h" +#include "dialogs/EditBookmarkDialog.h" +#include "dialogs/EditFolderDialog.h" // KDE Frameworks headers. #include @@ -28,10 +32,10 @@ // Qt toolkit headers. #include #include -#include // Construct the class. -BookmarksDialog::BookmarksDialog() : QDialog(nullptr) +BookmarksDialog::BookmarksDialog(QString currentWebsiteTitle, QString currentWebsiteUrl, QIcon currentWebsiteFavorieIcon) : + QDialog(nullptr), websiteFavoriteIcon(currentWebsiteFavorieIcon), websiteTitle(currentWebsiteTitle), websiteUrl(currentWebsiteUrl) { // Set the dialog window title. setWindowTitle(i18nc("The bookmarks dialog window title", "Bookmarks")); @@ -45,62 +49,346 @@ BookmarksDialog::BookmarksDialog() : QDialog(nullptr) // Setup the UI. bookmarksDialogUi.setupUi(this); - // Get the list of bookmarks. - std::list *bookmarksListPointer = BookmarksDatabase::getBookmarks(); - - // Get a handle for the tree view. - QTreeView *treeViewPointer = bookmarksDialogUi.treeView; + // Get a handle for the draggable tree view. + draggableTreeViewPointer = bookmarksDialogUi.draggableTreeView; // Initialize the tree model. - QStandardItemModel *treeModelPointer = new QStandardItemModel(); + treeModelPointer = new QStandardItemModel(); + + // Auto resize the headers. + draggableTreeViewPointer->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + + // Indicate that all the rows are the same height, which improves performance. + draggableTreeViewPointer->setUniformRowHeights(true); + + // Set the selection mode to allow multiple rows to be selected at once. + draggableTreeViewPointer->setSelectionMode(QAbstractItemView::ExtendedSelection); + + // Allow dragging of bookmarks to reorder. + draggableTreeViewPointer->setDragDropMode(QAbstractItemView::InternalMove); + + // Set the tree model. + draggableTreeViewPointer->setModel(treeModelPointer); + + // Get a handle for the tree selection model. + treeSelectionModelPointer = draggableTreeViewPointer->selectionModel(); + + // Listen for selection changes. + connect(treeSelectionModelPointer, SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(updateSelection())); + + // Repopulate the bookmarks when they are moved. + connect(draggableTreeViewPointer, SIGNAL(bookmarksMoved()), this, SLOT(refreshBookmarks())); + + // Get handles for the buttons. + QPushButton *addBookmarkButtonPointer = bookmarksDialogUi.addBookmarkButton; + QPushButton *addFolderButtonPointer = bookmarksDialogUi.addFolderButton; + editButtonPointer = bookmarksDialogUi.editButton; + deleteItemsButtonPointer = bookmarksDialogUi.deleteItemsButton; + QDialogButtonBox *dialogButtonBoxPointer = bookmarksDialogUi.dialogButtonBox; + QPushButton *closeButtonPointer = dialogButtonBoxPointer->button(QDialogButtonBox::Close); + + // Connect the buttons. + connect(addBookmarkButtonPointer, SIGNAL(clicked()), this, SLOT(showAddBookmarkDialog())); + connect(addFolderButtonPointer, SIGNAL(clicked()), this, SLOT(showAddFolderDialog())); + connect(editButtonPointer, SIGNAL(clicked()), this, SLOT(showEditDialog())); + connect(deleteItemsButtonPointer, SIGNAL(clicked()), this, SLOT(deleteItems())); + connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(reject())); + + // Set the close button to be the default. + closeButtonPointer->setDefault(true); + + // Monitor editing of data in the tree model. + connect(treeModelPointer, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(updateBookmarkFromTree(QStandardItem*))); + + // Populate the bookmarks. + populateBookmarks(); +} + +void BookmarksDialog::deleteItems() const +{ + // Create a parent folder ID standard C++ list (which can be sorted and from which duplicates can be removed). + std::list parentFolderIdList; + + // Get the list of selected model indexes. + QList selectedModelIndexList = treeSelectionModelPointer->selectedRows(DATABASE_ID_COLUMN); + + // Delete each of the bookmarks. + for (const QModelIndex &modelIndex : selectedModelIndexList) + { + // Add the parent folder ID to the list. + parentFolderIdList.push_back(modelIndex.parent().siblingAtColumn(FOLDER_ID_COLUMN).data().toDouble()); + + // Delete the bookmark. + BookmarksDatabase::deleteBookmark(modelIndex.data().toInt()); + } + + // Sort the parent folder ID. + parentFolderIdList.sort(); + + // Remove duplicates from the parent folder ID list. + parentFolderIdList.unique(); + + // Update the folder contents display order for each folder with a deleted bookmark. + for (const double parentFolderId : parentFolderIdList) + BookmarksDatabase::updateFolderContentsDisplayOrder(parentFolderId); + + // Repopulate the bookmarks in this dialog + populateBookmarks(); + + // Emit the bookmark updated signal to redraw the bookmarks in the menu and toolbar. + emit bookmarkUpdated(); +} + +void BookmarksDialog::populateBookmarks() const +{ + // Clear the current contents of the tree model. + treeModelPointer->clear(); // Set the column count. - treeModelPointer->setColumnCount(3); + treeModelPointer->setColumnCount(6); + + // Set the tree header data. + treeModelPointer->setHeaderData(NAME_COLUMN, Qt::Horizontal, i18nc("The bookmark Name header.", "Name")); + treeModelPointer->setHeaderData(URL_COLUMN, Qt::Horizontal, i18nc("The bookmark URL header.", "URL")); + + // Hide the backend columns. + draggableTreeViewPointer->setColumnHidden(DATABASE_ID_COLUMN, true); + draggableTreeViewPointer->setColumnHidden(DISPLAY_ORDER_COLUMN, true); + draggableTreeViewPointer->setColumnHidden(IS_FOLDER_COLUMN, true); + draggableTreeViewPointer->setColumnHidden(FOLDER_ID_COLUMN, true); + + // Create a bookmarks root item list. + QList bookmarksRootItemList; + + // Create the root items. + QStandardItem *rootItemNamePointer = new QStandardItem(QIcon::fromTheme(QLatin1String("bookmarks"), QIcon::fromTheme(QLatin1String("bookmark-new"))), + i18nc("The bookmarks root tree widget name", "Bookmarks")); + QStandardItem *rootItemUrlPointer = new QStandardItem(QLatin1String("")); + QStandardItem *rootItemDatabaseIdPonter = new QStandardItem(QLatin1String("-1")); // The root item doesn't have a database ID. + QStandardItem *rootItemDisplayOrderPointer = new QStandardItem(QLatin1String("-1")); // The root item doesn't have a display order. + QStandardItem *rootItemIsFolderPointer = new QStandardItem(QLatin1String("1")); + QStandardItem *rootItemFolderIdPointer = new QStandardItem(QLatin1String("0")); + + // Enable dropping on the root name column. + rootItemNamePointer->setDropEnabled(true); + + // Disable dropping on the URL. + rootItemUrlPointer->setDropEnabled(false); + + // Disable dragging of the bookmarks root item. + rootItemNamePointer->setDragEnabled(false); + rootItemUrlPointer->setDragEnabled(false); + + // Disable selecting the URL. + rootItemUrlPointer->setSelectable(false); + + // Populate the bookmarks root item list. + bookmarksRootItemList.append(rootItemNamePointer); + bookmarksRootItemList.append(rootItemUrlPointer); + bookmarksRootItemList.append(rootItemDatabaseIdPonter); + bookmarksRootItemList.append(rootItemDisplayOrderPointer); + bookmarksRootItemList.append(rootItemIsFolderPointer); + bookmarksRootItemList.append(rootItemFolderIdPointer); + + // Add the bookmarks root item to the tree. + treeModelPointer->appendRow(bookmarksRootItemList); + + // Populate the subfolders, starting with the root folder ID (`0`). + populateSubfolders(rootItemNamePointer, 0); + + // Expand all the folder. + draggableTreeViewPointer->expandAll(); - // Set the tree header data. The first column is the database ID, which is not displayed. - treeModelPointer->setHeaderData(1, Qt::Horizontal, i18nc("The bookmark Name header.", "Name")); - treeModelPointer->setHeaderData(2, Qt::Horizontal, i18nc("The bookmark URL header.", "URL")); + // Update the UI. + updateUi(); +} + +void BookmarksDialog::populateSubfolders(QStandardItem *folderItemNamePointer, const double folderId) const +{ + // Get the folder contents. + QList *folderContentsListPointer = BookmarksDatabase::getFolderContents(folderId); // Populate the bookmarks tree view. - for (BookmarkStruct bookmarkStruct : *bookmarksListPointer) + for (const BookmarkStruct &bookmarkStruct : *folderContentsListPointer) { - // Create a list for the bookmark items. + // Create a bookmark item list. QList bookmarkItemList; // Create the bookmark items. - QStandardItem *idItemPointer = new QStandardItem(QString::number(bookmarkStruct.id)); - QStandardItem *nameItemPointer = new QStandardItem(bookmarkStruct.favoriteIcon, bookmarkStruct.bookmarkName); - QStandardItem *urlItemPointer = new QStandardItem(bookmarkStruct.bookmarkUrl); + QStandardItem *nameItemPointer = new QStandardItem(bookmarkStruct.favoriteIcon, bookmarkStruct.name); + QStandardItem *urlItemPointer = new QStandardItem(bookmarkStruct.url); + QStandardItem *databaseIdItemPointer = new QStandardItem(QString::number(bookmarkStruct.databaseId)); + QStandardItem *displayOrderItemPointer = new QStandardItem(QString::number(bookmarkStruct.displayOrder)); + QStandardItem *isFolderItemPointer = new QStandardItem(QString::number(bookmarkStruct.isFolder)); + QStandardItem *folderIdItemPointer = new QStandardItem(QString::number(bookmarkStruct.folderId, 'f', 0)); // Format the folder ID as a floating point with no trailing zeros. + + // Enable dragging and dropping of the name column. + nameItemPointer->setDragEnabled(true); + + // Only allow dropping on the name if this is a folder. + nameItemPointer->setDropEnabled(bookmarkStruct.isFolder); - // Populate the cookie standard item list. - bookmarkItemList.append(idItemPointer); + // Disable dragging and dropping on the URL. + urlItemPointer->setDragEnabled(false); + urlItemPointer->setDropEnabled(false); + + // Disable selecting the URL. + urlItemPointer->setSelectable(false); + + // Populate the bookmark item list. bookmarkItemList.append(nameItemPointer); bookmarkItemList.append(urlItemPointer); + bookmarkItemList.append(databaseIdItemPointer); + bookmarkItemList.append(displayOrderItemPointer); + bookmarkItemList.append(isFolderItemPointer); + bookmarkItemList.append(folderIdItemPointer); - // Add the cookie to the tree. - treeModelPointer->appendRow(bookmarkItemList); + // Add the bookmark to the parent folder. + folderItemNamePointer->appendRow(bookmarkItemList); + + // Populate subfolders if this item is a folder. + if (bookmarkStruct.isFolder) + populateSubfolders(nameItemPointer, bookmarkStruct.folderId); } +} - // Auto resize the headers. - treeViewPointer->header()->setSectionResizeMode(QHeaderView::ResizeToContents); +void BookmarksDialog::refreshBookmarks() const +{ + // Repopulate the bookmarks in this dialog + populateBookmarks(); - // Indicate that all the rows are the same height, which improves performance. - treeViewPointer->setUniformRowHeights(true); + // Emit the bookmark updated signal to redraw the bookmarks in the menu and toolbar. + emit bookmarkUpdated(); +} - // Set the tree model. - treeViewPointer->setModel(treeModelPointer); +void BookmarksDialog::selectSubfolderContents(const QModelIndex &parentModelIndex) const +{ + // Get the index model. + const QAbstractItemModel *modelIndexAbstractItemPointer = parentModelIndex.model(); - // Hide the database ID column. - treeViewPointer->setColumnHidden(0, true); + // Get the number of items in the folder. + int numberOfChildrenInFolder = modelIndexAbstractItemPointer->rowCount(parentModelIndex); - // Get handles for the buttons. - QDialogButtonBox *dialogButtonBoxPointer = bookmarksDialogUi.dialogButtonBox; + // Select any child items. + if (numberOfChildrenInFolder > 0) + { + // Select the contents of any subfolders. + for (int i = 0; i < numberOfChildrenInFolder; ++i) + { + // Get the child model index. + QModelIndex childModelIndex = modelIndexAbstractItemPointer->index(i, 0, parentModelIndex); - // Connect the buttons. - connect(dialogButtonBoxPointer, SIGNAL(rejected()), this, SLOT(reject())); + // Select the subfolder contents if it is a folder. + if (childModelIndex.siblingAtColumn(IS_FOLDER_COLUMN).data().toBool()) + selectSubfolderContents(childModelIndex); + } - // Monitor editing of data in the tree model. - connect(treeModelPointer, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(updateBookmarkFromTree(QStandardItem*))); + // Get the first and last child model indexes. + QModelIndex firstChildModelIndex = modelIndexAbstractItemPointer->index(0, 0, parentModelIndex); + QModelIndex lastChildModelIndex = modelIndexAbstractItemPointer->index((numberOfChildrenInFolder - 1), 0, parentModelIndex); + + // Create an item selection that includes all the child items. + QItemSelection folderChildItemsSelection = QItemSelection(firstChildModelIndex, lastChildModelIndex); + + // Get the current selection. + QItemSelection currentSelection = treeSelectionModelPointer->selection(); + + // Combine the current selection and the folder child items selection. + currentSelection.merge(folderChildItemsSelection, QItemSelectionModel::SelectCurrent); + + // Selected the updated list of items. + treeSelectionModelPointer->select(currentSelection, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); + } +} + +void BookmarksDialog::showAddBookmarkDialog() const +{ + // Return the most recently selected index. + QModelIndex currentIndex = treeSelectionModelPointer->currentIndex(); + + // Instantiate a parent folder ID. + double parentFolderId; + + // Get the parent folder ID. + if (currentIndex.siblingAtColumn(IS_FOLDER_COLUMN).data().toInt() == 1) // The current index is a folder. + { + // Store the parent folder ID. + parentFolderId = currentIndex.siblingAtColumn(FOLDER_ID_COLUMN).data().toDouble(); + } + else // The current index is not a folder. + { + // Store the parent folder ID of the folder that contains the bookmark. + parentFolderId = currentIndex.parent().siblingAtColumn(FOLDER_ID_COLUMN).data().toDouble(); + } + + // Instantiate an add bookmark dialog. + AddBookmarkDialog *addBookmarkDialogPointer = new AddBookmarkDialog(websiteTitle, websiteUrl, websiteFavoriteIcon, parentFolderId); + + // Update the displayed bookmarks when a new one is added. + connect(addBookmarkDialogPointer, SIGNAL(bookmarkAdded()), this, SLOT(refreshBookmarks())); + + // Show the dialog. + addBookmarkDialogPointer->show(); +} + +void BookmarksDialog::showAddFolderDialog() const +{ + // Get the most recently selected index. + QModelIndex currentIndex = treeSelectionModelPointer->currentIndex(); + + // Instantiate a parent folder ID. + double parentFolderId; + + // Get the parent folder ID. + if (currentIndex.siblingAtColumn(IS_FOLDER_COLUMN).data().toInt() == 1) // The current index is a folder. + { + // Store the parent folder ID. + parentFolderId = currentIndex.siblingAtColumn(FOLDER_ID_COLUMN).data().toDouble(); + } + else // The current index is not a folder. + { + // Store the parent folder ID of the folder that contains the bookmark. + parentFolderId = currentIndex.parent().siblingAtColumn(FOLDER_ID_COLUMN).data().toDouble(); + } + + // Instantiate an add folder dialog. + AddFolderDialog *addFolderDialogPointer = new AddFolderDialog(websiteFavoriteIcon, parentFolderId); + + // Update the displayed bookmarks when a folder is added. + connect(addFolderDialogPointer, SIGNAL(folderAdded()), this, SLOT(refreshBookmarks())); + + // Show the dialog. + addFolderDialogPointer->show(); +} + +void BookmarksDialog::showEditDialog() +{ + // Get the current model index. + QModelIndex currentIndex = treeSelectionModelPointer->currentIndex(); + + // Check to see if the selected item is a folder. + if (currentIndex.siblingAtColumn(IS_FOLDER_COLUMN).data().toInt() == 1) // The selected item is a folder. + { + // Instantiate an edit folder dialog. + QDialog *editFolderDialogPointer = new EditFolderDialog(currentIndex.siblingAtColumn(DATABASE_ID_COLUMN).data().toInt(), websiteFavoriteIcon); + + // Show the dialog. + editFolderDialogPointer->show(); + + // Update the bookmarks UI. + connect(editFolderDialogPointer, SIGNAL(folderSaved()), this, SLOT(refreshBookmarks())); + } + else // The selected item is a bookmark. + { + // Instantiate an edit bookmark dialog. + QDialog *editBookmarkDialogPointer = new EditBookmarkDialog(currentIndex.siblingAtColumn(DATABASE_ID_COLUMN).data().toInt(), websiteFavoriteIcon); + + // Show the dialog. + editBookmarkDialogPointer->show(); + + // Update the bookmarks UI. + connect(editBookmarkDialogPointer, SIGNAL(bookmarkSaved()), this, SLOT(refreshBookmarks())); + } } void BookmarksDialog::updateBookmarkFromTree(QStandardItem *modifiedStandardItem) @@ -109,13 +397,13 @@ void BookmarksDialog::updateBookmarkFromTree(QStandardItem *modifiedStandardItem QModelIndex modifiedItemModelIndex = modifiedStandardItem->index(); // Get the model index of the database ID. - QModelIndex databaseIdModelIndex = modifiedItemModelIndex.siblingAtColumn(0); + QModelIndex databaseIdModelIndex = modifiedItemModelIndex.siblingAtColumn(DATABASE_ID_COLUMN); // Get the database ID. int databaseId = databaseIdModelIndex.data().toInt(); // Check to see if the bookmark name or the URL was edited. - if (modifiedStandardItem->column() == 1) // The bookmark name was edited. + if (modifiedStandardItem->column() == NAME_COLUMN) // The bookmark name was edited. { // Update the bookmark name. BookmarksDatabase::updateBookmarkName(databaseId, modifiedStandardItem->text()); @@ -129,3 +417,71 @@ void BookmarksDialog::updateBookmarkFromTree(QStandardItem *modifiedStandardItem // Emit the bookmark updated signal. emit bookmarkUpdated(); } + +void BookmarksDialog::updateSelection() const +{ + // Set the status of the buttons. + if (treeSelectionModelPointer->hasSelection()) // A bookmark or folder is selected. + { + // Get the list of selected model indexes. + QModelIndexList selectedRowsModelIndexList = treeSelectionModelPointer->selectedRows(); + + // Check to see if each selected item is a folder. + for(QModelIndex modelIndex : selectedRowsModelIndexList) + { + // If it is a folder, select all the children bookmarks. + if (modelIndex.siblingAtColumn(IS_FOLDER_COLUMN).data().toBool()) + selectSubfolderContents(modelIndex); + } + } + + // Update the UI. + updateUi(); +} + +void BookmarksDialog::updateUi() const +{ + // Set the status of the buttons. + if (treeSelectionModelPointer->hasSelection()) // A bookmark or folder is selected. + { + // Get the currently selected index. + QModelIndex currentSelectedIndex = treeSelectionModelPointer->currentIndex(); + + // Get the list of selected model indexes. + QModelIndexList selectedRowsModelIndexList = treeSelectionModelPointer->selectedRows(); + + // Get the number of selected rows. + int numberOfSelectedRows = selectedRowsModelIndexList.count(); + + // Enable the edit button if a folder or only one bookmark is selected. + editButtonPointer->setEnabled(currentSelectedIndex.siblingAtColumn(IS_FOLDER_COLUMN).data().toBool() || (numberOfSelectedRows == 1)); + + // Check if the root folder is selected. + if (treeSelectionModelPointer->isRowSelected(0)) + { + // Disable the edit button. + editButtonPointer->setEnabled(false); + + // Decrease the number of selected rows by 1. + --numberOfSelectedRows; + } + + // Enabled the delete button if at least one real bookmark or folder is selected. + deleteItemsButtonPointer->setEnabled(numberOfSelectedRows > 0); + + // Update the delete items button text. + if (numberOfSelectedRows > 0) + deleteItemsButtonPointer->setText(i18ncp("Delete items button populated text.", "Delete %1 item", "Delete %1 items", numberOfSelectedRows)); + else + deleteItemsButtonPointer->setText(i18nc("Delete items button default text", "Delete items")); + } + else // Nothing is selected. + { + // Disable the buttons. + editButtonPointer->setEnabled(false); + deleteItemsButtonPointer->setEnabled(false); + + // Update the delete items button text. + deleteItemsButtonPointer->setText(i18nc("Delete items button default text", "Delete items")); + } +}