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

#undef SC_DLLIMPLEMENTATION

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

#pragma hdrstop

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

#include <svtools/zforlist.hxx>
#include <vcl/msgbox.hxx>
#include <limits.h>

#include "scresid.hxx"
#include "document.hxx"
#include "miscdlgs.hrc"

#define _FILLDLG_CXX
#include "filldlg.hxx"
#undef _FILLDLG_CXX

//============================================================================
// class ScFillSeriesDlg

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

ScFillSeriesDlg::ScFillSeriesDlg( Window*       pParent,
                                  ScDocument&   rDocument,
                                  FillDir       eFillDir,
                                  FillCmd       eFillCmd,
                                  FillDateCmd   eFillDateCmd,
                                  String        aStartStr,
                                  double        fStep,
                                  double        fMax,
                                  USHORT        nPossDir )

    :   ModalDialog     ( pParent, ScResId( RID_SCDLG_FILLSERIES ) ),

        aFlDirection    ( this, ScResId( FL_DIRECTION ) ),
        aBtnLeft        ( this, ScResId( BTN_LEFT ) ),
        aBtnRight       ( this, ScResId( BTN_RIGHT ) ),
        aBtnUp          ( this, ScResId( BTN_TOP ) ),
        aBtnDown        ( this, ScResId( BTN_BOTTOM ) ),
        aFlSep1         ( this, ScResId( FL_SEP1 ) ),
        aFlType         ( this, ScResId( FL_TYPE ) ),
        aBtnArithmetic  ( this, ScResId( BTN_ARITHMETIC ) ),
        aBtnGeometric   ( this, ScResId( BTN_GEOMETRIC ) ),
        aBtnDate        ( this, ScResId( BTN_DATE ) ),
        aBtnAutoFill    ( this, ScResId( BTN_AUTOFILL ) ),
        aFlSep2         ( this, ScResId( FL_SEP2 ) ),
        aFlTimeUnit     ( this, ScResId( FL_TIME_UNIT ) ),
        aBtnDay         ( this, ScResId( BTN_DAY ) ),
        aBtnDayOfWeek   ( this, ScResId( BTN_DAY_OF_WEEK ) ),
        aBtnMonth       ( this, ScResId( BTN_MONTH ) ),
        aBtnYear        ( this, ScResId( BTN_YEAR ) ),

        aFtStartVal     ( this, ScResId( FT_START_VALUE ) ),
        aEdStartVal     ( this, ScResId( ED_START_VALUES ) ),
        aFtEndVal       ( this, ScResId( FT_END_VALUE ) ),
        aEdEndVal       ( this, ScResId( ED_END_VALUES ) ),
        aFtIncrement    ( this, ScResId( FT_INCREMENT ) ),
        aEdIncrement    ( this, ScResId( ED_INCREMENT ) ),

        aBtnOk          ( this, ScResId( BTN_OK ) ),
        aBtnCancel      ( this, ScResId( BTN_CANCEL ) ),
        aBtnHelp        ( this, ScResId( BTN_HELP ) ),
        errMsgInvalidVal( ScResId( STR_VALERR ) ),
        rDoc            ( rDocument ),
        theFillDir      ( eFillDir ),
        theFillCmd      ( eFillCmd ),
        theFillDateCmd  ( eFillDateCmd ),
        aStartStrVal    ( aStartStr),
        fIncrement      ( fStep ),
        fEndVal         ( fMax )
{
    Init( nPossDir );
    FreeResource();
}

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

__EXPORT ScFillSeriesDlg::~ScFillSeriesDlg()
{
}

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

void ScFillSeriesDlg::SetEdStartValEnabled(BOOL bFlag)
{
    bStartValFlag=bFlag;
    if(bFlag)
    {
       aFtStartVal.Enable();
       aEdStartVal.Enable();
    }
    else
    {
       aFtStartVal.Disable();
       aEdStartVal.Disable();
    }
}

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

void ScFillSeriesDlg::Init( USHORT nPossDir )
{
    aBtnOk.SetClickHdl         ( LINK( this, ScFillSeriesDlg, OKHdl ) );
    aBtnArithmetic.SetClickHdl ( LINK( this, ScFillSeriesDlg, DisableHdl ) );
    aBtnGeometric.SetClickHdl  ( LINK( this, ScFillSeriesDlg, DisableHdl ) );
    aBtnDate.SetClickHdl       ( LINK( this, ScFillSeriesDlg, DisableHdl ) );
    aBtnAutoFill.SetClickHdl   ( LINK( this, ScFillSeriesDlg, DisableHdl ) );

    if( nPossDir == FDS_OPT_NONE )
    {
        aBtnLeft.Disable();
        aBtnRight.Disable();
        aBtnDown.Disable();
        aBtnUp.Disable();
    }

    if( nPossDir == FDS_OPT_HORZ )
    {
        aBtnDown.Disable();
        aBtnUp.Disable();
    }

    if( nPossDir == FDS_OPT_VERT )
    {
        aBtnLeft.Disable();
        aBtnRight.Disable();
    }

    switch ( theFillDir )
    {
        case FILL_TO_LEFT:      aBtnLeft.Check();   break;
        case FILL_TO_RIGHT:     aBtnRight.Check();  break;
        case FILL_TO_BOTTOM:    aBtnDown.Check();   break;
        case FILL_TO_TOP:       aBtnUp.Check();     break;
        default:
        break;
    }

    switch ( theFillCmd )
    {
        case FILL_LINEAR:
            aBtnArithmetic.Check();
            DisableHdl( &aBtnArithmetic );
            break;
        case FILL_GROWTH:
            aBtnGeometric.Check();
            DisableHdl( &aBtnGeometric );
            break;
        case FILL_DATE:
            aBtnDate.Check();
            DisableHdl( &aBtnDate );
            break;
        case FILL_AUTO:
            aBtnAutoFill.Check();
            DisableHdl( &aBtnAutoFill );
            break;
        default:
        break;
    }

    switch ( theFillDateCmd )
    {
        case FILL_DAY:          aBtnDay.Check();        break;
        case FILL_WEEKDAY:      aBtnDayOfWeek.Check();  break;
        case FILL_MONTH:        aBtnMonth.Check();      break;
        case FILL_YEAR:         aBtnYear.Check();       break;
        default:
        break;
    }

    fStartVal = MAXDOUBLE;
    /*
    String aStartTxt;
    if ( fStartVal != MAXDOUBLE )
        rDoc.GetFormatTable()->GetInputLineString( fStartVal, 0, aStartTxt );
    aEdStartVal.SetText( aStartTxt );
    */

    aEdStartVal.SetText( aStartStrVal);

    String aIncrTxt;
    rDoc.GetFormatTable()->GetInputLineString( fIncrement, 0, aIncrTxt );
    aEdIncrement.SetText( aIncrTxt );

    String aEndTxt;
    if ( fEndVal != MAXDOUBLE )
        rDoc.GetFormatTable()->GetInputLineString( fEndVal, 0, aEndTxt );
    aEdEndVal.SetText( aEndTxt );

    bStartValFlag=FALSE;

    aFlSep1.SetStyle( aFlSep1.GetStyle() | WB_VERT );
    aFlSep2.SetStyle( aFlSep2.GetStyle() | WB_VERT );
}

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

BOOL __EXPORT ScFillSeriesDlg::CheckStartVal()
{
    BOOL bValOk = FALSE;
    ULONG  nKey = 0;
    String aStr( aEdStartVal.GetText() );

    if ( aStr.Len() == 0 || aBtnAutoFill.IsChecked())
    {
        fStartVal = MAXDOUBLE;
        bValOk = TRUE;
    }
    else
        bValOk = rDoc.GetFormatTable()->IsNumberFormat( aStr, nKey, fStartVal );

    return bValOk;
}

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

BOOL __EXPORT ScFillSeriesDlg::CheckIncrementVal()
{
    ULONG  nKey = 0;
    String aStr( aEdIncrement.GetText() );

    return rDoc.GetFormatTable()->IsNumberFormat( aStr, nKey, fIncrement );
}

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

BOOL __EXPORT ScFillSeriesDlg::CheckEndVal()
{
    BOOL    bValOk = FALSE;
    ULONG   nKey = 0;
    String  aStr( aEdEndVal.GetText() );

    if ( aStr.Len() == 0 )
    {
        fEndVal = (fIncrement < 0) ? -MAXDOUBLE : MAXDOUBLE;
        bValOk  = TRUE;
    }
    else
        bValOk = rDoc.GetFormatTable()->IsNumberFormat( aStr, nKey, fEndVal );

    return bValOk;
}

//----------------------------------------------------------------------------
// Handler:
//----------------------------------------------------------------------------

IMPL_LINK( ScFillSeriesDlg, DisableHdl, Button *, pBtn )
{
    if ( pBtn == &aBtnDate )
    {
        aBtnDay.Enable();
        aBtnDayOfWeek.Enable();
        aBtnMonth.Enable();
        aBtnYear.Enable();
        aFlTimeUnit.Enable();
    }
    else
    {
        aBtnDay.Disable();
        aBtnDayOfWeek.Disable();
        aBtnMonth.Disable();
        aBtnYear.Disable();
        aFlTimeUnit.Disable();
    }

    if ( pBtn != &aBtnAutoFill )
    {
        aFtIncrement.Enable();
        aEdIncrement.Enable();
        aFtEndVal.Enable();
        aEdEndVal.Enable();
    }
    else
    {
        aFtIncrement.Disable();
        aEdIncrement.Disable();
        aFtEndVal.Disable();
        aEdEndVal.Disable();
    }
    return 0;
}

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

IMPL_LINK( ScFillSeriesDlg, OKHdl, void *, EMPTYARG )
{
    if ( aBtnLeft.IsChecked() )             theFillDir = FILL_TO_LEFT;
    else if ( aBtnRight.IsChecked() )       theFillDir = FILL_TO_RIGHT;
    else if ( aBtnDown.IsChecked() )        theFillDir = FILL_TO_BOTTOM;
    else if ( aBtnUp.IsChecked() )          theFillDir = FILL_TO_TOP;

    if ( aBtnArithmetic.IsChecked() )       theFillCmd = FILL_LINEAR;
    else if ( aBtnGeometric.IsChecked() )   theFillCmd = FILL_GROWTH;
    else if ( aBtnDate.IsChecked() )        theFillCmd = FILL_DATE;
    else if ( aBtnAutoFill.IsChecked() )    theFillCmd = FILL_AUTO;

    if ( aBtnDay.IsChecked() )              theFillDateCmd = FILL_DAY;
    else if ( aBtnDayOfWeek.IsChecked() )   theFillDateCmd = FILL_WEEKDAY;
    else if ( aBtnMonth.IsChecked() )       theFillDateCmd = FILL_MONTH;
    else if ( aBtnYear.IsChecked() )        theFillDateCmd = FILL_YEAR;

    BOOL  bAllOk = TRUE;
    Edit* pEdWrong;
    if ( !CheckStartVal() )
    {
        bAllOk = FALSE;
        pEdWrong = &aEdStartVal;
    }
    else if ( !CheckIncrementVal() )
    {
        bAllOk = FALSE;
        pEdWrong = &aEdIncrement;
    }
    else if ( !CheckEndVal() )
    {
        bAllOk = FALSE;
        pEdWrong = &aEdEndVal;
    }
    if ( bAllOk )
        EndDialog( RET_OK );
    else
    {
        ErrorBox( this,
                  WinBits( WB_OK | WB_DEF_OK ),
                  errMsgInvalidVal
                ).Execute();
        pEdWrong->GrabFocus();
    }

    return 0;
}

<commit_msg>INTEGRATION: CWS numberformat (1.5.44); FILE MERGED 2005/10/26 17:52:42 kendy 1.5.44.1: #i55546# The ULONG -> sal_uInt32 patches related to NumberFormat extracted from ooo64bit02 CWS.<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: filldlg.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: rt $ $Date: 2005-12-14 15:10:33 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#undef SC_DLLIMPLEMENTATION

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

#pragma hdrstop

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

#include <svtools/zforlist.hxx>
#include <vcl/msgbox.hxx>
#include <limits.h>

#include "scresid.hxx"
#include "document.hxx"
#include "miscdlgs.hrc"

#define _FILLDLG_CXX
#include "filldlg.hxx"
#undef _FILLDLG_CXX

//============================================================================
// class ScFillSeriesDlg

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

ScFillSeriesDlg::ScFillSeriesDlg( Window*       pParent,
                                  ScDocument&   rDocument,
                                  FillDir       eFillDir,
                                  FillCmd       eFillCmd,
                                  FillDateCmd   eFillDateCmd,
                                  String        aStartStr,
                                  double        fStep,
                                  double        fMax,
                                  USHORT        nPossDir )

    :   ModalDialog     ( pParent, ScResId( RID_SCDLG_FILLSERIES ) ),

        aFlDirection    ( this, ScResId( FL_DIRECTION ) ),
        aBtnLeft        ( this, ScResId( BTN_LEFT ) ),
        aBtnRight       ( this, ScResId( BTN_RIGHT ) ),
        aBtnUp          ( this, ScResId( BTN_TOP ) ),
        aBtnDown        ( this, ScResId( BTN_BOTTOM ) ),
        aFlSep1         ( this, ScResId( FL_SEP1 ) ),
        aFlType         ( this, ScResId( FL_TYPE ) ),
        aBtnArithmetic  ( this, ScResId( BTN_ARITHMETIC ) ),
        aBtnGeometric   ( this, ScResId( BTN_GEOMETRIC ) ),
        aBtnDate        ( this, ScResId( BTN_DATE ) ),
        aBtnAutoFill    ( this, ScResId( BTN_AUTOFILL ) ),
        aFlSep2         ( this, ScResId( FL_SEP2 ) ),
        aFlTimeUnit     ( this, ScResId( FL_TIME_UNIT ) ),
        aBtnDay         ( this, ScResId( BTN_DAY ) ),
        aBtnDayOfWeek   ( this, ScResId( BTN_DAY_OF_WEEK ) ),
        aBtnMonth       ( this, ScResId( BTN_MONTH ) ),
        aBtnYear        ( this, ScResId( BTN_YEAR ) ),

        aFtStartVal     ( this, ScResId( FT_START_VALUE ) ),
        aEdStartVal     ( this, ScResId( ED_START_VALUES ) ),
        aFtEndVal       ( this, ScResId( FT_END_VALUE ) ),
        aEdEndVal       ( this, ScResId( ED_END_VALUES ) ),
        aFtIncrement    ( this, ScResId( FT_INCREMENT ) ),
        aEdIncrement    ( this, ScResId( ED_INCREMENT ) ),

        aBtnOk          ( this, ScResId( BTN_OK ) ),
        aBtnCancel      ( this, ScResId( BTN_CANCEL ) ),
        aBtnHelp        ( this, ScResId( BTN_HELP ) ),
        errMsgInvalidVal( ScResId( STR_VALERR ) ),
        rDoc            ( rDocument ),
        theFillDir      ( eFillDir ),
        theFillCmd      ( eFillCmd ),
        theFillDateCmd  ( eFillDateCmd ),
        aStartStrVal    ( aStartStr),
        fIncrement      ( fStep ),
        fEndVal         ( fMax )
{
    Init( nPossDir );
    FreeResource();
}

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

__EXPORT ScFillSeriesDlg::~ScFillSeriesDlg()
{
}

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

void ScFillSeriesDlg::SetEdStartValEnabled(BOOL bFlag)
{
    bStartValFlag=bFlag;
    if(bFlag)
    {
       aFtStartVal.Enable();
       aEdStartVal.Enable();
    }
    else
    {
       aFtStartVal.Disable();
       aEdStartVal.Disable();
    }
}

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

void ScFillSeriesDlg::Init( USHORT nPossDir )
{
    aBtnOk.SetClickHdl         ( LINK( this, ScFillSeriesDlg, OKHdl ) );
    aBtnArithmetic.SetClickHdl ( LINK( this, ScFillSeriesDlg, DisableHdl ) );
    aBtnGeometric.SetClickHdl  ( LINK( this, ScFillSeriesDlg, DisableHdl ) );
    aBtnDate.SetClickHdl       ( LINK( this, ScFillSeriesDlg, DisableHdl ) );
    aBtnAutoFill.SetClickHdl   ( LINK( this, ScFillSeriesDlg, DisableHdl ) );

    if( nPossDir == FDS_OPT_NONE )
    {
        aBtnLeft.Disable();
        aBtnRight.Disable();
        aBtnDown.Disable();
        aBtnUp.Disable();
    }

    if( nPossDir == FDS_OPT_HORZ )
    {
        aBtnDown.Disable();
        aBtnUp.Disable();
    }

    if( nPossDir == FDS_OPT_VERT )
    {
        aBtnLeft.Disable();
        aBtnRight.Disable();
    }

    switch ( theFillDir )
    {
        case FILL_TO_LEFT:      aBtnLeft.Check();   break;
        case FILL_TO_RIGHT:     aBtnRight.Check();  break;
        case FILL_TO_BOTTOM:    aBtnDown.Check();   break;
        case FILL_TO_TOP:       aBtnUp.Check();     break;
        default:
        break;
    }

    switch ( theFillCmd )
    {
        case FILL_LINEAR:
            aBtnArithmetic.Check();
            DisableHdl( &aBtnArithmetic );
            break;
        case FILL_GROWTH:
            aBtnGeometric.Check();
            DisableHdl( &aBtnGeometric );
            break;
        case FILL_DATE:
            aBtnDate.Check();
            DisableHdl( &aBtnDate );
            break;
        case FILL_AUTO:
            aBtnAutoFill.Check();
            DisableHdl( &aBtnAutoFill );
            break;
        default:
        break;
    }

    switch ( theFillDateCmd )
    {
        case FILL_DAY:          aBtnDay.Check();        break;
        case FILL_WEEKDAY:      aBtnDayOfWeek.Check();  break;
        case FILL_MONTH:        aBtnMonth.Check();      break;
        case FILL_YEAR:         aBtnYear.Check();       break;
        default:
        break;
    }

    fStartVal = MAXDOUBLE;
    /*
    String aStartTxt;
    if ( fStartVal != MAXDOUBLE )
        rDoc.GetFormatTable()->GetInputLineString( fStartVal, 0, aStartTxt );
    aEdStartVal.SetText( aStartTxt );
    */

    aEdStartVal.SetText( aStartStrVal);

    String aIncrTxt;
    rDoc.GetFormatTable()->GetInputLineString( fIncrement, 0, aIncrTxt );
    aEdIncrement.SetText( aIncrTxt );

    String aEndTxt;
    if ( fEndVal != MAXDOUBLE )
        rDoc.GetFormatTable()->GetInputLineString( fEndVal, 0, aEndTxt );
    aEdEndVal.SetText( aEndTxt );

    bStartValFlag=FALSE;

    aFlSep1.SetStyle( aFlSep1.GetStyle() | WB_VERT );
    aFlSep2.SetStyle( aFlSep2.GetStyle() | WB_VERT );
}

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

BOOL __EXPORT ScFillSeriesDlg::CheckStartVal()
{
    BOOL bValOk = FALSE;
    sal_uInt32 nKey = 0;
    String aStr( aEdStartVal.GetText() );

    if ( aStr.Len() == 0 || aBtnAutoFill.IsChecked())
    {
        fStartVal = MAXDOUBLE;
        bValOk = TRUE;
    }
    else
        bValOk = rDoc.GetFormatTable()->IsNumberFormat( aStr, nKey, fStartVal );

    return bValOk;
}

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

BOOL __EXPORT ScFillSeriesDlg::CheckIncrementVal()
{
    sal_uInt32 nKey = 0;
    String aStr( aEdIncrement.GetText() );

    return rDoc.GetFormatTable()->IsNumberFormat( aStr, nKey, fIncrement );
}

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

BOOL __EXPORT ScFillSeriesDlg::CheckEndVal()
{
    BOOL    bValOk = FALSE;
    sal_uInt32 nKey = 0;
    String  aStr( aEdEndVal.GetText() );

    if ( aStr.Len() == 0 )
    {
        fEndVal = (fIncrement < 0) ? -MAXDOUBLE : MAXDOUBLE;
        bValOk  = TRUE;
    }
    else
        bValOk = rDoc.GetFormatTable()->IsNumberFormat( aStr, nKey, fEndVal );

    return bValOk;
}

//----------------------------------------------------------------------------
// Handler:
//----------------------------------------------------------------------------

IMPL_LINK( ScFillSeriesDlg, DisableHdl, Button *, pBtn )
{
    if ( pBtn == &aBtnDate )
    {
        aBtnDay.Enable();
        aBtnDayOfWeek.Enable();
        aBtnMonth.Enable();
        aBtnYear.Enable();
        aFlTimeUnit.Enable();
    }
    else
    {
        aBtnDay.Disable();
        aBtnDayOfWeek.Disable();
        aBtnMonth.Disable();
        aBtnYear.Disable();
        aFlTimeUnit.Disable();
    }

    if ( pBtn != &aBtnAutoFill )
    {
        aFtIncrement.Enable();
        aEdIncrement.Enable();
        aFtEndVal.Enable();
        aEdEndVal.Enable();
    }
    else
    {
        aFtIncrement.Disable();
        aEdIncrement.Disable();
        aFtEndVal.Disable();
        aEdEndVal.Disable();
    }
    return 0;
}

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

IMPL_LINK( ScFillSeriesDlg, OKHdl, void *, EMPTYARG )
{
    if ( aBtnLeft.IsChecked() )             theFillDir = FILL_TO_LEFT;
    else if ( aBtnRight.IsChecked() )       theFillDir = FILL_TO_RIGHT;
    else if ( aBtnDown.IsChecked() )        theFillDir = FILL_TO_BOTTOM;
    else if ( aBtnUp.IsChecked() )          theFillDir = FILL_TO_TOP;

    if ( aBtnArithmetic.IsChecked() )       theFillCmd = FILL_LINEAR;
    else if ( aBtnGeometric.IsChecked() )   theFillCmd = FILL_GROWTH;
    else if ( aBtnDate.IsChecked() )        theFillCmd = FILL_DATE;
    else if ( aBtnAutoFill.IsChecked() )    theFillCmd = FILL_AUTO;

    if ( aBtnDay.IsChecked() )              theFillDateCmd = FILL_DAY;
    else if ( aBtnDayOfWeek.IsChecked() )   theFillDateCmd = FILL_WEEKDAY;
    else if ( aBtnMonth.IsChecked() )       theFillDateCmd = FILL_MONTH;
    else if ( aBtnYear.IsChecked() )        theFillDateCmd = FILL_YEAR;

    BOOL  bAllOk = TRUE;
    Edit* pEdWrong;
    if ( !CheckStartVal() )
    {
        bAllOk = FALSE;
        pEdWrong = &aEdStartVal;
    }
    else if ( !CheckIncrementVal() )
    {
        bAllOk = FALSE;
        pEdWrong = &aEdIncrement;
    }
    else if ( !CheckEndVal() )
    {
        bAllOk = FALSE;
        pEdWrong = &aEdEndVal;
    }
    if ( bAllOk )
        EndDialog( RET_OK );
    else
    {
        ErrorBox( this,
                  WinBits( WB_OK | WB_DEF_OK ),
                  errMsgInvalidVal
                ).Execute();
        pEdWrong->GrabFocus();
    }

    return 0;
}

<|endoftext|>


<commit_before>//Copyright (c) 2018 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "utils/linearAlg2D.h" //Distance from point to line.
#include "MergeInfillLines.h"

namespace cura
{

    MergeInfillLines::MergeInfillLines(ExtruderPlan& plan, const coord_t nozzle_size, const coord_t maximum_resolution) : extruder_plan(plan), nozzle_size(nozzle_size), maximum_resolution(maximum_resolution)
    {
        //Just copy the parameters to their fields.
    }

    coord_t MergeInfillLines::calcPathLength(const Point path_start, GCodePath& path) const
    {
        Point previous_point = path_start;
        coord_t result = 0;
        for (const Point point : path.points)
        {
            result += vSize(point - previous_point);
            previous_point = point;
        }
        return result;
    }

    /*
     * first_is_already_merged == false
     *
     *       o     o
     *      /     /
     *     /     /
     *    /  +  /      --->   -(t)-o-----o
     *   /     /
     *  /     /
     * o     o
     *
     * travel (t) to first location is done through first_path_start_changed and new_first_path_start.
     * this gets rid of the tiny "blips". Depending on the merged line distance a small gap may appear, but this is
     * accounted for in the volume.
     *
     * first_is_already_merged == true
     *
     *                   o
     *                  /
     *                 /
     *    o-----o  +  /     --->    o-----------o   or with slight   o-----o-----o
     *   /           /             /                   bend         /
     *  /           /             /                                /
     * o           o             o                                o
     *
     */
    bool MergeInfillLines::mergeLinesSideBySide(const bool first_is_already_merged, GCodePath& first_path, const Point first_path_start, GCodePath& second_path, const Point second_path_start, Point& new_first_path_start, coord_t& error_area) const
    {
        Point average_first_path;

        coord_t first_path_length = calcPathLength(first_path_start, first_path);
        coord_t first_path_length_flow = first_path_length * first_path.flow; //To get the volume we don't need to include the line width since it's the same for both lines.
        const coord_t line_width = first_path.config->getLineWidth();

        if (first_is_already_merged)
        {
            // take second point of path, first_path.points[0]
            average_first_path = first_path.points[0];
        }
        else
        {
            average_first_path += first_path_start;
            for (const Point point : first_path.points)
            {
                average_first_path += point;
            }
            average_first_path /= (first_path.points.size() + 1);
        }

        coord_t second_path_length = calcPathLength(second_path_start, second_path);
        Point average_second_path = second_path_start;
        for (const Point point : second_path.points)
        {
            average_second_path += point;
        }
        coord_t second_path_length_flow = second_path_length *= second_path.flow;
        average_second_path /= (coord_t) (second_path.points.size() + 1);

        // predict new length and flow and if the new flow is to big, don't merge. conditions in this part must exactly match the actual merging
        coord_t new_path_length = first_path_length;
        coord_t dist2_from_line = 0;
        coord_t new_error_area = 0;
        coord_t merged_part_length = 0;
        if (first_is_already_merged)
        {
            // check if the new point is a good extension of last part of existing polyline
            // because of potential accumulation of errors introduced each time a line is merged, we do not allow any error.
            if (first_path.points.size() > 1) {
                dist2_from_line = LinearAlg2D::getDist2FromLine(average_second_path, first_path.points[first_path.points.size() - 2], first_path.points[first_path.points.size() - 1]);
                merged_part_length = vSize(first_path.points[first_path.points.size() - 2] - average_second_path);
                new_error_area = sqrt(dist2_from_line) * merged_part_length / 2;
            }
            // The max error margin uses the meshfix_maximum_resolution setting
            if (first_path.points.size() > 1 && error_area + new_error_area < merged_part_length * maximum_resolution)
            {
                new_path_length -= vSize(first_path.points[first_path.points.size() - 2] - first_path.points[first_path.points.size() - 1]);
                new_path_length += vSize(first_path.points[first_path.points.size() - 2] - average_second_path);
            }
            else
            {
                new_path_length += vSize(first_path.points[first_path.points.size() - 1] - average_second_path);
            }
        }
        else
        {
            new_path_length -= vSize(first_path.points.back() - first_path_start);
            new_path_length += vSize(average_second_path - average_first_path);
        }
        double new_flow = ((first_path_length_flow + second_path_length_flow) / static_cast<double>(new_path_length));
        if (new_flow > 2 * nozzle_size / line_width)  // line width becomes too wide.
        {
            return false;
        }

        // do the actual merging
        if (first_is_already_merged)
        {
            // check if the new point is a good extension of last part of existing polyline
            // because of potential accumulation of errors introduced each time a line is merged, we do not allow any error.
            if (first_path.points.size() > 1 && error_area + new_error_area < line_width * line_width)
            {
                first_path.points[first_path.points.size() - 1] = average_second_path;
                error_area += new_error_area;
            } else {
                first_path.points.push_back(average_second_path);
                error_area = 0;
            }
        }
        else
        {
            new_first_path_start = average_first_path;
            first_path.points.clear();
            first_path.points.push_back(average_second_path);
            error_area = 0;
        }

        first_path.flow = static_cast<double>(first_path_length_flow + second_path_length_flow) / new_path_length;

        return true;
    }

    bool MergeInfillLines::tryMerge(const bool first_is_already_merged, GCodePath& first_path, const Point first_path_start, GCodePath& second_path, const Point second_path_start, Point& new_first_path_start, coord_t& error_area) const
    {
        const Point first_path_end = first_path.points.back();
        const Point second_path_end = second_path.points.back();
        const coord_t line_width = first_path.config->getLineWidth();

        // Reintroduction of this check prevents [CURA-5674] printing spurious infill-lines to origin:
        const coord_t line_width_squared = line_width * line_width;
        if (vSize2(first_path_end - second_path_start) < line_width_squared && vSize2(first_path_start - second_path_end) < line_width_squared)
        {
            return false;
        }

        //Lines may be adjacent side-by-side then.
        Point first_path_leave_point;
        coord_t merged_size2;
        if (first_is_already_merged)
        {
            first_path_leave_point = first_path.points.back();  // this is the point that's going to merge
        } else {
            first_path_leave_point = (first_path_start + first_path_end) / 2;
        }
        const Point second_path_destination_point = (second_path_start + second_path_end) / 2;
        const Point merged_direction = second_path_destination_point - first_path_leave_point;
        if (first_is_already_merged)
        {
            merged_size2 = vSize2(second_path_destination_point - first_path.points.back());  // check distance with last point in merged line that is to be replaced
        }
        else
        {
            merged_size2 = vSize2(merged_direction);
        }
        if (merged_size2 > 25 * line_width * line_width)
        {
            return false; //Lines are too far away from each other.
        }
        if (merged_direction.X == 0 && merged_direction.Y == 0)
        {
            return true;  // we can just disregard the second point as it's exactly at the leave point of the first path.
        }

        // Max 1 line width to the side of the merged_direction
        if (LinearAlg2D::getDist2FromLine(first_path_end, second_path_destination_point, second_path_destination_point + merged_direction) > line_width * line_width
            || LinearAlg2D::getDist2FromLine(second_path_start, first_path_leave_point, first_path_leave_point + merged_direction) > line_width * line_width
            || LinearAlg2D::getDist2FromLine(second_path_end,   first_path_leave_point, first_path_leave_point + merged_direction) > line_width * line_width
            //|| abs(dot(normal(merged_direction, 1000), normal(second_path_end - second_path_start, 1000))) > 866000    // 866000 angle of old second_path with new merged direction should not be too small (30 degrees), as it will introduce holes
            )
        {
            return false; //One of the lines is too far from the merged line. Lines would be too wide or too far off.
        }
        if (first_is_already_merged && first_path.points.size() > 1 && first_path.points[first_path.points.size() - 2] == second_path_destination_point)  // yes this can actually happen
        {
            return false;
        }

        return mergeLinesSideBySide(first_is_already_merged, first_path, first_path_start, second_path, second_path_start, new_first_path_start, error_area);
    }

    bool MergeInfillLines::mergeInfillLines(std::vector<GCodePath>& paths, const Point& starting_position) const
    {
        /* Algorithm overview:
            1. Loop over all lines to see if they can be merged.
            1a. Check if two adjacent lines can be merged (skipping travel moves in
                between).
            1b. If they can, merge both lines into the first line.
            1c. If they are merged, check next that the first line can be merged
                with the line after the second line.
            2. Do a second iteration over all paths to remove the tombstones. */
        std::vector<size_t> remove_path_indices;
        std::set<size_t> is_merged;
        std::set<size_t> removed;  // keep track of what we already removed, so don't remove it again

        //For each two adjacent lines, see if they can be merged.
        size_t first_path_index = 0;
        Point first_path_start = Point(starting_position.X, starting_position.Y);  // this one is not going to be overwritten
        size_t second_path_index = 1;
        coord_t error_area = 0;

        for (; second_path_index < paths.size(); second_path_index++)
        {
            GCodePath& first_path = paths[first_path_index];
            GCodePath& second_path = paths[second_path_index];
            Point second_path_start = paths[second_path_index - 1].points.back();

            if (second_path.config->isTravelPath())
            {
                continue; //Skip travel paths, we're looking for the first non-travel path.
            }

            bool allow_try_merge = true;
            // see if we meet criteria to merge. should be: travel - path1 not travel - (...) - travel - path2 not travel - travel
            // we're checking the travels here
            if (first_path_index <= 1 || !paths[first_path_index - 1].isTravelPath())  // "<= 1" because we don't want the first travel being changed. That may introduce a hole somewhere
            {
                allow_try_merge = false;
            }
            if (second_path_index + 1 >= paths.size() || !paths[second_path_index + 1].isTravelPath())
            {
                allow_try_merge = false;
            }
            if (first_path.config->isTravelPath()) //Don't merge travel moves.
            {
                allow_try_merge = false;
            }
            if (first_path.config != second_path.config) //Only merge lines that have the same type.
            {
                allow_try_merge = false;
            }
            if (first_path.config->type != PrintFeatureType::Infill && first_path.config->type != PrintFeatureType::Skin) //Only merge skin and infill lines.
            {
                allow_try_merge = false;
            }
            const bool first_is_already_merged = is_merged.find(first_path_index) != is_merged.end();
            if ((!first_is_already_merged && first_path.points.size() > 1) || second_path.points.size() > 1)
            {
                // For now we only merge simple lines, not polylines, to keep it simple.
                // If the first line is already a merged line, then allow it.
                allow_try_merge = false;
            }

            Point new_first_path_start;
            if (allow_try_merge && tryMerge(first_is_already_merged, first_path, first_path_start, second_path, second_path_start, new_first_path_start, error_area))
            {
                if (!first_is_already_merged)
                {
                    paths[first_path_index - 1].points.back().X = new_first_path_start.X;
                    paths[first_path_index - 1].points.back().Y = new_first_path_start.Y;
                }
                /* If we combine two lines, the next path may also be merged into the fist line, so we do NOT update
                first_path_index. */
                for (size_t to_delete_index = first_path_index + 1; to_delete_index <= second_path_index; to_delete_index++)
                {
                    if (removed.find(to_delete_index) == removed.end())  // if there are line(s) between first and second, then those lines are already marked as to be deleted, only add the new line(s)
                    {
                        remove_path_indices.push_back(to_delete_index);
                        removed.insert(to_delete_index);
                    }
                }
                is_merged.insert(first_path_index);
            }
            else
            {
                /* If we do not combine, the next iteration we must simply merge the
                second path with the line after it. */
                first_path_index = second_path_index;
                first_path_start = second_path_start;
            }
        }

        //Delete all removed lines in one pass so that we need to move lines less often.
        if (!remove_path_indices.empty())
        {
            size_t path_index = remove_path_indices[0];
            for (size_t removed_position = 1; removed_position < remove_path_indices.size(); removed_position++)
            {
                for (; path_index < remove_path_indices[removed_position] - removed_position; path_index++)
                {
                    paths[path_index] = paths[path_index + removed_position]; //Shift all paths.
                }
            }
            for (; path_index < paths.size() - remove_path_indices.size(); path_index++) //Remaining shifts at the end.
            {
                paths[path_index] = paths[path_index + remove_path_indices.size()];
            }
            paths.erase(paths.begin() + path_index, paths.end());
            return true;
        }
        else
        {
            return false;
        }
    }
}//namespace cura
<commit_msg>Fix printing lines to origin in rare cases.<commit_after>//Copyright (c) 2018 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "utils/linearAlg2D.h" //Distance from point to line.
#include "MergeInfillLines.h"

namespace cura
{

    MergeInfillLines::MergeInfillLines(ExtruderPlan& plan, const coord_t nozzle_size, const coord_t maximum_resolution) : extruder_plan(plan), nozzle_size(nozzle_size), maximum_resolution(maximum_resolution)
    {
        //Just copy the parameters to their fields.
    }

    coord_t MergeInfillLines::calcPathLength(const Point path_start, GCodePath& path) const
    {
        Point previous_point = path_start;
        coord_t result = 0;
        for (const Point point : path.points)
        {
            result += vSize(point - previous_point);
            previous_point = point;
        }
        return result;
    }

    /*
     * first_is_already_merged == false
     *
     *       o     o
     *      /     /
     *     /     /
     *    /  +  /      --->   -(t)-o-----o
     *   /     /
     *  /     /
     * o     o
     *
     * travel (t) to first location is done through first_path_start_changed and new_first_path_start.
     * this gets rid of the tiny "blips". Depending on the merged line distance a small gap may appear, but this is
     * accounted for in the volume.
     *
     * first_is_already_merged == true
     *
     *                   o
     *                  /
     *                 /
     *    o-----o  +  /     --->    o-----------o   or with slight   o-----o-----o
     *   /           /             /                   bend         /
     *  /           /             /                                /
     * o           o             o                                o
     *
     */
    bool MergeInfillLines::mergeLinesSideBySide(const bool first_is_already_merged, GCodePath& first_path, const Point first_path_start, GCodePath& second_path, const Point second_path_start, Point& new_first_path_start, coord_t& error_area) const
    {
        Point average_first_path;

        coord_t first_path_length = calcPathLength(first_path_start, first_path);
        coord_t first_path_length_flow = first_path_length * first_path.flow; //To get the volume we don't need to include the line width since it's the same for both lines.
        const coord_t line_width = first_path.config->getLineWidth();

        if (first_is_already_merged)
        {
            // take second point of path, first_path.points[0]
            average_first_path = first_path.points[0];
        }
        else
        {
            average_first_path += first_path_start;
            for (const Point point : first_path.points)
            {
                average_first_path += point;
            }
            average_first_path /= (first_path.points.size() + 1);
        }

        coord_t second_path_length = calcPathLength(second_path_start, second_path);
        Point average_second_path = second_path_start;
        for (const Point point : second_path.points)
        {
            average_second_path += point;
        }
        coord_t second_path_length_flow = second_path_length *= second_path.flow;
        average_second_path /= (coord_t) (second_path.points.size() + 1);

        // predict new length and flow and if the new flow is to big, don't merge. conditions in this part must exactly match the actual merging
        coord_t new_path_length = first_path_length;
        coord_t dist2_from_line = 0;
        coord_t new_error_area = 0;
        coord_t merged_part_length = 0;
        if (first_is_already_merged)
        {
            // check if the new point is a good extension of last part of existing polyline
            // because of potential accumulation of errors introduced each time a line is merged, we do not allow any error.
            if (first_path.points.size() > 1) {
                dist2_from_line = LinearAlg2D::getDist2FromLine(average_second_path, first_path.points[first_path.points.size() - 2], first_path.points[first_path.points.size() - 1]);
                merged_part_length = vSize(first_path.points[first_path.points.size() - 2] - average_second_path);
                new_error_area = sqrt(dist2_from_line) * merged_part_length / 2;
            }
            // The max error margin uses the meshfix_maximum_resolution setting
            if (first_path.points.size() > 1 && error_area + new_error_area < merged_part_length * maximum_resolution)
            {
                new_path_length -= vSize(first_path.points[first_path.points.size() - 2] - first_path.points[first_path.points.size() - 1]);
                new_path_length += vSize(first_path.points[first_path.points.size() - 2] - average_second_path);
            }
            else
            {
                new_path_length += vSize(first_path.points[first_path.points.size() - 1] - average_second_path);
            }
        }
        else
        {
            new_path_length -= vSize(first_path.points.back() - first_path_start);
            new_path_length += vSize(average_second_path - average_first_path);
        }
        double new_flow = ((first_path_length_flow + second_path_length_flow) / static_cast<double>(new_path_length));
        if (new_flow > 2 * nozzle_size / line_width)  // line width becomes too wide.
        {
            return false;
        }

        // do the actual merging
        if (first_is_already_merged)
        {
            // check if the new point is a good extension of last part of existing polyline
            // because of potential accumulation of errors introduced each time a line is merged, we do not allow any error.
            if (first_path.points.size() > 1 && error_area + new_error_area < line_width * line_width)
            {
                first_path.points[first_path.points.size() - 1] = average_second_path;
                error_area += new_error_area;
            } else {
                first_path.points.push_back(average_second_path);
                error_area = 0;
            }
        }
        else
        {
            new_first_path_start = average_first_path;
            first_path.points.clear();
            first_path.points.push_back(average_second_path);
            error_area = 0;
        }

        first_path.flow = static_cast<double>(first_path_length_flow + second_path_length_flow) / new_path_length;

        return true;
    }

    bool MergeInfillLines::tryMerge(const bool first_is_already_merged, GCodePath& first_path, const Point first_path_start, GCodePath& second_path, const Point second_path_start, Point& new_first_path_start, coord_t& error_area) const
    {
        const Point first_path_end = first_path.points.back();
        const Point second_path_end = second_path.points.back();
        const coord_t line_width = first_path.config->getLineWidth();

        // Reintroduction of this check prevents [CURA-5674] printing spurious infill-lines to origin:
        const coord_t line_width_squared = line_width * line_width;
        if (vSize2(first_path_end - second_path_start) < line_width_squared && vSize2(first_path_start - second_path_end) < line_width_squared)
        {
            return false;
        }

        //Lines may be adjacent side-by-side then.
        Point first_path_leave_point;
        coord_t merged_size2;
        if (first_is_already_merged)
        {
            first_path_leave_point = first_path.points.back();  // this is the point that's going to merge
        } else {
            first_path_leave_point = (first_path_start + first_path_end) / 2;
        }
        const Point second_path_destination_point = (second_path_start + second_path_end) / 2;
        const Point merged_direction = second_path_destination_point - first_path_leave_point;
        if (first_is_already_merged)
        {
            merged_size2 = vSize2(second_path_destination_point - first_path.points.back());  // check distance with last point in merged line that is to be replaced
        }
        else
        {
            merged_size2 = vSize2(merged_direction);
        }
        if (merged_size2 > 25 * line_width * line_width)
        {
            return false; //Lines are too far away from each other.
        }
        if (merged_direction.X == 0 && merged_direction.Y == 0)
        {
            new_first_path_start = first_path_start;
            return true;  // we can just disregard the second point as it's exactly at the leave point of the first path.
        }

        // Max 1 line width to the side of the merged_direction
        if (LinearAlg2D::getDist2FromLine(first_path_end, second_path_destination_point, second_path_destination_point + merged_direction) > line_width * line_width
            || LinearAlg2D::getDist2FromLine(second_path_start, first_path_leave_point, first_path_leave_point + merged_direction) > line_width * line_width
            || LinearAlg2D::getDist2FromLine(second_path_end,   first_path_leave_point, first_path_leave_point + merged_direction) > line_width * line_width
            //|| abs(dot(normal(merged_direction, 1000), normal(second_path_end - second_path_start, 1000))) > 866000    // 866000 angle of old second_path with new merged direction should not be too small (30 degrees), as it will introduce holes
            )
        {
            return false; //One of the lines is too far from the merged line. Lines would be too wide or too far off.
        }
        if (first_is_already_merged && first_path.points.size() > 1 && first_path.points[first_path.points.size() - 2] == second_path_destination_point)  // yes this can actually happen
        {
            return false;
        }

        return mergeLinesSideBySide(first_is_already_merged, first_path, first_path_start, second_path, second_path_start, new_first_path_start, error_area);
    }

    bool MergeInfillLines::mergeInfillLines(std::vector<GCodePath>& paths, const Point& starting_position) const
    {
        /* Algorithm overview:
            1. Loop over all lines to see if they can be merged.
            1a. Check if two adjacent lines can be merged (skipping travel moves in
                between).
            1b. If they can, merge both lines into the first line.
            1c. If they are merged, check next that the first line can be merged
                with the line after the second line.
            2. Do a second iteration over all paths to remove the tombstones. */
        std::vector<size_t> remove_path_indices;
        std::set<size_t> is_merged;
        std::set<size_t> removed;  // keep track of what we already removed, so don't remove it again

        //For each two adjacent lines, see if they can be merged.
        size_t first_path_index = 0;
        Point first_path_start = Point(starting_position.X, starting_position.Y);  // this one is not going to be overwritten
        size_t second_path_index = 1;
        coord_t error_area = 0;

        for (; second_path_index < paths.size(); second_path_index++)
        {
            GCodePath& first_path = paths[first_path_index];
            GCodePath& second_path = paths[second_path_index];
            Point second_path_start = paths[second_path_index - 1].points.back();

            if (second_path.config->isTravelPath())
            {
                continue; //Skip travel paths, we're looking for the first non-travel path.
            }

            bool allow_try_merge = true;
            // see if we meet criteria to merge. should be: travel - path1 not travel - (...) - travel - path2 not travel - travel
            // we're checking the travels here
            if (first_path_index <= 1 || !paths[first_path_index - 1].isTravelPath())  // "<= 1" because we don't want the first travel being changed. That may introduce a hole somewhere
            {
                allow_try_merge = false;
            }
            if (second_path_index + 1 >= paths.size() || !paths[second_path_index + 1].isTravelPath())
            {
                allow_try_merge = false;
            }
            if (first_path.config->isTravelPath()) //Don't merge travel moves.
            {
                allow_try_merge = false;
            }
            if (first_path.config != second_path.config) //Only merge lines that have the same type.
            {
                allow_try_merge = false;
            }
            if (first_path.config->type != PrintFeatureType::Infill && first_path.config->type != PrintFeatureType::Skin) //Only merge skin and infill lines.
            {
                allow_try_merge = false;
            }
            const bool first_is_already_merged = is_merged.find(first_path_index) != is_merged.end();
            if ((!first_is_already_merged && first_path.points.size() > 1) || second_path.points.size() > 1)
            {
                // For now we only merge simple lines, not polylines, to keep it simple.
                // If the first line is already a merged line, then allow it.
                allow_try_merge = false;
            }

            Point new_first_path_start;
            if (allow_try_merge && tryMerge(first_is_already_merged, first_path, first_path_start, second_path, second_path_start, new_first_path_start, error_area))
            {
                if (!first_is_already_merged)
                {
                    paths[first_path_index - 1].points.back().X = new_first_path_start.X;
                    paths[first_path_index - 1].points.back().Y = new_first_path_start.Y;
                }
                /* If we combine two lines, the next path may also be merged into the fist line, so we do NOT update
                first_path_index. */
                for (size_t to_delete_index = first_path_index + 1; to_delete_index <= second_path_index; to_delete_index++)
                {
                    if (removed.find(to_delete_index) == removed.end())  // if there are line(s) between first and second, then those lines are already marked as to be deleted, only add the new line(s)
                    {
                        remove_path_indices.push_back(to_delete_index);
                        removed.insert(to_delete_index);
                    }
                }
                is_merged.insert(first_path_index);
            }
            else
            {
                /* If we do not combine, the next iteration we must simply merge the
                second path with the line after it. */
                first_path_index = second_path_index;
                first_path_start = second_path_start;
            }
        }

        //Delete all removed lines in one pass so that we need to move lines less often.
        if (!remove_path_indices.empty())
        {
            size_t path_index = remove_path_indices[0];
            for (size_t removed_position = 1; removed_position < remove_path_indices.size(); removed_position++)
            {
                for (; path_index < remove_path_indices[removed_position] - removed_position; path_index++)
                {
                    paths[path_index] = paths[path_index + removed_position]; //Shift all paths.
                }
            }
            for (; path_index < paths.size() - remove_path_indices.size(); path_index++) //Remaining shifts at the end.
            {
                paths[path_index] = paths[path_index + remove_path_indices.size()];
            }
            paths.erase(paths.begin() + path_index, paths.end());
            return true;
        }
        else
        {
            return false;
        }
    }
}//namespace cura
<|endoftext|>


