<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: bookmarkcontainer.cxx,v $
 *
 *  $Revision: 1.11 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 10:36:33 $
 *
 *  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 _DBA_CORE_BOOKMARKCONTAINER_HXX_
#include "bookmarkcontainer.hxx"
#endif
#ifndef DBACCESS_SHARED_DBASTRINGS_HRC
#include "dbastrings.hrc"
#endif
#ifndef _DBASHARED_APITOOLS_HXX_
#include "apitools.hxx"
#endif
#ifndef _DBA_CORE_RESOURCE_HXX_
#include "core_resource.hxx"
#endif
#ifndef _DBA_CORE_RESOURCE_HRC_
#include "core_resource.hrc"
#endif

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif
#ifndef _COMPHELPER_SEQUENCE_HXX_
#include <comphelper/sequence.hxx>
#endif
#ifndef _COMPHELPER_ENUMHELPER_HXX_
#include <comphelper/enumhelper.hxx>
#endif
#ifndef _COMPHELPER_EXTRACT_HXX_
#include <comphelper/extract.hxx>
#endif
#ifndef _COM_SUN_STAR_LANG_XCOMPONENT_HPP_
#include <com/sun/star/lang/XComponent.hpp>
#endif
#ifndef _COMPHELPER_TYPES_HXX_
#include <comphelper/types.hxx>
#endif

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::container;
using namespace ::osl;
using namespace ::comphelper;
using namespace ::cppu;

//........................................................................
namespace dbaccess
{
//........................................................................

//==========================================================================
//= OBookmarkContainer
//==========================================================================
DBG_NAME(OBookmarkContainer)
//--------------------------------------------------------------------------
OBookmarkContainer::OBookmarkContainer(OWeakObject& _rParent, Mutex& _rMutex)
    :m_aContainerListeners(_rMutex)
    ,m_rParent(_rParent)
    ,m_rMutex(_rMutex)
{
    DBG_CTOR(OBookmarkContainer, NULL);
}

//--------------------------------------------------------------------------
void OBookmarkContainer::dispose()
{
    MutexGuard aGuard(m_rMutex);

    // say our listeners goobye
    EventObject aEvt(*this);
    m_aContainerListeners.disposeAndClear(aEvt);

    // remove our elements
    m_aBookmarksIndexed.clear();
    m_aBookmarks.clear();
}

//--------------------------------------------------------------------------
void SAL_CALL OBookmarkContainer::acquire(  ) throw()
{
    m_rParent.acquire();
}

//--------------------------------------------------------------------------
void SAL_CALL OBookmarkContainer::release(  ) throw()
{
    m_rParent.release();
}

//--------------------------------------------------------------------------
OBookmarkContainer::~OBookmarkContainer()
{
    DBG_DTOR(OBookmarkContainer, NULL);
}

// XServiceInfo
//--------------------------------------------------------------------------
::rtl::OUString SAL_CALL OBookmarkContainer::getImplementationName(  ) throw(RuntimeException)
{
    return ::rtl::OUString::createFromAscii("com.sun.star.comp.dba.OBookmarkContainer");
}

//--------------------------------------------------------------------------
sal_Bool SAL_CALL OBookmarkContainer::supportsService( const ::rtl::OUString& _rServiceName ) throw (RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    checkValid(sal_False);
    return findValue(getSupportedServiceNames(), _rServiceName, sal_True).getLength() != 0;
}

//--------------------------------------------------------------------------
Sequence< ::rtl::OUString > SAL_CALL OBookmarkContainer::getSupportedServiceNames(  ) throw(RuntimeException)
{
    Sequence< ::rtl::OUString > aReturn(1);
    aReturn.getArray()[0] = ::rtl::OUString::createFromAscii("com.sun.star.sdb.DefinitionContainer");
    return aReturn;
}

// XNameContainer
//--------------------------------------------------------------------------
void SAL_CALL OBookmarkContainer::insertByName( const ::rtl::OUString& _rName, const Any& aElement ) throw(IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    checkValid(sal_True);

    if (checkExistence(_rName))
        throw ElementExistException();

    if (0 == _rName.getLength())
        throw IllegalArgumentException();

    // approve the new object
    ::rtl::OUString sNewLink;
    if (!(aElement >>= sNewLink))
        throw IllegalArgumentException();

    implAppend(_rName, sNewLink);

    // notify the listeners
    if (m_aContainerListeners.getLength())
    {
        ContainerEvent aEvent(*this, makeAny(_rName), makeAny(sNewLink), Any());
        OInterfaceIteratorHelper aListenerIterator(m_aContainerListeners);
        while (aListenerIterator.hasMoreElements())
            static_cast< XContainerListener* >(aListenerIterator.next())->elementInserted(aEvent);
    }
}

//--------------------------------------------------------------------------
void SAL_CALL OBookmarkContainer::removeByName( const ::rtl::OUString& _rName ) throw(NoSuchElementException, WrappedTargetException, RuntimeException)
{
    ::rtl::OUString sOldBookmark;
    {
        MutexGuard aGuard(m_rMutex);
        checkValid(sal_True);

        // check the arguments
        if (!_rName.getLength())
            throw IllegalArgumentException();

        if (!checkExistence(_rName))
            throw NoSuchElementException();

        // the old element (for the notifications)
        sOldBookmark = m_aBookmarks[_rName];

        // do the removal
        implRemove(_rName);
    }

    // notify the listeners
    if (m_aContainerListeners.getLength())
    {
        ContainerEvent aEvent(*this, makeAny(_rName), makeAny(sOldBookmark), Any());
        OInterfaceIteratorHelper aListenerIterator(m_aContainerListeners);
        while (aListenerIterator.hasMoreElements())
            static_cast< XContainerListener* >(aListenerIterator.next())->elementRemoved(aEvent);
    }
}

// XNameReplace
//--------------------------------------------------------------------------
void SAL_CALL OBookmarkContainer::replaceByName( const ::rtl::OUString& _rName, const Any& aElement ) throw(IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException)
{
    ClearableMutexGuard aGuard(m_rMutex);
    checkValid(sal_True);

    // check the arguments
    if (!_rName.getLength())
        throw IllegalArgumentException();

    // do we have such an element?
    if (!checkExistence(_rName))
        throw NoSuchElementException();

    // approve the new object
    ::rtl::OUString sNewLink;
    if (!(aElement >>= sNewLink))
        throw IllegalArgumentException();

    // the old element (for the notifications)
    ::rtl::OUString sOldLink = m_aBookmarks[_rName];

    // do the replace
    implReplace(_rName, sNewLink);

    // notify the listeners
    aGuard.clear();
    if (m_aContainerListeners.getLength())
    {
        ContainerEvent aEvent(*this, makeAny(_rName), makeAny(sNewLink), makeAny(sOldLink));
        OInterfaceIteratorHelper aListenerIterator(m_aContainerListeners);
        while (aListenerIterator.hasMoreElements())
            static_cast< XContainerListener* >(aListenerIterator.next())->elementReplaced(aEvent);
    }
}

//--------------------------------------------------------------------------
void SAL_CALL OBookmarkContainer::addContainerListener( const Reference< XContainerListener >& _rxListener ) throw(RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    if (_rxListener.is())
        m_aContainerListeners.addInterface(_rxListener);
}

//--------------------------------------------------------------------------
void SAL_CALL OBookmarkContainer::removeContainerListener( const Reference< XContainerListener >& _rxListener ) throw(RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    if (_rxListener.is())
        m_aContainerListeners.removeInterface(_rxListener);
}

// XElementAccess
//--------------------------------------------------------------------------
Type SAL_CALL OBookmarkContainer::getElementType( ) throw (RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    checkValid(sal_False);
    return ::getCppuType( static_cast< ::rtl::OUString* >(NULL) );
}

//--------------------------------------------------------------------------
sal_Bool SAL_CALL OBookmarkContainer::hasElements( ) throw (RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    checkValid(sal_False);
    return !m_aBookmarks.empty();
}

// XEnumerationAccess
//--------------------------------------------------------------------------
Reference< XEnumeration > SAL_CALL OBookmarkContainer::createEnumeration(  ) throw(RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    checkValid(sal_False);
    return new ::comphelper::OEnumerationByIndex(static_cast<XIndexAccess*>(this));
}

//--------------------------------------------------------------------------
// XIndexAccess
sal_Int32 SAL_CALL OBookmarkContainer::getCount(  ) throw(RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    checkValid(sal_False);
    return m_aBookmarks.size();
}

//--------------------------------------------------------------------------
Any SAL_CALL OBookmarkContainer::getByIndex( sal_Int32 _nIndex ) throw(IndexOutOfBoundsException, WrappedTargetException, RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    checkValid(sal_False);

    if ((_nIndex < 0) || (_nIndex >= (sal_Int32)m_aBookmarksIndexed.size()))
        throw IndexOutOfBoundsException();

    return makeAny(m_aBookmarksIndexed[_nIndex]->second);
}

//--------------------------------------------------------------------------
Any SAL_CALL OBookmarkContainer::getByName( const ::rtl::OUString& _rName ) throw(NoSuchElementException, WrappedTargetException, RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    checkValid(sal_False);

    if (!checkExistence(_rName))
        throw NoSuchElementException();

    return makeAny(m_aBookmarks[_rName]);
}

//--------------------------------------------------------------------------
Sequence< ::rtl::OUString > SAL_CALL OBookmarkContainer::getElementNames(  ) throw(RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    checkValid(sal_False);

    Sequence< ::rtl::OUString > aNames(m_aBookmarks.size());
    ::rtl::OUString* pNames = aNames.getArray();
    ;
    for (   ConstMapIteratorVectorIterator aNameIter = m_aBookmarksIndexed.begin();
            aNameIter != m_aBookmarksIndexed.end();
            ++pNames, ++aNameIter
        )
    {
        *pNames = (*aNameIter)->first;
    }

    return aNames;
}

//--------------------------------------------------------------------------
sal_Bool SAL_CALL OBookmarkContainer::hasByName( const ::rtl::OUString& _rName ) throw(RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    checkValid(sal_False);

    return checkExistence(_rName);
}

//--------------------------------------------------------------------------
sal_Bool OBookmarkContainer::isReadOnly() const
{
    return sal_False;
}

//--------------------------------------------------------------------------
void OBookmarkContainer::implRemove(const ::rtl::OUString& _rName)
{
    MutexGuard aGuard(m_rMutex);

    // look for the name in the index access vector
    MapString2StringIterator aMapPos = m_aBookmarks.end();
    for (   MapIteratorVectorIterator aSearch = m_aBookmarksIndexed.begin();
            aSearch != m_aBookmarksIndexed.end();
            ++aSearch
        )
    {
#ifdef DBG_UTIL
        ::rtl::OUString sName = (*aSearch)->first;
#endif
        if ((*aSearch)->first == _rName)
        {
            aMapPos = *aSearch;
            m_aBookmarksIndexed.erase(aSearch);
            break;
        }
    }

    if (m_aBookmarks.end() == aMapPos)
    {
        DBG_ERROR("OBookmarkContainer::implRemove: inconsistence!");
        return;
    }

    // remove the map entries
    m_aBookmarks.erase(aMapPos);
}

//--------------------------------------------------------------------------
void OBookmarkContainer::implAppend(const ::rtl::OUString& _rName, const ::rtl::OUString& _rDocumentLocation)
{
    MutexGuard aGuard(m_rMutex);

    OSL_ENSURE(m_aBookmarks.find(_rName) == m_aBookmarks.end(),"Bookmark already known!");
    m_aBookmarksIndexed.push_back(m_aBookmarks.insert(  MapString2String::value_type(_rName,_rDocumentLocation)).first);
}

//--------------------------------------------------------------------------
void OBookmarkContainer::implReplace(const ::rtl::OUString& _rName, const ::rtl::OUString& _rNewLink)
{
    MutexGuard aGuard(m_rMutex);
    DBG_ASSERT(checkExistence(_rName), "OBookmarkContainer::implReplace : invalid name !");

    m_aBookmarks[_rName] = _rNewLink;
}

//--------------------------------------------------------------------------
void OBookmarkContainer::checkValid(sal_Bool _bIntendWriteAccess) const throw (RuntimeException, DisposedException)
{
}

//--------------------------------------------------------------------------
Reference< XInterface > SAL_CALL OBookmarkContainer::getParent(  ) throw (RuntimeException)
{
    return m_rParent;
}

//--------------------------------------------------------------------------
void SAL_CALL OBookmarkContainer::setParent( const Reference< XInterface >& Parent ) throw (NoSupportException, RuntimeException)
{
    throw NoSupportException();
}

//........................................................................
}   // namespace dbaccess
//........................................................................
<commit_msg>INTEGRATION: CWS warnings01 (1.11.50); FILE MERGED 2006/03/24 15:35:51 fs 1.11.50.1: #i57457# warning-free code (unxlngi6/.pro + unxsoli4.pro)<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: bookmarkcontainer.cxx,v $
 *
 *  $Revision: 1.12 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-20 02:43:38 $
 *
 *  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 _DBA_CORE_BOOKMARKCONTAINER_HXX_
