xref: /trunk/main/ucb/source/ucp/ext/ucpext_content.cxx (revision cdf0e10c)
1 /*************************************************************************
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * Copyright 2000, 2010 Oracle and/or its affiliates.
5  *
6  * OpenOffice.org - a multi-platform office productivity suite
7  *
8  * This file is part of OpenOffice.org.
9  *
10  * OpenOffice.org is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Lesser General Public License version 3
12  * only, as published by the Free Software Foundation.
13  *
14  * OpenOffice.org is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Lesser General Public License version 3 for more details
18  * (a copy is included in the LICENSE file that accompanied this code).
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * version 3 along with OpenOffice.org.  If not, see
22  * <http://www.openoffice.org/license.html>
23  * for a copy of the LGPLv3 License.
24  *
25 ************************************************************************/
26 
27 #include "precompiled_ucb.hxx"
28 
29 #include "ucpext_content.hxx"
30 
31 #include "ucpext_content.hxx"
32 #include "ucpext_provider.hxx"
33 #include "ucpext_resultset.hxx"
34 
35 /** === begin UNO includes === **/
36 #include <com/sun/star/beans/PropertyAttribute.hpp>
37 #include <com/sun/star/beans/XPropertyAccess.hpp>
38 #include <com/sun/star/lang/IllegalAccessException.hpp>
39 #include <com/sun/star/sdbc/XRow.hpp>
40 #include <com/sun/star/ucb/XCommandInfo.hpp>
41 #include <com/sun/star/ucb/XPersistentPropertySet.hpp>
42 #include <com/sun/star/io/XOutputStream.hpp>
43 #include <com/sun/star/io/XActiveDataSink.hpp>
44 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
45 #include <com/sun/star/ucb/OpenMode.hpp>
46 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
47 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
48 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
49 #include <com/sun/star/ucb/OpenMode.hpp>
50 #include <com/sun/star/ucb/XDynamicResultSet.hpp>
51 #include <com/sun/star/lang/IllegalAccessException.hpp>
52 #include <com/sun/star/deployment/XPackageInformationProvider.hpp>
53 /** === end UNO includes === **/
54 
55 #include <ucbhelper/contentidentifier.hxx>
56 #include <ucbhelper/propertyvalueset.hxx>
57 #include <ucbhelper/cancelcommandexecution.hxx>
58 #include <ucbhelper/content.hxx>
59 #include <tools/diagnose_ex.h>
60 #include <comphelper/string.hxx>
61 #include <comphelper/componentcontext.hxx>
62 #include <rtl/ustrbuf.hxx>
63 #include <rtl/uri.hxx>
64 
65 #include <algorithm>
66 
67 //......................................................................................................................
68 namespace ucb { namespace ucp { namespace ext
69 {
70 //......................................................................................................................
71 
72 	/** === begin UNO using === **/
73 	using ::com::sun::star::uno::Reference;
74 	using ::com::sun::star::uno::XInterface;
75 	using ::com::sun::star::uno::UNO_QUERY;
76 	using ::com::sun::star::uno::UNO_QUERY_THROW;
77 	using ::com::sun::star::uno::UNO_SET_THROW;
78 	using ::com::sun::star::uno::Exception;
79 	using ::com::sun::star::uno::RuntimeException;
80 	using ::com::sun::star::uno::Any;
81 	using ::com::sun::star::uno::makeAny;
82 	using ::com::sun::star::uno::Sequence;
83 	using ::com::sun::star::uno::Type;
84     using ::com::sun::star::lang::XMultiServiceFactory;
85     using ::com::sun::star::ucb::XContentIdentifier;
86     using ::com::sun::star::ucb::IllegalIdentifierException;
87     using ::com::sun::star::ucb::XContent;
88     using ::com::sun::star::ucb::XCommandEnvironment;
89     using ::com::sun::star::ucb::Command;
90     using ::com::sun::star::ucb::CommandAbortedException;
91     using ::com::sun::star::beans::Property;
92     using ::com::sun::star::lang::IllegalArgumentException;
93     using ::com::sun::star::beans::PropertyValue;
94     using ::com::sun::star::ucb::OpenCommandArgument2;
95     using ::com::sun::star::ucb::XDynamicResultSet;
96     using ::com::sun::star::ucb::UnsupportedOpenModeException;
97     using ::com::sun::star::io::XOutputStream;
98     using ::com::sun::star::io::XActiveDataSink;
99     using ::com::sun::star::io::XInputStream;
100     using ::com::sun::star::ucb::UnsupportedDataSinkException;
101     using ::com::sun::star::ucb::UnsupportedCommandException;
102     using ::com::sun::star::sdbc::XRow;
103     using ::com::sun::star::beans::XPropertySet;
104     using ::com::sun::star::beans::PropertyChangeEvent;
105     using ::com::sun::star::lang::IllegalAccessException;
106     using ::com::sun::star::ucb::CommandInfo;
107     using ::com::sun::star::deployment::XPackageInformationProvider;
108 	/** === end UNO using === **/
109     namespace OpenMode = ::com::sun::star::ucb::OpenMode;
110     namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute;
111 
112     //==================================================================================================================
113     //= helper
114     //==================================================================================================================
115     namespace
116     {
117         //--------------------------------------------------------------------------------------------------------------
118         ::rtl::OUString lcl_compose( const ::rtl::OUString& i_rBaseURL, const ::rtl::OUString& i_rRelativeURL )
119         {
120             ENSURE_OR_RETURN( i_rBaseURL.getLength(), "illegal base URL", i_rRelativeURL );
121 
122             ::rtl::OUStringBuffer aComposer( i_rBaseURL );
123             if ( i_rBaseURL.getStr()[ i_rBaseURL.getLength() - 1 ] != '/' )
124                 aComposer.append( sal_Unicode( '/' ) );
125             aComposer.append( i_rRelativeURL );
126             return aComposer.makeStringAndClear();
127         }
128 
129         //--------------------------------------------------------------------------------------------------------------
130         struct SelectPropertyName : public ::std::unary_function< Property, ::rtl::OUString >
131         {
132             const ::rtl::OUString& operator()( const Property& i_rProperty ) const
133             {
134                 return i_rProperty.Name;
135             }
136         };
137     }
138 
139     //==================================================================================================================
140     //= Content
141     //==================================================================================================================
142     //------------------------------------------------------------------------------------------------------------------
143     Content::Content( const Reference< XMultiServiceFactory >& i_rORB, ::ucbhelper::ContentProviderImplHelper* i_pProvider,
144                       const Reference< XContentIdentifier >& i_rIdentifier )
145         :Content_Base( i_rORB, i_pProvider, i_rIdentifier )
146         ,m_eExtContentType( E_UNKNOWN )
147         ,m_aIsFolder()
148         ,m_aContentType()
149         ,m_sExtensionId()
150         ,m_sPathIntoExtension()
151     {
152         const ::rtl::OUString sURL( getIdentifier()->getContentIdentifier() );
153         if ( denotesRootContent( sURL ) )
154         {
155             m_eExtContentType = E_ROOT;
156         }
157         else
158         {
159             const ::rtl::OUString sRelativeURL( sURL.copy( ContentProvider::getRootURL().getLength() ) );
160             const sal_Int32 nSepPos = sRelativeURL.indexOf( '/' );
161             if ( ( nSepPos == -1 ) || ( nSepPos == sRelativeURL.getLength() - 1 ) )
162             {
163                 m_eExtContentType = E_EXTENSION_ROOT;
164             }
165             else
166             {
167                 m_eExtContentType = E_EXTENSION_CONTENT;
168             }
169         }
170 
171         if ( m_eExtContentType != E_ROOT )
172         {
173             const ::rtl::OUString sRootURL = ContentProvider::getRootURL();
174             m_sExtensionId = sURL.copy( sRootURL.getLength() );
175 
176             const sal_Int32 nNextSep = m_sExtensionId.indexOf( '/' );
177             if ( nNextSep > -1 )
178             {
179                 m_sPathIntoExtension = m_sExtensionId.copy( nNextSep + 1 );
180                 m_sExtensionId = m_sExtensionId.copy( 0, nNextSep );
181             }
182             m_sExtensionId = Content::decodeIdentifier( m_sExtensionId );
183         }
184     }
185 
186     //------------------------------------------------------------------------------------------------------------------
187     Content::~Content()
188     {
189     }
190 
191     //------------------------------------------------------------------------------------------------------------------
192     ::rtl::OUString SAL_CALL Content::getImplementationName() throw( RuntimeException )
193     {
194         return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.comp.ucp.ext.Content" ) );
195     }
196 
197     //------------------------------------------------------------------------------------------------------------------
198     Sequence< ::rtl::OUString > SAL_CALL Content::getSupportedServiceNames() throw( RuntimeException )
199     {
200         Sequence< ::rtl::OUString > aServiceNames(2);
201         aServiceNames[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.ucb.Content" ) );
202         aServiceNames[1] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.ucb.ExtensionContent" ) );
203         return aServiceNames;
204     }
205 
206     //------------------------------------------------------------------------------------------------------------------
207     ::rtl::OUString SAL_CALL Content::getContentType() throw( RuntimeException )
208     {
209         impl_determineContentType();
210         return *m_aContentType;
211     }
212 
213     //------------------------------------------------------------------------------------------------------------------
214     Any SAL_CALL Content::execute( const Command& aCommand, sal_Int32 /* CommandId */, const Reference< XCommandEnvironment >& i_rEvironment )
215         throw( Exception, CommandAbortedException, RuntimeException )
216     {
217         Any aRet;
218 
219         if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "getPropertyValues" ) ) )
220 	    {
221             Sequence< Property > Properties;
222 		    if ( !( aCommand.Argument >>= Properties ) )
223 		    {
224                 ::ucbhelper::cancelCommandExecution( makeAny( IllegalArgumentException(
225                     ::rtl::OUString(), *this, -1 ) ),
226                     i_rEvironment );
227                 // unreachable
228 		    }
229 
230             aRet <<= getPropertyValues( Properties, i_rEvironment );
231 	    }
232         else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "setPropertyValues" ) ) )
233         {
234             Sequence< PropertyValue > aProperties;
235 		    if ( !( aCommand.Argument >>= aProperties ) )
236 		    {
237                 ::ucbhelper::cancelCommandExecution( makeAny( IllegalArgumentException(
238                     ::rtl::OUString(), *this, -1 ) ),
239                     i_rEvironment );
240                 // unreachable
241             }
242 
243 		    if ( !aProperties.getLength() )
244 		    {
245                 ::ucbhelper::cancelCommandExecution( makeAny( IllegalArgumentException(
246                     ::rtl::OUString(), *this, -1 ) ),
247                     i_rEvironment );
248                 // unreachable
249             }
250 
251             aRet <<= setPropertyValues( aProperties, i_rEvironment );
252 	    }
253         else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "getPropertySetInfo" ) ) )
254         {
255 		    // implemented by base class.
256 		    aRet <<= getPropertySetInfo( i_rEvironment );
257 	    }
258         else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "getCommandInfo" ) ) )
259         {
260 		    // implemented by base class.
261 		    aRet <<= getCommandInfo( i_rEvironment );
262 	    }
263         else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "open" ) ) )
264         {
265             OpenCommandArgument2 aOpenCommand;
266       	    if ( !( aCommand.Argument >>= aOpenCommand ) )
267 		    {
268                 ::ucbhelper::cancelCommandExecution( makeAny( IllegalArgumentException(
269                     ::rtl::OUString(), *this, -1 ) ),
270                     i_rEvironment );
271                 // unreachable
272             }
273 
274             sal_Bool bOpenFolder =
275                 ( ( aOpenCommand.Mode == OpenMode::ALL ) ||
276                   ( aOpenCommand.Mode == OpenMode::FOLDERS ) ||
277                   ( aOpenCommand.Mode == OpenMode::DOCUMENTS ) );
278 
279 
280             if ( bOpenFolder && impl_isFolder() )
281 		    {
282                 Reference< XDynamicResultSet > xSet = new ResultSet(
283                     m_xSMgr, this, aOpenCommand, i_rEvironment );
284     		    aRet <<= xSet;
285   		    }
286 
287             if ( aOpenCommand.Sink.is() )
288             {
289                 const ::rtl::OUString sPhysicalContentURL( getPhysicalURL() );
290                 ::ucbhelper::Content aRequestedContent( sPhysicalContentURL, i_rEvironment );
291                 aRet = aRequestedContent.executeCommand( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "open" ) ), makeAny( aOpenCommand ) );
292 		    }
293 	    }
294 
295 	    else
296 	    {
297             ::ucbhelper::cancelCommandExecution( makeAny( UnsupportedCommandException(
298                 ::rtl::OUString(), *this ) ),
299                 i_rEvironment );
300             // unreachable
301         }
302 
303 	    return aRet;
304     }
305 
306     //------------------------------------------------------------------------------------------------------------------
307     void SAL_CALL Content::abort( sal_Int32 ) throw( RuntimeException )
308     {
309     }
310 
311     //------------------------------------------------------------------------------------------------------------------
312     ::rtl::OUString Content::encodeIdentifier( const ::rtl::OUString& i_rIdentifier )
313     {
314         return ::rtl::Uri::encode( i_rIdentifier, rtl_UriCharClassRegName, rtl_UriEncodeIgnoreEscapes,
315             RTL_TEXTENCODING_UTF8 );
316     }
317 
318     //------------------------------------------------------------------------------------------------------------------
319     ::rtl::OUString Content::decodeIdentifier( const ::rtl::OUString& i_rIdentifier )
320     {
321         return ::rtl::Uri::decode( i_rIdentifier, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 );
322     }
323 
324     //------------------------------------------------------------------------------------------------------------------
325     bool Content::denotesRootContent( const ::rtl::OUString& i_rContentIdentifier )
326     {
327         const ::rtl::OUString sRootURL( ContentProvider::getRootURL() );
328         if ( i_rContentIdentifier == sRootURL )
329             return true;
330 
331         // the root URL contains only two trailing /, but we also recognize 3 of them as denoting the root URL
332         if  (   i_rContentIdentifier.match( sRootURL )
333             &&  ( i_rContentIdentifier.getLength() == sRootURL.getLength() + 1 )
334             &&  ( i_rContentIdentifier[ i_rContentIdentifier.getLength() - 1 ] == '/' )
335             )
336             return true;
337 
338         return false;
339     }
340 
341     //------------------------------------------------------------------------------------------------------------------
342     ::rtl::OUString Content::getParentURL()
343     {
344         const ::rtl::OUString sRootURL( ContentProvider::getRootURL() );
345 
346         switch ( m_eExtContentType )
347         {
348         case E_ROOT:
349             // don't have a parent
350             return sRootURL;
351 
352         case E_EXTENSION_ROOT:
353             // our parent is the root itself
354             return sRootURL;
355 
356         case E_EXTENSION_CONTENT:
357         {
358             const ::rtl::OUString sURL = m_xIdentifier->getContentIdentifier();
359 
360             // cut the root URL
361             ENSURE_OR_BREAK( sURL.match( sRootURL, 0 ), "illegal URL structure - no root" );
362             ::rtl::OUString sRelativeURL( sURL.copy( sRootURL.getLength() ) );
363 
364             // cut the extension ID
365             const ::rtl::OUString sSeparatedExtensionId( encodeIdentifier( m_sExtensionId ) + ::rtl::OUString( sal_Unicode( '/' ) ) );
366             ENSURE_OR_BREAK( sRelativeURL.match( sSeparatedExtensionId ), "illegal URL structure - no extension ID" );
367             sRelativeURL = sRelativeURL.copy( sSeparatedExtensionId.getLength() );
368 
369             // cut the final slash (if any)
370             ENSURE_OR_BREAK( sRelativeURL.getLength(), "illegal URL structure - ExtensionContent should have a level below the extension ID" );
371             if ( sRelativeURL.getStr()[ sRelativeURL.getLength() - 1 ] == '/' )
372                 sRelativeURL = sRelativeURL.copy( 0, sRelativeURL.getLength() - 1 );
373 
374             // remove the last segment
375             const sal_Int32 nLastSep = sRelativeURL.lastIndexOf( '/' );
376             sRelativeURL = sRelativeURL.copy( 0, nLastSep != -1 ? nLastSep : 0 );
377 
378             ::rtl::OUStringBuffer aComposer;
379             aComposer.append( sRootURL );
380             aComposer.append( sSeparatedExtensionId );
381             aComposer.append( sRelativeURL );
382             return aComposer.makeStringAndClear();
383         }
384 
385         default:
386             OSL_ENSURE( false, "Content::getParentURL: unhandled case!" );
387             break;
388         }
389         return ::rtl::OUString();
390     }
391 
392     //------------------------------------------------------------------------------------------------------------------
393     Reference< XRow > Content::getArtificialNodePropertyValues( const Reference< XMultiServiceFactory >& i_rORB,
394         const Sequence< Property >& i_rProperties, const ::rtl::OUString& i_rTitle )
395     {
396 	    // note: empty sequence means "get values of all supported properties".
397         ::rtl::Reference< ::ucbhelper::PropertyValueSet > xRow = new ::ucbhelper::PropertyValueSet( i_rORB );
398 
399 	    const sal_Int32 nCount = i_rProperties.getLength();
400 	    if ( nCount )
401 	    {
402             Reference< XPropertySet > xAdditionalPropSet;
403 
404             const Property* pProps = i_rProperties.getConstArray();
405 		    for ( sal_Int32 n = 0; n < nCount; ++n )
406 		    {
407                 const Property& rProp = pProps[ n ];
408 
409 			    // Process Core properties.
410                 if ( rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) )
411                 {
412                     xRow->appendString ( rProp, ContentProvider::getArtificialNodeContentType() );
413 			    }
414                 else if ( rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
415 			    {
416 				    xRow->appendString ( rProp, i_rTitle );
417 			    }
418                 else if ( rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) )
419 			    {
420 				    xRow->appendBoolean( rProp, sal_False );
421 			    }
422                 else if ( rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) )
423 			    {
424 				    xRow->appendBoolean( rProp, sal_True );
425 			    }
426 			    else
427 			    {
428 				    // append empty entry.
429 				    xRow->appendVoid( rProp );
430 			    }
431 		    }
432 	    }
433 	    else
434 	    {
435 		    // Append all Core Properties.
436 		    xRow->appendString ( Property( ::rtl::OUString::createFromAscii( "ContentType" ),
437 					      -1,
438                           getCppuType( static_cast< const ::rtl::OUString * >( 0 ) ),
439                           PropertyAttribute::BOUND | PropertyAttribute::READONLY ),
440 			    ContentProvider::getArtificialNodeContentType() );
441 		    xRow->appendString ( Property( ::rtl::OUString::createFromAscii( "Title" ),
442 					      -1,
443                           getCppuType( static_cast< const ::rtl::OUString * >( 0 ) ),
444                           PropertyAttribute::BOUND | PropertyAttribute::READONLY ),
445 			    i_rTitle );
446 		    xRow->appendBoolean( Property( ::rtl::OUString::createFromAscii( "IsDocument" ),
447 					      -1,
448 					      getCppuBooleanType(),
449                           PropertyAttribute::BOUND | PropertyAttribute::READONLY ),
450 			    sal_False );
451 		    xRow->appendBoolean( Property( ::rtl::OUString::createFromAscii( "IsFolder" ),
452 					      -1,
453 					      getCppuBooleanType(),
454                           PropertyAttribute::BOUND | PropertyAttribute::READONLY ),
455 			    sal_True );
456 	    }
457 
458         return Reference< XRow >( xRow.get() );
459     }
460 
461     //------------------------------------------------------------------------------------------------------------------
462     ::rtl::OUString Content::getPhysicalURL() const
463     {
464         ENSURE_OR_RETURN( m_eExtContentType != E_ROOT, "illegal call", ::rtl::OUString() );
465 
466         // create an ucb::XContent for the physical file within the deployed extension
467         const ::comphelper::ComponentContext aContext( m_xSMgr );
468         const Reference< XPackageInformationProvider > xPackageInfo(
469             aContext.getSingleton( "com.sun.star.deployment.PackageInformationProvider" ), UNO_QUERY_THROW );
470         const ::rtl::OUString sPackageLocation( xPackageInfo->getPackageLocation( m_sExtensionId ) );
471 
472         if ( m_sPathIntoExtension.getLength() == 0 )
473             return sPackageLocation;
474         return lcl_compose( sPackageLocation, m_sPathIntoExtension );
475     }
476 
477     //------------------------------------------------------------------------------------------------------------------
478     Reference< XRow > Content::getPropertyValues( const Sequence< Property >& i_rProperties, const Reference< XCommandEnvironment >& i_rEnv )
479     {
480         ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex );
481 
482         switch ( m_eExtContentType )
483         {
484         case E_ROOT:
485 	        return getArtificialNodePropertyValues( m_xSMgr, i_rProperties, ContentProvider::getRootURL() );
486         case E_EXTENSION_ROOT:
487 	        return getArtificialNodePropertyValues( m_xSMgr, i_rProperties, m_sExtensionId );
488         case E_EXTENSION_CONTENT:
489         {
490             const ::rtl::OUString sPhysicalContentURL( getPhysicalURL() );
491             ::ucbhelper::Content aRequestedContent( sPhysicalContentURL, i_rEnv );
492 
493             // translate the property request
494             Sequence< ::rtl::OUString > aPropertyNames( i_rProperties.getLength() );
495             ::std::transform(
496                 i_rProperties.getConstArray(),
497                 i_rProperties.getConstArray() + i_rProperties.getLength(),
498                 aPropertyNames.getArray(),
499                 SelectPropertyName()
500             );
501             const Sequence< Any > aPropertyValues = aRequestedContent.getPropertyValues( aPropertyNames );
502             const ::rtl::Reference< ::ucbhelper::PropertyValueSet > xValueRow = new ::ucbhelper::PropertyValueSet( m_xSMgr );
503             sal_Int32 i=0;
504             for (   const Any* value = aPropertyValues.getConstArray();
505                     value != aPropertyValues.getConstArray() + aPropertyValues.getLength();
506                     ++value, ++i
507                 )
508             {
509                 xValueRow->appendObject( aPropertyNames[i], *value );
510             }
511             return xValueRow.get();
512         }
513 
514         default:
515             OSL_ENSURE( false, "Content::getPropertyValues: unhandled case!" );
516             break;
517         }
518 
519         OSL_ENSURE( false, "Content::getPropertyValues: unreachable!" );
520         return NULL;
521     }
522 
523     //------------------------------------------------------------------------------------------------------------------
524     Sequence< Any > Content::setPropertyValues( const Sequence< PropertyValue >& i_rValues, const Reference< XCommandEnvironment >& /* xEnv */)
525     {
526         ::osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
527 
528         Sequence< Any > aRet( i_rValues.getLength() );
529         Sequence< PropertyChangeEvent > aChanges( i_rValues.getLength() );
530 
531         PropertyChangeEvent aEvent;
532         aEvent.Source         = static_cast< cppu::OWeakObject * >( this );
533 	    aEvent.Further 		  = sal_False;
534         aEvent.PropertyHandle = -1;
535 
536         const PropertyValue* pValues = i_rValues.getConstArray();
537 	    const sal_Int32 nCount = i_rValues.getLength();
538 
539 	    for ( sal_Int32 n = 0; n < nCount; ++n, ++pValues )
540 	    {
541 		    // all our properties are read-only ...
542             aRet[ n ] <<= IllegalAccessException( ::rtl::OUString::createFromAscii( "property is read-only." ), *this );
543 	    }
544 
545         return aRet;
546     }
547 
548     //------------------------------------------------------------------------------------------------------------------
549     Sequence< CommandInfo > Content::getCommands( const Reference< XCommandEnvironment > & /*xEnv*/ )
550     {
551 	    sal_uInt32 nCommandCount = 5;
552         static const CommandInfo aCommandInfoTable[] =
553 	    {
554 		    ///////////////////////////////////////////////////////////////
555 		    // Mandatory commands
556 		    ///////////////////////////////////////////////////////////////
557             CommandInfo(
558                 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getCommandInfo" ) ),
559 			    -1,
560 			    getCppuVoidType()
561 		    ),
562             CommandInfo(
563                 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getPropertySetInfo" ) ),
564 			    -1,
565 			    getCppuVoidType()
566 		    ),
567             CommandInfo(
568                 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getPropertyValues" ) ),
569 			    -1,
570                 getCppuType(
571                     static_cast< Sequence< Property > * >( 0 ) )
572 		    ),
573             CommandInfo(
574                 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "setPropertyValues" ) ),
575 			    -1,
576                 getCppuType(
577                     static_cast< Sequence< PropertyValue > * >( 0 ) )
578 		    )
579 		    ///////////////////////////////////////////////////////////////
580 		    // Optional standard commands
581 		    ///////////////////////////////////////////////////////////////
582             , CommandInfo(
583                 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "open" ) ),
584 			    -1,
585                 getCppuType( static_cast< OpenCommandArgument2 * >( 0 ) )
586 		    )
587 	    };
588 
589         return Sequence< CommandInfo >( aCommandInfoTable, nCommandCount );
590     }
591 
592     //------------------------------------------------------------------------------------------------------------------
593     Sequence< Property > Content::getProperties( const Reference< XCommandEnvironment > & /*xEnv*/ )
594     {
595         static Property aProperties[] =
596 	    {
597             Property(
598                 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ContentType" ) ),
599 			    -1,
600                 getCppuType( static_cast< const ::rtl::OUString * >( 0 ) ),
601                 PropertyAttribute::BOUND | PropertyAttribute::READONLY
602 		    ),
603             Property(
604                 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsDocument" ) ),
605 			    -1,
606 			    getCppuBooleanType(),
607                 PropertyAttribute::BOUND | PropertyAttribute::READONLY
608 		    ),
609             Property(
610                 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFolder" ) ),
611 			    -1,
612 			    getCppuBooleanType(),
613                 PropertyAttribute::BOUND | PropertyAttribute::READONLY
614 		    ),
615             Property(
616                 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ),
617 			    -1,
618                 getCppuType( static_cast< const ::rtl::OUString * >( 0 ) ),
619                 PropertyAttribute::BOUND | PropertyAttribute::READONLY
620 		    )
621 	    };
622         return Sequence< Property >( aProperties, sizeof( aProperties ) / sizeof( aProperties[0] ) );
623     }
624 
625     //------------------------------------------------------------------------------------------------------------------
626     bool Content::impl_isFolder()
627     {
628         if ( !!m_aIsFolder )
629             return *m_aIsFolder;
630 
631         bool bIsFolder = false;
632         try
633         {
634             Sequence< Property > aProps(1);
635             aProps[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFolder" ) );
636             Reference< XRow > xRow( getPropertyValues( aProps, NULL ), UNO_SET_THROW );
637             bIsFolder = xRow->getBoolean(1);
638         }
639         catch( const Exception& )
640         {
641         	DBG_UNHANDLED_EXCEPTION();
642         }
643         m_aIsFolder.reset( bIsFolder );
644         return *m_aIsFolder;
645     }
646 
647     //------------------------------------------------------------------------------------------------------------------
648     void Content::impl_determineContentType()
649     {
650         if ( !!m_aContentType )
651             return;
652 
653         m_aContentType.reset( ContentProvider::getArtificialNodeContentType() );
654         if ( m_eExtContentType == E_EXTENSION_CONTENT )
655         {
656             try
657             {
658                 Sequence< Property > aProps(1);
659                 aProps[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ContentType" ) );
660                 Reference< XRow > xRow( getPropertyValues( aProps, NULL ), UNO_SET_THROW );
661                 m_aContentType.reset( xRow->getString(1) );
662             }
663             catch( const Exception& )
664             {
665         	    DBG_UNHANDLED_EXCEPTION();
666             }
667         }
668     }
669 
670 //......................................................................................................................
671 } } }   // namespace ucp::ext
672 //......................................................................................................................
673