<commit_before>/* Siconos-Kernel, Copyright INRIA 2005-2010.
 * Siconos is a program dedicated to modeling, simulation and control
 * of non smooth dynamical systems.
 * Siconos is a free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * Siconos 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Siconos; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Contact: Vincent ACARY, siconos-team@lists.gforge.inria.fr
 */
/*! \file NewtonEulerR.h

*/
#ifndef NEWTONEULERIMPACT_H
#define NEWTONEULERIMPACT_H

#include "NewtonEulerR.hpp"

/** NewtonEulerRImpact
 *
 * \author O. Bonnefon
 *  \version 3.0.0.
 *  \date Dec, 2010
 *
 * This class is an interface for a relation with impact.  It
 * implements the computation of the jacoboian of h from the points of
 * contacts and the normal.  Use this class consists in overloading
 * the method computeh, by setting the menber pc1, pc2, nc and y.  The
 * matrix jachq is used both for the building of the OSNSP (with T)
 * and for the predictor of activation of deactivation of the UR.
*
 */

class NewtonEulerRImpact : public NewtonEulerR
{
protected:
  /*Point of contact*/
  SP::SimpleVector _Pc1;
  SP::SimpleVector _Pc2;

  /*Inward Normal at the contact */
  SP::SimpleVector _Nc;

  // /*because set is not sorted!*/
  // SP::NewtonEulerDS _ds1;
  // SP::NewtonEulerDS _ds2;
  virtual void initComponents();

public:

  bool _isOnContact;
  NewtonEulerRImpact():
    NewtonEulerR(), cd _Pc1(new SimpleVector(3)), _Pc2(new SimpleVector(3)),
    _Nc(new SimpleVector(3))
  {
    /*_ds1=NULL;_ds2=NULL;*/
  }

  // inline void setDs1(SP::NewtonEulerDS ds1){_ds1=ds1;}
  // inline void setDs2(SP::NewtonEulerDS ds2){_ds2=ds2;}
  // inline SP::NewtonEulerDS ds1(){return _ds1;}
  // inline SP::NewtonEulerDS ds2(){return _ds2;}

  /** destructor
   */
  virtual ~NewtonEulerRImpact() {};

  virtual void computeJachq(double t);
  virtual void computeJachqT();

  inline SP::SimpleVector pc1()
  {
    return _Pc1;
  }
  inline SP::SimpleVector pc2()
  {
    return _Pc2;
  }
  inline SP::SimpleVector nc()
  {
    return _Nc;
  }

  /** set the coordinates of first contact point
   * \param SP::SimpleVector new coordinates
   */
  void setpc1(SP::SimpleVector npc)
  {
    _Pc1 = npc;
  };

  /** set the coordinates of second contact point
   * \param SP::SimpleVector new coordinates
   */
  void setpc2(SP::SimpleVector npc)
  {
    _Pc2 = npc;
  };

  /** set the coordinates of inside normal vector at the contact point
   * \param SP::SimpleVector new coordinates
   */
  void setnc(SP::SimpleVector nnc)
  {
    _Nc = nnc;
  };

  // visitors hook
  ACCEPT_STD_VISITORS();

};
TYPEDEF_SPTR(NewtonEulerRImpact);
#endif // NEWTONEULERRIMPACT_H
<commit_msg>cd compil on mac? Joke<commit_after>/* Siconos-Kernel, Copyright INRIA 2005-2010.
 * Siconos is a program dedicated to modeling, simulation and control
 * of non smooth dynamical systems.
 * Siconos is a free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * Siconos 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Siconos; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Contact: Vincent ACARY, siconos-team@lists.gforge.inria.fr
 */
/*! \file NewtonEulerR.h

*/
#ifndef NEWTONEULERIMPACT_H
#define NEWTONEULERIMPACT_H

#include "NewtonEulerR.hpp"

/** NewtonEulerRImpact
 *
 * \author O. Bonnefon
 *  \version 3.0.0.
 *  \date Dec, 2010
 *
 * This class is an interface for a relation with impact.  It
 * implements the computation of the jacoboian of h from the points of
 * contacts and the normal.  Use this class consists in overloading
 * the method computeh, by setting the menber pc1, pc2, nc and y.  The
 * matrix jachq is used both for the building of the OSNSP (with T)
 * and for the predictor of activation of deactivation of the UR.
*
 */

class NewtonEulerRImpact : public NewtonEulerR
{
protected:
  /*Point of contact*/
  SP::SimpleVector _Pc1;
  SP::SimpleVector _Pc2;

  /*Inward Normal at the contact */
  SP::SimpleVector _Nc;

  // /*because set is not sorted!*/
  // SP::NewtonEulerDS _ds1;
  // SP::NewtonEulerDS _ds2;
  virtual void initComponents();

public:

  bool _isOnContact;
  NewtonEulerRImpact():
    NewtonEulerR(), _Pc1(new SimpleVector(3)), _Pc2(new SimpleVector(3)),
    _Nc(new SimpleVector(3))
  {
    /*_ds1=NULL;_ds2=NULL;*/
  }

  // inline void setDs1(SP::NewtonEulerDS ds1){_ds1=ds1;}
  // inline void setDs2(SP::NewtonEulerDS ds2){_ds2=ds2;}
  // inline SP::NewtonEulerDS ds1(){return _ds1;}
  // inline SP::NewtonEulerDS ds2(){return _ds2;}

  /** destructor
   */
  virtual ~NewtonEulerRImpact() {};

  virtual void computeJachq(double t);
  virtual void computeJachqT();

  inline SP::SimpleVector pc1()
  {
    return _Pc1;
  }
  inline SP::SimpleVector pc2()
  {
    return _Pc2;
  }
  inline SP::SimpleVector nc()
  {
    return _Nc;
  }

  /** set the coordinates of first contact point
   * \param SP::SimpleVector new coordinates
   */
  void setpc1(SP::SimpleVector npc)
  {
    _Pc1 = npc;
  };

  /** set the coordinates of second contact point
   * \param SP::SimpleVector new coordinates
   */
  void setpc2(SP::SimpleVector npc)
  {
    _Pc2 = npc;
  };

  /** set the coordinates of inside normal vector at the contact point
   * \param SP::SimpleVector new coordinates
   */
  void setnc(SP::SimpleVector nnc)
  {
    _Nc = nnc;
  };

  // visitors hook
  ACCEPT_STD_VISITORS();

};
TYPEDEF_SPTR(NewtonEulerRImpact);
#endif // NEWTONEULERRIMPACT_H
<|endoftext|>


<commit_before>/* Siconos-Example version 3.0.0, Copyright INRIA 2005-2010.
 * Siconos is a program dedicated to modeling, simulation and control
 * of non smooth dynamical systems.
 * Siconos is a free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * Siconos 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Siconos; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth FLOOR, Boston, MA  02110-1301  USA
 *
 * Contact: Vincent ACARY, siconos-team@lists.gforge.inria.fr
 *
 */

#include <math.h>
#include "SphereLDSPlanR.hpp"

SphereLDSPlanR::SphereLDSPlanR(double r, double A, double B, double C, double D)
  : LagrangianScleronomousR(), r(r), A(A), B(B), C(C), D(D)
{
  nN = sqrt(A * A + B * B + C * C);

  n1 = A / nN;
  n2 = B / nN;
  n3 = C / nN;

  nU = sqrt((A + B) * (A + B) + (B - C) * (B - C) + (A + C) * (A + C));
  u1 = (B - C) / nU;
  u2 = -(A + C) / nU;
  u3 = (A + B) / nU;

  // v = n /\ u

  v1 = B * (A + B) / (nN * nU) - C * (-A - C) / (nN * nU);
  v2 = C * (B - C) / (nN * nU) - A * (A + B) / (nN * nU);
  v3 = A * (-A - C) / (nN * nU) - B * (B - C) / (nN * nU);

  // r*u & r *v

  ru1 = r * u1;
  ru2 = r * u2;
  ru3 = r * u3;

  rv1 = r * v1;
  rv2 = r * v2;
  rv3 = r * v3;

}

double SphereLDSPlanR::distance(double x, double y, double z, double rad)
{

  return (fabs(A * x + B * y + C * z + D) / nN - rad);
}

void SphereLDSPlanR::computeh(double)
{

  double q_0 = (*data[q0])(0);
  double q_1 = (*data[q0])(1);
  double q_2 = (*data[q0])(2);

  SP::SiconosVector y = interaction()->y(0);

  y->setValue(0, distance(q_0, q_1, q_2, r));

};

void normalize(SP::SiconosVector, unsigned int);

void SphereLDSPlanR::computeJachq(double)
{
  SimpleMatrix *g = (SimpleMatrix *)_jachq.get();

  double theta = (*data[q0])(3);
  double phi   = (*data[q0])(4);
  double psi   = (*data[q0])(5);

  double cthe = cos(theta);
  double sthe = sin(theta);
  double cphi = cos(phi);
  double sphi = sin(phi);

  (*g)(0, 0) = n1;
  (*g)(1, 0) = u1;
  (*g)(2, 0) = v1;
  (*g)(0, 1) = n2;
  (*g)(1, 1) = u2;
  (*g)(2, 1) = v2;
  (*g)(0, 2) = n3;
  (*g)(1, 2) = u3;
  (*g)(2, 2) = v3;
  (*g)(0, 3) = 0;
  (*g)(1, 3) = -rv1 * cphi - rv2 * sphi;
  (*g)(2, 3) = ru1 * cphi + ru2 * sphi;
  (*g)(0, 4) = 0;
  (*g)(1, 4) = -rv3;
  (*g)(2, 4) = ru3;
  (*g)(0, 5) = 0;
  (*g)(1, 5) = -rv3 * cthe + rv2 * cphi * sthe - rv1 * sphi * sthe;
  (*g)(2, 5) = ru3 * cthe + ru1 * sphi * sthe - ru2 * cphi * sthe;

}

<commit_msg>use orthoBaseFromVector<commit_after>/* Siconos-Example version 3.0.0, Copyright INRIA 2005-2010.
 * Siconos is a program dedicated to modeling, simulation and control
 * of non smooth dynamical systems.
 * Siconos is a free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * Siconos 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Siconos; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth FLOOR, Boston, MA  02110-1301  USA
 *
 * Contact: Vincent ACARY, siconos-team@lists.gforge.inria.fr
 *
 */

#include <math.h>
#include "SphereLDSPlanR.hpp"

