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