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