Vuo 2.4.4
Loading...
Searching...
No Matches
VuoCommandReplaceNode.cc
Go to the documentation of this file.
1
10#include "VuoCommandCommon.hh"
12
14#include "VuoCompilerNode.hh"
18#include "VuoGenericType.hh"
19#include "VuoNodeClass.hh"
22#include "VuoEditorWindow.hh"
24#include "VuoRendererNode.hh"
25#include "VuoStringUtilities.hh"
26
31 bool preserveDanglingCables, bool resetConstantValues)
32 : VuoCommandCommon(window)
33{
34 map<VuoRendererNode *, VuoRendererNode *> newNodeForOldNode;
35 newNodeForOldNode[oldNode] = newNode;
36
37 initialize(window, commandDescription, newNodeForOldNode, preserveDanglingCables, resetConstantValues);
38}
39
43VuoCommandReplaceNode::VuoCommandReplaceNode(map<VuoRendererNode *, VuoRendererNode *> newNodeForOldNode, VuoEditorWindow *window, string commandDescription,
44 bool preserveDanglingCables, bool resetConstantValues)
45 : VuoCommandCommon(window)
46{
47 initialize(window, commandDescription, newNodeForOldNode, preserveDanglingCables, resetConstantValues);
48}
49
54void VuoCommandReplaceNode::initialize(VuoEditorWindow *window, string commandDescription, map<VuoRendererNode *, VuoRendererNode *> newNodeForOldNode,
55 bool preserveDanglingCables, bool resetConstantValues)
56{
57 // Set the graphviz identifiers of each new node the same as the node it's replacing so the runtime can transfer port data
58 // from the old node to corresponding ports on the new node.
59 for (map<VuoRendererNode *, VuoRendererNode *>::iterator i = newNodeForOldNode.begin(); i != newNodeForOldNode.end(); ++i)
60 {
61 VuoCompilerNode *oldNode = i->first->getBase()->getCompiler();
62 VuoCompilerNode *newNode = i->second->getBase()->getCompiler();
64 }
65
66 setText(commandDescription.c_str());
67 this->window = window;
68 this->revertedSnapshot = window->getComposition()->takeSnapshot();
69 vector<string> descriptions;
70
71 // Start of command content.
72 {
73 this->operationInvolvesGenericPort = false;
74 vector<VuoCommandReplaceNode::SingleNodeReplacement *> singleNodeReplacements;
75
76 for (map<VuoRendererNode *, VuoRendererNode *>::iterator i = newNodeForOldNode.begin(); i != newNodeForOldNode.end(); ++i)
77 {
78 VuoRendererNode *oldNode = i->first;
79 VuoRendererNode *newNode = i->second;
80
81 if (oldNode->hasGenericPort() || newNode->hasGenericPort())
82 this->operationInvolvesGenericPort = true;
83
84 VuoCommandReplaceNode::SingleNodeReplacement *nodeReplacement = new SingleNodeReplacement(oldNode,
85 newNode,
86 window->getComposition(),
87 preserveDanglingCables,
88 resetConstantValues);
89 singleNodeReplacements.push_back(nodeReplacement);
90
91 descriptions.push_back(oldNode->getBase()->getCompiler()->getIdentifier()
92 + " ("
93 + oldNode->getBase()->getNodeClass()->getClassName()
94 + " -> "
95 + newNode->getBase()->getNodeClass()->getClassName()
96 + ")");
97 }
98
99 for (vector<SingleNodeReplacement *>::iterator i = singleNodeReplacements.begin(); i != singleNodeReplacements.end(); ++i)
100 {
101 (*i)->createAllMappings();
102 (*i)->redo();
103 }
104
105 diffInfo = new VuoCompilerCompositionDiff();
106 for (SingleNodeReplacement *nodeReplacement : singleNodeReplacements)
108 nodeReplacement->oldNode,
109 nodeReplacement->newNode,
110 nodeReplacement->updatedPortForOriginalPort,
111 window->getComposition());
112 }
113 // End of command content.
114
115 this->updatedSnapshot = window->getComposition()->takeSnapshot();
116
117 setDescription("%s: %s",
118 commandDescription.c_str(),
119 VuoStringUtilities::join(descriptions, ", ").c_str());
120}
121
129
135{
137
138 window->resetCompositionWithSnapshot(updatedSnapshot);
139
140 if (operationInvolvesGenericPort)
142
143 VuoCompilerCompositionDiff *diffInfoCopy = new VuoCompilerCompositionDiff(*diffInfo);
144 window->coalesceSnapshots(revertedSnapshot, updatedSnapshot, diffInfoCopy);
145}
146
151{
153
154 window->resetCompositionWithSnapshot(revertedSnapshot);
155
156 if (operationInvolvesGenericPort)
158
159 VuoCompilerCompositionDiff *diffInfoCopy = new VuoCompilerCompositionDiff(*diffInfo);
160 window->coalesceSnapshots(updatedSnapshot, revertedSnapshot, diffInfoCopy);
161}
162
166VuoCommandReplaceNode::SingleNodeReplacement::SingleNodeReplacement(VuoRendererNode *oldNode, VuoRendererNode *newNode, VuoEditorComposition *composition, bool preserveDanglingCables, bool resetConstantValues)
167{
168 this->oldNode = oldNode;
169 this->newNode = newNode;
170 this->composition = composition;
171 this->preserveDanglingCables = preserveDanglingCables;
172 this->resetConstantValues = resetConstantValues;
173
174 replacingDictionaryKeyList = false;
175 replacingDictionaryValueList = false;
176}
177
181void VuoCommandReplaceNode::SingleNodeReplacement::createAllMappings()
182{
183 replacingDictionaryKeyList = dynamic_cast<VuoRendererKeyListForReadOnlyDictionary *>(oldNode) && dynamic_cast<VuoRendererKeyListForReadOnlyDictionary *>(newNode);
184 replacingDictionaryValueList = dynamic_cast<VuoRendererValueListForReadOnlyDictionary *>(oldNode) && dynamic_cast<VuoRendererValueListForReadOnlyDictionary *>(newNode);
185
186 // Inventory the port constants and connected input cables associated with the old node, to be re-associated with the new node.
187 vector<VuoPort *> oldInputPorts = oldNode->getBase()->getInputPorts();
188 for (vector<VuoPort *>::iterator inputPort = oldInputPorts.begin(); inputPort != oldInputPorts.end(); ++inputPort)
189 {
190 if ((*inputPort)->getRenderer()->getDataType())
191 constantValueForOriginalPort[*inputPort] = (*inputPort)->getRenderer()->getConstantAsString();
192
193 vector<VuoCable *> inputCables = (*inputPort)->getConnectedCables(true);
194 foreach(VuoCable *cable, inputCables)
195 {
196 if (cable->isPublished())
197 {
198 VuoPort *internalPublishedPort = cable->getToPort();
199 VuoPublishedPort *externalPublishedPort = dynamic_cast<VuoPublishedPort *>(cable->getFromPort());
200 this->revertedPublishedInternalExternalPortCombinations.push_back(make_pair(internalPublishedPort, externalPublishedPort));
201 publishedConnectionCarriedData[make_pair(internalPublishedPort, externalPublishedPort)] = cable->getRenderer()->effectivelyCarriesData();
202 }
203
204 else
205 this->incomingCables.insert(cable);
206 }
207
208 // Also inventory any typecasts attached to the old node, to be attached to the new node instead.
209 VuoRendererTypecastPort *typecastPort = dynamic_cast<VuoRendererTypecastPort *>((*inputPort)->getRenderer());
210 if (typecastPort)
211 {
212 VuoRendererNode *typecastNode = typecastPort->getUncollapsedTypecastNode();
213 this->collapsedTypecasts.push_back(typecastNode);
214
215 // Inventory the typecast's own input cables.
216 VuoPort *typecastInPort = typecastNode->getBase()->getInputPorts()[VuoNodeClass::unreservedInputPortStartIndex];
217
218 vector<VuoCable *> typecastInputCables = typecastInPort->getConnectedCables(true);
219 foreach (VuoCable *cable, typecastInputCables)
220 {
221 if (cable->isPublished())
222 {
223 VuoPort *internalPublishedPort = cable->getToPort();
224 VuoPublishedPort *externalPublishedPort = dynamic_cast<VuoPublishedPort *>(cable->getFromPort());
225 this->publishedInternalExternalPortCombinationsForTypecast[typecastNode].push_back(make_pair(internalPublishedPort, externalPublishedPort));
226 publishedConnectionCarriedData[make_pair(internalPublishedPort, externalPublishedPort)] = cable->getRenderer()->effectivelyCarriesData();
227 }
228
229 else
230 {
231 this->incomingCablesForTypecast[typecastNode].insert(cable);
232 originalFromPortForCable[cable] = cable->getFromPort();
233 originalToPortForCable[cable] = cable->getToPort();
234 }
235 }
236
237 hostPortForTypecast[typecastNode] = (*inputPort);
238 }
239 }
240
241 // Inventory the set of output cables connected to the old node, to be re-routed to the new node.
242 vector<VuoPort *> oldOutputPorts = oldNode->getBase()->getOutputPorts();
243 for(vector<VuoPort *>::iterator outputPort = oldOutputPorts.begin(); outputPort != oldOutputPorts.end(); ++outputPort)
244 {
245 vector<VuoCable *> outputCables = (*outputPort)->getConnectedCables(true);
246 foreach(VuoCable *cable, outputCables)
247 {
248 if (cable->isPublished())
249 {
250 VuoPort *internalPublishedPort = cable->getFromPort();
251 VuoPublishedPort *externalPublishedPort = dynamic_cast<VuoPublishedPort *>(cable->getToPort());
252 this->revertedPublishedInternalExternalPortCombinations.push_back(make_pair(internalPublishedPort, externalPublishedPort));
253 publishedConnectionCarriedData[make_pair(internalPublishedPort, externalPublishedPort)] = cable->getRenderer()->effectivelyCarriesData();
254 }
255
256 else
257 this->outgoingCables.insert(cable);
258 }
259 }
260
261 createPortMappings();
262}
263
268void VuoCommandReplaceNode::SingleNodeReplacement::redo()
269{
270 {
271 // If the original node is currently being rendered as collapsed typecast, uncollapse it.
272 if (oldNode->getProxyCollapsedTypecast())
273 composition->uncollapseTypecastNode(oldNode);
274
275 // Uncollapse typecasts attached to the original node.
276 for (vector<VuoRendererNode *>::iterator i = collapsedTypecasts.begin(); i != collapsedTypecasts.end(); ++i)
277 composition->uncollapseTypecastNode(*i);
278
279 for (vector<pair<VuoPort *, VuoPublishedPort *> >::iterator i = revertedPublishedInternalExternalPortCombinations.begin(); i != revertedPublishedInternalExternalPortCombinations.end(); ++i)
280 {
281 bool unpublishIsolatedExternalPort = false;
282 VuoCommandCommon::unpublishInternalExternalPortCombination((*i).first, (*i).second, composition, unpublishIsolatedExternalPort);
283 }
284
285 // Swap nodes.
286 composition->replaceNode(oldNode, newNode->getBase());
287
288 // Restore port constants.
289 if (!resetConstantValues)
290 {
291 for (map<VuoPort *, string>::iterator i = constantValueForOriginalPort.begin(); i != constantValueForOriginalPort.end(); ++i)
292 {
293 VuoPort *oldInputPort = (*i).first;
294 VuoPort *newInputPort = updatedPortForOriginalPort[oldInputPort];
295 if (valueShouldCarryOver(oldInputPort, newInputPort))
296 composition->updatePortConstant(static_cast<VuoCompilerInputEventPort *>(newInputPort->getCompiler()), constantValueForOriginalPort[oldInputPort], false);
297 }
298 }
299
300 // Re-route cables.
301 for (set<VuoCable *>::iterator i = outgoingCables.begin(); i != outgoingCables.end(); ++i)
302 {
303 VuoCommandCommon::updateCable((*i)->getRenderer(),
304 updatedPortForOriginalPort[originalFromPortForCable[*i] ],
305 updatedPortForOriginalPort[originalToPortForCable[*i] ],
306 composition,
307 preserveDanglingCables);
308 }
309
310 for (set<VuoCable *>::iterator i = incomingCables.begin(); i != incomingCables.end(); ++i)
311 {
312 VuoCommandCommon::updateCable((*i)->getRenderer(),
313 updatedPortForOriginalPort[originalFromPortForCable[*i] ],
314 updatedPortForOriginalPort[originalToPortForCable[*i] ],
315 composition,
316 preserveDanglingCables);
317 }
318
319 // Re-publish published ports.
320 for (vector<pair<VuoPort *, VuoPublishedPort *> >::iterator i = revertedPublishedInternalExternalPortCombinations.begin(); i != revertedPublishedInternalExternalPortCombinations.end(); ++i)
321 {
322 if (updatedPortForOriginalPort[(*i).first])
323 {
324 bool forceEventOnlyPublication = !publishedConnectionCarriedData[(*i)];
325 VuoPublishedPort *updatedExternalPublishedPort = VuoCommandCommon::publishInternalExternalPortCombination(updatedPortForOriginalPort[(*i).first], (*i).second, forceEventOnlyPublication, composition);
326 updatedPublishedInternalExternalPortCombinations.push_back(make_pair(updatedPortForOriginalPort[(*i).first], updatedExternalPublishedPort));
327 publishedConnectionCarriedData[make_pair(updatedPortForOriginalPort[(*i).first], updatedExternalPublishedPort)] = publishedConnectionCarriedData[(*i)];
328 }
329 }
330
331 // Re-collapse typecasts onto the updated node.
332 for (vector<VuoRendererNode *>::iterator i = collapsedTypecasts.begin(); i != collapsedTypecasts.end(); ++i)
333 {
334 if (updatedPortForOriginalPort[hostPortForTypecast[*i] ])
335 composition->collapseTypecastNode(*i);
336
337 else
338 {
339 composition->removeNode(*i);
340 foreach (VuoCable *cable, incomingCablesForTypecast[*i])
341 VuoCommandCommon::removeCable(cable->getRenderer(), composition);
342
343 for (vector<pair<VuoPort *, VuoPublishedPort *> >::iterator j = publishedInternalExternalPortCombinationsForTypecast[*i].begin(); j != publishedInternalExternalPortCombinationsForTypecast[*i].end(); ++j)
344 {
345 bool unpublishIsolatedExternalPort = false;
346 VuoCommandCommon::unpublishInternalExternalPortCombination((*j).first, (*j).second, composition, unpublishIsolatedExternalPort);
347 }
348 }
349 }
350
351 // Re-collapse the updated node, if applicable.
352 composition->collapseTypecastNode(newNode);
353
354 VuoRendererInputAttachment *newAttachment = dynamic_cast<VuoRendererInputAttachment *>(newNode);
355 if (newAttachment)
356 {
357 VuoNode *hostNode = newAttachment->getRenderedHostNode();
358 if (hostNode && hostNode->hasRenderer())
360 }
361 }
362}
363
368void VuoCommandReplaceNode::SingleNodeReplacement::createPortMappings()
369{
370 for (set<VuoCable *>::iterator i = incomingCables.begin(); i != incomingCables.end(); ++i)
371 {
372 VuoCable *cable = (*i);
373
374 originalFromPortForCable[cable] = cable->getFromPort();
375 originalToPortForCable[cable] = cable->getToPort();
376
377 updatedPortForOriginalPort[cable->getFromPort()] = cable->getFromPort();
378 updatedPortForOriginalPort[cable->getToPort()] = getEquivalentInputPortInNewNode(cable->getToPort(), oldNode, newNode);
379 }
380
381 for (set<VuoCable *>::iterator i = outgoingCables.begin(); i != outgoingCables.end(); ++i)
382 {
383 VuoCable *cable = (*i);
384
385 originalFromPortForCable[cable] = cable->getFromPort();
386 originalToPortForCable[cable] = cable->getToPort();
387
388 updatedPortForOriginalPort[cable->getFromPort()] = newNode->getBase()->getOutputPortWithName(cable->getFromPort()->getClass()->getName());
389 updatedPortForOriginalPort[cable->getToPort()] = cable->getToPort();
390 }
391
392 foreach (VuoPort *originalInputPort, oldNode->getBase()->getInputPorts())
393 updatedPortForOriginalPort[originalInputPort] = getEquivalentInputPortInNewNode(originalInputPort, oldNode, newNode);
394
395 foreach (VuoPort *originalOutputPort, oldNode->getBase()->getOutputPorts())
396 updatedPortForOriginalPort[originalOutputPort] = newNode->getBase()->getOutputPortWithName(originalOutputPort->getClass()->getName());
397}
398
405VuoPort * VuoCommandReplaceNode::SingleNodeReplacement::getEquivalentInputPortInNewNode(VuoPort *oldInputPort, VuoRendererNode *oldNode, VuoRendererNode *newNode)
406{
407 if (!replacingDictionaryKeyList && !replacingDictionaryValueList)
408 return newNode->getBase()->getInputPortWithName(oldInputPort->getClass()->getName());
409 else if (replacingDictionaryKeyList)
410 {
412 if (!newKeyList)
413 return nullptr;
414
415 VuoCompilerInputEventPort *oldKeyInputCompilerPort = dynamic_cast<VuoCompilerInputEventPort *>(oldInputPort->getCompiler());
416 if (!oldKeyInputCompilerPort || !oldKeyInputCompilerPort->getData())
417 return nullptr;
418 string targetKeyName = oldKeyInputCompilerPort->getData()->getInitialValue();
419
420 vector<VuoPort *> newKeyListInputs = newKeyList->getBase()->getInputPorts();
421 for (int i = VuoNodeClass::unreservedInputPortStartIndex; i < newKeyListInputs.size(); ++i)
422 {
423 VuoCompilerInputEventPort *newKeyInputPort = dynamic_cast<VuoCompilerInputEventPort *>(newKeyListInputs[i]->getCompiler());
424 if (!newKeyInputPort)
425 return nullptr;
426 if (newKeyInputPort->getData()->getInitialValue() == targetKeyName)
427 return newKeyInputPort->getBase();
428 }
429 }
430 else if (replacingDictionaryValueList)
431 {
434 VuoNode *oldKeyList = oldValueList->getKeyListNode();
435 VuoNode *newKeyList = newValueList->getKeyListNode();
436
437 if (!(oldKeyList && newKeyList))
438 return NULL;
439
440 vector<VuoPort *> oldKeyListInputs = oldKeyList->getInputPorts();
441 vector<VuoPort *> oldValueListInputs = oldValueList->getBase()->getInputPorts();
442 VuoPort *oldKeyInputPort = NULL;
443 for (int i = VuoNodeClass::unreservedInputPortStartIndex; i < oldValueListInputs.size() && i < oldKeyListInputs.size() && !oldKeyInputPort; ++i)
444 {
445 if (oldValueListInputs[i] == oldInputPort)
446 oldKeyInputPort = oldKeyListInputs[i];
447 }
448
449 if (!oldKeyInputPort)
450 return NULL;
451
452 VuoCompilerInputEventPort *oldKeyInputCompilerPort= static_cast<VuoCompilerInputEventPort *>(oldKeyInputPort->getCompiler());
453 string targetKeyName = oldKeyInputCompilerPort->getData()->getInitialValue();
454
455 vector<VuoPort *> newKeyListInputs = newKeyList->getInputPorts();
456 vector<VuoPort *> newValueListInputs = newValueList->getBase()->getInputPorts();
457 VuoPort *newValueInputPort = NULL;
458 for (int i = VuoNodeClass::unreservedInputPortStartIndex; i < newValueListInputs.size() && i < newKeyListInputs.size() && !newValueInputPort; ++i)
459 {
460 VuoCompilerInputEventPort *newKeyInputPort= static_cast<VuoCompilerInputEventPort *>(newKeyListInputs[i]->getCompiler());
461 if (newKeyInputPort->getData()->getInitialValue() == targetKeyName)
462 return newValueListInputs[i];
463 }
464 }
465
466 return nullptr;
467}
468
474bool VuoCommandReplaceNode::SingleNodeReplacement::valueShouldCarryOver(VuoPort *oldInputPort, VuoPort *newInputPort)
475{
476 if (resetConstantValues)
477 return false;
478
479 if (!(oldInputPort && newInputPort))
480 return false;
481
482 bool isOldPortGeneric = dynamic_cast<VuoGenericType *>( static_cast<VuoCompilerPort *>(oldInputPort->getCompiler() )->getDataVuoType() );
483 bool isNewPortGeneric = dynamic_cast<VuoGenericType *>( static_cast<VuoCompilerPort *>( newInputPort->getCompiler() )->getDataVuoType() );
484 if (isOldPortGeneric || isNewPortGeneric)
485 return false;
486
487 return (oldInputPort->getRenderer()->getDataType() == newInputPort->getRenderer()->getDataType());
488}