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