3 // Copyright (c) 2007 The Dasher Team
5 // This file is part of Dasher.
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
;
26 // Track memory leaks on Windows to the line that new'd the memory
28 #ifdef _DEBUG_MEMLEAKS
29 #define DEBUG_NEW new( _NORMAL_BLOCK, THIS_FILE, __LINE__ )
32 static char THIS_FILE
[] = __FILE__
;
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
);
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
53 LoadLabelsFromFile(strFileName
, sFileInfo
.st_size
);
56 LoadLabelsFromFile(strFileName
, sFileInfo
.st_size
);
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
);
79 delete [] szFileBuffer
;
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);
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);
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
) {
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
;
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
];
248 node
->vChildren
.push_back(NULL
);
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
;
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() );
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
));
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);
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
);
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
) {
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
) {
419 void CControlManager::XmlCDataHandler(void *pUserData
, const XML_Char
*szData
, int iLength
){
423 void CControlManager::SetControlOffset(CDasherNode
*pNode
, int iOffset
) {
424 (static_cast<SControlData
*>(pNode
->m_pUserData
))->iOffset
= iOffset
;