Author: derek Date: Thu Sep 21 01:19:27 2006 New Revision: 109 Modified: sofaswitch/trunk/callflow/Makefile.am sofaswitch/trunk/callflow/overview.dxy sofaswitch/trunk/callflow/src/callflow.cpp sofaswitch/trunk/callflow/src/dnd.cpp sofaswitch/trunk/callflow/src/dnd.h sofaswitch/trunk/callflow/src/eventer.cpp sofaswitch/trunk/callflow/src/eventer.h sofaswitch/trunk/callflow/src/information.cpp sofaswitch/trunk/callflow/src/shapelist.cpp Log: Documentation improvement. Add ability to specify a regular expression to describe the event sought. In this way, an event handler could catch every dtmf event sent by any node (that is controlled by this particular call flow). Add some new Make targets, and associated documentation. Resize the information window. Resize the main window. Modified: sofaswitch/trunk/callflow/Makefile.am ============================================================================== --- sofaswitch/trunk/callflow/Makefile.am (original) +++ sofaswitch/trunk/callflow/Makefile.am Thu Sep 21 01:19:27 2006 @@ -5,6 +5,7 @@ doc:docs +both:all docs: doxygen callflow.dxy @@ -16,6 +17,10 @@ @echo " " @echo "Available make targets" @echo "=================================================" + @echo " " + @echo "all build everything" + @echo " " + @echo "both build everything" @echo " " @echo "dist create a tarball of the source files" @echo " " Modified: sofaswitch/trunk/callflow/overview.dxy ============================================================================== --- sofaswitch/trunk/callflow/overview.dxy (original) +++ sofaswitch/trunk/callflow/overview.dxy Thu Sep 21 01:19:27 2006 @@ -15,10 +15,41 @@ Copyright (C) 2006 Indranet Technologies Ltd, All right reserved +\section WhyCallFlow Why do we neeed CallFlow ? +My (DJS) initial thoughts on the design of SofaSwitch was that there would +be individual entities (server, voip, am etc) all controlled by a custom +script, written in some scripting language. I wrote the entities first, and +then wrote simple python scripts to test the entities. -\subsection history History +The python scripts started to grow quite large. Along the way, I altered the +control protocol, as I realised that there were some aspects missing from the +original design. This had the unfortunate outcome of making those scripts +invalid. A second lesson was learnt - python is not very good on +threads. Things like the global interpreter lock started to get in the +way. python script. -\li 15 September 2005 - Created by Derek J Smithies +At this stage, I was uncertain. Should I change to a different (and more +superior) scripting language? Some thought and discussion showed that python +is the way to go. Choosing an unknonw (but superior?) language like XYZ would +indeed solve the above problems, but introduce two new problems: 1)it is now +much harder to get get going in the project and 2)it becomes much harder to +install sofaswitch. Minor considerations such as, "we might loose +cross-platform features if we switch to XYZ" were part of the problem space. +Clearly, the way ahead was to write a custom utility to write the python +controlscripts. Now, we expect that some may wish to write their own python +scripts. This is fine - you are welcome to learn from our current +codebase. Given the modular structure of SofaSwitch, this is +inevitable. Different modules will be glued together in different ways. + +Thus, the design of CallFlow was such that you can create scripts to do very +complex things with the minimum of effort. + + + +\subsection history History + +\li 15 September 2006 - Created by Derek J Smithies +\li 21 September 2006 - Add Why section Derek J Smithies */ Modified: sofaswitch/trunk/callflow/src/callflow.cpp ============================================================================== --- sofaswitch/trunk/callflow/src/callflow.cpp (original) +++ sofaswitch/trunk/callflow/src/callflow.cpp Thu Sep 21 01:19:27 2006 @@ -162,6 +162,11 @@ CreateStatusBar(); SetStatusText(" Welcome to Call Flow. "); + + int w, h; + GetSize(&w, &h); + w= w << 1; + SetSize(w, h); } Modified: sofaswitch/trunk/callflow/src/dnd.cpp ============================================================================== --- sofaswitch/trunk/callflow/src/dnd.cpp (original) +++ sofaswitch/trunk/callflow/src/dnd.cpp Thu Sep 21 01:19:27 2006 @@ -338,6 +338,12 @@ return outputPoints.AllLinked(); } +bool DndShape::TestInternalVariables() +{ + ClearCompileError(); + return true; +} + void DndShape::StoreNewKey(wxString newKey) { uniqueKey = newKey; Modified: sofaswitch/trunk/callflow/src/dnd.h ============================================================================== --- sofaswitch/trunk/callflow/src/dnd.h (original) +++ sofaswitch/trunk/callflow/src/dnd.h Thu Sep 21 01:19:27 2006 @@ -480,6 +480,17 @@ void SetCompileError(const wxString & newError) { compileError = newError; } + /**Examine the different shape specific variables, and check them for + correctness. This method is called as part of the compile process. One + illustration is DndShapeEventer, which is required to name one event to + look for. Conversely, there is nothing the DndShapeSelect can do which + will stop the compilation process. + + On finding a fault, the compileError variable will be set, and false + returned. On success, true will be returned and compileError will be + cleared.*/ + virtual bool TestInternalVariables(); + /**Draw to the screen the current compile message for this shape */ void DrawCompileError(wxDC & dc); Modified: sofaswitch/trunk/callflow/src/eventer.cpp ============================================================================== --- sofaswitch/trunk/callflow/src/eventer.cpp (original) +++ sofaswitch/trunk/callflow/src/eventer.cpp Thu Sep 21 01:19:27 2006 @@ -29,12 +29,38 @@ AdjustIoPoints(); displayData[displayData.size()] = - InformationSection(wxT("Event sought"), wxT("incoming")); + InformationSection(wxT("Event sought (Python code)"), wxT("")); displayData[displayData.size()] = + InformationSection(wxT("Event sought (Regular Exp)"), wxT("*DTMF")); + + displayData[displayData.size()] = InformationSection(wxT("Competing timer label"), wxT("")); } +bool DndShapeEventer::TestInternalVariables() +{ + DndShape::TestInternalVariables(); + + bool oneEmpty = displayData[1].data.IsEmpty(); + bool twoEmpty = displayData[2].data.IsEmpty(); + + if (oneEmpty && (!twoEmpty)) { + return true; + } + + if (twoEmpty && (!oneEmpty)) { + return true; + } + + if (oneEmpty && twoEmpty) + SetCompileError(wxT("Cannot specify both python code and a regular expression.\nEnter just one statement.")); + else + SetCompileError(wxT("You must enter one statement.\nEither python code, or a regular expression")); + + return false; +} + void DndShapeEventer::Draw(wxDC& dc) { DrawCompileError(dc); @@ -88,7 +114,7 @@ file.AddLine(" def Eventer(self, sTuple): "); file.AddLine(" \"\"\"Register the left down output as being available to handle a particular event "); file.AddLine(" After registration, continue execution to right horizontal output. Should this "); - file.AddLine(" link not be connected, a None value will be returned. "); + file.AddLine(" link not be connected, a None value will be returned. "); file.AddLine(" \"\"\" "); file.AddLine(" a,b,c = sTuple "); file.AddLine(" self.currentHandlers[self.data[a][\"Event\"]] = a "); @@ -119,11 +145,14 @@ file.AddLine(wxString::Format(" \"OutputKeepGoing\" : ")); file.AddLine(wxString::Format(" %s, ", outputLabel2.c_str())); - file.AddLine(wxString::Format(" \"Event\" : ")); + file.AddLine(wxString::Format(" \"Event Python\" : ")); file.AddLine(wxString::Format(" \"%s\", ", displayData[1].data.c_str())); - file.AddLine(wxString::Format(" \"Competing timer label\" : ")); + file.AddLine(wxString::Format(" \"Event RegExp\" : ")); file.AddLine(wxString::Format(" \"%s\", ", displayData[2].data.c_str())); + + file.AddLine(wxString::Format(" \"Competing timer label\" : ")); + file.AddLine(wxString::Format(" \"%s\", ", displayData[3].data.c_str())); file.AddLine(wxString::Format(" },")); Modified: sofaswitch/trunk/callflow/src/eventer.h ============================================================================== --- sofaswitch/trunk/callflow/src/eventer.h (original) +++ sofaswitch/trunk/callflow/src/eventer.h Thu Sep 21 01:19:27 2006 @@ -3,10 +3,20 @@ #include "dnd.h" -////////////////////////////////////////////////////////////////////////////////////////////// -/**Define a event registration, and wait for event shape. Normal flow of execution enters this shape, -and an event is registered for. There is always a connection to the event detected and process output. -There is an optional outgoing connection for the "do other things while waiting" output. */ +///////////////////////////////////////////////////////////////////////////// +/**Define a event registration, and wait for event shape. Normal flow of + execution enters this shape, and an event is registered for. + + There is always a connection to the event detected and process output. + There is an optional outgoing connection for the "do other things while + waiting" output. + + The user may specify the event in one of two ways. Either as a 1) python + regular expression, or as 2)the outcome of some python calculations. The + outcome of either way is treated as a python regular expression, which is + compared with the current events. It is an error to specify the event + sought for in both ways. +*/ class DndShapeEventer : public DndShape { public: @@ -33,6 +43,9 @@ /**Check that every output point of this shape goes somewhere. Return False if there is a dangling output point */ virtual bool CheckOutputPointsLinked(); + + /**Make cerrtain that there is one valid event to look for.*/ + virtual bool TestInternalVariables(); }; #endif // SHAPE_EVENTER_H Modified: sofaswitch/trunk/callflow/src/information.cpp ============================================================================== --- sofaswitch/trunk/callflow/src/information.cpp (original) +++ sofaswitch/trunk/callflow/src/information.cpp Thu Sep 21 01:19:27 2006 @@ -46,9 +46,10 @@ mainsizer -> Add (staticText[i], 0, wxALL | wxEXPAND, 1); wxString initialMessage = wxString::Format("initial value %d", i + 1); + wxSize nSize = wxSize(400,50); textEntry[i] = new wxTextCtrl(this, wxID_ANY, initialMessage, - wxDefaultPosition, wxDefaultSize, + wxDefaultPosition, nSize, wxTE_MULTILINE); textEntry[i]->SetValue(data[i].data); mainsizer -> Add(textEntry[i], 0, wxALL | wxEXPAND, 10); Modified: sofaswitch/trunk/callflow/src/shapelist.cpp ============================================================================== --- sofaswitch/trunk/callflow/src/shapelist.cpp (original) +++ sofaswitch/trunk/callflow/src/shapelist.cpp Thu Sep 21 01:19:27 2006 @@ -219,15 +219,19 @@ ClearConnectionPoints(); MarkConnectionPoints(); - /***Zero, go through and remove all previous compiler errors */ - MyListShapes::iterator it = begin(); + /* First, go through and check that all variables etc are set correctly. + This will also remove all previous compiler errors */ + MyListShapes::iterator it = begin(); + bool variablesOk = true; while (it != end()) { DndShape *thisShape = it->second; - thisShape->ClearCompileError(); + if (thisShape != NULL) { + variablesOk = thisShape->TestInternalVariables(); + } it++; - } + } - /**First, go through and check all output points link to something. */ + /**Second, go through and check all output points link to something. */ bool pointsLinked = true; it = begin(); while (it != end()) { @@ -239,10 +243,10 @@ it++; } - if (!pointsLinked) + if ((!pointsLinked) || (!variablesOk)) return false; - /**second go through and calculate reverse links etc. */ + /**third go through and calculate reverse links etc. */ it = begin(); while (it != end()) { DndShape *thisShape = it->second; @@ -254,7 +258,7 @@ it++; } - /**third, go through and set the kind variable on all input&output points */ + /**fourth, go through and set the kind variable on all input&output points */ it = begin(); while (it != end()) { DndShape *thisShape = it->second;