1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
50 #include <unordered_map>
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
;
78 // UserDefinedFeatures
79 class UserDefinedFeatures
82 explicit UserDefinedFeatures( const Reference
< XController
>& _rxController
);
84 void execute( const URL
& _rFeatureURL
, const Sequence
< PropertyValue
>& _rArgs
);
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
)
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(
106 FrameSearchFlag::AUTO
109 if ( xDispatch
== xController
)
111 SAL_WARN("dbaccess.ui", "UserDefinedFeatures::execute: the controller shouldn't be the dispatcher here!" );
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() )
142 ,m_bDescribingSupportedFeatures( false )
144 ,m_aAsyncInvalidateAll(LINK(this, OGenericUnoController
, OnAsyncInvalidateAll
))
145 ,m_aAsyncCloseTask(LINK(this, OGenericUnoController
, OnAsyncCloseTask
))
147 ,m_aCurrentFrame( *this )
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
);
166 DBG_UNHANDLED_EXCEPTION("dbaccess");
170 OGenericUnoController::~OGenericUnoController()
175 bool OGenericUnoController::Construct(vcl::Window
* /*pParent*/)
177 OSL_ENSURE( getView(), "the view is NULL!" );
181 getView()->Construct();
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);
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
;
240 throw IllegalArgumentException("need a frame", *this, 1 );
242 Reference
<XWindow
> xParent
= xFrame
->getContainerWindow();
243 VclPtr
<vcl::Window
> pParentWin
= VCLUnoHelper::GetWindow(xParent
);
246 throw IllegalArgumentException("Parent window is null", *this, 1 );
249 m_aInitParameters
.assign( aArguments
);
250 Construct( pParentWin
);
252 ODataView
* pView
= getView();
254 throw RuntimeException("unable to create a view", *this );
256 if ( m_bReadOnly
|| m_bPreview
)
257 pView
->EnableInput( false );
263 // no one clears my view if I won't
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
)
282 _rxFrame
->addFrameActionListener( this );
285 void OGenericUnoController::stopFrameListening( const Reference
< XFrame
>& _rxFrame
)
288 _rxFrame
->removeFrameActionListener( this );
291 void OGenericUnoController::disposing(const EventObject
& Source
)
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
);
305 m_bCurrentlyModified
= xModi
->isModified(); // can only be reset by save
307 m_bCurrentlyModified
= true;
309 InvalidateFeature(ID_BROWSER_SAVEDOC
);
310 InvalidateFeature(ID_BROWSER_UNDO
);
313 Reference
< XWindow
> SAL_CALL
OGenericUnoController::getComponentWindow()
316 return VCLUnoHelper::GetInterface( getView() );
319 Reference
<XSidebarProvider
> SAL_CALL
OGenericUnoController::getSidebar()
324 OUString SAL_CALL
OGenericUnoController::getViewControllerName()
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
);
348 getView()->attachFrame( xFrame
);
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
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
)
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
415 lcl_collectStates( aFeatState
, aStates
);
417 // a special listener ?
418 if ( xListener
.is() )
419 lcl_notifyMultipleStates( *xListener
, aEvent
, aStates
);
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()
460 FeatureListener aNextFeature
;
462 ::osl::MutexGuard
aGuard( m_aFeatureMutex
);
463 bEmpty
= m_aFeaturesToInvalidate
.empty();
465 aNextFeature
= m_aFeaturesToInvalidate
.front();
469 if ( ALL_FEATURES
== aNextFeature
.nId
)
471 InvalidateAll_Impl();
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 "
487 << " has been invalidated, but is not supported!" );
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();
499 aNextFeature
= m_aFeaturesToInvalidate
.front();
503 void OGenericUnoController::ImplInvalidateFeature( sal_Int32 _nId
, const Reference
< XStatusListener
>& _xListener
, bool _bForceBroadcast
)
505 #if OSL_DEBUG_LEVEL > 0
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!" );
517 FeatureListener aListener
;
518 aListener
.nId
= _nId
;
519 aListener
.xListener
= _xListener
;
520 aListener
.bForceBroadcast
= _bForceBroadcast
;
524 ::osl::MutexGuard
aGuard( m_aFeatureMutex
);
525 bWasEmpty
= m_aFeaturesToInvalidate
.empty();
526 m_aFeaturesToInvalidate
.push_back( aListener
);
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
)
575 // no? -> ask the slave dispatcher
576 else if ( m_xSlaveDispatcher
.is() )
578 xReturn
= m_xSlaveDispatcher
->queryDispatch(aURL
, aTargetFrameName
, nSearchFlags
);
585 Sequence
< Reference
< XDispatch
> > OGenericUnoController::queryDispatches(const Sequence
< DispatchDescriptor
>& aDescripts
)
587 Sequence
< Reference
< XDispatch
> > aReturn
;
588 sal_Int32 nLen
= aDescripts
.getLength();
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
);
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.
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());
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
& )
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
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
)
742 OGenericUnoController_Base::WeakComponentImplHelperBase::addEventListener( xListener
);
745 void SAL_CALL
OGenericUnoController::removeEventListener( const Reference
< XEventListener
>& xListener
)
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
)
762 OSL_ENSURE( m_bDescribingSupportedFeatures
, "OGenericUnoController::implDescribeSupportedFeature: bad timing for this call!" );
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!" );
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)
796 case ID_BROWSER_UNDO
:
797 case ID_BROWSER_SAVEDOC
:
798 aReturn
.bEnabled
= true;
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;
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
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
);
841 bool OGenericUnoController::isUserDefinedFeature( const sal_uInt16 _nFeatureId
)
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
);
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
);
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
);
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
);
903 void OGenericUnoController::setView( const VclPtr
<ODataView
> &i_rView
)
908 void OGenericUnoController::clearView()
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
;
926 xLayoutManager
.set(xPropSet
->getPropertyValue("LayoutManager"),UNO_QUERY
);
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*/)
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()
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!" );
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() );
1041 xWindow
= xFrame
->getContainerWindow();
1043 while ( xFrame
.is() && !xFrame
->isTop() )
1045 xFrame
= xFrame
->getCreator();
1048 xWindow
= xFrame
->getContainerWindow();
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
;
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 ();
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
1140 Reference
< XController
> OGenericUnoController::getXController()
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
);
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()
1196 m_bDescribingSupportedFeatures
= true;
1198 describeSupportedFeatures();
1200 m_bDescribingSupportedFeatures
= false;
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: */