SphereLDSPlanR::SphereLDSPlanR(double r, double A, double B, double C, double D)
  : LagrangianScleronomousR(), r(r), A(A), B(B), C(C), D(D)
{
  n1 = A;
  n2 = B;
  n3 = C;

  nN = sqrt(A * A + B * B + C * C);

  orthoBaseFromVector(&n1, &n2, &n3, &u1, &u2, &u3, &v1, &v2, &v3);

  // r*u & r *v

  ru1 = r * u1;
  ru2 = r * u2;
  ru3 = r * u3;

  rv1 = r * v1;
  rv2 = r * v2;
  rv3 = r * v3;

}

double SphereLDSPlanR::distance(double x, double y, double z, double rad)
{

  return (fabs(A * x + B * y + C * z + D) / nN - rad);
}

void SphereLDSPlanR::computeh(double)
{

  double q_0 = (*data[q0])(0);
  double q_1 = (*data[q0])(1);
  double q_2 = (*data[q0])(2);

  SP::SiconosVector y = interaction()->y(0);

  y->setValue(0, distance(q_0, q_1, q_2, r));

};

void normalize(SP::SiconosVector, unsigned int);

void SphereLDSPlanR::computeJachq(double)
{
  SimpleMatrix *g = (SimpleMatrix *)_jachq.get();

  double theta = (*data[q0])(3);
  double phi   = (*data[q0])(4);
  double psi   = (*data[q0])(5);

  double cthe = cos(theta);
  double sthe = sin(theta);
  double cphi = cos(phi);
  double sphi = sin(phi);

  (*g)(0, 0) = n1;
  (*g)(1, 0) = u1;
  (*g)(2, 0) = v1;
  (*g)(0, 1) = n2;
  (*g)(1, 1) = u2;
  (*g)(2, 1) = v2;
  (*g)(0, 2) = n3;
  (*g)(1, 2) = u3;
  (*g)(2, 2) = v3;
  (*g)(0, 3) = 0;
  (*g)(1, 3) = -rv1 * cphi - rv2 * sphi;
  (*g)(2, 3) = ru1 * cphi + ru2 * sphi;
  (*g)(0, 4) = 0;
  (*g)(1, 4) = -rv3;
  (*g)(2, 4) = ru3;
  (*g)(0, 5) = 0;
  (*g)(1, 5) = -rv3 * cthe + rv2 * cphi * sthe - rv1 * sphi * sthe;
  (*g)(2, 5) = ru3 * cthe + ru1 * sphi * sthe - ru2 * cphi * sthe;

}

<|endoftext|>


<commit_before>#include "DatasetBrowser.h"
#include "ui_DatasetBrowser.h"
#include "dataset/MSRDaily/MSRDailyActivity3D.h"
#include "dataset/MSRAction3D/MSR3Action3D.h"
#include "playback/PlaybackControl.h"
#include "viewer/InstanceViewerWindow.h"
#include "InstanceWidgetItem.h"
#include "DatasetSelector.h"
#include <QtWidgets/QDesktopWidget>
#include <QTimer>
#include <QMessageBox>

using namespace dai;

DatasetBrowser::DatasetBrowser(QWidget *parent) :
    QMainWindow(parent), ui(new Ui::DatasetBrowser), m_settings(this)
{
    ui->setupUi(this);

    m_playback.enablePlayLoop(true);
    m_playback.setFPS(10);
    m_dataset = nullptr;

    // First Setup
    if (m_settings.getMSRAction3D().isEmpty() || m_settings.getMSRDailyActivity3D().isEmpty()) {
        QTimer::singleShot(1, &m_settings, SLOT(show()));
    }

    // Connect Signals
    connect(ui->actionClose_dataset, SIGNAL(triggered()), this, SLOT(closeDataset()));
    connect(ui->actionOpen_dataset, SIGNAL(triggered()), this, SLOT(openDatasetSelector()));
    connect(ui->actionSettings, SIGNAL(triggered()), this, SLOT(openSettings()));
    connect(ui->listActivities, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(listItemChange(QListWidgetItem*)));
    connect(ui->listActors, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(listItemChange(QListWidgetItem*)));
    connect(ui->listSamples, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(listItemChange(QListWidgetItem*)));
    connect(ui->listInstances, SIGNAL(itemActivated(QListWidgetItem*)), this, SLOT(instanceItemActivated(QListWidgetItem*)));
    connect(ui->comboType, SIGNAL(currentIndexChanged(int)), this, SLOT(comboBoxChange(int)));

    // Show this window centered
    QDesktopWidget *desktop = QApplication::desktop();
    int screenWidth, width;
    int screenHeight, height;
    int x, y;
    QSize windowSize;

    screenWidth = desktop->availableGeometry(desktop->primaryScreen()).width();
    screenHeight = desktop->availableGeometry(desktop->primaryScreen()).height();
    windowSize = size();
    width = windowSize.width();
    height = windowSize.height();

    x = (screenWidth - width) / 2;
    y = (screenHeight - height) / 2;
    y -= 50;

    move ( x, y );
}

DatasetBrowser::~DatasetBrowser()
{
    ui->listActivities->disconnect();
    ui->listActors->disconnect();
    ui->listSamples->disconnect();
    ui->listInstances->disconnect();
    ui->comboType->disconnect();

    closeDataset();
    delete ui;
}

void DatasetBrowser::openSettings()
{
    if (m_settings.exec() == QDialog::Accepted) {
        closeDataset();
    }
}

void DatasetBrowser::openDatasetSelector()
{
    DatasetSelector* window = new DatasetSelector(this);

    if (window->exec() != QDialog::Rejected) {
        loadDataset( (Dataset::DatasetType) (window->result()-1) );
    }
}

void DatasetBrowser::closeDataset()
{
    ui->comboType->blockSignals(true);

    if (m_dataset != nullptr) {
        delete m_dataset;
        m_dataset = nullptr;
    }

    ui->listActivities->clear();
    ui->listActors->clear();
    ui->listSamples->clear();
    ui->listInstances->clear();
    ui->comboType->clear();

    ui->comboType->blockSignals(false);
}

void DatasetBrowser::listItemChange(QListWidgetItem * item)
{
    Q_UNUSED(item);
    loadInstances();
}

void DatasetBrowser::comboBoxChange(int index)
{
    Q_UNUSED(index);
    loadInstances();
}

void DatasetBrowser::instanceItemActivated(QListWidgetItem * item)
{
    InstanceWidgetItem* instanceItem = dynamic_cast<InstanceWidgetItem*>(item);
    InstanceInfo& info = instanceItem->getInfo();
    shared_ptr<StreamInstance> instance = m_dataset->getInstance(info);

    if (instance)
    {
        InstanceViewerWindow* windowViewer = new InstanceViewerWindow;

        m_playback.stop();
        m_playback.clearInstances();
        m_playback.addInstance(instance);
        m_playback.addListener(&m_depthFilter);
        m_depthFilter.addListener(windowViewer);

        try {
            m_playback.play();
            windowViewer->setTitle("Instance Viewer");
            windowViewer->show();
        }
        catch (CannotOpenInstanceException)
        {
            QMessageBox::warning(this, tr("Error reading the instance"),
                                           tr("The selected instance cannot be opened maybe\n"
                                              "due to file permissions or wrong dataset path"));
        }
    }
}

void DatasetBrowser::loadDataset(Dataset::DatasetType type)
{
    closeDataset();

    ui->comboType->blockSignals(true);

    if (type == Dataset::Dataset_MSRDailyActivity3D) {
        m_dataset = new MSRDailyActivity3D();
        m_dataset->setPath(m_settings.getMSRDailyActivity3D());
    } else if (type == Dataset::Dataset_MSRAction3D) {
        m_dataset = new MSR3Action3D();
        m_dataset->setPath(m_settings.getMSRAction3D());
    }

    // Load widgets with DataSet Info
    const DatasetMetadata& dsMetaData = m_dataset->getMetadata();

    // Load Activities
    for (int i=1; i<=dsMetaData.getNumberOfActivities(); ++i) {
        QListWidgetItem* item = new QListWidgetItem(dsMetaData.getActivityName(i), ui->listActivities);
        item->setFlags(item->flags() | Qt::ItemIsUserCheckable); // set checkable flag
        item->setCheckState(Qt::Checked);
    }

    // Load Actors
    for (int i=1; i<=dsMetaData.getNumberOfActors(); ++i) {
        QListWidgetItem* item = new QListWidgetItem(dsMetaData.getActorName(i), ui->listActors);
        item->setFlags(item->flags() | Qt::ItemIsUserCheckable); // set checkable flag
        item->setCheckState(Qt::Checked); // AND initialize check state
    }

    // Load Samples
    for (int i=1; i<=dsMetaData.getNumberOfSampleTypes(); ++i) {
        QListWidgetItem* item = new QListWidgetItem(dsMetaData.getSampleName(i), ui->listSamples);
        item->setFlags(item->flags() | Qt::ItemIsUserCheckable); // set checkable flag
        item->setCheckState(Qt::Checked); // AND initialize check state
    }

    // Load Instance Types
    const DataFrame::SupportedFrames supportedFrames = dsMetaData.availableInstanceTypes();

    if (supportedFrames.testFlag(DataFrame::Depth)) {
        ui->comboType->addItem("Depth", QVariant(DataFrame::Depth));
    }
    if (supportedFrames.testFlag(DataFrame::Color)) {
        ui->comboType->addItem("Color", QVariant(DataFrame::Color));
    }
    if (supportedFrames.testFlag(DataFrame::Skeleton)) {
        ui->comboType->addItem("Skeleton", QVariant(DataFrame::Skeleton));
    }
    if (supportedFrames.testFlag(DataFrame::Mask)) {
        ui->comboType->addItem("User", QVariant(DataFrame::Mask));
    }

    ui->comboType->blockSignals(false);
    loadInstances();
}

void DatasetBrowser::loadInstances()
{
    const DatasetMetadata& dsMetadata = m_dataset->getMetadata();

    ui->listInstances->clear();

    // Prepare Filter
    DataFrame::FrameType showType = (DataFrame::FrameType) ui->comboType->itemData(ui->comboType->currentIndex()).toInt();
    QList<int> activities;

    for (int i=0; i<ui->listActivities->count(); ++i) {
        QListWidgetItem* item = ui->listActivities->item(i);
        if (item != 0 && item->checkState() == Qt::Checked)
            activities.append(i+1);
    }

    QList<int> actors;

    for (int i=0; i<ui->listActors->count(); ++i) {
        QListWidgetItem* item = ui->listActors->item(i);
        if (item != 0 && item->checkState() == Qt::Checked)
            actors.append(i+1);
    }

    QList<int> samples;

    for (int i=0; i<ui->listSamples->count(); ++i) {
        QListWidgetItem* item = ui->listSamples->item(i);
        if (item != 0 && item->checkState() == Qt::Checked)
            samples.append(i+1);
    }

    // Get and Load Instances (I'm responsible to free this memory)
    const InstanceInfoList* instances = dsMetadata.instances(showType, &activities, &actors, &samples);

    for (int i=0; i<instances->count(); ++i) {
        InstanceInfo* instanceInfo = instances->at(i);
        InstanceWidgetItem* item = new InstanceWidgetItem(instanceInfo->getFileName(), ui->listInstances);
        item->setInfo(*instanceInfo);
    }

    delete instances;
}

void DatasetBrowser::on_btnSelectAllActivities_clicked()
{
    for (int i=0; i<ui->listActivities->count(); ++i) {
        QListWidgetItem* item = ui->listActivities->item(i);
        item->setCheckState(Qt::Checked);
    }
}

void DatasetBrowser::on_btnUnselectAllActivities_clicked()
{
    for (int i=0; i<ui->listActivities->count(); ++i) {
        QListWidgetItem* item = ui->listActivities->item(i);
        item->setCheckState(Qt::Unchecked);
    }
}

void DatasetBrowser::on_btnSelectAllActors_clicked()
{
    for (int i=0; i<ui->listActors->count(); ++i) {
        QListWidgetItem* item = ui->listActors->item(i);
        item->setCheckState(Qt::Checked);
    }
}

