calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / dbaccess / source / ui / browser / genericcontroller.cxx
blob5c44232277840b6697cc0fcccb90870692d12f4d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <dbaccess/genericcontroller.hxx>
21 #include <browserids.hxx>
22 #include <vcl/svapp.hxx>
23 #include <vcl/weld.hxx>
24 #include <toolkit/helper/vclunohelper.hxx>
25 #include <dbaccess/dataview.hxx>
26 #include <comphelper/diagnose_ex.hxx>
27 #include <osl/diagnose.h>
28 #include <vcl/stdtext.hxx>
29 #include <framework/titlehelper.hxx>
30 #include <connectivity/dbtools.hxx>
31 #include <comphelper/sequence.hxx>
32 #include <cppuhelper/supportsservice.hxx>
33 #include <com/sun/star/sdbc/XDataSource.hpp>
34 #include <com/sun/star/sdb/DatabaseContext.hpp>
35 #include <com/sun/star/beans/XPropertySet.hpp>
36 #include <com/sun/star/util/URLTransformer.hpp>
37 #include <com/sun/star/util/XCloseable.hpp>
39 #include <com/sun/star/ui/XSidebarProvider.hpp>
40 #include <sfx2/userinputinterception.hxx>
42 #include <datasourceconnector.hxx>
43 #include <com/sun/star/frame/FrameSearchFlag.hpp>
44 #include <com/sun/star/frame/status/Visibility.hpp>
45 #include <com/sun/star/frame/XUntitledNumbers.hpp>
46 #include <com/sun/star/util/XModifiable.hpp>
47 #include <rtl/ustring.hxx>
48 #include <sal/log.hxx>
49 #include <limits>
50 #include <unordered_map>
51 #include <set>
53 using namespace ::com::sun::star;
54 using namespace ::com::sun::star::uno;
55 using namespace ::com::sun::star::beans;
56 using namespace ::com::sun::star::frame;
57 using namespace ::com::sun::star::frame::status;
58 using namespace ::com::sun::star::util;
59 using namespace ::com::sun::star::lang;
60 using namespace ::com::sun::star::container;
61 using namespace ::com::sun::star::sdbc;
62 using namespace ::com::sun::star::sdb;
63 using namespace ::com::sun::star::task;
64 using namespace ::com::sun::star::awt;
65 using namespace ::com::sun::star::ui;
66 using namespace ::dbtools;
67 using namespace ::comphelper;
69 #define ALL_FEATURES -1
71 typedef std::unordered_map< sal_Int16, sal_Int16 > CommandHashMap;
73 namespace dbaui
76 namespace {
78 // UserDefinedFeatures
79 class UserDefinedFeatures
81 public:
82 explicit UserDefinedFeatures( const Reference< XController >& _rxController );
84 void execute( const URL& _rFeatureURL, const Sequence< PropertyValue>& _rArgs );
86 private:
87 css::uno::WeakReference< XController > m_aController;
92 UserDefinedFeatures::UserDefinedFeatures( const Reference< XController >& _rxController )
93 :m_aController( _rxController )
97 void UserDefinedFeatures::execute( const URL& _rFeatureURL, const Sequence< PropertyValue>& _rArgs )
99 try
101 Reference< XController > xController( Reference< XController >(m_aController), UNO_SET_THROW );
102 Reference< XDispatchProvider > xDispatchProvider( xController->getFrame(), UNO_QUERY_THROW );
103 Reference< XDispatch > xDispatch( xDispatchProvider->queryDispatch(
104 _rFeatureURL,
105 "_self",
106 FrameSearchFlag::AUTO
107 ) );
109 if ( xDispatch == xController )
111 SAL_WARN("dbaccess.ui", "UserDefinedFeatures::execute: the controller shouldn't be the dispatcher here!" );
112 xDispatch.clear();
115 if ( xDispatch.is() )
116 xDispatch->dispatch( _rFeatureURL, _rArgs );
118 catch( const Exception& )
120 DBG_UNHANDLED_EXCEPTION("dbaccess");
124 // OGenericUnoController_Data
125 struct OGenericUnoController_Data
127 ::sfx2::UserInputInterception m_aUserInputInterception;
128 UserDefinedFeatures m_aUserDefinedFeatures;
130 OGenericUnoController_Data( OGenericUnoController& _rController, ::osl::Mutex& _rMutex )
131 :m_aUserInputInterception( _rController, _rMutex )
132 ,m_aUserDefinedFeatures( _rController.getXController() )
137 // OGenericUnoController
138 OGenericUnoController::OGenericUnoController(const Reference< XComponentContext >& _rM)
139 :OGenericUnoController_Base( getMutex() )
140 ,m_pView(nullptr)
141 #ifdef DBG_UTIL
142 ,m_bDescribingSupportedFeatures( false )
143 #endif
144 ,m_aAsyncInvalidateAll(LINK(this, OGenericUnoController, OnAsyncInvalidateAll))
145 ,m_aAsyncCloseTask(LINK(this, OGenericUnoController, OnAsyncCloseTask))
146 ,m_xContext(_rM)
147 ,m_aCurrentFrame( *this )
148 ,m_bPreview(false)
149 ,m_bReadOnly(false)
150 ,m_bCurrentlyModified(false)
151 ,m_bExternalTitle(false)
153 osl_atomic_increment( &m_refCount );
155 m_pData.reset( new OGenericUnoController_Data( *this, getMutex() ) );
157 osl_atomic_decrement( &m_refCount );
162 m_xUrlTransformer = URLTransformer::create(_rM);
164 catch(Exception&)
166 DBG_UNHANDLED_EXCEPTION("dbaccess");
170 OGenericUnoController::~OGenericUnoController()
175 bool OGenericUnoController::Construct(vcl::Window* /*pParent*/)
177 OSL_ENSURE( getView(), "the view is NULL!" );
179 if ( getView() )
181 getView()->Construct();
182 getView()->Show();
185 m_aSupportedFeatures.clear();
186 fillSupportedFeatures();
188 // create the database context
189 OSL_ENSURE(getORB().is(), "OGenericUnoController::Construct need a service factory!");
192 m_xDatabaseContext = DatabaseContext::create(getORB());
194 catch(const Exception&)
196 SAL_WARN("dbaccess.ui","OGenericUnoController::Construct: could not create (or start listening at) the database context!");
197 // at least notify the user. Though the whole component does not make any sense without the database context ...
198 ShowServiceNotAvailableError(getFrameWeld(), u"com.sun.star.sdb.DatabaseContext", true);
201 return true;
204 IMPL_LINK_NOARG(OGenericUnoController, OnAsyncInvalidateAll, void*, void)
206 if ( !OGenericUnoController_Base::rBHelper.bInDispose && !OGenericUnoController_Base::rBHelper.bDisposed )
207 InvalidateFeature_Impl();
210 void OGenericUnoController::impl_initialize()
214 void SAL_CALL OGenericUnoController::initialize( const Sequence< Any >& aArguments )
216 SolarMutexGuard aSolarGuard;
217 ::osl::MutexGuard aGuard( getMutex() );
219 Reference< XFrame > xFrame;
221 PropertyValue aValue;
222 const Any* pIter = aArguments.getConstArray();
223 const Any* pEnd = pIter + aArguments.getLength();
225 for ( ; pIter != pEnd; ++pIter )
227 if ( ( *pIter >>= aValue ) && aValue.Name == "Frame" )
229 xFrame.set(aValue.Value,UNO_QUERY_THROW);
231 else if ( ( *pIter >>= aValue ) && aValue.Name == "Preview" )
233 aValue.Value >>= m_bPreview;
234 m_bReadOnly = true;
239 if ( !xFrame.is() )
240 throw IllegalArgumentException("need a frame", *this, 1 );
242 Reference<XWindow> xParent = xFrame->getContainerWindow();
243 VclPtr<vcl::Window> pParentWin = VCLUnoHelper::GetWindow(xParent);
244 if (!pParentWin)
246 throw IllegalArgumentException("Parent window is null", *this, 1 );
249 m_aInitParameters.assign( aArguments );
250 Construct( pParentWin );
252 ODataView* pView = getView();
253 if ( !pView )
254 throw RuntimeException("unable to create a view", *this );
256 if ( m_bReadOnly || m_bPreview )
257 pView->EnableInput( false );
259 impl_initialize();
261 catch(Exception&)
263 // no one clears my view if I won't
264 m_pView = nullptr;
265 throw;
269 void SAL_CALL OGenericUnoController::acquire( ) noexcept
271 OGenericUnoController_Base::acquire();
274 void SAL_CALL OGenericUnoController::release( ) noexcept
276 OGenericUnoController_Base::release();
279 void OGenericUnoController::startFrameListening( const Reference< XFrame >& _rxFrame )
281 if ( _rxFrame.is() )
282 _rxFrame->addFrameActionListener( this );
285 void OGenericUnoController::stopFrameListening( const Reference< XFrame >& _rxFrame )
287 if ( _rxFrame.is() )
288 _rxFrame->removeFrameActionListener( this );
291 void OGenericUnoController::disposing(const EventObject& Source)
293 // our frame ?
294 if ( Source.Source == getFrame() )
295 stopFrameListening( getFrame() );
298 void OGenericUnoController::modified(const EventObject& aEvent)
300 ::osl::MutexGuard aGuard( getMutex() );
301 if ( !isDataSourceReadOnly() )
303 Reference<XModifiable> xModi(aEvent.Source,UNO_QUERY);
304 if ( xModi.is() )
305 m_bCurrentlyModified = xModi->isModified(); // can only be reset by save
306 else
307 m_bCurrentlyModified = true;
309 InvalidateFeature(ID_BROWSER_SAVEDOC);
310 InvalidateFeature(ID_BROWSER_UNDO);
313 Reference< XWindow > SAL_CALL OGenericUnoController::getComponentWindow()
315 SolarMutexGuard g;
316 return VCLUnoHelper::GetInterface( getView() );
319 Reference<XSidebarProvider> SAL_CALL OGenericUnoController::getSidebar()
321 return nullptr;
324 OUString SAL_CALL OGenericUnoController::getViewControllerName()
326 return "Default";
329 Sequence< PropertyValue > SAL_CALL OGenericUnoController::getCreationArguments()
331 // currently we do not support any creation args, so anything passed to XModel2::createViewController would be
332 // lost, so we can equally return an empty sequence here
333 return Sequence< PropertyValue >();
336 void OGenericUnoController::attachFrame( const Reference< XFrame >& _rxFrame )
338 SolarMutexGuard aSolarGuard;
339 ::osl::MutexGuard aGuard( getMutex() );
341 stopFrameListening( m_aCurrentFrame.getFrame() );
342 Reference< XFrame > xFrame = m_aCurrentFrame.attachFrame( _rxFrame );
343 startFrameListening( xFrame );
345 loadMenu( xFrame );
347 if ( getView() )
348 getView()->attachFrame( xFrame );
351 namespace
353 typedef std::vector< Any > States;
355 void lcl_notifyMultipleStates( XStatusListener& _rListener, FeatureStateEvent& _rEvent, const States& _rStates )
357 for (auto const& elem : _rStates)
359 _rEvent.State = elem;
360 _rListener.statusChanged( _rEvent );
364 void lcl_collectStates( const FeatureState& _rFeatureState, States& _out_rStates )
366 // order matters, due to a bug in framework which resets the check state when any non-boolean event
367 // arrives
368 // #i68215# is the bug to (re-)introduce this "ordered" notification here
369 // #i67882# is the bug which was caused by the real fix which we did in framework
370 // #i68216# is the bug which requests to fix the code in Draw which relies on
371 // framework's implementation details
372 if ( !!_rFeatureState.sTitle )
373 _out_rStates.push_back( Any( *_rFeatureState.sTitle ) );
374 if ( !!_rFeatureState.bChecked )
375 _out_rStates.push_back( Any( *_rFeatureState.bChecked ) );
376 if ( !!_rFeatureState.bInvisible )
377 _out_rStates.push_back( Any( Visibility( !*_rFeatureState.bInvisible ) ) );
378 if ( _rFeatureState.aValue.hasValue() )
379 _out_rStates.push_back( _rFeatureState.aValue );
380 if ( _out_rStates.empty() )
381 _out_rStates.emplace_back( );
385 void OGenericUnoController::ImplBroadcastFeatureState(const OUString& _rFeature, const Reference< XStatusListener > & xListener, bool _bIgnoreCache)
387 sal_uInt16 nFeat = m_aSupportedFeatures[ _rFeature ].nFeatureId;
388 FeatureState aFeatState( GetState( nFeat ) );
390 FeatureState& rCachedState = m_aStateCache[nFeat]; // creates if necessary
391 if ( !_bIgnoreCache )
393 // check if we really need to notify the listeners : this method may be called much more often than needed, so check
394 // the cached state of the feature
395 bool bAlreadyCached = ( m_aStateCache.find(nFeat) != m_aStateCache.end() );
396 if ( bAlreadyCached )
397 if ( ( rCachedState.bEnabled == aFeatState.bEnabled )
398 && ( rCachedState.bChecked == aFeatState.bChecked )
399 && ( rCachedState.bInvisible == aFeatState.bInvisible )
400 && ( rCachedState.sTitle == aFeatState.sTitle )
402 return;
404 rCachedState = aFeatState;
406 FeatureStateEvent aEvent;
407 aEvent.FeatureURL.Complete = _rFeature;
408 if (m_xUrlTransformer.is())
409 m_xUrlTransformer->parseStrict(aEvent.FeatureURL);
410 aEvent.Source = static_cast<XDispatch*>(this);
411 aEvent.IsEnabled = aFeatState.bEnabled;
413 // collect all states to be notified
414 States aStates;
415 lcl_collectStates( aFeatState, aStates );
417 // a special listener ?
418 if ( xListener.is() )
419 lcl_notifyMultipleStates( *xListener, aEvent, aStates );
420 else
421 { // no -> iterate through all listeners responsible for the URL
422 std::set<OUString> aFeatureCommands;
423 for( const auto& rFeature : m_aSupportedFeatures )
425 if( rFeature.second.nFeatureId == nFeat )
426 aFeatureCommands.insert( rFeature.first );
429 // it is possible that listeners are registered or revoked while
430 // we are notifying them, so we must use a copy of m_arrStatusListener, not
431 // m_arrStatusListener itself
432 Dispatch aNotifyLoop( m_arrStatusListener );
434 for (auto const& elem : aNotifyLoop)
436 if ( aFeatureCommands.find( elem.aURL.Complete ) != aFeatureCommands.end() )
438 aEvent.FeatureURL = elem.aURL;
439 lcl_notifyMultipleStates( *elem.xListener, aEvent, aStates );
446 bool OGenericUnoController::isFeatureSupported( sal_Int32 _nId )
448 SupportedFeatures::const_iterator aFeaturePos = std::find_if(
449 m_aSupportedFeatures.begin(),
450 m_aSupportedFeatures.end(),
451 CompareFeatureById(_nId)
454 return ( m_aSupportedFeatures.end() != aFeaturePos && !aFeaturePos->first.isEmpty());
457 void OGenericUnoController::InvalidateFeature_Impl()
459 bool bEmpty = true;
460 FeatureListener aNextFeature;
462 ::osl::MutexGuard aGuard( m_aFeatureMutex);
463 bEmpty = m_aFeaturesToInvalidate.empty();
464 if (!bEmpty)
465 aNextFeature = m_aFeaturesToInvalidate.front();
467 while(!bEmpty)
469 if ( ALL_FEATURES == aNextFeature.nId )
471 InvalidateAll_Impl();
472 break;
474 else
476 SupportedFeatures::const_iterator aFeaturePos = std::find_if(
477 m_aSupportedFeatures.begin(),
478 m_aSupportedFeatures.end(),
479 CompareFeatureById( aNextFeature.nId )
482 #if OSL_DEBUG_LEVEL > 0
483 if ( m_aSupportedFeatures.end() == aFeaturePos )
485 SAL_WARN( "dbaccess.ui", "OGenericUnoController::InvalidateFeature_Impl: feature id "
486 << aNextFeature.nId
487 << " has been invalidated, but is not supported!" );
489 #endif
490 if ( m_aSupportedFeatures.end() != aFeaturePos )
491 // we really know this feature
492 ImplBroadcastFeatureState( aFeaturePos->first, aNextFeature.xListener, aNextFeature.bForceBroadcast );
495 ::osl::MutexGuard aGuard( m_aFeatureMutex);
496 m_aFeaturesToInvalidate.pop_front();
497 bEmpty = m_aFeaturesToInvalidate.empty();
498 if (!bEmpty)
499 aNextFeature = m_aFeaturesToInvalidate.front();
503 void OGenericUnoController::ImplInvalidateFeature( sal_Int32 _nId, const Reference< XStatusListener >& _xListener, bool _bForceBroadcast )
505 #if OSL_DEBUG_LEVEL > 0
506 if ( _nId != -1 )
508 auto isSupportedFeature = std::any_of(
509 m_aSupportedFeatures.begin(),
510 m_aSupportedFeatures.end(),
511 CompareFeatureById( _nId )
513 OSL_ENSURE( isSupportedFeature, "OGenericUnoController::ImplInvalidateFeature: invalidating an unsupported feature is suspicious, at least!" );
515 #endif
517 FeatureListener aListener;
518 aListener.nId = _nId;
519 aListener.xListener = _xListener;
520 aListener.bForceBroadcast = _bForceBroadcast;
522 bool bWasEmpty;
524 ::osl::MutexGuard aGuard( m_aFeatureMutex );
525 bWasEmpty = m_aFeaturesToInvalidate.empty();
526 m_aFeaturesToInvalidate.push_back( aListener );
529 if ( bWasEmpty )
530 m_aAsyncInvalidateAll.Call();
533 void OGenericUnoController::InvalidateFeature(sal_uInt16 _nId, const Reference< XStatusListener > & _xListener, bool _bForceBroadcast)
535 ImplInvalidateFeature( _nId, _xListener, _bForceBroadcast );
538 void OGenericUnoController::InvalidateAll()
540 ImplInvalidateFeature( ALL_FEATURES, nullptr, true );
543 void OGenericUnoController::InvalidateAll_Impl()
545 // invalidate all supported features
546 for (auto const& supportedFeature : m_aSupportedFeatures)
547 ImplBroadcastFeatureState( supportedFeature.first, nullptr, true );
550 ::osl::MutexGuard aGuard( m_aFeatureMutex);
551 OSL_ENSURE(m_aFeaturesToInvalidate.size(), "OGenericUnoController::InvalidateAll_Impl: to be called from within InvalidateFeature_Impl only!");
552 m_aFeaturesToInvalidate.pop_front();
553 if(!m_aFeaturesToInvalidate.empty())
554 m_aAsyncInvalidateAll.Call();
558 Reference< XDispatch > OGenericUnoController::queryDispatch(const URL& aURL, const OUString& aTargetFrameName, sal_Int32 nSearchFlags)
560 Reference< XDispatch > xReturn;
562 OSL_PRECOND( !m_aSupportedFeatures.empty(), "OGenericUnoController::queryDispatch: shouldn't this be filled at construction time?" );
563 if ( m_aSupportedFeatures.empty() )
564 fillSupportedFeatures();
566 // URL's we can handle ourself?
567 if ( aURL.Complete == ".uno:FormSlots/ConfirmDeletion"
568 || ( ( m_aSupportedFeatures.find( aURL.Complete ) != m_aSupportedFeatures.end() )
569 && !isUserDefinedFeature( aURL.Complete )
573 xReturn = this;
575 // no? -> ask the slave dispatcher
576 else if ( m_xSlaveDispatcher.is() )
578 xReturn = m_xSlaveDispatcher->queryDispatch(aURL, aTargetFrameName, nSearchFlags);
581 // outta here
582 return xReturn;
585 Sequence< Reference< XDispatch > > OGenericUnoController::queryDispatches(const Sequence< DispatchDescriptor >& aDescripts)
587 Sequence< Reference< XDispatch > > aReturn;
588 sal_Int32 nLen = aDescripts.getLength();
589 if ( nLen )
591 aReturn.realloc( nLen );
592 Reference< XDispatch >* pReturn = aReturn.getArray();
593 const Reference< XDispatch >* pReturnEnd = aReturn.getArray() + nLen;
594 const DispatchDescriptor* pDescripts = aDescripts.getConstArray();
596 for ( ; pReturn != pReturnEnd; ++ pReturn, ++pDescripts )
598 *pReturn = queryDispatch( pDescripts->FeatureURL, pDescripts->FrameName, pDescripts->SearchFlags );
602 return aReturn;
605 Reference< XDispatchProvider > OGenericUnoController::getSlaveDispatchProvider()
607 return m_xSlaveDispatcher;
610 void OGenericUnoController::setSlaveDispatchProvider(const Reference< XDispatchProvider > & _xNewProvider)
612 m_xSlaveDispatcher = _xNewProvider;
615 Reference< XDispatchProvider > OGenericUnoController::getMasterDispatchProvider()
617 return m_xMasterDispatcher;
620 void OGenericUnoController::setMasterDispatchProvider(const Reference< XDispatchProvider > & _xNewProvider)
622 m_xMasterDispatcher = _xNewProvider;
625 void OGenericUnoController::dispatch(const URL& _aURL, const Sequence< PropertyValue >& aArgs)
627 SolarMutexGuard aSolarGuard;
628 // The SolarMutex is not locked anymore when the framework calls into
629 // here. So, lock it ourself. The real solution would be to lock it only in the places
630 // where it's needed, but a) this might turn out difficult, since we then also need to care
631 // for locking in the proper order (SolarMutex and m_aMutex), and b) this would be too many places
632 // for the time frame of the fix.
633 // #i52602#
634 executeChecked(_aURL,aArgs);
637 void OGenericUnoController::addStatusListener(const Reference< XStatusListener > & aListener, const URL& _rURL)
639 // parse the URL now and here, this saves later parsing in each notification round
640 URL aParsedURL( _rURL );
641 if ( m_xUrlTransformer.is() )
642 m_xUrlTransformer->parseStrict( aParsedURL );
644 // remember the listener together with the URL
645 m_arrStatusListener.insert( m_arrStatusListener.end(), DispatchTarget( aParsedURL, aListener ) );
647 // initially broadcast the state
648 ImplBroadcastFeatureState( aParsedURL.Complete, aListener, true );
649 // force the new state to be broadcast to the new listener
652 void OGenericUnoController::removeStatusListener(const Reference< XStatusListener > & aListener, const URL& _rURL)
654 if (_rURL.Complete.isEmpty())
656 m_arrStatusListener.erase(std::remove_if(m_arrStatusListener.begin(), m_arrStatusListener.end(),
657 [&aListener](const DispatchTarget& rCurrent) { return rCurrent.xListener == aListener; }),
658 m_arrStatusListener.end());
660 else
662 // remove the listener only for the given URL
663 Dispatch::iterator iterSearch = std::find_if(m_arrStatusListener.begin(), m_arrStatusListener.end(),
664 [&aListener, &_rURL](const DispatchTarget& rCurrent) {
665 return (rCurrent.xListener == aListener) && (rCurrent.aURL.Complete == _rURL.Complete); });
666 if (iterSearch != m_arrStatusListener.end())
667 m_arrStatusListener.erase(iterSearch);
670 OSL_PRECOND( !m_aSupportedFeatures.empty(), "OGenericUnoController::removeStatusListener: shouldn't this be filled at construction time?" );
671 if ( m_aSupportedFeatures.empty() )
672 fillSupportedFeatures();
674 SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find(_rURL.Complete);
675 if (aIter != m_aSupportedFeatures.end())
676 { // clear the cache for that feature
677 StateCache::const_iterator aCachePos = m_aStateCache.find( aIter->second.nFeatureId );
678 if ( aCachePos != m_aStateCache.end() )
679 m_aStateCache.erase( aCachePos );
682 // now remove the listener from the deque
683 ::osl::MutexGuard aGuard( m_aFeatureMutex );
684 m_aFeaturesToInvalidate.erase(
685 std::remove_if( m_aFeaturesToInvalidate.begin(),
686 m_aFeaturesToInvalidate.end(),
687 FindFeatureListener(aListener))
688 ,m_aFeaturesToInvalidate.end());
691 void OGenericUnoController::releaseNumberForComponent()
695 Reference< XUntitledNumbers > xUntitledProvider(getPrivateModel(), UNO_QUERY );
696 if ( xUntitledProvider.is() )
697 xUntitledProvider->releaseNumberForComponent(static_cast<XWeak*>(this));
699 catch( const Exception& )
701 // NII
705 void OGenericUnoController::disposing()
708 EventObject aDisposeEvent;
709 aDisposeEvent.Source = static_cast<XWeak*>(this);
710 Dispatch aStatusListener = m_arrStatusListener;
711 for (auto const& statusListener : aStatusListener)
713 statusListener.xListener->disposing(aDisposeEvent);
715 m_arrStatusListener.clear();
718 m_xDatabaseContext = nullptr;
720 ::osl::MutexGuard aGuard( m_aFeatureMutex);
721 m_aAsyncInvalidateAll.CancelCall();
722 m_aFeaturesToInvalidate.clear();
725 releaseNumberForComponent();
727 // check out from all the objects we are listening
728 // the frame
729 stopFrameListening( m_aCurrentFrame.getFrame() );
730 m_aCurrentFrame.attachFrame( nullptr );
732 m_xMasterDispatcher = nullptr;
733 m_xSlaveDispatcher = nullptr;
734 m_xTitleHelper.clear();
735 m_xUrlTransformer.clear();
736 m_aInitParameters.clear();
739 void SAL_CALL OGenericUnoController::addEventListener( const Reference< XEventListener >& xListener )
741 // disambiguate
742 OGenericUnoController_Base::WeakComponentImplHelperBase::addEventListener( xListener );
745 void SAL_CALL OGenericUnoController::removeEventListener( const Reference< XEventListener >& xListener )
747 // disambiguate
748 OGenericUnoController_Base::WeakComponentImplHelperBase::removeEventListener( xListener );
751 void OGenericUnoController::frameAction(const FrameActionEvent& aEvent)
753 ::osl::MutexGuard aGuard( getMutex() );
754 if ( aEvent.Frame == m_aCurrentFrame.getFrame() )
755 m_aCurrentFrame.frameAction( aEvent.Action );
758 void OGenericUnoController::implDescribeSupportedFeature( const OUString& _rCommandURL,
759 sal_uInt16 _nFeatureId, sal_Int16 _nCommandGroup )
761 #ifdef DBG_UTIL
762 OSL_ENSURE( m_bDescribingSupportedFeatures, "OGenericUnoController::implDescribeSupportedFeature: bad timing for this call!" );
763 #endif
764 OSL_PRECOND( _nFeatureId < ( std::numeric_limits< sal_uInt16 >::max() - 1000 ), // FIRST_USER_DEFINED_FEATURE
765 "OGenericUnoController::implDescribeSupportedFeature: invalid feature id!" );
767 ControllerFeature aFeature;
768 aFeature.Command = _rCommandURL;
769 aFeature.nFeatureId = _nFeatureId;
770 aFeature.GroupId = _nCommandGroup;
772 #if OSL_DEBUG_LEVEL > 0
773 OSL_ENSURE( m_aSupportedFeatures.find( aFeature.Command ) == m_aSupportedFeatures.end(),
774 "OGenericUnoController::implDescribeSupportedFeature: this feature is already there!" );
775 #endif
776 m_aSupportedFeatures[ aFeature.Command ] = aFeature;
779 void OGenericUnoController::describeSupportedFeatures()
781 // add all supported features
782 implDescribeSupportedFeature( ".uno:Copy", ID_BROWSER_COPY, CommandGroup::EDIT );
783 implDescribeSupportedFeature( ".uno:Cut", ID_BROWSER_CUT, CommandGroup::EDIT );
784 implDescribeSupportedFeature( ".uno:Paste", ID_BROWSER_PASTE, CommandGroup::EDIT );
785 implDescribeSupportedFeature( ".uno:ClipboardFormatItems", ID_BROWSER_CLIPBOARD_FORMAT_ITEMS );
786 implDescribeSupportedFeature( ".uno:DSBEditDoc", ID_BROWSER_EDITDOC, CommandGroup::DOCUMENT );
789 FeatureState OGenericUnoController::GetState( sal_uInt16 _nId ) const
791 FeatureState aReturn;
792 // (disabled automatically)
794 switch ( _nId )
796 case ID_BROWSER_UNDO:
797 case ID_BROWSER_SAVEDOC:
798 aReturn.bEnabled = true;
799 break;
800 default:
801 // for now, enable all the time
802 // TODO: we should ask the dispatcher. However, this is laborious, since you cannot ask a dispatcher
803 // directly, but need to add a status listener.
804 aReturn.bEnabled = true;
805 break;
808 return aReturn;
811 void OGenericUnoController::Execute( sal_uInt16 _nId, const Sequence< PropertyValue>& _rArgs )
813 OSL_ENSURE( isUserDefinedFeature( _nId ),
814 "OGenericUnoController::Execute: responsible for user defined features only!" );
816 // user defined features can be handled by dispatch interceptors resp. protocol handlers only.
817 // So, we need to do a queryDispatch, and dispatch the URL
818 m_pData->m_aUserDefinedFeatures.execute( getURLForId( _nId ), _rArgs );
821 URL OGenericUnoController::getURLForId(sal_Int32 _nId) const
823 URL aReturn;
824 if ( m_xUrlTransformer.is() )
826 SupportedFeatures::const_iterator aIter = std::find_if(
827 m_aSupportedFeatures.begin(),
828 m_aSupportedFeatures.end(),
829 CompareFeatureById( _nId )
832 if ( m_aSupportedFeatures.end() != aIter && !aIter->first.isEmpty() )
834 aReturn.Complete = aIter->first;
835 m_xUrlTransformer->parseStrict( aReturn );
838 return aReturn;
841 bool OGenericUnoController::isUserDefinedFeature( const sal_uInt16 _nFeatureId )
843 return
844 (_nFeatureId >= ( std::numeric_limits< sal_uInt16 >::max() - 1000 )) // test if >= FIRST_USER_DEFINED_FEATURE
846 ( _nFeatureId < (std::numeric_limits< sal_uInt16 >::max())) // test if < LAST_USER_DEFINED_FEATURE
850 bool OGenericUnoController::isUserDefinedFeature( const OUString& _rFeatureURL ) const
852 SupportedFeatures::const_iterator pos = m_aSupportedFeatures.find( _rFeatureURL );
853 OSL_PRECOND( pos != m_aSupportedFeatures.end(),
854 "OGenericUnoController::isUserDefinedFeature: this is no supported feature at all!" );
856 return ( pos != m_aSupportedFeatures.end() ) && isUserDefinedFeature( pos->second.nFeatureId );
859 sal_Bool SAL_CALL OGenericUnoController::supportsService(const OUString& ServiceName)
861 return cppu::supportsService(this, ServiceName);
864 void OGenericUnoController::startConnectionListening(const Reference< XConnection >& _rxConnection)
866 // we have to remove ourself before disposing the connection
867 Reference< XComponent > xComponent(_rxConnection, UNO_QUERY);
868 if (xComponent.is())
869 xComponent->addEventListener(static_cast<XFrameActionListener*>(this));
872 void OGenericUnoController::stopConnectionListening(const Reference< XConnection >& _rxConnection)
874 // we have to remove ourself before disposing the connection
875 Reference< XComponent > xComponent(_rxConnection, UNO_QUERY);
876 if (xComponent.is())
877 xComponent->removeEventListener(static_cast<XFrameActionListener*>(this));
880 Reference< XConnection > OGenericUnoController::connect( const Reference< XDataSource>& _xDataSource )
882 weld::WaitObject aWaitCursor(getFrameWeld());
884 ODatasourceConnector aConnector( getORB(), getFrameWeld(), OUString() );
885 Reference< XConnection > xConnection = aConnector.connect( _xDataSource, nullptr );
886 startConnectionListening( xConnection );
888 return xConnection;
891 Reference< XConnection > OGenericUnoController::connect( const OUString& _rDataSourceName,
892 const OUString& _rContextInformation, ::dbtools::SQLExceptionInfo* _pErrorInfo )
894 weld::WaitObject aWaitCursor(getFrameWeld());
896 ODatasourceConnector aConnector( getORB(), getFrameWeld(), _rContextInformation );
897 Reference<XConnection> xConnection = aConnector.connect( _rDataSourceName, _pErrorInfo );
898 startConnectionListening( xConnection );
900 return xConnection;
903 void OGenericUnoController::setView( const VclPtr<ODataView> &i_rView )
905 m_pView = i_rView;
908 void OGenericUnoController::clearView()
910 m_pView = nullptr;
913 void OGenericUnoController::showError(const SQLExceptionInfo& _rInfo)
915 ::dbtools::showError(_rInfo,VCLUnoHelper::GetInterface(getView()),getORB());
918 Reference< XLayoutManager > OGenericUnoController::getLayoutManager(const Reference< XFrame >& _xFrame)
920 Reference< XPropertySet > xPropSet( _xFrame, UNO_QUERY );
921 Reference< XLayoutManager > xLayoutManager;
922 if ( xPropSet.is() )
926 xLayoutManager.set(xPropSet->getPropertyValue("LayoutManager"),UNO_QUERY);
928 catch ( Exception& )
932 return xLayoutManager;
935 void OGenericUnoController::loadMenu(const Reference< XFrame >& _xFrame)
937 Reference< XLayoutManager > xLayoutManager = getLayoutManager(_xFrame);
938 if ( xLayoutManager.is() )
940 xLayoutManager->lock();
941 xLayoutManager->createElement( "private:resource/menubar/menubar" );
942 xLayoutManager->createElement( "private:resource/toolbar/toolbar" );
943 xLayoutManager->unlock();
944 xLayoutManager->doLayout();
947 onLoadedMenu( xLayoutManager );
950 void OGenericUnoController::onLoadedMenu(const Reference< XLayoutManager >& /*_xLayoutManager*/)
952 // not interested in
955 void OGenericUnoController::closeTask()
957 m_aAsyncCloseTask.Call();
960 IMPL_LINK_NOARG(OGenericUnoController, OnAsyncCloseTask, void*, void)
962 if ( !OGenericUnoController_Base::rBHelper.bInDispose )
966 Reference< util::XCloseable > xCloseable( m_aCurrentFrame.getFrame(), UNO_QUERY_THROW );
967 xCloseable->close( false ); // false - holds the owner ship for this frame inside this object!
969 catch( const Exception& )
971 DBG_UNHANDLED_EXCEPTION("dbaccess");
976 Any SAL_CALL OGenericUnoController::getViewData()
978 return Any();
981 void SAL_CALL OGenericUnoController::restoreViewData(const Any& /*Data*/)
985 Reference< XModel > SAL_CALL OGenericUnoController::getModel()
987 return Reference< XModel >();
990 Reference< XFrame > SAL_CALL OGenericUnoController::getFrame()
992 ::osl::MutexGuard aGuard( getMutex() );
993 return m_aCurrentFrame.getFrame();
996 sal_Bool SAL_CALL OGenericUnoController::attachModel(const Reference< XModel > & /*xModel*/)
998 SAL_WARN("dbaccess.ui", "OGenericUnoController::attachModel: not supported!" );
999 return false;
1002 void OGenericUnoController::executeUnChecked(sal_uInt16 _nCommandId, const Sequence< PropertyValue >& aArgs)
1004 Execute(_nCommandId, aArgs);
1007 void OGenericUnoController::executeUnChecked(const util::URL& _rCommand, const Sequence< PropertyValue >& aArgs)
1009 OSL_PRECOND( !m_aSupportedFeatures.empty(), "OGenericUnoController::executeUnChecked: shouldn't this be filled at construction time?" );
1010 if ( m_aSupportedFeatures.empty() )
1011 fillSupportedFeatures();
1013 SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( _rCommand.Complete );
1014 if (aIter != m_aSupportedFeatures.end())
1015 Execute( aIter->second.nFeatureId, aArgs );
1018 void OGenericUnoController::executeChecked(const util::URL& _rCommand, const Sequence< PropertyValue >& aArgs)
1020 OSL_PRECOND( !m_aSupportedFeatures.empty(), "OGenericUnoController::executeChecked: shouldn't this be filled at construction time?" );
1021 if ( m_aSupportedFeatures.empty() )
1022 fillSupportedFeatures();
1024 SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( _rCommand.Complete );
1025 if ( aIter != m_aSupportedFeatures.end() )
1027 sal_uInt16 nFeatureId = aIter->second.nFeatureId;
1028 if ( GetState( nFeatureId ).bEnabled )
1029 Execute( nFeatureId, aArgs );
1033 Reference< awt::XWindow> OGenericUnoController::getTopMostContainerWindow() const
1035 Reference< css::awt::XWindow> xWindow;
1037 // get the top most window
1038 Reference< XFrame > xFrame( m_aCurrentFrame.getFrame() );
1039 if ( xFrame.is() )
1041 xWindow = xFrame->getContainerWindow();
1043 while ( xFrame.is() && !xFrame->isTop() )
1045 xFrame = xFrame->getCreator();
1047 if ( xFrame.is() )
1048 xWindow = xFrame->getContainerWindow();
1050 return xWindow;
1053 Reference< XTitle > OGenericUnoController::impl_getTitleHelper_throw(bool bCreateIfNecessary)
1055 SolarMutexGuard aSolarGuard;
1056 ::osl::MutexGuard aGuard( getMutex() );
1058 if (!m_xTitleHelper.is() && bCreateIfNecessary)
1060 Reference< XUntitledNumbers > xUntitledProvider(getPrivateModel(), UNO_QUERY );
1062 m_xTitleHelper = new ::framework::TitleHelper( m_xContext, Reference< XController >(this), xUntitledProvider );
1065 return m_xTitleHelper;
1068 // XTitle
1069 OUString SAL_CALL OGenericUnoController::getTitle()
1071 ::osl::MutexGuard aGuard( getMutex() );
1072 if ( m_bExternalTitle )
1073 return impl_getTitleHelper_throw()->getTitle ();
1074 return getPrivateTitle() + impl_getTitleHelper_throw()->getTitle ();
1077 // XTitle
1078 void SAL_CALL OGenericUnoController::setTitle(const OUString& sTitle)
1080 SolarMutexGuard aSolarGuard;
1081 ::osl::MutexGuard aGuard( getMutex() );
1082 m_bExternalTitle = true;
1083 impl_getTitleHelper_throw()->setTitle (sTitle);
1086 // XTitleChangeBroadcaster
1087 void SAL_CALL OGenericUnoController::addTitleChangeListener(const Reference< XTitleChangeListener >& xListener)
1089 Reference< XTitleChangeBroadcaster > xBroadcaster(impl_getTitleHelper_throw(), UNO_QUERY);
1090 if (xBroadcaster.is ())
1091 xBroadcaster->addTitleChangeListener (xListener);
1094 void SAL_CALL OGenericUnoController::removeTitleChangeListener(const Reference< XTitleChangeListener >& xListener)
1096 Reference< XTitleChangeBroadcaster > xBroadcaster(impl_getTitleHelper_throw(false), UNO_QUERY);
1097 if (xBroadcaster.is ())
1098 xBroadcaster->removeTitleChangeListener (xListener);
1101 // XUserInputInterception
1102 void SAL_CALL OGenericUnoController::addKeyHandler( const Reference< XKeyHandler >& _rxHandler )
1104 if ( _rxHandler.is() )
1105 m_pData->m_aUserInputInterception.addKeyHandler( _rxHandler );
1108 void SAL_CALL OGenericUnoController::removeKeyHandler( const Reference< XKeyHandler >& _rxHandler )
1110 m_pData->m_aUserInputInterception.removeKeyHandler( _rxHandler );
1113 void SAL_CALL OGenericUnoController::addMouseClickHandler( const Reference< XMouseClickHandler >& _rxHandler )
1115 if ( _rxHandler.is() )
1116 m_pData->m_aUserInputInterception.addMouseClickHandler( _rxHandler );
1119 void SAL_CALL OGenericUnoController::removeMouseClickHandler( const Reference< XMouseClickHandler >& _rxHandler )
1121 m_pData->m_aUserInputInterception.removeMouseClickHandler( _rxHandler );
1124 void OGenericUnoController::executeChecked(sal_uInt16 _nCommandId, const Sequence< PropertyValue >& aArgs)
1126 if ( isCommandEnabled(_nCommandId) )
1127 Execute(_nCommandId, aArgs);
1130 bool OGenericUnoController::isCommandEnabled(sal_uInt16 _nCommandId) const
1132 return GetState( _nCommandId ).bEnabled;
1135 bool OGenericUnoController::isDataSourceReadOnly() const
1137 return false;
1140 Reference< XController > OGenericUnoController::getXController()
1142 return this;
1145 bool OGenericUnoController::interceptUserInput( const NotifyEvent& _rEvent )
1147 return m_pData->m_aUserInputInterception.handleNotifyEvent( _rEvent );
1150 bool OGenericUnoController::isCommandChecked(sal_uInt16 _nCommandId) const
1152 FeatureState aState = GetState( _nCommandId );
1154 return aState.bChecked && *aState.bChecked;
1157 bool OGenericUnoController::isCommandEnabled( const OUString& _rCompleteCommandURL ) const
1159 OSL_ENSURE( !_rCompleteCommandURL.isEmpty(), "OGenericUnoController::isCommandEnabled: Empty command url!" );
1161 bool bIsEnabled = false;
1162 SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( _rCompleteCommandURL );
1163 if ( aIter != m_aSupportedFeatures.end() )
1164 bIsEnabled = isCommandEnabled( aIter->second.nFeatureId );
1166 return bIsEnabled;
1169 Sequence< ::sal_Int16 > SAL_CALL OGenericUnoController::getSupportedCommandGroups()
1171 CommandHashMap aCmdHashMap;
1172 for (auto const& supportedFeature : m_aSupportedFeatures)
1173 if ( supportedFeature.second.GroupId != CommandGroup::INTERNAL )
1174 aCmdHashMap.emplace( supportedFeature.second.GroupId, 0 );
1176 return comphelper::mapKeysToSequence( aCmdHashMap );
1179 Sequence< DispatchInformation > SAL_CALL OGenericUnoController::getConfigurableDispatchInformation( ::sal_Int16 CommandGroup )
1181 std::vector< DispatchInformation > aInformationVector;
1182 for (auto const& supportedFeature : m_aSupportedFeatures)
1184 if ( sal_Int16( supportedFeature.second.GroupId ) == CommandGroup )
1186 aInformationVector.push_back( supportedFeature.second );
1190 return comphelper::containerToSequence( aInformationVector );
1193 void OGenericUnoController::fillSupportedFeatures()
1195 #ifdef DBG_UTIL
1196 m_bDescribingSupportedFeatures = true;
1197 #endif
1198 describeSupportedFeatures();
1199 #ifdef DBG_UTIL
1200 m_bDescribingSupportedFeatures = false;
1201 #endif
1204 void SAL_CALL OGenericUnoController::dispose()
1206 SolarMutexGuard aSolarGuard;
1207 OGenericUnoController_Base::dispose();
1210 weld::Window* OGenericUnoController::getFrameWeld() const
1212 return m_pView ? m_pView->GetFrameWeld() : nullptr;
1215 } // namespace dbaui
1217 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */