merge the formfield patch from ooo-build
[ooovba.git] / connectivity / source / sdbcx / VCollection.cxx
blobbf102695351740adf9452aa675172471177a6972
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: VCollection.cxx,v $
10 * $Revision: 1.43.56.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_connectivity.hxx"
34 #include <algorithm>
35 #include <stdio.h>
36 #include "connectivity/sdbcx/VCollection.hxx"
37 #include "connectivity/sdbcx/VDescriptor.hxx"
38 #include "connectivity/dbexception.hxx"
39 #include <comphelper/enumhelper.hxx>
40 #include <comphelper/container.hxx>
41 #include <comphelper/types.hxx>
42 #include <comphelper/property.hxx>
43 #include "TConnection.hxx"
44 #include <rtl/ustrbuf.hxx>
45 #include "resource/common_res.hrc"
46 #include "resource/sharedresources.hxx"
48 using namespace connectivity::sdbcx;
49 using namespace connectivity;
50 using namespace comphelper;
51 using namespace ::cppu;
52 using namespace ::com::sun::star::beans;
53 using namespace ::com::sun::star::uno;
54 using namespace ::com::sun::star::lang;
55 using namespace ::com::sun::star::sdbc;
56 using namespace ::com::sun::star::container;
57 using namespace ::com::sun::star::util;
59 namespace
61 template < typename T> class OHardRefMap : public connectivity::sdbcx::IObjectCollection
63 typedef ::std::multimap< ::rtl::OUString, T , ::comphelper::UStringMixLess> ObjectMap;
64 typedef typename ObjectMap::iterator ObjectIter;
65 typedef typename ObjectMap::value_type ObjectEntry;
67 // private:
68 // this combination of map and vector is used to have a fast name and index access
69 ::std::vector< ObjectIter > m_aElements; // hold the iterators which point to map
70 ObjectMap m_aNameMap; // hold the elements and a name
71 public:
72 OHardRefMap(sal_Bool _bCase)
73 : m_aNameMap(_bCase ? true : false)
76 virtual ~OHardRefMap()
80 virtual void reserve(size_t nLength)
82 m_aElements.reserve(nLength);
84 // -----------------------------------------------------------------------------
85 virtual bool exists(const ::rtl::OUString& _sName )
87 return m_aNameMap.find(_sName) != m_aNameMap.end();
89 // -----------------------------------------------------------------------------
90 virtual bool empty()
92 return m_aNameMap.empty();
94 // -----------------------------------------------------------------------------
95 virtual void swapAll()
97 ::std::vector< ObjectIter >(m_aElements).swap(m_aElements);
98 ObjectMap(m_aNameMap).swap(m_aNameMap);
100 // -----------------------------------------------------------------------------
101 virtual void swap()
103 ::std::vector< ObjectIter >().swap(m_aElements);
105 OSL_ENSURE( m_aNameMap.empty(), "swap: what did disposeElements do?" );
106 ObjectMap( m_aNameMap ).swap( m_aNameMap );
107 // Note that it's /important/ to construct the new ObjectMap from m_aNameMap before
108 // swapping. This way, it's ensured that the compare object held by these maps is preserved
109 // during the swap. If we would not do this, the UStringMixLess instance which is used would be
110 // default constructed (instead of being constructed from the same instance in m_aNameMap), and
111 // it's case-sensitive flag would have an unpredictable value.
112 // 2002-01-09 - #106589# - fs@openoffice.org
114 // -----------------------------------------------------------------------------
115 virtual void clear()
117 m_aElements.clear();
118 m_aNameMap.clear();
120 // -----------------------------------------------------------------------------
121 virtual void insert(const ::rtl::OUString& _sName,const ObjectType& _xObject)
123 m_aElements.push_back(m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(_sName,_xObject)));
125 // -----------------------------------------------------------------------------
126 virtual void reFill(const TStringVector &_rVector)
128 OSL_ENSURE(!m_aNameMap.size(),"OCollection::reFill: collection isn't empty");
129 m_aElements.reserve(_rVector.size());
131 for(TStringVector::const_iterator i=_rVector.begin(); i != _rVector.end();++i)
132 m_aElements.push_back(m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(*i,ObjectType())));
134 // -----------------------------------------------------------------------------
135 virtual bool rename(const ::rtl::OUString _sOldName,const ::rtl::OUString _sNewName)
137 bool bRet = false;
138 ObjectIter aIter = m_aNameMap.find(_sOldName);
139 if ( aIter != m_aNameMap.end() )
141 typename ::std::vector< ObjectIter >::iterator aFind = ::std::find(m_aElements.begin(),m_aElements.end(),aIter);
142 if(m_aElements.end() != aFind)
144 (*aFind) = m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(_sNewName,(*aFind)->second));
145 m_aNameMap.erase(aIter);
147 bRet = true;
150 return bRet;
152 // -----------------------------------------------------------------------------
153 virtual sal_Int32 size()
155 return static_cast<sal_Int32>(m_aNameMap.size());
157 // -----------------------------------------------------------------------------
158 virtual Sequence< ::rtl::OUString > getElementNames()
160 Sequence< ::rtl::OUString > aNameList(m_aElements.size());
162 ::rtl::OUString* pStringArray = aNameList.getArray();
163 typename ::std::vector< ObjectIter >::const_iterator aEnd = m_aElements.end();
164 for(typename ::std::vector< ObjectIter >::const_iterator aIter = m_aElements.begin(); aIter != aEnd;++aIter,++pStringArray)
165 *pStringArray = (*aIter)->first;
167 return aNameList;
169 // -----------------------------------------------------------------------------
170 virtual ::rtl::OUString getName(sal_Int32 _nIndex)
172 return m_aElements[_nIndex]->first;
174 // -----------------------------------------------------------------------------
175 virtual void disposeAndErase(sal_Int32 _nIndex)
177 OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
178 Reference<XComponent> xComp(m_aElements[_nIndex]->second.get(),UNO_QUERY);
179 ::comphelper::disposeComponent(xComp);
180 m_aElements[_nIndex]->second = T();
182 ::rtl::OUString sName = m_aElements[_nIndex]->first;
183 m_aElements.erase(m_aElements.begin()+_nIndex);
184 m_aNameMap.erase(sName);
186 // -----------------------------------------------------------------------------
187 virtual void disposeElements()
189 for( ObjectIter aIter = m_aNameMap.begin(); aIter != m_aNameMap.end(); ++aIter)
191 Reference<XComponent> xComp(aIter->second.get(),UNO_QUERY);
192 if ( xComp.is() )
194 ::comphelper::disposeComponent(xComp);
195 (*aIter).second = T();
198 m_aElements.clear();
199 m_aNameMap.clear();
201 // -----------------------------------------------------------------------------
202 virtual sal_Int32 findColumn( const ::rtl::OUString& columnName )
204 ObjectIter aIter = m_aNameMap.find(columnName);
205 OSL_ENSURE(aIter != m_aNameMap.end(),"findColumn:: Illegal name!");
206 return m_aElements.size() - (m_aElements.end() - ::std::find(m_aElements.begin(),m_aElements.end(),aIter));
208 // -----------------------------------------------------------------------------
209 virtual ::rtl::OUString findColumnAtIndex( sal_Int32 _nIndex)
211 OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
212 return m_aElements[_nIndex]->first;
214 // -----------------------------------------------------------------------------
215 virtual ObjectType getObject(sal_Int32 _nIndex)
217 OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
218 return m_aElements[_nIndex]->second;
220 // -----------------------------------------------------------------------------
221 virtual ObjectType getObject(const ::rtl::OUString& columnName)
223 return m_aNameMap.find(columnName)->second;
225 // -----------------------------------------------------------------------------
226 virtual void setObject(sal_Int32 _nIndex,const ObjectType& _xObject)
228 OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
229 m_aElements[_nIndex]->second = _xObject;
231 // -----------------------------------------------------------------------------
232 sal_Bool isCaseSensitive() const
234 return m_aNameMap.key_comp().isCaseSensitive();
236 // -----------------------------------------------------------------------------
239 // -----------------------------------------------------------------------------
241 IMPLEMENT_SERVICE_INFO(OCollection,"com.sun.star.sdbcx.VContainer" , "com.sun.star.sdbcx.Container")
243 OCollection::OCollection(::cppu::OWeakObject& _rParent
244 , sal_Bool _bCase
245 , ::osl::Mutex& _rMutex
246 , const TStringVector &_rVector
247 , sal_Bool _bUseIndexOnly
248 , sal_Bool _bUseHardRef)
249 :m_aContainerListeners(_rMutex)
250 ,m_aRefreshListeners(_rMutex)
251 ,m_rParent(_rParent)
252 ,m_rMutex(_rMutex)
253 ,m_bUseIndexOnly(_bUseIndexOnly)
255 if ( _bUseHardRef )
257 m_pElements.reset(new OHardRefMap< ObjectType >(_bCase));
259 else
261 m_pElements.reset(new OHardRefMap< WeakReference< XPropertySet> >(_bCase));
263 m_pElements->reFill(_rVector);
265 // -------------------------------------------------------------------------
266 OCollection::~OCollection()
269 // -----------------------------------------------------------------------------
270 Any SAL_CALL OCollection::queryInterface( const Type & rType ) throw (RuntimeException)
272 if ( m_bUseIndexOnly && rType == ::getCppuType(static_cast< Reference< XNameAccess > *> (NULL)) )
274 return Any();
276 return OCollectionBase::queryInterface( rType );
278 // -----------------------------------------------------------------------------
279 Sequence< Type > SAL_CALL OCollection::getTypes() throw (RuntimeException)
281 if ( m_bUseIndexOnly )
283 Sequence< Type > aTypes(OCollectionBase::getTypes());
284 Type* pBegin = aTypes.getArray();
285 Type* pEnd = pBegin + aTypes.getLength();
287 ::std::vector<Type> aOwnTypes;
288 aOwnTypes.reserve(aTypes.getLength());
289 Type aType = ::getCppuType(static_cast< Reference<XNameAccess> *>(NULL));
290 for(;pBegin != pEnd; ++pBegin)
292 if ( *pBegin != aType )
293 aOwnTypes.push_back(*pBegin);
295 Type* pTypes = aOwnTypes.empty() ? 0 : &aOwnTypes[0];
296 return Sequence< Type >(pTypes,aOwnTypes.size());
298 return OCollectionBase::getTypes( );
300 // -------------------------------------------------------------------------
301 void OCollection::clear_NoDispose()
303 ::osl::MutexGuard aGuard(m_rMutex);
305 m_pElements->clear();
306 m_pElements->swapAll();
309 // -------------------------------------------------------------------------
310 void OCollection::disposing(void)
312 m_aContainerListeners.disposeAndClear(EventObject(static_cast<XTypeProvider*>(this)));
313 m_aRefreshListeners.disposeAndClear(EventObject(static_cast<XTypeProvider*>(this)));
315 ::osl::MutexGuard aGuard(m_rMutex);
317 disposeElements();
319 m_pElements->swap();
321 // -------------------------------------------------------------------------
322 Any SAL_CALL OCollection::getByIndex( sal_Int32 Index ) throw(IndexOutOfBoundsException, WrappedTargetException, RuntimeException)
324 ::osl::MutexGuard aGuard(m_rMutex);
325 if (Index < 0 || Index >= m_pElements->size() )
326 throw IndexOutOfBoundsException(::rtl::OUString::valueOf(Index),static_cast<XTypeProvider*>(this));
328 return makeAny(getObject(Index));
330 // -------------------------------------------------------------------------
331 Any SAL_CALL OCollection::getByName( const ::rtl::OUString& aName ) throw(NoSuchElementException, WrappedTargetException, RuntimeException)
333 ::osl::MutexGuard aGuard(m_rMutex);
335 if ( !m_pElements->exists(aName) )
337 ::connectivity::SharedResources aResources;
338 const ::rtl::OUString sError( aResources.getResourceStringWithSubstitution(
339 STR_NO_ELEMENT_NAME,
340 "$name$", aName
341 ) );
342 throw NoSuchElementException( sError, static_cast< XTypeProvider* >( this ) );
345 return makeAny(getObject(m_pElements->findColumn(aName)));
347 // -------------------------------------------------------------------------
348 Sequence< ::rtl::OUString > SAL_CALL OCollection::getElementNames( ) throw(RuntimeException)
350 ::osl::MutexGuard aGuard(m_rMutex);
351 return m_pElements->getElementNames();
353 // -------------------------------------------------------------------------
354 void SAL_CALL OCollection::refresh( ) throw(RuntimeException)
356 ::osl::MutexGuard aGuard(m_rMutex);
358 disposeElements();
360 impl_refresh();
361 EventObject aEvt(static_cast<XTypeProvider*>(this));
362 m_aRefreshListeners.notifyEach( &XRefreshListener::refreshed, aEvt );
364 // -----------------------------------------------------------------------------
365 void OCollection::reFill(const TStringVector &_rVector)
367 m_pElements->reFill(_rVector);
369 // -------------------------------------------------------------------------
370 // XDataDescriptorFactory
371 Reference< XPropertySet > SAL_CALL OCollection::createDataDescriptor( ) throw(RuntimeException)
373 ::osl::MutexGuard aGuard(m_rMutex);
375 return createDescriptor();
377 // -----------------------------------------------------------------------------
378 ::rtl::OUString OCollection::getNameForObject(const ObjectType& _xObject)
380 OSL_ENSURE(_xObject.is(),"OCollection::getNameForObject: Object is NULL!");
381 ::rtl::OUString sName;
382 _xObject->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= sName;
383 return sName;
385 // -------------------------------------------------------------------------
386 // XAppend
387 void SAL_CALL OCollection::appendByDescriptor( const Reference< XPropertySet >& descriptor ) throw(SQLException, ElementExistException, RuntimeException)
389 ::osl::ClearableMutexGuard aGuard(m_rMutex);
391 ::rtl::OUString sName = getNameForObject( descriptor );
393 if ( m_pElements->exists(sName) )
394 throw ElementExistException(sName,static_cast<XTypeProvider*>(this));
396 ObjectType xNewlyCreated = appendObject( sName, descriptor );
397 if ( !xNewlyCreated.is() )
398 throw RuntimeException();
400 ODescriptor* pDescriptor = ODescriptor::getImplementation( xNewlyCreated );
401 if ( pDescriptor )
402 pDescriptor->setNew( sal_False );
404 sName = getNameForObject( xNewlyCreated );
405 if ( !m_pElements->exists( sName ) ) // this may happen when the drived class included it itself
406 m_pElements->insert( sName, xNewlyCreated );
408 // notify our container listeners
409 ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(sName), makeAny(xNewlyCreated), Any());
410 aGuard.clear();
411 m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent );
413 // -------------------------------------------------------------------------
414 // XDrop
415 void SAL_CALL OCollection::dropByName( const ::rtl::OUString& elementName ) throw(SQLException, NoSuchElementException, RuntimeException)
417 ::osl::MutexGuard aGuard(m_rMutex);
419 if ( !m_pElements->exists(elementName) )
420 throw NoSuchElementException(elementName,static_cast<XTypeProvider*>(this));
422 dropImpl(m_pElements->findColumn(elementName));
424 // -------------------------------------------------------------------------
425 void SAL_CALL OCollection::dropByIndex( sal_Int32 index ) throw(SQLException, IndexOutOfBoundsException, RuntimeException)
427 ::osl::MutexGuard aGuard(m_rMutex);
428 if(index <0 || index >= getCount())
429 throw IndexOutOfBoundsException(::rtl::OUString::valueOf(index),static_cast<XTypeProvider*>(this));
431 dropImpl(index);
433 // -----------------------------------------------------------------------------
434 void OCollection::dropImpl(sal_Int32 _nIndex,sal_Bool _bReallyDrop)
436 ::rtl::OUString elementName = m_pElements->getName(_nIndex);
438 if ( _bReallyDrop )
439 dropObject(_nIndex,elementName);
441 m_pElements->disposeAndErase(_nIndex);
443 // notify our container listeners
444 notifyElementRemoved(elementName);
446 // -----------------------------------------------------------------------------
447 void OCollection::notifyElementRemoved(const ::rtl::OUString& _sName)
449 ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(_sName), Any(), Any());
450 // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
451 OInterfaceIteratorHelper aListenerLoop(m_aContainerListeners);
452 while (aListenerLoop.hasMoreElements())
453 static_cast<XContainerListener*>(aListenerLoop.next())->elementRemoved(aEvent);
455 // -------------------------------------------------------------------------
456 sal_Int32 SAL_CALL OCollection::findColumn( const ::rtl::OUString& columnName ) throw(SQLException, RuntimeException)
458 if ( !m_pElements->exists(columnName) )
460 ::connectivity::SharedResources aResources;
461 const ::rtl::OUString sError( aResources.getResourceStringWithSubstitution(
462 STR_UNKNOWN_COLUMN_NAME,
463 "$columnname$", columnName
464 ) );
465 ::dbtools::throwGenericSQLException(sError,static_cast< XIndexAccess*>(this));
468 return m_pElements->findColumn(columnName) + 1; // because columns start at one
470 // -------------------------------------------------------------------------
471 Reference< XEnumeration > SAL_CALL OCollection::createEnumeration( ) throw(RuntimeException)
473 ::osl::MutexGuard aGuard(m_rMutex);
474 return new OEnumerationByIndex( static_cast< XIndexAccess*>(this));
476 // -----------------------------------------------------------------------------
477 void SAL_CALL OCollection::addContainerListener( const Reference< XContainerListener >& _rxListener ) throw(RuntimeException)
479 m_aContainerListeners.addInterface(_rxListener);
482 //------------------------------------------------------------------------------
483 void SAL_CALL OCollection::removeContainerListener( const Reference< XContainerListener >& _rxListener ) throw(RuntimeException)
485 m_aContainerListeners.removeInterface(_rxListener);
487 // -----------------------------------------------------------------------------
488 void SAL_CALL OCollection::acquire() throw()
490 m_rParent.acquire();
492 // -----------------------------------------------------------------------------
493 void SAL_CALL OCollection::release() throw()
495 m_rParent.release();
497 // -----------------------------------------------------------------------------
498 Type SAL_CALL OCollection::getElementType( ) throw(RuntimeException)
500 return::getCppuType(static_cast< Reference< XPropertySet>*>(NULL));
502 // -----------------------------------------------------------------------------
503 sal_Bool SAL_CALL OCollection::hasElements( ) throw(RuntimeException)
505 ::osl::MutexGuard aGuard(m_rMutex);
506 return !m_pElements->empty();
508 // -----------------------------------------------------------------------------
509 sal_Int32 SAL_CALL OCollection::getCount( ) throw(RuntimeException)
511 ::osl::MutexGuard aGuard(m_rMutex);
512 return m_pElements->size();
514 // -----------------------------------------------------------------------------
515 sal_Bool SAL_CALL OCollection::hasByName( const ::rtl::OUString& aName ) throw(RuntimeException)
517 ::osl::MutexGuard aGuard(m_rMutex);
518 return m_pElements->exists(aName);
520 // -----------------------------------------------------------------------------
521 void SAL_CALL OCollection::addRefreshListener( const Reference< XRefreshListener >& l ) throw(RuntimeException)
523 m_aRefreshListeners.addInterface(l);
525 // -----------------------------------------------------------------------------
526 void SAL_CALL OCollection::removeRefreshListener( const Reference< XRefreshListener >& l ) throw(RuntimeException)
528 m_aRefreshListeners.removeInterface(l);
530 // -----------------------------------------------------------------------------
531 void OCollection::insertElement(const ::rtl::OUString& _sElementName,const ObjectType& _xElement)
533 OSL_ENSURE(!m_pElements->exists(_sElementName),"Element already exists");
534 if ( !m_pElements->exists(_sElementName) )
535 m_pElements->insert(_sElementName,_xElement);
537 // -----------------------------------------------------------------------------
538 void OCollection::renameObject(const ::rtl::OUString _sOldName,const ::rtl::OUString _sNewName)
540 OSL_ENSURE(m_pElements->exists(_sOldName),"Element doesn't exist");
541 OSL_ENSURE(!m_pElements->exists(_sNewName),"Element already exists");
542 OSL_ENSURE(_sNewName.getLength(),"New name must not be empty!");
543 OSL_ENSURE(_sOldName.getLength(),"New name must not be empty!");
545 if ( m_pElements->rename(_sOldName,_sNewName) )
547 ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(_sNewName), makeAny(m_pElements->getObject(_sNewName)),makeAny(_sOldName));
548 // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
549 OInterfaceIteratorHelper aListenerLoop(m_aContainerListeners);
550 while (aListenerLoop.hasMoreElements())
551 static_cast<XContainerListener*>(aListenerLoop.next())->elementReplaced(aEvent);
554 // -----------------------------------------------------------------------------
555 ObjectType OCollection::getObject(sal_Int32 _nIndex)
557 ObjectType xName = m_pElements->getObject(_nIndex);
558 if ( !xName.is() )
562 xName = createObject(m_pElements->getName(_nIndex));
564 catch(const SQLException& e)
568 dropImpl(_nIndex,sal_False);
570 catch(const Exception& )
573 throw WrappedTargetException(e.Message,static_cast<XTypeProvider*>(this),makeAny(e));
575 m_pElements->setObject(_nIndex,xName);
577 return xName;
579 // -----------------------------------------------------------------------------
580 void OCollection::disposeElements()
582 m_pElements->disposeElements();
584 // -----------------------------------------------------------------------------
585 Reference< XPropertySet > OCollection::createDescriptor()
587 OSL_ASSERT(!"Need to be overloaded when used!");
588 throw SQLException();
590 // -----------------------------------------------------------------------------
591 ObjectType OCollection::cloneDescriptor( const ObjectType& _descriptor )
593 ObjectType xNewDescriptor( createDescriptor() );
594 ::comphelper::copyProperties( _descriptor, xNewDescriptor );
595 return xNewDescriptor;
597 // -----------------------------------------------------------------------------
598 ObjectType OCollection::appendObject( const ::rtl::OUString& /*_rForName*/, const Reference< XPropertySet >& descriptor )
600 return cloneDescriptor( descriptor );
602 // -----------------------------------------------------------------------------
603 void OCollection::dropObject(sal_Int32 /*_nPos*/,const ::rtl::OUString /*_sElementName*/)
606 // -----------------------------------------------------------------------------