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