<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.

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

//#define MBILOG_ENABLE_DEBUG

#include <dcvrdt.h>

#define BOOST_DATE_TIME_NO_LIB

#include <boost/date_time/posix_time/posix_time_types.hpp>

#include "mitkITKDICOMSeriesReaderHelper.h"
#include "mitkITKDICOMSeriesReaderHelper.txx"

#include "mitkDICOMGDCMTagScanner.h"
#include "mitkArbitraryTimeGeometry.h"

#define switch3DCase(IOType, T) \
  case IOType: return LoadDICOMByITK< T >(filenames, correctTilt, tiltInfo, io);

bool
  mitk::ITKDICOMSeriesReaderHelper
  ::CanHandleFile(const std::string& filename)
{
  MITK_DEBUG << "ITKDICOMSeriesReaderHelper::CanHandleFile " << filename;
  itk::GDCMImageIO::Pointer tester = itk::GDCMImageIO::New();
  return tester->CanReadFile(filename.c_str());
}

mitk::Image::Pointer
  mitk::ITKDICOMSeriesReaderHelper
  ::Load( const StringContainer& filenames, bool correctTilt, const GantryTiltInformation& tiltInfo )
{
  if( filenames.empty() )
  {
    MITK_DEBUG << "Calling LoadDicomSeries with empty filename string container. Probably invalid application logic.";
    return nullptr; // this is not actually an error but the result is very simple
  }

  typedef itk::GDCMImageIO DcmIoType;
  DcmIoType::Pointer io = DcmIoType::New();

  try
  {
    if (io->CanReadFile(filenames.front().c_str()))
    {
      io->SetFileName(filenames.front().c_str());
      io->ReadImageInformation();

      if (io->GetPixelType() == itk::ImageIOBase::SCALAR)
      {
        switch (io->GetComponentType())
        {
          switch3DCase(DcmIoType::UCHAR, unsigned char)
            switch3DCase(DcmIoType::CHAR, char)
            switch3DCase(DcmIoType::USHORT, unsigned short)
            switch3DCase(DcmIoType::SHORT, short)
            switch3DCase(DcmIoType::UINT, unsigned int)
            switch3DCase(DcmIoType::INT, int)
            switch3DCase(DcmIoType::ULONG, long unsigned int)
            switch3DCase(DcmIoType::LONG, long int)
            switch3DCase(DcmIoType::FLOAT, float)
            switch3DCase(DcmIoType::DOUBLE, double)
        default:
          MITK_ERROR << "Found unsupported DICOM scalar pixel type: (enum value) " << io->GetComponentType();
        }
      }
      else if (io->GetPixelType() == itk::ImageIOBase::RGB)
      {
        switch (io->GetComponentType())
        {
          switch3DCase(DcmIoType::UCHAR, itk::RGBPixel<unsigned char>)
            switch3DCase(DcmIoType::CHAR, itk::RGBPixel<char>)
            switch3DCase(DcmIoType::USHORT, itk::RGBPixel<unsigned short>)
            switch3DCase(DcmIoType::SHORT, itk::RGBPixel<short>)
            switch3DCase(DcmIoType::UINT, itk::RGBPixel<unsigned int>)
            switch3DCase(DcmIoType::INT, itk::RGBPixel<int>)
            switch3DCase(DcmIoType::ULONG, itk::RGBPixel<long unsigned int>)
            switch3DCase(DcmIoType::LONG, itk::RGBPixel<long int>)
            switch3DCase(DcmIoType::FLOAT, itk::RGBPixel<float>)
            switch3DCase(DcmIoType::DOUBLE, itk::RGBPixel<double>)
        default:
          MITK_ERROR << "Found unsupported DICOM scalar pixel type: (enum value) " << io->GetComponentType();
        }
      }

      MITK_ERROR << "Unsupported DICOM pixel type";
      return nullptr;
    }
  }
  catch(itk::MemoryAllocationError& e)
  {
    MITK_ERROR << "Out of memory. Cannot load DICOM series: " << e.what();
  }
  catch(std::exception& e)
  {
    MITK_ERROR << "Error encountered when loading DICOM series:" << e.what();
  }
  catch(...)
  {
    MITK_ERROR << "Unspecified error encountered when loading DICOM series.";
  }

  return nullptr;
}

#define switch3DnTCase(IOType, T) \
  case IOType: return LoadDICOMByITK3DnT< T >(filenamesLists, correctTilt, tiltInfo, io);

mitk::Image::Pointer
  mitk::ITKDICOMSeriesReaderHelper
  ::Load3DnT( const StringContainerList& filenamesLists, bool correctTilt, const GantryTiltInformation& tiltInfo )
{
  if( filenamesLists.empty() || filenamesLists.front().empty() )
  {
    MITK_DEBUG << "Calling LoadDicomSeries with empty filename string container. Probably invalid application logic.";
    return nullptr; // this is not actually an error but the result is very simple
  }

  typedef itk::GDCMImageIO DcmIoType;
  DcmIoType::Pointer io = DcmIoType::New();

  try
  {
    if (io->CanReadFile(filenamesLists.front().front().c_str()))
    {
      io->SetFileName(filenamesLists.front().front().c_str());
      io->ReadImageInformation();

      if (io->GetPixelType() == itk::ImageIOBase::SCALAR)
      {
        switch (io->GetComponentType())
        {
          switch3DnTCase(DcmIoType::UCHAR, unsigned char)
            switch3DnTCase(DcmIoType::CHAR, char)
            switch3DnTCase(DcmIoType::USHORT, unsigned short)
            switch3DnTCase(DcmIoType::SHORT, short)
            switch3DnTCase(DcmIoType::UINT, unsigned int)
            switch3DnTCase(DcmIoType::INT, int)
            switch3DnTCase(DcmIoType::ULONG, long unsigned int)
            switch3DnTCase(DcmIoType::LONG, long int)
            switch3DnTCase(DcmIoType::FLOAT, float)
            switch3DnTCase(DcmIoType::DOUBLE, double)
        default:
          MITK_ERROR << "Found unsupported DICOM scalar pixel type: (enum value) " << io->GetComponentType();
        }
      }
      else if (io->GetPixelType() == itk::ImageIOBase::RGB)
      {
        switch (io->GetComponentType())
        {
          switch3DnTCase(DcmIoType::UCHAR, itk::RGBPixel<unsigned char>)
            switch3DnTCase(DcmIoType::CHAR, itk::RGBPixel<char>)
            switch3DnTCase(DcmIoType::USHORT, itk::RGBPixel<unsigned short>)
            switch3DnTCase(DcmIoType::SHORT, itk::RGBPixel<short>)
            switch3DnTCase(DcmIoType::UINT, itk::RGBPixel<unsigned int>)
            switch3DnTCase(DcmIoType::INT, itk::RGBPixel<int>)
            switch3DnTCase(DcmIoType::ULONG, itk::RGBPixel<long unsigned int>)
            switch3DnTCase(DcmIoType::LONG, itk::RGBPixel<long int>)
            switch3DnTCase(DcmIoType::FLOAT, itk::RGBPixel<float>)
            switch3DnTCase(DcmIoType::DOUBLE, itk::RGBPixel<double>)
        default:
          MITK_ERROR << "Found unsupported DICOM scalar pixel type: (enum value) " << io->GetComponentType();
        }
      }

      MITK_ERROR << "Unsupported DICOM pixel type";
      return nullptr;
    }
  }
  catch(itk::MemoryAllocationError& e)
  {
    MITK_ERROR << "Out of memory. Cannot load DICOM series: " << e.what();
  }
  catch(std::exception& e)
  {
    MITK_ERROR << "Error encountered when loading DICOM series:" << e.what();
  }
  catch(...)
  {
    MITK_ERROR << "Unspecified error encountered when loading DICOM series.";
  }

  return nullptr;
}

bool ConvertDICOMDateTimeString(const std::string& dateString, const std::string& timeString, OFDateTime& time)
{
  OFString content(timeString.c_str());

  if (!dateString.empty())
  {
    content = OFString(dateString.c_str()).append(content);
  }

  OFCondition result = DcmDateTime::getOFDateTimeFromString(content,time);

  return result.good();
}

boost::posix_time::ptime ConvertOFDateTimeToPTime(const OFDateTime& time)
{
  boost::gregorian::date boostDate(time.getDate().getYear(),time.getDate().getMonth(),time.getDate().getDay());
  boost::posix_time::time_duration boostTime = boost::posix_time::hours(time.getTime().getHour())
                                              +boost::posix_time::minutes(time.getTime().getMinute())
                                              +boost::posix_time::seconds(time.getTime().getSecond())
                                              +boost::posix_time::milliseconds(time.getTime().getMilliSecond());

  boost::posix_time::ptime result(boostDate,boostTime);

  return result;
}

OFDateTime GetLowerDateTime(const OFDateTime& time1, const OFDateTime& time2)
{
  OFDateTime result = time1;

  if ((time2.getDate()<time1.getDate()) ||
      ((time2.getDate() == time1.getDate()) && (time2.getTime()<time1.getTime())))
  {
    result = time2;
  }

  return result;
}

OFDateTime GetUpperDateTime(const OFDateTime& time1, const OFDateTime& time2)
{
  OFDateTime result = time1;

  if ((time2.getDate()>time1.getDate()) ||
      ((time2.getDate() == time1.getDate()) && (time2.getTime()>time1.getTime())))
  {
    result = time2;
  }

  return result;
}

double ComputeMiliSecDuration(const OFDateTime& start, const OFDateTime& stop)
{
  boost::posix_time::ptime startTime = ConvertOFDateTimeToPTime(start);
  boost::posix_time::ptime stopTime = ConvertOFDateTimeToPTime(stop);

  ::boost::posix_time::time_duration duration = stopTime - startTime;

  double result = duration.total_milliseconds();

  return result;
}

bool
  mitk::ITKDICOMSeriesReaderHelper::ExtractTimeBoundsOfTimeStep (const StringContainer& filenamesOfTimeStep, DateTimeBounds& bounds)
{
  DICOMTag acquisitionDateTag(0x0008, 0x0022);
  DICOMTag acquisitionTimeTag(0x0008, 0x0032);
  DICOMGDCMTagScanner::Pointer filescanner = DICOMGDCMTagScanner::New();
  filescanner->SetInputFiles(filenamesOfTimeStep);
  filescanner->AddTag( acquisitionDateTag );
  filescanner->AddTag( acquisitionTimeTag );
  filescanner->Scan();

  DICOMGDCMImageFrameList frameList = filescanner->GetFrameInfoList();

  bool result = false;
  bool first = true;

  for (DICOMGDCMImageFrameList::const_iterator pos = frameList.begin(); pos != frameList.end(); ++pos)
  {
    std::string dateStr = (*pos)->GetTagValueAsString(acquisitionDateTag);
    std::string timeStr = (*pos)->GetTagValueAsString(acquisitionTimeTag);

    OFDateTime time;
    bool convertResult = ConvertDICOMDateTimeString(dateStr, timeStr, time);

    if (convertResult)
    {
      if (first)
      {
        bounds[0] = time;
        bounds[1] = time;
        first = false;
      }
      else
      {
        bounds[0] = GetLowerDateTime(bounds[0], time);
        bounds[1] = GetUpperDateTime(bounds[1], time);
      }
      result = true;
    }
  }

  return result;
};

