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 "sortdynres.hxx"
21 #include <cppuhelper/supportsservice.hxx>
22 #include <cppuhelper/weak.hxx>
23 #include <com/sun/star/ucb/ContentResultSetCapability.hpp>
24 #include <com/sun/star/ucb/ListActionType.hpp>
25 #include <com/sun/star/ucb/ListenerAlreadySetException.hpp>
26 #include <com/sun/star/ucb/ServiceNotFoundException.hpp>
27 #include <com/sun/star/ucb/WelcomeDynamicResultSetStruct.hpp>
28 #include <com/sun/star/ucb/CachedDynamicResultSetStubFactory.hpp>
29 #include <com/sun/star/ucb/XSourceInitialization.hpp>
31 using namespace com::sun::star::beans
;
32 using namespace com::sun::star::lang
;
33 using namespace com::sun::star::sdbc
;
34 using namespace com::sun::star::ucb
;
35 using namespace com::sun::star::uno
;
36 using namespace comphelper
;
39 // SortedDynamicResultSet
41 SortedDynamicResultSet::SortedDynamicResultSet(
42 const Reference
< XDynamicResultSet
> &xOriginal
,
43 const Sequence
< NumberedSortingInfo
> &aOptions
,
44 const Reference
< XAnyCompareFactory
> &xCompFac
,
45 const Reference
< XComponentContext
> &rxContext
)
47 mxOwnListener
= new SortedDynamicResultSetListener( this );
49 mxOriginal
= xOriginal
;
52 m_xContext
= rxContext
;
60 SortedDynamicResultSet::~SortedDynamicResultSet()
62 mxOwnListener
->impl_OwnerDies();
63 mxOwnListener
.clear();
66 std::unique_lock
aGuard(maMutex
);
67 maDisposeEventListeners
.clear(aGuard
);
75 // XServiceInfo methods.
77 OUString SAL_CALL
SortedDynamicResultSet::getImplementationName()
79 return "com.sun.star.comp.ucb.SortedDynamicResultSet";
82 sal_Bool SAL_CALL
SortedDynamicResultSet::supportsService( const OUString
& ServiceName
)
84 return cppu::supportsService( this, ServiceName
);
87 css::uno::Sequence
< OUString
> SAL_CALL
SortedDynamicResultSet::getSupportedServiceNames()
89 return { "com.sun.star.ucb.SortedDynamicResultSet" };
92 // XComponent methods.
94 void SAL_CALL
SortedDynamicResultSet::dispose()
96 std::unique_lock
aGuard( maMutex
);
98 if ( maDisposeEventListeners
.getLength(aGuard
) )
101 aEvt
.Source
= static_cast< XComponent
* >( this );
102 maDisposeEventListeners
.disposeAndClear( aGuard
, aEvt
);
112 void SAL_CALL
SortedDynamicResultSet::addEventListener(
113 const Reference
< XEventListener
>& Listener
)
115 std::unique_lock
aGuard( maMutex
);
117 maDisposeEventListeners
.addInterface( aGuard
, Listener
);
120 void SAL_CALL
SortedDynamicResultSet::removeEventListener(
121 const Reference
< XEventListener
>& Listener
)
123 std::unique_lock
aGuard( maMutex
);
125 maDisposeEventListeners
.removeInterface( aGuard
, Listener
);
129 // XDynamicResultSet methods.
131 Reference
< XResultSet
> SAL_CALL
132 SortedDynamicResultSet::getStaticResultSet()
134 std::unique_lock
aGuard( maMutex
);
136 if ( mxListener
.is() )
137 throw ListenerAlreadySetException();
141 if ( mxOriginal
.is() )
143 mxOne
= new SortedResultSet( mxOriginal
->getStaticResultSet() );
144 mxOne
->Initialize( maOptions
, mxCompFac
);
152 SortedDynamicResultSet::setListener( const Reference
< XDynamicResultSetListener
>& Listener
)
154 std::unique_lock
aGuard( maMutex
);
156 if ( mxListener
.is() )
157 throw ListenerAlreadySetException();
159 maDisposeEventListeners
.addInterface( aGuard
, Listener
);
161 mxListener
= Listener
;
163 if ( mxOriginal
.is() )
164 mxOriginal
->setListener( mxOwnListener
);
169 SortedDynamicResultSet::connectToCache( const Reference
< XDynamicResultSet
> & xCache
)
171 if( mxListener
.is() )
172 throw ListenerAlreadySetException();
175 throw ListenerAlreadySetException();
177 Reference
< XSourceInitialization
> xTarget( xCache
, UNO_QUERY
);
178 if( xTarget
.is() && m_xContext
.is() )
180 Reference
< XCachedDynamicResultSetStubFactory
> xStubFactory
;
183 xStubFactory
= CachedDynamicResultSetStubFactory::create( m_xContext
);
185 catch ( Exception
const & )
189 if( xStubFactory
.is() )
191 xStubFactory
->connectToCache(
192 this, xCache
, Sequence
< NumberedSortingInfo
> (), nullptr );
196 throw ServiceNotFoundException();
200 sal_Int16 SAL_CALL
SortedDynamicResultSet::getCapabilities()
202 std::unique_lock
aGuard( maMutex
);
206 if ( mxOriginal
.is() )
207 nCaps
= mxOriginal
->getCapabilities();
209 nCaps
|= ContentResultSetCapability::SORTED
;
215 // XDynamicResultSetListener methods.
218 /** In the first notify-call the listener gets the two
219 <type>XResultSet</type>s and has to hold them. The <type>XResultSet</type>s
220 are implementations of the service <type>ContentResultSet</type>.
222 <p>The notified new <type>XResultSet</type> will stay valid after returning
223 notification. The old one will become invalid after returning notification.
225 <p>While in notify-call the listener is allowed to read old and new version,
226 except in the first call, where only the new Resultset is valid.
228 <p>The Listener is allowed to blockade this call, until he really want to go
229 to the new version. The only situation, where the listener has to return the
230 update call at once is, while he disposes his broadcaster or while he is
231 removing himself as listener (otherwise you deadlock)!!!
233 void SortedDynamicResultSet::impl_notify( const ListEvent
& Changes
)
235 std::unique_lock
aGuard( maMutex
);
237 bool bHasNew
= false;
238 bool bHasModified
= false;
240 SortedResultSet
*pCurSet
= nullptr;
242 // exchange mxNew and mxOld and immediately afterwards copy the tables
249 mxTwo
->CopyData( mxOne
.get() );
250 pCurSet
= mxTwo
.get();
255 mxOne
->CopyData( mxTwo
.get() );
256 pCurSet
= mxOne
.get();
266 aRet
= pCurSet
->getPropertyValue("IsRowCountFinal");
268 catch (const UnknownPropertyException
&) {}
269 catch (const WrappedTargetException
&) {}
271 sal_Int32 nOldCount
= pCurSet
->GetCount();
272 bool bWasFinal
= false;
276 // handle the actions in the list
277 for ( const ListAction
& aAction
: Changes
.Changes
)
279 switch ( aAction
.ListActionType
)
281 case ListActionType::WELCOME
:
283 WelcomeDynamicResultSetStruct aWelcome
;
284 if ( aAction
.ActionInfo
>>= aWelcome
)
286 mxTwo
= new SortedResultSet( aWelcome
.Old
);
287 mxOne
= new SortedResultSet( aWelcome
.New
);
288 mxOne
->Initialize( maOptions
, mxCompFac
);
291 pCurSet
= mxOne
.get();
293 aWelcome
.Old
= mxTwo
.get();
294 aWelcome
.New
= mxOne
.get();
296 ListAction aWelcomeAction
;
297 aWelcomeAction
.ActionInfo
<<= aWelcome
;
298 aWelcomeAction
.Position
= 0;
299 aWelcomeAction
.Count
= 0;
300 aWelcomeAction
.ListActionType
= ListActionType::WELCOME
;
302 maActions
.Insert( aWelcomeAction
);
306 // throw RuntimeException();
310 case ListActionType::INSERTED
:
312 pCurSet
->InsertNew( aAction
.Position
, aAction
.Count
);
316 case ListActionType::REMOVED
:
318 pCurSet
->Remove( aAction
.Position
,
323 case ListActionType::MOVED
:
325 sal_Int32 nOffset
= 0;
326 if ( aAction
.ActionInfo
>>= nOffset
)
328 pCurSet
->Move( aAction
.Position
,
334 case ListActionType::PROPERTIES_CHANGED
:
336 pCurSet
->SetChanged( aAction
.Position
, aAction
.Count
);
345 pCurSet
->ResortModified( &maActions
);
348 pCurSet
->ResortNew( &maActions
);
350 // send the new actions with a notify to the listeners
353 // check for propertyChangeEvents
354 pCurSet
->CheckProperties( nOldCount
, bWasFinal
);
359 void SortedDynamicResultSet::impl_disposing()
367 void SortedDynamicResultSet::SendNotify()
369 sal_Int32 nCount
= maActions
.Count();
371 if ( nCount
&& mxListener
.is() )
373 Sequence
< ListAction
> aActionList( maActions
.Count() );
374 ListAction
*pActionList
= aActionList
.getArray();
376 for ( sal_Int32 i
=0; i
<nCount
; i
++ )
378 pActionList
[ i
] = maActions
.GetAction( i
);
382 aNewEvent
.Changes
= aActionList
;
384 mxListener
->notify( aNewEvent
);
391 // SortedDynamicResultSetFactory
393 SortedDynamicResultSetFactory::SortedDynamicResultSetFactory(
394 const Reference
< XComponentContext
> & rxContext
)
396 m_xContext
= rxContext
;
400 SortedDynamicResultSetFactory::~SortedDynamicResultSetFactory()
405 // XServiceInfo methods.
407 OUString SAL_CALL
SortedDynamicResultSetFactory::getImplementationName()
409 return "com.sun.star.comp.ucb.SortedDynamicResultSetFactory";
412 sal_Bool SAL_CALL
SortedDynamicResultSetFactory::supportsService( const OUString
& ServiceName
)
414 return cppu::supportsService( this, ServiceName
);
417 css::uno::Sequence
< OUString
> SAL_CALL
SortedDynamicResultSetFactory::getSupportedServiceNames()
419 return { "com.sun.star.ucb.SortedDynamicResultSetFactory" };
423 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
424 ucb_SortedDynamicResultSetFactory_get_implementation(
425 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const&)
427 return cppu::acquire(new SortedDynamicResultSetFactory(context
));
430 // SortedDynamicResultSetFactory methods.
432 Reference
< XDynamicResultSet
> SAL_CALL
433 SortedDynamicResultSetFactory::createSortedDynamicResultSet(
434 const Reference
< XDynamicResultSet
> & Source
,
435 const Sequence
< NumberedSortingInfo
> & Info
,
436 const Reference
< XAnyCompareFactory
> & CompareFactory
)
438 Reference
< XDynamicResultSet
> xRet
= new SortedDynamicResultSet( Source
, Info
, CompareFactory
, m_xContext
);
444 void EventList::Clear()
449 void EventList::AddEvent( sal_IntPtr nType
, sal_Int32 nPos
)
452 aAction
.Position
= nPos
;
454 aAction
.ListActionType
= nType
;
459 // SortedDynamicResultSetListener
461 SortedDynamicResultSetListener::SortedDynamicResultSetListener(
462 SortedDynamicResultSet
*mOwner
)
468 SortedDynamicResultSetListener::~SortedDynamicResultSetListener()
472 // XEventListener ( base of XDynamicResultSetListener )
475 SortedDynamicResultSetListener::disposing( const EventObject
& /*Source*/ )
477 std::unique_lock
aGuard( maMutex
);
480 mpOwner
->impl_disposing();
484 // XDynamicResultSetListener
487 SortedDynamicResultSetListener::notify( const ListEvent
& Changes
)
489 std::unique_lock
aGuard( maMutex
);
492 mpOwner
->impl_notify( Changes
);
498 SortedDynamicResultSetListener::impl_OwnerDies()
500 std::unique_lock
aGuard( maMutex
);
504 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */