Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PD: Fix crash when adding sketch to loft via tree view #13686

Merged
merged 1 commit into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
91 changes: 79 additions & 12 deletions src/Gui/Tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,15 @@
#include "Workbench.h"


FC_LOG_LEVEL_INIT("Tree", false, true, true)

Check warning on line 71 in src/Gui/Tree.cpp

View workflow job for this annotation

GitHub Actions / Lint / Lint

variable '_s_fclvl' is non-const and globally accessible, consider making it const [cppcoreguidelines-avoid-non-const-global-variables]

#define _TREE_PRINT(_level,_func,_msg) \

Check warning on line 73 in src/Gui/Tree.cpp

View workflow job for this annotation

GitHub Actions / Lint / Lint

function-like macro '_TREE_PRINT' used; consider a 'constexpr' template function [cppcoreguidelines-macro-usage]
_FC_PRINT(FC_LOG_INSTANCE,_level,_func, '['<<getTreeName()<<"] " << _msg)

Check warning on line 74 in src/Gui/Tree.cpp

View workflow job for this annotation

GitHub Actions / Lint / Lint

macro argument should be enclosed in parentheses [bugprone-macro-parentheses]
#define TREE_MSG(_msg) _TREE_PRINT(FC_LOGLEVEL_MSG,Notify<Base::LogStyle::Message>,_msg)

Check warning on line 75 in src/Gui/Tree.cpp

View workflow job for this annotation

GitHub Actions / Lint / Lint

function-like macro 'TREE_MSG' used; consider a 'constexpr' template function [cppcoreguidelines-macro-usage]
#define TREE_WARN(_msg) _TREE_PRINT(FC_LOGLEVEL_WARN,Notify<Base::LogStyle::Warning>,_msg)

Check warning on line 76 in src/Gui/Tree.cpp

View workflow job for this annotation

GitHub Actions / Lint / Lint

function-like macro 'TREE_WARN' used; consider a 'constexpr' template function [cppcoreguidelines-macro-usage]
#define TREE_ERR(_msg) _TREE_PRINT(FC_LOGLEVEL_ERR,Notify<Base::LogStyle::Error>,_msg)

Check warning on line 77 in src/Gui/Tree.cpp

View workflow job for this annotation

GitHub Actions / Lint / Lint

function-like macro 'TREE_ERR' used; consider a 'constexpr' template function [cppcoreguidelines-macro-usage]
#define TREE_LOG(_msg) _TREE_PRINT(FC_LOGLEVEL_LOG,Notify<Base::LogStyle::Log>,_msg)

Check warning on line 78 in src/Gui/Tree.cpp

View workflow job for this annotation

GitHub Actions / Lint / Lint

function-like macro 'TREE_LOG' used; consider a 'constexpr' template function [cppcoreguidelines-macro-usage]
#define TREE_TRACE(_msg) _TREE_PRINT(FC_LOGLEVEL_TRACE,Notify<Base::LogStyle::Log>,_msg)

Check warning on line 79 in src/Gui/Tree.cpp

View workflow job for this annotation

GitHub Actions / Lint / Lint

function-like macro 'TREE_TRACE' used; consider a 'constexpr' template function [cppcoreguidelines-macro-usage]

using namespace Gui;
namespace sp = std::placeholders;
Expand Down Expand Up @@ -206,6 +206,7 @@

class Gui::DocumentObjectData {
public:
bool dirtyFlag {};
DocumentItem* docItem;
DocumentObjectItems items;
ViewProviderDocumentObject* viewObject;
Expand Down Expand Up @@ -243,6 +244,24 @@
label2 = viewObject->getObject()->Label2.getValue();
}

void insertItem(DocumentObjectItem* item)
{
items.insert(item);
dirtyFlag = true;
}

void removeItem(DocumentObjectItem* item)
{
auto it = items.find(item);
if (it == items.end()) {
assert(0);
}
else {
items.erase(it);
dirtyFlag = true;
}
}