mitk::ITKDICOMSeriesReaderHelper::TimeBoundsList
  mitk::ITKDICOMSeriesReaderHelper::ExtractTimeBoundsOfTimeSteps (const StringContainerList& filenamesOfTimeSteps)
{
  TimeBoundsList result;

  OFDateTime baseLine;
  bool baseLineSet = false;

  for(StringContainerList::const_iterator pos = filenamesOfTimeSteps.begin(); pos!=filenamesOfTimeSteps.end(); ++pos)
  {
    TimeBounds bounds(0.0);
    DateTimeBounds dateTimeBounds;

    if(ExtractTimeBoundsOfTimeStep(*pos,dateTimeBounds))
    {
      if(!baseLineSet)
      {
        baseLineSet = true;
        baseLine = dateTimeBounds[0];
      }

      bounds[0] = ComputeMiliSecDuration(baseLine, dateTimeBounds[0]);
      bounds[1] = ComputeMiliSecDuration(baseLine, dateTimeBounds[1]);
    }

    result.push_back(bounds);
  }

  return result;
};

mitk::TimeGeometry::Pointer
  mitk::ITKDICOMSeriesReaderHelper::
  GenerateTimeGeometry(const BaseGeometry* templateGeometry, const TimeBoundsList& boundsList)
{
  ArbitraryTimeGeometry::Pointer timeGeometry = ArbitraryTimeGeometry::New();
  timeGeometry->ClearAllGeometries();

  for (TimeBoundsList::size_type pos = 0; pos < boundsList.size(); ++pos)
  {
    TimeBounds bounds = boundsList[pos];
    if (pos+1 < boundsList.size())
    {
      bounds[1] = boundsList[pos+1][0];
    }

    timeGeometry->AppendTimeStepClone(templateGeometry,bounds[1],bounds[0]);
  }

  return timeGeometry.GetPointer();
};
<commit_msg>- fixed bug 19388<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.

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

//#define MBILOG_ENABLE_DEBUG

#include <dcvrdt.h>

#define BOOST_DATE_TIME_NO_LIB
//Prevent unnecessary/unwanted auto link in this compilation when activating boost libraries in the MITK superbuild
//It is necessary because BOOST_ALL_DYN_LINK overwrites BOOST_DATE_TIME_NO_LIB
#if defined(BOOST_ALL_DYN_LINK)
  #undef BOOST_ALL_DYN_LINK
#endif

#include <boost/date_time/posix_time/posix_time_types.hpp>

#include "mitkITKDICOMSeriesReaderHelper.h"
#include "mitkITKDICOMSeriesReaderHelper.txx"

#include "mitkDICOMGDCMTagScanner.h"
#include "mitkArbitraryTimeGeometry.h"

#define switch3DCase(IOType, T) \
  case IOType: return LoadDICOMByITK< T >(filenames, correctTilt, tiltInfo, io);

bool
  mitk::ITKDICOMSeriesReaderHelper
  ::CanHandleFile(const std::string& filename)
{
  MITK_DEBUG << "ITKDICOMSeriesReaderHelper::CanHandleFile " << filename;
  itk::GDCMImageIO::Pointer tester = itk::GDCMImageIO::New();
  return tester->CanReadFile(filename.c_str());
}

mitk::Image::Pointer
  mitk::ITKDICOMSeriesReaderHelper
  ::Load( const StringContainer& filenames, bool correctTilt, const GantryTiltInformation& tiltInfo )
{
  if( filenames.empty() )
  {
    MITK_DEBUG << "Calling LoadDicomSeries with empty filename string container. Probably invalid application logic.";
    return nullptr; // this is not actually an error but the result is very simple
  }

  typedef itk::GDCMImageIO DcmIoType;
  DcmIoType::Pointer io = DcmIoType::New();

  try
  {
    if (io->CanReadFile(filenames.front().c_str()))
    {
      io->SetFileName(filenames.front().c_str());
      io->ReadImageInformation();

      if (io->GetPixelType() == itk::ImageIOBase::SCALAR)
      {
        switch (io->GetComponentType())
        {
          switch3DCase(DcmIoType::UCHAR, unsigned char)
            switch3DCase(DcmIoType::CHAR, char)
            switch3DCase(DcmIoType::USHORT, unsigned short)
            switch3DCase(DcmIoType::SHORT, short)
            switch3DCase(DcmIoType::UINT, unsigned int)
            switch3DCase(DcmIoType::INT, int)
            switch3DCase(DcmIoType::ULONG, long unsigned int)
            switch3DCase(DcmIoType::LONG, long int)
            switch3DCase(DcmIoType::FLOAT, float)
            switch3DCase(DcmIoType::DOUBLE, double)
        default:
          MITK_ERROR << "Found unsupported DICOM scalar pixel type: (enum value) " << io->GetComponentType();
        }
      }
      else if (io->GetPixelType() == itk::ImageIOBase::RGB)
      {
        switch (io->GetComponentType())
        {
          switch3DCase(DcmIoType::UCHAR, itk::RGBPixel<unsigned char>)
            switch3DCase(DcmIoType::CHAR, itk::RGBPixel<char>)
            switch3DCase(DcmIoType::USHORT, itk::RGBPixel<unsigned short>)
            switch3DCase(DcmIoType::SHORT, itk::RGBPixel<short>)
            switch3DCase(DcmIoType::UINT, itk::RGBPixel<unsigned int>)
            switch3DCase(DcmIoType::INT, itk::RGBPixel<int>)
            switch3DCase(DcmIoType::ULONG, itk::RGBPixel<long unsigned int>)
            switch3DCase(DcmIoType::LONG, itk::RGBPixel<long int>)
            switch3DCase(DcmIoType::FLOAT, itk::RGBPixel<float>)
            switch3DCase(DcmIoType::DOUBLE, itk::RGBPixel<double>)
        default:
          MITK_ERROR << "Found unsupported DICOM scalar pixel type: (enum value) " << io->GetComponentType();
        }
      }

      MITK_ERROR << "Unsupported DICOM pixel type";
      return nullptr;
    }
  }
  catch(itk::MemoryAllocationError& e)
  {
    MITK_ERROR << "Out of memory. Cannot load DICOM series: " << e.what();
  }
  catch(std::exception& e)
  {
    MITK_ERROR << "Error encountered when loading DICOM series:" << e.what();
  }
  catch(...)
  {
    MITK_ERROR << "Unspecified error encountered when loading DICOM series.";
  }

  return nullptr;
}

#define switch3DnTCase(IOType, T) \
  case IOType: return LoadDICOMByITK3DnT< T >(filenamesLists, correctTilt, tiltInfo, io);

mitk::Image::Pointer
  mitk::ITKDICOMSeriesReaderHelper
  ::Load3DnT( const StringContainerList& filenamesLists, bool correctTilt, const GantryTiltInformation& tiltInfo )
{
  if( filenamesLists.empty() || filenamesLists.front().empty() )
  {
    MITK_DEBUG << "Calling LoadDicomSeries with empty filename string container. Probably invalid application logic.";
    return nullptr; // this is not actually an error but the result is very simple
  }

  typedef itk::GDCMImageIO DcmIoType;
  DcmIoType::Pointer io = DcmIoType::New();

  try
  {
    if (io->CanReadFile(filenamesLists.front().front().c_str()))
    {
      io->SetFileName(filenamesLists.front().front().c_str());
      io->ReadImageInformation();

      if (io->GetPixelType() == itk::ImageIOBase::SCALAR)
      {
        switch (io->GetComponentType())
        {
          switch3DnTCase(DcmIoType::UCHAR, unsigned char)
            switch3DnTCase(DcmIoType::CHAR, char)
            switch3DnTCase(DcmIoType::USHORT, unsigned short)
            switch3DnTCase(DcmIoType::SHORT, short)
            switch3DnTCase(DcmIoType::UINT, unsigned int)
            switch3DnTCase(DcmIoType::INT, int)
            switch3DnTCase(DcmIoType::ULONG, long unsigned int)
            switch3DnTCase(DcmIoType::LONG, long int)
            switch3DnTCase(DcmIoType::FLOAT, float)
            switch3DnTCase(DcmIoType::DOUBLE, double)
        default:
          MITK_ERROR << "Found unsupported DICOM scalar pixel type: (enum value) " << io->GetComponentType();
        }
      }
      else if (io->GetPixelType() == itk::ImageIOBase::RGB)
      {
        switch (io->GetComponentType())
        {
          switch3DnTCase(DcmIoType::UCHAR, itk::RGBPixel<unsigned char>)
            switch3DnTCase(DcmIoType::CHAR, itk::RGBPixel<char>)
            switch3DnTCase(DcmIoType::USHORT, itk::RGBPixel<unsigned short>)
            switch3DnTCase(DcmIoType::SHORT, itk::RGBPixel<short>)
            switch3DnTCase(DcmIoType::UINT, itk::RGBPixel<unsigned int>)
            switch3DnTCase(DcmIoType::INT, itk::RGBPixel<int>)
            switch3DnTCase(DcmIoType::ULONG, itk::RGBPixel<long unsigned int>)
            switch3DnTCase(DcmIoType::LONG, itk::RGBPixel<long int>)
            switch3DnTCase(DcmIoType::FLOAT, itk::RGBPixel<float>)
            switch3DnTCase(DcmIoType::DOUBLE, itk::RGBPixel<double>)
        default:
          MITK_ERROR << "Found unsupported DICOM scalar pixel type: (enum value) " << io->GetComponentType();
        }
      }

      MITK_ERROR << "Unsupported DICOM pixel type";
      return nullptr;
    }
  }
  catch(itk::MemoryAllocationError& e)
  {
    MITK_ERROR << "Out of memory. Cannot load DICOM series: " << e.what();
  }
  catch(std::exception& e)
  {
    MITK_ERROR << "Error encountered when loading DICOM series:" << e.what();
  }
  catch(...)
  {
    MITK_ERROR << "Unspecified error encountered when loading DICOM series.";
  }

  return nullptr;
}

bool ConvertDICOMDateTimeString(const std::string& dateString, const std::string& timeString, OFDateTime& time)
{
  OFString content(timeString.c_str());

  if (!dateString.empty())
  {
    content = OFString(dateString.c_str()).append(content);
  }

  OFCondition result = DcmDateTime::getOFDateTimeFromString(content,time);

  return result.good();
}

