xref: /aoo42x/main/ucb/source/ucp/odma/odma_content.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_ucb.hxx"
30 
31 /**************************************************************************
32 								TODO
33  **************************************************************************
34 
35  *************************************************************************/
36 #include <osl/diagnose.h>
37 #include "odma_contentprops.hxx"
38 #include <com/sun/star/ucb/XDynamicResultSet.hpp>
39 #include <com/sun/star/beans/PropertyAttribute.hpp>
40 #include <com/sun/star/beans/XPropertyAccess.hpp>
41 #include <com/sun/star/lang/IllegalAccessException.hpp>
42 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
43 #include <com/sun/star/sdbc/XRow.hpp>
44 #include <com/sun/star/io/XOutputStream.hpp>
45 #include <com/sun/star/io/XActiveDataSink.hpp>
46 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
47 #include <com/sun/star/ucb/OpenMode.hpp>
48 #include <com/sun/star/ucb/XCommandInfo.hpp>
49 #include <com/sun/star/ucb/XPersistentPropertySet.hpp>
50 #include <ucbhelper/contentidentifier.hxx>
51 #include <ucbhelper/propertyvalueset.hxx>
52 #include <ucbhelper/cancelcommandexecution.hxx>
53 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
54 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
55 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
56 #include <com/sun/star/ucb/MissingPropertiesException.hpp>
57 #include <com/sun/star/io/XActiveDataStreamer.hpp>
58 #include <com/sun/star/ucb/TransferInfo.hpp>
59 #include <com/sun/star/ucb/NameClash.hpp>
60 #include "odma_content.hxx"
61 #include "odma_provider.hxx"
62 #include "odma_resultset.hxx"
63 #include "odma_inputstream.hxx"
64 #include <ucbhelper/content.hxx>
65 #include <com/sun/star/uno/Exception.hpp>
66 #include <rtl/ref.hxx>
67 #include <osl/file.hxx>
68 
69 using namespace com::sun::star;
70 using namespace odma;
71 
72 //=========================================================================
73 //=========================================================================
74 //
75 // Content Implementation.
76 //
77 //=========================================================================
78 //=========================================================================
79 
80 Content::Content( const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
81                   ContentProvider* pProvider,
82                   const uno::Reference< ucb::XContentIdentifier >& Identifier,
83 				  const ::rtl::Reference<ContentProperties>& _rProps)
84 	: ContentImplHelper( rxSMgr, pProvider, Identifier )
85 	,m_aProps(_rProps)
86 	,m_pProvider(pProvider)
87 	,m_pContent(NULL)
88 {
89 	OSL_ENSURE(m_aProps.is(),"No valid ContentPropeties!");
90 }
91 
92 //=========================================================================
93 // virtual
94 Content::~Content()
95 {
96 	delete m_pContent;
97 }
98 
99 //=========================================================================
100 //
101 // XInterface methods.
102 //
103 //=========================================================================
104 
105 // virtual
106 void SAL_CALL Content::acquire() throw()
107 {
108 	ContentImplHelper::acquire();
109 }
110 
111 //=========================================================================
112 // virtual
113 void SAL_CALL Content::release() throw()
114 {
115 	ContentImplHelper::release();
116 }
117 
118 //=========================================================================
119 // virtual
120 uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType )
121     throw ( uno::RuntimeException )
122 {
123     uno::Any aRet;
124 
125 	// @@@ Add support for additional interfaces.
126 #if 0
127   	aRet = cppu::queryInterface( rType,
128                                  static_cast< yyy::Xxxxxxxxx * >( this ) );
129 #endif
130 
131  	return aRet.hasValue() ? aRet : ContentImplHelper::queryInterface( rType );
132 }
133 
134 //=========================================================================
135 //
136 // XTypeProvider methods.
137 //
138 //=========================================================================
139 
140 XTYPEPROVIDER_COMMON_IMPL( Content );
141 
142 //=========================================================================
143 // virtual
144 uno::Sequence< uno::Type > SAL_CALL Content::getTypes()
145     throw( uno::RuntimeException )
146 {
147 	// @@@ Add own interfaces.
148 
149     static cppu::OTypeCollection* pCollection = 0;
150 
151 	if ( !pCollection )
152 	{
153 		osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() );
154 	  	if ( !pCollection )
155 	  	{
156             static cppu::OTypeCollection aCollection(
157                 CPPU_TYPE_REF( lang::XTypeProvider ),
158                 CPPU_TYPE_REF( lang::XServiceInfo ),
159                 CPPU_TYPE_REF( lang::XComponent ),
160                 CPPU_TYPE_REF( ucb::XContent ),
161                 CPPU_TYPE_REF( ucb::XCommandProcessor ),
162                 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
163                 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
164                 CPPU_TYPE_REF( beans::XPropertyContainer ),
165                 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
166                 CPPU_TYPE_REF( container::XChild ) );
167 	  		pCollection = &aCollection;
168 		}
169 	}
170 
171 	return (*pCollection).getTypes();
172 }
173 
174 //=========================================================================
175 //
176 // XServiceInfo methods.
177 //
178 //=========================================================================
179 
180 // virtual
181 rtl::OUString SAL_CALL Content::getImplementationName()
182     throw( uno::RuntimeException )
183 {
184     // @@@ Adjust implementation name. Keep the prefix "com.sun.star.comp."!
185     return rtl::OUString::createFromAscii( "com.sun.star.comp.odma.Content" );
186 }
187 
188 //=========================================================================
189 // virtual
190 uno::Sequence< rtl::OUString > SAL_CALL Content::getSupportedServiceNames()
191     throw( uno::RuntimeException )
192 {
193 	// @@@ Adjust macro name.
194     uno::Sequence< rtl::OUString > aSNS( 1 );
195 	aSNS.getArray()[ 0 ]
196             = rtl::OUString::createFromAscii( ODMA_CONTENT_SERVICE_NAME );
197 	return aSNS;
198 }
199 
200 //=========================================================================
201 //
202 // XContent methods.
203 //
204 //=========================================================================
205 
206 // virtual
207 rtl::OUString SAL_CALL Content::getContentType()
208     throw( uno::RuntimeException )
209 {
210 	// @@@ Adjust macro name ( def in odma_provider.hxx ).
211     return rtl::OUString::createFromAscii( ODMA_CONTENT_TYPE );
212 }
213 
214 //=========================================================================
215 //
216 // XCommandProcessor methods.
217 //
218 //=========================================================================
219 
220 // virtual
221 uno::Any SAL_CALL Content::execute(
222         const ucb::Command& aCommand,
223         sal_Int32 /*CommandId*/,
224         const uno::Reference< ucb::XCommandEnvironment >& Environment )
225     throw( uno::Exception,
226            ucb::CommandAbortedException,
227            uno::RuntimeException )
228 {
229     uno::Any aRet;
230 
231     if ( aCommand.Name.equalsAsciiL(
232 			RTL_CONSTASCII_STRINGPARAM( "getPropertyValues" ) ) )
233 	{
234 		//////////////////////////////////////////////////////////////////
235 		// getPropertyValues
236 		//////////////////////////////////////////////////////////////////
237 
238         uno::Sequence< beans::Property > Properties;
239 		if ( !( aCommand.Argument >>= Properties ) )
240 		{
241             OSL_ENSURE( sal_False, "Wrong argument type!" );
242             ucbhelper::cancelCommandExecution(
243                 uno::makeAny( lang::IllegalArgumentException(
244                                     rtl::OUString(),
245                                     static_cast< cppu::OWeakObject * >( this ),
246                                     -1 ) ),
247                 Environment );
248             // Unreachable
249 		}
250 
251         aRet <<= getPropertyValues( Properties, Environment );
252 	}
253     else if ( aCommand.Name.equalsAsciiL(
254 				RTL_CONSTASCII_STRINGPARAM( "setPropertyValues" ) ) )
255     {
256 		//////////////////////////////////////////////////////////////////
257 		// setPropertyValues
258 		//////////////////////////////////////////////////////////////////
259 
260         uno::Sequence< beans::PropertyValue > aProperties;
261 		if ( !( aCommand.Argument >>= aProperties ) )
262 		{
263             OSL_ENSURE( sal_False, "Wrong argument type!" );
264             ucbhelper::cancelCommandExecution(
265                 uno::makeAny( lang::IllegalArgumentException(
266                                     rtl::OUString(),
267                                     static_cast< cppu::OWeakObject * >( this ),
268                                     -1 ) ),
269                 Environment );
270             // Unreachable
271         }
272 
273 		if ( !aProperties.getLength() )
274 		{
275             OSL_ENSURE( sal_False, "No properties!" );
276             ucbhelper::cancelCommandExecution(
277                 uno::makeAny( lang::IllegalArgumentException(
278                                     rtl::OUString(),
279                                     static_cast< cppu::OWeakObject * >( this ),
280                                     -1 ) ),
281                 Environment );
282             // Unreachable
283         }
284 
285         aRet <<= setPropertyValues( aProperties, Environment );
286 	}
287     else if ( aCommand.Name.equalsAsciiL(
288 				RTL_CONSTASCII_STRINGPARAM( "getPropertySetInfo" ) ) )
289     {
290 		//////////////////////////////////////////////////////////////////
291 		// getPropertySetInfo
292 		//////////////////////////////////////////////////////////////////
293 
294 		// Note: Implemented by base class.
295 		aRet <<= getPropertySetInfo( Environment );
296 	}
297     else if ( aCommand.Name.equalsAsciiL(
298 				RTL_CONSTASCII_STRINGPARAM( "getCommandInfo" ) ) )
299     {
300 		//////////////////////////////////////////////////////////////////
301 		// getCommandInfo
302 		//////////////////////////////////////////////////////////////////
303 
304 		// Note: Implemented by base class.
305 		aRet <<= getCommandInfo( Environment );
306 	}
307     else if ( aCommand.Name.equalsAsciiL(
308 				RTL_CONSTASCII_STRINGPARAM( "open" ) ) )
309     {
310         ucb::OpenCommandArgument2 aOpenCommand;
311       	if ( !( aCommand.Argument >>= aOpenCommand ) )
312 		{
313             OSL_ENSURE( sal_False, "Wrong argument type!" );
314             ucbhelper::cancelCommandExecution(
315                 uno::makeAny( lang::IllegalArgumentException(
316                                     rtl::OUString(),
317                                     static_cast< cppu::OWeakObject * >( this ),
318                                     -1 ) ),
319                 Environment );
320             // Unreachable
321         }
322 
323         sal_Bool bOpenFolder =
324             ( ( aOpenCommand.Mode == ucb::OpenMode::ALL ) ||
325               ( aOpenCommand.Mode == ucb::OpenMode::FOLDERS ) ||
326               ( aOpenCommand.Mode == ucb::OpenMode::DOCUMENTS ) );
327 
328         if ( bOpenFolder)
329 		{
330             // open as folder - return result set
331 
332             uno::Reference< ucb::XDynamicResultSet > xSet
333                             = new DynamicResultSet( m_xSMgr,
334 													this,
335 													aOpenCommand,
336 													Environment );
337     		aRet <<= xSet;
338   		}
339 
340         if ( aOpenCommand.Sink.is() )
341         {
342             // Open document - supply document data stream.
343 
344             // Check open mode
345             if ( ( aOpenCommand.Mode
346                     == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
347                  ( aOpenCommand.Mode
348                     == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) )
349             {
350                 // Unsupported.
351                 ucbhelper::cancelCommandExecution(
352                     uno::makeAny( ucb::UnsupportedOpenModeException(
353                                     rtl::OUString(),
354                                     static_cast< cppu::OWeakObject * >( this ),
355                                     sal_Int16( aOpenCommand.Mode ) ) ),
356                     Environment );
357                 // Unreachable
358             }
359 
360 
361             rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
362 			rtl::OUString sFileURL = openDoc();
363 			delete m_pContent;
364 			m_pContent = new ::ucbhelper::Content(sFileURL,NULL);
365 			if(!m_pContent->isDocument())
366 			{
367 				rtl::OUString sErrorMsg(RTL_CONSTASCII_USTRINGPARAM("File: "));
368 				sErrorMsg += sFileURL;
369 				sErrorMsg += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" could not be found."));
370 				ucbhelper::cancelCommandExecution(
371 						uno::makeAny( io::IOException(
372 										sErrorMsg,
373 										static_cast< cppu::OWeakObject * >( this )) ),
374 						Environment );
375 			}
376 
377             uno::Reference< io::XOutputStream > xOut
378                 = uno::Reference< io::XOutputStream >(
379                     aOpenCommand.Sink, uno::UNO_QUERY );
380     		if ( xOut.is() )
381       		{
382 				// @@@ PUSH: write data into xOut
383 				m_pContent->openStream(xOut);
384       		}
385     		else
386       		{
387                 uno::Reference< io::XActiveDataSink > xDataSink
388                     = uno::Reference< io::XActiveDataSink >(
389                         aOpenCommand.Sink, uno::UNO_QUERY );
390       			if ( xDataSink.is() )
391 				{
392 	  				// @@@ PULL: wait for client read
393 					uno::Reference< io::XInputStream > xIn;
394 					try
395 					{
396 						xIn = m_pContent->openStream();
397 					}
398 					catch(uno::Exception&)
399 					{
400 						OSL_ENSURE(0,"Exception occured while creating the file content!");
401 					}
402     				xDataSink->setInputStream( xIn );
403 				}
404       			else
405 				{
406 					uno::Reference< io::XActiveDataStreamer > activeDataStreamer( aOpenCommand.Sink,uno::UNO_QUERY );
407 					if(activeDataStreamer.is())
408 					{
409 						activeDataStreamer->setStream(new OOdmaStream(m_pContent,getContentProvider(),m_aProps));
410 						m_pContent = NULL; // don't delete here because the stream is now the owner
411 					}
412 					else
413 					{
414 						// Note: aOpenCommand.Sink may contain an XStream
415 						//       implementation. Support for this type of
416 						//       sink is optional...
417 						ucbhelper::cancelCommandExecution(
418 							uno::makeAny( ucb::UnsupportedDataSinkException(
419 									rtl::OUString(),
420 									static_cast< cppu::OWeakObject * >( this ),
421 									aOpenCommand.Sink ) ),
422 							Environment );
423 						// Unreachable
424 					}
425                 }
426 	  		}
427 		}
428 	}
429 	else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "close" ) ) )
430     {
431 		getContentProvider()->closeDocument(m_aProps->m_sDocumentId);
432 	}
433 	else if ( aCommand.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "delete" ) ) )
434     {
435 		//////////////////////////////////////////////////////////////////
436 		// delete
437 		//////////////////////////////////////////////////////////////////
438 
439 		// Remove own and all children's Additional Core Properties.
440 		removeAdditionalPropertySet( sal_True );
441 		// Remove own and all childrens(!) persistent data.
442 		if(!getContentProvider()->deleteDocument(m_aProps))
443 			ucbhelper::cancelCommandExecution(
444                 uno::makeAny( lang::IllegalArgumentException(
445                                     rtl::OUString(),
446                                     static_cast< cppu::OWeakObject * >( this ),
447                                     -1 ) ),
448                 Environment );
449 	}
450     else if ( aCommand.Name.equalsAsciiL(
451 				RTL_CONSTASCII_STRINGPARAM( "insert" ) ) )
452     {
453 		//////////////////////////////////////////////////////////////////
454 		// insert
455 		//////////////////////////////////////////////////////////////////
456 
457         ucb::InsertCommandArgument arg;
458       	if ( !( aCommand.Argument >>= arg ) )
459 		{
460 	  		OSL_ENSURE( sal_False, "Wrong argument type!" );
461             ucbhelper::cancelCommandExecution(
462                 uno::makeAny( lang::IllegalArgumentException(
463                                     rtl::OUString(),
464                                     static_cast< cppu::OWeakObject * >( this ),
465                                     -1 ) ),
466                 Environment );
467             // Unreachable
468 		}
469 
470       	insert( arg.Data, arg.ReplaceExisting, Environment );
471     }
472 	else if( ! aCommand.Name.compareToAscii( "transfer" ) )
473 	{
474 		ucb::TransferInfo aTransferInfo;
475 		if( ! ( aCommand.Argument >>= aTransferInfo ) )
476 		{
477 			OSL_ENSURE( sal_False, "Wrong argument type!" );
478             ucbhelper::cancelCommandExecution(
479                 uno::makeAny( lang::IllegalArgumentException(
480                                     rtl::OUString(),
481                                     static_cast< cppu::OWeakObject * >( this ),
482                                     -1 ) ),
483                 Environment );
484             // Unreachable
485 		}
486 		::rtl::Reference<ContentProperties> aProp = m_aProps;
487 		if(aProp->m_bIsFolder)
488 		{
489 			aProp = getContentProvider()->getContentPropertyWithTitle(aTransferInfo.NewTitle);
490 			if(!aProp.is())
491 				aProp = getContentProvider()->getContentPropertyWithSavedAsName(aTransferInfo.NewTitle);
492 			sal_Bool bError = !aProp.is();
493 			if(bError)
494 			{
495 				sal_Char* pExtension = NULL;
496 				::rtl::OString sExt;
497 				sal_Int32 nPos = aTransferInfo.NewTitle.lastIndexOf('.');
498 				if(nPos != -1)
499 				{
500 					sExt = ::rtl::OUStringToOString(aTransferInfo.NewTitle.copy(nPos+1),RTL_TEXTENCODING_ASCII_US);
501 					if(sExt.equalsIgnoreAsciiCase("txt"))
502 						pExtension = ODM_FORMAT_TEXT;
503 					else if(sExt.equalsIgnoreAsciiCase("rtf"))
504 						pExtension = ODM_FORMAT_RTF;
505 					else if(sExt.equalsIgnoreAsciiCase("ps"))
506 						pExtension = ODM_FORMAT_PS;
507 					else
508 						pExtension = const_cast<sal_Char*>(sExt.getStr());
509 				}
510 				else
511 					pExtension = ODM_FORMAT_TEXT;
512 
513 				sal_Char* lpszNewDocId = new sal_Char[ODM_DOCID_MAX];
514 				void *pData = NULL;
515 				DWORD dwFlags = ODM_SILENT;
516 				ODMSTATUS odm = NODMSaveAsEx(ContentProvider::getHandle(),
517 											 NULL, // means it is saved the first time
518 											 lpszNewDocId,
519 											 pExtension,
520 											 NULL, // no callback function here
521 											 pData,
522 											 &dwFlags);
523 
524 				// check if we have to call the DMS dialog
525 				if(odm == ODM_E_USERINT)
526 				{
527 					dwFlags = 0;
528 					odm = NODMSaveAsEx(ContentProvider::getHandle(),
529 											 NULL, // means it is saved the first time
530 											 lpszNewDocId,
531 											 pExtension,
532 											 NULL, // no callback function here
533 											 pData,
534 											 &dwFlags);
535 				}
536 				bError = odm != ODM_SUCCESS;
537 				if(!bError)
538 				{
539 					aProp = new ContentProperties();
540 					aProp->m_sDocumentId	= ::rtl::OString(lpszNewDocId);
541 					aProp->m_sContentType	= ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(ODMA_CONTENT_TYPE));
542 					aProp->m_sSavedAsName	= aTransferInfo.NewTitle;
543 					getContentProvider()->append(aProp);
544 
545 					// now set the title
546 					WORD nDocInfo = ODM_NAME;
547 					::rtl::OUString sFileName = aTransferInfo.NewTitle;
548 					sal_Int32 nIndex = aTransferInfo.NewTitle.lastIndexOf( sal_Unicode('.') );
549 					if(nIndex != -1)
550 						sFileName = aTransferInfo.NewTitle.copy(0,nIndex);
551 
552 					::rtl::OString sDocInfoValue = ::rtl::OUStringToOString(sFileName,RTL_TEXTENCODING_ASCII_US);
553 					odm = NODMSetDocInfo(	ContentProvider::getHandle(),
554 											lpszNewDocId,
555 											nDocInfo,
556 											const_cast<sal_Char*>(sDocInfoValue.getStr())
557 											);
558 
559 				}
560 				else if ( odm == ODM_E_CANCEL)
561                     NODMActivate(ContentProvider::getHandle(),
562                                  ODM_DELETE,
563                                  lpszNewDocId);
564 
565 				delete [] lpszNewDocId;
566 			}
567 			if(bError)
568 				ucbhelper::cancelCommandExecution(
569 						uno::makeAny( lang::IllegalArgumentException(
570 											rtl::OUString(),
571 											static_cast< cppu::OWeakObject * >( this ),
572 											-1 ) ),
573 						Environment );
574 		}
575 		rtl::OUString sFileURL = ContentProvider::openDoc(aProp);
576 
577 		sal_Int32 nLastIndex = sFileURL.lastIndexOf( sal_Unicode('/') );
578 		::ucbhelper::Content aContent(sFileURL.copy(0,nLastIndex),NULL);
579 		//	aTransferInfo.NameClash = ucb::NameClash::OVERWRITE;
580 		aTransferInfo.NewTitle = sFileURL.copy( 1 + nLastIndex );
581 		aContent.executeCommand(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("transfer")),uno::makeAny(aTransferInfo));
582 		getContentProvider()->saveDocument(aProp->m_sDocumentId);
583 	}
584 	else
585 	{
586 		//////////////////////////////////////////////////////////////////
587 		// Unsupported command
588 		//////////////////////////////////////////////////////////////////
589 
590         OSL_ENSURE( sal_False, "Content::execute - unsupported command!" );
591 
592         ucbhelper::cancelCommandExecution(
593             uno::makeAny( ucb::UnsupportedCommandException(
594                             rtl::OUString(),
595                             static_cast< cppu::OWeakObject * >( this ) ) ),
596             Environment );
597         // Unreachable
598     }
599 
600 	return aRet;
601 }
602 
603 //=========================================================================
604 // virtual
605 void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ )
606     throw( uno::RuntimeException )
607 {
608 	// @@@ Implement logic to abort running commands, if this makes
609 	//     sense for your content.
610 }
611 
612 //=========================================================================
613 //
614 // Non-interface methods.
615 //
616 //=========================================================================
617 
618 // virtual
619 ::rtl::OUString Content::getParentURL()
620 {
621     ::rtl::OUString sURL = m_xIdentifier->getContentIdentifier();
622 
623     // @@@ Extract URL of parent from aURL and return it...
624 	static ::rtl::OUString sScheme1(RTL_CONSTASCII_USTRINGPARAM(ODMA_URL_SCHEME ODMA_URL_SHORT "/"));
625 	static ::rtl::OUString sScheme2(RTL_CONSTASCII_USTRINGPARAM(ODMA_URL_SCHEME ODMA_URL_SHORT));
626 	if(sURL == sScheme1 || sURL == sScheme2)
627 		sURL = ::rtl::OUString();
628 	else
629 		sURL = sScheme1;
630 
631     return sURL;
632 }
633 
634 //=========================================================================
635 // static
636 uno::Reference< sdbc::XRow > Content::getPropertyValues(
637             const uno::Reference< lang::XMultiServiceFactory >& rSMgr,
638             const uno::Sequence< beans::Property >& rProperties,
639             const rtl::Reference<ContentProperties>& rData,
640             const rtl::Reference< ::ucbhelper::ContentProviderImplHelper >& rProvider,
641             const rtl::OUString& rContentId )
642 {
643 	// Note: Empty sequence means "get values of all supported properties".
644 
645     rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
646                                 = new ::ucbhelper::PropertyValueSet( rSMgr );
647 
648 	sal_Int32 nCount = rProperties.getLength();
649 	if ( nCount )
650 	{
651         uno::Reference< beans::XPropertySet > xAdditionalPropSet;
652 		sal_Bool bTriedToGetAdditonalPropSet = sal_False;
653 
654         const beans::Property* pProps = rProperties.getConstArray();
655 		for ( sal_Int32 n = 0; n < nCount; ++n )
656 		{
657             const beans::Property& rProp = pProps[ n ];
658 
659 			// Process Core properties.
660 
661             if ( rProp.Name.equalsAsciiL(
662 					RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) )
663             {
664 				xRow->appendString ( rProp, rData->m_sContentType );
665 			}
666             else if ( rProp.Name.equalsAsciiL(
667                     RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
668 			{
669 				xRow->appendString ( rProp, rData->m_sTitle );
670 			}
671             else if ( rProp.Name.equalsAsciiL(
672                     RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) )
673 			{
674 				xRow->appendBoolean( rProp, rData->m_bIsDocument );
675 			}
676             else if ( rProp.Name.equalsAsciiL(
677                     RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) )
678 			{
679 				xRow->appendBoolean( rProp, rData->m_bIsFolder );
680 			}
681             else if ( rProp.Name.equalsAsciiL(
682                     RTL_CONSTASCII_STRINGPARAM( "DateCreated" ) ) )
683 			{
684 				xRow->appendTimestamp( rProp, rData->m_aDateCreated );
685 			}
686 			else if ( rProp.Name.equalsAsciiL(
687                     RTL_CONSTASCII_STRINGPARAM( "DateModified" ) ) )
688 			{
689 				xRow->appendTimestamp( rProp, rData->m_aDateModified );
690 			}
691 			else if ( rProp.Name.equalsAsciiL(
692                     RTL_CONSTASCII_STRINGPARAM( "IsReadOnly" ) ) )
693 			{
694 				xRow->appendBoolean( rProp, rData->m_bIsReadOnly );
695 			}
696 			else if ( rProp.Name.equalsAsciiL(
697                     RTL_CONSTASCII_STRINGPARAM( "Author" ) ) )
698 			{
699 				xRow->appendString ( rProp, rData->m_sAuthor );
700 			}
701 			else if ( rProp.Name.equalsAsciiL(
702                     RTL_CONSTASCII_STRINGPARAM( "Subject" ) ) )
703 			{
704 				xRow->appendString ( rProp, rData->m_sSubject );
705 			}
706 			else if ( rProp.Name.equalsAsciiL(
707                     RTL_CONSTASCII_STRINGPARAM( "Keywords" ) ) )
708 			{
709 				xRow->appendString ( rProp, rData->m_sKeywords );
710 			}
711 			else
712 			{
713 				// @@@ Note: If your data source supports adding/removing
714 				//     properties, you should implement the interface
715 				//     XPropertyContainer by yourself and supply your own
716 				//     logic here. The base class uses the service
717 				//     "com.sun.star.ucb.Store" to maintain Additional Core
718 				//     properties. But using server functionality is preferred!
719 
720 				// Not a Core Property! Maybe it's an Additional Core Property?!
721 
722 				if ( !bTriedToGetAdditonalPropSet && !xAdditionalPropSet.is() )
723 				{
724 					xAdditionalPropSet
725                         = uno::Reference< beans::XPropertySet >(
726 							rProvider->getAdditionalPropertySet( rContentId,
727 																 sal_False ),
728                             uno::UNO_QUERY );
729 					bTriedToGetAdditonalPropSet = sal_True;
730 				}
731 
732 				if ( xAdditionalPropSet.is() )
733 				{
734 					if ( !xRow->appendPropertySetValue(
735 												xAdditionalPropSet,
736 												rProp ) )
737 					{
738 						// Append empty entry.
739 						xRow->appendVoid( rProp );
740 					}
741 				}
742 				else
743 				{
744 					// Append empty entry.
745 					xRow->appendVoid( rProp );
746 				}
747 			}
748 		}
749 	}
750 	else
751 	{
752 		// Append all Core Properties.
753 		xRow->appendString (
754             beans::Property( rtl::OUString::createFromAscii( "ContentType" ),
755 					  -1,
756                       getCppuType( static_cast< const rtl::OUString * >( 0 ) ),
757                       beans::PropertyAttribute::BOUND
758                         | beans::PropertyAttribute::READONLY ),
759 			rData->m_sContentType );
760 		xRow->appendString (
761             beans::Property( rtl::OUString::createFromAscii( "Title" ),
762 					  -1,
763                       getCppuType( static_cast< const rtl::OUString * >( 0 ) ),
764                       beans::PropertyAttribute::BOUND ),
765 			rData->m_sTitle );
766 		xRow->appendBoolean(
767             beans::Property( rtl::OUString::createFromAscii( "IsDocument" ),
768 					  -1,
769 					  getCppuBooleanType(),
770                       beans::PropertyAttribute::BOUND
771                         | beans::PropertyAttribute::READONLY ),
772 			rData->m_bIsDocument );
773 		xRow->appendBoolean(
774             beans::Property( rtl::OUString::createFromAscii( "IsFolder" ),
775 					  -1,
776 					  getCppuBooleanType(),
777                       beans::PropertyAttribute::BOUND
778                         | beans::PropertyAttribute::READONLY ),
779 			rData->m_bIsFolder );
780 
781 		// @@@ Append other properties supported directly.
782 		xRow->appendTimestamp(
783             beans::Property( rtl::OUString::createFromAscii( "DateCreated" ),
784 					  -1,
785 					  getCppuType(static_cast< const util::DateTime * >( 0 ) ),
786                       beans::PropertyAttribute::BOUND
787                         | beans::PropertyAttribute::READONLY ),
788 			rData->m_aDateCreated );
789 		xRow->appendTimestamp(
790             beans::Property( rtl::OUString::createFromAscii( "DateModified" ),
791 					  -1,
792 					  getCppuType(static_cast< const util::DateTime * >( 0 ) ),
793                       beans::PropertyAttribute::BOUND
794                         | beans::PropertyAttribute::READONLY ),
795 			rData->m_aDateModified );
796 		xRow->appendBoolean(
797             beans::Property( rtl::OUString::createFromAscii( "IsReadOnly" ),
798 					  -1,
799 					  getCppuBooleanType(),
800                       beans::PropertyAttribute::BOUND
801                         | beans::PropertyAttribute::READONLY ),
802 			rData->m_bIsReadOnly );
803 		xRow->appendString (
804             beans::Property( rtl::OUString::createFromAscii( "Author" ),
805 					  -1,
806                       getCppuType( static_cast< const rtl::OUString * >( 0 ) ),
807                       beans::PropertyAttribute::BOUND ),
808 			rData->m_sAuthor );
809 		xRow->appendString (
810             beans::Property( rtl::OUString::createFromAscii( "Subject" ),
811 					  -1,
812                       getCppuType( static_cast< const rtl::OUString * >( 0 ) ),
813                       beans::PropertyAttribute::BOUND ),
814 			rData->m_sSubject );
815 		xRow->appendString (
816             beans::Property( rtl::OUString::createFromAscii( "Keywords" ),
817 					  -1,
818                       getCppuType( static_cast< const rtl::OUString * >( 0 ) ),
819                       beans::PropertyAttribute::BOUND ),
820 			rData->m_sKeywords );
821 
822 		// @@@ Note: If your data source supports adding/removing
823 		//     properties, you should implement the interface
824 		//     XPropertyContainer by yourself and supply your own
825 		//     logic here. The base class uses the service
826 		//     "com.sun.star.ucb.Store" to maintain Additional Core
827 		//     properties. But using server functionality is preferred!
828 
829 		// Append all Additional Core Properties.
830 
831         uno::Reference< beans::XPropertySet > xSet(
832 			rProvider->getAdditionalPropertySet( rContentId, sal_False ),
833             uno::UNO_QUERY );
834 		xRow->appendPropertySet( xSet );
835 	}
836 
837     return uno::Reference< sdbc::XRow >( xRow.get() );
838 }
839 
840 //=========================================================================
841 uno::Reference< sdbc::XRow > Content::getPropertyValues(
842             const uno::Sequence< beans::Property >& rProperties,
843             const uno::Reference< ucb::XCommandEnvironment >& /*xEnv*/ )
844 {
845 	osl::Guard< osl::Mutex > aGuard( m_aMutex );
846 	return getPropertyValues( m_xSMgr,
847 							  rProperties,
848 							  m_aProps,
849                               rtl::Reference<
850                                 ::ucbhelper::ContentProviderImplHelper >(
851                                     m_xProvider.get() ),
852 							  m_xIdentifier->getContentIdentifier() );
853 }
854 
855 //=========================================================================
856 uno::Sequence< uno::Any > Content::setPropertyValues(
857             const uno::Sequence< beans::PropertyValue >& rValues,
858             const uno::Reference< ucb::XCommandEnvironment >& /*xEnv*/ )
859 {
860 	osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
861 
862     uno::Sequence< uno::Any > aRet( rValues.getLength() );
863     uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
864 	sal_Int32 nChanged = 0;
865 
866     beans::PropertyChangeEvent aEvent;
867     aEvent.Source         = static_cast< cppu::OWeakObject * >( this );
868 	aEvent.Further 		  = sal_False;
869 //	aEvent.PropertyName	  =
870 	aEvent.PropertyHandle = -1;
871 //	aEvent.OldValue		  =
872 //	aEvent.NewValue       =
873 
874     const beans::PropertyValue* pValues = rValues.getConstArray();
875 	sal_Int32 nCount = rValues.getLength();
876 
877     uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
878 	sal_Bool bTriedToGetAdditonalPropSet = sal_False;
879 
880 	for ( sal_Int32 n = 0; n < nCount; ++n )
881 	{
882         const beans::PropertyValue& rValue = pValues[ n ];
883 
884         if ( rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
885 		{
886 			changePropertyValue(rValue,n,m_aProps->m_sTitle,nChanged,aRet,aChanges);
887 		}
888 		else if ( rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "Author") ) )
889 		{
890 			changePropertyValue(rValue,n,m_aProps->m_sAuthor,nChanged,aRet,aChanges);
891 		}
892 		else if ( rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "Keywords") ) )
893 		{
894 			changePropertyValue(rValue,n,m_aProps->m_sKeywords,nChanged,aRet,aChanges);
895 		}
896 		else if ( rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "Subject") ) )
897 		{
898 			changePropertyValue(rValue,n,m_aProps->m_sSubject,nChanged,aRet,aChanges);
899 		}
900 		else if (	rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "ContentType" ) )	||
901 					rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) )	||
902 					rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) )		||
903 					rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "DateCreated" ) )	||
904 					rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "DateModified" ) )	||
905 					rValue.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "IsReadOnly" ) ) )
906         {
907 			// Read-only property!
908             aRet[ n ] <<= lang::IllegalAccessException(
909                             rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
910                                 "Property is read-only!") ),
911                             static_cast< cppu::OWeakObject * >( this ) );
912 		}
913 		else
914 		{
915 			// @@@ Note: If your data source supports adding/removing
916 			//     properties, you should implement the interface
917 			//     XPropertyContainer by yourself and supply your own
918 			//     logic here. The base class uses the service
919 			//     "com.sun.star.ucb.Store" to maintain Additional Core
920 			//     properties. But using server functionality is preferred!
921 
922 			// Not a Core Property! Maybe it's an Additional Core Property?!
923 
924 			if ( !bTriedToGetAdditonalPropSet && !xAdditionalPropSet.is() )
925 			{
926 				xAdditionalPropSet = getAdditionalPropertySet( sal_False );
927 				bTriedToGetAdditonalPropSet = sal_True;
928 			}
929 
930 			if ( xAdditionalPropSet.is() )
931 			{
932 				try
933 				{
934                     uno::Any aOldValue
935                         = xAdditionalPropSet->getPropertyValue( rValue.Name );
936 					if ( aOldValue != rValue.Value )
937 					{
938 						xAdditionalPropSet->setPropertyValue(
939 												rValue.Name, rValue.Value );
940 
941 						aEvent.PropertyName = rValue.Name;
942 						aEvent.OldValue		= aOldValue;
943 						aEvent.NewValue     = rValue.Value;
944 
945 						aChanges.getArray()[ nChanged ] = aEvent;
946 						nChanged++;
947 					}
948                     else
949                     {
950                         // Old value equals new value. No error!
951                     }
952 				}
953                 catch ( beans::UnknownPropertyException const & e )
954 				{
955                     aRet[ n ] <<= e;
956 				}
957                 catch ( lang::WrappedTargetException const & e )
958 				{
959                     aRet[ n ] <<= e;
960 				}
961                 catch ( beans::PropertyVetoException const & e )
962 				{
963                     aRet[ n ] <<= e;
964 				}
965                 catch ( lang::IllegalArgumentException const & e )
966 				{
967                     aRet[ n ] <<= e;
968 				}
969 			}
970             else
971             {
972                 aRet[ n ] <<= uno::Exception(
973                                 rtl::OUString::createFromAscii(
974                                     "No property set for storing the value!" ),
975                                 static_cast< cppu::OWeakObject * >( this ) );
976             }
977 		}
978 	}
979 
980 	if ( nChanged > 0 )
981 	{
982 		// @@@ Save changes.
983 //		storeData();
984 
985 		aGuard.clear();
986 		aChanges.realloc( nChanged );
987 		notifyPropertiesChange( aChanges );
988 	}
989 
990     return aRet;
991 }
992 
993 #if 0
994 //=========================================================================
995 void Content::queryChildren( ContentRefList& rChildren )
996 {
997 	// @@@ Adapt method to your URL scheme...
998 
999 	// Obtain a list with a snapshot of all currently instanciated contents
1000 	// from provider and extract the contents which are direct children
1001 	// of this content.
1002 
1003 	::ucbhelper::ContentRefList aAllContents;
1004 	m_xProvider->queryExistingContents( aAllContents );
1005 
1006 	OUString aURL = m_xIdentifier->getContentIdentifier();
1007 	sal_Int32 nPos = aURL.lastIndexOf( '/' );
1008 
1009 	if ( nPos != ( aURL.getLength() - 1 ) )
1010 	{
1011 		// No trailing slash found. Append.
1012 		aURL += OUString::createFromAscii( "/" );
1013 	}
1014 
1015 	sal_Int32 nLen = aURL.getLength();
1016 
1017 	::ucbhelper::ContentRefList::const_iterator it  = aAllContents.begin();
1018 	::ucbhelper::ContentRefList::const_iterator end = aAllContents.end();
1019 
1020 	while ( it != end )
1021 	{
1022 		::ucbhelper::ContentImplHelperRef xChild = (*it);
1023 		OUString aChildURL = xChild->getIdentifier()->getContentIdentifier();
1024 
1025 		// Is aURL a prefix of aChildURL?
1026 		if ( ( aChildURL.getLength() > nLen ) &&
1027 			 ( aChildURL.compareTo( aURL, nLen ) == 0 ) )
1028 		{
1029 			sal_Int32 nPos = nLen;
1030 			nPos = aChildURL.indexOf( '/', nPos );
1031 
1032 			if ( ( nPos == -1 ) ||
1033 				 ( nPos == ( aChildURL.getLength() - 1 ) ) )
1034 			{
1035 				// No further slashes / only a final slash. It's a child!
1036 				rChildren.push_back(
1037 					ContentRef(
1038 						static_cast< Content * >( xChild.get() ) ) );
1039 			}
1040 		}
1041 		++it;
1042 	}
1043 }
1044 #endif
1045 //=========================================================================
1046 void Content::insert(
1047         const uno::Reference< io::XInputStream > & xInputStream,
1048         sal_Bool bReplaceExisting,
1049         const uno::Reference< ucb::XCommandEnvironment >& Environment )
1050     throw( uno::Exception )
1051 {
1052 	osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
1053 
1054 	// Check, if all required properties were set.
1055 	if ( !m_aProps->m_sTitle.getLength())
1056 	{
1057         OSL_ENSURE( sal_False, "Content::insert - property value missing!" );
1058 
1059         uno::Sequence< rtl::OUString > aProps( 1 );
1060         aProps[ 0 ] = rtl::OUString::createFromAscii( "zzzz" );
1061         ucbhelper::cancelCommandExecution(
1062             uno::makeAny( ucb::MissingPropertiesException(
1063                                 rtl::OUString(),
1064                                 static_cast< cppu::OWeakObject * >( this ),
1065                                 aProps ) ),
1066             Environment );
1067         // Unreachable
1068 	}
1069 
1070     if ( !xInputStream.is() )
1071     {
1072         OSL_ENSURE( sal_False, "Content::insert - No data stream!" );
1073 
1074         ucbhelper::cancelCommandExecution(
1075             uno::makeAny( ucb::MissingInputStreamException(
1076                             rtl::OUString(),
1077                             static_cast< cppu::OWeakObject * >( this ) ) ),
1078             Environment );
1079         // Unreachable
1080     }
1081 
1082 	// Assemble new content identifier...
1083 
1084     //	uno::Reference< ucb::XContentIdentifier > xId = ...;
1085 
1086     // Fail, if a resource with given id already exists.
1087     if ( !bReplaceExisting ) // && hasData( m_xIdentifier ) )
1088     {
1089 		ucbhelper::cancelCommandExecution(
1090             uno::makeAny( ucb::UnsupportedCommandException(
1091                             rtl::OUString(),
1092                             static_cast< cppu::OWeakObject * >( this ) ) ),
1093             Environment );
1094 //        ucbhelper::cancelCommandExecution(
1095 //						ucb::IOErrorCode_ALREADY_EXISTING,
1096 //						Environment,
1097 //						uno::makeAny(static_cast< cppu::OWeakObject * >( this ))
1098 //                         );
1099         // Unreachable
1100     }
1101 
1102 	//	m_xIdentifier = xId;
1103 
1104 //  @@@
1105 //	storeData();
1106 
1107 	aGuard.clear();
1108 	inserted();
1109 }
1110 #if 0
1111 //=========================================================================
1112 void Content::destroy( sal_Bool bDeletePhysical )
1113     throw( uno::Exception )
1114 {
1115 	// @@@ take care about bDeletePhysical -> trashcan support
1116 
1117     uno::Reference< ucb::XContent > xThis = this;
1118 
1119 	deleted();
1120 
1121 	osl::Guard< osl::Mutex > aGuard( m_aMutex );
1122 
1123 	// Process instanciated children...
1124 
1125 	ContentRefList aChildren;
1126 	queryChildren( aChildren );
1127 
1128 	ContentRefList::const_iterator it  = aChildren.begin();
1129 	ContentRefList::const_iterator end = aChildren.end();
1130 
1131 	while ( it != end )
1132 	{
1133 		(*it)->destroy( bDeletePhysical );
1134 		++it;
1135 	}
1136 }
1137 #endif
1138 
1139 // -----------------------------------------------------------------------------
1140 ::rtl::OUString Content::openDoc()
1141 {
1142 	OSL_ENSURE(m_aProps.is(),"No valid content properties!");
1143 	return ContentProvider::openDoc(m_aProps);
1144 }
1145 // -----------------------------------------------------------------------------
1146 void Content::changePropertyValue(const beans::PropertyValue& _rValue,
1147 								  sal_Int32 _rnCurrentPos,
1148 								  ::rtl::OUString& _rsMemberValue,
1149 								  sal_Int32& _rnChanged,
1150 								  uno::Sequence< uno::Any >& _rRet,
1151 								  uno::Sequence< beans::PropertyChangeEvent >& _rChanges) throw (beans::IllegalTypeException)
1152 {
1153     rtl::OUString sNewValue;
1154 	sal_Bool bError = sal_False;
1155 	if ( _rValue.Value >>= sNewValue )
1156 	{
1157 		if ( sNewValue != _rsMemberValue )
1158 		{
1159 			osl::Guard< osl::Mutex > aGuard( m_aMutex );
1160 			// first we have to check if we could change the property inside the DMS
1161 			::rtl::OString sDocInfoValue = ::rtl::OUStringToOString(sNewValue,RTL_TEXTENCODING_ASCII_US);
1162 			WORD nDocInfo = 0;
1163 			if(&_rsMemberValue == &m_aProps->m_sTitle)
1164 				nDocInfo = ODM_TITLETEXT;
1165 			else if(&_rsMemberValue == &m_aProps->m_sAuthor)
1166 				nDocInfo = ODM_AUTHOR;
1167 			else if(&_rsMemberValue == &m_aProps->m_sSubject)
1168 				nDocInfo = ODM_SUBJECT;
1169 			else if(&_rsMemberValue == &m_aProps->m_sKeywords)
1170 				nDocInfo = ODM_KEYWORDS;
1171 			else
1172 				bError = sal_True;
1173 
1174 			if(!bError)
1175 			{
1176 				ODMSTATUS odm = NODMSetDocInfo(	ContentProvider::getHandle(),
1177 												const_cast<sal_Char*>(m_aProps->m_sDocumentId.getStr()),
1178 												nDocInfo,
1179 												const_cast<sal_Char*>(sDocInfoValue.getStr())
1180 												);
1181 				if(odm == ODM_SUCCESS)
1182 				{
1183 					beans::PropertyChangeEvent aEvent;
1184 					aEvent.Source			= static_cast< cppu::OWeakObject * >( this );
1185 					aEvent.Further 			= sal_False;
1186 					aEvent.PropertyHandle	= -1;
1187 					aEvent.PropertyName		= _rValue.Name;
1188 					aEvent.OldValue			= uno::makeAny( _rsMemberValue );
1189 					aEvent.NewValue			= uno::makeAny( sNewValue );
1190 
1191 					_rChanges.getArray()[ _rnChanged ] = aEvent;
1192 
1193 					_rsMemberValue = sNewValue;
1194 					++_rnChanged;
1195 				}
1196 			}
1197 		}
1198         else
1199         {
1200             // Old value equals new value. No error!
1201         }
1202 	}
1203     else
1204 		bError = sal_True;
1205 
1206 	if(bError)
1207     {
1208         _rRet[ _rnCurrentPos ] <<= beans::IllegalTypeException(
1209                         rtl::OUString::createFromAscii(
1210                             "Property value has wrong type!" ),
1211                         static_cast< cppu::OWeakObject * >( this ) );
1212     }
1213 }
1214 // -----------------------------------------------------------------------------
1215 
1216