xref: /aoo41x/main/sfx2/source/doc/objuno.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sfx2.hxx"
30 
31 #include <com/sun/star/lang/DisposedException.hpp>
32 #include <com/sun/star/util/DateTime.hpp>
33 #include <com/sun/star/util/Date.hpp>
34 #include <com/sun/star/util/Time.hpp>
35 #include <com/sun/star/beans/PropertyAttribute.hpp>
36 #include <com/sun/star/beans/NamedValue.hpp>
37 #include <com/sun/star/beans/StringPair.hpp>
38 #include <com/sun/star/embed/ElementModes.hpp>
39 #include <com/sun/star/xml/sax/XParser.hpp>
40 #include <com/sun/star/document/XImporter.hpp>
41 #include <com/sun/star/document/XExporter.hpp>
42 #include <com/sun/star/io/XActiveDataSource.hpp>
43 #include <com/sun/star/document/XFilter.hpp>
44 #include <com/sun/star/embed/XTransactedObject.hpp>
45 #include <com/sun/star/lang/Locale.hpp>
46 #include <com/sun/star/util/XModifiable.hpp>
47 #include <com/sun/star/document/XDocumentProperties.hpp>
48 
49 #include <unotools/configmgr.hxx>
50 #include <tools/inetdef.hxx>
51 #include <unotools/bootstrap.hxx>
52 #include <cppuhelper/interfacecontainer.hxx>
53 #include <osl/mutex.hxx>
54 #include <rtl/ustrbuf.hxx>
55 #include <vcl/svapp.hxx>
56 #include <vos/mutex.hxx>
57 
58 #include <tools/errcode.hxx>
59 #include <svl/cntwids.hrc>
60 #include <comphelper/string.hxx>
61 #include <comphelper/sequenceasvector.hxx>
62 #include <comphelper/storagehelper.hxx>
63 #include <sot/storage.hxx>
64 
65 #include <sfx2/objuno.hxx>
66 #include <sfx2/sfx.hrc>
67 
68 #include <vector>
69 #include <algorithm>
70 
71 #include "sfx2/sfxresid.hxx"
72 #include "doc.hrc"
73 
74 using namespace ::com::sun::star;
75 
76 // TODO/REFACTOR: provide service for MS formats
77 // TODO/REFACTOR: IsEncrypted is never set nor read
78 // Generator is not saved ATM; which value?!
79 // Generator handling must be implemented
80 // Deprecate "Theme", rework IDL
81 // AutoLoadEnabled is deprecated?!
82 // Reasonable defaults for DateTime
83 // MIMEType readonly?!
84 // Announce changes about Theme, Language, Generator, removed entries etc.
85 // IsEncrypted is necessary for binary formats!
86 // Open: When to call PrepareDocInfoForSave? Currently only called for own formats and HTML/Writer
87 // Open: How to load and save EditingTime to MS formats
88 // PPT-Export should use SavePropertySet
89 
90 //=============================================================================
91 
92 // The number of user defined fields handled by the evil XDocumentInfo
93 // interface. There are exactly 4. No more, no less.
94 #define FOUR 4
95 
96 #define PROPERTY_UNBOUND 0
97 #define PROPERTY_MAYBEVOID ::com::sun::star::beans::PropertyAttribute::MAYBEVOID
98 
99 const SfxItemPropertyMapEntry* lcl_GetDocInfoPropertyMap()
100 {
101     static SfxItemPropertyMapEntry aDocInfoPropertyMap_Impl[] =
102     {
103         { "Author"          , 6 , WID_FROM,           &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 },
104         { "AutoloadEnabled" , 15, MID_DOCINFO_AUTOLOADENABLED, &::getBooleanCppuType(),   PROPERTY_UNBOUND, 0 },
105         { "AutoloadSecs"    , 12, MID_DOCINFO_AUTOLOADSECS, &::getCppuType((const sal_Int32*)0),     PROPERTY_UNBOUND, 0 },
106         { "AutoloadURL"     , 11, MID_DOCINFO_AUTOLOADURL, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 },
107         { "CreationDate"    , 12, WID_DATE_CREATED,   &::getCppuType((const ::com::sun::star::util::DateTime*)0),PROPERTY_MAYBEVOID, 0 },
108         { "DefaultTarget"   , 13, MID_DOCINFO_DEFAULTTARGET, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 },
109         { "Description"     , 11, MID_DOCINFO_DESCRIPTION, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 },
110         { "DocumentStatistic", 17 , MID_DOCINFO_STATISTIC, &::getCppuType((const uno::Sequence< beans::NamedValue >*)0), PROPERTY_UNBOUND, 0 },
111         { "EditingCycles"   , 13, MID_DOCINFO_REVISION, &::getCppuType((const sal_Int16*)0),   PROPERTY_UNBOUND, 0 },
112         { "EditingDuration" , 15, MID_DOCINFO_EDITTIME, &::getCppuType((const sal_Int32*)0),   PROPERTY_UNBOUND, 0 },
113         { "Generator"       , 9,  SID_APPLICATION, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 },
114         { "Keywords"        , 8 , WID_KEYWORDS,       &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 },
115         { "Language"        , 8,  MID_DOCINFO_CHARLOCALE, &::getCppuType((const lang::Locale*)0), PROPERTY_UNBOUND, 0 },
116         { "MIMEType"        , 8 , WID_CONTENT_TYPE,   &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND | ::com::sun::star::beans::PropertyAttribute::READONLY, 0 },
117         { "ModifiedBy"      , 10, MID_DOCINFO_MODIFICATIONAUTHOR, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 },
118         { "ModifyDate"      , 10, WID_DATE_MODIFIED,  &::getCppuType((const ::com::sun::star::util::DateTime*)0),PROPERTY_MAYBEVOID, 0 },
119         { "PrintDate"       , 9 , MID_DOCINFO_PRINTDATE, &::getCppuType((const ::com::sun::star::util::DateTime*)0),PROPERTY_MAYBEVOID, 0 },
120         { "PrintedBy"       , 9 , MID_DOCINFO_PRINTEDBY, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 },
121         { "Subject"         , 7 , MID_DOCINFO_SUBJECT, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 },
122         { "Template"        , 8 , MID_DOCINFO_TEMPLATE, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 },
123         { "TemplateFileName", 16, SID_TEMPLATE_NAME, &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 },
124         { "TemplateDate"    , 12, MID_DOCINFO_TEMPLATEDATE, &::getCppuType((const ::com::sun::star::util::DateTime*)0),PROPERTY_MAYBEVOID, 0 },
125         { "Title"           , 5 , WID_TITLE,          &::getCppuType((const ::rtl::OUString*)0), PROPERTY_UNBOUND, 0 },
126         {0,0,0,0,0,0}
127     };
128     return aDocInfoPropertyMap_Impl;
129 }
130 
131 static sal_uInt16 aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30,
132 								   31, 31, 30, 31, 30, 31 };
133 
134 inline sal_uInt16 DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear )
135 {
136 	if ( nMonth != 2 )
137 		return aDaysInMonth[nMonth-1];
138 	else
139 	{
140 		if ( (((nYear % 4) == 0) && ((nYear % 100) != 0)) ||
141 			 ((nYear % 400) == 0) )
142 			return aDaysInMonth[nMonth-1] + 1;
143 		else
144 			return aDaysInMonth[nMonth-1];
145 	}
146 }
147 
148 bool IsValidDateTime( const util::DateTime& rDT )
149 {
150 	if ( !rDT.Month || (rDT.Month > 12) )
151 		return false;
152 	if ( !rDT.Day || (rDT.Day > DaysInMonth( rDT.Month, rDT.Year )) )
153 		return false;
154 	else if ( rDT.Year <= 1582 )
155 	{
156 		if ( rDT.Year < 1582 )
157 			return false;
158 		else if ( rDT.Month < 10 )
159 			return false;
160 		else if ( (rDT.Month == 10) && (rDT.Day < 15) )
161 			return false;
162 	}
163 
164 	return true;
165 }
166 
167 struct OUStringHashCode
168 {
169     size_t operator()( const ::rtl::OUString& sString ) const
170 	{
171 		return sString.hashCode();
172 	}
173 };
174 
175 struct SfxExtendedItemPropertyMap : public SfxItemPropertyMapEntry
176 {
177     ::com::sun::star::uno::Any aValue;
178 };
179 
180 void Copy( const uno::Reference < document::XStandaloneDocumentInfo >& rSource, const uno::Reference < document::XStandaloneDocumentInfo >& rTarget )
181 {
182     try
183     {
184         uno::Reference< beans::XPropertySet > xSet( rSource, uno::UNO_QUERY );
185         uno::Reference< beans::XPropertySet > xTarget( rTarget, uno::UNO_QUERY );
186         uno::Reference< beans::XPropertySetInfo > xSetInfo = xSet->getPropertySetInfo();
187         uno::Reference< beans::XPropertyContainer > xContainer( rTarget, uno::UNO_QUERY );
188         uno::Sequence< beans::Property > lProps = xSetInfo->getProperties();
189         const beans::Property* pProps = lProps.getConstArray();
190         sal_Int32 c = lProps.getLength();
191         sal_Int32 i = 0;
192         for (i=0; i<c; ++i)
193         {
194             uno::Any aValue = xSet->getPropertyValue( pProps[i].Name );
195             if ( pProps[i].Attributes & ::com::sun::star::beans::PropertyAttribute::REMOVABLE )
196                 // QUESTION: DefaultValue?!
197                 xContainer->addProperty( pProps[i].Name, pProps[i].Attributes, aValue );
198             try
199             {
200                 // it is possible that the propertysets from XML and binary files differ; we shouldn't break then
201                 xTarget->setPropertyValue( pProps[i].Name, aValue );
202             }
203             catch ( uno::Exception& ) {}
204         }
205 
206         sal_Int16 nCount = rSource->getUserFieldCount();
207         sal_Int16 nSupportedCount = rTarget->getUserFieldCount();
208         for ( sal_Int16 nInd = 0; nInd < nCount && nInd < nSupportedCount; nInd++ )
209         {
210             ::rtl::OUString aPropName = rSource->getUserFieldName( nInd );
211             rTarget->setUserFieldName( nInd, aPropName );
212             ::rtl::OUString aPropVal = rSource->getUserFieldValue( nInd );
213             rTarget->setUserFieldValue( nInd, aPropVal );
214         }
215     }
216     catch ( uno::Exception& ) {}
217 }
218 
219 class MixedPropertySetInfo : public ::cppu::WeakImplHelper1< ::com::sun::star::beans::XPropertySetInfo >
220 {
221     private:
222 
223         SfxItemPropertyMap  _aPropertyMap;
224         ::rtl::OUString* _pUserKeys;
225         uno::Reference<beans::XPropertySet> _xUDProps;
226 
227     public:
228 
229         MixedPropertySetInfo( const SfxItemPropertyMapEntry* pFixProps,
230                              ::rtl::OUString* pUserKeys,
231                              uno::Reference<beans::XPropertySet> xUDProps);
232 
233         virtual ~MixedPropertySetInfo();
234 
235         virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property > SAL_CALL getProperties(  ) throw (::com::sun::star::uno::RuntimeException);
236         virtual ::com::sun::star::beans::Property SAL_CALL getPropertyByName( const ::rtl::OUString& aName ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException);
237         virtual ::sal_Bool SAL_CALL hasPropertyByName( const ::rtl::OUString& Name ) throw (::com::sun::star::uno::RuntimeException);
238 };
239 
240 //-----------------------------------------------------------------------------
241 
242 MixedPropertySetInfo::MixedPropertySetInfo(const SfxItemPropertyMapEntry* pFixProps,
243                      ::rtl::OUString* pUserKeys,
244                      uno::Reference<beans::XPropertySet> xUDProps)
245     : _aPropertyMap( pFixProps )
246     , _pUserKeys(pUserKeys)
247     , _xUDProps(xUDProps)
248 {
249 }
250 
251 //-----------------------------------------------------------------------------
252 
253 MixedPropertySetInfo::~MixedPropertySetInfo()
254 {
255 }
256 
257 //-----------------------------------------------------------------------------
258 
259 ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property > SAL_CALL MixedPropertySetInfo::getProperties()
260     throw(::com::sun::star::uno::RuntimeException)
261 {
262     ::comphelper::SequenceAsVector< ::com::sun::star::beans::Property > lProps;
263 
264     // copy "fix" props
265     //todo: os: this ugly thing should be replaced
266     const SfxItemPropertyMapEntry* pFixProp = lcl_GetDocInfoPropertyMap();
267 
268     while(pFixProp && pFixProp->pName)
269     {
270         ::com::sun::star::beans::Property aProp;
271 
272         aProp.Name       = ::rtl::OUString::createFromAscii(pFixProp->pName);
273         aProp.Handle     = pFixProp->nWID;
274         aProp.Type       = *(pFixProp->pType);
275         aProp.Attributes = (sal_Int16)(pFixProp->nFlags);
276 
277         lProps.push_back(aProp);
278         ++pFixProp;
279     }
280 
281     // copy "dynamic" props
282 
283     // NB: this is really ugly:
284     // The returned properties must _not_ include the 4 user-defined fields!
285     // These are _not_ properties of the XDocumentInfo interface.
286     // Some things rely on this, e.g. Copy would break otherwise.
287     // This will have interesting consequences if someone expects to insert
288     // a property with the same name as an user-defined key, but nobody
289     // sane does that.
290     uno::Sequence<beans::Property> udProps =
291         _xUDProps->getPropertySetInfo()->getProperties();
292     for (sal_Int32 i = 0; i < udProps.getLength(); ++i) {
293         if (std::find(_pUserKeys, _pUserKeys+FOUR, udProps[i].Name)
294             == _pUserKeys+FOUR) {
295                 // #i100027#: handles from udProps are not valid here
296                 udProps[i].Handle = -1;
297                 lProps.push_back(udProps[i]);
298         }
299     }
300 
301     return lProps.getAsConstList();
302 }
303 
304 //-----------------------------------------------------------------------------
305 
306 ::com::sun::star::beans::Property SAL_CALL MixedPropertySetInfo::getPropertyByName(
307     const ::rtl::OUString& sName )
308     throw(::com::sun::star::beans::UnknownPropertyException,
309           ::com::sun::star::uno::RuntimeException          )
310 {
311     ::com::sun::star::beans::Property aProp;
312 
313     // search it as "fix" prop
314     if( _aPropertyMap.hasPropertyByName( sName ) )
315         return _aPropertyMap.getPropertyByName( sName );
316     else
317     // search it as "dynamic" prop
318     return _xUDProps->getPropertySetInfo()->getPropertyByName(sName);
319 }
320 
321 //-----------------------------------------------------------------------------
322 
323 ::sal_Bool SAL_CALL MixedPropertySetInfo::hasPropertyByName(const ::rtl::OUString& sName)
324     throw(::com::sun::star::uno::RuntimeException)
325 {
326     return _aPropertyMap.hasPropertyByName( sName ) ? // "fix" prop?
327         sal_True :
328         _xUDProps->getPropertySetInfo()->hasPropertyByName(sName); // "dynamic" prop?
329 }
330 
331 //-----------------------------------------------------------------------------
332 
333 struct SfxDocumentInfoObject_Impl
334 {
335 	::osl::Mutex						_aMutex;
336 	::cppu::OInterfaceContainerHelper	_aDisposeContainer;
337 
338     sal_Bool            bDisposed;
339 
340     // this contains the names of the 4 user defined properties
341     // which are accessible via the evil XDocumentInfo interface
342     ::rtl::OUString m_UserDefined[FOUR];
343 
344     // the actual contents
345     uno::Reference<document::XDocumentProperties> m_xDocProps;
346     SfxItemPropertyMap      m_aPropertyMap;
347 
348     SfxDocumentInfoObject_Impl()
349         : _aDisposeContainer( _aMutex )
350         , bDisposed(sal_False)
351         , m_xDocProps()
352         , m_aPropertyMap( lcl_GetDocInfoPropertyMap() )
353 	{
354         // the number of user fields is not changeable from the outside
355         // we can't set it too high because every name/value pair will be written to the file (even if empty)
356         // currently our dialog has only 4 user keys so 4 is still a reasonable number
357 	}
358 
359     /// the initialization function
360     void Reset(uno::Reference<document::XDocumentProperties> xDocProps, ::rtl::OUString* pUserDefined = 0);
361 };
362 
363 void SfxDocumentInfoObject_Impl::Reset(uno::Reference<document::XDocumentProperties> xDocProps, ::rtl::OUString* pUserDefined)
364 {
365     if (pUserDefined == 0) {
366         // NB: this is an ugly hack; the "Properties" ui dialog displays
367         //     exactly 4 user-defined fields and expects these to be available
368         //     (should be redesigned), but I do not want to do this in
369         //     DocumentProperties; do it here instead
370         uno::Reference<beans::XPropertyAccess> xPropAccess(
371             xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW);
372         uno::Reference<beans::XPropertyContainer> xPropContainer(
373             xPropAccess, uno::UNO_QUERY_THROW);
374         uno::Sequence< beans::PropertyValue >
375             props = xPropAccess->getPropertyValues();
376         sal_Int32 oldLength = props.getLength();
377         if (oldLength < FOUR) {
378             std::vector< ::rtl::OUString > names;
379             for (sal_Int32 i = 0; i < oldLength; ++i) {
380                 names.push_back(props[i].Name);
381             }
382             const ::rtl::OUString sInfo(
383                         String( SfxResId( STR_DOCINFO_INFOFIELD ) ));
384             for (sal_Int32 i = oldLength; i < FOUR; ++i) {
385                 ::rtl::OUString sName(sInfo);
386                 sal_Int32 idx = sName.indexOfAsciiL("%1", 2);
387                 ::rtl::OUString name = (idx > 0)
388                     ? sName.replaceAt(idx, 2, ::rtl::OUString::valueOf(i+1))
389                     : sName + ::rtl::OUString::valueOf(i+1);
390                 while (std::find(names.begin(), names.end(), name)
391                        != names.end()) {
392                     name += ::rtl::OUString::createFromAscii("'");
393                 }
394                 // FIXME there is a race condition here
395                 try {
396                     xPropContainer->addProperty(name,
397                         beans::PropertyAttribute::REMOVEABLE,
398                         uno::makeAny(::rtl::OUString::createFromAscii("")));
399                 } catch (uno::RuntimeException) {
400                     throw;
401                 } catch (uno::Exception) {
402                     // ignore
403                 }
404             }
405         }
406         props = xPropAccess->getPropertyValues();
407         for (sal_Int32 i = 0; i < FOUR; ++i) {
408             m_UserDefined[i] = props[i].Name;
409         }
410     } else {
411         std::copy(pUserDefined, pUserDefined+FOUR, m_UserDefined);
412     }
413     m_xDocProps = xDocProps;
414 }
415 
416 //-----------------------------------------------------------------------------
417 
418 SfxDocumentInfoObject::SfxDocumentInfoObject()
419     : _pImp( new SfxDocumentInfoObject_Impl() )
420 {
421 }
422 
423 //-----------------------------------------------------------------------------
424 
425 SfxDocumentInfoObject::~SfxDocumentInfoObject()
426 {
427 	delete _pImp;
428 }
429 
430 //-----------------------------------------------------------------------------
431 
432 // ::com::sun::star::lang::XInitialization:
433 void SAL_CALL
434 SfxDocumentInfoObject::initialize(const uno::Sequence< uno::Any > & aArguments)
435     throw (uno::RuntimeException, uno::Exception)
436 {
437     if (aArguments.getLength() >= 1) {
438         uno::Any any = aArguments[0];
439         uno::Reference<document::XDocumentProperties> xDoc;
440         if (!(any >>= xDoc) || !xDoc.is()) throw lang::IllegalArgumentException(
441             ::rtl::OUString::createFromAscii(
442                 "SfxDocumentInfoObject::initialize: no XDocumentProperties given"),
443                 *this, 0);
444         _pImp->Reset(xDoc);
445     } else {
446         throw lang::IllegalArgumentException(
447             ::rtl::OUString::createFromAscii(
448                 "SfxDocumentInfoObject::initialize: no argument given"),
449                 *this, 0);
450     }
451 }
452 
453 // ::com::sun::star::util::XCloneable:
454 uno::Reference<util::XCloneable> SAL_CALL
455 SfxDocumentInfoObject::createClone() throw (uno::RuntimeException)
456 {
457     SfxDocumentInfoObject *pNew = new SfxDocumentInfoObject;
458     uno::Reference< util::XCloneable >
459         xCloneable(_pImp->m_xDocProps, uno::UNO_QUERY_THROW);
460     uno::Reference<document::XDocumentProperties> xDocProps(
461         xCloneable->createClone(), uno::UNO_QUERY_THROW);
462     pNew->_pImp->Reset(xDocProps, _pImp->m_UserDefined);
463     return pNew;
464 }
465 
466 // ::com::sun::star::document::XDocumentProperties:
467 uno::Reference< document::XDocumentProperties > SAL_CALL
468 SfxDocumentInfoObject::getDocumentProperties()
469     throw(::com::sun::star::uno::RuntimeException)
470 {
471     return _pImp->m_xDocProps;
472 }
473 
474 //-----------------------------------------------------------------------------
475 
476 const SfxDocumentInfoObject& SfxDocumentInfoObject::operator=( const SfxDocumentInfoObject & rOther)
477 {
478     uno::Reference< util::XCloneable >
479         xCloneable(rOther._pImp->m_xDocProps, uno::UNO_QUERY_THROW);
480     uno::Reference<document::XDocumentProperties> xDocProps(
481         xCloneable->createClone(), uno::UNO_QUERY_THROW);
482     _pImp->Reset(xDocProps, rOther._pImp->m_UserDefined);
483     return *this;
484 }
485 
486 //-----------------------------------------------------------------------------
487 
488 void SAL_CALL SfxDocumentInfoObject::dispose() throw( ::com::sun::star::uno::RuntimeException )
489 {
490 	::com::sun::star::lang::EventObject aEvent( (::cppu::OWeakObject *)this );
491 	_pImp->_aDisposeContainer.disposeAndClear( aEvent );
492 	::osl::MutexGuard aGuard( _pImp->_aMutex );
493     _pImp->m_xDocProps = 0;
494     // NB: do not call m_xDocProps->dispose(), there could be other refs
495     _pImp->bDisposed = sal_True;
496 }
497 
498 //-----------------------------------------------------------------------------
499 
500 void SAL_CALL  SfxDocumentInfoObject::addEventListener(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener > & aListener) throw( ::com::sun::star::uno::RuntimeException )
501 {
502 	_pImp->_aDisposeContainer.addInterface( aListener );
503 }
504 
505 //-----------------------------------------------------------------------------
506 
507 void SAL_CALL  SfxDocumentInfoObject::removeEventListener(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener > & aListener) throw( ::com::sun::star::uno::RuntimeException )
508 {
509 	_pImp->_aDisposeContainer.removeInterface( aListener );
510 }
511 //-----------------------------------------------------------------------------
512 
513 ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo >  SAL_CALL  SfxDocumentInfoObject::getPropertySetInfo()  throw( ::com::sun::star::uno::RuntimeException )
514 {
515     ::osl::MutexGuard aGuard( _pImp->_aMutex );
516 
517     uno::Reference<beans::XPropertySet> xPropSet(
518         _pImp->m_xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW);
519     MixedPropertySetInfo* pInfo = new MixedPropertySetInfo( lcl_GetDocInfoPropertyMap(), _pImp->m_UserDefined, xPropSet);
520     uno::Reference< beans::XPropertySetInfo > xInfo(
521         static_cast< beans::XPropertySetInfo* >(pInfo), uno::UNO_QUERY_THROW);
522     return xInfo;
523 }
524 
525 //-----------------------------------------------------------------------------
526 
527 void SAL_CALL  SfxDocumentInfoObject::setPropertyValue(const ::rtl::OUString& aPropertyName, const uno::Any& aValue) throw (
528         uno::RuntimeException, beans::UnknownPropertyException,
529         beans::PropertyVetoException, lang::IllegalArgumentException,
530         lang::WrappedTargetException)
531 {
532     const SfxItemPropertySimpleEntry* pEntry = _pImp->m_aPropertyMap.getByName( aPropertyName );
533     // fix prop!
534     if ( pEntry )
535         setFastPropertyValue( pEntry->nWID, aValue );
536     else
537     // dynamic prop!
538     {
539         uno::Reference<beans::XPropertySet> xPropSet(
540             _pImp->m_xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW);
541         return xPropSet->setPropertyValue(aPropertyName, aValue);
542     }
543 }
544 
545 //-----------------------------------------------------------------------------
546 
547 uno::Any  SAL_CALL  SfxDocumentInfoObject::getPropertyValue(const ::rtl::OUString& aPropertyName)  throw(
548         uno::RuntimeException, beans::UnknownPropertyException,
549         lang::WrappedTargetException)
550 {
551     const SfxItemPropertySimpleEntry* pEntry = _pImp->m_aPropertyMap.getByName( aPropertyName );
552     // fix prop!
553     if ( pEntry )
554         return getFastPropertyValue( pEntry->nWID );
555 	else
556     // dynamic prop!
557     {
558         uno::Reference<beans::XPropertySet> xPropSet(
559             _pImp->m_xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW);
560         return xPropSet->getPropertyValue(aPropertyName);
561     }
562 }
563 
564 sal_Bool SAL_CALL SfxDocumentInfoObject::isModified() throw(::com::sun::star::uno::RuntimeException)
565 {
566     uno::Reference<util::XModifiable> xModif(
567             _pImp->m_xDocProps, uno::UNO_QUERY_THROW);
568     return xModif->isModified();
569 }
570 
571 void SAL_CALL SfxDocumentInfoObject::setModified( sal_Bool bModified )
572         throw (::com::sun::star::beans::PropertyVetoException, ::com::sun::star::uno::RuntimeException)
573 {
574     uno::Reference<util::XModifiable> xModif(
575             _pImp->m_xDocProps, uno::UNO_QUERY_THROW);
576     return xModif->setModified(bModified);
577 }
578 
579 void SAL_CALL SfxDocumentInfoObject::addModifyListener( const uno::Reference< util::XModifyListener >& xListener) throw( uno::RuntimeException )
580 {
581     uno::Reference<util::XModifiable> xModif(
582             _pImp->m_xDocProps, uno::UNO_QUERY_THROW);
583     return xModif->addModifyListener(xListener);
584 }
585 
586 void SAL_CALL SfxDocumentInfoObject::removeModifyListener( const uno::Reference< util::XModifyListener >& xListener) throw( uno::RuntimeException )
587 {
588     uno::Reference<util::XModifiable> xModif(
589             _pImp->m_xDocProps, uno::UNO_QUERY_THROW);
590     return xModif->removeModifyListener(xListener);
591 }
592 
593 //-----------------------------------------------------------------------------
594 
595 void SAL_CALL  SfxDocumentInfoObject::addPropertyChangeListener(const ::rtl::OUString&, const uno::Reference< beans::XPropertyChangeListener > & ) throw(
596         uno::RuntimeException, beans::UnknownPropertyException,
597         lang::WrappedTargetException)
598 {}
599 
600 //-----------------------------------------------------------------------------
601 
602 void SAL_CALL  SfxDocumentInfoObject::removePropertyChangeListener(const ::rtl::OUString&, const uno::Reference< beans::XPropertyChangeListener > & ) throw(
603         uno::RuntimeException, beans::UnknownPropertyException,
604         lang::WrappedTargetException)
605 {}
606 
607 //-----------------------------------------------------------------------------
608 
609 void SAL_CALL  SfxDocumentInfoObject::addVetoableChangeListener(const ::rtl::OUString&, const uno::Reference< beans::XVetoableChangeListener > & ) throw(
610         uno::RuntimeException, beans::UnknownPropertyException,
611         lang::WrappedTargetException)
612 {}
613 
614 //-----------------------------------------------------------------------------
615 
616 void SAL_CALL  SfxDocumentInfoObject::removeVetoableChangeListener(const ::rtl::OUString&, const uno::Reference< beans::XVetoableChangeListener > & ) throw(
617         uno::RuntimeException, beans::UnknownPropertyException,
618         lang::WrappedTargetException)
619 {}
620 
621 uno::Sequence< beans::PropertyValue > SAL_CALL  SfxDocumentInfoObject::getPropertyValues( void ) throw( uno::RuntimeException )
622 {
623 	::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo >  xInfo = getPropertySetInfo();
624 	::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property > aProps = xInfo->getProperties();
625 
626 	const ::com::sun::star::beans::Property* pProps  = aProps.getConstArray();
627 	sal_uInt32 nCount = aProps.getLength();
628 
629 	::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >aSeq( nCount );
630 	::com::sun::star::beans::PropertyValue*  pValues = aSeq.getArray();
631 
632 	for ( sal_uInt32 n = 0; n < nCount; ++n )
633 	{
634 		::com::sun::star::beans::PropertyValue& rCurrValue = pValues[n];
635 		const ::com::sun::star::beans::Property& rCurrProp = pProps[n];
636 
637 		rCurrValue.Name = rCurrProp.Name;
638 		rCurrValue.Handle = rCurrProp.Handle;
639 		rCurrValue.Value = getPropertyValue( rCurrProp.Name );
640 	}
641 
642 	return aSeq;
643 }
644 
645 void SAL_CALL  SfxDocumentInfoObject::setPropertyValues( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aProps )
646         throw( ::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException )
647 {
648 	const ::com::sun::star::beans::PropertyValue* pProps  = aProps.getConstArray();
649 	sal_uInt32 nCount = aProps.getLength();
650 
651 	for ( sal_uInt32 n = 0; n < nCount; ++n )
652 	{
653 		const ::com::sun::star::beans::PropertyValue& rProp = pProps[n];
654 		setPropertyValue( rProp.Name, rProp.Value );
655 	}
656 }
657 
658 void SAL_CALL SfxDocumentInfoObject::addProperty(const ::rtl::OUString&            sName        ,
659                                                        sal_Int16                   nAttributes  ,
660                                                  const ::com::sun::star::uno::Any& aDefaultValue)
661     throw(::com::sun::star::beans::PropertyExistException ,
662           ::com::sun::star::beans::IllegalTypeException   ,
663           ::com::sun::star::lang::IllegalArgumentException,
664           ::com::sun::star::uno::RuntimeException         )
665 {
666     // clash with "fix" properties ?
667     sal_Bool bFixProp = _pImp->m_aPropertyMap.getByName( sName ) != 0;
668     if ( bFixProp )
669     {
670         ::rtl::OUStringBuffer sMsg(256);
671         sMsg.appendAscii("The property \""   );
672         sMsg.append     (sName               );
673         sMsg.appendAscii("\" "               );
674         if ( bFixProp )
675             sMsg.appendAscii(" already exists as a fix property. Please have a look into the IDL documentation of the DocumentInfo service.");
676 
677         throw ::com::sun::star::beans::PropertyExistException(
678                 sMsg.makeStringAndClear(),
679                 static_cast< ::cppu::OWeakObject* >(this));
680     }
681 
682     uno::Reference<beans::XPropertyContainer> xPropSet(
683         _pImp->m_xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW);
684     return xPropSet->addProperty(sName, nAttributes, aDefaultValue);
685 }
686 
687 void SAL_CALL SfxDocumentInfoObject::removeProperty(const ::rtl::OUString& sName)
688     throw(::com::sun::star::beans::UnknownPropertyException,
689           ::com::sun::star::beans::NotRemoveableException  ,
690           ::com::sun::star::uno::RuntimeException          )
691 {
692     // clash with "fix" properties ?
693     sal_Bool bFixProp = _pImp->m_aPropertyMap.getByName( sName ) != 0;
694     if ( bFixProp )
695     {
696         ::rtl::OUStringBuffer sMsg(256);
697         sMsg.appendAscii("The property \""                                                    );
698         sMsg.append     (sName                                                                );
699         sMsg.appendAscii("\" cant be removed. Its a fix property of the DocumentInfo service.");
700 
701         throw ::com::sun::star::beans::NotRemoveableException(
702                 sMsg.makeStringAndClear(),
703                 static_cast< ::cppu::OWeakObject* >(this));
704     }
705 
706     uno::Reference<beans::XPropertyContainer> xPropSet(
707         _pImp->m_xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW);
708     return xPropSet->removeProperty(sName);
709 }
710 
711 sal_Bool equalsDateTime( const util::DateTime& D1, const util::DateTime& D2 )
712 {
713     return D1.HundredthSeconds == D2.HundredthSeconds &&
714            D1.Seconds == D2.Seconds &&
715            D1.Minutes == D2.Minutes &&
716            D1.Hours == D2.Hours &&
717            D1.Day == D2.Day &&
718            D1.Month == D2.Month &&
719            D1.Year == D2.Year;
720 }
721 
722 void SAL_CALL  SfxDocumentInfoObject::setFastPropertyValue(sal_Int32 nHandle, const ::com::sun::star::uno::Any& aValue) throw(
723         uno::RuntimeException, beans::UnknownPropertyException,
724         beans::PropertyVetoException, lang::IllegalArgumentException,
725         lang::WrappedTargetException)
726 {
727     // Attention: Only fix properties should be provided by this method.
728     // Dynamic properties has no handle in real ... because it cant be used inside multithreaded environments :-)
729 
730     ::osl::ClearableMutexGuard aGuard( _pImp->_aMutex );
731 
732     if ( aValue.getValueType() == ::getCppuType((const ::rtl::OUString*)0) )
733 	{
734 		::rtl::OUString sTemp ;
735 		aValue >>= sTemp ;
736 		switch ( nHandle )
737 		{
738             case SID_APPLICATION :
739                 _pImp->m_xDocProps->setGenerator(sTemp);
740                 break;
741 			case WID_FROM :
742 			{
743                 // QUESTION: do we still need this?
744                 /*
745                 // String aStrVal( sTemp );
746 				if ( aStrVal.Len() > TIMESTAMP_MAXLENGTH )
747 				{
748 					SvAddressParser aParser( aStrVal );
749 					if ( aParser.Count() > 0 )
750 					{
751 						String aEmail = aParser.GetEmailAddress(0);
752 						String aRealname = aParser.GetRealName(0);
753 
754 						if ( aRealname.Len() <= TIMESTAMP_MAXLENGTH )
755 							aStrVal = aRealname;
756 						else if ( aEmail.Len() <= TIMESTAMP_MAXLENGTH )
757 							aStrVal = aEmail;
758 					}
759                 } */
760 
761                 if ( _pImp->m_xDocProps->getAuthor() != sTemp )
762                     _pImp->m_xDocProps->setAuthor(sTemp);
763 				break;
764 			}
765             case MID_DOCINFO_PRINTEDBY:
766                 if ( _pImp->m_xDocProps->getPrintedBy() != sTemp )
767                     _pImp->m_xDocProps->setPrintedBy(sTemp);
768                 break;
769 			case MID_DOCINFO_MODIFICATIONAUTHOR:
770                 if ( _pImp->m_xDocProps->getModifiedBy() != sTemp )
771                     _pImp->m_xDocProps->setModifiedBy(sTemp);
772 				break;
773 			case WID_TITLE :
774             {
775                 if ( _pImp->m_xDocProps->getTitle() != sTemp )
776                     _pImp->m_xDocProps->setTitle(sTemp);
777 				break;
778             }
779 			case MID_DOCINFO_SUBJECT :
780                 if ( _pImp->m_xDocProps->getSubject() != sTemp )
781                     _pImp->m_xDocProps->setSubject(sTemp);
782 				break;
783 			case WID_KEYWORDS :
784                 {
785                     _pImp->m_xDocProps->setKeywords(
786                         ::comphelper::string::convertCommaSeparated(sTemp));
787                 }
788 				break;
789 			case MID_DOCINFO_TEMPLATE:
790                 if ( _pImp->m_xDocProps->getTemplateName() != sTemp )
791                     _pImp->m_xDocProps->setTemplateName(sTemp);
792 				break;
793 			case SID_TEMPLATE_NAME:
794                 if ( _pImp->m_xDocProps->getTemplateURL() != sTemp )
795                     _pImp->m_xDocProps->setTemplateURL(sTemp);
796 				break;
797 			case MID_DOCINFO_DESCRIPTION:
798                 if ( _pImp->m_xDocProps->getDescription() != sTemp )
799                     _pImp->m_xDocProps->setDescription(sTemp);
800 				break;
801 			case MID_DOCINFO_AUTOLOADURL:
802                 if ( _pImp->m_xDocProps->getAutoloadURL() != sTemp )
803                     _pImp->m_xDocProps->setAutoloadURL(sTemp);
804 				break;
805 			case MID_DOCINFO_DEFAULTTARGET:
806                 if ( _pImp->m_xDocProps->getDefaultTarget() != sTemp )
807                     _pImp->m_xDocProps->setDefaultTarget(sTemp);
808 				break;
809 //            case WID_CONTENT_TYPE : // this is readonly!
810 			default:
811 				break;
812 		}
813 	}
814     else if ( aValue.getValueType() == ::getCppuType((const ::com::sun::star::util::DateTime*)0) )
815 	{
816         com::sun::star::util::DateTime aTemp;
817         aValue >>= aTemp ;
818 		switch ( nHandle )
819 		{
820 			case WID_DATE_CREATED :
821 			{
822                 if ( !equalsDateTime(_pImp->m_xDocProps->getCreationDate(), aTemp ) )
823 				{
824 					_pImp->m_xDocProps->setCreationDate(aTemp);
825 				}
826 				break;
827 			}
828 			case WID_DATE_MODIFIED :
829 			{
830                 if ( !equalsDateTime(_pImp->m_xDocProps->getModificationDate(), aTemp ) )
831 				{
832 					_pImp->m_xDocProps->setModificationDate(aTemp);
833 				}
834 				break;
835 			}
836             case MID_DOCINFO_PRINTDATE :
837 			{
838                 if ( !equalsDateTime(_pImp->m_xDocProps->getPrintDate(), aTemp ) )
839 				{
840 					_pImp->m_xDocProps->setPrintDate(aTemp);
841 				}
842 				break;
843 			}
844             case MID_DOCINFO_TEMPLATEDATE :
845 			{
846                 if ( !equalsDateTime(_pImp->m_xDocProps->getTemplateDate(), aTemp ) )
847 				{
848 					_pImp->m_xDocProps->setTemplateDate(aTemp);
849 				}
850 				break;
851 			}
852 			default:
853 				break;
854 		}
855 	}
856 
857     else if ( aValue.getValueType() == ::getBooleanCppuType() )
858 	{
859 		sal_Bool bBoolVal = false;
860 		aValue >>= bBoolVal ;
861 		switch ( nHandle )
862 		{
863 			case MID_DOCINFO_AUTOLOADENABLED:
864                 // NB: this property does not exist any more
865                 //     it is emulated as enabled iff delay > 0
866                 if ( bBoolVal && (0 == _pImp->m_xDocProps->getAutoloadSecs()) ) {
867                     _pImp->m_xDocProps->setAutoloadSecs(60); // default
868                 } else if ( !bBoolVal && (0 != _pImp->m_xDocProps->getAutoloadSecs()) ) {
869                     _pImp->m_xDocProps->setAutoloadSecs(0);
870                     _pImp->m_xDocProps->setAutoloadURL(::rtl::OUString::createFromAscii(""));
871                 }
872 				break;
873 			default:
874 				break;
875 		}
876 	}
877     else if ( aValue.getValueType() == ::getCppuType((const sal_Int32*)0) )
878 	{
879 		sal_Int32 nIntVal = 0;
880 		aValue >>= nIntVal ;
881 		switch ( nHandle )
882 		{
883 			case MID_DOCINFO_AUTOLOADSECS:
884                 if ( nIntVal != _pImp->m_xDocProps->getAutoloadSecs())
885                     _pImp->m_xDocProps->setAutoloadSecs(nIntVal);
886 				break;
887 			case MID_DOCINFO_EDITTIME:
888                 if ( nIntVal != _pImp->m_xDocProps->getEditingDuration())
889                     _pImp->m_xDocProps->setEditingDuration(nIntVal);
890 				break;
891 			default:
892 				break;
893 		}
894 	}
895     else if ( aValue.getValueType() == ::getCppuType((const sal_Int16*)0) )
896 	{
897 		short nIntVal = 0;
898 		aValue >>= nIntVal ;
899 		switch ( nHandle )
900 		{
901             case MID_DOCINFO_REVISION:
902                 if ( nIntVal != _pImp->m_xDocProps->getEditingCycles())
903                     _pImp->m_xDocProps->setEditingCycles(nIntVal);
904 				break;
905 			default:
906 				break;
907 		}
908 	}
909 	else if ( aValue.getValueType() == ::getCppuType((const uno::Sequence< beans::NamedValue >*)0) )
910 	{
911         if ( nHandle == MID_DOCINFO_STATISTIC )
912 		{
913             uno::Sequence < beans::NamedValue > aData;
914             aValue >>= aData;
915             {
916                 _pImp->m_xDocProps->setDocumentStatistics(aData);
917             }
918 		}
919 	}
920 	else if ( aValue.getValueType() == ::getCppuType((const lang::Locale*)0) )
921 	{
922         if ( nHandle == MID_DOCINFO_CHARLOCALE )
923 		{
924             lang::Locale aLocale;
925             aValue >>= aLocale;
926             lang::Locale oldLocale = _pImp->m_xDocProps->getLanguage();
927             if ( aLocale.Language != oldLocale.Language ||
928                  aLocale.Country  != oldLocale.Country  ||
929                  aLocale.Variant  != oldLocale.Variant   )
930 			{
931 				_pImp->m_xDocProps->setLanguage(aLocale);
932 			}
933 		}
934 	}
935 }
936 
937 //-----------------------------------------------------------------------------
938 
939 ::com::sun::star::uno::Any SAL_CALL  SfxDocumentInfoObject::getFastPropertyValue(sal_Int32 nHandle) throw(
940         uno::RuntimeException, beans::UnknownPropertyException,
941         lang::WrappedTargetException)
942 {
943     // Attention: Only fix properties should be provided by this method.
944     // Dynamic properties has no handle in real ... because it cant be used inside multithreaded environments :-)
945 
946     ::osl::MutexGuard aGuard( _pImp->_aMutex );
947 	::com::sun::star::uno::Any aValue;
948     switch ( nHandle )
949     {
950         case SID_APPLICATION :
951             aValue <<= _pImp->m_xDocProps->getGenerator();
952             break;
953         case WID_CONTENT_TYPE :
954 // FIXME this is not available anymore
955             aValue <<= ::rtl::OUString();
956             break;
957         case MID_DOCINFO_REVISION :
958             aValue <<= _pImp->m_xDocProps->getEditingCycles();
959             break;
960         case MID_DOCINFO_EDITTIME :
961             aValue <<= _pImp->m_xDocProps->getEditingDuration();
962             break;
963         case WID_FROM :
964 			aValue <<= _pImp->m_xDocProps->getAuthor();
965             break;
966         case WID_DATE_CREATED :
967             if ( IsValidDateTime( _pImp->m_xDocProps->getCreationDate() ) )
968 	            aValue <<= _pImp->m_xDocProps->getCreationDate();
969             break;
970         case WID_TITLE :
971             aValue <<= _pImp->m_xDocProps->getTitle();
972             break;
973         case MID_DOCINFO_SUBJECT:
974             aValue <<= _pImp->m_xDocProps->getSubject();
975             break;
976         case MID_DOCINFO_MODIFICATIONAUTHOR:
977             aValue <<= _pImp->m_xDocProps->getModifiedBy();
978             break;
979         case WID_DATE_MODIFIED :
980             if ( IsValidDateTime( _pImp->m_xDocProps->getModificationDate() ) )
981 	            aValue <<= _pImp->m_xDocProps->getModificationDate();
982             break;
983         case MID_DOCINFO_PRINTEDBY:
984             aValue <<= _pImp->m_xDocProps->getPrintedBy();
985             break;
986         case MID_DOCINFO_PRINTDATE:
987             if ( IsValidDateTime( _pImp->m_xDocProps->getPrintDate() ) )
988 	            aValue <<= _pImp->m_xDocProps->getPrintDate();
989             break;
990         case WID_KEYWORDS :
991             aValue <<= ::comphelper::string::convertCommaSeparated(
992                 _pImp->m_xDocProps->getKeywords());
993             break;
994         case MID_DOCINFO_DESCRIPTION:
995             aValue <<= _pImp->m_xDocProps->getDescription();
996             break;
997         case MID_DOCINFO_TEMPLATE:
998             aValue <<= _pImp->m_xDocProps->getTemplateName();
999             break;
1000         case SID_TEMPLATE_NAME:
1001             aValue <<= _pImp->m_xDocProps->getTemplateURL();
1002             break;
1003         case MID_DOCINFO_TEMPLATEDATE:
1004             if ( IsValidDateTime( _pImp->m_xDocProps->getTemplateDate() ) )
1005 				aValue <<= _pImp->m_xDocProps->getTemplateDate();
1006             break;
1007         case MID_DOCINFO_AUTOLOADENABLED:
1008             aValue <<= static_cast<sal_Bool>
1009                         (   (_pImp->m_xDocProps->getAutoloadSecs() != 0)
1010                         || !(_pImp->m_xDocProps->getAutoloadURL().equalsAscii("")));
1011             break;
1012         case MID_DOCINFO_AUTOLOADURL:
1013             aValue <<= _pImp->m_xDocProps->getAutoloadURL();
1014             break;
1015         case MID_DOCINFO_AUTOLOADSECS:
1016             aValue <<= _pImp->m_xDocProps->getAutoloadSecs();
1017             break;
1018         case MID_DOCINFO_DEFAULTTARGET:
1019             aValue <<= _pImp->m_xDocProps->getDefaultTarget();
1020             break;
1021         case MID_DOCINFO_STATISTIC:
1022             aValue <<= _pImp->m_xDocProps->getDocumentStatistics();
1023             break;
1024         case MID_DOCINFO_CHARLOCALE:
1025             aValue <<= _pImp->m_xDocProps->getLanguage();
1026             break;
1027         default:
1028             aValue <<= ::rtl::OUString();
1029             break;
1030     }
1031 
1032 	return aValue;
1033 }
1034 
1035 //-----------------------------------------------------------------------------
1036 
1037 sal_Int16 SAL_CALL  SfxDocumentInfoObject::getUserFieldCount() throw( ::com::sun::star::uno::RuntimeException )
1038 {
1039 //    uno::Reference<beans::XPropertyAccess> xPropSet(
1040 //        _pImp->m_xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW);
1041 //    return xPropSet->getPropertyValues().getLength();
1042     return FOUR;
1043 }
1044 
1045 //-----------------------------------------------------------------------------
1046 
1047 ::rtl::OUString SAL_CALL  SfxDocumentInfoObject::getUserFieldName(sal_Int16 nIndex) throw( ::com::sun::star::uno::RuntimeException )
1048 {
1049     ::osl::MutexGuard aGuard( _pImp->_aMutex );
1050     if (nIndex < FOUR)
1051         return _pImp->m_UserDefined[nIndex];
1052 	else
1053 		return ::rtl::OUString();
1054 }
1055 
1056 //-----------------------------------------------------------------------------
1057 
1058 ::rtl::OUString SAL_CALL  SfxDocumentInfoObject::getUserFieldValue(sal_Int16 nIndex) throw( ::com::sun::star::uno::RuntimeException )
1059 {
1060     ::osl::MutexGuard aGuard( _pImp->_aMutex );
1061     if (nIndex < FOUR) {
1062         ::rtl::OUString name = _pImp->m_UserDefined[nIndex];
1063         uno::Reference<beans::XPropertySet> xPropSet(
1064             _pImp->m_xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW);
1065         ::rtl::OUString val;
1066         try {
1067             xPropSet->getPropertyValue(name) >>= val;
1068             return val;
1069         } catch (uno::RuntimeException &) {
1070             throw;
1071         } catch (uno::Exception &) {
1072             return ::rtl::OUString(); // ignore
1073         }
1074     } else
1075 		return ::rtl::OUString();
1076 }
1077 
1078 //-----------------------------------------------------------------------------
1079 
1080 void  SAL_CALL SfxDocumentInfoObject::setUserFieldName(sal_Int16 nIndex, const ::rtl::OUString& aName ) throw( ::com::sun::star::uno::RuntimeException )
1081 {
1082     ::osl::ClearableMutexGuard aGuard( _pImp->_aMutex );
1083     if (nIndex < FOUR) // yes, four!
1084     {
1085         // FIXME this is full of race conditions because the PropertyBag
1086         // can be accessed from clients of the DocumentProperties!
1087         ::rtl::OUString name = _pImp->m_UserDefined[nIndex];
1088         if (name != aName) {
1089             uno::Reference<beans::XPropertySet> xPropSet(
1090                 _pImp->m_xDocProps->getUserDefinedProperties(),
1091                 uno::UNO_QUERY_THROW);
1092             uno::Reference<beans::XPropertyContainer> xPropContainer(
1093                 _pImp->m_xDocProps->getUserDefinedProperties(),
1094                 uno::UNO_QUERY_THROW);
1095             uno::Any value;
1096             try {
1097                 value = xPropSet->getPropertyValue(name);
1098                 xPropContainer->removeProperty(name);
1099                 xPropContainer->addProperty(aName,
1100                     beans::PropertyAttribute::REMOVEABLE, value);
1101                 _pImp->m_UserDefined[nIndex] = aName;
1102             } catch (beans::UnknownPropertyException) {
1103                 try {
1104                     xPropContainer->addProperty(aName,
1105                         beans::PropertyAttribute::REMOVEABLE,
1106                         uno::makeAny(::rtl::OUString::createFromAscii("")));
1107                     _pImp->m_UserDefined[nIndex] = aName;
1108                 } catch (beans::PropertyExistException) {
1109                     _pImp->m_UserDefined[nIndex] = aName;
1110                     // ignore
1111                 }
1112             } catch (beans::PropertyExistException) {
1113                 try {
1114                     xPropContainer->addProperty(name,
1115                         beans::PropertyAttribute::REMOVEABLE, value);
1116                 } catch (beans::PropertyExistException) {
1117                     // bugger...
1118                 }
1119             } catch (uno::RuntimeException &) {
1120                 throw;
1121             } catch (uno::Exception &) {
1122                 // ignore everything else; xPropSet _may_ be corrupted
1123             }
1124 		}
1125     }
1126 }
1127 
1128 //-----------------------------------------------------------------------------
1129 
1130 void SAL_CALL  SfxDocumentInfoObject::setUserFieldValue( sal_Int16 nIndex, const ::rtl::OUString& aValue ) throw( ::com::sun::star::uno::RuntimeException )
1131 {
1132     ::osl::ClearableMutexGuard aGuard( _pImp->_aMutex );
1133     if (nIndex < FOUR) // yes, four!
1134     {
1135         ::rtl::OUString name = _pImp->m_UserDefined[nIndex];
1136         uno::Reference<beans::XPropertySet> xPropSet(
1137             _pImp->m_xDocProps->getUserDefinedProperties(),
1138             uno::UNO_QUERY_THROW);
1139         uno::Reference<beans::XPropertyContainer> xPropContainer(
1140             _pImp->m_xDocProps->getUserDefinedProperties(),
1141             uno::UNO_QUERY_THROW);
1142         uno::Any aAny;
1143         aAny <<= aValue;
1144         try {
1145             uno::Any value = xPropSet->getPropertyValue(name);
1146             if (value != aAny) {
1147                 xPropSet->setPropertyValue(name, aAny);
1148             }
1149         } catch (beans::UnknownPropertyException) {
1150             try {
1151                 // someone removed it, add it back again
1152                 xPropContainer->addProperty(name,
1153                     beans::PropertyAttribute::REMOVEABLE, aAny);
1154             } catch (uno::RuntimeException &) {
1155                 throw;
1156             } catch (uno::Exception &) {
1157                 // ignore everything else
1158             }
1159         } catch (uno::RuntimeException &) {
1160             throw;
1161         } catch (uno::Exception &) {
1162             // ignore everything else
1163         }
1164     }
1165 }
1166 
1167 //-----------------------------------------------------------------------------
1168 SFX_IMPL_XINTERFACE_2( SfxStandaloneDocumentInfoObject, SfxDocumentInfoObject, ::com::sun::star::lang::XServiceInfo, ::com::sun::star::document::XStandaloneDocumentInfo  )
1169 SFX_IMPL_XTYPEPROVIDER_10( SfxStandaloneDocumentInfoObject, ::com::sun::star::document::XDocumentInfo, ::com::sun::star::lang::XComponent,
1170     ::com::sun::star::beans::XPropertySet, ::com::sun::star::beans::XFastPropertySet, ::com::sun::star::beans::XPropertyAccess,
1171     ::com::sun::star::beans::XPropertyContainer, ::com::sun::star::util::XModifiable, ::com::sun::star::util::XModifyBroadcaster,
1172     ::com::sun::star::document::XStandaloneDocumentInfo, ::com::sun::star::lang::XServiceInfo )
1173 
1174 SFX_IMPL_XSERVICEINFO( SfxStandaloneDocumentInfoObject, "com.sun.star.document.StandaloneDocumentInfo", "com.sun.star.comp.sfx2.StandaloneDocumentInfo" )
1175 SFX_IMPL_SINGLEFACTORY( SfxStandaloneDocumentInfoObject )
1176 
1177 SfxStandaloneDocumentInfoObject::SfxStandaloneDocumentInfoObject( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xFactory )
1178     : SfxDocumentInfoObject()
1179     , _xFactory( xFactory )
1180 {
1181     uno::Reference< lang::XInitialization > xDocProps(
1182         _xFactory->createInstance( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1183             "com.sun.star.document.DocumentProperties"))), uno::UNO_QUERY_THROW);
1184 //    xDocProps->initialize(uno::Sequence<uno::Any>());
1185     uno::Any a;
1186     a <<= xDocProps;
1187     uno::Sequence<uno::Any> args(1);
1188     args[0] = a;
1189     initialize(args);
1190 }
1191 
1192 //-----------------------------------------------------------------------------
1193 
1194 SfxStandaloneDocumentInfoObject::~SfxStandaloneDocumentInfoObject()
1195 {
1196 }
1197 
1198 //-----------------------------------------------------------------------------
1199 
1200 uno::Reference< embed::XStorage > GetStorage_Impl( const ::rtl::OUString& rName, sal_Bool bWrite, uno::Reference < lang::XMultiServiceFactory >& xFactory )
1201 {
1202     // catch unexpected exceptions under solaris
1203     // Client code checks the returned reference but is not interested on error details.
1204     try
1205     {
1206 		::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
1207         return ::comphelper::OStorageHelper::GetStorageFromURL(
1208 						rName,
1209 						bWrite ? embed::ElementModes::READWRITE : embed::ElementModes::READ,
1210                         xFactory );
1211     }
1212     catch(const uno::Exception&)
1213     {}
1214 
1215     return uno::Reference< embed::XStorage >();
1216 }
1217 
1218 //-----------------------------------------------------------------------------
1219 
1220 sal_Int16 SAL_CALL SfxStandaloneDocumentInfoObject::getUserFieldCount() throw( ::com::sun::star::uno::RuntimeException )
1221 {
1222 	return SfxDocumentInfoObject::getUserFieldCount();
1223 }
1224 
1225 //-----------------------------------------------------------------------------
1226 
1227 ::rtl::OUString SAL_CALL  SfxStandaloneDocumentInfoObject::getUserFieldName(sal_Int16 nIndex) throw( ::com::sun::star::uno::RuntimeException )
1228 {
1229 	return SfxDocumentInfoObject::getUserFieldName(nIndex);
1230 }
1231 
1232 //-----------------------------------------------------------------------------
1233 
1234 ::rtl::OUString SAL_CALL  SfxStandaloneDocumentInfoObject::getUserFieldValue(sal_Int16 nIndex) throw( ::com::sun::star::uno::RuntimeException )
1235 {
1236 	return SfxDocumentInfoObject::getUserFieldValue(nIndex);
1237 }
1238 
1239 //-----------------------------------------------------------------------------
1240 
1241 void  SAL_CALL SfxStandaloneDocumentInfoObject::setUserFieldName(sal_Int16 nIndex, const ::rtl::OUString& aName ) throw( ::com::sun::star::uno::RuntimeException )
1242 {
1243 	SfxDocumentInfoObject::setUserFieldName( nIndex, aName );
1244 }
1245 
1246 //-----------------------------------------------------------------------------
1247 
1248 void SAL_CALL  SfxStandaloneDocumentInfoObject::setUserFieldValue( sal_Int16 nIndex, const ::rtl::OUString& aValue ) throw( ::com::sun::star::uno::RuntimeException )
1249 {
1250 	SfxDocumentInfoObject::setUserFieldValue( nIndex, aValue );
1251 }
1252 
1253 //-----------------------------------------------------------------------------
1254 
1255 void SAL_CALL  SfxStandaloneDocumentInfoObject::loadFromURL(const ::rtl::OUString& aURL)
1256 	throw( ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException )
1257 {
1258 	sal_Bool bOK = sal_False;
1259 
1260     ::osl::ClearableMutexGuard aGuard( _pImp->_aMutex );
1261     uno::Reference< document::XDocumentProperties > xDocProps(
1262         _xFactory->createInstance( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1263             "com.sun.star.document.DocumentProperties"))), uno::UNO_QUERY_THROW);
1264 //    uno::Reference< lang::XInitialization > xInit(xDocProps, uno::UNO_QUERY_THROW);
1265 //    xInit->initialize(uno::Sequence<uno::Any>());
1266     _pImp->Reset(xDocProps);
1267 	aGuard.clear();
1268 
1269     uno::Reference< embed::XStorage > xStorage = GetStorage_Impl( aURL, sal_False, _xFactory );
1270     if ( xStorage.is() )
1271 	{
1272 		try
1273 		{
1274             uno::Sequence<beans::PropertyValue> medium(2);
1275             medium[0].Name = ::rtl::OUString::createFromAscii("DocumentBaseURL");
1276             medium[0].Value <<= aURL;
1277             medium[1].Name = ::rtl::OUString::createFromAscii("URL");
1278             medium[1].Value <<= aURL;
1279             _pImp->m_xDocProps->loadFromStorage(xStorage, medium);
1280             _pImp->Reset(_pImp->m_xDocProps);
1281             bOK = sal_True;
1282 		}
1283 		catch( uno::Exception& )
1284 		{
1285 		}
1286     }
1287 	else
1288 	{
1289         uno::Reference < document::XStandaloneDocumentInfo > xBinary( _xFactory->createInstance(
1290             ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.BinaryStandaloneDocumentInfo" ) ) ), uno::UNO_QUERY );
1291         if ( xBinary.is() )
1292         {
1293             xBinary->loadFromURL( aURL );
1294             bOK = sal_True;
1295             uno::Reference < document::XStandaloneDocumentInfo > xTarget( static_cast < document::XStandaloneDocumentInfo*> (this), uno::UNO_QUERY );
1296             Copy( xBinary, xTarget );
1297         }
1298 	}
1299 
1300 	if ( !bOK )
1301 		throw task::ErrorCodeIOException( ::rtl::OUString(), uno::Reference< uno::XInterface >(), ERRCODE_IO_CANTREAD );
1302 }
1303 
1304 //-----------------------------------------------------------------------------
1305 
1306 void SAL_CALL  SfxStandaloneDocumentInfoObject::storeIntoURL(const ::rtl::OUString& aURL) throw( ::com::sun::star::io::IOException )
1307 {
1308 	sal_Bool bOK = sal_False;
1309     uno::Reference< embed::XStorage > xStorage = GetStorage_Impl( aURL, sal_True, _xFactory );
1310 	if ( xStorage.is() )
1311 	{
1312 		try
1313 		{
1314             uno::Sequence<beans::PropertyValue> medium(2);
1315             medium[0].Name = ::rtl::OUString::createFromAscii("DocumentBaseURL");
1316             medium[0].Value <<= aURL;
1317             medium[1].Name = ::rtl::OUString::createFromAscii("URL");
1318             medium[1].Value <<= aURL;
1319 
1320             _pImp->m_xDocProps->storeToStorage(xStorage, medium);
1321             bOK = sal_True;
1322 		}
1323 		catch( io::IOException & )
1324 		{
1325 			throw;
1326 		}
1327 		catch( uno::RuntimeException& )
1328 		{
1329 			throw;
1330 		}
1331 		catch( uno::Exception& )
1332 		{
1333 		}
1334 	}
1335 	else
1336 	{
1337         uno::Reference < document::XStandaloneDocumentInfo > xBinary( _xFactory->createInstance(
1338 			::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.BinaryStandaloneDocumentInfo" ) ) ), uno::UNO_QUERY );
1339         if ( xBinary.is() )
1340         {
1341             Copy( this, xBinary );
1342             xBinary->storeIntoURL( aURL );
1343             bOK = sal_True;
1344         }
1345 	}
1346 
1347 	if ( !bOK )
1348 		throw task::ErrorCodeIOException( ::rtl::OUString(), uno::Reference< uno::XInterface >(), ERRCODE_IO_CANTWRITE );
1349 }
1350 
1351