boost::posix_time::ptime ConvertOFDateTimeToPTime(const OFDateTime& time)
{
  boost::gregorian::date boostDate(time.getDate().getYear(),time.getDate().getMonth(),time.getDate().getDay());
  boost::posix_time::time_duration boostTime = boost::posix_time::hours(time.getTime().getHour())
                                              +boost::posix_time::minutes(time.getTime().getMinute())
                                              +boost::posix_time::seconds(time.getTime().getSecond())
                                              +boost::posix_time::milliseconds(time.getTime().getMilliSecond());

  boost::posix_time::ptime result(boostDate,boostTime);

  return result;
}

OFDateTime GetLowerDateTime(const OFDateTime& time1, const OFDateTime& time2)
{
  OFDateTime result = time1;

  if ((time2.getDate()<time1.getDate()) ||
      ((time2.getDate() == time1.getDate()) && (time2.getTime()<time1.getTime())))
  {
    result = time2;
  }

  return result;
}

OFDateTime GetUpperDateTime(const OFDateTime& time1, const OFDateTime& time2)
{
  OFDateTime result = time1;

  if ((time2.getDate()>time1.getDate()) ||
      ((time2.getDate() == time1.getDate()) && (time2.getTime()>time1.getTime())))
  {
    result = time2;
  }

  return result;
}

double ComputeMiliSecDuration(const OFDateTime& start, const OFDateTime& stop)
{
  boost::posix_time::ptime startTime = ConvertOFDateTimeToPTime(start);
  boost::posix_time::ptime stopTime = ConvertOFDateTimeToPTime(stop);

  ::boost::posix_time::time_duration duration = stopTime - startTime;

  double result = duration.total_milliseconds();

  return result;
}

bool
  mitk::ITKDICOMSeriesReaderHelper::ExtractTimeBoundsOfTimeStep (const StringContainer& filenamesOfTimeStep, DateTimeBounds& bounds)
{
  DICOMTag acquisitionDateTag(0x0008, 0x0022);
  DICOMTag acquisitionTimeTag(0x0008, 0x0032);
  DICOMGDCMTagScanner::Pointer filescanner = DICOMGDCMTagScanner::New();
  filescanner->SetInputFiles(filenamesOfTimeStep);
  filescanner->AddTag( acquisitionDateTag );
  filescanner->AddTag( acquisitionTimeTag );
  filescanner->Scan();

  DICOMGDCMImageFrameList frameList = filescanner->GetFrameInfoList();

  bool result = false;
  bool first = true;

  for (DICOMGDCMImageFrameList::const_iterator pos = frameList.begin(); pos != frameList.end(); ++pos)
  {
    std::string dateStr = (*pos)->GetTagValueAsString(acquisitionDateTag);
    std::string timeStr = (*pos)->GetTagValueAsString(acquisitionTimeTag);

    OFDateTime time;
    bool convertResult = ConvertDICOMDateTimeString(dateStr, timeStr, time);

    if (convertResult)
    {
      if (first)
      {
        bounds[0] = time;
        bounds[1] = time;
        first = false;
      }
      else
      {
        bounds[0] = GetLowerDateTime(bounds[0], time);
        bounds[1] = GetUpperDateTime(bounds[1], time);
      }
      result = true;
    }
  }

  return result;
};

mitk::ITKDICOMSeriesReaderHelper::TimeBoundsList
  mitk::ITKDICOMSeriesReaderHelper::ExtractTimeBoundsOfTimeSteps (const StringContainerList& filenamesOfTimeSteps)
{
  TimeBoundsList result;

  OFDateTime baseLine;
  bool baseLineSet = false;

  for(StringContainerList::const_iterator pos = filenamesOfTimeSteps.begin(); pos!=filenamesOfTimeSteps.end(); ++pos)
  {
    TimeBounds bounds(0.0);
    DateTimeBounds dateTimeBounds;

    if(ExtractTimeBoundsOfTimeStep(*pos,dateTimeBounds))
    {
      if(!baseLineSet)
      {
        baseLineSet = true;
        baseLine = dateTimeBounds[0];
      }

      bounds[0] = ComputeMiliSecDuration(baseLine, dateTimeBounds[0]);
      bounds[1] = ComputeMiliSecDuration(baseLine, dateTimeBounds[1]);
    }

    result.push_back(bounds);
  }

  return result;
};

mitk::TimeGeometry::Pointer
  mitk::ITKDICOMSeriesReaderHelper::
  GenerateTimeGeometry(const BaseGeometry* templateGeometry, const TimeBoundsList& boundsList)
{
  ArbitraryTimeGeometry::Pointer timeGeometry = ArbitraryTimeGeometry::New();
  timeGeometry->ClearAllGeometries();

  for (TimeBoundsList::size_type pos = 0; pos < boundsList.size(); ++pos)
  {
    TimeBounds bounds = boundsList[pos];
    if (pos+1 < boundsList.size())
    {
      bounds[1] = boundsList[pos+1][0];
    }

    timeGeometry->AppendTimeStepClone(templateGeometry,bounds[1],bounds[0]);
  }

  return timeGeometry.GetPointer();
};
<|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 <mitkTestFixture.h>
#include <mitkTestingMacros.h>

#include <mitkPAMonteCarloThreadHandler.h>

// us
#include <usModule.h>
#include <usModuleResource.h>
#include <usGetModuleContext.h>
#include <usModuleContext.h>
#include <usModuleResourceStream.h>

#include <random>
#include <chrono>

class mitkMCThreadHandlerTestSuite : public mitk::TestFixture
{
  CPPUNIT_TEST_SUITE(mitkMCThreadHandlerTestSuite);
  MITK_TEST(testConstructorBehavior);
  MITK_TEST(testCorrectNumberOfPhotons);
  MITK_TEST(testCorrectNumberOfPhotonsWithUnevenPackageSize);
  MITK_TEST(testCorrectNumberOfPhotonsWithTooLargePackageSize);
  MITK_TEST(testCorrectTimeMeasure);
  CPPUNIT_TEST_SUITE_END();

private:

  mitk::pa::MonteCarloThreadHandler::Pointer m_MonteCarloThreadHandler;
  long m_NumberOrTime = 500;

public:

  void setUp() override
  {
  }

  void testConstructorBehavior()
  {
    auto threadHandler1 = mitk::pa::MonteCarloThreadHandler::New(m_NumberOrTime, true, true);
    auto threadHandler2 = mitk::pa::MonteCarloThreadHandler::New(m_NumberOrTime, true);

    CPPUNIT_ASSERT(mitk::pa::Equal(threadHandler1, threadHandler2, 1e-6, true));
  }

  void testCorrectTimeMeasure()
  {
    for (int i = 0; i < 10; i++)
    {
      m_MonteCarloThreadHandler = mitk::pa::MonteCarloThreadHandler::New(m_NumberOrTime, true, false);
      auto timeBefore = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
      long nextWorkPackage = 0;
      while ((nextWorkPackage = m_MonteCarloThreadHandler->GetNextWorkPackage()) > 0)
      {//Do nothing
      }
      auto timeAfter = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();

      //Assert that the time error is less than 10% in a 500ms sample size
      //This test might not be stable when on different machines.
      CPPUNIT_ASSERT(std::labs((timeAfter - timeBefore) - m_NumberOrTime) <= 50);
    }
  }

  void testCorrectNumberOfPhotons()
  {
    m_MonteCarloThreadHandler = mitk::pa::MonteCarloThreadHandler::New(m_NumberOrTime, false, false);
    m_MonteCarloThreadHandler->SetPackageSize(100);
    long numberOfPhotonsSimulated = 0;
    long nextWorkPackage = 0;
    while ((nextWorkPackage = m_MonteCarloThreadHandler->GetNextWorkPackage()) > 0)
    {
      numberOfPhotonsSimulated += nextWorkPackage;
    }
    CPPUNIT_ASSERT(numberOfPhotonsSimulated == m_NumberOrTime);
  }

  void testCorrectNumberOfPhotonsWithUnevenPackageSize()
  {
    m_MonteCarloThreadHandler = mitk::pa::MonteCarloThreadHandler::New(m_NumberOrTime, false, false);
    m_MonteCarloThreadHandler->SetPackageSize(77);
    long numberOfPhotonsSimulated = 0;
    long nextWorkPackage = 0;
    while ((nextWorkPackage = m_MonteCarloThreadHandler->GetNextWorkPackage()) > 0)
    {
      numberOfPhotonsSimulated += nextWorkPackage;
    }
    CPPUNIT_ASSERT(numberOfPhotonsSimulated == m_NumberOrTime);
  }

  void testCorrectNumberOfPhotonsWithTooLargePackageSize()
  {
    m_MonteCarloThreadHandler = mitk::pa::MonteCarloThreadHandler::New(m_NumberOrTime, false, false);
    m_MonteCarloThreadHandler->SetPackageSize(10000);
    long numberOfPhotonsSimulated = 0;
    long nextWorkPackage = 0;
    while ((nextWorkPackage = m_MonteCarloThreadHandler->GetNextWorkPackage()) > 0)
    {
      numberOfPhotonsSimulated += nextWorkPackage;
    }
    CPPUNIT_ASSERT(numberOfPhotonsSimulated == m_NumberOrTime);
  }

  void tearDown() override
  {
    m_MonteCarloThreadHandler = nullptr;
  }
};

MITK_TEST_SUITE_REGISTRATION(mitkMCThreadHandler)
<commit_msg>remove time measurement test<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 <mitkTestFixture.h>
#include <mitkTestingMacros.h>

#include <mitkPAMonteCarloThreadHandler.h>

// us
#include <usModule.h>
#include <usModuleResource.h>
#include <usGetModuleContext.h>
#include <usModuleContext.h>
#include <usModuleResourceStream.h>

#include <random>
#include <chrono>

class mitkMCThreadHandlerTestSuite : public mitk::TestFixture
{
  CPPUNIT_TEST_SUITE(mitkMCThreadHandlerTestSuite);
  MITK_TEST(testConstructorBehavior);
  MITK_TEST(testCorrectNumberOfPhotons);
  MITK_TEST(testCorrectNumberOfPhotonsWithUnevenPackageSize);
  MITK_TEST(testCorrectNumberOfPhotonsWithTooLargePackageSize);
  CPPUNIT_TEST_SUITE_END();

private:

  mitk::pa::MonteCarloThreadHandler::Pointer m_MonteCarloThreadHandler;
  long m_NumberOrTime = 500;

public:

  void setUp() override
  {
  }

