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