Assembly: Fix "deactivated by activating a App::Part, assembly stay in edit"

Fix "Activating a body in a part in an assembly deactivates the assembly and activate the part"
Fix "A manually deactivated assembly is still restoring later"
This commit is contained in:
paddle
2026-01-22 14:21:28 +01:00
committed by PaddleStroke
parent abc5f90466
commit 62cbaf7336
8 changed files with 58 additions and 15 deletions

View File

@@ -187,6 +187,9 @@ void Gui::ActiveObjectList::setObject(
}
if (!obj) {
if (_Doc) {
_Doc->signalActivatedVP(nullptr, name);
}
return;
}
@@ -202,6 +205,11 @@ void Gui::ActiveObjectList::setObject(
_ObjectMap[name] = info;
setHighlight(info, mode, true);
auto vp = freecad_cast<ViewProviderDocumentObject*>(Application::Instance->getViewProvider(obj));
if (vp) {
vp->getDocument()->signalActivatedVP(vp, name);
}
}
bool Gui::ActiveObjectList::hasObject(const char* name) const

View File

@@ -106,5 +106,6 @@ private:
static const char PDBODYKEY[] = "pdbody";
static const char PARTKEY[] = "part";
static const char ASSEMBLYKEY[] = "assembly";
#endif

View File

@@ -121,8 +121,10 @@ public:
signalChangedObject;
/// signal on renamed Object
mutable fastsignals::signal<void(const Gui::ViewProviderDocumentObject&)> signalRelabelObject;
/// signal on activated Object
/// signal on activated Object (relay of App activation signal)
mutable fastsignals::signal<void(const Gui::ViewProviderDocumentObject&)> signalActivatedObject;
/// signal on activated Object in the tree (bold item)
mutable fastsignals::signal<void(const Gui::ViewProviderDocumentObject*, const char*)> signalActivatedVP;
/// signal on entering in edit mode
mutable fastsignals::signal<void(const Gui::ViewProviderDocumentObject&)> signalInEdit;
/// signal on leaving edit mode

View File

