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 .
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>
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()
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
)
70 ,m_aErrorHelper( m_aContext
)
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
)
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() )
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
);
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
)
159 if ( aCommand
.Name
== "getPropertyValues" )
163 Sequence
< Property
> Properties
;
164 if ( !( aCommand
.Argument
>>= Properties
) )
166 OSL_FAIL( "Wrong argument type!" );
167 ucbhelper::cancelCommandExecution(
168 makeAny( IllegalArgumentException(
170 static_cast< cppu::OWeakObject
* >( this ),
175 aRet
<<= getPropertyValues( Properties
);
177 else if ( aCommand
.Name
== "setPropertyValues" )
181 Sequence
< PropertyValue
> aProperties
;
182 if ( !( aCommand
.Argument
>>= aProperties
) )
184 OSL_FAIL( "Wrong argument type!" );
185 ucbhelper::cancelCommandExecution(
186 makeAny( IllegalArgumentException(
188 static_cast< cppu::OWeakObject
* >( this ),
194 if ( !aProperties
.getLength() )
196 OSL_FAIL( "No properties!" );
197 ucbhelper::cancelCommandExecution(
198 makeAny( IllegalArgumentException(
200 static_cast< cppu::OWeakObject
* >( this ),
206 aRet
<<= setPropertyValues( aProperties
, Environment
);
208 else if ( aCommand
.Name
== "getPropertySetInfo" )
210 // getPropertySetInfo
212 Reference
<XPropertySet
> xProp(*this,UNO_QUERY
);
214 aRet
<<= xProp
->getPropertySetInfo();
215 // aRet <<= getPropertySetInfo(); // TODO
219 // Unsupported command
221 OSL_FAIL( "Content::execute - unsupported command!" );
223 ucbhelper::cancelCommandExecution(
224 makeAny( UnsupportedCommandException(
226 static_cast< cppu::OWeakObject
* >( this ) ) ),
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();
245 // Note: An empty sequence means a listener for "all" properties.
246 m_aPropertyChangeListeners
.addInterface(OUString(), Listener
);
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();
267 // Note: An empty sequence means a listener for "all" properties.
268 m_aPropertyChangeListeners
.removeInterface( OUString(), Listener
);
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!" );
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
)
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" )
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
;
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();
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() )
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
;
528 propertyEvents
= (*it
).second
;
530 if ( propertyEvents
)
531 (*propertyEvents
)[n
] = rEvent
;
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
);
548 pListener
->propertiesChange( *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);
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() ) );
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
) )
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
;
605 m_pImpl
->m_aProps
.aTitle
= _sNewName
;
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: */