#include "bookmarkcontainer.hxx"
#endif
#ifndef DBACCESS_SHARED_DBASTRINGS_HRC
#include "dbastrings.hrc"
#endif
#ifndef _DBASHARED_APITOOLS_HXX_
#include "apitools.hxx"
#endif
#ifndef _DBA_CORE_RESOURCE_HXX_
#include "core_resource.hxx"
#endif
#ifndef _DBA_CORE_RESOURCE_HRC_
#include "core_resource.hrc"
#endif

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif
#ifndef _COMPHELPER_SEQUENCE_HXX_
#include <comphelper/sequence.hxx>
#endif
#ifndef _COMPHELPER_ENUMHELPER_HXX_
#include <comphelper/enumhelper.hxx>
#endif
#ifndef _COMPHELPER_EXTRACT_HXX_
#include <comphelper/extract.hxx>
#endif
#ifndef _COM_SUN_STAR_LANG_XCOMPONENT_HPP_
#include <com/sun/star/lang/XComponent.hpp>
#endif
#ifndef _COMPHELPER_TYPES_HXX_
#include <comphelper/types.hxx>
#endif

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::container;
using namespace ::osl;
using namespace ::comphelper;
using namespace ::cppu;

//........................................................................
namespace dbaccess
{
//........................................................................

//==========================================================================
//= OBookmarkContainer
//==========================================================================
DBG_NAME(OBookmarkContainer)
//--------------------------------------------------------------------------
OBookmarkContainer::OBookmarkContainer(OWeakObject& _rParent, Mutex& _rMutex)
    :m_rParent(_rParent)
    ,m_aContainerListeners(_rMutex)
    ,m_rMutex(_rMutex)
{
    DBG_CTOR(OBookmarkContainer, NULL);
}

//--------------------------------------------------------------------------
void OBookmarkContainer::dispose()
{
    MutexGuard aGuard(m_rMutex);

    // say our listeners goobye
    EventObject aEvt(*this);
    m_aContainerListeners.disposeAndClear(aEvt);

    // remove our elements
    m_aBookmarksIndexed.clear();
    m_aBookmarks.clear();
}

//--------------------------------------------------------------------------
void SAL_CALL OBookmarkContainer::acquire(  ) throw()
{
    m_rParent.acquire();
}

//--------------------------------------------------------------------------
void SAL_CALL OBookmarkContainer::release(  ) throw()
{
    m_rParent.release();
}

//--------------------------------------------------------------------------
OBookmarkContainer::~OBookmarkContainer()
{
    DBG_DTOR(OBookmarkContainer, NULL);
}

// XServiceInfo
//--------------------------------------------------------------------------
::rtl::OUString SAL_CALL OBookmarkContainer::getImplementationName(  ) throw(RuntimeException)
{
    return ::rtl::OUString::createFromAscii("com.sun.star.comp.dba.OBookmarkContainer");
}

//--------------------------------------------------------------------------
sal_Bool SAL_CALL OBookmarkContainer::supportsService( const ::rtl::OUString& _rServiceName ) throw (RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    checkValid(sal_False);
    return findValue(getSupportedServiceNames(), _rServiceName, sal_True).getLength() != 0;
}

//--------------------------------------------------------------------------
Sequence< ::rtl::OUString > SAL_CALL OBookmarkContainer::getSupportedServiceNames(  ) throw(RuntimeException)
{
    Sequence< ::rtl::OUString > aReturn(1);
    aReturn.getArray()[0] = ::rtl::OUString::createFromAscii("com.sun.star.sdb.DefinitionContainer");
    return aReturn;
}

// XNameContainer
//--------------------------------------------------------------------------
void SAL_CALL OBookmarkContainer::insertByName( const ::rtl::OUString& _rName, const Any& aElement ) throw(IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    checkValid(sal_True);

    if (checkExistence(_rName))
        throw ElementExistException();

    if (0 == _rName.getLength())
        throw IllegalArgumentException();

    // approve the new object
    ::rtl::OUString sNewLink;
    if (!(aElement >>= sNewLink))
        throw IllegalArgumentException();

    implAppend(_rName, sNewLink);

    // notify the listeners
    if (m_aContainerListeners.getLength())
    {
        ContainerEvent aEvent(*this, makeAny(_rName), makeAny(sNewLink), Any());
        OInterfaceIteratorHelper aListenerIterator(m_aContainerListeners);
        while (aListenerIterator.hasMoreElements())
            static_cast< XContainerListener* >(aListenerIterator.next())->elementInserted(aEvent);
    }
}

//--------------------------------------------------------------------------
void SAL_CALL OBookmarkContainer::removeByName( const ::rtl::OUString& _rName ) throw(NoSuchElementException, WrappedTargetException, RuntimeException)
{
    ::rtl::OUString sOldBookmark;
    {
        MutexGuard aGuard(m_rMutex);
        checkValid(sal_True);

        // check the arguments
        if (!_rName.getLength())
            throw IllegalArgumentException();

        if (!checkExistence(_rName))
            throw NoSuchElementException();

        // the old element (for the notifications)
        sOldBookmark = m_aBookmarks[_rName];

        // do the removal
        implRemove(_rName);
    }

    // notify the listeners
    if (m_aContainerListeners.getLength())
    {
        ContainerEvent aEvent(*this, makeAny(_rName), makeAny(sOldBookmark), Any());
        OInterfaceIteratorHelper aListenerIterator(m_aContainerListeners);
        while (aListenerIterator.hasMoreElements())
            static_cast< XContainerListener* >(aListenerIterator.next())->elementRemoved(aEvent);
    }
}

// XNameReplace
//--------------------------------------------------------------------------
void SAL_CALL OBookmarkContainer::replaceByName( const ::rtl::OUString& _rName, const Any& aElement ) throw(IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException)
{
    ClearableMutexGuard aGuard(m_rMutex);
    checkValid(sal_True);

    // check the arguments
    if (!_rName.getLength())
        throw IllegalArgumentException();

    // do we have such an element?
    if (!checkExistence(_rName))
        throw NoSuchElementException();

    // approve the new object
    ::rtl::OUString sNewLink;
    if (!(aElement >>= sNewLink))
        throw IllegalArgumentException();

    // the old element (for the notifications)
    ::rtl::OUString sOldLink = m_aBookmarks[_rName];

    // do the replace
    implReplace(_rName, sNewLink);

    // notify the listeners
    aGuard.clear();
    if (m_aContainerListeners.getLength())
    {
        ContainerEvent aEvent(*this, makeAny(_rName), makeAny(sNewLink), makeAny(sOldLink));
        OInterfaceIteratorHelper aListenerIterator(m_aContainerListeners);
        while (aListenerIterator.hasMoreElements())
            static_cast< XContainerListener* >(aListenerIterator.next())->elementReplaced(aEvent);
    }
}

//--------------------------------------------------------------------------
void SAL_CALL OBookmarkContainer::addContainerListener( const Reference< XContainerListener >& _rxListener ) throw(RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    if (_rxListener.is())
        m_aContainerListeners.addInterface(_rxListener);
}

//--------------------------------------------------------------------------
void SAL_CALL OBookmarkContainer::removeContainerListener( const Reference< XContainerListener >& _rxListener ) throw(RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    if (_rxListener.is())
        m_aContainerListeners.removeInterface(_rxListener);
}

// XElementAccess
//--------------------------------------------------------------------------
Type SAL_CALL OBookmarkContainer::getElementType( ) throw (RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    checkValid(sal_False);
    return ::getCppuType( static_cast< ::rtl::OUString* >(NULL) );
}

//--------------------------------------------------------------------------
sal_Bool SAL_CALL OBookmarkContainer::hasElements( ) throw (RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    checkValid(sal_False);
    return !m_aBookmarks.empty();
}

// XEnumerationAccess
//--------------------------------------------------------------------------
Reference< XEnumeration > SAL_CALL OBookmarkContainer::createEnumeration(  ) throw(RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    checkValid(sal_False);
    return new ::comphelper::OEnumerationByIndex(static_cast<XIndexAccess*>(this));
}

//--------------------------------------------------------------------------
// XIndexAccess
sal_Int32 SAL_CALL OBookmarkContainer::getCount(  ) throw(RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    checkValid(sal_False);
    return m_aBookmarks.size();
}

//--------------------------------------------------------------------------
Any SAL_CALL OBookmarkContainer::getByIndex( sal_Int32 _nIndex ) throw(IndexOutOfBoundsException, WrappedTargetException, RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    checkValid(sal_False);

    if ((_nIndex < 0) || (_nIndex >= (sal_Int32)m_aBookmarksIndexed.size()))
        throw IndexOutOfBoundsException();

    return makeAny(m_aBookmarksIndexed[_nIndex]->second);
}

//--------------------------------------------------------------------------
Any SAL_CALL OBookmarkContainer::getByName( const ::rtl::OUString& _rName ) throw(NoSuchElementException, WrappedTargetException, RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    checkValid(sal_False);

    if (!checkExistence(_rName))
        throw NoSuchElementException();

    return makeAny(m_aBookmarks[_rName]);
}

//--------------------------------------------------------------------------
Sequence< ::rtl::OUString > SAL_CALL OBookmarkContainer::getElementNames(  ) throw(RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    checkValid(sal_False);

    Sequence< ::rtl::OUString > aNames(m_aBookmarks.size());
    ::rtl::OUString* pNames = aNames.getArray();
    ;
    for (   ConstMapIteratorVectorIterator aNameIter = m_aBookmarksIndexed.begin();
            aNameIter != m_aBookmarksIndexed.end();
            ++pNames, ++aNameIter
        )
    {
        *pNames = (*aNameIter)->first;
    }

    return aNames;
}

//--------------------------------------------------------------------------
sal_Bool SAL_CALL OBookmarkContainer::hasByName( const ::rtl::OUString& _rName ) throw(RuntimeException)
{
    MutexGuard aGuard(m_rMutex);
    checkValid(sal_False);

    return checkExistence(_rName);
}

//--------------------------------------------------------------------------
sal_Bool OBookmarkContainer::isReadOnly() const
{
    return sal_False;
}

//--------------------------------------------------------------------------
void OBookmarkContainer::implRemove(const ::rtl::OUString& _rName)
{
    MutexGuard aGuard(m_rMutex);

    // look for the name in the index access vector
    MapString2StringIterator aMapPos = m_aBookmarks.end();
    for (   MapIteratorVectorIterator aSearch = m_aBookmarksIndexed.begin();
            aSearch != m_aBookmarksIndexed.end();
            ++aSearch
        )
    {
#ifdef DBG_UTIL
        ::rtl::OUString sName = (*aSearch)->first;
#endif
        if ((*aSearch)->first == _rName)
        {
            aMapPos = *aSearch;
            m_aBookmarksIndexed.erase(aSearch);
            break;
        }
    }

    if (m_aBookmarks.end() == aMapPos)
    {
        DBG_ERROR("OBookmarkContainer::implRemove: inconsistence!");
        return;
    }

    // remove the map entries
    m_aBookmarks.erase(aMapPos);
}

//--------------------------------------------------------------------------
void OBookmarkContainer::implAppend(const ::rtl::OUString& _rName, const ::rtl::OUString& _rDocumentLocation)
{
    MutexGuard aGuard(m_rMutex);

    OSL_ENSURE(m_aBookmarks.find(_rName) == m_aBookmarks.end(),"Bookmark already known!");
    m_aBookmarksIndexed.push_back(m_aBookmarks.insert(  MapString2String::value_type(_rName,_rDocumentLocation)).first);
}

//--------------------------------------------------------------------------
void OBookmarkContainer::implReplace(const ::rtl::OUString& _rName, const ::rtl::OUString& _rNewLink)
{
    MutexGuard aGuard(m_rMutex);
    DBG_ASSERT(checkExistence(_rName), "OBookmarkContainer::implReplace : invalid name !");

    m_aBookmarks[_rName] = _rNewLink;
}

//--------------------------------------------------------------------------
void OBookmarkContainer::checkValid(sal_Bool /*_bIntendWriteAccess*/) const throw (RuntimeException, DisposedException)
{
}

//--------------------------------------------------------------------------
Reference< XInterface > SAL_CALL OBookmarkContainer::getParent(  ) throw (RuntimeException)
{
    return m_rParent;
}

//--------------------------------------------------------------------------
void SAL_CALL OBookmarkContainer::setParent( const Reference< XInterface >& /*Parent*/ ) throw (NoSupportException, RuntimeException)
{
    throw NoSupportException();
}

//........................................................................
}   // namespace dbaccess
//........................................................................
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2005 by Dr. Marc Boris Duerner
 * Copyright (C) 2005 Stephan Beal
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * As a special exception, you may use this file as part of a free
 * software library without restriction. Specifically, if other files
 * instantiate templates or use macros or inline functions from this
 * file, or you compile this file and link it with other files to
 * produce an executable, this file does not by itself cause the
 * resulting executable to be covered by the GNU General Public
 * License. This exception does not however invalidate any other
 * reasons why the executable file might be covered by the GNU Library
 * General Public License.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
