<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: propertysethelper.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: kz $ $Date: 2005-11-04 15:42: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
 *
 ************************************************************************/

//_________________________________________________________________________________________________________________
//  my own includes

#include <classes/propertysethelper.hxx>
#include <threadhelp/transactionguard.hxx>
#include <threadhelp/readguard.hxx>
#include <threadhelp/writeguard.hxx>

//_________________________________________________________________________________________________________________
//  interface includes

//_________________________________________________________________________________________________________________
//  other includes

//_________________________________________________________________________________________________________________
//  namespace

namespace framework{

//_________________________________________________________________________________________________________________
//  non exported definitions

//-----------------------------------------------------------------------------
PropertySetHelper::PropertySetHelper(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR             ,
                                           ::vos::IMutex*                                          pSolarMutex       ,
                                           sal_Bool                                                bReleaseLockOnCall)
    : ThreadHelpBase         (pSolarMutex                   )
    , TransactionBase        (                              )
    , m_xSMGR                (xSMGR                         )
    , m_lSimpleChangeListener(m_aLock.getShareableOslMutex())
    , m_lVetoChangeListener  (m_aLock.getShareableOslMutex())
    , m_bReleaseLockOnCall   (bReleaseLockOnCall            )
{
}

//-----------------------------------------------------------------------------
PropertySetHelper::~PropertySetHelper()
{
}

//-----------------------------------------------------------------------------
void PropertySetHelper::impl_setPropertyChangeBroadcaster(const css::uno::Reference< css::uno::XInterface >& xBroadcaster)
{
    TransactionGuard aTransaction(m_aTransactionManager, E_SOFTEXCEPTIONS);

    // SAFE ->
    WriteGuard aWriteLock(m_aLock);
    m_xBroadcaster = xBroadcaster;
    aWriteLock.unlock();
    // <- SAFE
}

//-----------------------------------------------------------------------------
void SAL_CALL PropertySetHelper::impl_addPropertyInfo(const css::beans::Property& aProperty)
    throw(css::beans::PropertyExistException,
          css::uno::Exception               )
{
    TransactionGuard aTransaction(m_aTransactionManager, E_SOFTEXCEPTIONS);

    // SAFE ->
    WriteGuard aWriteLock(m_aLock);

    PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(aProperty.Name);
    if (pIt != m_lProps.end())
        throw css::beans::PropertyExistException();

    m_lProps[aProperty.Name] = aProperty;
    // <- SAFE
}

//-----------------------------------------------------------------------------
void SAL_CALL PropertySetHelper::impl_removePropertyInfo(const ::rtl::OUString& sProperty)
    throw(css::beans::UnknownPropertyException,
          css::uno::Exception                 )
{
    TransactionGuard aTransaction(m_aTransactionManager, E_SOFTEXCEPTIONS);

    // SAFE ->
    WriteGuard aWriteLock(m_aLock);

    PropertySetHelper::TPropInfoHash::iterator pIt = m_lProps.find(sProperty);
    if (pIt == m_lProps.end())
        throw css::beans::UnknownPropertyException();

    m_lProps.erase(pIt);
    // <- SAFE
}

//-----------------------------------------------------------------------------
void SAL_CALL PropertySetHelper::impl_enablePropertySet()
{
}

//-----------------------------------------------------------------------------
void SAL_CALL PropertySetHelper::impl_disablePropertySet()
{
    TransactionGuard aTransaction(m_aTransactionManager, E_SOFTEXCEPTIONS);

    // SAFE ->
    WriteGuard aWriteLock(m_aLock);

    css::uno::Reference< css::uno::XInterface > xThis(static_cast< css::beans::XPropertySet* >(this), css::uno::UNO_QUERY);
    css::lang::EventObject aEvent(xThis);

    m_lSimpleChangeListener.disposeAndClear(aEvent);
    m_lVetoChangeListener.disposeAndClear(aEvent);
    m_lProps.free();

    aWriteLock.unlock();
    // <- SAFE
}

//-----------------------------------------------------------------------------
sal_Bool PropertySetHelper::impl_existsVeto(const css::beans::PropertyChangeEvent& aEvent)
{
    /*  Dont use the lock here!
        The used helper is threadsafe and it lives for the whole lifetime of
        our own object.
    */
    ::cppu::OInterfaceContainerHelper* pVetoListener = m_lVetoChangeListener.getContainer(aEvent.PropertyName);
    if (! pVetoListener)
        return sal_False;

    ::cppu::OInterfaceIteratorHelper pListener(*pVetoListener);
    while (pListener.hasMoreElements())
    {
        try
        {
            css::uno::Reference< css::beans::XVetoableChangeListener > xListener(
                ((css::beans::XVetoableChangeListener*)pListener.next()),
                css::uno::UNO_QUERY_THROW);
            xListener->vetoableChange(aEvent);
        }
        catch(const css::uno::RuntimeException&)
            { pListener.remove(); }
        catch(const css::beans::PropertyVetoException&)
            { return sal_True; }
    }

    return sal_False;
}

//-----------------------------------------------------------------------------
void PropertySetHelper::impl_notifyChangeListener(const css::beans::PropertyChangeEvent& aEvent)
{
    /*  Dont use the lock here!
        The used helper is threadsafe and it lives for the whole lifetime of
        our own object.
    */
    ::cppu::OInterfaceContainerHelper* pSimpleListener = m_lSimpleChangeListener.getContainer(aEvent.PropertyName);
    if (! pSimpleListener)
        return;

    ::cppu::OInterfaceIteratorHelper pListener(*pSimpleListener);
    while (pListener.hasMoreElements())
    {
        try
        {
            css::uno::Reference< css::beans::XPropertyChangeListener > xListener(
                ((css::beans::XVetoableChangeListener*)pListener.next()),
                css::uno::UNO_QUERY_THROW);
            xListener->propertyChange(aEvent);
        }
        catch(const css::uno::RuntimeException&)
            { pListener.remove(); }
    }
}

//-----------------------------------------------------------------------------
css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL PropertySetHelper::getPropertySetInfo()
    throw(css::uno::RuntimeException)
{
    TransactionGuard aTransaction(m_aTransactionManager, E_HARDEXCEPTIONS);

    css::uno::Reference< css::beans::XPropertySetInfo > xInfo(static_cast< css::beans::XPropertySetInfo* >(this), css::uno::UNO_QUERY_THROW);
    return xInfo;
}

//-----------------------------------------------------------------------------
void SAL_CALL PropertySetHelper::setPropertyValue(const ::rtl::OUString& sProperty,
                                                  const css::uno::Any&   aValue   )
    throw(css::beans::UnknownPropertyException,
          css::beans::PropertyVetoException   ,
          css::lang::IllegalArgumentException ,
          css::lang::WrappedTargetException   ,
          css::uno::RuntimeException          )
{
    // TODO look for e.g. readonly props and reject setProp() call!

    TransactionGuard aTransaction(m_aTransactionManager, E_HARDEXCEPTIONS);

    // SAFE ->
    WriteGuard aWriteLock(m_aLock);

    PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(sProperty);
    if (pIt == m_lProps.end())
        throw css::beans::UnknownPropertyException();

    css::beans::Property aPropInfo = pIt->second;

    sal_Bool bLocked = sal_True;
    if (m_bReleaseLockOnCall)
    {
        aWriteLock.unlock();
        bLocked = sal_False;
        // <- SAFE
    }

    css::uno::Any aCurrentValue = impl_getPropertyValue(aPropInfo.Name, aPropInfo.Handle);

    if (! bLocked)
    {
        // SAFE ->
        aWriteLock.lock();
        bLocked = sal_True;
    }

    sal_Bool bWillBeChanged = (aCurrentValue != aValue);
    if (! bWillBeChanged)
        return;

    css::beans::PropertyChangeEvent aEvent;
    aEvent.PropertyName   = aPropInfo.Name;
    aEvent.Further        = sal_False;
    aEvent.PropertyHandle = aPropInfo.Handle;
    aEvent.OldValue       = aCurrentValue;
    aEvent.NewValue       = aValue;
    aEvent.Source         = css::uno::Reference< css::uno::XInterface >(m_xBroadcaster.get(), css::uno::UNO_QUERY);

    if (m_bReleaseLockOnCall)
    {
        aWriteLock.unlock();
        bLocked = sal_False;
        // <- SAFE
    }

    if (impl_existsVeto(aEvent))
        throw css::beans::PropertyVetoException();

    impl_setPropertyValue(aPropInfo.Name, aPropInfo.Handle, aValue);

    impl_notifyChangeListener(aEvent);
}

//-----------------------------------------------------------------------------
css::uno::Any SAL_CALL PropertySetHelper::getPropertyValue(const ::rtl::OUString& sProperty)
    throw(css::beans::UnknownPropertyException,
          css::lang::WrappedTargetException   ,
          css::uno::RuntimeException          )
{
    TransactionGuard aTransaction(m_aTransactionManager, E_HARDEXCEPTIONS);

    // SAFE ->
    ReadGuard aReadLock(m_aLock);

    PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(sProperty);
    if (pIt == m_lProps.end())
        throw css::beans::UnknownPropertyException();

    css::beans::Property aPropInfo = pIt->second;

    sal_Bool bLocked = sal_True;
    if (m_bReleaseLockOnCall)
    {
        aReadLock.unlock();
        bLocked = sal_False;
        // <- SAFE
    }

    css::uno::Any aValue = impl_getPropertyValue(aPropInfo.Name, aPropInfo.Handle);
    return aValue;
}

//-----------------------------------------------------------------------------
void SAL_CALL PropertySetHelper::addPropertyChangeListener(const ::rtl::OUString&                                            sProperty,
                                                           const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener)
    throw(css::beans::UnknownPropertyException,
          css::lang::WrappedTargetException   ,
          css::uno::RuntimeException          )
{
    TransactionGuard aTransaction(m_aTransactionManager, E_HARDEXCEPTIONS);

    // SAFE ->
    ReadGuard aReadLock(m_aLock);

    PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(sProperty);
    if (pIt == m_lProps.end())
        throw css::beans::UnknownPropertyException();

    aReadLock.unlock();
    // <- SAFE

    m_lSimpleChangeListener.addInterface(sProperty, xListener);
}

//-----------------------------------------------------------------------------
void SAL_CALL PropertySetHelper::removePropertyChangeListener(const ::rtl::OUString&                                            sProperty,
                                                              const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener)
    throw(css::beans::UnknownPropertyException,
          css::lang::WrappedTargetException   ,
          css::uno::RuntimeException          )
{
    TransactionGuard aTransaction(m_aTransactionManager, E_SOFTEXCEPTIONS);

    // SAFE ->
    ReadGuard aReadLock(m_aLock);

    PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(sProperty);
    if (pIt == m_lProps.end())
        throw css::beans::UnknownPropertyException();

    aReadLock.unlock();
    // <- SAFE

    m_lSimpleChangeListener.removeInterface(sProperty, xListener);
}

//-----------------------------------------------------------------------------
void SAL_CALL PropertySetHelper::addVetoableChangeListener(const ::rtl::OUString&                                            sProperty,
                                                           const css::uno::Reference< css::beans::XVetoableChangeListener >& xListener)
    throw(css::beans::UnknownPropertyException,
          css::lang::WrappedTargetException   ,
          css::uno::RuntimeException          )
{
    TransactionGuard aTransaction(m_aTransactionManager, E_HARDEXCEPTIONS);

    // SAFE ->
    ReadGuard aReadLock(m_aLock);

    PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(sProperty);
    if (pIt == m_lProps.end())
        throw css::beans::UnknownPropertyException();

    aReadLock.unlock();
    // <- SAFE

    m_lVetoChangeListener.addInterface(sProperty, xListener);
}

//-----------------------------------------------------------------------------
void SAL_CALL PropertySetHelper::removeVetoableChangeListener(const ::rtl::OUString&                                            sProperty,
                                                              const css::uno::Reference< css::beans::XVetoableChangeListener >& xListener)
    throw(css::beans::UnknownPropertyException,
          css::lang::WrappedTargetException   ,
          css::uno::RuntimeException          )
{
    TransactionGuard aTransaction(m_aTransactionManager, E_SOFTEXCEPTIONS);

    // SAFE ->
    ReadGuard aReadLock(m_aLock);

    PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(sProperty);
    if (pIt == m_lProps.end())
        throw css::beans::UnknownPropertyException();

    aReadLock.unlock();
    // <- SAFE

    m_lVetoChangeListener.removeInterface(sProperty, xListener);
}

//-----------------------------------------------------------------------------
css::uno::Sequence< css::beans::Property > SAL_CALL PropertySetHelper::getProperties()
    throw(css::uno::RuntimeException)
{
    TransactionGuard aTransaction(m_aTransactionManager, E_HARDEXCEPTIONS);

    // SAFE ->
    ReadGuard aReadLock(m_aLock);

    sal_Int32                                        c     = (sal_Int32)m_lProps.size();
    css::uno::Sequence< css::beans::Property >       lProps(c);
    PropertySetHelper::TPropInfoHash::const_iterator pIt   ;

    for (  pIt  = m_lProps.begin();
           pIt != m_lProps.end()  ;
         ++pIt                    )
    {
        lProps[--c] = pIt->second;
    }

    return lProps;
    // <- SAFE
}

//-----------------------------------------------------------------------------
css::beans::Property SAL_CALL PropertySetHelper::getPropertyByName(const ::rtl::OUString& sName)
    throw(css::beans::UnknownPropertyException,
          css::uno::RuntimeException          )
{
    TransactionGuard aTransaction(m_aTransactionManager, E_HARDEXCEPTIONS);

    // SAFE ->
    ReadGuard aReadLock(m_aLock);

    PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(sName);
    if (pIt == m_lProps.end())
        throw css::beans::UnknownPropertyException();

    return pIt->second;
    // <- SAFE
}

//-----------------------------------------------------------------------------
sal_Bool SAL_CALL PropertySetHelper::hasPropertyByName(const ::rtl::OUString& sName)
    throw(css::uno::RuntimeException)
{
    TransactionGuard aTransaction(m_aTransactionManager, E_HARDEXCEPTIONS);

    // SAFE ->
    ReadGuard aReadLock(m_aLock);

    PropertySetHelper::TPropInfoHash::iterator pIt    = m_lProps.find(sName);
    sal_Bool                                   bExist = (pIt != m_lProps.end());

    return bExist;
    // <- SAFE
}

} // namespace framework
<commit_msg>INTEGRATION: CWS fwk29 (1.4.24); FILE MERGED 2005/12/12 09:41:59 as 1.4.24.1: #120310# use right TransactionManager instance ... and use it right<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: propertysethelper.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2006-02-07 10:23:55 $
 *
 *  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
 *
 ************************************************************************/

