1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_vcl.hxx" 26 27 #include <tools/rcid.h> 28 29 #include <vcl/dockwin.hxx> 30 #include <vcl/taskpanelist.hxx> 31 32 #include <svdata.hxx> 33 34 #include <functional> 35 #include <algorithm> 36 37 // can't have static linkage because SUNPRO 5.2 complains 38 Point ImplTaskPaneListGetPos( const Window *w ) 39 { 40 Point pos; 41 if( w->ImplIsDockingWindow() ) 42 { 43 pos = ((DockingWindow*)w)->GetPosPixel(); 44 Window *pF = ((DockingWindow*)w)->GetFloatingWindow(); 45 if( pF ) 46 pos = pF->OutputToAbsoluteScreenPixel( pF->ScreenToOutputPixel( pos ) ); 47 else 48 pos = w->OutputToAbsoluteScreenPixel( pos ); 49 } 50 else 51 pos = w->OutputToAbsoluteScreenPixel( w->GetPosPixel() ); 52 53 return pos; 54 } 55 56 // compares window pos left-to-right 57 struct LTRSort : public ::std::binary_function< const Window*, const Window*, bool > 58 { 59 bool operator()( const Window* w1, const Window* w2 ) const 60 { 61 Point pos1(ImplTaskPaneListGetPos( w1 )); 62 Point pos2(ImplTaskPaneListGetPos( w2 )); 63 64 if( pos1.X() == pos2.X() ) 65 return ( pos1.Y() < pos2.Y() ); 66 else 67 return ( pos1.X() < pos2.X() ); 68 } 69 }; 70 struct LTRSortBackward : public ::std::binary_function< const Window*, const Window*, bool > 71 { 72 bool operator()( const Window* w2, const Window* w1 ) const 73 { 74 Point pos1(ImplTaskPaneListGetPos( w1 )); 75 Point pos2(ImplTaskPaneListGetPos( w2 )); 76 77 if( pos1.X() == pos2.X() ) 78 return ( pos1.Y() < pos2.Y() ); 79 else 80 return ( pos1.X() < pos2.X() ); 81 } 82 }; 83 84 // -------------------------------------------------- 85 86 static void ImplTaskPaneListGrabFocus( Window *pWindow ) 87 { 88 // put focus in child of floating windows which is typically a toolbar 89 // that can deal with the focus 90 if( pWindow->ImplIsFloatingWindow() && pWindow->GetWindow( WINDOW_FIRSTCHILD ) ) 91 pWindow = pWindow->GetWindow( WINDOW_FIRSTCHILD ); 92 pWindow->GrabFocus(); 93 } 94 95 // -------------------------------------------------- 96 97 TaskPaneList::TaskPaneList() 98 { 99 } 100 101 TaskPaneList::~TaskPaneList() 102 { 103 } 104 105 // -------------------------------------------------- 106 107 void TaskPaneList::AddWindow( Window *pWindow ) 108 { 109 #if OSL_DEBUG_LEVEL > 0 110 bool bDockingWindow=false; 111 bool bToolbox=false; 112 bool bDialog=false; 113 bool bUnknown=false; 114 #endif 115 116 if( pWindow ) 117 { 118 #if OSL_DEBUG_LEVEL > 0 119 if( pWindow->GetType() == RSC_DOCKINGWINDOW ) 120 bDockingWindow = true; 121 else if( pWindow->GetType() == RSC_TOOLBOX ) 122 bToolbox = true; 123 else if( pWindow->IsDialog() ) 124 bDialog = true; 125 else 126 bUnknown = true; 127 #endif 128 129 ::std::vector< Window* >::iterator insertionPos = mTaskPanes.end(); 130 for ( ::std::vector< Window* >::iterator p = mTaskPanes.begin(); 131 p != mTaskPanes.end(); 132 ++p 133 ) 134 { 135 if ( *p == pWindow ) 136 // avoid duplicates 137 return; 138 139 // If the new window is the child of an existing pane window, or vice versa, 140 // ensure that in our pane list, *first* the child window appears, *then* 141 // the ancestor window. 142 // This is necessary for HandleKeyEvent: There, the list is traveled from the 143 // beginning, until the first window is found which has the ChildPathFocus. Now 144 // if this would be the ancestor window of another pane window, this would fudge 145 // the result 146 // 2004-09-27 - fs@openoffice.org, while fixing #i33573#, which included replacing 147 // the original fix for #98916# with this one here. 148 if ( pWindow->IsWindowOrChild( *p ) ) 149 { 150 insertionPos = p + 1; 151 break; 152 } 153 if ( (*p)->IsWindowOrChild( pWindow ) ) 154 { 155 insertionPos = p; 156 break; 157 } 158 } 159 160 mTaskPanes.insert( insertionPos, pWindow ); 161 pWindow->ImplIsInTaskPaneList( sal_True ); 162 } 163 } 164 165 // -------------------------------------------------- 166 167 void TaskPaneList::RemoveWindow( Window *pWindow ) 168 { 169 ::std::vector< Window* >::iterator p; 170 p = ::std::find( mTaskPanes.begin(), mTaskPanes.end(), pWindow ); 171 if( p != mTaskPanes.end() ) 172 { 173 mTaskPanes.erase( p ); 174 pWindow->ImplIsInTaskPaneList( sal_False ); 175 } 176 } 177 178 // -------------------------------------------------- 179 180 sal_Bool TaskPaneList::IsInList( Window *pWindow ) 181 { 182 ::std::vector< Window* >::iterator p; 183 p = ::std::find( mTaskPanes.begin(), mTaskPanes.end(), pWindow ); 184 if( p != mTaskPanes.end() ) 185 return sal_True; 186 else 187 return sal_False; 188 } 189 190 // -------------------------------------------------- 191 192 sal_Bool TaskPaneList::HandleKeyEvent( KeyEvent aKeyEvent ) 193 { 194 195 // F6 cycles through everything and works always 196 197 // MAV, #i104204# 198 // The old design was the following one: 199 // < Ctrl-TAB cycles through Menubar, Toolbars and Floatingwindows only and is 200 // < only active if one of those items has the focus 201 // 202 // Since the design of Ctrl-Tab looks to be inconsistent ( non-modal dialogs are not reachable 203 // and the shortcut conflicts with tab-control shortcut ), it is no more supported 204 sal_Bool bSplitterOnly = sal_False; 205 sal_Bool bFocusInList = sal_False; 206 KeyCode aKeyCode = aKeyEvent.GetKeyCode(); 207 sal_Bool bForward = !aKeyCode.IsShift(); 208 if( aKeyCode.GetCode() == KEY_F6 && ! aKeyCode.IsMod2() ) // F6 209 { 210 bSplitterOnly = aKeyCode.IsMod1() && aKeyCode.IsShift(); 211 212 // is the focus in the list ? 213 ::std::vector< Window* >::iterator p = mTaskPanes.begin(); 214 while( p != mTaskPanes.end() ) 215 { 216 Window *pWin = *p; 217 if( pWin->HasChildPathFocus( sal_True ) ) 218 { 219 bFocusInList = sal_True; 220 221 // Ctrl-F6 goes directly to the document 222 if( !pWin->IsDialog() && aKeyCode.IsMod1() && !aKeyCode.IsShift() ) 223 { 224 pWin->GrabFocusToDocument(); 225 return sal_True; 226 } 227 228 // activate next task pane 229 Window *pNextWin = NULL; 230 231 if( bSplitterOnly ) 232 pNextWin = FindNextSplitter( *p, sal_True ); 233 else 234 pNextWin = FindNextFloat( *p, bForward ); 235 236 if( pNextWin != pWin ) 237 { 238 ImplGetSVData()->maWinData.mbNoSaveFocus = sal_True; 239 ImplTaskPaneListGrabFocus( pNextWin ); 240 ImplGetSVData()->maWinData.mbNoSaveFocus = sal_False; 241 } 242 else 243 { 244 // forward key if no splitter found 245 if( bSplitterOnly ) 246 return sal_False; 247 248 // we did not find another taskpane, so 249 // put focus back into document 250 pWin->GrabFocusToDocument(); 251 } 252 253 return sal_True; 254 } 255 else 256 p++; 257 } 258 259 // the focus is not in the list: activate first float if F6 was pressed 260 if( !bFocusInList ) 261 { 262 Window *pWin; 263 if( bSplitterOnly ) 264 pWin = FindNextSplitter( NULL, sal_True ); 265 else 266 pWin = FindNextFloat( NULL, bForward ); 267 if( pWin ) 268 { 269 ImplTaskPaneListGrabFocus( pWin ); 270 return sal_True; 271 } 272 } 273 } 274 275 return sal_False; 276 } 277 278 // -------------------------------------------------- 279 280 // returns next valid pane 281 Window* TaskPaneList::FindNextPane( Window *pWindow, sal_Bool bForward ) 282 { 283 if( bForward ) 284 ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSort() ); 285 else 286 ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSortBackward() ); 287 288 ::std::vector< Window* >::iterator p = mTaskPanes.begin(); 289 while( p != mTaskPanes.end() ) 290 { 291 if( *p == pWindow ) 292 { 293 unsigned n = mTaskPanes.size(); 294 while( --n ) 295 { 296 if( ++p == mTaskPanes.end() ) 297 p = mTaskPanes.begin(); 298 if( (*p)->IsReallyVisible() && !(*p)->IsDialog() && !(*p)->ImplIsSplitter() ) 299 { 300 pWindow = *p; 301 break; 302 } 303 } 304 break; 305 } 306 else 307 ++p; 308 } 309 310 return pWindow; 311 } 312 313 // -------------------------------------------------- 314 315 // returns next splitter 316 Window* TaskPaneList::FindNextSplitter( Window *pWindow, sal_Bool bForward ) 317 { 318 if( bForward ) 319 ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSort() ); 320 else 321 ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSortBackward() ); 322 323 ::std::vector< Window* >::iterator p = mTaskPanes.begin(); 324 while( p != mTaskPanes.end() ) 325 { 326 if( !pWindow || *p == pWindow ) 327 { 328 unsigned n = mTaskPanes.size(); 329 while( --n ) 330 { 331 if( pWindow ) // increment before test 332 ++p; 333 if( p == mTaskPanes.end() ) 334 p = mTaskPanes.begin(); 335 if( (*p)->ImplIsSplitter() && (*p)->IsReallyVisible() && !(*p)->IsDialog() && (*p)->GetParent()->HasChildPathFocus() ) 336 { 337 pWindow = *p; 338 break; 339 } 340 if( !pWindow ) // increment after test, otherwise first element is skipped 341 ++p; 342 } 343 break; 344 } 345 else 346 ++p; 347 } 348 349 return pWindow; 350 } 351 352 // -------------------------------------------------- 353 354 // returns first valid item (regardless of type) if pWindow==0, otherwise returns next valid float 355 Window* TaskPaneList::FindNextFloat( Window *pWindow, sal_Bool bForward ) 356 { 357 if( bForward ) 358 ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSort() ); 359 else 360 ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSortBackward() ); 361 362 ::std::vector< Window* >::iterator p = mTaskPanes.begin(); 363 while( p != mTaskPanes.end() ) 364 { 365 if( !pWindow || *p == pWindow ) 366 { 367 while( p != mTaskPanes.end() ) 368 { 369 if( pWindow ) // increment before test 370 ++p; 371 if( p == mTaskPanes.end() ) 372 break; // do not wrap, send focus back to document at end of list 373 /* #i83908# do not use the menubar if it is native and invisible 374 this relies on MenuBar::ImplCreate setting the height of the menubar 375 to 0 in this case 376 */ 377 if( (*p)->IsReallyVisible() && !(*p)->ImplIsSplitter() && 378 ( (*p)->GetType() != WINDOW_MENUBARWINDOW || (*p)->GetSizePixel().Height() > 0 ) 379 ) 380 { 381 pWindow = *p; 382 break; 383 } 384 if( !pWindow ) // increment after test, otherwise first element is skipped 385 ++p; 386 } 387 break; 388 } 389 else 390 ++p; 391 } 392 393 return pWindow; 394 } 395 396 // -------------------------------------------------- 397 398