#include "cxxtools/signal.h"

namespace cxxtools {

SignalBase::Sentry::Sentry(const SignalBase* signal)
: _signal(signal)
{
    _signal->_sentry = this;
    _signal->_sending = true;
    _signal->_dirty = false;
}

SignalBase::Sentry::~Sentry()
{
    if( _signal )
        this->detach();
}

void SignalBase::Sentry::detach()
{
    _signal->_sending = false;

    if( _signal->_dirty == false )
    {
        _signal->_sentry = 0;
        _signal = 0;
        return;
    }

    std::list<Connection>::iterator it = _signal->_connections.begin();
    while( it != _signal->_connections.end() )
    {
        if( it->valid() )
        {
            ++it;
        }
        else
        {
            it = _signal->_connections.erase(it);
        }
    }

    _signal->_dirty = false;
    _signal->_sentry = 0;
    _signal = 0;
}

SignalBase::SignalBase()
: _sentry(0)
, _sending(false)
, _dirty(false)
{ }

SignalBase::~SignalBase()
{
    if(_sentry)
    {
        _sentry->detach();
    }
}

SignalBase& SignalBase::operator=(const SignalBase& other)
{
    this->clear();

    std::list<Connection>::const_iterator it = other.connections().begin();
    std::list<Connection>::const_iterator end = other.connections().end();

    for( ; it != end; ++it)
    {
        const Connectable& signal = it->sender();
        if( &signal == &other)
        {
            const Slot& slot = it->slot();
            Connection connection( *this, slot.clone()  );
        }
    }

    return *this;
}

void SignalBase::onConnectionOpen(const Connection& c)
{
    Connectable::onConnectionOpen(c);
}

void SignalBase::onConnectionClose(const Connection& c)
{
    // if the signal is currently calling its slots, do not
    // remove the connection now, but only set the cleanup flag
    // Any invalid connection objects will be removed after
    // the signal has finished calling its slots by the Sentry.
    if( _sending )
    {
        _dirty = true;
    }
    else
    {
        Connectable::onConnectionClose(c);
    }
}

void SignalBase::disconnectSlot(const Slot& slot)
{
    std::list<Connection>::iterator it = Connectable::connections().begin();
    std::list<Connection>::iterator end = Connectable::connections().end();

    for(; it != end; ++it)
    {
        if( it->slot().equals(slot) )
        {
            it->close();
            return;
        }
    }
}

bool CompareEventTypeInfo::operator()(const std::type_info* t1,
                                      const std::type_info* t2) const
{
    if(t2 == 0)
        return false;

    if(t1 == 0)
        return true;

    return t1->before(*t2) != 0;
}

Signal<const cxxtools::Event&>::Sentry::Sentry(const Signal* signal)
: _signal(signal)
{
    _signal->_sentry = this;
    _signal->_sending = true;
    _signal->_dirty = false;
}

Signal<const cxxtools::Event&>::Sentry::~Sentry()
{
    if( _signal )
        this->detach();
}

void Signal<const cxxtools::Event&>::Sentry::detach()
{
    _signal->_sending = false;

    if( _signal->_dirty == false )
    {
        _signal->_sentry = 0;
        _signal = 0;
        return;
    }

    Signal::RouteMap::iterator it = _signal->_routes.begin();
    while( it != _signal->_routes.end() )
    {
        if( it->second->valid() )
        {
            ++it;
        }
        else
        {
            delete it->second;
            _signal->_routes.erase(it++);
        }
    }

    _signal->_dirty = false;
    _signal->_sentry = 0;
    _signal = 0;
}

Signal<const cxxtools::Event&>::Signal()
: _sentry(0)
, _sending(false)
, _dirty(false)
{}

Signal<const cxxtools::Event&>::~Signal()
{
    if(_sentry)
        _sentry->detach();

    while( ! _routes.empty() )
    {
        IEventRoute* route = _routes.begin()->second;
        route->connection().close();
    }
}

void Signal<const cxxtools::Event&>::send(const cxxtools::Event& ev) const
{
    // The sentry will set the Signal to the sending state and
    // reset it to not-sending upon destruction. In the sending
    // state, removing connection will leave invalid connections
    // in the connection list to keep the iterator valid, but mark
    // the Signal dirty. If the Signal is dirty, all invalid
    // connections will be removed by the Sentry when it destructs..
    Signal::Sentry sentry(this);

    RouteMap::iterator it = _routes.begin();
    while( true )
    {
        if( it == _routes.end() )
            return;

        if(it->first != 0)
            break;

        // The following scenarios must be considered when the
        // slot is called:
        // - The slot might get deleted and thus disconnected from
        //   this signal
        // - The slot might delete this signal and we must end
        //   calling any slots immediately
        // - A new Connection might get added to this Signal in
        //   the slot
        IEventRoute* route = it->second;
        if( route->valid() )
            route->route(ev);

        // if this signal gets deleted by the slot, the Sentry
        // will be detached. In this case we bail out immediately
        if( !sentry )
            return;

        ++it;
    }

    const std::type_info& ti = ev.typeInfo();

    it = _routes.lower_bound( &ti );
    while(it != _routes.end() && *(it->first) == ti)
    {
        IEventRoute* route = it->second;

        if(route)
            route->route(ev);

        ++it;

        // if this signal gets deleted by the slot, the Sentry
        // will be detached. In this case we bail out immediately
        if( !sentry )
            return;
    }
}

void Signal<const cxxtools::Event&>::onConnectionOpen(const Connection& c)
{
    const Connectable& sender = c.sender();
    if(&sender != this)
    {
        return Connectable::onConnectionOpen(c);
    }
}

void Signal<const cxxtools::Event&>::onConnectionClose(const Connection& c)
{
    // if the signal is currently calling its slots, do not
    // remove the connection now, but only set the cleanup flag
    // Any invalid connection objects will be removed after
    // the signal has finished calling its slots by the Sentry.
    if( _sending )
    {
        _dirty = true;
    }
    else
    {
        RouteMap::iterator it;
        for(it = _routes.begin(); it != _routes.end(); ++it )
        {
            IEventRoute* route = it->second;
            if(route->connection() == c )
            {
                delete route;
                _routes.erase(it++);
                return;
            }
        }

        Connectable::onConnectionClose(c);
    }
}

void Signal<const cxxtools::Event&>::addRoute(const std::type_info* ti, IEventRoute* route)
{
    RouteMap::value_type elem(ti, route);
    _routes.insert( elem );
}

void Signal<const cxxtools::Event&>::removeRoute(const Slot& slot)
{
    RouteMap::iterator it = _routes.begin();
    while( it != _routes.end() && it->first == 0 )
    {
        IEventRoute* route = it->second;
        if(route->connection().slot().equals(slot) )
        {
            route->connection().close();
            break;
        }
    }
}

void Signal<const cxxtools::Event&>::removeRoute(const std::type_info* ti, const Slot& slot)
{
    RouteMap::iterator it = _routes.lower_bound( ti );
    while(it != _routes.end() && *(it->first) == *ti)
    {
        IEventRoute* route = it->second;
        if(route->connection().slot().equals(slot) )
        {
            route->connection().close();
            break;
        }
    }
}

}
<commit_msg>fix compile bug: sunstudio compiler complaint about syntax error<commit_after>/*
 * Copyright (C) 2005 by Dr. Marc Boris Duerner
 * Copyright (C) 2005 Stephan Beal
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * As a special exception, you may use this file as part of a free
 * software library without restriction. Specifically, if other files
 * instantiate templates or use macros or inline functions from this
 * file, or you compile this file and link it with other files to
 * produce an executable, this file does not by itself cause the
 * resulting executable to be covered by the GNU General Public
 * License. This exception does not however invalidate any other
 * reasons why the executable file might be covered by the GNU Library
 * General Public License.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
#include "cxxtools/signal.h"

namespace cxxtools {

SignalBase::Sentry::Sentry(const SignalBase* signal)
: _signal(signal)
{
    _signal->_sentry = this;
    _signal->_sending = true;
    _signal->_dirty = false;
}

SignalBase::Sentry::~Sentry()
{
    if( _signal )
        this->detach();
}

void SignalBase::Sentry::detach()
{
    _signal->_sending = false;

    if( _signal->_dirty == false )
    {
        _signal->_sentry = 0;
        _signal = 0;
        return;
    }

    std::list<Connection>::iterator it = _signal->_connections.begin();
    while( it != _signal->_connections.end() )
    {
        if( it->valid() )
        {
            ++it;
        }
        else
        {
            it = _signal->_connections.erase(it);
        }
    }

    _signal->_dirty = false;
    _signal->_sentry = 0;
    _signal = 0;
}

SignalBase::SignalBase()
: _sentry(0)
, _sending(false)
, _dirty(false)
{ }

SignalBase::~SignalBase()
{
    if(_sentry)
    {
        _sentry->detach();
    }
}

SignalBase& SignalBase::operator=(const SignalBase& other)
{
    this->clear();

    std::list<Connection>::const_iterator it = other.connections().begin();
    std::list<Connection>::const_iterator end = other.connections().end();

    for( ; it != end; ++it)
    {
        const Connectable& signal = it->sender();
        if( &signal == &other)
        {
            const Slot& slot = it->slot();
            Connection connection( *this, slot.clone()  );
        }
    }

    return *this;
}

void SignalBase::onConnectionOpen(const Connection& c)
{
    Connectable::onConnectionOpen(c);
}

void SignalBase::onConnectionClose(const Connection& c)
{
    // if the signal is currently calling its slots, do not
    // remove the connection now, but only set the cleanup flag
    // Any invalid connection objects will be removed after
    // the signal has finished calling its slots by the Sentry.
    if( _sending )
    {
        _dirty = true;
    }
    else
    {
        Connectable::onConnectionClose(c);
    }
}

void SignalBase::disconnectSlot(const Slot& slot)
{
    std::list<Connection>::iterator it = Connectable::connections().begin();
    std::list<Connection>::iterator end = Connectable::connections().end();

    for(; it != end; ++it)
    {
        if( it->slot().equals(slot) )
        {
            it->close();
            return;
        }
    }
}

bool CompareEventTypeInfo::operator()(const std::type_info* t1,
                                      const std::type_info* t2) const
{
    if(t2 == 0)
        return false;

    if(t1 == 0)
        return true;

    return t1->before(*t2) != 0;
}

Signal<const Event&, Void, Void, Void, Void, Void, Void, Void, Void, Void>::Sentry::Sentry(const Signal* signal)
: _signal(signal)
{
    _signal->_sentry = this;
    _signal->_sending = true;
    _signal->_dirty = false;
}

Signal<const Event&, Void, Void, Void, Void, Void, Void, Void, Void, Void>::Sentry::~Sentry()
{
    if( _signal )
        this->detach();
}

void Signal<const Event&, Void, Void, Void, Void, Void, Void, Void, Void, Void>::Sentry::detach()
{
    _signal->_sending = false;

    if( _signal->_dirty == false )
    {
        _signal->_sentry = 0;
        _signal = 0;
        return;
    }

    Signal::RouteMap::iterator it = _signal->_routes.begin();
    while( it != _signal->_routes.end() )
    {
        if( it->second->valid() )
        {
            ++it;
        }
        else
        {
            delete it->second;
            _signal->_routes.erase(it++);
        }
    }

    _signal->_dirty = false;
    _signal->_sentry = 0;
    _signal = 0;
}

Signal<const Event&, Void, Void, Void, Void, Void, Void, Void, Void, Void>::Signal()
: _sentry(0)
, _sending(false)
, _dirty(false)
{}

Signal<const Event&, Void, Void, Void, Void, Void, Void, Void, Void, Void>::~Signal()
{
    if(_sentry)
        _sentry->detach();

    while( ! _routes.empty() )
    {
        IEventRoute* route = _routes.begin()->second;
        route->connection().close();
    }
}

void Signal<const Event&, Void, Void, Void, Void, Void, Void, Void, Void, Void>::send(const cxxtools::Event& ev) const
{
    // The sentry will set the Signal to the sending state and
    // reset it to not-sending upon destruction. In the sending
    // state, removing connection will leave invalid connections
    // in the connection list to keep the iterator valid, but mark
    // the Signal dirty. If the Signal is dirty, all invalid
    // connections will be removed by the Sentry when it destructs..
    Signal::Sentry sentry(this);

    RouteMap::iterator it = _routes.begin();
    while( true )
    {
        if( it == _routes.end() )
            return;

        if(it->first != 0)
            break;

        // The following scenarios must be considered when the
        // slot is called:
        // - The slot might get deleted and thus disconnected from
        //   this signal
        // - The slot might delete this signal and we must end
        //   calling any slots immediately
        // - A new Connection might get added to this Signal in
        //   the slot
        IEventRoute* route = it->second;
        if( route->valid() )
            route->route(ev);

        // if this signal gets deleted by the slot, the Sentry
        // will be detached. In this case we bail out immediately
        if( !sentry )
            return;

        ++it;
    }

    const std::type_info& ti = ev.typeInfo();

    it = _routes.lower_bound( &ti );
    while(it != _routes.end() && *(it->first) == ti)
    {
        IEventRoute* route = it->second;

        if(route)
            route->route(ev);

        ++it;

        // if this signal gets deleted by the slot, the Sentry
        // will be detached. In this case we bail out immediately
        if( !sentry )
            return;
    }
}

void Signal<const Event&, Void, Void, Void, Void, Void, Void, Void, Void, Void>::onConnectionOpen(const Connection& c)
{
    const Connectable& sender = c.sender();
    if(&sender != this)
    {
        return Connectable::onConnectionOpen(c);
    }
}

void Signal<const Event&, Void, Void, Void, Void, Void, Void, Void, Void, Void>::onConnectionClose(const Connection& c)
{
    // if the signal is currently calling its slots, do not
    // remove the connection now, but only set the cleanup flag
    // Any invalid connection objects will be removed after
    // the signal has finished calling its slots by the Sentry.
    if( _sending )
    {
        _dirty = true;
    }
    else
    {
        RouteMap::iterator it;
        for(it = _routes.begin(); it != _routes.end(); ++it )
        {
            IEventRoute* route = it->second;
            if(route->connection() == c )
            {
                delete route;
                _routes.erase(it++);
                return;
            }
        }

        Connectable::onConnectionClose(c);
    }
}

void Signal<const Event&, Void, Void, Void, Void, Void, Void, Void, Void, Void>::addRoute(const std::type_info* ti, IEventRoute* route)
{
    RouteMap::value_type elem(ti, route);
    _routes.insert( elem );
}

void Signal<const Event&, Void, Void, Void, Void, Void, Void, Void, Void, Void>::removeRoute(const Slot& slot)
{
    RouteMap::iterator it = _routes.begin();
    while( it != _routes.end() && it->first == 0 )
    {
        IEventRoute* route = it->second;
        if(route->connection().slot().equals(slot) )
        {
            route->connection().close();
            break;
        }
    }
}

void Signal<const Event&, Void, Void, Void, Void, Void, Void, Void, Void, Void>::removeRoute(const std::type_info* ti, const Slot& slot)
{
    RouteMap::iterator it = _routes.lower_bound( ti );
    while(it != _routes.end() && *(it->first) == *ti)
    {
        IEventRoute* route = it->second;
        if(route->connection().slot().equals(slot) )
        {
            route->connection().close();
            break;
        }
    }
}

}
<|endoftext|>


<commit_before>#include <QTimer>
#include <QHash>
#include <QDebug>
#include <algorithm>            // std::sort

#include "api/server-repo.h"
#include "utils/utils.h"
#include "seafile-applet.h"
#include "main-window.h"
#include "rpc/rpc-client.h"
#include "repo-item.h"
#include "repo-tree-view.h"
#include "repo-tree-model.h"
#include "rpc/clone-task.h"

namespace {

const int kRefreshLocalReposInterval = 1000;
const int kMaxRecentUpdatedRepos = 10;

bool compareRepoByTimestamp(const ServerRepo& a, const ServerRepo& b)
{
    return a.mtime > b.mtime;
}

bool isSameRepo(const ServerRepo& a, const ServerRepo& b)
{
    return a.id == b.id;
}

} // namespace

RepoTreeModel::RepoTreeModel(QObject *parent)
    : QStandardItemModel(parent),
      tree_view_(NULL)
{
    initialize();

    refresh_local_timer_ = new QTimer(this);
    connect(refresh_local_timer_, SIGNAL(timeout()),
            this, SLOT(refreshLocalRepos()));

    refresh_local_timer_->start(kRefreshLocalReposInterval);
}

void RepoTreeModel::initialize()
{
    recent_updated_category_ = new RepoCategoryItem(tr("Recent Updated"));
    my_repos_catetory_ = new RepoCategoryItem(tr("My Libraries"));
    shared_repos_catetory_ = new RepoCategoryItem(tr("Shared Libraries"));

    appendRow(recent_updated_category_);
    appendRow(my_repos_catetory_);
    appendRow(shared_repos_catetory_);

    if (tree_view_) {
        tree_view_->expand(indexFromItem(recent_updated_category_));
    }
}

void RepoTreeModel::clear()
{
    QStandardItemModel::clear();
    initialize();
}

void RepoTreeModel::setRepos(const std::vector<ServerRepo>& repos)
{
    int i, n = repos.size();
    // removeReposDeletedOnServer(repos);

    clear();

    for (i = 0; i < n; i++) {
        const ServerRepo& repo = repos[i];
        if (repo.isPersonalRepo()) {
            checkPersonalRepo(repo);
        } else if (repo.isSharedRepo()) {
            checkSharedRepo(repo);
        } else {
            checkGroupRepo(repo);
        }
    }

    std::vector<ServerRepo> repos_copy(repos);
    // sort all repso by timestamp
    std::sort(repos_copy.begin(), repos_copy.end(), compareRepoByTimestamp);
    // erase duplidates
    repos_copy.erase(std::unique(repos_copy.begin(), repos_copy.end(), isSameRepo), repos_copy.end());

    n = qMin((int)repos_copy.size(), kMaxRecentUpdatedRepos);
    for (i = 0; i < n; i++) {
        RepoItem *item = new RepoItem(repos_copy[i]);
        recent_updated_category_->appendRow(item);
    }
}

struct DeleteRepoData {
    QHash<QString, const ServerRepo*> map;
    QList<RepoItem*> itemsToDelete;
};

void RepoTreeModel::collectDeletedRepos(RepoItem *item, void *vdata)
{
    DeleteRepoData *data = (DeleteRepoData *)vdata;
    const ServerRepo* repo = data->map.value(item->repo().id);
    if (!repo || repo->type != item->repo().type) {
        data->itemsToDelete << item;
    }
}

void RepoTreeModel::removeReposDeletedOnServer(const std::vector<ServerRepo>& repos)
{
    int i, n;
    DeleteRepoData data;
    n = repos.size();
    for (i = 0; i < n; i++) {
        const ServerRepo& repo = repos[i];
        data.map.insert(repo.id, &repo);
    }

    forEachRepoItem(&RepoTreeModel::collectDeletedRepos, (void *)&data);

    QListIterator<RepoItem*> iter(data.itemsToDelete);
    while(iter.hasNext()) {
        RepoItem *item = iter.next();

        const ServerRepo& repo = item->repo();

        qDebug("remove repo %s(%s) from \"%s\"\n",
               toCStr(repo.name), toCStr(repo.id),
               toCStr(((RepoCategoryItem*)item->parent())->name()));

        item->parent()->removeRow(item->row());
    }
}

void RepoTreeModel::checkPersonalRepo(const ServerRepo& repo)
{
    int row, n = my_repos_catetory_->rowCount();
    for (row = 0; row < n; row++) {
        RepoItem *item = (RepoItem *)(my_repos_catetory_->child(row));
        if (item->repo().id == repo.id) {
            updateRepoItem(item, repo);
            return;
        }
    }

    // The repo is new
    RepoItem *item = new RepoItem(repo);
    my_repos_catetory_->appendRow(item);
}

void RepoTreeModel::checkSharedRepo(const ServerRepo& repo)
{
    int row, n = shared_repos_catetory_->rowCount();
    for (row = 0; row < n; row++) {
        RepoItem *item = (RepoItem *)(shared_repos_catetory_->child(row));
        if (item->repo().id == repo.id) {
            updateRepoItem(item, repo);
            return;
        }
    }

    // The repo is new
    RepoItem *item = new RepoItem(repo);
    shared_repos_catetory_->appendRow(item);
}

void RepoTreeModel::checkGroupRepo(const ServerRepo& repo)
{
    QStandardItem *root = invisibleRootItem();
    RepoCategoryItem *group = NULL;

    int row, n = root->rowCount();

    // First find for create the group
    // Starts from row 2 because the first two rows are "My Libraries" and "Shared Libraries"
    for (row = 2; row < n; row ++) {
        RepoCategoryItem *item = (RepoCategoryItem *)(root->child(row));
        if (item->groupId() == repo.group_id) {
            group = item;
            break;
        }
    }
    if (!group) {
        if (repo.group_name == "Organization") {
            group = new RepoCategoryItem(tr("Organization"), repo.group_id);
            // Insert pub repos after "recent updated", "my libraries", "shared libraries"
            insertRow(3, group);
        } else {
            group = new RepoCategoryItem(repo.group_name, repo.group_id);
            appendRow(group);
        }
    }

    // Find the repo in this group
    n = group->rowCount();
    for (row = 0; row < n; row++) {
        RepoItem *item = (RepoItem *)(group->child(row));
        if (item->repo().id == repo.id) {
            updateRepoItem(item, repo);
            return;
        }
    }

    // Current repo not in this group yet
    RepoItem *item = new RepoItem(repo);
    group->appendRow(item);
}

void RepoTreeModel::updateRepoItem(RepoItem *item, const ServerRepo& repo)
{
    item->setRepo(repo);
}

void RepoTreeModel::forEachRepoItem(void (RepoTreeModel::*func)(RepoItem *, void *),
                                    void *data)
{
    int row;
    int n;
    QStandardItem *root = invisibleRootItem();
    n = root->rowCount();
    for (row = 0; row < n; row++) {
        RepoCategoryItem *category = (RepoCategoryItem *)root->child(row);
        int j, total;
        total = category->rowCount();
        for (j = 0; j < total; j++) {
            RepoItem *item = (RepoItem *)category->child(j);
            (this->*func)(item, data);
        }
    }
}

void RepoTreeModel::refreshLocalRepos()
{
    if (!seafApplet->mainWindow()->isVisible()) {
        return;
    }

    std::vector<CloneTask> tasks;
    seafApplet->rpcClient()->getCloneTasks(&tasks);

    forEachRepoItem(&RepoTreeModel::refreshRepoItem, (void*) &tasks);
}

void RepoTreeModel::refreshRepoItem(RepoItem *item, void *data)
{
    if (!tree_view_->isExpanded(indexFromItem(item->parent()))) {
        return;
    }

    LocalRepo local_repo;
    seafApplet->rpcClient()->getLocalRepo(item->repo().id, &local_repo);
    if (local_repo != item->localRepo()) {
        item->setLocalRepo(local_repo);
        QModelIndex index = indexFromItem(item);
        emit dataChanged(index,index);
        // qDebug("repo %s is changed\n", toCStr(item->repo().name));
    }

    CloneTask clone_task;
    std::vector<CloneTask>* tasks = (std::vector<CloneTask>*)data;
    if (!local_repo.isValid()) {
        for (size_t i=0; i < tasks->size(); ++i) {
            clone_task = tasks->at(i);
            if (clone_task.repo_id == item->repo().id) {
                item->setCloneTask(clone_task);
                QModelIndex index = indexFromItem(item);
                emit dataChanged(index,index);
            }
        }
    }
}
<commit_msg>fixed display of download status<commit_after>#include <QTimer>
#include <QHash>
#include <QDebug>
#include <algorithm>            // std::sort

#include "api/server-repo.h"
#include "utils/utils.h"
#include "seafile-applet.h"
#include "main-window.h"
#include "rpc/rpc-client.h"
#include "repo-item.h"
#include "repo-tree-view.h"
#include "repo-tree-model.h"
#include "rpc/clone-task.h"

namespace {

const int kRefreshLocalReposInterval = 1000;
const int kMaxRecentUpdatedRepos = 10;

bool compareRepoByTimestamp(const ServerRepo& a, const ServerRepo& b)
{
    return a.mtime > b.mtime;
}

bool isSameRepo(const ServerRepo& a, const ServerRepo& b)
{
    return a.id == b.id;
}

} // namespace

RepoTreeModel::RepoTreeModel(QObject *parent)
    : QStandardItemModel(parent),
      tree_view_(NULL)
{
    initialize();

    refresh_local_timer_ = new QTimer(this);
    connect(refresh_local_timer_, SIGNAL(timeout()),
            this, SLOT(refreshLocalRepos()));

    refresh_local_timer_->start(kRefreshLocalReposInterval);
}

void RepoTreeModel::initialize()
{
    recent_updated_category_ = new RepoCategoryItem(tr("Recent Updated"));
    my_repos_catetory_ = new RepoCategoryItem(tr("My Libraries"));
    shared_repos_catetory_ = new RepoCategoryItem(tr("Shared Libraries"));

    appendRow(recent_updated_category_);
    appendRow(my_repos_catetory_);
    appendRow(shared_repos_catetory_);

    if (tree_view_) {
        tree_view_->expand(indexFromItem(recent_updated_category_));
    }
}

void RepoTreeModel::clear()
{
    QStandardItemModel::clear();
    initialize();
}

void RepoTreeModel::setRepos(const std::vector<ServerRepo>& repos)
{
    int i, n = repos.size();
    // removeReposDeletedOnServer(repos);

    clear();

    for (i = 0; i < n; i++) {
        const ServerRepo& repo = repos[i];
        if (repo.isPersonalRepo()) {
            checkPersonalRepo(repo);
        } else if (repo.isSharedRepo()) {
            checkSharedRepo(repo);
        } else {
            checkGroupRepo(repo);
        }
    }

    std::vector<ServerRepo> repos_copy(repos);
    // sort all repso by timestamp
    std::sort(repos_copy.begin(), repos_copy.end(), compareRepoByTimestamp);
    // erase duplidates
    repos_copy.erase(std::unique(repos_copy.begin(), repos_copy.end(), isSameRepo), repos_copy.end());

    n = qMin((int)repos_copy.size(), kMaxRecentUpdatedRepos);
    for (i = 0; i < n; i++) {
        RepoItem *item = new RepoItem(repos_copy[i]);
        recent_updated_category_->appendRow(item);
    }
}

struct DeleteRepoData {
    QHash<QString, const ServerRepo*> map;
    QList<RepoItem*> itemsToDelete;
};

void RepoTreeModel::collectDeletedRepos(RepoItem *item, void *vdata)
{
    DeleteRepoData *data = (DeleteRepoData *)vdata;
    const ServerRepo* repo = data->map.value(item->repo().id);
    if (!repo || repo->type != item->repo().type) {
        data->itemsToDelete << item;
    }
}

void RepoTreeModel::removeReposDeletedOnServer(const std::vector<ServerRepo>& repos)
{
    int i, n;
    DeleteRepoData data;
    n = repos.size();
    for (i = 0; i < n; i++) {
        const ServerRepo& repo = repos[i];
        data.map.insert(repo.id, &repo);
    }

    forEachRepoItem(&RepoTreeModel::collectDeletedRepos, (void *)&data);

    QListIterator<RepoItem*> iter(data.itemsToDelete);
    while(iter.hasNext()) {
        RepoItem *item = iter.next();

        const ServerRepo& repo = item->repo();

        qDebug("remove repo %s(%s) from \"%s\"\n",
               toCStr(repo.name), toCStr(repo.id),
               toCStr(((RepoCategoryItem*)item->parent())->name()));

        item->parent()->removeRow(item->row());
    }
}

void RepoTreeModel::checkPersonalRepo(const ServerRepo& repo)
{
    int row, n = my_repos_catetory_->rowCount();
    for (row = 0; row < n; row++) {
        RepoItem *item = (RepoItem *)(my_repos_catetory_->child(row));
        if (item->repo().id == repo.id) {
            updateRepoItem(item, repo);
            return;
        }
    }

    // The repo is new
    RepoItem *item = new RepoItem(repo);
    my_repos_catetory_->appendRow(item);
}

void RepoTreeModel::checkSharedRepo(const ServerRepo& repo)
{
    int row, n = shared_repos_catetory_->rowCount();
    for (row = 0; row < n; row++) {
        RepoItem *item = (RepoItem *)(shared_repos_catetory_->child(row));
        if (item->repo().id == repo.id) {
            updateRepoItem(item, repo);
            return;
        }
    }

    // The repo is new
    RepoItem *item = new RepoItem(repo);
    shared_repos_catetory_->appendRow(item);
}

void RepoTreeModel::checkGroupRepo(const ServerRepo& repo)
{
    QStandardItem *root = invisibleRootItem();
    RepoCategoryItem *group = NULL;

    int row, n = root->rowCount();

    // First find for create the group
    // Starts from row 2 because the first two rows are "My Libraries" and "Shared Libraries"
    for (row = 2; row < n; row ++) {
        RepoCategoryItem *item = (RepoCategoryItem *)(root->child(row));
        if (item->groupId() == repo.group_id) {
            group = item;
            break;
        }
    }
    if (!group) {
        if (repo.group_name == "Organization") {
            group = new RepoCategoryItem(tr("Organization"), repo.group_id);
            // Insert pub repos after "recent updated", "my libraries", "shared libraries"
            insertRow(3, group);
        } else {
            group = new RepoCategoryItem(repo.group_name, repo.group_id);
            appendRow(group);
        }
    }

    // Find the repo in this group
    n = group->rowCount();
    for (row = 0; row < n; row++) {
        RepoItem *item = (RepoItem *)(group->child(row));
        if (item->repo().id == repo.id) {
            updateRepoItem(item, repo);
            return;
        }
    }

    // Current repo not in this group yet
    RepoItem *item = new RepoItem(repo);
    group->appendRow(item);
}

void RepoTreeModel::updateRepoItem(RepoItem *item, const ServerRepo& repo)
{
    item->setRepo(repo);
}

void RepoTreeModel::forEachRepoItem(void (RepoTreeModel::*func)(RepoItem *, void *),
                                    void *data)
{
    int row;
    int n;
    QStandardItem *root = invisibleRootItem();
    n = root->rowCount();
    for (row = 0; row < n; row++) {
        RepoCategoryItem *category = (RepoCategoryItem *)root->child(row);
        int j, total;
        total = category->rowCount();
        for (j = 0; j < total; j++) {
            RepoItem *item = (RepoItem *)category->child(j);
            (this->*func)(item, data);
        }
    }
}

void RepoTreeModel::refreshLocalRepos()
{
    if (!seafApplet->mainWindow()->isVisible()) {
        return;
    }

    std::vector<CloneTask> tasks;
    seafApplet->rpcClient()->getCloneTasks(&tasks);

    forEachRepoItem(&RepoTreeModel::refreshRepoItem, (void*) &tasks);
}

void RepoTreeModel::refreshRepoItem(RepoItem *item, void *data)
{
    if (!tree_view_->isExpanded(indexFromItem(item->parent()))) {
        return;
    }

    LocalRepo local_repo;
    seafApplet->rpcClient()->getLocalRepo(item->repo().id, &local_repo);
    if (local_repo != item->localRepo()) {
        item->setLocalRepo(local_repo);
        QModelIndex index = indexFromItem(item);
        emit dataChanged(index,index);
        // qDebug("repo %s is changed\n", toCStr(item->repo().name));
    }

    item->setCloneTask();

    CloneTask clone_task;
    std::vector<CloneTask>* tasks = (std::vector<CloneTask>*)data;
    if (!local_repo.isValid()) {
        for (size_t i=0; i < tasks->size(); ++i) {
            clone_task = tasks->at(i);
            if (clone_task.repo_id == item->repo().id) {
                item->setCloneTask(clone_task);
                QModelIndex index = indexFromItem(item);
                emit dataChanged(index,index);
            }
        }
    }
}
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
/// \file  string.cpp
//------------------------------------------------------------------------------
/// \brief Implementation of general purpose functions for string processing
//------------------------------------------------------------------------------
// Copyright (c) 2010 Serge Aleynikov <saleyn@gmail.com>
// Created: 2010-05-06
//------------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project.

Copyright (C) 2010 Serge Aleynikov <saleyn@gmail.com>

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

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

***** END LICENSE BLOCK *****
*/