  void testConstructorBehavior()
  {
    auto threadHandler1 = mitk::pa::MonteCarloThreadHandler::New(m_NumberOrTime, true, true);
    auto threadHandler2 = mitk::pa::MonteCarloThreadHandler::New(m_NumberOrTime, true);

    CPPUNIT_ASSERT(mitk::pa::Equal(threadHandler1, threadHandler2, 1e-6, true));
  }

  void testCorrectNumberOfPhotons()
  {
    m_MonteCarloThreadHandler = mitk::pa::MonteCarloThreadHandler::New(m_NumberOrTime, false, false);
    m_MonteCarloThreadHandler->SetPackageSize(100);
    long numberOfPhotonsSimulated = 0;
    long nextWorkPackage = 0;
    while ((nextWorkPackage = m_MonteCarloThreadHandler->GetNextWorkPackage()) > 0)
    {
      numberOfPhotonsSimulated += nextWorkPackage;
    }
    CPPUNIT_ASSERT(numberOfPhotonsSimulated == m_NumberOrTime);
  }

  void testCorrectNumberOfPhotonsWithUnevenPackageSize()
  {
    m_MonteCarloThreadHandler = mitk::pa::MonteCarloThreadHandler::New(m_NumberOrTime, false, false);
    m_MonteCarloThreadHandler->SetPackageSize(77);
    long numberOfPhotonsSimulated = 0;
    long nextWorkPackage = 0;
    while ((nextWorkPackage = m_MonteCarloThreadHandler->GetNextWorkPackage()) > 0)
    {
      numberOfPhotonsSimulated += nextWorkPackage;
    }
    CPPUNIT_ASSERT(numberOfPhotonsSimulated == m_NumberOrTime);
  }

  void testCorrectNumberOfPhotonsWithTooLargePackageSize()
  {
    m_MonteCarloThreadHandler = mitk::pa::MonteCarloThreadHandler::New(m_NumberOrTime, false, false);
    m_MonteCarloThreadHandler->SetPackageSize(10000);
    long numberOfPhotonsSimulated = 0;
    long nextWorkPackage = 0;
    while ((nextWorkPackage = m_MonteCarloThreadHandler->GetNextWorkPackage()) > 0)
    {
      numberOfPhotonsSimulated += nextWorkPackage;
    }
    CPPUNIT_ASSERT(numberOfPhotonsSimulated == m_NumberOrTime);
  }

  void tearDown() override
  {
    m_MonteCarloThreadHandler = nullptr;
  }
};

MITK_TEST_SUITE_REGISTRATION(mitkMCThreadHandler)
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/status/language_menu_button.h"

#include <string>

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/status/language_menu_l10n_util.h"
#include "chrome/browser/chromeos/status/status_area_host.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"

// The language menu consists of 3 parts (in this order):
//
//   (1) input method names. The size of the list is always >= 1.
//   (2) input method properties. This list might be empty.
//   (3) "Configure IME..." button.
//
// Example of the menu (Japanese):
//
// ============================== (border of the popup window)
// [ ] English                    (|index| in the following functions is 0)
// [*] Japanese
// [ ] Chinese (Simplified)
// ------------------------------ (separator)
// [*] Hiragana                   (index = 5, The property has 2 radio groups)
// [ ] Katakana
// [ ] HalfWidthKatakana
// [*] Roman
// [ ] Kana
// ------------------------------ (separator)
// Configure IME...               (index = 11)
// ============================== (border of the popup window)
//
// Example of the menu (Simplified Chinese):
//
// ============================== (border of the popup window)
// [ ] English
// [ ] Japanese
// [*] Chinese (Simplified)
// ------------------------------ (separator)
// Switch to full letter mode     (The property has 2 command buttons)
// Switch to half punctuation mode
// ------------------------------ (separator)
// Configure IME...
// ============================== (border of the popup window)
//

namespace {

// Constants to specify the type of items in |model_|.
enum {
  COMMAND_ID_INPUT_METHODS = 0,  // US, Anthy, PinYin, ...
  COMMAND_ID_IME_PROPERTIES,  // Hiragana, Katakana, ...
  COMMAND_ID_CONFIGURE_IME,  // The "Configure IME..." button.
};

// A group ID for IME properties starts from 0. We use the huge value for the
// input method list to avoid conflict.
const int kRadioGroupLanguage = 1 << 16;
const int kRadioGroupNone = -1;
const size_t kMaxLanguageNameLen = 2;
const wchar_t kSpacer[] = L"MMMMMMM";

// Returns the language name for the given |language_code|.
std::wstring GetLanguageName(const std::string& language_code) {
  const string16 language_name = l10n_util::GetDisplayNameForLocale(
      language_code, g_browser_process->GetApplicationLocale(), true);
  // TODO(satorux): We should add input method names if multiple input
  // methods are available for one input language.
  return UTF16ToWide(language_name);
}

// Converts chromeos::InputMethodDescriptor object into human readable string.
// Returns a string for the drop-down menu if |for_menu| is true. Otherwise,
// returns a string for the status area.
std::wstring FormatInputLanguage(
    const chromeos::InputMethodDescriptor& input_method, bool for_menu) {
  const std::string language_code
      = chromeos::LanguageLibrary::GetLanguageCodeFromDescriptor(input_method);

  std::wstring formatted;
  if (language_code == "t") {
    // "t" is used by input methods that do not associate with a
    // particular language. Returns the display name as-is.
    formatted = UTF8ToWide(input_method.display_name);
  }

  if (for_menu) {
    // For the drop-down menu, we'll show language names like
    // "Chinese (Simplified)" and "Japanese", instead of input method names
    // like "Pinyin" and "Anthy".
    if (formatted.empty()) {
      formatted = GetLanguageName(language_code);
    }
  } else {
    // For the status area, we use two-letter, upper-case language code like
    // "EN" and "JA".
    if (formatted.empty()) {
      formatted = UTF8ToWide(language_code);
    }
    formatted = StringToUpperASCII(formatted).substr(0, kMaxLanguageNameLen);
  }
  DCHECK(!formatted.empty());
  return formatted;
}

}  // namespace

