Vuo 2.4.4
Loading...
Searching...
No Matches
VuoCommandRemove.cc
Go to the documentation of this file.
1
10#include "VuoCommandCommon.hh"
11#include "VuoCommandRemove.hh"
12
13#include "VuoComment.hh"
14#include "VuoCompilerComment.hh"
15#include "VuoEditor.hh"
17#include "VuoEditorWindow.hh"
19#include "VuoNodeClass.hh"
20#include "VuoCable.hh"
21#include "VuoCompilerCable.hh"
23#include "VuoCompilerNode.hh"
25#include "VuoCompilerType.hh"
27#include "VuoGenericType.hh"
28#include "VuoPort.hh"
29#include "VuoRendererCable.hh"
30#include "VuoRendererComment.hh"
31#include "VuoRendererNode.hh"
32#include "VuoStringUtilities.hh"
33
38VuoCommandRemove::VuoCommandRemove(QList<QGraphicsItem *> explicitlyRemovedComponents,
39 VuoEditorWindow *window,
40 VuoInputEditorManager *inputEditorManager,
41 string commandDescription,
42 bool disableAttachmentInsertion)
43 : VuoCommandCommon(window)
44{
45 setText(commandDescription.c_str());
46 this->window = window;
47 this->cableInProgress = NULL;
48 vector<string> removedComponentDescriptions;
49
50 // Normally we would take the composition's "Before" snapshot here, but in the case
51 // of a cable disconnection we need to reconstruct what the composition looked like before
52 // the cable drag began, so we do this a little bit later within the constructor.
53
54 // Start of command content.
55 {
56 // Inventory the set of explicitly deleted composition components and their dependent components
57 // that will also need to be deleted or re-routed.
58 VuoEditorComposition *composition = window->getComposition();
59
60 // First pass: Inventory all attachments or co-attachments of nodes marked for deletion.
61 QList<QGraphicsItem *> explicitlyRemovedComponentsAndTheirAttachments;
62 foreach (QGraphicsItem *component, explicitlyRemovedComponents)
63 {
64 if (!explicitlyRemovedComponentsAndTheirAttachments.contains(component))
65 explicitlyRemovedComponentsAndTheirAttachments.append(component);
66
67 VuoRendererNode *rn = dynamic_cast<VuoRendererNode *>(component);
68 if (rn)
69 {
70 set<QGraphicsItem *> attachments = composition->getDependentAttachmentsForNode(rn, true);
71 foreach (QGraphicsItem *attachment, attachments)
72 {
73 if (!explicitlyRemovedComponentsAndTheirAttachments.contains(attachment))
74 explicitlyRemovedComponentsAndTheirAttachments.append(attachment);
75 }
76
77 removedComponentDescriptions.push_back("node " + (rn->getBase()->hasCompiler() ? rn->getBase()->getCompiler()->getIdentifier() : "?"));
78 }
79
80 else
81 {
82 VuoRendererComment *rcomment = dynamic_cast<VuoRendererComment *>(component);
83 if (rcomment)
84 {
85 removedComments.insert(rcomment);
86 removedComponentDescriptions.push_back("comment " + rcomment->getBase()->getCompiler()->getGraphvizIdentifier());
87 }
88 }
89 }
90
91 // Second pass: Inventory cables and typecasts dependent on components marked for deletion.
92 for (QList<QGraphicsItem *>::iterator i = explicitlyRemovedComponentsAndTheirAttachments.begin(); i != explicitlyRemovedComponentsAndTheirAttachments.end(); ++i)
93 {
94 VuoRendererNode *rn = dynamic_cast<VuoRendererNode *>(*i);
95 VuoRendererCable *rc = dynamic_cast<VuoRendererCable *>(*i);
96
97 if (rn)
98 inventoryNodeAndDependentCables(rn);
99 else if (rc)
100 inventoryCableAndDependentTypecasts(rc);
101 }
102
103 // Marking a cable for deletion trumps marking it for re-routing.
104 for (set<VuoRendererCable *>::iterator rc = reroutedCables.begin(); rc != reroutedCables.end();)
105 {
106 if (removedCables.find(*rc) != removedCables.end())
107 reroutedCables.erase(rc++);
108 else
109 ++rc;
110 }
111
112 // For each deleted data+event cable, mark the 'To' port's constant value to be updated to match
113 // the port's last value in the running composition, if applicable.
114 set<VuoRendererCable *> removedInternalAndPublishedCables;
115 removedInternalAndPublishedCables.insert(removedCables.begin(), removedCables.end());
116 removedInternalAndPublishedCables.insert(removedPublishedCables.begin(), removedPublishedCables.end());
117 foreach (VuoRendererCable *removedCable, removedInternalAndPublishedCables)
118 {
119 removedComponentDescriptions.push_back("cable "
120 + (removedCable->getBase()->getFromNode() && removedCable->getBase()->getFromNode()->hasCompiler()
121 ? removedCable->getBase()->getFromNode()->getCompiler()->getIdentifier() + ":" + removedCable->getBase()->getFromPort()->getClass()->getName()
122 : "")
123 + " -> "
124 + (removedCable->getBase()->getToNode() && removedCable->getBase()->getToNode()->hasCompiler()
125 ? removedCable->getBase()->getToNode()->getCompiler()->getIdentifier() + ":" + removedCable->getBase()->getToPort()->getClass()->getName()
126 : ""));
127
128 if (!removedCable->effectivelyCarriesData())
129 continue;
130
131 VuoPort *toPort = removedCable->getBase()->getToPort();
132 if (!toPort)
133 toPort = removedCable->getFloatingEndpointPreviousToPort();
134
135 if (!(toPort && toPort->hasRenderer() && !dynamic_cast<VuoRendererPublishedPort *>(toPort->getRenderer()) &&
136 (removedNodes.find(toPort->getRenderer()->getUnderlyingParentNode()) == removedNodes.end())))
137 continue;
138
139 VuoCompilerInputEventPort *eventPort = (toPort->hasCompiler()? static_cast<VuoCompilerInputEventPort *>(toPort->getCompiler()) : NULL);
140 if (!eventPort)
141 continue;
142
143 if (!inputEditorManager->doesTypeAllowOfflineSerialization(eventPort->getDataVuoType()))
144 continue;
145
146 revertedConstantForPort[toPort] = eventPort->getData()->getInitialValue();
147
148 json_object *currentRunningValue = composition->getPortValueInRunningComposition(toPort);
149 updatedConstantForPort[toPort] = (currentRunningValue? json_object_to_json_string_ext(currentRunningValue, JSON_C_TO_STRING_PLAIN) :
150 revertedConstantForPort[toPort]);
151 }
152
153 // If applicable, reconstruct the state of the composition before the beginning of the cable drag
154 // that concluded with the cable deletion, for the composition's "Before" snapshot.
155 {
156 VuoPort *currentFromPortForCableInProgress = NULL;
157 VuoPort *currentToPortForCableInProgress = NULL;
158 bool currentAlwaysEventOnlyStatusForCableInProgress = false;
159 bool mustReconstructRevertedSnapshot = false;
160
161 if (cableInProgress)
162 {
163 currentFromPortForCableInProgress = cableInProgress->getBase()->getFromPort();
164 currentToPortForCableInProgress = cableInProgress->getBase()->getToPort();
165 currentAlwaysEventOnlyStatusForCableInProgress = cableInProgress->getBase()->getCompiler()->getAlwaysEventOnly();
166
167 mustReconstructRevertedSnapshot = ((currentFromPortForCableInProgress != revertedFromPortForCable[cableInProgress]) ||
168 (currentToPortForCableInProgress != revertedToPortForCable[cableInProgress]));
169 }
170
171 if (mustReconstructRevertedSnapshot)
172 {
173 VuoCommandCommon::updateCable(cableInProgress, revertedFromPortForCable[cableInProgress], revertedToPortForCable[cableInProgress], composition, true);
174 cableInProgress->getBase()->getCompiler()->setAlwaysEventOnly(cableInProgress->getPreviouslyAlwaysEventOnly());
175 }
176
177 this->revertedSnapshot = window->getComposition()->takeSnapshot();
178
179 if (mustReconstructRevertedSnapshot)
180 {
181 cableInProgress->getBase()->getCompiler()->setAlwaysEventOnly(currentAlwaysEventOnlyStatusForCableInProgress);
182 VuoCommandCommon::updateCable(cableInProgress, currentFromPortForCableInProgress, currentToPortForCableInProgress, composition, true);
183 }
184 }
185
186 // Connect a "Make List" node to each list input port whose incoming data cable was removed.
187 if (! disableAttachmentInsertion)
188 {
189 foreach (VuoRendererCable *rc, removedCables)
190 prepareMakeListToReplaceDeletedCable(rc);
191
192 foreach (VuoRendererCable *rc, removedPublishedCables)
193 prepareMakeListToReplaceDeletedCable(rc);
194 }
195
196 this->operationInvolvesGenericPort = modifiedComponentsIncludeGenericPorts();
197 this->operationRequiresRunningCompositionUpdate = (removedComments.size() < explicitlyRemovedComponents.size());
198
199 // Now apply required changes.
200
201 // Uncollapse any typecasts collapsed during the previous 'Undo' of this component removal, if applicable.
202 for (vector<VuoRendererNode *>::iterator i = typecastsCollapsedUponUndo.begin(); i != typecastsCollapsedUponUndo.end(); ++i)
203 composition->uncollapseTypecastNode(*i);
204
205 // Re-uncollapse any typecasts that had to be uncollapsed when initially inventorying components for removal,
206 // but that were re-collapsed during a subsequent 'Undo' operation.
207 for (vector<VuoRendererNode *>::iterator i = typecastsUncollapsedDuringInventory.begin(); i != typecastsUncollapsedDuringInventory.end(); ++i)
208 composition->uncollapseTypecastNode(*i);
209
210 for (set<VuoRendererNode *>::iterator i = removedNodes.begin(); i != removedNodes.end(); ++i)
211 composition->removeNode(*i);
212
213 for (set<VuoRendererCable *>::iterator i = removedCables.begin(); i != removedCables.end(); ++i)
214 VuoCommandCommon::removeCable(*i, composition);
215
216 for (set<VuoRendererCable *>::iterator i = reroutedCables.begin(); i != reroutedCables.end(); ++i)
217 VuoCommandCommon::updateCable(*i, updatedFromPortForCable[*i], updatedToPortForCable[*i], composition);
218
219 for (set<VuoRendererNode *>::iterator i = addedNodes.begin(); i != addedNodes.end(); ++i)
220 composition->addNode((*i)->getBase());
221
222 for (set<VuoRendererCable *>::iterator i = addedCables.begin(); i != addedCables.end(); ++i)
223 VuoCommandCommon::addCable(*i, updatedFromPortForCable[*i], updatedToPortForCable[*i], composition);
224
225 for (set<VuoRendererComment *>::iterator i = removedComments.begin(); i != removedComments.end(); ++i)
226 composition->removeComment(*i);
227
228 for (vector<pair<VuoPort *, VuoPublishedPort *> >::iterator i = unpublishedInternalExternalPortCombinations.begin(); i != unpublishedInternalExternalPortCombinations.end(); ++i)
229 {
230 bool unpublishIsolatedExternalPort = false;
231 VuoCommandCommon::unpublishInternalExternalPortCombination((*i).first, (*i).second, composition, unpublishIsolatedExternalPort);
232 }
233
234 // Collapse any typecasts possible following the removal of the specified components.
235 this->typecastsCollapsedFollowingComponentRemoval = composition->collapseTypecastNodes();
236
237 // Update generic types.
238 if (operationInvolvesGenericPort)
239 composition->updateGenericPortTypes();
240
241 // For each deleted data+event cable, set the 'To' port's constant value to the last value
242 // that flowed through the cable before its disconnection, if applicable.
243 for (map<VuoPort *, string>::iterator i = updatedConstantForPort.begin(); i != updatedConstantForPort.end(); ++i)
244 {
245 VuoPort *toPort = i->first;
246
247 if (revertedConstantForPort[toPort] != updatedConstantForPort[toPort])
248 {
249 composition->updatePortConstant(static_cast<VuoCompilerInputEventPort *>(toPort->getCompiler()), updatedConstantForPort[toPort], false);
250 updatedPortIDs.insert(window->getComposition()->getIdentifierForStaticPort(toPort));
251 }
252 }
253 }
254 // End of command content.
255
256 this->updatedSnapshot = window->getComposition()->takeSnapshot();
257
258 // Inventory the subcomposition nodes, so that each can be unlinked from / relinked to its open subcomposition window (if any)
259 // when the node is removed / re-added.
260 for (VuoRendererNode *removedNode : removedNodes)
261 {
262 if (removedNode->getBase()->getNodeClass()->hasCompiler() && removedNode->getBase()->getNodeClass()->getCompiler()->isSubcomposition())
263 {
264 string nodeIdentifier = removedNode->getBase()->getCompiler()->getGraphvizIdentifier();
265 removedSubcompositionNodeIdentifiers.insert(nodeIdentifier);
266 }
267 }
268
269 if (!removedComponentDescriptions.empty())
270 setDescription("%s %s",
271 commandDescription.c_str(),
272 VuoStringUtilities::join(removedComponentDescriptions, ", ").c_str());
273}
274
282
287{
289
290 window->resetCompositionWithSnapshot(revertedSnapshot);
291
292 if (operationInvolvesGenericPort)
294
295 if (operationRequiresRunningCompositionUpdate)
296 window->coalesceSnapshots(updatedSnapshot, revertedSnapshot);
297
298 foreach (string updatedPortID, updatedPortIDs)
299 window->coalesceInternalPortConstantsToSync(updatedPortID);
300
301 for (string nodeIdentifier : removedSubcompositionNodeIdentifiers)
302 window->coalesceNodesToRelink(nodeIdentifier);
303}
304
309{
311
312 for (string nodeIdentifier : removedSubcompositionNodeIdentifiers)
313 window->coalesceNodesToUnlink(nodeIdentifier);
314
315 window->resetCompositionWithSnapshot(updatedSnapshot);
316
317 if (operationInvolvesGenericPort)
319
320 if (operationRequiresRunningCompositionUpdate)
321 window->coalesceSnapshots(revertedSnapshot, updatedSnapshot);
322
323 foreach (string updatedPortID, updatedPortIDs)
324 window->coalesceInternalPortConstantsToSync(updatedPortID);
325}
326
332void VuoCommandRemove::inventoryCableAndDependentTypecasts(VuoRendererCable *rc)
333{
334 // If this cable has already been marked for deletion, do nothing.
335 if ((removedCables.find(rc) != removedCables.end()) || (removedPublishedCables.find(rc) != removedPublishedCables.end()))
336 return;
337
338 bool wasPublishedCable = (rc->getBase()->isPublished() ||
339 (!rc->getBase()->getToPort() &&
342
343 if (wasPublishedCable)
344 {
345 removedPublishedCables.insert(rc);
346
347 bool isInputCable = rc->getBase()->isPublishedInputCable();
348 VuoPort *toPort = (rc->getBase()->getToPort()? rc->getBase()->getToPort() : rc->getFloatingEndpointPreviousToPort());
349 VuoPort *fromPort = rc->getBase()->getFromPort();
350
351 VuoPort *internalPublishedPort = (isInputCable? toPort : fromPort);
352 VuoPublishedPort *externalPublishedPort = (isInputCable? dynamic_cast<VuoPublishedPort *>(fromPort) : dynamic_cast<VuoPublishedPort *>(toPort));
353
354 this->unpublishedInternalExternalPortCombinations.push_back(make_pair(internalPublishedPort, externalPublishedPort));
355 this->publishedConnectionCarriedData[make_pair(internalPublishedPort, externalPublishedPort)] = rc->effectivelyCarriesData();
356 }
357
358 else
359 removedCables.insert(rc);
360
361 // Record the cable's original endpoints in case this operation is undone.
362 revertedFromPortForCable[rc] = rc->getBase()->getFromPort();
363 revertedToPortForCable[rc] = rc->getBase()->getToPort();
364
365 // Case: The cable had already been disconnected from its 'To' port at the time it was deleted.
366 if (! revertedToPortForCable[rc])
367 {
368 cableInProgress = rc;
369 revertedToPortForCable[rc] = rc->getFloatingEndpointPreviousToPort();
370 }
371
372 // If the cable is a data+event cable connected to a collapsed typecast, mark the typecast for deletion as well.
373 if (rc->effectivelyCarriesData())
374 {
375 if (revertedToPortForCable[rc] && revertedToPortForCable[rc]->hasRenderer())
376 {
377 VuoRendererTypecastPort *typecastToPort = (VuoRendererTypecastPort *)(revertedToPortForCable[rc]->getRenderer()->getTypecastParentPort());
378 if (typecastToPort)
379 inventoryTypecastAndDependentCables(typecastToPort, true);
380 }
381
382 if (rc->getBase()->getFromNode() && rc->getBase()->getFromNode()->hasRenderer())
383 {
384 VuoRendererTypecastPort *typecastFromPort = (rc->getBase()->getFromNode()->getRenderer()->getProxyCollapsedTypecast());
385 if (typecastFromPort)
386 inventoryTypecastAndDependentCables(typecastFromPort, false);
387 }
388 }
389}
390
396void VuoCommandRemove::inventoryTypecastAndDependentCables(VuoRendererTypecastPort *tp, bool triggeredByIncomingCableDeletion)
397{
398 // We do not have to worry about this function being called on the same collapsed typecast twice, since
399 // the first thing we do here is uncollapse the typecast to its original node form,
400 // causing it effectively no longer to exist in collapsed typecast form.
401 VuoRendererNode *uncollapsedNode = window->getComposition()->uncollapseTypecastNode(tp);
402 this->typecastsUncollapsedDuringInventory.push_back(uncollapsedNode);
403
404 // Re-route any incoming event-only cables connected to the typecast.
405 // Assumption: Typeconverters will not be chained.
406 VuoPort *typecastInPort = uncollapsedNode->getBase()->getInputPorts()[VuoNodeClass::unreservedInputPortStartIndex];
407 VuoPort *typecastOutPort = uncollapsedNode->getBase()->getOutputPorts()[VuoNodeClass::unreservedOutputPortStartIndex];
408
409 vector<VuoCable *> inputCables = typecastInPort->getConnectedCables(false);
410 VuoCable *outCable = *(typecastOutPort->getConnectedCables(false).begin());
411 VuoPort *reroutedToPort = outCable->getToPort();
412
413 for (vector<VuoCable *>::iterator inputCable = inputCables.begin(); inputCable != inputCables.end(); ++inputCable)
414 {
415 VuoRendererCable *inputRc = (*inputCable)->getRenderer();
416 if (!inputRc->effectivelyCarriesData())
417 {
418 revertedFromPortForCable[inputRc] = inputRc->getBase()->getFromPort();
419 revertedToPortForCable[inputRc] = inputRc->getBase()->getToPort();
420
421 updatedFromPortForCable[inputRc] = inputRc->getBase()->getFromPort();
422 updatedToPortForCable[inputRc] = reroutedToPort;
423
424 reroutedCables.insert(inputRc);
425 }
426 }
427
428 // All incoming cables have now been marked for re-routing (if event-only) or deletion
429 // (if deletion of the incoming data+event cable is what triggered deletion of this typecast), so in
430 // deleting the newly uncollapsed typecast node, be sure to tell inventoryNodeAndDependentCables()
431 // not to blindly mark all of its incoming cables for deletion.
432 inventoryNodeAndDependentCables(uncollapsedNode, triggeredByIncomingCableDeletion);
433}
434
440void VuoCommandRemove::inventoryNodeAndDependentCables(VuoRendererNode *rn, bool inputCablesPreprocessed)
441{
442 // If this node has already been marked for deletion, do nothing.
443 if (removedNodes.find(rn) != removedNodes.end())
444 {
445 return;
446 }
447
448 // Mark the node for deletion.
449 removedNodes.insert(rn);
450
451 // Mark the node's connected cables for deletion.
452 if (! inputCablesPreprocessed)
453 {
454 set<VuoCable *> connectedInputCables = rn->getConnectedInputCables(true);
455 for (set<VuoCable *>::iterator cable = connectedInputCables.begin(); cable != connectedInputCables.end(); ++cable)
456 {
457 VuoRendererCable *rc = (*cable)->getRenderer();
458 inventoryCableAndDependentTypecasts(rc);
459 }
460 }
461
462 set<VuoCable *> connectedOutputCables = rn->getConnectedOutputCables(true);
463 for (set<VuoCable *>::iterator cable = connectedOutputCables.begin(); cable != connectedOutputCables.end(); ++cable)
464 {
465 VuoRendererCable *rc = (*cable)->getRenderer();
466 inventoryCableAndDependentTypecasts(rc);
467 }
468}
469
476void VuoCommandRemove::prepareMakeListToReplaceDeletedCable(VuoRendererCable *rc)
477{
478 if (! (rc->getBase()->hasCompiler() && rc->effectivelyCarriesData()))
479 return;
480
481 VuoPort *toPort = rc->getBase()->getToPort();
482
483 // Case: The cable had already been disconnected from its 'To' port at the time it was deleted.
484 if (! toPort)
486
487 if (!(toPort && toPort->hasRenderer() && toPort->getRenderer()->getUnderlyingParentNode()))
488 return;
489
490 VuoNode *toNode = toPort->getRenderer()->getUnderlyingParentNode()->getBase();
491
492 // Automatically insert an input list drawer if appropriate.
493 if (removedNodes.find(toNode->getRenderer()) == removedNodes.end())
494 {
495 VuoCompilerInputEventPort *inputEventPort = (toPort->hasCompiler()? dynamic_cast<VuoCompilerInputEventPort *>(toPort->getCompiler()) : NULL);
496 if (inputEventPort && VuoCompilerType::isListType(inputEventPort->getDataType()))
497 {
498 VuoRendererCable *cable = NULL;
499 VuoRendererNode *makeListNode = window->getComposition()->createAndConnectMakeListNode(toNode, toPort, cable);
500
501 addedNodes.insert(makeListNode);
502 addedCables.insert(cable);
503 updatedFromPortForCable[cable] = cable->getBase()->getFromPort();
504 updatedToPortForCable[cable] = cable->getBase()->getToPort();
505 }
506
507 // Automatically insert an input read-only dictionary attachment if appropriate.
508 else if (VuoStringUtilities::beginsWith(toNode->getNodeClass()->getClassName(), "vuo.math.calculate") &&
509 (toPort->getClass()->getName() == "values"))
510 {
511 set<VuoRendererNode *> createdNodes;
512 set<VuoRendererCable *> createdCables;
513 window->getComposition()->createAndConnectDictionaryAttachmentsForNode(toNode, createdNodes, createdCables);
514
515 foreach (VuoRendererNode *node, createdNodes)
516 addedNodes.insert(node);
517 foreach (VuoRendererCable *cable, createdCables)
518 {
519 addedCables.insert(cable);
520 updatedFromPortForCable[cable] = cable->getBase()->getFromPort();
521 updatedToPortForCable[cable] = cable->getBase()->getToPort();
522 }
523 }
524 }
525}
526
532bool VuoCommandRemove::modifiedComponentsIncludeGenericPorts()
533{
534 foreach (VuoRendererNode *rn, removedNodes)
535 {
536 if (rn->hasGenericPort())
537 return true;
538 }
539
540 foreach (VuoRendererNode *rn, addedNodes)
541 {
542 if (rn->hasGenericPort())
543 return true;
544 }
545
546 foreach (VuoRendererCable *rc, removedCables)
547 {
548 bool revertedFromPortIsGeneric = (revertedFromPortForCable[rc] && dynamic_cast<VuoGenericType *>(revertedFromPortForCable[rc]->getRenderer()->getDataType()));
549 bool revertedToPortIsGeneric = (revertedToPortForCable[rc] && dynamic_cast<VuoGenericType *>(revertedToPortForCable[rc]->getRenderer()->getDataType()));
550
551 if (revertedFromPortIsGeneric || revertedToPortIsGeneric)
552 return true;
553 }
554
555 foreach (VuoRendererCable *rc, addedCables)
556 {
557 bool updatedFromPortIsGeneric = (updatedFromPortForCable[rc] && dynamic_cast<VuoGenericType *>(updatedFromPortForCable[rc]->getRenderer()->getDataType()));
558 bool updatedToPortIsGeneric = (updatedToPortForCable[rc] && dynamic_cast<VuoGenericType *>(updatedToPortForCable[rc]->getRenderer()->getDataType()));
559
560 if (updatedFromPortIsGeneric || updatedToPortIsGeneric)
561 return true;
562 }
563
564 foreach (VuoRendererCable *rc, reroutedCables)
565 {
566 bool revertedFromPortIsGeneric = (revertedFromPortForCable[rc] && dynamic_cast<VuoGenericType *>(revertedFromPortForCable[rc]->getRenderer()->getDataType()));
567 bool revertedToPortIsGeneric = (revertedToPortForCable[rc] && dynamic_cast<VuoGenericType *>(revertedToPortForCable[rc]->getRenderer()->getDataType()));
568 bool updatedFromPortIsGeneric = (updatedFromPortForCable[rc] && dynamic_cast<VuoGenericType *>(updatedFromPortForCable[rc]->getRenderer()->getDataType()));
569 bool updatedToPortIsGeneric = (updatedToPortForCable[rc] && dynamic_cast<VuoGenericType *>(updatedToPortForCable[rc]->getRenderer()->getDataType()));
570
571 if (revertedFromPortIsGeneric || revertedToPortIsGeneric || updatedFromPortIsGeneric || updatedToPortIsGeneric)
572 return true;
573 }
574
575 return false;
576}