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