void DatasetBrowser::on_btnUnselectAllActors_clicked()
{
    for (int i=0; i<ui->listActors->count(); ++i) {
        QListWidgetItem* item = ui->listActors->item(i);
        item->setCheckState(Qt::Unchecked);
    }
}

void DatasetBrowser::on_btnSelectAllSamples_clicked()
{
    for (int i=0; i<ui->listSamples->count(); ++i) {
        QListWidgetItem* item = ui->listSamples->item(i);
        item->setCheckState(Qt::Checked);
    }
}

void DatasetBrowser::on_btnUnselectAllSamples_clicked()
{
    for (int i=0; i<ui->listSamples->count(); ++i) {
        QListWidgetItem* item = ui->listSamples->item(i);
        item->setCheckState(Qt::Unchecked);
    }
}
<commit_msg>Remove window centering code<commit_after>#include "DatasetBrowser.h"
#include "ui_DatasetBrowser.h"
#include "dataset/MSRDaily/MSRDailyActivity3D.h"
#include "dataset/MSRAction3D/MSR3Action3D.h"
#include "playback/PlaybackControl.h"
#include "viewer/InstanceViewerWindow.h"
#include "InstanceWidgetItem.h"
#include "DatasetSelector.h"
#include <QTimer>
#include <QMessageBox>

using namespace dai;

DatasetBrowser::DatasetBrowser(QWidget *parent) :
    QMainWindow(parent), ui(new Ui::DatasetBrowser), m_settings(this)
{
    ui->setupUi(this);

    m_playback.enablePlayLoop(true);
    m_playback.setFPS(10);
    m_dataset = nullptr;

    // First Setup
    if (m_settings.getMSRAction3D().isEmpty() || m_settings.getMSRDailyActivity3D().isEmpty()) {
        QTimer::singleShot(1, &m_settings, SLOT(show()));
    }

    // Connect Signals
    connect(ui->actionClose_dataset, SIGNAL(triggered()), this, SLOT(closeDataset()));
    connect(ui->actionOpen_dataset, SIGNAL(triggered()), this, SLOT(openDatasetSelector()));
    connect(ui->actionSettings, SIGNAL(triggered()), this, SLOT(openSettings()));
    connect(ui->listActivities, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(listItemChange(QListWidgetItem*)));
    connect(ui->listActors, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(listItemChange(QListWidgetItem*)));
    connect(ui->listSamples, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(listItemChange(QListWidgetItem*)));
    connect(ui->listInstances, SIGNAL(itemActivated(QListWidgetItem*)), this, SLOT(instanceItemActivated(QListWidgetItem*)));
    connect(ui->comboType, SIGNAL(currentIndexChanged(int)), this, SLOT(comboBoxChange(int)));
}

DatasetBrowser::~DatasetBrowser()
{
    ui->listActivities->disconnect();
    ui->listActors->disconnect();
    ui->listSamples->disconnect();
    ui->listInstances->disconnect();
    ui->comboType->disconnect();

    closeDataset();
    delete ui;
}

void DatasetBrowser::openSettings()
{
    if (m_settings.exec() == QDialog::Accepted) {
        closeDataset();
    }
}

void DatasetBrowser::openDatasetSelector()
{
    DatasetSelector* window = new DatasetSelector(this);

    if (window->exec() != QDialog::Rejected) {
        loadDataset( (Dataset::DatasetType) (window->result()-1) );
    }
}

void DatasetBrowser::closeDataset()
{
    ui->comboType->blockSignals(true);

    if (m_dataset != nullptr) {
        delete m_dataset;
        m_dataset = nullptr;
    }

    ui->listActivities->clear();
    ui->listActors->clear();
    ui->listSamples->clear();
    ui->listInstances->clear();
    ui->comboType->clear();

    ui->comboType->blockSignals(false);
}

void DatasetBrowser::listItemChange(QListWidgetItem * item)
{
    Q_UNUSED(item);
    loadInstances();
}

void DatasetBrowser::comboBoxChange(int index)
{
    Q_UNUSED(index);
    loadInstances();
}

void DatasetBrowser::instanceItemActivated(QListWidgetItem * item)
{
    InstanceWidgetItem* instanceItem = dynamic_cast<InstanceWidgetItem*>(item);
    InstanceInfo& info = instanceItem->getInfo();
    shared_ptr<StreamInstance> instance = m_dataset->getInstance(info);

    if (instance)
    {
        InstanceViewerWindow* windowViewer = new InstanceViewerWindow;

        m_playback.stop();
        m_playback.clearInstances();
        m_playback.addInstance(instance);
        m_playback.addListener(&m_depthFilter);
        m_depthFilter.addListener(windowViewer);

        try {
            m_playback.play();
            windowViewer->setTitle("Instance Viewer");
            windowViewer->show();
        }
        catch (CannotOpenInstanceException)
        {
            QMessageBox::warning(this, tr("Error reading the instance"),
                                           tr("The selected instance cannot be opened maybe\n"
                                              "due to file permissions or wrong dataset path"));
        }
    }
}

void DatasetBrowser::loadDataset(Dataset::DatasetType type)
{
    closeDataset();

    ui->comboType->blockSignals(true);

    if (type == Dataset::Dataset_MSRDailyActivity3D) {
        m_dataset = new MSRDailyActivity3D();
        m_dataset->setPath(m_settings.getMSRDailyActivity3D());
    } else if (type == Dataset::Dataset_MSRAction3D) {
        m_dataset = new MSR3Action3D();
        m_dataset->setPath(m_settings.getMSRAction3D());
    }

    // Load widgets with DataSet Info
    const DatasetMetadata& dsMetaData = m_dataset->getMetadata();

    // Load Activities
    for (int i=1; i<=dsMetaData.getNumberOfActivities(); ++i) {
        QListWidgetItem* item = new QListWidgetItem(dsMetaData.getActivityName(i), ui->listActivities);
        item->setFlags(item->flags() | Qt::ItemIsUserCheckable); // set checkable flag
        item->setCheckState(Qt::Checked);
    }

    // Load Actors
    for (int i=1; i<=dsMetaData.getNumberOfActors(); ++i) {
        QListWidgetItem* item = new QListWidgetItem(dsMetaData.getActorName(i), ui->listActors);
        item->setFlags(item->flags() | Qt::ItemIsUserCheckable); // set checkable flag
        item->setCheckState(Qt::Checked); // AND initialize check state
    }

    // Load Samples
    for (int i=1; i<=dsMetaData.getNumberOfSampleTypes(); ++i) {
        QListWidgetItem* item = new QListWidgetItem(dsMetaData.getSampleName(i), ui->listSamples);
        item->setFlags(item->flags() | Qt::ItemIsUserCheckable); // set checkable flag
        item->setCheckState(Qt::Checked); // AND initialize check state
    }

    // Load Instance Types
    const DataFrame::SupportedFrames supportedFrames = dsMetaData.availableInstanceTypes();

    if (supportedFrames.testFlag(DataFrame::Depth)) {
        ui->comboType->addItem("Depth", QVariant(DataFrame::Depth));
    }
    if (supportedFrames.testFlag(DataFrame::Color)) {
        ui->comboType->addItem("Color", QVariant(DataFrame::Color));
    }
    if (supportedFrames.testFlag(DataFrame::Skeleton)) {
        ui->comboType->addItem("Skeleton", QVariant(DataFrame::Skeleton));
    }
    if (supportedFrames.testFlag(DataFrame::Mask)) {
        ui->comboType->addItem("User", QVariant(DataFrame::Mask));
    }

    ui->comboType->blockSignals(false);
    loadInstances();
}

void DatasetBrowser::loadInstances()
{
    const DatasetMetadata& dsMetadata = m_dataset->getMetadata();

    ui->listInstances->clear();

    // Prepare Filter
    DataFrame::FrameType showType = (DataFrame::FrameType) ui->comboType->itemData(ui->comboType->currentIndex()).toInt();
    QList<int> activities;

    for (int i=0; i<ui->listActivities->count(); ++i) {
        QListWidgetItem* item = ui->listActivities->item(i);
        if (item != 0 && item->checkState() == Qt::Checked)
            activities.append(i+1);
    }

    QList<int> actors;

    for (int i=0; i<ui->listActors->count(); ++i) {
        QListWidgetItem* item = ui->listActors->item(i);
        if (item != 0 && item->checkState() == Qt::Checked)
            actors.append(i+1);
    }

    QList<int> samples;

    for (int i=0; i<ui->listSamples->count(); ++i) {
        QListWidgetItem* item = ui->listSamples->item(i);
        if (item != 0 && item->checkState() == Qt::Checked)
            samples.append(i+1);
    }

    // Get and Load Instances (I'm responsible to free this memory)
    const InstanceInfoList* instances = dsMetadata.instances(showType, &activities, &actors, &samples);

    for (int i=0; i<instances->count(); ++i) {
        InstanceInfo* instanceInfo = instances->at(i);
        InstanceWidgetItem* item = new InstanceWidgetItem(instanceInfo->getFileName(), ui->listInstances);
        item->setInfo(*instanceInfo);
    }

    delete instances;
}

void DatasetBrowser::on_btnSelectAllActivities_clicked()
{
    for (int i=0; i<ui->listActivities->count(); ++i) {
        QListWidgetItem* item = ui->listActivities->item(i);
        item->setCheckState(Qt::Checked);
    }
}

void DatasetBrowser::on_btnUnselectAllActivities_clicked()
{
    for (int i=0; i<ui->listActivities->count(); ++i) {
        QListWidgetItem* item = ui->listActivities->item(i);
        item->setCheckState(Qt::Unchecked);
    }
}

void DatasetBrowser::on_btnSelectAllActors_clicked()
{
    for (int i=0; i<ui->listActors->count(); ++i) {
        QListWidgetItem* item = ui->listActors->item(i);
        item->setCheckState(Qt::Checked);
    }
}

void DatasetBrowser::on_btnUnselectAllActors_clicked()
{
    for (int i=0; i<ui->listActors->count(); ++i) {
        QListWidgetItem* item = ui->listActors->item(i);
        item->setCheckState(Qt::Unchecked);
    }
}

void DatasetBrowser::on_btnSelectAllSamples_clicked()
{
    for (int i=0; i<ui->listSamples->count(); ++i) {
        QListWidgetItem* item = ui->listSamples->item(i);
        item->setCheckState(Qt::Checked);
    }
}

void DatasetBrowser::on_btnUnselectAllSamples_clicked()
{
    for (int i=0; i<ui->listSamples->count(); ++i) {
        QListWidgetItem* item = ui->listSamples->item(i);
        item->setCheckState(Qt::Unchecked);
    }
}
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>

struct Node
{
	Node* left;
	Node* right;
	Node* p;
	int v;
};

void insert(Node** root, Node* newNode)
{
	if (newNode == nullptr)
	{
		return;
	}

	if (root == nullptr || *root == nullptr)
	{
		*root = newNode;
		newNode->p = nullptr;

		return;
	}

	Node* current = *root;
	Node* temp = current;

	while (current != nullptr)
	{
		temp = current;
		if (newNode->v < current->v)
		{
			current = current->left;
		}
		else
		{
			current = current->right;
		}
	};

	newNode->p = temp;
	if (newNode->v < temp->v)
	{
		temp->left = newNode;
	}
	else
	{
		temp->right = newNode;
	}
}

