<commit_before>/*************************************************************************
 *
 *  $RCSfile: accessiblecontexthelper.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: fs $ $Date: 2002-04-26 05:51:23 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc..
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef COMPHELPER_ACCESSIBLE_CONTEXT_HELPER_HXX
#define COMPHELPER_ACCESSIBLE_CONTEXT_HELPER_HXX

#ifndef _CPPUHELPER_COMPBASE2_HXX_
#include <cppuhelper/compbase2.hxx>
#endif
#ifndef _DRAFTS_COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLECONTEXT_HPP_
#include <drafts/com/sun/star/accessibility/XAccessibleContext.hpp>
#endif
#ifndef _DRAFTS_COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLEEVENTBROADCASTER_HPP_
#include <drafts/com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_DISPOSEDEXCEPTION_HPP_
#include <com/sun/star/lang/DisposedException.hpp>
#endif
#ifndef _COMPHELPER_BROADCASTHELPER_HXX_
#include <comphelper/broadcasthelper.hxx>
#endif

//.........................................................................
namespace comphelper
{
//.........................................................................

    //=====================================================================
    //= OAccessibleContextHelper
    //=====================================================================

    class OContextHelper_Impl;
    typedef ::cppu::WeakAggComponentImplHelper2 <   ::drafts::com::sun::star::accessibility::XAccessibleContext,
                                                    ::drafts::com::sun::star::accessibility::XAccessibleEventBroadcaster
                                                >   OAccessibleContextHelper_Base;

    /** helper class for implementing an AccessibleContext
    */
    class OAccessibleContextHelper
                :public ::comphelper::OBaseMutex
                ,public OAccessibleContextHelper_Base
    {
    private:
        OContextHelper_Impl*    m_pImpl;

    protected:
        OAccessibleContextHelper( );
        ~OAccessibleContextHelper( );

        /** late construction
        @param _rxAccessible
            the Accessible object which created this context.

If your derived implementation implements the XAccessible (and does not follow the proposed
            separation of XAccessible from XAccessibleContext), you may pass this here.

The object is hold weak, so it's life time is not affected.

The object is needed for performance reasons: for <method>getAccessibleIndexInParent</method>,
            all children (which are XAccessible's theirself) of our parent have to be asked. If we know our
            XAccessible, we can compare it with all the children, instead of asking all children for their
            context and comparing this context with ourself.

        */
        void lateInit( const ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessible >& _rxAccessible );

    public:
        // XAccessibleEventBroadcaster
        virtual void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessibleEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException);
        virtual void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessibleEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException);

        // XAccessibleContext - still waiting to be overwritten
        virtual sal_Int32 SAL_CALL getAccessibleChildCount(  ) throw (::com::sun::star::uno::RuntimeException) = 0;
        virtual ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException) = 0;
        virtual ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleParent(  ) throw (::com::sun::star::uno::RuntimeException) = 0;
        virtual sal_Int16 SAL_CALL getAccessibleRole(  ) throw (::com::sun::star::uno::RuntimeException) = 0;
        virtual ::rtl::OUString SAL_CALL getAccessibleDescription(  ) throw (::com::sun::star::uno::RuntimeException) = 0;
        virtual ::rtl::OUString SAL_CALL getAccessibleName(  ) throw (::com::sun::star::uno::RuntimeException) = 0;
        virtual ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet(  ) throw (::com::sun::star::uno::RuntimeException) = 0;
        virtual ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet(  ) throw (::com::sun::star::uno::RuntimeException) = 0;

        // XAccessibleContext - default implementations
        /** default implementation for retrieving the index of this object within the parent

This basic implementation here returns the index i of the child for which
                <parent>.getAccessibleChild( i ) equals our creator.

        */
        virtual sal_Int32 SAL_CALL getAccessibleIndexInParent(  ) throw (::com::sun::star::uno::RuntimeException);
        /** default implementation for retrieving the locale

This basic implementation returns the locale of the parent context,
            as retrieved via getAccessibleParent()->getAccessibleContext.

        */
        virtual ::com::sun::star::lang::Locale SAL_CALL getLocale(  ) throw (::drafts::com::sun::star::accessibility::IllegalAccessibleComponentStateException, ::com::sun::star::uno::RuntimeException);

    public:
        // helper struct for granting selective access rights
        struct OAccessControl { friend class OContextEntryGuard; };

        // ensures that the object is alive
        inline  void            ensureAlive( const OAccessControl& _rAccessControl ) const SAL_THROW( ( ::com::sun::star::lang::DisposedException ) );
        inline  ::osl::Mutex&   GetMutex( const OAccessControl& _rAccessControl );

    protected:
        // OComponentHelper
        virtual void SAL_CALL disposing();

    protected:
        // helper
        /** notifies all AccessibleEventListeners of a certain event

        @precond    not too be called with our mutex locked
        @param  _nEventId
            the id of the even. See AccessibleEventType
        @param  _rOldValue
            the old value to be notified
        @param  _rNewValue
            the new value to be notified
        */
        void SAL_CALL   NotifyAccessibleEvent(
                    const sal_Int16 _nEventId,
                    const ::com::sun::star::uno::Any& _rOldValue,
                    const ::com::sun::star::uno::Any& _rNewValue
                );

        // life time control
        /// checks whether the object is alive (returns <TRUE/> then) or disposed
        sal_Bool    isAlive() const;
        /// checks for beeing alive. If the object is already disposed (i.e. not alive), an exception is thrown.
        void        ensureAlive() const SAL_THROW( ( ::com::sun::star::lang::DisposedException ) );

        /** ensures that the object is disposed.
        @precond
            to be called from within the destructor of your derived class only!
        */
        void        ensureDisposed( );

        /** shortcut for retrieving the context of the parent (returned by getAccessibleParent)
        */
        ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessibleContext >
                    implGetParentContext() SAL_THROW( ( ::com::sun::star::uno::RuntimeException ) );

        // access to the base class' broadcast helper/mutex
        ::cppu::OBroadcastHelper&       GetBroadcastHelper()        { return rBHelper; }
        const ::cppu::OBroadcastHelper& GetBroadcastHelper() const  { return rBHelper; }
        ::osl::Mutex&                   GetMutex()                  { return m_aMutex; }
    };

    //---------------------------------------------------------------------
    inline  void OAccessibleContextHelper::ensureAlive( const OAccessControl& _rAccessControl ) const SAL_THROW( ( ::com::sun::star::lang::DisposedException ) )
    {
        ensureAlive();
    }

    //---------------------------------------------------------------------
    inline  ::osl::Mutex& OAccessibleContextHelper::GetMutex( const OAccessControl& _rAccessControl )
    {
        return GetMutex();
    }

    //=====================================================================
    //= OContextEntryGuard
    //=====================================================================
    typedef ::osl::ClearableMutexGuard  OContextEntryGuard_Base;
    /** helper class for guarding the entry into OAccessibleContextHelper methods.

The class has two responsibilities:

it locks the mutex of an OAccessibleContextHelper instance, as long as the guard lives

it checks if an given OAccessibleContextHelper instance is alive, else an exception is thrown
                our of the constructor of the guard

        This makes it your first choice (hopefully :) for guarding any interface method implementations of
        you derived class.

    */
    class OContextEntryGuard : public OContextEntryGuard_Base
    {
    public:
        /** constructs the guard

The given context (it's mutex, respectively) is locked, and an exception is thrown if the context
            is not alive anymore. In the latter case, of course, the mutex is freed, again.

        @param _pContext
            the context which shall be guarded
        @precond <arg>_pContext</arg> != NULL
        */
        inline OContextEntryGuard( OAccessibleContextHelper* _pContext );

        /** destructs the guard.

The context (it's mutex, respectively) is unlocked.

        */
        inline ~OContextEntryGuard();
    };

    //.....................................................................
    inline OContextEntryGuard::OContextEntryGuard( OAccessibleContextHelper* _pContext  )
        :OContextEntryGuard_Base( _pContext->GetMutex( OAccessibleContextHelper::OAccessControl() ) )
    {
        _pContext->ensureAlive( OAccessibleContextHelper::OAccessControl() );
    }

    //.....................................................................
    inline OContextEntryGuard::~OContextEntryGuard()
    {
    }

//.........................................................................
}   // namespace comphelper
//.........................................................................

