[dasher: 59/217] Completely customized control box - all commands are parsed from control.xml



commit 67b6544e9af8426c8b92c63ccc05d6cdb3d9c394
Author: ipomoena <amajorek google com>
Date:   Tue Oct 13 18:19:42 2015 -0700

    Completely customized control box - all commands are parsed from control.xml

 Data/control/control.dtd          |   18 ++-
 Src/DasherCore/ControlManager.cpp |  242 ++++++++++++++++++++-----------------
 Src/DasherCore/ControlManager.h   |   32 +----
 3 files changed, 150 insertions(+), 142 deletions(-)
---
diff --git a/Data/control/control.dtd b/Data/control/control.dtd
index 28a5b79..5d9c428 100644
--- a/Data/control/control.dtd
+++ b/Data/control/control.dtd
@@ -1,7 +1,7 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="utf-8"?>
 <!ELEMENT nodes (node*)>
 
-<!ELEMENT node ((node|move|delete|ref|root|alph)*)>
+<!ELEMENT node ((node|move|delete|copy|speak|pause|stop|ref|root|alph)*)>
 <!--by specifying the name attribute as type ID rather than CDATA, the XML
     validator checks that all IDs are distinct:-->
 <!ATTLIST node name ID #IMPLIED>
@@ -10,11 +10,21 @@
 
 <!ELEMENT move EMPTY>
 <!ATTLIST move forward (yes|no) #REQUIRED>
-<!ATTLIST move dist (char|word|line|file) #REQUIRED>
+<!ATTLIST move dist (char|word|line|sentence|paragraph|file) #REQUIRED>
 
 <!ELEMENT delete EMPTY>
 <!ATTLIST delete forward (yes|no) #REQUIRED>
-<!ATTLIST delete dist (char|word|line|file) #REQUIRED>
+<!ATTLIST delete dist (char|word|line|sentence|paragraph|file) #REQUIRED>
+
+<!ELEMENT copy EMPTY>
+<!ATTLIST copy dist (all|new|repeat|sentence|paragraph) #REQUIRED>
+
+<!ELEMENT speak EMPTY>
+<!ATTLIST speak what (cancel|all|new|repeat|sentence|paragraph) #REQUIRED>
+
+<!ELEMENT pause EMPTY>
+
+<!ELEMENT stop EMPTY>
 
 <!ELEMENT ref EMPTY>
 <!--by specifying the name attribute as type IDREF rather than CDATA, the XML
diff --git a/Src/DasherCore/ControlManager.cpp b/Src/DasherCore/ControlManager.cpp
index c7342e6..855ad79 100644
--- a/Src/DasherCore/ControlManager.cpp
+++ b/Src/DasherCore/ControlManager.cpp
@@ -236,30 +236,129 @@ void CControlParser::XmlEndHandler(const XML_Char *szName) {
   }
 }
 