//_________________________________________________________________________________________________________________
//  my own includes

#include <classes/propertysethelper.hxx>
#include <threadhelp/transactionguard.hxx>
#include <threadhelp/readguard.hxx>
#include <threadhelp/writeguard.hxx>

//_________________________________________________________________________________________________________________
//  interface includes

//_________________________________________________________________________________________________________________
//  other includes

//_________________________________________________________________________________________________________________
//  namespace

namespace framework{

//_________________________________________________________________________________________________________________
//  non exported definitions

//-----------------------------------------------------------------------------
PropertySetHelper::PropertySetHelper(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR                       ,
                                           LockHelper*                                             pExternalLock               ,
                                           TransactionManager*                                     pExternalTransactionManager ,
                                           sal_Bool                                                bReleaseLockOnCall          )
    : m_xSMGR                (xSMGR                                )
    , m_lSimpleChangeListener(pExternalLock->getShareableOslMutex())
    , m_lVetoChangeListener  (pExternalLock->getShareableOslMutex())
    , m_bReleaseLockOnCall   (bReleaseLockOnCall                   )
    , m_rLock                (*pExternalLock                       )
    , m_rTransactionManager  (*pExternalTransactionManager         )
{
}

//-----------------------------------------------------------------------------
PropertySetHelper::~PropertySetHelper()
{
}

//-----------------------------------------------------------------------------
void PropertySetHelper::impl_setPropertyChangeBroadcaster(const css::uno::Reference< css::uno::XInterface >& xBroadcaster)
{
    TransactionGuard aTransaction(m_rTransactionManager, E_SOFTEXCEPTIONS);

    // SAFE ->
    WriteGuard aWriteLock(m_rLock);
    m_xBroadcaster = xBroadcaster;
    aWriteLock.unlock();
    // <- SAFE
}

//-----------------------------------------------------------------------------
void SAL_CALL PropertySetHelper::impl_addPropertyInfo(const css::beans::Property& aProperty)
    throw(css::beans::PropertyExistException,
          css::uno::Exception               )
{
    TransactionGuard aTransaction(m_rTransactionManager, E_SOFTEXCEPTIONS);

    // SAFE ->
    WriteGuard aWriteLock(m_rLock);

    PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(aProperty.Name);
    if (pIt != m_lProps.end())
        throw css::beans::PropertyExistException();

    m_lProps[aProperty.Name] = aProperty;
    // <- SAFE
}

//-----------------------------------------------------------------------------
void SAL_CALL PropertySetHelper::impl_removePropertyInfo(const ::rtl::OUString& sProperty)
    throw(css::beans::UnknownPropertyException,
          css::uno::Exception                 )
{
    TransactionGuard aTransaction(m_rTransactionManager, E_SOFTEXCEPTIONS);

    // SAFE ->
    WriteGuard aWriteLock(m_rLock);

    PropertySetHelper::TPropInfoHash::iterator pIt = m_lProps.find(sProperty);
    if (pIt == m_lProps.end())
        throw css::beans::UnknownPropertyException();

    m_lProps.erase(pIt);
    // <- SAFE
}

//-----------------------------------------------------------------------------
void SAL_CALL PropertySetHelper::impl_enablePropertySet()
{
}

//-----------------------------------------------------------------------------
void SAL_CALL PropertySetHelper::impl_disablePropertySet()
{
    TransactionGuard aTransaction(m_rTransactionManager, E_SOFTEXCEPTIONS);

    // SAFE ->
    WriteGuard aWriteLock(m_rLock);

    css::uno::Reference< css::uno::XInterface > xThis(static_cast< css::beans::XPropertySet* >(this), css::uno::UNO_QUERY);
    css::lang::EventObject aEvent(xThis);

    m_lSimpleChangeListener.disposeAndClear(aEvent);
    m_lVetoChangeListener.disposeAndClear(aEvent);
    m_lProps.free();

    aWriteLock.unlock();
    // <- SAFE
}

//-----------------------------------------------------------------------------
sal_Bool PropertySetHelper::impl_existsVeto(const css::beans::PropertyChangeEvent& aEvent)
{
    /*  Dont use the lock here!
        The used helper is threadsafe and it lives for the whole lifetime of
        our own object.
    */
    ::cppu::OInterfaceContainerHelper* pVetoListener = m_lVetoChangeListener.getContainer(aEvent.PropertyName);
    if (! pVetoListener)
        return sal_False;

    ::cppu::OInterfaceIteratorHelper pListener(*pVetoListener);
    while (pListener.hasMoreElements())
    {
        try
        {
            css::uno::Reference< css::beans::XVetoableChangeListener > xListener(
                ((css::beans::XVetoableChangeListener*)pListener.next()),
                css::uno::UNO_QUERY_THROW);
            xListener->vetoableChange(aEvent);
        }
        catch(const css::uno::RuntimeException&)
            { pListener.remove(); }
        catch(const css::beans::PropertyVetoException&)
            { return sal_True; }
    }

    return sal_False;
}

//-----------------------------------------------------------------------------
void PropertySetHelper::impl_notifyChangeListener(const css::beans::PropertyChangeEvent& aEvent)
{
    /*  Dont use the lock here!
        The used helper is threadsafe and it lives for the whole lifetime of
        our own object.
    */
    ::cppu::OInterfaceContainerHelper* pSimpleListener = m_lSimpleChangeListener.getContainer(aEvent.PropertyName);
    if (! pSimpleListener)
        return;

    ::cppu::OInterfaceIteratorHelper pListener(*pSimpleListener);
    while (pListener.hasMoreElements())
    {
        try
        {
            css::uno::Reference< css::beans::XPropertyChangeListener > xListener(
                ((css::beans::XVetoableChangeListener*)pListener.next()),
                css::uno::UNO_QUERY_THROW);
            xListener->propertyChange(aEvent);
        }
        catch(const css::uno::RuntimeException&)
            { pListener.remove(); }
    }
}

//-----------------------------------------------------------------------------
css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL PropertySetHelper::getPropertySetInfo()
    throw(css::uno::RuntimeException)
{
    TransactionGuard aTransaction(m_rTransactionManager, E_HARDEXCEPTIONS);

    css::uno::Reference< css::beans::XPropertySetInfo > xInfo(static_cast< css::beans::XPropertySetInfo* >(this), css::uno::UNO_QUERY_THROW);
    return xInfo;
}

//-----------------------------------------------------------------------------
void SAL_CALL PropertySetHelper::setPropertyValue(const ::rtl::OUString& sProperty,
                                                  const css::uno::Any&   aValue   )
    throw(css::beans::UnknownPropertyException,
          css::beans::PropertyVetoException   ,
          css::lang::IllegalArgumentException ,
          css::lang::WrappedTargetException   ,
          css::uno::RuntimeException          )
{
    // TODO look for e.g. readonly props and reject setProp() call!

    TransactionGuard aTransaction(m_rTransactionManager, E_HARDEXCEPTIONS);

    // SAFE ->
    WriteGuard aWriteLock(m_rLock);

    PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(sProperty);
    if (pIt == m_lProps.end())
        throw css::beans::UnknownPropertyException();

    css::beans::Property aPropInfo = pIt->second;

    sal_Bool bLocked = sal_True;
    if (m_bReleaseLockOnCall)
    {
        aWriteLock.unlock();
        bLocked = sal_False;
        // <- SAFE
    }

    css::uno::Any aCurrentValue = impl_getPropertyValue(aPropInfo.Name, aPropInfo.Handle);

    if (! bLocked)
    {
        // SAFE ->
        aWriteLock.lock();
        bLocked = sal_True;
    }

    sal_Bool bWillBeChanged = (aCurrentValue != aValue);
    if (! bWillBeChanged)
        return;

    css::beans::PropertyChangeEvent aEvent;
    aEvent.PropertyName   = aPropInfo.Name;
    aEvent.Further        = sal_False;
    aEvent.PropertyHandle = aPropInfo.Handle;
    aEvent.OldValue       = aCurrentValue;
    aEvent.NewValue       = aValue;
    aEvent.Source         = css::uno::Reference< css::uno::XInterface >(m_xBroadcaster.get(), css::uno::UNO_QUERY);

    if (m_bReleaseLockOnCall)
    {
        aWriteLock.unlock();
        bLocked = sal_False;
        // <- SAFE
    }

    if (impl_existsVeto(aEvent))
        throw css::beans::PropertyVetoException();

    impl_setPropertyValue(aPropInfo.Name, aPropInfo.Handle, aValue);

    impl_notifyChangeListener(aEvent);
}

//-----------------------------------------------------------------------------
css::uno::Any SAL_CALL PropertySetHelper::getPropertyValue(const ::rtl::OUString& sProperty)
    throw(css::beans::UnknownPropertyException,
          css::lang::WrappedTargetException   ,
          css::uno::RuntimeException          )
{
    TransactionGuard aTransaction(m_rTransactionManager, E_HARDEXCEPTIONS);

    // SAFE ->
    ReadGuard aReadLock(m_rLock);

    PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(sProperty);
    if (pIt == m_lProps.end())
        throw css::beans::UnknownPropertyException();

    css::beans::Property aPropInfo = pIt->second;

    sal_Bool bLocked = sal_True;
    if (m_bReleaseLockOnCall)
    {
        aReadLock.unlock();
        bLocked = sal_False;
        // <- SAFE
    }

    css::uno::Any aValue = impl_getPropertyValue(aPropInfo.Name, aPropInfo.Handle);
    return aValue;
}

//-----------------------------------------------------------------------------
void SAL_CALL PropertySetHelper::addPropertyChangeListener(const ::rtl::OUString&                                            sProperty,
                                                           const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener)
    throw(css::beans::UnknownPropertyException,
          css::lang::WrappedTargetException   ,
          css::uno::RuntimeException          )
{
    TransactionGuard aTransaction(m_rTransactionManager, E_HARDEXCEPTIONS);

    // SAFE ->
    ReadGuard aReadLock(m_rLock);

    PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(sProperty);
    if (pIt == m_lProps.end())
        throw css::beans::UnknownPropertyException();

    aReadLock.unlock();
    // <- SAFE

    m_lSimpleChangeListener.addInterface(sProperty, xListener);
}

//-----------------------------------------------------------------------------
void SAL_CALL PropertySetHelper::removePropertyChangeListener(const ::rtl::OUString&                                            sProperty,
                                                              const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener)
    throw(css::beans::UnknownPropertyException,
          css::lang::WrappedTargetException   ,
          css::uno::RuntimeException          )
{
    TransactionGuard aTransaction(m_rTransactionManager, E_SOFTEXCEPTIONS);

    // SAFE ->
    ReadGuard aReadLock(m_rLock);

    PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(sProperty);
    if (pIt == m_lProps.end())
        throw css::beans::UnknownPropertyException();

    aReadLock.unlock();
    // <- SAFE

    m_lSimpleChangeListener.removeInterface(sProperty, xListener);
}

//-----------------------------------------------------------------------------
void SAL_CALL PropertySetHelper::addVetoableChangeListener(const ::rtl::OUString&                                            sProperty,
                                                           const css::uno::Reference< css::beans::XVetoableChangeListener >& xListener)
    throw(css::beans::UnknownPropertyException,
          css::lang::WrappedTargetException   ,
          css::uno::RuntimeException          )
{
    TransactionGuard aTransaction(m_rTransactionManager, E_HARDEXCEPTIONS);

    // SAFE ->
    ReadGuard aReadLock(m_rLock);

    PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(sProperty);
    if (pIt == m_lProps.end())
        throw css::beans::UnknownPropertyException();

    aReadLock.unlock();
    // <- SAFE

    m_lVetoChangeListener.addInterface(sProperty, xListener);
}

//-----------------------------------------------------------------------------
void SAL_CALL PropertySetHelper::removeVetoableChangeListener(const ::rtl::OUString&                                            sProperty,
                                                              const css::uno::Reference< css::beans::XVetoableChangeListener >& xListener)
    throw(css::beans::UnknownPropertyException,
          css::lang::WrappedTargetException   ,
          css::uno::RuntimeException          )
{
    TransactionGuard aTransaction(m_rTransactionManager, E_SOFTEXCEPTIONS);

    // SAFE ->
    ReadGuard aReadLock(m_rLock);

    PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(sProperty);
    if (pIt == m_lProps.end())
        throw css::beans::UnknownPropertyException();

    aReadLock.unlock();
    // <- SAFE

    m_lVetoChangeListener.removeInterface(sProperty, xListener);
}

//-----------------------------------------------------------------------------
css::uno::Sequence< css::beans::Property > SAL_CALL PropertySetHelper::getProperties()
    throw(css::uno::RuntimeException)
{
    TransactionGuard aTransaction(m_rTransactionManager, E_HARDEXCEPTIONS);

    // SAFE ->
    ReadGuard aReadLock(m_rLock);

    sal_Int32                                        c     = (sal_Int32)m_lProps.size();
    css::uno::Sequence< css::beans::Property >       lProps(c);
    PropertySetHelper::TPropInfoHash::const_iterator pIt   ;

    for (  pIt  = m_lProps.begin();
           pIt != m_lProps.end()  ;
         ++pIt                    )
    {
        lProps[--c] = pIt->second;
    }

    return lProps;
    // <- SAFE
}

//-----------------------------------------------------------------------------
css::beans::Property SAL_CALL PropertySetHelper::getPropertyByName(const ::rtl::OUString& sName)
    throw(css::beans::UnknownPropertyException,
          css::uno::RuntimeException          )
{
    TransactionGuard aTransaction(m_rTransactionManager, E_HARDEXCEPTIONS);

    // SAFE ->
    ReadGuard aReadLock(m_rLock);

    PropertySetHelper::TPropInfoHash::const_iterator pIt = m_lProps.find(sName);
    if (pIt == m_lProps.end())
        throw css::beans::UnknownPropertyException();

    return pIt->second;
    // <- SAFE
}

//-----------------------------------------------------------------------------
sal_Bool SAL_CALL PropertySetHelper::hasPropertyByName(const ::rtl::OUString& sName)
    throw(css::uno::RuntimeException)
{
    TransactionGuard aTransaction(m_rTransactionManager, E_HARDEXCEPTIONS);

    // SAFE ->
    ReadGuard aReadLock(m_rLock);

    PropertySetHelper::TPropInfoHash::iterator pIt    = m_lProps.find(sName);
    sal_Bool                                   bExist = (pIt != m_lProps.end());

    return bExist;
    // <- SAFE
}

} // namespace framework
<|endoftext|>


<commit_before>// Copyright 2010-2012 RethinkDB, all rights reserved.
#include <string.h>
#include <algorithm>

#include "rdb_protocol/exceptions.hpp"
#include "rdb_protocol/rdb_protocol_json.hpp"
#include "utils.hpp"

write_message_t &operator<<(write_message_t &msg, const boost::shared_ptr<scoped_cJSON_t> &cjson) {
    rassert(NULL != cjson.get() && NULL != cjson->get());
    msg << *cjson->get();
    return msg;
}

MUST_USE archive_result_t deserialize(read_stream_t *s, boost::shared_ptr<scoped_cJSON_t> *cjson) {
    cJSON *data = cJSON_CreateBlank();

    archive_result_t res = deserialize(s, data);
    if (res) { return res; }

    *cjson = boost::shared_ptr<scoped_cJSON_t>(new scoped_cJSON_t(data));

    return ARCHIVE_SUCCESS;
}

namespace query_language {

/* In a less ridiculous world, the C++ standard wouldn't have dropped designated
   initializers for arrays, and this namespace wouldn't be necessary. */
namespace cJSON_type_ordering {
struct rank_wrapper {
    std::map<int, int> rank;
    rank_wrapper() {
        rank[cJSON_Array]  = 0;
        rank[cJSON_False]  = 1;
        rank[cJSON_True]   = 2;
        rank[cJSON_NULL]   = 3;
        rank[cJSON_Number] = 4;
        rank[cJSON_Object] = 5;
        rank[cJSON_String] = 6;
    }
};
rank_wrapper wrapper;
int cmp(int t1, int t2) { return wrapper.rank[t1] - wrapper.rank[t2]; }
}

class char_star_cmp_functor {
public:
    bool operator()(const char *x, const char *y) {
        return strcmp(x, y) < 0;
    }
};

class compare_functor {
public:
    bool operator()(const std::pair<std::string, cJSON *> &l, const std::pair<std::string, cJSON *> &r) {
        if (l.first != r.first) {
            return l.first < r.first;
        } else {
            return json_cmp(l.second, r.second);
        }
    }
};

int json_cmp(cJSON *l, cJSON *r) {
    if (l->type != r->type) {
        return cJSON_type_ordering::cmp(l->type, r->type);
    }
    switch (l->type) {
        case cJSON_False:
            if (r->type == cJSON_True) {
                return -1;
            } else if (r->type == cJSON_False) {
                return 0;
            }
            break;
        case cJSON_True:
            if (r->type == cJSON_True) {
                return 0;
            } else if (r->type == cJSON_False) {
                return 1;
            }
            break;
        case cJSON_NULL:
            return 0;
            break;
        case cJSON_Number:
            if (l->valuedouble < r->valuedouble) {
                return -1;
            } else if (l->valuedouble > r->valuedouble) {
                return 1;
            } else {
                return 0;   // TODO: Handle NaN?
            }
            break;
        case cJSON_String:
            return strcmp(l->valuestring, r->valuestring);
            break;
        case cJSON_Array:
            {
                int lsize = cJSON_GetArraySize(l),
                    rsize = cJSON_GetArraySize(r);
                for (int i = 0; i < lsize; ++i) {
                    if (i >= rsize) {
                        return 1;  // e.g. cmp([0, 1], [0])
                    }
                    int cmp = json_cmp(cJSON_GetArrayItem(l, i), cJSON_GetArrayItem(r, i));
                    if (cmp) {
                        return cmp;
                    }
                }
                if (rsize > lsize) return -1;  // e.g. cmp([0], [0, 1]);
                return 0;
            }
            break;
        case cJSON_Object:
            {
                std::map<char *, cJSON *, char_star_cmp_functor> lvalues, rvalues;
                json_iterator_t l_json_it(l);

                while (cJSON *cur = l_json_it.next()) {
                    //guarantee makes sure there are no duplicates
                    guarantee(lvalues.insert(std::make_pair(cur->string, cur)).second);
                }

                json_iterator_t r_json_it(r);
                while (cJSON *cur = r_json_it.next()) {
                    //guarantee makes sure there are no duplicates
                    guarantee(rvalues.insert(std::make_pair(cur->string, cur)).second);
                }

                if (lexicographical_compare(lvalues.begin(), lvalues.end(), rvalues.begin(), rvalues.end(), compare_functor())) {
                    return -1;
                } else if (lexicographical_compare(rvalues.begin(), rvalues.end(), lvalues.begin(), lvalues.end(), compare_functor())) {
                    return 1;
                } else {
                    return 0;
                }
            }

            break;
        default:
            unreachable();
            break;
    }
    unreachable();
}

void require_type(const cJSON *json, int type, const backtrace_t &b) {
    if (json->type != type) {
        throw runtime_exc_t(strprintf("Required type: %s but found %s.",
                                      cJSON_type_to_string(type).c_str(),
                                      cJSON_type_to_string(json->type).c_str()),
                            b);
    }
}

} // namespace query_language
<commit_msg>Fixes an issue that would have caused us to segfault.<commit_after>// Copyright 2010-2012 RethinkDB, all rights reserved.
#include <string.h>
#include <algorithm>

#include "rdb_protocol/exceptions.hpp"
#include "rdb_protocol/rdb_protocol_json.hpp"
#include "utils.hpp"

write_message_t &operator<<(write_message_t &msg, const boost::shared_ptr<scoped_cJSON_t> &cjson) {
    rassert(NULL != cjson.get() && NULL != cjson->get());
    msg << *cjson->get();
    return msg;
}

MUST_USE archive_result_t deserialize(read_stream_t *s, boost::shared_ptr<scoped_cJSON_t> *cjson) {
    cJSON *data = cJSON_CreateBlank();

    archive_result_t res = deserialize(s, data);
    if (res) { return res; }

    *cjson = boost::shared_ptr<scoped_cJSON_t>(new scoped_cJSON_t(data));

    return ARCHIVE_SUCCESS;
}

namespace query_language {

/* In a less ridiculous world, the C++ standard wouldn't have dropped designated
   initializers for arrays, and this namespace wouldn't be necessary. */
namespace cJSON_type_ordering {
struct rank_wrapper {
    std::map<int, int> rank;
    rank_wrapper() {
        rank[cJSON_Array]  = 0;
        rank[cJSON_False]  = 1;
        rank[cJSON_True]   = 2;
        rank[cJSON_NULL]   = 3;
        rank[cJSON_Number] = 4;
        rank[cJSON_Object] = 5;
        rank[cJSON_String] = 6;
    }
};
rank_wrapper wrapper;
int cmp(int t1, int t2) { return wrapper.rank[t1] - wrapper.rank[t2]; }
}

class char_star_cmp_functor {
public:
    bool operator()(const char *x, const char *y) {
        return strcmp(x, y) < 0;
    }
};

class compare_functor {
public:
    bool operator()(const std::pair<std::string, cJSON *> &l, const std::pair<std::string, cJSON *> &r) {
        if (l.first != r.first) {
            return l.first < r.first;
        } else {
            return json_cmp(l.second, r.second);
        }
    }
};

int json_cmp(cJSON *l, cJSON *r) {
    if (l->type != r->type) {
        return cJSON_type_ordering::cmp(l->type, r->type);
    }
    switch (l->type) {
        case cJSON_False:
            if (r->type == cJSON_True) {
                return -1;
            } else if (r->type == cJSON_False) {
                return 0;
            }
            break;
        case cJSON_True:
            if (r->type == cJSON_True) {
                return 0;
            } else if (r->type == cJSON_False) {
                return 1;
            }
            break;
        case cJSON_NULL:
            return 0;
            break;
        case cJSON_Number:
            if (l->valuedouble < r->valuedouble) {
                return -1;
            } else if (l->valuedouble > r->valuedouble) {
                return 1;
            } else {
                return 0;   // TODO: Handle NaN?
            }
            break;
        case cJSON_String:
            return strcmp(l->valuestring, r->valuestring);
            break;
        case cJSON_Array:
            {
                int lsize = cJSON_GetArraySize(l),
                    rsize = cJSON_GetArraySize(r);
                for (int i = 0; i < lsize; ++i) {
                    if (i >= rsize) {
                        return 1;  // e.g. cmp([0, 1], [0])
                    }
                    int cmp = json_cmp(cJSON_GetArrayItem(l, i), cJSON_GetArrayItem(r, i));
                    if (cmp != 0) {
                        return cmp;
                    }
                }
                if (rsize > lsize) return -1;  // e.g. cmp([0], [0, 1]);
                return 0;
            }
            break;
        case cJSON_Object:
            {
                std::map<char *, cJSON *, char_star_cmp_functor> lvalues, rvalues;
                json_iterator_t l_json_it(l);

                while (cJSON *cur = l_json_it.next()) {
                    //If this guarantee trips we would have segfaulted on insertion
                    guarantee(cur->string != NULL, "cJSON object is in a map but has no key set... something has gone wrong with cJSON.");
                    //guarantee makes sure there are no duplicates
                    guarantee(lvalues.insert(std::make_pair(cur->string, cur)).second);
                }

                json_iterator_t r_json_it(r);
                while (cJSON *cur = r_json_it.next()) {
                    //If this guarantee trips we would have segfaulted on insertion
                    guarantee(cur->string != NULL, "cJSON object is in a map but has no key set... something has gone wrong with cJSON.");
                    //guarantee makes sure there are no duplicates
                    guarantee(rvalues.insert(std::make_pair(cur->string, cur)).second);
                }

                if (lexicographical_compare(lvalues.begin(), lvalues.end(), rvalues.begin(), rvalues.end(), compare_functor())) {
                    return -1;
                } else if (lexicographical_compare(rvalues.begin(), rvalues.end(), lvalues.begin(), lvalues.end(), compare_functor())) {
                    return 1;
                } else {
                    return 0;
                }
            }

            break;
        default:
            unreachable();
            break;
    }
    unreachable();
}

void require_type(const cJSON *json, int type, const backtrace_t &b) {
    if (json->type != type) {
        throw runtime_exc_t(strprintf("Required type: %s but found %s.",
                                      cJSON_type_to_string(type).c_str(),
                                      cJSON_type_to_string(json->type).c_str()),
                            b);
    }
}

} // namespace query_language
<|endoftext|>


<commit_before>#include "MaterialEditorScene.hh"
#include <imgui/imgui.h>
#include <Utils/OpenGL.hh>
#include <Convertor/MaterialConvertor.hpp>
#include <Utils/Directory.hpp>
#include <Utils/Path.hpp>
#include <Utils/FileSystemHelpers.hpp>
#include <EditorConfiguration.hpp>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>

namespace AGE
{
	static const char const *_nameTexture[ModeTexture::size] = {
		"ambient texture",
		"diffuse texture",
		"emissive texture",
		"reflective texture",
		"specular texture",
		"normal texture",
		"bump texture"
	};

	const std::string MaterialEditorScene::Name = "MaterialEditor";

	MaterialEditorScene::MaterialEditorScene(AGE::Engine *engine)
		: AScene(engine),
		_mode(ModeMaterialEditor::selectMaterial),
		_indexMaterial(-1)
	{
		_resetEdition();
	}

	MaterialEditorScene::~MaterialEditorScene(void)
	{
	}

	bool MaterialEditorScene::_userStart()
	{
		return true;
	}

	void MaterialEditorScene::_resetEdition()
	{
		_editModeName = false;
		_indexSubMaterial = -1;
		memset(_bufferName, 0, NAME_LENGTH);
		for (auto index = 0; index < ModeTexture::size; ++index) {
			memset(_bufferTexture[index], 0, TEXTURE_LENGTH);
		}
		for (auto index = 0; index < ModeTexture::size; ++index) {
			_editModeTexture[index] = false;
		}
	}

	void MaterialEditorScene::_selectMaterial()
	{
		const std::string currentDir = Directory::GetCurrentDirectory();
		const std::string absPath = Path::AbsoluteName(currentDir.c_str(), WE::EditorConfiguration::GetCookedDirectory().c_str());
		std::vector<std::string> materialGettable;
		std::vector<std::string> materialFullPath;
		Directory dir;
		const bool succeed = dir.open(absPath.c_str());
		AGE_ASSERT(succeed && "Impossible to open directory");
		for (auto it = dir.recursive_begin(); it != dir.recursive_end(); ++it)
		{
			if (Directory::IsFile(*it) && AGE::FileSystemHelpers::GetExtension(*it) == "mage")
			{
				materialGettable.push_back(std::string(Path::RelativeName(absPath.c_str(), *it)));
				materialFullPath.push_back(*it);
			}
		}
		dir.close();
		char const **matListBox = new char const *[materialGettable.size()];
		for (auto index = 0; index < materialFullPath.size(); ++index) {
			matListBox[index] = materialGettable[index].c_str();
		}
		ImGui::ListBox("List of material existing", &_indexMaterial, matListBox, materialFullPath.size());
		delete[] matListBox;
		if (_indexMaterial != -1 && ImGui::Button("open a material"))
		{
			_resetEdition();
			std::shared_ptr<MaterialDataSet> material_data_set = std::make_shared<MaterialDataSet>();
			std::ifstream ifs(materialFullPath[_indexMaterial]);
			cereal::PortableBinaryInputArchive ar(ifs);
			ar(*material_data_set.get());
			_current = *material_data_set;
			if (_current.name == "")
			{
				std::string fileName = std::string(materialGettable[_indexMaterial]);
				_current.name = fileName.substr(0, fileName.find('.'));
			}
			_mode = ModeMaterialEditor::selectSubMaterial;
		}
		if (_indexMaterial == -1)
		{
			ImGui::Text("Please select one material for edition");
		}
	}

	void MaterialEditorScene::_editTexture(ModeTexture mode, std::string &current)
	{
		if (!_editModeTexture[mode])
		{
			if (current.empty())
				ImGui::Text(std::string("No " + std::string(_nameTexture[mode]) +  "...").c_str());
			else
				ImGui::Text(current.c_str());
			ImGui::SameLine();
			if (ImGui::Button("Edit texture"))
				_editModeTexture[mode] = true;
		}
		else
		{
			ImGui::InputText(_nameTexture[mode], _bufferTexture[mode], NAME_LENGTH);
			ImGui::SameLine();
			if (ImGui::Button("valid new texture"))
			{
				current = std::string(_bufferName);
				_editModeTexture[mode] = false;
			}
		}
	}

	void MaterialEditorScene::_editName()
	{
		if (!_editModeName)
		{
			if (_current.name.empty())
				ImGui::Text("No name...");
			else
				ImGui::Text(_current.name.c_str());
			ImGui::SameLine();
			if (ImGui::Button("Edit name"))
				_editModeName = true;
		}
		else
		{
			ImGui::InputText("", _bufferName, NAME_LENGTH);
			ImGui::SameLine();
			if (ImGui::Button("valid new name"))
			{
				_current.name = std::string(_bufferName);
				_editModeName = false;
			}
		}
	}

	void MaterialEditorScene::_selectSubMaterial()
	{
		if (ImGui::Button("precedent"))
			_mode = ModeMaterialEditor::selectMaterial;
		ImGui::Separator();
		ImGui::Spacing();
		_editName();
		std::vector<std::string> subMaterials;
		for (auto index = 0; index < _current.collection.size(); ++index)
			subMaterials.emplace_back(std::string("sub material: ") + std::to_string(index));
		char const **matListBox = new char const *[_current.collection.size()];
		for (auto index = 0; index < _current.collection.size(); ++index)
			matListBox[index] = subMaterials[index].c_str();
		ImGui::ListBox("List of sub material", &_indexSubMaterial, matListBox, _current.collection.size());
		delete[] matListBox;
		if (_indexSubMaterial != -1 && ImGui::Button("open a sub material"))
			_mode = ModeMaterialEditor::edit;
		if (_indexSubMaterial == -1)
			ImGui::Text("Please select one sub material for edition");
		_saveEdit();
	}

	void MaterialEditorScene::_saveEdit()
	{
		if (ImGui::Button("Save Edition")) {
			const std::string currentDir = Directory::GetCurrentDirectory();
			const std::string absPath = Path::AbsoluteName(currentDir.c_str(), WE::EditorConfiguration::GetCookedDirectory().c_str());
			std::ofstream file(absPath + _current.name + ".mage");
			cereal::PortableBinaryOutputArchive ar(file);
			ar(_current);
		}
	}

	void MaterialEditorScene::_editData()
	{
		if (ImGui::Button("precedent"))
			_mode = ModeMaterialEditor::selectSubMaterial;
		MaterialData &mat = _current.collection[_indexSubMaterial];
		ImGui::InputFloat3("ambient", glm::value_ptr(mat.ambient));
		ImGui::InputFloat3("diffuse", glm::value_ptr(mat.diffuse));
		ImGui::InputFloat3("emissive", glm::value_ptr(mat.emissive));
		ImGui::InputFloat3("reflective", glm::value_ptr(mat.reflective));
		ImGui::InputFloat3("specular", glm::value_ptr(mat.specular));
		_editTexture(ModeTexture::diffuse, mat.diffuseTexPath);
		_editTexture(ModeTexture::specular, mat.specularTexPath);
		_editTexture(ModeTexture::ambient, mat.ambientTexPath);
		_editTexture(ModeTexture::reflective, mat.reflectiveTexPath);
		_editTexture(ModeTexture::emissive, mat.emissiveTexPath);
		_editTexture(ModeTexture::normal, mat.reflectiveTexPath);
		_editTexture(ModeTexture::bump, mat.bumpTexPath);
		_saveEdit();
	}

	bool MaterialEditorScene::_userUpdateBegin(float time)
	{
		glClear(GL_COLOR_BUFFER_BIT);
		ImGui::BeginChild("Material editor", ImVec2(0, 0), true);
		switch (_mode) {
		case ModeMaterialEditor::selectMaterial:
			_selectMaterial();
			break;
		case ModeMaterialEditor::selectSubMaterial:
			_selectSubMaterial();
			break;
		case ModeMaterialEditor::edit:
			_editData();
			break;
		}
		return true;
	}

	bool MaterialEditorScene::_userUpdateEnd(float time)
	{
		ImGui::EndChild();
		ImGui::End();
		return true;
	}
}<commit_msg>Crash fix when loading materials<commit_after>#include "MaterialEditorScene.hh"
#include <imgui/imgui.h>
#include <Utils/OpenGL.hh>
#include <Convertor/MaterialConvertor.hpp>
#include <Utils/Directory.hpp>
#include <Utils/Path.hpp>
#include <Utils/FileSystemHelpers.hpp>
#include <EditorConfiguration.hpp>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>

namespace AGE
{
	static const char const *_nameTexture[ModeTexture::size] = {
		"ambient texture",
		"diffuse texture",
		"emissive texture",
		"reflective texture",
		"specular texture",
		"normal texture",
		"bump texture"
	};

	const std::string MaterialEditorScene::Name = "MaterialEditor";

	MaterialEditorScene::MaterialEditorScene(AGE::Engine *engine)
		: AScene(engine),
		_mode(ModeMaterialEditor::selectMaterial),
		_indexMaterial(-1)
	{
		_resetEdition();
	}

	MaterialEditorScene::~MaterialEditorScene(void)
	{
	}

	bool MaterialEditorScene::_userStart()
	{
		return true;
	}

	void MaterialEditorScene::_resetEdition()
	{
		_editModeName = false;
		_indexSubMaterial = -1;
		memset(_bufferName, 0, NAME_LENGTH);
		for (auto index = 0; index < ModeTexture::size; ++index) {
			memset(_bufferTexture[index], 0, TEXTURE_LENGTH);
		}
		for (auto index = 0; index < ModeTexture::size; ++index) {
			_editModeTexture[index] = false;
		}
	}

	void MaterialEditorScene::_selectMaterial()
	{
		const std::string currentDir = Directory::GetCurrentDirectory();
		const std::string absPath = Path::AbsoluteName(currentDir.c_str(), WE::EditorConfiguration::GetCookedDirectory().c_str());
		std::vector<std::string> materialGettable;
		std::vector<std::string> materialFullPath;
		Directory dir;
		const bool succeed = dir.open(absPath.c_str());
		AGE_ASSERT(succeed && "Impossible to open directory");
		for (auto it = dir.recursive_begin(); it != dir.recursive_end(); ++it)
		{
			if (Directory::IsFile(*it) && AGE::FileSystemHelpers::GetExtension(*it) == "mage")
			{
				materialGettable.push_back(std::string(Path::RelativeName(absPath.c_str(), *it)));
				materialFullPath.push_back(*it);
			}
		}
		dir.close();
		char const **matListBox = new char const *[materialGettable.size()];
		for (auto index = 0; index < materialFullPath.size(); ++index) {
			matListBox[index] = materialGettable[index].c_str();
		}
		ImGui::ListBox("List of material existing", &_indexMaterial, matListBox, materialFullPath.size());
		delete[] matListBox;
		if (_indexMaterial != -1 && ImGui::Button("open a material"))
		{
			_resetEdition();

			//std::shared_ptr<MaterialDataSet> material_data_set = std::make_shared<MaterialDataSet>();
			//std::ifstream ifs(filePath.getFullName(), std::ios::binary);
			//cereal::PortableBinaryInputArchive ar(ifs);
			//ar(*material_data_set.get());
			//material->name = material_data_set->name;
			//material->path = _filePath.getFullName();

			//getInstance<AssetsManager>()->loadMaterial()

			std::shared_ptr<MaterialDataSet> material_data_set = std::make_shared<MaterialDataSet>();
			std::ifstream ifs(materialFullPath[_indexMaterial], std::ios::binary);
			cereal::PortableBinaryInputArchive ar(ifs);
			ar(*material_data_set.get());
			_current = *material_data_set;
			if (_current.name == "")
			{
				std::string fileName = std::string(materialGettable[_indexMaterial]);
				_current.name = fileName.substr(0, fileName.find('.'));
			}
			_mode = ModeMaterialEditor::selectSubMaterial;
		}
		if (_indexMaterial == -1)
		{
			ImGui::Text("Please select one material for edition");
		}
	}

	void MaterialEditorScene::_editTexture(ModeTexture mode, std::string &current)
	{
		if (!_editModeTexture[mode])
		{
			if (current.empty())
				ImGui::Text(std::string("No " + std::string(_nameTexture[mode]) +  "...").c_str());
			else
				ImGui::Text(current.c_str());
			ImGui::SameLine();
			if (ImGui::Button("Edit texture"))
				_editModeTexture[mode] = true;
		}
		else
		{
			ImGui::InputText(_nameTexture[mode], _bufferTexture[mode], NAME_LENGTH);
			ImGui::SameLine();
			if (ImGui::Button("valid new texture"))
			{
				current = std::string(_bufferName);
				_editModeTexture[mode] = false;
			}
		}
	}

	void MaterialEditorScene::_editName()
	{
		if (!_editModeName)
		{
			if (_current.name.empty())
				ImGui::Text("No name...");
			else
				ImGui::Text(_current.name.c_str());
			ImGui::SameLine();
			if (ImGui::Button("Edit name"))
				_editModeName = true;
		}
		else
		{
			ImGui::InputText("", _bufferName, NAME_LENGTH);
			ImGui::SameLine();
			if (ImGui::Button("valid new name"))
			{
				_current.name = std::string(_bufferName);
				_editModeName = false;
			}
		}
	}

	void MaterialEditorScene::_selectSubMaterial()
	{
		if (ImGui::Button("precedent"))
			_mode = ModeMaterialEditor::selectMaterial;
		ImGui::Separator();
		ImGui::Spacing();
		_editName();
		std::vector<std::string> subMaterials;
		for (auto index = 0; index < _current.collection.size(); ++index)
			subMaterials.emplace_back(std::string("sub material: ") + std::to_string(index));
		char const **matListBox = new char const *[_current.collection.size()];
		for (auto index = 0; index < _current.collection.size(); ++index)
			matListBox[index] = subMaterials[index].c_str();
		ImGui::ListBox("List of sub material", &_indexSubMaterial, matListBox, _current.collection.size());
		delete[] matListBox;
		if (_indexSubMaterial != -1 && ImGui::Button("open a sub material"))
			_mode = ModeMaterialEditor::edit;
		if (_indexSubMaterial == -1)
			ImGui::Text("Please select one sub material for edition");
		_saveEdit();
	}

	void MaterialEditorScene::_saveEdit()
	{
		if (ImGui::Button("Save Edition")) {
			const std::string currentDir = Directory::GetCurrentDirectory();
			const std::string absPath = Path::AbsoluteName(currentDir.c_str(), WE::EditorConfiguration::GetCookedDirectory().c_str());
			std::ofstream file(absPath + _current.name + ".mage");
			cereal::PortableBinaryOutputArchive ar(file);
			ar(_current);
		}
	}

	void MaterialEditorScene::_editData()
	{
		if (ImGui::Button("precedent"))
			_mode = ModeMaterialEditor::selectSubMaterial;
		MaterialData &mat = _current.collection[_indexSubMaterial];
		ImGui::InputFloat3("ambient", glm::value_ptr(mat.ambient));
		ImGui::InputFloat3("diffuse", glm::value_ptr(mat.diffuse));
		ImGui::InputFloat3("emissive", glm::value_ptr(mat.emissive));
		ImGui::InputFloat3("reflective", glm::value_ptr(mat.reflective));
		ImGui::InputFloat3("specular", glm::value_ptr(mat.specular));
		_editTexture(ModeTexture::diffuse, mat.diffuseTexPath);
		_editTexture(ModeTexture::specular, mat.specularTexPath);
		_editTexture(ModeTexture::ambient, mat.ambientTexPath);
		_editTexture(ModeTexture::reflective, mat.reflectiveTexPath);
		_editTexture(ModeTexture::emissive, mat.emissiveTexPath);
		_editTexture(ModeTexture::normal, mat.reflectiveTexPath);
		_editTexture(ModeTexture::bump, mat.bumpTexPath);
		_saveEdit();
	}

	bool MaterialEditorScene::_userUpdateBegin(float time)
	{
		glClear(GL_COLOR_BUFFER_BIT);
		ImGui::BeginChild("Material editor", ImVec2(0, 0), true);
		switch (_mode) {
		case ModeMaterialEditor::selectMaterial:
			_selectMaterial();
			break;
		case ModeMaterialEditor::selectSubMaterial:
			_selectSubMaterial();
			break;
		case ModeMaterialEditor::edit:
			_editData();
			break;
		}
		return true;
	}

	bool MaterialEditorScene::_userUpdateEnd(float time)
	{
		ImGui::EndChild();
		ImGui::End();
		return true;
	}
}<|endoftext|>


<commit_before>#include "AsyncLogger.h"
#include "thread/Thread.h"
#include "thread/Mutex.h"
#include "thread/Condition.h"
#include "thread/CountDownLatch.h"
#include "base/Logger.h"
#include "base/LogFile.h"
NAMESPACE_ZL_BASE_START

AsyncLogger::AsyncLogger(int flushInterval/* = 3*/)
    : isRunning_(false),
      mutex_(new thread::Mutex),
      condition_(new thread::Condition(*mutex_)),
      latch_(new thread::CountDownLatch(1)),
      thread_(new thread::Thread(std::bind(&AsyncLogger::logThread, this), "AsyncLogger")),
      flushInterval_(flushInterval),
      currentBuffer_(new Buffer),
      remainBuffer_(new Buffer)
{
    //latch_->wait();
}

AsyncLogger::~AsyncLogger()
{
    if (isRunning_)
    {
        stop();
    }
    thread_->join();
    delete mutex_;
    delete condition_;
    delete latch_;
    delete thread_;
}

void AsyncLogger::start()
{
    latch_->wait();
}

void AsyncLogger::stop()
{
    isRunning_ = false;
    condition_->notify_all();
}

void AsyncLogger::output(const char* data, size_t len)
{
    thread::LockGuard<thread::Mutex> lock(*mutex_);
    if (currentBuffer_->avail() > len)
    {
        currentBuffer_->append(data, len);
    }
    else
    {
        buffers_.push_back(std::move(currentBuffer_));
        if (remainBuffer_)
        {
            currentBuffer_ = std::move(remainBuffer_);
        }
        else
        {
            currentBuffer_.reset(new Buffer);
        }
        currentBuffer_->append(data, len);
        condition_->notify_all();
    }
}

void AsyncLogger::logThread()
{
    isRunning_ = true;
    LogFile logfile(NULL, NULL, false, 3);
    std::vector<BufferPtr> writeBuffers;
    latch_->countDown();

    while(isRunning_)
    {
        //printf("111111111111\n");
        {
            thread::LockGuard<thread::Mutex> lock(*mutex_);
            if (buffers_.empty())
            {
                condition_->timed_wait(flushInterval_ * 1000);
            }
            //if (!isRunning_)
            //{
            //    break;
            //}
            buffers_.push_back(std::move(currentBuffer_));
            if (remainBuffer_)
            {
                currentBuffer_ = std::move(remainBuffer_);
            }
            else
            {
                currentBuffer_.reset(new Buffer);
            }
            writeBuffers.swap(buffers_);
        }

        assert(!writeBuffers.empty());
        for (size_t i = 0; i < writeBuffers.size(); ++i)
        {
            logfile.dumpLog(writeBuffers[i]->data(), writeBuffers[i]->size());
        }

        {
            thread::LockGuard<thread::Mutex> lock(*mutex_);
            if (!remainBuffer_)
            {
                remainBuffer_ = std::move(writeBuffers[0]);
                remainBuffer_.reset();
            }
        }

        writeBuffers.clear();
        logfile.flush();
    }
    logfile.flush();
}

NAMESPACE_ZL_BASE_END
<commit_msg>update<commit_after>#include "AsyncLogger.h"
#include "thread/Thread.h"
#include "thread/Mutex.h"
#include "thread/Condition.h"
#include "thread/CountDownLatch.h"
#include "base/Logger.h"
#include "base/LogFile.h"
NAMESPACE_ZL_BASE_START

AsyncLogger::AsyncLogger(int flushInterval/* = 3*/)
    : isRunning_(false),
      mutex_(new thread::Mutex),
      condition_(new thread::Condition(*mutex_)),
      latch_(new thread::CountDownLatch(1)),
      thread_(new thread::Thread(std::bind(&AsyncLogger::logThread, this), "AsyncLogger")),
      flushInterval_(flushInterval),
      currentBuffer_(new Buffer),
      remainBuffer_(new Buffer)
{
    //latch_->wait();
}

AsyncLogger::~AsyncLogger()
{
    if (isRunning_)
    {
        stop();
    }
    thread_->join();
    delete mutex_;
    delete condition_;
    delete latch_;
    delete thread_;
}

void AsyncLogger::start()
{
    LOG_SET_LOGHANDLER(std::bind(&AsyncLogger::output, &logger, std::placeholders::_1, std::placeholders::_2));
    latch_->wait();
}

void AsyncLogger::stop()
{
    isRunning_ = false;
    condition_->notify_all();
}

void AsyncLogger::output(const char* data, size_t len)
{
    thread::LockGuard<thread::Mutex> lock(*mutex_);
    if (currentBuffer_->avail() > len)
    {
        currentBuffer_->append(data, len);
    }
    else
    {
        buffers_.push_back(std::move(currentBuffer_));
        if (remainBuffer_)
        {
            currentBuffer_ = std::move(remainBuffer_);
        }
        else
        {
            currentBuffer_.reset(new Buffer);
        }
        currentBuffer_->append(data, len);
        condition_->notify_all();
    }
}