namespace chromeos {

////////////////////////////////////////////////////////////////////////////////
// LanguageMenuButton

LanguageMenuButton::LanguageMenuButton(StatusAreaHost* host)
    : MenuButton(NULL, std::wstring(), this, false),
      input_method_descriptors_(CrosLibrary::Get()->GetLanguageLibrary()->
                                GetActiveInputMethods()),
      model_(NULL),
      // Be aware that the constructor of |language_menu_| calls GetItemCount()
      // in this class. Therefore, GetItemCount() have to return 0 when
      // |model_| is NULL.
      ALLOW_THIS_IN_INITIALIZER_LIST(language_menu_(this)),
      host_(host) {
  DCHECK(input_method_descriptors_.get() &&
         !input_method_descriptors_->empty());
  set_border(NULL);
  SetFont(ResourceBundle::GetSharedInstance().GetFont(
      ResourceBundle::BaseFont).DeriveFont(1, gfx::Font::BOLD));
  SetEnabledColor(0xB3FFFFFF); // White with 70% Alpha
  SetShowHighlighted(false);
  // Update the model
  RebuildModel();
  // Grab the real estate.
  UpdateIcon(kSpacer);
  // Display the default input method name.
  const std::wstring name
      = FormatInputLanguage(input_method_descriptors_->at(0), false);
  UpdateIcon(name);
  CrosLibrary::Get()->GetLanguageLibrary()->AddObserver(this);
}

LanguageMenuButton::~LanguageMenuButton() {
  CrosLibrary::Get()->GetLanguageLibrary()->RemoveObserver(this);
}

////////////////////////////////////////////////////////////////////////////////
// LanguageMenuButton, menus::MenuModel implementation:

int LanguageMenuButton::GetCommandIdAt(int index) const {
  return 0;  // dummy
}

bool LanguageMenuButton::IsLabelDynamicAt(int index) const {
  // Menu content for the language button could change time by time.
  return true;
}

bool LanguageMenuButton::GetAcceleratorAt(
    int index, menus::Accelerator* accelerator) const {
  // Views for Chromium OS does not support accelerators yet.
  return false;
}

bool LanguageMenuButton::IsItemCheckedAt(int index) const {
  DCHECK_GE(index, 0);
  DCHECK(input_method_descriptors_.get());

  if (IndexIsInInputMethodList(index)) {
    const InputMethodDescriptor& input_method
        = input_method_descriptors_->at(index);
    return input_method == CrosLibrary::Get()->GetLanguageLibrary()->
          current_input_method();
  }

  if (GetPropertyIndex(index, &index)) {
    const ImePropertyList& property_list
        = CrosLibrary::Get()->GetLanguageLibrary()->current_ime_properties();
    return property_list.at(index).is_selection_item_checked;
  }

  // Separator(s) or the "Configure IME" button.
  return false;
}

int LanguageMenuButton::GetGroupIdAt(int index) const {
  DCHECK_GE(index, 0);

  if (IndexIsInInputMethodList(index)) {
    return kRadioGroupLanguage;
  }

  if (GetPropertyIndex(index, &index)) {
    const ImePropertyList& property_list
        = CrosLibrary::Get()->GetLanguageLibrary()->current_ime_properties();
    return property_list.at(index).selection_item_id;
  }

  return kRadioGroupNone;
}

bool LanguageMenuButton::HasIcons() const  {
  // We don't support icons on Chrome OS.
  return false;
}

bool LanguageMenuButton::GetIconAt(int index, SkBitmap* icon) const {
  return false;
}

bool LanguageMenuButton::IsEnabledAt(int index) const {
  // Just return true so all input method names and input method propertie names
  // could be clicked.
  return true;
}

menus::MenuModel* LanguageMenuButton::GetSubmenuModelAt(int index) const {
  // We don't use nested menus.
  return NULL;
}

void LanguageMenuButton::HighlightChangedTo(int index) {
  // Views for Chromium OS does not support this interface yet.
}

void LanguageMenuButton::MenuWillShow() {
  // Views for Chromium OS does not support this interface yet.
}

int LanguageMenuButton::GetItemCount() const {
  if (!model_.get()) {
    // Model is not constructed yet. This means that LanguageMenuButton is
    // being constructed. Return zero.
    return 0;
  }
  return model_->GetItemCount();
}

menus::MenuModel::ItemType LanguageMenuButton::GetTypeAt(int index) const {
  DCHECK_GE(index, 0);

  if (IndexPointsToConfigureImeMenuItem(index)) {
    return menus::MenuModel::TYPE_COMMAND;  // "Configure IME"
  }

  if (IndexIsInInputMethodList(index)) {
    return menus::MenuModel::TYPE_RADIO;
  }

  if (GetPropertyIndex(index, &index)) {
    const ImePropertyList& property_list
        = CrosLibrary::Get()->GetLanguageLibrary()->current_ime_properties();
    if (property_list.at(index).is_selection_item) {
      return menus::MenuModel::TYPE_RADIO;
    }
    return menus::MenuModel::TYPE_COMMAND;
  }

  return menus::MenuModel::TYPE_SEPARATOR;
}

string16 LanguageMenuButton::GetLabelAt(int index) const {
  DCHECK_GE(index, 0);
  DCHECK(input_method_descriptors_.get());

  if (IndexPointsToConfigureImeMenuItem(index)) {
    return l10n_util::GetStringUTF16(IDS_STATUSBAR_IME_CONFIGURE);
  }

  std::wstring name;
  if (IndexIsInInputMethodList(index)) {
    name = FormatInputLanguage(input_method_descriptors_->at(index), true);
  } else if (GetPropertyIndex(index, &index)) {
    const ImePropertyList& property_list
        = CrosLibrary::Get()->GetLanguageLibrary()->current_ime_properties();
    return LanguageMenuL10nUtil::GetStringUTF16(
        property_list.at(index).label);
  }

  return WideToUTF16(name);
}

void LanguageMenuButton::ActivatedAt(int index) {
  DCHECK_GE(index, 0);
  DCHECK(input_method_descriptors_.get());

  if (IndexPointsToConfigureImeMenuItem(index)) {
    host_->OpenButtonOptions(this);
    return;
  }

  if (IndexIsInInputMethodList(index)) {
    // Inter-IME switching.
    const InputMethodDescriptor& input_method
        = input_method_descriptors_->at(index);
    CrosLibrary::Get()->GetLanguageLibrary()->ChangeInputMethod(
        input_method.id);
    return;
  }

  if (GetPropertyIndex(index, &index)) {
    // Intra-IME switching (e.g. Japanese-Hiragana to Japanese-Katakana).
    const ImePropertyList& property_list
        = CrosLibrary::Get()->GetLanguageLibrary()->current_ime_properties();
    const std::string key = property_list.at(index).key;
    if (property_list.at(index).is_selection_item) {
      // Radio button is clicked.
      const int id = property_list.at(index).selection_item_id;
      // First, deactivate all other properties in the same radio group.
      for (int i = 0; i < static_cast<int>(property_list.size()); ++i) {
        if (i != index && id == property_list.at(i).selection_item_id) {
          CrosLibrary::Get()->GetLanguageLibrary()->SetImePropertyActivated(
              property_list.at(i).key, false);
        }
      }
      // Then, activate the property clicked.
      CrosLibrary::Get()->GetLanguageLibrary()->SetImePropertyActivated(key,
                                                                        true);
    } else {
      // Command button like "Switch to half punctuation mode" is clicked.
      // We can always use "Deactivate" for command buttons.
      CrosLibrary::Get()->GetLanguageLibrary()->SetImePropertyActivated(key,
                                                                        false);
    }
    return;
  }

  // Separators are not clickable.
  NOTREACHED();
}

////////////////////////////////////////////////////////////////////////////////
// LanguageMenuButton, views::ViewMenuDelegate implementation:

void LanguageMenuButton::RunMenu(views::View* source, const gfx::Point& pt) {
  input_method_descriptors_.reset(CrosLibrary::Get()->GetLanguageLibrary()->
                                  GetActiveInputMethods());
  RebuildModel();
  language_menu_.Rebuild();
  language_menu_.UpdateStates();
  language_menu_.RunMenuAt(pt, views::Menu2::ALIGN_TOPRIGHT);
}

////////////////////////////////////////////////////////////////////////////////
// LanguageLibrary::Observer implementation:

void LanguageMenuButton::InputMethodChanged(LanguageLibrary* obj) {
  const std::wstring name = FormatInputLanguage(
      obj->current_input_method(), false);
  UpdateIcon(name);

  // This is necessary to remove input method properties when the current
  // language is switched to XKB.
  // TODO(yusukes): remove this call?
  RebuildModel();
}

void LanguageMenuButton::ImePropertiesChanged(LanguageLibrary* obj) {
  RebuildModel();
}

void LanguageMenuButton::UpdateIcon(const std::wstring& name) {
  SetText(name);
  set_alignment(TextButton::ALIGN_RIGHT);
  SchedulePaint();
}

void LanguageMenuButton::RebuildModel() {
  model_.reset(new menus::SimpleMenuModel(NULL));
  string16 dummy_label = UTF8ToUTF16("");
  // Indicates if separator's needed before each section.
  bool need_separator = false;

  if (!input_method_descriptors_->empty()) {
    // We "abuse" the command_id and group_id arguments of AddRadioItem method.
    // A COMMAND_ID_XXX enum value is passed as command_id, and array index of
    // |input_method_descriptors_| or |property_list| is passed as group_id.
    for (size_t i = 0; i < input_method_descriptors_->size(); ++i) {
      model_->AddRadioItem(COMMAND_ID_INPUT_METHODS, dummy_label, i);
    }
    need_separator = true;
  }

  const ImePropertyList& property_list
      = CrosLibrary::Get()->GetLanguageLibrary()->current_ime_properties();
  if (!property_list.empty()) {
    if (need_separator)
      model_->AddSeparator();
    for (size_t i = 0; i < property_list.size(); ++i) {
      model_->AddRadioItem(COMMAND_ID_IME_PROPERTIES, dummy_label, i);
    }
    need_separator = true;
  }

  if (host_->ShouldOpenButtonOptions(this)) {
    // Note: We use AddSeparator() for separators, and AddRadioItem() for all
    // other items even if an item is not actually a radio item.
    if (need_separator)
      model_->AddSeparator();
    model_->AddRadioItem(COMMAND_ID_CONFIGURE_IME, dummy_label, 0 /* dummy */);
  }
}

bool LanguageMenuButton::IndexIsInInputMethodList(int index) const {
  DCHECK_GE(index, 0);
  DCHECK(model_.get());

  return ((model_->GetTypeAt(index) == menus::MenuModel::TYPE_RADIO) &&
          (model_->GetCommandIdAt(index) == COMMAND_ID_INPUT_METHODS));
}

bool LanguageMenuButton::GetPropertyIndex(
    int index, int* property_index) const {
  DCHECK_GE(index, 0);
  DCHECK(property_index);
  DCHECK(model_.get());

  if ((model_->GetTypeAt(index) == menus::MenuModel::TYPE_RADIO) &&
      (model_->GetCommandIdAt(index) == COMMAND_ID_IME_PROPERTIES)) {
    *property_index = model_->GetGroupIdAt(index);
    return true;
  }
  return false;
}

bool LanguageMenuButton::IndexPointsToConfigureImeMenuItem(int index) const {
  DCHECK_GE(index, 0);
  DCHECK(model_.get());

  return ((model_->GetTypeAt(index) == menus::MenuModel::TYPE_RADIO) &&
          (model_->GetCommandIdAt(index) == COMMAND_ID_CONFIGURE_IME));
}

}  // namespace chromeos
<commit_msg>Don't use too much space for the language indicator.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/status/language_menu_button.h"

#include <string>

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/status/language_menu_l10n_util.h"
#include "chrome/browser/chromeos/status/status_area_host.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"

// The language menu consists of 3 parts (in this order):
//
//   (1) input method names. The size of the list is always >= 1.
//   (2) input method properties. This list might be empty.
//   (3) "Configure IME..." button.
//
// Example of the menu (Japanese):
//
// ============================== (border of the popup window)
// [ ] English                    (|index| in the following functions is 0)
// [*] Japanese
// [ ] Chinese (Simplified)
// ------------------------------ (separator)
// [*] Hiragana                   (index = 5, The property has 2 radio groups)
// [ ] Katakana
// [ ] HalfWidthKatakana
// [*] Roman
// [ ] Kana
// ------------------------------ (separator)
// Configure IME...               (index = 11)
// ============================== (border of the popup window)
//
// Example of the menu (Simplified Chinese):
//
// ============================== (border of the popup window)
// [ ] English
// [ ] Japanese
// [*] Chinese (Simplified)
// ------------------------------ (separator)
// Switch to full letter mode     (The property has 2 command buttons)
// Switch to half punctuation mode
// ------------------------------ (separator)
// Configure IME...
// ============================== (border of the popup window)
//

namespace {

// Constants to specify the type of items in |model_|.
enum {
  COMMAND_ID_INPUT_METHODS = 0,  // US, Anthy, PinYin, ...
  COMMAND_ID_IME_PROPERTIES,  // Hiragana, Katakana, ...
  COMMAND_ID_CONFIGURE_IME,  // The "Configure IME..." button.
};

// A group ID for IME properties starts from 0. We use the huge value for the
// input method list to avoid conflict.
const int kRadioGroupLanguage = 1 << 16;
const int kRadioGroupNone = -1;
const size_t kMaxLanguageNameLen = 2;
const wchar_t kSpacer[] = L"MMM";

// Returns the language name for the given |language_code|.
std::wstring GetLanguageName(const std::string& language_code) {
  const string16 language_name = l10n_util::GetDisplayNameForLocale(
      language_code, g_browser_process->GetApplicationLocale(), true);
  // TODO(satorux): We should add input method names if multiple input
  // methods are available for one input language.
  return UTF16ToWide(language_name);
}

// Converts chromeos::InputMethodDescriptor object into human readable string.
// Returns a string for the drop-down menu if |for_menu| is true. Otherwise,
// returns a string for the status area.
std::wstring FormatInputLanguage(
    const chromeos::InputMethodDescriptor& input_method, bool for_menu) {
  const std::string language_code
      = chromeos::LanguageLibrary::GetLanguageCodeFromDescriptor(input_method);

  std::wstring formatted;
  if (language_code == "t") {
    // "t" is used by input methods that do not associate with a
    // particular language. Returns the display name as-is.
    formatted = UTF8ToWide(input_method.display_name);
  }

  if (for_menu) {
    // For the drop-down menu, we'll show language names like
    // "Chinese (Simplified)" and "Japanese", instead of input method names
    // like "Pinyin" and "Anthy".
    if (formatted.empty()) {
      formatted = GetLanguageName(language_code);
    }
  } else {
    // For the status area, we use two-letter, upper-case language code like
    // "EN" and "JA".
    if (formatted.empty()) {
      formatted = UTF8ToWide(language_code);
    }
    formatted = StringToUpperASCII(formatted).substr(0, kMaxLanguageNameLen);
  }
  DCHECK(!formatted.empty());
  return formatted;
}

}  // namespace

