diff --git a/src/document/UBDocumentController.cpp b/src/document/UBDocumentController.cpp index a5a6685c..87042f6c 100644 --- a/src/document/UBDocumentController.cpp +++ b/src/document/UBDocumentController.cpp @@ -263,9 +263,13 @@ UBDocumentGroupTreeItem* UBDocumentController::selectedDocumentGroupTreeItem() void UBDocumentController::itemSelectionChanged() { + updateCurrentSelection(); + reloadThumbnails(); - if (selectedDocumentProxy()) + if (multipleSelection()) + mSelectionType = Multiple; + else if (selectedDocumentProxy()) mSelectionType = Document; else if (selectedDocumentGroupTreeItem()) mSelectionType = Folder; @@ -366,7 +370,7 @@ void UBDocumentController::setupViews() loadDocumentProxies(); - mDocumentUI->documentTreeWidget->setSelectionMode(QAbstractItemView::SingleSelection); + mDocumentUI->documentTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); mDocumentUI->documentTreeWidget->setDragEnabled(true); mDocumentUI->documentTreeWidget->viewport()->setAcceptDrops(true); mDocumentUI->documentTreeWidget->setDropIndicatorShown(true); @@ -695,90 +699,121 @@ void UBDocumentController::moveFolderToTrash(UBDocumentGroupTreeItem* groupTi) reloadThumbnails(); } -void UBDocumentController::deleteSelectedItem() +/** + * @brief Empty the trash folder, deleting all contents permanently. + * @param showConfirmationDialog If set to true, prompts confirmation from the user + */ +void UBDocumentController::emptyTrash(bool showConfirmationDialog) { - if (mSelectionType == Page) - { - QList selectedItems = mDocumentUI->thumbnailWidget->selectedItems(); + if (showConfirmationDialog && + !UBApplication::mainWindow->yesNoQuestion(tr("Empty Trash"), tr("Are you sure you want to empty trash?"))) + return; - deletePages(selectedItems); + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + QList toBeDeleted; + + for (int i(0); i < mTrashTi->childCount(); ++i) { + UBDocumentProxyTreeItem* proxyTi = dynamic_cast(mTrashTi->child(i)); + if (proxyTi && proxyTi->proxy()){ + if(proxyTi->proxy() == mBoardController->selectedDocument()){ + selectADocumentOnTrashingSelectedOne(dynamic_cast(mDocumentUI->documentTreeWidget),proxyTi); + } + toBeDeleted << proxyTi; + } } - else - { - UBDocumentProxyTreeItem *proxyTi = selectedDocumentProxyTreeItem(); + showMessage(tr("Emptying trash")); - UBDocumentGroupTreeItem* groupTi = selectedDocumentGroupTreeItem(); + for (int i(0); i < toBeDeleted.count(); ++i) { + UBDocumentProxyTreeItem* proxyTi = toBeDeleted.at(i); - if (proxyTi && proxyTi->proxy() && proxyTi->parent()) - { - if(UBApplication::mainWindow->yesNoQuestion(tr("Remove Document"), tr("Are you sure you want to remove the document '%1'?").arg(proxyTi->proxy()->metaData(UBSettings::documentName).toString()))) - { - if (proxyTi->parent() != mTrashTi) - { - moveDocumentToTrash(groupTi, proxyTi); - } - else - { - // We have to physically delete document - proxyTi->parent()->removeChild(proxyTi); - UBPersistenceManager::persistenceManager()->deleteDocument(proxyTi->proxy()); - - if (mTrashTi->childCount()==0) - selectDocument(NULL); - else - selectDocument(((UBDocumentProxyTreeItem*)mTrashTi->child(0))->proxy()); - reloadThumbnails(); - } - } - } - else if (groupTi) - { - if (groupTi == mTrashTi) - { - if(UBApplication::mainWindow->yesNoQuestion(tr("Empty Trash"), tr("Are you sure you want to empty trash?"))) - { - QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - QList toBeDeleted; + proxyTi->parent()->removeChild(proxyTi); + UBPersistenceManager::persistenceManager()->deleteDocument(proxyTi->proxy()); + } - for (int i = 0; i < groupTi->childCount(); i++) - { - UBDocumentProxyTreeItem* proxyTi = dynamic_cast(groupTi->child(i)); - if (proxyTi && proxyTi->proxy()){ - if(proxyTi->proxy() == mBoardController->selectedDocument()){ - selectADocumentOnTrashingSelectedOne(dynamic_cast(mDocumentUI->documentTreeWidget),proxyTi); - } - toBeDeleted << proxyTi; - } - } + showMessage(tr("Emptied trash")); - showMessage(tr("Emptying trash")); + QApplication::restoreOverrideCursor(); + mMainWindow->actionDelete->setEnabled(false); +} - for (int i = 0; i < toBeDeleted.count(); i++) - { - UBDocumentProxyTreeItem* proxyTi = toBeDeleted.at(i); +/** + * @brief Delete an item (document or folder) from the document list + * @param item The document or folder to delete + * @param showConfirmationDialog If set to true, the user will be asked for confirmation + * + * If the item passed as parameter is a document that is in the trash, then it is deleted + * permanently. If the trash folder is passed, then all its contents are deleted. + * Finally, if a folder is passed, all its contents are moved to trash. + */ +void UBDocumentController::deleteTreeItem(QTreeWidgetItem * item, bool showConfirmationDialog) +{ + UBDocumentProxyTreeItem * document = dynamic_cast(item); + UBDocumentGroupTreeItem * folder = dynamic_cast(item); - proxyTi->parent()->removeChild(proxyTi); - UBPersistenceManager::persistenceManager()->deleteDocument(proxyTi->proxy()); - } + if (document) { + if (showConfirmationDialog && + !UBApplication::mainWindow->yesNoQuestion(tr("Remove Document"), + tr("Are you sure you want to remove the document '%1'?").arg(document->proxy()->metaData(UBSettings::documentName).toString()))) + return; - showMessage(tr("Emptied trash")); + if (!isDocumentInTrash(document)) + moveDocumentToTrash(dynamic_cast(document->parent()), document); - QApplication::restoreOverrideCursor(); - mMainWindow->actionDelete->setEnabled(false); - } - } + else { + document->parent()->removeChild(document); + UBPersistenceManager::persistenceManager()->deleteDocument(document->proxy()); + + if (mTrashTi->childCount()==0) + selectDocument(NULL); else - { - if(UBApplication::mainWindow->yesNoQuestion(tr("Remove Folder"), tr("Are you sure you want to remove the folder '%1' and all its content?").arg(groupTi->groupName()))) - { - QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - moveFolderToTrash(groupTi); - QApplication::restoreOverrideCursor(); - } - } + selectDocument(((UBDocumentProxyTreeItem*)mTrashTi->child(0))->proxy()); + + reloadThumbnails(); + } + } + + else if (folder) { + if (folder == mTrashTi) + emptyTrash(showConfirmationDialog); + + else { + if (showConfirmationDialog && + !UBApplication::mainWindow->yesNoQuestion(tr("Remove Folder"), + tr("Are you sure you want to remove the folder '%1' and all its content?").arg(folder->groupName()))) + return; + + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + moveFolderToTrash(folder); + QApplication::restoreOverrideCursor(); + } + } +} + + + +void UBDocumentController::deleteSelectedItem() +{ + if (mSelectionType == Page) { + QList selectedItems = mDocumentUI->thumbnailWidget->selectedItems(); + deletePages(selectedItems); + } + + else if (mSelectionType == Multiple) { + if (!UBApplication::mainWindow->yesNoQuestion(tr("Remove mutliple documents"), + tr("Are you sure you want to remove all selected documents?"))) + return; + + foreach (QTreeWidgetItem * item, mCurrentSelection) { + deleteTreeItem(item, false); } } + + else if (mSelectionType == Document || mSelectionType == Folder) { + QTreeWidgetItem * item = mCurrentSelection.first(); + if (item) + deleteTreeItem(item, true); + } } @@ -897,14 +932,17 @@ void UBDocumentController::loadDocumentProxies() mDocumentUI->documentTreeWidget->addTopLevelItem(emptyGroupNameTi); mDocumentUI->documentTreeWidget->addTopLevelItem(mTrashTi); - } +} + void UBDocumentController::itemClicked(QTreeWidgetItem * item, int column ) { Q_UNUSED(item); Q_UNUSED(column); + /* selectDocument(selectedDocumentProxy(), false); itemSelectionChanged(); + */ } void UBDocumentController::itemChanged(QTreeWidgetItem * item, int column) @@ -1119,6 +1157,90 @@ void UBDocumentController::pageSelectionChanged() selectionChanged(); } +bool UBDocumentController::isDocumentInTrash(UBDocumentProxyTreeItem * document) +{ + return dynamic_cast(document->parent())->isTrashFolder(); +} + +bool UBDocumentController::isCurrentSelectionInTrash() +{ + bool selectionIsInTrash = false; + foreach (QTreeWidgetItem* item, mCurrentSelection) { + // Find the first valid element; no need to check all of them + UBDocumentProxyTreeItem * document = dynamic_cast(item); + if (document) { + selectionIsInTrash = isDocumentInTrash(document); + break; + } + } + + return selectionIsInTrash; +} + +/** + * @brief Set the currently selected items, after checking the selection is valid + * + * This method compares the current selection with the previous one, and deselects + * the "incorrectly" selected items if necessary. For example, it shouldn't be possible + * to select items both in the trash and out; and the Trash folder shouldn't be + * included in multiple selections. + */ +void UBDocumentController::updateCurrentSelection() +{ + QList newSelection = mDocumentUI->documentTreeWidget->selectedItems(); + + // If the selection is of size 1 or 0, we don't need to do any checking, we just accept it. + if (newSelection.size() <= 1) { + mCurrentSelection = newSelection; + return; + } + + // We don't allow the Trash folder in multiple selections + // If it is currently selected, we deselect all the newly selected items + if (mCurrentSelection.size() == 1) { + UBDocumentGroupTreeItem* folder = dynamic_cast(mCurrentSelection.first()); + + if (folder && folder->isTrashFolder()) { + foreach (QTreeWidgetItem* item, newSelection) { + if (item != folder) + item->setSelected(false); + } + + return; + } + } + + // Find the elements of the new selection that aren't in the old one + QSet newItems = newSelection.toSet().subtract(mCurrentSelection.toSet()); + + bool selectionIsInTrash = isCurrentSelectionInTrash(); + + foreach (QTreeWidgetItem* item, newItems) { + bool addToSelection = true; + UBDocumentProxyTreeItem * document = dynamic_cast(item); + if (document) { + // No mix between trashed and non-trashed items + if (isDocumentInTrash(document) != selectionIsInTrash) + addToSelection = false; + } + + UBDocumentGroupTreeItem * folder = dynamic_cast(item); + if (folder) { + // Trash folder is not allowed in multiple selections + if (folder->isTrashFolder()) + addToSelection = false; + + // Don't add a folder when trash items are selected + if (selectionIsInTrash) + addToSelection = false; + } + + if (addToSelection) + mCurrentSelection.append(item); + else + item->setSelected(false); + } +} void UBDocumentController::selectionChanged() { @@ -1135,14 +1257,20 @@ void UBDocumentController::selectionChanged() bool pageSelected = (mSelectionType == Page); bool groupSelected = (mSelectionType == Folder); bool docSelected = (mSelectionType == Document); + bool multipleSelected = (mSelectionType == Multiple); + bool selectedItemsAreInTrash = isCurrentSelectionInTrash(); - bool trashSelected = false; + + bool trashSelected = false; // set to true if selected items are in trash or if trash folder is selected if (groupSelected && selectedDocumentGroupTreeItem()) trashSelected = selectedDocumentGroupTreeItem()->isTrashFolder(); if ((docSelected || pageSelected) && proxyTi) trashSelected = dynamic_cast(proxyTi->parent())->isTrashFolder(); + if (multipleSelected) + trashSelected = selectedItemsAreInTrash; + bool defaultGroupSelected = false; if (groupSelected && selectedDocumentGroupTreeItem()) defaultGroupSelected = selectedDocumentGroupTreeItem()->isDefaultFolder(); @@ -1179,7 +1307,7 @@ void UBDocumentController::selectionChanged() bool deleteEnabled = false; if (trashSelected) { - if (docSelected) + if (docSelected || multipleSelected) deleteEnabled = true; else if (groupSelected && selectedDocumentGroupTreeItem()) { @@ -1189,7 +1317,7 @@ void UBDocumentController::selectionChanged() } else { - deleteEnabled = groupSelected || docSelected || pageSelected; + deleteEnabled = groupSelected || docSelected || pageSelected || multipleSelected; // TODO: clean up. this is weirdly done } if (pageSelected && (pageCount == mDocumentUI->thumbnailWidget->selectedItems().count())) @@ -1204,7 +1332,7 @@ void UBDocumentController::selectionChanged() if (trashSelected) { - if (docSelected) + if (docSelected || multipleSelected) // TODO: clean this up. have only "selectedItemsAreInTrash" { mMainWindow->actionDelete->setIcon(QIcon(":/images/toolbar/deleteDocument.png")); mMainWindow->actionDelete->setText(tr("Delete")); @@ -1221,8 +1349,8 @@ void UBDocumentController::selectionChanged() mMainWindow->actionDelete->setText(tr("Trash")); } - mMainWindow->actionDocumentAdd->setEnabled((docSelected || pageSelected) && !trashSelected); - mMainWindow->actionImport->setEnabled(!trashSelected); + mMainWindow->actionDocumentAdd->setEnabled((docSelected || pageSelected) && !trashSelected && !multipleSelected); + mMainWindow->actionImport->setEnabled(!trashSelected && !multipleSelected); } @@ -1565,7 +1693,9 @@ void UBDocumentController::focusChanged(QWidget *old, QWidget *current) } else if (current == mDocumentUI->documentTreeWidget) { - if (selectedDocumentProxy()) + if (multipleSelection()) + mSelectionType = Multiple; + else if (selectedDocumentProxy()) mSelectionType = Document; else if (selectedDocumentGroupTreeItem()) mSelectionType = Folder; @@ -1652,6 +1782,10 @@ void UBDocumentController::refreshDocumentThumbnailsView(UBDocumentContainer*) UBDocumentProxy *proxy = selectedDocumentProxy(); QGraphicsPixmapItem *selection = 0; + // Don't display thumbnails if multiple documents are selected + if (multipleSelection()) + proxy = 0; + QStringList labels; if (proxy) @@ -1696,3 +1830,9 @@ void UBDocumentController::refreshDocumentThumbnailsView(UBDocumentContainer*) QApplication::restoreOverrideCursor(); } + +bool UBDocumentController::multipleSelection() +{ + QList items = mDocumentUI->documentTreeWidget->selectedItems(); + return (items.size() > 1); +} diff --git a/src/document/UBDocumentController.h b/src/document/UBDocumentController.h index 7fc70926..da2806a3 100644 --- a/src/document/UBDocumentController.h +++ b/src/document/UBDocumentController.h @@ -102,7 +102,7 @@ class UBDocumentController : public UBDocumentContainer enum LastSelectedElementType { - None = 0, Folder, Document, Page + None = 0, Folder, Document, Page, Multiple }; LastSelectedElementType mSelectionType; @@ -121,13 +121,20 @@ class UBDocumentController : public UBDocumentContainer UBDocumentToolsPalette *mToolsPalette; bool mToolsPalettePositionned; UBDocumentGroupTreeItem* mTrashTi; + QList mCurrentSelection; + QString mDocumentTrashGroupName; + QString mDefaultDocumentGroupName; void selectADocumentOnTrashingSelectedOne(UBDocumentGroupTreeItem* groupTi,UBDocumentProxyTreeItem *proxyTi); - void moveDocumentToTrash(UBDocumentGroupTreeItem* groupTi, UBDocumentProxyTreeItem *proxyTi); void moveFolderToTrash(UBDocumentGroupTreeItem* groupTi); - QString mDocumentTrashGroupName; - QString mDefaultDocumentGroupName; + void emptyTrash(bool showConfirmationDialog); + void deleteTreeItem(QTreeWidgetItem * item, bool showConfirmationDialog); + + void updateCurrentSelection(); + bool multipleSelection(); + bool isDocumentInTrash(UBDocumentProxyTreeItem * document); + bool isCurrentSelectionInTrash(); private slots: void documentZoomSliderValueChanged (int value);