[dasher] * NodeManager::Ref() & ClearNode() put into DasherNode subclass con/destructors



commit a81b1e499165235219f30cebd9ea70b15029c05d
Author: Alan Lawrence <acl33 inf phy cam ac uk>
Date:   Mon Nov 16 10:01:59 2009 +0100

    * NodeManager::Ref() & ClearNode() put into DasherNode subclass con/destructors
    * Other calls pNode->m_pNodeManager->Foo(pNode,...) replaced by pNode->Foo(...).
      NodeManager class now serves no purpose, so removed.
    * Access to m_pUserData still via casting at present.

 ChangeLog                                   |    9 ++
 Src/DasherCore/AlphabetManager.cpp          |  116 +++++++++++-----------
 Src/DasherCore/AlphabetManager.h            |   53 +++++-----
 Src/DasherCore/ControlManager.cpp           |   70 +++++++-------
 Src/DasherCore/ControlManager.h             |   54 ++++-------
 Src/DasherCore/ConversionHelper.cpp         |   56 ++++++-----
 Src/DasherCore/ConversionHelper.h           |   24 +++--
 Src/DasherCore/ConversionManager.cpp        |   85 +++++++++--------
 Src/DasherCore/ConversionManager.h          |   44 ++++-----
 Src/DasherCore/DasherModel.cpp              |   31 +++---
 Src/DasherCore/DasherNode.cpp               |   12 +--
 Src/DasherCore/DasherNode.h                 |   67 +++++++++----
 Src/DasherCore/MandarinAlphMgr.cpp          |   21 +++-
 Src/DasherCore/MandarinAlphMgr.h            |   10 ++-
 Src/DasherCore/NodeManager.h                |  141 ---------------------------
 Src/DasherCore/PinYinConversionHelper.cpp   |   26 ++++--
 Src/DasherCore/PinYinConversionHelper.h     |   25 +++--
 Src/MacOSX/Dasher.xcodeproj/project.pbxproj |    4 -
 18 files changed, 384 insertions(+), 464 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index dea52c6..8760e03 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2009-11-16  Alan Lawrence <acl33 inf phy cam ac uk>
 