namespace chromeos {

////////////////////////////////////////////////////////////////////////////////
// LanguageMenuButton

LanguageMenuButton::LanguageMenuButton(StatusAreaHost* host)
    : MenuButton(NULL, std::wstring(), this, false),
      input_method_descriptors_(CrosLibrary::Get()->GetLanguageLibrary()->
                                GetActiveInputMethods()),
      model_(NULL),
      // Be aware that the constructor of |language_menu_| calls GetItemCount()
      // in this class. Therefore, GetItemCount() have to return 0 when
      // |model_| is NULL.
      ALLOW_THIS_IN_INITIALIZER_LIST(language_menu_(this)),
      host_(host) {
  DCHECK(input_method_descriptors_.get() &&
         !input_method_descriptors_->empty());
  set_border(NULL);
  SetFont(ResourceBundle::GetSharedInstance().GetFont(
      ResourceBundle::BaseFont).DeriveFont(1, gfx::Font::BOLD));
  SetEnabledColor(0xB3FFFFFF); // White with 70% Alpha
  SetShowHighlighted(false);
  // Update the model
  RebuildModel();
  // Grab the real estate.
  UpdateIcon(kSpacer);
  // Display the default input method name.
  const std::wstring name
      = FormatInputLanguage(input_method_descriptors_->at(0), false);
  UpdateIcon(name);
  CrosLibrary::Get()->GetLanguageLibrary()->AddObserver(this);
}

LanguageMenuButton::~LanguageMenuButton() {
  CrosLibrary::Get()->GetLanguageLibrary()->RemoveObserver(this);
}

////////////////////////////////////////////////////////////////////////////////
// LanguageMenuButton, menus::MenuModel implementation:

int LanguageMenuButton::GetCommandIdAt(int index) const {
  return 0;  // dummy
}

bool LanguageMenuButton::IsLabelDynamicAt(int index) const {
  // Menu content for the language button could change time by time.
  return true;
}

bool LanguageMenuButton::GetAcceleratorAt(
    int index, menus::Accelerator* accelerator) const {
  // Views for Chromium OS does not support accelerators yet.
  return false;
}

bool LanguageMenuButton::IsItemCheckedAt(int index) const {
  DCHECK_GE(index, 0);
  DCHECK(input_method_descriptors_.get());

  if (IndexIsInInputMethodList(index)) {
    const InputMethodDescriptor& input_method
        = input_method_descriptors_->at(index);
    return input_method == CrosLibrary::Get()->GetLanguageLibrary()->
          current_input_method();
  }

  if (GetPropertyIndex(index, &index)) {
    const ImePropertyList& property_list
        = CrosLibrary::Get()->GetLanguageLibrary()->current_ime_properties();
    return property_list.at(index).is_selection_item_checked;
  }

  // Separator(s) or the "Configure IME" button.
  return false;
}

int LanguageMenuButton::GetGroupIdAt(int index) const {
  DCHECK_GE(index, 0);

  if (IndexIsInInputMethodList(index)) {
    return kRadioGroupLanguage;
  }

  if (GetPropertyIndex(index, &index)) {
    const ImePropertyList& property_list
        = CrosLibrary::Get()->GetLanguageLibrary()->current_ime_properties();
    return property_list.at(index).selection_item_id;
  }

  return kRadioGroupNone;
}

bool LanguageMenuButton::HasIcons() const  {
  // We don't support icons on Chrome OS.
  return false;
}

bool LanguageMenuButton::GetIconAt(int index, SkBitmap* icon) const {
  return false;
}

bool LanguageMenuButton::IsEnabledAt(int index) const {
  // Just return true so all input method names and input method propertie names
  // could be clicked.
  return true;
}

menus::MenuModel* LanguageMenuButton::GetSubmenuModelAt(int index) const {
  // We don't use nested menus.
  return NULL;
}

void LanguageMenuButton::HighlightChangedTo(int index) {
  // Views for Chromium OS does not support this interface yet.
}

void LanguageMenuButton::MenuWillShow() {
  // Views for Chromium OS does not support this interface yet.
}

int LanguageMenuButton::GetItemCount() const {
  if (!model_.get()) {
    // Model is not constructed yet. This means that LanguageMenuButton is
    // being constructed. Return zero.
    return 0;
  }
  return model_->GetItemCount();
}

menus::MenuModel::ItemType LanguageMenuButton::GetTypeAt(int index) const {
  DCHECK_GE(index, 0);

  if (IndexPointsToConfigureImeMenuItem(index)) {
    return menus::MenuModel::TYPE_COMMAND;  // "Configure IME"
  }

  if (IndexIsInInputMethodList(index)) {
    return menus::MenuModel::TYPE_RADIO;
  }

  if (GetPropertyIndex(index, &index)) {
    const ImePropertyList& property_list
        = CrosLibrary::Get()->GetLanguageLibrary()->current_ime_properties();
    if (property_list.at(index).is_selection_item) {
      return menus::MenuModel::TYPE_RADIO;
    }
    return menus::MenuModel::TYPE_COMMAND;
  }

  return menus::MenuModel::TYPE_SEPARATOR;
}

string16 LanguageMenuButton::GetLabelAt(int index) const {
  DCHECK_GE(index, 0);
  DCHECK(input_method_descriptors_.get());

  if (IndexPointsToConfigureImeMenuItem(index)) {
    return l10n_util::GetStringUTF16(IDS_STATUSBAR_IME_CONFIGURE);
  }

  std::wstring name;
  if (IndexIsInInputMethodList(index)) {
    name = FormatInputLanguage(input_method_descriptors_->at(index), true);
  } else if (GetPropertyIndex(index, &index)) {
    const ImePropertyList& property_list
        = CrosLibrary::Get()->GetLanguageLibrary()->current_ime_properties();
    return LanguageMenuL10nUtil::GetStringUTF16(
        property_list.at(index).label);
  }

  return WideToUTF16(name);
}

void LanguageMenuButton::ActivatedAt(int index) {
  DCHECK_GE(index, 0);
  DCHECK(input_method_descriptors_.get());

  if (IndexPointsToConfigureImeMenuItem(index)) {
    host_->OpenButtonOptions(this);
    return;
  }

  if (IndexIsInInputMethodList(index)) {
    // Inter-IME switching.
    const InputMethodDescriptor& input_method
        = input_method_descriptors_->at(index);
    CrosLibrary::Get()->GetLanguageLibrary()->ChangeInputMethod(
        input_method.id);
    return;
  }

  if (GetPropertyIndex(index, &index)) {
    // Intra-IME switching (e.g. Japanese-Hiragana to Japanese-Katakana).
    const ImePropertyList& property_list
        = CrosLibrary::Get()->GetLanguageLibrary()->current_ime_properties();
    const std::string key = property_list.at(index).key;
    if (property_list.at(index).is_selection_item) {
      // Radio button is clicked.
      const int id = property_list.at(index).selection_item_id;
      // First, deactivate all other properties in the same radio group.
      for (int i = 0; i < static_cast<int>(property_list.size()); ++i) {
        if (i != index && id == property_list.at(i).selection_item_id) {
          CrosLibrary::Get()->GetLanguageLibrary()->SetImePropertyActivated(
              property_list.at(i).key, false);
        }
      }
      // Then, activate the property clicked.
      CrosLibrary::Get()->GetLanguageLibrary()->SetImePropertyActivated(key,
                                                                        true);
    } else {
      // Command button like "Switch to half punctuation mode" is clicked.
      // We can always use "Deactivate" for command buttons.
      CrosLibrary::Get()->GetLanguageLibrary()->SetImePropertyActivated(key,
                                                                        false);
    }
    return;
  }

  // Separators are not clickable.
  NOTREACHED();
}

////////////////////////////////////////////////////////////////////////////////
// LanguageMenuButton, views::ViewMenuDelegate implementation:

void LanguageMenuButton::RunMenu(views::View* source, const gfx::Point& pt) {
  input_method_descriptors_.reset(CrosLibrary::Get()->GetLanguageLibrary()->
                                  GetActiveInputMethods());
  RebuildModel();
  language_menu_.Rebuild();
  language_menu_.UpdateStates();
  language_menu_.RunMenuAt(pt, views::Menu2::ALIGN_TOPRIGHT);
}

////////////////////////////////////////////////////////////////////////////////
// LanguageLibrary::Observer implementation:

void LanguageMenuButton::InputMethodChanged(LanguageLibrary* obj) {
  const std::wstring name = FormatInputLanguage(
      obj->current_input_method(), false);
  UpdateIcon(name);

  // This is necessary to remove input method properties when the current
  // language is switched to XKB.
  // TODO(yusukes): remove this call?
  RebuildModel();
}

void LanguageMenuButton::ImePropertiesChanged(LanguageLibrary* obj) {
  RebuildModel();
}

void LanguageMenuButton::UpdateIcon(const std::wstring& name) {
  SetText(name);
  set_alignment(TextButton::ALIGN_RIGHT);
  SchedulePaint();
}

void LanguageMenuButton::RebuildModel() {
  model_.reset(new menus::SimpleMenuModel(NULL));
  string16 dummy_label = UTF8ToUTF16("");
  // Indicates if separator's needed before each section.
  bool need_separator = false;

  if (!input_method_descriptors_->empty()) {
    // We "abuse" the command_id and group_id arguments of AddRadioItem method.
    // A COMMAND_ID_XXX enum value is passed as command_id, and array index of
    // |input_method_descriptors_| or |property_list| is passed as group_id.
    for (size_t i = 0; i < input_method_descriptors_->size(); ++i) {
      model_->AddRadioItem(COMMAND_ID_INPUT_METHODS, dummy_label, i);
    }
    need_separator = true;
  }

  const ImePropertyList& property_list
      = CrosLibrary::Get()->GetLanguageLibrary()->current_ime_properties();
  if (!property_list.empty()) {
    if (need_separator)
      model_->AddSeparator();
    for (size_t i = 0; i < property_list.size(); ++i) {
      model_->AddRadioItem(COMMAND_ID_IME_PROPERTIES, dummy_label, i);
    }
    need_separator = true;
  }

  if (host_->ShouldOpenButtonOptions(this)) {
    // Note: We use AddSeparator() for separators, and AddRadioItem() for all
    // other items even if an item is not actually a radio item.
    if (need_separator)
      model_->AddSeparator();
    model_->AddRadioItem(COMMAND_ID_CONFIGURE_IME, dummy_label, 0 /* dummy */);
  }
}

bool LanguageMenuButton::IndexIsInInputMethodList(int index) const {
  DCHECK_GE(index, 0);
  DCHECK(model_.get());

  return ((model_->GetTypeAt(index) == menus::MenuModel::TYPE_RADIO) &&
          (model_->GetCommandIdAt(index) == COMMAND_ID_INPUT_METHODS));
}

bool LanguageMenuButton::GetPropertyIndex(
    int index, int* property_index) const {
  DCHECK_GE(index, 0);
  DCHECK(property_index);
  DCHECK(model_.get());

  if ((model_->GetTypeAt(index) == menus::MenuModel::TYPE_RADIO) &&
      (model_->GetCommandIdAt(index) == COMMAND_ID_IME_PROPERTIES)) {
    *property_index = model_->GetGroupIdAt(index);
    return true;
  }
  return false;
}

bool LanguageMenuButton::IndexPointsToConfigureImeMenuItem(int index) const {
  DCHECK_GE(index, 0);
  DCHECK(model_.get());

  return ((model_->GetTypeAt(index) == menus::MenuModel::TYPE_RADIO) &&
          (model_->GetCommandIdAt(index) == COMMAND_ID_CONFIGURE_IME));
}

}  // namespace chromeos
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/memory/ref_counted.h"
#include "chrome/browser/extensions/api/socket/socket_api.h"
#include "chrome/browser/extensions/api/socket/test_echo_server_udp.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_function_test_utils.h"
#include "chrome/browser/extensions/extension_test_message_listener.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"

