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_dbui.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 occurred. 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