1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: TaskPaneFocusManager.cxx,v $
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_sd.hxx"
34 #include "TaskPaneFocusManager.hxx"
36 #include <vcl/window.hxx>
37 #include <vos/mutex.hxx>
38 #include <vcl/svapp.hxx>
39 #include <vcl/event.hxx>
47 size_t operator()(const ::Window
* argument
) const
48 { return reinterpret_cast<unsigned long>(argument
); }
54 EventDescriptor (const KeyCode
& rKey
, ::Window
* pWindow
)
55 : maKeyCode(rKey
), mpTargetWindow(pWindow
) {}
57 ::Window
* mpTargetWindow
;
60 } // end of anonymous namespace
65 namespace sd
{ namespace toolpanel
{
69 class FocusManager::LinkMap
70 : public ::std::hash_multimap
< ::Window
*, EventDescriptor
, WindowHash
>
76 FocusManager
* FocusManager::spInstance
= NULL
;
79 FocusManager
& FocusManager::Instance (void)
81 if (spInstance
== NULL
)
83 ::vos::OGuard
aGuard (::Application::GetSolarMutex());
84 if (spInstance
== NULL
)
85 spInstance
= new FocusManager ();
93 FocusManager::FocusManager (void)
94 : mpLinks(new LinkMap())
101 FocusManager::~FocusManager (void)
109 void FocusManager::Clear (void)
111 if (mpLinks
.get() != NULL
)
113 while ( ! mpLinks
->empty())
115 ::Window
* pWindow
= mpLinks
->begin()->first
;
118 mpLinks
->erase(mpLinks
->begin());
122 RemoveLinks(pWindow
);
131 void FocusManager::RegisterUpLink (::Window
* pSource
, ::Window
* pTarget
)
133 RegisterLink(pSource
, pTarget
, KEY_ESCAPE
);
139 void FocusManager::RegisterDownLink (::Window
* pSource
, ::Window
* pTarget
)
141 RegisterLink(pSource
, pTarget
, KEY_RETURN
);
147 void FocusManager::RegisterLink (
152 OSL_ASSERT(pSource
!=NULL
);
153 OSL_ASSERT(pTarget
!=NULL
);
155 if (pSource
==NULL
|| pTarget
==NULL
)
158 // Register this focus manager as event listener at the source window.
159 if (mpLinks
->equal_range(pSource
).first
== mpLinks
->end())
160 pSource
->AddEventListener (LINK (this, FocusManager
, WindowEventListener
));
161 mpLinks
->insert(LinkMap::value_type(pSource
, EventDescriptor(rKey
,pTarget
)));
167 void FocusManager::RemoveLinks (
168 ::Window
* pSourceWindow
,
169 ::Window
* pTargetWindow
)
171 OSL_ASSERT(pSourceWindow
!=NULL
);
172 OSL_ASSERT(pTargetWindow
!=NULL
);
174 if (pSourceWindow
==NULL
|| pTargetWindow
==NULL
)
176 // This method was called with invalid arguments. To avoid
177 // referencing windows that will soon be deleted we clear *all*
178 // links as an emergency fallback.
183 ::std::pair
<LinkMap::iterator
,LinkMap::iterator
> aCandidates
;
184 LinkMap::iterator iCandidate
;
185 bool bLoop (mpLinks
->size() > 0);
188 aCandidates
= mpLinks
->equal_range(pSourceWindow
);
189 if (aCandidates
.first
== mpLinks
->end())
191 // No links for the source window found -> nothing more to do.
196 // Set the loop control to false so that when no candidate for
197 // deletion is found the loop is left.
199 for (iCandidate
=aCandidates
.first
; iCandidate
!=aCandidates
.second
; ++iCandidate
)
200 if (iCandidate
->second
.mpTargetWindow
== pTargetWindow
)
202 mpLinks
->erase(iCandidate
);
203 // One link erased. The iterators have become invalid so
204 // start the search for links to delete anew.
211 RemoveUnusedEventListener(pSourceWindow
);
217 void FocusManager::RemoveLinks (::Window
* pWindow
)
219 OSL_ASSERT(pWindow
!=NULL
);
223 // This method was called with invalid arguments. To avoid
224 // referencing windows that will soon be deleted we clear *all*
225 // links as an emergency fallback.
230 // Make sure that we are not called back for the window.
231 pWindow
->RemoveEventListener (LINK (this, FocusManager
, WindowEventListener
));
233 // Remove the links from the given window.
234 ::std::pair
<LinkMap::iterator
,LinkMap::iterator
> aCandidates(mpLinks
->equal_range(pWindow
));
235 mpLinks
->erase(aCandidates
.first
, aCandidates
.second
);
237 // Remove links to the given window.
241 bLinkRemoved
= false;
242 LinkMap::iterator iLink
;
243 for (iLink
=mpLinks
->begin(); iLink
!=mpLinks
->end(); ++iLink
)
245 if (iLink
->second
.mpTargetWindow
== pWindow
)
247 RemoveUnusedEventListener(iLink
->first
);
248 mpLinks
->erase(iLink
);
254 while (bLinkRemoved
);
260 void FocusManager::RemoveUnusedEventListener (::Window
* pWindow
)
262 OSL_ASSERT(pWindow
!=NULL
);
267 // When there are no more links from the window to another window
268 // then remove the event listener from the window.
269 if (mpLinks
->find(pWindow
) == mpLinks
->end())
270 pWindow
->RemoveEventListener (LINK (this, FocusManager
, WindowEventListener
));
276 bool FocusManager::TransferFocus (
277 ::Window
* pSourceWindow
,
278 const KeyCode
& rKeyCode
)
280 bool bSuccess (false);
282 OSL_ASSERT(pSourceWindow
!=NULL
);
283 if (pSourceWindow
== NULL
)
286 ::std::pair
<LinkMap::iterator
,LinkMap::iterator
> aCandidates (
287 mpLinks
->equal_range(pSourceWindow
));
288 LinkMap::const_iterator iCandidate
;
289 for (iCandidate
=aCandidates
.first
; iCandidate
!=aCandidates
.second
; ++iCandidate
)
290 if (iCandidate
->second
.maKeyCode
== rKeyCode
)
292 OSL_ASSERT(iCandidate
->second
.mpTargetWindow
!= NULL
);
293 iCandidate
->second
.mpTargetWindow
->GrabFocus();
304 IMPL_LINK(FocusManager
, WindowEventListener
, VclSimpleEvent
*, pEvent
)
306 if (pEvent
!=NULL
&& pEvent
->ISA(VclWindowEvent
))
308 VclWindowEvent
* pWindowEvent
= static_cast<VclWindowEvent
*>(pEvent
);
309 switch (pWindowEvent
->GetId())
311 case VCLEVENT_WINDOW_KEYINPUT
:
313 ::Window
* pSource
= pWindowEvent
->GetWindow();
314 KeyEvent
* pKeyEvent
= static_cast<KeyEvent
*>(pWindowEvent
->GetData());
315 TransferFocus(pSource
, pKeyEvent
->GetKeyCode());
319 case VCLEVENT_OBJECT_DYING
:
320 RemoveLinks(pWindowEvent
->GetWindow());
328 } } // end of namespace ::sd::toolpanel