using namespace extension_function_test_utils;

namespace {

class SocketApiTest : public ExtensionApiTest {
 public:
  virtual void SetUpCommandLine(CommandLine* command_line) {
    ExtensionApiTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
    command_line->AppendSwitch(switches::kEnablePlatformApps);
  }
};

}

IN_PROC_BROWSER_TEST_F(SocketApiTest, SocketCreateGood) {
  scoped_refptr<extensions::SocketCreateFunction> socket_create_function(
      new extensions::SocketCreateFunction());
  scoped_refptr<Extension> empty_extension(CreateEmptyExtension());

  socket_create_function->set_extension(empty_extension.get());
  socket_create_function->set_has_callback(true);

  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
      socket_create_function, "[\"udp\"]", browser(), NONE));
  ASSERT_EQ(base::Value::TYPE_DICTIONARY, result->GetType());
  DictionaryValue *value = static_cast<DictionaryValue*>(result.get());
  int socketId = -1;
  EXPECT_TRUE(value->GetInteger("socketId", &socketId));
  EXPECT_TRUE(socketId > 0);
}

IN_PROC_BROWSER_TEST_F(SocketApiTest, SocketCreateBad) {
  scoped_refptr<extensions::SocketCreateFunction> socket_create_function(
      new extensions::SocketCreateFunction());
  scoped_refptr<Extension> empty_extension(CreateEmptyExtension());

  socket_create_function->set_extension(empty_extension.get());
  socket_create_function->set_has_callback(true);

  // TODO(miket): this test currently passes only because of artificial code
  // that doesn't run in production. Fix this when we're able to.
  RunFunctionAndReturnError(socket_create_function, "[\"xxxx\"]", browser(),
                            NONE);
}

// http://code.google.com/p/chromium/issues/detail?id=109337
//
// Currently believed to be fixed, but we're leaving it marked flaky
// for a few days to let it percolate through the trybots.
IN_PROC_BROWSER_TEST_F(SocketApiTest, FLAKY_SocketExtension) {
  scoped_refptr<extensions::TestEchoServerUDP> server =
      new extensions::TestEchoServerUDP();

  ResultCatcher catcher;
  catcher.RestrictToProfile(browser()->profile());

  ASSERT_TRUE(StartTestServer());
  ExtensionTestMessageListener listener("port_please", true);

  int port = server->Start();
  ASSERT_TRUE(port > 0);

  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("socket/api")));
  EXPECT_TRUE(listener.WaitUntilSatisfied());
  listener.Reply(port);

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();

  EXPECT_TRUE(server->WaitUntilFinished());
}
<commit_msg>Remove FLAKY_ prefix after confirming several good days on waterfall.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/memory/ref_counted.h"
#include "chrome/browser/extensions/api/socket/socket_api.h"
#include "chrome/browser/extensions/api/socket/test_echo_server_udp.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_function_test_utils.h"
#include "chrome/browser/extensions/extension_test_message_listener.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"

using namespace extension_function_test_utils;

namespace {

class SocketApiTest : public ExtensionApiTest {
 public:
  virtual void SetUpCommandLine(CommandLine* command_line) {
    ExtensionApiTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
    command_line->AppendSwitch(switches::kEnablePlatformApps);
  }
};

}

IN_PROC_BROWSER_TEST_F(SocketApiTest, SocketCreateGood) {
  scoped_refptr<extensions::SocketCreateFunction> socket_create_function(
      new extensions::SocketCreateFunction());
  scoped_refptr<Extension> empty_extension(CreateEmptyExtension());

  socket_create_function->set_extension(empty_extension.get());
  socket_create_function->set_has_callback(true);

  scoped_ptr<base::Value> result(RunFunctionAndReturnResult(
      socket_create_function, "[\"udp\"]", browser(), NONE));
  ASSERT_EQ(base::Value::TYPE_DICTIONARY, result->GetType());
  DictionaryValue *value = static_cast<DictionaryValue*>(result.get());
  int socketId = -1;
  EXPECT_TRUE(value->GetInteger("socketId", &socketId));
  EXPECT_TRUE(socketId > 0);
}

IN_PROC_BROWSER_TEST_F(SocketApiTest, SocketCreateBad) {
  scoped_refptr<extensions::SocketCreateFunction> socket_create_function(
      new extensions::SocketCreateFunction());
  scoped_refptr<Extension> empty_extension(CreateEmptyExtension());

  socket_create_function->set_extension(empty_extension.get());
  socket_create_function->set_has_callback(true);

  // TODO(miket): this test currently passes only because of artificial code
  // that doesn't run in production. Fix this when we're able to.
  RunFunctionAndReturnError(socket_create_function, "[\"xxxx\"]", browser(),
                            NONE);
}

IN_PROC_BROWSER_TEST_F(SocketApiTest, SocketExtension) {
  scoped_refptr<extensions::TestEchoServerUDP> server =
      new extensions::TestEchoServerUDP();

  ResultCatcher catcher;
  catcher.RestrictToProfile(browser()->profile());

  ASSERT_TRUE(StartTestServer());
  ExtensionTestMessageListener listener("port_please", true);

  int port = server->Start();
  ASSERT_TRUE(port > 0);

  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("socket/api")));
  EXPECT_TRUE(listener.WaitUntilSatisfied());
  listener.Reply(port);

  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();

  EXPECT_TRUE(server->WaitUntilFinished());
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/file_path.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/tab_restore_service.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/common/page_transition_types.h"

namespace {

// BrowserList::Observer implementation that waits for a browser to be
// removed.
class BrowserListObserverImpl : public BrowserList::Observer {
 public:
  BrowserListObserverImpl() : did_remove_(false), running_(false) {
    BrowserList::AddObserver(this);
  }

  ~BrowserListObserverImpl() {
    BrowserList::RemoveObserver(this);
  }

  // Returns when a browser has been removed.
  void Run() {
    running_ = true;
    if (!did_remove_)
      ui_test_utils::RunMessageLoop();
  }

  // BrowserList::Observer
  virtual void OnBrowserAdded(const Browser* browser) OVERRIDE {
  }
  virtual void OnBrowserRemoved(const Browser* browser) OVERRIDE {
    did_remove_ = true;
    if (running_)
      MessageLoop::current()->Quit();
  }

 private:
  // Was OnBrowserRemoved invoked?
  bool did_remove_;

  // Was Run invoked?
  bool running_;

  DISALLOW_COPY_AND_ASSIGN(BrowserListObserverImpl);
};

}  // namespace

typedef InProcessBrowserTest SessionRestoreTest;

#if defined(OS_LINUX) && defined(TOOLKIT_VIEWS)
// Crashes on Linux Views: http://crbug.com/39476
#define MAYBE_RestoreOnNewWindowWithNoTabbedBrowsers \
        DISABLED_RestoreOnNewWindowWithNoTabbedBrowsers
#else
#define MAYBE_RestoreOnNewWindowWithNoTabbedBrowsers \
        RestoreOnNewWindowWithNoTabbedBrowsers
#endif

// Makes sure when session restore is triggered in the same process we don't end
// up with an extra tab.
IN_PROC_BROWSER_TEST_F(SessionRestoreTest,
                       MAYBE_RestoreOnNewWindowWithNoTabbedBrowsers) {
  if (browser_defaults::kRestorePopups)
    return;

  const FilePath::CharType* kTitle1File = FILE_PATH_LITERAL("title1.html");
  GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
                                     FilePath(kTitle1File)));
  ui_test_utils::NavigateToURL(browser(), url);

  // Turn on session restore.
  SessionStartupPref::SetStartupPref(
      browser()->profile(),
      SessionStartupPref(SessionStartupPref::LAST));

  // Create a new popup.
  Profile* profile = browser()->profile();
  Browser* popup = Browser::CreateForType(Browser::TYPE_POPUP, profile);
  popup->window()->Show();

  // Close the browser.
  browser()->window()->Close();

  // Create a new window, which should trigger session restore.
  popup->NewWindow();

  Browser* new_browser = ui_test_utils::WaitForNewBrowser();

  ASSERT_TRUE(new_browser != NULL);

  // The browser should only have one tab.
  ASSERT_EQ(1, new_browser->tab_count());

  // And the first url should be url.
  EXPECT_EQ(url, new_browser->GetTabContentsAt(0)->GetURL());
}

IN_PROC_BROWSER_TEST_F(SessionRestoreTest, RestoreIndividualTabFromWindow) {
  GURL url1(ui_test_utils::GetTestUrl(
      FilePath(FilePath::kCurrentDirectory),
      FilePath(FILE_PATH_LITERAL("title1.html"))));
  GURL url2(ui_test_utils::GetTestUrl(
      FilePath(FilePath::kCurrentDirectory),
      FilePath(FILE_PATH_LITERAL("title2.html"))));
  GURL url3(ui_test_utils::GetTestUrl(
      FilePath(FilePath::kCurrentDirectory),
      FilePath(FILE_PATH_LITERAL("title3.html"))));

  // Add and navigate three tabs.
  ui_test_utils::NavigateToURL(browser(), url1);
  browser()->AddSelectedTabWithURL(url2, PageTransition::LINK);
  ui_test_utils::WaitForNavigationInCurrentTab(browser());

  browser()->AddSelectedTabWithURL(url3, PageTransition::LINK);
  ui_test_utils::WaitForNavigationInCurrentTab(browser());

  TabRestoreService* service = browser()->profile()->GetTabRestoreService();
  service->ClearEntries();

  browser()->window()->Close();

  // Expect a window with three tabs.
  EXPECT_EQ(1U, service->entries().size());
  ASSERT_EQ(TabRestoreService::WINDOW, service->entries().front()->type);
  const TabRestoreService::Window* window =
      static_cast<TabRestoreService::Window*>(service->entries().front());
  EXPECT_EQ(3U, window->tabs.size());

  // Find the SessionID for entry2. Since the session service was destroyed,
  // there is no guarantee that the SessionID for the tab has remained the same.
  std::vector<TabRestoreService::Tab>::const_iterator it = window->tabs.begin();
  for ( ; it != window->tabs.end(); ++it) {
    const TabRestoreService::Tab& tab = *it;
    // If this tab held url2, then restore this single tab.
    if (tab.navigations[0].virtual_url() == url2) {
      service->RestoreEntryById(NULL, tab.id, false);
      break;
    }
  }

  // Make sure that the Window got updated.
  EXPECT_EQ(1U, service->entries().size());
  ASSERT_EQ(TabRestoreService::WINDOW, service->entries().front()->type);
  window = static_cast<TabRestoreService::Window*>(service->entries().front());
  EXPECT_EQ(2U, window->tabs.size());
}

IN_PROC_BROWSER_TEST_F(SessionRestoreTest, WindowWithOneTab) {
  GURL url(ui_test_utils::GetTestUrl(
      FilePath(FilePath::kCurrentDirectory),
      FilePath(FILE_PATH_LITERAL("title1.html"))));

  // Add a single tab.
  ui_test_utils::NavigateToURL(browser(), url);

  TabRestoreService* service = browser()->profile()->GetTabRestoreService();
  service->ClearEntries();
  EXPECT_EQ(0U, service->entries().size());

  // Close the window.
  browser()->window()->Close();

  // Expect the window to be converted to a tab by the TRS.
  EXPECT_EQ(1U, service->entries().size());
  ASSERT_EQ(TabRestoreService::TAB, service->entries().front()->type);
  const TabRestoreService::Tab* tab =
      static_cast<TabRestoreService::Tab*>(service->entries().front());

  // Restore the tab.
  service->RestoreEntryById(NULL, tab->id, false);

  // Make sure the restore was successful.
  EXPECT_EQ(0U, service->entries().size());
}

// Verifies we remember the last browser window when closing the last
// non-incognito window while an incognito window is open.
IN_PROC_BROWSER_TEST_F(SessionRestoreTest, IncognitotoNonIncognito) {
  // Turn on session restore.
  SessionStartupPref pref(SessionStartupPref::LAST);
  SessionStartupPref::SetStartupPref(browser()->profile(), pref);

  GURL url(ui_test_utils::GetTestUrl(
      FilePath(FilePath::kCurrentDirectory),
      FilePath(FILE_PATH_LITERAL("title1.html"))));

  // Add a single tab.
  ui_test_utils::NavigateToURL(browser(), url);

  // Create a new incognito window.
  Browser* incognito_browser = CreateIncognitoBrowser();
  incognito_browser->AddBlankTab(true);
  incognito_browser->window()->Show();

  // Close the normal browser. After this we only have the incognito window
  // open. We wait until the window closes as window closing is async.
  {
    BrowserListObserverImpl observer;
    browser()->window()->Close();
    observer.Run();
  }

  // Create a new window, which should trigger session restore.
  incognito_browser->NewWindow();

  // The first tab should have 'url' as its url.
  Browser* new_browser = ui_test_utils::WaitForNewBrowser();
  ASSERT_TRUE(new_browser);
  EXPECT_EQ(url, new_browser->GetTabContentsAt(0)->GetURL());
}
<commit_msg>Fix header include for reals.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/file_path.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/tab_restore_service.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/common/page_transition_types.h"

namespace {

// BrowserList::Observer implementation that waits for a browser to be
// removed.
class BrowserListObserverImpl : public BrowserList::Observer {
 public:
  BrowserListObserverImpl() : did_remove_(false), running_(false) {
    BrowserList::AddObserver(this);
  }

  ~BrowserListObserverImpl() {
    BrowserList::RemoveObserver(this);
  }

  // Returns when a browser has been removed.
  void Run() {
    running_ = true;
    if (!did_remove_)
      ui_test_utils::RunMessageLoop();
  }

  // BrowserList::Observer
  virtual void OnBrowserAdded(const Browser* browser) OVERRIDE {
  }
  virtual void OnBrowserRemoved(const Browser* browser) OVERRIDE {
    did_remove_ = true;
    if (running_)
      MessageLoop::current()->Quit();
  }

 private:
  // Was OnBrowserRemoved invoked?
  bool did_remove_;

  // Was Run invoked?
  bool running_;

  DISALLOW_COPY_AND_ASSIGN(BrowserListObserverImpl);
};

}  // namespace

typedef InProcessBrowserTest SessionRestoreTest;

#if defined(OS_LINUX) && defined(TOOLKIT_VIEWS)
// Crashes on Linux Views: http://crbug.com/39476
#define MAYBE_RestoreOnNewWindowWithNoTabbedBrowsers \
        DISABLED_RestoreOnNewWindowWithNoTabbedBrowsers
#else
#define MAYBE_RestoreOnNewWindowWithNoTabbedBrowsers \
        RestoreOnNewWindowWithNoTabbedBrowsers
#endif

// Makes sure when session restore is triggered in the same process we don't end
// up with an extra tab.
IN_PROC_BROWSER_TEST_F(SessionRestoreTest,
                       MAYBE_RestoreOnNewWindowWithNoTabbedBrowsers) {
  if (browser_defaults::kRestorePopups)
    return;

  const FilePath::CharType* kTitle1File = FILE_PATH_LITERAL("title1.html");
  GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
                                     FilePath(kTitle1File)));
  ui_test_utils::NavigateToURL(browser(), url);

  // Turn on session restore.
  SessionStartupPref::SetStartupPref(
      browser()->profile(),
      SessionStartupPref(SessionStartupPref::LAST));

  // Create a new popup.
  Profile* profile = browser()->profile();
  Browser* popup = Browser::CreateForType(Browser::TYPE_POPUP, profile);
  popup->window()->Show();

  // Close the browser.
  browser()->window()->Close();

  // Create a new window, which should trigger session restore.
  popup->NewWindow();

  Browser* new_browser = ui_test_utils::WaitForNewBrowser();

  ASSERT_TRUE(new_browser != NULL);

  // The browser should only have one tab.
  ASSERT_EQ(1, new_browser->tab_count());

  // And the first url should be url.
  EXPECT_EQ(url, new_browser->GetTabContentsAt(0)->GetURL());
}

IN_PROC_BROWSER_TEST_F(SessionRestoreTest, RestoreIndividualTabFromWindow) {
  GURL url1(ui_test_utils::GetTestUrl(
      FilePath(FilePath::kCurrentDirectory),
      FilePath(FILE_PATH_LITERAL("title1.html"))));
  GURL url2(ui_test_utils::GetTestUrl(
      FilePath(FilePath::kCurrentDirectory),
      FilePath(FILE_PATH_LITERAL("title2.html"))));
  GURL url3(ui_test_utils::GetTestUrl(
      FilePath(FilePath::kCurrentDirectory),
      FilePath(FILE_PATH_LITERAL("title3.html"))));

  // Add and navigate three tabs.
  ui_test_utils::NavigateToURL(browser(), url1);
  browser()->AddSelectedTabWithURL(url2, PageTransition::LINK);
  ui_test_utils::WaitForNavigationInCurrentTab(browser());

  browser()->AddSelectedTabWithURL(url3, PageTransition::LINK);
  ui_test_utils::WaitForNavigationInCurrentTab(browser());

  TabRestoreService* service = browser()->profile()->GetTabRestoreService();
  service->ClearEntries();

  browser()->window()->Close();

  // Expect a window with three tabs.
  EXPECT_EQ(1U, service->entries().size());
  ASSERT_EQ(TabRestoreService::WINDOW, service->entries().front()->type);
  const TabRestoreService::Window* window =
      static_cast<TabRestoreService::Window*>(service->entries().front());
  EXPECT_EQ(3U, window->tabs.size());

  // Find the SessionID for entry2. Since the session service was destroyed,
  // there is no guarantee that the SessionID for the tab has remained the same.
  std::vector<TabRestoreService::Tab>::const_iterator it = window->tabs.begin();
  for ( ; it != window->tabs.end(); ++it) {
    const TabRestoreService::Tab& tab = *it;
    // If this tab held url2, then restore this single tab.
    if (tab.navigations[0].virtual_url() == url2) {
      service->RestoreEntryById(NULL, tab.id, false);
      break;
    }
  }

  // Make sure that the Window got updated.
  EXPECT_EQ(1U, service->entries().size());
  ASSERT_EQ(TabRestoreService::WINDOW, service->entries().front()->type);
  window = static_cast<TabRestoreService::Window*>(service->entries().front());
  EXPECT_EQ(2U, window->tabs.size());
}

IN_PROC_BROWSER_TEST_F(SessionRestoreTest, WindowWithOneTab) {
  GURL url(ui_test_utils::GetTestUrl(
      FilePath(FilePath::kCurrentDirectory),
      FilePath(FILE_PATH_LITERAL("title1.html"))));

  // Add a single tab.
  ui_test_utils::NavigateToURL(browser(), url);

  TabRestoreService* service = browser()->profile()->GetTabRestoreService();
  service->ClearEntries();
  EXPECT_EQ(0U, service->entries().size());

  // Close the window.
  browser()->window()->Close();

  // Expect the window to be converted to a tab by the TRS.
  EXPECT_EQ(1U, service->entries().size());
  ASSERT_EQ(TabRestoreService::TAB, service->entries().front()->type);
  const TabRestoreService::Tab* tab =
      static_cast<TabRestoreService::Tab*>(service->entries().front());

  // Restore the tab.
  service->RestoreEntryById(NULL, tab->id, false);

  // Make sure the restore was successful.
  EXPECT_EQ(0U, service->entries().size());
}

// Verifies we remember the last browser window when closing the last
// non-incognito window while an incognito window is open.
IN_PROC_BROWSER_TEST_F(SessionRestoreTest, IncognitotoNonIncognito) {
  // Turn on session restore.
  SessionStartupPref pref(SessionStartupPref::LAST);
  SessionStartupPref::SetStartupPref(browser()->profile(), pref);

  GURL url(ui_test_utils::GetTestUrl(
      FilePath(FilePath::kCurrentDirectory),
      FilePath(FILE_PATH_LITERAL("title1.html"))));

  // Add a single tab.
  ui_test_utils::NavigateToURL(browser(), url);

  // Create a new incognito window.
  Browser* incognito_browser = CreateIncognitoBrowser();
  incognito_browser->AddBlankTab(true);
  incognito_browser->window()->Show();

  // Close the normal browser. After this we only have the incognito window
  // open. We wait until the window closes as window closing is async.
  {
    BrowserListObserverImpl observer;
    browser()->window()->Close();
    observer.Run();
  }

  // Create a new window, which should trigger session restore.
  incognito_browser->NewWindow();

  // The first tab should have 'url' as its url.
  Browser* new_browser = ui_test_utils::WaitForNewBrowser();
  ASSERT_TRUE(new_browser);
  EXPECT_EQ(url, new_browser->GetTabContentsAt(0)->GetURL());
}
<|endoftext|>