void AsyncLogger::logThread()
{
    isRunning_ = true;
    LogFile logfile(NULL, NULL, false, 3);
    std::vector<BufferPtr> writeBuffers;
    latch_->countDown();

    while(isRunning_)
    {
        {
            thread::LockGuard<thread::Mutex> lock(*mutex_);
            if (buffers_.empty())
            {
                condition_->timed_wait(flushInterval_ * 1000);
            }
            //if (!isRunning_)
            //{
            //    break;
            //}
            buffers_.push_back(std::move(currentBuffer_));
            if (remainBuffer_)
            {
                currentBuffer_ = std::move(remainBuffer_);
            }
            else
            {
                currentBuffer_.reset(new Buffer);
            }
            writeBuffers.swap(buffers_);
        }

        assert(!writeBuffers.empty());
        for (size_t i = 0; i < writeBuffers.size(); ++i)
        {
            logfile.dumpLog(writeBuffers[i]->data(), writeBuffers[i]->size());
        }

        {
            thread::LockGuard<thread::Mutex> lock(*mutex_);
            if (!remainBuffer_)
            {
                remainBuffer_ = std::move(writeBuffers[0]);
                remainBuffer_.reset();
            }
        }

        writeBuffers.clear();
        logfile.flush();
    }
    logfile.flush();
}

NAMESPACE_ZL_BASE_END
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "cppeditordocument.h"

#include "cppeditorconstants.h"
#include "cpphighlighter.h"

#include <cpptools/baseeditordocumentparser.h>
#include <cpptools/builtineditordocumentprocessor.h>
#include <cpptools/cppcodeformatter.h>
#include <cpptools/cppcodemodelsettings.h>
#include <cpptools/cppmodelmanager.h>
#include <cpptools/cppqtstyleindenter.h>
#include <cpptools/cpptoolsconstants.h>
#include <cpptools/cpptoolsplugin.h>

#include <projectexplorer/session.h>

#include <coreplugin/editormanager/editormanager.h>
#include <utils/mimetypes/mimedatabase.h>
#include <utils/qtcassert.h>
#include <utils/runextensions.h>

#include <QTextDocument>

namespace {

CppTools::CppModelManager *mm()
{
    return CppTools::CppModelManager::instance();
}

} // anonymous namespace

namespace CppEditor {
namespace Internal {

enum { processDocumentIntervalInMs = 150 };

class CppEditorDocumentHandleImpl : public CppTools::CppEditorDocumentHandle
{
public:
    CppEditorDocumentHandleImpl(CppEditorDocument *cppEditorDocument)
        : m_cppEditorDocument(cppEditorDocument)
        , m_registrationFilePath(cppEditorDocument->filePath().toString())
    {
        mm()->registerCppEditorDocument(this);
    }

    ~CppEditorDocumentHandleImpl() { mm()->unregisterCppEditorDocument(m_registrationFilePath); }

    QString filePath() const override { return m_cppEditorDocument->filePath().toString(); }
    QByteArray contents() const override { return m_cppEditorDocument->contentsText(); }
    unsigned revision() const override { return m_cppEditorDocument->contentsRevision(); }

    CppTools::BaseEditorDocumentProcessor *processor() const override
    { return m_cppEditorDocument->processor(); }

    void resetProcessor()
    { m_cppEditorDocument->resetProcessor(); }

private:
    CppEditor::Internal::CppEditorDocument * const m_cppEditorDocument;
    // The file path of the editor document can change (e.g. by "Save As..."), so make sure
    // that un-registration happens with the path the document was registered.
    const QString m_registrationFilePath;
};

CppEditorDocument::CppEditorDocument()
    : m_fileIsBeingReloaded(false)
    , m_isObjCEnabled(false)
    , m_cachedContentsRevision(-1)
    , m_processorRevision(0)
    , m_completionAssistProvider(0)
{
    setId(CppEditor::Constants::CPPEDITOR_ID);
    setSyntaxHighlighter(new CppHighlighter);
    setIndenter(new CppTools::CppQtStyleIndenter);

    connect(this, SIGNAL(tabSettingsChanged()), this, SLOT(invalidateFormatterCache()));
    connect(this, SIGNAL(mimeTypeChanged()), this, SLOT(onMimeTypeChanged()));

    connect(this, SIGNAL(aboutToReload()), this, SLOT(onAboutToReload()));
    connect(this, SIGNAL(reloadFinished(bool)), this, SLOT(onReloadFinished()));
    connect(this, &IDocument::filePathChanged,
            this, &CppEditorDocument::onFilePathChanged);

    m_processorTimer.setSingleShot(true);
    m_processorTimer.setInterval(processDocumentIntervalInMs);
    connect(&m_processorTimer, SIGNAL(timeout()), this, SLOT(processDocument()));

    // See also onFilePathChanged() for more initialization
}

bool CppEditorDocument::isObjCEnabled() const
{
    return m_isObjCEnabled;
}

TextEditor::CompletionAssistProvider *CppEditorDocument::completionAssistProvider() const
{
    return m_completionAssistProvider;
}

void CppEditorDocument::recalculateSemanticInfoDetached()
{
    CppTools::BaseEditorDocumentProcessor *p = processor();
    QTC_ASSERT(p, return);
    p->recalculateSemanticInfoDetached(true);
}

CppTools::SemanticInfo CppEditorDocument::recalculateSemanticInfo()
{
    CppTools::BaseEditorDocumentProcessor *p = processor();
    QTC_ASSERT(p, CppTools::SemanticInfo());
    return p->recalculateSemanticInfo();
}

QByteArray CppEditorDocument::contentsText() const
{
    QMutexLocker locker(&m_cachedContentsLock);

    const int currentRevision = document()->revision();
    if (m_cachedContentsRevision != currentRevision && !m_fileIsBeingReloaded) {
        m_cachedContentsRevision = currentRevision;
        m_cachedContents = plainText().toUtf8();
    }

    return m_cachedContents;
}

void CppEditorDocument::applyFontSettings()
{
    if (TextEditor::SyntaxHighlighter *highlighter = syntaxHighlighter()) {
        // Clear all additional formats since they may have changed
        QTextBlock b = document()->firstBlock();
        while (b.isValid()) {
            QList<QTextLayout::FormatRange> noFormats;
            highlighter->setExtraAdditionalFormats(b, noFormats);
            b = b.next();
        }
    }
    TextDocument::applyFontSettings(); // rehighlights and updates additional formats
    m_processor->semanticRehighlight();
}

void CppEditorDocument::invalidateFormatterCache()
{
    CppTools::QtStyleCodeFormatter formatter;
    formatter.invalidateCache(document());
}

void CppEditorDocument::onMimeTypeChanged()
{
    const QString &mt = mimeType();
    m_isObjCEnabled = (mt == QLatin1String(CppTools::Constants::OBJECTIVE_C_SOURCE_MIMETYPE)
                       || mt == QLatin1String(CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE));
    m_completionAssistProvider = mm()->completionAssistProvider(mt);
}

void CppEditorDocument::onAboutToReload()
{
    QTC_CHECK(!m_fileIsBeingReloaded);
    m_fileIsBeingReloaded = true;
}

void CppEditorDocument::onReloadFinished()
{
    QTC_CHECK(m_fileIsBeingReloaded);
    m_fileIsBeingReloaded = false;
}

void CppEditorDocument::onFilePathChanged(const Utils::FileName &oldPath,
                                          const Utils::FileName &newPath)
{
    Q_UNUSED(oldPath);

    if (!newPath.isEmpty()) {
        Utils::MimeDatabase mdb;
        setMimeType(mdb.mimeTypeForFile(newPath.toFileInfo()).name());

        disconnect(this, SIGNAL(contentsChanged()), this, SLOT(scheduleProcessDocument()));
        connect(this, SIGNAL(contentsChanged()), this, SLOT(scheduleProcessDocument()));

        // Un-Register/Register in ModelManager
        m_editorDocumentHandle.reset();
        m_editorDocumentHandle.reset(new CppEditorDocumentHandleImpl(this));

        resetProcessor();
        updatePreprocessorSettings();
        m_processorRevision = document()->revision();
        processDocument();
    }
}

void CppEditorDocument::scheduleProcessDocument()
{
    m_processorRevision = document()->revision();
    m_processorTimer.start(processDocumentIntervalInMs);
}

void CppEditorDocument::processDocument()
{
    if (processor()->isParserRunning() || m_processorRevision != contentsRevision()) {
        m_processorTimer.start();
        return;
    }

    m_processorTimer.stop();
    if (m_fileIsBeingReloaded || filePath().isEmpty())
        return;

    processor()->run();
}

void CppEditorDocument::resetProcessor()
{
    releaseResources();
    processor(); // creates a new processor
}

void CppEditorDocument::updatePreprocessorSettings()
{
    if (filePath().isEmpty())
        return;

    const QString prefix = QLatin1String(Constants::CPP_PREPROCESSOR_PROJECT_PREFIX);
    const QString &projectFile = ProjectExplorer::SessionManager::value(
                prefix + filePath().toString()).toString();
    const QString directivesKey = projectFile + QLatin1Char(',') + filePath().toString();
    const QByteArray additionalDirectives = ProjectExplorer::SessionManager::value(
                directivesKey).toString().toUtf8();

    setPreprocessorSettings(mm()->projectPartForProjectFile(projectFile), additionalDirectives);
}

void CppEditorDocument::setPreprocessorSettings(const CppTools::ProjectPart::Ptr &projectPart,
                                                const QByteArray &defines)
{
    CppTools::BaseEditorDocumentParser *parser = processor()->parser();
    QTC_ASSERT(parser, return);
    if (parser->projectPart() != projectPart || parser->editorDefines() != defines) {
        parser->setProjectPart(projectPart);
        parser->setEditorDefines(defines);

        emit preprocessorSettingsChanged(!defines.trimmed().isEmpty());
    }
}

unsigned CppEditorDocument::contentsRevision() const
{
    return document()->revision();
}

void CppEditorDocument::releaseResources()
{
    if (m_processor)
        disconnect(m_processor.data(), 0, this, 0);
    m_processor.reset();
}

CppTools::BaseEditorDocumentProcessor *CppEditorDocument::processor()
{
    if (!m_processor) {
        m_processor.reset(mm()->editorDocumentProcessor(this));
        connect(m_processor.data(), &CppTools::BaseEditorDocumentProcessor::codeWarningsUpdated,
                this, &CppEditorDocument::codeWarningsUpdated);
        connect(m_processor.data(), &CppTools::BaseEditorDocumentProcessor::ifdefedOutBlocksUpdated,
                this, &CppEditorDocument::ifdefedOutBlocksUpdated);
        connect(m_processor.data(), &CppTools::BaseEditorDocumentProcessor::cppDocumentUpdated,
                this, &CppEditorDocument::cppDocumentUpdated);
        connect(m_processor.data(), &CppTools::BaseEditorDocumentProcessor::semanticInfoUpdated,
                this, &CppEditorDocument::semanticInfoUpdated);
    }

    return m_processor.data();
}

} // namespace Internal
} // namespace CppEditor
<commit_msg>CppEditor: Fix accessing null pointer...<commit_after>/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "cppeditordocument.h"

