Author: derek Date: Mon Jan 8 16:54:19 2007 New Revision: 226 Modified: sofaswitch/trunk/callflow/src/canvas.cpp sofaswitch/trunk/callflow/src/dnd.cpp sofaswitch/trunk/callflow/src/dnd.h sofaswitch/trunk/callflow/src/python.cpp sofaswitch/trunk/callflow/src/shapelist.cpp sofaswitch/trunk/callflow/src/shapelist.h sofaswitch/trunk/callflow/tests/makevoipcall.src Log: Add automatic gridding, so join lines always connect. Increase the size of the join circle, so it is clearer when objects are joined. Modified: sofaswitch/trunk/callflow/src/canvas.cpp ============================================================================== --- sofaswitch/trunk/callflow/src/canvas.cpp (original) +++ sofaswitch/trunk/callflow/src/canvas.cpp Mon Jan 8 16:54:19 2007 @@ -27,8 +27,19 @@ #include "canvas.h" #include "callflow.h" -BEGIN_EVENT_TABLE (MyCanvas, wxScrolledWindow) EVT_LEFT_DOWN (MyCanvas::OnLeftDown) EVT_LEFT_UP (MyCanvas::OnLeftUp) EVT_RIGHT_DOWN (MyCanvas::OnRightDown) EVT_MOTION (MyCanvas::OnMouseMove) EVT_PAINT (MyCanvas::OnPaint) EVT_ENTER_WINDOW (MyCanvas::OnMouseEnter) EVT_LEAVE_WINDOW (MyCanvas::OnMouseLeave) EVT_CHAR (MyCanvas::OnChar) EVT_TIMER (TimerId, MyCanvas::OnProgressTimer) END_EVENT_TABLE ()MyCanvas::MyCanvas (MyFrame * parent): -wxScrolledWindow ((wxWindow *) parent, -1) +BEGIN_EVENT_TABLE (MyCanvas, wxScrolledWindow) + EVT_LEFT_DOWN (MyCanvas::OnLeftDown) + EVT_LEFT_UP (MyCanvas::OnLeftUp) + EVT_RIGHT_DOWN (MyCanvas::OnRightDown) + EVT_MOTION (MyCanvas::OnMouseMove) + EVT_PAINT (MyCanvas::OnPaint) + EVT_ENTER_WINDOW (MyCanvas::OnMouseEnter) + EVT_LEAVE_WINDOW (MyCanvas::OnMouseLeave) + EVT_CHAR (MyCanvas::OnChar) + EVT_TIMER (TimerId, MyCanvas::OnProgressTimer) +END_EVENT_TABLE () + +MyCanvas::MyCanvas (MyFrame * parent):wxScrolledWindow ((wxWindow *) parent, -1) { pFrame = parent; SetVirtualSize (1000, 1000); // width, height @@ -103,10 +114,8 @@ wxPoint MyCanvas::GetUnscrolledPosition (wxMouseEvent & event) { - wxPoint - pt (event.GetX (), event.GetY ()); - wxPoint - disp; + wxPoint pt (event.GetX (), event.GetY ()); + wxPoint disp; CalcUnscrolledPosition (pt.x, pt.y, &disp.x, &disp.y); // printf(" %d,%d ===> %d,%d\n", pt.x, pt.y, disp.x, disp.y); return disp; @@ -121,19 +130,17 @@ lastMousePoint = pt; lastMouseDownPoint = pt; - if (GetEditingMode () == PlaceJoinBlocks) - { - joinBlocks.AddNewPoint (pt); - Refresh (); - return; + if (GetEditingMode () == PlaceJoinBlocks) { + wxPoint gravityPt = activeShapes.GravityPoint(pt); + joinBlocks.AddNewPoint (gravityPt); + Refresh (); + return; } - if (GetEditingMode () == PlaceOneShape) - { + if (GetEditingMode () == PlaceOneShape) { DndShape::Kind kind = pFrame->GetImageTypeForPlacing (); DndShape *newShape = DndShape::Construct (kind); - if (newShape != NULL) - { + if (newShape != NULL) { pFrame->SetImageTypeForPlacing (DndShape::None); newShape->CenterOnThisPosition (pt); activeShapes.Append (newShape); @@ -145,8 +152,7 @@ /* Left button down, no current "Kind" selected. we are therefore going to * move an object from the cureent position, or mark additional buttons.. */ - if (!event.ShiftDown ()) - { + if (!event.ShiftDown ()) { selectingRegion.SetSelected (false); selectingRegion.SetPosition (lastMousePoint); activeShapes.UnselectAllShapes (); @@ -154,13 +160,10 @@ SetEditingMode (DownEventNew); MyListShapes::iterator it = activeShapes.begin (); - while (it != activeShapes.end ()) - { + while (it != activeShapes.end ()) { DndShape *oneShape = it->second; - if (oneShape != NULL) - { - if (oneShape->Intersects (pt)) - { + if (oneShape != NULL) { + if (oneShape->Intersects (pt)) { oneShape->SetSelected (); Refresh (); return; @@ -351,19 +354,19 @@ MyCanvas::OnRightDown (wxMouseEvent & event) { wxPoint pt = GetUnscrolledPosition (event); - if (editingMode == PlaceJoinBlocks) - { - joinBlocks.AddNewPoint (pt); - - DndShape *nJoin = DndShape::Construct (DndShape::JoinBlocks); - wxString points = joinBlocks.GetShapeInfoSpecial (); - joinBlocks.RemoveCurrentPoints (); - nJoin->SetShapeInfoSpecial (points); - activeShapes.Append (nJoin); - - SetEditingMode (WaitDownEvent); - Refresh (); - return; + if (editingMode == PlaceJoinBlocks) { + wxPoint gravityPt = activeShapes.GravityPoint(pt); + joinBlocks.AddNewPoint (gravityPt); + + DndShape *nJoin = DndShape::Construct (DndShape::JoinBlocks); + wxString points = joinBlocks.GetShapeInfoSpecial (); + joinBlocks.RemoveCurrentPoints (); + nJoin->SetShapeInfoSpecial (points); + activeShapes.Append (nJoin); + + SetEditingMode (WaitDownEvent); + Refresh (); + return; } MyListShapes::iterator it = activeShapes.begin (); Modified: sofaswitch/trunk/callflow/src/dnd.cpp ============================================================================== --- sofaswitch/trunk/callflow/src/dnd.cpp (original) +++ sofaswitch/trunk/callflow/src/dnd.cpp Mon Jan 8 16:54:19 2007 @@ -181,6 +181,17 @@ return true; } + +int LabelledPoint::DistanceBetween(wxPoint & suppliedPoint) +{ + int deltaX = suppliedPoint.x - thisPoint.x; + int deltaY = suppliedPoint.y - thisPoint.y; + + double ans = sqrt((deltaX*deltaX) + (deltaY * deltaY)); + + return (int) ans; +} + ///////////////////////////////////////////////////////////////////////////// void MyListPoints::RemoveCurrentPoints() @@ -282,6 +293,25 @@ Append(addMe); } + +bool MyListPoints::GravityPoint(wxPoint & srcPoint) +{ + wxNode *node = (wxNode *)GetFirst(); + + while (node != NULL) { + LabelledPoint *currentPoint = (LabelledPoint *)node->GetData(); + + if (currentPoint->DistanceBetween(srcPoint) < 20) { + srcPoint = currentPoint->GetPoint(); + return true; + } + node = node->GetNext(); + } + + return false; +} + + bool MyListPoints::AllLinked() { wxNode *node = (wxNode *)GetFirst(); @@ -671,7 +701,7 @@ ioPointsLinked = false; if (style == Connected) - dc.DrawCircle(locn, 2); + dc.DrawCircle(locn, 3); } void DndShape::DrawBox(wxDC &dc, int xOff, int yOff, int width, int height) @@ -923,3 +953,15 @@ return answer; } + + +bool DndShape::GravityPoint(wxPoint & srcPoint) +{ + if (inputPoints.GravityPoint(srcPoint)) + return true; + + if (outputPoints.GravityPoint(srcPoint)) + return true; + + return false; +} Modified: sofaswitch/trunk/callflow/src/dnd.h ============================================================================== --- sofaswitch/trunk/callflow/src/dnd.h (original) +++ sofaswitch/trunk/callflow/src/dnd.h Mon Jan 8 16:54:19 2007 @@ -133,6 +133,9 @@ the list of type "MyExtendedShapes"*/ bool LinksToShape(); + /**Report the distance from the supplied point to this point */ + int DistanceBetween(wxPoint & supppliedPoint); + protected: /** the label, describing the node who links to us, is held in this @@ -232,6 +235,14 @@ @param index is the position in the list, and values are 0, 1, 2 ....*/ bool PointLinked(int index); + /**The user is endeavouring to to draw a line that connects two + objects. This method is used to round the "left mouse down" position to + the location of this objects input/output points. + + If rounding is done, true is returned and the point is modified. If no + rounding is done, false is returned. */ + bool GravityPoint(wxPoint & srcPoint); + protected: /**the key of the owner of this list. This key is the unique Id @@ -509,6 +520,14 @@ each point, so it is marked as unconnected. */ void AdjustIoPoints(); + /**The user is endeavouring to to draw a line that connects two + objects. This method is used to round the "left mouse down" position to + the location of this objects input/output points. + + If rounding is done, true is returned and the point is modified. If no + rounding is done, false is returned. */ + bool GravityPoint(wxPoint & srcPoint); + protected: /**Given a string (from the user command line) we need to turn all quotes into \\\", so that when run in the python program, a quote will be Modified: sofaswitch/trunk/callflow/src/python.cpp ============================================================================== --- sofaswitch/trunk/callflow/src/python.cpp (original) +++ sofaswitch/trunk/callflow/src/python.cpp Mon Jan 8 16:54:19 2007 @@ -24,7 +24,7 @@ SetSize(newSize); relInputPoints.Add(16, 0); - relOutputPoints.Add(16, 50); + relOutputPoints.Add(16, 60); displayData[displayData.size()] = InformationSection(wxT("Python Code"), wxT("self.i = 0")); @@ -39,7 +39,7 @@ dc.SetPen(*wxBLACK_PEN); wxPoint p1(m_rect.GetPosition()); - wxPoint pA(p1.x + 16, p1.y + 14); + wxPoint pA(p1.x + 16, p1.y + 12); wxPoint pB(p1.x + 16, p1.y + 0); wxPoint pC(p1.x + 16, p1.y + 60); wxPoint pD(p1.x + 16, p1.y + 46); @@ -49,7 +49,7 @@ dc.DrawLine(pA, pB); dc.DrawLine(pD, pC); - dc.DrawBitmap(Python_xpm, p1.x, p1.y + 14, true); + dc.DrawBitmap(Python_xpm, p1.x, p1.y + 16, true); DndShape::Draw(dc); } Modified: sofaswitch/trunk/callflow/src/shapelist.cpp ============================================================================== --- sofaswitch/trunk/callflow/src/shapelist.cpp (original) +++ sofaswitch/trunk/callflow/src/shapelist.cpp Mon Jan 8 16:54:19 2007 @@ -50,6 +50,19 @@ } } +wxPoint MyListShapesExtended::GravityPoint(wxPoint & srcPoint) +{ + wxPoint activePoint = srcPoint; + MyListShapes::iterator it = begin(); + while (it != end()) { + if (it->second->GravityPoint(activePoint)) + return activePoint; + it++; + } + return activePoint; +} + + void MyListShapesExtended::RemoveCurrentShapes() { MyListShapes::iterator it = begin(); Modified: sofaswitch/trunk/callflow/src/shapelist.h ============================================================================== --- sofaswitch/trunk/callflow/src/shapelist.h (original) +++ sofaswitch/trunk/callflow/src/shapelist.h Mon Jan 8 16:54:19 2007 @@ -21,6 +21,11 @@ bool markSelected = false ///If true, mark new shapes as being selected. ); + /**Take the supplied point, and round it to the nearest shape input/output, + if such a point exists. If no nearest input/output point exists, don't + round it. Once finished, the resultant point is returned */ + wxPoint GravityPoint(wxPoint & srcPoint); + /**Remove the shapes from this list that are marked as being selected. It is up to the calling routine to do a refresh.*/ void RemoveSelectedShapes(); Modified: sofaswitch/trunk/callflow/tests/makevoipcall.src ============================================================================== --- sofaswitch/trunk/callflow/tests/makevoipcall.src (original) +++ sofaswitch/trunk/callflow/tests/makevoipcall.src Mon Jan 8 16:54:19 2007 @@ -1,4 +1,4 @@ -5<B>189<B>304<B> extra <special>Tool Tip<ms>Conditional<ms><special>Test (Python code)<ms>(self.voipNode != None) and (self.soundNode != None)<ms><special> <B><Shape>11<B>191<B>71<B> extra <special>Tool Tip<ms>Request Node<ms><special>Request node from (Python code)<ms>"voip"<ms><special>Timer period (seconds)<ms>1<ms><special>Timer label<ms>requestvoip<ms><special>Additional information (Python code)<ms><ms><special> <B><Shape>9<B>214<B>307<B>214,307,308,331<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>2<B>227<B>517<B> extra <special>Tool Tip<ms>End Processing<ms><special> <B><Shape>9<B>248<B>182<B>248,183,308,182<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>9<B>214<B>353<B>214,353,216,402<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>5<B>193<B>579<B> extra <special>Tool Tip<ms>Conditional<ms><special>Test (Python code)<ms>self.dtmfData=="9"<ms><special> <B><Shape>9<B>466<B>471<B>499,471,493,554,466,567<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>20<B>336<B>255<B> extra <special>Tool Tip<ms>Death<ms><special> <B><Shape>10<B>198<B>252<B> extra <special>Tool Tip<ms>Python<ms><special>Python Code<ms>print "Have a new voip node on ", self.voipNode<ms><special> <B><Shape>10<B>293<B>279<B> extra <special>Tool Tip<ms>Python<ms><special>Python Code<ms>print " have a sound node of ", self.soundNode<ms><special> <B><Shape>6<B>189<B>402<B> extra <special>Tool Tip<ms>Make Call<ms><special>Worker node to activate (python code)<ms>self.voipNode<ms><special>Call destination (python code)<ms>"h323:h323.voxgratia.org"<ms><special> <B><Shape>9<B>496<B>330<B>511,330,496,421<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>14<B>333<B>211<B> extra <special>Tool Tip<ms>Catch the timer which, when fired, -indicates the end of this call<ms><special>Event sought (Python code)<ms><ms><special>Event sought (Regular Exp)<ms>hanguptime<ms><special>Python variable to hold event data<ms>self.hanguptime<ms><special> <B><Shape>10<B>200<B>531<B> extra <special>Tool Tip<ms>Python<ms><special>Python Code<ms>print "dtmf received of ", self.dtmfData<ms><special> <B><Shape>9<B>506<B>388<B>506,388<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>10<B>403<B>444<B> extra <special>Tool Tip<ms>Python<ms><special>Python Code<ms>print "End this as the voip or sound did not respond in time"<ms><special> <B><Shape>15<B>438<B>571<B> extra <special>Tool Tip<ms>Transfer Media<ms><special>First SofaSwitch worker (python)<ms>"sound"<ms><special>Second SofaSwitch worker (python)<ms>"sound"<ms><special> <B><Shape>14<B>204<B>496<B> extra <special>Tool Tip<ms>Catch DTMF events<ms><special>Event sought (Python code)<ms><ms><special>Event sought (Regular Exp)<ms>DTMF<ms><special>Python variable to hold event data<ms>self.dtmfData<ms><special> <B><Shape>9<B>218<B>518<B>218,628,463,518<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>9<B>418<B>359<B>421,359,418,448<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>13<B>284<B>231<B> extra <special>Tool Tip<ms>Stop Timer<ms><special>Timer to stop<ms>requestsound<ms><special> <B><Shape>14<B>498<B>280<B> extra <special>Tool Tip<ms>The voip node has died.<ms><special>Event sought (Python code)<ms><ms><special>Event sought (Regular Exp)<ms>voip[0-9]*Terminating<ms><special>Python variable to hold event data<ms>self.eventData<ms><special> <B><Shape>7<B>438<B>617<B> extra <special>Tool Tip<ms>End Call<ms><special>Worker node to activate (python code)<ms>self.voipNode<ms><special> <B><Shape>9<B>458<B>279<B>458,279,511,279<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>9<B>216<B>573<B>216,573<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>13<B>189<B>210<B> extra <special>Tool Tip<ms>Stop Timer<ms><special>Timer to stop<ms>requestvoip<ms><special> <B><Shape>2<B>215<B>653<B> extra <special>Tool Tip<ms>End Processing<ms><special> <B><Shape>11<B>191<B>109<B> extra <special>Tool Tip<ms>Request Node<ms><special>Request node from (Python code)<ms>"sound"<ms><special>Timer period (seconds)<ms>1<ms><special>Timer label<ms>requestsound<ms><special>Additional information (Python code)<ms><ms><special> <B><Shape>12<B>440<B>660<B> extra <special>Tool Tip<ms>Timer<ms><special>Timer period (seconds, Python code)<ms>1<ms><special>Timer label (Python code)<ms>"hanguptime"<ms><special> <B><Shape>14<B>295<B>185<B> extra <special>Tool Tip<ms>Catch the creation -of the sound node<ms><special>Event sought (Python code)<ms><ms><special>Event sought (Regular Exp)<ms>soundREQU<ms><special>Python variable to hold event data<ms>self.soundNode<ms><special> <B><Shape>1<B>190<B>19<B> extra <special>Tool Tip<ms>Start Processing<ms><special> <B><Shape>14<B>373<B>236<B> extra <special>Tool Tip<ms>Eventer<ms><special>Event sought (Python code)<ms><ms><special>Event sought (Regular Exp)<ms>requestvoip<ms><special>Python variable to hold event data<ms>self.requestVoip<ms><special> <B><Shape>14<B>409<B>257<B> extra <special>Tool Tip<ms>Eventer<ms><special>Event sought (Python code)<ms><ms><special>Event sought (Regular Exp)<ms>requestsound<ms><special>Python variable to hold event data<ms>self.requestSound<ms><special> <B><Shape>9<B>411<B>496<B>421,496,411,560,465,571<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>9<B>386<B>284<B>386,284,386,313,424,314<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>10<B>481<B>418<B> extra <special>Tool Tip<ms>Python<ms><special>Python Code<ms>print "the voip node has died ", self.eventData<ms><special> <B><Shape>2<B>440<B>708<B> extra <special>Tool Tip<ms>End Processing<ms><special> <B><Shape>2<B>425<B>333<B> extra <special>Tool Tip<ms>End Processing<ms><special> <B><Shape>15<B>190<B>450<B> extra <special>Tool Tip<ms>Transfer Media<ms><special>First SofaSwitch worker (python)<ms>self.voipNode<ms><special>Second SofaSwitch worker (python)<ms>self.soundNode<ms><special> <B><Shape>5<B>397<B>310<B> extra <special>Tool Tip<ms>Conditional<ms><special>Test (Python code)<ms>(self.requestVoip==None) or(self.requestSound==None)<ms><special> <B><Shape>2<B>218<B>330<B> extra <special>Tool Tip<ms>End Processing<ms><special> <B><Shape>14<B>202<B>162<B> extra <special>Tool Tip<ms>Catch the creation of -the voip node<ms><special>Event sought (Python code)<ms><ms><special>Event sought (Regular Exp)<ms>voipREQ<ms><special>Python variable to hold event data<ms>self.voipNode<ms><special> <B><Shape>19<B>216<B>606<B> extra <special>Tool Tip<ms>Send Dtmf<ms><special>Worker node to activate (python code)<ms>self.voipNode<ms><special>DTMF to send to worker node (python code)<ms>self.dtmfData<ms><special> <B><Shape>10<B>448<B>518<B> extra <special>Tool Tip<ms>Python<ms><special>Python Code<ms>print "hangup, as dtmf 9 has been received"<ms><special> <B><Shape>2<B>523<B>304<B> extra <special>Tool Tip<ms>End Processing<ms><special> <B><Shape> +10<B>448<B>518<B> extra <special>Tool Tip<ms>Python<ms><special>Python Code<ms>print "hangup, as dtmf 9 has been received"<ms><special> <B><Shape>12<B>439<B>683<B> extra <special>Tool Tip<ms>Timer<ms><special>Timer period (seconds, Python code)<ms>1<ms><special>Timer label (Python code)<ms>"hanguptime"<ms><special> <B><Shape>2<B>438<B>731<B> extra <special>Tool Tip<ms>End Processing<ms><special> <B><Shape>2<B>215<B>653<B> extra <special>Tool Tip<ms>End Processing<ms><special> <B><Shape>2<B>425<B>333<B> extra <special>Tool Tip<ms>End Processing<ms><special> <B><Shape>9<B>386<B>284<B>386,284,386,313,424,314<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>9<B>248<B>182<B>248,183,308,182<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>10<B>403<B>444<B> extra <special>Tool Tip<ms>Python<ms><special>Python Code<ms>print "End this as the voip or sound did not respond in time"<ms><special> <B><Shape>10<B>481<B>418<B> extra <special>Tool Tip<ms>Python<ms><special>Python Code<ms>print "the voip node has died ", self.eventData<ms><special> <B><Shape>1<B>190<B>19<B> extra <special>Tool Tip<ms>Start Processing<ms><special> <B><Shape>14<B>204<B>496<B> extra <special>Tool Tip<ms>Catch DTMF events<ms><special>Event sought (Python code)<ms><ms><special>Event sought (Regular Exp)<ms>DTMF<ms><special>Python variable to hold event data<ms>self.dtmfData<ms><special> <B><Shape>11<B>191<B>71<B> extra <special>Tool Tip<ms>Request Node<ms><special>Request node from (Python code)<ms>"voip"<ms><special>Timer period (seconds)<ms>1<ms><special>Timer label<ms>requestvoip<ms><special>Additional information (Python code)<ms><ms><special> <B><Shape>10<B>200<B>531<B> extra <special>Tool Tip<ms>Python<ms><special>Python Code<ms>print "dtmf received of ", self.dtmfData<ms><special> <B><Shape>2<B>227<B>517<B> extra <special>Tool Tip<ms>End Processing<ms><special> <B><Shape>14<B>409<B>257<B> extra <special>Tool Tip<ms>Eventer<ms><special>Event sought (Python code)<ms><ms><special>Event sought (Regular Exp)<ms>requestsound<ms><special>Python variable to hold event data<ms>self.requestSound<ms><special> <B><Shape>6<B>189<B>402<B> extra <special>Tool Tip<ms>Make Call<ms><special>Worker node to activate (python code)<ms>self.voipNode<ms><special>Call destination (python code)<ms>"h323:h323.voxgratia.org"<ms><special> <B><Shape>9<B>214<B>308<B>309,335,214,308<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>9<B>214<B>353<B>214,353,216,402<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>2<B>523<B>304<B> extra <special>Tool Tip<ms>End Processing<ms><special> <B><Shape>9<B>418<B>359<B>421,359,418,448<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>13<B>284<B>231<B> extra <special>Tool Tip<ms>Stop Timer<ms><special>Timer to stop<ms>requestsound<ms><special> <B><Shape>2<B>218<B>330<B> extra <special>Tool Tip<ms>End Processing<ms><special> <B><Shape>19<B>216<B>606<B> extra <special>Tool Tip<ms>Send Dtmf<ms><special>Worker node to activate (python code)<ms>self.voipNode<ms><special>DTMF to send to worker node (python code)<ms>self.dtmfData<ms><special> <B><Shape>9<B>218<B>518<B>218,628,463,518<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>10<B>198<B>252<B> extra <special>Tool Tip<ms>Python<ms><special>Python Code<ms>print "Have a new voip node on ", self.voipNode<ms><special> <B><Shape>14<B>373<B>236<B> extra <special>Tool Tip<ms>Eventer<ms><special>Event sought (Python code)<ms><ms><special>Event sought (Regular Exp)<ms>requestvoip<ms><special>Python variable to hold event data<ms>self.requestVoip<ms><special> <B><Shape>9<B>216<B>573<B>216,573<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>14<B>295<B>185<B> extra <special>Tool Tip<ms>Catch the creation +of the sound node<ms><special>Event sought (Python code)<ms><ms><special>Event sought (Regular Exp)<ms>soundREQU<ms><special>Python variable to hold event data<ms>self.soundNode<ms><special> <B><Shape>14<B>202<B>162<B> extra <special>Tool Tip<ms>Catch the creation of +the voip node<ms><special>Event sought (Python code)<ms><ms><special>Event sought (Regular Exp)<ms>voipREQ<ms><special>Python variable to hold event data<ms>self.voipNode<ms><special> <B><Shape>13<B>189<B>210<B> extra <special>Tool Tip<ms>Stop Timer<ms><special>Timer to stop<ms>requestvoip<ms><special> <B><Shape>14<B>333<B>211<B> extra <special>Tool Tip<ms>Catch the timer which, when fired, +indicates the end of this call<ms><special>Event sought (Python code)<ms><ms><special>Event sought (Regular Exp)<ms>hanguptime<ms><special>Python variable to hold event data<ms>self.hanguptime<ms><special> <B><Shape>15<B>190<B>450<B> extra <special>Tool Tip<ms>Transfer Media<ms><special>First SofaSwitch worker (python)<ms>self.voipNode<ms><special>Second SofaSwitch worker (python)<ms>self.soundNode<ms><special> <B><Shape>7<B>440<B>632<B> extra <special>Tool Tip<ms>End Call<ms><special>Worker node to activate (python code)<ms>self.voipNode<ms><special> <B><Shape>5<B>193<B>579<B> extra <special>Tool Tip<ms>Conditional<ms><special>Test (Python code)<ms>self.dtmfData=="9"<ms><special> <B><Shape>5<B>189<B>304<B> extra <special>Tool Tip<ms>Conditional<ms><special>Test (Python code)<ms>(self.voipNode != None) and (self.soundNode != None)<ms><special> <B><Shape>9<B>506<B>388<B>506,388<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>10<B>293<B>279<B> extra <special>Tool Tip<ms>Python<ms><special>Python Code<ms>print " have a sound node of ", self.soundNode<ms><special> <B><Shape>15<B>439<B>579<B> extra <special>Tool Tip<ms>Transfer Media<ms><special>First SofaSwitch worker (python)<ms>"sound"<ms><special>Second SofaSwitch worker (python)<ms>"sound"<ms><special> <B><Shape>20<B>336<B>255<B> extra <special>Tool Tip<ms>Death<ms><special> <B><Shape>9<B>458<B>279<B>458,279,511,279<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>9<B>497<B>330<B>511,330,497,418<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>14<B>498<B>280<B> extra <special>Tool Tip<ms>The voip node has died.<ms><special>Event sought (Python code)<ms><ms><special>Event sought (Regular Exp)<ms>voip[0-9]*Terminating<ms><special>Python variable to hold event data<ms>self.eventData<ms><special> <B><Shape>9<B>464<B>478<B>497,478,495,572,464,578<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>11<B>191<B>109<B> extra <special>Tool Tip<ms>Request Node<ms><special>Request node from (Python code)<ms>"sound"<ms><special>Timer period (seconds)<ms>1<ms><special>Timer label<ms>requestsound<ms><special>Additional information (Python code)<ms><ms><special> <B><Shape>9<B>419<B>504<B>419,504,420,570,464,578<special>Tool Tip<ms>Join blocks shape<ms><special> <B><Shape>5<B>397<B>310<B> extra <special>Tool Tip<ms>Conditional<ms><special>Test (Python code)<ms>(self.requestVoip==None) or(self.requestSound==None)<ms><special> <B><Shape>