#include <utxx/string.hpp>
#include <utxx/print_opts.hpp>

namespace utxx {

std::string to_bin_string(const char* buf, size_t sz,
                          bool hex, bool readable, bool eol)
{
    std::stringstream out;
    const char* begin = buf, *end = buf + sz;
    print_opts  opts  = hex
                      ? (readable ? print_opts::printable_or_hex : print_opts::hex)
                      : (readable ? print_opts::printable_or_dec : print_opts::dec);
    output(out, begin, end, opts, ",", "", "\"", "<<", ">>");
    if (eol) out << std::endl;
    return out.str();
}

bool wildcard_match(const char* a_input, const char* a_pattern)
{
    // Pattern match on everything that follows '*', and exit
    // at the end of the input string
    for(const char* ip = nullptr, *pp = nullptr; *a_input;)
        if (*a_pattern == '*') {
            if (!*++a_pattern)
                return true;    // Reached end of pattern

            pp = a_pattern;     // Store state after '*'
            ip = a_input+1;
        } else if ((*a_pattern == *a_input) || (*a_pattern == '?')) {
            a_pattern++;        // Continue successful match
            a_input++;
        } else if (pp) {
            a_pattern = pp;     // Match failed - restore state of pattern after '*'
            a_input   = ip++;
        } else
            return false;       // Match failed before the first wildcard is found

    // Skip trailing '*' in the pattern, since they don't affect the outcome:
    while (*a_pattern == '*') a_pattern++;

    // Are both input and pattern complete?
    return !*a_pattern;
}

} // namespace utxx
<commit_msg>Unify var names<commit_after>//------------------------------------------------------------------------------
/// \file  string.cpp
//------------------------------------------------------------------------------
/// \brief Implementation of general purpose functions for string processing
//------------------------------------------------------------------------------
// Copyright (c) 2010 Serge Aleynikov <saleyn@gmail.com>
// Created: 2010-05-06
//------------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project.

Copyright (C) 2010 Serge Aleynikov <saleyn@gmail.com>

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

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

***** END LICENSE BLOCK *****
*/

#include <utxx/string.hpp>
#include <utxx/print_opts.hpp>

namespace utxx {

std::string to_bin_string(const char* a_buf, size_t a_sz,
                          bool a_hex, bool a_readable, bool a_eol)
{
    std::stringstream out;
    const char* begin = a_buf, *end = a_buf + a_sz;
    print_opts  opts  = a_hex
                      ? (a_readable ? print_opts::printable_or_hex : print_opts::hex)
                      : (a_readable ? print_opts::printable_or_dec : print_opts::dec);
    output(out, begin, end, opts, ",", "", "\"", "<<", ">>");
    if (a_eol) out << std::endl;
    return out.str();
}

bool wildcard_match(const char* a_input, const char* a_pattern)
{
    // Pattern match on everything that follows '*', and exit
    // at the end of the input string
    for(const char* ip = nullptr, *pp = nullptr; *a_input;)
        if (*a_pattern == '*') {
            if (!*++a_pattern)
                return true;    // Reached end of pattern

            pp = a_pattern;     // Store state after '*'
            ip = a_input+1;
        } else if ((*a_pattern == *a_input) || (*a_pattern == '?')) {
            a_pattern++;        // Continue successful match
            a_input++;
        } else if (pp) {
            a_pattern = pp;     // Match failed - restore state of pattern after '*'
            a_input   = ip++;
        } else
            return false;       // Match failed before the first wildcard is found

    // Skip trailing '*' in the pattern, since they don't affect the outcome:
    while (*a_pattern == '*') a_pattern++;

    // Are both input and pattern complete?
    return !*a_pattern;
}

} // namespace utxx
<|endoftext|>


<commit_before>/*
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef BENG_PROXY_STRSET_HXX
#define BENG_PROXY_STRSET_HXX

#include <inline/compiler.h>

#include <boost/intrusive/slist.hpp>

#include <stddef.h>

struct pool;

/**
 * An unordered set of strings.
 */
struct StringSet {
    struct Item : boost::intrusive::slist_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> {
        const char *value;
    };

    typedef boost::intrusive::slist<Item,
                                    boost::intrusive::constant_time_size<false>> List;

    List list;

    StringSet() = default;
    StringSet(const StringSet &) = delete;
    StringSet(StringSet &&) = default;
    StringSet &operator=(const StringSet &) = delete;
    StringSet &operator=(StringSet &&src) = default;

    void Init() {
        list.clear();
    }

    gcc_pure
    bool IsEmpty() const {
        return list.empty();
    }

    gcc_pure
    bool Contains(const char *p) const;

    /**
     * Add a string to the set.  It does not check whether the string
     * already exists.
     *
     * @param p the string value which must be allocated by the caller
     * @param pool a pool that is used to allocate the node (not the value)
     */
    void Add(struct pool &pool, const char *p);

    /**
     * Copy all strings from one set to this, creating duplicates of
     * all values from the specified pool.
     */
    void CopyFrom(struct pool &pool, const StringSet &s);

