tagging release
[dasher.git] / trunk / Src / DasherCore / ControlManager.cpp
blobef9f659609816cf2c8800eaea4f2e8806c3f4ec0
1 // ControlManager.cpp
2 //
3 // Copyright (c) 2007 The Dasher Team
4 //
5 // This file is part of Dasher.
6 //
7 // Dasher is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
12 // Dasher is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with Dasher; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "../Common/Common.h"
23 #include "ControlManager.h"
24 using namespace Dasher;
25 using namespace std;
26 // Track memory leaks on Windows to the line that new'd the memory
27 #ifdef _WIN32
28 #ifdef _DEBUG_MEMLEAKS
29 #define DEBUG_NEW new( _NORMAL_BLOCK, THIS_FILE, __LINE__ )
30 #define new DEBUG_NEW
31 #undef THIS_FILE
32 static char THIS_FILE[] = __FILE__;
33 #endif
34 #endif
36 int CControlManager::m_iNextID = 0;
38 CControlManager::CControlManager( CNodeCreationManager *pNCManager )
39 : CNodeManager(1), m_pNCManager(pNCManager), m_pLanguageModel(NULL) {
40 string SystemString = m_pNCManager->GetStringParameter(SP_SYSTEM_LOC);
41 string UserLocation = m_pNCManager->GetStringParameter(SP_USER_LOC);
42 m_iNextID = 0;
43 struct stat sFileInfo;
44 string strFileName = UserLocation + "controllabels.xml"; // check first location for file
45 if(stat(strFileName.c_str(), &sFileInfo) == -1) {
46 // something went wrong
47 strFileName = SystemString + "controllabels.xml"; // check second location for file
48 if(stat(strFileName.c_str(), &sFileInfo) == -1) {
49 // all else fails do something default
50 LoadDefaultLabels();
52 else
53 LoadLabelsFromFile(strFileName, sFileInfo.st_size);
55 else
56 LoadLabelsFromFile(strFileName, sFileInfo.st_size);
58 ConnectNodes();
61 int CControlManager::LoadLabelsFromFile(string strFileName, int iFileSize) {
63 // Implement Unicode names via xml from file:
64 char* szFileBuffer = new char[iFileSize];
65 ifstream oFile(strFileName.c_str());
66 oFile.read(szFileBuffer, iFileSize);
67 XML_Parser Parser = XML_ParserCreate(NULL);
69 // Members passed as callbacks must be static, so don't have a "this" pointer.
70 // We give them one through horrible casting so they can effect changes.
71 XML_SetUserData(Parser, this);
73 XML_SetElementHandler(Parser, XmlStartHandler, XmlEndHandler);
74 XML_SetCharacterDataHandler(Parser, XmlCDataHandler);
75 XML_Parse(Parser, szFileBuffer, iFileSize, false);
76 // deallocate resources
77 XML_ParserFree(Parser);
78 oFile.close();
79 delete [] szFileBuffer;
80 return 0;
83 int CControlManager::LoadDefaultLabels() {
84 // TODO: Need to figure out how to handle offset changes here
86 RegisterNode(CTL_ROOT, "Control", 8);
87 RegisterNode(CTL_STOP, "Stop", 242);
88 RegisterNode(CTL_PAUSE, "Pause", 241);
89 RegisterNode(CTL_MOVE, "Move", -1);
90 RegisterNode(CTL_MOVE_FORWARD, "->", -1);
91 RegisterNode(CTL_MOVE_FORWARD_CHAR, ">", -1);
92 RegisterNode(CTL_MOVE_FORWARD_WORD, ">>", -1);
93 RegisterNode(CTL_MOVE_FORWARD_LINE, ">>>", -1);
94 RegisterNode(CTL_MOVE_FORWARD_FILE, ">>>>", -1);
95 RegisterNode(CTL_MOVE_BACKWARD, "<-", -1);
96 RegisterNode(CTL_MOVE_BACKWARD_CHAR, "<", -1);
97 RegisterNode(CTL_MOVE_BACKWARD_WORD, "<<", -1);
98 RegisterNode(CTL_MOVE_BACKWARD_LINE, "<<<", -1);
99 RegisterNode(CTL_MOVE_BACKWARD_FILE, "<<<<", -1);
100 RegisterNode(CTL_DELETE, "Delete", -1);
101 RegisterNode(CTL_DELETE_FORWARD, "->", -1);
102 RegisterNode(CTL_DELETE_FORWARD_CHAR, ">", -1);
103 RegisterNode(CTL_DELETE_FORWARD_WORD, ">>", -1);
104 RegisterNode(CTL_DELETE_FORWARD_LINE, ">>>", -1);
105 RegisterNode(CTL_DELETE_FORWARD_FILE, ">>>>", -1);
106 RegisterNode(CTL_DELETE_BACKWARD, "<-", -1);
107 RegisterNode(CTL_DELETE_BACKWARD_CHAR, "<", -1);
108 RegisterNode(CTL_DELETE_BACKWARD_WORD, "<<", -1);
109 RegisterNode(CTL_DELETE_BACKWARD_LINE, "<<<", -1);
110 RegisterNode(CTL_DELETE_BACKWARD_FILE, "<<<<", -1);
111 return 0;
114 int CControlManager::ConnectNodes() {
115 ConnectNode(-1, CTL_ROOT, -2);
116 ConnectNode(CTL_STOP, CTL_ROOT, -2);
117 ConnectNode(CTL_PAUSE, CTL_ROOT, -2);
118 ConnectNode(CTL_MOVE, CTL_ROOT, -2);
119 ConnectNode(CTL_DELETE, CTL_ROOT, -2);
121 ConnectNode(-1, CTL_STOP, -2);
122 ConnectNode(CTL_ROOT, CTL_STOP, -2);
124 ConnectNode(-1, CTL_PAUSE, -2);
125 ConnectNode(CTL_ROOT, CTL_PAUSE, -2);
127 ConnectNode(CTL_MOVE_FORWARD, CTL_MOVE, -2);
128 ConnectNode(CTL_MOVE_BACKWARD, CTL_MOVE, -2);
130 ConnectNode(CTL_MOVE_FORWARD_CHAR, CTL_MOVE_FORWARD, -2);
131 ConnectNode(CTL_MOVE_FORWARD_WORD, CTL_MOVE_FORWARD, -2);
132 ConnectNode(CTL_MOVE_FORWARD_LINE, CTL_MOVE_FORWARD, -2);
133 ConnectNode(CTL_MOVE_FORWARD_FILE, CTL_MOVE_FORWARD, -2);
135 ConnectNode(CTL_ROOT, CTL_MOVE_FORWARD_CHAR, -2);
136 ConnectNode(CTL_MOVE_FORWARD, CTL_MOVE_FORWARD_CHAR, -2);
137 ConnectNode(CTL_MOVE_BACKWARD, CTL_MOVE_FORWARD_CHAR, -2);
139 ConnectNode(CTL_ROOT, CTL_MOVE_FORWARD_WORD, -2);
140 ConnectNode(CTL_MOVE_FORWARD, CTL_MOVE_FORWARD_WORD, -2);
141 ConnectNode(CTL_MOVE_BACKWARD, CTL_MOVE_FORWARD_WORD, -2);
143 ConnectNode(CTL_ROOT, CTL_MOVE_FORWARD_LINE, -2);
144 ConnectNode(CTL_MOVE_FORWARD, CTL_MOVE_FORWARD_LINE, -2);
145 ConnectNode(CTL_MOVE_BACKWARD, CTL_MOVE_FORWARD_LINE, -2);
147 ConnectNode(CTL_ROOT, CTL_MOVE_FORWARD_FILE, -2);
148 ConnectNode(CTL_MOVE_FORWARD, CTL_MOVE_FORWARD_FILE, -2);
149 ConnectNode(CTL_MOVE_BACKWARD, CTL_MOVE_FORWARD_FILE, -2);
151 ConnectNode(CTL_MOVE_BACKWARD_CHAR, CTL_MOVE_BACKWARD, -2);
152 ConnectNode(CTL_MOVE_BACKWARD_WORD, CTL_MOVE_BACKWARD, -2);
153 ConnectNode(CTL_MOVE_BACKWARD_LINE, CTL_MOVE_BACKWARD, -2);
154 ConnectNode(CTL_MOVE_BACKWARD_FILE, CTL_MOVE_BACKWARD, -2);
156 ConnectNode(CTL_ROOT, CTL_MOVE_BACKWARD_CHAR, -2);
157 ConnectNode(CTL_MOVE_FORWARD, CTL_MOVE_BACKWARD_CHAR, -2);
158 ConnectNode(CTL_MOVE_BACKWARD, CTL_MOVE_BACKWARD_CHAR, -2);
160 ConnectNode(CTL_ROOT, CTL_MOVE_BACKWARD_WORD, -2);
161 ConnectNode(CTL_MOVE_FORWARD, CTL_MOVE_BACKWARD_WORD, -2);
162 ConnectNode(CTL_MOVE_BACKWARD, CTL_MOVE_BACKWARD_WORD, -2);
164 ConnectNode(CTL_ROOT, CTL_MOVE_BACKWARD_LINE, -2);
165 ConnectNode(CTL_MOVE_FORWARD, CTL_MOVE_BACKWARD_LINE, -2);
166 ConnectNode(CTL_MOVE_BACKWARD, CTL_MOVE_BACKWARD_LINE, -2);
168 ConnectNode(CTL_ROOT, CTL_MOVE_BACKWARD_FILE, -2);
169 ConnectNode(CTL_MOVE_FORWARD, CTL_MOVE_BACKWARD_FILE, -2);
170 ConnectNode(CTL_MOVE_BACKWARD, CTL_MOVE_BACKWARD_FILE, -2);
172 ConnectNode(CTL_DELETE_FORWARD, CTL_DELETE, -2);
173 ConnectNode(CTL_DELETE_BACKWARD, CTL_DELETE, -2);
175 ConnectNode(CTL_DELETE_FORWARD_CHAR, CTL_DELETE_FORWARD, -2);
176 ConnectNode(CTL_DELETE_FORWARD_WORD, CTL_DELETE_FORWARD, -2);
177 ConnectNode(CTL_DELETE_FORWARD_LINE, CTL_DELETE_FORWARD, -2);
178 ConnectNode(CTL_DELETE_FORWARD_FILE, CTL_DELETE_FORWARD, -2);
180 ConnectNode(CTL_ROOT, CTL_DELETE_FORWARD_CHAR, -2);
181 ConnectNode(CTL_DELETE_FORWARD, CTL_DELETE_FORWARD_CHAR, -2);
182 ConnectNode(CTL_DELETE_BACKWARD, CTL_DELETE_FORWARD_CHAR, -2);
184 ConnectNode(CTL_ROOT, CTL_DELETE_FORWARD_WORD, -2);
185 ConnectNode(CTL_DELETE_FORWARD, CTL_DELETE_FORWARD_WORD, -2);
186 ConnectNode(CTL_DELETE_BACKWARD, CTL_DELETE_FORWARD_WORD, -2);
188 ConnectNode(CTL_ROOT, CTL_DELETE_FORWARD_LINE, -2);
189 ConnectNode(CTL_DELETE_FORWARD, CTL_DELETE_FORWARD_LINE, -2);
190 ConnectNode(CTL_DELETE_BACKWARD, CTL_DELETE_FORWARD_LINE, -2);
192 ConnectNode(CTL_ROOT, CTL_DELETE_FORWARD_FILE, -2);
193 ConnectNode(CTL_DELETE_FORWARD, CTL_DELETE_FORWARD_FILE, -2);
194 ConnectNode(CTL_DELETE_BACKWARD, CTL_DELETE_FORWARD_FILE, -2);
196 ConnectNode(CTL_DELETE_BACKWARD_CHAR, CTL_DELETE_BACKWARD, -2);
197 ConnectNode(CTL_DELETE_BACKWARD_WORD, CTL_DELETE_BACKWARD, -2);
198 ConnectNode(CTL_DELETE_BACKWARD_LINE, CTL_DELETE_BACKWARD, -2);
199 ConnectNode(CTL_DELETE_BACKWARD_FILE, CTL_DELETE_BACKWARD, -2);
201 ConnectNode(CTL_ROOT, CTL_DELETE_BACKWARD_CHAR, -2);
202 ConnectNode(CTL_DELETE_FORWARD, CTL_DELETE_BACKWARD_CHAR, -2);
203 ConnectNode(CTL_DELETE_BACKWARD, CTL_DELETE_BACKWARD_CHAR, -2);
205 ConnectNode(CTL_ROOT, CTL_DELETE_BACKWARD_WORD, -2);
206 ConnectNode(CTL_DELETE_FORWARD, CTL_DELETE_BACKWARD_WORD, -2);
207 ConnectNode(CTL_DELETE_BACKWARD, CTL_DELETE_BACKWARD_WORD, -2);
209 ConnectNode(CTL_ROOT, CTL_DELETE_BACKWARD_LINE, -2);
210 ConnectNode(CTL_DELETE_FORWARD, CTL_DELETE_BACKWARD_LINE, -2);
211 ConnectNode(CTL_DELETE_BACKWARD, CTL_DELETE_BACKWARD_LINE, -2);
213 ConnectNode(CTL_ROOT, CTL_DELETE_BACKWARD_FILE, -2);
214 ConnectNode(CTL_DELETE_FORWARD, CTL_DELETE_BACKWARD_FILE, -2);
215 ConnectNode(CTL_DELETE_BACKWARD, CTL_DELETE_BACKWARD_FILE, -2);
216 return 0;
219 CControlManager::~CControlManager()
221 for(std::map<int,CControlNode*>::iterator i = m_mapControlMap.begin(); i != m_mapControlMap.end(); i++) {
222 CControlNode* pNewNode = i->second;
223 if (pNewNode != NULL) {
224 delete pNewNode;
225 pNewNode = NULL;
230 void CControlManager::RegisterNode( int iID, std::string strLabel, int iColour ) {
231 CControlNode *pNewNode;
233 pNewNode = new CControlNode; // FIXME - do constructor sanely
234 pNewNode->strLabel = strLabel;
235 pNewNode->iID = iID;
236 pNewNode->iColour = iColour;
238 m_mapControlMap[iID] = pNewNode;
241 void CControlManager::ConnectNode(int iChild, int iParent, int iAfter) {
243 // FIXME - iAfter currently ignored (eventually -1 = start, -2 = end)
245 if( iChild == -1 ) {// Corresponds to escaping back to alphabet
246 CControlNode* node = m_mapControlMap[iParent];
247 if(node)
248 node->vChildren.push_back(NULL);
250 else
251 m_mapControlMap[iParent]->vChildren.push_back(m_mapControlMap[iChild]);
254 void CControlManager::DisconnectNode(int iChild, int iParent) {
255 CControlNode* pParentNode = m_mapControlMap[iParent];
256 CControlNode* pChildNode = m_mapControlMap[iChild];
258 for(std::vector<CControlNode *>::iterator itChild(pParentNode->vChildren.begin()); itChild != pParentNode->vChildren.end(); ++itChild)
259 if(*itChild == pChildNode)
260 pParentNode->vChildren.erase(itChild);
264 CDasherNode *CControlManager::GetRoot(CDasherNode *pParent, int iLower, int iUpper, void *pUserData) {
265 CDasherNode *pNewNode;
267 // TODO: Tie this structure to info contained in control map
268 CDasherNode::SDisplayInfo *pDisplayInfo = new CDasherNode::SDisplayInfo;
269 pDisplayInfo->iColour = m_mapControlMap[0]->iColour;
270 pDisplayInfo->bShove = false;
271 pDisplayInfo->bVisible = true;
272 pDisplayInfo->strDisplayText = m_mapControlMap[0]->strLabel;
274 pNewNode = new CDasherNode(pParent, iLower, iUpper, pDisplayInfo);
276 int iOffset = *((int *)pUserData);
278 // FIXME - handle context properly
280 // pNewNode->SetContext(m_pLanguageModel->CreateEmptyContext());
282 pNewNode->m_pNodeManager = this;
284 SControlData *pNodeUserData = new SControlData;
286 pNodeUserData->pControlNode = m_mapControlMap[0];
287 pNodeUserData->iOffset = iOffset;
289 pNewNode->m_pUserData = pNodeUserData;
291 return pNewNode;
294 void CControlManager::PopulateChildren( CDasherNode *pNode ) {
295 CDasherNode *pNewNode;
297 CControlNode *pControlNode((static_cast<SControlData *>(pNode->m_pUserData))->pControlNode);
299 int iNChildren( pControlNode->vChildren.size() );
301 int iIdx(0);
303 for(std::vector<CControlNode *>::iterator it(pControlNode->vChildren.begin()); it != pControlNode->vChildren.end(); ++it) {
305 // FIXME - could do this better
307 int iLbnd( iIdx*(m_pNCManager->GetLongParameter(LP_NORMALIZATION)/iNChildren));
308 int iHbnd( (iIdx+1)*(m_pNCManager->GetLongParameter(LP_NORMALIZATION)/iNChildren));
310 if( *it == NULL ) {
311 // Escape back to alphabet
312 CAlphabetManager::SRootData *pRootData = new CAlphabetManager::SRootData;
314 // TODO: Check that these are eventually getting deleted
316 pRootData->iOffset = (static_cast<SControlData *>(pNode->m_pUserData))->iOffset;
317 pRootData->szContext = NULL; // TODO: Fix this
319 pNewNode = m_pNCManager->GetRoot(0, pNode, iLbnd, iHbnd, pRootData);
320 pNewNode->SetFlag(NF_SEEN, false);
322 else {
324 int iColour((*it)->iColour);
326 if( iColour == -1 ) {
327 iColour = (iIdx%99)+11;
330 CDasherNode::SDisplayInfo *pDisplayInfo = new CDasherNode::SDisplayInfo;
331 pDisplayInfo->iColour = iColour;
332 pDisplayInfo->bShove = false;
333 pDisplayInfo->bVisible = true;
334 pDisplayInfo->strDisplayText = (*it)->strLabel;
336 pNewNode = new CDasherNode(pNode, iLbnd, iHbnd, pDisplayInfo);
338 pNewNode->m_pNodeManager = this;
339 pNewNode->m_pUserData = *it;
341 SControlData *pNodeUserData = new SControlData;
343 pNodeUserData->pControlNode = *it;
344 pNodeUserData->iOffset = (static_cast<SControlData *>(pNode->m_pUserData))->iOffset;
346 pNewNode->m_pUserData = pNodeUserData;
349 pNode->Children().push_back(pNewNode);
350 ++iIdx;
354 void CControlManager::ClearNode( CDasherNode *pNode ) {
355 delete (static_cast<SControlData *>(pNode->m_pUserData));
358 void CControlManager::Output( CDasherNode *pNode, Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization ) {
360 CControlNode *pControlNode((static_cast<SControlData *>(pNode->m_pUserData))->pControlNode);
362 CControlEvent oEvent(pControlNode->iID);
363 // TODO: Need to reimplement this
364 // m_pNCManager->m_bContextSensitive=false;
365 m_pNCManager->InsertEvent(&oEvent);
368 void CControlManager::Undo( CDasherNode *pNode ) {
369 // Do we ever need this?
370 // 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
371 m_pNCManager->SetLongParameter(LP_SPEED_DIVISOR, 100);
372 //Re-enable auto speed control!
373 m_pNCManager->SetBoolParameter(BP_AUTO_SPEEDCONTROL, 1);
377 void CControlManager::Enter(CDasherNode *pNode) {
378 // Slow down to half the speed we were at
379 m_pNCManager->SetLongParameter(LP_SPEED_DIVISOR, 200);
380 //Disable auto speed control!
381 m_pNCManager->SetBoolParameter(BP_AUTO_SPEEDCONTROL, 0);
385 void CControlManager::Leave(CDasherNode *pNode) {
386 // Now speed back up, by doubling the speed we were at in control mode
387 m_pNCManager->SetLongParameter(LP_SPEED_DIVISOR, 100);
388 //Re-enable auto speed control!
389 m_pNCManager->SetBoolParameter(BP_AUTO_SPEEDCONTROL, 1);
393 void CControlManager::XmlStartHandler(void *pUserData, const XML_Char *szName, const XML_Char **aszAttr) {
395 int colour;
396 string str;
397 if(0==strcmp(szName, "label"))
399 for(int i = 0; aszAttr[i]; i += 2)
401 if(0==strcmp(aszAttr[i],"value"))
403 str = string(aszAttr[i+1]);
405 if(0==strcmp(aszAttr[i],"color"))
407 colour = atoi(aszAttr[i+1]);
410 ((CControlManager*)pUserData)->RegisterNode(CControlManager::m_iNextID++, str, colour);
415 void CControlManager::XmlEndHandler(void *pUserData, const XML_Char *szName) {
416 return;
419 void CControlManager::XmlCDataHandler(void *pUserData, const XML_Char *szData, int iLength){
420 return;
423 void CControlManager::SetControlOffset(CDasherNode *pNode, int iOffset) {
424 (static_cast<SControlData *>(pNode->m_pUserData))->iOffset = iOffset;