#endif // COMPHELPER_ACCESSIBLE_CONTEXT_HELPER_HXX

/*************************************************************************
 * history:
 *  $Log: not supported by cvs2svn $
 *  Revision 1.1  2002/04/23 11:07:38  fs
 *  initial checkin - helper for implementing an XAccessibleContext
 *
 *
 *  Revision 1.0 17.04.2002 15:47:54  fs
 ************************************************************************/

<commit_msg>#98750# +getAccessibleCreator<commit_after>/*************************************************************************
 *
 *  $RCSfile: accessiblecontexthelper.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: fs $ $Date: 2002-04-26 14:21:46 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc..
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef COMPHELPER_ACCESSIBLE_CONTEXT_HELPER_HXX
#define COMPHELPER_ACCESSIBLE_CONTEXT_HELPER_HXX

#ifndef _CPPUHELPER_COMPBASE2_HXX_
#include <cppuhelper/compbase2.hxx>
#endif
#ifndef _DRAFTS_COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLECONTEXT_HPP_
#include <drafts/com/sun/star/accessibility/XAccessibleContext.hpp>
#endif
#ifndef _DRAFTS_COM_SUN_STAR_ACCESSIBILITY_XACCESSIBLEEVENTBROADCASTER_HPP_
#include <drafts/com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_DISPOSEDEXCEPTION_HPP_
#include <com/sun/star/lang/DisposedException.hpp>
#endif
#ifndef _COMPHELPER_BROADCASTHELPER_HXX_
#include <comphelper/broadcasthelper.hxx>
#endif

//.........................................................................
namespace comphelper
{
//.........................................................................

    //=====================================================================
    //= OAccessibleContextHelper
    //=====================================================================

    class OContextHelper_Impl;
    typedef ::cppu::WeakAggComponentImplHelper2 <   ::drafts::com::sun::star::accessibility::XAccessibleContext,
                                                    ::drafts::com::sun::star::accessibility::XAccessibleEventBroadcaster
                                                >   OAccessibleContextHelper_Base;

    /** helper class for implementing an AccessibleContext
    */
    class OAccessibleContextHelper
                :public ::comphelper::OBaseMutex
                ,public OAccessibleContextHelper_Base
    {
    private:
        OContextHelper_Impl*    m_pImpl;

    protected:
        OAccessibleContextHelper( );
        ~OAccessibleContextHelper( );

        /** late construction
        @param _rxAccessible
            the Accessible object which created this context.

If your derived implementation implements the XAccessible (and does not follow the proposed
            separation of XAccessible from XAccessibleContext), you may pass this here.

The object is hold weak, so it's life time is not affected.

The object is needed for performance reasons: for <method>getAccessibleIndexInParent</method>,
            all children (which are XAccessible's theirself) of our parent have to be asked. If we know our
            XAccessible, we can compare it with all the children, instead of asking all children for their
            context and comparing this context with ourself.

        */
        void    lateInit( const ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessible >& _rxAccessible );

        /** retrieves the creator previously set with <method>lateInit</method>
        */
        ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessible >
                getAccessibleCreator( ) const;

    public:
        // XAccessibleEventBroadcaster
        virtual void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessibleEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException);
        virtual void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessibleEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException);

        // XAccessibleContext - still waiting to be overwritten
        virtual sal_Int32 SAL_CALL getAccessibleChildCount(  ) throw (::com::sun::star::uno::RuntimeException) = 0;
        virtual ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException) = 0;
        virtual ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleParent(  ) throw (::com::sun::star::uno::RuntimeException) = 0;
        virtual sal_Int16 SAL_CALL getAccessibleRole(  ) throw (::com::sun::star::uno::RuntimeException) = 0;
        virtual ::rtl::OUString SAL_CALL getAccessibleDescription(  ) throw (::com::sun::star::uno::RuntimeException) = 0;
        virtual ::rtl::OUString SAL_CALL getAccessibleName(  ) throw (::com::sun::star::uno::RuntimeException) = 0;
        virtual ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet(  ) throw (::com::sun::star::uno::RuntimeException) = 0;
        virtual ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet(  ) throw (::com::sun::star::uno::RuntimeException) = 0;

        // XAccessibleContext - default implementations
        /** default implementation for retrieving the index of this object within the parent

This basic implementation here returns the index i of the child for which
                <parent>.getAccessibleChild( i ) equals our creator.

        */
        virtual sal_Int32 SAL_CALL getAccessibleIndexInParent(  ) throw (::com::sun::star::uno::RuntimeException);
        /** default implementation for retrieving the locale

This basic implementation returns the locale of the parent context,
            as retrieved via getAccessibleParent()->getAccessibleContext.

        */
        virtual ::com::sun::star::lang::Locale SAL_CALL getLocale(  ) throw (::drafts::com::sun::star::accessibility::IllegalAccessibleComponentStateException, ::com::sun::star::uno::RuntimeException);

    public:
        // helper struct for granting selective access rights
        struct OAccessControl { friend class OContextEntryGuard; };

        // ensures that the object is alive
        inline  void            ensureAlive( const OAccessControl& _rAccessControl ) const SAL_THROW( ( ::com::sun::star::lang::DisposedException ) );
        inline  ::osl::Mutex&   GetMutex( const OAccessControl& _rAccessControl );

    protected:
        // OComponentHelper
        virtual void SAL_CALL disposing();

    protected:
        // helper
        /** notifies all AccessibleEventListeners of a certain event

        @precond    not too be called with our mutex locked
        @param  _nEventId
            the id of the even. See AccessibleEventType
        @param  _rOldValue
            the old value to be notified
        @param  _rNewValue
            the new value to be notified
        */
        void SAL_CALL   NotifyAccessibleEvent(
                    const sal_Int16 _nEventId,
                    const ::com::sun::star::uno::Any& _rOldValue,
                    const ::com::sun::star::uno::Any& _rNewValue
                );

        // life time control
        /// checks whether the object is alive (returns <TRUE/> then) or disposed
        sal_Bool    isAlive() const;
        /// checks for beeing alive. If the object is already disposed (i.e. not alive), an exception is thrown.
        void        ensureAlive() const SAL_THROW( ( ::com::sun::star::lang::DisposedException ) );

        /** ensures that the object is disposed.
        @precond
            to be called from within the destructor of your derived class only!
        */
        void        ensureDisposed( );

        /** shortcut for retrieving the context of the parent (returned by getAccessibleParent)
        */
        ::com::sun::star::uno::Reference< ::drafts::com::sun::star::accessibility::XAccessibleContext >
                    implGetParentContext() SAL_THROW( ( ::com::sun::star::uno::RuntimeException ) );

        // access to the base class' broadcast helper/mutex
        ::cppu::OBroadcastHelper&       GetBroadcastHelper()        { return rBHelper; }
        const ::cppu::OBroadcastHelper& GetBroadcastHelper() const  { return rBHelper; }
        ::osl::Mutex&                   GetMutex()                  { return m_aMutex; }
    };

    //---------------------------------------------------------------------
    inline  void OAccessibleContextHelper::ensureAlive( const OAccessControl& _rAccessControl ) const SAL_THROW( ( ::com::sun::star::lang::DisposedException ) )
    {
        ensureAlive();
    }

    //---------------------------------------------------------------------
    inline  ::osl::Mutex& OAccessibleContextHelper::GetMutex( const OAccessControl& _rAccessControl )
    {
        return GetMutex();
    }

    //=====================================================================
    //= OContextEntryGuard
    //=====================================================================
    typedef ::osl::ClearableMutexGuard  OContextEntryGuard_Base;
    /** helper class for guarding the entry into OAccessibleContextHelper methods.

The class has two responsibilities:

it locks the mutex of an OAccessibleContextHelper instance, as long as the guard lives

it checks if an given OAccessibleContextHelper instance is alive, else an exception is thrown
                our of the constructor of the guard

        This makes it your first choice (hopefully :) for guarding any interface method implementations of
        you derived class.

    */
    class OContextEntryGuard : public OContextEntryGuard_Base
    {
    public:
        /** constructs the guard

The given context (it's mutex, respectively) is locked, and an exception is thrown if the context
            is not alive anymore. In the latter case, of course, the mutex is freed, again.

        @param _pContext
            the context which shall be guarded
        @precond <arg>_pContext</arg> != NULL
        */
        inline OContextEntryGuard( OAccessibleContextHelper* _pContext );

        /** destructs the guard.

The context (it's mutex, respectively) is unlocked.

        */
        inline ~OContextEntryGuard();
    };

    //.....................................................................
    inline OContextEntryGuard::OContextEntryGuard( OAccessibleContextHelper* _pContext  )
        :OContextEntryGuard_Base( _pContext->GetMutex( OAccessibleContextHelper::OAccessControl() ) )
    {
        _pContext->ensureAlive( OAccessibleContextHelper::OAccessControl() );
    }

    //.....................................................................
    inline OContextEntryGuard::~OContextEntryGuard()
    {
    }

//.........................................................................
}   // namespace comphelper
//.........................................................................

#endif // COMPHELPER_ACCESSIBLE_CONTEXT_HELPER_HXX

/*************************************************************************
 * history:
 *  $Log: not supported by cvs2svn $
 *  Revision 1.2  2002/04/26 05:51:23  fs
 *  #98750# use correct broadcasthelper (in the WeagAggComponentImpl* base)
 *
 *  Revision 1.1  2002/04/23 11:07:38  fs
 *  initial checkin - helper for implementing an XAccessibleContext
 *
 *
 *  Revision 1.0 17.04.2002 15:47:54  fs
 ************************************************************************/

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: propertystatecontainer.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: hr $ $Date: 2004-08-02 17:52:11 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef COMPHELPER_PROPERTYSTATECONTAINER_HXX
#include "comphelper/propertystatecontainer.hxx"
#endif
#ifndef _RTL_USTRBUF_HXX_
#include <rtl/ustrbuf.hxx>
#endif

//.........................................................................
namespace comphelper
{
//.........................................................................

    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::beans;
    using namespace ::com::sun::star::lang;

    namespace
    {
        static ::rtl::OUString lcl_getUnknownPropertyErrorMessage( const ::rtl::OUString& _rPropertyName )
        {
            // TODO: perhaps it's time to think about resources in the comphelper module?
            // Would be nice to have localized exception strings (a simply resource file containing
            // strings only would suffice, and could be realized with an UNO service, so we do not
            // need the dependency to the Tools project)
            ::rtl::OUStringBuffer sMessage;
            sMessage.appendAscii( "The property \"" );
            sMessage.append( _rPropertyName );
            sMessage.appendAscii( "\" is unknown." );
            return sMessage.makeStringAndClear();
        }
    }

    //=====================================================================
    //= OPropertyStateContainer
    //=====================================================================
    //---------------------------------------------------------------------
    OPropertyStateContainer::OPropertyStateContainer( ::cppu::OBroadcastHelper& _rBHelper )
        :OPropertyContainer( _rBHelper )
    {
    }

    //--------------------------------------------------------------------
    Any SAL_CALL OPropertyStateContainer::queryInterface( const Type& _rType ) throw (RuntimeException)
    {
        Any aReturn = OPropertyContainer::queryInterface( _rType );
        if ( !aReturn.hasValue() )
            aReturn = OPropertyStateContainer_TBase::queryInterface( _rType );
        return aReturn;
    }

    //--------------------------------------------------------------------
    IMPLEMENT_FORWARD_XTYPEPROVIDER2( OPropertyStateContainer, OPropertyContainer, OPropertyStateContainer_TBase )

    //--------------------------------------------------------------------
    sal_Int32 OPropertyStateContainer::getHandleForName( const ::rtl::OUString& _rPropertyName ) SAL_THROW( ( UnknownPropertyException ) )
    {
        // look up the handle for the name
        ::cppu::IPropertyArrayHelper& rPH = getInfoHelper();
        sal_Int32 nHandle = rPH.getHandleByName( _rPropertyName );

        if ( -1 == nHandle )
            throw  UnknownPropertyException( lcl_getUnknownPropertyErrorMessage( _rPropertyName ), static_cast< XPropertyState* >( this ) );

        return nHandle;
    }

    //--------------------------------------------------------------------
    PropertyState SAL_CALL OPropertyStateContainer::getPropertyState( const ::rtl::OUString& _rPropertyName ) throw (UnknownPropertyException, RuntimeException)
    {
        return getPropertyStateByHandle( getHandleForName( _rPropertyName ) );
    }

    //--------------------------------------------------------------------
    Sequence< PropertyState > SAL_CALL OPropertyStateContainer::getPropertyStates( const Sequence< ::rtl::OUString >& _rPropertyNames ) throw (UnknownPropertyException, RuntimeException)
    {
        sal_Int32 nProperties = _rPropertyNames.getLength();
        Sequence< PropertyState> aStates( nProperties );
        if ( !nProperties )
            return aStates;

#ifdef _DEBUG
        // precondition: property sequence is sorted (the algorythm below relies on this)
        {
            const ::rtl::OUString* pNames = _rPropertyNames.getConstArray();
            const ::rtl::OUString* pNamesCompare = pNames + 1;
            const ::rtl::OUString* pNamesEnd = _rPropertyNames.getConstArray() + _rPropertyNames.getLength();
            for ( ; pNamesCompare != pNamesEnd; ++pNames, ++pNamesCompare )
                OSL_PRECOND( pNames->compareTo( *pNamesCompare ) < 0,
                    "OPropertyStateContainer::getPropertyStates: property sequence not sorted!" );
        }
#endif

        const ::rtl::OUString* pLookup = _rPropertyNames.getConstArray();
        const ::rtl::OUString* pLookupEnd = pLookup + nProperties;
        PropertyState* pStates = aStates.getArray();

        cppu::IPropertyArrayHelper& rHelper = getInfoHelper();
        Sequence< Property> aAllProperties  = rHelper.getProperties();
        sal_Int32 nAllProperties            = aAllProperties.getLength();
        const  Property* pAllProperties     = aAllProperties.getConstArray();
        const  Property* pAllPropertiesEnd  = pAllProperties + nAllProperties;

        osl::MutexGuard aGuard( rBHelper.rMutex );
        for ( ; ( pAllProperties != pAllPropertiesEnd ) && ( pLookup != pLookupEnd ); ++pAllProperties )
        {
#ifdef _DEBUG
            if ( pAllProperties < pAllPropertiesEnd - 1 )
                OSL_ENSURE( pAllProperties->Name.compareTo( (pAllProperties + 1)->Name ) < 0,
                    "OPropertyStateContainer::getPropertyStates: all-properties not sorted!" );
#endif
            if ( pAllProperties->Name.equals( *pLookup ) )
            {
                *pStates++ = getPropertyState( *pLookup );
                ++pLookup;
            }
        }

        if ( pLookup != pLookupEnd )
            // we run out of properties from the IPropertyArrayHelper, but still have properties to lookup
            // -> we were asked for a nonexistent property
            throw UnknownPropertyException( lcl_getUnknownPropertyErrorMessage( *pLookup ), static_cast< XPropertyState* >( this ) );

        return aStates;
    }

    //--------------------------------------------------------------------
    void SAL_CALL OPropertyStateContainer::setPropertyToDefault( const ::rtl::OUString& _rPropertyName ) throw (UnknownPropertyException, RuntimeException)
    {
        setPropertyToDefaultByHandle( getHandleForName( _rPropertyName ) );
    }

    //--------------------------------------------------------------------
    Any SAL_CALL OPropertyStateContainer::getPropertyDefault( const ::rtl::OUString& _rPropertyName ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
    {
        return getPropertyDefaultByHandle( getHandleForName( _rPropertyName ) );
    }

    //--------------------------------------------------------------------
    PropertyState OPropertyStateContainer::getPropertyStateByHandle( sal_Int32 _nHandle )
    {
        // simply compare the current and the default value
        Any aCurrentValue; getFastPropertyValue( aCurrentValue, _nHandle );
        Any aDefaultValue = getPropertyDefaultByHandle( _nHandle );

        sal_Bool bEqual = uno_type_equalData(
                const_cast< void* >( aCurrentValue.getValue() ), aCurrentValue.getValueType().getTypeLibType(),
                const_cast< void* >( aDefaultValue.getValue() ), aDefaultValue.getValueType().getTypeLibType(),
                cpp_queryInterface, cpp_release
            );
        if ( bEqual )
            return PropertyState_DEFAULT_VALUE;
        else
            return PropertyState_DIRECT_VALUE;
    }

    //--------------------------------------------------------------------
    void OPropertyStateContainer::setPropertyToDefaultByHandle( sal_Int32 _nHandle )
    {
        setFastPropertyValue( _nHandle, getPropertyDefaultByHandle( _nHandle ) );
    }

//.........................................................................
}   // namespace comphelper
//.........................................................................

#ifdef FS_PRIV_DEBUG
#define STATECONTAINER_TEST
#endif

#ifdef STATECONTAINER_TEST

#ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBUTE_HPP_
#include <com/sun/star/beans/PropertyAttribute.hpp>
#endif
#ifndef _COMPHELPER_PROPERTY_ARRAY_HELPER_HXX_
#include <comphelper/proparrhlp.hxx>
#endif
#ifndef _COMPHELPER_BROADCASTHELPER_HXX_
#include <comphelper/broadcasthelper.hxx>
#endif

//.........................................................................
namespace comphelper
{
//.........................................................................

    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::beans;

    //=====================================================================
    //= Test - compiler test
    //=====================================================================
    typedef ::cppu::OWeakAggObject  Test_RefCountBase;
    class Test  :public OMutexAndBroadcastHelper
                ,public OPropertyStateContainer
                ,public OPropertyArrayUsageHelper< Test >
                ,public Test_RefCountBase
    {
    private:
        ::rtl::OUString         m_sStringProperty;
        Reference< XInterface > m_xInterfaceProperty;
        Any                     m_aMayBeVoidProperty;

    protected:
        Test( );

        DECLARE_XINTERFACE( )

    public:
        static Test* Create( );

    protected:
        virtual Reference< XPropertySetInfo > SAL_CALL getPropertySetInfo(  ) throw(RuntimeException);
        virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper();
        virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const;

    protected:
        // OPropertyStateContainer overridables
        virtual Any getPropertyDefaultByHandle( sal_Int32 _nHandle ) const;
    };

    //---------------------------------------------------------------------
    Test::Test( )
        :OPropertyStateContainer( GetBroadcastHelper() )
    {
        registerProperty(
            ::rtl::OUString::createFromAscii( "StringProperty" ),
            1,
            PropertyAttribute::BOUND,
            &m_sStringProperty,
            ::getCppuType( &m_sStringProperty )
        );

        registerProperty(
            ::rtl::OUString::createFromAscii( "InterfaceProperty" ),
            2,
            PropertyAttribute::BOUND,
            &m_xInterfaceProperty,
            ::getCppuType( &m_xInterfaceProperty )
        );

        registerMayBeVoidProperty(
            ::rtl::OUString::createFromAscii( "IntProperty" ),
            3,
            PropertyAttribute::BOUND,
            &m_aMayBeVoidProperty,
            ::getCppuType( static_cast< sal_Int32* >( NULL ) )
        );

        registerPropertyNoMember(
            ::rtl::OUString::createFromAscii( "OtherInterfaceProperty" ),
            4,
            PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID,
            ::getCppuType( static_cast< Reference< XInterface >* >( NULL ) ),
            NULL
        );
    }

    //---------------------------------------------------------------------
    IMPLEMENT_FORWARD_XINTERFACE2( Test, Test_RefCountBase, OPropertyStateContainer )

    //---------------------------------------------------------------------
    Any Test::getPropertyDefaultByHandle( sal_Int32 _nHandle ) const
    {
        Any aDefault;
        switch ( _nHandle )
        {
            case 1:
                aDefault = makeAny( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StringPropertyDefault" ) ) );
                break;
            case 2:
                aDefault = makeAny( Reference< XInterface >( ) );
                break;
            case 3:
                // void
                break;
            case 4:
                aDefault = makeAny( Reference< XInterface >( ) );
                break;
            default:
                OSL_ENSURE( sal_False, "Test::getPropertyDefaultByHandle: invalid handle!" );
        }
        return aDefault;
    }

    //---------------------------------------------------------------------
    Reference< XPropertySetInfo > SAL_CALL Test::getPropertySetInfo(  ) throw(RuntimeException)
    {
        return createPropertySetInfo( getInfoHelper() );
    }

    //---------------------------------------------------------------------
    ::cppu::IPropertyArrayHelper& SAL_CALL Test::getInfoHelper()
    {
        return *getArrayHelper();
    }

    //---------------------------------------------------------------------
    ::cppu::IPropertyArrayHelper* Test::createArrayHelper( ) const
    {
        Sequence< Property > aProps;
        describeProperties( aProps );
        return new ::cppu::OPropertyArrayHelper( aProps );
    }

    //---------------------------------------------------------------------
    Test* Test::Create( )
    {
        Test* pInstance = new Test;
        return pInstance;
    }

//.........................................................................
}   // namespace comphelper
//.........................................................................

#endif

<commit_msg>INTEGRATION: CWS ooo19126 (1.2.122); FILE MERGED 2005/09/05 15:24:10 rt 1.2.122.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: propertystatecontainer.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 02:59:05 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef COMPHELPER_PROPERTYSTATECONTAINER_HXX
#include "comphelper/propertystatecontainer.hxx"
#endif
#ifndef _RTL_USTRBUF_HXX_
#include <rtl/ustrbuf.hxx>
#endif

//.........................................................................
namespace comphelper
{
//.........................................................................

    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::beans;
    using namespace ::com::sun::star::lang;

    namespace
    {
        static ::rtl::OUString lcl_getUnknownPropertyErrorMessage( const ::rtl::OUString& _rPropertyName )
        {
            // TODO: perhaps it's time to think about resources in the comphelper module?
            // Would be nice to have localized exception strings (a simply resource file containing
            // strings only would suffice, and could be realized with an UNO service, so we do not
            // need the dependency to the Tools project)
            ::rtl::OUStringBuffer sMessage;
            sMessage.appendAscii( "The property \"" );
            sMessage.append( _rPropertyName );
            sMessage.appendAscii( "\" is unknown." );
            return sMessage.makeStringAndClear();
        }
    }

    //=====================================================================
    //= OPropertyStateContainer
    //=====================================================================
    //---------------------------------------------------------------------
    OPropertyStateContainer::OPropertyStateContainer( ::cppu::OBroadcastHelper& _rBHelper )
        :OPropertyContainer( _rBHelper )
    {
    }

    //--------------------------------------------------------------------
    Any SAL_CALL OPropertyStateContainer::queryInterface( const Type& _rType ) throw (RuntimeException)
    {
        Any aReturn = OPropertyContainer::queryInterface( _rType );
        if ( !aReturn.hasValue() )
            aReturn = OPropertyStateContainer_TBase::queryInterface( _rType );
        return aReturn;
    }

    //--------------------------------------------------------------------
    IMPLEMENT_FORWARD_XTYPEPROVIDER2( OPropertyStateContainer, OPropertyContainer, OPropertyStateContainer_TBase )

    //--------------------------------------------------------------------
    sal_Int32 OPropertyStateContainer::getHandleForName( const ::rtl::OUString& _rPropertyName ) SAL_THROW( ( UnknownPropertyException ) )
    {
        // look up the handle for the name
        ::cppu::IPropertyArrayHelper& rPH = getInfoHelper();
        sal_Int32 nHandle = rPH.getHandleByName( _rPropertyName );

        if ( -1 == nHandle )
            throw  UnknownPropertyException( lcl_getUnknownPropertyErrorMessage( _rPropertyName ), static_cast< XPropertyState* >( this ) );

        return nHandle;
    }

    //--------------------------------------------------------------------
    PropertyState SAL_CALL OPropertyStateContainer::getPropertyState( const ::rtl::OUString& _rPropertyName ) throw (UnknownPropertyException, RuntimeException)
    {
        return getPropertyStateByHandle( getHandleForName( _rPropertyName ) );
    }

    //--------------------------------------------------------------------
    Sequence< PropertyState > SAL_CALL OPropertyStateContainer::getPropertyStates( const Sequence< ::rtl::OUString >& _rPropertyNames ) throw (UnknownPropertyException, RuntimeException)
    {
        sal_Int32 nProperties = _rPropertyNames.getLength();
        Sequence< PropertyState> aStates( nProperties );
        if ( !nProperties )
            return aStates;

#ifdef _DEBUG
        // precondition: property sequence is sorted (the algorythm below relies on this)
        {
            const ::rtl::OUString* pNames = _rPropertyNames.getConstArray();
            const ::rtl::OUString* pNamesCompare = pNames + 1;
            const ::rtl::OUString* pNamesEnd = _rPropertyNames.getConstArray() + _rPropertyNames.getLength();
            for ( ; pNamesCompare != pNamesEnd; ++pNames, ++pNamesCompare )
                OSL_PRECOND( pNames->compareTo( *pNamesCompare ) < 0,
                    "OPropertyStateContainer::getPropertyStates: property sequence not sorted!" );
        }
#endif

        const ::rtl::OUString* pLookup = _rPropertyNames.getConstArray();
        const ::rtl::OUString* pLookupEnd = pLookup + nProperties;
        PropertyState* pStates = aStates.getArray();

        cppu::IPropertyArrayHelper& rHelper = getInfoHelper();
        Sequence< Property> aAllProperties  = rHelper.getProperties();
        sal_Int32 nAllProperties            = aAllProperties.getLength();
        const  Property* pAllProperties     = aAllProperties.getConstArray();
        const  Property* pAllPropertiesEnd  = pAllProperties + nAllProperties;

        osl::MutexGuard aGuard( rBHelper.rMutex );
        for ( ; ( pAllProperties != pAllPropertiesEnd ) && ( pLookup != pLookupEnd ); ++pAllProperties )
        {
#ifdef _DEBUG
            if ( pAllProperties < pAllPropertiesEnd - 1 )
                OSL_ENSURE( pAllProperties->Name.compareTo( (pAllProperties + 1)->Name ) < 0,
                    "OPropertyStateContainer::getPropertyStates: all-properties not sorted!" );
#endif
            if ( pAllProperties->Name.equals( *pLookup ) )
            {
                *pStates++ = getPropertyState( *pLookup );
                ++pLookup;
            }
        }

        if ( pLookup != pLookupEnd )
            // we run out of properties from the IPropertyArrayHelper, but still have properties to lookup
            // -> we were asked for a nonexistent property
            throw UnknownPropertyException( lcl_getUnknownPropertyErrorMessage( *pLookup ), static_cast< XPropertyState* >( this ) );

        return aStates;
    }

    //--------------------------------------------------------------------
    void SAL_CALL OPropertyStateContainer::setPropertyToDefault( const ::rtl::OUString& _rPropertyName ) throw (UnknownPropertyException, RuntimeException)
    {
        setPropertyToDefaultByHandle( getHandleForName( _rPropertyName ) );
    }

    //--------------------------------------------------------------------
    Any SAL_CALL OPropertyStateContainer::getPropertyDefault( const ::rtl::OUString& _rPropertyName ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
    {
        return getPropertyDefaultByHandle( getHandleForName( _rPropertyName ) );
    }

    //--------------------------------------------------------------------
    PropertyState OPropertyStateContainer::getPropertyStateByHandle( sal_Int32 _nHandle )
    {
        // simply compare the current and the default value
        Any aCurrentValue; getFastPropertyValue( aCurrentValue, _nHandle );
        Any aDefaultValue = getPropertyDefaultByHandle( _nHandle );

        sal_Bool bEqual = uno_type_equalData(
                const_cast< void* >( aCurrentValue.getValue() ), aCurrentValue.getValueType().getTypeLibType(),
                const_cast< void* >( aDefaultValue.getValue() ), aDefaultValue.getValueType().getTypeLibType(),
                cpp_queryInterface, cpp_release
            );
        if ( bEqual )
            return PropertyState_DEFAULT_VALUE;
        else
            return PropertyState_DIRECT_VALUE;
    }

    //--------------------------------------------------------------------
    void OPropertyStateContainer::setPropertyToDefaultByHandle( sal_Int32 _nHandle )
    {
        setFastPropertyValue( _nHandle, getPropertyDefaultByHandle( _nHandle ) );
    }

//.........................................................................
}   // namespace comphelper
//.........................................................................

#ifdef FS_PRIV_DEBUG
#define STATECONTAINER_TEST
#endif

#ifdef STATECONTAINER_TEST

#ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBUTE_HPP_
#include <com/sun/star/beans/PropertyAttribute.hpp>
#endif
#ifndef _COMPHELPER_PROPERTY_ARRAY_HELPER_HXX_
#include <comphelper/proparrhlp.hxx>
#endif
#ifndef _COMPHELPER_BROADCASTHELPER_HXX_
#include <comphelper/broadcasthelper.hxx>
#endif

//.........................................................................
namespace comphelper
{
//.........................................................................

    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::beans;

    //=====================================================================
    //= Test - compiler test
    //=====================================================================
    typedef ::cppu::OWeakAggObject  Test_RefCountBase;
    class Test  :public OMutexAndBroadcastHelper
                ,public OPropertyStateContainer
                ,public OPropertyArrayUsageHelper< Test >
                ,public Test_RefCountBase
    {
    private:
        ::rtl::OUString         m_sStringProperty;
        Reference< XInterface > m_xInterfaceProperty;
        Any                     m_aMayBeVoidProperty;

    protected:
        Test( );

        DECLARE_XINTERFACE( )

    public:
        static Test* Create( );

    protected:
        virtual Reference< XPropertySetInfo > SAL_CALL getPropertySetInfo(  ) throw(RuntimeException);
        virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper();
        virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const;

    protected:
        // OPropertyStateContainer overridables
        virtual Any getPropertyDefaultByHandle( sal_Int32 _nHandle ) const;
    };

    //---------------------------------------------------------------------
    Test::Test( )
        :OPropertyStateContainer( GetBroadcastHelper() )
    {
        registerProperty(
            ::rtl::OUString::createFromAscii( "StringProperty" ),
            1,
            PropertyAttribute::BOUND,
            &m_sStringProperty,
            ::getCppuType( &m_sStringProperty )
        );

        registerProperty(
            ::rtl::OUString::createFromAscii( "InterfaceProperty" ),
            2,
            PropertyAttribute::BOUND,
            &m_xInterfaceProperty,
            ::getCppuType( &m_xInterfaceProperty )
        );

        registerMayBeVoidProperty(
            ::rtl::OUString::createFromAscii( "IntProperty" ),
            3,
            PropertyAttribute::BOUND,
            &m_aMayBeVoidProperty,
            ::getCppuType( static_cast< sal_Int32* >( NULL ) )
        );

        registerPropertyNoMember(
            ::rtl::OUString::createFromAscii( "OtherInterfaceProperty" ),
            4,
            PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID,
            ::getCppuType( static_cast< Reference< XInterface >* >( NULL ) ),
            NULL
        );
    }

    //---------------------------------------------------------------------
    IMPLEMENT_FORWARD_XINTERFACE2( Test, Test_RefCountBase, OPropertyStateContainer )

    //---------------------------------------------------------------------
    Any Test::getPropertyDefaultByHandle( sal_Int32 _nHandle ) const
    {
        Any aDefault;
        switch ( _nHandle )
        {
            case 1:
                aDefault = makeAny( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StringPropertyDefault" ) ) );
                break;
            case 2:
                aDefault = makeAny( Reference< XInterface >( ) );
                break;
            case 3:
                // void
                break;
            case 4:
                aDefault = makeAny( Reference< XInterface >( ) );
                break;
            default:
                OSL_ENSURE( sal_False, "Test::getPropertyDefaultByHandle: invalid handle!" );
        }
        return aDefault;
    }

    //---------------------------------------------------------------------
    Reference< XPropertySetInfo > SAL_CALL Test::getPropertySetInfo(  ) throw(RuntimeException)
    {
        return createPropertySetInfo( getInfoHelper() );
    }

    //---------------------------------------------------------------------
    ::cppu::IPropertyArrayHelper& SAL_CALL Test::getInfoHelper()
    {
        return *getArrayHelper();
    }

    //---------------------------------------------------------------------
    ::cppu::IPropertyArrayHelper* Test::createArrayHelper( ) const
    {
        Sequence< Property > aProps;
        describeProperties( aProps );
        return new ::cppu::OPropertyArrayHelper( aProps );
    }

    //---------------------------------------------------------------------
    Test* Test::Create( )
    {
        Test* pInstance = new Test;
        return pInstance;
    }

//.........................................................................
}   // namespace comphelper
//.........................................................................

#endif

<|endoftext|>


<commit_before>#include "monitoring.h"

#include <sstream>
#include <chrono>
#include <vector>
#include <unordered_map>

#include <boost/archive/text_iarchive.hpp>
#include <zmq.hpp>

int main() {
  zmq::context_t context{1};
  zmq::socket_t sub{context, ZMQ_SUB};
  sub.bind("tcp://*:31338");
  sub.setsockopt(ZMQ_SUBSCRIBE, "", 0);

  std::unordered_map<Monitoring::HistId, Monitoring::Histogram> histograms;

  auto start = std::chrono::high_resolution_clock::now();

  int interval{10};

  while (true) {
    // Receive message
    zmq::message_t in_msg;
    sub.recv(&in_msg);

    // Deserialize
    std::stringstream ss{static_cast<char*>(in_msg.data())};
    boost::archive::text_iarchive ia{ss};
    Monitoring::Chunk c;
    ia >> c;
    std::cout << " received " << c << std::endl;

    // Add to internal store
    if (!histograms.count(c.histId)) {
      histograms[c.histId] =
          Monitoring::Histogram{c.runNumber, c.tck, c.histId};
    }
    histograms[c.histId].addChunk(c);

    // If not displayed for interval seconds, show all current histograms
    auto now = std::chrono::high_resolution_clock::now();
    if (std::chrono::duration_cast<std::chrono::seconds>(now - start).count() >
        interval) {
      for (const auto& h : histograms) {
        std::cout << h.second << std::endl;
      }
    }
  }
}
<commit_msg>Change `start` after histograms have been printed.<commit_after>#include "monitoring.h"

#include <sstream>
#include <chrono>
#include <vector>
#include <unordered_map>

#include <boost/archive/text_iarchive.hpp>
#include <zmq.hpp>

int main() {
  zmq::context_t context{1};
  zmq::socket_t sub{context, ZMQ_SUB};
  sub.bind("tcp://*:31338");
  sub.setsockopt(ZMQ_SUBSCRIBE, "", 0);

  std::unordered_map<Monitoring::HistId, Monitoring::Histogram> histograms;

  auto start = std::chrono::high_resolution_clock::now();

  int interval{10};

  while (true) {
    // Receive message
    zmq::message_t in_msg;
    sub.recv(&in_msg);

    // Deserialize
    std::stringstream ss{static_cast<char*>(in_msg.data())};
    boost::archive::text_iarchive ia{ss};
    Monitoring::Chunk c;
    ia >> c;
    std::cout << " received " << c << std::endl;

    // Add to internal store
    if (!histograms.count(c.histId)) {
      histograms[c.histId] =
          Monitoring::Histogram{c.runNumber, c.tck, c.histId};
    }
    histograms[c.histId].addChunk(c);

    // If not displayed for interval seconds, show all current histograms
    auto now = std::chrono::high_resolution_clock::now();
    if (std::chrono::duration_cast<std::chrono::seconds>(now - start).count() >
        interval) {
      for (const auto& h : histograms) {
        std::cout << h.second << std::endl;
      }
      start = now;
    }
  }
}
<|endoftext|>


<commit_before>#include "photoeffects.hpp"
#include <math.h>

using namespace cv;

#define MAX_KERNELSIZE 15

int edgeBlur(InputArray src, OutputArray dst, int indentTop, int indentLeft)
{
    CV_Assert(src.type() == CV_8UC3);
    Mat image = src.getMat(), outputImage(image.size(), CV_8UC3);

    CV_Assert(indentTop >= 0 && indentTop <= (image.rows / 2 - 10));
    CV_Assert(indentLeft >= 0 && indentLeft <= (image.cols / 2 - 10));

    float halfWidth = (image.cols / 2.0f) * (image.cols / 2.0f);
    float halfHeight = (image.rows / 2.0f) * (image.rows / 2.0f);
    float a = (image.cols / 2.0f - indentLeft)
            * (image.cols / 2.0f - indentLeft);
    float b = (image.rows / 2.0f - indentTop)
            * (image.rows / 2.0f - indentTop);
    int kSizeEdges = halfWidth / a + halfHeight / b;

    if (kSizeEdges > MAX_KERNELSIZE)
    {
        kSizeEdges = MAX_KERNELSIZE;
    }
    Mat bearingImage(image.rows + 2 * kSizeEdges,
                    image.cols + 2 * kSizeEdges,
                    CV_8UC3);
    copyMakeBorder(image, bearingImage, kSizeEdges, kSizeEdges,
        kSizeEdges, kSizeEdges, BORDER_REPLICATE);

    int size, maxI = bearingImage.rows - kSizeEdges,
    maxJ = bearingImage.cols - kSizeEdges;
    Vec3f sumF;
    Vec3b Color;
    float radius, sumC, coeff;
    float bearHalfWidth = bearingImage.cols / 2.0f;
    float bearHalfHeight = bearingImage.rows / 2.0f;

    for (int i = kSizeEdges; i < maxI; i++)
    {
        for (int j = kSizeEdges; j < maxJ; j++)
        {
            radius = (bearHalfHeight - i)
                    * (bearHalfHeight - i)
                    / b

                    + (bearHalfWidth - j)
                    * (bearHalfWidth - j)
                    / a;
            if (radius < 1.0f)
            {
                outputImage.at<Vec3b>(i - kSizeEdges, j - kSizeEdges) =
                    bearingImage.at<Vec3b>(i, j);
                continue;
            }
            sumF[0] = 0.0f;
            sumF[1] = 0.0f;
            sumF[2] = 0.0f;
            sumC = 0.0f;
            size = radius;
            radius -= 0.5f;
            radius *= 2.0f * radius;
            if (size > kSizeEdges)
            {
                size = kSizeEdges;
            }
            for (int x = -size; x <= size; x++)
            {
                for (int y = -size; y <= size; y++)
                {
                    coeff = 1.0f / (CV_PI * radius)
                            * exp(- (x * x + y * y) / radius);

                    Color = bearingImage.at<Vec3b>(x + i, y + j);
                    sumF = sumF + (Vec3f) (coeff * Color);
                    sumC += coeff;
                }
            }
            sumF = sumF * (1.0f / sumC);
            outputImage.at<Vec3b>(i - kSizeEdges, j - kSizeEdges) = sumF;
        }
    }

    outputImage.convertTo(dst, CV_8UC3);
    return 0;
}
<commit_msg>Correct the mistakes<commit_after>#include "photoeffects.hpp"
#include <math.h>

using namespace cv;

#define MAX_KERNELSIZE 15

int edgeBlur(InputArray src, OutputArray dst, int indentTop, int indentLeft)
{
    CV_Assert(src.type() == CV_8UC3);
    dst.create(src.size(), src.type());
    Mat image = src.getMat(), outputImage = dst.getMat();

    CV_Assert(indentTop >= 0 && indentTop <= (image.rows / 2 - 10));
    CV_Assert(indentLeft >= 0 && indentLeft <= (image.cols / 2 - 10));

    float halfWidth = (image.cols / 2.0f) * (image.cols / 2.0f);
    float halfHeight = (image.rows / 2.0f) * (image.rows / 2.0f);
    float a = (image.cols / 2.0f - indentLeft)
            * (image.cols / 2.0f - indentLeft);
    float b = (image.rows / 2.0f - indentTop)
            * (image.rows / 2.0f - indentTop);
    int kSizeEdges = halfWidth / a + halfHeight / b;

    kSizeEdges = MIN(kSizeEdges, MAX_KERNELSIZE);
    Mat bearingImage(image.rows + 2 * kSizeEdges,
                    image.cols + 2 * kSizeEdges,
                    CV_8UC3);
    copyMakeBorder(image, bearingImage, kSizeEdges, kSizeEdges,
        kSizeEdges, kSizeEdges, BORDER_REPLICATE);

    for (int i = kSizeEdges; i < bearingImage.rows - kSizeEdges; i++)
    {
        for (int j = kSizeEdges; j < bearingImage.cols - kSizeEdges; j++)
        {
            int size;
            Vec3f sumF;
            Vec3b Color;
            float sumC = 0.0f, coeff;
            float bearHalfWidth = bearingImage.cols / 2.0f;
            float bearHalfHeight = bearingImage.rows / 2.0f;
            float radius = (bearHalfHeight - i)
                    * (bearHalfHeight - i)
                    / b

                    + (bearHalfWidth - j)
                    * (bearHalfWidth - j)
                    / a;
            if (radius < 1.0f)
            {
                outputImage.at<Vec3b>(i - kSizeEdges, j - kSizeEdges) =
                    bearingImage.at<Vec3b>(i, j);
                continue;
            }
            size = radius;
            radius = 2.0f * (radius - 0.5f) * (radius - 0.5f);
            size = MIN(size, kSizeEdges);
            for (int x = -size; x <= size; x++)
            {
                for (int y = -size; y <= size; y++)
                {
                    coeff = 1.0f / (CV_PI * radius)
                            * exp(- (x * x + y * y) / radius);

                    Color = bearingImage.at<Vec3b>(x + i, y + j);
                    sumF += (Vec3f) (coeff * Color);
                    sumC += coeff;
                }
            }
            sumF *= (1.0f / sumC);
            outputImage.at<Vec3b>(i - kSizeEdges, j - kSizeEdges) = sumF;
        }
    }

    return 0;
}
<|endoftext|>


<commit_before>#include <QString>

#include "kernel.h"
#include "geometries.h"
#include "ilwisdata.h"
#include "coordinatesystem.h"
#include "georeference.h"
#include "georefimplementation.h"
#include "simpelgeoreference.h"

using namespace Ilwis;

SimpelGeoReference::SimpelGeoReference(const QString& type) : GeoRefImplementation(type)
{
    clear();
}

SimpelGeoReference::SimpelGeoReference() : GeoRefImplementation("simpel")
{
    clear();
}

GeoRefImplementation *SimpelGeoReference::create()
{
    return new SimpelGeoReference();
}

void SimpelGeoReference::clear() {
    _a11 = _a12 = _a22 = _a21 = rUNDEF;
    _b1 = _b2 = rUNDEF;
    _det = 0;
}

Coordinate SimpelGeoReference::pixel2Coord(const Pixeld &pix) const
{
    Coordinate c((_a22 * (pix.x - _b1) - _a12 * (pix.y - _b2)) / _det,
                 (-_a21 * (pix.x - _b1) + _a11 * (pix.y - _b2)) / _det );
    return c;
}

Pixeld SimpelGeoReference::coord2Pixel(const Coordinate &crd) const
{
    double rCol = _a11 * crd.x + _a12 * crd.y + _b1; // - 1;
    double rRow = _a21 * crd.x + _a22 * crd.y + _b2; // - 1;
    Pixeld pix(rCol, rRow);

    return pix;
}

double SimpelGeoReference::pixelSize() const
{
    if ( _det == 0)
        return rUNDEF;

    return sqrt( 1/ _det);
}

std::vector<double> SimpelGeoReference::matrix() const {
    return {_a11,_a21,_a12,_a22};
}

std::vector<double> SimpelGeoReference::support() const {
    return {_b1, _b2};
}

QString SimpelGeoReference::typeName()
{
    return "simple";
}

bool SimpelGeoReference::isCompatible(const IGeoReference &georefOther) const
{

    if ( !georefOther->grfType<SimpelGeoReference>())
        return false;
    QSharedPointer<SimpelGeoReference> grfsmpl = georefOther->impl<SimpelGeoReference>();
    double delta = EPS6;
    const std::vector<double>& mat = grfsmpl->matrix();
    bool ok = std::abs(mat[0] - _a11) < delta && std::abs(mat[1] - _a21) < delta &&
            std::abs(mat[2] - _a12) < delta && delta && std::abs(mat[3] - _a22) < delta;
    if (!ok)
        return false;
    const std::vector<double>& sup = grfsmpl->support();
    ok = std::abs(sup[0] - _b1) < delta && std::abs(sup[1] - _b2) < delta;

    return ok;

}

<commit_msg>determinant could go negative so a sqrt will fail then.<commit_after>#include <QString>

#include "kernel.h"
#include "geometries.h"
#include "ilwisdata.h"
#include "coordinatesystem.h"
#include "georeference.h"
#include "georefimplementation.h"
#include "simpelgeoreference.h"

using namespace Ilwis;

SimpelGeoReference::SimpelGeoReference(const QString& type) : GeoRefImplementation(type)
{
    clear();
}

SimpelGeoReference::SimpelGeoReference() : GeoRefImplementation("simpel")
{
    clear();
}

GeoRefImplementation *SimpelGeoReference::create()
{
    return new SimpelGeoReference();
}

void SimpelGeoReference::clear() {
    _a11 = _a12 = _a22 = _a21 = rUNDEF;
    _b1 = _b2 = rUNDEF;
    _det = 0;
}

Coordinate SimpelGeoReference::pixel2Coord(const Pixeld &pix) const
{
    Coordinate c((_a22 * (pix.x - _b1) - _a12 * (pix.y - _b2)) / _det,
                 (-_a21 * (pix.x - _b1) + _a11 * (pix.y - _b2)) / _det );
    return c;
}

Pixeld SimpelGeoReference::coord2Pixel(const Coordinate &crd) const
{
    double rCol = _a11 * crd.x + _a12 * crd.y + _b1; // - 1;
    double rRow = _a21 * crd.x + _a22 * crd.y + _b2; // - 1;
    Pixeld pix(rCol, rRow);

    return pix;
}

double SimpelGeoReference::pixelSize() const
{
    if ( _det == 0)
        return rUNDEF;

    return sqrt( 1/ std::abs(_det));
}

std::vector<double> SimpelGeoReference::matrix() const {
    return {_a11,_a21,_a12,_a22};
}

std::vector<double> SimpelGeoReference::support() const {
    return {_b1, _b2};
}

QString SimpelGeoReference::typeName()
{
    return "simple";
}

bool SimpelGeoReference::isCompatible(const IGeoReference &georefOther) const
{

    if ( !georefOther->grfType<SimpelGeoReference>())
        return false;
    QSharedPointer<SimpelGeoReference> grfsmpl = georefOther->impl<SimpelGeoReference>();
    double delta = EPS6;
    const std::vector<double>& mat = grfsmpl->matrix();
    bool ok = std::abs(mat[0] - _a11) < delta && std::abs(mat[1] - _a21) < delta &&
            std::abs(mat[2] - _a12) < delta && delta && std::abs(mat[3] - _a22) < delta;
    if (!ok)
        return false;
    const std::vector<double>& sup = grfsmpl->support();
    ok = std::abs(sup[0] - _b1) < delta && std::abs(sup[1] - _b2) < delta;

    return ok;

}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Francisco Zamora-Martinez (pakozm@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <client/redef_macros.h>
#include <client/dbclient.h>
#include <client/gridfs.h>
#include <fcntl.h>
#include <fstream>
#include <utility>
#include <algorithm>
#include "mongo_cxx_extension.h"

namespace mongo_cxx_extension {

  using namespace mongo;

  using std::ios;
  using std::ofstream;
  using std::ostream;
  using std::string;
  using std::min;

  GridFileBuilder::GridFileBuilder(DBClientBase *client,
                                   const string &dbName,
                                   unsigned int chunkSize,
                                   const string& prefix) :
    _client(client), _dbName(dbName), _prefix(prefix), _chunkSize(chunkSize),
    _current_chunk(0), _pending_data(NULL), _pending_data_size(0),
    _file_length(0) {
    _chunkNS = _dbName + "." + _prefix + ".chunks";
    _filesNS = _dbName + "." + _prefix + ".files";
    OID id;
    id.init();
    _file_id = BSON("_id" << id);
    // forces to build the gridFS collections
    GridFS aux(*client, dbName, prefix);
  }

  GridFileBuilder::~GridFileBuilder() {
    delete[] _pending_data;
  }

  const char *GridFileBuilder::privateAppendChunk(const char *data,
                                                  size_t length,
                                                  bool pending_insert) {
    size_t chunk_len;
    char const * const end = data + length;
    while (data < end) {
      chunk_len = min(_chunkSize, (size_t)(end-data));
      // the last chunk needs to be stored as pending_data
      if (chunk_len < _chunkSize && !pending_insert) break;
      /* from gridfs.cpp at https://github.com/mongodb/mongo-cxx-driver/blob/legacy/src/mongo/client/gridfs.cpp */
      BSONObjBuilder b;
      b.appendAs( _file_id["_id"] , "files_id" );
      b.append( "n" , _current_chunk );
      b.appendBinData( "data" , chunk_len, BinDataGeneral, data );
      BSONObj chunk_data = b.obj();
      /************************************************************************/
      ++_current_chunk;
      _client->insert( _chunkNS.c_str(), chunk_data );
      data += chunk_len;
      _file_length += chunk_len;
    }
    return data;
  }

  void GridFileBuilder::privateAppendPendingData() {
    if (_pending_data_size > 0) {
      privateAppendChunk(_pending_data, _pending_data_size, true);
      delete[] _pending_data;
      _pending_data_size = 0;
      _pending_data = NULL;
    }
  }

  void GridFileBuilder::appendChunk(const char *data, size_t length) {
    if (length == 0) return;
    // check if there are pending data
    if (_pending_data != NULL) {
      size_t total_size = _pending_data_size + length;
      size_t size = min(_chunkSize, total_size) - _pending_data_size;
      memcpy(_pending_data + _pending_data_size, data, size*sizeof(char));
      _pending_data_size += size;
      // CHECK _pending_data_size <= _chunkSize
      if (_pending_data_size == _chunkSize) {
        privateAppendPendingData();
        appendChunk(data + size, length - size);
      }
    }
    else {
      char const * const end = data + length;
      // split data in _chunkSize blocks, and store as pending the last block if
      // necessary
      data = privateAppendChunk(data, length);
      // process pending data if necessary
      if (data != end) {
        if (_pending_data_size == 0) _pending_data = new char[_chunkSize];
        size_t size = (size_t)(end-data);
        memcpy(_pending_data+_pending_data_size, data, size*sizeof(char));
        _pending_data_size += size;
      }
    }
  }

  BSONObj GridFileBuilder::buildFile(const string &name,
                                       const string& content_type) {
    privateAppendPendingData();

    /* from gridfs.cpp at https://github.com/mongodb/mongo-cxx-driver/blob/legacy/src/mongo/client/gridfs.cpp */

    // Wait for any pending writebacks to finish
    BSONObj errObj = _client->getLastErrorDetailed();
    uassert( 16428,
             str::stream() << "Error storing GridFS chunk for file: " << name
             << ", error: " << errObj,
             DBClientWithCommands::getLastErrorString(errObj) == "" );

    BSONObj res;
    if ( ! _client->runCommand( _dbName.c_str() ,
                                BSON( "filemd5" << _file_id << "root" << _prefix ) ,
                                res ) )
      throw UserException( 9008 , "filemd5 failed" );

    BSONObjBuilder file;
    file << "_id" << _file_id["_id"]
         << "filename" << name
         << "chunkSize" << (unsigned int)_chunkSize
         << "uploadDate" << DATENOW
         << "md5" << res["md5"]
      ;

    if (_file_length < 1024*1024*1024) { // 2^30
      file << "length" << (int) _file_length;
    }
    else {
      file << "length" << (long long) _file_length;
    }

    if (!content_type.empty())
      file << "contentType" << content_type;

    BSONObj ret = file.obj();
    _client->insert(_filesNS.c_str(), ret);

    // resets the object
    _current_chunk     = 0;
    _pending_data      = NULL;
    _pending_data_size = 0;
    _file_length       = 0;
    OID id;
    id.init();
    _file_id = BSON("_id" << id);

    return ret;
  }

}
<commit_msg>Modified indentation<commit_after>/*
 * Copyright (c) 2014 Francisco Zamora-Martinez (pakozm@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <client/redef_macros.h>
#include <client/dbclient.h>
#include <client/gridfs.h>
#include <fcntl.h>
#include <fstream>
#include <utility>
#include <algorithm>
#include "mongo_cxx_extension.h"

namespace mongo_cxx_extension {

  using namespace mongo;

  using std::ios;
  using std::ofstream;
  using std::ostream;
  using std::string;
  using std::min;

  GridFileBuilder::GridFileBuilder(DBClientBase *client,
                                   const string &dbName,
                                   unsigned int chunkSize,
                                   const string& prefix) :
    _client(client), _dbName(dbName), _prefix(prefix), _chunkSize(chunkSize),
    _current_chunk(0), _pending_data(NULL), _pending_data_size(0),
    _file_length(0) {
    _chunkNS = _dbName + "." + _prefix + ".chunks";
    _filesNS = _dbName + "." + _prefix + ".files";
    OID id;
    id.init();
    _file_id = BSON("_id" << id);
    // forces to build the gridFS collections
    GridFS aux(*client, dbName, prefix);
  }

  GridFileBuilder::~GridFileBuilder() {
    delete[] _pending_data;
  }

  const char *GridFileBuilder::privateAppendChunk(const char *data,
                                                  size_t length,
                                                  bool pending_insert) {
    size_t chunk_len;
    char const * const end = data + length;
    while (data < end) {
      chunk_len = min(_chunkSize, (size_t)(end-data));
      // the last chunk needs to be stored as pending_data
      if (chunk_len < _chunkSize && !pending_insert) break;
      /* from gridfs.cpp at https://github.com/mongodb/mongo-cxx-driver/blob/legacy/src/mongo/client/gridfs.cpp */
      BSONObjBuilder b;
      b.appendAs( _file_id["_id"] , "files_id" );
      b.append( "n" , _current_chunk );
      b.appendBinData( "data" , chunk_len, BinDataGeneral, data );
      BSONObj chunk_data = b.obj();
      /************************************************************************/
      ++_current_chunk;
      _client->insert( _chunkNS.c_str(), chunk_data );
      data += chunk_len;
      _file_length += chunk_len;
    }
    return data;
  }

