1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
34 size_t operator()(const ::Window
* argument
) const
35 { return reinterpret_cast<uintptr_t>(argument
); }
41 EventDescriptor (const KeyCode
& rKey
, ::Window
* pWindow
)
42 : maKeyCode(rKey
), mpTargetWindow(pWindow
) {}
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
;
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)
95 void FocusManager::Clear (void)
97 if (mpLinks
.get() != NULL
)
99 while ( ! mpLinks
->empty())
101 ::Window
* pWindow
= mpLinks
->begin()->first
;
104 mpLinks
->erase(mpLinks
->begin());
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 (
138 OSL_ASSERT(pSource
!=NULL
);
139 OSL_ASSERT(pTarget
!=NULL
);
141 if (pSource
==NULL
|| pTarget
==NULL
)
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.
169 ::std::pair
<LinkMap::iterator
,LinkMap::iterator
> aCandidates
;
170 LinkMap::iterator iCandidate
;
171 bool bLoop (mpLinks
->size() > 0);
174 aCandidates
= mpLinks
->equal_range(pSourceWindow
);
175 if (aCandidates
.first
== mpLinks
->end())
177 // No links for the source window found -> nothing more to do.
182 // Set the loop control to false so that when no candidate for
183 // deletion is found the loop is left.
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.
197 RemoveUnusedEventListener(pSourceWindow
);
203 void FocusManager::RemoveLinks (::Window
* pWindow
)
205 OSL_ASSERT(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.
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.
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
);
240 while (bLinkRemoved
);
246 void FocusManager::RemoveUnusedEventListener (::Window
* pWindow
)
248 OSL_ASSERT(pWindow
!=NULL
);
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
)
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();
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());
305 case VCLEVENT_OBJECT_DYING
:
306 RemoveLinks(pWindowEvent
->GetWindow());
314 } } // end of namespace ::sd::toolpanel
316 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */