diff options
author | Campbell Barton <ideasman42@gmail.com> | 2012-08-20 17:51:25 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2012-08-20 17:51:25 +0400 |
commit | 0f6a6c7499f0c1fa509355c5967f30a42cfa771e (patch) | |
tree | 0de8396d8dd554719f2103276ec14398b18ec298 /source/blender | |
parent | ad647b2767ea8b5cdc24cb3fae1173eca8a0da9b (diff) |
fix for crash pasting nodes into a node tree when the ID pointer is lost.
also fix for ID user count on paste which wasn't increasing.
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_node.h | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/node.c | 98 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_edit.c | 25 |
3 files changed, 119 insertions, 5 deletions
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 61845619452..c45afbe77a9 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -388,6 +388,7 @@ void nodeSocketSetType(struct bNodeSocket *sock, int type); /* Node Clipboard */ void BKE_node_clipboard_init(struct bNodeTree *ntree); void BKE_node_clipboard_clear(void); +int BKE_node_clipboard_validate(void); void BKE_node_clipboard_add_node(struct bNode *node); void BKE_node_clipboard_add_link(struct bNodeLink *link); const struct ListBase *BKE_node_clipboard_get_nodes(void); diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 7cee9626c3f..dc2f3a1a2fa 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -1425,13 +1425,37 @@ void nodeSocketSetType(bNodeSocket *sock, int type) /* ************** Node Clipboard *********** */ +#define USE_NODE_CB_VALIDATE + +#ifdef USE_NODE_CB_VALIDATE +/** + * This data structure is to validate the node on creation, + * otherwise we may reference missing data. + * + * Currently its only used for ID's, but nodes may one day + * referene other pointers which need validation. + */ +typedef struct bNodeClipboardExtraInfo { + struct bNodeClipboardExtraInfo *next, *prev; + ID *id; + char id_name[MAX_ID_NAME]; + char library_name[FILE_MAX]; +} bNodeClipboardExtraInfo; +#endif /* USE_NODE_CB_VALIDATE */ + + typedef struct bNodeClipboard { ListBase nodes; + +#ifdef USE_NODE_CB_VALIDATE + ListBase nodes_extra_info; +#endif + ListBase links; int type; } bNodeClipboard; -bNodeClipboard node_clipboard; +bNodeClipboard node_clipboard = {{0}}; void BKE_node_clipboard_init(struct bNodeTree *ntree) { @@ -1454,11 +1478,83 @@ void BKE_node_clipboard_clear(void) nodeFreeNode(NULL, node); } node_clipboard.nodes.first = node_clipboard.nodes.last = NULL; + +#ifdef USE_NODE_CB_VALIDATE + BLI_freelistN(&node_clipboard.nodes_extra_info); +#endif +} + +/* return FALSE when one or more ID's are lost */ +int BKE_node_clipboard_validate(void) +{ + int ok = TRUE; + +#ifdef USE_NODE_CB_VALIDATE + bNodeClipboardExtraInfo *node_info; + bNode *node; + + + /* lists must be aligned */ + BLI_assert(BLI_countlist(&node_clipboard.nodes) == + BLI_countlist(&node_clipboard.nodes_extra_info)); + + for (node = node_clipboard.nodes.first, node_info = node_clipboard.nodes_extra_info.first; + node; + node = node->next, node_info = node_info->next) + { + /* validate the node against the stored node info */ + + /* re-assign each loop since we may clear, + * open a new file where the ID is valid, and paste again */ + node->id = node_info->id; + + /* currently only validate the ID */ + if (node->id) { + ListBase *lb = which_libbase(G.main, GS(node_info->id_name)); + BLI_assert(lb != NULL); + + if (BLI_findindex(lb, node_info->id) == -1) { + /* may assign NULL */ + node->id = BLI_findstring(lb, node_info->id_name + 2, offsetof(ID, name) + 2); + printf("%s %p\n", node_info->id_name, node->id); + if (node->id == NULL) { + ok = FALSE; + } + } + } + } +#endif /* USE_NODE_CB_VALIDATE */ + + return ok; } void BKE_node_clipboard_add_node(bNode *node) { +#ifdef USE_NODE_CB_VALIDATE + /* add extra info */ + bNodeClipboardExtraInfo *node_info = MEM_mallocN(sizeof(bNodeClipboardExtraInfo), STRINGIFY(bNodeClipboardExtraInfo)); + + node_info->id = node->id; + if (node->id) { + BLI_strncpy(node_info->id_name, node->id->name, sizeof(node_info->id_name)); + if (node->id->lib) { + BLI_strncpy(node_info->library_name, node->id->lib->filepath, sizeof(node_info->library_name)); + } + else { + node_info->library_name[0] = '\0'; + } + } + else { + node_info->id_name[0] = '\0'; + node_info->library_name[0] = '\0'; + } + BLI_addtail(&node_clipboard.nodes_extra_info, node_info); + /* end extra info */ +#endif /* USE_NODE_CB_VALIDATE */ + + /* add node */ BLI_addtail(&node_clipboard.nodes, node); + } void BKE_node_clipboard_add_link(bNodeLink *link) diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index e4fc19fbd08..6d01fc83647 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -2019,10 +2019,13 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) bNodeTree *ntree = snode->edittree; bNode *gnode = node_tree_get_editgroup(snode->nodetree); float gnode_x = 0.0f, gnode_y = 0.0f; + const ListBase *clipboard_nodes_lb; + const ListBase *clipboard_links_lb; bNode *node; bNodeLink *link; int num_nodes; float centerx, centery; + int is_clipboard_valid; if (BKE_node_clipboard_get_type() != ntree->type) { BKE_report(op->reports, RPT_ERROR, "Clipboard nodes are an incompatible type"); @@ -2038,10 +2041,17 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) if (gnode) nodeToView(gnode, 0.0f, 0.0f, &gnode_x, &gnode_y); + + /* validate pointers in the clipboard */ + is_clipboard_valid = BKE_node_clipboard_validate(); + + clipboard_nodes_lb = BKE_node_clipboard_get_nodes(); + clipboard_links_lb = BKE_node_clipboard_get_links(); + /* calculate "barycenter" for placing on mouse cursor */ num_nodes = 0; centerx = centery = 0.0f; - for (node = BKE_node_clipboard_get_nodes()->first; node; node = node->next) { + for (node = clipboard_nodes_lb->first; node; node = node->next) { ++num_nodes; centerx += 0.5f * (node->totr.xmin + node->totr.xmax); centery += 0.5f * (node->totr.ymin + node->totr.ymax); @@ -2050,15 +2060,18 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) centery /= num_nodes; /* copy nodes from clipboard */ - for (node = BKE_node_clipboard_get_nodes()->first; node; node = node->next) { + for (node = clipboard_nodes_lb->first; node; node = node->next) { bNode *new_node = nodeCopyNode(ntree, node); + /* needed since nodeCopyNode() doesn't increase ID's */ + id_us_plus(node->id); + /* pasted nodes are selected */ node_select(new_node); } /* reparent copied nodes */ - for (node = BKE_node_clipboard_get_nodes()->first; node; node = node->next) { + for (node = clipboard_nodes_lb->first; node; node = node->next) { bNode *new_node = node->new_node; if (new_node->parent) new_node->parent = new_node->parent->new_node; @@ -2071,7 +2084,7 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) } } - for (link = BKE_node_clipboard_get_links()->first; link; link = link->next) { + for (link = clipboard_links_lb->first; link; link = link->next) { nodeAddLink(ntree, link->fromnode->new_node, link->fromsock->new_sock, link->tonode->new_node, link->tosock->new_sock); } @@ -2081,6 +2094,10 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) snode_notify(C, snode); snode_dag_update(C, snode); + if (is_clipboard_valid == FALSE) { + BKE_report(op->reports, RPT_ERROR, "Some nodes ID references could not be found"); + } + return OPERATOR_FINISHED; } |