CWS-TOOLING: integrate CWS os150
[LibreOffice.git] / sd / source / ui / toolpanel / TaskPaneFocusManager.cxx
blobd1c5d2c0ff535fc3ea25460ee4d67cece1e2264f
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>
37 #include <hash_map>
39 namespace {
41 class WindowHash
43 public:
44 size_t operator()(const ::Window* argument) const
45 { return reinterpret_cast<unsigned long>(argument); }
48 class EventDescriptor
50 public:
51 EventDescriptor (const KeyCode& rKey, ::Window* pWindow)
52 : maKeyCode(rKey), mpTargetWindow(pWindow) {}
53 KeyCode maKeyCode;
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;
87 else
89 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
91 return *spInstance;
97 FocusManager::FocusManager (void)
98 : mpLinks(new LinkMap())
105 FocusManager::~FocusManager (void)
107 Clear();
113 void FocusManager::Clear (void)
115 if (mpLinks.get() != NULL)
117 while ( ! mpLinks->empty())
119 ::Window* pWindow = mpLinks->begin()->first;
120 if (pWindow == NULL)
122 mpLinks->erase(mpLinks->begin());
124 else
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 (
152 ::Window* pSource,
153 ::Window* pTarget,
154 const KeyCode& rKey)
156 OSL_ASSERT(pSource!=NULL);
157 OSL_ASSERT(pTarget!=NULL);
159 if (pSource==NULL || pTarget==NULL)
160 return;
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.
183 Clear();
184 return;
187 ::std::pair<LinkMap::iterator,LinkMap::iterator> aCandidates;
188 LinkMap::iterator iCandidate;
189 bool bLoop (mpLinks->size() > 0);
190 while (bLoop)
192 aCandidates = mpLinks->equal_range(pSourceWindow);
193 if (aCandidates.first == mpLinks->end())
195 // No links for the source window found -> nothing more to do.
196 bLoop = false;
198 else
200 // Set the loop control to false so that when no candidate for
201 // deletion is found the loop is left.
202 bLoop = false;
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.
209 bLoop = true;
210 break;
215 RemoveUnusedEventListener(pSourceWindow);
221 void FocusManager::RemoveLinks (::Window* pWindow)
223 OSL_ASSERT(pWindow!=NULL);
225 if (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.
230 Clear();
231 return;
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.
242 bool bLinkRemoved;
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);
253 bLinkRemoved = true;
254 break;
258 while (bLinkRemoved);
264 void FocusManager::RemoveUnusedEventListener (::Window* pWindow)
266 OSL_ASSERT(pWindow!=NULL);
268 if (pWindow == NULL)
269 return;
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)
288 return bSuccess;
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();
298 bSuccess = true;
299 break;
302 return bSuccess;
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());
321 break;
323 case VCLEVENT_OBJECT_DYING:
324 RemoveLinks(pWindowEvent->GetWindow());
325 break;
328 return 1;
332 } } // end of namespace ::sd::toolpanel