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