From 67e8fd0b6a44593adb1085889098043add9c9787 Mon Sep 17 00:00:00 2001 From: donovaly Date: Sun, 13 Dec 2020 01:53:14 +0100 Subject: [PATCH] [GUI] fix tree object context menu issues - fix bug that you can select several objects across different document to make them a group - fix bug that when more than one object is selected you get a context menu to rename, despite it is unclear what object should be renamed - add feature to select also the child objects of the selection The latter was also requested long time ago: https://tracker.freecadweb.org/view.php?id=2397 --- src/Gui/Tree.cpp | 102 +++++++++++++++++++++++++++++++++++++++++++++-- src/Gui/Tree.h | 5 +++ 2 files changed, 103 insertions(+), 4 deletions(-) diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index 196ea983f2..6d400dbf66 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -472,6 +472,10 @@ TreeWidget::TreeWidget(const char *name, QWidget* parent) connect(this->finishEditingAction, SIGNAL(triggered()), this, SLOT(onFinishEditing())); + this->selectDependentsAction = new QAction(this); + connect(this->selectDependentsAction, SIGNAL(triggered()), + this, SLOT(onSelectDependents())); + this->closeDocAction = new QAction(this); connect(this->closeDocAction, SIGNAL(triggered()), this, SLOT(onCloseDoc())); @@ -843,6 +847,7 @@ void TreeWidget::contextMenuEvent (QContextMenuEvent * e) break; } } + contextMenu.addAction(this->selectDependentsAction); this->skipRecomputeAction->setChecked(doc->testStatus(App::Document::SkipRecompute)); contextMenu.addAction(this->skipRecomputeAction); this->allowPartialRecomputeAction->setChecked(doc->testStatus(App::Document::AllowPartialRecompute)); @@ -857,24 +862,43 @@ void TreeWidget::contextMenuEvent (QContextMenuEvent * e) DocumentObjectItem* objitem = static_cast (this->contextItem); + // check that the selection is not across several documents + bool acrossDocuments = false; + auto SelectedObjectsList = Selection().getCompleteSelection(); + // get the object's document as reference App::Document* doc = objitem->object()->getObject()->getDocument(); + for (auto it = SelectedObjectsList.begin(); it != SelectedObjectsList.end(); ++it) { + if ((*it).pDoc != doc) { + acrossDocuments = true; + break; + } + } + showHiddenAction->setChecked(doc->ShowHidden.getValue()); contextMenu.addAction(this->showHiddenAction); hideInTreeAction->setChecked(!objitem->object()->showInTree()); contextMenu.addAction(this->hideInTreeAction); - if (objitem->object()->getObject()->isDerivedFrom(App::DocumentObjectGroup::getClassTypeId())) - contextMenu.addAction(this->createGroupAction); + if (!acrossDocuments) { // is only sensible for selections within one document + if (objitem->object()->getObject()->isDerivedFrom(App::DocumentObjectGroup::getClassTypeId())) + contextMenu.addAction(this->createGroupAction); + // if there are dependent objects in the selection, add context menu to add them to selection + if (CheckForDependents()) + contextMenu.addAction(this->selectDependentsAction); + } contextMenu.addSeparator(); contextMenu.addAction(this->markRecomputeAction); contextMenu.addAction(this->recomputeObjectAction); contextMenu.addSeparator(); - contextMenu.addAction(this->relabelObjectAction); + + // relabeling is only possible for a single selected document + if (SelectedObjectsList.size() == 1) + contextMenu.addAction(this->relabelObjectAction); auto selItems = this->selectedItems(); - // if only one item is selected setup the edit menu + // if only one item is selected, setup the edit menu if (selItems.size() == 1) { objitem->object()->setupContextMenu(&editMenu, this, SLOT(onStartEditing())); QList editAct = editMenu.actions(); @@ -1037,6 +1061,73 @@ void TreeWidget::onFinishEditing() } } +// check if selection has dependent objects +bool TreeWidget::CheckForDependents() +{ + // if the selected object is a document + if (this->contextItem && this->contextItem->type() == DocumentType) { + return true; + } + // it can be an object + else { + QList items = this->selectedItems(); + for (QList::iterator it = items.begin(); it != items.end(); ++it) { + if ((*it)->type() == ObjectType) { + DocumentObjectItem* objitem = static_cast(*it); + App::DocumentObject* obj = objitem->object()->getObject(); + // get dependents + auto subObjectList = obj->getOutList(); + if (subObjectList.size() > 0) + return true; + } + } + } + + return false; +} + +// adds an App::DocumentObject* and its dependent objects to the selection +void TreeWidget::addDependentToSelection(App::Document* doc, App::DocumentObject* docObject) +{ + // add the docObject to the selection + Selection().addSelection(doc->getName(), docObject->getNameInDocument()); + // get the dependent + auto subObjectList = docObject->getOutList(); + // the dependent can in turn have dependents, thus add them recursively + for (auto itDepend = subObjectList.begin(); itDepend != subObjectList.end(); ++itDepend) + addDependentToSelection(doc, (*itDepend)); +} + +// add dependents of the selected tree object to selection +void TreeWidget::onSelectDependents() +{ + // We only have this context menu entry if the selection is within one document but it + // might be not the active document. Therefore get the document not here but later by casting. + App::Document* doc; + + // if the selected object is a document + if (this->contextItem && this->contextItem->type() == DocumentType) { + DocumentItem* docitem = static_cast(this->contextItem); + doc = docitem->document()->getDocument(); + std::vector obj = doc->getObjects(); + for (std::vector::iterator it = obj.begin(); it != obj.end(); ++it) + Selection().addSelection(doc->getName(), (*it)->getNameInDocument()); + } + // it can be an object + else { + QList items = this->selectedItems(); + for (QList::iterator it = items.begin(); it != items.end(); ++it) { + if ((*it)->type() == ObjectType) { + DocumentObjectItem* objitem = static_cast(*it); + doc = objitem->object()->getObject()->getDocument(); + App::DocumentObject* obj = objitem->object()->getObject(); + // the dependents can also have dependents, thus add them recursively via a separate void + addDependentToSelection(doc, obj); + } + } + } +} + void TreeWidget::onSkipRecompute(bool on) { // if a document item is selected then touch all objects @@ -2666,6 +2757,9 @@ void TreeWidget::setupText() this->finishEditingAction->setText(tr("Finish editing")); this->finishEditingAction->setStatusTip(tr("Finish editing object")); + this->selectDependentsAction->setText(tr("Add dependent objects to selection")); + this->selectDependentsAction->setStatusTip(tr("Adds all dependent objects to the selection")); + this->closeDocAction->setText(tr("Close document")); this->closeDocAction->setStatusTip(tr("Close the document")); diff --git a/src/Gui/Tree.h b/src/Gui/Tree.h index aa9e4cc9e2..f644f81a64 100644 --- a/src/Gui/Tree.h +++ b/src/Gui/Tree.h @@ -164,6 +164,7 @@ protected Q_SLOTS: void onActivateDocument(QAction*); void onStartEditing(); void onFinishEditing(); + void onSelectDependents(); void onSkipRecompute(bool on); void onAllowPartialRecompute(bool on); void onReloadDoc(); @@ -208,10 +209,14 @@ private: void updateChildren(App::DocumentObject *obj, const std::set &data, bool output, bool force); + bool CheckForDependents(); + void addDependentToSelection(App::Document* doc, App::DocumentObject* docObject); + private: QAction* createGroupAction; QAction* relabelObjectAction; QAction* finishEditingAction; + QAction* selectDependentsAction; QAction* skipRecomputeAction; QAction* allowPartialRecomputeAction; QAction* markRecomputeAction;