+	* NodeManager::Ref() & ClearNode() put into DasherNode subclass
+	  con/destructors
+	* Other calls pNode->m_pNodeManager->Foo(pNode,...) replaced
+	  by pNode->Foo(...). NodeManager class now serves no purpose,
+	  so removed.
+	* Access to m_pUserData still via casting at present
+
+2009-11-16  Alan Lawrence <acl33 inf phy cam ac uk>
+
 	 * Made SConversionData protected in CConversionManager
 	 * Bypassed by making CMandarinAlphMgr a friend of
 	   CPinYinConversionHelper ...and statically casting :-(
diff --git a/Src/DasherCore/AlphabetManager.cpp b/Src/DasherCore/AlphabetManager.cpp
index 4b4aa5c..c4aa9d0 100644
--- a/Src/DasherCore/AlphabetManager.cpp
+++ b/Src/DasherCore/AlphabetManager.cpp
@@ -46,13 +46,21 @@ static char THIS_FILE[] = __FILE__;
 #endif
 
 CAlphabetManager::CAlphabetManager(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, CLanguageModel *pLanguageModel, CLanguageModel::Context iLearnContext)
-  : CNodeManager(0), m_pLanguageModel(pLanguageModel), m_pNCManager(pNCManager) {
+  : m_pLanguageModel(pLanguageModel), m_pNCManager(pNCManager) {
   m_pInterface = pInterface;
 
   m_iLearnContext = iLearnContext;
 
 }
 
+CAlphabetManager::CAlphNode::CAlphNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDisplayInfo, CAlphabetManager *pMgr)
+: CDasherNode(pParent, iLbnd, iHbnd, pDisplayInfo), m_pMgr(pMgr) {
+};
+
+CAlphabetManager::CAlphNode *CAlphabetManager::makeNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDisplayInfo) {
+  return new CAlphNode(pParent, iLbnd, iHbnd, pDisplayInfo, this);
+}
+
 CDasherNode *CAlphabetManager::GetRoot(CDasherNode *pParent, int iLower, int iUpper, char *szContext, int iOffset) {
 
   CDasherNode *pNewNode;
@@ -98,9 +106,7 @@ CDasherNode *CAlphabetManager::GetRoot(CDasherNode *pParent, int iLower, int iUp
   pDisplayInfo->bVisible = true;
   pDisplayInfo->strDisplayText = m_pNCManager->GetAlphabet()->GetDisplayText(iSymbol);
 
-  pNewNode = new CDasherNode(pParent, iLower, iUpper, pDisplayInfo);
-
-  pNewNode->m_pNodeManager = this;
+  pNewNode = new CAlphNode(pParent, iLower, iUpper, pDisplayInfo, this);
 
   SAlphabetData *pNodeUserData = new SAlphabetData;
   pNewNode->m_pUserData = pNodeUserData;
@@ -125,31 +131,31 @@ CDasherNode *CAlphabetManager::GetRoot(CDasherNode *pParent, int iLower, int iUp
   return pNewNode;
 }
 
-bool CAlphabetManager::GameSearchNode(CDasherNode *pNode, string strTargetUtf8Char) {
-  if (pNode->GetFlag(NF_SUBNODE)) {
-    if (pNode->GameSearchChildren(strTargetUtf8Char)) {
-      pNode->SetFlag(NF_GAME, true);
+bool CAlphabetManager::CAlphNode::GameSearchNode(string strTargetUtf8Char) {
+  if (GetFlag(NF_SUBNODE)) {
+    if (GameSearchChildren(strTargetUtf8Char)) {
+      SetFlag(NF_GAME, true);
       return true;
     }
-  } else if (m_pNCManager->GetAlphabet()->GetText(static_cast<SAlphabetData *>(pNode->m_pUserData)->iSymbol) == strTargetUtf8Char) {
-    pNode->SetFlag(NF_GAME, true);
+  } else if (m_pMgr->m_pNCManager->GetAlphabet()->GetText(static_cast<SAlphabetData *>(m_pUserData)->iSymbol) == strTargetUtf8Char) {
+    SetFlag(NF_GAME, true);
     return true;
   }
   return false;
 }
 
-CLanguageModel::Context CAlphabetManager::CloneAlphContext(CDasherNode *pNode, CLanguageModel *pLanguageModel) {
-  SAlphabetData *pData = static_cast<SAlphabetData *>(pNode->m_pUserData);      
+CLanguageModel::Context CAlphabetManager::CAlphNode::CloneAlphContext(CLanguageModel *pLanguageModel) {
+  SAlphabetData *pData = static_cast<SAlphabetData *>(m_pUserData);      
   if(pData->iContext) return pLanguageModel->CloneContext(pData->iContext);
-  return CNodeManager::CloneAlphContext(pNode, pLanguageModel);
+  return CDasherNode::CloneAlphContext(pLanguageModel);
 }
 
-symbol CAlphabetManager::GetAlphSymbol(CDasherNode *pNode) {
-  return static_cast<SAlphabetData *>(pNode->m_pUserData)->iSymbol;
+symbol CAlphabetManager::CAlphNode::GetAlphSymbol() {
+  return static_cast<SAlphabetData *>(m_pUserData)->iSymbol;
 }
 
-void CAlphabetManager::PopulateChildren( CDasherNode *pNode ) {
-  PopulateChildrenWithSymbol( pNode, -2, 0 );
+void CAlphabetManager::CAlphNode::PopulateChildren() {
+  m_pMgr->PopulateChildrenWithSymbol( this, -2, 0 );
 }
 
 CDasherNode *CAlphabetManager::CreateGroupNode(CDasherNode *pParent, SGroupInfo *pInfo, std::vector<unsigned int> *pCProb, unsigned int iStart, unsigned int iEnd, unsigned int iMin, unsigned int iMax) {
@@ -179,9 +185,8 @@ CDasherNode *CAlphabetManager::CreateGroupNode(CDasherNode *pParent, SGroupInfo
   pDisplayInfo->bVisible = pInfo->bVisible;
   pDisplayInfo->strDisplayText = pInfo->strLabel;
 
-  CDasherNode *pNewNode = new CDasherNode(pParent, iLbnd, iHbnd, pDisplayInfo);
+  CDasherNode *pNewNode = new CAlphNode(pParent, iLbnd, iHbnd, pDisplayInfo, this);
 
-  pNewNode->m_pNodeManager = this;
   pNewNode->SetFlag(NF_SUBNODE, true);
 
   SAlphabetData *pNodeUserData = new SAlphabetData;
@@ -273,7 +278,7 @@ CDasherNode *CAlphabetManager::CreateSymbolNode(CDasherNode *pParent, symbol iSy
       pDisplayInfo->bVisible = true;
       pDisplayInfo->strDisplayText = m_pNCManager->GetAlphabet()->GetDisplayText(iSymbol);
 
-      pNewNode = new CDasherNode(pParent, iLbnd, iHbnd, pDisplayInfo);
+      pNewNode = new CAlphNode(pParent, iLbnd, iHbnd, pDisplayInfo, this);
 
       //     std::stringstream ssLabel;
 
@@ -282,8 +287,6 @@ CDasherNode *CAlphabetManager::CreateSymbolNode(CDasherNode *pParent, symbol iSy
       //    pDisplayInfo->strDisplayText = ssLabel.str();
 
 
-      pNewNode->m_pNodeManager = this;
-
       pNewNode->m_iNumSymbols = 1;
 
       SAlphabetData *pNodeUserData = new SAlphabetData;
@@ -382,50 +385,49 @@ void CAlphabetManager::PopulateChildrenWithSymbol( CDasherNode *pNode, int iExis
     &cum, 1, iChildCount, iExistingSymbol, pExistingChild);
 }
 
-void CAlphabetManager::ClearNode( CDasherNode *pNode ) {
-  SAlphabetData *pUserData(static_cast<SAlphabetData *>(pNode->m_pUserData));
+CAlphabetManager::CAlphNode::~CAlphNode() {
+  SAlphabetData *pUserData(static_cast<SAlphabetData *>(m_pUserData));
 
   pUserData->pLanguageModel->ReleaseContext(pUserData->iContext);
   delete pUserData;
 }
 
-void CAlphabetManager::Output( CDasherNode *pNode, Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization) {
-  symbol t = static_cast<SAlphabetData *>(pNode->m_pUserData)->iSymbol;
+void CAlphabetManager::CAlphNode::Output(Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization) {
+  symbol t = static_cast<SAlphabetData *>(m_pUserData)->iSymbol;
 
-  //std::cout << pNode << " " << pNode->Parent() << ": Output at offset " << pNode->m_iOffset << " *" << m_pNCManager->GetAlphabet()->GetText(t) << "* " << std::endl;
+  //std::cout << this << " " << Parent() << ": Output at offset " << m_iOffset << " *" << m_pMgr->m_pNCManager->GetAlphabet()->GetText(t) << "* " << std::endl;
 
   if(t) { // Ignore symbol 0 (root node)
-    Dasher::CEditEvent oEvent(1, m_pNCManager->GetAlphabet()->GetText(t), pNode->m_iOffset);
-    m_pNCManager->InsertEvent(&oEvent);
+    Dasher::CEditEvent oEvent(1, m_pMgr->m_pNCManager->GetAlphabet()->GetText(t), m_iOffset);
+    m_pMgr->m_pNCManager->InsertEvent(&oEvent);
 
     // Track this symbol and its probability for logging purposes
     if (pAdded != NULL) {
       Dasher::SymbolProb sItem;
       sItem.sym    = t;
-      sItem.prob   = pNode->GetProb(iNormalization);
+      sItem.prob   = GetProb(iNormalization);
 
       pAdded->push_back(sItem);
     }
   }
 }
 
-void CAlphabetManager::Undo( CDasherNode *pNode ) {
-  symbol t = static_cast<SAlphabetData *>(pNode->m_pUserData)->iSymbol;
+void CAlphabetManager::CAlphNode::Undo() {
+  symbol t = static_cast<SAlphabetData *>(m_pUserData)->iSymbol;
 
   if(t) { // Ignore symbol 0 (root node)
-    Dasher::CEditEvent oEvent(2, m_pNCManager->GetAlphabet()->GetText(t), pNode->m_iOffset);
-    m_pNCManager->InsertEvent(&oEvent);
+    Dasher::CEditEvent oEvent(2, m_pMgr->m_pNCManager->GetAlphabet()->GetText(t), m_iOffset);
+    m_pMgr->m_pNCManager->InsertEvent(&oEvent);
   }
 }
 
 // TODO: Sort out node deletion etc.
-CDasherNode *CAlphabetManager::RebuildParent(CDasherNode *pNode) {
-  int iOffset(pNode->m_iOffset);
-  int iNewOffset = iOffset - 1;
+CDasherNode *CAlphabetManager::CAlphNode::RebuildParent() {
+  int iNewOffset = m_iOffset - 1;
 
   CDasherNode *pNewNode;
 
-  int iOldPhase(static_cast<SAlphabetData *>(pNode->m_pUserData)->iPhase);
+  int iOldPhase(static_cast<SAlphabetData *>(m_pUserData)->iPhase);
   int iNewPhase;
 
   symbol iNewSymbol;
@@ -433,8 +435,8 @@ CDasherNode *CAlphabetManager::RebuildParent(CDasherNode *pNode) {
   std::string strContext;
   CLanguageModel::Context iContext;
 
-  if((iOffset == -1) || (static_cast<SAlphabetData *>(pNode->m_pUserData)->iSymbol == 0)) {
-    // pNode is already a root, or for some other reason has the null
+  if((m_iOffset == -1) || (static_cast<SAlphabetData *>(m_pUserData)->iSymbol == 0)) {
+    // already a root, or for some other reason has the null
     // symbol (eg because it was generated from a different alphabet)
     return NULL;
   }
@@ -443,40 +445,39 @@ CDasherNode *CAlphabetManager::RebuildParent(CDasherNode *pNode) {
   pDisplayInfo->bShove = true;
   pDisplayInfo->bVisible = true;
   
-  if(iOffset == 0) {
+  if(m_iOffset == 0) {
     // TODO: Creating a root node, Shouldn't be a special case
     iNewPhase = 0;
     iNewSymbol = 0;
-    strContext = m_pNCManager->GetAlphabet()->GetDefaultContext();
-    BuildContext(strContext, true, iContext, iNewSymbol);
+    strContext = m_pMgr->m_pNCManager->GetAlphabet()->GetDefaultContext();
+    m_pMgr->BuildContext(strContext, true, iContext, iNewSymbol);
 
     pDisplayInfo->iColour = 7; // TODO: Hard coded value
     pDisplayInfo->strDisplayText = "";
   }
   else {
-    int iMaxContextLength = m_pLanguageModel->GetContextLength() + 1;
+    int iMaxContextLength = m_pMgr->m_pLanguageModel->GetContextLength() + 1;
 
-    int iStart = iOffset - iMaxContextLength;
+    int iStart = m_iOffset - iMaxContextLength;
     if(iStart < 0)
       iStart = 0;
 
-    strContext = m_pInterface->GetContext(iStart, iOffset - iStart);
+    strContext = m_pMgr->m_pInterface->GetContext(iStart, m_iOffset - iStart);
 
-    BuildContext(strContext, false, iContext, iNewSymbol);
+    m_pMgr->BuildContext(strContext, false, iContext, iNewSymbol);
 
     iNewPhase = ((iOldPhase + 2 - 1) % 2);
 
-    int iColour(m_pNCManager->GetColour(iNewSymbol, iNewPhase));
-
+    int iColour(m_pMgr->m_pNCManager->GetColour(iNewSymbol, iNewPhase));
+            
     pDisplayInfo->iColour = iColour;
-    pDisplayInfo->strDisplayText = m_pNCManager->GetAlphabet()->GetDisplayText(iNewSymbol);
+    pDisplayInfo->strDisplayText = m_pMgr->m_pNCManager->GetAlphabet()->GetDisplayText(iNewSymbol);
   }
 
-  pNewNode = new CDasherNode(NULL, 0, 0, pDisplayInfo);
+  pNewNode = new CAlphNode(NULL, 0, 0, pDisplayInfo, m_pMgr);
   
   // TODO: Some of this context stuff could be consolidated
 
-  pNewNode->m_pNodeManager = this;
   pNewNode->SetFlag(NF_SEEN, true);
 
   SAlphabetData *pNodeUserData = new SAlphabetData;
@@ -485,11 +486,11 @@ CDasherNode *CAlphabetManager::RebuildParent(CDasherNode *pNode) {
   pNewNode->m_iOffset = iNewOffset;
   pNodeUserData->iPhase = iNewPhase;
   pNodeUserData->iSymbol = iNewSymbol;
-  pNodeUserData->pLanguageModel = m_pLanguageModel;
+  pNodeUserData->pLanguageModel = m_pMgr->m_pLanguageModel;
   pNodeUserData->iContext = iContext;
 
 
-  PopulateChildrenWithSymbol(pNewNode, static_cast<SAlphabetData *>(pNode->m_pUserData)->iSymbol, pNode);
+  m_pMgr->PopulateChildrenWithSymbol(pNewNode, static_cast<SAlphabetData *>(m_pUserData)->iSymbol, this);
 
   //  std::cout << "**" << std::endl;
 
@@ -498,11 +499,12 @@ CDasherNode *CAlphabetManager::RebuildParent(CDasherNode *pNode) {
 
 // TODO: Shouldn't there be an option whether or not to learn as we write?
 // For want of a better solution, game mode exemption explicit in this function
-void CAlphabetManager::SetFlag(CDasherNode *pNode, int iFlag, bool bValue) {
+void CAlphabetManager::CAlphNode::SetFlag(int iFlag, bool bValue) {
+  CDasherNode::SetFlag(iFlag, bValue);
   switch(iFlag) {
   case NF_COMMITTED:
-    if(bValue && !pNode->GetFlag(NF_GAME) && m_pInterface->GetBoolParameter(BP_LM_ADAPTIVE))
-      static_cast<SAlphabetData *>(pNode->m_pUserData)->pLanguageModel->LearnSymbol(m_iLearnContext, static_cast<SAlphabetData *>(pNode->m_pUserData)->iSymbol);
+    if(bValue && !GetFlag(NF_GAME) && m_pMgr->m_pInterface->GetBoolParameter(BP_LM_ADAPTIVE))
+      static_cast<SAlphabetData *>(m_pUserData)->pLanguageModel->LearnSymbol(m_pMgr->m_iLearnContext, static_cast<SAlphabetData *>(m_pUserData)->iSymbol);
     break;
   }
 }
diff --git a/Src/DasherCore/AlphabetManager.h b/Src/DasherCore/AlphabetManager.h
index 526dd8f..613b3fa 100644
--- a/Src/DasherCore/AlphabetManager.h
+++ b/Src/DasherCore/AlphabetManager.h
@@ -21,9 +21,8 @@
 #ifndef __alphabetmanager_h__
 #define __alphabetmanager_h__
 
-#include "NodeManager.h"
 #include "LanguageModelling/LanguageModel.h"
-
+#include "DasherNode.h"
 #include "Parameters.h"
 
 class CNodeCreationManager;
@@ -41,24 +40,12 @@ namespace Dasher {
   /// to the appropriate alphabet file, with sizes given by the
   /// language model.
   ///
-  class CAlphabetManager : public CNodeManager {
+  class CAlphabetManager {
   public:
 
     CAlphabetManager(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, CLanguageModel *pLanguageModel, CLanguageModel::Context iLearnContext);
 
     ///
-    /// Does nothing - alphabet manager isn't reference counted.
-    ///
-
-    virtual void Ref() {};
-    
-    ///
-    /// Does nothing - alphabet manager isn't reference counted.
-    ///
-    
-    virtual void Unref() {};
-
-    ///
     /// Get a new root node owned by this manager
     ///
     // ACL note 12/8/09 - if previously passed in an SRootData (containing a char* and int),
@@ -66,32 +53,38 @@ namespace Dasher {
     //   in null SRootData, then pass in szContext==null and iOffset==-1.
     virtual CDasherNode *GetRoot(CDasherNode *pParent, int iLower, int iUpper, char *szContext, int iOffset);
 
+  protected:
+    class CAlphNode : public CDasherNode {
+    public:
+      int mgrId() {return 0;}
+      CAlphNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo, CAlphabetManager *pMgr);
     ///
     /// Provide children for the supplied node
     ///
 
-    virtual void PopulateChildren( CDasherNode *pNode );
-    void PopulateChildrenWithSymbol( CDasherNode *pNode, int iExistingSymbol, CDasherNode *pExistingChild );
+    virtual void PopulateChildren();
 
     ///
     /// Delete any storage alocated for this node
     ///
 
-    virtual void ClearNode( CDasherNode *pNode );
+    virtual ~CAlphNode();
 
-    virtual void Output( CDasherNode *pNode, Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization);
-    virtual void Undo( CDasherNode *pNode );
+    virtual void Output(Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization);
+    virtual void Undo();
 
-    virtual CDasherNode *RebuildParent(CDasherNode *pNode);
+    virtual CDasherNode *RebuildParent();
 
-    virtual void SetFlag(CDasherNode *pNode, int iFlag, bool bValue);
+    virtual void SetFlag(int iFlag, bool bValue);
 
-    virtual bool GameSearchNode(CDasherNode *pNode, std::string strTargetUtf8Char);
+    virtual bool GameSearchNode(std::string strTargetUtf8Char);
     
-    virtual CLanguageModel::Context CloneAlphContext(CDasherNode *pNode, CLanguageModel *pLanguageModel);
-    virtual symbol GetAlphSymbol(CDasherNode *pNode);
+    virtual CLanguageModel::Context CloneAlphContext(CLanguageModel *pLanguageModel);
+    virtual symbol GetAlphSymbol();
+    private:
+      CAlphabetManager *m_pMgr;
+    };
     
-  protected:
     struct SAlphabetData {
       symbol iSymbol;
       int iPhase;
@@ -101,6 +94,14 @@ namespace Dasher {
       int iGameOffset;
     };
 
+    ///
+    /// Factory method for CAlphNode construction, so subclasses can override.
+    ///
+    virtual CAlphNode *makeNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo);    
+
+    
+  void PopulateChildrenWithSymbol( CDasherNode *pNode, int iExistingSymbol, CDasherNode *pExistingChild );
+
 	virtual CDasherNode *CreateSymbolNode(CDasherNode *pParent, symbol iSymbol, unsigned int iLbnd, unsigned int iHbnd, symbol iExistingSymbol, CDasherNode *pExistingChild);
     virtual CLanguageModel::Context CreateSymbolContext(SAlphabetData *pParentData, symbol iSymbol);
 
diff --git a/Src/DasherCore/ControlManager.cpp b/Src/DasherCore/ControlManager.cpp
index 8bec529..eec76e0 100644
--- a/Src/DasherCore/ControlManager.cpp
+++ b/Src/DasherCore/ControlManager.cpp
@@ -38,7 +38,7 @@ static char THIS_FILE[] = __FILE__;
 int CControlManager::m_iNextID = 0;
 
 CControlManager::CControlManager( CNodeCreationManager *pNCManager )
-  : CNodeManager(1), m_pNCManager(pNCManager), m_pLanguageModel(NULL) {
+  : m_pNCManager(pNCManager), m_pLanguageModel(NULL) {
   string SystemString = m_pNCManager->GetStringParameter(SP_SYSTEM_LOC);
   string UserLocation = m_pNCManager->GetStringParameter(SP_USER_LOC);
   m_iNextID = 0;
@@ -277,25 +277,28 @@ CDasherNode *CControlManager::GetRoot(CDasherNode *pParent, int iLower, int iUpp
   pDisplayInfo->bVisible = true;
   pDisplayInfo->strDisplayText = m_mapControlMap[0]->strLabel;
   
-  pNewNode = new CDasherNode(pParent, iLower, iUpper, pDisplayInfo);
+  pNewNode = new CContNode(pParent, iLower, iUpper, pDisplayInfo, this);
  
   // FIXME - handle context properly
 
   //  pNewNode->SetContext(m_pLanguageModel->CreateEmptyContext());
 
-  pNewNode->m_pNodeManager = this;
-
   pNewNode->m_pUserData = m_mapControlMap[0];
   pNewNode->m_iOffset = iOffset;
 
   return pNewNode;
 }
 
-void CControlManager::PopulateChildren( CDasherNode *pNode ) {
+CControlManager::CContNode::CContNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDisplayInfo, CControlManager *pMgr)
+: CDasherNode(pParent, iLbnd, iHbnd, pDisplayInfo), m_pMgr(pMgr) {
+}
+
+
+void CControlManager::CContNode::PopulateChildren() {
   
   CDasherNode *pNewNode;
 
-   SControlItem *pControlNode(static_cast<SControlItem *>(pNode->m_pUserData));
+   SControlItem *pControlNode(static_cast<SControlItem *>(m_pUserData));
 
    int iNChildren( pControlNode->vChildren.size() );
 
@@ -305,13 +308,13 @@ void CControlManager::PopulateChildren( CDasherNode *pNode ) {
 
      // FIXME - could do this better
 
-     int iLbnd( iIdx*(m_pNCManager->GetLongParameter(LP_NORMALIZATION)/iNChildren)); 
-     int iHbnd( (iIdx+1)*(m_pNCManager->GetLongParameter(LP_NORMALIZATION)/iNChildren)); 
+     int iLbnd( iIdx*(m_pMgr->m_pNCManager->GetLongParameter(LP_NORMALIZATION)/iNChildren)); 
+     int iHbnd( (iIdx+1)*(m_pMgr->m_pNCManager->GetLongParameter(LP_NORMALIZATION)/iNChildren)); 
 
      if( *it == NULL ) {
        // Escape back to alphabet
 
-       pNewNode = m_pNCManager->GetAlphRoot(pNode, iLbnd, iHbnd, NULL/*TODO fix this*/, pNode->m_iOffset);
+       pNewNode = m_pMgr->m_pNCManager->GetAlphRoot(this, iLbnd, iHbnd, NULL/*TODO fix this*/, m_iOffset);
        pNewNode->SetFlag(NF_SEEN, false);
      }
      else {
@@ -328,59 +331,56 @@ void CControlManager::PopulateChildren( CDasherNode *pNode ) {
        pDisplayInfo->bVisible = true;
        pDisplayInfo->strDisplayText = (*it)->strLabel;
        
-       pNewNode = new CDasherNode(pNode, iLbnd, iHbnd, pDisplayInfo);
+       pNewNode = new CContNode(this, iLbnd, iHbnd, pDisplayInfo, m_pMgr);
 
-       pNewNode->m_pNodeManager = this;
        pNewNode->m_pUserData = *it;
-       pNewNode->m_iOffset = pNode->m_iOffset;
+
+       pNewNode->m_iOffset = m_iOffset;
      }
-     pNode->Children().push_back(pNewNode);
+     Children().push_back(pNewNode);
      ++iIdx;
    }
 }
 
-void CControlManager::ClearNode( CDasherNode *pNode ) {
-}
-
-void CControlManager::Output( CDasherNode *pNode, Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization ) {
+void CControlManager::CContNode::Output(Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization ) {
 
-  SControlItem *pControlNode(static_cast<SControlItem *>(pNode->m_pUserData));
+  SControlItem *pControlNode(static_cast<SControlItem *>(m_pUserData));
 
   CControlEvent oEvent(pControlNode->iID);
   // TODO: Need to reimplement this
   //  m_pNCManager->m_bContextSensitive=false;
-  m_pNCManager->InsertEvent(&oEvent);
+  m_pMgr->m_pNCManager->InsertEvent(&oEvent);
 }
 
-void CControlManager::Undo( CDasherNode *pNode ) {
+void CControlManager::CContNode::Undo() {
   // Do we ever need this?
   // One other thing we probably want is notification when we leave a node - that way we can eg speed up again if we slowed down
-  m_pNCManager->SetLongParameter(LP_BOOSTFACTOR, 100);
+  m_pMgr->m_pNCManager->SetLongParameter(LP_BOOSTFACTOR, 100);
   //Re-enable auto speed control!
-  if (bDisabledSpeedControl)
+  if (m_pMgr->bDisabledSpeedControl)
   {
-    bDisabledSpeedControl = false;
-    m_pNCManager->SetBoolParameter(BP_AUTO_SPEEDCONTROL, 1);
+    m_pMgr->bDisabledSpeedControl = false;
+    m_pMgr->m_pNCManager->SetBoolParameter(BP_AUTO_SPEEDCONTROL, 1);
   }
 }
 
-void CControlManager::Enter(CDasherNode *pNode) {
+void CControlManager::CContNode::Enter() {
   // Slow down to half the speed we were at
-  m_pNCManager->SetLongParameter(LP_BOOSTFACTOR, 50);
+  m_pMgr->m_pNCManager->SetLongParameter(LP_BOOSTFACTOR, 50);
   //Disable auto speed control!
-  if ((bDisabledSpeedControl = m_pNCManager->GetBoolParameter(BP_AUTO_SPEEDCONTROL)) == true)
-    m_pNCManager->SetBoolParameter(BP_AUTO_SPEEDCONTROL, 0);
+  m_pMgr->bDisabledSpeedControl = m_pMgr->m_pNCManager->GetBoolParameter(BP_AUTO_SPEEDCONTROL); 
+  m_pMgr->m_pNCManager->SetBoolParameter(BP_AUTO_SPEEDCONTROL, 0);
 }
 
 
-void CControlManager::Leave(CDasherNode *pNode) {
+void CControlManager::CContNode::Leave() {
   // Now speed back up, by doubling the speed we were at in control mode
-  m_pNCManager->SetLongParameter(LP_BOOSTFACTOR, 100);
+  m_pMgr->m_pNCManager->SetLongParameter(LP_BOOSTFACTOR, 100);
   //Re-enable auto speed control!
-  if (bDisabledSpeedControl)
+  if (m_pMgr->bDisabledSpeedControl)
   {
-    bDisabledSpeedControl = false;
-    m_pNCManager->SetBoolParameter(BP_AUTO_SPEEDCONTROL, 1);
+    m_pMgr->bDisabledSpeedControl = false;
+    m_pMgr->m_pNCManager->SetBoolParameter(BP_AUTO_SPEEDCONTROL, 1);
   }
 }
 
@@ -415,6 +415,6 @@ void CControlManager::XmlCDataHandler(void *pUserData, const XML_Char *szData, i
   return;
 }
 
-void CControlManager::SetControlOffset(CDasherNode *pNode, int iOffset) {
-  pNode->m_iOffset = iOffset;
+void CControlManager::CContNode::SetControlOffset(int iOffset) {
+  m_iOffset = iOffset;
 }
diff --git a/Src/DasherCore/ControlManager.h b/Src/DasherCore/ControlManager.h
index 07d455d..f351007 100644
--- a/Src/DasherCore/ControlManager.h
+++ b/Src/DasherCore/ControlManager.h
@@ -21,7 +21,6 @@
 #ifndef __controlmanager_h__
 #define __controlmanager_h__
 
-#include "NodeManager.h"
 #include "LanguageModelling/LanguageModel.h" // Urgh - we really shouldn't need to know about language models here
 #include "DasherModel.h"
 #include "DasherNode.h"
@@ -53,7 +52,7 @@ namespace Dasher {
   /// Currently can only have one instance due to use 
   /// of static members for callbacks from expat.
   ///
-  class CControlManager : public CNodeManager {
+  class CControlManager {
   public:
 
     enum { CTL_ROOT, CTL_STOP, CTL_PAUSE, CTL_MOVE, CTL_MOVE_FORWARD, 
@@ -71,49 +70,36 @@ namespace Dasher {
     ~CControlManager();
 
     ///
-    /// Does nothing - control manager isn't reference counted.
-    ///
-
-    virtual void Ref() {};
-    
-    ///
-    /// Does nothing - control manager isn't reference counted.
-    ///
-    
-    virtual void Unref() {};
-
-    ///
     /// Get a new root node owned by this manager
     ///
 
     virtual CDasherNode *GetRoot(CDasherNode *pParent, int iLower, int iUpper, int iOffset);
-
-    ///
-    /// Provide children for the supplied node
-    ///
-
-    virtual void PopulateChildren( CDasherNode *pNode );
+    void RegisterNode( int iID, std::string strLabel, int iColour );
+    void ConnectNode(int iChild, int iParent, int iAfter);
+    void DisconnectNode(int iChild, int iParent);
     
+  private:
+    class CContNode : public CDasherNode {
+    public:
+      int mgrId() {return 1;}
+      CContNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDisplayInfo, CControlManager *pMgr);
     ///
-    /// Delete any storage alocated for this node
+    /// Provide children for the supplied node
     ///
 
-    virtual void ClearNode( CDasherNode *pNode );
+    virtual void PopulateChildren();
     
-    virtual void Output( CDasherNode *pNode, Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization );
-    virtual void Undo( CDasherNode *pNode );
+    virtual void Output(Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization );
+    virtual void Undo();
 
-    virtual void Enter(CDasherNode *pNode);
-    virtual void Leave(CDasherNode *pNode);
-
-    void RegisterNode( int iID, std::string strLabel, int iColour );
-    void ConnectNode(int iChild, int iParent, int iAfter);
-    void DisconnectNode(int iChild, int iParent);
-
-    void SetControlOffset(CDasherNode *pNode, int iOffset);
-
-  private:
+    virtual void Enter();
+    virtual void Leave();
 
+    void SetControlOffset(int iOffset);
+    private:
+      CControlManager *m_pMgr;
+    };
+    
     struct SControlItem {
       std::vector<SControlItem *> vChildren;
       std::string strLabel;
diff --git a/Src/DasherCore/ConversionHelper.cpp b/Src/DasherCore/ConversionHelper.cpp
index bf0f21e..1b6c2c0 100644
--- a/Src/DasherCore/ConversionHelper.cpp
+++ b/Src/DasherCore/ConversionHelper.cpp
@@ -62,7 +62,7 @@ CDasherNode *CConversionHelper::GetRoot(CDasherNode *pParent, int iLower, int iU
   // context of a conversion node (e.g. ^) is the context of the
   // letter (e.g. e) before it (as the ^ entails replacing the e with
   // a single accented character e-with-^)
-  pNodeUserData->iContext = pParent->m_pNodeManager->CloneAlphContext(pParent, m_pLanguageModel);
+  pNodeUserData->iContext = pParent->CloneAlphContext(m_pLanguageModel);
   return pNewNode;
 }
 
@@ -166,10 +166,10 @@ void CConversionHelper::AssignChildSizes(SCENode **pNode, CLanguageModel::Contex
 
 }
 
-void CConversionHelper::PopulateChildren( CDasherNode *pNode ) {
+void CConversionHelper::CConvHNode::PopulateChildren() {
   DASHER_ASSERT(m_pNCManager);
 
-  SConversionData * pCurrentDataNode (static_cast<SConversionData *>(pNode->m_pUserData));
+  SConversionData * pCurrentDataNode (static_cast<SConversionData *>(m_pUserData));
   CDasherNode *pNewNode;
 
   // Do the conversion and build the tree (lattice) if it hasn't been
@@ -178,7 +178,7 @@ void CConversionHelper::PopulateChildren( CDasherNode *pNode ) {
 
 
   if(pCurrentDataNode->bisRoot) {
-    BuildTree(pNode);
+    mgr()->BuildTree(this);
   }
 
   SCENode *pCurrentSCEChild;
@@ -216,7 +216,7 @@ void CConversionHelper::PopulateChildren( CDasherNode *pNode ) {
 
 
 
-    AssignChildSizes(&pCurrentSCEChild, pCurrentDataNode->iContext, pCurrentSCEChild->IsHeadAndCandNum);
+    mgr()->AssignChildSizes(&pCurrentSCEChild, pCurrentDataNode->iContext, pCurrentSCEChild->IsHeadAndCandNum);
 
     int iIdx(0);
     int iCum(0);
@@ -241,7 +241,7 @@ void CConversionHelper::PopulateChildren( CDasherNode *pNode ) {
 
 
       CDasherNode::SDisplayInfo *pDisplayInfo = new CDasherNode::SDisplayInfo;
-      pDisplayInfo->iColour = AssignColour(parentClr, pCurrentSCEChild, iIdx);
+      pDisplayInfo->iColour = mgr()->AssignColour(parentClr, pCurrentSCEChild, iIdx);
       pDisplayInfo->bShove = true;
       pDisplayInfo->bVisible = true;
 
@@ -249,7 +249,7 @@ void CConversionHelper::PopulateChildren( CDasherNode *pNode ) {
 
       pDisplayInfo->strDisplayText = pCurrentSCEChild->pszConversion;
 
-      pNewNode = new CDasherNode(pNode, iLbnd, iHbnd, pDisplayInfo);
+      pNewNode = mgr()->makeNode(this, iLbnd, iHbnd, pDisplayInfo);
 
       // TODO: Reimplement ----
 
@@ -257,14 +257,11 @@ void CConversionHelper::PopulateChildren( CDasherNode *pNode ) {
       //      pNewNode->SetContext(m_pLanguageModel->CreateEmptyContext());
       // -----
 
-      pNewNode->m_pNodeManager = this;
-      Ref();
-
       SConversionData *pNodeUserData = new SConversionData;
       pNodeUserData->bisRoot = false;
       pNodeUserData->pSCENode = pCurrentSCEChild;
       pNodeUserData->pLanguageModel = pCurrentDataNode->pLanguageModel;
-      pNewNode->m_iOffset = pNode->m_iOffset + 1;
+      pNewNode->m_iOffset = m_iOffset + 1;
 
       if(pCurrentDataNode->pLanguageModel) {
 	CLanguageModel::Context iContext;
@@ -279,7 +276,7 @@ void CConversionHelper::PopulateChildren( CDasherNode *pNode ) {
 
       pNewNode->m_pUserData = pNodeUserData;
 
-      pNode->Children().push_back(pNewNode);
+      Children().push_back(pNewNode);
 
       pCurrentSCEChild = pCurrentSCEChild->GetNext();
       ++iIdx;
@@ -293,12 +290,12 @@ void CConversionHelper::PopulateChildren( CDasherNode *pNode ) {
       // TODO: Placeholder algorithm here
       // TODO: Add an 'end of conversion' node?
       int iLbnd(0);
-      int iHbnd(m_pNCManager->GetLongParameter(LP_NORMALIZATION));
+      int iHbnd(mgr()->m_pNCManager->GetLongParameter(LP_NORMALIZATION));
 
-      pNewNode = m_pNCManager->GetAlphRoot(pNode, iLbnd, iHbnd, NULL, pNode->m_iOffset);
+      pNewNode = mgr()->m_pNCManager->GetAlphRoot(this, iLbnd, iHbnd, NULL, m_iOffset);
       pNewNode->SetFlag(NF_SEEN, false);
 
-      pNode->Children().push_back(pNewNode);
+      Children().push_back(pNewNode);
       //    pNode->SetHasAllChildren(false);
       //}
     /* What do the following code do?
@@ -314,7 +311,7 @@ void CConversionHelper::PopulateChildren( CDasherNode *pNode ) {
       pDisplayInfo->bVisible = true;
       pDisplayInfo->strDisplayText = "";
 
-      pNewNode = new CDasherNode(pNode, iLbnd, iHbnd, pDisplayInfo);
+      pNewNode = m_pMgr->makeNode(this, iLbnd, iHbnd, pDisplayInfo);
 
       // TODO: Reimplement ----
 
@@ -322,9 +319,6 @@ void CConversionHelper::PopulateChildren( CDasherNode *pNode ) {
       //      pNewNode->SetContext(m_pLanguageModel->CreateEmptyContext());
       // -----
 
-      pNewNode->m_pNodeManager = this;
-      pNewNode->m_pNodeManager->Ref();
-
       SConversionData *pNodeUserData = new SConversionData;
       pNodeUserData->bType = true;
       pNodeUserData->pSCENode = NULL;
@@ -341,17 +335,17 @@ void CConversionHelper::PopulateChildren( CDasherNode *pNode ) {
   }
 }
 
-void CConversionHelper::BuildTree(CDasherNode *pRoot) {
+void CConversionHelper::BuildTree(CConvHNode *pRoot) {
   // Build the string to convert.
   std::string strCurrentString;
   // Search backwards but stop at any conversion node.
   for (CDasherNode *pNode = pRoot->Parent();
-       pNode && pNode->m_pNodeManager->GetID() != 2;
+       pNode && pNode->mgrId() != 2;
        pNode = pNode->Parent()) {
       
     // TODO: Need to make this the edit text rather than the display text
     strCurrentString =
-              m_pAlphabet->GetText(pNode->m_pNodeManager->GetAlphSymbol(pNode))
+              m_pAlphabet->GetText(pNode->GetAlphSymbol())
               + strCurrentString;
   }
   // Handle/store the result.
@@ -364,13 +358,23 @@ void CConversionHelper::BuildTree(CDasherNode *pRoot) {
   static_cast<SConversionData *>(pRoot->m_pUserData)->pSCENode = pStartTemp;
 }
 
-void CConversionHelper::SetFlag(CDasherNode *pNode, int iFlag, bool bValue) {
+CConversionHelper::CConvHNode::CConvHNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo, CConversionHelper *pMgr)
+: CConvNode(pParent, iLbnd, iHbnd, pDispInfo, pMgr) {
+}
+
+
+CConversionHelper::CConvHNode *CConversionHelper::makeNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo) {
+  return new CConvHNode(pParent, iLbnd, iHbnd, pDispInfo, this);
+}
+
+void CConversionHelper::CConvHNode::SetFlag(int iFlag, bool bValue) {
+  CDasherNode::SetFlag(iFlag, bValue);
   switch(iFlag) {
   case NF_COMMITTED:
     if(bValue){
-      CLanguageModel * pLan =  static_cast<SConversionData *>(pNode->m_pUserData)->pLanguageModel;
+      CLanguageModel * pLan =  static_cast<SConversionData *>(m_pUserData)->pLanguageModel;
 
-      SCENode * pSCENode = static_cast<SConversionData *>(pNode->m_pUserData)->pSCENode;
+      SCENode * pSCENode = static_cast<SConversionData *>(m_pUserData)->pSCENode;
 
       if(!pSCENode)
 	return;
@@ -379,7 +383,7 @@ void CConversionHelper::SetFlag(CDasherNode *pNode, int iFlag, bool bValue) {
 
 
       if(s!=-1)
-	pLan->LearnSymbol(m_iLearnContext, s);
+	pLan->LearnSymbol(mgr()->m_iLearnContext, s);
     }
     break;
   }
diff --git a/Src/DasherCore/ConversionHelper.h b/Src/DasherCore/ConversionHelper.h
index d3cb82b..ae3a52f 100644
--- a/Src/DasherCore/ConversionHelper.h
+++ b/Src/DasherCore/ConversionHelper.h
@@ -114,23 +114,27 @@ namespace Dasher{
     
     virtual void AssignChildSizes(SCENode **pNode, CLanguageModel::Context context, int iNChildren);
 	
-	///
-    /// Provide children for the supplied node
-    ///
-	
-    virtual void PopulateChildren( CDasherNode *pNode );
+	protected:
+    class CConvHNode : public CConvNode {
+    public:
+      CConvHNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo, CConversionHelper *pMgr);
+      ///
+      /// Provide children for the supplied node
+      ///
+      virtual void PopulateChildren();
     	
-    virtual void SetFlag(CDasherNode *pNode, int iFlag, bool bValue);
-
-private:
-	
+    virtual void SetFlag(int iFlag, bool bValue);
+    protected:
+      CConversionHelper *mgr() {return static_cast<CConversionHelper *>(m_pMgr);}
+    };
+	  virtual CConvHNode *makeNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo);
     /// 
     /// Build the conversion tree (lattice) for the given string -
     /// evaluated late to prevent unnecessary conversions when the
     /// children of the root node are never instantiated
     ///
     
-    virtual void BuildTree(CDasherNode *pRoot);
+    virtual void BuildTree(CConvHNode *pRoot);
 	
     ///
     /// Language model (TODO: We don't need to know about this, surely)
diff --git a/Src/DasherCore/ConversionManager.cpp b/Src/DasherCore/ConversionManager.cpp
index a7c0856..7fc3f11 100644
--- a/Src/DasherCore/ConversionManager.cpp
+++ b/Src/DasherCore/ConversionManager.cpp
@@ -39,8 +39,7 @@
 
 using namespace Dasher;
 
-CConversionManager::CConversionManager(CNodeCreationManager *pNCManager, CAlphabet *pAlphabet)
-  : CNodeManager(2) {
+CConversionManager::CConversionManager(CNodeCreationManager *pNCManager, CAlphabet *pAlphabet) {
 
   m_pNCManager = pNCManager;
   m_pAlphabet = pAlphabet;
@@ -56,6 +55,10 @@ CConversionManager::CConversionManager(CNodeCreationManager *pNCManager, CAlphab
   */
 }
 
+CConversionManager::CConvNode *CConversionManager::makeNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo) {
+  return new CConvNode(pParent, iLbnd, iHbnd, pDispInfo, this);
+}
+
 CDasherNode *CConversionManager::GetRoot(CDasherNode *pParent, int iLower, int iUpper, int iOffset) {
   CDasherNode *pNewNode;
 
@@ -67,16 +70,13 @@ CDasherNode *CConversionManager::GetRoot(CDasherNode *pParent, int iLower, int i
   pDisplayInfo->bVisible = true;
   pDisplayInfo->strDisplayText = ""; // TODO: Hard coded value, needs i18n
 
-  pNewNode = new CDasherNode(pParent, iLower, iUpper, pDisplayInfo);
+  pNewNode = makeNode(pParent, iLower, iUpper, pDisplayInfo);
 
   // FIXME - handle context properly
   // TODO: Reimplemnt -----
   //  pNewNode->SetContext(m_pLanguageModel->CreateEmptyContext());
   // -----
 
-  pNewNode->m_pNodeManager = this;
-  Ref();
-
 
   SConversionData *pNodeUserData = new SConversionData;
   pNewNode->m_pUserData = pNodeUserData;
@@ -90,11 +90,15 @@ CDasherNode *CConversionManager::GetRoot(CDasherNode *pParent, int iLower, int i
   return pNewNode;
 }
 
+CConversionManager::CConvNode::CConvNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo, CConversionManager *pMgr)
+ : CDasherNode(pParent, iLbnd, iHbnd, pDispInfo), m_pMgr(pMgr) {
+  pMgr->m_iRefCount++;
+}
 
-void CConversionManager::PopulateChildren( CDasherNode *pNode ) {
-  DASHER_ASSERT(m_pNCManager);
+void CConversionManager::CConvNode::PopulateChildren() {
+  DASHER_ASSERT(m_pMgr->m_pNCManager);
 
-  SConversionData * pCurrentDataNode (static_cast<SConversionData *>(pNode->m_pUserData));
+  SConversionData * pCurrentDataNode (static_cast<SConversionData *>(m_pUserData));
   CDasherNode *pNewNode;
 
   // If no helper class is present then just drop straight back to an
@@ -102,23 +106,24 @@ void CConversionManager::PopulateChildren( CDasherNode *pNode ) {
   // user should have been warned here.
   //
   int iLbnd(0);
-  int iHbnd(m_pNCManager->GetLongParameter(LP_NORMALIZATION));
+  int iHbnd(m_pMgr->m_pNCManager->GetLongParameter(LP_NORMALIZATION));
 
-  pNewNode = m_pNCManager->GetAlphRoot(pNode, iLbnd, iHbnd, NULL, pNode->m_iOffset + 1);
+  pNewNode = m_pMgr->m_pNCManager->GetAlphRoot(this, iLbnd, iHbnd, NULL, m_iOffset + 1);
   pNewNode->SetFlag(NF_SEEN, false);
 
-  pNode->Children().push_back(pNewNode);
+  Children().push_back(pNewNode);
 
   return;
 }
 
-void CConversionManager::ClearNode( CDasherNode *pNode ) {
-  if(pNode->m_pUserData){
-    SConversionData *pUserData(static_cast<SConversionData *>(pNode->m_pUserData));
+CConversionManager::CConvNode::~CConvNode() {
+  if(m_pUserData){
+    SConversionData *pUserData(static_cast<SConversionData *>(m_pUserData));
 
     pUserData->pLanguageModel->ReleaseContext(pUserData->iContext);
-    delete (SConversionData *)(pNode->m_pUserData);
+    delete (SConversionData *)(m_pUserData);
   }
+  m_pMgr->Unref();
 }
 
 void CConversionManager::RecursiveDumpTree(SCENode *pCurrent, unsigned int iDepth) {
@@ -143,53 +148,55 @@ void CConversionManager::RecursiveDumpTree(SCENode *pCurrent, unsigned int iDept
   */
 }
 
-void CConversionManager::Output( CDasherNode *pNode, Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization) {
+void CConversionManager::CConvNode::Output(Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization) {
   // TODO: Reimplement this
   //  m_pNCManager->m_bContextSensitive = true;
 
-  SCENode *pCurrentSCENode((static_cast<SConversionData *>(pNode->m_pUserData))->pSCENode);
+  SCENode *pCurrentSCENode((static_cast<SConversionData *>(m_pUserData))->pSCENode);
 
   if(pCurrentSCENode){
-    Dasher::CEditEvent oEvent(1, pCurrentSCENode->pszConversion, pNode->m_iOffset);
-    m_pNCManager->InsertEvent(&oEvent);
-
-    if((pNode->GetChildren())[0]->m_pNodeManager != this) {
-      Dasher::CEditEvent oEvent(11, "", 0);
-      m_pNCManager->InsertEvent(&oEvent);
+    Dasher::CEditEvent oEvent(1, pCurrentSCENode->pszConversion, m_iOffset);
+    m_pMgr->m_pNCManager->InsertEvent(&oEvent);
+
+    if((GetChildren())[0]->mgrId() == 2) {
+      if (static_cast<CConvNode *>(GetChildren()[0])->m_pMgr == m_pMgr) {
+        Dasher::CEditEvent oEvent(11, "", 0);
+        m_pMgr->m_pNCManager->InsertEvent(&oEvent);
+      }
     }
   }
   else {
-    if(!((static_cast<SConversionData *>(pNode->m_pUserData))->bisRoot)) {
-      Dasher::CEditEvent oOPEvent(1, "|", pNode->m_iOffset);
-      m_pNCManager->InsertEvent(&oOPEvent);
+    if(!((static_cast<SConversionData *>(m_pUserData))->bisRoot)) {
+      Dasher::CEditEvent oOPEvent(1, "|", m_iOffset);
+      m_pMgr->m_pNCManager->InsertEvent(&oOPEvent);
     }
     else {
-      Dasher::CEditEvent oOPEvent(1, ">", pNode->m_iOffset);
-      m_pNCManager->InsertEvent(&oOPEvent);
+      Dasher::CEditEvent oOPEvent(1, ">", m_iOffset);
+      m_pMgr->m_pNCManager->InsertEvent(&oOPEvent);
     }
 
     Dasher::CEditEvent oEvent(10, "", 0);
-    m_pNCManager->InsertEvent(&oEvent);
+    m_pMgr->m_pNCManager->InsertEvent(&oEvent);
   }
 }
 
-void CConversionManager::Undo( CDasherNode *pNode ) {
-  SCENode *pCurrentSCENode((static_cast<SConversionData *>(pNode->m_pUserData))->pSCENode);
+void CConversionManager::CConvNode::Undo() {
+  SCENode *pCurrentSCENode((static_cast<SConversionData *>(m_pUserData))->pSCENode);
 
   if(pCurrentSCENode) {
     if(pCurrentSCENode->pszConversion && (strlen(pCurrentSCENode->pszConversion) > 0)) {
-      Dasher::CEditEvent oEvent(2, pCurrentSCENode->pszConversion, pNode->m_iOffset);
-      m_pNCManager->InsertEvent(&oEvent);
+      Dasher::CEditEvent oEvent(2, pCurrentSCENode->pszConversion, m_iOffset);
+      m_pMgr->m_pNCManager->InsertEvent(&oEvent);
     }
   }
   else {
-    if(!((static_cast<SConversionData *>(pNode->m_pUserData))->bisRoot)) {
-      Dasher::CEditEvent oOPEvent(2, "|", pNode->m_iOffset);
-      m_pNCManager->InsertEvent(&oOPEvent);
+    if(!((static_cast<SConversionData *>(m_pUserData))->bisRoot)) {
+      Dasher::CEditEvent oOPEvent(2, "|", m_iOffset);
+      m_pMgr->m_pNCManager->InsertEvent(&oOPEvent);
     }
     else {
-      Dasher::CEditEvent oOPEvent(2, ">", pNode->m_iOffset);
-      m_pNCManager->InsertEvent(&oOPEvent);
+      Dasher::CEditEvent oOPEvent(2, ">", m_iOffset);
+      m_pMgr->m_pNCManager->InsertEvent(&oOPEvent);
     }
   }
 }
diff --git a/Src/DasherCore/ConversionManager.h b/Src/DasherCore/ConversionManager.h
index aae9b75..6eaf217 100644
--- a/Src/DasherCore/ConversionManager.h
+++ b/Src/DasherCore/ConversionManager.h
@@ -21,17 +21,16 @@
 #ifndef __conversion_manager_h__
 #define __conversion_manager_h__
 
-#include "AlphabetManager.h"
 #include "DasherTypes.h"
 #include "LanguageModelling/LanguageModel.h" // Urgh - we really shouldn't need to know about language models here
-#include "NodeManager.h"
+#include "DasherNode.h"
 #include "SCENode.h"
 
 // TODO: Conversion manager needs to deal with offsets and contexts - Will: See Phil for an explanation.
 
-namespace Dasher {
-  class CDasherNode; // Forward declaration
+class CNodeCreationManager;
 
+namespace Dasher {
   /// \ingroup Model
   /// @{
 
@@ -57,18 +56,10 @@ namespace Dasher {
   /// aspects of conversion, and CNodeManager for details of the node
   /// management process.
   ///
-  class CConversionManager : public CNodeManager {
+  class CConversionManager {
   public:
     // TODO: We shouldn't need to know about this stuff, but the code is somewhat in knots at the moment
     CConversionManager(CNodeCreationManager *pNCManager, CAlphabet *pAlphabet);
-
-    ///
-    /// Increment reference count
-    ///
-
-    virtual void Ref() {
-      ++m_iRefCount;
-    };
     
     ///
     /// Decrement reference count
@@ -92,32 +83,38 @@ namespace Dasher {
 
     virtual CDasherNode *GetRoot(CDasherNode *pParent, int iLower, int iUpper, int iOffset);
 
+    protected:
+    class CConvNode : public CDasherNode {
+    public:
+      int mgrId() {return 2;}
+      CConvNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo, CConversionManager *pMgr);
     ///
     /// Provide children for the supplied node
     ///
 
-    virtual void PopulateChildren( CDasherNode *pNode );
+    virtual void PopulateChildren();
     
-    ///
-    /// Delete any storage alocated for this node
-    ///
-
-    virtual void ClearNode( CDasherNode *pNode );
-
+    ~CConvNode();
+      
     ///
     /// Called whenever a node belonging to this manager first 
     /// moves under the crosshair
     ///
 
-    virtual void Output( CDasherNode *pNode, Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization);
+    virtual void Output(Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization);
 
     ///
     /// Called when a node is left backwards
     ///
 
-    virtual void Undo( CDasherNode *pNode );
+    virtual void Undo();
 
-  protected:
+    protected:
+      CConversionManager *m_pMgr;
+    };
+    
+    virtual CConvNode *makeNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo);
+    
     //TODO: REVISE
     struct SConversionData {
       symbol iSymbol;
@@ -129,7 +126,6 @@ namespace Dasher {
       //int iGameOffset;
     };
 	  
-  protected:
 	CNodeCreationManager *m_pNCManager;
 	CAlphabet *m_pAlphabet;
 	
diff --git a/Src/DasherCore/DasherModel.cpp b/Src/DasherCore/DasherModel.cpp
index a50533a..1fb0de9 100644
--- a/Src/DasherCore/DasherModel.cpp
+++ b/Src/DasherCore/DasherModel.cpp
@@ -216,7 +216,7 @@ void CDasherModel::RebuildAroundNode(CDasherNode *pNode) {
   ClearRootQueue();
   m_Root->Delete_children();
 
-  m_Root->m_pNodeManager->PopulateChildren(m_Root);
+  m_Root->PopulateChildren();
 
   m_pLastOutput = m_Root;
 }
@@ -230,7 +230,7 @@ void CDasherModel::Reparent_root(int lower, int upper) {
   CDasherNode *pNewRoot;
 
   if(oldroots.size() == 0) {
-    pNewRoot = m_Root->m_pNodeManager->RebuildParent(m_Root);
+    pNewRoot = m_Root->RebuildParent();
   }
   else {
     pNewRoot = oldroots.back();
@@ -517,12 +517,12 @@ void CDasherModel::RecursiveOutput(CDasherNode *pNode, Dasher::VECTOR_SYMBOL_PRO
     RecursiveOutput(pNode->Parent(), pAdded);
 
   if(pNode->Parent())
-    pNode->Parent()->m_pNodeManager->Leave(pNode->Parent());
+    pNode->Parent()->Leave();
 
-  pNode->m_pNodeManager->Enter(pNode);
+  pNode->Enter();
 
   pNode->SetFlag(NF_SEEN, true);
-  pNode->m_pNodeManager->Output(pNode, pAdded, GetLongParameter(LP_NORMALIZATION));
+  pNode->Output(pAdded, GetLongParameter(LP_NORMALIZATION));
 
   // If the node we are outputting is the last one in a game target sentence, then
   // notify the game mode teacher.
@@ -600,8 +600,8 @@ bool CDasherModel::DeleteCharacters(CDasherNode *newnode, CDasherNode *oldnode,
     
     //   if(oldnode->Parent() == newnode) {
     //       std::cout << "DCA" << std::endl;
-    //       oldnode->m_pNodeManager->Undo(oldnode);
-    //       oldnode->Parent()->m_pNodeManager->Enter(oldnode->Parent());
+    //       oldnode->Undo();
+    //       oldnode->Parent()->Enter();
     //       if (pNumDeleted != NULL)
     //         (*pNumDeleted)++;
     //       oldnode->SetFlag(NF_SEEN, false);
@@ -609,16 +609,16 @@ bool CDasherModel::DeleteCharacters(CDasherNode *newnode, CDasherNode *oldnode,
     //     }
     //     if(DeleteCharacters(newnode, oldnode->Parent(), pNumDeleted) == true) {
     //       std::cout << "DCB" << std::endl;
-    //       oldnode->m_pNodeManager->Undo(oldnode);
-    //       oldnode->Parent()->m_pNodeManager->Enter(oldnode->Parent());
+    //       oldnode->Undo();
+    //       oldnode->Parent()->Enter();
     //       if (pNumDeleted != NULL)
     // 	(*pNumDeleted)++;
     //       oldnode->SetFlag(NF_SEEN, false);
     //       return true;
     //     }
 
-    oldnode->m_pNodeManager->Undo(oldnode);
-    oldnode->Parent()->m_pNodeManager->Enter(oldnode->Parent());
+    oldnode->Undo();
+    oldnode->Parent()->Enter();
 
     // TODO: This is completely the wrong place to trap output
     if(pNumDeleted != NULL)
@@ -646,10 +646,9 @@ bool CDasherModel::DeleteCharacters(CDasherNode *newnode, CDasherNode *oldnode,
 
       oldnode->SetFlag(NF_SEEN, false);
       
-      oldnode->m_pNodeManager->Undo(oldnode);
+      oldnode->Undo();
 
-      if(oldnode->Parent())
-	oldnode->Parent()->m_pNodeManager->Enter(oldnode->Parent());
+      if(oldnode->Parent()) oldnode->Parent()->Enter();
 
       if (pNumDeleted != NULL)
 	(*pNumDeleted) += oldnode->m_iNumSymbols;
@@ -681,7 +680,7 @@ void CDasherModel::Push_Node(CDasherNode *pNode) {
   pNode->Delete_children(); // trial commented out - pconlon
 
   // Populate children creates two levels at once - the groups and their children.
-  pNode->m_pNodeManager->PopulateChildren(pNode);
+  pNode->PopulateChildren();
 
   pNode->SetFlag(NF_ALLCHILDREN, true);
 
@@ -964,5 +963,5 @@ void CDasherModel::SetControlOffset(int iOffset) {
   // work right now.
   CDasherNode *pNode = Get_node_under_crosshair();
   
-  pNode->m_pNodeManager->SetControlOffset(pNode, iOffset);
+  pNode->SetControlOffset(iOffset);
 }
diff --git a/Src/DasherCore/DasherNode.cpp b/Src/DasherCore/DasherNode.cpp
index 2f93fc3..855755e 100644
--- a/Src/DasherCore/DasherNode.cpp
+++ b/Src/DasherCore/DasherNode.cpp
@@ -68,9 +68,6 @@ CDasherNode::~CDasherNode() {
   // unreference ref counted stuff etc.
   Delete_children();
 
-  m_pNodeManager->ClearNode( this );
-  m_pNodeManager->Unref();
-
   //  std::cout << "done." << std::endl;
 
   delete m_pDisplayInfo;
@@ -168,11 +165,11 @@ void CDasherNode::Delete_children() {
 
   ChildMap::iterator i;
   for(i = Children().begin(); i != Children().end(); i++) {
-    //    std::cout << "CNM: " << (*i)->m_pNodeManager << " (" << (*i)->m_pNodeManager->GetID() << ") " << (*i) << " " << (*i)->Parent() << std::endl;
+    //    std::cout << "CNM: " << (*i)->MgrID() << (*i) << " " << (*i)->Parent() << std::endl;
     delete (*i);
   }
   Children().clear();
-  //  std::cout << "NM: " << m_pNodeManager << std::endl;
+  //  std::cout << "NM: " << MgrID() << std::endl;
   SetFlag(NF_ALLCHILDREN, false);
 }
 
@@ -187,9 +184,6 @@ void CDasherNode::SetFlag(int iFlag, bool bValue) {
     m_iFlags = m_iFlags | iFlag;
   else
     m_iFlags = m_iFlags & (~iFlag);
-
- m_pNodeManager->SetFlag(this, iFlag, bValue);
-
 }
  
 void CDasherNode::SetParent(CDasherNode *pNewParent) {
@@ -212,7 +206,7 @@ int CDasherNode::MostProbableChild() {
 
 bool CDasherNode::GameSearchChildren(string strTargetUtf8Char) {
   for (ChildMap::iterator i = Children().begin(); i != Children().end(); i++) {
-    if ((*i)->m_pNodeManager->GameSearchNode((*i), strTargetUtf8Char)) return true;
+    if ((*i)->GameSearchNode(strTargetUtf8Char)) return true;
   }
   return false;
 }
diff --git a/Src/DasherCore/DasherNode.h b/Src/DasherCore/DasherNode.h
index d81ef02..9fe77cb 100644
--- a/Src/DasherCore/DasherNode.h
+++ b/Src/DasherCore/DasherNode.h
@@ -23,13 +23,11 @@
 
 #include "../Common/Common.h"
 #include "../Common/NoClones.h"
+#include "LanguageModelling/LanguageModel.h"
 #include "DasherTypes.h"
-#include "NodeManager.h"
-
-// These includes no longer required? - pconlon
-//#include "Alphabet/GroupInfo.h"
-//#include "LanguageModelling/LanguageModel.h"
-
+namespace Dasher {
+  class CDasherNode;
+};
 #include <deque>
 #include <iostream>
 
@@ -120,7 +118,7 @@ class Dasher::CDasherNode:private NoClones {
   /// @param iFlag The flag to set
   /// @param bValue The new value of the flag
   ///
-  void SetFlag(int iFlag, bool bValue);
+  virtual void SetFlag(int iFlag, bool bValue);
 
   /// @brief Get the value of a flag for this node
   ///
@@ -221,20 +219,51 @@ class Dasher::CDasherNode:private NoClones {
   ///
   bool GameSearchChildren(std::string strTargetUtf8Char);
   
+  void *m_pUserData;
+  /// @name Management routines (once accessed via NodeManager)
+  /// @{
+  virtual int mgrId() = 0;
+  ///
+  /// Provide children for the supplied node
+  ///
+  
+  virtual void PopulateChildren() = 0;
+    
+  ///
+  /// Called whenever a node belonging to this manager first 
+  /// moves under the crosshair
+  ///
+  
+  virtual void Output(Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization) {};
+  virtual void Undo() {};
+  
+  virtual void Enter() {};
+  virtual void Leave() {};
+  
+  virtual CDasherNode *RebuildParent() {
+    return 0;
+  }
+    
+  virtual void SetControlOffset(int iOffset) {};
+  
+  ///
+  /// See if this node, or *if an NF_SUBNODE* a descendant (recursively),
+  /// represents the specified alphanumeric character; if so, set it's NF_GAME flag and
+  /// return true; otherwise, return false.
+  ///
+  virtual bool GameSearchNode(std::string strTargetUtf8Char) {return false;}
+  
+  /// Clone the context of the specified node, if it's an alphabet node;
+  /// else return an empty context. (Used by ConversionManager)
+  virtual CLanguageModel::Context CloneAlphContext(CLanguageModel *pLanguageModel) {
+    return pLanguageModel->CreateEmptyContext();
+  };
 
-  /// \todo Make private, read only access?
-  // leave public, or implement a get method - pconlon
-  CNodeManager *m_pNodeManager;
+  virtual symbol GetAlphSymbol() {
+    throw "Hack for pre-MandarinDasher ConversionManager::BuildTree method, needs to access CAlphabetManager-private struct";
+  }
 
-  /// Pointer for the node manager to do with as it sees fit.
-  /// Remember to make sure that the node manager deletes anything it
-  /// puts here before the node is destroyed.
-  ///
-  /// Please put everything in here which isn't required to simply
-  /// render the node - basically the only exceptions should be the
-  /// node size, colour and display text.
-  /// \todo Make private, read only access?
-  void *m_pUserData;
+  /// @}
   int m_iOffset;
 
   // A hack, to allow this node to be tied to a particular number of symbols;
diff --git a/Src/DasherCore/MandarinAlphMgr.cpp b/Src/DasherCore/MandarinAlphMgr.cpp
index 042a19b..417fc44 100644
--- a/Src/DasherCore/MandarinAlphMgr.cpp
+++ b/Src/DasherCore/MandarinAlphMgr.cpp
@@ -57,10 +57,10 @@ CDasherNode *CMandarinAlphMgr::GetRoot(CDasherNode *pParent, int iLower, int iUp
 
   //Override context for Mandarin Dasher
   if (pParent){
-    CPinYinConversionHelper *pMgr = static_cast<CPinYinConversionHelper *>(pParent->m_pNodeManager);
+    CPinYinConversionHelper::CPYConvNode *pPYParent = static_cast<CPinYinConversionHelper::CPYConvNode *>(pParent);
     //ACL think this is how this Mandarin thing works here...
     // but would be nice if I could ASSERT that that cast is ok!
-    pNodeUserData->iContext = m_pLanguageModel->CloneContext(pMgr->GetConvContext(pParent));
+    pNodeUserData->iContext = m_pLanguageModel->CloneContext(pPYParent->GetConvContext());
   }
   else
 	pNodeUserData->iContext = m_pLanguageModel->CreateEmptyContext();
@@ -74,7 +74,7 @@ CDasherNode *CMandarinAlphMgr::CreateSymbolNode(CDasherNode *pParent, symbol iSy
     //Modified for Mandarin Dasher
     //The following logic switch allows punctuation nodes in Mandarin to be treated in the same way as English (i.e. display and populate next round) instead of invoking a conversion node
 	  CDasherNode *pNewNode = m_pNCManager->GetConvRoot(pParent, iLbnd, iHbnd, pParent->m_iOffset);
-	  static_cast<CPinYinConversionHelper *>(pNewNode->m_pNodeManager)->SetConvSymbol(pNewNode, iSymbol);
+	  static_cast<CPinYinConversionHelper::CPYConvNode *>(pNewNode)->SetConvSymbol(iSymbol);
 	  return pNewNode;
   }
   return CAlphabetManager::CreateSymbolNode(pParent, iSymbol, iLbnd, iHbnd, iExistingSymbol, pExistingChild);
@@ -86,7 +86,18 @@ CLanguageModel::Context CMandarinAlphMgr::CreateSymbolContext(SAlphabetData *pPa
 	return m_pLanguageModel->CloneContext(pParentData->iContext);
 }
 
-void CMandarinAlphMgr::SetFlag(CDasherNode *pNode, int iFlag, bool bValue) {
+CMandarinAlphMgr::CMandNode::CMandNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo, CAlphabetManager *pMgr)
+: CAlphNode(pParent, iLbnd, iHbnd, pDispInfo, pMgr) {
+}
+
+CAlphabetManager::CAlphNode *CMandarinAlphMgr::makeNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo) {
+  return new CMandNode(pParent, iLbnd, iHbnd, pDispInfo, this);
+}
+
+void CMandarinAlphMgr::CMandNode::SetFlag(int iFlag, bool bValue) {
   //disable learn-as-you-write for Mandarin Dasher
-  if (iFlag!=NF_COMMITTED) CAlphabetManager::SetFlag(pNode, iFlag, bValue);
+   if (iFlag==NF_COMMITTED)
+     CDasherNode::SetFlag(iFlag, bValue); //bypass CAlphNode setter!
+  else
+      CAlphNode::SetFlag(iFlag, bValue);
 }
diff --git a/Src/DasherCore/MandarinAlphMgr.h b/Src/DasherCore/MandarinAlphMgr.h
index 59da8fd..d8a57f8 100644
--- a/Src/DasherCore/MandarinAlphMgr.h
+++ b/Src/DasherCore/MandarinAlphMgr.h
@@ -43,10 +43,14 @@ namespace Dasher {
 
     virtual CDasherNode *GetRoot(CDasherNode *pParent, int iLower, int iUpper, char *szContext, int iOffset);
 
-    virtual void SetFlag(CDasherNode *pNode, int iFlag, bool bValue);
-
   protected:
-   	virtual CDasherNode *CreateSymbolNode(CDasherNode *pParent, symbol iSymbol, unsigned int iLbnd, unsigned int iHbnd, symbol iExistingSymbol, CDasherNode *pExistingChild);
+    class CMandNode : public CAlphNode {
+    public:
+      CMandNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo, CAlphabetManager *pMgr);
+      virtual void SetFlag(int iFlag, bool bValue);
+    };
+    CAlphNode *makeNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo);
+    virtual CDasherNode *CreateSymbolNode(CDasherNode *pParent, symbol iSymbol, unsigned int iLbnd, unsigned int iHbnd, symbol iExistingSymbol, CDasherNode *pExistingChild);
     virtual CLanguageModel::Context CreateSymbolContext(SAlphabetData *pParentData, symbol iSymbol);
   };
   /// @}
diff --git a/Src/DasherCore/PinYinConversionHelper.cpp b/Src/DasherCore/PinYinConversionHelper.cpp
index c705a29..892f37a 100644
--- a/Src/DasherCore/PinYinConversionHelper.cpp
+++ b/Src/DasherCore/PinYinConversionHelper.cpp
@@ -50,7 +50,7 @@ CPinYinConversionHelper::CPinYinConversionHelper(CNodeCreationManager *pNCManage
   pParser = new CPinyinParser(strCHAlphabetPath);
 }
 
-void CPinYinConversionHelper::BuildTree(CDasherNode *pRoot) {
+void CPinYinConversionHelper::BuildTree(CConvHNode *pRoot) {
   DASHER_ASSERT(pRoot->m_pNodeManager == this);
 
   // Find the pinyin (roman) text (stored in Display text) of the
@@ -254,17 +254,27 @@ void CPinYinConversionHelper::AssignSizes(SCENode **pStart, Dasher::CLanguageMod
     //    std::cout<<"Not equal! sum is "<<sumSize<<std::endl;
 //  }
 
-void CPinYinConversionHelper::SetFlag(CDasherNode *pNode, int iFlag, bool bValue)
+CPinYinConversionHelper::CPYConvNode *CPinYinConversionHelper::makeNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo) {
+  return new CPYConvNode(pParent, iLbnd, iHbnd, pDispInfo, this);
+}
+
+CPinYinConversionHelper::CPYConvNode::CPYConvNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo, CPinYinConversionHelper *pMgr)
+: CConvHNode(pParent, iLbnd, iHbnd, pDispInfo, pMgr) {
+};
+
+void CPinYinConversionHelper::CPYConvNode::SetFlag(int iFlag, bool bValue)
 {
 	//Blanked out for new Mandarin Dasher, if we want to have the language model learn as one types, need to work on this part
-	if (iFlag == NF_COMMITTED && bValue) return;
-	CConversionHelper::SetFlag(pNode, iFlag, bValue);
+	if (iFlag == NF_COMMITTED && bValue)
+    CConvNode::SetFlag(iFlag, bValue); //skip CConvHNode::SetFlag, which does learn-as-you-type
+  else
+    CConvHNode::SetFlag(iFlag, bValue);
 }
 
-CLanguageModel::Context CPinYinConversionHelper::GetConvContext(CDasherNode *pNode) {
-  return static_cast<SConversionData *>(pNode->m_pUserData)->iContext;
+CLanguageModel::Context CPinYinConversionHelper::CPYConvNode::GetConvContext() {
+  return static_cast<SConversionData *>(m_pUserData)->iContext;
 }
 
-void CPinYinConversionHelper::SetConvSymbol(CDasherNode *pNode, int iSymbol) {
-  static_cast<SConversionData *> (pNode->m_pUserData)->iSymbol = iSymbol;
+void CPinYinConversionHelper::CPYConvNode::SetConvSymbol(int iSymbol) {
+  static_cast<SConversionData *> (m_pUserData)->iSymbol = iSymbol;
 }
diff --git a/Src/DasherCore/PinYinConversionHelper.h b/Src/DasherCore/PinYinConversionHelper.h
index e5e9cca..8afb956 100644
--- a/Src/DasherCore/PinYinConversionHelper.h
+++ b/Src/DasherCore/PinYinConversionHelper.h
@@ -21,7 +21,7 @@ class CPinYinConversionHelper : public CConversionHelper {
 
   CPinYinConversionHelper(CNodeCreationManager *pNCManager, Dasher::CEventHandler *pEventHandler,  CSettingsStore *pSettingsStore, Dasher::CAlphIO *pAlphIO, const std::string strCHAlphabetPath, Dasher::CAlphabet * pAlphabet);
 
-  virtual void BuildTree(CDasherNode *pRoot);
+  virtual void BuildTree(CConvHNode *pRoot);
   
   virtual bool Convert(const std::string &strSource, SCENode ** pRoot);
 
@@ -35,15 +35,24 @@ class CPinYinConversionHelper : public CConversionHelper {
     return m_pLanguageModel;
   }
 
-  //override to blank out learn-as-write for Mandarin Dasher
-  virtual void SetFlag(CDasherNode *pNode, int iFlag, bool bValue);
+protected:
+  class CPYConvNode : public CConvHNode {
+  public:
+    CPYConvNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo, CPinYinConversionHelper *pMgr);
+    //override to blank out learn-as-write for Mandarin Dasher
+    virtual void SetFlag(int iFlag, bool bValue);
+    
+    ///Bit of a hack here - these two need to be accessed by CMandarinAlphMgr :-(.
+    ///However, by making MandarinAlphMgr a friend of PinYinConvHelper, it can see this nested class...
+    virtual CLanguageModel::Context GetConvContext();
+    virtual void SetConvSymbol(int iSymbol);
+    
+  protected:
+    CPinYinConversionHelper *mgr() {return static_cast<CPinYinConversionHelper *>(m_pMgr);}
+  };
+  CPYConvNode *makeNode(CDasherNode *pParent, int iLbnd, int iHbnd, CDasherNode::SDisplayInfo *pDispInfo);
 	
  private:
-  ///Bit of a hack here - these two need to be accessed by CMandarinAlphMgr :-(.
-  ///Seems neater to make MandarinAlphMgr a friend, than these public...
-  virtual CLanguageModel::Context GetConvContext(CDasherNode *pNode);
-  virtual void SetConvSymbol(CDasherNode *pNode, int iSymbol);
-
   void TrainChPPM(CSettingsStore *pSettingsStore);
   void ProcessFile(CSettingsStore *pSettingsStore, int index);
 
diff --git a/Src/MacOSX/Dasher.xcodeproj/project.pbxproj b/Src/MacOSX/Dasher.xcodeproj/project.pbxproj
index 726ad71..8caa005 100755
--- a/Src/MacOSX/Dasher.xcodeproj/project.pbxproj
+++ b/Src/MacOSX/Dasher.xcodeproj/project.pbxproj
@@ -114,7 +114,6 @@
 		1948BF110C226CFD001DFA32 /* ModuleManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1948BE6C0C226CFD001DFA32 /* ModuleManager.h */; };
 		1948BF120C226CFD001DFA32 /* NodeCreationManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1948BE6D0C226CFD001DFA32 /* NodeCreationManager.cpp */; };
 		1948BF130C226CFD001DFA32 /* NodeCreationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1948BE6E0C226CFD001DFA32 /* NodeCreationManager.h */; };
-		1948BF140C226CFD001DFA32 /* NodeManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1948BE6F0C226CFD001DFA32 /* NodeManager.h */; };
 		1948BF160C226CFD001DFA32 /* OneButtonFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1948BE710C226CFD001DFA32 /* OneButtonFilter.cpp */; };
 		1948BF170C226CFD001DFA32 /* OneButtonFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1948BE720C226CFD001DFA32 /* OneButtonFilter.h */; };
 		1948BF180C226CFD001DFA32 /* OneDimensionalFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1948BE730C226CFD001DFA32 /* OneDimensionalFilter.cpp */; };
@@ -534,7 +533,6 @@
 		1948BE6C0C226CFD001DFA32 /* ModuleManager.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ModuleManager.h; sourceTree = "<group>"; };
 		1948BE6D0C226CFD001DFA32 /* NodeCreationManager.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = NodeCreationManager.cpp; sourceTree = "<group>"; };
 		1948BE6E0C226CFD001DFA32 /* NodeCreationManager.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NodeCreationManager.h; sourceTree = "<group>"; };
-		1948BE6F0C226CFD001DFA32 /* NodeManager.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NodeManager.h; sourceTree = "<group>"; };
 		1948BE710C226CFD001DFA32 /* OneButtonFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = OneButtonFilter.cpp; sourceTree = "<group>"; };
 		1948BE720C226CFD001DFA32 /* OneButtonFilter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = OneButtonFilter.h; sourceTree = "<group>"; };
 		1948BE730C226CFD001DFA32 /* OneDimensionalFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = OneDimensionalFilter.cpp; sourceTree = "<group>"; };
@@ -1034,7 +1032,6 @@
 				3306E33B0FFFB9880017324C /* MandarinAlphMgr.cpp */,
 				3306E33C0FFFB9880017324C /* MandarinAlphMgr.h */,
 				1948BE6E0C226CFD001DFA32 /* NodeCreationManager.h */,
-				1948BE6F0C226CFD001DFA32 /* NodeManager.h */,
 				1948BE710C226CFD001DFA32 /* OneButtonFilter.cpp */,
 				1948BE720C226CFD001DFA32 /* OneButtonFilter.h */,
 				1921DB370C7ECAA400E6DAA5 /* OneButtonDynamicFilter.cpp */,
@@ -1495,7 +1492,6 @@
 				1948BF0E0C226CFD001DFA32 /* MemoryLeak.h in Headers */,
 				1948BF110C226CFD001DFA32 /* ModuleManager.h in Headers */,
 				1948BF130C226CFD001DFA32 /* NodeCreationManager.h in Headers */,
-				1948BF140C226CFD001DFA32 /* NodeManager.h in Headers */,
 				1948BF170C226CFD001DFA32 /* OneButtonFilter.h in Headers */,
 				1948BF190C226CFD001DFA32 /* OneDimensionalFilter.h in Headers */,
 				1948BF1A0C226CFD001DFA32 /* Parameters.h in Headers */,



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