Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <tools/rcid.h>
21 :
22 : #include <vcl/dockwin.hxx>
23 : #include <vcl/taskpanelist.hxx>
24 :
25 : #include <svdata.hxx>
26 :
27 : #include <functional>
28 : #include <algorithm>
29 :
30 : // can't have static linkage because SUNPRO 5.2 complains
31 0 : Point ImplTaskPaneListGetPos( const vcl::Window *w )
32 : {
33 0 : Point pos;
34 0 : if( w->ImplIsDockingWindow() )
35 : {
36 0 : pos = static_cast<const DockingWindow*>(w)->GetPosPixel();
37 0 : vcl::Window *pF = static_cast<const DockingWindow*>(w)->GetFloatingWindow();
38 0 : if( pF )
39 0 : pos = pF->OutputToAbsoluteScreenPixel( pF->ScreenToOutputPixel( pos ) );
40 : else
41 0 : pos = w->OutputToAbsoluteScreenPixel( pos );
42 : }
43 : else
44 0 : pos = w->OutputToAbsoluteScreenPixel( w->GetPosPixel() );
45 :
46 0 : return pos;
47 : }
48 :
49 : // compares window pos left-to-right
50 : struct LTRSort : public ::std::binary_function< const vcl::Window*, const vcl::Window*, bool >
51 : {
52 0 : bool operator()( const vcl::Window* w1, const vcl::Window* w2 ) const
53 : {
54 0 : Point pos1(ImplTaskPaneListGetPos( w1 ));
55 0 : Point pos2(ImplTaskPaneListGetPos( w2 ));
56 :
57 0 : if( pos1.X() == pos2.X() )
58 0 : return ( pos1.Y() < pos2.Y() );
59 : else
60 0 : return ( pos1.X() < pos2.X() );
61 : }
62 : };
63 : struct LTRSortBackward : public ::std::binary_function< const vcl::Window*, const vcl::Window*, bool >
64 : {
65 0 : bool operator()( const vcl::Window* w2, const vcl::Window* w1 ) const
66 : {
67 0 : Point pos1(ImplTaskPaneListGetPos( w1 ));
68 0 : Point pos2(ImplTaskPaneListGetPos( w2 ));
69 :
70 0 : if( pos1.X() == pos2.X() )
71 0 : return ( pos1.Y() < pos2.Y() );
72 : else
73 0 : return ( pos1.X() < pos2.X() );
74 : }
75 : };
76 :
77 0 : static void ImplTaskPaneListGrabFocus( vcl::Window *pWindow, bool bForward )
78 : {
79 : // put focus in child of floating windows which is typically a toolbar
80 : // that can deal with the focus
81 0 : if( pWindow->ImplIsFloatingWindow() && pWindow->GetWindow( WINDOW_FIRSTCHILD ) )
82 0 : pWindow = pWindow->GetWindow( WINDOW_FIRSTCHILD );
83 0 : pWindow->ImplGrabFocus( GETFOCUS_F6 | (bForward ? GETFOCUS_FORWARD : GETFOCUS_BACKWARD));
84 0 : }
85 :
86 5548 : TaskPaneList::TaskPaneList()
87 : {
88 5548 : }
89 :
90 5542 : TaskPaneList::~TaskPaneList()
91 : {
92 5542 : }
93 :
94 33866 : void TaskPaneList::AddWindow( vcl::Window *pWindow )
95 : {
96 33866 : if( pWindow )
97 : {
98 33866 : ::std::vector< vcl::Window* >::iterator insertionPos = mTaskPanes.end();
99 366390 : for ( ::std::vector< vcl::Window* >::iterator p = mTaskPanes.begin();
100 244260 : p != mTaskPanes.end();
101 : ++p
102 : )
103 : {
104 88268 : if ( *p == pWindow )
105 : // avoid duplicates
106 33866 : return;
107 :
108 : // If the new window is the child of an existing pane window, or vice versa,
109 : // ensure that in our pane list, *first* the child window appears, *then*
110 : // the ancestor window.
111 : // This is necessary for HandleKeyEvent: There, the list is traveled from the
112 : // beginning, until the first window is found which has the ChildPathFocus. Now
113 : // if this would be the ancestor window of another pane window, this would fudge
114 : // the result
115 88268 : if ( pWindow->IsWindowOrChild( *p ) )
116 : {
117 0 : insertionPos = p + 1;
118 0 : break;
119 : }
120 88268 : if ( (*p)->IsWindowOrChild( pWindow ) )
121 : {
122 4 : insertionPos = p;
123 4 : break;
124 : }
125 : }
126 :
127 33866 : mTaskPanes.insert( insertionPos, pWindow );
128 33866 : pWindow->ImplIsInTaskPaneList( true );
129 : }
130 : }
131 :
132 33852 : void TaskPaneList::RemoveWindow( vcl::Window *pWindow )
133 : {
134 33852 : ::std::vector< vcl::Window* >::iterator p;
135 33852 : p = ::std::find( mTaskPanes.begin(), mTaskPanes.end(), pWindow );
136 33852 : if( p != mTaskPanes.end() )
137 : {
138 33852 : mTaskPanes.erase( p );
139 33852 : pWindow->ImplIsInTaskPaneList( false );
140 : }
141 33852 : }
142 :
143 26312 : bool TaskPaneList::IsInList( vcl::Window *pWindow )
144 : {
145 26312 : ::std::vector< vcl::Window* >::iterator p;
146 26312 : p = ::std::find( mTaskPanes.begin(), mTaskPanes.end(), pWindow );
147 26312 : if( p != mTaskPanes.end() )
148 11542 : return true;
149 : else
150 14770 : return false;
151 : }
152 :
153 0 : bool TaskPaneList::HandleKeyEvent( KeyEvent aKeyEvent )
154 : {
155 :
156 : // F6 cycles through everything and works always
157 :
158 : // MAV, #i104204#
159 : // The old design was the following one:
160 : // < Ctrl-TAB cycles through Menubar, Toolbars and Floatingwindows only and is
161 : // < only active if one of those items has the focus
162 :
163 : // Since the design of Ctrl-Tab looks to be inconsistent ( non-modal dialogs are not reachable
164 : // and the shortcut conflicts with tab-control shortcut ), it is no more supported
165 0 : bool bSplitterOnly = false;
166 0 : bool bFocusInList = false;
167 0 : vcl::KeyCode aKeyCode = aKeyEvent.GetKeyCode();
168 0 : bool bForward = !aKeyCode.IsShift();
169 0 : if( aKeyCode.GetCode() == KEY_F6 && ! aKeyCode.IsMod2() ) // F6
170 : {
171 0 : bSplitterOnly = aKeyCode.IsMod1() && aKeyCode.IsShift();
172 :
173 : // is the focus in the list ?
174 0 : ::std::vector< vcl::Window* >::iterator p = mTaskPanes.begin();
175 0 : while( p != mTaskPanes.end() )
176 : {
177 0 : vcl::Window *pWin = *p;
178 0 : if( pWin->HasChildPathFocus( true ) )
179 : {
180 0 : bFocusInList = true;
181 :
182 : // Ctrl-F6 goes directly to the document
183 0 : if( !pWin->IsDialog() && aKeyCode.IsMod1() && !aKeyCode.IsShift() )
184 : {
185 0 : pWin->ImplGrabFocusToDocument( GETFOCUS_F6 );
186 0 : return true;
187 : }
188 :
189 : // activate next task pane
190 0 : vcl::Window *pNextWin = NULL;
191 :
192 0 : if( bSplitterOnly )
193 0 : pNextWin = FindNextSplitter( *p, true );
194 : else
195 0 : pNextWin = FindNextFloat( *p, bForward );
196 :
197 0 : if( pNextWin != pWin )
198 : {
199 0 : ImplGetSVData()->maWinData.mbNoSaveFocus = true;
200 0 : ImplTaskPaneListGrabFocus( pNextWin, bForward );
201 0 : ImplGetSVData()->maWinData.mbNoSaveFocus = false;
202 : }
203 : else
204 : {
205 : // forward key if no splitter found
206 0 : if( bSplitterOnly )
207 0 : return false;
208 :
209 : // we did not find another taskpane, so
210 : // put focus back into document
211 0 : pWin->ImplGrabFocusToDocument( GETFOCUS_F6 | (bForward ? GETFOCUS_FORWARD : GETFOCUS_BACKWARD));
212 : }
213 :
214 0 : return true;
215 : }
216 : else
217 0 : ++p;
218 : }
219 :
220 : // the focus is not in the list: activate first float if F6 was pressed
221 0 : if( !bFocusInList )
222 : {
223 : vcl::Window *pWin;
224 0 : if( bSplitterOnly )
225 0 : pWin = FindNextSplitter( NULL, true );
226 : else
227 0 : pWin = FindNextFloat( NULL, bForward );
228 0 : if( pWin )
229 : {
230 0 : ImplTaskPaneListGrabFocus( pWin, bForward );
231 0 : return true;
232 : }
233 : }
234 : }
235 :
236 0 : return false;
237 : }
238 :
239 : // returns next splitter
240 0 : vcl::Window* TaskPaneList::FindNextSplitter( vcl::Window *pWindow, bool bForward )
241 : {
242 0 : if( bForward )
243 0 : ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSort() );
244 : else
245 0 : ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSortBackward() );
246 :
247 0 : ::std::vector< vcl::Window* >::iterator p = mTaskPanes.begin();
248 0 : while( p != mTaskPanes.end() )
249 : {
250 0 : if( !pWindow || *p == pWindow )
251 : {
252 0 : unsigned n = mTaskPanes.size();
253 0 : while( --n )
254 : {
255 0 : if( pWindow ) // increment before test
256 0 : ++p;
257 0 : if( p == mTaskPanes.end() )
258 0 : p = mTaskPanes.begin();
259 0 : if( (*p)->ImplIsSplitter() && (*p)->IsReallyVisible() && !(*p)->IsDialog() && (*p)->GetParent()->HasChildPathFocus() )
260 : {
261 0 : pWindow = *p;
262 0 : break;
263 : }
264 0 : if( !pWindow ) // increment after test, otherwise first element is skipped
265 0 : ++p;
266 : }
267 0 : break;
268 : }
269 : else
270 0 : ++p;
271 : }
272 :
273 0 : return pWindow;
274 : }
275 :
276 : // returns first valid item (regardless of type) if pWindow==0, otherwise returns next valid float
277 0 : vcl::Window* TaskPaneList::FindNextFloat( vcl::Window *pWindow, bool bForward )
278 : {
279 0 : if( bForward )
280 0 : ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSort() );
281 : else
282 0 : ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSortBackward() );
283 :
284 0 : ::std::vector< vcl::Window* >::iterator p = mTaskPanes.begin();
285 0 : while( p != mTaskPanes.end() )
286 : {
287 0 : if( !pWindow || *p == pWindow )
288 : {
289 0 : while( p != mTaskPanes.end() )
290 : {
291 0 : if( pWindow ) // increment before test
292 0 : ++p;
293 0 : if( p == mTaskPanes.end() )
294 0 : break; // do not wrap, send focus back to document at end of list
295 : /* #i83908# do not use the menubar if it is native and invisible
296 : this relies on MenuBar::ImplCreate setting the height of the menubar
297 : to 0 in this case
298 : */
299 0 : if( (*p)->IsReallyVisible() && !(*p)->ImplIsSplitter() &&
300 0 : ( (*p)->GetType() != WINDOW_MENUBARWINDOW || (*p)->GetSizePixel().Height() > 0 )
301 : )
302 : {
303 0 : pWindow = *p;
304 0 : break;
305 : }
306 0 : if( !pWindow ) // increment after test, otherwise first element is skipped
307 0 : ++p;
308 : }
309 0 : break;
310 : }
311 : else
312 0 : ++p;
313 : }
314 :
315 0 : return pWindow;
316 1233 : }
317 :
318 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|