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