Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / ucb / source / sorter / sortdynres.cxx
blob52229f62d7a39b5c0c077a21a816268f9cdd6262
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 "sortdynres.hxx"
21 #include <comphelper/interfacecontainer2.hxx>
22 #include <cppuhelper/supportsservice.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>
30 #include <ucbhelper/getcomponentcontext.hxx>
32 using namespace com::sun::star::beans;
33 using namespace com::sun::star::lang;
34 using namespace com::sun::star::sdbc;
35 using namespace com::sun::star::ucb;
36 using namespace com::sun::star::uno;
37 using namespace comphelper;
40 // The mutex to synchronize access to containers.
41 static osl::Mutex& getContainerMutex()
43 static osl::Mutex ourMutex;
45 return ourMutex;
49 // SortedDynamicResultSet
51 SortedDynamicResultSet::SortedDynamicResultSet(
52 const Reference < XDynamicResultSet > &xOriginal,
53 const Sequence < NumberedSortingInfo > &aOptions,
54 const Reference < XAnyCompareFactory > &xCompFac,
55 const Reference < XComponentContext > &rxContext )
57 mpDisposeEventListeners = nullptr;
58 mxOwnListener = new SortedDynamicResultSetListener( this );
60 mxOriginal = xOriginal;
61 maOptions = aOptions;
62 mxCompFac = xCompFac;
63 m_xContext = rxContext;
65 mbGotWelcome = false;
66 mbUseOne = true;
67 mbStatic = false;
71 SortedDynamicResultSet::~SortedDynamicResultSet()
73 mxOwnListener->impl_OwnerDies();
74 mxOwnListener.clear();
76 mpDisposeEventListeners.reset();
78 mxOne.clear();
79 mxTwo.clear();
80 mxOriginal.clear();
83 // XServiceInfo methods.
85 OUString SAL_CALL SortedDynamicResultSet::getImplementationName()
87 return "com.sun.star.comp.ucb.SortedDynamicResultSet";
90 sal_Bool SAL_CALL SortedDynamicResultSet::supportsService( const OUString& ServiceName )
92 return cppu::supportsService( this, ServiceName );
95 css::uno::Sequence< OUString > SAL_CALL SortedDynamicResultSet::getSupportedServiceNames()
97 return { DYNAMIC_RESULTSET_SERVICE_NAME };
100 // XComponent methods.
102 void SAL_CALL SortedDynamicResultSet::dispose()
104 osl::Guard< osl::Mutex > aGuard( maMutex );
106 if ( mpDisposeEventListeners && mpDisposeEventListeners->getLength() )
108 EventObject aEvt;
109 aEvt.Source = static_cast< XComponent * >( this );
110 mpDisposeEventListeners->disposeAndClear( aEvt );
113 mxOne.clear();
114 mxTwo.clear();
115 mxOriginal.clear();
117 mbUseOne = true;
120 void SAL_CALL SortedDynamicResultSet::addEventListener(
121 const Reference< XEventListener >& Listener )
123 osl::Guard< osl::Mutex > aGuard( maMutex );
125 if ( !mpDisposeEventListeners )
126 mpDisposeEventListeners.reset(
127 new OInterfaceContainerHelper2( getContainerMutex() ) );
129 mpDisposeEventListeners->addInterface( Listener );
132 void SAL_CALL SortedDynamicResultSet::removeEventListener(
133 const Reference< XEventListener >& Listener )
135 osl::Guard< osl::Mutex > aGuard( maMutex );
137 if ( mpDisposeEventListeners )
138 mpDisposeEventListeners->removeInterface( Listener );
142 // XDynamicResultSet methods.
144 Reference< XResultSet > SAL_CALL
145 SortedDynamicResultSet::getStaticResultSet()
147 osl::Guard< osl::Mutex > aGuard( maMutex );
149 if ( mxListener.is() )
150 throw ListenerAlreadySetException();
152 mbStatic = true;
154 if ( mxOriginal.is() )
156 mxOne = new SortedResultSet( mxOriginal->getStaticResultSet() );
157 mxOne->Initialize( maOptions, mxCompFac );
160 return mxOne.get();
164 void SAL_CALL
165 SortedDynamicResultSet::setListener( const Reference< XDynamicResultSetListener >& Listener )
167 osl::Guard< osl::Mutex > aGuard( maMutex );
169 if ( mxListener.is() )
170 throw ListenerAlreadySetException();
172 addEventListener( Reference< XEventListener >::query( Listener ) );
174 mxListener = Listener;
176 if ( mxOriginal.is() )
177 mxOriginal->setListener( mxOwnListener.get() );
181 void SAL_CALL
182 SortedDynamicResultSet::connectToCache( const Reference< XDynamicResultSet > & xCache )
184 if( mxListener.is() )
185 throw ListenerAlreadySetException();
187 if( mbStatic )
188 throw ListenerAlreadySetException();
190 Reference< XSourceInitialization > xTarget( xCache, UNO_QUERY );
191 if( xTarget.is() && m_xContext.is() )
193 Reference< XCachedDynamicResultSetStubFactory > xStubFactory;
196 xStubFactory = CachedDynamicResultSetStubFactory::create( m_xContext );
198 catch ( Exception const & )
202 if( xStubFactory.is() )
204 xStubFactory->connectToCache(
205 this, xCache, Sequence< NumberedSortingInfo > (), nullptr );
206 return;
209 throw ServiceNotFoundException();
213 sal_Int16 SAL_CALL SortedDynamicResultSet::getCapabilities()
215 osl::Guard< osl::Mutex > aGuard( maMutex );
217 sal_Int16 nCaps = 0;
219 if ( mxOriginal.is() )
220 nCaps = mxOriginal->getCapabilities();
222 nCaps |= ContentResultSetCapability::SORTED;
224 return nCaps;
228 // XDynamicResultSetListener methods.
231 /** In the first notify-call the listener gets the two
232 <type>XResultSet</type>s and has to hold them. The <type>XResultSet</type>s
233 are implementations of the service <type>ContentResultSet</type>.
235 <p>The notified new <type>XResultSet</type> will stay valid after returning
236 notification. The old one will become invalid after returning notification.
238 <p>While in notify-call the listener is allowed to read old and new version,
239 except in the first call, where only the new Resultset is valid.
241 <p>The Listener is allowed to blockade this call, until he really want to go
242 to the new version. The only situation, where the listener has to return the
243 update call at once is, while he disposes his broadcaster or while he is
244 removing himself as listener (otherwise you deadlock)!!!
246 void SortedDynamicResultSet::impl_notify( const ListEvent& Changes )
248 osl::Guard< osl::Mutex > aGuard( maMutex );
250 bool bHasNew = false;
251 bool bHasModified = false;
253 SortedResultSet *pCurSet = nullptr;
255 // exchange mxNew and mxOld and immediately afterwards copy the tables
256 // from Old to New
257 if ( mbGotWelcome )
259 if ( mbUseOne )
261 mbUseOne = false;
262 mxTwo->CopyData( mxOne.get() );
263 pCurSet = mxTwo.get();
265 else
267 mbUseOne = true;
268 mxOne->CopyData( mxTwo.get() );
269 pCurSet = mxOne.get();
273 if (!pCurSet)
274 return;
276 Any aRet;
278 try {
279 aRet = pCurSet->getPropertyValue("IsRowCountFinal");
281 catch (const UnknownPropertyException&) {}
282 catch (const WrappedTargetException&) {}
284 long nOldCount = pCurSet->GetCount();
285 bool bWasFinal = false;
287 aRet >>= bWasFinal;
289 // handle the actions in the list
290 for ( const ListAction& aAction : Changes.Changes )
292 switch ( aAction.ListActionType )
294 case ListActionType::WELCOME:
296 WelcomeDynamicResultSetStruct aWelcome;
297 if ( aAction.ActionInfo >>= aWelcome )
299 mxTwo = new SortedResultSet( aWelcome.Old );
300 mxOne = new SortedResultSet( aWelcome.New );
301 mxOne->Initialize( maOptions, mxCompFac );
302 mbGotWelcome = true;
303 mbUseOne = true;
304 pCurSet = mxOne.get();
306 aWelcome.Old = mxTwo.get();
307 aWelcome.New = mxOne.get();
309 std::unique_ptr<ListAction> pWelcomeAction(new ListAction);
310 pWelcomeAction->ActionInfo <<= aWelcome;
311 pWelcomeAction->Position = 0;
312 pWelcomeAction->Count = 0;
313 pWelcomeAction->ListActionType = ListActionType::WELCOME;
315 maActions.Insert( std::move(pWelcomeAction) );
317 else
319 // throw RuntimeException();
321 break;
323 case ListActionType::INSERTED:
325 pCurSet->InsertNew( aAction.Position, aAction.Count );
326 bHasNew = true;
327 break;
329 case ListActionType::REMOVED:
331 pCurSet->Remove( aAction.Position,
332 aAction.Count,
333 &maActions );
334 break;
336 case ListActionType::MOVED:
338 long nOffset = 0;
339 if ( aAction.ActionInfo >>= nOffset )
341 pCurSet->Move( aAction.Position,
342 aAction.Count,
343 nOffset );
345 break;
347 case ListActionType::PROPERTIES_CHANGED:
349 pCurSet->SetChanged( aAction.Position, aAction.Count );
350 bHasModified = true;
351 break;
353 default: break;
357 if ( bHasModified )
358 pCurSet->ResortModified( &maActions );
360 if ( bHasNew )
361 pCurSet->ResortNew( &maActions );
363 // send the new actions with a notify to the listeners
364 SendNotify();
366 // check for propertyChangeEvents
367 pCurSet->CheckProperties( nOldCount, bWasFinal );
370 // XEventListener
372 void SortedDynamicResultSet::impl_disposing()
374 mxListener.clear();
375 mxOriginal.clear();
378 // private methods
380 void SortedDynamicResultSet::SendNotify()
382 sal_Int32 nCount = maActions.Count();
384 if ( nCount && mxListener.is() )
386 Sequence< ListAction > aActionList( maActions.Count() );
387 ListAction *pActionList = aActionList.getArray();
389 for ( sal_Int32 i=0; i<nCount; i++ )
391 pActionList[ i ] = *(maActions.GetAction( i ));
394 ListEvent aNewEvent;
395 aNewEvent.Changes = aActionList;
397 mxListener->notify( aNewEvent );
400 // clean up
401 maActions.Clear();
404 // SortedDynamicResultSetFactory
406 SortedDynamicResultSetFactory::SortedDynamicResultSetFactory(
407 const Reference< XComponentContext > & rxContext )
409 m_xContext = rxContext;
413 SortedDynamicResultSetFactory::~SortedDynamicResultSetFactory()
418 // XServiceInfo methods.
420 OUString SAL_CALL SortedDynamicResultSetFactory::getImplementationName()
422 return getImplementationName_Static();
425 OUString SortedDynamicResultSetFactory::getImplementationName_Static()
427 return "com.sun.star.comp.ucb.SortedDynamicResultSetFactory";
430 sal_Bool SAL_CALL SortedDynamicResultSetFactory::supportsService( const OUString& ServiceName )
432 return cppu::supportsService( this, ServiceName );
435 css::uno::Sequence< OUString > SAL_CALL SortedDynamicResultSetFactory::getSupportedServiceNames()
437 return getSupportedServiceNames_Static();
440 /// @throws css::uno::Exception
441 static css::uno::Reference< css::uno::XInterface >
442 SortedDynamicResultSetFactory_CreateInstance( const css::uno::Reference<
443 css::lang::XMultiServiceFactory> & rSMgr )
445 return static_cast<css::lang::XServiceInfo*>(
446 new SortedDynamicResultSetFactory(ucbhelper::getComponentContext(rSMgr)));
449 css::uno::Sequence< OUString > SortedDynamicResultSetFactory::getSupportedServiceNames_Static()
451 css::uno::Sequence<OUString> aSNS { DYNAMIC_RESULTSET_FACTORY_NAME };
452 return aSNS;
456 // Service factory implementation.
457 css::uno::Reference< css::lang::XSingleServiceFactory >
458 SortedDynamicResultSetFactory::createServiceFactory( const css::uno::Reference< css::lang::XMultiServiceFactory >& rxServiceMgr )
460 return cppu::createOneInstanceFactory(
461 rxServiceMgr,
462 SortedDynamicResultSetFactory::getImplementationName_Static(),
463 SortedDynamicResultSetFactory_CreateInstance,
464 SortedDynamicResultSetFactory::getSupportedServiceNames_Static() );
467 // SortedDynamicResultSetFactory methods.
469 Reference< XDynamicResultSet > SAL_CALL
470 SortedDynamicResultSetFactory::createSortedDynamicResultSet(
471 const Reference< XDynamicResultSet > & Source,
472 const Sequence< NumberedSortingInfo > & Info,
473 const Reference< XAnyCompareFactory > & CompareFactory )
475 Reference< XDynamicResultSet > xRet = new SortedDynamicResultSet( Source, Info, CompareFactory, m_xContext );
476 return xRet;
479 // EventList
481 void EventList::Clear()
483 maData.clear();
486 void EventList::AddEvent( sal_IntPtr nType, sal_IntPtr nPos )
488 std::unique_ptr<ListAction> pAction(new ListAction);
489 pAction->Position = nPos;
490 pAction->Count = 1;
491 pAction->ListActionType = nType;
493 Insert( std::move(pAction) );
496 // SortedDynamicResultSetListener
498 SortedDynamicResultSetListener::SortedDynamicResultSetListener(
499 SortedDynamicResultSet *mOwner )
501 mpOwner = mOwner;
505 SortedDynamicResultSetListener::~SortedDynamicResultSetListener()
509 // XEventListener ( base of XDynamicResultSetListener )
511 void SAL_CALL
512 SortedDynamicResultSetListener::disposing( const EventObject& /*Source*/ )
514 osl::Guard< osl::Mutex > aGuard( maMutex );
516 if ( mpOwner )
517 mpOwner->impl_disposing();
521 // XDynamicResultSetListener
523 void SAL_CALL
524 SortedDynamicResultSetListener::notify( const ListEvent& Changes )
526 osl::Guard< osl::Mutex > aGuard( maMutex );
528 if ( mpOwner )
529 mpOwner->impl_notify( Changes );
532 // own methods:
534 void
535 SortedDynamicResultSetListener::impl_OwnerDies()
537 osl::Guard< osl::Mutex > aGuard( maMutex );
538 mpOwner = nullptr;
541 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */