<commit_before>/*
 * Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "otbWrapperOutputImageParameter.h"
#include "otbClampImageFilter.h"
#include "otbImageIOFactory.h"
#include "itksys/SystemTools.hxx"

#ifdef OTB_USE_MPI

#include "otbMPIConfig.h"
#include "otbMPIVrtWriter.h"

#ifdef OTB_USE_SPTW
#include "otbSimpleParallelTiffWriter.h"
#endif

#endif

#define CAST_IMAGE_BASE( T, image_base )		\
  {							\
    T * img = dynamic_cast< T * >( image_base );	\
							\
    if( img )						\
      SwitchInput< T >( img );				\
    							\
    return;						\
  }

namespace otb
{
namespace Wrapper
{

// Declare specialisation for UInt8RGBAImageType
template<>
void OutputImageParameter::SwitchInput(UInt8RGBAImageType * );

// Declare specialisation for UInt8RGBImageType
template <>
void OutputImageParameter::SwitchInput( UInt8RGBImageType * );

OutputImageParameter::OutputImageParameter()
  : m_PixelType(ImagePixelType_float),
    m_DefaultPixelType(ImagePixelType_float),
    m_RAMValue(0)
{
  SetName("Output Image");
  SetKey("out");
}

OutputImageParameter::~OutputImageParameter()
{
}

std::string OutputImageParameter::ConvertPixelTypeToString(ImagePixelType type)
{
  // TODO: Could be replaced by constant static string array e.g.:
  // return PIXEL_TYPE_NAME[ type ];

  std::string ret;
  switch(type)
    {
    case ImagePixelType_uint8:
      {
      ret = "uint8";
      break;
      }
    case ImagePixelType_int16:
      {
      ret = "int16";
      break;
      }
    case ImagePixelType_uint16:
      {
      ret = "uint16";
      break;
      }
    case ImagePixelType_int32:
      {
      ret = "int32";
      break;
      }
    case ImagePixelType_uint32:
      {
      ret = "uint32";
      break;
      }
    case ImagePixelType_float:
      {
      ret = "float";
      break;
      }
    case ImagePixelType_double:
      {
      ret = "double";
      break;
      }
    case ImagePixelType_cint16:
      {
      ret = "cint16";
      break;
      }
    case ImagePixelType_cint32:
      {
      ret = "cint32";
      break;
      }
    case ImagePixelType_cfloat:
      {
      ret = "cfloat";
      break;
      }
    case ImagePixelType_cdouble:
      {
      ret = "cdouble";
      break;
      }
    }
  return ret;
}

bool
OutputImageParameter::ConvertStringToPixelType(const std::string &value, ImagePixelType &type)
{
  // TODO: Could be replaced std::find_if() in constant static string
  // array (see ::ConvertPixelTypeToString().

  if (value == "uint8")
    type = ImagePixelType_uint8;
  else if (value == "int16")
    type = ImagePixelType_int16;
  else if (value == "uint16")
    type = ImagePixelType_uint16;
  else if (value == "int32")
    type = ImagePixelType_int32;
  else if (value == "uint32")
    type = ImagePixelType_uint32;
  else if (value == "float")
    type = ImagePixelType_float;
  else if (value == "double")
    type = ImagePixelType_double;
  else if (value == "cint16")
    type = ImagePixelType_cint16;
  else if (value == "cint32")
    type = ImagePixelType_cint32;
  else if (value == "cfloat")
    type = ImagePixelType_cfloat;
  else if (value == "cdouble")
    type = ImagePixelType_cdouble;
  else
    return false;
  return true;
}

void
OutputImageParameter
::InitializeWriters()
{
  ImageBaseType * image = m_Image.GetPointer();

  CAST_IMAGE_BASE( UInt8VectorImageType, image );
  CAST_IMAGE_BASE( Int16VectorImageType, image );
  CAST_IMAGE_BASE( UInt16VectorImageType, image );
  CAST_IMAGE_BASE( Int32VectorImageType, image );
  CAST_IMAGE_BASE( UInt32VectorImageType, image );

  CAST_IMAGE_BASE( FloatVectorImageType, image );
  CAST_IMAGE_BASE( DoubleVectorImageType, image );

  CAST_IMAGE_BASE( ComplexInt16VectorImageType, image );
  CAST_IMAGE_BASE( ComplexInt32VectorImageType, image );
  CAST_IMAGE_BASE( ComplexFloatVectorImageType, image );
  CAST_IMAGE_BASE( ComplexDoubleVectorImageType, image );

  CAST_IMAGE_BASE( UInt8ImageType, image );
  CAST_IMAGE_BASE( Int16ImageType, image );
  CAST_IMAGE_BASE( UInt16ImageType, image );
  CAST_IMAGE_BASE( Int32ImageType, image );
  CAST_IMAGE_BASE( UInt32ImageType, image );

  CAST_IMAGE_BASE( FloatImageType, image );
  CAST_IMAGE_BASE( DoubleImageType, image );

  CAST_IMAGE_BASE( ComplexInt16ImageType, image );
  CAST_IMAGE_BASE( ComplexInt32ImageType, image );
  CAST_IMAGE_BASE( ComplexFloatImageType, image );
  CAST_IMAGE_BASE( ComplexDoubleImageType, image );

  CAST_IMAGE_BASE( UInt8RGBImageType, image );
  CAST_IMAGE_BASE( UInt8RGBAImageType, image );

  itkExceptionMacro( "Unknown image-base type." );
}

template< typename TOutputImage,
	  typename TInputImage >
void
OutputImageParameter
::ClampAndWriteVectorImage( TInputImage * in )
{
  assert( !m_FileName.empty() );

  auto icif =
    ClampImageFilter< TInputImage, DoubleVectorImageType >::New();

  auto clampFilter =
    ClampImageFilter< DoubleVectorImageType , TOutputImage >::New();

  icif->SetInput( in );

  clampFilter->SetInput( icif->GetOutput() );

#ifdef OTB_USE_MPI

  otb::MPIConfig::Pointer mpiConfig = otb::MPIConfig::Instance();

  if( mpiConfig->GetNbProcs() > 1 )
    {
    useStandardWriter = false;

    std::string extension =
      itksys::SystemTools::GetFilenameExtension( m_Filename );

    if(extension == ".vrt")
      {
      // Use the MPIVrtWriter

      auto vrtWriter =
	otb::MPIVrtWriter< TOutputImage >::New();

      vrtWriter->SetInput( clampFilter->GetOutput() );
      vrtWriter->SetFileName( m_Filename );
      vrtWriter->SetAvailableRAM( m_RAMValue);

      // Change internal state only when everything has been setup
      // without raising exception.

      m_Caster = clampFilter;
      m_Writer = vrtWriter;

      return;
      }

#ifdef OTB_USE_SPTW

    else if (extension == ".tif")
      {
      // Use simple parallel tiff writer

      auto sptWriter =
	otb::SimpleParallelTiffWriter< TOutputImage >::New();

      sptWriter->SetFileName( m_Filename );
      sptWriter->SetInput( clampFilter->GetOutput() );
      sptWriter->GetStreamingManager()->SetDefaultRAM( m_RAMValue );

      // Change internal state only when everything has been setup
      // without raising exception.

      m_Caster = clampFilter;
      m_Writer = sptWriter;

      return;
      }

#endif // OTB_USE_SPTW

    else
      {
      itkGenericExceptionMacro(
	"File format "
	<< extension
	<< " not supported for parallel writing with MPI. Supported formats are "
	   ".vrt and .tif. Extended filenames are not supported."
      );
      }
    }

#endif // OTB_USE_MPI

  //
  // Use default OTB writer.

  auto writer = otb::ImageFileWriter< TOutputImage >::New();

  writer->SetFileName( m_FileName );
  writer->SetInput( clampFilter->GetOutput() );
  writer->GetStreamingManager()->SetDefaultRAM( m_RAMValue );

  // Change internal state only when everything has been setup
  // without raising exception.

  m_InputCaster = icif;
  m_OutputCaster = clampFilter;

  m_Writer = writer;
}

template< typename TInputImage >
void
OutputImageParameter
::SwitchInput( TInputImage * image )
{
  assert( image );

  switch( m_PixelType )
    {
    case ImagePixelType_uint8:
      ClampAndWriteVectorImage< UInt8VectorImageType >( image );
      break;

    case ImagePixelType_int16:
      ClampAndWriteVectorImage< Int16VectorImageType >( image );
      break;

    case ImagePixelType_uint16:
      ClampAndWriteVectorImage< UInt16VectorImageType >( image );
      break;

    case ImagePixelType_int32:

      ClampAndWriteVectorImage< Int32VectorImageType >( image );
      break;

    case ImagePixelType_uint32:
      ClampAndWriteVectorImage< UInt32VectorImageType >( image );
      break;

    case ImagePixelType_float:
      ClampAndWriteVectorImage< FloatVectorImageType >( image );
      break;

    case ImagePixelType_double:
      ClampAndWriteVectorImage< DoubleVectorImageType >( image );
      break;

    case ImagePixelType_cint16:
      ClampAndWriteVectorImage < ComplexInt16VectorImageType >( image );
      break;

    case ImagePixelType_cint32:
      ClampAndWriteVectorImage < ComplexInt32VectorImageType >( image );
      break;

    case ImagePixelType_cfloat:
      ClampAndWriteVectorImage< ComplexFloatVectorImageType >( image );
    break;

    case ImagePixelType_cdouble:
      ClampAndWriteVectorImage < ComplexDoubleVectorImageType >( image );
    break;

    default:
      assert( false && "Unexpected image-type." );
      break;
    }
}

void
OutputImageParameter::Write()
{
  m_Writer->Update();

  // Clean internal filters
  m_InputCaster = nullptr;
  m_OutputCaster = nullptr;

  m_Writer = nullptr;
}

itk::ProcessObject*
OutputImageParameter::GetWriter()
{
  return m_Writer;
}

ImageBaseType*
OutputImageParameter::GetValue( )
{
  return m_Image;
}

void
OutputImageParameter::SetValue(ImageBaseType* image)
{
  m_Image = image;
  SetActive(true);
}

bool
OutputImageParameter
::HasValue() const
{
  return !m_FileName.empty();
}

std::string
OutputImageParameter::CheckFileName(bool fixMissingExtension)
{
  std::string ret("");
  // Check that there is an ImageIO capable of writing the file
  otb::ExtendedFilenameToWriterOptions::Pointer filenameHelper =
    otb::ExtendedFilenameToWriterOptions::New();
  filenameHelper->SetExtendedFileName(this->GetFileName());
  std::string simpleFilename = filenameHelper->GetSimpleFileName();
  // TODO : check if simpleFilename is empty

  otb::ImageIOBase::Pointer imageIO =
    otb::ImageIOFactory::CreateImageIO(simpleFilename.c_str(),
                                       otb::ImageIOFactory::WriteMode);
  if(imageIO.IsNull())
    {
    // check for missing extension
    std::string outExt = itksys::SystemTools::GetFilenameLastExtension(simpleFilename);
    if (outExt.empty())
      {
      if (fixMissingExtension)
        {
        // try with .tif
        std::string fullFileName(this->GetFileName());
        std::string extendedPart = fullFileName.substr(simpleFilename.size());
        this->SetFileName(simpleFilename+std::string(".tif")+extendedPart);
        ret += std::string("no extension detected, using TIF as default.");
        }
      else
        {
        // TODO : call exception here?
        }
      }
    else
      {
      // TODO : call exception here?
      }
    }
  return ret;
}

// Specialization for UInt8RGBAImageType

template<>
void
OutputImageParameter
::SwitchInput( UInt8RGBAImageType * img )
{
  assert( img );

  if( m_PixelType != ImagePixelType_uint8 )
     itkExceptionMacro("Unknown PixelType for RGBA Image. Only uint8 is supported.");

  auto writer =
    otb::ImageFileWriter< UInt8RGBAImageType >::New();

  writer->SetFileName( GetFileName() );
  writer->SetInput( img );
  writer->GetStreamingManager()->SetDefaultRAM( m_RAMValue );

  m_Writer = writer;
}

// Specialization for UInt8RGBImageType
template<>
void
OutputImageParameter
::SwitchInput( UInt8RGBImageType * img )
{
  if( m_PixelType != ImagePixelType_uint8 )
    itkExceptionMacro("Unknown PixelType for RGB Image. Only uint8 is supported.");

  auto writer = otb::ImageFileWriter< UInt8RGBImageType >::New();

  writer->SetFileName( GetFileName() );
  writer->SetInput( img );
  writer->GetStreamingManager()->SetDefaultRAM( m_RAMValue );

  m_Writer = writer;
}

void OutputImageParameter::SetFileName (const char* filename)
{
  this->SetFileName(std::string(filename));
}

void OutputImageParameter::SetFileName (const std::string& filename)
{
  m_FileName = filename;
  SetActive(true);
}

}
}
<commit_msg>ENH: 1649: Fixed compile-time error (OTB_USE_MPI).<commit_after>/*
 * Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "otbWrapperOutputImageParameter.h"
#include "otbClampImageFilter.h"
#include "otbImageIOFactory.h"
#include "itksys/SystemTools.hxx"

#ifdef OTB_USE_MPI

#include "otbMPIConfig.h"
#include "otbMPIVrtWriter.h"

#ifdef OTB_USE_SPTW
#include "otbSimpleParallelTiffWriter.h"
#endif

#endif

#define CAST_IMAGE_BASE( T, image_base )		\
  {							\
    T * img = dynamic_cast< T * >( image_base );	\
							\
    if( img )						\
      SwitchInput< T >( img );				\
    							\
    return;						\
  }

namespace otb
{
namespace Wrapper
{

// Declare specialisation for UInt8RGBAImageType
template<>
void OutputImageParameter::SwitchInput(UInt8RGBAImageType * );

// Declare specialisation for UInt8RGBImageType
template <>
void OutputImageParameter::SwitchInput( UInt8RGBImageType * );

OutputImageParameter::OutputImageParameter()
  : m_PixelType(ImagePixelType_float),
    m_DefaultPixelType(ImagePixelType_float),
    m_RAMValue(0)
{
  SetName("Output Image");
  SetKey("out");
}

OutputImageParameter::~OutputImageParameter()
{
}

std::string OutputImageParameter::ConvertPixelTypeToString(ImagePixelType type)
{
  // TODO: Could be replaced by constant static string array e.g.:
  // return PIXEL_TYPE_NAME[ type ];

  std::string ret;
  switch(type)
    {
    case ImagePixelType_uint8:
      {
      ret = "uint8";
      break;
      }
    case ImagePixelType_int16:
      {
      ret = "int16";
      break;
      }
    case ImagePixelType_uint16:
      {
      ret = "uint16";
      break;
      }
    case ImagePixelType_int32:
      {
      ret = "int32";
      break;
      }
    case ImagePixelType_uint32:
      {
      ret = "uint32";
      break;
      }
    case ImagePixelType_float:
      {
      ret = "float";
      break;
      }
    case ImagePixelType_double:
      {
      ret = "double";
      break;
      }
    case ImagePixelType_cint16:
      {
      ret = "cint16";
      break;
      }
    case ImagePixelType_cint32:
      {
      ret = "cint32";
      break;
      }
    case ImagePixelType_cfloat:
      {
      ret = "cfloat";
      break;
      }
    case ImagePixelType_cdouble:
      {
      ret = "cdouble";
      break;
      }
    }
  return ret;
}

bool
OutputImageParameter::ConvertStringToPixelType(const std::string &value, ImagePixelType &type)
{
  // TODO: Could be replaced std::find_if() in constant static string
  // array (see ::ConvertPixelTypeToString().

  if (value == "uint8")
    type = ImagePixelType_uint8;
  else if (value == "int16")
    type = ImagePixelType_int16;
  else if (value == "uint16")
    type = ImagePixelType_uint16;
  else if (value == "int32")
    type = ImagePixelType_int32;
  else if (value == "uint32")
    type = ImagePixelType_uint32;
  else if (value == "float")
    type = ImagePixelType_float;
  else if (value == "double")
    type = ImagePixelType_double;
  else if (value == "cint16")
    type = ImagePixelType_cint16;
  else if (value == "cint32")
    type = ImagePixelType_cint32;
  else if (value == "cfloat")
    type = ImagePixelType_cfloat;
  else if (value == "cdouble")
    type = ImagePixelType_cdouble;
  else
    return false;
  return true;
}

void
OutputImageParameter
::InitializeWriters()
{
  ImageBaseType * image = m_Image.GetPointer();

  CAST_IMAGE_BASE( UInt8VectorImageType, image );
  CAST_IMAGE_BASE( Int16VectorImageType, image );
  CAST_IMAGE_BASE( UInt16VectorImageType, image );
  CAST_IMAGE_BASE( Int32VectorImageType, image );
  CAST_IMAGE_BASE( UInt32VectorImageType, image );

  CAST_IMAGE_BASE( FloatVectorImageType, image );
  CAST_IMAGE_BASE( DoubleVectorImageType, image );

  CAST_IMAGE_BASE( ComplexInt16VectorImageType, image );
  CAST_IMAGE_BASE( ComplexInt32VectorImageType, image );
  CAST_IMAGE_BASE( ComplexFloatVectorImageType, image );
  CAST_IMAGE_BASE( ComplexDoubleVectorImageType, image );

  CAST_IMAGE_BASE( UInt8ImageType, image );
  CAST_IMAGE_BASE( Int16ImageType, image );
  CAST_IMAGE_BASE( UInt16ImageType, image );
  CAST_IMAGE_BASE( Int32ImageType, image );
  CAST_IMAGE_BASE( UInt32ImageType, image );

  CAST_IMAGE_BASE( FloatImageType, image );
  CAST_IMAGE_BASE( DoubleImageType, image );

  CAST_IMAGE_BASE( ComplexInt16ImageType, image );
  CAST_IMAGE_BASE( ComplexInt32ImageType, image );
  CAST_IMAGE_BASE( ComplexFloatImageType, image );
  CAST_IMAGE_BASE( ComplexDoubleImageType, image );

  CAST_IMAGE_BASE( UInt8RGBImageType, image );
  CAST_IMAGE_BASE( UInt8RGBAImageType, image );

  itkExceptionMacro( "Unknown image-base type." );
}

template< typename TOutputImage,
	  typename TInputImage >
void
OutputImageParameter
::ClampAndWriteVectorImage( TInputImage * in )
{
  assert( !m_FileName.empty() );

  auto icif =
    ClampImageFilter< TInputImage, DoubleVectorImageType >::New();

  auto clampFilter =
    ClampImageFilter< DoubleVectorImageType , TOutputImage >::New();

  icif->SetInput( in );

  clampFilter->SetInput( icif->GetOutput() );

#ifdef OTB_USE_MPI

  otb::MPIConfig::Pointer mpiConfig = otb::MPIConfig::Instance();

  if( mpiConfig->GetNbProcs() > 1 )
    {
    useStandardWriter = false;

    std::string extension =
      itksys::SystemTools::GetFilenameExtension( m_Filename );

    if(extension == ".vrt")
      {
      // Use the MPIVrtWriter

      auto vrtWriter =
	otb::MPIVrtWriter< TOutputImage >::New();

      vrtWriter->SetInput( clampFilter->GetOutput() );
      vrtWriter->SetFileName( m_Filename );
      vrtWriter->SetAvailableRAM( m_RAMValue);

      // Change internal state only when everything has been setup
      // without raising exception.

      m_InputCaster = icif;
      m_OutputCaster = clampFilter;

      m_Writer = vrtWriter;

      return;
      }

#ifdef OTB_USE_SPTW

    else if (extension == ".tif")
      {
      // Use simple parallel tiff writer

      auto sptWriter =
	otb::SimpleParallelTiffWriter< TOutputImage >::New();

      sptWriter->SetFileName( m_Filename );
      sptWriter->SetInput( clampFilter->GetOutput() );
      sptWriter->GetStreamingManager()->SetDefaultRAM( m_RAMValue );

      // Change internal state only when everything has been setup
      // without raising exception.

      m_InputCaster = icif;
      m_OutputCaster = clampFilter;

      m_Writer = sptWriter;

      return;
      }

#endif // OTB_USE_SPTW

    else
      {
      itkGenericExceptionMacro(
	"File format "
	<< extension
	<< " not supported for parallel writing with MPI. Supported formats are "
	   ".vrt and .tif. Extended filenames are not supported."
      );
      }
    }

#endif // OTB_USE_MPI

  //
  // Use default OTB writer.

  auto writer = otb::ImageFileWriter< TOutputImage >::New();

  writer->SetFileName( m_FileName );
  writer->SetInput( clampFilter->GetOutput() );
  writer->GetStreamingManager()->SetDefaultRAM( m_RAMValue );

  // Change internal state only when everything has been setup
  // without raising exception.

  m_InputCaster = icif;
  m_OutputCaster = clampFilter;

  m_Writer = writer;
}

template< typename TInputImage >
void
OutputImageParameter
::SwitchInput( TInputImage * image )
{
  assert( image );

  switch( m_PixelType )
    {
    case ImagePixelType_uint8:
      ClampAndWriteVectorImage< UInt8VectorImageType >( image );
      break;

    case ImagePixelType_int16:
      ClampAndWriteVectorImage< Int16VectorImageType >( image );
      break;

    case ImagePixelType_uint16:
      ClampAndWriteVectorImage< UInt16VectorImageType >( image );
      break;

    case ImagePixelType_int32:

      ClampAndWriteVectorImage< Int32VectorImageType >( image );
      break;

    case ImagePixelType_uint32:
      ClampAndWriteVectorImage< UInt32VectorImageType >( image );
      break;

    case ImagePixelType_float:
      ClampAndWriteVectorImage< FloatVectorImageType >( image );
      break;

    case ImagePixelType_double:
      ClampAndWriteVectorImage< DoubleVectorImageType >( image );
      break;

    case ImagePixelType_cint16:
      ClampAndWriteVectorImage < ComplexInt16VectorImageType >( image );
      break;

    case ImagePixelType_cint32:
      ClampAndWriteVectorImage < ComplexInt32VectorImageType >( image );
      break;

    case ImagePixelType_cfloat:
      ClampAndWriteVectorImage< ComplexFloatVectorImageType >( image );
    break;

    case ImagePixelType_cdouble:
      ClampAndWriteVectorImage < ComplexDoubleVectorImageType >( image );
    break;

    default:
      assert( false && "Unexpected image-type." );
      break;
    }
}

void
OutputImageParameter::Write()
{
  m_Writer->Update();

  // Clean internal filters
  m_InputCaster = nullptr;
  m_OutputCaster = nullptr;

  m_Writer = nullptr;
}

itk::ProcessObject*
OutputImageParameter::GetWriter()
{
  return m_Writer;
}

ImageBaseType*
OutputImageParameter::GetValue( )
{
  return m_Image;
}

void
OutputImageParameter::SetValue(ImageBaseType* image)
{
  m_Image = image;
  SetActive(true);
}

bool
OutputImageParameter
::HasValue() const
{
  return !m_FileName.empty();
}

std::string
OutputImageParameter::CheckFileName(bool fixMissingExtension)
{
  std::string ret("");
  // Check that there is an ImageIO capable of writing the file
  otb::ExtendedFilenameToWriterOptions::Pointer filenameHelper =
    otb::ExtendedFilenameToWriterOptions::New();
  filenameHelper->SetExtendedFileName(this->GetFileName());
  std::string simpleFilename = filenameHelper->GetSimpleFileName();
  // TODO : check if simpleFilename is empty

  otb::ImageIOBase::Pointer imageIO =
    otb::ImageIOFactory::CreateImageIO(simpleFilename.c_str(),
                                       otb::ImageIOFactory::WriteMode);
  if(imageIO.IsNull())
    {
    // check for missing extension
    std::string outExt = itksys::SystemTools::GetFilenameLastExtension(simpleFilename);
    if (outExt.empty())
      {
      if (fixMissingExtension)
        {
        // try with .tif
        std::string fullFileName(this->GetFileName());
        std::string extendedPart = fullFileName.substr(simpleFilename.size());
        this->SetFileName(simpleFilename+std::string(".tif")+extendedPart);
        ret += std::string("no extension detected, using TIF as default.");
        }
      else
        {
        // TODO : call exception here?
        }
      }
    else
      {
      // TODO : call exception here?
      }
    }
  return ret;
}

// Specialization for UInt8RGBAImageType

template<>
void
OutputImageParameter
::SwitchInput( UInt8RGBAImageType * img )
{
  assert( img );

  if( m_PixelType != ImagePixelType_uint8 )
     itkExceptionMacro("Unknown PixelType for RGBA Image. Only uint8 is supported.");

  auto writer =
    otb::ImageFileWriter< UInt8RGBAImageType >::New();

  writer->SetFileName( GetFileName() );
  writer->SetInput( img );
  writer->GetStreamingManager()->SetDefaultRAM( m_RAMValue );

  m_Writer = writer;
}

// Specialization for UInt8RGBImageType
template<>
void
OutputImageParameter
::SwitchInput( UInt8RGBImageType * img )
{
  if( m_PixelType != ImagePixelType_uint8 )
    itkExceptionMacro("Unknown PixelType for RGB Image. Only uint8 is supported.");

  auto writer = otb::ImageFileWriter< UInt8RGBImageType >::New();

  writer->SetFileName( GetFileName() );
  writer->SetInput( img );
  writer->GetStreamingManager()->SetDefaultRAM( m_RAMValue );

  m_Writer = writer;
}

void OutputImageParameter::SetFileName (const char* filename)
{
  this->SetFileName(std::string(filename));
}

void OutputImageParameter::SetFileName (const std::string& filename)
{
  m_FileName = filename;
  SetActive(true);
}

}
}
<|endoftext|>


<commit_before>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "mitkGetPropertyService.h"
#include "QmitkAddNewPropertyDialog.h"
#include "QmitkPropertiesPreferencePage.h"
#include "QmitkPropertyItemDelegate.h"
#include "QmitkPropertyItemModel.h"
#include "QmitkPropertyItemSortFilterProxyModel.h"
#include "QmitkPropertyTreeView.h"
#include <berryIBerryPreferences.h>
#include <mitkIPropertyAliases.h>
#include <mitkIPropertyDescriptions.h>
#include <QmitkRenderWindow.h>
#include <QPainter>

const std::string QmitkPropertyTreeView::VIEW_ID = "org.mitk.views.properties";

QmitkPropertyTreeView::QmitkPropertyTreeView()
  : m_Parent(NULL),
    m_PropertyNameChangedTag(0),
    m_PropertyAliases(NULL),
    m_PropertyDescriptions(NULL),
    m_ShowAliasesInDescription(true),
    m_DeveloperMode(false),
    m_ProxyModel(NULL),
    m_Model(NULL),
    m_Delegate(NULL),
    m_Renderer(NULL)
{
}

QmitkPropertyTreeView::~QmitkPropertyTreeView()
{
}

void QmitkPropertyTreeView::CreateQtPartControl(QWidget* parent)
{
  m_Parent = parent;

  m_Controls.setupUi(parent);

  m_Controls.propertyListComboBox->addItem("global");

  m_Controls.newButton->setEnabled(false);

  m_Controls.description->hide();
  m_Controls.propertyListLabel->hide();
  m_Controls.propertyListComboBox->hide();
  m_Controls.newButton->hide();

  m_ProxyModel = new QmitkPropertyItemSortFilterProxyModel(m_Controls.treeView);
  m_Model = new QmitkPropertyItemModel(m_ProxyModel);

  m_ProxyModel->setSourceModel(m_Model);
  m_ProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
  m_ProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
  m_ProxyModel->setDynamicSortFilter(true);

  m_Delegate = new QmitkPropertyItemDelegate(m_Controls.treeView);

  m_Controls.treeView->setItemDelegateForColumn(1, m_Delegate);
  m_Controls.treeView->setModel(m_ProxyModel);
  m_Controls.treeView->setColumnWidth(0, 180);
  m_Controls.treeView->sortByColumn(0, Qt::AscendingOrder);
  m_Controls.treeView->setSelectionBehavior(QAbstractItemView::SelectRows);
  m_Controls.treeView->setSelectionMode(QAbstractItemView::SingleSelection);
  m_Controls.treeView->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::DoubleClicked);

  connect(m_Controls.filterLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(OnFilterTextChanged(const QString&)));
  connect(m_Controls.propertyListComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnPropertyListChanged(int)));
  connect(m_Controls.newButton, SIGNAL(clicked()), this, SLOT(OnAddNewProperty()));
  connect(m_Controls.treeView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(OnCurrentRowChanged(const QModelIndex&, const QModelIndex&)));
  connect(m_Model, SIGNAL(modelReset()), this, SLOT(OnModelReset()));
}

QString QmitkPropertyTreeView::GetPropertyNameOrAlias(const QModelIndex& index)
{
  QString propertyName;

  if (index.isValid())
  {
    QModelIndex current = index;

    while (current.isValid())
    {
      QString name = m_ProxyModel->data(m_ProxyModel->index(current.row(), 0, current.parent())).toString();

      propertyName.prepend(propertyName.isEmpty()
        ? name
        : name.append('.'));

      current = current.parent();
    }
  }

  return propertyName;
}

void QmitkPropertyTreeView::OnCurrentRowChanged(const QModelIndex& current, const QModelIndex&)
{
  if (m_PropertyDescriptions != NULL && current.isValid())
  {
    QString name = this->GetPropertyNameOrAlias(current);

    if (!name.isEmpty())
    {
      QString alias;
      bool isTrueName = true;

      if (m_PropertyAliases != NULL)
      {
        std::string trueName = m_PropertyAliases->GetPropertyName(name.toStdString());

        if (trueName.empty() && !m_SelectionClassName.empty())
          trueName = m_PropertyAliases->GetPropertyName(name.toStdString(), m_SelectionClassName);

        if (!trueName.empty())
        {
          alias = name;
          name = QString::fromStdString(trueName);
          isTrueName = false;
        }
      }

      QString description = QString::fromStdString(m_PropertyDescriptions->GetDescription(name.toStdString()));
      std::vector<std::string> aliases;

      if (!isTrueName && m_PropertyAliases != NULL)
      {
        aliases = m_PropertyAliases->GetAliases(name.toStdString(), m_SelectionClassName);

        if (aliases.empty() && !m_SelectionClassName.empty())
          aliases = m_PropertyAliases->GetAliases(name.toStdString());
      }

      if (!description.isEmpty() || !aliases.empty())
      {
        QString customizedDescription;

        if (m_ShowAliasesInDescription && !aliases.empty())
        {
          customizedDescription = "
" + name + "
";

          std::size_t numAliases = aliases.size();
          std::size_t lastAlias = numAliases - 1;

          for (std::size_t i = 0; i < numAliases; ++i)
          {
            customizedDescription += i != lastAlias
              ? "
"
              : "
";

            customizedDescription += QString::fromStdString(aliases[i]) + "
";
          }
        }
        else
        {
          customizedDescription = "
" + name + "
";
        }

        if (!description.isEmpty())
          customizedDescription += description;

        m_Controls.description->setText(customizedDescription);
        m_Controls.description->show();

        return;
      }
    }
  }

  m_Controls.description->hide();
}

void QmitkPropertyTreeView::OnFilterTextChanged(const QString& filter)
{
  m_ProxyModel->setFilterWildcard(filter);

  if (filter.isEmpty())
    m_Controls.treeView->collapseAll();
  else
    m_Controls.treeView->expandAll();
}

void QmitkPropertyTreeView::OnModelReset()
{
  m_Controls.description->hide();
}

void QmitkPropertyTreeView::OnPreferencesChanged(const berry::IBerryPreferences* preferences)
{
  bool showAliases = preferences->GetBool(QmitkPropertiesPreferencePage::SHOW_ALIASES, true);
  bool showDescriptions = preferences->GetBool(QmitkPropertiesPreferencePage::SHOW_DESCRIPTIONS, true);
  bool showAliasesInDescription = preferences->GetBool(QmitkPropertiesPreferencePage::SHOW_ALIASES_IN_DESCRIPTION, true);
  bool developerMode = preferences->GetBool(QmitkPropertiesPreferencePage::DEVELOPER_MODE, true);

  bool updateAliases = showAliases != (m_PropertyAliases != NULL);
  bool updateDescriptions = showDescriptions != (m_PropertyDescriptions != NULL);
  bool updateAliasesInDescription = showAliasesInDescription != m_ShowAliasesInDescription;
  bool updateDeveloperMode = developerMode != m_DeveloperMode;

  if (updateAliases)
    m_PropertyAliases = showAliases
      ? mitk::GetPropertyService<mitk::IPropertyAliases>()
      : NULL;

  if (updateDescriptions)
    m_PropertyDescriptions = showDescriptions
      ? mitk::GetPropertyService<mitk::IPropertyDescriptions>()
      : NULL;

  if (updateAliasesInDescription)
    m_ShowAliasesInDescription = showAliasesInDescription;

  if (updateDescriptions || updateAliasesInDescription)
  {
    QModelIndexList selection = m_Controls.treeView->selectionModel()->selectedRows();

    if (!selection.isEmpty())
      this->OnCurrentRowChanged(selection[0], selection[0]);
  }

  if (updateDeveloperMode)
  {
    m_DeveloperMode = developerMode;

    if (!developerMode)
      m_Controls.propertyListComboBox->setCurrentIndex(0);

    m_Controls.propertyListLabel->setVisible(developerMode);
    m_Controls.propertyListComboBox->setVisible(developerMode);
    m_Controls.newButton->setVisible(developerMode);
  }

  m_Model->OnPreferencesChanged(preferences);
}

void QmitkPropertyTreeView::OnPropertyNameChanged(const itk::EventObject&)
{
  mitk::PropertyList* propertyList = m_Model->GetPropertyList();

  if (propertyList != NULL)
  {
    mitk::BaseProperty* nameProperty = propertyList->GetProperty("name");

    if (nameProperty != NULL)
    {
      std::ostringstream partName;
      partName << "Properties (" << nameProperty->GetValueAsString() << ')';
      this->SetPartName(partName.str());
    }
  }
}

void QmitkPropertyTreeView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList<mitk::DataNode::Pointer>& nodes)
{
  mitk::PropertyList* propertyList = m_Model->GetPropertyList();

  if (propertyList != NULL)
  {
    mitk::BaseProperty* nameProperty = propertyList->GetProperty("name");

    if (nameProperty != NULL)
      nameProperty->RemoveObserver(m_PropertyNameChangedTag);

    m_PropertyNameChangedTag = 0;
  }

  if (nodes.empty() || nodes.front().IsNull())
  {
    m_SelectedNode = NULL;

    this->SetPartName("Properties");
    m_Model->SetPropertyList(NULL);
    m_Delegate->SetPropertyList(NULL);

    m_Controls.newButton->setEnabled(false);
  }
  else
  {
    m_SelectedNode = nodes.front();

    QString selectionClassName = m_SelectedNode->GetData() != NULL
      ? m_SelectedNode->GetData()->GetNameOfClass()
      : "";

    m_SelectionClassName = selectionClassName.toStdString();
    m_Model->SetPropertyList(m_SelectedNode->GetPropertyList(m_Renderer), selectionClassName);
    m_Delegate->SetPropertyList(m_SelectedNode->GetPropertyList(m_Renderer));
    OnPropertyNameChanged(itk::ModifiedEvent());

    mitk::BaseProperty* nameProperty = m_SelectedNode->GetProperty("name");

    if (nameProperty != NULL)
    {
      itk::ReceptorMemberCommand<QmitkPropertyTreeView>::Pointer command = itk::ReceptorMemberCommand<QmitkPropertyTreeView>::New();
      command->SetCallbackFunction(this, &QmitkPropertyTreeView::OnPropertyNameChanged);
      m_PropertyNameChangedTag = nameProperty->AddObserver(itk::ModifiedEvent(), command);
    }

    m_Controls.newButton->setEnabled(true);
  }

  if (!m_ProxyModel->filterRegExp().isEmpty())
    m_Controls.treeView->expandAll();
}

void QmitkPropertyTreeView::SetFocus()
{
  m_Controls.filterLineEdit->setFocus();
}

void QmitkPropertyTreeView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart)
{
  QHash<QString, QmitkRenderWindow*> renderWindows = this->GetRenderWindowPart()->GetQmitkRenderWindows();

  Q_FOREACH(QString renderWindow, renderWindows.keys())
  {
    m_Controls.propertyListComboBox->addItem(renderWindow);
  }
}

void QmitkPropertyTreeView::RenderWindowPartDeactivated(mitk::IRenderWindowPart*)
{
  m_Controls.propertyListComboBox->clear();
  m_Controls.propertyListComboBox->addItem("global");
}

void QmitkPropertyTreeView::OnPropertyListChanged(int index)
{
  if (index == -1)
    return;

  QString renderWindow = m_Controls.propertyListComboBox->itemText(index);

  m_Renderer = renderWindow != "global"
    ? this->GetRenderWindowPart()->GetQmitkRenderWindow(renderWindow)->GetRenderer()
    : NULL;

  QList<mitk::DataNode::Pointer> nodes;

  if (m_SelectedNode.IsNotNull())
    nodes << m_SelectedNode;

  berry::IWorkbenchPart::Pointer workbenchPart;

  this->OnSelectionChanged(workbenchPart, nodes);
}

void QmitkPropertyTreeView::OnAddNewProperty()
{
  QmitkAddNewPropertyDialog dialog(m_SelectedNode, m_Renderer, m_Parent);

  if (dialog.exec() == QDialog::Accepted)
    this->m_Model->Update();
}
<commit_msg>Made creation of property list combo box items more robust regarding re-opening the properties view.<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "mitkGetPropertyService.h"
#include "QmitkAddNewPropertyDialog.h"
#include "QmitkPropertiesPreferencePage.h"
#include "QmitkPropertyItemDelegate.h"
#include "QmitkPropertyItemModel.h"
#include "QmitkPropertyItemSortFilterProxyModel.h"
#include "QmitkPropertyTreeView.h"
#include <berryIBerryPreferences.h>
#include <mitkIPropertyAliases.h>
#include <mitkIPropertyDescriptions.h>
#include <QmitkRenderWindow.h>
#include <QPainter>

const std::string QmitkPropertyTreeView::VIEW_ID = "org.mitk.views.properties";

QmitkPropertyTreeView::QmitkPropertyTreeView()
  : m_Parent(NULL),
    m_PropertyNameChangedTag(0),
    m_PropertyAliases(NULL),
    m_PropertyDescriptions(NULL),
    m_ShowAliasesInDescription(true),
    m_DeveloperMode(false),
    m_ProxyModel(NULL),
    m_Model(NULL),
    m_Delegate(NULL),
    m_Renderer(NULL)
{
}

QmitkPropertyTreeView::~QmitkPropertyTreeView()
{
}

void QmitkPropertyTreeView::CreateQtPartControl(QWidget* parent)
{
  m_Parent = parent;

  m_Controls.setupUi(parent);

  m_Controls.propertyListComboBox->addItem("independent");

  mitk::IRenderWindowPart* renderWindowPart = this->GetRenderWindowPart();

  if (renderWindowPart != NULL)
  {
    QHash<QString, QmitkRenderWindow*> renderWindows = renderWindowPart->GetQmitkRenderWindows();

    Q_FOREACH(QString renderWindow, renderWindows.keys())
    {
      m_Controls.propertyListComboBox->addItem(renderWindow);
    }
  }

  m_Controls.newButton->setEnabled(false);

  m_Controls.description->hide();
  m_Controls.propertyListLabel->hide();
  m_Controls.propertyListComboBox->hide();
  m_Controls.newButton->hide();

  m_ProxyModel = new QmitkPropertyItemSortFilterProxyModel(m_Controls.treeView);
  m_Model = new QmitkPropertyItemModel(m_ProxyModel);

  m_ProxyModel->setSourceModel(m_Model);
  m_ProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
  m_ProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
  m_ProxyModel->setDynamicSortFilter(true);

  m_Delegate = new QmitkPropertyItemDelegate(m_Controls.treeView);

  m_Controls.treeView->setItemDelegateForColumn(1, m_Delegate);
  m_Controls.treeView->setModel(m_ProxyModel);
  m_Controls.treeView->setColumnWidth(0, 160);
  m_Controls.treeView->sortByColumn(0, Qt::AscendingOrder);
  m_Controls.treeView->setSelectionBehavior(QAbstractItemView::SelectRows);
  m_Controls.treeView->setSelectionMode(QAbstractItemView::SingleSelection);
  m_Controls.treeView->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::DoubleClicked);

  connect(m_Controls.filterLineEdit, SIGNAL(textChanged(const QString&)), this, SLOT(OnFilterTextChanged(const QString&)));
  connect(m_Controls.propertyListComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnPropertyListChanged(int)));
  connect(m_Controls.newButton, SIGNAL(clicked()), this, SLOT(OnAddNewProperty()));
  connect(m_Controls.treeView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(OnCurrentRowChanged(const QModelIndex&, const QModelIndex&)));
  connect(m_Model, SIGNAL(modelReset()), this, SLOT(OnModelReset()));
}

QString QmitkPropertyTreeView::GetPropertyNameOrAlias(const QModelIndex& index)
{
  QString propertyName;

  if (index.isValid())
  {
    QModelIndex current = index;

    while (current.isValid())
    {
      QString name = m_ProxyModel->data(m_ProxyModel->index(current.row(), 0, current.parent())).toString();

      propertyName.prepend(propertyName.isEmpty()
        ? name
        : name.append('.'));

      current = current.parent();
    }
  }

  return propertyName;
}

void QmitkPropertyTreeView::OnCurrentRowChanged(const QModelIndex& current, const QModelIndex&)
{
  if (m_PropertyDescriptions != NULL && current.isValid())
  {
    QString name = this->GetPropertyNameOrAlias(current);

    if (!name.isEmpty())
    {
      QString alias;
      bool isTrueName = true;

      if (m_PropertyAliases != NULL)
      {
        std::string trueName = m_PropertyAliases->GetPropertyName(name.toStdString());

        if (trueName.empty() && !m_SelectionClassName.empty())
          trueName = m_PropertyAliases->GetPropertyName(name.toStdString(), m_SelectionClassName);

        if (!trueName.empty())
        {
          alias = name;
          name = QString::fromStdString(trueName);
          isTrueName = false;
        }
      }

      QString description = QString::fromStdString(m_PropertyDescriptions->GetDescription(name.toStdString()));
      std::vector<std::string> aliases;

      if (!isTrueName && m_PropertyAliases != NULL)
      {
        aliases = m_PropertyAliases->GetAliases(name.toStdString(), m_SelectionClassName);

        if (aliases.empty() && !m_SelectionClassName.empty())
          aliases = m_PropertyAliases->GetAliases(name.toStdString());
      }

      if (!description.isEmpty() || !aliases.empty())
      {
        QString customizedDescription;

        if (m_ShowAliasesInDescription && !aliases.empty())
        {
          customizedDescription = "
" + name + "
";

          std::size_t numAliases = aliases.size();
          std::size_t lastAlias = numAliases - 1;

          for (std::size_t i = 0; i < numAliases; ++i)
          {
            customizedDescription += i != lastAlias
              ? "
"
              : "
";

            customizedDescription += QString::fromStdString(aliases[i]) + "
";
          }
        }
        else
        {
          customizedDescription = "
" + name + "
";
        }

        if (!description.isEmpty())
          customizedDescription += description;

        m_Controls.description->setText(customizedDescription);
        m_Controls.description->show();

        return;
      }
    }
  }

  m_Controls.description->hide();
}

void QmitkPropertyTreeView::OnFilterTextChanged(const QString& filter)
{
  m_ProxyModel->setFilterWildcard(filter);

  if (filter.isEmpty())
    m_Controls.treeView->collapseAll();
  else
    m_Controls.treeView->expandAll();
}

void QmitkPropertyTreeView::OnModelReset()
{
  m_Controls.description->hide();
}

void QmitkPropertyTreeView::OnPreferencesChanged(const berry::IBerryPreferences* preferences)
{
  bool showAliases = preferences->GetBool(QmitkPropertiesPreferencePage::SHOW_ALIASES, true);
  bool showDescriptions = preferences->GetBool(QmitkPropertiesPreferencePage::SHOW_DESCRIPTIONS, true);
  bool showAliasesInDescription = preferences->GetBool(QmitkPropertiesPreferencePage::SHOW_ALIASES_IN_DESCRIPTION, true);
  bool developerMode = preferences->GetBool(QmitkPropertiesPreferencePage::DEVELOPER_MODE, false);

  bool updateAliases = showAliases != (m_PropertyAliases != NULL);
  bool updateDescriptions = showDescriptions != (m_PropertyDescriptions != NULL);
  bool updateAliasesInDescription = showAliasesInDescription != m_ShowAliasesInDescription;
  bool updateDeveloperMode = developerMode != m_DeveloperMode;

  if (updateAliases)
    m_PropertyAliases = showAliases
      ? mitk::GetPropertyService<mitk::IPropertyAliases>()
      : NULL;

  if (updateDescriptions)
    m_PropertyDescriptions = showDescriptions
      ? mitk::GetPropertyService<mitk::IPropertyDescriptions>()
      : NULL;

  if (updateAliasesInDescription)
    m_ShowAliasesInDescription = showAliasesInDescription;

  if (updateDescriptions || updateAliasesInDescription)
  {
    QModelIndexList selection = m_Controls.treeView->selectionModel()->selectedRows();

    if (!selection.isEmpty())
      this->OnCurrentRowChanged(selection[0], selection[0]);
  }

  if (updateDeveloperMode)
  {
    m_DeveloperMode = developerMode;

    if (!developerMode)
      m_Controls.propertyListComboBox->setCurrentIndex(0);

    m_Controls.propertyListLabel->setVisible(developerMode);
    m_Controls.propertyListComboBox->setVisible(developerMode);
    m_Controls.newButton->setVisible(developerMode);
  }

  m_Model->OnPreferencesChanged(preferences);
}

void QmitkPropertyTreeView::OnPropertyNameChanged(const itk::EventObject&)
{
  mitk::PropertyList* propertyList = m_Model->GetPropertyList();

  if (propertyList != NULL)
  {
    mitk::BaseProperty* nameProperty = propertyList->GetProperty("name");

    if (nameProperty != NULL)
    {
      std::ostringstream partName;
      partName << "Properties (" << nameProperty->GetValueAsString() << ')';
      this->SetPartName(partName.str());
    }
  }
}

void QmitkPropertyTreeView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList<mitk::DataNode::Pointer>& nodes)
{
  mitk::PropertyList* propertyList = m_Model->GetPropertyList();

  if (propertyList != NULL)
  {
    mitk::BaseProperty* nameProperty = propertyList->GetProperty("name");

    if (nameProperty != NULL)
      nameProperty->RemoveObserver(m_PropertyNameChangedTag);

    m_PropertyNameChangedTag = 0;
  }

  if (nodes.empty() || nodes.front().IsNull())
  {
    m_SelectedNode = NULL;

    this->SetPartName("Properties");
    m_Model->SetPropertyList(NULL);
    m_Delegate->SetPropertyList(NULL);

    m_Controls.newButton->setEnabled(false);
  }
  else
  {
    m_SelectedNode = nodes.front();

    QString selectionClassName = m_SelectedNode->GetData() != NULL
      ? m_SelectedNode->GetData()->GetNameOfClass()
      : "";

    m_SelectionClassName = selectionClassName.toStdString();
    m_Model->SetPropertyList(m_SelectedNode->GetPropertyList(m_Renderer), selectionClassName);
    m_Delegate->SetPropertyList(m_SelectedNode->GetPropertyList(m_Renderer));
    OnPropertyNameChanged(itk::ModifiedEvent());

    mitk::BaseProperty* nameProperty = m_SelectedNode->GetProperty("name");

    if (nameProperty != NULL)
    {
      itk::ReceptorMemberCommand<QmitkPropertyTreeView>::Pointer command = itk::ReceptorMemberCommand<QmitkPropertyTreeView>::New();
      command->SetCallbackFunction(this, &QmitkPropertyTreeView::OnPropertyNameChanged);
      m_PropertyNameChangedTag = nameProperty->AddObserver(itk::ModifiedEvent(), command);
    }

    m_Controls.newButton->setEnabled(true);
  }

  if (!m_ProxyModel->filterRegExp().isEmpty())
    m_Controls.treeView->expandAll();
}

void QmitkPropertyTreeView::SetFocus()
{
  m_Controls.filterLineEdit->setFocus();
}

void QmitkPropertyTreeView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart)
{
  if (m_Controls.propertyListComboBox->count() == 1)
  {
    QHash<QString, QmitkRenderWindow*> renderWindows = this->GetRenderWindowPart()->GetQmitkRenderWindows();

    Q_FOREACH(QString renderWindow, renderWindows.keys())
    {
      m_Controls.propertyListComboBox->addItem(renderWindow);
    }
  }
}

void QmitkPropertyTreeView::RenderWindowPartDeactivated(mitk::IRenderWindowPart*)
{
  if (m_Controls.propertyListComboBox->count() > 1)
  {
    m_Controls.propertyListComboBox->clear();
    m_Controls.propertyListComboBox->addItem("independent");
  }
}

void QmitkPropertyTreeView::OnPropertyListChanged(int index)
{
  if (index == -1)
    return;

  QString renderer = m_Controls.propertyListComboBox->itemText(index);

  m_Renderer = renderer != "independent"
    ? this->GetRenderWindowPart()->GetQmitkRenderWindow(renderer)->GetRenderer()
    : NULL;

  QList<mitk::DataNode::Pointer> nodes;

  if (m_SelectedNode.IsNotNull())
    nodes << m_SelectedNode;

  berry::IWorkbenchPart::Pointer workbenchPart;

  this->OnSelectionChanged(workbenchPart, nodes);
}

void QmitkPropertyTreeView::OnAddNewProperty()
{
  QmitkAddNewPropertyDialog dialog(m_SelectedNode, m_Renderer, m_Parent);

  if (dialog.exec() == QDialog::Accepted)
    this->m_Model->Update();
}
<|endoftext|>


<commit_before>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/// This test is based on Truth Cube experimental dataset that is obtained from:
/// "Establishing Physical Standards for Real Time Soft Tissue Simulation" project.
///  URL: http://biorobotics.harvard.edu/truthcube/truthcube.html

#include "SurgSim/Physics/RenderTests/RenderTest.h"

#include "SurgSim/Framework/ApplicationData.h"
#include "SurgSim/Graphics/PointCloudRepresentation.h"
#include "SurgSim/Graphics/OsgPointCloudRepresentation.h"
#include "SurgSim/Math/Quaternion.h"
#include "SurgSim/Math/Vector.h"
#include "SurgSim/Math/RigidTransform.h"

using SurgSim::Math::Vector3d;
using SurgSim::Math::Quaterniond;
using SurgSim::Math::RigidTransform3d;
using SurgSim::Math::makeRigidTransform;

namespace SurgSim
{
namespace Physics
{

typedef SurgSim::DataStructures::Vertices<void> CloudMesh;

struct TruthCube
{
	// Data positions of uncompressed data
	std::vector<Vector3d> cubeData0;

	// Data positions of 5% strain
	std::vector<Vector3d> cubeData1;

	// Data positions of  12.5% strain
	std::vector<Vector3d> cubeData2;

	// Data positions of  18.25% strain
	std::vector<Vector3d> cubeData3;
};

struct TruthCubeRenderTests : public RenderTests
{
	/// Parsing Truth Cube data from an external file
	/// \param truthCube a container of cube data for all strains
	/// \return True if the Truth Cube Data is successful loaded, otherwise false
	bool parseTruthCubeData(std::shared_ptr<TruthCube> truthCube)
	{
		// Position of uncompressed data, 5% strain, 12.5% strain, 18.25% strain
		Vector3d position0, position1, position2, position3;

		const int numCommentLine = 7;
		std::string lineId;
		char comma;
		int i,j,k, index = 0;

		const SurgSim::Framework::ApplicationData data("config.txt");

		std::string filename = data.findFile("uniaxial_positions.csv");

		std::ifstream datafile(filename);

		if (! datafile.good())
		{
			return false;
		}

		while (std::getline(datafile, lineId))
			if (++index > numCommentLine)
			{
				std::stringstream strstream(lineId);
				strstream >> i >> comma >> j >> comma >> k >> comma
					>> position0.x() >> comma >> position0.y() >> comma >> position0.z() >> comma
					>> position1.x() >> comma >> position1.y() >> comma >> position1.z() >> comma
					>> position2.x() >> comma >> position2.y() >> comma >> position2.z() >> comma
					>> position3.x() >> comma >> position3.y() >> comma >> position3.z();

				// Store proper strains for each cubeData
				truthCube->cubeData0.push_back(position0);
				truthCube->cubeData1.push_back(position1);
				truthCube->cubeData2.push_back(position2);
				truthCube->cubeData3.push_back(position3);
			}

			return true;

	};

	void doInitialize()
	{
		// Initialize truthCube variable
		truthCube = std::make_shared<TruthCube>();

		// Parsing TruthCube data
		parseTruthCubeData(truthCube);
	};

	void runTest(std::shared_ptr<SurgSim::Graphics::OsgPointCloudRepresentation<void>> representation)
	{
		representation->setPointSize(4.0);
		RigidTransform3d pose = makeRigidTransform(Quaterniond::Identity(), Vector3d::Zero());
		representation->setInitialPose(pose);

		viewElement->addComponent(representation);
		viewElement->enableManipulator(true);
		viewElement->setManipulatorParameters(Vector3d(0.0, 140.0, 0.0), Vector3d::Zero());

		/// Run the thread
		runtime->start();

		boost::this_thread::sleep(boost::posix_time::milliseconds(3000));
	}

	std::shared_ptr<TruthCube> truthCube;
};

TEST_F(TruthCubeRenderTests, LoadTruthCubeData_Uncompressed)
{
	doInitialize();

	auto representation = std::make_shared<SurgSim::Graphics::OsgPointCloudRepresentation<void>>
		("TruthCube uncompressed");
	auto pointCloud = representation->getVertices();

	/// Loading the Truth Cube uncompressed data into point cloud
	for (size_t i = 0; i < truthCube->cubeData0.size(); ++i)
	{
		pointCloud->addVertex(CloudMesh::VertexType(truthCube->cubeData0[i]));
	}

	runTest(representation);
}

TEST_F(TruthCubeRenderTests, LoadTruthCubeData_Compressed_5)
{
	doInitialize();

	auto representation = std::make_shared<SurgSim::Graphics::OsgPointCloudRepresentation<void>>
		("TruthCube 5% strain");
	auto pointCloud = representation->getVertices();

	/// Loading the Truth Cube data into point cloud
	for (size_t i = 0; i < truthCube->cubeData1.size(); ++i)
	{
		pointCloud->addVertex(CloudMesh::VertexType(truthCube->cubeData1[i]));
	}

	runTest(representation);
}

TEST_F(TruthCubeRenderTests, LoadTruthCubeData_Compressed_12_5)
{
	doInitialize();

	auto representation = std::make_shared<SurgSim::Graphics::OsgPointCloudRepresentation<void>>
		("TruthCube 12.5 strain");
	auto pointCloud = representation->getVertices();

	/// Loading the Truth Cube data into point cloud
	for (size_t i = 0; i < truthCube->cubeData2.size(); ++i)
	{
		pointCloud->addVertex(CloudMesh::VertexType(truthCube->cubeData2[i]));
	}

	runTest(representation);
}

TEST_F(TruthCubeRenderTests, LoadTruthCubeData_Compressed_18_25)
{
	doInitialize();

	auto representation = std::make_shared<SurgSim::Graphics::OsgPointCloudRepresentation<void>>
		("TruthCube 18.25%");
	auto pointCloud = representation->getVertices();

	/// Loading the Truth Cube data into point cloud
	for (size_t i = 0; i < truthCube->cubeData3.size(); ++i)
	{
		pointCloud->addVertex(CloudMesh::VertexType(truthCube->cubeData3[i]));
	}

	runTest(representation);
}

}; // namespace Physics
}; // namespace SurgSim
<commit_msg>Add curly braces to while loop statement.<commit_after>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/// This test is based on Truth Cube experimental dataset that is obtained from:
/// "Establishing Physical Standards for Real Time Soft Tissue Simulation" project.
///  URL: http://biorobotics.harvard.edu/truthcube/truthcube.html

#include "SurgSim/Physics/RenderTests/RenderTest.h"

#include "SurgSim/Framework/ApplicationData.h"
#include "SurgSim/Graphics/PointCloudRepresentation.h"
#include "SurgSim/Graphics/OsgPointCloudRepresentation.h"
#include "SurgSim/Math/Quaternion.h"
#include "SurgSim/Math/Vector.h"
#include "SurgSim/Math/RigidTransform.h"

using SurgSim::Math::Vector3d;
using SurgSim::Math::Quaterniond;
using SurgSim::Math::RigidTransform3d;
using SurgSim::Math::makeRigidTransform;

namespace SurgSim
{
namespace Physics
{

typedef SurgSim::DataStructures::Vertices<void> CloudMesh;

struct TruthCube
{
	// Data positions of uncompressed data
	std::vector<Vector3d> cubeData0;

	// Data positions of 5% strain
	std::vector<Vector3d> cubeData1;

	// Data positions of  12.5% strain
	std::vector<Vector3d> cubeData2;

	// Data positions of  18.25% strain
	std::vector<Vector3d> cubeData3;
};

struct TruthCubeRenderTests : public RenderTests
{
	/// Parsing Truth Cube data from an external file
	/// \param truthCube a container of cube data for all strains
	/// \return True if the Truth Cube Data is successful loaded, otherwise false
	bool parseTruthCubeData(std::shared_ptr<TruthCube> truthCube)
	{
		// Position of uncompressed data, 5% strain, 12.5% strain, 18.25% strain
		Vector3d position0, position1, position2, position3;

		const int numCommentLine = 7;
		std::string lineId;
		char comma;
		int i,j,k, index = 0;

		const SurgSim::Framework::ApplicationData data("config.txt");

		std::string filename = data.findFile("uniaxial_positions.csv");

		std::ifstream datafile(filename);

		if (! datafile.good())
		{
			return false;
		}

		while (std::getline(datafile, lineId))
		{
			if (++index > numCommentLine)
			{
				std::stringstream strstream(lineId);
				strstream >> i >> comma >> j >> comma >> k >> comma
					>> position0.x() >> comma >> position0.y() >> comma >> position0.z() >> comma
					>> position1.x() >> comma >> position1.y() >> comma >> position1.z() >> comma
					>> position2.x() >> comma >> position2.y() >> comma >> position2.z() >> comma
					>> position3.x() >> comma >> position3.y() >> comma >> position3.z();

				// Store proper strains for each cubeData
				truthCube->cubeData0.push_back(position0);
				truthCube->cubeData1.push_back(position1);
				truthCube->cubeData2.push_back(position2);
				truthCube->cubeData3.push_back(position3);
			}
		}
			return true;

	};

	void doInitialize()
	{
		// Initialize truthCube variable
		truthCube = std::make_shared<TruthCube>();

		// Parsing TruthCube data
		parseTruthCubeData(truthCube);
	};

	void runTest(std::shared_ptr<SurgSim::Graphics::OsgPointCloudRepresentation<void>> representation)
	{
		representation->setPointSize(4.0);
		RigidTransform3d pose = makeRigidTransform(Quaterniond::Identity(), Vector3d::Zero());
		representation->setInitialPose(pose);

		viewElement->addComponent(representation);
		viewElement->enableManipulator(true);
		viewElement->setManipulatorParameters(Vector3d(0.0, 140.0, 0.0), Vector3d::Zero());

		/// Run the thread
		runtime->start();

		boost::this_thread::sleep(boost::posix_time::milliseconds(3000));
	}

	std::shared_ptr<TruthCube> truthCube;
};

TEST_F(TruthCubeRenderTests, LoadTruthCubeData_Uncompressed)
{
	doInitialize();

	auto representation = std::make_shared<SurgSim::Graphics::OsgPointCloudRepresentation<void>>
		("TruthCube uncompressed");
	auto pointCloud = representation->getVertices();

	/// Loading the Truth Cube uncompressed data into point cloud
	for (size_t i = 0; i < truthCube->cubeData0.size(); ++i)
	{
		pointCloud->addVertex(CloudMesh::VertexType(truthCube->cubeData0[i]));
	}

	runTest(representation);
}

TEST_F(TruthCubeRenderTests, LoadTruthCubeData_Compressed_5)
{
	doInitialize();

	auto representation = std::make_shared<SurgSim::Graphics::OsgPointCloudRepresentation<void>>
		("TruthCube 5% strain");
	auto pointCloud = representation->getVertices();

	/// Loading the Truth Cube data into point cloud
	for (size_t i = 0; i < truthCube->cubeData1.size(); ++i)
	{
		pointCloud->addVertex(CloudMesh::VertexType(truthCube->cubeData1[i]));
	}

	runTest(representation);
}

TEST_F(TruthCubeRenderTests, LoadTruthCubeData_Compressed_12_5)
{
	doInitialize();

	auto representation = std::make_shared<SurgSim::Graphics::OsgPointCloudRepresentation<void>>
		("TruthCube 12.5 strain");
	auto pointCloud = representation->getVertices();

	/// Loading the Truth Cube data into point cloud
	for (size_t i = 0; i < truthCube->cubeData2.size(); ++i)
	{
		pointCloud->addVertex(CloudMesh::VertexType(truthCube->cubeData2[i]));
	}

	runTest(representation);
}

TEST_F(TruthCubeRenderTests, LoadTruthCubeData_Compressed_18_25)
{
	doInitialize();

	auto representation = std::make_shared<SurgSim::Graphics::OsgPointCloudRepresentation<void>>
		("TruthCube 18.25%");
	auto pointCloud = representation->getVertices();

	/// Loading the Truth Cube data into point cloud
	for (size_t i = 0; i < truthCube->cubeData3.size(); ++i)
	{
		pointCloud->addVertex(CloudMesh::VertexType(truthCube->cubeData3[i]));
	}

	runTest(representation);
}

}; // namespace Physics
}; // namespace SurgSim
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "InactivityMonitor.h"

#include "ReadChecker.h"
#include "WriteChecker.h"

#include <activemq/threads/CompositeTask.h>
#include <activemq/threads/CompositeTaskRunner.h>
#include <activemq/commands/WireFormatInfo.h>
#include <activemq/commands/KeepAliveInfo.h>

#include <decaf/lang/Math.h>
#include <decaf/lang/Thread.h>
#include <decaf/lang/Runnable.h>
#include <decaf/lang/Boolean.h>

using namespace std;
using namespace activemq;
using namespace activemq::commands;
using namespace activemq::threads;
using namespace activemq::transport;
using namespace activemq::transport::inactivity;
using namespace activemq::exceptions;
using namespace activemq::wireformat;
using namespace decaf;
using namespace decaf::io;
using namespace decaf::util;
using namespace decaf::util::concurrent;
using namespace decaf::util::concurrent::atomic;
using namespace decaf::lang;
using namespace decaf::lang::exceptions;

////////////////////////////////////////////////////////////////////////////////
namespace activemq{
namespace transport{
namespace inactivity{

    class InactivityMonitorData {
    public:

        // The configured WireFormat for the Transport Chain.
        Pointer<WireFormat> wireFormat;

        // Local and Remote WireFormat information.
        Pointer<WireFormatInfo> localWireFormatInfo;
        Pointer<WireFormatInfo> remoteWireFormatInfo;

        Pointer<ReadChecker> readCheckerTask;
        Pointer<WriteChecker> writeCheckerTask;

        Timer readCheckTimer;
        Timer writeCheckTimer;

        Pointer<CompositeTaskRunner> asyncTasks;

        Pointer<AsyncSignalReadErrorkTask> asyncReadTask;
        Pointer<AsyncWriteTask> asyncWriteTask;

        AtomicBoolean monitorStarted;

        AtomicBoolean commandSent;
        AtomicBoolean commandReceived;

        AtomicBoolean failed;
        AtomicBoolean inRead;
        AtomicBoolean inWrite;

        Mutex inWriteMutex;
        Mutex monitor;

        long long readCheckTime;
        long long writeCheckTime;
        long long initialDelayTime;

        bool keepAliveResponseRequired;
    };

    // Task that fires when the TaskRunner is signaled by the ReadCheck Timer Task.
    class AsyncSignalReadErrorkTask : public CompositeTask {
    private:

        InactivityMonitor* parent;
        std::string remote;
        AtomicBoolean failed;

    public:

        AsyncSignalReadErrorkTask( InactivityMonitor* parent, const std::string& remote ) {
            this->parent = parent;
            this->remote = remote;
        }

        void setFailed( bool failed ) {
            this->failed.set( failed );
        }

        virtual bool isPending() const {
            return this->failed.get();
        }

        virtual bool iterate() {

            if( this->failed.compareAndSet( true, false ) ) {

                IOException ex (
                    __FILE__, __LINE__,
                    ( std::string( "Channel was inactive for too long: " ) + remote ).c_str() );

                this->parent->onException( ex );
            }

            return this->failed.get();
        }
    };

    // Task that fires when the TaskRunner is signaled by the WriteCheck Timer Task.
    class AsyncWriteTask : public CompositeTask {
    private:

        InactivityMonitor* parent;
        AtomicBoolean write;

    public:

        AsyncWriteTask( InactivityMonitor* parent ) : parent( parent ) {
        }

        void setWrite( bool write ) {
            this->write.set( write );
        }

        virtual bool isPending() const {
            return this->write.get();
        }

        virtual bool iterate() {

            if( this->write.compareAndSet( true, false ) &&
                this->parent->members->monitorStarted.get() ) {

                try {
                    Pointer<KeepAliveInfo> info( new KeepAliveInfo() );
                    info->setResponseRequired( this->parent->members->keepAliveResponseRequired );
                    this->parent->oneway( info );
                } catch( IOException& e ) {
                    this->parent->onException( e );
                }
            }

            return this->write.get();
        }
    };

}}}

////////////////////////////////////////////////////////////////////////////////
InactivityMonitor::InactivityMonitor( const Pointer<Transport>& next, const Pointer<WireFormat>& wireFormat )
:   TransportFilter( next ), members( new InactivityMonitorData() ) {

    this->members->wireFormat = wireFormat;
    this->members->monitorStarted = false;
    this->members->commandSent = false;
    this->members->commandReceived = true;
    this->members->failed = false;
    this->members->inRead = false;
    this->members->inWrite = false;
    this->members->readCheckTime = 0;
    this->members->writeCheckTime = 0;
    this->members->initialDelayTime = 0;
    this->members->keepAliveResponseRequired = false;
}

////////////////////////////////////////////////////////////////////////////////
InactivityMonitor::InactivityMonitor( const Pointer<Transport>& next,
                                      const decaf::util::Properties& properties,
                                      const Pointer<wireformat::WireFormat>& wireFormat )
:   TransportFilter( next ), members( new InactivityMonitorData() ) {

    this->members->wireFormat = wireFormat;
    this->members->monitorStarted = false;
    this->members->commandSent = false;
    this->members->commandReceived = true;
    this->members->failed = false;
    this->members->inRead = false;
    this->members->inWrite = false;
    this->members->readCheckTime = 0;
    this->members->writeCheckTime = 0;
    this->members->initialDelayTime = 0;
    this->members->keepAliveResponseRequired =
        Boolean::parseBoolean( properties.getProperty( "keepAliveResponseRequired", "false" ) );
}

////////////////////////////////////////////////////////////////////////////////
InactivityMonitor::~InactivityMonitor() {
    try{
        this->stopMonitorThreads();
    }
    AMQ_CATCHALL_NOTHROW()
}

////////////////////////////////////////////////////////////////////////////////
long long InactivityMonitor::getReadCheckTime() const {
    return this->members->readCheckTime;
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::setReadCheckTime( long long value ) {
    this->members->readCheckTime = value;
}

////////////////////////////////////////////////////////////////////////////////
long long InactivityMonitor::getWriteCheckTime() const {
    return this->members->writeCheckTime;
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::setWriteCheckTime( long long value ) {
    this->members->writeCheckTime = value;
}

////////////////////////////////////////////////////////////////////////////////
long long InactivityMonitor::getInitialDelayTime() const {
    return this->members->initialDelayTime;
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::setInitialDelayTime( long long value ) const {
    this->members->initialDelayTime = value;
}

////////////////////////////////////////////////////////////////////////////////
bool InactivityMonitor::isKeepAliveResponseRequired() const {
    return this->members->keepAliveResponseRequired;
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::setKeepAliveResponseRequired( bool value ) {
    this->members->keepAliveResponseRequired = value;
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::close() throw( decaf::io::IOException ) {
    try{
        stopMonitorThreads();
        TransportFilter::close();
    }
    AMQ_CATCH_RETHROW( IOException )
    AMQ_CATCH_EXCEPTION_CONVERT( Exception, IOException )
    AMQ_CATCHALL_THROW( IOException )
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::onException( const decaf::lang::Exception& ex ) {

    if( this->members->failed.compareAndSet( false, true ) ) {
        stopMonitorThreads();
        TransportFilter::onException( ex );
    }
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::onCommand( const Pointer<Command>& command ) {

    this->members->commandReceived.set( true );
    this->members->inRead.set( true );

    try {

        if( command->isWireFormatInfo() ) {
            synchronized( &this->members->monitor ) {

                this->members->remoteWireFormatInfo = command.dynamicCast<WireFormatInfo>();
                try {
                    startMonitorThreads();
                } catch( IOException& e ) {
                    onException( e );
                }
            }
        }

        TransportFilter::onCommand( command );

        this->members->inRead.set( false );

    } catch( Exception& ex ) {
        this->members->inRead.set( false );
        ex.setMark( __FILE__, __LINE__ );
        throw ex;
    }
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::oneway( const Pointer<Command>& command )
    throw( decaf::io::IOException, decaf::lang::exceptions::UnsupportedOperationException ) {

    try{
        // Disable inactivity monitoring while processing a command.  Synchronize this
        // method - its not synchronized
        // further down the transport stack and gets called by more
        // than one thread  by this class
        synchronized( &this->members->inWriteMutex ) {
            this->members->inWrite.set( true );
            try {

                if( this->members->failed.get() ) {
                    throw IOException(
                        __FILE__, __LINE__,
                        ( std::string( "Channel was inactive for too long: " ) + next->getRemoteAddress() ).c_str() );
                }

                if( command->isWireFormatInfo() ) {
                    synchronized( &this->members->monitor ) {
                        this->members->localWireFormatInfo = command.dynamicCast<WireFormatInfo>();
                        startMonitorThreads();
                    }
                }

                this->next->oneway( command );

                this->members->commandSent.set( true );
                this->members->inWrite.set( false );

            } catch( Exception& ex ) {
                this->members->commandSent.set( true );
                this->members->inWrite.set( false );

                ex.setMark( __FILE__, __LINE__ );
                throw ex;
            }
        }
    }
    AMQ_CATCH_RETHROW( IOException )
    AMQ_CATCH_RETHROW( UnsupportedOperationException )
    AMQ_CATCH_EXCEPTION_CONVERT( Exception, IOException )
    AMQ_CATCHALL_THROW( IOException )
}

////////////////////////////////////////////////////////////////////////////////
bool InactivityMonitor::allowReadCheck( long long elapsed ) {
    return elapsed > ( this->members->readCheckTime * 9 / 10 );
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::readCheck() {

    if( this->members->inRead.get() || this->members->wireFormat->inReceive() ) {
        return;
    }

    if( !this->members->commandReceived.get() ) {

        // Set the failed state on our async Read Failure Task and wakeup its runner.
        this->members->asyncReadTask->setFailed( true );
        this->members->asyncTasks->wakeup();
    }

    this->members->commandReceived.set( false );
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::writeCheck() {

    if( this->members->inWrite.get() ) {
        return;
    }

    if(! this->members->commandSent.get() ) {

        this->members->asyncWriteTask->setWrite( true );
        this->members->asyncTasks->wakeup();
    }

    this->members->commandSent.set( false );
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::startMonitorThreads() {

    synchronized( &this->members->monitor ) {

        if( this->members->monitorStarted.get() ) {
            return;
        }
        if( this->members->localWireFormatInfo == NULL ) {
            return;
        }
        if( this->members->remoteWireFormatInfo == NULL ) {
            return;
        }

        this->members->asyncTasks.reset( new CompositeTaskRunner() );
        this->members->asyncReadTask.reset( new AsyncSignalReadErrorkTask( this, this->getRemoteAddress() ) );
        this->members->asyncWriteTask.reset( new AsyncWriteTask( this ) );

        this->members->asyncTasks->addTask( this->members->asyncReadTask.get() );
        this->members->asyncTasks->addTask( this->members->asyncWriteTask.get() );

        this->members->readCheckTime =
            Math::min( this->members->localWireFormatInfo->getMaxInactivityDuration(),
                        this->members->remoteWireFormatInfo->getMaxInactivityDuration() );

        this->members->initialDelayTime =
            Math::min( this->members->localWireFormatInfo->getMaxInactivityDurationInitalDelay(),
                       this->members->remoteWireFormatInfo->getMaxInactivityDurationInitalDelay() );

        if( this->members->readCheckTime > 0 ) {

            this->members->monitorStarted.set( true );
            this->members->writeCheckerTask.reset( new WriteChecker( this ) );
            this->members->readCheckerTask.reset( new ReadChecker( this ) );
            this->members->writeCheckTime = this->members->readCheckTime > 3 ?
                                                this->members->readCheckTime / 3 : this->members->readCheckTime;

            this->members->writeCheckTimer.scheduleAtFixedRate(
                this->members->writeCheckerTask, this->members->initialDelayTime, this->members->writeCheckTime );
            this->members->readCheckTimer.scheduleAtFixedRate(
                this->members->readCheckerTask, this->members->initialDelayTime, this->members->readCheckTime );
        }
    }
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::stopMonitorThreads() {

    synchronized( &this->members->monitor ) {

        if( this->members->monitorStarted.compareAndSet( true, false ) ) {

            this->members->readCheckerTask->cancel();
            this->members->writeCheckerTask->cancel();

            this->members->readCheckTimer.purge();
            this->members->readCheckTimer.cancel();
            this->members->writeCheckTimer.purge();
            this->members->writeCheckTimer.cancel();

            this->members->asyncTasks->shutdown();
        }
    }
}
<commit_msg>Cleanup code.<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "InactivityMonitor.h"

#include "ReadChecker.h"
#include "WriteChecker.h"

#include <activemq/threads/CompositeTask.h>
#include <activemq/threads/CompositeTaskRunner.h>
#include <activemq/commands/WireFormatInfo.h>
#include <activemq/commands/KeepAliveInfo.h>

#include <decaf/lang/Math.h>
#include <decaf/lang/Thread.h>
#include <decaf/lang/Runnable.h>
#include <decaf/lang/Boolean.h>

using namespace std;
using namespace activemq;
using namespace activemq::commands;
using namespace activemq::threads;
using namespace activemq::transport;
using namespace activemq::transport::inactivity;
using namespace activemq::exceptions;
using namespace activemq::wireformat;
using namespace decaf;
using namespace decaf::io;
using namespace decaf::util;
using namespace decaf::util::concurrent;
using namespace decaf::util::concurrent::atomic;
using namespace decaf::lang;
using namespace decaf::lang::exceptions;

////////////////////////////////////////////////////////////////////////////////
namespace activemq{
namespace transport{
namespace inactivity{

    class InactivityMonitorData {
    public:

        // The configured WireFormat for the Transport Chain.
        Pointer<WireFormat> wireFormat;

        // Local and Remote WireFormat information.
        Pointer<WireFormatInfo> localWireFormatInfo;
        Pointer<WireFormatInfo> remoteWireFormatInfo;

        Pointer<ReadChecker> readCheckerTask;
        Pointer<WriteChecker> writeCheckerTask;

        Timer readCheckTimer;
        Timer writeCheckTimer;

        Pointer<CompositeTaskRunner> asyncTasks;

        Pointer<AsyncSignalReadErrorkTask> asyncReadTask;
        Pointer<AsyncWriteTask> asyncWriteTask;

        AtomicBoolean monitorStarted;

        AtomicBoolean commandSent;
        AtomicBoolean commandReceived;

        AtomicBoolean failed;
        AtomicBoolean inRead;
        AtomicBoolean inWrite;

        Mutex inWriteMutex;
        Mutex monitor;

        long long readCheckTime;
        long long writeCheckTime;
        long long initialDelayTime;

        bool keepAliveResponseRequired;
    };

    // Task that fires when the TaskRunner is signaled by the ReadCheck Timer Task.
    class AsyncSignalReadErrorkTask : public CompositeTask {
    private:

        InactivityMonitor* parent;
        std::string remote;
        AtomicBoolean failed;

    public:

        AsyncSignalReadErrorkTask( InactivityMonitor* parent, const std::string& remote ) {
            this->parent = parent;
            this->remote = remote;
        }

        void setFailed( bool failed ) {
            this->failed.set( failed );
        }

        virtual bool isPending() const {
            return this->failed.get();
        }

        virtual bool iterate() {

            if( this->failed.compareAndSet( true, false ) ) {

                IOException ex (
                    __FILE__, __LINE__,
                    ( std::string( "Channel was inactive for too long: " ) + remote ).c_str() );

                this->parent->onException( ex );
            }

            return this->failed.get();
        }
    };

    // Task that fires when the TaskRunner is signaled by the WriteCheck Timer Task.
    class AsyncWriteTask : public CompositeTask {
    private:

        InactivityMonitor* parent;
        AtomicBoolean write;

    public:

        AsyncWriteTask( InactivityMonitor* parent ) : parent( parent ) {
        }

        void setWrite( bool write ) {
            this->write.set( write );
        }

        virtual bool isPending() const {
            return this->write.get();
        }

        virtual bool iterate() {

            if( this->write.compareAndSet( true, false ) &&
                this->parent->members->monitorStarted.get() ) {

                try {
                    Pointer<KeepAliveInfo> info( new KeepAliveInfo() );
                    info->setResponseRequired( this->parent->members->keepAliveResponseRequired );
                    this->parent->oneway( info );
                } catch( IOException& e ) {
                    this->parent->onException( e );
                }
            }

            return this->write.get();
        }
    };

}}}

////////////////////////////////////////////////////////////////////////////////
InactivityMonitor::InactivityMonitor( const Pointer<Transport>& next, const Pointer<WireFormat>& wireFormat )
:   TransportFilter( next ), members( new InactivityMonitorData() ) {

    this->members->wireFormat = wireFormat;
    this->members->monitorStarted = false;
    this->members->commandSent = false;
    this->members->commandReceived = true;
    this->members->failed = false;
    this->members->inRead = false;
    this->members->inWrite = false;
    this->members->readCheckTime = 0;
    this->members->writeCheckTime = 0;
    this->members->initialDelayTime = 0;
    this->members->keepAliveResponseRequired = false;
}

////////////////////////////////////////////////////////////////////////////////
InactivityMonitor::InactivityMonitor( const Pointer<Transport>& next,
                                      const decaf::util::Properties& properties,
                                      const Pointer<wireformat::WireFormat>& wireFormat )
:   TransportFilter( next ), members( new InactivityMonitorData() ) {

    this->members->wireFormat = wireFormat;
    this->members->monitorStarted = false;
    this->members->commandSent = false;
    this->members->commandReceived = true;
    this->members->failed = false;
    this->members->inRead = false;
    this->members->inWrite = false;
    this->members->readCheckTime = 0;
    this->members->writeCheckTime = 0;
    this->members->initialDelayTime = 0;
    this->members->keepAliveResponseRequired =
        Boolean::parseBoolean( properties.getProperty( "keepAliveResponseRequired", "false" ) );
}

////////////////////////////////////////////////////////////////////////////////
InactivityMonitor::~InactivityMonitor() {
    try{
        this->stopMonitorThreads();
    }
    AMQ_CATCHALL_NOTHROW()
}

////////////////////////////////////////////////////////////////////////////////
long long InactivityMonitor::getReadCheckTime() const {
    return this->members->readCheckTime;
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::setReadCheckTime( long long value ) {
    this->members->readCheckTime = value;
}

////////////////////////////////////////////////////////////////////////////////
long long InactivityMonitor::getWriteCheckTime() const {
    return this->members->writeCheckTime;
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::setWriteCheckTime( long long value ) {
    this->members->writeCheckTime = value;
}

////////////////////////////////////////////////////////////////////////////////
long long InactivityMonitor::getInitialDelayTime() const {
    return this->members->initialDelayTime;
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::setInitialDelayTime( long long value ) const {
    this->members->initialDelayTime = value;
}

////////////////////////////////////////////////////////////////////////////////
bool InactivityMonitor::isKeepAliveResponseRequired() const {
    return this->members->keepAliveResponseRequired;
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::setKeepAliveResponseRequired( bool value ) {
    this->members->keepAliveResponseRequired = value;
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::close() throw( decaf::io::IOException ) {
    try{
        stopMonitorThreads();
        TransportFilter::close();
    }
    AMQ_CATCH_RETHROW( IOException )
    AMQ_CATCH_EXCEPTION_CONVERT( Exception, IOException )
    AMQ_CATCHALL_THROW( IOException )
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::onException( const decaf::lang::Exception& ex ) {

    if( this->members->failed.compareAndSet( false, true ) ) {
        stopMonitorThreads();
        TransportFilter::onException( ex );
    }
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::onCommand( const Pointer<Command>& command ) {

    this->members->commandReceived.set( true );
    this->members->inRead.set( true );

    try {

        if( command->isWireFormatInfo() ) {
            synchronized( &this->members->monitor ) {

                this->members->remoteWireFormatInfo = command.dynamicCast<WireFormatInfo>();
                try {
                    startMonitorThreads();
                } catch( IOException& e ) {
                    onException( e );
                }
            }
        }

        TransportFilter::onCommand( command );

        this->members->inRead.set( false );

    } catch( Exception& ex ) {
        this->members->inRead.set( false );
        ex.setMark( __FILE__, __LINE__ );
        throw ex;
    }
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::oneway( const Pointer<Command>& command )
    throw( decaf::io::IOException, decaf::lang::exceptions::UnsupportedOperationException ) {

    try{
        // Disable inactivity monitoring while processing a command.  Synchronize this
        // method - its not synchronized
        // further down the transport stack and gets called by more
        // than one thread  by this class
        synchronized( &this->members->inWriteMutex ) {
            this->members->inWrite.set( true );
            try {

                if( this->members->failed.get() ) {
                    throw IOException(
                        __FILE__, __LINE__,
                        ( std::string( "Channel was inactive for too long: " ) + next->getRemoteAddress() ).c_str() );
                }

                if( command->isWireFormatInfo() ) {
                    synchronized( &this->members->monitor ) {
                        this->members->localWireFormatInfo = command.dynamicCast<WireFormatInfo>();
                        startMonitorThreads();
                    }
                }

                this->next->oneway( command );

                this->members->commandSent.set( true );
                this->members->inWrite.set( false );

            } catch( Exception& ex ) {
                this->members->commandSent.set( true );
                this->members->inWrite.set( false );

                ex.setMark( __FILE__, __LINE__ );
                throw ex;
            }
        }
    }
    AMQ_CATCH_RETHROW( IOException )
    AMQ_CATCH_RETHROW( UnsupportedOperationException )
    AMQ_CATCH_EXCEPTION_CONVERT( Exception, IOException )
    AMQ_CATCHALL_THROW( IOException )
}

////////////////////////////////////////////////////////////////////////////////
bool InactivityMonitor::allowReadCheck( long long elapsed ) {
    return elapsed > ( this->members->readCheckTime * 9 / 10 );
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::readCheck() {

    if( this->members->inRead.get() || this->members->wireFormat->inReceive() ) {
        return;
    }

    if( !this->members->commandReceived.get() ) {

        // Set the failed state on our async Read Failure Task and wakeup its runner.
        this->members->asyncReadTask->setFailed( true );
        this->members->asyncTasks->wakeup();
    }

    this->members->commandReceived.set( false );
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::writeCheck() {

    if( this->members->inWrite.get() ) {
        return;
    }

    if( !this->members->commandSent.get() ) {

        this->members->asyncWriteTask->setWrite( true );
        this->members->asyncTasks->wakeup();
    }

    this->members->commandSent.set( false );
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::startMonitorThreads() {

    synchronized( &this->members->monitor ) {

        if( this->members->monitorStarted.get() ) {
            return;
        }
        if( this->members->localWireFormatInfo == NULL ) {
            return;
        }
        if( this->members->remoteWireFormatInfo == NULL ) {
            return;
        }

        this->members->asyncTasks.reset( new CompositeTaskRunner() );
        this->members->asyncReadTask.reset( new AsyncSignalReadErrorkTask( this, this->getRemoteAddress() ) );
        this->members->asyncWriteTask.reset( new AsyncWriteTask( this ) );

        this->members->asyncTasks->addTask( this->members->asyncReadTask.get() );
        this->members->asyncTasks->addTask( this->members->asyncWriteTask.get() );

        this->members->readCheckTime =
            Math::min( this->members->localWireFormatInfo->getMaxInactivityDuration(),
                        this->members->remoteWireFormatInfo->getMaxInactivityDuration() );

        this->members->initialDelayTime =
            Math::min( this->members->localWireFormatInfo->getMaxInactivityDurationInitalDelay(),
                       this->members->remoteWireFormatInfo->getMaxInactivityDurationInitalDelay() );

        if( this->members->readCheckTime > 0 ) {

            this->members->monitorStarted.set( true );
            this->members->writeCheckerTask.reset( new WriteChecker( this ) );
            this->members->readCheckerTask.reset( new ReadChecker( this ) );
            this->members->writeCheckTime = this->members->readCheckTime > 3 ?
                                                this->members->readCheckTime / 3 : this->members->readCheckTime;

            this->members->writeCheckTimer.scheduleAtFixedRate(
                this->members->writeCheckerTask, this->members->initialDelayTime, this->members->writeCheckTime );
            this->members->readCheckTimer.scheduleAtFixedRate(
                this->members->readCheckerTask, this->members->initialDelayTime, this->members->readCheckTime );
        }
    }
}

////////////////////////////////////////////////////////////////////////////////
void InactivityMonitor::stopMonitorThreads() {

    synchronized( &this->members->monitor ) {

        if( this->members->monitorStarted.compareAndSet( true, false ) ) {

            this->members->readCheckerTask->cancel();
            this->members->writeCheckerTask->cancel();

            this->members->readCheckTimer.purge();
            this->members->readCheckTimer.cancel();
            this->members->writeCheckTimer.purge();
            this->members->writeCheckTimer.cancel();

            this->members->asyncTasks->shutdown();
        }
    }
}
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include "itkPyCommand.h"

namespace itk
{

PyCommand::PyCommand()
{
  this->m_Object = nullptr;
}

PyCommand::~PyCommand()
{
  if (this->m_Object)
    {
    Py_DECREF(this->m_Object);
    }
  this->m_Object = nullptr;
}

void PyCommand::SetCommandCallable(PyObject *o)
{
  if (o != this->m_Object)
    {
    if (this->m_Object)
      {
      // get rid of our reference
      Py_DECREF(this->m_Object);
      }

    // store the new object
    this->m_Object = o;

    if (this->m_Object)
      {
      // take out reference (so that the calling code doesn't
      // have to keep a binding to the callable around)
      Py_INCREF(this->m_Object);
      }
    }
}

PyObject * PyCommand::GetCommandCallable()
{
  return this->m_Object;
}

void PyCommand::Execute(Object *, const EventObject&)
{
  this->PyExecute();
}

void PyCommand::Execute(const Object*, const EventObject&)
{
  this->PyExecute();
}

void PyCommand::PyExecute()
{
  // make sure that the CommandCallable is in fact callable
  if (!PyCallable_Check(this->m_Object))
    {
      // we throw a standard ITK exception: this makes it possible for
      // our standard Swig exception handling logic to take this
      // through to the invoking Python process
      itkExceptionMacro(<<"CommandCallable is not a callable Python object, "
                        <<"or it has not been set.");
    }
  else
    {
    PyObject *result = PyEval_CallObject(this->m_Object, (PyObject *)nullptr);

    if (result)
      {
      Py_DECREF(result);
      }
    else
      {
      // there was a Python error.  Clear the error by printing to stdout
      PyErr_Print();
      // make sure the invoking Python code knows there was a problem
      // by raising an exception
      itkExceptionMacro(<<"There was an error executing the "
                        <<"CommandCallable.");
      }
    }
}

} // end namespace itk
<commit_msg>BUG: itk::PyCommand ensures the GIL state<commit_after>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include "itkPyCommand.h"

namespace
{
// Wrapper to automatics obtain and release GIL
// RAII idiom
class PyGILStateEnsure
{
public:
  PyGILStateEnsure()
    {
      m_GIL = PyGILState_Ensure();
    }
  ~PyGILStateEnsure()
    {
      PyGILState_Release(m_GIL);
    }
private:
  PyGILState_STATE m_GIL;
};
} // end anonymous namespace

namespace itk
{

PyCommand::PyCommand()
{
  this->m_Object = nullptr;
}

PyCommand::~PyCommand()
{
  if (this->m_Object)
    {
    PyGILStateEnsure gil;
    Py_DECREF(this->m_Object);
    }
  this->m_Object = nullptr;
}

void PyCommand::SetCommandCallable(PyObject *o)
{
  if (o != this->m_Object)
    {
    PyGILStateEnsure gil;
    if (this->m_Object)
      {
      // get rid of our reference
      Py_DECREF(this->m_Object);
      }

    // store the new object
    this->m_Object = o;

    if (this->m_Object)
      {
      // take out reference (so that the calling code doesn't
      // have to keep a binding to the callable around)
      Py_INCREF(this->m_Object);
      }
    }
}

PyObject * PyCommand::GetCommandCallable()
{
  return this->m_Object;
}

void PyCommand::Execute(Object *, const EventObject&)
{
  this->PyExecute();
}

void PyCommand::Execute(const Object*, const EventObject&)
{
  this->PyExecute();
}

void PyCommand::PyExecute()
{
  // make sure that the CommandCallable is in fact callable
  if (!PyCallable_Check(this->m_Object))
    {
      // we throw a standard ITK exception: this makes it possible for
      // our standard Swig exception handling logic to take this
      // through to the invoking Python process
      itkExceptionMacro(<<"CommandCallable is not a callable Python object, "
                        <<"or it has not been set.");
    }
  else
    {
    PyGILStateEnsure gil;
    PyObject *result = PyEval_CallObject(this->m_Object, (PyObject *)nullptr);

    if (result)
      {
      Py_DECREF(result);
      }
    else
      {
      // there was a Python error.  Clear the error by printing to stdout
      PyErr_Print();
      // make sure the invoking Python code knows there was a problem
      // by raising an exception
      itkExceptionMacro(<<"There was an error executing the "
                        <<"CommandCallable.");
      }
    }
}

} // end namespace itk
<|endoftext|>