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

#ifdef PCH
#include "ui_pch.hxx"
#endif

#pragma hdrstop

#ifndef _SFXSMPLHINT_HXX //autogen
#include <svtools/smplhint.hxx>
#endif

#include "scitems.hxx"
#include <tools/debug.hxx>
#include <svx/editeng.hxx>
#include <svx/unofored.hxx>
#include <svx/editobj.hxx>

#include "textuno.hxx"
#include "editsrc.hxx"
#include "editutil.hxx"
#include "docsh.hxx"
#include "docfunc.hxx"
#include "cell.hxx"
#include "hints.hxx"
#include "patattr.hxx"
#include "scmod.hxx"
#include "unoguard.hxx"

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

TYPEINIT1( ScHeaderFooterChangedHint, SfxHint );

ScHeaderFooterChangedHint::ScHeaderFooterChangedHint(USHORT nP) :
    nPart( nP )
{
}

ScHeaderFooterChangedHint::~ScHeaderFooterChangedHint()
{
}

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

ScHeaderFooterEditSource::ScHeaderFooterEditSource( ScHeaderFooterContentObj* pContent,
                                                        USHORT nP ) :
    pContentObj( pContent ),
    nPart( nP ),
    pEditEngine( NULL ),
    pForwarder( NULL ),
    bDataValid( FALSE ),
    bInUpdate( FALSE )
{
    if (pContentObj)                // pContentObj can be 0 if constructed via getReflection
    {
        pContentObj->acquire();     // must not go away

        pContentObj->AddListener( *this );
    }
}

ScHeaderFooterEditSource::~ScHeaderFooterEditSource()
{
    ScUnoGuard aGuard;      //  needed for EditEngine dtor

    if (pContentObj)
        pContentObj->RemoveListener( *this );

    delete pForwarder;
    delete pEditEngine;

    if (pContentObj)
        pContentObj->release();
}

SvxEditSource* ScHeaderFooterEditSource::Clone() const
{
    return new ScHeaderFooterEditSource( pContentObj, nPart );
}

SvxTextForwarder* ScHeaderFooterEditSource::GetTextForwarder()
{
    if (!pEditEngine)
    {
        ScHeaderEditEngine* pHdrEngine = new ScHeaderEditEngine( EditEngine::CreatePool(), TRUE );

        pHdrEngine->EnableUndo( FALSE );
        pHdrEngine->SetRefMapMode( MAP_TWIP );

        //  default font must be set, independently of document
        //  -> use global pool from module

        SfxItemSet aDefaults( pHdrEngine->GetEmptyItemSet() );
        const ScPatternAttr& rPattern = (const ScPatternAttr&)SC_MOD()->GetPool().GetDefaultItem(ATTR_PATTERN);
        rPattern.FillEditItemSet( &aDefaults );
        //  FillEditItemSet adjusts font height to 1/100th mm,
        //  but for header/footer twips is needed, as in the PatternAttr:
        aDefaults.Put( rPattern.GetItem(ATTR_FONT_HEIGHT), EE_CHAR_FONTHEIGHT );
        aDefaults.Put( rPattern.GetItem(ATTR_CJK_FONT_HEIGHT), EE_CHAR_FONTHEIGHT_CJK );
        aDefaults.Put( rPattern.GetItem(ATTR_CTL_FONT_HEIGHT), EE_CHAR_FONTHEIGHT_CTL );
        pHdrEngine->SetDefaults( aDefaults );

        ScHeaderFieldData aData;
        ScHeaderFooterTextObj::FillDummyFieldData( aData );
        pHdrEngine->SetData( aData );

        pEditEngine = pHdrEngine;
        pForwarder = new SvxEditEngineForwarder(*pEditEngine);
    }

    if (bDataValid)
        return pForwarder;

    if (pContentObj)
    {
        const EditTextObject* pData;
        if (nPart == SC_HDFT_LEFT)
            pData = pContentObj->GetLeftEditObject();
        else if (nPart == SC_HDFT_CENTER)
            pData = pContentObj->GetCenterEditObject();
        else
            pData = pContentObj->GetRightEditObject();

        if (pData)
            pEditEngine->SetText(*pData);
    }

    bDataValid = TRUE;
    return pForwarder;
}

void ScHeaderFooterEditSource::UpdateData()
{
    if ( pContentObj && pEditEngine )
    {
        bInUpdate = TRUE;   // don't reset bDataValid during UpdateText

        pContentObj->UpdateText( nPart, *pEditEngine );

        bInUpdate = FALSE;
    }
}

void ScHeaderFooterEditSource::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
{
    if ( rHint.ISA( ScHeaderFooterChangedHint ) )
    {
        if ( ((const ScHeaderFooterChangedHint&)rHint).GetPart() == nPart )
        {
            if (!bInUpdate)             // not for own updates
                bDataValid = FALSE;     // text has to be fetched again
        }
    }
}

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

ScCellEditSource::ScCellEditSource(ScDocShell* pDocSh, const ScAddress& rP) :
    pDocShell( pDocSh ),
    aCellPos( rP ),
    pEditEngine( NULL ),
    pForwarder( NULL ),
    bDataValid( FALSE ),
    bInUpdate( FALSE )
{
    if (pDocShell)
        pDocShell->GetDocument()->AddUnoObject(*this);
}

ScCellEditSource::~ScCellEditSource()
{
    ScUnoGuard aGuard;      //  needed for EditEngine dtor

    if (pDocShell)
        pDocShell->GetDocument()->RemoveUnoObject(*this);

    delete pForwarder;
    delete pEditEngine;
}

SvxEditSource* ScCellEditSource::Clone() const
{
    return new ScCellEditSource( pDocShell, aCellPos );
}

SvxTextForwarder* ScCellEditSource::GetTextForwarder()
{
    if (!pEditEngine)
    {
        if ( pDocShell )
        {
            const ScDocument* pDoc = pDocShell->GetDocument();
            pEditEngine = new ScFieldEditEngine( pDoc->GetEnginePool(),
                pDoc->GetEditPool(), FALSE );
        }
        else
            pEditEngine = new ScFieldEditEngine( EditEngine::CreatePool(),
                NULL, TRUE );
#if SUPD > 600
        //  currently, GetPortions doesn't work if UpdateMode is FALSE,
        //  this will be fixed (in EditEngine) by src600
//      pEditEngine->SetUpdateMode( FALSE );
#endif
        pEditEngine->EnableUndo( FALSE );
        pEditEngine->SetRefMapMode( MAP_100TH_MM );
        pForwarder = new SvxEditEngineForwarder(*pEditEngine);
    }

    if (bDataValid)
        return pForwarder;

    BOOL bEditCell = FALSE;
    String aText;

    if (pDocShell)
    {
        ScDocument* pDoc = pDocShell->GetDocument();

        const ScBaseCell* pCell = pDoc->GetCell( aCellPos );
        if ( pCell && pCell->GetCellType() == CELLTYPE_EDIT )
        {
            pEditEngine->SetText( *((const ScEditCell*)pCell)->GetData() );
            bEditCell = TRUE;
        }
        else
            pDoc->GetInputString( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(), aText );

        SfxItemSet aDefaults( pEditEngine->GetEmptyItemSet() );
        const ScPatternAttr* pPattern =
                pDoc->GetPattern( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab() );
        pPattern->FillEditItemSet( &aDefaults );
        pPattern->FillEditParaItems( &aDefaults );  // auch Ausrichtung etc. auslesbar
        pEditEngine->SetDefaults( aDefaults );
    }

    if (!bEditCell)
        pEditEngine->SetText( aText );

    bDataValid = TRUE;
    return pForwarder;
}

void ScCellEditSource::UpdateData()
{
    if ( pDocShell && pEditEngine )
    {
        //  beim eigenen Update darf bDataValid nicht zurueckgesetzt werden,
        //  damit z.B. Attribute hinter dem Text nicht verloren gehen
        //  (werden in die Zelle nicht uebernommen)

        bInUpdate = TRUE;   // damit wird bDataValid nicht zurueckgesetzt

        ScDocFunc aFunc(*pDocShell);
        aFunc.PutData( aCellPos, *pEditEngine, FALSE, TRUE );   // immer Text

        bInUpdate = FALSE;
    }
}

void ScCellEditSource::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
{
    if ( rHint.ISA( ScUpdateRefHint ) )
    {
        const ScUpdateRefHint& rRef = (const ScUpdateRefHint&)rHint;

        //! Ref-Update
    }
    else if ( rHint.ISA( SfxSimpleHint ) )
    {
        ULONG nId = ((const SfxSimpleHint&)rHint).GetId();
        if ( nId == SFX_HINT_DYING )
        {
            pDocShell = NULL;                       // ungueltig geworden

            DELETEZ( pForwarder );
            DELETEZ( pEditEngine );     // EditEngine uses document's pool
        }
        else if ( nId == SFX_HINT_DATACHANGED )
        {
            if (!bInUpdate)                         // eigene Updates zaehlen nicht
                bDataValid = FALSE;                 // Text muss neu geholt werden
        }
    }
}

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

ScAnnotationEditSource::ScAnnotationEditSource(ScDocShell* pDocSh, const ScAddress& rP) :
    pDocShell( pDocSh ),
    aCellPos( rP ),
    pEditEngine( NULL ),
    pForwarder( NULL ),
    bDataValid( FALSE )
{
    if (pDocShell)
        pDocShell->GetDocument()->AddUnoObject(*this);
}

ScAnnotationEditSource::~ScAnnotationEditSource()
{
    ScUnoGuard aGuard;      //  needed for EditEngine dtor

    if (pDocShell)
        pDocShell->GetDocument()->RemoveUnoObject(*this);

    delete pForwarder;
    delete pEditEngine;
}

SvxEditSource* ScAnnotationEditSource::Clone() const
{
    return new ScAnnotationEditSource( pDocShell, aCellPos );
}

SvxTextForwarder* ScAnnotationEditSource::GetTextForwarder()
{
    if (!pEditEngine)
    {
        // Notizen haben keine Felder
        if ( pDocShell )
            pEditEngine = new ScEditEngineDefaulter(
                pDocShell->GetDocument()->GetEnginePool(), FALSE );
        else
            pEditEngine = new ScEditEngineDefaulter(
                EditEngine::CreatePool(), TRUE );
        pForwarder = new SvxEditEngineForwarder(*pEditEngine);
    }

    if (bDataValid)
        return pForwarder;

    if ( pDocShell )
    {
        ScPostIt aNote;
        ScDocument* pDoc = pDocShell->GetDocument();
        pDoc->GetNote( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(), aNote );

        pEditEngine->SetText( aNote.GetText() );        // incl. Umbrueche
    }

    bDataValid = TRUE;
    return pForwarder;
}

void ScAnnotationEditSource::UpdateData()
{
    if ( pDocShell && pEditEngine )
    {
        String aNewText = pEditEngine->GetText( LINEEND_LF );   // im SetNoteText passiert ConvertLineEnd
        ScDocFunc aFunc(*pDocShell);
        aFunc.SetNoteText( aCellPos, aNewText, TRUE );

        // bDataValid wird bei SetDocumentModified zurueckgesetzt
    }
}

void ScAnnotationEditSource::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
{
    if ( rHint.ISA( ScUpdateRefHint ) )
    {
        const ScUpdateRefHint& rRef = (const ScUpdateRefHint&)rHint;

        //! Ref-Update
    }
    else if ( rHint.ISA( SfxSimpleHint ) )
    {
        ULONG nId = ((const SfxSimpleHint&)rHint).GetId();
        if ( nId == SFX_HINT_DYING )
        {
            pDocShell = NULL;                       // ungueltig geworden

            DELETEZ( pForwarder );
            DELETEZ( pEditEngine );     // EditEngine uses document's pool
        }
        else if ( nId == SFX_HINT_DATACHANGED )
            bDataValid = FALSE;                     // Text muss neu geholt werden
    }
}

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

ScSimpleEditSource::ScSimpleEditSource( SvxTextForwarder* pForw ) :
    pForwarder( pForw )
{
    //  The same forwarder (and EditEngine) is shared by all children of the same Text object.
    //  Text range and cursor keep a reference to their parent text, so the text object is
    //  always alive and the forwarder is valid as long as there are children.
}

ScSimpleEditSource::~ScSimpleEditSource()
{
}

SvxEditSource* ScSimpleEditSource::Clone() const
{
    return new ScSimpleEditSource( pForwarder );
}

SvxTextForwarder* ScSimpleEditSource::GetTextForwarder()
{
    return pForwarder;
}

void ScSimpleEditSource::UpdateData()
{
    //  nothing
}

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

#ifdef PCH
#include "ui_pch.hxx"
#endif

#pragma hdrstop

#ifndef _SFXSMPLHINT_HXX //autogen
#include <svtools/smplhint.hxx>
#endif

#include "scitems.hxx"
#include <tools/debug.hxx>
#include <svx/editeng.hxx>
#include <svx/unofored.hxx>
#include <svx/editobj.hxx>

#include "textuno.hxx"
#include "editsrc.hxx"
#include "editutil.hxx"
#include "docsh.hxx"
#include "docfunc.hxx"
#include "cell.hxx"
#include "hints.hxx"
#include "patattr.hxx"
#include "scmod.hxx"
#include "unoguard.hxx"

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

TYPEINIT1( ScHeaderFooterChangedHint, SfxHint );

ScHeaderFooterChangedHint::ScHeaderFooterChangedHint(USHORT nP) :
    nPart( nP )
{
}

ScHeaderFooterChangedHint::~ScHeaderFooterChangedHint()
{
}

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

ScHeaderFooterEditSource::ScHeaderFooterEditSource( ScHeaderFooterContentObj* pContent,
                                                        USHORT nP ) :
    pContentObj( pContent ),
    nPart( nP ),
    pEditEngine( NULL ),
    pForwarder( NULL ),
    bDataValid( FALSE ),
    bInUpdate( FALSE )
{
    if (pContentObj)                // pContentObj can be 0 if constructed via getReflection
    {
        pContentObj->acquire();     // must not go away

        pContentObj->AddListener( *this );
    }
}

ScHeaderFooterEditSource::~ScHeaderFooterEditSource()
{
    ScUnoGuard aGuard;      //  needed for EditEngine dtor

    if (pContentObj)
        pContentObj->RemoveListener( *this );

    delete pForwarder;
    delete pEditEngine;

    if (pContentObj)
        pContentObj->release();
}

SvxEditSource* ScHeaderFooterEditSource::Clone() const
{
    return new ScHeaderFooterEditSource( pContentObj, nPart );
}

SvxTextForwarder* ScHeaderFooterEditSource::GetTextForwarder()
{
    if (!pEditEngine)
    {
        SfxItemPool* pEnginePool = EditEngine::CreatePool();
        pEnginePool->FreezeIdRanges();
        ScHeaderEditEngine* pHdrEngine = new ScHeaderEditEngine( pEnginePool, TRUE );

        pHdrEngine->EnableUndo( FALSE );
        pHdrEngine->SetRefMapMode( MAP_TWIP );

        //  default font must be set, independently of document
        //  -> use global pool from module

        SfxItemSet aDefaults( pHdrEngine->GetEmptyItemSet() );
        const ScPatternAttr& rPattern = (const ScPatternAttr&)SC_MOD()->GetPool().GetDefaultItem(ATTR_PATTERN);
        rPattern.FillEditItemSet( &aDefaults );
        //  FillEditItemSet adjusts font height to 1/100th mm,
        //  but for header/footer twips is needed, as in the PatternAttr:
        aDefaults.Put( rPattern.GetItem(ATTR_FONT_HEIGHT), EE_CHAR_FONTHEIGHT );
        aDefaults.Put( rPattern.GetItem(ATTR_CJK_FONT_HEIGHT), EE_CHAR_FONTHEIGHT_CJK );
        aDefaults.Put( rPattern.GetItem(ATTR_CTL_FONT_HEIGHT), EE_CHAR_FONTHEIGHT_CTL );
        pHdrEngine->SetDefaults( aDefaults );

        ScHeaderFieldData aData;
        ScHeaderFooterTextObj::FillDummyFieldData( aData );
        pHdrEngine->SetData( aData );

        pEditEngine = pHdrEngine;
        pForwarder = new SvxEditEngineForwarder(*pEditEngine);
    }

    if (bDataValid)
        return pForwarder;

    if (pContentObj)
    {
        const EditTextObject* pData;
        if (nPart == SC_HDFT_LEFT)
            pData = pContentObj->GetLeftEditObject();
        else if (nPart == SC_HDFT_CENTER)
            pData = pContentObj->GetCenterEditObject();
        else
            pData = pContentObj->GetRightEditObject();

        if (pData)
            pEditEngine->SetText(*pData);
    }

    bDataValid = TRUE;
    return pForwarder;
}

void ScHeaderFooterEditSource::UpdateData()
{
    if ( pContentObj && pEditEngine )
    {
        bInUpdate = TRUE;   // don't reset bDataValid during UpdateText

        pContentObj->UpdateText( nPart, *pEditEngine );

        bInUpdate = FALSE;
    }
}

void ScHeaderFooterEditSource::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
{
    if ( rHint.ISA( ScHeaderFooterChangedHint ) )
    {
        if ( ((const ScHeaderFooterChangedHint&)rHint).GetPart() == nPart )
        {
            if (!bInUpdate)             // not for own updates
                bDataValid = FALSE;     // text has to be fetched again
        }
    }
}

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

ScCellEditSource::ScCellEditSource(ScDocShell* pDocSh, const ScAddress& rP) :
    pDocShell( pDocSh ),
    aCellPos( rP ),
    pEditEngine( NULL ),
    pForwarder( NULL ),
    bDataValid( FALSE ),
    bInUpdate( FALSE )
{
    if (pDocShell)
        pDocShell->GetDocument()->AddUnoObject(*this);
}

ScCellEditSource::~ScCellEditSource()
{
    ScUnoGuard aGuard;      //  needed for EditEngine dtor

    if (pDocShell)
        pDocShell->GetDocument()->RemoveUnoObject(*this);

    delete pForwarder;
    delete pEditEngine;
}

SvxEditSource* ScCellEditSource::Clone() const
{
    return new ScCellEditSource( pDocShell, aCellPos );
}

SvxTextForwarder* ScCellEditSource::GetTextForwarder()
{
    if (!pEditEngine)
    {
        if ( pDocShell )
        {
            const ScDocument* pDoc = pDocShell->GetDocument();
            pEditEngine = new ScFieldEditEngine( pDoc->GetEnginePool(),
                pDoc->GetEditPool(), FALSE );
        }
        else
        {
            SfxItemPool* pEnginePool = EditEngine::CreatePool();
            pEnginePool->FreezeIdRanges();
            pEditEngine = new ScFieldEditEngine( pEnginePool, NULL, TRUE );
        }
#if SUPD > 600
        //  currently, GetPortions doesn't work if UpdateMode is FALSE,
        //  this will be fixed (in EditEngine) by src600
//      pEditEngine->SetUpdateMode( FALSE );
#endif
        pEditEngine->EnableUndo( FALSE );
        pEditEngine->SetRefMapMode( MAP_100TH_MM );
        pForwarder = new SvxEditEngineForwarder(*pEditEngine);
    }

    if (bDataValid)
        return pForwarder;

    BOOL bEditCell = FALSE;
    String aText;

    if (pDocShell)
    {
        ScDocument* pDoc = pDocShell->GetDocument();

        const ScBaseCell* pCell = pDoc->GetCell( aCellPos );
        if ( pCell && pCell->GetCellType() == CELLTYPE_EDIT )
        {
            pEditEngine->SetText( *((const ScEditCell*)pCell)->GetData() );
            bEditCell = TRUE;
        }
        else
            pDoc->GetInputString( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(), aText );

        SfxItemSet aDefaults( pEditEngine->GetEmptyItemSet() );
        const ScPatternAttr* pPattern =
                pDoc->GetPattern( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab() );
        pPattern->FillEditItemSet( &aDefaults );
        pPattern->FillEditParaItems( &aDefaults );  // auch Ausrichtung etc. auslesbar
        pEditEngine->SetDefaults( aDefaults );
    }

    if (!bEditCell)
        pEditEngine->SetText( aText );

    bDataValid = TRUE;
    return pForwarder;
}

void ScCellEditSource::UpdateData()
{
    if ( pDocShell && pEditEngine )
    {
        //  beim eigenen Update darf bDataValid nicht zurueckgesetzt werden,
        //  damit z.B. Attribute hinter dem Text nicht verloren gehen
        //  (werden in die Zelle nicht uebernommen)

        bInUpdate = TRUE;   // damit wird bDataValid nicht zurueckgesetzt

        ScDocFunc aFunc(*pDocShell);
        aFunc.PutData( aCellPos, *pEditEngine, FALSE, TRUE );   // immer Text

        bInUpdate = FALSE;
    }
}

void ScCellEditSource::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
{
    if ( rHint.ISA( ScUpdateRefHint ) )
    {
        const ScUpdateRefHint& rRef = (const ScUpdateRefHint&)rHint;

        //! Ref-Update
    }
    else if ( rHint.ISA( SfxSimpleHint ) )
    {
        ULONG nId = ((const SfxSimpleHint&)rHint).GetId();
        if ( nId == SFX_HINT_DYING )
        {
            pDocShell = NULL;                       // ungueltig geworden

            DELETEZ( pForwarder );
            DELETEZ( pEditEngine );     // EditEngine uses document's pool
        }
        else if ( nId == SFX_HINT_DATACHANGED )
        {
            if (!bInUpdate)                         // eigene Updates zaehlen nicht
                bDataValid = FALSE;                 // Text muss neu geholt werden
        }
    }
}

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

ScAnnotationEditSource::ScAnnotationEditSource(ScDocShell* pDocSh, const ScAddress& rP) :
    pDocShell( pDocSh ),
    aCellPos( rP ),
    pEditEngine( NULL ),
    pForwarder( NULL ),
    bDataValid( FALSE )
{
    if (pDocShell)
        pDocShell->GetDocument()->AddUnoObject(*this);
}

ScAnnotationEditSource::~ScAnnotationEditSource()
{
    ScUnoGuard aGuard;      //  needed for EditEngine dtor

    if (pDocShell)
        pDocShell->GetDocument()->RemoveUnoObject(*this);

    delete pForwarder;
    delete pEditEngine;
}

SvxEditSource* ScAnnotationEditSource::Clone() const
{
    return new ScAnnotationEditSource( pDocShell, aCellPos );
}

SvxTextForwarder* ScAnnotationEditSource::GetTextForwarder()
{
    if (!pEditEngine)
    {
        // Notizen haben keine Felder
        if ( pDocShell )
            pEditEngine = new ScEditEngineDefaulter(
                pDocShell->GetDocument()->GetEnginePool(), FALSE );
        else
        {
            SfxItemPool* pEnginePool = EditEngine::CreatePool();
            pEnginePool->FreezeIdRanges();
            pEditEngine = new ScEditEngineDefaulter( pEnginePool, TRUE );
        }
        pForwarder = new SvxEditEngineForwarder(*pEditEngine);
    }

    if (bDataValid)
        return pForwarder;

    if ( pDocShell )
    {
        ScPostIt aNote;
        ScDocument* pDoc = pDocShell->GetDocument();
        pDoc->GetNote( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(), aNote );

        pEditEngine->SetText( aNote.GetText() );        // incl. Umbrueche
    }

    bDataValid = TRUE;
    return pForwarder;
}

void ScAnnotationEditSource::UpdateData()
{
    if ( pDocShell && pEditEngine )
    {
        String aNewText = pEditEngine->GetText( LINEEND_LF );   // im SetNoteText passiert ConvertLineEnd
        ScDocFunc aFunc(*pDocShell);
        aFunc.SetNoteText( aCellPos, aNewText, TRUE );

        // bDataValid wird bei SetDocumentModified zurueckgesetzt
    }
}

void ScAnnotationEditSource::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
{
    if ( rHint.ISA( ScUpdateRefHint ) )
    {
        const ScUpdateRefHint& rRef = (const ScUpdateRefHint&)rHint;

        //! Ref-Update
    }
    else if ( rHint.ISA( SfxSimpleHint ) )
    {
        ULONG nId = ((const SfxSimpleHint&)rHint).GetId();
        if ( nId == SFX_HINT_DYING )
        {
            pDocShell = NULL;                       // ungueltig geworden

            DELETEZ( pForwarder );
            DELETEZ( pEditEngine );     // EditEngine uses document's pool
        }
        else if ( nId == SFX_HINT_DATACHANGED )
            bDataValid = FALSE;                     // Text muss neu geholt werden
    }
}

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

ScSimpleEditSource::ScSimpleEditSource( SvxTextForwarder* pForw ) :
    pForwarder( pForw )
{
    //  The same forwarder (and EditEngine) is shared by all children of the same Text object.
    //  Text range and cursor keep a reference to their parent text, so the text object is
    //  always alive and the forwarder is valid as long as there are children.
}

ScSimpleEditSource::~ScSimpleEditSource()
{
}

SvxEditSource* ScSimpleEditSource::Clone() const
{
    return new ScSimpleEditSource( pForwarder );
}

SvxTextForwarder* ScSimpleEditSource::GetTextForwarder()
{
    return pForwarder;
}

void ScSimpleEditSource::UpdateData()
{
    //  nothing
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2010, Willow Garage, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "mesh_resource_marker.h"

#include "marker_selection_handler.h"
#include "rviz/default_plugin/marker_display.h"
#include "rviz/selection/selection_manager.h"

#include "rviz/visualization_manager.h"
#include "rviz/mesh_loader.h"
#include "marker_display.h"

#include <OGRE/OgreSceneNode.h>
#include <OGRE/OgreSceneManager.h>
#include <OGRE/OgreEntity.h>
#include <OGRE/OgreMaterialManager.h>
#include <OGRE/OgreTextureManager.h>

namespace rviz
{

MeshResourceMarker::MeshResourceMarker(MarkerDisplay* owner, VisualizationManager* manager, Ogre::SceneNode* parent_node)
: MarkerBase(owner, manager, parent_node)
, entity_(0)
{
  if (parent_node)
  {
    scene_node_ = parent_node->createChildSceneNode();
  }
  else
  {
    scene_node_ = vis_manager_->getSceneManager()->getRootSceneNode()->createChildSceneNode();
  }
}

MeshResourceMarker::~MeshResourceMarker()
{
  vis_manager_->getSceneManager()->destroySceneNode(scene_node_->getName());
  vis_manager_->getSceneManager()->destroyEntity( entity_ );

  for (size_t i = 0; i < material_->getNumTechniques(); ++i)
  {
    Ogre::Technique* t = material_->getTechnique(i);
    // hack hack hack, really need to do a shader-based way of picking, rather than
    // creating a texture for each object
    if (t->getSchemeName() == "Pick")
    {
      Ogre::TextureManager::getSingleton().remove(t->getPass(0)->getTextureUnitState(0)->getTextureName());
    }
  }

  material_->unload();
  Ogre::MaterialManager::getSingleton().remove(material_->getName());
}

void MeshResourceMarker::onNewMessage(const MarkerConstPtr& old_message, const MarkerConstPtr& new_message)
{
  ROS_ASSERT(new_message->type == visualization_msgs::Marker::MESH_RESOURCE);

  scene_node_->setVisible(false);

  if (!entity_)
  {
    if (new_message->mesh_resource.empty())
    {
      return;
    }

    if (loadMeshFromResource(new_message->mesh_resource).isNull())
    {
      std::stringstream ss;
      ss << "Mesh resource marker [" << getStringID() << "] could not load [" << new_message->mesh_resource << "]";
      owner_->setMarkerStatus(getID(), status_levels::Error, ss.str());
      ROS_DEBUG("%s", ss.str().c_str());
      return;
    }

    static uint32_t count = 0;
    std::stringstream ss;
    ss << "Mesh Resource Marker" << count++;
    entity_ = vis_manager_->getSceneManager()->createEntity(ss.str(), new_message->mesh_resource);
    scene_node_->attachObject(entity_);

    ss << "Material";
    material_name_ = ss.str();
    material_ = Ogre::MaterialManager::getSingleton().create( material_name_, ROS_PACKAGE_NAME );
    material_->setReceiveShadows(false);
    material_->getTechnique(0)->setLightingEnabled(true);
    material_->getTechnique(0)->setAmbient( 0.5, 0.5, 0.5 );

    entity_->setMaterialName(material_name_);

    coll_ = vis_manager_->getSelectionManager()->createCollisionForEntity(entity_, SelectionHandlerPtr(new MarkerSelectionHandler(this, MarkerID(new_message->ns, new_message->id))), coll_);
  }

  Ogre::Vector3 pos, scale;
  Ogre::Quaternion orient;
  transform(new_message, pos, orient, scale, false);

  scene_node_->setVisible(true);
  scene_node_->setPosition(pos);
  scene_node_->setOrientation(orient);
  scene_node_->setScale(scale);

  float r = new_message->color.r;
  float g = new_message->color.g;
  float b = new_message->color.b;
  float a = new_message->color.a;
  material_->getTechnique(0)->setAmbient( r*0.5, g*0.5, b*0.5 );
  material_->getTechnique(0)->setDiffuse( r, g, b, a );

  if ( a < 0.9998 )
  {
    material_->getTechnique(0)->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA );
    material_->getTechnique(0)->setDepthWriteEnabled( false );
  }
  else
  {
    material_->getTechnique(0)->setSceneBlending( Ogre::SBT_REPLACE );
    material_->getTechnique(0)->setDepthWriteEnabled( true );
  }
}

}

<commit_msg>fix MESH_RESOURCE marker to not crash on destruction when it had never received a valid resource (#4180)<commit_after>/*
 * Copyright (c) 2010, Willow Garage, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "mesh_resource_marker.h"

#include "marker_selection_handler.h"
#include "rviz/default_plugin/marker_display.h"
#include "rviz/selection/selection_manager.h"

#include "rviz/visualization_manager.h"
#include "rviz/mesh_loader.h"
#include "marker_display.h"

#include <OGRE/OgreSceneNode.h>
#include <OGRE/OgreSceneManager.h>
#include <OGRE/OgreEntity.h>
#include <OGRE/OgreMaterialManager.h>
#include <OGRE/OgreTextureManager.h>

namespace rviz
{

MeshResourceMarker::MeshResourceMarker(MarkerDisplay* owner, VisualizationManager* manager, Ogre::SceneNode* parent_node)
: MarkerBase(owner, manager, parent_node)
, entity_(0)
{
  if (parent_node)
  {
    scene_node_ = parent_node->createChildSceneNode();
  }
  else
  {
    scene_node_ = vis_manager_->getSceneManager()->getRootSceneNode()->createChildSceneNode();
  }
}

MeshResourceMarker::~MeshResourceMarker()
{
  vis_manager_->getSceneManager()->destroySceneNode(scene_node_->getName());

  if (entity_)
  {
    vis_manager_->getSceneManager()->destroyEntity( entity_ );
  }

  if (!material_.isNull())
  {
    for (size_t i = 0; i < material_->getNumTechniques(); ++i)
    {
      Ogre::Technique* t = material_->getTechnique(i);
      // hack hack hack, really need to do a shader-based way of picking, rather than
      // creating a texture for each object
      if (t->getSchemeName() == "Pick")
      {
        Ogre::TextureManager::getSingleton().remove(t->getPass(0)->getTextureUnitState(0)->getTextureName());
      }
    }

    material_->unload();
    Ogre::MaterialManager::getSingleton().remove(material_->getName());
  }
}

void MeshResourceMarker::onNewMessage(const MarkerConstPtr& old_message, const MarkerConstPtr& new_message)
{
  ROS_ASSERT(new_message->type == visualization_msgs::Marker::MESH_RESOURCE);

  scene_node_->setVisible(false);

  if (!entity_)
  {
    if (new_message->mesh_resource.empty())
    {
      return;
    }

    if (loadMeshFromResource(new_message->mesh_resource).isNull())
    {
      std::stringstream ss;
      ss << "Mesh resource marker [" << getStringID() << "] could not load [" << new_message->mesh_resource << "]";
      owner_->setMarkerStatus(getID(), status_levels::Error, ss.str());
      ROS_DEBUG("%s", ss.str().c_str());
      return;
    }

    static uint32_t count = 0;
    std::stringstream ss;
    ss << "Mesh Resource Marker" << count++;
    entity_ = vis_manager_->getSceneManager()->createEntity(ss.str(), new_message->mesh_resource);
    scene_node_->attachObject(entity_);

    ss << "Material";
    material_name_ = ss.str();
    material_ = Ogre::MaterialManager::getSingleton().create( material_name_, ROS_PACKAGE_NAME );
    material_->setReceiveShadows(false);
    material_->getTechnique(0)->setLightingEnabled(true);
    material_->getTechnique(0)->setAmbient( 0.5, 0.5, 0.5 );

    entity_->setMaterialName(material_name_);

    coll_ = vis_manager_->getSelectionManager()->createCollisionForEntity(entity_, SelectionHandlerPtr(new MarkerSelectionHandler(this, MarkerID(new_message->ns, new_message->id))), coll_);
  }

  Ogre::Vector3 pos, scale;
  Ogre::Quaternion orient;
  transform(new_message, pos, orient, scale, false);

  scene_node_->setVisible(true);
  scene_node_->setPosition(pos);
  scene_node_->setOrientation(orient);
  scene_node_->setScale(scale);

  float r = new_message->color.r;
  float g = new_message->color.g;
  float b = new_message->color.b;
  float a = new_message->color.a;
  material_->getTechnique(0)->setAmbient( r*0.5, g*0.5, b*0.5 );
  material_->getTechnique(0)->setDiffuse( r, g, b, a );

  if ( a < 0.9998 )
  {
    material_->getTechnique(0)->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA );
    material_->getTechnique(0)->setDepthWriteEnabled( false );
  }
  else
  {
    material_->getTechnique(0)->setSceneBlending( Ogre::SBT_REPLACE );
    material_->getTechnique(0)->setDepthWriteEnabled( true );
  }
}

}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2010, Willow Garage, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "triangle_list_marker.h"

