Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <tools/debug.hxx>
21 : #include <tools/rc.h>
22 :
23 : #include <vcl/svapp.hxx>
24 : #include <accel.h>
25 : #include <vcl/accel.hxx>
26 : #include <map>
27 : #include <vector>
28 :
29 : typedef ::std::map< sal_uLong, ImplAccelEntry* > ImplAccelMap;
30 : typedef ::std::vector< ImplAccelEntry* > ImplAccelList;
31 :
32 : #define ACCELENTRY_NOTFOUND ((sal_uInt16)0xFFFF)
33 :
34 0 : class ImplAccelData
35 : {
36 : public:
37 : ImplAccelMap maKeyMap; // for keycodes, generated with a code
38 : ImplAccelList maIdList; // Id-List
39 : };
40 :
41 0 : sal_uInt16 ImplAccelEntryGetIndex( ImplAccelList* pList, sal_uInt16 nId,
42 : sal_uInt16* pIndex = NULL )
43 : {
44 : size_t nLow;
45 : size_t nHigh;
46 : size_t nMid;
47 0 : size_t nCount = pList->size();
48 : sal_uInt16 nCompareId;
49 :
50 : // check if first key is larger then the key to compare
51 0 : if ( !nCount || (nId < (*pList)[ 0 ]->mnId) )
52 : {
53 0 : if ( pIndex )
54 0 : *pIndex = 0;
55 0 : return ACCELENTRY_NOTFOUND;
56 : }
57 :
58 : // Binairy search
59 0 : nLow = 0;
60 0 : nHigh = nCount-1;
61 0 : do
62 : {
63 0 : nMid = (nLow + nHigh) / 2;
64 0 : nCompareId = (*pList)[ nMid ]->mnId;
65 0 : if ( nId < nCompareId )
66 0 : nHigh = nMid-1;
67 : else
68 : {
69 0 : if ( nId > nCompareId )
70 0 : nLow = nMid + 1;
71 : else
72 0 : return (sal_uInt16)nMid;
73 : }
74 : }
75 : while ( nLow <= nHigh );
76 :
77 0 : if ( pIndex )
78 : {
79 0 : if ( nId > nCompareId )
80 0 : *pIndex = (sal_uInt16)(nMid+1);
81 : else
82 0 : *pIndex = (sal_uInt16)nMid;
83 : }
84 :
85 0 : return ACCELENTRY_NOTFOUND;
86 : }
87 :
88 0 : static void ImplAccelEntryInsert( ImplAccelList* pList, ImplAccelEntry* pEntry )
89 : {
90 : sal_uInt16 nInsIndex;
91 0 : sal_uInt16 nIndex = ImplAccelEntryGetIndex( pList, pEntry->mnId, &nInsIndex );
92 :
93 0 : if ( nIndex != ACCELENTRY_NOTFOUND )
94 : {
95 0 : do
96 : {
97 0 : nIndex++;
98 0 : ImplAccelEntry* pTempEntry = NULL;
99 0 : if ( nIndex < pList->size() )
100 0 : pTempEntry = (*pList)[ nIndex ];
101 0 : if ( !pTempEntry || (pTempEntry->mnId != pEntry->mnId) )
102 : break;
103 : }
104 0 : while ( nIndex < pList->size() );
105 :
106 0 : if ( nIndex < pList->size() ) {
107 0 : ImplAccelList::iterator it = pList->begin();
108 0 : ::std::advance( it, nIndex );
109 0 : pList->insert( it, pEntry );
110 : } else {
111 0 : pList->push_back( pEntry );
112 : }
113 : }
114 : else {
115 0 : if ( nInsIndex < pList->size() ) {
116 0 : ImplAccelList::iterator it = pList->begin();
117 0 : ::std::advance( it, nInsIndex );
118 0 : pList->insert( it, pEntry );
119 : } else {
120 0 : pList->push_back( pEntry );
121 : }
122 : }
123 0 : }
124 :
125 0 : static sal_uInt16 ImplAccelEntryGetFirstPos( ImplAccelList* pList, sal_uInt16 nId )
126 : {
127 0 : sal_uInt16 nIndex = ImplAccelEntryGetIndex( pList, nId );
128 0 : if ( nIndex != ACCELENTRY_NOTFOUND )
129 : {
130 0 : while ( nIndex )
131 : {
132 0 : nIndex--;
133 0 : if ( (*pList)[ nIndex ]->mnId != nId )
134 0 : break;
135 : }
136 :
137 0 : if ( (*pList)[ nIndex ]->mnId != nId )
138 0 : nIndex++;
139 : }
140 :
141 0 : return nIndex;
142 : }
143 :
144 0 : void Accelerator::ImplInit()
145 : {
146 0 : mnCurId = 0;
147 0 : mnCurRepeat = 0;
148 0 : mbIsCancel = false;
149 0 : mpDel = NULL;
150 0 : }
151 :
152 0 : ImplAccelEntry* Accelerator::ImplGetAccelData( const KeyCode& rKeyCode ) const
153 : {
154 0 : ImplAccelMap::iterator it = mpData->maKeyMap.find( rKeyCode.GetFullCode() );
155 0 : if( it != mpData->maKeyMap.end() )
156 0 : return it->second;
157 : else
158 0 : return NULL;
159 : }
160 :
161 0 : void Accelerator::ImplCopyData( ImplAccelData& rAccelData )
162 : {
163 : // copy table
164 0 : for ( size_t i = 0, n = rAccelData.maIdList.size(); i < n; ++i )
165 : {
166 0 : ImplAccelEntry* pEntry = new ImplAccelEntry( *rAccelData.maIdList[ i ] );
167 :
168 : // sequence accelerator, then copy also
169 0 : if ( pEntry->mpAccel )
170 : {
171 0 : pEntry->mpAccel = new Accelerator( *(pEntry->mpAccel) );
172 0 : pEntry->mpAutoAccel = pEntry->mpAccel;
173 : }
174 : else
175 0 : pEntry->mpAutoAccel = NULL;
176 :
177 0 : mpData->maKeyMap.insert( std::make_pair( pEntry->maKeyCode.GetFullCode(), pEntry ) );
178 0 : mpData->maIdList.push_back( pEntry );
179 : }
180 0 : }
181 :
182 0 : void Accelerator::ImplDeleteData()
183 : {
184 : // delete accelerator-entries using the id-table
185 0 : for ( size_t i = 0, n = mpData->maIdList.size(); i < n; ++i ) {
186 0 : ImplAccelEntry* pEntry = mpData->maIdList[ i ];
187 0 : if ( pEntry->mpAutoAccel ) {
188 0 : delete pEntry->mpAutoAccel;
189 : }
190 0 : delete pEntry;
191 : }
192 0 : mpData->maIdList.clear();
193 0 : }
194 :
195 0 : void Accelerator::ImplInsertAccel( sal_uInt16 nItemId, const KeyCode& rKeyCode,
196 : bool bEnable, Accelerator* pAutoAccel )
197 : {
198 : DBG_ASSERT( nItemId, "Accelerator::InsertItem(): ItemId == 0" );
199 :
200 0 : if ( rKeyCode.IsFunction() )
201 : {
202 : sal_uInt16 nCode1;
203 : sal_uInt16 nCode2;
204 : sal_uInt16 nCode3;
205 : sal_uInt16 nCode4;
206 0 : ImplGetKeyCode( rKeyCode.GetFunction(), nCode1, nCode2, nCode3, nCode4 );
207 0 : if ( nCode1 )
208 0 : ImplInsertAccel( nItemId, KeyCode( nCode1, nCode1 ), bEnable, pAutoAccel );
209 0 : if ( nCode2 )
210 : {
211 0 : if ( pAutoAccel )
212 0 : pAutoAccel = new Accelerator( *pAutoAccel );
213 0 : ImplInsertAccel( nItemId, KeyCode( nCode2, nCode2 ), bEnable, pAutoAccel );
214 0 : if ( nCode3 )
215 : {
216 0 : if ( pAutoAccel )
217 0 : pAutoAccel = new Accelerator( *pAutoAccel );
218 0 : ImplInsertAccel( nItemId, KeyCode( nCode3, nCode3 ), bEnable, pAutoAccel );
219 : }
220 : }
221 0 : return;
222 : }
223 :
224 : // fetch and fill new entries
225 0 : ImplAccelEntry* pEntry = new ImplAccelEntry;
226 0 : pEntry->mnId = nItemId;
227 0 : pEntry->maKeyCode = rKeyCode;
228 0 : pEntry->mpAccel = pAutoAccel;
229 0 : pEntry->mpAutoAccel = pAutoAccel;
230 0 : pEntry->mbEnabled = bEnable;
231 :
232 : // now into the tables
233 0 : sal_uLong nCode = rKeyCode.GetFullCode();
234 0 : if ( !nCode )
235 : {
236 : OSL_FAIL( "Accelerator::InsertItem(): KeyCode with KeyCode 0 not allowed" );
237 0 : delete pEntry;
238 : }
239 0 : else if ( !mpData->maKeyMap.insert( std::make_pair( nCode, pEntry ) ).second )
240 : {
241 : SAL_WARN( "vcl.layout", "Accelerator::InsertItem(): KeyCode (Key: " << nCode << ") already exists" );
242 0 : delete pEntry;
243 : }
244 : else
245 0 : ImplAccelEntryInsert( &(mpData->maIdList), pEntry );
246 : }
247 :
248 0 : Accelerator::Accelerator()
249 : {
250 :
251 0 : ImplInit();
252 0 : mpData = new ImplAccelData;
253 0 : }
254 :
255 0 : Accelerator::Accelerator( const Accelerator& rAccel ) :
256 : Resource(),
257 : maHelpStr( rAccel.maHelpStr ),
258 0 : maCurKeyCode( rAccel.maCurKeyCode )
259 : {
260 :
261 0 : ImplInit();
262 0 : mpData = new ImplAccelData;
263 0 : ImplCopyData( *((ImplAccelData*)(rAccel.mpData)) );
264 0 : }
265 :
266 0 : Accelerator::Accelerator( const ResId& rResId )
267 : {
268 :
269 0 : ImplInit();
270 0 : mpData = new ImplAccelData;
271 0 : rResId.SetRT( RSC_ACCEL );
272 0 : ImplLoadRes( rResId );
273 0 : }
274 :
275 0 : void Accelerator::ImplLoadRes( const ResId& rResId )
276 : {
277 0 : GetRes( rResId );
278 :
279 0 : maHelpStr = ReadStringRes();
280 0 : sal_uLong nObjFollows = ReadLongRes();
281 :
282 0 : for( sal_uLong i = 0; i < nObjFollows; i++ )
283 : {
284 0 : InsertItem( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) );
285 0 : IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
286 : }
287 0 : }
288 :
289 0 : Accelerator::~Accelerator()
290 : {
291 :
292 : // inform AccelManager about deleting the Accelerator
293 0 : if ( mpDel )
294 0 : *mpDel = true;
295 :
296 0 : ImplDeleteData();
297 0 : delete mpData;
298 0 : }
299 :
300 0 : void Accelerator::Activate()
301 : {
302 0 : maActivateHdl.Call( this );
303 0 : }
304 :
305 0 : void Accelerator::Deactivate()
306 : {
307 0 : maDeactivateHdl.Call( this );
308 0 : }
309 :
310 0 : void Accelerator::Select()
311 : {
312 0 : maSelectHdl.Call( this );
313 0 : }
314 :
315 0 : void Accelerator::InsertItem( sal_uInt16 nItemId, const KeyCode& rKeyCode )
316 : {
317 0 : ImplInsertAccel( nItemId, rKeyCode, true, NULL );
318 0 : }
319 :
320 0 : void Accelerator::InsertItem( const ResId& rResId )
321 : {
322 :
323 : sal_uLong nObjMask;
324 : sal_uInt16 nAccelKeyId;
325 : sal_uInt16 bDisable;
326 0 : KeyCode aKeyCode;
327 0 : Accelerator* pAutoAccel = NULL;
328 :
329 0 : GetRes( rResId.SetRT( RSC_ACCELITEM ) );
330 0 : nObjMask = ReadLongRes();
331 0 : nAccelKeyId = sal::static_int_cast<sal_uInt16>(ReadLongRes());
332 0 : bDisable = ReadShortRes();
333 :
334 0 : if ( nObjMask & ACCELITEM_KEY )
335 : {
336 : // new context was created
337 0 : RSHEADER_TYPE * pKeyCodeRes = (RSHEADER_TYPE *)GetClassRes();
338 0 : ResId aResId( pKeyCodeRes, *rResId.GetResMgr());
339 0 : aKeyCode = KeyCode( aResId );
340 0 : IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
341 : }
342 :
343 0 : if ( nObjMask & ACCELITEM_ACCEL )
344 : {
345 0 : pAutoAccel = new Accelerator( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) );
346 0 : IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
347 : }
348 :
349 0 : ImplInsertAccel( nAccelKeyId, aKeyCode, !bDisable, pAutoAccel );
350 0 : }
351 :
352 0 : sal_uInt16 Accelerator::GetItemCount() const
353 : {
354 :
355 0 : return (sal_uInt16)mpData->maIdList.size();
356 : }
357 :
358 0 : KeyCode Accelerator::GetKeyCode( sal_uInt16 nItemId ) const
359 : {
360 :
361 0 : sal_uInt16 nIndex = ImplAccelEntryGetFirstPos( &(mpData->maIdList), nItemId );
362 0 : if ( nIndex != ACCELENTRY_NOTFOUND )
363 0 : return mpData->maIdList[ nIndex ]->maKeyCode;
364 : else
365 0 : return KeyCode();
366 : }
367 :
368 0 : sal_uInt16 Accelerator::GetItemId( sal_uInt16 nPos ) const
369 : {
370 :
371 0 : ImplAccelEntry* pEntry = ( nPos < mpData->maIdList.size() ) ? mpData->maIdList[ nPos ] : NULL;
372 0 : if ( pEntry )
373 0 : return pEntry->mnId;
374 : else
375 0 : return 0;
376 : }
377 :
378 0 : Accelerator* Accelerator::GetAccel( sal_uInt16 nItemId ) const
379 : {
380 :
381 0 : sal_uInt16 nIndex = ImplAccelEntryGetIndex( &(mpData->maIdList), nItemId );
382 0 : if ( nIndex != ACCELENTRY_NOTFOUND )
383 0 : return mpData->maIdList[ nIndex ]->mpAccel;
384 : else
385 0 : return NULL;
386 : }
387 :
388 0 : Accelerator& Accelerator::operator=( const Accelerator& rAccel )
389 : {
390 :
391 : // assign new data
392 0 : maHelpStr = rAccel.maHelpStr;
393 0 : maCurKeyCode = KeyCode();
394 0 : mnCurId = 0;
395 0 : mnCurRepeat = 0;
396 0 : mbIsCancel = false;
397 :
398 : // delete and copy tables
399 0 : ImplDeleteData();
400 0 : mpData->maKeyMap.clear();
401 0 : ImplCopyData( *((ImplAccelData*)(rAccel.mpData)) );
402 :
403 0 : return *this;
404 : }
405 :
406 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|