[dasher] Extract CAlphBase supertype of CAlphNode w/ common code for rebuilding



commit fc7e857d5f78ef73460de3ea3a8bc2238d3fbdec
Author: Alan Lawrence <acl33 inf phy cam ac uk>
Date:   Sat Feb 12 21:38:04 2011 +0000

    Extract CAlphBase supertype of CAlphNode w/ common code for rebuilding
    
    inc for CConvRoot. Should now have all the architecture for Mandarin rebuilding,
      but still need to (a) figure out m_pyParent from chinese symbol,
      (b) Modify CConvRoot to allow call to PopulateChildren w/ existing CMandSym

 Src/DasherCore/AlphabetManager.cpp |   94 +++++++++++++++++------------------
 Src/DasherCore/AlphabetManager.h   |   71 +++++++++++++++++++--------
 Src/DasherCore/MandarinAlphMgr.cpp |   70 +++++++++++++++++++++------
 Src/DasherCore/MandarinAlphMgr.h   |   26 ++++++----
 4 files changed, 168 insertions(+), 93 deletions(-)
---
diff --git a/Src/DasherCore/AlphabetManager.cpp b/Src/DasherCore/AlphabetManager.cpp
index cfe4b72..f01b245 100644
--- a/Src/DasherCore/AlphabetManager.cpp
+++ b/Src/DasherCore/AlphabetManager.cpp
@@ -116,8 +116,12 @@ int CAlphabetManager::GetColour(symbol sym, int iOffset) const {
 }
 
 
+CAlphabetManager::CAlphBase::CAlphBase(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const string &strDisplayText, CAlphabetManager *pMgr)
+: CDasherNode(pParent, iOffset, iLbnd, iHbnd, iColour, strDisplayText), m_pMgr(pMgr) {
+}
+
 CAlphabetManager::CAlphNode::CAlphNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const string &strDisplayText, CAlphabetManager *pMgr)
-: CDasherNode(pParent, iOffset, iLbnd, iHbnd, iColour, strDisplayText), m_pProbInfo(NULL), m_pMgr(pMgr) {
+: CAlphBase(pParent, iOffset, iLbnd, iHbnd, iColour, strDisplayText, pMgr), m_pProbInfo(NULL) {
 }
 
 CAlphabetManager::CSymbolNode::CSymbolNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, CAlphabetManager *pMgr, symbol _iSymbol)
@@ -313,6 +317,15 @@ CAlphabetManager::CGroupNode *CAlphabetManager::CreateGroupNode(CAlphNode *pPare
   return pNewNode;
 }
 
+CDasherNode *CAlphabetManager::CAlphBase::RebuildGroup(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strEnc, int iBkgCol, const SGroupInfo *pInfo) {
+  CGroupNode *pRet=m_pMgr->CreateGroupNode(pParent, iLbnd, iHbnd, strEnc, iBkgCol, pInfo);
+  if (isInGroup(pInfo)) {
+    //created group node should contain this one
+    m_pMgr->IterateChildGroups(pRet,pInfo,this);
+  }
+  return pRet;
+}
+
 CDasherNode *CAlphabetManager::CGroupNode::RebuildGroup(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strEnc, int iBkgCol, const SGroupInfo *pInfo) {
   if (pInfo == m_pGroup) {
     SetRange(iLbnd, iHbnd);
@@ -321,20 +334,15 @@ CDasherNode *CAlphabetManager::CGroupNode::RebuildGroup(CAlphNode *pParent, unsi
     DASHER_ASSERT (offset() == pParent->offset());
     return this;
   }
-  CGroupNode *pRet=m_pMgr->CreateGroupNode(pParent, iLbnd, iHbnd, strEnc, iBkgCol, pInfo);
-  if (pInfo->iStart <= m_pGroup->iStart && pInfo->iEnd >= m_pGroup->iEnd) {
-    //created group node should contain this one
-    m_pMgr->IterateChildGroups(pRet,pInfo,this);
-  }
-  return pRet;
+  return CAlphBase::RebuildGroup(pParent, iLbnd, iHbnd, strEnc, iBkgCol, pInfo);
 }
 
-CDasherNode *CAlphabetManager::CSymbolNode::RebuildGroup(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strEnc, int iBkgCol, const SGroupInfo *pInfo) {
-  CGroupNode *pRet=m_pMgr->CreateGroupNode(pParent, iLbnd, iHbnd, strEnc, iBkgCol, pInfo);
-  if (pInfo->iStart <= iSymbol && pInfo->iEnd > iSymbol) {
-    m_pMgr->IterateChildGroups(pRet, pInfo, this);
-  }
-  return pRet;
+bool CAlphabetManager::CGroupNode::isInGroup(const SGroupInfo *pInfo) {
+  return pInfo->iStart <= m_pGroup->iStart && pInfo->iEnd >= m_pGroup->iEnd;
+}
+
+bool CAlphabetManager::CSymbolNode::isInGroup(const SGroupInfo *pInfo) {
+  return (pInfo->iStart <= iSymbol && pInfo->iEnd > iSymbol);
 }
 
 CDasherNode *CAlphabetManager::CreateSymbolNode(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSymbol) {
@@ -359,6 +367,10 @@ CDasherNode *CAlphabetManager::CreateSymbolNode(CAlphNode *pParent, unsigned int
   return pAlphNode;
 }
 
+CDasherNode *CAlphabetManager::CAlphBase::RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSymbol) {
+  return m_pMgr->CreateSymbolNode(pParent, iLbnd, iHbnd, strGroup, iBkgCol, iSymbol);
+}
+
 CDasherNode *CAlphabetManager::CSymbolNode::RebuildSymbol(CAlphNode *pParent,  unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSymbol) {
   if(iSymbol == this->iSymbol) {
     SetRange(iLbnd, iHbnd);
@@ -366,14 +378,10 @@ CDasherNode *CAlphabetManager::CSymbolNode::RebuildSymbol(CAlphNode *pParent,  u
     DASHER_ASSERT(offset() == pParent->offset() + numChars());
     return this;
   }
-  return m_pMgr->CreateSymbolNode(pParent, iLbnd, iHbnd, strGroup, iBkgCol, iSymbol);
-}
-
-CDasherNode *CAlphabetManager::CGroupNode::RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSymbol) {
-  return m_pMgr->CreateSymbolNode(pParent, iLbnd, iHbnd, strGroup, iBkgCol, iSymbol);
+  return CAlphBase::RebuildSymbol(pParent, iLbnd, iHbnd, strGroup, iBkgCol, iSymbol);
 }
 
-void CAlphabetManager::IterateChildGroups(CAlphNode *pParent, const SGroupInfo *pParentGroup, CAlphNode *buildAround) {
+void CAlphabetManager::IterateChildGroups(CAlphNode *pParent, const SGroupInfo *pParentGroup, CAlphBase *buildAround) {
   std::vector<unsigned int> *pCProb(pParent->GetProbInfo());
   DASHER_ASSERT((*pCProb)[0] == 0);
   const int iMin(pParentGroup ? pParentGroup->iStart : 1);
@@ -500,40 +508,30 @@ void CAlphabetManager::CSymbolNode::Undo(int *pNumDeleted) {
 }
 
 CDasherNode *CAlphabetManager::CGroupNode::RebuildParent() {
-  // CAlphNode's always have a parent, they inserted a symbol; CGroupNode's
-  // with an m_pGroup have a container i.e. the parent group, unless
+  
+  if (Parent()) return Parent();
+  
+  // CGroupNodes with an m_pGroup have a container i.e. the parent group, unless
   // m_pGroup==NULL => "root" node where Alphabet->m_pBaseGroup is the *first*child*...
   if (m_pGroup == NULL) return NULL;
-  //offset of group node is same as parent...
-  return CAlphNode::RebuildParent(offset());
+    
+  return CAlphBase::RebuildParent();
 }
 
-CDasherNode *CAlphabetManager::CSymbolNode::RebuildParent() {
-  //parent's offset usually one less than this, but can be two for the paragraph symbol.
-  return CAlphNode::RebuildParent(offset()-numChars());
-}
+CDasherNode *CAlphabetManager::CAlphBase::RebuildParent() {
+  if (!Parent()) {
+    //Parent's offset usually one less than this, but can be two for the paragraph symbol.
+    int iNewOffset = offset()-numChars();
 
-CDasherNode *CAlphabetManager::CAlphNode::RebuildParent(int iNewOffset) {
-  //possible that we have a parent, as RebuildParent() rebuilds back to closest AlphNode.
-  if (Parent()) return Parent();
-  
-  CAlphNode *pNewNode = m_pMgr->GetRoot(NULL, 0, 0, iNewOffset!=-1, iNewOffset+1);
-  
-  //now fill in the new node - recursively - until it reaches us
-  m_pMgr->IterateChildGroups(pNewNode, NULL, this);
-
-  //finally return our immediate parent (pNewNode may be an ancestor rather than immediate parent!)
-  DASHER_ASSERT(Parent() != NULL);
-
-  //although not required, we believe only NF_SEEN nodes are ever requested to rebuild their parents...
-  DASHER_ASSERT(GetFlag(NF_SEEN));
-  //so set NF_SEEN on all created ancestors (of which pNewNode is the last)
-  CDasherNode *pNode = this;
-  do {
-    pNode = pNode->Parent();
-    pNode->SetFlag(NF_SEEN, true);
-  } while (pNode != pNewNode);
-  
+    CAlphNode *pNewNode = m_pMgr->GetRoot(NULL, 0, 0, iNewOffset!=-1, iNewOffset+1);
+    
+    //now fill in the new node - recursively - until it reaches us
+    m_pMgr->IterateChildGroups(pNewNode, NULL, this);
+    
+    if (GetFlag(NF_SEEN)) {
+      for (CDasherNode *pNode=this; (pNode=pNode->Parent()); pNode->SetFlag(NF_SEEN, true));
+    }
+  }
   return Parent();
 }
 
diff --git a/Src/DasherCore/AlphabetManager.h b/Src/DasherCore/AlphabetManager.h
index de40cba..804b824 100644
--- a/Src/DasherCore/AlphabetManager.h
+++ b/Src/DasherCore/AlphabetManager.h
@@ -57,10 +57,44 @@ namespace Dasher {
     virtual ~CAlphabetManager();
 
   protected:
+    class CAlphNode;
+    /// Abstract superclass for alphabet manager nodes, provides common implementation
+    /// code for rebuilding parent nodes = reversing.
+    class CAlphBase : public CDasherNode {
+    public:
+      CAlphabetManager *mgr() {return m_pMgr;}
+      CDasherNode *RebuildParent();
+      ///Called to build a symbol (leaf) node which is a descendant of the symbol or root node preceding this.
+      /// Default implementation just calls the manager's CreateSymbolNode method to create a new node,
+      /// but subclasses can override to graft themselves into the appropriate point beneath the previous node.
+      /// \param pParent parent of the symbol node to create; could be the previous root, or an intervening node (e.g. group)
+      /// \param strGroup caption of any elided group node. If a new node is created, this should be appended to that node's caption;
+      /// however, if this existing node is grafted in instead, the caption will already have been prepended (as the group structure
+      /// is always the same and just repeats endlessly), so should be ignored.
+      /// \param iBkgCol background colour to show through any new transparent node created;
+      /// if the existing node is grafted in, again this will already have been taken into account.
+      virtual CDasherNode *RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSymbol);
+      ///Called to build a group node which is a descendant of the symbol or root node preceding this.
+      /// Default implementation calls the manager's CreateGroupNode method to create a new node,
+      /// but then populates that group (i.e. further descends the hierarchy) _if_ that group
+      /// would contain this node (see IsInGroup). Subclasses can override to graft themselves into the hierarchy, if appropriate.
+      /// \param pParent parent of the symbol node to create; could be the previous root, or an intervening node (e.g. group)      
+      virtual CDasherNode *RebuildGroup(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strEnc, int iBkgCol, const SGroupInfo *pInfo);
+    protected:
+      CAlphBase(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const std::string &strDisplayText, CAlphabetManager *pMgr);
+      CAlphabetManager *m_pMgr;
+      ///Number of unicode characters entered by this node; i.e., the number
+      /// to take off this node's offset, to get the offset of the most-recent
+      /// root (e.g. previous symbol). Default is 0.
+      virtual int numChars() {return 0;}
+      ///return true if the specified group would contain this node
+      /// (as a symbol or subgroup), any number of levels beneath it
+      virtual bool isInGroup(const SGroupInfo *pGroup)=0;
+    };
     class CGroupNode;
-    class CAlphNode : public CDasherNode {
+    ///Additionally stores LM contexts and probabilities calculated therefrom
+    class CAlphNode : public CAlphBase {
     public:
-      virtual CAlphabetManager *mgr() {return m_pMgr;}
       CAlphNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const std::string &strDisplayText, CAlphabetManager *pMgr);
       CLanguageModel::Context iContext;
       ///
@@ -68,16 +102,11 @@ namespace Dasher {
       ///      
       virtual ~CAlphNode();
       virtual CLanguageModel::Context CloneAlphContext(CLanguageModel *pLanguageModel);
-      CDasherNode *RebuildParent(int iNewOffset);
       ///Have to call this from CAlphabetManager, and from CGroupNode on a _different_ CAlphNode, hence public...
       virtual std::vector<unsigned int> *GetProbInfo();
       virtual int ExpectedNumChildren();
-      virtual CDasherNode *RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSymbol)=0;
-      virtual CDasherNode *RebuildGroup(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strEnc, int iBkgCol, const SGroupInfo *pInfo)=0;
     private:
       std::vector<unsigned int> *m_pProbInfo;
-    protected:
-      CAlphabetManager *m_pMgr;
     };
     class CSymbolNode : public CAlphNode {
     public:
@@ -87,12 +116,8 @@ namespace Dasher {
       /// any such group, as GetColour() always returns an opaque color.
       CSymbolNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, CAlphabetManager *pMgr, symbol iSymbol);
 
-      ///
-      /// Provide children for the supplied node
-      ///
-
+      ///Create the children of this node, by starting traversal of the alphabet from the top
       virtual void PopulateChildren();
-      virtual CDasherNode *RebuildParent();
       virtual void Output(Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization);
       virtual void Undo(int *pNumDeleted);
 
@@ -101,9 +126,8 @@ namespace Dasher {
       virtual bool GameSearchNode(std::string strTargetUtf8Char);
       virtual void GetContext(CDasherInterfaceBase *pInterface, const CAlphabetMap *pAlphabetMap, std::vector<symbol> &vContextSymbols, int iOffset, int iLength);
       virtual symbol GetAlphSymbol();
-      const symbol iSymbol;
+      ///Override: if the symbol to create is the same as this node's symbol, return this node instead of creating a new one
       virtual CDasherNode *RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSymbol);
-      virtual CDasherNode *RebuildGroup(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strEnc, int iBkgCol, const SGroupInfo *pInfo);
     protected:
       virtual const std::string &outputText();
       /// Number of unicode _characters_ (not octets) for this symbol.
@@ -113,22 +137,29 @@ namespace Dasher {
       int numChars();
       ///Compatibility constructor, so that subclasses can specify their own colour & label
       CSymbolNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const std::string &strDisplayText, CAlphabetManager *pMgr, symbol _iSymbol);
+      ///Override: true iff pGroup encloses this symbol (according to its start/end symbol#)
+      bool isInGroup(const SGroupInfo *pGroup);
+      const symbol iSymbol;
     };
 
     class CGroupNode : public CAlphNode {
     public:
       CGroupNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, const std::string &strEnc, int iBkgCol, CAlphabetManager *pMgr, const SGroupInfo *pGroup);
       
-      ///
-      /// Provide children for the supplied node
-      ///
+      ///Override: if m_pGroup==NULL, i.e. whole/root-of alphabet, cannot rebuild.
       virtual CDasherNode *RebuildParent();
+      
+      ///Create children of this group node, by traversing the section of the alphabet
+      /// indicated by m_pGroup.
       virtual void PopulateChildren();
       virtual int ExpectedNumChildren();
       virtual bool GameSearchNode(std::string strTargetUtf8Char);
-      virtual CDasherNode *RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSymbol);
-      virtual CDasherNode *RebuildGroup(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strEnc, int iBkgCol, const SGroupInfo *pInfo);
       std::vector<unsigned int> *GetProbInfo();
+      ///Override: if the group to create is the same as this node's group, return this node instead of creating a new one
+      virtual CDasherNode *RebuildGroup(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strEnc, int iBkgCol, const SGroupInfo *pInfo);
+    protected:
+      ///Override: true if pGroup encloses this one (by start/end symbol#)
+      bool isInGroup(const SGroupInfo *pGroup);
     private:
       const SGroupInfo *m_pGroup;
     };
@@ -193,7 +224,7 @@ namespace Dasher {
     /// instead of the AlphabetManager's CreateSymbolNode/CreateGroupNode methods. This is used when
     /// rebuilding parents: passing in the pre-existing node here, allows it to intercept those calls
     /// and graft itself in in place of a new node, when appropriate.
-    void IterateChildGroups(CAlphNode *pParent, const SGroupInfo *pParentGroup, CAlphNode *buildAround);
+    void IterateChildGroups(CAlphNode *pParent, const SGroupInfo *pParentGroup, CAlphBase *buildAround);
 
     CDasherInterfaceBase *m_pInterface;
     
diff --git a/Src/DasherCore/MandarinAlphMgr.cpp b/Src/DasherCore/MandarinAlphMgr.cpp
index 153da25..072cfa3 100644
--- a/Src/DasherCore/MandarinAlphMgr.cpp
+++ b/Src/DasherCore/MandarinAlphMgr.cpp
@@ -127,7 +127,7 @@ CAlphabetManager::CAlphNode *CMandarinAlphMgr::GetRoot(CDasherNode *pParent, uns
     pNewNode = new CGroupNode(pParent, iNewOffset, iLower, iUpper, "", 0, this, NULL);
   } else {
     DASHER_ASSERT(p.first>0 && p.first<=m_pCHAlphabet->GetNumberTextSymbols());
-    pNewNode = new CMandSym(pParent, iNewOffset, iLower, iUpper,  "", this, p.first);
+    pNewNode = new CMandSym(pParent, iNewOffset, iLower, iUpper,  "", this, p.first, 0);
   }
   pNewNode->iContext = p.second;
   
@@ -162,7 +162,7 @@ CDasherNode *CMandarinAlphMgr::CreateSymbolNode(CAlphNode *pParent, unsigned int
   if (m_pConversionsBySymbol[iSymbol].size()>1)
     return CreateConvRoot(pParent, iLbnd, iHbnd, strGroup, iSymbol);
   
-  return CreateCHSymbol(pParent,pParent->iContext, iLbnd, iHbnd, strGroup, *(m_pConversionsBySymbol[iSymbol].begin()));
+  return CreateCHSymbol(pParent,pParent->iContext, iLbnd, iHbnd, strGroup, *(m_pConversionsBySymbol[iSymbol].begin()), iSymbol);
 }
 
 CMandarinAlphMgr::CConvRoot *CMandarinAlphMgr::CreateConvRoot(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, symbol iPYsym) {
@@ -177,24 +177,24 @@ CMandarinAlphMgr::CConvRoot *CMandarinAlphMgr::CreateConvRoot(CAlphNode *pParent
 }
 
 CMandarinAlphMgr::CConvRoot::CConvRoot(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, CMandarinAlphMgr *pMgr, symbol pySym)
-: CDasherNode(pParent, iOffset, iLbnd, iHbnd, 9, strGroup), m_pMgr(pMgr), m_pySym(pySym) {
-  DASHER_ASSERT(m_pMgr->m_pConversionsBySymbol[pySym].size()>1);
+: CAlphBase(pParent, iOffset, iLbnd, iHbnd, 9, strGroup, pMgr), m_pySym(pySym) {
+  DASHER_ASSERT(pMgr->m_pConversionsBySymbol[pySym].size()>1);
   //colour + label from ConversionManager.
 }
 
 int CMandarinAlphMgr::CConvRoot::ExpectedNumChildren() {
-  return m_pMgr->m_pConversionsBySymbol[m_pySym].size();
+  return mgr()->m_pConversionsBySymbol[m_pySym].size();
 }
 
 void CMandarinAlphMgr::CConvRoot::PopulateChildren() {
   if (m_vChInfo.empty()) {
-    const set<symbol> &convs(m_pMgr->m_pConversionsBySymbol[m_pySym]);
+    const set<symbol> &convs(mgr()->m_pConversionsBySymbol[m_pySym]);
     for(set<symbol>::const_iterator it = convs.begin(); it != convs.end(); ++it) {
       m_vChInfo.push_back(std::pair<symbol, unsigned int>(*it,0));
     }
     //ACL I think it's a good idea to keep those in a consistent order - symbol order will do nicely
     sort(m_vChInfo.begin(),m_vChInfo.end());
-    m_pMgr->AssignSizes(m_vChInfo, iContext);
+    mgr()->AssignSizes(m_vChInfo, iContext);
   }
   
   int iCum(0);
@@ -205,29 +205,43 @@ void CMandarinAlphMgr::CConvRoot::PopulateChildren() {
     const unsigned int iLbnd(iCum), iHbnd(iCum + it->second);
     
     iCum = iHbnd;
-    CMandSym *pNewNode = mgr()->CreateCHSymbol(this, this->iContext, iLbnd, iHbnd, "", it->first);
+    CMandSym *pNewNode = mgr()->CreateCHSymbol(this, this->iContext, iLbnd, iHbnd, "", it->first, m_pySym);
     
     DASHER_ASSERT(GetChildren().back()==pNewNode);
     
   }
 }
 
-CMandarinAlphMgr::CMandSym *CMandarinAlphMgr::CreateCHSymbol(CDasherNode *pParent, CLanguageModel::Context iContext, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, symbol iCHsym) {
+CMandarinAlphMgr::CMandSym *CMandarinAlphMgr::CreateCHSymbol(CDasherNode *pParent, CLanguageModel::Context iContext, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, symbol iCHsym, symbol iPYparent) {
   // TODO: Parameters here are placeholders - need to figure out
   // what's right 
 
   int iNewOffset = pParent->offset()+1;
   if (m_pCHAlphabet->GetText(iCHsym) == "\r\n") iNewOffset++;
-  CMandSym *pNewNode = new CMandSym(pParent, iNewOffset, iLbnd, iHbnd, strGroup, this, iCHsym);
+  CMandSym *pNewNode = new CMandSym(pParent, iNewOffset, iLbnd, iHbnd, strGroup, this, iCHsym, iPYparent);
   pNewNode->iContext = m_pLanguageModel->CloneContext(iContext);
   m_pLanguageModel->EnterSymbol(pNewNode->iContext, iCHsym);
   return pNewNode;
 }
 
+CDasherNode *CMandarinAlphMgr::CConvRoot::RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSym) {
+  if (iSym == m_pySym) {
+    SetParent(pParent);
+    SetRange(iLbnd,iHbnd);
+    return this;
+  }
+  return CAlphBase::RebuildSymbol(pParent, iLbnd, iHbnd, strGroup, iBkgCol, iSym);
+}
+
+bool CMandarinAlphMgr::CConvRoot::isInGroup(const SGroupInfo *pGroup) {
+  return pGroup->iStart <= m_pySym && pGroup->iEnd > m_pySym;
+}
+
 void CMandarinAlphMgr::CConvRoot::SetFlag(int iFlag, bool bValue) {
-  if (iFlag==NF_COMMITTED && bValue && !GetFlag(NF_COMMITTED))
-    if (!GetFlag(NF_GAME) && m_pMgr->m_pNCManager->GetBoolParameter(BP_LM_ADAPTIVE))
-      static_cast<CPPMPYLanguageModel *>(m_pMgr->m_pLanguageModel)->LearnPYSymbol(m_pMgr->m_iLearnContext, m_pySym);
+  if (iFlag==NF_COMMITTED && bValue && !GetFlag(NF_COMMITTED)
+      && !GetFlag(NF_GAME) && mgr()->m_pNCManager->GetBoolParameter(BP_LM_ADAPTIVE)) {
+    static_cast<CPPMPYLanguageModel *>(mgr()->m_pLanguageModel)->LearnPYSymbol(mgr()->m_iLearnContext, m_pySym);
+  }
   CDasherNode::SetFlag(iFlag,bValue);
 }
 
@@ -309,8 +323,34 @@ void CMandarinAlphMgr::AssignSizes(std::vector<pair<symbol,unsigned int> > &vChi
   
 }
 
-CMandarinAlphMgr::CMandSym::CMandSym(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, CMandarinAlphMgr *pMgr, symbol iSymbol)
-: CSymbolNode(pParent, iOffset, iLbnd, iHbnd, pMgr->GetCHColour(iSymbol,iOffset), strGroup+pMgr->m_pCHAlphabet->GetDisplayText(iSymbol), pMgr, iSymbol) {
+CMandarinAlphMgr::CMandSym::CMandSym(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, CMandarinAlphMgr *pMgr, symbol iSymbol, symbol pyParent)
+: CSymbolNode(pParent, iOffset, iLbnd, iHbnd, pMgr->GetCHColour(iSymbol,iOffset), strGroup+pMgr->m_pCHAlphabet->GetDisplayText(iSymbol), pMgr, iSymbol), m_pyParent(pyParent) {
+}
+
+CDasherNode *CMandarinAlphMgr::CMandSym::RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSymbol) {
+  //TODO m_pyParent should have been computed in RebuildParent()
+  DASHER_ASSERT(m_pyParent!=0);
+  if (iSymbol==m_pyParent) {
+    //create the PY node that lead to this chinese
+    if (mgr()->m_pConversionsBySymbol[m_pyParent].size()==1) {
+      DASHER_ASSERT( *(mgr()->m_pConversionsBySymbol[m_pyParent].begin()) == this->iSymbol);
+      SetRange(iLbnd, iHbnd);
+      SetParent(pParent);
+      return this;
+    }
+    //ok, will be a PY-to-Chinese conversion choice
+    CConvRoot *pConv = mgr()->CreateConvRoot(pParent, iLbnd, iHbnd, strGroup, iSymbol);
+    //TODO equivalent of IterateChildGroups - make CConvRoot generate children, but replacing one with this
+    return pConv;
+  }
+  return CAlphBase::RebuildSymbol(pParent, iLbnd, iHbnd, strGroup, iBkgCol, iSymbol);
+}
+
+bool CMandarinAlphMgr::CMandSym::isInGroup(const SGroupInfo *pGroup) {
+  //TODO m_pyParent should have been computed in RebuildParent()
+  DASHER_ASSERT(m_pyParent!=0);
+  //pinyin group contains the pinyin-"symbol"=CConvRoot which we want to be our parent...
+  return pGroup->iStart <= m_pyParent && pGroup->iEnd > m_pyParent;
 }
 
 const std::string &CMandarinAlphMgr::CMandSym::outputText() {
diff --git a/Src/DasherCore/MandarinAlphMgr.h b/Src/DasherCore/MandarinAlphMgr.h
index 881923f..47d610d 100644
--- a/Src/DasherCore/MandarinAlphMgr.h
+++ b/Src/DasherCore/MandarinAlphMgr.h
@@ -56,27 +56,32 @@ namespace Dasher {
       CMandarinAlphMgr *mgr() {return static_cast<CMandarinAlphMgr *>(CSymbolNode::mgr());}
       ///Symbol constructor: display text from CHAlphabet, colour from GetCHColour
       /// \param strGroup caption of any group(s) containing this symbol for which no nodes created; prepended to display text.
-      CMandSym(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, CMandarinAlphMgr *pMgr, symbol iSymbol);
-      ///Rebuilding not supported
-      virtual CDasherNode *RebuildParent() {return 0;}
+      CMandSym(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, CMandarinAlphMgr *pMgr, symbol iSymbol, symbol pyParent);
+    protected:
+      CDasherNode *RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSymbol);
+      bool isInGroup(const SGroupInfo *pGroup);
     private:
       virtual const std::string &outputText();
+      ///The Pinyin symbol used to produce this chinese symbol, if known (0 if not!)
+      symbol m_pyParent;
     };
-    ///Offers a choice between a set of chinese symbols, all corresponding to a single PY symbol.
-    /// Relative sizes of the CH symbols is obtained by CPPMPYLanguageModel::GetPartProbs, passing
-    /// the set of possible CH symbols.
-    class CConvRoot : public CDasherNode {
+      ///Offers a choice between a set of chinese symbols, all corresponding to a single PY symbol.
+      /// Relative sizes of the CH symbols is obtained by CPPMPYLanguageModel::GetPartProbs, passing
+      /// the set of possible CH symbols.
+      class CConvRoot : public CAlphBase {
     public:
-      CMandarinAlphMgr *mgr() {return m_pMgr;}
       /// \param pySym symbol in pinyin alphabet; must have >1 possible chinese conversion.
       CConvRoot(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, CMandarinAlphMgr *pMgr, symbol pySym);
+      CMandarinAlphMgr *mgr() {return static_cast<CMandarinAlphMgr *>(CAlphBase::mgr());}
       void PopulateChildren();
       int ExpectedNumChildren();
       CLanguageModel::Context iContext;
       void SetFlag(int iFlag, bool bValue);
+      CDasherNode *RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSymbol);
+    protected:
+      bool isInGroup(const SGroupInfo *pGroup);
     private:        
       std::vector<std::pair<symbol, unsigned int> > m_vChInfo;
-      CMandarinAlphMgr *m_pMgr;
       symbol m_pySym;
     };
     ///Called to create the node for a pinyin leaf symbol;
@@ -97,7 +102,8 @@ namespace Dasher {
     /// \param iContext parent node's context, from which to generate context for this node
     /// \param strGroup caption of any elided groups (prepended to this node's caption)
     /// \param iCHsym symbol number in chinese alphabet
-    CMandSym *CreateCHSymbol(CDasherNode *pParent, CLanguageModel::Context iContext, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, symbol iCHsym);
+    /// \param pyParent pinyin-alphabet symbol which was used to enter this chinese symbol (if known, else 0)
+    CMandSym *CreateCHSymbol(CDasherNode *pParent, CLanguageModel::Context iContext, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, symbol iCHsym, symbol pyParent);
 
     void AssignSizes(std::vector<std::pair<symbol,unsigned int> > &vChildren, Dasher::CLanguageModel::Context context);
 



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