Update ooo320-m1
[ooovba.git] / sd / source / ui / toolpanel / TaskPaneFocusManager.cxx
blobd7d02da071ba39085c52bcca2e74c61480cfc9fb
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: TaskPaneFocusManager.cxx,v $
10 * $Revision: 1.8 $
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>
40 #include <hash_map>
42 namespace {
44 class WindowHash
46 public:
47 size_t operator()(const ::Window* argument) const
48 { return reinterpret_cast<unsigned long>(argument); }
51 class EventDescriptor
53 public:
54 EventDescriptor (const KeyCode& rKey, ::Window* pWindow)
55 : maKeyCode(rKey), mpTargetWindow(pWindow) {}
56 KeyCode maKeyCode;
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 ();
87 return *spInstance;
93 FocusManager::FocusManager (void)
94 : mpLinks(new LinkMap())
101 FocusManager::~FocusManager (void)
103 Clear();
109 void FocusManager::Clear (void)
111 if (mpLinks.get() != NULL)
113 while ( ! mpLinks->empty())
115 ::Window* pWindow = mpLinks->begin()->first;
116 if (pWindow == NULL)
118 mpLinks->erase(mpLinks->begin());
120 else
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 (
148 ::Window* pSource,
149 ::Window* pTarget,
150 const KeyCode& rKey)
152 OSL_ASSERT(pSource!=NULL);
153 OSL_ASSERT(pTarget!=NULL);
155 if (pSource==NULL || pTarget==NULL)
156 return;
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.
179 Clear();
180 return;
183 ::std::pair<LinkMap::iterator,LinkMap::iterator> aCandidates;
184 LinkMap::iterator iCandidate;
185 bool bLoop (mpLinks->size() > 0);
186 while (bLoop)
188 aCandidates = mpLinks->equal_range(pSourceWindow);
189 if (aCandidates.first == mpLinks->end())
191 // No links for the source window found -> nothing more to do.
192 bLoop = false;
194 else
196 // Set the loop control to false so that when no candidate for
197 // deletion is found the loop is left.
198 bLoop = false;
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.
205 bLoop = true;
206 break;
211 RemoveUnusedEventListener(pSourceWindow);
217 void FocusManager::RemoveLinks (::Window* pWindow)
219 OSL_ASSERT(pWindow!=NULL);
221 if (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.
226 Clear();
227 return;
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.
238 bool bLinkRemoved;
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);
249 bLinkRemoved = true;
250 break;
254 while (bLinkRemoved);
260 void FocusManager::RemoveUnusedEventListener (::Window* pWindow)
262 OSL_ASSERT(pWindow!=NULL);
264 if (pWindow == NULL)
265 return;
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)
284 return bSuccess;
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();
294 bSuccess = true;
295 break;
298 return bSuccess;
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());
317 break;
319 case VCLEVENT_OBJECT_DYING:
320 RemoveLinks(pWindowEvent->GetWindow());
321 break;
324 return 1;
328 } } // end of namespace ::sd::toolpanel