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