<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: cstitem.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: obo $ $Date: 2006-10-12 15:21:03 $
 *
 *  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
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svtools.hxx"

#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif

#include <unotools/intlwrapper.hxx>

#include <tools/stream.hxx>
#include <tools/debug.hxx>
#include <tools/datetime.hxx>

#include "svtdata.hxx"
#include "cstitem.hxx"

#include "svtools.hrc"

#ifndef _COM_SUN_STAR_LANG_LOCALE_HPP_
#include <com/sun/star/lang/Locale.hpp>
#endif

DBG_NAME( SfxCrawlStatusItem )
TYPEINIT1( SfxCrawlStatusItem, SfxPoolItem );

// -----------------------------------------------------------------------

SfxCrawlStatusItem::SfxCrawlStatusItem( USHORT which ) :
    SfxPoolItem( which )
{
    DBG_CTOR( SfxCrawlStatusItem, 0 );
}

// -----------------------------------------------------------------------

SfxCrawlStatusItem::SfxCrawlStatusItem( USHORT which, CrawlStatus eStat ) :
    SfxPoolItem( which ),
    eStatus( eStat )
{
    DBG_CTOR( SfxCrawlStatusItem, 0 );
}

// -----------------------------------------------------------------------

SfxCrawlStatusItem::SfxCrawlStatusItem( const SfxCrawlStatusItem& rItem ) :
    SfxPoolItem( rItem ),
    eStatus( rItem.eStatus )
{
    DBG_CTOR( SfxCrawlStatusItem, 0 );
}

// -----------------------------------------------------------------------

int SfxCrawlStatusItem::operator==( const SfxPoolItem& rItem ) const
{
    DBG_CHKTHIS( SfxCrawlStatusItem, 0 );
    DBG_ASSERT( SfxPoolItem::operator==( rItem ), "unequal type" );

    return ((SfxCrawlStatusItem&)rItem).eStatus == eStatus;
}

// -----------------------------------------------------------------------

int SfxCrawlStatusItem::Compare( const SfxPoolItem& rItem ) const
{
    DBG_CHKTHIS( SfxCrawlStatusItem, 0 );
    DBG_ASSERT( SfxPoolItem::operator==( rItem ), "unequal type" );

    if( ((const SfxCrawlStatusItem&)rItem).eStatus < eStatus )
        return -1;
    else if( ((const SfxCrawlStatusItem&)rItem).eStatus == eStatus )
        return 0;
    else
        return 1;
}

// -----------------------------------------------------------------------

SfxPoolItem* SfxCrawlStatusItem::Create( SvStream& rStream, USHORT ) const
{
    DBG_CHKTHIS(SfxCrawlStatusItem, 0);

    USHORT _eStatus;
    rStream >> _eStatus;

    return new SfxCrawlStatusItem( Which(), (CrawlStatus)_eStatus );
}

// -----------------------------------------------------------------------

SvStream& SfxCrawlStatusItem::Store( SvStream& rStream, USHORT ) const
{
    DBG_CHKTHIS( SfxCrawlStatusItem, 0 );

    USHORT nStatus = (USHORT)eStatus;
    rStream << (USHORT) nStatus;

    return rStream;
}

// -----------------------------------------------------------------------

SfxPoolItem* SfxCrawlStatusItem::Clone( SfxItemPool* ) const
{
    DBG_CHKTHIS( SfxCrawlStatusItem, 0 );
    return new SfxCrawlStatusItem( *this );
}
// -----------------------------------------------------------------------

SfxItemPresentation SfxCrawlStatusItem::GetPresentation
(
    SfxItemPresentation     /*ePresentation*/,
    SfxMapUnit              /*eCoreMetric*/,
    SfxMapUnit              /*ePresentationMetric*/,
    XubString&              rText,
    const IntlWrapper *   pIntlWrapper
)   const
{
    DBG_CHKTHIS(SfxCrawlStatusItem, 0);
    DBG_ASSERT(pIntlWrapper,
               "SfxCrawlStatusItem::GetPresentation():"
                " Using default IntlWrapper");

    ::com::sun::star::lang::Locale aLocale;

    switch (eStatus)
    {
        case CSTAT_NEVER_UPD:
            rText = String(SvtResId(STR_CSTAT_NEVER_UPD,
                                    pIntlWrapper ?
                                     pIntlWrapper->getLocale() :
                                     aLocale));
            break;

        case CSTAT_IN_UPD:
            rText = String(SvtResId(STR_CSTAT_IN_UPD,
                                    pIntlWrapper ?
                                     pIntlWrapper->getLocale() :
                                     aLocale));
            break;

        case CSTAT_UPD_NEWER:
            rText = String(SvtResId(STR_CSTAT_UPD_NEWER,
                                    pIntlWrapper ?
                                     pIntlWrapper->getLocale() :
                                     aLocale));
            break;

        case CSTAT_UPD_NOT_NEWER:
            rText = String(SvtResId(STR_CSTAT_UPD_NOT_NEWER,
                                    pIntlWrapper ?
                                     pIntlWrapper->getLocale() :
                                     aLocale));
            break;

        case CSTAT_UPD_CANCEL:
            rText = String(SvtResId(STR_CSTAT_UPD_CANCEL,
                                    pIntlWrapper ?
                                     pIntlWrapper->getLocale() :
                                     aLocale));
            break;

        case CSTAT_ERR_GENERAL:
            rText = String(SvtResId(STR_CSTAT_ERR_GENERAL,
                                    pIntlWrapper ?
                                     pIntlWrapper->getLocale() :
                                     aLocale));
            break;

        case CSTAT_ERR_NOTEXISTS:
            rText = String(SvtResId(STR_CSTAT_ERR_NOTEXISTS,
                                    pIntlWrapper ?
                                     pIntlWrapper->getLocale() :
                                     aLocale));
            break;

        case CSTAT_ERR_NOTREACHED:
            rText = String(SvtResId(STR_CSTAT_ERR_NOTREACHED,
                                    pIntlWrapper ?
                                     pIntlWrapper->getLocale() :
                                     aLocale));
            break;

        case CSTAT_UPD_IMMEDIATELY:
            rText = String(SvtResId(STR_CSTAT_UPD_IMMEDIATELY,
                                    pIntlWrapper ?
                                     pIntlWrapper->getLocale() :
                                     aLocale));
            break;

        case CSTAT_ERR_OFFLINE:
            rText = String(SvtResId(STR_CSTAT_ERR_OFFLINE,
                                    pIntlWrapper ?
                                     pIntlWrapper->getLocale() :
                                     aLocale));
            break;

        default:
            rText.Erase();
            break;
    }
    return SFX_ITEM_PRESENTATION_NAMELESS;
}

//----------------------------------------------------------------------------
// virtual
BOOL SfxCrawlStatusItem::PutValue( const com::sun::star::uno::Any& rVal,BYTE )
{
    sal_Int16 aValue = sal_Int16();
    if ( rVal >>= aValue )
    {
        SetStatus( static_cast< CrawlStatus >( aValue ) );
        return TRUE;
    }

    DBG_ERROR( "SfxCrawlStatusItem::PutValue - Wrong type!" );
    return FALSE;
}

//----------------------------------------------------------------------------
// virtual
BOOL SfxCrawlStatusItem::QueryValue( com::sun::star::uno::Any& rVal,BYTE ) const
{
    sal_Int16 aValue = sal::static_int_cast< sal_Int16 >(GetStatus());
    rVal <<= aValue;
    return TRUE;
}

<commit_msg>INTEGRATION: CWS vgbugs07 (1.7.182); FILE MERGED 2007/06/04 13:31:39 vg 1.7.182.1: #i76605# Remove -I .../inc/module hack introduced by hedaburemove01<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: cstitem.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: hr $ $Date: 2007-06-27 21:42: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
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svtools.hxx"

#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif

#include <unotools/intlwrapper.hxx>

#include <tools/stream.hxx>
#include <tools/debug.hxx>
#include <tools/datetime.hxx>

#include <svtools/svtdata.hxx>
#include <svtools/cstitem.hxx>

#include <svtools/svtools.hrc>

#ifndef _COM_SUN_STAR_LANG_LOCALE_HPP_
#include <com/sun/star/lang/Locale.hpp>
#endif

DBG_NAME( SfxCrawlStatusItem )
TYPEINIT1( SfxCrawlStatusItem, SfxPoolItem );

// -----------------------------------------------------------------------

SfxCrawlStatusItem::SfxCrawlStatusItem( USHORT which ) :
    SfxPoolItem( which )
{
    DBG_CTOR( SfxCrawlStatusItem, 0 );
}

// -----------------------------------------------------------------------

SfxCrawlStatusItem::SfxCrawlStatusItem( USHORT which, CrawlStatus eStat ) :
    SfxPoolItem( which ),
    eStatus( eStat )
{
    DBG_CTOR( SfxCrawlStatusItem, 0 );
}

// -----------------------------------------------------------------------

SfxCrawlStatusItem::SfxCrawlStatusItem( const SfxCrawlStatusItem& rItem ) :
    SfxPoolItem( rItem ),
    eStatus( rItem.eStatus )
{
    DBG_CTOR( SfxCrawlStatusItem, 0 );
}

// -----------------------------------------------------------------------

int SfxCrawlStatusItem::operator==( const SfxPoolItem& rItem ) const
{
    DBG_CHKTHIS( SfxCrawlStatusItem, 0 );
    DBG_ASSERT( SfxPoolItem::operator==( rItem ), "unequal type" );

    return ((SfxCrawlStatusItem&)rItem).eStatus == eStatus;
}

// -----------------------------------------------------------------------

int SfxCrawlStatusItem::Compare( const SfxPoolItem& rItem ) const
{
    DBG_CHKTHIS( SfxCrawlStatusItem, 0 );
    DBG_ASSERT( SfxPoolItem::operator==( rItem ), "unequal type" );

    if( ((const SfxCrawlStatusItem&)rItem).eStatus < eStatus )
        return -1;
    else if( ((const SfxCrawlStatusItem&)rItem).eStatus == eStatus )
        return 0;
    else
        return 1;
}

// -----------------------------------------------------------------------

SfxPoolItem* SfxCrawlStatusItem::Create( SvStream& rStream, USHORT ) const
{
    DBG_CHKTHIS(SfxCrawlStatusItem, 0);

    USHORT _eStatus;
    rStream >> _eStatus;

    return new SfxCrawlStatusItem( Which(), (CrawlStatus)_eStatus );
}

// -----------------------------------------------------------------------

SvStream& SfxCrawlStatusItem::Store( SvStream& rStream, USHORT ) const
{
    DBG_CHKTHIS( SfxCrawlStatusItem, 0 );

    USHORT nStatus = (USHORT)eStatus;
    rStream << (USHORT) nStatus;

    return rStream;
}

// -----------------------------------------------------------------------

SfxPoolItem* SfxCrawlStatusItem::Clone( SfxItemPool* ) const
{
    DBG_CHKTHIS( SfxCrawlStatusItem, 0 );
    return new SfxCrawlStatusItem( *this );
}
// -----------------------------------------------------------------------

SfxItemPresentation SfxCrawlStatusItem::GetPresentation
(
    SfxItemPresentation     /*ePresentation*/,
    SfxMapUnit              /*eCoreMetric*/,
    SfxMapUnit              /*ePresentationMetric*/,
    XubString&              rText,
    const IntlWrapper *   pIntlWrapper
)   const
{
    DBG_CHKTHIS(SfxCrawlStatusItem, 0);
    DBG_ASSERT(pIntlWrapper,
               "SfxCrawlStatusItem::GetPresentation():"
                " Using default IntlWrapper");

    ::com::sun::star::lang::Locale aLocale;

    switch (eStatus)
    {
        case CSTAT_NEVER_UPD:
            rText = String(SvtResId(STR_CSTAT_NEVER_UPD,
                                    pIntlWrapper ?
                                     pIntlWrapper->getLocale() :
                                     aLocale));
            break;

        case CSTAT_IN_UPD:
            rText = String(SvtResId(STR_CSTAT_IN_UPD,
                                    pIntlWrapper ?
                                     pIntlWrapper->getLocale() :
                                     aLocale));
            break;

        case CSTAT_UPD_NEWER:
            rText = String(SvtResId(STR_CSTAT_UPD_NEWER,
                                    pIntlWrapper ?
                                     pIntlWrapper->getLocale() :
                                     aLocale));
            break;

        case CSTAT_UPD_NOT_NEWER:
            rText = String(SvtResId(STR_CSTAT_UPD_NOT_NEWER,
                                    pIntlWrapper ?
                                     pIntlWrapper->getLocale() :
                                     aLocale));
            break;

        case CSTAT_UPD_CANCEL:
            rText = String(SvtResId(STR_CSTAT_UPD_CANCEL,
                                    pIntlWrapper ?
                                     pIntlWrapper->getLocale() :
                                     aLocale));
            break;

        case CSTAT_ERR_GENERAL:
            rText = String(SvtResId(STR_CSTAT_ERR_GENERAL,
                                    pIntlWrapper ?
                                     pIntlWrapper->getLocale() :
                                     aLocale));
            break;

        case CSTAT_ERR_NOTEXISTS:
            rText = String(SvtResId(STR_CSTAT_ERR_NOTEXISTS,
                                    pIntlWrapper ?
                                     pIntlWrapper->getLocale() :
                                     aLocale));
            break;

        case CSTAT_ERR_NOTREACHED:
            rText = String(SvtResId(STR_CSTAT_ERR_NOTREACHED,
                                    pIntlWrapper ?
                                     pIntlWrapper->getLocale() :
                                     aLocale));
            break;

        case CSTAT_UPD_IMMEDIATELY:
            rText = String(SvtResId(STR_CSTAT_UPD_IMMEDIATELY,
                                    pIntlWrapper ?
                                     pIntlWrapper->getLocale() :
                                     aLocale));
            break;

        case CSTAT_ERR_OFFLINE:
            rText = String(SvtResId(STR_CSTAT_ERR_OFFLINE,
                                    pIntlWrapper ?
                                     pIntlWrapper->getLocale() :
                                     aLocale));
            break;

        default:
            rText.Erase();
            break;
    }
    return SFX_ITEM_PRESENTATION_NAMELESS;
}

//----------------------------------------------------------------------------
// virtual
BOOL SfxCrawlStatusItem::PutValue( const com::sun::star::uno::Any& rVal,BYTE )
{
    sal_Int16 aValue = sal_Int16();
    if ( rVal >>= aValue )
    {
        SetStatus( static_cast< CrawlStatus >( aValue ) );
        return TRUE;
    }

    DBG_ERROR( "SfxCrawlStatusItem::PutValue - Wrong type!" );
    return FALSE;
}

