Vuo 2.4.4
Loading...
Searching...
No Matches
VuoCommandAdd.cc
Go to the documentation of this file.
1
10#include "VuoCommandCommon.hh"
11#include "VuoCommandAdd.hh"
12
13#include "VuoComment.hh"
14#include "VuoCompilerComment.hh"
17#include "VuoCompilerNode.hh"
18#include "VuoCompilerType.hh"
19#include "VuoRendererComment.hh"
21#include "VuoEditorWindow.hh"
22#include "VuoNodeClass.hh"
23#include "VuoGenericType.hh"
24#include "VuoStringUtilities.hh"
25
29VuoCommandAdd::VuoCommandAdd(QList<QGraphicsItem *> addedComponents, VuoEditorWindow *window, string commandDescription, bool disableAttachmentInsertion)
30 : VuoCommandCommon(window)
31{
32 setText(commandDescription.c_str());
33 this->window = window;
34 this->revertedSnapshot = window->getComposition()->takeSnapshot();
35 vector<string> addedComponentDescriptions;
36
37 // Start of command content.
38 {
39 VuoEditorComposition *composition = window->getComposition();
40 set<VuoRendererNode *> addedNodes;
41 set<VuoRendererCable *> addedCables;
42 map<VuoRendererCable *, VuoPort *> fromPortForCable;
43 map<VuoRendererCable *, VuoPort *> toPortForCable;
44 set<VuoRendererComment *> addedComments;
45
46 for (QList<QGraphicsItem *>::iterator i = addedComponents.begin(); i != addedComponents.end(); ++i)
47 {
48 QGraphicsItem *compositionComponent = *i;
49 VuoRendererNode *rn = dynamic_cast<VuoRendererNode *>(compositionComponent);
50 if (rn)
51 {
52 addedNodes.insert(rn);
53 addedComponentDescriptions.push_back("node "
54 + (rn->getBase()->hasCompiler()
56 : "\"" + rn->getBase()->getTitle() + "\"")
57 + " (" + rn->getBase()->getNodeClass()->getClassName() + ")");
58 }
59 else
60 {
61 VuoRendererCable *rc = dynamic_cast<VuoRendererCable *>(compositionComponent);
62 if (rc)
63 {
64 addedCables.insert(rc);
65 fromPortForCable[rc] = rc->getBase()->getFromPort();
66 toPortForCable[rc] = rc->getBase()->getToPort();
67
68 addedComponentDescriptions.push_back("cable "
69 + (rc->getBase()->getFromNode()->hasCompiler()
71 : "?")
72 + ":" + rc->getBase()->getFromPort()->getClass()->getName()
73 + " -> "
74 + (rc->getBase()->getToNode()->hasCompiler()
76 : "?")
77 + ":" + rc->getBase()->getToPort()->getClass()->getName());
78 }
79 else
80 {
81 VuoRendererComment *rcomment = dynamic_cast<VuoRendererComment *>(compositionComponent);
82 if (rcomment)
83 {
84 addedComments.insert(rcomment);
85 addedComponentDescriptions.push_back(rcomment->getBase()->getCompiler()->getGraphvizIdentifier());
86 }
87 }
88 }
89 }
90
91 // Insert appropriate input port attachments.
92 if (! disableAttachmentInsertion)
93 {
94 foreach (VuoRendererNode *rendererNode, addedNodes)
95 {
96 VuoNode *node = rendererNode->getBase();
97
98 if (! node->getNodeClass()->hasCompiler())
99 continue;
100
101 // If this is a "Calculate" node, insert and connect the components that it needs
102 // to provide its read-only input keys/values dictionary.
103 if (VuoStringUtilities::beginsWith(node->getNodeClass()->getClassName(), "vuo.math.calculate"))
104 {
105 VuoPort *valuesInputPort = node->getInputPortWithName("values");
106 if (valuesInputPort)
107 {
108 bool hasIncomingDataCable = false;
109 vector<VuoCable *> connectedCables = valuesInputPort->getConnectedCables(true);
110 foreach (VuoRendererCable *addedCable, addedCables)
111 if (addedCable->getBase()->getToPort() == valuesInputPort)
112 connectedCables.push_back(addedCable->getBase());
113 foreach (VuoCable *connectedCable, connectedCables)
114 if (static_cast<VuoCompilerPortClass *>(connectedCable->getFromPort()->getClass()->getCompiler())->getDataVuoType())
115 hasIncomingDataCable = true;
116
117 if (! hasIncomingDataCable)
118 {
119 set<VuoRendererNode *> nodesToAdd;
120 set<VuoRendererCable *> cablesToAdd;
121 composition->createAndConnectDictionaryAttachmentsForNode(node, nodesToAdd, cablesToAdd);
122
123 addedNodes.insert(nodesToAdd.begin(), nodesToAdd.end());
124 addedCables.insert(cablesToAdd.begin(), cablesToAdd.end());
125
126 foreach (VuoRendererCable *cable, cablesToAdd)
127 {
128 fromPortForCable[cable] = cable->getBase()->getFromPort();
129 toPortForCable[cable] = cable->getBase()->getToPort();
130 }
131 }
132 }
133 }
134
135 // Connect a "Make List" node to each list input port with no incoming data cable.
136 {
137 foreach (VuoPort *port, node->getInputPorts())
138 {
139 VuoCompilerInputEventPort *inputEventPort = dynamic_cast<VuoCompilerInputEventPort *>(port->getCompiler());
140 if (inputEventPort && VuoCompilerType::isListType(inputEventPort->getDataType()))
141 {
142 bool hasIncomingDataCable = false;
143 vector<VuoCable *> connectedCables = port->getConnectedCables(true);
144 foreach (VuoRendererCable *addedCable, addedCables)
145 if (addedCable->getBase()->getToPort() == port)
146 connectedCables.push_back(addedCable->getBase());
147 foreach (VuoCable *connectedCable, connectedCables)
148 if (static_cast<VuoCompilerPortClass *>(connectedCable->getFromPort()->getClass()->getCompiler())->getDataVuoType())
149 hasIncomingDataCable = true;
150
151 if (! hasIncomingDataCable)
152 {
153 VuoRendererCable *cable = NULL;
154 VuoRendererNode *makeListNode = composition->createAndConnectMakeListNode(node, port, cable);
155
156 addedNodes.insert(makeListNode);
157 addedCables.insert(cable);
158 fromPortForCable[cable] = cable->getBase()->getFromPort();
159 toPortForCable[cable] = port;
160 }
161 }
162 }
163 }
164 }
165 }
166
167 // Determine whether the operation will involve at least one generic port.
168 this->operationInvolvesGenericPort = false;
169
170 foreach (VuoRendererNode *rn, addedNodes)
171 {
172 if (rn->hasGenericPort())
173 {
174 this->operationInvolvesGenericPort = true;
175 break;
176 }
177 }
178
179 if (!this->operationInvolvesGenericPort)
180 {
181 foreach (VuoRendererCable *rc, addedCables)
182 {
183 bool fromPortIsGeneric = (fromPortForCable[rc] && dynamic_cast<VuoGenericType *>(fromPortForCable[rc]->getRenderer()->getDataType()));
184 bool toPortIsGeneric = (toPortForCable[rc] && dynamic_cast<VuoGenericType *>(toPortForCable[rc]->getRenderer()->getDataType()));
185 if (fromPortIsGeneric || toPortIsGeneric)
186 {
187 operationInvolvesGenericPort = true;
188 break;
189 }
190 }
191 }
192
193 this->operationRequiresRunningCompositionUpdate = (addedComments.size() < addedComponents.size());
194
195 // Now that the inventory of necessary changes is complete, apply the changes.
196 for (set<VuoRendererCable *>::iterator i = addedCables.begin(); i != addedCables.end(); ++i)
197 VuoCommandCommon::addCable(*i, fromPortForCable[*i], toPortForCable[*i], composition);
198
199 for (set<VuoRendererNode *>::iterator i = addedNodes.begin(); i != addedNodes.end(); ++i)
200 composition->addNode((*i)->getBase());
201
202 for (set<VuoRendererComment *>::iterator i = addedComments.begin(); i != addedComments.end(); ++i)
203 composition->addComment((*i)->getBase());
204
205 // Collapse any typecasts possible.
206 composition->collapseTypecastNodes();
207 }
208 // End of command content.
209
210 this->updatedSnapshot = window->getComposition()->takeSnapshot();
211
212 if (!addedComponentDescriptions.empty())
213 setDescription("%s %s",
214 commandDescription.empty() ? "Add" : commandDescription.c_str(),
215 VuoStringUtilities::join(addedComponentDescriptions, ", ").c_str());
216}
217
222{
224}
225
230{
232
233 window->resetCompositionWithSnapshot(revertedSnapshot);
234
235 if (operationInvolvesGenericPort)
237
238 if (operationRequiresRunningCompositionUpdate)
239 window->coalesceSnapshots(updatedSnapshot, revertedSnapshot);
240}
241
246{
248
249 window->resetCompositionWithSnapshot(updatedSnapshot);
250
251 // Update generic types.
252 if (operationInvolvesGenericPort)
254
255 if (operationRequiresRunningCompositionUpdate)
256 window->coalesceSnapshots(revertedSnapshot, updatedSnapshot);
257}