| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_ucb.hxx" |
| |
| #include <vector> |
| #include <sortdynres.hxx> |
| #include <cppuhelper/interfacecontainer.hxx> |
| #include <com/sun/star/ucb/ContentResultSetCapability.hpp> |
| #include <com/sun/star/ucb/ListActionType.hpp> |
| #include <com/sun/star/ucb/WelcomeDynamicResultSetStruct.hpp> |
| #include <com/sun/star/ucb/XCachedDynamicResultSetStubFactory.hpp> |
| #include <com/sun/star/ucb/XSourceInitialization.hpp> |
| |
| //----------------------------------------------------------------------------- |
| using namespace com::sun::star::beans; |
| using namespace com::sun::star::lang; |
| using namespace com::sun::star::sdbc; |
| using namespace com::sun::star::ucb; |
| using namespace com::sun::star::uno; |
| using namespace cppu; |
| using namespace rtl; |
| |
| //========================================================================= |
| |
| // The mutex to synchronize access to containers. |
| static osl::Mutex& getContainerMutex() |
| { |
| static osl::Mutex* pMutex = NULL; |
| if( !pMutex ) |
| { |
| osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() ); |
| if( !pMutex ) |
| { |
| static osl::Mutex aMutex; |
| pMutex = &aMutex; |
| } |
| } |
| |
| return *pMutex; |
| } |
| |
| //========================================================================= |
| // |
| // SortedDynamicResultSet |
| // |
| //========================================================================= |
| |
| SortedDynamicResultSet::SortedDynamicResultSet( |
| const Reference < XDynamicResultSet > &xOriginal, |
| const Sequence < NumberedSortingInfo > &aOptions, |
| const Reference < XAnyCompareFactory > &xCompFac, |
| const Reference < XMultiServiceFactory > &xSMgr ) |
| { |
| mpDisposeEventListeners = NULL; |
| mpOwnListener = new SortedDynamicResultSetListener( this ); |
| |
| mxOwnListener = Reference< XDynamicResultSetListener >( mpOwnListener ); |
| |
| mxOriginal = xOriginal; |
| maOptions = aOptions; |
| mxCompFac = xCompFac; |
| mxSMgr = xSMgr; |
| |
| mpOne = NULL; |
| mpTwo = NULL; |
| |
| mbGotWelcome = sal_False; |
| mbUseOne = sal_True; |
| mbStatic = sal_False; |
| } |
| |
| //-------------------------------------------------------------------------- |
| SortedDynamicResultSet::~SortedDynamicResultSet() |
| { |
| mpOwnListener->impl_OwnerDies(); |
| mxOwnListener.clear(); |
| |
| delete mpDisposeEventListeners; |
| |
| mxOne.clear(); |
| mxTwo.clear(); |
| mxOriginal.clear(); |
| |
| mpOne = NULL; |
| mpTwo = NULL; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // XInterface methods. |
| //-------------------------------------------------------------------------- |
| |
| XINTERFACE_IMPL_4( SortedDynamicResultSet, |
| XTypeProvider, |
| XServiceInfo, |
| XComponent, /* base class of XDynamicResultSet */ |
| XDynamicResultSet ); |
| |
| //-------------------------------------------------------------------------- |
| // XTypeProvider methods. |
| //-------------------------------------------------------------------------- |
| |
| XTYPEPROVIDER_IMPL_3( SortedDynamicResultSet, |
| XTypeProvider, |
| XServiceInfo, |
| XDynamicResultSet ); |
| |
| //-------------------------------------------------------------------------- |
| // XServiceInfo methods. |
| //-------------------------------------------------------------------------- |
| |
| XSERVICEINFO_NOFACTORY_IMPL_1( SortedDynamicResultSet, |
| OUString::createFromAscii( |
| "com.sun.star.comp.ucb.SortedDynamicResultSet" ), |
| OUString::createFromAscii( |
| DYNAMIC_RESULTSET_SERVICE_NAME ) ); |
| |
| //-------------------------------------------------------------------------- |
| // XComponent methods. |
| //-------------------------------------------------------------------------- |
| void SAL_CALL SortedDynamicResultSet::dispose() |
| throw( RuntimeException ) |
| { |
| osl::Guard< osl::Mutex > aGuard( maMutex ); |
| |
| if ( mpDisposeEventListeners && mpDisposeEventListeners->getLength() ) |
| { |
| EventObject aEvt; |
| aEvt.Source = static_cast< XComponent * >( this ); |
| mpDisposeEventListeners->disposeAndClear( aEvt ); |
| } |
| |
| mxOne.clear(); |
| mxTwo.clear(); |
| mxOriginal.clear(); |
| |
| mpOne = NULL; |
| mpTwo = NULL; |
| mbUseOne = sal_True; |
| } |
| |
| //-------------------------------------------------------------------------- |
| void SAL_CALL SortedDynamicResultSet::addEventListener( |
| const Reference< XEventListener >& Listener ) |
| throw( RuntimeException ) |
| { |
| osl::Guard< osl::Mutex > aGuard( maMutex ); |
| |
| if ( !mpDisposeEventListeners ) |
| mpDisposeEventListeners = |
| new OInterfaceContainerHelper( getContainerMutex() ); |
| |
| mpDisposeEventListeners->addInterface( Listener ); |
| } |
| |
| //-------------------------------------------------------------------------- |
| void SAL_CALL SortedDynamicResultSet::removeEventListener( |
| const Reference< XEventListener >& Listener ) |
| throw( RuntimeException ) |
| { |
| osl::Guard< osl::Mutex > aGuard( maMutex ); |
| |
| if ( mpDisposeEventListeners ) |
| mpDisposeEventListeners->removeInterface( Listener ); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // XDynamicResultSet methods. |
| // ------------------------------------------------------------------------------ |
| Reference< XResultSet > SAL_CALL |
| SortedDynamicResultSet::getStaticResultSet() |
| throw( ListenerAlreadySetException, RuntimeException ) |
| { |
| osl::Guard< osl::Mutex > aGuard( maMutex ); |
| |
| if ( mxListener.is() ) |
| throw ListenerAlreadySetException(); |
| |
| mbStatic = sal_True; |
| |
| if ( mxOriginal.is() ) |
| { |
| mpOne = new SortedResultSet( mxOriginal->getStaticResultSet() ); |
| mxOne = mpOne; |
| mpOne->Initialize( maOptions, mxCompFac ); |
| } |
| |
| return mxOne; |
| } |
| |
| // ------------------------------------------------------------------------------ |
| void SAL_CALL |
| SortedDynamicResultSet::setListener( const Reference< XDynamicResultSetListener >& Listener ) |
| throw( ListenerAlreadySetException, RuntimeException ) |
| { |
| osl::Guard< osl::Mutex > aGuard( maMutex ); |
| |
| if ( mxListener.is() ) |
| throw ListenerAlreadySetException(); |
| |
| addEventListener( Reference< XEventListener >::query( Listener ) ); |
| |
| mxListener = Listener; |
| |
| if ( mxOriginal.is() ) |
| mxOriginal->setListener( mxOwnListener ); |
| } |
| |
| // ------------------------------------------------------------------------------ |
| void SAL_CALL |
| SortedDynamicResultSet::connectToCache( |
| const Reference< XDynamicResultSet > & xCache ) |
| throw( ListenerAlreadySetException, |
| AlreadyInitializedException, |
| ServiceNotFoundException, |
| RuntimeException ) |
| { |
| if( mxListener.is() ) |
| throw ListenerAlreadySetException(); |
| |
| if( mbStatic ) |
| throw ListenerAlreadySetException(); |
| |
| Reference< XSourceInitialization > xTarget( xCache, UNO_QUERY ); |
| if( xTarget.is() && mxSMgr.is() ) |
| { |
| Reference< XCachedDynamicResultSetStubFactory > xStubFactory; |
| try |
| { |
| xStubFactory = Reference< XCachedDynamicResultSetStubFactory >( |
| mxSMgr->createInstance( |
| OUString::createFromAscii( |
| "com.sun.star.ucb.CachedDynamicResultSetStubFactory" ) ), |
| UNO_QUERY ); |
| } |
| catch ( Exception const & ) |
| { |
| } |
| |
| if( xStubFactory.is() ) |
| { |
| xStubFactory->connectToCache( |
| this, xCache, Sequence< NumberedSortingInfo > (), NULL ); |
| return; |
| } |
| } |
| throw ServiceNotFoundException(); |
| } |
| |
| // ------------------------------------------------------------------------------ |
| sal_Int16 SAL_CALL |
| SortedDynamicResultSet::getCapabilities() |
| throw( RuntimeException ) |
| { |
| osl::Guard< osl::Mutex > aGuard( maMutex ); |
| |
| sal_Int16 nCaps = 0; |
| |
| if ( mxOriginal.is() ) |
| nCaps = mxOriginal->getCapabilities(); |
| |
| nCaps |= ContentResultSetCapability::SORTED; |
| |
| return nCaps; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // XDynamicResultSetListener methods. |
| // ------------------------------------------------------------------------------ |
| |
| /** In the first notify-call the listener gets the two |
| <type>XResultSet</type>s and has to hold them. The <type>XResultSet</type>s |
| are implementations of the service <type>ContentResultSet</type>. |
| |
| <p>The notified new <type>XResultSet</type> will stay valid after returning |
| notification. The old one will become invalid after returning notification. |
| |
| <p>While in notify-call the listener is allowed to read old and new version, |
| except in the first call, where only the new Resultset is valid. |
| |
| <p>The Listener is allowed to blockade this call, until he really want to go |
| to the new version. The only situation, where the listener has to return the |
| update call at once is, while he disposes his broadcaster or while he is |
| removing himsef as listener (otherwise you deadlock)!!! |
| */ |
| void SAL_CALL |
| SortedDynamicResultSet::impl_notify( const ListEvent& Changes ) |
| throw( RuntimeException ) |
| { |
| osl::Guard< osl::Mutex > aGuard( maMutex ); |
| |
| sal_Bool bHasNew = sal_False; |
| sal_Bool bHasModified = sal_False; |
| |
| SortedResultSet *pCurSet = NULL; |
| |
| // mxNew und mxOld vertauschen und anschliessend die Tabellen von Old |
| // nach New kopieren |
| if ( mbGotWelcome ) |
| { |
| if ( mbUseOne ) |
| { |
| mbUseOne = sal_False; |
| mpTwo->CopyData( mpOne ); |
| pCurSet = mpTwo; |
| } |
| else |
| { |
| mbUseOne = sal_True; |
| mpOne->CopyData( mpTwo ); |
| pCurSet = mpOne; |
| } |
| } |
| |
| Any aRet; |
| |
| try { |
| aRet = pCurSet->getPropertyValue( OUString::createFromAscii( "IsRowCountFinal" ) ); |
| } |
| catch ( UnknownPropertyException ) {} |
| catch ( WrappedTargetException ) {} |
| |
| long nOldCount = pCurSet->GetCount(); |
| sal_Bool bWasFinal = false; |
| |
| aRet >>= bWasFinal; |
| |
| // handle the actions in the list |
| for ( long i=0; i<Changes.Changes.getLength(); i++ ) |
| { |
| const ListAction aAction = Changes.Changes[i]; |
| switch ( aAction.ListActionType ) |
| { |
| case ListActionType::WELCOME: |
| { |
| WelcomeDynamicResultSetStruct aWelcome; |
| if ( aAction.ActionInfo >>= aWelcome ) |
| { |
| mpTwo = new SortedResultSet( aWelcome.Old ); |
| mxTwo = mpTwo; |
| mpOne = new SortedResultSet( aWelcome.New ); |
| mxOne = mpOne; |
| mpOne->Initialize( maOptions, mxCompFac ); |
| mbGotWelcome = sal_True; |
| mbUseOne = sal_True; |
| pCurSet = mpOne; |
| |
| aWelcome.Old = mxTwo; |
| aWelcome.New = mxOne; |
| |
| ListAction *pWelcomeAction = new ListAction; |
| pWelcomeAction->ActionInfo <<= aWelcome; |
| pWelcomeAction->Position = 0; |
| pWelcomeAction->Count = 0; |
| pWelcomeAction->ListActionType = ListActionType::WELCOME; |
| |
| maActions.Insert( pWelcomeAction ); |
| } |
| else |
| { |
| // throw RuntimeException(); |
| } |
| break; |
| } |
| case ListActionType::INSERTED: |
| { |
| pCurSet->InsertNew( aAction.Position, aAction.Count ); |
| bHasNew = sal_True; |
| break; |
| } |
| case ListActionType::REMOVED: |
| { |
| pCurSet->Remove( aAction.Position, |
| aAction.Count, |
| &maActions ); |
| break; |
| } |
| case ListActionType::MOVED: |
| { |
| long nOffset = 0; |
| if ( aAction.ActionInfo >>= nOffset ) |
| { |
| pCurSet->Move( aAction.Position, |
| aAction.Count, |
| nOffset ); |
| } |
| break; |
| } |
| case ListActionType::PROPERTIES_CHANGED: |
| { |
| pCurSet->SetChanged( aAction.Position, aAction.Count ); |
| bHasModified = sal_True; |
| break; |
| } |
| default: break; |
| } |
| } |
| |
| if ( bHasModified ) |
| pCurSet->ResortModified( &maActions ); |
| |
| if ( bHasNew ) |
| pCurSet->ResortNew( &maActions ); |
| |
| // send the new actions with a notify to the listeners |
| SendNotify(); |
| |
| // check for propertyChangeEvents |
| pCurSet->CheckProperties( nOldCount, bWasFinal ); |
| } |
| |
| //----------------------------------------------------------------- |
| // XEventListener |
| //----------------------------------------------------------------- |
| void SAL_CALL |
| SortedDynamicResultSet::impl_disposing( const EventObject& ) |
| throw( RuntimeException ) |
| { |
| mxListener.clear(); |
| mxOriginal.clear(); |
| } |
| |
| // ------------------------------------------------------------------------------ |
| // private methods |
| // ------------------------------------------------------------------------------ |
| void SortedDynamicResultSet::SendNotify() |
| { |
| long nCount = maActions.Count(); |
| |
| if ( nCount && mxListener.is() ) |
| { |
| Sequence< ListAction > aActionList( maActions.Count() ); |
| ListAction *pActionList = aActionList.getArray(); |
| |
| for ( long i=0; i<nCount; i++ ) |
| { |
| pActionList[ i ] = *(maActions.GetAction( i )); |
| } |
| |
| ListEvent aNewEvent; |
| aNewEvent.Changes = aActionList; |
| |
| mxListener->notify( aNewEvent ); |
| } |
| |
| // clean up |
| maActions.Clear(); |
| } |
| |
| //========================================================================= |
| // |
| // SortedDynamicResultSetFactory |
| // |
| //========================================================================= |
| SortedDynamicResultSetFactory::SortedDynamicResultSetFactory( |
| const Reference< XMultiServiceFactory > & rSMgr ) |
| { |
| mxSMgr = rSMgr; |
| } |
| |
| //-------------------------------------------------------------------------- |
| SortedDynamicResultSetFactory::~SortedDynamicResultSetFactory() |
| { |
| } |
| |
| //-------------------------------------------------------------------------- |
| // XInterface methods. |
| //-------------------------------------------------------------------------- |
| |
| XINTERFACE_IMPL_3( SortedDynamicResultSetFactory, |
| XTypeProvider, |
| XServiceInfo, |
| XSortedDynamicResultSetFactory ); |
| |
| //-------------------------------------------------------------------------- |
| // XTypeProvider methods. |
| //-------------------------------------------------------------------------- |
| |
| XTYPEPROVIDER_IMPL_3( SortedDynamicResultSetFactory, |
| XTypeProvider, |
| XServiceInfo, |
| XSortedDynamicResultSetFactory ); |
| |
| //-------------------------------------------------------------------------- |
| // XServiceInfo methods. |
| //-------------------------------------------------------------------------- |
| |
| XSERVICEINFO_IMPL_1( SortedDynamicResultSetFactory, |
| OUString::createFromAscii( |
| "com.sun.star.comp.ucb.SortedDynamicResultSetFactory" ), |
| OUString::createFromAscii( |
| DYNAMIC_RESULTSET_FACTORY_NAME ) ); |
| |
| //-------------------------------------------------------------------------- |
| // Service factory implementation. |
| //-------------------------------------------------------------------------- |
| |
| ONE_INSTANCE_SERVICE_FACTORY_IMPL( SortedDynamicResultSetFactory ); |
| |
| //-------------------------------------------------------------------------- |
| // SortedDynamicResultSetFactory methods. |
| //-------------------------------------------------------------------------- |
| Reference< XDynamicResultSet > SAL_CALL |
| SortedDynamicResultSetFactory::createSortedDynamicResultSet( |
| const Reference< XDynamicResultSet > & Source, |
| const Sequence< NumberedSortingInfo > & Info, |
| const Reference< XAnyCompareFactory > & CompareFactory ) |
| throw( RuntimeException ) |
| { |
| Reference< XDynamicResultSet > xRet; |
| xRet = new SortedDynamicResultSet( Source, Info, CompareFactory, mxSMgr ); |
| return xRet; |
| } |
| |
| //========================================================================= |
| // |
| // EventList |
| // |
| //========================================================================= |
| |
| void EventList::Clear() |
| { |
| for ( std::deque< LISTACTION* >::size_type i = 0; |
| i < maData.size(); ++i ) |
| { |
| delete maData[i]; |
| } |
| |
| maData.clear(); |
| } |
| |
| //-------------------------------------------------------------------------- |
| void EventList::AddEvent( long nType, long nPos, long nCount ) |
| { |
| ListAction *pAction = new ListAction; |
| pAction->Position = nPos; |
| pAction->Count = nCount; |
| pAction->ListActionType = nType; |
| |
| Insert( pAction ); |
| } |
| |
| //================================================================= |
| // |
| // SortedDynamicResultSetListener |
| // |
| //================================================================= |
| |
| SortedDynamicResultSetListener::SortedDynamicResultSetListener( |
| SortedDynamicResultSet *mOwner ) |
| { |
| mpOwner = mOwner; |
| } |
| |
| //----------------------------------------------------------------- |
| SortedDynamicResultSetListener::~SortedDynamicResultSetListener() |
| { |
| } |
| |
| //----------------------------------------------------------------- |
| // XInterface methods. |
| //----------------------------------------------------------------- |
| |
| XINTERFACE_IMPL_2( SortedDynamicResultSetListener, |
| XEventListener, /* base class of XDynamicResultSetListener */ |
| XDynamicResultSetListener ); |
| |
| //----------------------------------------------------------------- |
| // XEventListener ( base of XDynamicResultSetListener ) |
| //----------------------------------------------------------------- |
| void SAL_CALL |
| SortedDynamicResultSetListener::disposing( const EventObject& Source ) |
| throw( RuntimeException ) |
| { |
| osl::Guard< osl::Mutex > aGuard( maMutex ); |
| |
| if ( mpOwner ) |
| mpOwner->impl_disposing( Source ); |
| } |
| |
| //----------------------------------------------------------------- |
| // XDynamicResultSetListener |
| //----------------------------------------------------------------- |
| void SAL_CALL |
| SortedDynamicResultSetListener::notify( const ListEvent& Changes ) |
| throw( RuntimeException ) |
| { |
| osl::Guard< osl::Mutex > aGuard( maMutex ); |
| |
| if ( mpOwner ) |
| mpOwner->impl_notify( Changes ); |
| } |
| |
| //----------------------------------------------------------------- |
| // own methods: |
| //----------------------------------------------------------------- |
| void SAL_CALL |
| SortedDynamicResultSetListener::impl_OwnerDies() |
| { |
| osl::Guard< osl::Mutex > aGuard( maMutex ); |
| mpOwner = NULL; |
| } |
| |