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