  void GridFileBuilder::privateAppendPendingData() {
    if (_pending_data_size > 0) {
      privateAppendChunk(_pending_data, _pending_data_size, true);
      delete[] _pending_data;
      _pending_data_size = 0;
      _pending_data = NULL;
    }
  }

  void GridFileBuilder::appendChunk(const char *data, size_t length) {
    if (length == 0) return;
    // check if there are pending data
    if (_pending_data != NULL) {
      size_t total_size = _pending_data_size + length;
      size_t size = min(_chunkSize, total_size) - _pending_data_size;
      memcpy(_pending_data + _pending_data_size, data, size*sizeof(char));
      _pending_data_size += size;
      // CHECK _pending_data_size <= _chunkSize
      if (_pending_data_size == _chunkSize) {
        privateAppendPendingData();
        appendChunk(data + size, length - size);
      }
    }
    else {
      char const * const end = data + length;
      // split data in _chunkSize blocks, and store as pending the last block if
      // necessary
      data = privateAppendChunk(data, length);
      // process pending data if necessary
      if (data != end) {
        if (_pending_data_size == 0) _pending_data = new char[_chunkSize];
        size_t size = (size_t)(end-data);
        memcpy(_pending_data+_pending_data_size, data, size*sizeof(char));
        _pending_data_size += size;
      }
    }
  }