int main()
{
	Node* tree = nullptr;
	std::vector<int> input = { 2, 252, 401, 398, 330, 344, 397, 363 };
	for (auto iter = input.begin(); iter != input.end(); ++iter)
	{
		Node* n = new Node();
		n->v = *iter;

		insert(&tree, n);
	}

	// Release allocated memories of the tree.
	Node* c = tree;
	Node* p = nullptr;
	while (c != nullptr)
	{
		p = c;
		if (c->left != nullptr)
		{
			c = c->left;
		}
		else if (c->right != nullptr)
		{
			c = c->right;
		}
		else
		{
			p = c->p;
			if (p == nullptr)
			{
				delete c;
				c = nullptr;
				continue;
			}

			if (c->v < p->v)
			{
				p->left = nullptr;
			}
			else
			{
				p->right = nullptr;
			}

			delete c;
			c = p;
		}
	}

	return 0;
}
<commit_msg>Added search, max, min functions.<commit_after>#include <iostream>
#include <vector>

struct Node
{
	Node* left;
	Node* right;
	Node* p;
	int v;
};

Node* search(Node* tree, int value)
{
	Node* c = tree;
	while (c != nullptr && c->v != value)
	{
		if (value < c->v)
		{
			c = c->left;
		}
		else
		{
			c = c->right;
		}
	}

	return c;
}

Node* min(Node* tree)
{
	if (tree == nullptr)
	{
		return nullptr;
	}

	while (tree->left != nullptr)
	{
		tree = tree->left;
	}

	return tree;
}
Node* max(Node* tree)
{
	if (tree == nullptr)
	{
		return nullptr;
	}

	while (tree->right != nullptr)
	{
		tree = tree->right;
	}

	return tree;
}

void insert(Node** root, Node* newNode)
{
	if (newNode == nullptr)
	{
		return;
	}

	if (root == nullptr || *root == nullptr)
	{
		*root = newNode;
		newNode->p = nullptr;

		return;
	}

	Node* current = *root;
	Node* temp = current;

	while (current != nullptr)
	{
		temp = current;
		if (newNode->v < current->v)
		{
			current = current->left;
		}
		else
		{
			current = current->right;
		}
	};

	newNode->p = temp;
	if (newNode->v < temp->v)
	{
		temp->left = newNode;
	}
	else
	{
		temp->right = newNode;
	}
}

int main()
{
	Node* tree = nullptr;
	std::vector<int> input = { 2, 252, 401, 398, 330, 344, 397, 363 };
	for (auto iter = input.begin(); iter != input.end(); ++iter)
	{
		Node* n = new Node();
		n->v = *iter;

		insert(&tree, n);
	}

	// Search
	Node* s = search(tree, 398);
	std::cout << "search result : " << s->v << std::endl;

	// Min
	Node* minNode = min(tree);
	std::cout << "min result : " << minNode->v << std::endl;

	// Max
	Node* maxNode = max(tree);
	std::cout << "max result : " << maxNode->v << std::endl;

	// Release allocated memories of the tree.
	Node* c = tree;
	Node* p = nullptr;
	while (c != nullptr)
	{
		p = c;
		if (c->left != nullptr)
		{
			c = c->left;
		}
		else if (c->right != nullptr)
		{
			c = c->right;
		}
		else
		{
			p = c->p;
			if (p == nullptr)
			{
				delete c;
				c = nullptr;
				continue;
			}

			if (c->v < p->v)
			{
				p->left = nullptr;
			}
			else
			{
				p->right = nullptr;
			}

			delete c;
			c = p;
		}
	}

	return 0;
}
<|endoftext|>


<commit_before>/**
 * @file
 *
 * @brief Source for yamlcpp plugin
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 *
 */

// -- Imports ------------------------------------------------------------------------------------------------------------------------------

#include "yamlcpp.hpp"
#include "log.hpp"
#include "read.hpp"
#include "write.hpp"
using namespace yamlcpp;

#include <kdb.hpp>
using namespace ckdb;
#include <kdberrors.h>
#include <kdblogger.h>

#include "yaml-cpp/yaml.h"

// -- Functions ----------------------------------------------------------------------------------------------------------------------------

namespace
{

/**
 * @brief This function returns a key set containing the contract of this plugin.
 *
 * @return A contract describing the functionality of this plugin.
 */
KeySet * contractYamlCpp (void)
{
	return ksNew (30, keyNew ("system/elektra/modules/yamlcpp", KEY_VALUE, "yamlcpp plugin waits for your orders", KEY_END),
		      keyNew ("system/elektra/modules/yamlcpp/exports", KEY_END),
		      keyNew ("system/elektra/modules/yamlcpp/exports/get", KEY_FUNC, elektraYamlcppGet, KEY_END),
		      keyNew ("system/elektra/modules/yamlcpp/exports/set", KEY_FUNC, elektraYamlcppSet, KEY_END),
#include ELEKTRA_README
		      keyNew ("system/elektra/modules/yamlcpp/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END),
		      keyNew ("system/elektra/modules/yamlcpp/config/needs/binary/meta", KEY_VALUE, "true", KEY_END), KS_END);
}

}

// ====================
// = Plugin Interface =
// ====================

/** @see elektraDocGet */
int elektraYamlcppGet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned, Key * parentKey)
{
	if (std::string (keyName (parentKey)) == "system/elektra/modules/yamlcpp")
	{
		KeySet * contract = contractYamlCpp ();
		ksAppend (returned, contract);
		ksDel (contract);

		return ELEKTRA_PLUGIN_STATUS_SUCCESS;
	}

	kdb::Key parent = kdb::Key (parentKey);
	kdb::KeySet keys = kdb::KeySet (returned);

	ELEKTRA_LOG_DEBUG ("Read file “%s”", parent.getString ().c_str ());

	int status = ELEKTRA_PLUGIN_STATUS_ERROR;

	try
	{
		yamlRead (keys, parent);
		status = ELEKTRA_PLUGIN_STATUS_SUCCESS;
	}
	catch (YAML::ParserException const & exception)
	{
		ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_PARSE, parent.getKey (), "Unable to parse file “%s”: %s.", parent.getString ().c_str (),
				    exception.what ());
	}
	catch (YAML::RepresentationException const & exception)
	{
		ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_YAMLCPP_REPRESENTATION, parent.getKey (), "Unable to read data from file “%s”: %s",
				    parent.getString ().c_str (), exception.what ());
	}

	parent.release ();
	keys.release ();

	return status;
}

/** @see elektraDocSet */
int elektraYamlcppSet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned, Key * parentKey)
{
	kdb::Key parent = kdb::Key (parentKey);
	kdb::KeySet keys = kdb::KeySet (returned);

#ifdef HAVE_LOGGER
	ELEKTRA_LOG_DEBUG ("Write keys:");
	logKeySet (keys);
#endif

	int status = ELEKTRA_PLUGIN_STATUS_ERROR;

	try
	{
		yamlWrite (keys, parent);
		status = ELEKTRA_PLUGIN_STATUS_SUCCESS;
	}
	catch (YAML::BadFile const & exception)
	{
		ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_YAMLCPP_WRITE_FAILED, parent.getKey (), "Unable to write to file “%s”: %s.",
				    parent.getString ().c_str (), exception.what ());
	}
	catch (YAML::EmitterException const & exception)
	{
		ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_YAMLCPP_EMITTER_FAILED, parent.getKey (),
				    "Something went wrong while emitting YAML data to file “%s”: %s.", parent.getString ().c_str (),
				    exception.what ());
	}

	parent.release ();
	keys.release ();

	return status;
}

Plugin * ELEKTRA_PLUGIN_EXPORT
{
	return elektraPluginExport ("yamlcpp", ELEKTRA_PLUGIN_GET, &elektraYamlcppGet, ELEKTRA_PLUGIN_SET, &elektraYamlcppSet,
				    ELEKTRA_PLUGIN_END);
}
<commit_msg>YAML CPP: Reformat code with Clang-Format 6<commit_after>/**
 * @file
 *
 * @brief Source for yamlcpp plugin
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 *
 */

// -- Imports ------------------------------------------------------------------------------------------------------------------------------

#include "yamlcpp.hpp"
#include "log.hpp"
#include "read.hpp"
#include "write.hpp"
using namespace yamlcpp;

#include <kdb.hpp>
using namespace ckdb;
#include <kdberrors.h>
#include <kdblogger.h>

#include "yaml-cpp/yaml.h"

// -- Functions ----------------------------------------------------------------------------------------------------------------------------

namespace
{

/**
 * @brief This function returns a key set containing the contract of this plugin.
 *
 * @return A contract describing the functionality of this plugin.
 */
KeySet * contractYamlCpp (void)
{
	return ksNew (30, keyNew ("system/elektra/modules/yamlcpp", KEY_VALUE, "yamlcpp plugin waits for your orders", KEY_END),
		      keyNew ("system/elektra/modules/yamlcpp/exports", KEY_END),
		      keyNew ("system/elektra/modules/yamlcpp/exports/get", KEY_FUNC, elektraYamlcppGet, KEY_END),
		      keyNew ("system/elektra/modules/yamlcpp/exports/set", KEY_FUNC, elektraYamlcppSet, KEY_END),
#include ELEKTRA_README
		      keyNew ("system/elektra/modules/yamlcpp/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END),
		      keyNew ("system/elektra/modules/yamlcpp/config/needs/binary/meta", KEY_VALUE, "true", KEY_END), KS_END);
}
}

// ====================
// = Plugin Interface =
// ====================

/** @see elektraDocGet */
int elektraYamlcppGet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned, Key * parentKey)
{
	if (std::string (keyName (parentKey)) == "system/elektra/modules/yamlcpp")
	{
		KeySet * contract = contractYamlCpp ();
		ksAppend (returned, contract);
		ksDel (contract);

		return ELEKTRA_PLUGIN_STATUS_SUCCESS;
	}

	kdb::Key parent = kdb::Key (parentKey);
	kdb::KeySet keys = kdb::KeySet (returned);

	ELEKTRA_LOG_DEBUG ("Read file “%s”", parent.getString ().c_str ());

	int status = ELEKTRA_PLUGIN_STATUS_ERROR;

	try
	{
		yamlRead (keys, parent);
		status = ELEKTRA_PLUGIN_STATUS_SUCCESS;
	}
	catch (YAML::ParserException const & exception)
	{
		ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_PARSE, parent.getKey (), "Unable to parse file “%s”: %s.", parent.getString ().c_str (),
				    exception.what ());
	}
	catch (YAML::RepresentationException const & exception)
	{
		ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_YAMLCPP_REPRESENTATION, parent.getKey (), "Unable to read data from file “%s”: %s",
				    parent.getString ().c_str (), exception.what ());
	}

	parent.release ();
	keys.release ();

	return status;
}

/** @see elektraDocSet */
int elektraYamlcppSet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned, Key * parentKey)
{
	kdb::Key parent = kdb::Key (parentKey);
	kdb::KeySet keys = kdb::KeySet (returned);

#ifdef HAVE_LOGGER
	ELEKTRA_LOG_DEBUG ("Write keys:");
	logKeySet (keys);
#endif

	int status = ELEKTRA_PLUGIN_STATUS_ERROR;

	try
	{
		yamlWrite (keys, parent);
		status = ELEKTRA_PLUGIN_STATUS_SUCCESS;
	}
	catch (YAML::BadFile const & exception)
	{
		ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_YAMLCPP_WRITE_FAILED, parent.getKey (), "Unable to write to file “%s”: %s.",
				    parent.getString ().c_str (), exception.what ());
	}
	catch (YAML::EmitterException const & exception)
	{
		ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_YAMLCPP_EMITTER_FAILED, parent.getKey (),
				    "Something went wrong while emitting YAML data to file “%s”: %s.", parent.getString ().c_str (),
				    exception.what ());
	}

	parent.release ();
	keys.release ();

	return status;
}

Plugin * ELEKTRA_PLUGIN_EXPORT
{
	return elektraPluginExport ("yamlcpp", ELEKTRA_PLUGIN_GET, &elektraYamlcppGet, ELEKTRA_PLUGIN_SET, &elektraYamlcppSet,
				    ELEKTRA_PLUGIN_END);
}
<|endoftext|>