Bump version to 5.0-14
[LibreOffice.git] / dbaccess / source / core / dataaccess / ContentHelper.cxx
blobae24cd45938db88e55ecd9299ce7bd4286d7802b
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 <string.h>
21 #include "ContentHelper.hxx"
22 #include <rtl/ustrbuf.hxx>
23 #include <ucbhelper/cancelcommandexecution.hxx>
24 #include <comphelper/property.hxx>
25 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
26 #include <com/sun/star/lang/IllegalArgumentException.hpp>
27 #include <com/sun/star/lang/IllegalAccessException.hpp>
28 #include <com/sun/star/io/XOutputStream.hpp>
29 #include <com/sun/star/io/XActiveDataSink.hpp>
30 #include <com/sun/star/beans/PropertyAttribute.hpp>
31 #include <ucbhelper/propertyvalueset.hxx>
32 #include <ucbhelper/contentidentifier.hxx>
33 #include "myucp_resultset.hxx"
34 #include <com/sun/star/container/XNameContainer.hpp>
35 #include "sdbcoretools.hxx"
36 #include "dbastrings.hrc"
37 #include <tools/debug.hxx>
39 namespace dbaccess
41 using namespace ::com::sun::star::uno;
42 using namespace ::com::sun::star::ucb;
43 using namespace ::com::sun::star::beans;
44 using namespace ::com::sun::star::lang;
45 using namespace ::com::sun::star::sdbc;
46 using namespace ::com::sun::star::io;
47 using namespace ::com::sun::star::util;
48 using namespace ::com::sun::star::embed;
49 using namespace ::com::sun::star::container;
50 using namespace ::comphelper;
51 using namespace ::cppu;
53 OContentHelper_Impl::OContentHelper_Impl()
54 : m_pDataSource(0)
58 OContentHelper_Impl::~OContentHelper_Impl()
62 OContentHelper::OContentHelper(const Reference< XComponentContext >& _xORB
63 ,const Reference< XInterface >& _xParentContainer
64 ,const TContentPtr& _pImpl)
65 : OContentHelper_COMPBASE(m_aMutex)
66 ,m_aContentListeners(m_aMutex)
67 ,m_aPropertyChangeListeners(m_aMutex)
68 ,m_xParentContainer( _xParentContainer )
69 ,m_aContext( _xORB )
70 ,m_aErrorHelper( m_aContext )
71 ,m_pImpl(_pImpl)
72 ,m_nCommandId(0)
76 void SAL_CALL OContentHelper::disposing()
78 ::osl::MutexGuard aGuard(m_aMutex);
80 // say goodbye to our listeners
81 EventObject aEvt(*this);
82 m_aContentListeners.disposeAndClear(aEvt);
84 m_xParentContainer = NULL;
87 IMPLEMENT_SERVICE_INFO1(OContentHelper,"com.sun.star.comp.sdb.Content","com.sun.star.ucb.Content");
88 IMPLEMENT_IMPLEMENTATION_ID(OContentHelper)
90 // XContent
91 Reference< XContentIdentifier > SAL_CALL OContentHelper::getIdentifier( ) throw (RuntimeException, std::exception)
93 ::osl::MutexGuard aGuard(m_aMutex);
94 OUString aIdentifier( "private:" + impl_getHierarchicalName( true ) );
95 return new ::ucbhelper::ContentIdentifier( aIdentifier );
98 OUString OContentHelper::impl_getHierarchicalName( bool _includingRootContainer ) const
100 OUStringBuffer aHierarchicalName( m_pImpl->m_aProps.aTitle );
101 Reference< XInterface > xParent = m_xParentContainer;
102 while( xParent.is() )
104 Reference<XPropertySet> xProp( xParent, UNO_QUERY );
105 Reference< XChild > xChild( xParent, UNO_QUERY );
106 xParent.set( xChild.is() ? xChild->getParent() : Reference< XInterface >(), UNO_QUERY );
107 if ( xProp.is() && xParent.is() )
109 OUString sName;
110 xProp->getPropertyValue( PROPERTY_NAME ) >>= sName;
112 OUString sPrevious = aHierarchicalName.makeStringAndClear();
113 aHierarchicalName.append( sName + "/" + sPrevious );
116 OUString sHierarchicalName( aHierarchicalName.makeStringAndClear() );
117 if ( !_includingRootContainer )
118 sHierarchicalName = sHierarchicalName.copy( sHierarchicalName.indexOf( '/' ) + 1 );
119 return sHierarchicalName;
122 OUString SAL_CALL OContentHelper::getContentType() throw (RuntimeException, std::exception)
124 ::osl::MutexGuard aGuard(m_aMutex);
126 if ( !m_pImpl->m_aProps.aContentType )
127 { // content type not yet retrieved
128 m_pImpl->m_aProps.aContentType.reset( determineContentType() );
131 return *m_pImpl->m_aProps.aContentType;
134 void SAL_CALL OContentHelper::addContentEventListener( const Reference< XContentEventListener >& _rxListener ) throw (RuntimeException, std::exception)
136 ::osl::MutexGuard aGuard(m_aMutex);
137 if ( _rxListener.is() )
138 m_aContentListeners.addInterface(_rxListener);
141 void SAL_CALL OContentHelper::removeContentEventListener( const Reference< XContentEventListener >& _rxListener ) throw (RuntimeException, std::exception)
143 ::osl::MutexGuard aGuard(m_aMutex);
144 if (_rxListener.is())
145 m_aContentListeners.removeInterface(_rxListener);
148 // XCommandProcessor
149 sal_Int32 SAL_CALL OContentHelper::createCommandIdentifier( ) throw (RuntimeException, std::exception)
151 ::osl::MutexGuard aGuard(m_aMutex);
152 // Just increase counter on every call to generate an identifier.
153 return ++m_nCommandId;
156 Any SAL_CALL OContentHelper::execute( const Command& aCommand, sal_Int32 /*CommandId*/, const Reference< XCommandEnvironment >& Environment ) throw (Exception, CommandAbortedException, RuntimeException, std::exception)
158 Any aRet;
159 if ( aCommand.Name == "getPropertyValues" )
161 // getPropertyValues
163 Sequence< Property > Properties;
164 if ( !( aCommand.Argument >>= Properties ) )
166 OSL_FAIL( "Wrong argument type!" );
167 ucbhelper::cancelCommandExecution(
168 makeAny( IllegalArgumentException(
169 OUString(),
170 static_cast< cppu::OWeakObject * >( this ),
171 -1 ) ),
172 Environment );
173 // Unreachable
175 aRet <<= getPropertyValues( Properties);
177 else if ( aCommand.Name == "setPropertyValues" )
179 // setPropertyValues
181 Sequence< PropertyValue > aProperties;
182 if ( !( aCommand.Argument >>= aProperties ) )
184 OSL_FAIL( "Wrong argument type!" );
185 ucbhelper::cancelCommandExecution(
186 makeAny( IllegalArgumentException(
187 OUString(),
188 static_cast< cppu::OWeakObject * >( this ),
189 -1 ) ),
190 Environment );
191 // Unreachable
194 if ( !aProperties.getLength() )
196 OSL_FAIL( "No properties!" );
197 ucbhelper::cancelCommandExecution(
198 makeAny( IllegalArgumentException(
199 OUString(),
200 static_cast< cppu::OWeakObject * >( this ),
201 -1 ) ),
202 Environment );
203 // Unreachable
206 aRet <<= setPropertyValues( aProperties, Environment );
208 else if ( aCommand.Name == "getPropertySetInfo" )
210 // getPropertySetInfo
212 Reference<XPropertySet> xProp(*this,UNO_QUERY);
213 if ( xProp.is() )
214 aRet <<= xProp->getPropertySetInfo();
215 // aRet <<= getPropertySetInfo(); // TODO
217 else
219 // Unsupported command
221 OSL_FAIL( "Content::execute - unsupported command!" );
223 ucbhelper::cancelCommandExecution(
224 makeAny( UnsupportedCommandException(
225 OUString(),
226 static_cast< cppu::OWeakObject * >( this ) ) ),
227 Environment );
228 // Unreachable
231 return aRet;
234 void SAL_CALL OContentHelper::abort( sal_Int32 /*CommandId*/ ) throw (RuntimeException, std::exception)
238 // XPropertiesChangeNotifier
239 void SAL_CALL OContentHelper::addPropertiesChangeListener( const Sequence< OUString >& PropertyNames, const Reference< XPropertiesChangeListener >& Listener ) throw (RuntimeException, std::exception)
241 ::osl::MutexGuard aGuard(m_aMutex);
242 sal_Int32 nCount = PropertyNames.getLength();
243 if ( !nCount )
245 // Note: An empty sequence means a listener for "all" properties.
246 m_aPropertyChangeListeners.addInterface(OUString(), Listener );
248 else
250 const OUString* pSeq = PropertyNames.getConstArray();
252 for ( sal_Int32 n = 0; n < nCount; ++n )
254 const OUString& rName = pSeq[ n ];
255 if ( !rName.isEmpty() )
256 m_aPropertyChangeListeners.addInterface(rName, Listener );
261 void SAL_CALL OContentHelper::removePropertiesChangeListener( const Sequence< OUString >& PropertyNames, const Reference< XPropertiesChangeListener >& Listener ) throw (RuntimeException, std::exception)
263 ::osl::MutexGuard aGuard(m_aMutex);
264 sal_Int32 nCount = PropertyNames.getLength();
265 if ( !nCount )
267 // Note: An empty sequence means a listener for "all" properties.
268 m_aPropertyChangeListeners.removeInterface( OUString(), Listener );
270 else
272 const OUString* pSeq = PropertyNames.getConstArray();
274 for ( sal_Int32 n = 0; n < nCount; ++n )
276 const OUString& rName = pSeq[ n ];
277 if ( !rName.isEmpty() )
278 m_aPropertyChangeListeners.removeInterface( rName, Listener );
283 // XPropertyContainer
284 void SAL_CALL OContentHelper::addProperty( const OUString& /*Name*/, sal_Int16 /*Attributes*/, const Any& /*DefaultValue*/ ) throw (PropertyExistException, IllegalTypeException, IllegalArgumentException, RuntimeException, std::exception)
286 OSL_FAIL( "OContentHelper::addProperty: not implemented!" );
289 void SAL_CALL OContentHelper::removeProperty( const OUString& /*Name*/ ) throw (UnknownPropertyException, NotRemoveableException, RuntimeException, std::exception)
291 OSL_FAIL( "OContentHelper::removeProperty: not implemented!" );
294 // XInitialization
295 void SAL_CALL OContentHelper::initialize( const Sequence< Any >& _aArguments ) throw(Exception, RuntimeException, std::exception)
297 const Any* pBegin = _aArguments.getConstArray();
298 const Any* pEnd = pBegin + _aArguments.getLength();
299 PropertyValue aValue;
300 for(;pBegin != pEnd;++pBegin)
302 *pBegin >>= aValue;
303 if ( aValue.Name == "Parent" )
305 m_xParentContainer.set(aValue.Value,UNO_QUERY);
307 else if ( aValue.Name == PROPERTY_NAME )
309 aValue.Value >>= m_pImpl->m_aProps.aTitle;
311 else if ( aValue.Name == PROPERTY_PERSISTENT_NAME )
313 aValue.Value >>= m_pImpl->m_aProps.sPersistentName;
318 Sequence< Any > OContentHelper::setPropertyValues(const Sequence< PropertyValue >& rValues,const Reference< XCommandEnvironment >& /*xEnv*/ )
320 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
322 Sequence< Any > aRet( rValues.getLength() );
323 Sequence< PropertyChangeEvent > aChanges( rValues.getLength() );
324 sal_Int32 nChanged = 0;
326 PropertyChangeEvent aEvent;
327 aEvent.Source = static_cast< cppu::OWeakObject * >( this );
328 aEvent.Further = sal_False;
329 aEvent.PropertyHandle = -1;
331 const PropertyValue* pValues = rValues.getConstArray();
332 sal_Int32 nCount = rValues.getLength();
334 for ( sal_Int32 n = 0; n < nCount; ++n )
336 const PropertyValue& rValue = pValues[ n ];
338 if ( rValue.Name == "ContentType" )
340 // Read-only property!
341 aRet[ n ] <<= IllegalAccessException("Property is read-only!",
342 static_cast< cppu::OWeakObject * >( this ) );
344 else if ( rValue.Name == "IsDocument" )
346 // Read-only property!
347 aRet[ n ] <<= IllegalAccessException("Property is read-only!",
348 static_cast< cppu::OWeakObject * >( this ) );
350 else if ( 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 = makeAny( 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 = makeAny( 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 )
486 // First, notify listeners interested in changes of every property.
487 OInterfaceContainerHelper* pAllPropsContainer = m_aPropertyChangeListeners.getContainer( OUString() );
488 if ( pAllPropsContainer )
490 OInterfaceIteratorHelper aIter( *pAllPropsContainer );
491 while ( aIter.hasMoreElements() )
493 // Propagate event.
494 Reference< XPropertiesChangeListener > xListener( aIter.next(), UNO_QUERY );
495 if ( xListener.is() )
496 xListener->propertiesChange( evt );
500 typedef Sequence< PropertyChangeEvent > PropertyEventSequence;
501 typedef ::std::map< XPropertiesChangeListener*, PropertyEventSequence* > 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 PropertyEventSequence* propertyEvents = NULL;
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 propertyEvents = new PropertyEventSequence( nCount );
525 aListeners[ pListener ] = propertyEvents;
527 else
528 propertyEvents = (*it).second;
530 if ( propertyEvents )
531 (*propertyEvents)[n] = rEvent;
536 // Notify listeners.
537 PropertiesEventListenerMap::iterator it = aListeners.begin();
538 while ( !aListeners.empty() )
540 XPropertiesChangeListener* pListener =
541 static_cast< XPropertiesChangeListener * >( (*it).first );
542 PropertyEventSequence* pSeq = (*it).second;
544 // Remove current element.
545 it = aListeners.erase( it );
547 // Propagate event.
548 pListener->propertiesChange( *pSeq );
550 delete pSeq;
555 // com::sun::star::lang::XUnoTunnel
556 sal_Int64 OContentHelper::getSomething( const Sequence< sal_Int8 > & rId ) throw (RuntimeException, std::exception)
558 if (rId.getLength() == 16 && 0 == memcmp(getUnoTunnelImplementationId().getConstArray(), rId.getConstArray(), 16 ) )
559 return reinterpret_cast<sal_Int64>(this);
561 return 0;
564 OContentHelper* OContentHelper::getImplementation( const Reference< XInterface >& _rxComponent )
566 OContentHelper* pContent( NULL );
568 Reference< XUnoTunnel > xUnoTunnel( _rxComponent, UNO_QUERY );
569 if ( xUnoTunnel.is() )
570 pContent = reinterpret_cast< OContentHelper* >( xUnoTunnel->getSomething( getUnoTunnelImplementationId() ) );
572 return pContent;
575 Reference< XInterface > SAL_CALL OContentHelper::getParent( ) throw (RuntimeException, std::exception)
577 ::osl::MutexGuard aGuard(m_aMutex);
578 return m_xParentContainer;
581 void SAL_CALL OContentHelper::setParent( const Reference< XInterface >& _xParent ) throw (NoSupportException, RuntimeException, std::exception)
583 ::osl::MutexGuard aGuard(m_aMutex);
584 m_xParentContainer = _xParent;
587 void OContentHelper::impl_rename_throw(const OUString& _sNewName,bool _bNotify )
589 osl::ClearableGuard< osl::Mutex > aGuard(m_aMutex);
590 if ( _sNewName.equals( m_pImpl->m_aProps.aTitle ) )
591 return;
594 Sequence< PropertyChangeEvent > aChanges( 1 );
596 aChanges[0].Source = static_cast< cppu::OWeakObject * >( this );
597 aChanges[0].Further = sal_False;
598 aChanges[0].PropertyName = PROPERTY_NAME;
599 aChanges[0].PropertyHandle = PROPERTY_ID_NAME;
600 aChanges[0].OldValue <<= m_pImpl->m_aProps.aTitle;
601 aChanges[0].NewValue <<= _sNewName;
603 aGuard.clear();
605 m_pImpl->m_aProps.aTitle = _sNewName;
606 if ( _bNotify )
607 notifyPropertiesChange( aChanges );
608 notifyDataSourceModified();
610 catch(const PropertyVetoException&)
612 throw ElementExistException(_sNewName,*this);
616 void SAL_CALL OContentHelper::rename( const OUString& newName ) throw (SQLException, ElementExistException, RuntimeException, std::exception)
619 impl_rename_throw(newName);
623 void OContentHelper::notifyDataSourceModified()
625 ::dbaccess::notifyDataSourceModified(m_xParentContainer,true);
628 } // namespace dbaccess
630 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */