1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sd.hxx"
31 #include "TaskPaneFocusManager.hxx"
33 #include <vcl/window.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/event.hxx>
36 #include <rtl/instance.hxx>
44 size_t operator()(const ::Window
* argument
) const
45 { return reinterpret_cast<unsigned long>(argument
); }
51 EventDescriptor (const KeyCode
& rKey
, ::Window
* pWindow
)
52 : maKeyCode(rKey
), mpTargetWindow(pWindow
) {}
54 ::Window
* mpTargetWindow
;
57 } // end of anonymous namespace
62 namespace sd
{ namespace toolpanel
{
66 class FocusManager::LinkMap
67 : public ::std::hash_multimap
< ::Window
*, EventDescriptor
, WindowHash
>
73 FocusManager
& FocusManager::Instance (void)
75 static FocusManager
* spInstance
= NULL
;
77 if (spInstance
== NULL
)
79 ::osl::MutexGuard
aGuard (::osl::Mutex::getGlobalMutex());
80 if (spInstance
== NULL
)
82 static FocusManager aInstance
;
83 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
84 spInstance
= &aInstance
;
89 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
97 FocusManager::FocusManager (void)
98 : mpLinks(new LinkMap())
105 FocusManager::~FocusManager (void)
113 void FocusManager::Clear (void)
115 if (mpLinks
.get() != NULL
)
117 while ( ! mpLinks
->empty())
119 ::Window
* pWindow
= mpLinks
->begin()->first
;
122 mpLinks
->erase(mpLinks
->begin());
126 RemoveLinks(pWindow
);
135 void FocusManager::RegisterUpLink (::Window
* pSource
, ::Window
* pTarget
)
137 RegisterLink(pSource
, pTarget
, KEY_ESCAPE
);
143 void FocusManager::RegisterDownLink (::Window
* pSource
, ::Window
* pTarget
)
145 RegisterLink(pSource
, pTarget
, KEY_RETURN
);
151 void FocusManager::RegisterLink (
156 OSL_ASSERT(pSource
!=NULL
);
157 OSL_ASSERT(pTarget
!=NULL
);
159 if (pSource
==NULL
|| pTarget
==NULL
)
162 // Register this focus manager as event listener at the source window.
163 if (mpLinks
->equal_range(pSource
).first
== mpLinks
->end())
164 pSource
->AddEventListener (LINK (this, FocusManager
, WindowEventListener
));
165 mpLinks
->insert(LinkMap::value_type(pSource
, EventDescriptor(rKey
,pTarget
)));
171 void FocusManager::RemoveLinks (
172 ::Window
* pSourceWindow
,
173 ::Window
* pTargetWindow
)
175 OSL_ASSERT(pSourceWindow
!=NULL
);
176 OSL_ASSERT(pTargetWindow
!=NULL
);
178 if (pSourceWindow
==NULL
|| pTargetWindow
==NULL
)
180 // This method was called with invalid arguments. To avoid
181 // referencing windows that will soon be deleted we clear *all*
182 // links as an emergency fallback.
187 ::std::pair
<LinkMap::iterator
,LinkMap::iterator
> aCandidates
;
188 LinkMap::iterator iCandidate
;
189 bool bLoop (mpLinks
->size() > 0);
192 aCandidates
= mpLinks
->equal_range(pSourceWindow
);
193 if (aCandidates
.first
== mpLinks
->end())
195 // No links for the source window found -> nothing more to do.
200 // Set the loop control to false so that when no candidate for
201 // deletion is found the loop is left.
203 for (iCandidate
=aCandidates
.first
; iCandidate
!=aCandidates
.second
; ++iCandidate
)
204 if (iCandidate
->second
.mpTargetWindow
== pTargetWindow
)
206 mpLinks
->erase(iCandidate
);
207 // One link erased. The iterators have become invalid so
208 // start the search for links to delete anew.
215 RemoveUnusedEventListener(pSourceWindow
);
221 void FocusManager::RemoveLinks (::Window
* pWindow
)
223 OSL_ASSERT(pWindow
!=NULL
);
227 // This method was called with invalid arguments. To avoid
228 // referencing windows that will soon be deleted we clear *all*
229 // links as an emergency fallback.
234 // Make sure that we are not called back for the window.
235 pWindow
->RemoveEventListener (LINK (this, FocusManager
, WindowEventListener
));
237 // Remove the links from the given window.
238 ::std::pair
<LinkMap::iterator
,LinkMap::iterator
> aCandidates(mpLinks
->equal_range(pWindow
));
239 mpLinks
->erase(aCandidates
.first
, aCandidates
.second
);
241 // Remove links to the given window.
245 bLinkRemoved
= false;
246 LinkMap::iterator iLink
;
247 for (iLink
=mpLinks
->begin(); iLink
!=mpLinks
->end(); ++iLink
)
249 if (iLink
->second
.mpTargetWindow
== pWindow
)
251 RemoveUnusedEventListener(iLink
->first
);
252 mpLinks
->erase(iLink
);
258 while (bLinkRemoved
);
264 void FocusManager::RemoveUnusedEventListener (::Window
* pWindow
)
266 OSL_ASSERT(pWindow
!=NULL
);
271 // When there are no more links from the window to another window
272 // then remove the event listener from the window.
273 if (mpLinks
->find(pWindow
) == mpLinks
->end())
274 pWindow
->RemoveEventListener (LINK (this, FocusManager
, WindowEventListener
));
280 bool FocusManager::TransferFocus (
281 ::Window
* pSourceWindow
,
282 const KeyCode
& rKeyCode
)
284 bool bSuccess (false);
286 OSL_ASSERT(pSourceWindow
!=NULL
);
287 if (pSourceWindow
== NULL
)
290 ::std::pair
<LinkMap::iterator
,LinkMap::iterator
> aCandidates (
291 mpLinks
->equal_range(pSourceWindow
));
292 LinkMap::const_iterator iCandidate
;
293 for (iCandidate
=aCandidates
.first
; iCandidate
!=aCandidates
.second
; ++iCandidate
)
294 if (iCandidate
->second
.maKeyCode
== rKeyCode
)
296 OSL_ASSERT(iCandidate
->second
.mpTargetWindow
!= NULL
);
297 iCandidate
->second
.mpTargetWindow
->GrabFocus();
308 IMPL_LINK(FocusManager
, WindowEventListener
, VclSimpleEvent
*, pEvent
)
310 if (pEvent
!=NULL
&& pEvent
->ISA(VclWindowEvent
))
312 VclWindowEvent
* pWindowEvent
= static_cast<VclWindowEvent
*>(pEvent
);
313 switch (pWindowEvent
->GetId())
315 case VCLEVENT_WINDOW_KEYINPUT
:
317 ::Window
* pSource
= pWindowEvent
->GetWindow();
318 KeyEvent
* pKeyEvent
= static_cast<KeyEvent
*>(pWindowEvent
->GetData());
319 TransferFocus(pSource
, pKeyEvent
->GetKeyCode());
323 case VCLEVENT_OBJECT_DYING
:
324 RemoveLinks(pWindowEvent
->GetWindow());
332 } } // end of namespace ::sd::toolpanel