#include "marker_selection_handler.h"
#include "rviz/default_plugin/marker_display.h"
#include "rviz/selection/selection_manager.h"
#include "rviz/uniform_string_stream.h"

#include "rviz/display_context.h"
#include "rviz/mesh_loader.h"
#include "marker_display.h"

#include <OGRE/OgreSceneNode.h>
#include <OGRE/OgreSceneManager.h>
#include <OGRE/OgreManualObject.h>
#include <OGRE/OgreMaterialManager.h>
#include <OGRE/OgreTextureManager.h>
#include <OGRE/OgreTechnique.h>

namespace rviz
{

TriangleListMarker::TriangleListMarker(MarkerDisplay* owner, DisplayContext* context, Ogre::SceneNode* parent_node)
: MarkerBase(owner, context, parent_node)
, manual_object_(0)
{
}

TriangleListMarker::~TriangleListMarker()
{
  context_->getSceneManager()->destroyManualObject(manual_object_);
  material_->unload();
  Ogre::MaterialManager::getSingleton().remove(material_->getName());
}

void TriangleListMarker::onNewMessage(const MarkerConstPtr& old_message, const MarkerConstPtr& new_message)
{
  ROS_ASSERT(new_message->type == visualization_msgs::Marker::TRIANGLE_LIST);

  size_t num_points = new_message->points.size();
  if( (num_points % 3) != 0 || num_points == 0 )
  {
    std::stringstream ss;
    if( num_points == 0 )
    {
      ss << "TriMesh marker [" << getStringID() << "] has no points.";
    }
    else
    {
      ss << "TriMesh marker [" << getStringID() << "] has a point count which is not divisible by 3 [" << num_points <<"]";
    }
    if ( owner_ )
    {
      owner_->setMarkerStatus(getID(), StatusProperty::Error, ss.str());
    }
    ROS_DEBUG("%s", ss.str().c_str());

    scene_node_->setVisible( false );
    return;
  }
  else
  {
    scene_node_->setVisible( true );
  }

  if (!manual_object_)
  {
    static uint32_t count = 0;
    UniformStringStream ss;
    ss << "Triangle List Marker" << count++;
    manual_object_ = context_->getSceneManager()->createManualObject(ss.str());
    scene_node_->attachObject(manual_object_);

    ss << "Material";
    material_name_ = ss.str();
    material_ = Ogre::MaterialManager::getSingleton().create( material_name_, ROS_PACKAGE_NAME );
    material_->setReceiveShadows(false);
    material_->getTechnique(0)->setLightingEnabled(true);
    material_->setCullingMode(Ogre::CULL_NONE);

    handler_.reset( new MarkerSelectionHandler( this, MarkerID( new_message->ns, new_message->id ), context_ ));
  }

  Ogre::Vector3 pos, scale;
  Ogre::Quaternion orient;
  if (!transform(new_message, pos, orient, scale))
  {
    ROS_DEBUG("Unable to transform marker message");
    scene_node_->setVisible( false );
    return;
  }

  if ( owner_ &&  (new_message->scale.x * new_message->scale.y * new_message->scale.z == 0.0f) )
  {
    owner_->setMarkerStatus(getID(), StatusProperty::Warn, "Scale of 0 in one of x/y/z");
  }

  setPosition(pos);
  setOrientation(orient);
  scene_node_->setScale(scale);

  // If we have the same number of tris as previously, just update the object
  if (old_message && num_points == old_message->points.size())
  {
    manual_object_->beginUpdate(0);
  }
  else // Otherwise clear it and begin anew
  {
    manual_object_->clear();
    manual_object_->estimateVertexCount(num_points);
    manual_object_->begin(material_name_, Ogre::RenderOperation::OT_TRIANGLE_LIST);
  }

  bool has_vertex_colors = new_message->colors.size() == num_points;
  bool any_vertex_has_alpha = false;

  if (has_vertex_colors)
  {
    for (size_t i = 0; i < num_points; ++i)
    {
      manual_object_->position(new_message->points[i].x, new_message->points[i].y, new_message->points[i].z);
      any_vertex_has_alpha = any_vertex_has_alpha || (new_message->colors[i].a < 0.9998);
      manual_object_->colour(new_message->colors[i].r, new_message->colors[i].g, new_message->colors[i].b, new_message->color.a * new_message->colors[i].a);
    }
  }
  else
  {
    for (size_t i = 0; i < num_points; ++i)
    {
      manual_object_->position(new_message->points[i].x, new_message->points[i].y, new_message->points[i].z);
    }
  }

  manual_object_->end();

  if (has_vertex_colors)
  {
    material_->getTechnique(0)->setLightingEnabled(false);
  }
  else
  {
    material_->getTechnique(0)->setLightingEnabled(true);
    float r,g,b,a;
    r = new_message->color.r;
    g = new_message->color.g;
    b = new_message->color.b;
    a = new_message->color.a;
    material_->getTechnique(0)->setAmbient( r,g,b );
    material_->getTechnique(0)->setDiffuse( 0,0,0,a );
  }

  if( (!has_vertex_colors && new_message->color.a < 0.9998) || (has_vertex_colors && any_vertex_has_alpha))
  {
    material_->getTechnique(0)->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA );
    material_->getTechnique(0)->setDepthWriteEnabled( false );
  }
  else
  {
    material_->getTechnique(0)->setSceneBlending( Ogre::SBT_REPLACE );
    material_->getTechnique(0)->setDepthWriteEnabled( true );
  }

  handler_->addTrackedObject( manual_object_ );
}

S_MaterialPtr TriangleListMarker::getMaterials()
{
  S_MaterialPtr materials;
  materials.insert( material_ );
  return materials;
}

}

