xref: /AOO42X/main/ucb/source/ucp/odma/odma_content.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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