  BSONObj GridFileBuilder::buildFile(const string &name,
                                     const string& content_type) {
    privateAppendPendingData();

    /* from gridfs.cpp at https://github.com/mongodb/mongo-cxx-driver/blob/legacy/src/mongo/client/gridfs.cpp */

    // Wait for any pending writebacks to finish
    BSONObj errObj = _client->getLastErrorDetailed();
    uassert( 16428,
             str::stream() << "Error storing GridFS chunk for file: " << name
             << ", error: " << errObj,
             DBClientWithCommands::getLastErrorString(errObj) == "" );

    BSONObj res;
    if ( ! _client->runCommand( _dbName.c_str() ,
                                BSON( "filemd5" << _file_id << "root" << _prefix ) ,
                                res ) )
      throw UserException( 9008 , "filemd5 failed" );

    BSONObjBuilder file;
    file << "_id" << _file_id["_id"]
         << "filename" << name
         << "chunkSize" << (unsigned int)_chunkSize
         << "uploadDate" << DATENOW
         << "md5" << res["md5"]
      ;

    if (_file_length < 1024*1024*1024) { // 2^30
      file << "length" << (int) _file_length;
    }
    else {
      file << "length" << (long long) _file_length;
    }

    if (!content_type.empty())
      file << "contentType" << content_type;

    BSONObj ret = file.obj();
    _client->insert(_filesNS.c_str(), ret);

    // resets the object
    _current_chunk     = 0;
    _pending_data      = NULL;
    _pending_data_size = 0;
    _file_length       = 0;
    OID id;
    id.init();
    _file_id = BSON("_id" << id);

    return ret;
  }

}
<|endoftext|>