xref: /AOO41X/main/dbaccess/source/ui/control/dbtreelistbox.cxx (revision 96de54900b79e13b861fbc62cbf36018b54e21b7)
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 
DBG_NAME(DBTreeListBox)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 // -----------------------------------------------------------------------------
DBTreeListBox(Window * pParent,const Reference<XMultiServiceFactory> & _rxORB,const ResId & rResId,sal_Bool _bHandleEnterKey)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 // -----------------------------------------------------------------------------
init()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 //------------------------------------------------------------------------
~DBTreeListBox()143 DBTreeListBox::~DBTreeListBox()
144 {
145     DBG_DTOR(DBTreeListBox,NULL);
146     implStopSelectionTimer();
147 }
148 //------------------------------------------------------------------------
GetEntryPosByName(const String & aName,SvLBoxEntry * pStart,const IEntryFilter * _pFilter) const149 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 // -------------------------------------------------------------------------
EnableExpandHandler(SvLBoxEntry * _pEntry)175 void DBTreeListBox::EnableExpandHandler(SvLBoxEntry* _pEntry)
176 {
177     LINK(this, DBTreeListBox, OnResetEntry).Call(_pEntry);
178 }
179 
180 // -------------------------------------------------------------------------
RequestingChilds(SvLBoxEntry * pParent)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 // -------------------------------------------------------------------------
InitEntry(SvLBoxEntry * _pEntry,const XubString & aStr,const Image & _rCollEntryBmp,const Image & _rExpEntryBmp,SvLBoxButtonKind eButtonKind)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 // -------------------------------------------------------------------------
implStopSelectionTimer()205 void DBTreeListBox::implStopSelectionTimer()
206 {
207     if ( m_aTimer.IsActive() )
208         m_aTimer.Stop();
209 }
210 
211 // -------------------------------------------------------------------------
implStartSelectionTimer()212 void DBTreeListBox::implStartSelectionTimer()
213 {
214     implStopSelectionTimer();
215     m_aTimer.Start();
216 }
217 
218 // -----------------------------------------------------------------------------
219 
DeselectHdl()220 void DBTreeListBox::DeselectHdl()
221 {
222     m_aSelectedEntries.erase( GetHdlEntry() );
223     SvTreeListBox::DeselectHdl();
224     implStartSelectionTimer();
225 }
226 // -------------------------------------------------------------------------
SelectHdl()227 void DBTreeListBox::SelectHdl()
228 {
229     m_aSelectedEntries.insert( GetHdlEntry() );
230     SvTreeListBox::SelectHdl();
231     implStartSelectionTimer();
232 }
233 
234 // -------------------------------------------------------------------------
MouseButtonDown(const MouseEvent & rMEvt)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 // -------------------------------------------------------------------------
IMPL_LINK(DBTreeListBox,OnResetEntry,SvLBoxEntry *,pEntry)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 // -----------------------------------------------------------------------------
ModelHasEntryInvalidated(SvListEntry * _pEntry)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 // -------------------------------------------------------------------------
ModelHasRemoved(SvListEntry * _pEntry)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 // -------------------------------------------------------------------------
AcceptDrop(const AcceptDropEvent & _rEvt)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 // -------------------------------------------------------------------------
ExecuteDrop(const ExecuteDropEvent & _rEvt)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 // -------------------------------------------------------------------------
StartDrag(sal_Int8 _nAction,const Point & _rPosPixel)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 // -------------------------------------------------------------------------
RequestHelp(const HelpEvent & rHEvt)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 // -----------------------------------------------------------------------------
KeyInput(const KeyEvent & rKEvt)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 // -----------------------------------------------------------------------------
EditingEntry(SvLBoxEntry * pEntry,Selection &)443 sal_Bool DBTreeListBox::EditingEntry( SvLBoxEntry* pEntry, Selection& /*_aSelection*/)
444 {
445     return m_aEditingHandler.Call(pEntry) != 0;
446 }
447 // -----------------------------------------------------------------------------
EditedEntry(SvLBoxEntry * pEntry,const XubString & rNewText)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 // -----------------------------------------------------------------------------
DoubleClickHdl()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 // -----------------------------------------------------------------------------
scrollWindow(DBTreeListBox * _pListBox,const Point & _rPos,sal_Bool _bUp)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 {
lcl_enableEntries(PopupMenu * _pPopup,IController & _rController)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 {
lcl_adjustMenuItemIDs(Menu & _rMenu,IController & _rCommandController)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     }
lcl_insertMenuItemImages(Menu & _rMenu,IController & _rCommandController)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:
SelectionSupplier(const Any & _rSelection)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:
~SelectionSupplier()610         virtual ~SelectionSupplier()
611         {
612         }
613 
614     private:
615         Any m_aSelection;
616     };
617 
618     //--------------------------------------------------------------------
select(const Any &)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     //--------------------------------------------------------------------
getSelection()626     Any SAL_CALL SelectionSupplier::getSelection(  ) throw (RuntimeException)
627     {
628         return m_aSelection;
629     }
630 
631     //--------------------------------------------------------------------
addSelectionChangeListener(const Reference<XSelectionChangeListener> &)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     //--------------------------------------------------------------------
removeSelectionChangeListener(const Reference<XSelectionChangeListener> &)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 // -----------------------------------------------------------------------------
CreateContextMenu(void)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 // -----------------------------------------------------------------------------
ExcecuteContextMenuAction(sal_uInt16 _nSelectedPopupEntry)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 // -----------------------------------------------------------------------------
StateChanged(StateChangedType nStateChange)747 void DBTreeListBox::StateChanged( StateChangedType nStateChange )
748 {
749     if ( nStateChange == STATE_CHANGE_VISIBLE )
750         implStopSelectionTimer();
751 }
752 // .........................................................................
753 }   // namespace dbaui
754 // .........................................................................
755