#include "cppeditorconstants.h"
#include "cpphighlighter.h"

#include <cpptools/baseeditordocumentparser.h>
#include <cpptools/builtineditordocumentprocessor.h>
#include <cpptools/cppcodeformatter.h>
#include <cpptools/cppcodemodelsettings.h>
#include <cpptools/cppmodelmanager.h>
#include <cpptools/cppqtstyleindenter.h>
#include <cpptools/cpptoolsconstants.h>
#include <cpptools/cpptoolsplugin.h>

#include <projectexplorer/session.h>

#include <coreplugin/editormanager/editormanager.h>
#include <utils/mimetypes/mimedatabase.h>
#include <utils/qtcassert.h>
#include <utils/runextensions.h>

#include <QTextDocument>

namespace {

CppTools::CppModelManager *mm()
{
    return CppTools::CppModelManager::instance();
}

} // anonymous namespace

namespace CppEditor {
namespace Internal {

enum { processDocumentIntervalInMs = 150 };

class CppEditorDocumentHandleImpl : public CppTools::CppEditorDocumentHandle
{
public:
    CppEditorDocumentHandleImpl(CppEditorDocument *cppEditorDocument)
        : m_cppEditorDocument(cppEditorDocument)
        , m_registrationFilePath(cppEditorDocument->filePath().toString())
    {
        mm()->registerCppEditorDocument(this);
    }

    ~CppEditorDocumentHandleImpl() { mm()->unregisterCppEditorDocument(m_registrationFilePath); }

    QString filePath() const override { return m_cppEditorDocument->filePath().toString(); }
    QByteArray contents() const override { return m_cppEditorDocument->contentsText(); }
    unsigned revision() const override { return m_cppEditorDocument->contentsRevision(); }

    CppTools::BaseEditorDocumentProcessor *processor() const override
    { return m_cppEditorDocument->processor(); }

    void resetProcessor()
    { m_cppEditorDocument->resetProcessor(); }

private:
    CppEditor::Internal::CppEditorDocument * const m_cppEditorDocument;
    // The file path of the editor document can change (e.g. by "Save As..."), so make sure
    // that un-registration happens with the path the document was registered.
    const QString m_registrationFilePath;
};

CppEditorDocument::CppEditorDocument()
    : m_fileIsBeingReloaded(false)
    , m_isObjCEnabled(false)
    , m_cachedContentsRevision(-1)
    , m_processorRevision(0)
    , m_completionAssistProvider(0)
{
    setId(CppEditor::Constants::CPPEDITOR_ID);
    setSyntaxHighlighter(new CppHighlighter);
    setIndenter(new CppTools::CppQtStyleIndenter);

    connect(this, SIGNAL(tabSettingsChanged()), this, SLOT(invalidateFormatterCache()));
    connect(this, SIGNAL(mimeTypeChanged()), this, SLOT(onMimeTypeChanged()));

    connect(this, SIGNAL(aboutToReload()), this, SLOT(onAboutToReload()));
    connect(this, SIGNAL(reloadFinished(bool)), this, SLOT(onReloadFinished()));
    connect(this, &IDocument::filePathChanged,
            this, &CppEditorDocument::onFilePathChanged);

    m_processorTimer.setSingleShot(true);
    m_processorTimer.setInterval(processDocumentIntervalInMs);
    connect(&m_processorTimer, SIGNAL(timeout()), this, SLOT(processDocument()));

    // See also onFilePathChanged() for more initialization
}

bool CppEditorDocument::isObjCEnabled() const
{
    return m_isObjCEnabled;
}

TextEditor::CompletionAssistProvider *CppEditorDocument::completionAssistProvider() const
{
    return m_completionAssistProvider;
}

void CppEditorDocument::recalculateSemanticInfoDetached()
{
    CppTools::BaseEditorDocumentProcessor *p = processor();
    QTC_ASSERT(p, return);
    p->recalculateSemanticInfoDetached(true);
}

CppTools::SemanticInfo CppEditorDocument::recalculateSemanticInfo()
{
    CppTools::BaseEditorDocumentProcessor *p = processor();
    QTC_ASSERT(p, CppTools::SemanticInfo());
    return p->recalculateSemanticInfo();
}

QByteArray CppEditorDocument::contentsText() const
{
    QMutexLocker locker(&m_cachedContentsLock);

    const int currentRevision = document()->revision();
    if (m_cachedContentsRevision != currentRevision && !m_fileIsBeingReloaded) {
        m_cachedContentsRevision = currentRevision;
        m_cachedContents = plainText().toUtf8();
    }

    return m_cachedContents;
}

void CppEditorDocument::applyFontSettings()
{
    if (TextEditor::SyntaxHighlighter *highlighter = syntaxHighlighter()) {
        // Clear all additional formats since they may have changed
        QTextBlock b = document()->firstBlock();
        while (b.isValid()) {
            QList<QTextLayout::FormatRange> noFormats;
            highlighter->setExtraAdditionalFormats(b, noFormats);
            b = b.next();
        }
    }
    TextDocument::applyFontSettings(); // rehighlights and updates additional formats
    if (m_processor)
        m_processor->semanticRehighlight();
}

void CppEditorDocument::invalidateFormatterCache()
{
    CppTools::QtStyleCodeFormatter formatter;
    formatter.invalidateCache(document());
}

void CppEditorDocument::onMimeTypeChanged()
{
    const QString &mt = mimeType();
    m_isObjCEnabled = (mt == QLatin1String(CppTools::Constants::OBJECTIVE_C_SOURCE_MIMETYPE)
                       || mt == QLatin1String(CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE));
    m_completionAssistProvider = mm()->completionAssistProvider(mt);
}

void CppEditorDocument::onAboutToReload()
{
    QTC_CHECK(!m_fileIsBeingReloaded);
    m_fileIsBeingReloaded = true;
}

void CppEditorDocument::onReloadFinished()
{
    QTC_CHECK(m_fileIsBeingReloaded);
    m_fileIsBeingReloaded = false;
}

void CppEditorDocument::onFilePathChanged(const Utils::FileName &oldPath,
                                          const Utils::FileName &newPath)
{
    Q_UNUSED(oldPath);

    if (!newPath.isEmpty()) {
        Utils::MimeDatabase mdb;
        setMimeType(mdb.mimeTypeForFile(newPath.toFileInfo()).name());

        disconnect(this, SIGNAL(contentsChanged()), this, SLOT(scheduleProcessDocument()));
        connect(this, SIGNAL(contentsChanged()), this, SLOT(scheduleProcessDocument()));

        // Un-Register/Register in ModelManager
        m_editorDocumentHandle.reset();
        m_editorDocumentHandle.reset(new CppEditorDocumentHandleImpl(this));

        resetProcessor();
        updatePreprocessorSettings();
        m_processorRevision = document()->revision();
        processDocument();
    }
}

void CppEditorDocument::scheduleProcessDocument()
{
    m_processorRevision = document()->revision();
    m_processorTimer.start(processDocumentIntervalInMs);
}

void CppEditorDocument::processDocument()
{
    if (processor()->isParserRunning() || m_processorRevision != contentsRevision()) {
        m_processorTimer.start();
        return;
    }

    m_processorTimer.stop();
    if (m_fileIsBeingReloaded || filePath().isEmpty())
        return;

    processor()->run();
}

void CppEditorDocument::resetProcessor()
{
    releaseResources();
    processor(); // creates a new processor
}

void CppEditorDocument::updatePreprocessorSettings()
{
    if (filePath().isEmpty())
        return;

    const QString prefix = QLatin1String(Constants::CPP_PREPROCESSOR_PROJECT_PREFIX);
    const QString &projectFile = ProjectExplorer::SessionManager::value(
                prefix + filePath().toString()).toString();
    const QString directivesKey = projectFile + QLatin1Char(',') + filePath().toString();
    const QByteArray additionalDirectives = ProjectExplorer::SessionManager::value(
                directivesKey).toString().toUtf8();

    setPreprocessorSettings(mm()->projectPartForProjectFile(projectFile), additionalDirectives);
}

void CppEditorDocument::setPreprocessorSettings(const CppTools::ProjectPart::Ptr &projectPart,
                                                const QByteArray &defines)
{
    CppTools::BaseEditorDocumentParser *parser = processor()->parser();
    QTC_ASSERT(parser, return);
    if (parser->projectPart() != projectPart || parser->editorDefines() != defines) {
        parser->setProjectPart(projectPart);
        parser->setEditorDefines(defines);

        emit preprocessorSettingsChanged(!defines.trimmed().isEmpty());
    }
}

unsigned CppEditorDocument::contentsRevision() const
{
    return document()->revision();
}

void CppEditorDocument::releaseResources()
{
    if (m_processor)
        disconnect(m_processor.data(), 0, this, 0);
    m_processor.reset();
}

CppTools::BaseEditorDocumentProcessor *CppEditorDocument::processor()
{
    if (!m_processor) {
        m_processor.reset(mm()->editorDocumentProcessor(this));
        connect(m_processor.data(), &CppTools::BaseEditorDocumentProcessor::codeWarningsUpdated,
                this, &CppEditorDocument::codeWarningsUpdated);
        connect(m_processor.data(), &CppTools::BaseEditorDocumentProcessor::ifdefedOutBlocksUpdated,
                this, &CppEditorDocument::ifdefedOutBlocksUpdated);
        connect(m_processor.data(), &CppTools::BaseEditorDocumentProcessor::cppDocumentUpdated,
                this, &CppEditorDocument::cppDocumentUpdated);
        connect(m_processor.data(), &CppTools::BaseEditorDocumentProcessor::semanticInfoUpdated,
                this, &CppEditorDocument::semanticInfoUpdated);
    }

    return m_processor.data();
}

} // namespace Internal
} // namespace CppEditor
<|endoftext|>