update dev300-m58
[ooovba.git] / vcl / source / window / accel.cxx
blobe582e2a4369a8c942bc8a34700183f46208e6662
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: accel.cxx,v $
10 * $Revision: 1.11 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
33 #include <tools/list.hxx>
34 #ifndef _TABLE_HXX
35 #include <tools/table.hxx>
36 #endif
37 #include <tools/debug.hxx>
38 #include <vcl/svapp.hxx>
39 #include <vcl/accel.h>
40 #include <vcl/accel.hxx>
41 #ifndef _RC_H
42 #include <tools/rc.h>
43 #endif
47 // =======================================================================
49 DECLARE_TABLE( ImplAccelTable, ImplAccelEntry* )
50 DECLARE_LIST( ImplAccelList, ImplAccelEntry* )
52 #define ACCELENTRY_NOTFOUND ((USHORT)0xFFFF)
54 // =======================================================================
56 class ImplAccelData
58 public:
59 ImplAccelTable maKeyTable; // Fuer KeyCodes, die mit einem Code erzeugt wurden
60 ImplAccelList maIdList; // Id-List
63 // =======================================================================
65 DBG_NAME( Accelerator )
67 // =======================================================================
69 USHORT ImplAccelEntryGetIndex( ImplAccelList* pList, USHORT nId,
70 USHORT* pIndex = NULL )
72 ULONG nLow;
73 ULONG nHigh;
74 ULONG nMid;
75 ULONG nCount = pList->Count();
76 USHORT nCompareId;
78 // Abpruefen, ob der erste Key groesser als der Vergleichskey ist
79 if ( !nCount || (nId < pList->GetObject( 0 )->mnId) )
81 if ( pIndex )
82 *pIndex = 0;
83 return ACCELENTRY_NOTFOUND;
86 // Binaeres Suchen
87 nLow = 0;
88 nHigh = nCount-1;
91 nMid = (nLow + nHigh) / 2;
92 nCompareId = pList->GetObject( nMid )->mnId;
93 if ( nId < nCompareId )
94 nHigh = nMid-1;
95 else
97 if ( nId > nCompareId )
98 nLow = nMid + 1;
99 else
100 return (USHORT)nMid;
103 while ( nLow <= nHigh );
105 if ( pIndex )
107 if ( nId > nCompareId )
108 *pIndex = (USHORT)(nMid+1);
109 else
110 *pIndex = (USHORT)nMid;
113 return ACCELENTRY_NOTFOUND;
116 // -----------------------------------------------------------------------
118 static void ImplAccelEntryInsert( ImplAccelList* pList, ImplAccelEntry* pEntry )
120 USHORT nInsIndex;
121 USHORT nIndex = ImplAccelEntryGetIndex( pList, pEntry->mnId, &nInsIndex );
123 if ( nIndex != ACCELENTRY_NOTFOUND )
127 nIndex++;
128 ImplAccelEntry* pTempEntry = pList->GetObject( nIndex );
129 if ( !pTempEntry || (pTempEntry->mnId != pEntry->mnId) )
130 break;
132 while ( nIndex < pList->Count() );
134 pList->Insert( pEntry, (ULONG)nIndex );
136 else
137 pList->Insert( pEntry, (ULONG)nInsIndex );
140 // -----------------------------------------------------------------------
142 static USHORT ImplAccelEntryGetFirstPos( ImplAccelList* pList, USHORT nId )
144 USHORT nIndex = ImplAccelEntryGetIndex( pList, nId );
145 if ( nIndex != ACCELENTRY_NOTFOUND )
147 while ( nIndex )
149 nIndex--;
150 if ( pList->GetObject( nIndex )->mnId != nId )
151 break;
154 if ( pList->GetObject( nIndex )->mnId != nId )
155 nIndex++;
158 return nIndex;
161 // =======================================================================
163 void Accelerator::ImplInit()
165 mnCurId = 0;
166 mnCurRepeat = 0;
167 mbIsCancel = FALSE;
168 mpDel = NULL;
171 // -----------------------------------------------------------------------
173 ImplAccelEntry* Accelerator::ImplGetAccelData( const KeyCode& rKeyCode ) const
175 return mpData->maKeyTable.Get( rKeyCode.GetFullKeyCode() );
178 // -----------------------------------------------------------------------
180 void Accelerator::ImplCopyData( ImplAccelData& rAccelData )
182 // Tabellen kopieren
183 ImplAccelEntry* pEntry = rAccelData.maIdList.First();
184 while ( pEntry )
186 pEntry = new ImplAccelEntry( *pEntry );
188 // Folge-Accelerator, dann auch kopieren
189 if ( pEntry->mpAccel )
191 pEntry->mpAccel = new Accelerator( *(pEntry->mpAccel) );
192 pEntry->mpAutoAccel = pEntry->mpAccel;
194 else
195 pEntry->mpAutoAccel = NULL;
197 mpData->maKeyTable.Insert( (ULONG)pEntry->maKeyCode.GetFullKeyCode(), pEntry );
198 mpData->maIdList.Insert( pEntry, LIST_APPEND );
200 pEntry = rAccelData.maIdList.Next();
204 // -----------------------------------------------------------------------
206 void Accelerator::ImplDeleteData()
208 // Accelerator-Eintraege ueber die Id-Tabelle loeschen
209 ImplAccelEntry* pEntry = mpData->maIdList.First();
210 while ( pEntry )
212 // AutoResAccel zerstoeren
213 if ( pEntry->mpAutoAccel )
214 delete pEntry->mpAutoAccel;
215 delete pEntry;
217 pEntry = mpData->maIdList.Next();
221 // -----------------------------------------------------------------------
223 void Accelerator::ImplInsertAccel( USHORT nItemId, const KeyCode& rKeyCode,
224 BOOL bEnable, Accelerator* pAutoAccel )
226 DBG_CHKTHIS( Accelerator, NULL );
227 DBG_ASSERT( nItemId, "Accelerator::InsertItem(): ItemId == 0" );
229 if ( rKeyCode.IsFunction() )
231 USHORT nCode1;
232 USHORT nCode2;
233 USHORT nCode3;
234 USHORT nCode4;
235 ImplGetKeyCode( rKeyCode.GetFunction(), nCode1, nCode2, nCode3, nCode4 );
236 if ( nCode1 )
237 ImplInsertAccel( nItemId, KeyCode( nCode1, nCode1 ), bEnable, pAutoAccel );
238 if ( nCode2 )
240 if ( pAutoAccel )
241 pAutoAccel = new Accelerator( *pAutoAccel );
242 ImplInsertAccel( nItemId, KeyCode( nCode2, nCode2 ), bEnable, pAutoAccel );
243 if ( nCode3 )
245 if ( pAutoAccel )
246 pAutoAccel = new Accelerator( *pAutoAccel );
247 ImplInsertAccel( nItemId, KeyCode( nCode3, nCode3 ), bEnable, pAutoAccel );
250 return;
253 // Neuen Eintrag holen und fuellen
254 ImplAccelEntry* pEntry = new ImplAccelEntry;
255 pEntry->mnId = nItemId;
256 pEntry->maKeyCode = rKeyCode;
257 pEntry->mpAccel = pAutoAccel;
258 pEntry->mpAutoAccel = pAutoAccel;
259 pEntry->mbEnabled = bEnable;
261 // Ab in die Tabellen
262 ULONG nCode = rKeyCode.GetFullKeyCode();
263 if ( !nCode )
265 DBG_ERROR( "Accelerator::InsertItem(): KeyCode with KeyCode 0 not allowed" );
266 delete pEntry;
268 else if ( !mpData->maKeyTable.Insert( nCode, pEntry ) )
270 DBG_ERROR1( "Accelerator::InsertItem(): KeyCode (Key: %lx) already exists", nCode );
271 delete pEntry;
273 else
274 ImplAccelEntryInsert( &(mpData->maIdList), pEntry );
277 // -----------------------------------------------------------------------
279 Accelerator::Accelerator()
281 DBG_CTOR( Accelerator, NULL );
283 ImplInit();
284 mpData = new ImplAccelData;
287 // -----------------------------------------------------------------------
289 Accelerator::Accelerator( const Accelerator& rAccel ) :
290 Resource(),
291 maHelpStr( rAccel.maHelpStr ),
292 maCurKeyCode( rAccel.maCurKeyCode )
294 DBG_CTOR( Accelerator, NULL );
295 DBG_CHKOBJ( &rAccel, Accelerator, NULL );
297 ImplInit();
298 mpData = new ImplAccelData;
299 ImplCopyData( *((ImplAccelData*)(rAccel.mpData)) );
302 // -----------------------------------------------------------------------
304 Accelerator::Accelerator( const ResId& rResId )
306 DBG_CTOR( Accelerator, NULL );
308 ImplInit();
309 mpData = new ImplAccelData;
310 rResId.SetRT( RSC_ACCEL );
311 ImplLoadRes( rResId );
314 // -----------------------------------------------------------------------
316 void Accelerator::ImplLoadRes( const ResId& rResId )
318 GetRes( rResId );
320 maHelpStr = ReadStringRes();
321 ULONG nObjFollows = ReadLongRes();
323 for( ULONG i = 0; i < nObjFollows; i++ )
325 InsertItem( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) );
326 IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
330 // -----------------------------------------------------------------------
332 Accelerator::~Accelerator()
334 DBG_DTOR( Accelerator, NULL );
336 // AccelManager benachrichtigen, das Accelrator geloescht wurde
337 if ( mpDel )
338 *mpDel = TRUE;
340 ImplDeleteData();
341 delete mpData;
344 // -----------------------------------------------------------------------
346 void Accelerator::Activate()
348 maActivateHdl.Call( this );
351 // -----------------------------------------------------------------------
353 void Accelerator::Deactivate()
355 maDeactivateHdl.Call( this );
358 // -----------------------------------------------------------------------
360 void Accelerator::Select()
362 maSelectHdl.Call( this );
365 // -----------------------------------------------------------------------
367 void Accelerator::InsertItem( USHORT nItemId, const KeyCode& rKeyCode )
369 ImplInsertAccel( nItemId, rKeyCode, TRUE, NULL );
372 // -----------------------------------------------------------------------
374 void Accelerator::InsertItem( const ResId& rResId )
376 DBG_CHKTHIS( Accelerator, NULL );
378 ULONG nObjMask;
379 USHORT nAccelKeyId;
380 USHORT bDisable;
381 KeyCode aKeyCode;
382 Accelerator* pAutoAccel = NULL;
384 GetRes( rResId.SetRT( RSC_ACCELITEM ) );
385 nObjMask = ReadLongRes();
386 nAccelKeyId = sal::static_int_cast<USHORT>(ReadLongRes());
387 bDisable = ReadShortRes();
389 if ( nObjMask & ACCELITEM_KEY )
391 // es wird ein neuer Kontext aufgespannt
392 RSHEADER_TYPE * pKeyCodeRes = (RSHEADER_TYPE *)GetClassRes();
393 ResId aResId( pKeyCodeRes, *rResId.GetResMgr());
394 aKeyCode = KeyCode( aResId );
395 IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
398 if ( nObjMask & ACCELITEM_ACCEL )
400 pAutoAccel = new Accelerator( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) );
401 IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) );
404 ImplInsertAccel( nAccelKeyId, aKeyCode, !bDisable, pAutoAccel );
407 // -----------------------------------------------------------------------
409 void Accelerator::RemoveItem( USHORT nItemId )
411 DBG_CHKTHIS( Accelerator, NULL );
413 // Aus der Id-Liste entfernen
414 USHORT nIndex = ImplAccelEntryGetFirstPos( &(mpData->maIdList), nItemId );
415 if ( nIndex != ACCELENTRY_NOTFOUND )
417 USHORT nItemCount = GetItemCount();
420 ImplAccelEntry* pEntry = mpData->maIdList.GetObject( (ULONG)nIndex );
421 if ( pEntry && pEntry->mnId == nItemId )
423 mpData->maKeyTable.Remove( pEntry->maKeyCode.GetFullKeyCode() );
424 mpData->maIdList.Remove( (ULONG)nIndex );
426 // AutoResAccel zerstoeren
427 if ( pEntry->mpAutoAccel )
428 delete pEntry->mpAutoAccel;
430 delete pEntry;
432 else
433 break;
435 while ( nIndex < nItemCount );
439 // -----------------------------------------------------------------------
441 void Accelerator::RemoveItem( const KeyCode rKeyCode )
443 DBG_CHKTHIS( Accelerator, NULL );
445 ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode );
446 if ( pEntry )
448 // Aus der Id-Liste entfernen
449 USHORT nIndex = ImplAccelEntryGetFirstPos( &(mpData->maIdList), pEntry->mnId );
450 USHORT nItemCount = GetItemCount();
453 if ( mpData->maIdList.GetObject( (ULONG)nIndex ) == pEntry )
454 break;
455 nIndex++;
457 while ( nIndex < nItemCount );
459 mpData->maKeyTable.Remove( rKeyCode.GetFullKeyCode() );
460 mpData->maIdList.Remove( (ULONG)nIndex );
462 // AutoResAccel zerstoeren
463 if ( pEntry->mpAutoAccel )
464 delete pEntry->mpAutoAccel;
466 delete pEntry;
470 // -----------------------------------------------------------------------
472 void Accelerator::Clear()
474 DBG_CHKTHIS( Accelerator, NULL );
476 ImplDeleteData();
477 mpData->maKeyTable.Clear();
478 mpData->maIdList.Clear();
481 // -----------------------------------------------------------------------
483 USHORT Accelerator::GetItemCount() const
485 DBG_CHKTHIS( Accelerator, NULL );
487 return (USHORT)mpData->maIdList.Count();
490 // -----------------------------------------------------------------------
492 USHORT Accelerator::GetItemId( USHORT nPos ) const
494 DBG_CHKTHIS( Accelerator, NULL );
496 ImplAccelEntry* pEntry = mpData->maIdList.GetObject( (ULONG)nPos );
497 if ( pEntry )
498 return pEntry->mnId;
499 else
500 return 0;
503 // -----------------------------------------------------------------------
505 KeyCode Accelerator::GetItemKeyCode( USHORT nPos ) const
507 DBG_CHKTHIS( Accelerator, NULL );
509 ImplAccelEntry* pEntry = mpData->maIdList.GetObject( (ULONG)nPos );
510 if ( pEntry )
511 return pEntry->maKeyCode;
512 else
513 return KeyCode();
516 // -----------------------------------------------------------------------
518 USHORT Accelerator::GetItemId( const KeyCode& rKeyCode ) const
520 DBG_CHKTHIS( Accelerator, NULL );
522 ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode );
523 if ( pEntry )
524 return pEntry->mnId;
525 else
526 return 0;
529 // -----------------------------------------------------------------------
531 KeyCode Accelerator::GetKeyCode( USHORT nItemId ) const
533 DBG_CHKTHIS( Accelerator, NULL );
535 USHORT nIndex = ImplAccelEntryGetFirstPos( &(mpData->maIdList), nItemId );
536 if ( nIndex != ACCELENTRY_NOTFOUND )
537 return mpData->maIdList.GetObject( (ULONG)nIndex )->maKeyCode;
538 else
539 return KeyCode();
542 // -----------------------------------------------------------------------
544 BOOL Accelerator::IsIdValid( USHORT nItemId ) const
546 DBG_CHKTHIS( Accelerator, NULL );
548 USHORT nIndex = ImplAccelEntryGetIndex( &(mpData->maIdList), nItemId );
549 return (nIndex != ACCELENTRY_NOTFOUND);
552 // -----------------------------------------------------------------------
554 BOOL Accelerator::IsKeyCodeValid( const KeyCode rKeyCode ) const
556 DBG_CHKTHIS( Accelerator, NULL );
558 ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode );
559 return (pEntry != NULL);
562 // -----------------------------------------------------------------------
564 BOOL Accelerator::Call( const KeyCode& rKeyCode, USHORT nRepeat )
566 DBG_CHKTHIS( Accelerator, NULL );
568 ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode );
569 if ( pEntry )
571 if ( pEntry->mbEnabled )
573 BOOL bDel = FALSE;
574 mnCurId = pEntry->mnId;
575 maCurKeyCode = rKeyCode;
576 mnCurRepeat = nRepeat;
577 mpDel = &bDel;
578 Select();
579 if ( !bDel )
581 mnCurId = 0;
582 maCurKeyCode = KeyCode();
583 mnCurRepeat = 0;
586 return TRUE;
590 return FALSE;
593 // -----------------------------------------------------------------------
595 void Accelerator::SetAccel( USHORT nItemId, Accelerator* pAccel )
597 DBG_CHKTHIS( Accelerator, NULL );
599 USHORT nIndex = ImplAccelEntryGetFirstPos( &(mpData->maIdList), nItemId );
600 if ( nIndex != ACCELENTRY_NOTFOUND )
602 USHORT nItemCount = GetItemCount();
605 ImplAccelEntry* pEntry = mpData->maIdList.GetObject( (ULONG)nIndex );
606 if ( pEntry->mnId != nItemId )
607 break;
609 pEntry->mpAccel = pAccel;
610 nIndex++;
612 while ( nIndex < nItemCount );
616 // -----------------------------------------------------------------------
618 Accelerator* Accelerator::GetAccel( USHORT nItemId ) const
620 DBG_CHKTHIS( Accelerator, NULL );
622 USHORT nIndex = ImplAccelEntryGetIndex( &(mpData->maIdList), nItemId );
623 if ( nIndex != ACCELENTRY_NOTFOUND )
624 return mpData->maIdList.GetObject( (ULONG)nIndex )->mpAccel;
625 else
626 return NULL;
629 // -----------------------------------------------------------------------
631 void Accelerator::SetAccel( const KeyCode rKeyCode, Accelerator* pAccel )
633 DBG_CHKTHIS( Accelerator, NULL );
635 ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode );
636 if ( pEntry )
637 pEntry->mpAccel = pAccel;
640 // -----------------------------------------------------------------------
642 Accelerator* Accelerator::GetAccel( const KeyCode rKeyCode ) const
644 DBG_CHKTHIS( Accelerator, NULL );
646 ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode );
647 if ( pEntry )
648 return pEntry->mpAccel;
649 else
650 return FALSE;
653 // -----------------------------------------------------------------------
655 void Accelerator::EnableItem( USHORT nItemId, BOOL bEnable )
657 DBG_CHKTHIS( Accelerator, NULL );
659 USHORT nIndex = ImplAccelEntryGetFirstPos( &(mpData->maIdList), nItemId );
660 if ( nIndex != ACCELENTRY_NOTFOUND )
662 USHORT nItemCount = GetItemCount();
665 ImplAccelEntry* pEntry = mpData->maIdList.GetObject( (ULONG)nIndex );
666 if ( pEntry->mnId != nItemId )
667 break;
669 pEntry->mbEnabled = bEnable;
670 nIndex++;
672 while ( nIndex < nItemCount );
676 // -----------------------------------------------------------------------
678 BOOL Accelerator::IsItemEnabled( USHORT nItemId ) const
680 DBG_CHKTHIS( Accelerator, NULL );
682 USHORT nIndex = ImplAccelEntryGetIndex( &(mpData->maIdList), nItemId );
683 if ( nIndex != ACCELENTRY_NOTFOUND )
684 return mpData->maIdList.GetObject( (ULONG)nIndex )->mbEnabled;
685 else
686 return FALSE;
689 // -----------------------------------------------------------------------
691 void Accelerator::EnableItem( const KeyCode rKeyCode, BOOL bEnable )
693 DBG_CHKTHIS( Accelerator, NULL );
695 ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode );
696 if ( pEntry )
697 pEntry->mbEnabled = bEnable;
700 // -----------------------------------------------------------------------
702 BOOL Accelerator::IsItemEnabled( const KeyCode rKeyCode ) const
704 DBG_CHKTHIS( Accelerator, NULL );
706 ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode );
707 if ( pEntry )
708 return pEntry->mbEnabled;
709 else
710 return FALSE;
713 // -----------------------------------------------------------------------
715 Accelerator& Accelerator::operator=( const Accelerator& rAccel )
717 DBG_CHKTHIS( Accelerator, NULL );
718 DBG_CHKOBJ( &rAccel, Accelerator, NULL );
720 // Neue Daten zuweisen
721 maHelpStr = rAccel.maHelpStr;
722 maCurKeyCode = KeyCode();
723 mnCurId = 0;
724 mnCurRepeat = 0;
725 mbIsCancel = FALSE;
727 // Tabellen loeschen und kopieren
728 ImplDeleteData();
729 mpData->maKeyTable.Clear();
730 mpData->maIdList.Clear();
731 ImplCopyData( *((ImplAccelData*)(rAccel.mpData)) );
733 return *this;