const char* getTreeName() const {
return docItem->getTreeName();
}
Expand Down Expand Up @@ -972,7 +991,7 @@
auto selItems = this->selectedItems();
// if only one item is selected, setup the edit menu
if (selItems.size() == 1) {
objitem->object()->setupContextMenu(&editMenu, this, SLOT(onStartEditing()));

Check warning on line 994 in src/Gui/Tree.cpp

View workflow job for this annotation

GitHub Actions / Lint / Lint

objitem->object()->setupContextMenu(&editMenu, this, SLOT(onStartEditing()));
QList<QAction*> editAct = editMenu.actions();
if (!editAct.isEmpty()) {
QAction* topact = contextMenu.actions().constFirst();
Expand Down Expand Up @@ -4544,12 +4563,18 @@
// Block signals here otherwise we get a recursion and quadratic runtime
bool ok = treeWidget()->blockSignals(true);
FOREACH_ITEM_ALL(item);
_v.second->dirtyFlag = false;
if (item == exclude) {
if (item->selected > 0)
item->selected = -1;
else
item->selected = 0;
updateItemSelection(item);
// The set has been changed while calling updateItemSelection
// so that the iterator has become invalid -> Abort
if (_v.second->dirtyFlag) {
break;
}
}
else {
item->selected = 0;
Expand Down Expand Up @@ -4586,7 +4611,13 @@
updateSelection(ti->child(i));
}

void DocumentItem::updateItemSelection(DocumentObjectItem* item) {
void DocumentItem::updateItemSelection(DocumentObjectItem* item)
{
// Note: In several places of this function the selection is altered and the notification of
// the selection observers can trigger a recreation of all DocumentObjectItem so that the
// passed 'item' can become a dangling pointer.
// Thus,'item' mustn't be accessed any more after altering the selection.
// For further details see the bug analsysis of #13107
bool selected = item->isSelected();
bool checked = item->checkState(0) == Qt::Checked;

Expand Down Expand Up @@ -4654,23 +4685,30 @@
Gui::Selection().rmvSelection(docname, objname, subname.c_str());
return;
}

auto vobj = item->object();
selected = false;
if (!item->mySubs.empty()) {
for (auto& sub : item->mySubs) {
if (Gui::Selection().addSelection(docname, objname, (subname + sub).c_str()))
if (Gui::Selection().addSelection(docname, objname, (subname + sub).c_str())) {
selected = true;
}
}
}
if (!selected) {
item->mySubs.clear();
if (!Gui::Selection().addSelection(docname, objname, subname.c_str())) {
item->selected = 0;
item->setSelected(false);
item->setCheckState(false);
// Safely re-access the item
DocumentObjectItem* item2 = findItem(vobj->getObject(), subname);
if (item2) {
item2->selected = 0;
item2->setSelected(false);
item2->setCheckState(false);
}
return;
}
}
getTree()->syncView(item->object());
getTree()->syncView(vobj);
}

App::DocumentObject* DocumentItem::getTopParent(App::DocumentObject* obj, std::string& subname) {
Expand Down Expand Up @@ -4717,6 +4755,39 @@
return topParent;
}

DocumentObjectItem *DocumentItem::findItem(App::DocumentObject* obj, const std::string& subname) const
{
auto it = ObjectMap.find(obj);
if (it == ObjectMap.end()) {
return nullptr;
}

// There is only one instance in the tree view
if (it->second->items.size() == 1) {
return *(it->second->items.begin());
}

// If there are multiple instances use the one with the same subname
DocumentObjectItem* item {};
for (auto jt : it->second->items) {
std::ostringstream str;
App::DocumentObject* topParent = nullptr;
jt->getSubName(str, topParent);
if (topParent) {
if (!obj->redirectSubName(str, topParent, nullptr)) {
str << obj->getNameInDocument() << '.';
}
}

if (subname == str.str()) {
item = jt;
break;
}
}

return item;
}

DocumentObjectItem* DocumentItem::findItemByObject(
bool sync, App::DocumentObject* obj, const char* subname, bool select)
{
Expand Down Expand Up @@ -5017,7 +5088,7 @@
setFlags(flags() | Qt::ItemIsEditable | Qt::ItemIsUserCheckable);
setCheckState(false);

myData->items.insert(this);
myData->insertItem(this);
++countItems;
TREE_LOG("Create item: " << countItems << ", " << object()->getObject()->getFullName());
}
Expand All @@ -5026,11 +5097,7 @@
{
--countItems;
TREE_LOG("Delete item: " << countItems << ", " << object()->getObject()->getFullName());
auto it = myData->items.find(this);
if (it == myData->items.end())
assert(0);
else
myData->items.erase(it);
myData->removeItem(this);

if (myData->rootItem == this)
myData->rootItem = nullptr;
Expand Down Expand Up @@ -5308,7 +5375,7 @@

// Prepend the visibility pixmap to the final icon pixmaps and use these as the icon.
QIcon new_icon;
for (auto state: {QIcon::On, QIcon::Off}) {

Check warning on line 5378 in src/Gui/Tree.cpp

View workflow job for this annotation

GitHub Actions / Lint / Lint

Missing space around colon in range-based for loop [whitespace/forcolon] [2]
QPixmap px_org = icon.pixmap(0xFFFF, 0xFFFF, QIcon::Normal, state);

QPixmap px(2*px_org.width(), px_org.height());
Expand Down Expand Up @@ -5674,4 +5741,4 @@
}
}

#include "moc_Tree.cpp"

Check failure on line 5744 in src/Gui/Tree.cpp

View workflow job for this annotation

GitHub Actions / Lint / Lint

'moc_Tree.cpp' file not found [clang-diagnostic-error]
1 change: 1 addition & 0 deletions src/Gui/Tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ class DocumentItem : public QTreeWidgetItem, public Base::Persistence
App::DocumentObject *obj, const char *subname, bool select=false);

DocumentObjectItem *findItem(bool sync, DocumentObjectItem *item, const char *subname, bool select=true);
DocumentObjectItem *findItem(App::DocumentObject* obj, const std::string& subname) const;

App::DocumentObject *getTopParent(App::DocumentObject *obj, std::string &subname);

Expand Down