<commit_msg>trangle list marker: added support for per-face color in addition to per-vertex color<commit_after>/*
 * Copyright (c) 2010, Willow Garage, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "triangle_list_marker.h"

#include "marker_selection_handler.h"
#include "rviz/default_plugin/marker_display.h"
#include "rviz/selection/selection_manager.h"
#include "rviz/uniform_string_stream.h"

#include "rviz/display_context.h"
#include "rviz/mesh_loader.h"
#include "marker_display.h"

#include <OGRE/OgreSceneNode.h>
#include <OGRE/OgreSceneManager.h>
#include <OGRE/OgreManualObject.h>
#include <OGRE/OgreMaterialManager.h>
#include <OGRE/OgreTextureManager.h>
#include <OGRE/OgreTechnique.h>

namespace rviz
{

TriangleListMarker::TriangleListMarker(MarkerDisplay* owner, DisplayContext* context, Ogre::SceneNode* parent_node)
: MarkerBase(owner, context, parent_node)
, manual_object_(0)
{
}

TriangleListMarker::~TriangleListMarker()
{
  context_->getSceneManager()->destroyManualObject(manual_object_);
  material_->unload();
  Ogre::MaterialManager::getSingleton().remove(material_->getName());
}

void TriangleListMarker::onNewMessage(const MarkerConstPtr& old_message, const MarkerConstPtr& new_message)
{
  ROS_ASSERT(new_message->type == visualization_msgs::Marker::TRIANGLE_LIST);

  size_t num_points = new_message->points.size();
  if( (num_points % 3) != 0 || num_points == 0 )
  {
    std::stringstream ss;
    if( num_points == 0 )
    {
      ss << "TriMesh marker [" << getStringID() << "] has no points.";
    }
    else
    {
      ss << "TriMesh marker [" << getStringID() << "] has a point count which is not divisible by 3 [" << num_points <<"]";
    }
    if ( owner_ )
    {
      owner_->setMarkerStatus(getID(), StatusProperty::Error, ss.str());
    }
    ROS_DEBUG("%s", ss.str().c_str());

    scene_node_->setVisible( false );
    return;
  }
  else
  {
    scene_node_->setVisible( true );
  }

  if (!manual_object_)
  {
    static uint32_t count = 0;
    UniformStringStream ss;
    ss << "Triangle List Marker" << count++;
    manual_object_ = context_->getSceneManager()->createManualObject(ss.str());
    scene_node_->attachObject(manual_object_);

    ss << "Material";
    material_name_ = ss.str();
    material_ = Ogre::MaterialManager::getSingleton().create( material_name_, ROS_PACKAGE_NAME );
    material_->setReceiveShadows(false);
    material_->getTechnique(0)->setLightingEnabled(true);
    material_->setCullingMode(Ogre::CULL_NONE);

    handler_.reset( new MarkerSelectionHandler( this, MarkerID( new_message->ns, new_message->id ), context_ ));
  }

  Ogre::Vector3 pos, scale;
  Ogre::Quaternion orient;
  if (!transform(new_message, pos, orient, scale))
  {
    ROS_DEBUG("Unable to transform marker message");
    scene_node_->setVisible( false );
    return;
  }

  if ( owner_ &&  (new_message->scale.x * new_message->scale.y * new_message->scale.z == 0.0f) )
  {
    owner_->setMarkerStatus(getID(), StatusProperty::Warn, "Scale of 0 in one of x/y/z");
  }

  setPosition(pos);
  setOrientation(orient);
  scene_node_->setScale(scale);

  // If we have the same number of tris as previously, just update the object
  if (old_message && num_points == old_message->points.size())
  {
    manual_object_->beginUpdate(0);
  }
  else // Otherwise clear it and begin anew
  {
    manual_object_->clear();
    manual_object_->estimateVertexCount(num_points);
    manual_object_->begin(material_name_, Ogre::RenderOperation::OT_TRIANGLE_LIST);
  }

  bool has_vertex_colors = new_message->colors.size() == num_points;
  bool has_face_colors = new_message->colors.size() == num_points / 3;
  bool any_vertex_has_alpha = false;

  if (has_vertex_colors)
  {
    for (size_t i = 0; i < num_points; ++i)
    {
      manual_object_->position(new_message->points[i].x, new_message->points[i].y, new_message->points[i].z);
      any_vertex_has_alpha = any_vertex_has_alpha || (new_message->colors[i].a < 0.9998);
      manual_object_->colour(new_message->colors[i].r, new_message->colors[i].g, new_message->colors[i].b, new_message->color.a * new_message->colors[i].a);
    }
  }
  else if (has_face_colors)
  {
    for (size_t i = 0; i < num_points; ++i)
    {
      manual_object_->position(new_message->points[i].x, new_message->points[i].y, new_message->points[i].z);
      any_vertex_has_alpha = any_vertex_has_alpha || (new_message->colors[i].a < 0.9998);
      manual_object_->colour(new_message->colors[i/3].r, new_message->colors[i/3].g, new_message->colors[i/3].b, new_message->color.a * new_message->colors[i/3].a);
    }
  }
  else
  {
    for (size_t i = 0; i < num_points; ++i)
    {
      manual_object_->position(new_message->points[i].x, new_message->points[i].y, new_message->points[i].z);
    }
  }

  manual_object_->end();

  if (has_vertex_colors || has_face_colors)
  {
    material_->getTechnique(0)->setLightingEnabled(false);
  }
  else
  {
    material_->getTechnique(0)->setLightingEnabled(true);
    float r,g,b,a;
    r = new_message->color.r;
    g = new_message->color.g;
    b = new_message->color.b;
    a = new_message->color.a;
    material_->getTechnique(0)->setAmbient( r,g,b );
    material_->getTechnique(0)->setDiffuse( 0,0,0,a );
  }

  if( (!has_vertex_colors && new_message->color.a < 0.9998) || (has_vertex_colors && any_vertex_has_alpha))
  {
    material_->getTechnique(0)->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA );
    material_->getTechnique(0)->setDepthWriteEnabled( false );
  }
  else
  {
    material_->getTechnique(0)->setSceneBlending( Ogre::SBT_REPLACE );
    material_->getTechnique(0)->setDepthWriteEnabled( true );
  }

  handler_->addTrackedObject( manual_object_ );
}

S_MaterialPtr TriangleListMarker::getMaterials()
{
  S_MaterialPtr materials;
  materials.insert( material_ );
  return materials;
}

}

<|endoftext|>


<commit_before>// $Id$

// The libMesh Finite Element Library.
// Copyright (C) 2002-2008 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

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

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// Local includes
#include "boundary_info.h"
#include "elem.h"
#include "libmesh_logging.h"
#include "metis_partitioner.h"
#include "serial_mesh.h"

namespace libMesh
{

// ------------------------------------------------------------
// SerialMesh class member functions
SerialMesh::SerialMesh (unsigned int d) :
  UnstructuredMesh (d)
{
  _partitioner = AutoPtr<Partitioner>(new MetisPartitioner());
}

SerialMesh::~SerialMesh ()
{
  this->clear();  // Free nodes and elements
}

// This might be specialized later, but right now it's just here to
// make sure the compiler doesn't give us a default (non-deep) copy
// constructor instead.
SerialMesh::SerialMesh (const SerialMesh &other_mesh) :
  UnstructuredMesh (other_mesh)
{
  this->copy_nodes_and_elements(other_mesh);
  *this->boundary_info = *other_mesh.boundary_info;
}

SerialMesh::SerialMesh (const UnstructuredMesh &other_mesh) :
  UnstructuredMesh (other_mesh)
{
  this->copy_nodes_and_elements(other_mesh);
  *this->boundary_info = *other_mesh.boundary_info;
}

const Point& SerialMesh::point (const unsigned int i) const
{
  libmesh_assert (i < this->n_nodes());
  libmesh_assert (_nodes[i] != NULL);
  libmesh_assert (_nodes[i]->id() == i); // This will change soon

  return (*_nodes[i]);
}

const Node& SerialMesh::node (const unsigned int i) const
{
  libmesh_assert (i < this->n_nodes());
  libmesh_assert (_nodes[i] != NULL);
  libmesh_assert (_nodes[i]->id() == i); // This will change soon

  return (*_nodes[i]);
}

Node& SerialMesh::node (const unsigned int i)
{
  if (i >= this->n_nodes())
    {
      libMesh::out << " i=" << i
		    << ", n_nodes()=" << this->n_nodes()
		    << std::endl;
      libmesh_error();
    }

  libmesh_assert (i < this->n_nodes());
  libmesh_assert (_nodes[i] != NULL);
  libmesh_assert (_nodes[i]->id() == i); // This will change soon

  return (*_nodes[i]);
}

const Node* SerialMesh::node_ptr (const unsigned int i) const
{
  libmesh_assert (i < this->n_nodes());
  libmesh_assert (_nodes[i] != NULL);
  libmesh_assert (_nodes[i]->id() == i); // This will change soon

  return _nodes[i];
}

Node* & SerialMesh::node_ptr (const unsigned int i)
{
  libmesh_assert (i < this->n_nodes());
  libmesh_assert (_nodes[i] != NULL);
  libmesh_assert (_nodes[i]->id() == i); // This will change soon

  return _nodes[i];
}

Elem* SerialMesh::elem (const unsigned int i) const
{
  libmesh_assert (i < this->n_elem());
  libmesh_assert (_elements[i] != NULL);
  libmesh_assert (_elements[i]->id() == i); // This will change soon

  return _elements[i];
}

Elem* SerialMesh::add_elem (Elem* e)
{
  libmesh_assert(e);

  // We only append elements with SerialMesh
  libmesh_assert (!e->valid_id() ||
          e->id() == _elements.size());

  e->set_id (_elements.size());

  _elements.push_back(e);

  return e;
}

Elem* SerialMesh::insert_elem (Elem* e)
{
  unsigned int eid = e->id();
  libmesh_assert(eid < _elements.size());
  Elem *oldelem = _elements[eid];

  if (oldelem)
    {
      libmesh_assert(oldelem->id() == eid);
      this->delete_elem(oldelem);
    }

  _elements[e->id()] = e;

  return e;
}

void SerialMesh::delete_elem(Elem* e)
{
  libmesh_assert (e != NULL);

  // Initialize an iterator to eventually point to the element we want to delete
  std::vector<Elem*>::iterator pos = _elements.end();

  // In many cases, e->id() gives us a clue as to where e
  // is located in the _elements vector.  Try that first
  // before trying the O(n_elem) search.
  libmesh_assert (e->id() < _elements.size());

  if (_elements[e->id()] == e)
    {
      // We found it!
      pos = _elements.begin();
      std::advance(pos, e->id());
    }

  else
    {
      // This search is O(n_elem)
      pos = std::find (_elements.begin(),
		       _elements.end(),
		       e);
    }

  // Huh? Element not in the vector?
  libmesh_assert (pos != _elements.end());

  // Remove the element from the BoundaryInfo object
  this->boundary_info->remove(e);

  // delete the element
  delete e;

  // explicitly NULL the pointer
  *pos = NULL;
}

void SerialMesh::renumber_elem(const unsigned int old_id,
                               const unsigned int new_id)
{
  // This doesn't get used in serial yet
  Elem *elem = _elements[old_id];
  libmesh_assert (elem);

  elem->set_id(new_id);
  libmesh_assert (!_elements[new_id]);
  _elements[new_id] = elem;
  _elements[old_id] = NULL;
}

Node* SerialMesh::add_point (const Point& p,
			     const unsigned int id,
			     const unsigned int proc_id)
{
//   // We only append points with SerialMesh
//   libmesh_assert(id == DofObject::invalid_id || id == _nodes.size());
//   Node *n = Node::build(p, _nodes.size()).release();
//   n->processor_id() = proc_id;
//   _nodes.push_back (n);

  Node *n = NULL;

  // If the user requests a valid id, either
  // provide the existing node or resize the container
  // to fit the new node.
  if (id != DofObject::invalid_id)
    if (id < _nodes.size())
      n = _nodes[id];
    else
      _nodes.resize(id+1);
  else
    _nodes.push_back (static_cast<Node*>(NULL));

  // if the node already exists, then assign new (x,y,z) values
  if (n)
    *n = p;
  // otherwise build a new node, put it in the right spot, and return
  // a valid pointer.
  else
    {
      n = Node::build(p, (id == DofObject::invalid_id) ? _nodes.size()-1 : id).release();
      n->processor_id() = proc_id;

      if (id == DofObject::invalid_id)
	_nodes.back() = n;
      else
	_nodes[id] = n;
    }

  // better not pass back a NULL pointer.
  libmesh_assert (n);

  return n;
}

Node* SerialMesh::add_node (Node* n)
{
  libmesh_assert(n);
  // We only append points with SerialMesh
  libmesh_assert(!n->valid_id() || n->id() == _nodes.size());

  n->set_id (_nodes.size());

  _nodes.push_back(n);

  return n;
}

void SerialMesh::delete_node(Node* n)
{
  libmesh_assert (n != NULL);
  libmesh_assert (n->id() < _nodes.size());

  // Initialize an iterator to eventually point to the element we want
  // to delete
  std::vector<Node*>::iterator pos;

  // In many cases, e->id() gives us a clue as to where e
  // is located in the _elements vector.  Try that first
  // before trying the O(n_elem) search.
  if (_nodes[n->id()] == n)
    {
      pos = _nodes.begin();
      std::advance(pos, n->id());
    }
  else
    {
      pos = std::find (_nodes.begin(),
		       _nodes.end(),
		       n);
    }

  // Huh? Node not in the vector?
  libmesh_assert (pos != _nodes.end());

  // Delete the node from the BoundaryInfo object
  this->boundary_info->remove(n);

  // delete the node
  delete n;

  // explicitly NULL the pointer
  *pos = NULL;
}

void SerialMesh::renumber_node(const unsigned int old_id,
                               const unsigned int new_id)
{
  // This doesn't get used in serial yet
  Node *node = _nodes[old_id];
  libmesh_assert (node);

  node->set_id(new_id);
  libmesh_assert (!_nodes[new_id]);
  _nodes[new_id] = node;
  _nodes[old_id] = NULL;
}

void SerialMesh::clear ()
{
  // Call parent clear function
  MeshBase::clear();

  // Clear our elements and nodes
  {
    std::vector<Elem*>::iterator       it  = _elements.begin();
    const std::vector<Elem*>::iterator end = _elements.end();

    // There is no need to remove the elements from
    // the BoundaryInfo data structure since we
    // already cleared it.
    for (; it != end; ++it)
      delete *it;

    _elements.clear();
  }

  // clear the nodes data structure
  {
    std::vector<Node*>::iterator       it  = _nodes.begin();
    const std::vector<Node*>::iterator end = _nodes.end();

    // There is no need to remove the nodes from
    // the BoundaryInfo data structure since we
    // already cleared it.
    for (; it != end; ++it)
      delete *it;

    _nodes.clear();
  }
}

void SerialMesh::renumber_nodes_and_elements ()
{

  START_LOG("renumber_nodes_and_elem()", "Mesh");

  // node and element id counters
  unsigned int next_free_elem = 0;
  unsigned int next_free_node = 0;

  // Loop over the elements.  Note that there may
  // be NULLs in the _elements vector from the coarsening
  // process.  Pack the elements in to a contiguous array
  // and then trim any excess.
  {
    std::vector<Elem*>::iterator in        = _elements.begin();
    std::vector<Elem*>::iterator out       = _elements.begin();
    const std::vector<Elem*>::iterator end = _elements.end();

    for (; in != end; ++in)
      if (*in != NULL)
	{
	  Elem* elem = *in;

	  *out = *in;
	  ++out;

	  // Increment the element counter
	  elem->set_id (next_free_elem++);

	  // Loop over this element's nodes.  Number them,
	  // if they have not been numbered already.  Also,
	  // position them in the _nodes vector so that they
	  // are packed contiguously from the beginning.
	  for (unsigned int n=0; n<elem->n_nodes(); n++)
	    if (elem->node(n) == next_free_node)     // don't need to process
	      next_free_node++;                      // [(src == dst) below]

	    else if (elem->node(n) > next_free_node) // need to process
	      {
		// The source and destination indices
		// for this node
		const unsigned int src_idx = elem->node(n);
		const unsigned int dst_idx = next_free_node++;

		// ensure we want to swap valid nodes
		libmesh_assert (_nodes[src_idx] != NULL);
		libmesh_assert (_nodes[dst_idx] != NULL);

		// Swap the source and destination nodes
                std::swap(_nodes[src_idx],
                          _nodes[dst_idx] );

		// Set proper indices
		_nodes[src_idx]->set_id (src_idx);
		_nodes[dst_idx]->set_id (dst_idx);
	      }
	}

    // Erase any additional storage. These elements have been
    // copied into NULL voids by the procedure above, and are
    // thus repeated and unnecessary.
    _elements.erase (out, end);
  }

  // Any nodes in the vector >= _nodes[next_free_node]
  // are not connected to any elements and may be deleted
  // if desired.

  // (This code block will erase the unused nodes)
  // Now, delete the unused nodes
  {
    std::vector<Node*>::iterator nd        = _nodes.begin();
    const std::vector<Node*>::iterator end = _nodes.end();

    std::advance (nd, next_free_node);

    for (std::vector<Node*>::iterator it=nd;
	 it != end; ++it)
      {
	libmesh_assert (*it != NULL);

	// remove any boundary information associated with
	// this node
	this->boundary_info->remove (*it);

	// delete the node
	delete *it;
	*it = NULL;
      }

    _nodes.erase (nd, end);
  }

  libmesh_assert (next_free_elem == _elements.size());
  libmesh_assert (next_free_node == _nodes.size());

  STOP_LOG("renumber_nodes_and_elem()", "Mesh");
}

void SerialMesh::fix_broken_node_and_element_numbering ()
{
   // Nodes first
  for (unsigned int n=0; n<this->_nodes.size(); n++)
    if (this->_nodes[n] != NULL)
      this->_nodes[n]->set_id() = n;

  // Elements next
  for (unsigned int e=0; e<this->_elements.size(); e++)
    if (this->_elements[e] != NULL)
      this->_elements[e]->set_id() = e;
}

unsigned int SerialMesh::n_active_elem () const
{
  return static_cast<unsigned int>(std::distance (this->active_elements_begin(),
						  this->active_elements_end()));
}

} // namespace libMesh
<commit_msg>Fix for SerialMesh::delete_node()<commit_after>// $Id$

// The libMesh Finite Element Library.
// Copyright (C) 2002-2008 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

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

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// Local includes
#include "boundary_info.h"
#include "elem.h"
#include "libmesh_logging.h"
#include "metis_partitioner.h"
#include "serial_mesh.h"

namespace libMesh
{

// ------------------------------------------------------------
// SerialMesh class member functions
SerialMesh::SerialMesh (unsigned int d) :
  UnstructuredMesh (d)
{
  _partitioner = AutoPtr<Partitioner>(new MetisPartitioner());
}

SerialMesh::~SerialMesh ()
{
  this->clear();  // Free nodes and elements
}

// This might be specialized later, but right now it's just here to
// make sure the compiler doesn't give us a default (non-deep) copy
// constructor instead.
SerialMesh::SerialMesh (const SerialMesh &other_mesh) :
  UnstructuredMesh (other_mesh)
{
  this->copy_nodes_and_elements(other_mesh);
  *this->boundary_info = *other_mesh.boundary_info;
}

SerialMesh::SerialMesh (const UnstructuredMesh &other_mesh) :
  UnstructuredMesh (other_mesh)
{
  this->copy_nodes_and_elements(other_mesh);
  *this->boundary_info = *other_mesh.boundary_info;
}

const Point& SerialMesh::point (const unsigned int i) const
{
  libmesh_assert (i < this->n_nodes());
  libmesh_assert (_nodes[i] != NULL);
  libmesh_assert (_nodes[i]->id() == i); // This will change soon

  return (*_nodes[i]);
}

const Node& SerialMesh::node (const unsigned int i) const
{
  libmesh_assert (i < this->n_nodes());
  libmesh_assert (_nodes[i] != NULL);
  libmesh_assert (_nodes[i]->id() == i); // This will change soon

  return (*_nodes[i]);
}

Node& SerialMesh::node (const unsigned int i)
{
  if (i >= this->n_nodes())
    {
      libMesh::out << " i=" << i
		    << ", n_nodes()=" << this->n_nodes()
		    << std::endl;
      libmesh_error();
    }

  libmesh_assert (i < this->n_nodes());
  libmesh_assert (_nodes[i] != NULL);
  libmesh_assert (_nodes[i]->id() == i); // This will change soon

  return (*_nodes[i]);
}

const Node* SerialMesh::node_ptr (const unsigned int i) const
{
  libmesh_assert (i < this->n_nodes());
  libmesh_assert (_nodes[i] != NULL);
  libmesh_assert (_nodes[i]->id() == i); // This will change soon

  return _nodes[i];
}

Node* & SerialMesh::node_ptr (const unsigned int i)
{
  libmesh_assert (i < this->n_nodes());
  libmesh_assert (_nodes[i] != NULL);
  libmesh_assert (_nodes[i]->id() == i); // This will change soon

  return _nodes[i];
}

Elem* SerialMesh::elem (const unsigned int i) const
{
  libmesh_assert (i < this->n_elem());
  libmesh_assert (_elements[i] != NULL);
  libmesh_assert (_elements[i]->id() == i); // This will change soon

  return _elements[i];
}

Elem* SerialMesh::add_elem (Elem* e)
{
  libmesh_assert(e);

  // We only append elements with SerialMesh
  libmesh_assert (!e->valid_id() ||
          e->id() == _elements.size());

  e->set_id (_elements.size());

  _elements.push_back(e);

  return e;
}

Elem* SerialMesh::insert_elem (Elem* e)
{
  unsigned int eid = e->id();
  libmesh_assert(eid < _elements.size());
  Elem *oldelem = _elements[eid];

  if (oldelem)
    {
      libmesh_assert(oldelem->id() == eid);
      this->delete_elem(oldelem);
    }

  _elements[e->id()] = e;

  return e;
}

void SerialMesh::delete_elem(Elem* e)
{
  libmesh_assert (e != NULL);

  // Initialize an iterator to eventually point to the element we want to delete
  std::vector<Elem*>::iterator pos = _elements.end();

  // In many cases, e->id() gives us a clue as to where e
  // is located in the _elements vector.  Try that first
  // before trying the O(n_elem) search.
  libmesh_assert (e->id() < _elements.size());

  if (_elements[e->id()] == e)
    {
      // We found it!
      pos = _elements.begin();
      std::advance(pos, e->id());
    }

  else
    {
      // This search is O(n_elem)
      pos = std::find (_elements.begin(),
		       _elements.end(),
		       e);
    }

  // Huh? Element not in the vector?
  libmesh_assert (pos != _elements.end());

  // Remove the element from the BoundaryInfo object
  this->boundary_info->remove(e);

  // delete the element
  delete e;

  // explicitly NULL the pointer
  *pos = NULL;
}

void SerialMesh::renumber_elem(const unsigned int old_id,
                               const unsigned int new_id)
{
  // This doesn't get used in serial yet
  Elem *elem = _elements[old_id];
  libmesh_assert (elem);

  elem->set_id(new_id);
  libmesh_assert (!_elements[new_id]);
  _elements[new_id] = elem;
  _elements[old_id] = NULL;
}

Node* SerialMesh::add_point (const Point& p,
			     const unsigned int id,
			     const unsigned int proc_id)
{
//   // We only append points with SerialMesh
//   libmesh_assert(id == DofObject::invalid_id || id == _nodes.size());
//   Node *n = Node::build(p, _nodes.size()).release();
//   n->processor_id() = proc_id;
//   _nodes.push_back (n);

  Node *n = NULL;

  // If the user requests a valid id, either
  // provide the existing node or resize the container
  // to fit the new node.
  if (id != DofObject::invalid_id)
    if (id < _nodes.size())
      n = _nodes[id];
    else
      _nodes.resize(id+1);
  else
    _nodes.push_back (static_cast<Node*>(NULL));

  // if the node already exists, then assign new (x,y,z) values
  if (n)
    *n = p;
  // otherwise build a new node, put it in the right spot, and return
  // a valid pointer.
  else
    {
      n = Node::build(p, (id == DofObject::invalid_id) ? _nodes.size()-1 : id).release();
      n->processor_id() = proc_id;

      if (id == DofObject::invalid_id)
	_nodes.back() = n;
      else
	_nodes[id] = n;
    }

  // better not pass back a NULL pointer.
  libmesh_assert (n);

  return n;
}

Node* SerialMesh::add_node (Node* n)
{
  libmesh_assert(n);
  // We only append points with SerialMesh
  libmesh_assert(!n->valid_id() || n->id() == _nodes.size());

  n->set_id (_nodes.size());

  _nodes.push_back(n);

  return n;
}

void SerialMesh::delete_node(Node* n)
{
  libmesh_assert (n != NULL);
  libmesh_assert (n->id() < _nodes.size());

  // Initialize an iterator to eventually point to the element we want
  // to delete
  std::vector<Node*>::iterator pos;

  // In many cases, e->id() gives us a clue as to where e
  // is located in the _elements vector.  Try that first
  // before trying the O(n_elem) search.
  if (_nodes[n->id()] == n)
    {
      pos = _nodes.begin();
      std::advance(pos, n->id());
    }
  else
    {
      pos = std::find (_nodes.begin(),
		       _nodes.end(),
		       n);
    }

  // Huh? Node not in the vector?
  libmesh_assert (pos != _nodes.end());

  // Delete the node from the BoundaryInfo object
  this->boundary_info->remove(n);

  // delete the node
  delete n;

  // explicitly NULL the pointer
  *pos = NULL;
}

void SerialMesh::renumber_node(const unsigned int old_id,
                               const unsigned int new_id)
{
  // This doesn't get used in serial yet
  Node *node = _nodes[old_id];
  libmesh_assert (node);

  node->set_id(new_id);
  libmesh_assert (!_nodes[new_id]);
  _nodes[new_id] = node;
  _nodes[old_id] = NULL;
}

void SerialMesh::clear ()
{
  // Call parent clear function
  MeshBase::clear();

  // Clear our elements and nodes
  {
    std::vector<Elem*>::iterator       it  = _elements.begin();
    const std::vector<Elem*>::iterator end = _elements.end();

    // There is no need to remove the elements from
    // the BoundaryInfo data structure since we
    // already cleared it.
    for (; it != end; ++it)
      delete *it;

    _elements.clear();
  }

  // clear the nodes data structure
  {
    std::vector<Node*>::iterator       it  = _nodes.begin();
    const std::vector<Node*>::iterator end = _nodes.end();

    // There is no need to remove the nodes from
    // the BoundaryInfo data structure since we
    // already cleared it.
    for (; it != end; ++it)
      delete *it;

    _nodes.clear();
  }
}

void SerialMesh::renumber_nodes_and_elements ()
{

  START_LOG("renumber_nodes_and_elem()", "Mesh");

  // node and element id counters
  unsigned int next_free_elem = 0;
  unsigned int next_free_node = 0;

  // Loop over the elements.  Note that there may
  // be NULLs in the _elements vector from the coarsening
  // process.  Pack the elements in to a contiguous array
  // and then trim any excess.
  {
    std::vector<Elem*>::iterator in        = _elements.begin();
    std::vector<Elem*>::iterator out       = _elements.begin();
    const std::vector<Elem*>::iterator end = _elements.end();

    for (; in != end; ++in)
      if (*in != NULL)
	{
	  Elem* elem = *in;

	  *out = *in;
	  ++out;

	  // Increment the element counter
	  elem->set_id (next_free_elem++);

	  // Loop over this element's nodes.  Number them,
	  // if they have not been numbered already.  Also,
	  // position them in the _nodes vector so that they
	  // are packed contiguously from the beginning.
	  for (unsigned int n=0; n<elem->n_nodes(); n++)
	    if (elem->node(n) == next_free_node)     // don't need to process
	      next_free_node++;                      // [(src == dst) below]

	    else if (elem->node(n) > next_free_node) // need to process
	      {
		// The source and destination indices
		// for this node
		const unsigned int src_idx = elem->node(n);
		const unsigned int dst_idx = next_free_node++;

		// ensure we want to swap a valid nodes
		libmesh_assert (_nodes[src_idx] != NULL);

		// Swap the source and destination nodes
                std::swap(_nodes[src_idx],
                          _nodes[dst_idx] );

		// Set proper indices where that makes sense
		if (_nodes[src_idx] != NULL)
		  _nodes[src_idx]->set_id (src_idx);
		_nodes[dst_idx]->set_id (dst_idx);
	      }
	}

    // Erase any additional storage. These elements have been
    // copied into NULL voids by the procedure above, and are
    // thus repeated and unnecessary.
    _elements.erase (out, end);
  }

  // Any nodes in the vector >= _nodes[next_free_node]
  // are not connected to any elements and may be deleted
  // if desired.

  // (This code block will erase the unused nodes)
  // Now, delete the unused nodes
  {
    std::vector<Node*>::iterator nd        = _nodes.begin();
    const std::vector<Node*>::iterator end = _nodes.end();

    std::advance (nd, next_free_node);

    for (std::vector<Node*>::iterator it=nd;
	 it != end; ++it)
      {
        // Mesh modification code might have already deleted some
        // nodes
	if (*it == NULL)
          continue;

	// remove any boundary information associated with
	// this node
	this->boundary_info->remove (*it);

	// delete the node
	delete *it;
	*it = NULL;
      }

    _nodes.erase (nd, end);
  }

  libmesh_assert (next_free_elem == _elements.size());
  libmesh_assert (next_free_node == _nodes.size());

  STOP_LOG("renumber_nodes_and_elem()", "Mesh");
}

void SerialMesh::fix_broken_node_and_element_numbering ()
{
   // Nodes first
  for (unsigned int n=0; n<this->_nodes.size(); n++)
    if (this->_nodes[n] != NULL)
      this->_nodes[n]->set_id() = n;

  // Elements next
  for (unsigned int e=0; e<this->_elements.size(); e++)
    if (this->_elements[e] != NULL)
      this->_elements[e]->set_id() = e;
}

unsigned int SerialMesh::n_active_elem () const
{
  return static_cast<unsigned int>(std::distance (this->active_elements_begin(),
						  this->active_elements_end()));
}

} // namespace libMesh
<|endoftext|>


<commit_before>#include "table.h"
#include "ui_table.h"

table::table(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::table),
    m_fileName("")
{
    ui->setupUi(this);
    ui->tableView->move(0, 0);
    m_model = new TeamModel(ui->actionSave, this);
    ui->tableView->setModel(m_model);
    ui->actionSave->setEnabled(false);
    ui->tableView->horizontalHeader()->setStretchLastSection(true);
}

table::~table()
{
    delete ui;
    if (m_model)
    {
        delete m_model;
    }
}

void table::resizeEvent(QResizeEvent*)
{
    ui->tableView->resize(size());
    ui->tableView->setColumnWidth(0, ui->tableView->width() / 2);
}

void table::on_actionInsert_row_triggered()
{
    input dlg;
    dlg.setModal(true);
    if (dlg.exec() == dlg.Accepted)
    {
        m_model->append(dlg.newTeamRow);
    }
}

void table::on_actionDelete_row_triggered()
{
    m_model->RemoveLast();
}

void table::on_actionOpen_triggered()
{
    Open();
}

void table::on_actionSave_triggered()
{
    Save();
}

void table::on_actionNew_triggered()
{
    New();
}

void table::on_actionSave_as_triggered()
{
    SaveAs();
}

void table::on_actionAbout_Application_triggered()
{
    QMessageBox box;
    box.setWindowTitle("About author");
    box.setText("Statistics Editor");
    box.setInformativeText("Copyright © 2015 Alitov Vladimir");
    box.exec();
}

bool table::SaveRequest()
{
    auto confirmDlg = QMessageBox::question(this, tr("Save request"), tr("Do you want to save changes?"),
                                  QMessageBox::Yes|QMessageBox::No);
    return (confirmDlg == QMessageBox::Yes);
}

void table::Save(QString filePath)
{
    if (m_model->smthChanged || filePath != "")
    {
        if (m_fileName == "" && filePath == "")
        {
            SaveAs();
            return;
        }
        if (filePath == "")
        {
            filePath = m_fileName;
        }
        QFile f(filePath);
        if(f.open(QIODevice::WriteOnly))
        {
            QVariantMap data;
            for (int i = 0; i < m_model->rowCount(QModelIndex()); ++i)
            {
                data.insert(m_model->data(m_model->index(i, 0), Qt::DisplayRole).toString(),
                            m_model->data(m_model->index(i, 1), Qt::DisplayRole).toInt());
            }
            QJsonDocument doc;
            f.write(doc.fromVariant(data).toJson());
            f.close();
        }
        m_model->smthChanged = false;
        ui->actionSave->setEnabled(false);
    }
}

void table::SaveAs()
{
    QString filePath = QFileDialog::getSaveFileName(this,tr("Open"),QString(),tr("JSON Files (*.json)"));
    if (filePath != "")
    {
        Save(filePath);
    }
}

void table::Open()
{
    if (m_model->smthChanged)
    {
        if (SaveRequest())
        {
            Save();
        }
    }
    QString fileName = QFileDialog::getOpenFileName(this,tr("Open"),QString(),tr("JSON Files (*.json)"));
    if (fileName == "")
    {
        return;
    }
    QFile f(fileName);
    QString data = "";
    if(f.open(QIODevice::ReadOnly))
    {
        data = f.readAll();
        f.close();
    }
    QJsonParseError  parseError;
    QJsonDocument doc = QJsonDocument::fromJson(data.toUtf8(), &parseError);
    if(parseError.error)
    {
        QMessageBox::warning(this, tr("Error"), tr("Parse error"));
        return;
    }
    auto items = doc.object();
    m_model->clear();
    for (QJsonObject::Iterator iter = items.begin(); iter != items.end(); ++iter)
    {
        Team newTeam(iter.key(), iter.value().toInt());
        m_model->append(newTeam);
    }

    m_fileName = fileName;
    m_model->smthChanged = false;
    ui->actionSave->setEnabled(false);
}

void table::New()
{
    if (m_model->smthChanged)
    {
        if (SaveRequest())
        {
            if (m_fileName == "")
            {
                SaveAs();
            }
            else
            {
                Save();
            }
        }
    }
    m_fileName = "";
    m_model->clear();
    m_model->smthChanged = false;
}

void table::closeEvent(QCloseEvent*)
{
    if(m_model->smthChanged)
    {
      if(SaveRequest())
      {
          Save();
      }
    }
}
<commit_msg>Одну строчку забыл<commit_after>#include "table.h"
#include "ui_table.h"

table::table(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::table),
    m_fileName("")
{
    ui->setupUi(this);
    ui->tableView->move(0, 0);
    m_model = new TeamModel(ui->actionSave, this);
    ui->tableView->setModel(m_model);
    ui->actionSave->setEnabled(false);
    ui->tableView->horizontalHeader()->setStretchLastSection(true);
}

table::~table()
{
    delete ui;
    if (m_model)
    {
        delete m_model;
    }
}

void table::resizeEvent(QResizeEvent*)
{
    ui->tableView->resize(size());
    ui->tableView->setColumnWidth(0, ui->tableView->width() / 2);
}

void table::on_actionInsert_row_triggered()
{
    input dlg;
    dlg.setModal(true);
    if (dlg.exec() == dlg.Accepted)
    {
        m_model->append(dlg.newTeamRow);
    }
}

void table::on_actionDelete_row_triggered()
{
    m_model->RemoveLast();
}

void table::on_actionOpen_triggered()
{
    Open();
}

void table::on_actionSave_triggered()
{
    Save();
}

void table::on_actionNew_triggered()
{
    New();
}

void table::on_actionSave_as_triggered()
{
    SaveAs();
}

void table::on_actionAbout_Application_triggered()
{
    QMessageBox box;
    box.setWindowTitle("About author");
    box.setText("Statistics Editor");
    box.setInformativeText("Copyright © 2015 Alitov Vladimir");
    box.exec();
}

bool table::SaveRequest()
{
    auto confirmDlg = QMessageBox::question(this, tr("Save request"), tr("Do you want to save changes?"),
                                  QMessageBox::Yes|QMessageBox::No);
    return (confirmDlg == QMessageBox::Yes);
}

void table::Save(QString filePath)
{
    if (m_model->smthChanged || filePath != "")
    {
        if (m_fileName == "" && filePath == "")
        {
            SaveAs();
            return;
        }
        if (filePath == "")
        {
            filePath = m_fileName;
        }
        QFile f(filePath);
        if(f.open(QIODevice::WriteOnly))
        {
            QVariantMap data;
            for (int i = 0; i < m_model->rowCount(QModelIndex()); ++i)
            {
                data.insert(m_model->data(m_model->index(i, 0), Qt::DisplayRole).toString(),
                            m_model->data(m_model->index(i, 1), Qt::DisplayRole).toInt());
            }
            QJsonDocument doc;
            f.write(doc.fromVariant(data).toJson());
            f.close();
        }
        m_fileName = filePath;
        m_model->smthChanged = false;
        ui->actionSave->setEnabled(false);
    }
}

void table::SaveAs()
{
    QString filePath = QFileDialog::getSaveFileName(this,tr("Open"),QString(),tr("JSON Files (*.json)"));
    if (filePath != "")
    {
        Save(filePath);
    }
}

void table::Open()
{
    if (m_model->smthChanged)
    {
        if (SaveRequest())
        {
            Save();
        }
    }
    QString fileName = QFileDialog::getOpenFileName(this,tr("Open"),QString(),tr("JSON Files (*.json)"));
    if (fileName == "")
    {
        return;
    }
    QFile f(fileName);
    QString data = "";
    if(f.open(QIODevice::ReadOnly))
    {
        data = f.readAll();
        f.close();
    }
    QJsonParseError  parseError;
    QJsonDocument doc = QJsonDocument::fromJson(data.toUtf8(), &parseError);
    if(parseError.error)
    {
        QMessageBox::warning(this, tr("Error"), tr("Parse error"));
        return;
    }
    auto items = doc.object();
    m_model->clear();
    for (QJsonObject::Iterator iter = items.begin(); iter != items.end(); ++iter)
    {
        Team newTeam(iter.key(), iter.value().toInt());
        m_model->append(newTeam);
    }

    m_fileName = fileName;
    m_model->smthChanged = false;
    ui->actionSave->setEnabled(false);
}

void table::New()
{
    if (m_model->smthChanged)
    {
        if (SaveRequest())
        {
            if (m_fileName == "")
            {
                SaveAs();
            }
            else
            {
                Save();
            }
        }
    }
    m_fileName = "";
    m_model->clear();
    m_model->smthChanged = false;
}

void table::closeEvent(QCloseEvent*)
{
    if(m_model->smthChanged)
    {
      if(SaveRequest())
      {
          Save();
      }
    }
}
<|endoftext|>


<commit_before>// $Id$
//
//  Copyright (C) 2004-2006 Rational Discovery LLC
//
//   @@ All Rights Reserved  @@
//
#define NO_IMPORT_ARRAY
#include <boost/python.hpp>

#include <GraphMol/RDKitBase.h>
#include <RDGeneral/types.h>
#include <RDBoost/Exceptions.h>
#include <GraphMol/MolChemicalFeatures/MolChemicalFeatureFactory.h>
#include <GraphMol/MolChemicalFeatures/MolChemicalFeature.h>
#include <boost/python/converter/shared_ptr_to_python.hpp>

namespace python = boost::python;

namespace RDKit {
  // ----------------------------------------------------------------------------
  // NOTE: the reason we don't provide an interface to get all the
  // features from a molecule at the same time directly from C++ is a
  // potential problem with the lifetime of molecules and features:
  // Each Feature carries around a pointer to its owning molecule,
  //  and that pointer must remain valid. So we need to use the BPL's
  //  with_custodian_and_ward() functionality to tie the lifetime
  //  of the molecule to that of the feature. This is not currently
  //  possible in BPL v1.32 if we return a tuple of objects; so if
  //  we return a set of features, there's no way to use
  //  with_custodian_and_ward() to ensure that the molecule doesn't vanish
  //  underneath them.  Access to all of a molecule's features is provided
  //  from within python (looping over getMolFeature() and gaining efficiency
  //  by not recomputing after the first call).
  // ----------------------------------------------------------------------------

  int getNumMolFeatures(const MolChemicalFeatureFactory &factory,
			const ROMol &mol,
			std::string includeOnly="") {
    FeatSPtrList feats = factory.getFeaturesForMol(mol,includeOnly.c_str());
    return feats.size();
  }

  FeatSPtr getMolFeature(const MolChemicalFeatureFactory &factory,
			 const ROMol &mol,
			 int idx,
			 std::string includeOnly="",
			 bool recompute=true) {
    static FeatSPtrList feats;
    if(recompute){
      feats = factory.getFeaturesForMol(mol,includeOnly.c_str());
    }
    if(idx<0 || idx>=static_cast<int>(feats.size())){
      throw IndexErrorException(idx);
    }

    FeatSPtrList_I fi=feats.begin();
    for(int i=0;i<idx;++i){
      ++fi;
    }
    return (*fi);
  }

  python::tuple getFeatureFamilies(const MolChemicalFeatureFactory &factory){
    python::list res;

    MolChemicalFeatureDef::CollectionType::const_iterator iter;
    for(iter=factory.beginFeatureDefs();iter!=factory.endFeatureDefs();++iter){
      std::string fam= (*iter)->getFamily();
      if(res.count(fam)==0) res.append(fam);
    }
    return python::tuple(res);
  }

  struct featfactory_wrapper {
    static void wrap() {
      std::string factoryClassDoc="Class to featurize a molecule\n";
      // no direct constructor - use buildFactory function
      python::class_<MolChemicalFeatureFactory>("MolChemicalFeatureFactory",
						factoryClassDoc.c_str(), python::no_init)
        .def("GetNumFeatureDefs", &MolChemicalFeatureFactory::getNumFeatureDefs,
             "Get the number of feature definitions")
        .def("GetFeatureFamilies", getFeatureFamilies,
             "Get a tuple of feature types")
        .def("GetNumMolFeatures", getNumMolFeatures,
	     (python::arg("mol"),python::arg("includeOnly")=std::string("")),
             "Get the number of features the molecule has")
        .def("GetMolFeature", getMolFeature,
	     (python::arg("mol"),python::arg("idx"),
	      python::arg("includeOnly")=std::string(""),
	      python::arg("recompute")=true),
	     python::with_custodian_and_ward_postcall<0,2>(),
             "returns a particular feature (by index)")
        ;
    };
  };
}

void wrap_factory() {
  RDKit::featfactory_wrapper::wrap();
}

<commit_msg>add GetFeatureDefs() method<commit_after>// $Id$
//
//  Copyright (C) 2004-2006 Rational Discovery LLC
//
//   @@ All Rights Reserved  @@
//
#define NO_IMPORT_ARRAY
#include <boost/python.hpp>

#include <GraphMol/RDKitBase.h>
#include <RDGeneral/types.h>
#include <RDBoost/Exceptions.h>
#include <GraphMol/MolChemicalFeatures/MolChemicalFeatureFactory.h>
#include <GraphMol/MolChemicalFeatures/MolChemicalFeature.h>
#include <boost/python/converter/shared_ptr_to_python.hpp>

namespace python = boost::python;

namespace RDKit {
  // ----------------------------------------------------------------------------
  // NOTE: the reason we don't provide an interface to get all the
  // features from a molecule at the same time directly from C++ is a
  // potential problem with the lifetime of molecules and features:
  // Each Feature carries around a pointer to its owning molecule,
  //  and that pointer must remain valid. So we need to use the BPL's
  //  with_custodian_and_ward() functionality to tie the lifetime
  //  of the molecule to that of the feature. This is not currently
  //  possible in BPL v1.32 if we return a tuple of objects; so if
  //  we return a set of features, there's no way to use
  //  with_custodian_and_ward() to ensure that the molecule doesn't vanish
  //  underneath them.  Access to all of a molecule's features is provided
  //  from within python (looping over getMolFeature() and gaining efficiency
  //  by not recomputing after the first call).
  // ----------------------------------------------------------------------------

  int getNumMolFeatures(const MolChemicalFeatureFactory &factory,
			const ROMol &mol,
			std::string includeOnly="") {
    FeatSPtrList feats = factory.getFeaturesForMol(mol,includeOnly.c_str());
    return feats.size();
  }

  FeatSPtr getMolFeature(const MolChemicalFeatureFactory &factory,
			 const ROMol &mol,
			 int idx,
			 std::string includeOnly="",
			 bool recompute=true) {
    static FeatSPtrList feats;
    if(recompute){
      feats = factory.getFeaturesForMol(mol,includeOnly.c_str());
    }
    if(idx<0 || idx>=static_cast<int>(feats.size())){
      throw IndexErrorException(idx);
    }

    FeatSPtrList_I fi=feats.begin();
    for(int i=0;i<idx;++i){
      ++fi;
    }
    return (*fi);
  }

  python::tuple getFeatureFamilies(const MolChemicalFeatureFactory &factory){
    python::list res;

    MolChemicalFeatureDef::CollectionType::const_iterator iter;
    for(iter=factory.beginFeatureDefs();iter!=factory.endFeatureDefs();++iter){
      std::string fam= (*iter)->getFamily();
      if(res.count(fam)==0) res.append(fam);
    }
    return python::tuple(res);
  }

  python::dict getFeatureDefs(const MolChemicalFeatureFactory &factory){
    python::dict res;
    MolChemicalFeatureDef::CollectionType::const_iterator iter;
    for(iter=factory.beginFeatureDefs();iter!=factory.endFeatureDefs();++iter){
      std::string key= (*iter)->getFamily()+"."+(*iter)->getType();
      res[key]=(*iter)->getSmarts();
    }
    return res;
  }

  struct featfactory_wrapper {
    static void wrap() {
      std::string factoryClassDoc="Class to featurize a molecule\n";
      // no direct constructor - use buildFactory function
      python::class_<MolChemicalFeatureFactory>("MolChemicalFeatureFactory",
						factoryClassDoc.c_str(), python::no_init)
        .def("GetNumFeatureDefs", &MolChemicalFeatureFactory::getNumFeatureDefs,
             "Get the number of feature definitions")
        .def("GetFeatureFamilies", getFeatureFamilies,
             "Get a tuple of feature types")
        .def("GetFeatureDefs", getFeatureDefs,
             "Get a dictionary with SMARTS definitions for each feature type")
        .def("GetNumMolFeatures", getNumMolFeatures,
	     (python::arg("mol"),python::arg("includeOnly")=std::string("")),
             "Get the number of features the molecule has")
        .def("GetMolFeature", getMolFeature,
	     (python::arg("mol"),python::arg("idx"),
	      python::arg("includeOnly")=std::string(""),
	      python::arg("recompute")=true),
	     python::with_custodian_and_ward_postcall<0,2>(),
             "returns a particular feature (by index)")
        ;
    };
  };
}

void wrap_factory() {
  RDKit::featfactory_wrapper::wrap();
}

<|endoftext|>