fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / sd / source / ui / toolpanel / TaskPaneFocusManager.cxx
blobdf5fe4477b7a095a59ce6e09d6dac661991df15f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "TaskPaneFocusManager.hxx"
23 #include <vcl/window.hxx>
24 #include <vcl/svapp.hxx>
25 #include <vcl/event.hxx>
26 #include <rtl/instance.hxx>
27 #include <boost/unordered_map.hpp>
29 namespace {
31 class WindowHash
33 public:
34 size_t operator()(const ::Window* argument) const
35 { return reinterpret_cast<uintptr_t>(argument); }
38 class EventDescriptor
40 public:
41 EventDescriptor (const KeyCode& rKey, ::Window* pWindow)
42 : maKeyCode(rKey), mpTargetWindow(pWindow) {}
43 KeyCode maKeyCode;
44 ::Window* mpTargetWindow;
47 } // end of anonymous namespace
52 namespace sd { namespace toolpanel {
56 class FocusManager::LinkMap
57 : public ::boost::unordered_multimap< ::Window*, EventDescriptor, WindowHash>
61 struct FocusManagerCreator
63 FocusManager m_aFocusManager;
66 namespace
68 class theFocusManagerInstance : public rtl::Static< FocusManagerCreator, theFocusManagerInstance> {};
71 FocusManager& FocusManager::Instance (void)
73 return theFocusManagerInstance::get().m_aFocusManager;
79 FocusManager::FocusManager (void)
80 : mpLinks(new LinkMap())
87 FocusManager::~FocusManager (void)
89 Clear();
95 void FocusManager::Clear (void)
97 if (mpLinks.get() != NULL)
99 while ( ! mpLinks->empty())
101 ::Window* pWindow = mpLinks->begin()->first;
102 if (pWindow == NULL)
104 mpLinks->erase(mpLinks->begin());
106 else
108 RemoveLinks(pWindow);
117 void FocusManager::RegisterUpLink (::Window* pSource, ::Window* pTarget)
119 RegisterLink(pSource, pTarget, KEY_ESCAPE);
125 void FocusManager::RegisterDownLink (::Window* pSource, ::Window* pTarget)
127 RegisterLink(pSource, pTarget, KEY_RETURN);
133 void FocusManager::RegisterLink (
134 ::Window* pSource,
135 ::Window* pTarget,
136 const KeyCode& rKey)
138 OSL_ASSERT(pSource!=NULL);
139 OSL_ASSERT(pTarget!=NULL);
141 if (pSource==NULL || pTarget==NULL)
142 return;
144 // Register this focus manager as event listener at the source window.
145 if (mpLinks->equal_range(pSource).first == mpLinks->end())
146 pSource->AddEventListener (LINK (this, FocusManager, WindowEventListener));
147 mpLinks->insert(LinkMap::value_type(pSource, EventDescriptor(rKey,pTarget)));
153 void FocusManager::RemoveLinks (
154 ::Window* pSourceWindow,
155 ::Window* pTargetWindow)
157 OSL_ASSERT(pSourceWindow!=NULL);
158 OSL_ASSERT(pTargetWindow!=NULL);
160 if (pSourceWindow==NULL || pTargetWindow==NULL)
162 // This method was called with invalid arguments. To avoid
163 // referencing windows that will soon be deleted we clear *all*
164 // links as an emergency fallback.
165 Clear();
166 return;
169 ::std::pair<LinkMap::iterator,LinkMap::iterator> aCandidates;
170 LinkMap::iterator iCandidate;
171 bool bLoop (mpLinks->size() > 0);
172 while (bLoop)
174 aCandidates = mpLinks->equal_range(pSourceWindow);
175 if (aCandidates.first == mpLinks->end())
177 // No links for the source window found -> nothing more to do.
178 bLoop = false;
180 else
182 // Set the loop control to false so that when no candidate for
183 // deletion is found the loop is left.
184 bLoop = false;
185 for (iCandidate=aCandidates.first; iCandidate!=aCandidates.second; ++iCandidate)
186 if (iCandidate->second.mpTargetWindow == pTargetWindow)
188 mpLinks->erase(iCandidate);
189 // One link erased. The iterators have become invalid so
190 // start the search for links to delete anew.
191 bLoop = true;
192 break;
197 RemoveUnusedEventListener(pSourceWindow);
203 void FocusManager::RemoveLinks (::Window* pWindow)
205 OSL_ASSERT(pWindow!=NULL);
207 if (pWindow == NULL)
209 // This method was called with invalid arguments. To avoid
210 // referencing windows that will soon be deleted we clear *all*
211 // links as an emergency fallback.
212 Clear();
213 return;
216 // Make sure that we are not called back for the window.
217 pWindow->RemoveEventListener (LINK (this, FocusManager, WindowEventListener));
219 // Remove the links from the given window.
220 mpLinks->erase(pWindow);
222 // Remove links to the given window.
223 bool bLinkRemoved;
226 bLinkRemoved = false;
227 LinkMap::iterator iLink;
228 for (iLink=mpLinks->begin(); iLink!=mpLinks->end(); ++iLink)
230 if (iLink->second.mpTargetWindow == pWindow)
232 ::Window* const pSourceWindow(iLink->first);
233 mpLinks->erase(iLink);
234 RemoveUnusedEventListener(pSourceWindow);
235 bLinkRemoved = true;
236 break;
240 while (bLinkRemoved);
246 void FocusManager::RemoveUnusedEventListener (::Window* pWindow)
248 OSL_ASSERT(pWindow!=NULL);
250 if (pWindow == NULL)
251 return;
253 // When there are no more links from the window to another window
254 // then remove the event listener from the window.
255 if (mpLinks->find(pWindow) == mpLinks->end())
256 pWindow->RemoveEventListener (LINK (this, FocusManager, WindowEventListener));
262 bool FocusManager::TransferFocus (
263 ::Window* pSourceWindow,
264 const KeyCode& rKeyCode)
266 bool bSuccess (false);
268 OSL_ASSERT(pSourceWindow!=NULL);
269 if (pSourceWindow == NULL)
270 return bSuccess;
272 ::std::pair<LinkMap::iterator,LinkMap::iterator> aCandidates (
273 mpLinks->equal_range(pSourceWindow));
274 LinkMap::const_iterator iCandidate;
275 for (iCandidate=aCandidates.first; iCandidate!=aCandidates.second; ++iCandidate)
276 if (iCandidate->second.maKeyCode == rKeyCode)
278 OSL_ASSERT(iCandidate->second.mpTargetWindow != NULL);
279 iCandidate->second.mpTargetWindow->GrabFocus();
280 bSuccess = true;
281 break;
284 return bSuccess;
290 IMPL_LINK(FocusManager, WindowEventListener, VclSimpleEvent*, pEvent)
292 if (pEvent!=NULL && pEvent->ISA(VclWindowEvent))
294 VclWindowEvent* pWindowEvent = static_cast<VclWindowEvent*>(pEvent);
295 switch (pWindowEvent->GetId())
297 case VCLEVENT_WINDOW_KEYINPUT:
299 ::Window* pSource = pWindowEvent->GetWindow();
300 KeyEvent* pKeyEvent = static_cast<KeyEvent*>(pWindowEvent->GetData());
301 TransferFocus(pSource, pKeyEvent->GetKeyCode());
303 break;
305 case VCLEVENT_OBJECT_DYING:
306 RemoveLinks(pWindowEvent->GetWindow());
307 break;
310 return 1;
314 } } // end of namespace ::sd::toolpanel
316 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */