Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : #include "TaskPaneFocusManager.hxx"
31 : :
32 : : #include <vcl/window.hxx>
33 : : #include <vcl/svapp.hxx>
34 : : #include <vcl/event.hxx>
35 : : #include <rtl/instance.hxx>
36 : : #include <boost/unordered_map.hpp>
37 : :
38 : : namespace {
39 : :
40 : : class WindowHash
41 : : {
42 : : public:
43 : 269 : size_t operator()(const ::Window* argument) const
44 : 269 : { return reinterpret_cast<uintptr_t>(argument); }
45 : : };
46 : :
47 : : class EventDescriptor
48 : : {
49 : : public:
50 : 82 : EventDescriptor (const KeyCode& rKey, ::Window* pWindow)
51 : 82 : : maKeyCode(rKey), mpTargetWindow(pWindow) {}
52 : : KeyCode maKeyCode;
53 : : ::Window* mpTargetWindow;
54 : : };
55 : :
56 : : } // end of anonymous namespace
57 : :
58 : :
59 : :
60 : :
61 : : namespace sd { namespace toolpanel {
62 : :
63 : :
64 : :
65 [ + - ]: 16 : class FocusManager::LinkMap
66 : : : public ::boost::unordered_multimap< ::Window*, EventDescriptor, WindowHash>
67 : : {
68 : : };
69 : :
70 : 16 : struct FocusManagerCreator
71 : : {
72 : : FocusManager m_aFocusManager;
73 : : };
74 : :
75 : : namespace
76 : : {
77 : : class theFocusManagerInstance : public rtl::Static< FocusManagerCreator, theFocusManagerInstance> {};
78 : : }
79 : :
80 : 119 : FocusManager& FocusManager::Instance (void)
81 : : {
82 : 119 : return theFocusManagerInstance::get().m_aFocusManager;
83 : : }
84 : :
85 : :
86 : :
87 : :
88 : 8 : FocusManager::FocusManager (void)
89 [ + - ]: 8 : : mpLinks(new LinkMap())
90 : : {
91 : 8 : }
92 : :
93 : :
94 : :
95 : :
96 : 8 : FocusManager::~FocusManager (void)
97 : : {
98 [ + - ]: 8 : Clear();
99 : 8 : }
100 : :
101 : :
102 : :
103 : :
104 : 8 : void FocusManager::Clear (void)
105 : : {
106 [ + - ]: 8 : if (mpLinks.get() != NULL)
107 : : {
108 [ - + ]: 8 : while ( ! mpLinks->empty())
109 : : {
110 [ # # ]: 0 : ::Window* pWindow = mpLinks->begin()->first;
111 [ # # ]: 0 : if (pWindow == NULL)
112 : : {
113 [ # # ]: 0 : mpLinks->erase(mpLinks->begin());
114 : : }
115 : : else
116 : : {
117 : 0 : RemoveLinks(pWindow);
118 : : }
119 : : }
120 : : }
121 : 8 : }
122 : :
123 : :
124 : :
125 : :
126 : 15 : void FocusManager::RegisterUpLink (::Window* pSource, ::Window* pTarget)
127 : : {
128 [ + - ]: 15 : RegisterLink(pSource, pTarget, KEY_ESCAPE);
129 : 15 : }
130 : :
131 : :
132 : :
133 : :
134 : 67 : void FocusManager::RegisterDownLink (::Window* pSource, ::Window* pTarget)
135 : : {
136 [ + - ]: 67 : RegisterLink(pSource, pTarget, KEY_RETURN);
137 : 67 : }
138 : :
139 : :
140 : :
141 : :
142 : 82 : void FocusManager::RegisterLink (
143 : : ::Window* pSource,
144 : : ::Window* pTarget,
145 : : const KeyCode& rKey)
146 : : {
147 : : OSL_ASSERT(pSource!=NULL);
148 : : OSL_ASSERT(pTarget!=NULL);
149 : :
150 [ + - ][ - + ]: 82 : if (pSource==NULL || pTarget==NULL)
151 : 82 : return;
152 : :
153 : : // Register this focus manager as event listener at the source window.
154 [ + - ][ + - ]: 82 : if (mpLinks->equal_range(pSource).first == mpLinks->end())
155 [ + - ]: 82 : pSource->AddEventListener (LINK (this, FocusManager, WindowEventListener));
156 [ + - ]: 82 : mpLinks->insert(LinkMap::value_type(pSource, EventDescriptor(rKey,pTarget)));
157 : : }
158 : :
159 : :
160 : :
161 : :
162 : 52 : void FocusManager::RemoveLinks (
163 : : ::Window* pSourceWindow,
164 : : ::Window* pTargetWindow)
165 : : {
166 : : OSL_ASSERT(pSourceWindow!=NULL);
167 : : OSL_ASSERT(pTargetWindow!=NULL);
168 : :
169 [ + - ][ - + ]: 52 : if (pSourceWindow==NULL || pTargetWindow==NULL)
170 : : {
171 : : // This method was called with invalid arguments. To avoid
172 : : // referencing windows that will soon be deleted we clear *all*
173 : : // links as an emergency fallback.
174 [ # # ]: 0 : Clear();
175 : 52 : return;
176 : : }
177 : :
178 [ + - ]: 52 : ::std::pair<LinkMap::iterator,LinkMap::iterator> aCandidates;
179 : 52 : LinkMap::iterator iCandidate;
180 : 52 : bool bLoop (mpLinks->size() > 0);
181 [ + + ]: 119 : while (bLoop)
182 : : {
183 [ + - ]: 67 : aCandidates = mpLinks->equal_range(pSourceWindow);
184 [ + + ][ + - ]: 67 : if (aCandidates.first == mpLinks->end())
185 : : {
186 : : // No links for the source window found -> nothing more to do.
187 : 41 : bLoop = false;
188 : : }
189 : : else
190 : : {
191 : : // Set the loop control to false so that when no candidate for
192 : : // deletion is found the loop is left.
193 : 26 : bLoop = false;
194 [ + - ]: 26 : for (iCandidate=aCandidates.first; iCandidate!=aCandidates.second; ++iCandidate)
195 [ + - ][ + - ]: 26 : if (iCandidate->second.mpTargetWindow == pTargetWindow)
196 : : {
197 [ + - ]: 26 : mpLinks->erase(iCandidate);
198 : : // One link erased. The iterators have become invalid so
199 : : // start the search for links to delete anew.
200 : 26 : bLoop = true;
201 : 26 : break;
202 : : }
203 : : }
204 : : }
205 : :
206 [ + - ]: 52 : RemoveUnusedEventListener(pSourceWindow);
207 : : }
208 : :
209 : :
210 : :
211 : :
212 : 41 : void FocusManager::RemoveLinks (::Window* pWindow)
213 : : {
214 : : OSL_ASSERT(pWindow!=NULL);
215 : :
216 [ - + ]: 41 : if (pWindow == NULL)
217 : : {
218 : : // This method was called with invalid arguments. To avoid
219 : : // referencing windows that will soon be deleted we clear *all*
220 : : // links as an emergency fallback.
221 : 0 : Clear();
222 : 41 : return;
223 : : }
224 : :
225 : : // Make sure that we are not called back for the window.
226 [ + - ]: 41 : pWindow->RemoveEventListener (LINK (this, FocusManager, WindowEventListener));
227 : :
228 : : // Remove the links from the given window.
229 : 41 : mpLinks->erase(pWindow);
230 : :
231 : : // Remove links to the given window.
232 : : bool bLinkRemoved;
233 [ + + ]: 56 : do
234 : : {
235 : 56 : bLinkRemoved = false;
236 : 56 : LinkMap::iterator iLink;
237 [ + - ][ + + ]: 86 : for (iLink=mpLinks->begin(); iLink!=mpLinks->end(); ++iLink)
[ + - ]
238 : : {
239 [ + - ][ + + ]: 45 : if (iLink->second.mpTargetWindow == pWindow)
240 : : {
241 [ + - ]: 15 : ::Window* const pSourceWindow(iLink->first);
242 [ + - ]: 15 : mpLinks->erase(iLink);
243 [ + - ]: 15 : RemoveUnusedEventListener(pSourceWindow);
244 : 15 : bLinkRemoved = true;
245 : 15 : break;
246 : : }
247 : : }
248 : : }
249 : : while (bLinkRemoved);
250 : : }
251 : :
252 : :
253 : :
254 : :
255 : 67 : void FocusManager::RemoveUnusedEventListener (::Window* pWindow)
256 : : {
257 : : OSL_ASSERT(pWindow!=NULL);
258 : :
259 [ - + ]: 67 : if (pWindow == NULL)
260 : 67 : return;
261 : :
262 : : // When there are no more links from the window to another window
263 : : // then remove the event listener from the window.
264 [ + - ][ + - ]: 67 : if (mpLinks->find(pWindow) == mpLinks->end())
265 [ + - ]: 67 : pWindow->RemoveEventListener (LINK (this, FocusManager, WindowEventListener));
266 : : }
267 : :
268 : :
269 : :
270 : :
271 : 0 : bool FocusManager::TransferFocus (
272 : : ::Window* pSourceWindow,
273 : : const KeyCode& rKeyCode)
274 : : {
275 : 0 : bool bSuccess (false);
276 : :
277 : : OSL_ASSERT(pSourceWindow!=NULL);
278 [ # # ]: 0 : if (pSourceWindow == NULL)
279 : 0 : return bSuccess;
280 : :
281 : : ::std::pair<LinkMap::iterator,LinkMap::iterator> aCandidates (
282 [ # # ]: 0 : mpLinks->equal_range(pSourceWindow));
283 : 0 : LinkMap::const_iterator iCandidate;
284 [ # # ]: 0 : for (iCandidate=aCandidates.first; iCandidate!=aCandidates.second; ++iCandidate)
285 [ # # ][ # # ]: 0 : if (iCandidate->second.maKeyCode == rKeyCode)
[ # # ]
286 : : {
287 : : OSL_ASSERT(iCandidate->second.mpTargetWindow != NULL);
288 [ # # ][ # # ]: 0 : iCandidate->second.mpTargetWindow->GrabFocus();
289 : 0 : bSuccess = true;
290 : 0 : break;
291 : : }
292 : :
293 : 0 : return bSuccess;
294 : : }
295 : :
296 : :
297 : :
298 : :
299 : 456 : IMPL_LINK(FocusManager, WindowEventListener, VclSimpleEvent*, pEvent)
300 : : {
301 [ + - ][ + - ]: 456 : if (pEvent!=NULL && pEvent->ISA(VclWindowEvent))
[ + - ]
302 : : {
303 : 456 : VclWindowEvent* pWindowEvent = static_cast<VclWindowEvent*>(pEvent);
304 [ - + + ]: 456 : switch (pWindowEvent->GetId())
305 : : {
306 : : case VCLEVENT_WINDOW_KEYINPUT:
307 : : {
308 : 0 : ::Window* pSource = pWindowEvent->GetWindow();
309 : 0 : KeyEvent* pKeyEvent = static_cast<KeyEvent*>(pWindowEvent->GetData());
310 : 0 : TransferFocus(pSource, pKeyEvent->GetKeyCode());
311 : : }
312 : 0 : break;
313 : :
314 : : case VCLEVENT_OBJECT_DYING:
315 : 41 : RemoveLinks(pWindowEvent->GetWindow());
316 : 456 : break;
317 : : }
318 : : }
319 : 456 : return 1;
320 : : }
321 : :
322 : :
323 : : } } // end of namespace ::sd::toolpanel
324 : :
325 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|