+class Dasher::SpeechHeader : public CDasherInterfaceBase::TextAction{
+public:
+  SpeechHeader(CDasherInterfaceBase *pIntf) : TextAction(pIntf) {}
+  void operator()(const std::string &strText) {
+    m_pIntf->Speak(strText, false);
+  }
+};
+
+class Dasher::CopyHeader : public CDasherInterfaceBase::TextAction{
+public:
+  CopyHeader(CDasherInterfaceBase *pIntf) : TextAction(pIntf) {}
+  void operator()(const std::string &strText) {
+    m_pIntf->CopyToClipboard(strText);
+  }
+};
+
+class Pause : public CControlBase::Action{
+public:
+  void happen(CControlBase::CContNode *pNode) {
+    pNode->mgr()->GetDasherInterface()->GetActiveInputMethod()->pause();
+  }
+};
+
+class SpeakCancel : public CControlBase::Action {
+public:
+  void happen(CControlBase::CContNode *pNode) {
+    pNode->mgr()->GetDasherInterface()->Speak("", true);
+  }
+};
+
+template <typename T> class MethodAction : public CControlBase::Action {
+public:
+  ///A "Method" is pointer to a function "void X()", that is a member of a T...
+  typedef void (T::*Method)();
+  MethodAction(T *pRecv, Method f) : m_pRecv(pRecv), m_f(f) {
+  }
+  virtual void happen(CControlBase::CContNode *pNode) {
+    //invoke pointer-to-member-function m_f on object *m_pRecv!
+    (m_pRecv->*m_f)();
+  }
+private:
+  T *m_pRecv;
+  Method m_f;
+};
+
+class Delete : public CControlBase::Action {
+  const bool m_bForwards;
+  const CControlManager::EditDistance m_dist;
+public:
+  Delete(bool bForwards, CControlManager::EditDistance dist) : m_bForwards(bForwards), m_dist(dist)  {
+  }
+  virtual void happen(CControlBase::CContNode *pNode) {
+    pNode->mgr()->GetDasherInterface()->ctrlDelete(m_bForwards, m_dist);
+  }
+};
+
+class Move : public CControlBase::Action {
+  const bool m_bForwards;
+  const CControlManager::EditDistance m_dist;
+public:
+  Move(bool bForwards, CControlManager::EditDistance dist) : m_bForwards(bForwards), m_dist(dist)  {
+  }
+  virtual void happen(CControlBase::CContNode *pNode) {
+    pNode->mgr()->GetDasherInterface()->ctrlMove(m_bForwards, m_dist);
+  }
+};
+
+
 CControlManager::CControlManager(CSettingsUser *pCreateFrom, CNodeCreationManager *pNCManager, 
CDasherInterfaceBase *pInterface)
 : CControlParser(pInterface), CControlBase(pCreateFrom, pInterface, pNCManager), 
CSettingsObserver(pCreateFrom), m_pSpeech(NULL), m_pCopy(NULL) {
   //TODO, used to be able to change label+colour of root/pause/stop from controllabels.xml
   // (or, get the root node title "control" from the alphabet!)
+  m_pSpeech = new SpeechHeader(pInterface);
+  m_pCopy = new CopyHeader(pInterface);
   SetRootTemplate(new NodeTemplate("",8)); //default NodeTemplate does nothing
   GetRootTemplate()->successors.push_back(NULL);
 
-  m_pPause = new Pause("Pause",241);
-  m_pPause->successors.push_back(NULL);
-  m_pPause->successors.push_back(GetRootTemplate());
-  m_pStop = new MethodTemplate<CDasherInterfaceBase>(_("Done"), 242, pInterface, 
&CDasherInterfaceBase::Done);
-  m_pStop->successors.push_back(NULL);
-  m_pStop->successors.push_back(GetRootTemplate());
+  // Key in actions map is name plus arguments in alphabetical order.
+  m_actions["stop"] = new MethodAction<CDasherInterfaceBase>(pInterface, &CDasherInterfaceBase::Done);
+  m_actions["pause"] = new Pause();
+
+  m_actions["speak what=cancel"] = new SpeakCancel();
+  m_actions["speak what=all"] = new MethodAction<SpeechHeader>(m_pSpeech, &SpeechHeader::executeOnAll);
+  m_actions["speak what=new"] = new MethodAction<SpeechHeader>(m_pSpeech, &SpeechHeader::executeOnNew);
+  m_actions["speak what=repeat"] = new MethodAction<SpeechHeader>(m_pSpeech, &SpeechHeader::executeLast);
+
+  m_actions["copy what=all"] = new MethodAction<CopyHeader>(m_pCopy, &CopyHeader::executeOnAll);
+  m_actions["copy what=new"] = new MethodAction<CopyHeader>(m_pCopy, &CopyHeader::executeOnNew);
+  m_actions["copy what=repeat"] = new MethodAction<CopyHeader>(m_pCopy, &CopyHeader::executeLast);
+
+  m_actions["move dist=char forward=yes"] = new Move(true, EDIT_CHAR);
+  m_actions["move dist=word forward=yes"] = new Move(true, EDIT_WORD);
+  m_actions["move dist=line forward=yes"] = new Move(true, EDIT_LINE);
+  m_actions["move dist=sentence forward=yes"] = new Move(true, EDIT_SENTENCE);
+  m_actions["move dist=paragraph forward=yes"] = new Move(true, EDIT_PARAGRAPH);
+  m_actions["move dist=file forward=yes"] = new Move(true, EDIT_FILE);
+
+  m_actions["move dist=char forward=no"] = new Move(true, EDIT_CHAR);
+  m_actions["move dist=word forward=no"] = new Move(true, EDIT_WORD);
+  m_actions["move dist=line forward=no"] = new Move(true, EDIT_LINE);
+  m_actions["move dist=sentence forward=no"] = new Move(true, EDIT_SENTENCE);
+  m_actions["move dist=paragraph forward=no"] = new Move(true, EDIT_PARAGRAPH);
+  m_actions["move dist=file forward=no"] = new Move(true, EDIT_FILE);
+
+  m_actions["delete dist=char forward=yes"] = new Delete(true, EDIT_CHAR);
+  m_actions["delete dist=word forward=yes"] = new Delete(true, EDIT_WORD);
+  m_actions["delete dist=line forward=yes"] = new Delete(true, EDIT_LINE);
+  m_actions["delete dist=sentence forward=yes"] = new Delete(true, EDIT_SENTENCE);
+  m_actions["delete dist=paragraph forward=yes"] = new Delete(true, EDIT_PARAGRAPH);
+  m_actions["delete dist=file forward=yes"] = new Delete(true, EDIT_FILE);
+
+  m_actions["delete dist=char forward=no"] = new Delete(true, EDIT_CHAR);
+  m_actions["delete dist=word forward=no"] = new Delete(true, EDIT_WORD);
+  m_actions["delete dist=line forward=no"] = new Delete(true, EDIT_LINE);
+  m_actions["delete dist=sentence forward=no"] = new Delete(true, EDIT_SENTENCE);
+  m_actions["delete dist=paragraph forward=no"] = new Delete(true, EDIT_PARAGRAPH);
+  m_actions["delete dist=file forward=no"] = new Delete(true, EDIT_FILE);
 
   m_pInterface->ScanFiles(this, "control.xml"); //just look for the one
 
   updateActions();
 }
 
-CControlBase::Pause::Pause(const string &strLabel, int iColour) : NodeTemplate(strLabel,iColour) {
-}
-void CControlBase::Pause::happen(CContNode *pNode) {
-  pNode->mgr()->m_pInterface->GetActiveInputMethod()->pause();
-}
 
 CControlBase::NodeTemplate *CControlManager::parseOther(const XML_Char *name, const XML_Char **atts) {
   if (strcmp(name,"root")==0) return GetRootTemplate();
@@ -267,117 +366,30 @@ CControlBase::NodeTemplate *CControlManager::parseOther(const XML_Char *name, co
 }
 
 CControlBase::Action *CControlManager::parseAction(const XML_Char *name, const XML_Char **atts) {
-  if (strcmp(name,"delete")==0 || strcmp(name,"move")==0) {
-    bool bForwards=true; //pick some defaults...
-    EditDistance dist=EDIT_WORD; // (?!)
-    while (*atts) {
-      if (strcmp(*atts,"forward")==0)
-        bForwards=(strcmp(*(atts+1),"yes")==0 || strcmp(*(atts+1),"true")==0 || strcmp(*(atts+1),"on")==0);
-      else if (strcmp(*atts,"dist")==0) {
-        if (strcmp(*(atts+1),"char")==0)
-          dist=EDIT_CHAR;
-        else if (strcmp(*(atts+1),"word")==0)
-          dist=EDIT_WORD;
-        else if (strcmp(*(atts+1),"line")==0)
-          dist = EDIT_LINE;
-        else if (strcmp(*(atts + 1), "sentence") == 0)
-          dist = EDIT_SENTENCE;
-        else if (strcmp(*(atts + 1), "paragraph") == 0)
-          dist = EDIT_PARAGRAPH;
-        else if (strcmp(*(atts + 1), "file") == 0)
-          dist = EDIT_FILE;
-      }
-      atts+=2;
-    }
-    class DirDist {
-    protected:
-      const bool m_bForwards;
-      const EditDistance m_dist;
-    public:
-      DirDist(bool bForwards,EditDistance dist) : m_bForwards(bForwards), m_dist(dist) {
-      }
-    };
-
-    if (name[0]=='d') {
-      class Delete : private DirDist, public Action {
-      public:
-        Delete(bool bForwards,EditDistance dist) : DirDist(bForwards,dist) {
-        }
-        void happen(CContNode *pNode) {
-          static_cast<CControlManager*>(pNode->mgr())->m_pInterface->ctrlDelete(m_bForwards,m_dist);
-        }
-      };
-      return new Delete(bForwards,dist);
-    } else {
-      class Move : private DirDist, public Action {
-      public:
-        Move(bool bForwards,EditDistance dist) : DirDist(bForwards, dist) {}
-        void happen(CContNode *pNode) {
-          static_cast<CControlManager*>(pNode->mgr())->m_pInterface->ctrlMove(m_bForwards,m_dist);
-        };
-      };
-      return new Move(bForwards, dist);
+  map<string, string> arguments;
+  while (*atts) {
+    arguments[*atts] = *(atts + 1);
+    atts += 2;
+  }
+  stringstream key;
+  // Key in actions map is name plus arguments in alphabetical order.
+  key << name;
+  if (!arguments.empty()) {
+    for each (auto arg in arguments) {
+      key << " " << arg.first << "=" << arg.second;
     }
   }
+  if (auto action = m_actions[key.str()])
+    return action;
+
   return CControlParser::parseAction(name, atts);
 }
 
 CControlManager::~CControlManager() {
 }
 
-class TextActionHeader : public CDasherInterfaceBase::TextAction, public CControlBase::NodeTemplate {
-public:
-  TextActionHeader(CDasherInterfaceBase *pIntf, const string &strHdr, NodeTemplate *pRoot) : 
TextAction(pIntf), NodeTemplate(strHdr,-1),
-  m_all("All", -1, this, &CDasherInterfaceBase::TextAction::executeOnAll),
-  m_new("New", -1, this, &CDasherInterfaceBase::TextAction::executeOnNew),
-  m_again("Repeat", -1, this, &CDasherInterfaceBase::TextAction::executeLast) {
-    successors.push_back(&m_all); m_all.successors.push_back(NULL); m_all.successors.push_back(pRoot);
-    successors.push_back(&m_new); m_new.successors.push_back(NULL); m_new.successors.push_back(pRoot);
-    successors.push_back(&m_again); m_again.successors.push_back(NULL); m_again.successors.push_back(pRoot);
-  }
-private:
-  CControlBase::MethodTemplate<CDasherInterfaceBase::TextAction> m_all, m_new, m_again;
-};
-
-class CancelSpeech : public CControlBase::NodeTemplate {
-public:
-  CancelSpeech(CDasherInterfaceBase *pIntf, const std::string &strLabel, int iColour) 
-    : NodeTemplate(strLabel, iColour), m_pIntf(pIntf){}
-
-    void happen(CControlBase::CContNode *pNode) {
-    m_pIntf->Speak("", true);
-    }
-    CDasherInterfaceBase *m_pIntf;
-};
-
-class SpeechHeader : public TextActionHeader {
-public:
-  SpeechHeader(CDasherInterfaceBase *pIntf, NodeTemplate *pRoot) 
-    : TextActionHeader(pIntf, "Speak", pRoot), m_stop(pIntf,"Cancel",242){
-    successors.push_back(&m_stop); m_stop.successors.push_back(NULL); m_stop.successors.push_back(pRoot);
-  }
-  void operator()(const std::string &strText) {
-    m_pIntf->Speak(strText, false);
-  }
-private:
-  CancelSpeech m_stop;
-};
-
-class CopyHeader  : public TextActionHeader {
-public:
-  CopyHeader(CDasherInterfaceBase *pIntf, NodeTemplate *pRoot) : TextActionHeader(pIntf, "Copy", pRoot) {
-  }
-  void operator()(const std::string &strText) {
-    m_pIntf->CopyToClipboard(strText);
-  }
-};
-
 void CControlManager::HandleEvent(int iParameter) {
   switch (iParameter) {
-    case BP_CONTROL_MODE_HAS_HALT:
-    case BP_CONTROL_MODE_HAS_EDIT:
-    case BP_CONTROL_MODE_HAS_SPEECH:
-    case BP_CONTROL_MODE_HAS_COPY:
     case BP_COPY_ALL_ON_STOP:
     case BP_SPEAK_ALL_ON_STOP:
     case SP_INPUT_FILTER:
@@ -386,6 +398,10 @@ void CControlManager::HandleEvent(int iParameter) {
 }
 
 void CControlManager::updateActions() {
+  // decide if removal of pause and stop are worth the trouble 
+  // reimplement if yes 
+  // imo with control.xml it isn't.
+  /*
   vector<NodeTemplate *> &vRootSuccessors(GetRootTemplate()->successors);
   vector<NodeTemplate *> vOldRootSuccessors;
   vOldRootSuccessors.swap(vRootSuccessors);
@@ -428,7 +444,7 @@ void CControlManager::updateActions() {
 
   //copy anything else (custom) that might have been added...
   while (it != vOldRootSuccessors.end()) vRootSuccessors.push_back(*it++);
-  
+  */
   if (CDasherScreen *pScreen = m_pScreen) {
     //hack to make ChangeScreen do something
     m_pScreen = NULL; //i.e. make it think the screen has changed
diff --git a/Src/DasherCore/ControlManager.h b/Src/DasherCore/ControlManager.h
index d83e54d..88c92d9 100644
--- a/Src/DasherCore/ControlManager.h
+++ b/Src/DasherCore/ControlManager.h
@@ -46,6 +46,8 @@ class CNodeCreationManager;
 namespace Dasher {
 
   class CDasherInterfaceBase;
+  class SpeechHeader;
+  class CopyHeader;
 
   /// \ingroup Model
   /// @{
@@ -94,27 +96,6 @@ namespace Dasher {
       CDasherScreen::Label *m_pLabel;
     };
 
-    class Pause : public NodeTemplate {
-    public:
-      Pause(const std::string &strLabel, int iColour);
-      void happen(CContNode *pNode);
-    };
-
-    template <typename T> class MethodTemplate : public NodeTemplate {
-    public:
-      ///A "Method" is pointer to a function "void X()", that is a member of a T...
-      typedef void (T::*Method)();
-      MethodTemplate(const std::string &strLabel, int color, T *pRecv, Method f) : 
NodeTemplate(strLabel,color),m_pRecv(pRecv),m_f(f) {
-      }
-      virtual void happen(CContNode *pNode) {
-        //invoke pointer-to-member-function m_f on object *m_pRecv!
-        (m_pRecv->*m_f)();
-      }
-    private:
-      T *m_pRecv;
-      Method m_f;
-    };
-
     NodeTemplate *GetRootTemplate();
 
     CControlBase(CSettingsUser *pCreateFrom, CDasherInterfaceBase *pInterface, CNodeCreationManager 
*pNCManager);
@@ -127,7 +108,7 @@ namespace Dasher {
     ///
 
     virtual CDasherNode *GetRoot(CDasherNode *pContext, int iOffset);
-
+    CDasherInterfaceBase* GetDasherInterface() { return m_pInterface; }
   protected:
     ///Sets the root - should be called by subclass constructor to make
     /// superclass ready for use.
@@ -220,9 +201,10 @@ namespace Dasher {
     Action *parseAction(const XML_Char *name, const XML_Char **atts);
 
   private:
-    NodeTemplate *m_pPause, *m_pStop;
-    ///group headers, with three children each (all/new/repeat)
-    NodeTemplate *m_pSpeech, *m_pCopy;
+    map<string, CControlBase::Action*> m_actions;
+    ///group of state full actions (all/new/repeat/...)
+    SpeechHeader *m_pSpeech;
+    CopyHeader *m_pCopy;
   };
   /// @}
 }


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