    class const_iterator {
        List::const_iterator i;

    public:
        const_iterator(List::const_iterator _i):i(_i) {}

        bool operator!=(const const_iterator &other) const {
            return i != other.i;
        }

        const char *operator*() const {
            return i->value;
        }

        const_iterator &operator++() {
            ++i;
            return *this;
        }
    };

    const_iterator begin() const {
        return list.begin();
    }

    const_iterator end() const {
        return list.end();
    }
};

#endif
<commit_msg>strset: convert to class, make attributes private<commit_after>/*
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef BENG_PROXY_STRSET_HXX
#define BENG_PROXY_STRSET_HXX

#include <inline/compiler.h>

#include <boost/intrusive/slist.hpp>

#include <stddef.h>

struct pool;

/**
 * An unordered set of strings.
 */
class StringSet {
    struct Item : boost::intrusive::slist_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> {
        const char *value;
    };

    typedef boost::intrusive::slist<Item,
                                    boost::intrusive::constant_time_size<false>> List;

    List list;

public:
    StringSet() = default;
    StringSet(const StringSet &) = delete;
    StringSet(StringSet &&) = default;
    StringSet &operator=(const StringSet &) = delete;
    StringSet &operator=(StringSet &&src) = default;

    void Init() {
        list.clear();
    }

    gcc_pure
    bool IsEmpty() const {
        return list.empty();
    }

    gcc_pure
    bool Contains(const char *p) const;

    /**
     * Add a string to the set.  It does not check whether the string
     * already exists.
     *
     * @param p the string value which must be allocated by the caller
     * @param pool a pool that is used to allocate the node (not the value)
     */
    void Add(struct pool &pool, const char *p);

    /**
     * Copy all strings from one set to this, creating duplicates of
     * all values from the specified pool.
     */
    void CopyFrom(struct pool &pool, const StringSet &s);

    class const_iterator {
        List::const_iterator i;

    public:
        const_iterator(List::const_iterator _i):i(_i) {}

        bool operator!=(const const_iterator &other) const {
            return i != other.i;
        }

        const char *operator*() const {
            return i->value;
        }

        const_iterator &operator++() {
            ++i;
            return *this;
        }
    };

    const_iterator begin() const {
        return list.begin();
    }

    const_iterator end() const {
        return list.end();
    }
};

#endif
<|endoftext|>


<commit_before>#include <opencv2/opencv.hpp>

#include <iostream>

#include "dbn/dbn.hpp"
#include "dbn/layer.hpp"
#include "dbn/conf.hpp"
#include "dbn/labels.hpp"
#include "dbn/test.hpp"

#include "detector.hpp"
#include "data.hpp"
#include "image_utils.hpp"

vector<double> mat_to_image(const cv::Mat& mat){
    vector<double> image(CELL_SIZE * CELL_SIZE);

    assert(mat.rows == CELL_SIZE);
    assert(mat.cols == CELL_SIZE);

    for(size_t i = 0; i < static_cast<size_t>(mat.rows); ++i){
        for(size_t j = 0; j < static_cast<size_t>(mat.cols); ++j){
            auto value_c = static_cast<std::size_t>(mat.at<uint8_t>(i, j));

            //TODO Rebinarize after resize

            double value_d;
            if(value_c > 200){
                value_d = 0.0;
            } else {
                value_d = 1.0;
            }

            image[i * mat.cols + j] = value_d;
        }
    }

    return image;
}

int main(int argc, char** argv ){
    if(argc < 2){
        std::cout << "Usage: sudoku <command> <options>" << std::endl;
        return -1;
    }

    std::string command(argv[1]);

    if(command == "detect"){
        if(argc < 3){
            std::cout << "Usage: sudoku detect <image>..." << std::endl;
            return -1;
        }

        if(argc == 3){
            std::string image_source_path(argv[2]);

            auto source_image = cv::imread(image_source_path.c_str(), 1);

            if (!source_image.data){
                std::cout << "Invalid source_image" << std::endl;
                return -1;
            }

            cv::Mat dest_image;
            detect(source_image, dest_image);

            cv::namedWindow("Sudoku Grid", cv::WINDOW_AUTOSIZE);
            cv::imshow("Sudoku Grid", dest_image);

            cv::waitKey(0);
        } else {
            for(size_t i = 2; i < static_cast<size_t>(argc); ++i){
                std::string image_source_path(argv[i]);

                std::cout << image_source_path << std::endl;

                auto source_image = cv::imread(image_source_path.c_str(), 1);

                if (!source_image.data){
                    std::cout << "Invalid source_image" << std::endl;
                    continue;
                }

                cv::Mat dest_image;
                detect(source_image, dest_image);

                image_source_path.insert(image_source_path.rfind('.'), ".lines");
                imwrite(image_source_path.c_str(), dest_image);
            }
        }
    } else if(command == "train"){
        std::vector<vector<double>> training_images;
        std::vector<uint8_t> training_labels;

        std::vector<std::vector<cv::Mat>> source_images;
        std::vector<gt_data> source_data;

        for(size_t i = 2; i < static_cast<size_t>(argc); ++i){
            std::string image_source_path(argv[i]);

            std::cout << image_source_path << std::endl;

            auto source_image = cv::imread(image_source_path.c_str(), 1);

            if (!source_image.data){
                std::cout << "Invalid source_image" << std::endl;
                continue;
            }

            auto data = read_data(image_source_path);

            cv::Mat dest_image;
            auto mats = detect(source_image, dest_image);

            for(size_t i = 0; i < 9; ++i){
                for(size_t j = 0; j < 9; ++j){
                    if(data.results[i][j]){
                        training_labels.push_back(data.results[i][j]-1);
                        training_images.emplace_back(mat_to_image(mats[i * 9 + j]));
                    }
                }
            }

            source_images.push_back(std::move(mats));
            source_data.push_back(std::move(data));
        }

        std::cout << "Train with " << source_images.size() << " sudokus" << std::endl;
        std::cout << "Train with " << training_images.size() << " cells" << std::endl;

        assert(training_labels.size() == training_images.size());
        assert(source_images.size() == source_data.size());

        auto labels = dbn::make_fake(training_labels);

        typedef dbn::dbn<
            dbn::layer<dbn::conf<true, 50, true, true>, CELL_SIZE * CELL_SIZE, 500>,
            dbn::layer<dbn::conf<true, 50, false, true>, 500, 500>,
            dbn::layer<dbn::conf<true, 50, false, true>, 500, 2000>,
            dbn::layer<dbn::conf<true, 50, false, true, true, dbn::Type::EXP>, 2000, 9>> dbn_t;

        auto dbn = std::make_unique<dbn_t>();

        dbn->display();

        std::cout << "Start pretraining" << std::endl;
        dbn->pretrain(training_images, 10);

        std::cout << "Start fine-tuning" << std::endl;
        dbn->fine_tune(training_images, labels, 10, 100);

        std::ofstream os("dbn.dat", std::ofstream::binary);
        dbn->store(os);

        auto error_rate = dbn::test_set(dbn, training_images, training_labels, dbn::predictor());

        std::cout << std::endl;
        std::cout << "DBN Error rate (normal): " << 100.0 * error_rate << "%" << std::endl;

        std::size_t sudoku_hits = 0;
        std::size_t cell_hits = 0;

        for(std::size_t i = 0; i < source_images.size(); ++i){
            const auto& image = source_images[i];
            const auto& data = source_data[i];

            std::size_t local_hits = 0;

            for(size_t i = 0; i < 9; ++i){
                for(size_t j = 0; j < 9; ++j){
                    uint8_t answer;

                    auto& cell_mat = image[i * 9 + j];

                    auto fill = fill_factor(cell_mat);

                    if(fill == 1.0f){
                        answer = 0;
                    } else {
                        answer = dbn->predict(mat_to_image(cell_mat))+1;
                    }

                    if(answer == data.results[i][j]){
                        ++local_hits;
                    }
                }
            }

            if(local_hits == 81){
                ++sudoku_hits;
            }

            cell_hits += local_hits;
        }

        auto total_s = static_cast<float>(source_images.size());
        auto total_c = total_s * 81.0f;

        std::cout << "Cell Error Rate " << 100.0 * (total_c - cell_hits) / total_c << "%" << std::endl;
        std::cout << "Sudoku Error Rate " << 100.0 * (total_s - sudoku_hits) / total_s << "%" << std::endl;
    } else {
        std::cout << "Invalid command \"" << command << "\"" << std::endl;
        return -1;
    }

    return 0;
}<commit_msg>Add a test command<commit_after>#include <opencv2/opencv.hpp>