@@ -77,7 +77,7 @@ void ViewProviderPart::setupContextMenu(QMenu* menu, QObject* receiver, const ch
ViewProviderGeometryObject::setupContextMenu(menu, receiver, member);
}
bool ViewProviderPart::isActivePart()
bool ViewProviderPart::isActivePart(const char* key)
{
App::DocumentObject* activePart = nullptr;
auto activeDoc = Gui::Application::Instance->activeDocument();
@@ -89,7 +89,7 @@ bool ViewProviderPart::isActivePart()
return false;
}
activePart = activeView->getActiveObject<App::DocumentObject*>(PARTKEY);
activePart = activeView->getActiveObject<App::DocumentObject*>(key);
if (activePart == this->getObject()) {
return true;

View File

@@ -23,6 +23,7 @@
#ifndef GUI_VIEWPROVIDER_ViewProviderPart_H
#define GUI_VIEWPROVIDER_ViewProviderPart_H
#include "ActiveObjectList.h"
#include "ViewProviderGeometryObject.h"
#include "ViewProviderOriginGroup.h"
#include "ViewProviderFeaturePython.h"
@@ -44,7 +45,7 @@ public:
bool doubleClicked() override;
void setupContextMenu(QMenu* menu, QObject* receiver, const char* member) override;
bool isActivePart();
bool isActivePart(const char* key = PARTKEY);
void toggleActivePart();
/// deliver the icon shown in the tree view

View File

@@ -143,7 +143,7 @@ void ViewProviderAssembly::setupContextMenu(QMenu* menu, QObject* receiver, cons
QAction* act = menu->addAction(QObject::tr("Active object"));
act->setCheckable(true);
act->setChecked(isActivePart());
act->setChecked(isActivePart(ASSEMBLYKEY));
func->trigger(act, [this]() { this->doubleClicked(); });
ViewProviderDragger::setupContextMenu(menu, receiver, member); // NOLINT
@@ -153,6 +153,7 @@ bool ViewProviderAssembly::doubleClicked()
{
if (isInEditMode()) {
autoCollapseOnDeactivation = true;
getDocument()->setEditRestore(false);
getDocument()->resetEdit();
}
else {
@@ -280,6 +281,7 @@ bool ViewProviderAssembly::setEdit(int mode)
{
if (mode == ViewProvider::Default) {
// Ask that this edit mode be restored. For example if it is quit to edit a sketch.
Base::Console().warning("setEdit\n");
getDocument()->setEditRestore(true);
autoCollapseOnDeactivation = false;
@@ -290,7 +292,7 @@ bool ViewProviderAssembly::setEdit(int mode)
"Gui.getDocument(appDoc).ActiveView.setActiveObject('%s', "
"appDoc.getObject('%s'))",
this->getObject()->getDocument()->getName(),
PARTKEY,
ASSEMBLYKEY,
this->getObject()->getNameInDocument()
);
@@ -310,6 +312,13 @@ bool ViewProviderAssembly::setEdit(int mode)
UpdateSolverInformation();
});
connectActivatedVP = getDocument()->signalActivatedVP.connect(std::bind(
&ViewProviderAssembly::slotActivatedVP,
this,
std::placeholders::_1,
std::placeholders::_2
));
assembly->solve();
return true;
@@ -334,13 +343,15 @@ void ViewProviderAssembly::unsetEdit(int mode)
}
// Set the part as not 'Activated' ie not bold in the tree.
Gui::Command::doCommand(
Gui::Command::Gui,
"appDoc = App.getDocument('%s')\n"
"Gui.getDocument(appDoc).ActiveView.setActiveObject('%s', None)",
this->getObject()->getDocument()->getName(),
PARTKEY
);
if (isActivePart(ASSEMBLYKEY)) {
Gui::Command::doCommand(
Gui::Command::Gui,
"appDoc = App.getDocument('%s')\n"
"Gui.getDocument(appDoc).ActiveView.setActiveObject('%s', None)",
this->getObject()->getDocument()->getName(),
ASSEMBLYKEY
);
}
Gui::TaskView::TaskView* taskView = Gui::Control().taskPanel();
if (taskView) {
@@ -349,12 +360,26 @@ void ViewProviderAssembly::unsetEdit(int mode)
}
connectSolverUpdate.disconnect();
connectActivatedVP.disconnect();
return;
}
ViewProviderPart::unsetEdit(mode);
}
void ViewProviderAssembly::slotActivatedVP(const Gui::ViewProviderDocumentObject* vp, const char* name)
{
if (name && strcmp(name, ASSEMBLYKEY) == 0) {
// If the new active VP is NOT this assembly (meaning we lost activation or it was cleared)
if (vp != this && isInEditMode()) {
autoCollapseOnDeactivation = true;
getDocument()->setEditRestore(false);
getDocument()->resetEdit();
}
}
}
void ViewProviderAssembly::setDragger()
{
// Create the dragger coin object
@@ -404,7 +429,7 @@ App::DocumentObject* ViewProviderAssembly::getActivePart() const
if (!activeView) {
return nullptr;
}
return activeView->getActiveObject<App::DocumentObject*>(PARTKEY);
return activeView->getActiveObject<App::DocumentObject*>(ASSEMBLYKEY);
}
bool ViewProviderAssembly::keyPressed(bool pressed, int key)

View File

@@ -263,6 +263,7 @@ private:
);
void slotAboutToOpenTransaction(const std::string& cmdName);
void slotActivatedVP(const Gui::ViewProviderDocumentObject* vp, const char* name);
struct ComponentState
{
@@ -289,6 +290,7 @@ private:
TaskAssemblyMessages* taskSolver;
fastsignals::connection connectActivatedVP;
fastsignals::connection connectSolverUpdate;
fastsignals::scoped_connection m_preTransactionConn;
};

View File

@@ -284,7 +284,11 @@ App::Part* getActivePart()
{
Gui::MDIView* activeView = Gui::Application::Instance->activeView();
if (activeView) {
return activeView->getActiveObject<App::Part*>(PARTKEY);
auto* obj = activeView->getActiveObject<App::Part*>(PARTKEY);
if (!obj) {
obj = activeView->getActiveObject<App::Part*>(ASSEMBLYKEY);
}
return obj;
}
else {
return nullptr;