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 <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>
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
)
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
>();
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() )
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
);
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
)
171 if ( aCommand
.Name
== "getPropertyValues" )
175 Sequence
< Property
> Properties
;
176 if ( !( aCommand
.Argument
>>= Properties
) )
178 OSL_FAIL( "Wrong argument type!" );
179 ucbhelper::cancelCommandExecution(
180 makeAny( IllegalArgumentException(
182 static_cast< cppu::OWeakObject
* >( this ),
187 aRet
<<= getPropertyValues( Properties
);
189 else if ( aCommand
.Name
== "setPropertyValues" )
193 Sequence
< PropertyValue
> aProperties
;
194 if ( !( aCommand
.Argument
>>= aProperties
) )
196 OSL_FAIL( "Wrong argument type!" );
197 ucbhelper::cancelCommandExecution(
198 makeAny( IllegalArgumentException(
200 static_cast< cppu::OWeakObject
* >( this ),
206 if ( !aProperties
.hasElements() )
208 OSL_FAIL( "No properties!" );
209 ucbhelper::cancelCommandExecution(
210 makeAny( IllegalArgumentException(
212 static_cast< cppu::OWeakObject
* >( this ),
218 aRet
<<= setPropertyValues( aProperties
);
220 else if ( aCommand
.Name
== "getPropertySetInfo" )
222 // getPropertySetInfo
224 Reference
<XPropertySet
> xProp(*this,UNO_QUERY
);
226 aRet
<<= xProp
->getPropertySetInfo();
227 // aRet <<= getPropertySetInfo(); // TODO
231 // Unsupported command
233 OSL_FAIL( "Content::execute - unsupported command!" );
235 ucbhelper::cancelCommandExecution(
236 makeAny( UnsupportedCommandException(
238 static_cast< cppu::OWeakObject
* >( this ) ) ),
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();
257 // Note: An empty sequence means a listener for "all" properties.
258 m_aPropertyChangeListeners
.addInterface(OUString(), Listener
);
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();
279 // Note: An empty sequence means a listener for "all" properties.
280 m_aPropertyChangeListeners
.removeInterface( OUString(), Listener
);
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!" );
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
)
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" )
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
;
375 catch( const Exception
& )
377 OSL_FAIL( "OContentHelper::setPropertyValues('Title'): caught an exception while renaming!" );
382 // Old value equals new value. No error!
387 aRet
[ n
] <<= IllegalTypeException("Property value has wrong type!",
388 static_cast< cppu::OWeakObject
* >( this ) );
394 aRet
[ n
] <<= Exception("No property set for storing the value!",
395 static_cast< cppu::OWeakObject
* >( this ) );
401 notifyDataSourceModified();
403 aChanges
.realloc( nChanged
);
404 notifyPropertiesChange( aChanges
);
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();
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
);
444 xRow
->appendVoid(rProp
);
449 // Append all Core Properties.
451 Property( "ContentType", -1,
452 cppu::UnoType
<OUString
>::get(),
453 PropertyAttribute::BOUND
454 | PropertyAttribute::READONLY
),
457 Property( "Title", -1,
458 cppu::UnoType
<OUString
>::get(),
459 PropertyAttribute::BOUND
),
460 m_pImpl
->m_aProps
.aTitle
);
462 Property( "IsDocument", -1,
463 cppu::UnoType
<bool>::get(),
464 PropertyAttribute::BOUND
465 | PropertyAttribute::READONLY
),
466 m_pImpl
->m_aProps
.bIsDocument
);
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();
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() )
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
;
528 propertyEvents
= &(*it
).second
;
530 (*propertyEvents
)[n
] = rEvent
;
536 for (auto & rPair
: aListeners
)
538 XPropertiesChangeListener
* pListener
= rPair
.first
;
539 Sequence
< PropertyChangeEvent
>& rSeq
= rPair
.second
;
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);
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
)
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
;
585 m_pImpl
->m_aProps
.aTitle
= _sNewName
;
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: */