Vuo  2.3.2
VuoCommandReplaceNode.cc
Go to the documentation of this file.
1 
10 #include "VuoCommandCommon.hh"
11 #include "VuoCommandReplaceNode.hh"
12 
14 #include "VuoCompilerNode.hh"
18 #include "VuoGenericType.hh"
19 #include "VuoNodeClass.hh"
20 #include "VuoCompilerInputData.hh"
21 #include "VuoEditorComposition.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 
43 VuoCommandReplaceNode::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 
54 void 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();
63  newNode->setGraphvizIdentifier(oldNode->getGraphvizIdentifier());
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 
126 {
128 }
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 
166 VuoCommandReplaceNode::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 
181 void 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 
268 void 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 
368 void 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 
405 VuoPort * 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 
474 bool 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 }