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