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