#include <iostream>

#include "dbn/dbn.hpp"
#include "dbn/layer.hpp"
#include "dbn/conf.hpp"
#include "dbn/labels.hpp"
#include "dbn/test.hpp"

#include "detector.hpp"
#include "data.hpp"
#include "image_utils.hpp"

vector<double> mat_to_image(const cv::Mat& mat){
    vector<double> image(CELL_SIZE * CELL_SIZE);

    assert(mat.rows == CELL_SIZE);
    assert(mat.cols == CELL_SIZE);

    for(size_t i = 0; i < static_cast<size_t>(mat.rows); ++i){
        for(size_t j = 0; j < static_cast<size_t>(mat.cols); ++j){
            auto value_c = static_cast<std::size_t>(mat.at<uint8_t>(i, j));

            //TODO Rebinarize after resize

            double value_d;
            if(value_c > 200){
                value_d = 0.0;
            } else {
                value_d = 1.0;
            }

            image[i * mat.cols + j] = value_d;
        }
    }

    return image;
}

int main(int argc, char** argv ){
    if(argc < 2){
        std::cout << "Usage: sudoku <command> <options>" << std::endl;
        return -1;
    }

    std::string command(argv[1]);

    if(command == "detect"){
        if(argc < 3){
            std::cout << "Usage: sudoku detect <image>..." << std::endl;
            return -1;
        }

        if(argc == 3){
            std::string image_source_path(argv[2]);

            auto source_image = cv::imread(image_source_path.c_str(), 1);

            if (!source_image.data){
                std::cout << "Invalid source_image" << std::endl;
                return -1;
            }

            cv::Mat dest_image;
            detect(source_image, dest_image);

            cv::namedWindow("Sudoku Grid", cv::WINDOW_AUTOSIZE);
            cv::imshow("Sudoku Grid", dest_image);

            cv::waitKey(0);
        } else {
            for(size_t i = 2; i < static_cast<size_t>(argc); ++i){
                std::string image_source_path(argv[i]);

                std::cout << image_source_path << std::endl;

                auto source_image = cv::imread(image_source_path.c_str(), 1);

                if (!source_image.data){
                    std::cout << "Invalid source_image" << std::endl;
                    continue;
                }

                cv::Mat dest_image;
                detect(source_image, dest_image);

                image_source_path.insert(image_source_path.rfind('.'), ".lines");
                imwrite(image_source_path.c_str(), dest_image);
            }
        }
    } else if(command == "train"){
        std::vector<vector<double>> training_images;
        std::vector<uint8_t> training_labels;

        std::vector<std::vector<cv::Mat>> source_images;
        std::vector<gt_data> source_data;

        for(size_t i = 2; i < static_cast<size_t>(argc); ++i){
            std::string image_source_path(argv[i]);

            std::cout << image_source_path << std::endl;

            auto source_image = cv::imread(image_source_path.c_str(), 1);

            if (!source_image.data){
                std::cout << "Invalid source_image" << std::endl;
                continue;
            }

            auto data = read_data(image_source_path);

            cv::Mat dest_image;
            auto mats = detect(source_image, dest_image);

            for(size_t i = 0; i < 9; ++i){
                for(size_t j = 0; j < 9; ++j){
                    if(data.results[i][j]){
                        training_labels.push_back(data.results[i][j]-1);
                        training_images.emplace_back(mat_to_image(mats[i * 9 + j]));
                    }
                }
            }

            source_images.push_back(std::move(mats));
            source_data.push_back(std::move(data));
        }

        assert(training_labels.size() == training_images.size());
        assert(source_images.size() == source_data.size());

        std::cout << "Train with " << source_images.size() << " sudokus" << std::endl;
        std::cout << "Train with " << training_images.size() << " cells" << std::endl;

        auto labels = dbn::make_fake(training_labels);

        typedef dbn::dbn<
            dbn::layer<dbn::conf<true, 50, true, true>, CELL_SIZE * CELL_SIZE, 500>,
            dbn::layer<dbn::conf<true, 50, false, true>, 500, 500>,
            dbn::layer<dbn::conf<true, 50, false, true>, 500, 2000>,
            dbn::layer<dbn::conf<true, 50, false, true, true, dbn::Type::EXP>, 2000, 9>> dbn_t;

        auto dbn = std::make_unique<dbn_t>();

        dbn->display();

        std::cout << "Start pretraining" << std::endl;
        dbn->pretrain(training_images, 10);

        std::cout << "Start fine-tuning" << std::endl;
        dbn->fine_tune(training_images, labels, 10, 100);

        std::ofstream os("dbn.dat", std::ofstream::binary);
        dbn->store(os);

        auto error_rate = dbn::test_set(dbn, training_images, training_labels, dbn::predictor());

        std::cout << std::endl;
        std::cout << "DBN Error rate (normal): " << 100.0 * error_rate << "%" << std::endl;

        std::size_t sudoku_hits = 0;
        std::size_t cell_hits = 0;

        for(std::size_t i = 0; i < source_images.size(); ++i){
            const auto& image = source_images[i];
            const auto& data = source_data[i];

            std::size_t local_hits = 0;

            for(size_t i = 0; i < 9; ++i){
                for(size_t j = 0; j < 9; ++j){
                    uint8_t answer;

                    auto& cell_mat = image[i * 9 + j];

                    auto fill = fill_factor(cell_mat);

                    if(fill == 1.0f){
                        answer = 0;
                    } else {
                        answer = dbn->predict(mat_to_image(cell_mat))+1;
                    }

                    if(answer == data.results[i][j]){
                        ++local_hits;
                    }
                }
            }

            if(local_hits == 81){
                ++sudoku_hits;
            }

            cell_hits += local_hits;
        }

        auto total_s = static_cast<float>(source_images.size());
        auto total_c = total_s * 81.0f;

        std::cout << "Cell Error Rate " << 100.0 * (total_c - cell_hits) / total_c << "%" << std::endl;
        std::cout << "Sudoku Error Rate " << 100.0 * (total_s - sudoku_hits) / total_s << "%" << std::endl;
    } else if(command == "test"){
        std::vector<std::vector<cv::Mat>> source_images;
        std::vector<gt_data> source_data;

        std::vector<vector<double>> training_images;
        std::vector<uint8_t> training_labels;

        for(size_t i = 2; i < static_cast<size_t>(argc); ++i){
            std::string image_source_path(argv[i]);

            std::cout << image_source_path << std::endl;

            auto source_image = cv::imread(image_source_path.c_str(), 1);

            if (!source_image.data){
                std::cout << "Invalid source_image" << std::endl;
                continue;
            }

            auto data = read_data(image_source_path);

            cv::Mat dest_image;
            auto mats = detect(source_image, dest_image);

            for(size_t i = 0; i < 9; ++i){
                for(size_t j = 0; j < 9; ++j){
                    if(data.results[i][j]){
                        training_labels.push_back(data.results[i][j]-1);
                        training_images.emplace_back(mat_to_image(mats[i * 9 + j]));
                    }
                }
            }

            source_images.push_back(std::move(mats));
            source_data.push_back(std::move(data));
        }

        assert(training_labels.size() == training_images.size());
        assert(source_images.size() == source_data.size());

        auto labels = dbn::make_fake(training_labels);

        typedef dbn::dbn<
            dbn::layer<dbn::conf<true, 50, true, true>, CELL_SIZE * CELL_SIZE, 500>,
            dbn::layer<dbn::conf<true, 50, false, true>, 500, 500>,
            dbn::layer<dbn::conf<true, 50, false, true>, 500, 2000>,
            dbn::layer<dbn::conf<true, 50, false, true, true, dbn::Type::EXP>, 2000, 9>> dbn_t;

        auto dbn = std::make_unique<dbn_t>();

        dbn->display();

        std::ifstream is("dbn_2000.dat", std::ofstream::binary);
        dbn->load(is);

        auto error_rate = dbn::test_set(dbn, training_images, training_labels, dbn::predictor());

        std::cout << std::endl;
        std::cout << "DBN Error rate (normal): " << 100.0 * error_rate << "%" << std::endl;

        std::size_t sudoku_hits = 0;
        std::size_t cell_hits = 0;

        for(std::size_t i = 0; i < source_images.size(); ++i){
            const auto& image = source_images[i];
            const auto& data = source_data[i];

            std::size_t local_hits = 0;

            for(size_t i = 0; i < 9; ++i){
                for(size_t j = 0; j < 9; ++j){
                    uint8_t answer;

                    auto& cell_mat = image[i * 9 + j];

                    auto fill = fill_factor(cell_mat);

                    if(fill == 1.0f){
                        answer = 0;
                    } else {
                        answer = dbn->predict(mat_to_image(cell_mat))+1;
                    }

                    if(answer == data.results[i][j]){
                        ++local_hits;
                    }
                }
            }

            if(local_hits == 81){
                ++sudoku_hits;
            }

            cell_hits += local_hits;
        }

        auto total_s = static_cast<float>(source_images.size());
        auto total_c = total_s * 81.0f;

        std::cout << "Cell Error Rate " << 100.0 * (total_c - cell_hits) / total_c << "%" << std::endl;
        std::cout << "Sudoku Error Rate " << 100.0 * (total_s - sudoku_hits) / total_s << "%" << std::endl;
    } else {
        std::cout << "Invalid command \"" << command << "\"" << std::endl;
        return -1;
    }

    return 0;
}<|endoftext|>