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_dbaccess.hxx" 26 27 #ifndef DBAUI_DBTREELISTBOX_HXX 28 #include "dbtreelistbox.hxx" 29 #endif 30 #ifndef _DBU_RESOURCE_HRC_ 31 #include "dbu_resource.hrc" 32 #endif 33 #ifndef DBACCESS_UI_BROWSER_ID_HXX 34 #include "browserids.hxx" 35 #endif 36 #ifndef _DBAUI_LISTVIEWITEMS_HXX_ 37 #include "listviewitems.hxx" 38 #endif 39 #ifndef _DBACCESS_UI_CALLBACKS_HXX_ 40 #include "callbacks.hxx" 41 #endif 42 43 #ifndef _COM_SUN_STAR_DATATRANSFER_DND_XDRAGGESTURELISTENER_HDL_ 44 #include <com/sun/star/datatransfer/dnd/XDragGestureListener.hdl> 45 #endif 46 #ifndef _COM_SUN_STAR_DATATRANSFER_DND_XDRAGGESTURERECOGNIZER_HPP_ 47 #include <com/sun/star/datatransfer/dnd/XDragGestureRecognizer.hpp> 48 #endif 49 #ifndef _COM_SUN_STAR_UI_XCONTEXTMENUINTERCEPTOR_HPP_ 50 #include <com/sun/star/ui/XContextMenuInterceptor.hpp> 51 #endif 52 #include <com/sun/star/frame/XFrame.hpp> 53 #ifndef _COM_SUN_STAR_UTIL_URL_HPP_ 54 #include <com/sun/star/util/URL.hpp> 55 #endif 56 #ifndef _CPPUHELPER_IMPLBASE1_HXX_ 57 #include <cppuhelper/implbase1.hxx> 58 #endif 59 #ifndef _CPPUHELPER_INTERFACECONTAINER_HXX_ 60 #include <cppuhelper/interfacecontainer.hxx> 61 #endif 62 #ifndef _SV_HELP_HXX 63 #include <vcl/help.hxx> 64 #endif 65 #ifndef _DBAUI_TABLETREE_HRC_ 66 #include "tabletree.hrc" 67 #endif 68 #ifndef DBAUI_ICONTROLLER_HXX 69 #include "IController.hxx" 70 #endif 71 #ifndef __FRAMEWORK_HELPER_ACTIONTRIGGERHELPER_HXX_ 72 #include <framework/actiontriggerhelper.hxx> 73 #endif 74 #ifndef _TOOLKIT_HELPER_VCLUNOHELPER_HXX_ 75 #include <toolkit/helper/vclunohelper.hxx> 76 #endif 77 #include <framework/imageproducer.hxx> 78 #include <vcl/svapp.hxx> 79 #include <memory> 80 81 // ......................................................................... 82 namespace dbaui 83 { 84 // ......................................................................... 85 86 using namespace ::com::sun::star; 87 using namespace ::com::sun::star::uno; 88 using namespace ::com::sun::star::beans; 89 using namespace ::com::sun::star::lang; 90 using namespace ::com::sun::star::datatransfer; 91 using namespace ::com::sun::star::frame; 92 using namespace ::com::sun::star::ui; 93 using namespace ::com::sun::star::view; 94 95 DBG_NAME(DBTreeListBox) 96 #define SPACEBETWEENENTRIES 4 97 //======================================================================== 98 // class DBTreeListBox 99 //======================================================================== 100 //------------------------------------------------------------------------ 101 DBTreeListBox::DBTreeListBox( Window* pParent, const Reference< XMultiServiceFactory >& _rxORB, WinBits nWinStyle ,sal_Bool _bHandleEnterKey) 102 :SvTreeListBox(pParent,nWinStyle) 103 ,m_pDragedEntry(NULL) 104 ,m_pActionListener(NULL) 105 ,m_pContextMenuProvider( NULL ) 106 ,m_bHandleEnterKey(_bHandleEnterKey) 107 ,m_xORB(_rxORB) 108 { 109 DBG_CTOR(DBTreeListBox,NULL); 110 init(); 111 } 112 // ----------------------------------------------------------------------------- 113 DBTreeListBox::DBTreeListBox( Window* pParent, const Reference< XMultiServiceFactory >& _rxORB, const ResId& rResId,sal_Bool _bHandleEnterKey) 114 :SvTreeListBox(pParent,rResId) 115 ,m_pDragedEntry(NULL) 116 ,m_pActionListener(NULL) 117 ,m_pContextMenuProvider( NULL ) 118 ,m_bHandleEnterKey(_bHandleEnterKey) 119 ,m_xORB(_rxORB) 120 { 121 DBG_CTOR(DBTreeListBox,NULL); 122 init(); 123 } 124 // ----------------------------------------------------------------------------- 125 void DBTreeListBox::init() 126 { 127 sal_uInt16 nSize = SPACEBETWEENENTRIES; 128 SetSpaceBetweenEntries(nSize); 129 130 m_aTimer.SetTimeout(900); 131 m_aTimer.SetTimeoutHdl(LINK(this, DBTreeListBox, OnTimeOut)); 132 133 m_aScrollHelper.setUpScrollMethod( LINK(this, DBTreeListBox, ScrollUpHdl) ); 134 m_aScrollHelper.setDownScrollMethod( LINK(this, DBTreeListBox, ScrollDownHdl) ); 135 136 SetNodeDefaultImages( ); 137 138 EnableContextMenuHandling(); 139 140 SetStyle( GetStyle() | WB_QUICK_SEARCH ); 141 } 142 //------------------------------------------------------------------------ 143 DBTreeListBox::~DBTreeListBox() 144 { 145 DBG_DTOR(DBTreeListBox,NULL); 146 implStopSelectionTimer(); 147 } 148 //------------------------------------------------------------------------ 149 SvLBoxEntry* DBTreeListBox::GetEntryPosByName( const String& aName, SvLBoxEntry* pStart, const IEntryFilter* _pFilter ) const 150 { 151 SvLBoxTreeList* myModel = GetModel(); 152 SvTreeEntryList* pChilds = myModel->GetChildList(pStart); 153 SvLBoxEntry* pEntry = NULL; 154 if ( pChilds ) 155 { 156 sal_uLong nCount = pChilds->Count(); 157 for (sal_uLong i=0; i < nCount; ++i) 158 { 159 pEntry = static_cast<SvLBoxEntry*>(pChilds->GetObject(i)); 160 SvLBoxString* pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); 161 if ( pItem->GetText().Equals(aName) ) 162 { 163 if ( !_pFilter || _pFilter->includeEntry( pEntry ) ) 164 // found 165 break; 166 } 167 pEntry = NULL; 168 } 169 } 170 171 return pEntry; 172 } 173 174 // ------------------------------------------------------------------------- 175 void DBTreeListBox::EnableExpandHandler(SvLBoxEntry* _pEntry) 176 { 177 LINK(this, DBTreeListBox, OnResetEntry).Call(_pEntry); 178 } 179 180 // ------------------------------------------------------------------------- 181 void DBTreeListBox::RequestingChilds( SvLBoxEntry* pParent ) 182 { 183 if (m_aPreExpandHandler.IsSet()) 184 { 185 if (!m_aPreExpandHandler.Call(pParent)) 186 { 187 // an error occured. The method calling us will reset the entry flags, so it can't be expanded again. 188 // But we want that the user may do a second try (i.e. because he misstypes a password in this try), so 189 // we have to reset these flags controlling the expand ability 190 PostUserEvent(LINK(this, DBTreeListBox, OnResetEntry), pParent); 191 } 192 } 193 } 194 195 // ------------------------------------------------------------------------- 196 void DBTreeListBox::InitEntry( SvLBoxEntry* _pEntry, const XubString& aStr, const Image& _rCollEntryBmp, const Image& _rExpEntryBmp, SvLBoxButtonKind eButtonKind) 197 { 198 SvTreeListBox::InitEntry( _pEntry, aStr, _rCollEntryBmp,_rExpEntryBmp, eButtonKind); 199 SvLBoxItem* pTextItem(_pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); 200 SvLBoxString* pString = new OBoldListboxString( _pEntry, 0, aStr ); 201 _pEntry->ReplaceItem( pString,_pEntry->GetPos(pTextItem)); 202 } 203 204 // ------------------------------------------------------------------------- 205 void DBTreeListBox::implStopSelectionTimer() 206 { 207 if ( m_aTimer.IsActive() ) 208 m_aTimer.Stop(); 209 } 210 211 // ------------------------------------------------------------------------- 212 void DBTreeListBox::implStartSelectionTimer() 213 { 214 implStopSelectionTimer(); 215 m_aTimer.Start(); 216 } 217 218 // ----------------------------------------------------------------------------- 219 220 void DBTreeListBox::DeselectHdl() 221 { 222 m_aSelectedEntries.erase( GetHdlEntry() ); 223 SvTreeListBox::DeselectHdl(); 224 implStartSelectionTimer(); 225 } 226 // ------------------------------------------------------------------------- 227 void DBTreeListBox::SelectHdl() 228 { 229 m_aSelectedEntries.insert( GetHdlEntry() ); 230 SvTreeListBox::SelectHdl(); 231 implStartSelectionTimer(); 232 } 233 234 // ------------------------------------------------------------------------- 235 void DBTreeListBox::MouseButtonDown( const MouseEvent& rMEvt ) 236 { 237 sal_Bool bHitEmptySpace = (NULL == GetEntry(rMEvt.GetPosPixel(), sal_True)); 238 if (bHitEmptySpace && (rMEvt.GetClicks() == 2) && rMEvt.IsMod1()) 239 Control::MouseButtonDown(rMEvt); 240 else 241 SvTreeListBox::MouseButtonDown(rMEvt); 242 } 243 244 // ------------------------------------------------------------------------- 245 IMPL_LINK(DBTreeListBox, OnResetEntry, SvLBoxEntry*, pEntry) 246 { 247 // set the flag which allows if the entry can be expanded 248 pEntry->SetFlags( (pEntry->GetFlags() & ~(SV_ENTRYFLAG_NO_NODEBMP | SV_ENTRYFLAG_HAD_CHILDREN)) | SV_ENTRYFLAG_CHILDS_ON_DEMAND ); 249 // redraw the entry 250 GetModel()->InvalidateEntry( pEntry ); 251 return 0L; 252 } 253 // ----------------------------------------------------------------------------- 254 void DBTreeListBox::ModelHasEntryInvalidated( SvListEntry* _pEntry ) 255 { 256 SvTreeListBox::ModelHasEntryInvalidated( _pEntry ); 257 258 if ( m_aSelectedEntries.find( _pEntry ) != m_aSelectedEntries.end() ) 259 { 260 SvLBoxItem* pTextItem = static_cast< SvLBoxEntry* >( _pEntry )->GetFirstItem( SV_ITEM_ID_BOLDLBSTRING ); 261 if ( pTextItem && !static_cast< OBoldListboxString* >( pTextItem )->isEmphasized() ) 262 { 263 implStopSelectionTimer(); 264 m_aSelectedEntries.erase( _pEntry ); 265 // ehm - why? 266 } 267 } 268 } 269 // ------------------------------------------------------------------------- 270 void DBTreeListBox::ModelHasRemoved( SvListEntry* _pEntry ) 271 { 272 SvTreeListBox::ModelHasRemoved(_pEntry); 273 if ( m_aSelectedEntries.find( _pEntry ) != m_aSelectedEntries.end() ) 274 { 275 implStopSelectionTimer(); 276 m_aSelectedEntries.erase( _pEntry ); 277 } 278 } 279 280 // ------------------------------------------------------------------------- 281 sal_Int8 DBTreeListBox::AcceptDrop( const AcceptDropEvent& _rEvt ) 282 { 283 sal_Int8 nDropOption = DND_ACTION_NONE; 284 if ( m_pActionListener ) 285 { 286 SvLBoxEntry* pDroppedEntry = GetEntry(_rEvt.maPosPixel); 287 // check if drag is on child entry, which is not allowed 288 SvLBoxEntry* pParent = NULL; 289 if ( _rEvt.mnAction & DND_ACTION_MOVE ) 290 { 291 if ( !m_pDragedEntry ) // no entry to move 292 { 293 nDropOption = m_pActionListener->queryDrop( _rEvt, GetDataFlavorExVector() ); 294 m_aMousePos = _rEvt.maPosPixel; 295 m_aScrollHelper.scroll(m_aMousePos,GetOutputSizePixel()); 296 return nDropOption; 297 } 298 299 pParent = pDroppedEntry ? GetParent(pDroppedEntry) : NULL; 300 while ( pParent && pParent != m_pDragedEntry ) 301 pParent = GetParent(pParent); 302 } 303 304 if ( !pParent ) 305 { 306 nDropOption = m_pActionListener->queryDrop( _rEvt, GetDataFlavorExVector() ); 307 // check if move is allowed 308 if ( nDropOption & DND_ACTION_MOVE ) 309 { 310 if ( m_pDragedEntry == pDroppedEntry || GetEntryPosByName(GetEntryText(m_pDragedEntry),pDroppedEntry) ) 311 nDropOption = nDropOption & ~DND_ACTION_MOVE;//DND_ACTION_NONE; 312 } 313 m_aMousePos = _rEvt.maPosPixel; 314 m_aScrollHelper.scroll(m_aMousePos,GetOutputSizePixel()); 315 } 316 } 317 318 return nDropOption; 319 } 320 321 // ------------------------------------------------------------------------- 322 sal_Int8 DBTreeListBox::ExecuteDrop( const ExecuteDropEvent& _rEvt ) 323 { 324 if ( m_pActionListener ) 325 return m_pActionListener->executeDrop( _rEvt ); 326 327 return DND_ACTION_NONE; 328 } 329 330 // ------------------------------------------------------------------------- 331 void DBTreeListBox::StartDrag( sal_Int8 _nAction, const Point& _rPosPixel ) 332 { 333 if ( m_pActionListener ) 334 { 335 m_pDragedEntry = GetEntry(_rPosPixel); 336 if ( m_pDragedEntry && m_pActionListener->requestDrag( _nAction, _rPosPixel ) ) 337 { 338 // if the (asynchronous) drag started, stop the selection timer 339 implStopSelectionTimer(); 340 // and stop selecting entries by simply moving the mouse 341 EndSelection(); 342 } 343 } 344 } 345 346 // ------------------------------------------------------------------------- 347 void DBTreeListBox::RequestHelp( const HelpEvent& rHEvt ) 348 { 349 if ( !m_pActionListener ) 350 { 351 SvTreeListBox::RequestHelp( rHEvt ); 352 return; 353 } 354 355 if( rHEvt.GetMode() & HELPMODE_QUICK ) 356 { 357 Point aPos( ScreenToOutputPixel( rHEvt.GetMousePosPixel() )); 358 SvLBoxEntry* pEntry = GetEntry( aPos ); 359 if( pEntry ) 360 { 361 String sQuickHelpText; 362 if ( m_pActionListener->requestQuickHelp( pEntry, sQuickHelpText ) ) 363 { 364 Size aSize( GetOutputSizePixel().Width(), GetEntryHeight() ); 365 Rectangle aScreenRect( OutputToScreenPixel( GetEntryPosition( pEntry ) ), aSize ); 366 367 Help::ShowQuickHelp( this, aScreenRect, 368 sQuickHelpText, QUICKHELP_LEFT | QUICKHELP_VCENTER ); 369 return; 370 } 371 } 372 } 373 374 SvTreeListBox::RequestHelp( rHEvt ); 375 } 376 377 // ----------------------------------------------------------------------------- 378 void DBTreeListBox::KeyInput( const KeyEvent& rKEvt ) 379 { 380 KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction(); 381 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); 382 sal_Bool bHandled = sal_False; 383 384 if(eFunc != KEYFUNC_DONTKNOW) 385 { 386 switch(eFunc) 387 { 388 case KEYFUNC_CUT: 389 bHandled = ( m_aCutHandler.IsSet() && !m_aSelectedEntries.empty() ); 390 if ( bHandled ) 391 m_aCutHandler.Call( NULL ); 392 break; 393 case KEYFUNC_COPY: 394 bHandled = ( m_aCopyHandler.IsSet() && !m_aSelectedEntries.empty() ); 395 if ( bHandled ) 396 m_aCopyHandler.Call( NULL ); 397 break; 398 case KEYFUNC_PASTE: 399 bHandled = ( m_aPasteHandler.IsSet() && !m_aSelectedEntries.empty() ); 400 if ( bHandled ) 401 m_aPasteHandler.Call( NULL ); 402 break; 403 case KEYFUNC_DELETE: 404 bHandled = ( m_aDeleteHandler.IsSet() && !m_aSelectedEntries.empty() ); 405 if ( bHandled ) 406 m_aDeleteHandler.Call( NULL ); 407 break; 408 default: 409 break; 410 } 411 } 412 413 if ( KEY_RETURN == nCode ) 414 { 415 bHandled = m_bHandleEnterKey; 416 if ( m_aEnterKeyHdl.IsSet() ) 417 m_aEnterKeyHdl.Call(this); 418 // this is a HACK. If the data source browser is opened in the "beamer", while the main frame 419 // contains a writer document, then pressing enter in the DSB would be rerouted to the writer 420 // document if we would not do this hack here. 421 // The problem is that the Writer uses RETURN as _accelerator_ (which is quite weird itself), 422 // so the SFX framework is _obligated_ to pass it to the Writer if nobody else handled it. There 423 // is no chance to distinguish between 424 // "accelerators which are to be executed if the main document has the focus" 425 // and 426 // "accelerators which are always to be executed" 427 // 428 // Thus we cannot prevent the handling of this key in the writer without declaring the key event 429 // as "handled" herein. 430 // 431 // The bad thing about this approach is that it does not scale. Every other accelerator which 432 // is used by the document will raise a similar bug once somebody discovers it. 433 // If this is the case, we should discuss a real solution with the framework (SFX) and the 434 // applications. 435 // 436 // 2002-12-02 - 105831 - fs@openoffice.org 437 } 438 439 if ( !bHandled ) 440 SvTreeListBox::KeyInput(rKEvt); 441 } 442 // ----------------------------------------------------------------------------- 443 sal_Bool DBTreeListBox::EditingEntry( SvLBoxEntry* pEntry, Selection& /*_aSelection*/) 444 { 445 return m_aEditingHandler.Call(pEntry) != 0; 446 } 447 // ----------------------------------------------------------------------------- 448 sal_Bool DBTreeListBox::EditedEntry( SvLBoxEntry* pEntry, const XubString& rNewText ) 449 { 450 DBTreeEditedEntry aEntry; 451 aEntry.pEntry = pEntry; 452 aEntry.aNewText =rNewText; 453 if(m_aEditedHandler.Call(&aEntry) != 0) 454 { 455 implStopSelectionTimer(); 456 m_aSelectedEntries.erase( pEntry ); 457 } 458 SetEntryText(pEntry,aEntry.aNewText); 459 460 return sal_False; // we never want that the base change our text 461 } 462 463 // ----------------------------------------------------------------------------- 464 sal_Bool DBTreeListBox::DoubleClickHdl() 465 { 466 long nResult = aDoubleClickHdl.Call( this ); 467 // continue default processing if the DoubleClickHandler didn't handle it 468 return nResult == 0; 469 } 470 471 // ----------------------------------------------------------------------------- 472 void scrollWindow(DBTreeListBox* _pListBox, const Point& _rPos,sal_Bool _bUp) 473 { 474 SvLBoxEntry* pEntry = _pListBox->GetEntry( _rPos ); 475 if( pEntry && pEntry != _pListBox->Last() ) 476 { 477 _pListBox->ScrollOutputArea( _bUp ? -1 : 1 ); 478 } 479 } 480 // ----------------------------------------------------------------------------- 481 IMPL_LINK( DBTreeListBox, ScrollUpHdl, SvTreeListBox*, /*pBox*/ ) 482 { 483 scrollWindow(this,m_aMousePos,sal_True); 484 return 0; 485 } 486 487 //------------------------------------------------------------------------------ 488 IMPL_LINK( DBTreeListBox, ScrollDownHdl, SvTreeListBox*, /*pBox*/ ) 489 { 490 scrollWindow(this,m_aMousePos,sal_False); 491 return 0; 492 } 493 // ----------------------------------------------------------------------------- 494 namespace 495 { 496 void lcl_enableEntries( PopupMenu* _pPopup, IController& _rController ) 497 { 498 if ( !_pPopup ) 499 return; 500 501 sal_uInt16 nCount = _pPopup->GetItemCount(); 502 for (sal_uInt16 i=0; i < nCount; ++i) 503 { 504 if ( _pPopup->GetItemType(i) != MENUITEM_SEPARATOR ) 505 { 506 sal_uInt16 nId = _pPopup->GetItemId(i); 507 PopupMenu* pSubPopUp = _pPopup->GetPopupMenu(nId); 508 if ( pSubPopUp ) 509 { 510 lcl_enableEntries( pSubPopUp, _rController ); 511 _pPopup->EnableItem(nId,pSubPopUp->HasValidEntries()); 512 } 513 else 514 { 515 ::rtl::OUString sCommandURL( _pPopup->GetItemCommand( nId ) ); 516 bool bEnabled = ( sCommandURL.getLength() ) 517 ? _rController.isCommandEnabled( sCommandURL ) 518 : _rController.isCommandEnabled( nId ); 519 _pPopup->EnableItem( nId, bEnabled ); 520 } 521 } 522 } 523 524 _pPopup->RemoveDisabledEntries(); 525 } 526 } 527 528 // ----------------------------------------------------------------------------- 529 namespace 530 { 531 void lcl_adjustMenuItemIDs( Menu& _rMenu, IController& _rCommandController ) 532 { 533 sal_uInt16 nCount = _rMenu.GetItemCount(); 534 for ( sal_uInt16 pos = 0; pos < nCount; ++pos ) 535 { 536 // do not adjust separators 537 if ( _rMenu.GetItemType( pos ) == MENUITEM_SEPARATOR ) 538 continue; 539 540 sal_uInt16 nId = _rMenu.GetItemId(pos); 541 String aCommand = _rMenu.GetItemCommand( nId ); 542 PopupMenu* pPopup = _rMenu.GetPopupMenu( nId ); 543 if ( pPopup ) 544 { 545 lcl_adjustMenuItemIDs( *pPopup, _rCommandController ); 546 continue; 547 } // if ( pPopup ) 548 549 const sal_uInt16 nCommandId = _rCommandController.registerCommandURL( aCommand ); 550 _rMenu.InsertItem( nCommandId, _rMenu.GetItemText( nId ), _rMenu.GetItemImage( nId ), 551 _rMenu.GetItemBits( nId ), pos ); 552 553 // more things to preserve: 554 // - the help command 555 ::rtl::OUString sHelpURL = _rMenu.GetHelpCommand( nId ); 556 if ( sHelpURL.getLength() ) 557 _rMenu.SetHelpCommand( nCommandId, sHelpURL ); 558 559 // remove the "old" item 560 _rMenu.RemoveItem( pos+1 ); 561 } 562 } 563 void lcl_insertMenuItemImages( Menu& _rMenu, IController& _rCommandController ) 564 { 565 const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings(); 566 const sal_Bool bHiContrast = rSettings.GetHighContrastMode(); 567 uno::Reference< frame::XController > xController = _rCommandController.getXController(); 568 uno::Reference< frame::XFrame> xFrame; 569 if ( xController.is() ) 570 xFrame = xController->getFrame(); 571 sal_uInt16 nCount = _rMenu.GetItemCount(); 572 for ( sal_uInt16 pos = 0; pos < nCount; ++pos ) 573 { 574 // do not adjust separators 575 if ( _rMenu.GetItemType( pos ) == MENUITEM_SEPARATOR ) 576 continue; 577 578 sal_uInt16 nId = _rMenu.GetItemId(pos); 579 String aCommand = _rMenu.GetItemCommand( nId ); 580 PopupMenu* pPopup = _rMenu.GetPopupMenu( nId ); 581 if ( pPopup ) 582 { 583 lcl_insertMenuItemImages( *pPopup, _rCommandController ); 584 continue; 585 } // if ( pPopup ) 586 587 if ( xFrame.is() ) 588 _rMenu.SetItemImage(nId,framework::GetImageFromURL(xFrame,aCommand,sal_False,bHiContrast)); 589 } 590 } 591 // ========================================================================= 592 // = SelectionSupplier 593 // ========================================================================= 594 typedef ::cppu::WeakImplHelper1 < XSelectionSupplier 595 > SelectionSupplier_Base; 596 class SelectionSupplier : public SelectionSupplier_Base 597 { 598 public: 599 SelectionSupplier( const Any& _rSelection ) 600 :m_aSelection( _rSelection ) 601 { 602 } 603 604 virtual ::sal_Bool SAL_CALL select( const Any& xSelection ) throw (IllegalArgumentException, RuntimeException); 605 virtual Any SAL_CALL getSelection( ) throw (RuntimeException); 606 virtual void SAL_CALL addSelectionChangeListener( const Reference< XSelectionChangeListener >& xListener ) throw (RuntimeException); 607 virtual void SAL_CALL removeSelectionChangeListener( const Reference< XSelectionChangeListener >& xListener ) throw (RuntimeException); 608 609 protected: 610 virtual ~SelectionSupplier() 611 { 612 } 613 614 private: 615 Any m_aSelection; 616 }; 617 618 //-------------------------------------------------------------------- 619 ::sal_Bool SAL_CALL SelectionSupplier::select( const Any& /*_Selection*/ ) throw (IllegalArgumentException, RuntimeException) 620 { 621 throw IllegalArgumentException(); 622 // API bug: this should be a NoSupportException 623 } 624 625 //-------------------------------------------------------------------- 626 Any SAL_CALL SelectionSupplier::getSelection( ) throw (RuntimeException) 627 { 628 return m_aSelection; 629 } 630 631 //-------------------------------------------------------------------- 632 void SAL_CALL SelectionSupplier::addSelectionChangeListener( const Reference< XSelectionChangeListener >& /*_Listener*/ ) throw (RuntimeException) 633 { 634 OSL_ENSURE( false, "SelectionSupplier::removeSelectionChangeListener: no support!" ); 635 // API bug: this should be a NoSupportException 636 } 637 638 //-------------------------------------------------------------------- 639 void SAL_CALL SelectionSupplier::removeSelectionChangeListener( const Reference< XSelectionChangeListener >& /*_Listener*/ ) throw (RuntimeException) 640 { 641 OSL_ENSURE( false, "SelectionSupplier::removeSelectionChangeListener: no support!" ); 642 // API bug: this should be a NoSupportException 643 } 644 } 645 646 // ----------------------------------------------------------------------------- 647 PopupMenu* DBTreeListBox::CreateContextMenu( void ) 648 { 649 ::std::auto_ptr< PopupMenu > pContextMenu; 650 651 if ( !m_pContextMenuProvider ) 652 return pContextMenu.release(); 653 654 // the basic context menu 655 pContextMenu.reset( m_pContextMenuProvider->getContextMenu( *this ) ); 656 // disable what is not available currently 657 lcl_enableEntries( pContextMenu.get(), m_pContextMenuProvider->getCommandController() ); 658 // set images 659 lcl_insertMenuItemImages( *pContextMenu, m_pContextMenuProvider->getCommandController() ); 660 // allow context menu interception 661 ::cppu::OInterfaceContainerHelper* pInterceptors = m_pContextMenuProvider->getContextMenuInterceptors(); 662 if ( !pInterceptors || !pInterceptors->getLength() ) 663 return pContextMenu.release(); 664 665 ContextMenuExecuteEvent aEvent; 666 aEvent.SourceWindow = VCLUnoHelper::GetInterface( this ); 667 aEvent.ExecutePosition.X = -1; 668 aEvent.ExecutePosition.Y = -1; 669 aEvent.ActionTriggerContainer = ::framework::ActionTriggerHelper::CreateActionTriggerContainerFromMenu( 670 m_xORB, pContextMenu.get(), 0 ); 671 aEvent.Selection = new SelectionSupplier( m_pContextMenuProvider->getCurrentSelection( *this ) ); 672 673 ::cppu::OInterfaceIteratorHelper aIter( *pInterceptors ); 674 bool bModifiedMenu = false; 675 bool bAskInterceptors = true; 676 while ( aIter.hasMoreElements() && bAskInterceptors ) 677 { 678 Reference< XContextMenuInterceptor > xInterceptor( aIter.next(), UNO_QUERY ); 679 if ( !xInterceptor.is() ) 680 continue; 681 682 try 683 { 684 ContextMenuInterceptorAction eAction = xInterceptor->notifyContextMenuExecute( aEvent ); 685 switch ( eAction ) 686 { 687 case ContextMenuInterceptorAction_CANCELLED: 688 return NULL; 689 690 case ContextMenuInterceptorAction_EXECUTE_MODIFIED: 691 bModifiedMenu = true; 692 bAskInterceptors = false; 693 break; 694 695 case ContextMenuInterceptorAction_CONTINUE_MODIFIED: 696 bModifiedMenu = true; 697 bAskInterceptors = true; 698 break; 699 700 default: 701 DBG_ERROR( "DBTreeListBox::CreateContextMenu: unexpected return value of the interceptor call!" ); 702 703 case ContextMenuInterceptorAction_IGNORED: 704 break; 705 } 706 } 707 catch( const DisposedException& e ) 708 { 709 if ( e.Context == xInterceptor ) 710 aIter.remove(); 711 } 712 } 713 714 if ( bModifiedMenu ) 715 { 716 // the interceptor(s) modified the menu description => create a new PopupMenu 717 PopupMenu* pModifiedMenu = new PopupMenu; 718 ::framework::ActionTriggerHelper::CreateMenuFromActionTriggerContainer( 719 pModifiedMenu, aEvent.ActionTriggerContainer ); 720 aEvent.ActionTriggerContainer.clear(); 721 pContextMenu.reset( pModifiedMenu ); 722 723 // the interceptors only know command URLs, but our menus primarily work 724 // with IDs -> we need to translate the commands to IDs 725 lcl_adjustMenuItemIDs( *pModifiedMenu, m_pContextMenuProvider->getCommandController() ); 726 } // if ( bModifiedMenu ) 727 728 return pContextMenu.release(); 729 } 730 731 // ----------------------------------------------------------------------------- 732 void DBTreeListBox::ExcecuteContextMenuAction( sal_uInt16 _nSelectedPopupEntry ) 733 { 734 if ( m_pContextMenuProvider && _nSelectedPopupEntry ) 735 m_pContextMenuProvider->getCommandController().executeChecked( _nSelectedPopupEntry, Sequence< PropertyValue >() ); 736 } 737 738 // ----------------------------------------------------------------------------- 739 IMPL_LINK(DBTreeListBox, OnTimeOut, void*, /*EMPTY_ARG*/) 740 { 741 implStopSelectionTimer(); 742 743 m_aSelChangeHdl.Call( NULL ); 744 return 0L; 745 } 746 // ----------------------------------------------------------------------------- 747 void DBTreeListBox::StateChanged( StateChangedType nStateChange ) 748 { 749 if ( nStateChange == STATE_CHANGE_VISIBLE ) 750 implStopSelectionTimer(); 751 } 752 // ......................................................................... 753 } // namespace dbaui 754 // ......................................................................... 755