//----------------------------------------------------------------------------
// virtual
BOOL SfxCrawlStatusItem::QueryValue( com::sun::star::uno::Any& rVal,BYTE ) const
{
    sal_Int16 aValue = sal::static_int_cast< sal_Int16 >(GetStatus());
    rVal <<= aValue;
    return TRUE;
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: confirmdelete.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 15:51:17 $
 *
 *  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 SVX_FORM_CONFIRMDELETE_HXX
#include "confirmdelete.hxx"
#endif

#ifndef _SVX_DIALMGR_HXX
#include <dialmgr.hxx>
#endif
#ifndef _SVX_FMHELP_HRC
#include "fmhelp.hrc"
#endif
#ifndef _SVX_FMRESIDS_HRC
#include "fmresids.hrc"
#endif
#ifndef _UTL_CONFIGMGR_HXX_
#include <unotools/configmgr.hxx>
#endif
#ifndef _SV_MSGBOX_HXX
#include <vcl/msgbox.hxx>
#endif

//........................................................................
namespace svxform
{
//........................................................................

#define BORDER_HEIGHT   6 // default distance control-dialog
#define BORDER_WIDTH    6 // default distance control-dialog

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

    //====================================================================
    //= class ConfirmDeleteDialog
    //====================================================================
    //------------------------------------------------------------------------------
    ConfirmDeleteDialog::ConfirmDeleteDialog(Window* pParent, const String& _rTitle)
              :ButtonDialog(pParent, WB_HORZ | WB_STDDIALOG)
              ,m_aInfoImage (this)
              ,m_aTitle     (this, WB_WORDBREAK | WB_LEFT)
              ,m_aMessage   (this, WB_WORDBREAK | WB_LEFT)
    {
        String sMessage(SVX_RES(RID_STR_DELETECONFIRM));

        // Changed as per BugID 79541 Branding/Configuration
        ::utl::ConfigManager* pMgr = ::utl::ConfigManager::GetConfigManager();
        Any aProductName = pMgr->GetDirectConfigProperty(::utl::ConfigManager::PRODUCTNAME);
        ::rtl::OUString sProductName;
        aProductName >>= sProductName;

        String aTitle = sProductName;
        aProductName = pMgr->GetDirectConfigProperty(::utl::ConfigManager::PRODUCTVERSION);
        aProductName >>= sProductName;
        aTitle.AppendAscii(" ");
        aTitle += String(sProductName);
        SetText(aTitle);

        SetHelpId(HID_DLG_DBMSG);
        SetSizePixel(LogicToPixel(Size(220, 30),MAP_APPFONT));

        m_aInfoImage.SetPosSizePixel(LogicToPixel(Point(6, 6),MAP_APPFONT),
                                   LogicToPixel(Size(20, 20),MAP_APPFONT));
        m_aInfoImage.Show();

        m_aTitle.SetPosSizePixel(LogicToPixel(Point(45, 6),MAP_APPFONT),
                                 LogicToPixel(Size(169, 20),MAP_APPFONT));

        Font  aFont = m_aTitle.GetFont();
        aFont.SetWeight(WEIGHT_SEMIBOLD);
        m_aTitle.SetFont(aFont);
        m_aTitle.Show();

        m_aMessage.SetPosSizePixel(LogicToPixel(Point(45, 29),MAP_APPFONT),
                                   LogicToPixel(Size(169, 1),MAP_APPFONT));
        m_aMessage.Show();

        // Image festlegen
        m_aInfoImage.SetImage(WarningBox::GetStandardImage());

        // Title setzen
        m_aTitle.SetText(_rTitle);

        // Ermitteln der Hoehe des Textfeldes und des Dialogs
        Size aBorderSize = LogicToPixel(Size(BORDER_WIDTH, BORDER_HEIGHT),MAP_APPFONT);
        Rectangle aDlgRect(GetPosPixel(),GetSizePixel());
        Rectangle aMessageRect(m_aMessage.GetPosPixel(),m_aMessage.GetSizePixel());
        Rectangle aTextRect =
            GetTextRect(aMessageRect, sMessage, TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE | TEXT_DRAW_LEFT);

        long nHText = aTextRect.Bottom() > aMessageRect.Bottom() ? aTextRect.Bottom() - aMessageRect.Bottom() : 0;

        aDlgRect.Bottom() += nHText + 2 * aBorderSize.Height();
        aMessageRect.Bottom() += nHText;

        // Dialog anpassen
        SetSizePixel(aDlgRect.GetSize());
        SetPageSizePixel(aDlgRect.GetSize());

        // Message Text anpassen und setzen
        m_aMessage.SetSizePixel(aMessageRect.GetSize());
        m_aMessage.SetText(sMessage);

        // Buttons anlegen
        AddButton(BUTTON_YES, BUTTONID_YES, 0);
        AddButton(BUTTON_NO, BUTTONID_NO, BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON);
    }

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

//........................................................................
}   // namespace svxform
//........................................................................

<commit_msg>INTEGRATION: CWS pchfix02 (1.6.116); FILE MERGED 2006/09/01 17:46:47 kaib 1.6.116.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: confirmdelete.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 05:03: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
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svx.hxx"

#ifndef SVX_FORM_CONFIRMDELETE_HXX
#include "confirmdelete.hxx"
#endif

#ifndef _SVX_DIALMGR_HXX
#include <dialmgr.hxx>
#endif
#ifndef _SVX_FMHELP_HRC
#include "fmhelp.hrc"
#endif
#ifndef _SVX_FMRESIDS_HRC
#include "fmresids.hrc"
#endif
#ifndef _UTL_CONFIGMGR_HXX_
#include <unotools/configmgr.hxx>
#endif
#ifndef _SV_MSGBOX_HXX
#include <vcl/msgbox.hxx>
#endif

//........................................................................
namespace svxform
{
//........................................................................

#define BORDER_HEIGHT   6 // default distance control-dialog
#define BORDER_WIDTH    6 // default distance control-dialog

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

    //====================================================================
    //= class ConfirmDeleteDialog
    //====================================================================
    //------------------------------------------------------------------------------
    ConfirmDeleteDialog::ConfirmDeleteDialog(Window* pParent, const String& _rTitle)
              :ButtonDialog(pParent, WB_HORZ | WB_STDDIALOG)
              ,m_aInfoImage (this)
              ,m_aTitle     (this, WB_WORDBREAK | WB_LEFT)
              ,m_aMessage   (this, WB_WORDBREAK | WB_LEFT)
    {
        String sMessage(SVX_RES(RID_STR_DELETECONFIRM));

        // Changed as per BugID 79541 Branding/Configuration
        ::utl::ConfigManager* pMgr = ::utl::ConfigManager::GetConfigManager();
        Any aProductName = pMgr->GetDirectConfigProperty(::utl::ConfigManager::PRODUCTNAME);
        ::rtl::OUString sProductName;
        aProductName >>= sProductName;

        String aTitle = sProductName;
        aProductName = pMgr->GetDirectConfigProperty(::utl::ConfigManager::PRODUCTVERSION);
        aProductName >>= sProductName;
        aTitle.AppendAscii(" ");
        aTitle += String(sProductName);
        SetText(aTitle);

        SetHelpId(HID_DLG_DBMSG);
        SetSizePixel(LogicToPixel(Size(220, 30),MAP_APPFONT));

        m_aInfoImage.SetPosSizePixel(LogicToPixel(Point(6, 6),MAP_APPFONT),
                                   LogicToPixel(Size(20, 20),MAP_APPFONT));
        m_aInfoImage.Show();

        m_aTitle.SetPosSizePixel(LogicToPixel(Point(45, 6),MAP_APPFONT),
                                 LogicToPixel(Size(169, 20),MAP_APPFONT));

        Font  aFont = m_aTitle.GetFont();
        aFont.SetWeight(WEIGHT_SEMIBOLD);
        m_aTitle.SetFont(aFont);
        m_aTitle.Show();

        m_aMessage.SetPosSizePixel(LogicToPixel(Point(45, 29),MAP_APPFONT),
                                   LogicToPixel(Size(169, 1),MAP_APPFONT));
        m_aMessage.Show();

        // Image festlegen
        m_aInfoImage.SetImage(WarningBox::GetStandardImage());

        // Title setzen
        m_aTitle.SetText(_rTitle);

        // Ermitteln der Hoehe des Textfeldes und des Dialogs
        Size aBorderSize = LogicToPixel(Size(BORDER_WIDTH, BORDER_HEIGHT),MAP_APPFONT);
        Rectangle aDlgRect(GetPosPixel(),GetSizePixel());
        Rectangle aMessageRect(m_aMessage.GetPosPixel(),m_aMessage.GetSizePixel());
        Rectangle aTextRect =
            GetTextRect(aMessageRect, sMessage, TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE | TEXT_DRAW_LEFT);

        long nHText = aTextRect.Bottom() > aMessageRect.Bottom() ? aTextRect.Bottom() - aMessageRect.Bottom() : 0;

        aDlgRect.Bottom() += nHText + 2 * aBorderSize.Height();
        aMessageRect.Bottom() += nHText;

        // Dialog anpassen
        SetSizePixel(aDlgRect.GetSize());
        SetPageSizePixel(aDlgRect.GetSize());

        // Message Text anpassen und setzen
        m_aMessage.SetSizePixel(aMessageRect.GetSize());
        m_aMessage.SetText(sMessage);

        // Buttons anlegen
        AddButton(BUTTON_YES, BUTTONID_YES, 0);
        AddButton(BUTTON_NO, BUTTONID_NO, BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON);
    }

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

//........................................................................
}   // namespace svxform
//........................................................................

<|endoftext|>


<commit_before>#ifndef VEXCL_PROFILER_HPP
#define VEXCL_PROFILER_HPP

/**
 * \file   profiler.hpp
 * \author Denis Demidov <ddemidov@ksu.ru>
 * \brief  Simple OpenCL/Host profiler.
 */

#ifdef WIN32
#  pragma warning(disable : 4267 4290)
#  define NOMINMAX
#endif

#define __CL_ENABLE_EXCEPTIONS

#include <iostream>
#include <iomanip>
#include <chrono>
#include <string>
#include <map>
#include <memory>
#include <stack>
#include <vector>
#include <CL/cl.hpp>
#include <cassert>

namespace vex {

/// Class for gathering and printing OpenCL and Host profiling info.
class profiler {
    private:
	class profile_unit {
	    public:
		profile_unit() : length(0) {}
		virtual ~profile_unit() {}
		virtual void tic() = 0;
		virtual double toc() = 0;

		double length;
		std::map<std::string, std::unique_ptr<profile_unit>> children;

		double children_time() const {
		    double tm = 0;

		    for(auto c = children.begin(); c != children.end(); c++)
			tm += c->second->length;

		    return tm;
		}

		uint max_line_width(const std::string &name, uint level) const {
		    uint w = name.size() + level;

		    for(auto c = children.begin(); c != children.end(); c++)
			w = std::max(w, c->second->max_line_width(c->first, level + shift_width));

		    return w;
		}

		void print(std::ostream &out, const std::string &name,
			uint level, double total, uint width) const
		{
		    using namespace std;
		    out << "[" << setw(level) << "";
		    print_line(out, name, length, 100 * length / total, width - level);

		    if (!children.empty()) {
			double sec = length - children_time();
			double perc = 100 * sec / total;

			if (perc > 1e-1) {
			    out << "[" << setw(level + 1) << "";
			    print_line(out, "self", sec, perc, width - level - 1);
			}
		    }

		    for(auto c = children.begin(); c != children.end(); c++)
			c->second->print(out, c->first, level + shift_width, total, width);
		}

		void print_line(std::ostream &out, const std::string &name,
			double time, double perc, uint width) const
		{
		    using namespace std;
		    out << name << ":";
		    out << setw(width - name.size()) << "";
		    out << setiosflags(ios::fixed);
		    out << setw(10) << setprecision(3) << time << " sec.";
		    out << "] (" << setprecision(2) << setw(6) << perc << "%)" << endl;
		}
	    private:
		static const uint shift_width = 2U;
	};

	class cpu_profile_unit : public profile_unit {
	    public:
		void tic() {
		    start = std::chrono::high_resolution_clock::now();
		}

		double toc() {
		    double delta = std::chrono::duration<double>(
			    std::chrono::high_resolution_clock::now() - start).count();

		    length += delta;

		    return delta;
		}

	    private:
		std::chrono::time_point<std::chrono::high_resolution_clock> start;
	};

	class cl_profile_unit : public profile_unit {
	    public:
		cl_profile_unit(std::vector<cl::CommandQueue> &queue)
		    : queue(queue), start(queue.size()), stop(queue.size())
		{}

		void tic() {
		    auto e = start.begin();
		    for(auto q = queue.begin(); q != queue.end(); q++, e++)
			q->enqueueMarker(&e[0]);
		}

		double toc() {
		    for(uint d = 0; d < queue.size(); d++)
			queue[d].enqueueMarker(&stop[d]);

		    // Measured time ends before marker is in the queue.
		    cl_long max_delta = 0;
		    for(uint d = 0; d < queue.size(); d++) {
			stop[d].wait();
			max_delta = std::max<cl_long>(max_delta,
				stop [d].getProfilingInfo<CL_PROFILING_COMMAND_END>() -
				start[d].getProfilingInfo<CL_PROFILING_COMMAND_END>()
				);
		    }

		    double delta = max_delta * 1.0e-9;

		    length += delta;

		    return delta;
		}
	    private:
		std::vector<cl::CommandQueue> &queue;
		std::vector<cl::Event> start;
		std::vector<cl::Event> stop;
	};

    public:
	/// Constructor.
	/**
	 * \param queue vector of command queues. Each queue should have been
	 *              initialized with CL_QUEUE_PROFILING_ENABLE property.
	 * \param name  Opional name to be used when profiling info is printed.
	 */
	profiler(
		std::vector<cl::CommandQueue> &queue,
		const std::string &name = "Profile"
		) : name(name), queue(queue)
	{
	    root.tic();
	    stack.push(&root);
	}

	/// Starts a CPU timer.
	/**
	 * Also pushes named interval to the top of the profiler hierarchy.
	 * \param name name of the measured interval.
	 */
	void tic_cpu(const std::string &name) {
	    assert(!stack.empty());

	    profile_unit *top  = stack.top();
	    cpu_profile_unit *unit = new cpu_profile_unit();
	    unit->tic();

	    top->children[name].reset(unit);

	    stack.push(unit);
	}

	/// Enqueues a marker into each of the provided queues.
	/**
	 * Also pushes named interval to the top of the profiler hierarchy.
	 * \param name name of the measured interval.
	 */
	void tic_cl(const std::string &name) {
	    assert(!stack.empty());

	    profile_unit *top  = stack.top();
	    cl_profile_unit *unit = new cl_profile_unit(queue);
	    unit->tic();

	    top->children[name].reset(unit);

	    stack.push(unit);
	}

	/// Returns time since last tic.
	/**
	 * Also removes interval from the top of the profiler hierarchy.
	 * \param name name of the measured interval.
	 */
	double toc(const std::string &name) {
	    assert(!stack.empty());
	    assert(stack.top() != &root);

	    profile_unit *top = stack.top();
	    double delta = top->toc();
	    stack.pop();

	    return delta;
	}

    private:
	std::string name;
	std::vector<cl::CommandQueue> &queue;
	cpu_profile_unit root;
	std::stack<profile_unit*> stack;

	void print(std::ostream &out) {
	    if (stack.top() != &root)
		out << "Warning! Profile is incomplete." << std::endl;

	    double length = root.toc();

	    out << std::endl;
	    root.print(out, name, 0, length, root.max_line_width(name, 0));
	}

	friend std::ostream& operator<<(std::ostream &out, profiler &prof);

};

std::ostream& operator<<(std::ostream &os, profiler &prof) {
    prof.print(os);
    return os;
}

} // namespace vex

#endif
<commit_msg>Visual Studio does not know about std::chrono<commit_after>#ifndef VEXCL_PROFILER_HPP
#define VEXCL_PROFILER_HPP

/**
 * \file   profiler.hpp
 * \author Denis Demidov <ddemidov@ksu.ru>
 * \brief  Simple OpenCL/Host profiler.
 */

#ifdef WIN32
#  pragma warning(disable : 4267 4290)
#  define NOMINMAX
#endif

#define __CL_ENABLE_EXCEPTIONS

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <memory>
#include <stack>
#include <vector>
#include <CL/cl.hpp>
#include <cassert>

#ifdef WIN32
#  include <sys/timeb.h>
inline double operator-(const timeb &a, const timeb &b) {
    return a.time - b.time + 1e-3 * (a.millitm - b.millitm);
}
#else
#  include <chrono>
#endif

namespace vex {

/// Class for gathering and printing OpenCL and Host profiling info.
class profiler {
    private:
	class profile_unit {
	    public:
		profile_unit() : length(0) {}
		virtual ~profile_unit() {}
		virtual void tic() = 0;
		virtual double toc() = 0;

		double length;
		std::map<std::string, std::unique_ptr<profile_unit>> children;

		double children_time() const {
		    double tm = 0;

		    for(auto c = children.begin(); c != children.end(); c++)
			tm += c->second->length;

		    return tm;
		}

		uint max_line_width(const std::string &name, uint level) const {
		    uint w = name.size() + level;

		    for(auto c = children.begin(); c != children.end(); c++)
			w = std::max(w, c->second->max_line_width(c->first, level + shift_width));

		    return w;
		}

		void print(std::ostream &out, const std::string &name,
			uint level, double total, uint width) const
		{
		    using namespace std;
		    out << "[" << setw(level) << "";
		    print_line(out, name, length, 100 * length / total, width - level);

		    if (!children.empty()) {
			double sec = length - children_time();
			double perc = 100 * sec / total;

			if (perc > 1e-1) {
			    out << "[" << setw(level + 1) << "";
			    print_line(out, "self", sec, perc, width - level - 1);
			}
		    }

		    for(auto c = children.begin(); c != children.end(); c++)
			c->second->print(out, c->first, level + shift_width, total, width);
		}

		void print_line(std::ostream &out, const std::string &name,
			double time, double perc, uint width) const
		{
		    using namespace std;
		    out << name << ":";
		    out << setw(width - name.size()) << "";
		    out << setiosflags(ios::fixed);
		    out << setw(10) << setprecision(3) << time << " sec.";
		    out << "] (" << setprecision(2) << setw(6) << perc << "%)" << endl;
		}
	    private:
		static const uint shift_width = 2U;
	};

	class cpu_profile_unit : public profile_unit {
	    public:
		void tic() {
#ifdef WIN32
		    ftime(&start);
#endif
		    start = std::chrono::high_resolution_clock::now();
		}

		double toc() {
#ifdef WIN32
		    timeb now;
		    ftime(&now);
		    delta = now - start;
#else
		    double delta = std::chrono::duration<double>(
			    std::chrono::high_resolution_clock::now() - start).count();
#endif

		    length += delta;

		    return delta;
		}

	    private:
#ifdef WIN32
		timeb start;
#else
		std::chrono::time_point<std::chrono::high_resolution_clock> start;
#endif
	};

	class cl_profile_unit : public profile_unit {
	    public:
		cl_profile_unit(std::vector<cl::CommandQueue> &queue)
		    : queue(queue), start(queue.size()), stop(queue.size())
		{}

		void tic() {
		    auto e = start.begin();
		    for(auto q = queue.begin(); q != queue.end(); q++, e++)
			q->enqueueMarker(&e[0]);
		}

		double toc() {
		    for(uint d = 0; d < queue.size(); d++)
			queue[d].enqueueMarker(&stop[d]);

		    // Measured time ends before marker is in the queue.
		    cl_long max_delta = 0;
		    for(uint d = 0; d < queue.size(); d++) {
			stop[d].wait();
			max_delta = std::max<cl_long>(max_delta,
				stop [d].getProfilingInfo<CL_PROFILING_COMMAND_END>() -
				start[d].getProfilingInfo<CL_PROFILING_COMMAND_END>()
				);
		    }

		    double delta = max_delta * 1.0e-9;

		    length += delta;

		    return delta;
		}
	    private:
		std::vector<cl::CommandQueue> &queue;
		std::vector<cl::Event> start;
		std::vector<cl::Event> stop;
	};

    public:
	/// Constructor.
	/**
	 * \param queue vector of command queues. Each queue should have been
	 *              initialized with CL_QUEUE_PROFILING_ENABLE property.
	 * \param name  Opional name to be used when profiling info is printed.
	 */
	profiler(
		std::vector<cl::CommandQueue> &queue,
		const std::string &name = "Profile"
		) : name(name), queue(queue)
	{
	    root.tic();
	    stack.push(&root);
	}

	/// Starts a CPU timer.
	/**
	 * Also pushes named interval to the top of the profiler hierarchy.
	 * \param name name of the measured interval.
	 */
	void tic_cpu(const std::string &name) {
	    assert(!stack.empty());

	    profile_unit *top  = stack.top();
	    cpu_profile_unit *unit = new cpu_profile_unit();
	    unit->tic();

	    top->children[name].reset(unit);

	    stack.push(unit);
	}

	/// Enqueues a marker into each of the provided queues.
	/**
	 * Also pushes named interval to the top of the profiler hierarchy.
	 * \param name name of the measured interval.
	 */
	void tic_cl(const std::string &name) {
	    assert(!stack.empty());

	    profile_unit *top  = stack.top();
	    cl_profile_unit *unit = new cl_profile_unit(queue);
	    unit->tic();

	    top->children[name].reset(unit);

	    stack.push(unit);
	}

	/// Returns time since last tic.
	/**
	 * Also removes interval from the top of the profiler hierarchy.
	 * \param name name of the measured interval.
	 */
	double toc(const std::string &name) {
	    assert(!stack.empty());
	    assert(stack.top() != &root);

	    profile_unit *top = stack.top();
	    double delta = top->toc();
	    stack.pop();

	    return delta;
	}

    private:
	std::string name;
	std::vector<cl::CommandQueue> &queue;
	cpu_profile_unit root;
	std::stack<profile_unit*> stack;

	void print(std::ostream &out) {
	    if (stack.top() != &root)
		out << "Warning! Profile is incomplete." << std::endl;

	    double length = root.toc();

	    out << std::endl;
	    root.print(out, name, 0, length, root.max_line_width(name, 0));
	}

	friend std::ostream& operator<<(std::ostream &out, profiler &prof);

};

std::ostream& operator<<(std::ostream &os, profiler &prof) {
    prof.print(os);
    return os;
}

} // namespace vex

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007-2009 Digital Bazaar, Inc. All rights reserved.
 */
#include "db/event/Observable.h"

#include "db/rt/DynamicObjectIterator.h"
#include "db/rt/Iterator.h"
#include "db/event/ObserverDelegate.h"
#include <algorithm>

using namespace std;
using namespace db::event;
using namespace db::modest;
using namespace db::rt;

Observable::Observable()
{
   // no events to dispatch yet
   mDispatch = false;
}

Observable::~Observable()
{
   // ensure event dispatching is stopped
   Observable::stop();
}

void Observable::registerObserver(
   Observer* observer, EventId id, DynamicObject* filter)
{
   mRegistrationLock.lock();
   {
      // add tap to self if EventId doesn't exist yet
      EventIdMap::iterator i = mTaps.find(id);
      if(i == mTaps.end())
      {
         mTaps.insert(make_pair(id, id));
      }

      // get the event ID's filter map, creating it if necessary
      ObserverMap::iterator oi = mObservers.find(id);
      if(oi == mObservers.end())
      {
         // add a filter map
         FilterMap tmp;
         pair<ObserverMap::iterator, bool> p =
            mObservers.insert(make_pair(id, tmp));
         oi = p.first;
      }

      // create the event filter to compare against
      EventFilter ef(NULL);
      if(filter != NULL)
      {
         ef = filter->clone();
      }

      // get the observer list, creating it if necessary
      FilterMap::iterator fi = oi->second.find(ef);
      if(fi == oi->second.end())
      {
         // add an observer list
         ObserverList tmp;
         pair<FilterMap::iterator, bool> p =
            oi->second.insert(make_pair(ef, tmp));
         fi = p.first;
      }

      // add the observer to the list
      fi->second.push_back(observer);
   }
   mRegistrationLock.unlock();
}

void Observable::unregisterObserver(Observer* observer, EventId id)
{
   mRegistrationLock.lock();
   {
      // wait for any event processing operation that is not on the same
      // thread but is using the same observer that is being unregistered
      // -- this helps prevent a race condition where an observer could
      // be free'd after being unregistered by whilst still processing an event
      IteratorRef<Operation> itr = mOpList.getIterator();
      while(itr->hasNext())
      {
         Operation& op = itr->next();
         if(op->getUserData() == observer)
         {
            // wait for operation to complete
            op->waitFor();
         }
      }
      mOpList.prune();

      // find the filter map for the event
      ObserverMap::iterator i = mObservers.find(id);
      if(i != mObservers.end())
      {
         // remove observer
         vector<EventFilter> removableFilters;
         removeObserverFromFilterMap(observer, i->second, removableFilters);

         // erase filter map if it would be empty after processing
         // the removable filters
         if(removableFilters.size() == i->second.size())
         {
            mObservers.erase(i);
         }
         // remove all appropriate filters
         else
         {
            for(vector<EventFilter>::iterator fi = removableFilters.begin();
                fi != removableFilters.end(); fi++)
            {
               i->second.erase(*fi);
            }
         }
      }
   }
   mRegistrationLock.unlock();
}

void Observable::unregisterObserver(Observer* observer)
{
   // FIXME: add an optimization that stores all of the events that the
   // observer is registered to receive to shorten this unregistration process

   mRegistrationLock.lock();
   {
      // wait for any event processing operation that is not on the same
      // thread but is using the same observer that is being unregistered
      // -- this helps prevent a race condition where an observer could
      // be free'd after being unregistered by whilst still processing an event
      IteratorRef<Operation> itr = mOpList.getIterator();
      while(itr->hasNext())
      {
         Operation& op = itr->next();
         if(op->getUserData() == observer)
         {
            // wait for operation to complete
            op->waitFor();
         }
      }
      mOpList.prune();

      // iterate over all filter maps, keep a list of event IDs to remove
      vector<EventId> removeIds;
      for(ObserverMap::iterator i = mObservers.begin();
          i != mObservers.end(); i++)
      {
         // remove observer
         vector<EventFilter> removableFilters;
         removeObserverFromFilterMap(observer, i->second, removableFilters);

         // mark filter map for removal if it would be empty after processing
         // the removable filters
         if(removableFilters.size() == i->second.size())
         {
            removeIds.push_back(i->first);
         }
         // remove all appropriate filters
         else
         {
            for(vector<EventFilter>::iterator fi = removableFilters.begin();
                fi != removableFilters.end(); fi++)
            {
               i->second.erase(*fi);
            }
         }
      }

      // remove all appropriate filter map entries
      for(std::vector<EventId>::iterator ei = removeIds.begin();
          ei != removeIds.end(); ei++)
      {
         mObservers.erase(*ei);
      }
   }
   mRegistrationLock.unlock();
}

void Observable::addTap(EventId id, EventId tap)
{
   mRegistrationLock.lock();
   {
      // add tap to id-self if EventId doesn't exist yet
      EventIdMap::iterator i = mTaps.find(id);
      if(i == mTaps.end())
      {
         mTaps.insert(make_pair(id, id));
      }

      // insert tap for id
      mTaps.insert(make_pair(id, tap));

      // add tap to tap-self if EventId doesn't exist yet
      i = mTaps.find(tap);
      if(i == mTaps.end())
      {
         mTaps.insert(make_pair(tap, tap));
      }
   }
   mRegistrationLock.unlock();
}

void Observable::removeTap(EventId id, EventId tap)
{
   mRegistrationLock.lock();
   {
      // look for tap in the range of taps
      EventIdMap::iterator i = mTaps.find(id);
      if(i != mTaps.end())
      {
         EventIdMap::iterator end = mTaps.upper_bound(id);
         for(; i != end; i++)
         {
            if(i->second == tap)
            {
               // remove tap and break
               mTaps.erase(i);
               break;
            }
         }
      }
   }
   mRegistrationLock.unlock();
}

void Observable::schedule(Event e, EventId id, bool async)
{
   // set the event's ID
   e["id"] = id;

   if(async)
   {
      // lock to modify event queue and dispatch condition
      mQueueLock.lock();
      mDispatch = true;

      // add event to queue
      mEventQueue.push_back(e);

      // notify on queue lock and release
      mQueueLock.notifyAll();
      mQueueLock.unlock();
   }
   else
   {
      // dispatch the event immediately
      dispatchEvent(e);
   }
}

void Observable::start(OperationRunner* opRunner)
{
   mRegistrationLock.lock();
   {
      if(mOperation.isNull())
      {
         // store operation runner, activate dispatching,
         // create and run operation
         mOpRunner = opRunner;
         mDispatch = true;
         mOperation = *this;
         opRunner->runOperation(mOperation);
      }
   }
   mRegistrationLock.unlock();
}

void Observable::stop()
{
   mRegistrationLock.lock();
   {
      if(!mOperation.isNull())
      {
         // interrupt dispatch operation
         mOperation->interrupt();

         // Note: We only care about locking in this method to prevent
         // start() from running while we are shutting down -- we don't
         // care if more events are scheduled because that won't cause
         // any conflicts. Since this is the case, and start() will
         // check mOperation.isNull() before starting anything, then
         // we don't need to worry about it starting here since mOperation
         // can't be NULL until we relock and clear it below.
         //
         // We need to unlock() while we wait for the dispatch operation
         // to complete because it needs to lock after dispatching each
         // event and won't finish if we are holding the lock here waiting
         // for it to finish.

         // unlock, wait for dispatch operation to finish, relock
         mRegistrationLock.unlock();
         mOperation->waitFor();
         mRegistrationLock.lock();

         // clean up operation
         mOperation.setNull();
      }
   }
   mRegistrationLock.unlock();
}

void Observable::run()
{
   // keep dispatching until interrupted
   while(!mOperation->isInterrupted())
   {
      // lock event queue and check to see if we can dispatch
      mQueueLock.lock();
      if(mDispatch)
      {
         mQueueLock.unlock();
         dispatchEvents();
      }
      else
      {
         // wait until dispatch condition is marked true and we are notified
         mQueueLock.wait();
         mQueueLock.unlock();
      }
   }
}

void Observable::removeObserverFromFilterMap(
   Observer* observer, FilterMap& fm,
   vector<EventFilter>& removableFilters)
{
   // remove the observer from every filter's list
   for(FilterMap::iterator fi = fm.begin(); fi != fm.end(); fi++)
   {
      // erase all instances of the observer in this filter's list
      for(ObserverList::iterator li = fi->second.begin();
          li != fi->second.end();)
      {
         if(*li == observer)
         {
            // erase observer entry
            li = fi->second.erase(li);
         }
         else
         {
            li++;
         }
      }

      // if filter's list is now empty, mark it for removal
      if(fi->second.empty())
      {
         removableFilters.push_back(fi->first);
      }
   }
}

void Observable::dispatchEvent(
   Event& e, EventId id, OperationList& waitList)
{
   // go through the list of EventId taps
   EventIdMap::iterator ti = mTaps.find(id);
   if(ti != mTaps.end())
   {
      EventIdMap::iterator end = mTaps.upper_bound(id);
      for(; ti != end; ti++)
      {
         // dispatch event if the tap is the EventId itself
         if(ti->second == id)
         {
            // get the filter map for the EventId tap
            ObserverMap::iterator oi = mObservers.find(id);
            if(oi != mObservers.end())
            {
               FilterMap& fm = oi->second;

               // go through each filter
               bool pass;
               for(FilterMap::iterator fi = fm.begin(); fi != fm.end(); fi++)
               {
                  // check observer filter if appropriate
                  pass = true;
                  if(!fi->first.isNull())
                  {
                     // filter must be a subset of event
                     pass = fi->first.isSubset(e);
                  }

                  if(pass)
                  {
                     for(ObserverList::iterator li =
                         fi->second.begin(); li != fi->second.end(); li++)
                     {
                        // create and run event dispatcher for observer
                        // set operation user data to observer
                        RunnableRef ed = new ObserverDelegate<Observer>(*li, e);
                        Operation op(ed);
                        op->setUserData(*li);
                        mOpRunner->runOperation(op);

                        // add all operations to the current operation list
                        mOpList.add(op);

                        // only add serial events to the wait list,
                        // parallel events are not waited on for completion
                        if(!e->hasMember("parallel") ||
                           !e["parallel"]->getBoolean())
                        {
                           waitList.add(op);
                        }
                     }
                  }
               }
            }
         }
         else
         {
            // dispatch event to tap
            dispatchEvent(e, ti->second, waitList);
         }
      }
   }
}

void Observable::dispatchEvent(Event& e)
{
   // create an operation list for waiting
   OperationList waitList;

   // lock to process event and prevent registration modification
   mRegistrationLock.lock();

   // get the EventId for the event and dispatch it
   EventId id = e["id"]->getUInt64();
   dispatchEvent(e, id, waitList);

   if(!waitList.isEmpty())
   {
      // unlock registration and wait for dispatch operations to complete
      mRegistrationLock.unlock();

      if(!waitList.waitFor())
      {
         // dispatch thread interrupted, so interrupt all
         // event dispatches and wait for them to complete
         waitList.interrupt();
         waitList.waitFor(false);
         mOpList.interrupt();
         mOpList.waitFor(false);
      }

      // relock registration
      mRegistrationLock.lock();
   }

   // prune operation list
   mOpList.prune();

   // unlock registration lock
   mRegistrationLock.unlock();
}

void Observable::dispatchEvents()
{
   // lock event queue
   mQueueLock.lock();

   // continue dispatching until no events or interrupted
   while(!mEventQueue.empty() && !mOperation->isInterrupted())
   {
      // get the next event
      Event e = mEventQueue.front();
      mEventQueue.pop_front();

      // unlock queue, dispatch event, relock queue
      mQueueLock.unlock();
      dispatchEvent(e);
      mQueueLock.lock();
   }

   // turn off dispatching
   mDispatch = false;

   // unlock event queue
   mQueueLock.unlock();
}
<commit_msg>Fixed potential deadlock case where an unregistration call is waiting for an operation to complete that never will because the unregistration call is coming from the same thread.<commit_after>/*
 * Copyright (c) 2007-2009 Digital Bazaar, Inc. All rights reserved.
 */
#include "db/event/Observable.h"

#include "db/rt/DynamicObjectIterator.h"
#include "db/rt/Iterator.h"
#include "db/event/ObserverDelegate.h"
#include <algorithm>

using namespace std;
using namespace db::event;
using namespace db::modest;
using namespace db::rt;

Observable::Observable()
{
   // no events to dispatch yet
   mDispatch = false;
}

Observable::~Observable()
{
   // ensure event dispatching is stopped
   Observable::stop();
}

void Observable::registerObserver(
   Observer* observer, EventId id, DynamicObject* filter)
{
   mRegistrationLock.lock();
   {
      // add tap to self if EventId doesn't exist yet
      EventIdMap::iterator i = mTaps.find(id);
      if(i == mTaps.end())
      {
         mTaps.insert(make_pair(id, id));
      }

      // get the event ID's filter map, creating it if necessary
      ObserverMap::iterator oi = mObservers.find(id);
      if(oi == mObservers.end())
      {
         // add a filter map
         FilterMap tmp;
         pair<ObserverMap::iterator, bool> p =
            mObservers.insert(make_pair(id, tmp));
         oi = p.first;
      }

      // create the event filter to compare against
      EventFilter ef(NULL);
      if(filter != NULL)
      {
         ef = filter->clone();
      }

      // get the observer list, creating it if necessary
      FilterMap::iterator fi = oi->second.find(ef);
      if(fi == oi->second.end())
      {
         // add an observer list
         ObserverList tmp;
         pair<FilterMap::iterator, bool> p =
            oi->second.insert(make_pair(ef, tmp));
         fi = p.first;
      }

      // add the observer to the list
      fi->second.push_back(observer);
   }
   mRegistrationLock.unlock();
}

/**
 * A helper function that will wait for an observer to finish processing
 * events before proceeding -- unless the thread that is processing the
 * events is the current thread. This prevents a race condition where an
 * observer that is to be unregistered could be concurrently processing
 * an event during the unregister call. If this wait is not performed to
 * allow the observer to finish event processing, then the observer could
 * be free'd whilst processing an event, resulting in a segfault.
 *
 * @param observer the observer being unregistered.
 * @param opList the operation list that may contain the observer's event
 *               processing operation(s).
 */
static void waitForObserver(Observer* observer, OperationList& opList)
{
   // wait for the observer to finish event processing but only if the
   // unregistration request is not coming from this thread (prevents deadlock)
   Thread* t = Thread::currentThread();
   IteratorRef<Operation> itr = opList.getIterator();
   while(itr->hasNext())
   {
      Operation& op = itr->next();
      if(op->getUserData() == observer && t != op->getThread())
      {
         // wait for operation to complete
         op->waitFor();
      }
   }
   opList.prune();
}

void Observable::unregisterObserver(Observer* observer, EventId id)
{
   mRegistrationLock.lock();
   {
      // wait for the observer to finish any event processing
      waitForObserver(observer, mOpList);

      // find the filter map for the event
      ObserverMap::iterator i = mObservers.find(id);
      if(i != mObservers.end())
      {
         // remove observer
         vector<EventFilter> removableFilters;
         removeObserverFromFilterMap(observer, i->second, removableFilters);

         // erase filter map if it would be empty after processing
         // the removable filters
         if(removableFilters.size() == i->second.size())
         {
            mObservers.erase(i);
         }
         // remove all appropriate filters
         else
         {
            for(vector<EventFilter>::iterator fi = removableFilters.begin();
                fi != removableFilters.end(); fi++)
            {
               i->second.erase(*fi);
            }
         }
      }
   }
   mRegistrationLock.unlock();
}

void Observable::unregisterObserver(Observer* observer)
{
   // FIXME: add an optimization that stores all of the events that the
   // observer is registered to receive to shorten this unregistration process

   mRegistrationLock.lock();
   {
      // wait for the observer to finish any event processing
      waitForObserver(observer, mOpList);

      // iterate over all filter maps, keep a list of event IDs to remove
      vector<EventId> removeIds;
      for(ObserverMap::iterator i = mObservers.begin();
          i != mObservers.end(); i++)
      {
         // remove observer
         vector<EventFilter> removableFilters;
         removeObserverFromFilterMap(observer, i->second, removableFilters);

         // mark filter map for removal if it would be empty after processing
         // the removable filters
         if(removableFilters.size() == i->second.size())
         {
            removeIds.push_back(i->first);
         }
         // remove all appropriate filters
         else
         {
            for(vector<EventFilter>::iterator fi = removableFilters.begin();
                fi != removableFilters.end(); fi++)
            {
               i->second.erase(*fi);
            }
         }
      }

      // remove all appropriate filter map entries
      for(std::vector<EventId>::iterator ei = removeIds.begin();
          ei != removeIds.end(); ei++)
      {
         mObservers.erase(*ei);
      }
   }
   mRegistrationLock.unlock();
}

void Observable::addTap(EventId id, EventId tap)
{
   mRegistrationLock.lock();
   {
      // add tap to id-self if EventId doesn't exist yet
      EventIdMap::iterator i = mTaps.find(id);
      if(i == mTaps.end())
      {
         mTaps.insert(make_pair(id, id));
      }

      // insert tap for id
      mTaps.insert(make_pair(id, tap));

      // add tap to tap-self if EventId doesn't exist yet
      i = mTaps.find(tap);
      if(i == mTaps.end())
      {
         mTaps.insert(make_pair(tap, tap));
      }
   }
   mRegistrationLock.unlock();
}

void Observable::removeTap(EventId id, EventId tap)
{
   mRegistrationLock.lock();
   {
      // look for tap in the range of taps
      EventIdMap::iterator i = mTaps.find(id);
      if(i != mTaps.end())
      {
         EventIdMap::iterator end = mTaps.upper_bound(id);
         for(; i != end; i++)
         {
            if(i->second == tap)
            {
               // remove tap and break
               mTaps.erase(i);
               break;
            }
         }
      }
   }
   mRegistrationLock.unlock();
}

void Observable::schedule(Event e, EventId id, bool async)
{
   // set the event's ID
   e["id"] = id;

   if(async)
   {
      // lock to modify event queue and dispatch condition
      mQueueLock.lock();
      mDispatch = true;

      // add event to queue
      mEventQueue.push_back(e);

      // notify on queue lock and release
      mQueueLock.notifyAll();
      mQueueLock.unlock();
   }
   else
   {
      // dispatch the event immediately
      dispatchEvent(e);
   }
}

void Observable::start(OperationRunner* opRunner)
{
   mRegistrationLock.lock();
   {
      if(mOperation.isNull())
      {
         // store operation runner, activate dispatching,
         // create and run operation
         mOpRunner = opRunner;
         mDispatch = true;
         mOperation = *this;
         opRunner->runOperation(mOperation);
      }
   }
   mRegistrationLock.unlock();
}

void Observable::stop()
{
   mRegistrationLock.lock();
   {
      if(!mOperation.isNull())
      {
         // interrupt dispatch operation
         mOperation->interrupt();

         // Note: We only care about locking in this method to prevent
         // start() from running while we are shutting down -- we don't
         // care if more events are scheduled because that won't cause
         // any conflicts. Since this is the case, and start() will
         // check mOperation.isNull() before starting anything, then
         // we don't need to worry about it starting here since mOperation
         // can't be NULL until we relock and clear it below.
         //
         // We need to unlock() while we wait for the dispatch operation
         // to complete because it needs to lock after dispatching each
         // event and won't finish if we are holding the lock here waiting
         // for it to finish.

         // unlock, wait for dispatch operation to finish, relock
         mRegistrationLock.unlock();
         mOperation->waitFor();
         mRegistrationLock.lock();

         // clean up operation
         mOperation.setNull();
      }
   }
   mRegistrationLock.unlock();
}

void Observable::run()
{
   // keep dispatching until interrupted
   while(!mOperation->isInterrupted())
   {
      // lock event queue and check to see if we can dispatch
      mQueueLock.lock();
      if(mDispatch)
      {
         mQueueLock.unlock();
         dispatchEvents();
      }
      else
      {
         // wait until dispatch condition is marked true and we are notified
         mQueueLock.wait();
         mQueueLock.unlock();
      }
   }
}

void Observable::removeObserverFromFilterMap(
   Observer* observer, FilterMap& fm,
   vector<EventFilter>& removableFilters)
{
   // remove the observer from every filter's list
   for(FilterMap::iterator fi = fm.begin(); fi != fm.end(); fi++)
   {
      // erase all instances of the observer in this filter's list
      for(ObserverList::iterator li = fi->second.begin();
          li != fi->second.end();)
      {
         if(*li == observer)
         {
            // erase observer entry
            li = fi->second.erase(li);
         }
         else
         {
            li++;
         }
      }

      // if filter's list is now empty, mark it for removal
      if(fi->second.empty())
      {
         removableFilters.push_back(fi->first);
      }
   }
}

void Observable::dispatchEvent(
   Event& e, EventId id, OperationList& waitList)
{
   // go through the list of EventId taps
   EventIdMap::iterator ti = mTaps.find(id);
   if(ti != mTaps.end())
   {
      EventIdMap::iterator end = mTaps.upper_bound(id);
      for(; ti != end; ti++)
      {
         // dispatch event if the tap is the EventId itself
         if(ti->second == id)
         {
            // get the filter map for the EventId tap
            ObserverMap::iterator oi = mObservers.find(id);
            if(oi != mObservers.end())
            {
               FilterMap& fm = oi->second;

               // go through each filter
               bool pass;
               for(FilterMap::iterator fi = fm.begin(); fi != fm.end(); fi++)
               {
                  // check observer filter if appropriate
                  pass = true;
                  if(!fi->first.isNull())
                  {
                     // filter must be a subset of event
                     pass = fi->first.isSubset(e);
                  }

                  if(pass)
                  {
                     for(ObserverList::iterator li =
                         fi->second.begin(); li != fi->second.end(); li++)
                     {
                        // create and run event dispatcher for observer
                        // set operation user data to observer
                        RunnableRef ed = new ObserverDelegate<Observer>(*li, e);
                        Operation op(ed);
                        op->setUserData(*li);
                        mOpRunner->runOperation(op);

                        // add all operations to the current operation list
                        mOpList.add(op);

                        // only add serial events to the wait list,
                        // parallel events are not waited on for completion
                        if(!e->hasMember("parallel") ||
                           !e["parallel"]->getBoolean())
                        {
                           waitList.add(op);
                        }
                     }
                  }
               }
            }
         }
         else
         {
            // dispatch event to tap
            dispatchEvent(e, ti->second, waitList);
         }
      }
   }
}

void Observable::dispatchEvent(Event& e)
{
   // create an operation list for waiting
   OperationList waitList;

   // lock to process event and prevent registration modification
   mRegistrationLock.lock();

   // get the EventId for the event and dispatch it
   EventId id = e["id"]->getUInt64();
   dispatchEvent(e, id, waitList);

   if(!waitList.isEmpty())
   {
      // unlock registration and wait for dispatch operations to complete
      mRegistrationLock.unlock();

      if(!waitList.waitFor())
      {
         // dispatch thread interrupted, so interrupt all
         // event dispatches and wait for them to complete
         waitList.interrupt();
         waitList.waitFor(false);
         mOpList.interrupt();
         mOpList.waitFor(false);
      }

      // relock registration
      mRegistrationLock.lock();
   }

   // prune operation list
   mOpList.prune();

   // unlock registration lock
   mRegistrationLock.unlock();
}

void Observable::dispatchEvents()
{
   // lock event queue
   mQueueLock.lock();

   // continue dispatching until no events or interrupted
   while(!mEventQueue.empty() && !mOperation->isInterrupted())
   {
      // get the next event
      Event e = mEventQueue.front();
      mEventQueue.pop_front();

      // unlock queue, dispatch event, relock queue
      mQueueLock.unlock();
      dispatchEvent(e);
      mQueueLock.lock();
   }

   // turn off dispatching
   mDispatch = false;

   // unlock event queue
   mQueueLock.unlock();
}
<|endoftext|>


<commit_before>#include "serializer.h"
#include "container.h"
#include "node.h"
#include "tree.h"
#include "space.h"
#include "border.h"
#include "helpers.h"
#include "axlib/display.h"

#define internal static

internal void SerializeParentNode(tree_node *Parent, std::string Role, std::vector<std::string> &Serialized);
internal tree_node * DeserializeNodeTree(std::vector<std::string> &Serialized, ax_display *Display);
internal unsigned int DeserializeParentNode(tree_node *Parent, ax_display *Display, std::vector<std::string> &Serialized, unsigned int Index);
internal unsigned int DeserializeChildNode(tree_node *Parent, ax_display *Display, std::vector<std::string> &Serialized, unsigned int Index);

internal void
SerializeParentNode(tree_node *Parent, std::string Role, std::vector<std::string> &Serialized)
{
    Serialized.push_back("kwmc tree root create " + Role);
    Serialized.push_back("kwmc tree split-mode " + std::to_string(Parent->SplitMode));
    Serialized.push_back("kwmc tree split-ratio " + std::to_string(Parent->SplitRatio));

    if(IsLeafNode(Parent->LeftChild))
    {
        Serialized.push_back("kwmc tree child");
        Serialized.push_back("kwmc tree leaf create left");
    }
    else
    {
        Serialized.push_back("kwmc tree child");
        SerializeParentNode(Parent->LeftChild, "left", Serialized);
    }

    if(IsLeafNode(Parent->RightChild))
    {
        Serialized.push_back("kwmc tree child");
        Serialized.push_back("kwmc tree leaf create right");
    }
    else
    {
        Serialized.push_back("kwmc tree child");
        SerializeParentNode(Parent->RightChild, "right", Serialized);
    }
}

internal unsigned int
DeserializeParentNode(tree_node *Parent, ax_display *Display, std::vector<std::string> &Serialized, unsigned int Index)
{
    unsigned int LineNumber = Index;
    for(;LineNumber < Serialized.size(); ++LineNumber)
    {
        std::string Line = Serialized[LineNumber];
        std::vector<std::string> Tokens = SplitString(Line, ' ');

        if(Tokens[2] == "split-mode")
        {
            Parent->SplitMode = (split_type)ConvertStringToInt(Tokens[3]);
            DEBUG("Root: SplitMode Found " + Tokens[3]);
        }
        else if(Tokens[2] == "split-ratio")
        {
            Parent->SplitRatio = ConvertStringToDouble(Tokens[3]);
            DEBUG("Root: SplitRatio Found " + Tokens[3]);
        }
        else if(Tokens[2] == "child")
        {
            DEBUG("Root: Child Found");
            DEBUG("Parent: " << Parent->SplitMode << "|" << Parent->SplitRatio);
            LineNumber = DeserializeChildNode(Parent, Display, Serialized, LineNumber+1);
        }

        if(Parent->RightChild)
            return LineNumber;
    }

    return LineNumber;
}

internal unsigned int
DeserializeChildNode(tree_node *Parent, ax_display *Display, std::vector<std::string> &Serialized, unsigned int Index)
{
    unsigned int LineNumber = Index;
    for(;LineNumber < Serialized.size(); ++LineNumber)
    {
        std::string Line = Serialized[LineNumber];
        if(Line == "kwmc tree root create left")
        {
            DEBUG("Child: Create root");
            Parent->LeftChild = CreateLeafNode(Display, Parent, 0, CONTAINER_LEFT);
            CreateDeserializedNodeContainer(Display, Parent->LeftChild);
            LineNumber = DeserializeParentNode(Parent->LeftChild, Display, Serialized, LineNumber+1);
            return LineNumber;
        }
        else if(Line == "kwmc tree root create right")
        {
            DEBUG("Child: Create root");
            Parent->RightChild = CreateLeafNode(Display, Parent, 0, CONTAINER_RIGHT);
            CreateDeserializedNodeContainer(Display, Parent->RightChild);
            LineNumber = DeserializeParentNode(Parent->RightChild, Display, Serialized, LineNumber+1);
            return LineNumber;
        }
        else if(Line == "kwmc tree leaf create left")
        {
            DEBUG("Child: Create left leaf");
            Parent->LeftChild = CreateLeafNode(Display, Parent, 0, CONTAINER_LEFT);
            CreateDeserializedNodeContainer(Display, Parent->LeftChild);
            return LineNumber;
        }
        else if(Line == "kwmc tree leaf create right")
        {
            DEBUG("Child: Create right leaf");
            Parent->RightChild = CreateLeafNode(Display, Parent, 0, CONTAINER_RIGHT);
            CreateDeserializedNodeContainer(Display, Parent->RightChild);
            return LineNumber;
        }
    }

    return LineNumber;
}

internal tree_node *
DeserializeNodeTree(std::vector<std::string> &Serialized, ax_display *Display)
{
    if(Serialized.empty() || Serialized[0] != "kwmc tree root create parent")
        return NULL;

    DEBUG("Deserialize: Create Master");
    tree_node *RootNode = CreateRootNode();
    SetRootNodeContainer(Display, RootNode);
    DeserializeParentNode(RootNode, Display, Serialized, 1);
    return RootNode;
}

void SaveBSPTreeToFile(ax_display *Display, space_info *SpaceInfo, std::string Name)
{
    if(SpaceInfo->Settings.Mode != SpaceModeBSP || IsLeafNode(SpaceInfo->RootNode))
        return;

    struct stat Buffer;
    std::string TempPath = KWMPath.Layouts;
    if (stat(TempPath.c_str(), &Buffer) == -1)
        mkdir(TempPath.c_str(), 0700);

    std::ofstream OutFD(TempPath + "/" + Name);
    if(OutFD.fail())
        return;

    tree_node *Root = SpaceInfo->RootNode;
    std::vector<std::string> SerializedTree;
    SerializeParentNode(Root, "parent", SerializedTree);

    for(std::size_t LineNumber = 0; LineNumber < SerializedTree.size(); ++LineNumber)
        OutFD << SerializedTree[LineNumber] << std::endl;

    OutFD.close();
}

void LoadBSPTreeFromFile(ax_display *Display, space_info *SpaceInfo, std::string Name)
{
    if(SpaceInfo->Settings.Mode != SpaceModeBSP)
        return;

    std::string TempPath = KWMPath.Layouts;
    std::ifstream InFD(TempPath + "/" + Name);
    if(InFD.fail())
        return;

    std::string Line;
    std::vector<std::string> SerializedTree;
    while(std::getline(InFD, Line))
        SerializedTree.push_back(Line);

    DestroyNodeTree(SpaceInfo->RootNode);
    SpaceInfo->RootNode = DeserializeNodeTree(SerializedTree, Display);
}
<commit_msg>reference extern variable<commit_after>#include "serializer.h"
#include "container.h"
#include "node.h"
#include "tree.h"
#include "space.h"
#include "border.h"
#include "helpers.h"
#include "axlib/display.h"

#define internal static

extern kwm_path KWMPath;

internal void SerializeParentNode(tree_node *Parent, std::string Role, std::vector<std::string> &Serialized);
internal tree_node * DeserializeNodeTree(std::vector<std::string> &Serialized, ax_display *Display);
internal unsigned int DeserializeParentNode(tree_node *Parent, ax_display *Display, std::vector<std::string> &Serialized, unsigned int Index);
internal unsigned int DeserializeChildNode(tree_node *Parent, ax_display *Display, std::vector<std::string> &Serialized, unsigned int Index);

internal void
SerializeParentNode(tree_node *Parent, std::string Role, std::vector<std::string> &Serialized)
{
    Serialized.push_back("kwmc tree root create " + Role);
    Serialized.push_back("kwmc tree split-mode " + std::to_string(Parent->SplitMode));
    Serialized.push_back("kwmc tree split-ratio " + std::to_string(Parent->SplitRatio));

    if(IsLeafNode(Parent->LeftChild))
    {
        Serialized.push_back("kwmc tree child");
        Serialized.push_back("kwmc tree leaf create left");
    }
    else
    {
        Serialized.push_back("kwmc tree child");
        SerializeParentNode(Parent->LeftChild, "left", Serialized);
    }

    if(IsLeafNode(Parent->RightChild))
    {
        Serialized.push_back("kwmc tree child");
        Serialized.push_back("kwmc tree leaf create right");
    }
    else
    {
        Serialized.push_back("kwmc tree child");
        SerializeParentNode(Parent->RightChild, "right", Serialized);
    }
}

internal unsigned int
DeserializeParentNode(tree_node *Parent, ax_display *Display, std::vector<std::string> &Serialized, unsigned int Index)
{
    unsigned int LineNumber = Index;
    for(;LineNumber < Serialized.size(); ++LineNumber)
    {
        std::string Line = Serialized[LineNumber];
        std::vector<std::string> Tokens = SplitString(Line, ' ');

        if(Tokens[2] == "split-mode")
        {
            Parent->SplitMode = (split_type)ConvertStringToInt(Tokens[3]);
            DEBUG("Root: SplitMode Found " + Tokens[3]);
        }
        else if(Tokens[2] == "split-ratio")
        {
            Parent->SplitRatio = ConvertStringToDouble(Tokens[3]);
            DEBUG("Root: SplitRatio Found " + Tokens[3]);
        }
        else if(Tokens[2] == "child")
        {
            DEBUG("Root: Child Found");
            DEBUG("Parent: " << Parent->SplitMode << "|" << Parent->SplitRatio);
            LineNumber = DeserializeChildNode(Parent, Display, Serialized, LineNumber+1);
        }

        if(Parent->RightChild)
            return LineNumber;
    }

    return LineNumber;
}

internal unsigned int
DeserializeChildNode(tree_node *Parent, ax_display *Display, std::vector<std::string> &Serialized, unsigned int Index)
{
    unsigned int LineNumber = Index;
    for(;LineNumber < Serialized.size(); ++LineNumber)
    {
        std::string Line = Serialized[LineNumber];
        if(Line == "kwmc tree root create left")
        {
            DEBUG("Child: Create root");
            Parent->LeftChild = CreateLeafNode(Display, Parent, 0, CONTAINER_LEFT);
            CreateDeserializedNodeContainer(Display, Parent->LeftChild);
            LineNumber = DeserializeParentNode(Parent->LeftChild, Display, Serialized, LineNumber+1);
            return LineNumber;
        }
        else if(Line == "kwmc tree root create right")
        {
            DEBUG("Child: Create root");
            Parent->RightChild = CreateLeafNode(Display, Parent, 0, CONTAINER_RIGHT);
            CreateDeserializedNodeContainer(Display, Parent->RightChild);
            LineNumber = DeserializeParentNode(Parent->RightChild, Display, Serialized, LineNumber+1);
            return LineNumber;
        }
        else if(Line == "kwmc tree leaf create left")
        {
            DEBUG("Child: Create left leaf");
            Parent->LeftChild = CreateLeafNode(Display, Parent, 0, CONTAINER_LEFT);
            CreateDeserializedNodeContainer(Display, Parent->LeftChild);
            return LineNumber;
        }
        else if(Line == "kwmc tree leaf create right")
        {
            DEBUG("Child: Create right leaf");
            Parent->RightChild = CreateLeafNode(Display, Parent, 0, CONTAINER_RIGHT);
            CreateDeserializedNodeContainer(Display, Parent->RightChild);
            return LineNumber;
        }
    }

    return LineNumber;
}

internal tree_node *
DeserializeNodeTree(std::vector<std::string> &Serialized, ax_display *Display)
{
    if(Serialized.empty() || Serialized[0] != "kwmc tree root create parent")
        return NULL;

    DEBUG("Deserialize: Create Master");
    tree_node *RootNode = CreateRootNode();
    SetRootNodeContainer(Display, RootNode);
    DeserializeParentNode(RootNode, Display, Serialized, 1);
    return RootNode;
}

void SaveBSPTreeToFile(ax_display *Display, space_info *SpaceInfo, std::string Name)
{
    if(SpaceInfo->Settings.Mode != SpaceModeBSP || IsLeafNode(SpaceInfo->RootNode))
        return;

    struct stat Buffer;
    std::string TempPath = KWMPath.Layouts;
    if (stat(TempPath.c_str(), &Buffer) == -1)
        mkdir(TempPath.c_str(), 0700);

    std::ofstream OutFD(TempPath + "/" + Name);
    if(OutFD.fail())
        return;

    tree_node *Root = SpaceInfo->RootNode;
    std::vector<std::string> SerializedTree;
    SerializeParentNode(Root, "parent", SerializedTree);

    for(std::size_t LineNumber = 0; LineNumber < SerializedTree.size(); ++LineNumber)
        OutFD << SerializedTree[LineNumber] << std::endl;

    OutFD.close();
}

void LoadBSPTreeFromFile(ax_display *Display, space_info *SpaceInfo, std::string Name)
{
    if(SpaceInfo->Settings.Mode != SpaceModeBSP)
        return;

    std::string TempPath = KWMPath.Layouts;
    std::ifstream InFD(TempPath + "/" + Name);
    if(InFD.fail())
        return;

    std::string Line;
    std::vector<std::string> SerializedTree;
    while(std::getline(InFD, Line))
        SerializedTree.push_back(Line);

    DestroyNodeTree(SpaceInfo->RootNode);
    SpaceInfo->RootNode = DeserializeNodeTree(SerializedTree, Display);
}
<|endoftext|>