nss: upgrade to release 3.73
[LibreOffice.git] / dbaccess / source / core / dataaccess / ContentHelper.cxx
blob7ad1d22ba2f43e1610bf8b45624864acd989bcc5
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 <ContentHelper.hxx>
21 #include <rtl/ref.hxx>
22 #include <rtl/ustrbuf.hxx>
23 #include <ucbhelper/cancelcommandexecution.hxx>
24 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
25 #include <com/sun/star/lang/IllegalArgumentException.hpp>
26 #include <com/sun/star/lang/IllegalAccessException.hpp>
27 #include <com/sun/star/beans/IllegalTypeException.hpp>
28 #include <com/sun/star/beans/PropertyAttribute.hpp>
29 #include <com/sun/star/beans/PropertyValue.hpp>
30 #include <com/sun/star/beans/XPropertySet.hpp>
31 #include <com/sun/star/container/ElementExistException.hpp>
32 #include <ucbhelper/propertyvalueset.hxx>
33 #include <ucbhelper/contentidentifier.hxx>
34 #include <cppuhelper/interfacecontainer.hxx>
35 #include <comphelper/servicehelper.hxx>
36 #include <cppuhelper/typeprovider.hxx>
37 #include <apitools.hxx>
38 #include <sdbcoretools.hxx>
39 #include <stringconstants.hxx>
41 #include <map>
43 namespace dbaccess
45 using namespace ::com::sun::star::uno;
46 using namespace ::com::sun::star::ucb;
47 using namespace ::com::sun::star::beans;
48 using namespace ::com::sun::star::lang;
49 using namespace ::com::sun::star::sdbc;
50 using namespace ::com::sun::star::io;
51 using namespace ::com::sun::star::util;
52 using namespace ::com::sun::star::embed;
53 using namespace ::com::sun::star::container;
54 using namespace ::cppu;
56 OContentHelper_Impl::OContentHelper_Impl()
57 : m_pDataSource(nullptr)
61 OContentHelper_Impl::~OContentHelper_Impl()
65 OContentHelper::OContentHelper(const Reference< XComponentContext >& _xORB
66 ,const Reference< XInterface >& _xParentContainer
67 ,const TContentPtr& _pImpl)
68 : OContentHelper_COMPBASE(m_aMutex)
69 ,m_aContentListeners(m_aMutex)
70 ,m_aPropertyChangeListeners(m_aMutex)
71 ,m_xParentContainer( _xParentContainer )
72 ,m_aContext( _xORB )
73 ,m_pImpl(_pImpl)
74 ,m_nCommandId(0)
78 void SAL_CALL OContentHelper::disposing()
80 ::osl::MutexGuard aGuard(m_aMutex);
82 // say goodbye to our listeners
83 EventObject aEvt(*this);
84 m_aContentListeners.disposeAndClear(aEvt);
86 m_xParentContainer = nullptr;
89 IMPLEMENT_SERVICE_INFO1(OContentHelper,"com.sun.star.comp.sdb.Content","com.sun.star.ucb.Content");
91 css::uno::Sequence<sal_Int8> OContentHelper::getUnoTunnelId()
93 static cppu::OImplementationId aId;
94 return aId.getImplementationId();
97 css::uno::Sequence<sal_Int8> OContentHelper::getImplementationId()
99 return css::uno::Sequence<sal_Int8>();
102 // XContent
103 Reference< XContentIdentifier > SAL_CALL OContentHelper::getIdentifier( )
105 ::osl::MutexGuard aGuard(m_aMutex);
106 OUString aIdentifier( "private:" + impl_getHierarchicalName( true ) );
107 return new ::ucbhelper::ContentIdentifier( aIdentifier );
110 OUString OContentHelper::impl_getHierarchicalName( bool _includingRootContainer ) const
112 OUStringBuffer aHierarchicalName( m_pImpl->m_aProps.aTitle );
113 Reference< XInterface > xParent = m_xParentContainer;
114 while( xParent.is() )
116 Reference<XPropertySet> xProp( xParent, UNO_QUERY );
117 Reference< XChild > xChild( xParent, UNO_QUERY );
118 xParent.set( xChild.is() ? xChild->getParent() : Reference< XInterface >(), UNO_QUERY );
119 if ( xProp.is() && xParent.is() )
121 OUString sName;
122 xProp->getPropertyValue( PROPERTY_NAME ) >>= sName;
124 OUString sPrevious = aHierarchicalName.makeStringAndClear();
125 aHierarchicalName.append( sName ).append( "/" ).append( sPrevious );
128 OUString sHierarchicalName( aHierarchicalName.makeStringAndClear() );
129 if ( !_includingRootContainer )
130 sHierarchicalName = sHierarchicalName.copy( sHierarchicalName.indexOf( '/' ) + 1 );
131 return sHierarchicalName;
134 OUString SAL_CALL OContentHelper::getContentType()
136 ::osl::MutexGuard aGuard(m_aMutex);
138 if ( !m_pImpl->m_aProps.aContentType )
139 { // content type not yet retrieved
140 m_pImpl->m_aProps.aContentType = determineContentType();
143 return *m_pImpl->m_aProps.aContentType;
146 void SAL_CALL OContentHelper::addContentEventListener( const Reference< XContentEventListener >& _rxListener )
148 ::osl::MutexGuard aGuard(m_aMutex);
149 if ( _rxListener.is() )
150 m_aContentListeners.addInterface(_rxListener);
153 void SAL_CALL OContentHelper::removeContentEventListener( const Reference< XContentEventListener >& _rxListener )
155 ::osl::MutexGuard aGuard(m_aMutex);
156 if (_rxListener.is())
157 m_aContentListeners.removeInterface(_rxListener);
160 // XCommandProcessor
161 sal_Int32 SAL_CALL OContentHelper::createCommandIdentifier( )
163 ::osl::MutexGuard aGuard(m_aMutex);
164 // Just increase counter on every call to generate an identifier.
165 return ++m_nCommandId;
168 Any SAL_CALL OContentHelper::execute( const Command& aCommand, sal_Int32 /*CommandId*/, const Reference< XCommandEnvironment >& Environment )
170 Any aRet;
171 if ( aCommand.Name == "getPropertyValues" )
173 // getPropertyValues
175 Sequence< Property > Properties;
176 if ( !( aCommand.Argument >>= Properties ) )
178 OSL_FAIL( "Wrong argument type!" );
179 ucbhelper::cancelCommandExecution(
180 makeAny( IllegalArgumentException(
181 OUString(),
182 static_cast< cppu::OWeakObject * >( this ),
183 -1 ) ),
184 Environment );
185 // Unreachable
187 aRet <<= getPropertyValues( Properties);
189 else if ( aCommand.Name == "setPropertyValues" )
191 // setPropertyValues
193 Sequence< PropertyValue > aProperties;
194 if ( !( aCommand.Argument >>= aProperties ) )
196 OSL_FAIL( "Wrong argument type!" );
197 ucbhelper::cancelCommandExecution(
198 makeAny( IllegalArgumentException(
199 OUString(),
200 static_cast< cppu::OWeakObject * >( this ),
201 -1 ) ),
202 Environment );
203 // Unreachable
206 if ( !aProperties.hasElements() )
208 OSL_FAIL( "No properties!" );
209 ucbhelper::cancelCommandExecution(
210 makeAny( IllegalArgumentException(
211 OUString(),
212 static_cast< cppu::OWeakObject * >( this ),
213 -1 ) ),
214 Environment );
215 // Unreachable
218 aRet <<= setPropertyValues( aProperties );
220 else if ( aCommand.Name == "getPropertySetInfo" )
222 // getPropertySetInfo
224 Reference<XPropertySet> xProp(*this,UNO_QUERY);
225 if ( xProp.is() )
226 aRet <<= xProp->getPropertySetInfo();
227 // aRet <<= getPropertySetInfo(); // TODO
229 else
231 // Unsupported command
233 OSL_FAIL( "Content::execute - unsupported command!" );
235 ucbhelper::cancelCommandExecution(
236 makeAny( UnsupportedCommandException(
237 OUString(),
238 static_cast< cppu::OWeakObject * >( this ) ) ),
239 Environment );
240 // Unreachable
243 return aRet;
246 void SAL_CALL OContentHelper::abort( sal_Int32 /*CommandId*/ )
250 // XPropertiesChangeNotifier
251 void SAL_CALL OContentHelper::addPropertiesChangeListener( const Sequence< OUString >& PropertyNames, const Reference< XPropertiesChangeListener >& Listener )
253 ::osl::MutexGuard aGuard(m_aMutex);
254 sal_Int32 nCount = PropertyNames.getLength();
255 if ( !nCount )
257 // Note: An empty sequence means a listener for "all" properties.
258 m_aPropertyChangeListeners.addInterface(OUString(), Listener );
260 else
262 const OUString* pSeq = PropertyNames.getConstArray();
264 for ( sal_Int32 n = 0; n < nCount; ++n )
266 const OUString& rName = pSeq[ n ];
267 if ( !rName.isEmpty() )
268 m_aPropertyChangeListeners.addInterface(rName, Listener );
273 void SAL_CALL OContentHelper::removePropertiesChangeListener( const Sequence< OUString >& PropertyNames, const Reference< XPropertiesChangeListener >& Listener )
275 ::osl::MutexGuard aGuard(m_aMutex);
276 sal_Int32 nCount = PropertyNames.getLength();
277 if ( !nCount )
279 // Note: An empty sequence means a listener for "all" properties.
280 m_aPropertyChangeListeners.removeInterface( OUString(), Listener );
282 else
284 const OUString* pSeq = PropertyNames.getConstArray();
286 for ( sal_Int32 n = 0; n < nCount; ++n )
288 const OUString& rName = pSeq[ n ];
289 if ( !rName.isEmpty() )
290 m_aPropertyChangeListeners.removeInterface( rName, Listener );
295 // XPropertyContainer
296 void SAL_CALL OContentHelper::addProperty( const OUString& /*Name*/, sal_Int16 /*Attributes*/, const Any& /*DefaultValue*/ )
298 OSL_FAIL( "OContentHelper::addProperty: not implemented!" );
301 void SAL_CALL OContentHelper::removeProperty( const OUString& /*Name*/ )
303 OSL_FAIL( "OContentHelper::removeProperty: not implemented!" );
306 // XInitialization
307 void SAL_CALL OContentHelper::initialize( const Sequence< Any >& _aArguments )
309 const Any* pBegin = _aArguments.getConstArray();
310 const Any* pEnd = pBegin + _aArguments.getLength();
311 PropertyValue aValue;
312 for(;pBegin != pEnd;++pBegin)
314 *pBegin >>= aValue;
315 if ( aValue.Name == "Parent" )
317 m_xParentContainer.set(aValue.Value,UNO_QUERY);
319 else if ( aValue.Name == PROPERTY_NAME )
321 aValue.Value >>= m_pImpl->m_aProps.aTitle;
323 else if ( aValue.Name == PROPERTY_PERSISTENT_NAME )
325 aValue.Value >>= m_pImpl->m_aProps.sPersistentName;
330 Sequence< Any > OContentHelper::setPropertyValues(const Sequence< PropertyValue >& rValues )
332 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
334 Sequence< Any > aRet( rValues.getLength() );
335 Sequence< PropertyChangeEvent > aChanges( rValues.getLength() );
336 sal_Int32 nChanged = 0;
338 PropertyChangeEvent aEvent;
339 aEvent.Source = static_cast< cppu::OWeakObject * >( this );
340 aEvent.Further = false;
341 aEvent.PropertyHandle = -1;
343 const PropertyValue* pValues = rValues.getConstArray();
344 sal_Int32 nCount = rValues.getLength();
346 for ( sal_Int32 n = 0; n < nCount; ++n )
348 const PropertyValue& rValue = pValues[ n ];
350 if ( rValue.Name == "ContentType" || rValue.Name == "IsDocument" || rValue.Name == "IsFolder" )
352 // Read-only property!
353 aRet[ n ] <<= IllegalAccessException("Property is read-only!",
354 static_cast< cppu::OWeakObject * >( this ) );
356 else if ( rValue.Name == "Title" )
358 OUString aNewValue;
359 if ( rValue.Value >>= aNewValue )
361 if ( aNewValue != m_pImpl->m_aProps.aTitle )
363 aEvent.PropertyName = rValue.Name;
364 aEvent.OldValue <<= m_pImpl->m_aProps.aTitle;
368 impl_rename_throw( aNewValue ,false);
369 OSL_ENSURE( m_pImpl->m_aProps.aTitle == aNewValue, "OContentHelper::setPropertyValues('Title'): rename did not work!" );
371 aEvent.NewValue <<= aNewValue;
372 aChanges.getArray()[ nChanged ] = aEvent;
373 nChanged++;
375 catch( const Exception& )
377 OSL_FAIL( "OContentHelper::setPropertyValues('Title'): caught an exception while renaming!" );
380 else
382 // Old value equals new value. No error!
385 else
387 aRet[ n ] <<= IllegalTypeException("Property value has wrong type!",
388 static_cast< cppu::OWeakObject * >( this ) );
392 else
394 aRet[ n ] <<= Exception("No property set for storing the value!",
395 static_cast< cppu::OWeakObject * >( this ) );
399 if ( nChanged > 0 )
401 notifyDataSourceModified();
402 aGuard.clear();
403 aChanges.realloc( nChanged );
404 notifyPropertiesChange( aChanges );
407 return aRet;
410 // static
411 Reference< XRow > OContentHelper::getPropertyValues( const Sequence< Property >& rProperties)
413 // Note: Empty sequence means "get values of all supported properties".
415 rtl::Reference< ::ucbhelper::PropertyValueSet > xRow = new ::ucbhelper::PropertyValueSet( m_aContext );
417 sal_Int32 nCount = rProperties.getLength();
418 if ( nCount )
420 const Property* pProps = rProperties.getConstArray();
421 for ( sal_Int32 n = 0; n < nCount; ++n )
423 const Property& rProp = pProps[ n ];
425 // Process Core properties.
427 if ( rProp.Name == "ContentType" )
429 xRow->appendString ( rProp, getContentType() );
431 else if ( rProp.Name == "Title" )
433 xRow->appendString ( rProp, m_pImpl->m_aProps.aTitle );
435 else if ( rProp.Name == "IsDocument" )
437 xRow->appendBoolean( rProp, m_pImpl->m_aProps.bIsDocument );
439 else if ( rProp.Name == "IsFolder" )
441 xRow->appendBoolean( rProp, m_pImpl->m_aProps.bIsFolder );
443 else
444 xRow->appendVoid(rProp);
447 else
449 // Append all Core Properties.
450 xRow->appendString (
451 Property( "ContentType", -1,
452 cppu::UnoType<OUString>::get(),
453 PropertyAttribute::BOUND
454 | PropertyAttribute::READONLY ),
455 getContentType() );
456 xRow->appendString (
457 Property( "Title", -1,
458 cppu::UnoType<OUString>::get(),
459 PropertyAttribute::BOUND ),
460 m_pImpl->m_aProps.aTitle );
461 xRow->appendBoolean(
462 Property( "IsDocument", -1,
463 cppu::UnoType<bool>::get(),
464 PropertyAttribute::BOUND
465 | PropertyAttribute::READONLY ),
466 m_pImpl->m_aProps.bIsDocument );
467 xRow->appendBoolean(
468 Property( "IsFolder", -1,
469 cppu::UnoType<bool>::get(),
470 PropertyAttribute::BOUND
471 | PropertyAttribute::READONLY ),
472 m_pImpl->m_aProps.bIsFolder );
474 // @@@ Append other properties supported directly.
477 return Reference< XRow >( xRow.get() );
480 void OContentHelper::notifyPropertiesChange( const Sequence< PropertyChangeEvent >& evt ) const
483 sal_Int32 nCount = evt.getLength();
484 if ( !nCount )
485 return;
487 // First, notify listeners interested in changes of every property.
488 OInterfaceContainerHelper* pAllPropsContainer = m_aPropertyChangeListeners.getContainer( OUString() );
489 if ( pAllPropsContainer )
491 OInterfaceIteratorHelper aIter( *pAllPropsContainer );
492 while ( aIter.hasMoreElements() )
494 // Propagate event.
495 Reference< XPropertiesChangeListener > xListener( aIter.next(), UNO_QUERY );
496 if ( xListener.is() )
497 xListener->propertiesChange( evt );
501 typedef std::map< XPropertiesChangeListener*, Sequence< PropertyChangeEvent > > PropertiesEventListenerMap;
502 PropertiesEventListenerMap aListeners;
504 const PropertyChangeEvent* propertyChangeEvent = evt.getConstArray();
506 for ( sal_Int32 n = 0; n < nCount; ++n, ++propertyChangeEvent )
508 const PropertyChangeEvent& rEvent = *propertyChangeEvent;
509 const OUString& rName = rEvent.PropertyName;
511 OInterfaceContainerHelper* pPropsContainer = m_aPropertyChangeListeners.getContainer( rName );
512 if ( pPropsContainer )
514 OInterfaceIteratorHelper aIter( *pPropsContainer );
515 while ( aIter.hasMoreElements() )
517 Sequence< PropertyChangeEvent >* propertyEvents;
519 XPropertiesChangeListener* pListener = static_cast< XPropertiesChangeListener * >( aIter.next() );
520 PropertiesEventListenerMap::iterator it = aListeners.find( pListener );
521 if ( it == aListeners.end() )
523 // Not in map - create and insert new entry.
524 auto pair = aListeners.emplace( pListener, Sequence< PropertyChangeEvent >( nCount ));
525 propertyEvents = &pair.first->second;
527 else
528 propertyEvents = &(*it).second;
530 (*propertyEvents)[n] = rEvent;
535 // Notify listeners.
536 for (auto & rPair : aListeners)
538 XPropertiesChangeListener* pListener = rPair.first;
539 Sequence< PropertyChangeEvent >& rSeq = rPair.second;
541 // Propagate event.
542 pListener->propertiesChange( rSeq );
546 // css::lang::XUnoTunnel
547 sal_Int64 OContentHelper::getSomething( const Sequence< sal_Int8 > & rId )
549 if (isUnoTunnelId<OContentHelper>(rId))
550 return reinterpret_cast<sal_Int64>(this);
552 return 0;
555 Reference< XInterface > SAL_CALL OContentHelper::getParent( )
557 ::osl::MutexGuard aGuard(m_aMutex);
558 return m_xParentContainer;
561 void SAL_CALL OContentHelper::setParent( const Reference< XInterface >& _xParent )
563 ::osl::MutexGuard aGuard(m_aMutex);
564 m_xParentContainer = _xParent;
567 void OContentHelper::impl_rename_throw(const OUString& _sNewName,bool _bNotify )
569 osl::ClearableGuard< osl::Mutex > aGuard(m_aMutex);
570 if ( _sNewName == m_pImpl->m_aProps.aTitle )
571 return;
574 Sequence< PropertyChangeEvent > aChanges( 1 );
576 aChanges[0].Source = static_cast< cppu::OWeakObject * >( this );
577 aChanges[0].Further = false;
578 aChanges[0].PropertyName = PROPERTY_NAME;
579 aChanges[0].PropertyHandle = PROPERTY_ID_NAME;
580 aChanges[0].OldValue <<= m_pImpl->m_aProps.aTitle;
581 aChanges[0].NewValue <<= _sNewName;
583 aGuard.clear();
585 m_pImpl->m_aProps.aTitle = _sNewName;
586 if ( _bNotify )
587 notifyPropertiesChange( aChanges );
588 notifyDataSourceModified();
590 catch(const PropertyVetoException&)
592 throw ElementExistException(_sNewName,*this);
596 void SAL_CALL OContentHelper::rename( const OUString& newName )
599 impl_rename_throw(newName);
603 void OContentHelper::notifyDataSourceModified()
605 ::dbaccess::notifyDataSourceModified(m_xParentContainer);
608 } // namespace dbaccess
610 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */