[dasher] Refactor control mode!



commit 9072a94e3fac086abc3c5ef8dc365c8005f0d123
Author: Alan Lawrence <acl33 inf phy cam ac uk>
Date:   Wed May 5 22:17:08 2010 +0100

    Refactor control mode!
    
    CControlBase implements basic CControlManager functionality but "empty";
        allows arbitrary NodeTemplates, with vector of successors.
    EventBroadcast<:NodeTemplate sends old-style CControlEvents with specified IDs
    COrigNodes<:CControlBase creates old layout & API, inc reading controllabels.xml
    CControlManager <: COrigNodes is actual class created - adds nothing for now.

 Src/DasherCore/ControlManager.cpp |  335 +++++++++++++++++++------------------
 Src/DasherCore/ControlManager.h   |  143 +++++++++++-----
 2 files changed, 269 insertions(+), 209 deletions(-)
---
diff --git a/Src/DasherCore/ControlManager.cpp b/Src/DasherCore/ControlManager.cpp
index da580f9..04e43c5 100644
--- a/Src/DasherCore/ControlManager.cpp
+++ b/Src/DasherCore/ControlManager.cpp
@@ -35,47 +35,139 @@ static char THIS_FILE[] = __FILE__;
 #endif
 #endif
 
-int CControlManager::m_iNextID = 0;
+CControlBase::CControlBase( CNodeCreationManager *pNCManager)
+  : m_pNCManager(pNCManager), m_pRoot(NULL) {
+}
 
-CControlManager::CControlManager( CNodeCreationManager *pNCManager )
-  : m_pNCManager(pNCManager) {
-  string SystemString = m_pNCManager->GetStringParameter(SP_SYSTEM_LOC);
-  string UserLocation = m_pNCManager->GetStringParameter(SP_USER_LOC);
-  m_iNextID = 0;
+CControlBase::NodeTemplate *CControlBase::GetRootTemplate() {
+  return m_pRoot;
+}
+
+void CControlBase::SetRootTemplate(NodeTemplate *pRoot) {
+  if (m_pRoot || !pRoot) throw "SetRoot should only be called once, with a non-null root";
+  m_pRoot = pRoot;
+}
+
+CDasherNode *CControlBase::GetRoot(CDasherNode *pParent, unsigned int iLower, unsigned int iUpper, int iOffset) {
+  if (!m_pRoot) return m_pNCManager->GetAlphRoot(pParent, iLower, iUpper, false, iOffset);
+
+  CContNode *pNewNode = new CContNode(pParent, iOffset, iLower, iUpper, m_pRoot, this);
+ 
+  // FIXME - handle context properly
+
+  //  pNewNode->SetContext(m_pLanguageModel->CreateEmptyContext());
+
+  return pNewNode;
+}
+
+CControlBase::NodeTemplate::NodeTemplate(const string &strLabel,int iColour)
+: m_strLabel(strLabel), m_iColour(iColour) {
+}
+
+CControlBase::EventBroadcast::EventBroadcast(int iEvent, const string &strLabel, int iColour)
+: NodeTemplate(strLabel, iColour), m_iEvent(iEvent) {
+  
+}
+
+void CControlBase::EventBroadcast::happen(CContNode *pNode) {
+  CControlEvent oEvent(m_iEvent);
+  // TODO: Need to reimplement this
+  //  m_pNCManager->m_bContextSensitive=false;
+  pNode->mgr()->m_pNCManager->InsertEvent(&oEvent);
+}
 
+CControlBase::CContNode::CContNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, NodeTemplate *pTemplate, CControlBase *pMgr)
+: CDasherNode(pParent, iOffset, iLbnd, iHbnd, (pTemplate->colour() != -1) ? pTemplate->colour() : (pParent->ChildCount()%99)+11, pTemplate->label()), m_pTemplate(pTemplate), m_pMgr(pMgr) {
+}
+
+void CControlBase::CContNode::PopulateChildren() {
+  
+  CDasherNode *pNewNode;
+  
+  const unsigned int iNChildren( m_pTemplate->successors.size() );
+  const unsigned int iNorm(m_pMgr->m_pNCManager->GetLongParameter(LP_NORMALIZATION));
+  unsigned int iLbnd(0), iIdx(0);
+  
+  for (vector<NodeTemplate *>::iterator it = m_pTemplate->successors.begin(); it!=m_pTemplate->successors.end(); it++) {
+    
+    const unsigned int iHbnd((++iIdx*iNorm)/iNChildren); 
+    
+    if( *it == NULL ) {
+      // Escape back to alphabet
+      
+      pNewNode = m_pMgr->m_pNCManager->GetAlphRoot(this, iLbnd, iHbnd, false, offset());
+    }
+    else {
+      
+      pNewNode = new CContNode(this, offset(), iLbnd, iHbnd, *it, m_pMgr);
+    }
+    iLbnd=iHbnd;
+    DASHER_ASSERT(GetChildren().back()==pNewNode);
+  }
+}
+    
+int CControlBase::CContNode::ExpectedNumChildren() {
+  return m_pTemplate->successors.size();
+}
+
+void CControlBase::CContNode::Output(Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization ) {
+  m_pTemplate->happen(this);
+}
+
+void CControlBase::CContNode::Enter() {
+  // Slow down to half the speed we were at
+  m_pMgr->m_pNCManager->SetLongParameter(LP_BOOSTFACTOR, 50);
+  //Disable auto speed control!
+  m_pMgr->bDisabledSpeedControl = m_pMgr->m_pNCManager->GetBoolParameter(BP_AUTO_SPEEDCONTROL); 
+  m_pMgr->m_pNCManager->SetBoolParameter(BP_AUTO_SPEEDCONTROL, 0);
+}
+
+
+void CControlBase::CContNode::Leave() {
+  // Now speed back up, by doubling the speed we were at in control mode
+  m_pMgr->m_pNCManager->SetLongParameter(LP_BOOSTFACTOR, 100);
+  //Re-enable auto speed control!
+  if (m_pMgr->bDisabledSpeedControl)
+  {
+    m_pMgr->bDisabledSpeedControl = false;
+    m_pMgr->m_pNCManager->SetBoolParameter(BP_AUTO_SPEEDCONTROL, 1);
+  }
+}
+
+COrigNodes::COrigNodes(CNodeCreationManager *pNCManager) : CControlBase(pNCManager) {
+  m_iNextID = 0;
+  
   // TODO: Need to fix this on WinCE build
 #ifndef _WIN32_WCE
-  struct stat sFileInfo;
-  string strFileName = UserLocation + "controllabels.xml";  //  check first location for file
-  if(stat(strFileName.c_str(), &sFileInfo) == -1) {
+  if(!LoadLabelsFromFile(m_pNCManager->GetStringParameter(SP_USER_LOC) + "controllabels.xml")) {
     //  something went wrong
-    strFileName = SystemString + "controllabels.xml"; //  check second location for file
-    if(stat(strFileName.c_str(), &sFileInfo) == -1) {
+    if (!LoadLabelsFromFile(m_pNCManager->GetStringParameter(SP_SYSTEM_LOC)+"controllabels.xml")) {
       // all else fails do something default
       LoadDefaultLabels();
     }
-      else
-	LoadLabelsFromFile(strFileName, sFileInfo.st_size);
   }
-  else
-    LoadLabelsFromFile(strFileName, sFileInfo.st_size);
-  
   ConnectNodes();
+  SetRootTemplate(m_perId[CTL_ROOT]);
 #endif
 }
 
-int CControlManager::LoadLabelsFromFile(string strFileName, int iFileSize) {
-
+bool COrigNodes::LoadLabelsFromFile(string strFileName) {
+  int iFileSize;
+  {
+    struct stat sFileInfo;
+    if (stat(strFileName.c_str(), &sFileInfo)==-1) return false; //fail
+    iFileSize = sFileInfo.st_size;
+  }
   // Implement Unicode names via xml from file:
   char* szFileBuffer = new char[iFileSize];
   ifstream oFile(strFileName.c_str());
   oFile.read(szFileBuffer, iFileSize);
   XML_Parser Parser = XML_ParserCreate(NULL);
-
+  
   // Members passed as callbacks must be static, so don't have a "this" pointer.
   // We give them one through horrible casting so they can effect changes.
   XML_SetUserData(Parser, this);
-
+  
   XML_SetElementHandler(Parser, XmlStartHandler, XmlEndHandler);
   XML_SetCharacterDataHandler(Parser, XmlCDataHandler);
   XML_Parse(Parser, szFileBuffer, iFileSize, false);
@@ -86,9 +178,11 @@ int CControlManager::LoadLabelsFromFile(string strFileName, int iFileSize) {
   return 0;
 }
 
-int CControlManager::LoadDefaultLabels() {
+bool COrigNodes::LoadDefaultLabels() {
+  //hmmm. This is probably not the most flexible policy...
+  if (!m_perId.empty()) return false;
+  
   // TODO: Need to figure out how to handle offset changes here
-
   RegisterNode(CTL_ROOT, "Control", 8);
   RegisterNode(CTL_STOP, "Stop", 242);
   RegisterNode(CTL_PAUSE, "Pause", 241);
@@ -114,235 +208,148 @@ int CControlManager::LoadDefaultLabels() {
   RegisterNode(CTL_DELETE_BACKWARD_WORD, "<<", -1);
   RegisterNode(CTL_DELETE_BACKWARD_LINE, "<<<", -1);
   RegisterNode(CTL_DELETE_BACKWARD_FILE, "<<<<", -1);
-  return 0;
+  return true;
 }
 
-int CControlManager::ConnectNodes() {
+void COrigNodes::ConnectNodes() {
   ConnectNode(-1, CTL_ROOT, -2);
   ConnectNode(CTL_STOP, CTL_ROOT, -2);
   ConnectNode(CTL_PAUSE, CTL_ROOT, -2);
   ConnectNode(CTL_MOVE, CTL_ROOT, -2);
   ConnectNode(CTL_DELETE, CTL_ROOT, -2);
-
+  
   ConnectNode(-1, CTL_STOP, -2);
   ConnectNode(CTL_ROOT, CTL_STOP, -2);
   
   ConnectNode(-1, CTL_PAUSE, -2);
   ConnectNode(CTL_ROOT, CTL_PAUSE, -2);
-
+  
   ConnectNode(CTL_MOVE_FORWARD, CTL_MOVE, -2);
   ConnectNode(CTL_MOVE_BACKWARD, CTL_MOVE, -2);
-
+  
   ConnectNode(CTL_MOVE_FORWARD_CHAR, CTL_MOVE_FORWARD, -2);
   ConnectNode(CTL_MOVE_FORWARD_WORD, CTL_MOVE_FORWARD, -2);
   ConnectNode(CTL_MOVE_FORWARD_LINE, CTL_MOVE_FORWARD, -2);
   ConnectNode(CTL_MOVE_FORWARD_FILE, CTL_MOVE_FORWARD, -2);
-
+  
   ConnectNode(CTL_ROOT, CTL_MOVE_FORWARD_CHAR, -2);
   ConnectNode(CTL_MOVE_FORWARD, CTL_MOVE_FORWARD_CHAR, -2);
   ConnectNode(CTL_MOVE_BACKWARD, CTL_MOVE_FORWARD_CHAR, -2);
-
+  
   ConnectNode(CTL_ROOT, CTL_MOVE_FORWARD_WORD, -2);
   ConnectNode(CTL_MOVE_FORWARD, CTL_MOVE_FORWARD_WORD, -2);
   ConnectNode(CTL_MOVE_BACKWARD, CTL_MOVE_FORWARD_WORD, -2);
-
+  
   ConnectNode(CTL_ROOT, CTL_MOVE_FORWARD_LINE, -2);
   ConnectNode(CTL_MOVE_FORWARD, CTL_MOVE_FORWARD_LINE, -2);
   ConnectNode(CTL_MOVE_BACKWARD, CTL_MOVE_FORWARD_LINE, -2);
-
+  
   ConnectNode(CTL_ROOT, CTL_MOVE_FORWARD_FILE, -2);
   ConnectNode(CTL_MOVE_FORWARD, CTL_MOVE_FORWARD_FILE, -2);
   ConnectNode(CTL_MOVE_BACKWARD, CTL_MOVE_FORWARD_FILE, -2);
-
+  
   ConnectNode(CTL_MOVE_BACKWARD_CHAR, CTL_MOVE_BACKWARD, -2);
   ConnectNode(CTL_MOVE_BACKWARD_WORD, CTL_MOVE_BACKWARD, -2);
   ConnectNode(CTL_MOVE_BACKWARD_LINE, CTL_MOVE_BACKWARD, -2);
   ConnectNode(CTL_MOVE_BACKWARD_FILE, CTL_MOVE_BACKWARD, -2);
-
+  
   ConnectNode(CTL_ROOT, CTL_MOVE_BACKWARD_CHAR, -2);
   ConnectNode(CTL_MOVE_FORWARD, CTL_MOVE_BACKWARD_CHAR, -2);
   ConnectNode(CTL_MOVE_BACKWARD, CTL_MOVE_BACKWARD_CHAR, -2);
-
+  
   ConnectNode(CTL_ROOT, CTL_MOVE_BACKWARD_WORD, -2);
   ConnectNode(CTL_MOVE_FORWARD, CTL_MOVE_BACKWARD_WORD, -2);
   ConnectNode(CTL_MOVE_BACKWARD, CTL_MOVE_BACKWARD_WORD, -2);
-
+  
   ConnectNode(CTL_ROOT, CTL_MOVE_BACKWARD_LINE, -2);
   ConnectNode(CTL_MOVE_FORWARD, CTL_MOVE_BACKWARD_LINE, -2);
   ConnectNode(CTL_MOVE_BACKWARD, CTL_MOVE_BACKWARD_LINE, -2);
-
+  
   ConnectNode(CTL_ROOT, CTL_MOVE_BACKWARD_FILE, -2);
   ConnectNode(CTL_MOVE_FORWARD, CTL_MOVE_BACKWARD_FILE, -2);
   ConnectNode(CTL_MOVE_BACKWARD, CTL_MOVE_BACKWARD_FILE, -2);
-
+  
   ConnectNode(CTL_DELETE_FORWARD, CTL_DELETE, -2);
   ConnectNode(CTL_DELETE_BACKWARD, CTL_DELETE, -2);
-
+  
   ConnectNode(CTL_DELETE_FORWARD_CHAR, CTL_DELETE_FORWARD, -2);
   ConnectNode(CTL_DELETE_FORWARD_WORD, CTL_DELETE_FORWARD, -2);
   ConnectNode(CTL_DELETE_FORWARD_LINE, CTL_DELETE_FORWARD, -2);
   ConnectNode(CTL_DELETE_FORWARD_FILE, CTL_DELETE_FORWARD, -2);
-
+  
   ConnectNode(CTL_ROOT, CTL_DELETE_FORWARD_CHAR, -2);
   ConnectNode(CTL_DELETE_FORWARD, CTL_DELETE_FORWARD_CHAR, -2);
   ConnectNode(CTL_DELETE_BACKWARD, CTL_DELETE_FORWARD_CHAR, -2);
-
+  
   ConnectNode(CTL_ROOT, CTL_DELETE_FORWARD_WORD, -2);
   ConnectNode(CTL_DELETE_FORWARD, CTL_DELETE_FORWARD_WORD, -2);
   ConnectNode(CTL_DELETE_BACKWARD, CTL_DELETE_FORWARD_WORD, -2);
-
+  
   ConnectNode(CTL_ROOT, CTL_DELETE_FORWARD_LINE, -2);
   ConnectNode(CTL_DELETE_FORWARD, CTL_DELETE_FORWARD_LINE, -2);
   ConnectNode(CTL_DELETE_BACKWARD, CTL_DELETE_FORWARD_LINE, -2);
-
+  
   ConnectNode(CTL_ROOT, CTL_DELETE_FORWARD_FILE, -2);
   ConnectNode(CTL_DELETE_FORWARD, CTL_DELETE_FORWARD_FILE, -2);
   ConnectNode(CTL_DELETE_BACKWARD, CTL_DELETE_FORWARD_FILE, -2);
-
+  
   ConnectNode(CTL_DELETE_BACKWARD_CHAR, CTL_DELETE_BACKWARD, -2);
   ConnectNode(CTL_DELETE_BACKWARD_WORD, CTL_DELETE_BACKWARD, -2);
   ConnectNode(CTL_DELETE_BACKWARD_LINE, CTL_DELETE_BACKWARD, -2);
   ConnectNode(CTL_DELETE_BACKWARD_FILE, CTL_DELETE_BACKWARD, -2);
-
+  
   ConnectNode(CTL_ROOT, CTL_DELETE_BACKWARD_CHAR, -2);
   ConnectNode(CTL_DELETE_FORWARD, CTL_DELETE_BACKWARD_CHAR, -2);
   ConnectNode(CTL_DELETE_BACKWARD, CTL_DELETE_BACKWARD_CHAR, -2);
-
+  
   ConnectNode(CTL_ROOT, CTL_DELETE_BACKWARD_WORD, -2);
   ConnectNode(CTL_DELETE_FORWARD, CTL_DELETE_BACKWARD_WORD, -2);
   ConnectNode(CTL_DELETE_BACKWARD, CTL_DELETE_BACKWARD_WORD, -2);
-
+  
   ConnectNode(CTL_ROOT, CTL_DELETE_BACKWARD_LINE, -2);
   ConnectNode(CTL_DELETE_FORWARD, CTL_DELETE_BACKWARD_LINE, -2);
   ConnectNode(CTL_DELETE_BACKWARD, CTL_DELETE_BACKWARD_LINE, -2);
-
+  
   ConnectNode(CTL_ROOT, CTL_DELETE_BACKWARD_FILE, -2);
   ConnectNode(CTL_DELETE_FORWARD, CTL_DELETE_BACKWARD_FILE, -2);
   ConnectNode(CTL_DELETE_BACKWARD, CTL_DELETE_BACKWARD_FILE, -2);
-  return 0;
-}
-
-CControlManager::~CControlManager()
-{
-  for(std::map<int,SControlItem*>::iterator i = m_mapControlMap.begin(); i != m_mapControlMap.end(); i++) {
-    SControlItem* pNewNode = i->second;
-    if (pNewNode != NULL) {
-      delete pNewNode;
-      pNewNode = NULL;
-    }
-  }
-}
-
-void CControlManager::RegisterNode( int iID, std::string strLabel, int iColour ) {
-  SControlItem *pNewNode;
-  
-  pNewNode = new SControlItem; // FIXME - do constructor sanely
-  pNewNode->strLabel = strLabel;
-  pNewNode->iID = iID;
-  pNewNode->iColour = iColour;
-
-  m_mapControlMap[iID] = pNewNode;
-}
-
-void CControlManager::ConnectNode(int iChild, int iParent, int iAfter) {
-
-  // FIXME - iAfter currently ignored (eventually -1 = start, -2 = end)
-
-  if( iChild == -1 ) {// Corresponds to escaping back to alphabet
-    SControlItem* node = m_mapControlMap[iParent];
-    if(node)
-      node->vChildren.push_back(NULL);
-  }
-  else
-    m_mapControlMap[iParent]->vChildren.push_back(m_mapControlMap[iChild]); 
-}
-
-void CControlManager::DisconnectNode(int iChild, int iParent) {
-  SControlItem* pParentNode = m_mapControlMap[iParent];
-  SControlItem* pChildNode = m_mapControlMap[iChild];
-
-  for(std::vector<SControlItem *>::iterator itChild(pParentNode->vChildren.begin()); itChild != pParentNode->vChildren.end(); ++itChild)
-    if(*itChild == pChildNode)
-      pParentNode->vChildren.erase(itChild);
 }
 
-
-CDasherNode *CControlManager::GetRoot(CDasherNode *pParent, unsigned int iLower, unsigned int iUpper, int iOffset) {
-
-  CContNode *pNewNode = new CContNode(pParent, iOffset, iLower, iUpper, m_mapControlMap[0], this);
- 
-  // FIXME - handle context properly
-
-  //  pNewNode->SetContext(m_pLanguageModel->CreateEmptyContext());
-
-  return pNewNode;
+COrigNodes::~COrigNodes() {
+  for (std::map<int,NodeTemplate *>::iterator it = m_perId.begin(); it!=m_perId.end(); it++)
+    delete it->second;
 }
 
-CControlManager::CContNode::CContNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, const SControlItem *pControlItem, CControlManager *pMgr)
-: CDasherNode(pParent, iOffset, iLbnd, iHbnd, (pControlItem->iColour != -1) ? pControlItem->iColour : (pParent->ChildCount()%99)+11, pControlItem->strLabel), m_pControlItem(pControlItem), m_pMgr(pMgr) {
+void COrigNodes::RegisterNode( int iID, std::string strLabel, int iColour ) {
+  DASHER_ASSERT(m_perId.count(iID)==0);
+  m_perId[iID] = new EventBroadcast(iID,strLabel,iColour);
 }
 
-
-void CControlManager::CContNode::PopulateChildren() {
+void COrigNodes::ConnectNode(int iChild, int iParent, int iAfter) {
+  //ACL duplicating old functionality here. Node idea had been to do
+  // something with iAfter "(eventually -1 = start, -2 = end)", but
+  // since this wasn't used, and this is all legacy code anyway ;-),
+  // I'm leaving as is...
   
-  CDasherNode *pNewNode;
-
-   const unsigned int iNChildren( m_pControlItem->vChildren.size() );
-   const unsigned int iNorm(m_pMgr->m_pNCManager->GetLongParameter(LP_NORMALIZATION));
-   unsigned int iLbnd(0), iIdx(0);
-
-   for(std::vector<SControlItem *>::const_iterator it(m_pControlItem->vChildren.begin()); it != m_pControlItem->vChildren.end(); ++it) {
-
-     const unsigned int iHbnd((++iIdx*iNorm)/iNChildren); 
-
-     if( *it == NULL ) {
-       // Escape back to alphabet
-
-       pNewNode = m_pMgr->m_pNCManager->GetAlphRoot(this, iLbnd, iHbnd, false, offset());
-     }
-     else {
-
-       pNewNode = new CContNode(this, offset(), iLbnd, iHbnd, *it, m_pMgr);
-
-     }
-     iLbnd=iHbnd;
-     DASHER_ASSERT(GetChildren().back()==pNewNode);
-   }
-}
-int CControlManager::CContNode::ExpectedNumChildren() {
-  return m_pControlItem->vChildren.size();
-}
-void CControlManager::CContNode::Output(Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization ) {
-
-  CControlEvent oEvent(m_pControlItem->iID);
-  // TODO: Need to reimplement this
-  //  m_pNCManager->m_bContextSensitive=false;
-  m_pMgr->m_pNCManager->InsertEvent(&oEvent);
+  NodeTemplate *pParent(m_perId[iParent]);
+  if (pParent) //Note - old code only checked this if iChild==-1...?!
+    pParent->successors.push_back(iChild==-1 ? NULL : m_perId[iChild]);
 }
 
-void CControlManager::CContNode::Enter() {
-  // Slow down to half the speed we were at
-  m_pMgr->m_pNCManager->SetLongParameter(LP_BOOSTFACTOR, 50);
-  //Disable auto speed control!
-  m_pMgr->bDisabledSpeedControl = m_pMgr->m_pNCManager->GetBoolParameter(BP_AUTO_SPEEDCONTROL); 
-  m_pMgr->m_pNCManager->SetBoolParameter(BP_AUTO_SPEEDCONTROL, 0);
-}
-
-
-void CControlManager::CContNode::Leave() {
-  // Now speed back up, by doubling the speed we were at in control mode
-  m_pMgr->m_pNCManager->SetLongParameter(LP_BOOSTFACTOR, 100);
-  //Re-enable auto speed control!
-  if (m_pMgr->bDisabledSpeedControl)
-  {
-    m_pMgr->bDisabledSpeedControl = false;
-    m_pMgr->m_pNCManager->SetBoolParameter(BP_AUTO_SPEEDCONTROL, 1);
+void COrigNodes::DisconnectNode(int iChild, int iParent) {
+  NodeTemplate *pChild(m_perId[iChild]), *pParent(m_perId[iParent]);
+  if (pParent && (pChild || iChild == -1)) {
+    for (vector<NodeTemplate *>::iterator it = pParent->successors.begin(); it!=pParent->successors.end(); it++) {
+      if (*it == pChild) {
+        pParent->successors.erase(it);
+      }
+    }
   }
 }
 
 
-void CControlManager::XmlStartHandler(void *pUserData, const XML_Char *szName, const XML_Char **aszAttr) {
-  
+void COrigNodes::XmlStartHandler(void *pUserData, const XML_Char *szName, const XML_Char **aszAttr) {
+  COrigNodes *pMgr(static_cast<COrigNodes *>(pUserData));
   int colour=-1;
   string str;
   if(0==strcmp(szName, "label"))
@@ -358,15 +365,15 @@ void CControlManager::XmlStartHandler(void *pUserData, const XML_Char *szName, c
         colour = atoi(aszAttr[i+1]);
       }  
     }
-	((CControlManager*)pUserData)->RegisterNode(CControlManager::m_iNextID++, str, colour);
-    
+    pMgr->RegisterNode(pMgr->m_iNextID++, str, colour);
   }
 }
 
-void CControlManager::XmlEndHandler(void *pUserData, const XML_Char *szName) {
-  return;
+void COrigNodes::XmlEndHandler(void *pUserData, const XML_Char *szName) {
+}
+
+void COrigNodes::XmlCDataHandler(void *pUserData, const XML_Char *szData, int iLength){
 }
 
-void CControlManager::XmlCDataHandler(void *pUserData, const XML_Char *szData, int iLength){
-  return;
+CControlManager::CControlManager(CNodeCreationManager *pNCMgr) : COrigNodes(pNCMgr) {
 }
diff --git a/Src/DasherCore/ControlManager.h b/Src/DasherCore/ControlManager.h
index 377f94c..395ccb7 100644
--- a/Src/DasherCore/ControlManager.h
+++ b/Src/DasherCore/ControlManager.h
@@ -49,10 +49,8 @@ namespace Dasher {
   /// @{
 
   /// A node manager which deals with control nodes.
-  /// Currently can only have one instance due to use 
-  /// of static members for callbacks from expat.
   ///
-  class CControlManager : public CNodeManager {
+  class CControlBase : public CNodeManager {
   public:
 
     enum { CTL_ROOT, CTL_STOP, CTL_PAUSE, CTL_MOVE, CTL_MOVE_FORWARD, 
@@ -66,66 +64,121 @@ namespace Dasher {
 	   CTL_USER
     };
 
-    CControlManager(CNodeCreationManager *pNCManager);
-    ~CControlManager();
-
-    ///
-    /// Get a new root node owned by this manager
-    ///
-
-    virtual CDasherNode *GetRoot(CDasherNode *pParent, unsigned int iLower, unsigned int iUpper, int iOffset);
-    void RegisterNode( int iID, std::string strLabel, int iColour );
-    void ConnectNode(int iChild, int iParent, int iAfter);
-    void DisconnectNode(int iChild, int iParent);
+    class NodeTemplate;
     
-  private:
-
-    struct SControlItem {
-      std::vector<SControlItem *> vChildren;
-      std::string strLabel;
-      int iID;
-      int iColour;
-    };
+  protected:
+    ///Sets the root - should be called by subclass constructor to make
+    /// superclass ready for use.
+    ///Note, may only be called once, and with a non-null pRoot, or will throw an error message.
+    void SetRootTemplate(NodeTemplate *pRoot);
+    
+    CNodeCreationManager *m_pNCManager;
     
     class CContNode : public CDasherNode {
     public:
-      CControlManager *mgr() {return m_pMgr;}
-      CContNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, const SControlItem *pControlItem, CControlManager *pMgr);
+      CControlBase *mgr() {return m_pMgr;}
+      CContNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, NodeTemplate *pTemplate, CControlBase *pMgr);
       
       bool bShove() {return false;}
-    ///
-    /// Provide children for the supplied node
-    ///
-
-    virtual void PopulateChildren();
+      ///
+      /// Provide children for the supplied node
+      ///
+      
+      virtual void PopulateChildren();
       virtual int ExpectedNumChildren();
+      
+      virtual void Output(Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization );
+      
+      virtual void Enter();
+      virtual void Leave();
+      
+    private:
+      NodeTemplate *m_pTemplate;
+      CControlBase *m_pMgr;
+    };
     
-    virtual void Output(Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization );
-
-    virtual void Enter();
-    virtual void Leave();
-
-      const SControlItem *m_pControlItem;
+  public:    
+    class NodeTemplate {
+    public:
+      NodeTemplate(const std::string &strLabel, int iColour);
+      virtual ~NodeTemplate() {}
+      int colour() {return m_iColour;};
+      const std::string &label() {return m_strLabel;};
+      std::vector<NodeTemplate *> successors;
+      virtual void happen(CContNode *pNode) {}
     private:
-      CControlManager *m_pMgr;
+      std::string m_strLabel;
+      int m_iColour;
     };
     
-    static void XmlStartHandler(void *pUserData, const XML_Char *szName, const XML_Char **aszAttr);
-    static void XmlEndHandler(void *pUserData, const XML_Char *szName);
-    static void XmlCDataHandler(void *pUserData, const XML_Char *szData, int iLength);
+    class EventBroadcast : public NodeTemplate {
+    public:
+      EventBroadcast(int iEvent, const std::string &strLabel, int iColour);
+      virtual void happen(CContNode *pNode);
+    private:
+      const int m_iEvent;
+    };
     
-    int LoadLabelsFromFile(string strFileName, int iFileSize);
-    int LoadDefaultLabels();
-    int ConnectNodes();
+    NodeTemplate *GetRootTemplate();
+    
+    CControlBase(CNodeCreationManager *pNCManager);
 
-    static int m_iNextID;
-    CNodeCreationManager *m_pNCManager;
-    std::map<int,SControlItem*> m_mapControlMap;
+    ///
+    /// Get a new root node owned by this manager
+    ///
+
+    virtual CDasherNode *GetRoot(CDasherNode *pParent, unsigned int iLower, unsigned int iUpper, int iOffset);
+
+  private:
+    NodeTemplate *m_pRoot;
 
     ///Whether we'd temporarily disabled Automatic Speed Control
     ///(if _and only if_ so, should re-enable it when leaving a node)
     bool bDisabledSpeedControl;
+    
+  };
+  
+  ///subclass attempts to recreate interface of previous control manager...
+  class COrigNodes : public CControlBase {
+  public:
+    COrigNodes(CNodeCreationManager *pNCManager);
+    ~COrigNodes();
+    
+    //keep these around for now, as this might let Win32/Gtk2 work?
+    void RegisterNode( int iID, std::string strLabel, int iColour );
+    void ConnectNode(int iChild, int iParent, int iAfter);
+    void DisconnectNode(int iChild, int iParent);
+    
+  private:
+    //For now, make all the loading routines private:
+    // they are called from the constructor in the same fashion as in old ControlManager.
+    
+    // The possibility of loading labels/layouts from different files/formats
+    // remains, but is left to alternative subclasses of ControlBase.
+    
+    ///Attempts to load control labels from specified file.
+    /// Returns true for success, false for failure (e.g. no such file!)
+    bool LoadLabelsFromFile(string strFileName);
+    
+    ///Load a default set of labels. Return true for success, or false
+    /// if labels already loaded
+    bool LoadDefaultLabels();
+    
+    void ConnectNodes();
 
+    static void XmlStartHandler(void *pUserData, const XML_Char *szName, const XML_Char **aszAttr);
+    static void XmlEndHandler(void *pUserData, const XML_Char *szName);
+    static void XmlCDataHandler(void *pUserData, const XML_Char *szData, int iLength);
+
+    int m_iNextID;
+  protected:
+    std::map<int,NodeTemplate *> m_perId;
+  };
+  
+  ///subclass which we actually construct - more of a marker than anything for now.
+  class CControlManager : public COrigNodes {
+  public:
+    CControlManager(CNodeCreationManager *pNCManager);
   };
   /// @}
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]