<commit_before>/*=========================================================================
 *
 *  Copyright UMC Utrecht and contributors
 *
 *  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.
 *
 *=========================================================================*/

#ifndef __itkParameterFileParser_cxx
#define __itkParameterFileParser_cxx

#include "itkParameterFileParser.h"

#include <itksys/SystemTools.hxx>
#include <itksys/RegularExpression.hxx>

namespace itk
{

/**
 * **************** Constructor ***************
 */

ParameterFileParser
::ParameterFileParser()
{
  this->m_ParameterFileName = "";
  this->m_ParameterMap.clear();

} // end Constructor()

/**
 * **************** Destructor ***************
 */

ParameterFileParser
::~ParameterFileParser()
{
  if( this->m_ParameterFile.is_open() )
  {
    this->m_ParameterFile.close();
  }

} // end Destructor()

/**
 * **************** GetParameterMap ***************
 */

const ParameterFileParser::ParameterMapType &
ParameterFileParser
::GetParameterMap( void ) const
{
  return this->m_ParameterMap;

} // end GetParameterMap()

/**
 * **************** ReadParameterFile ***************
 */

void
ParameterFileParser
::ReadParameterFile( void )
{
  /** Perform some basic checks. */
  this->BasicFileChecking();

  /** Open the parameter file for reading. */
  if( this->m_ParameterFile.is_open() )
  {
    this->m_ParameterFile.clear();
    this->m_ParameterFile.close();
  }
  this->m_ParameterFile.open( this->m_ParameterFileName, std::fstream::in );

  /** Check if it opened. */
  if( !this->m_ParameterFile.is_open() )
  {
    itkExceptionMacro( << "ERROR: could not open "
                       << this->m_ParameterFileName
                       << " for reading." );
  }

  /** Clear the map. */
  this->m_ParameterMap.clear();

  /** Loop over the parameter file, line by line. */
  std::string lineIn  = "";
  std::string lineOut = "";
  while( this->m_ParameterFile.good() )
  {
    /** Extract a line. */
    itksys::SystemTools::GetLineFromStream( this->m_ParameterFile, lineIn );

    /** Check this line. */
    bool validLine = this->CheckLine( lineIn, lineOut );

    if( validLine )
    {
      /** Get the parameter name from this line and store it. */
      this->GetParameterFromLine( lineIn, lineOut );
    }
    // Otherwise, we simply ignore this line

  }

  /** Close the parameter file. */
  this->m_ParameterFile.clear();
  this->m_ParameterFile.close();

} // end ReadParameterFile()

/**
 * **************** BasicFileChecking ***************
 */

void
ParameterFileParser
::BasicFileChecking( void ) const
{
  /** Check if the file name is given. */
  if( this->m_ParameterFileName == "" )
  {
    itkExceptionMacro( << "ERROR: FileName has not been set." );
  }

  /** Basic error checking: existence. */
  bool exists = itksys::SystemTools::FileExists(
    this->m_ParameterFileName );
  if( !exists )
  {
    itkExceptionMacro( << "ERROR: the file "
                       << this->m_ParameterFileName
                       << " does not exist." );
  }

  /** Basic error checking: file or directory. */
  bool isDir = itksys::SystemTools::FileIsDirectory(
    this->m_ParameterFileName );
  if( isDir )
  {
    itkExceptionMacro( << "ERROR: the file "
                       << this->m_ParameterFileName
                       << " is a directory." );
  }

  /** Check the extension. */
  std::string ext = itksys::SystemTools::GetFilenameLastExtension(
    this->m_ParameterFileName );
  if( ext != ".txt" )
  {
    itkExceptionMacro( << "ERROR: the file "
                       << this->m_ParameterFileName
                       << " should be a text file (*.txt)." );
  }

} // end BasicFileChecking()

/**
 * **************** CheckLine ***************
 */

bool
ParameterFileParser
::CheckLine( const std::string & lineIn, std::string & lineOut ) const
{
  /** Preprocessing of lineIn:
   * 1) Replace tabs with spaces
   * 2) Remove everything after comment sign //
   * 3) Remove leading spaces
   * 4) Remove trailing spaces
   */
  lineOut = lineIn;
  itksys::SystemTools::ReplaceString( lineOut, "\t", " " );

  itksys::RegularExpression commentPart( "//" );
  if( commentPart.find( lineOut ) )
  {
    lineOut = lineOut.substr( 0, commentPart.start() );
  }

  itksys::RegularExpression leadingSpaces( "^[ ]*(.*)" );
  leadingSpaces.find( lineOut );
  lineOut = leadingSpaces.match( 1 );

  itksys::RegularExpression trailingSpaces( "[ \t]+$" );
  if( trailingSpaces.find( lineOut ) )
  {
    lineOut = lineOut.substr( 0, trailingSpaces.start() );
  }

  /**
   * Checks:
   * 1. Empty line -> false
   * 2. Comment (line starts with "//") -> false
   * 3. Line is not between brackets (...) -> exception
   * 4. Line contains less than two words -> exception
   *
   * Otherwise return true.
   */

  /** 1. Check for non-empty lines. */
  itksys::RegularExpression reNonEmptyLine( "[^ ]+" );
  bool                      match1 = reNonEmptyLine.find( lineOut );
  if( !match1 )
  {
    return false;
  }

  /** 2. Check for comments. */
  itksys::RegularExpression reComment( "^//" );
  bool                      match2 = reComment.find( lineOut );
  if( match2 )
  {
    return false;
  }

  /** 3. Check if line is between brackets. */
  if( !itksys::SystemTools::StringStartsWith( lineOut, "(" )
    || !itksys::SystemTools::StringEndsWith( lineOut, ")" ) )
  {
    std::string hint = "Line is not between brackets: \"(...)\".";
    this->ThrowException( lineIn, hint );
  }

  /** Remove brackets. */
  lineOut = lineOut.substr( 1, lineOut.size() - 2 );

  /** 4. Check: the line should contain at least two words. */
  itksys::RegularExpression reTwoWords( "([ ]+)([^ ]+)" );
  bool                      match4 = reTwoWords.find( lineOut );
  if( !match4 )
  {
    std::string hint = "Line does not contain a parameter name and value.";
    this->ThrowException( lineIn, hint );
  }

  /** At this point we know its at least a line containing a parameter.
   * However, this line can still be invalid, for example:
   * (string &^%^*)
   * This will be checked later.
   */

  return true;

} // end CheckLine()

/**
 * **************** GetParameterFromLine ***************
 */

void
ParameterFileParser
::GetParameterFromLine( const std::string & fullLine,
  const std::string & line )
{
  /** A line has a parameter name followed by one or more parameters.
   * They are all separated by one or more spaces (all tabs have been
   * removed previously) or by quotes in case of strings. So,
   * 1) we split the line at the spaces or quotes
   * 2) the first one is the parameter name
   * 3) the other strings that are not a series of spaces, are parameter values
   */

  /** 1) Split the line. */
  std::vector< std::string > splittedLine;
  this->SplitLine( fullLine, line, splittedLine );

  /** 2) Get the parameter name. */
  std::string parameterName = splittedLine[ 0 ];
  itksys::SystemTools::ReplaceString( parameterName, " ", "" );
  splittedLine.erase( splittedLine.begin() );

  /** 3) Get the parameter values. */
  std::vector< std::string > parameterValues;
  for( unsigned int i = 0; i < splittedLine.size(); ++i )
  {
    if( splittedLine[ i ] != "" )
    {
      parameterValues.push_back( splittedLine[ i ] );
    }
  }

  /** 4) Perform some checks on the parameter name. */
  itksys::RegularExpression reInvalidCharacters1( "[.,:;!@#$%^&-+|<>?]" );
  bool                      match = reInvalidCharacters1.find( parameterName );
  if( match )
  {
    std::string hint = "The parameter \""
      + parameterName
      + "\" contains invalid characters (.,:;!@#$%^&-+|<>?).";
    this->ThrowException( fullLine, hint );
  }

  /** 5) Perform checks on the parameter values. */
  itksys::RegularExpression reInvalidCharacters2( "[,;!@#$%&|<>?]" );
  for( unsigned int i = 0; i < parameterValues.size(); ++i )
  {
    /** For all entries some characters are not allowed. */
    if( reInvalidCharacters2.find( parameterValues[ i ] ) )
    {
      std::string hint = "The parameter value \""
        + parameterValues[ i ]
        + "\" contains invalid characters (,;!@#$%&|<>?).";
      this->ThrowException( fullLine, hint );
    }
  }

  /** 6) Insert this combination in the parameter map. */
  if( this->m_ParameterMap.count( parameterName ) )
  {
    std::string hint = "The parameter \""
      + parameterName
      + "\" is specified more than once.";
    this->ThrowException( fullLine, hint );
  }
  else
  {
    this->m_ParameterMap.insert( make_pair( parameterName, parameterValues ) );
  }

} // end GetParameterFromLine()

/**
 * **************** SplitLine ***************
 */

void
ParameterFileParser
::SplitLine( const std::string & fullLine, const std::string & line,
  std::vector< std::string > & splittedLine ) const
{
  splittedLine.clear();
  splittedLine.resize( 1 );

  /** Count the number of quotes in the line. If it is an odd value, the
   * line contains an error; strings should start and end with a quote, so
   * the total number of quotes is even.
   */
  std::size_t numQuotes = itksys::SystemTools::CountChar( line.c_str(), '"' );
  if( numQuotes % 2 == 1 )
  {
    /** An invalid parameter line. */
    std::string hint = "This line has an odd number of quotes (\").";
    this->ThrowException( fullLine, hint );
  }

  /** Loop over the line. */
  std::string::const_iterator it;
  unsigned int                index = 0;
  numQuotes = 0;
  for( it = line.begin(); it < line.end(); ++it )
  {
    if( *it == '"' )
    {
      /** Start a new element. */
      splittedLine.push_back( "" );
      index++;
      numQuotes++;
    }
    else if( *it == ' ' )
    {
      /** Only start a new element if it is not a quote, otherwise just add
       * the space to the string.
       */
      if( numQuotes % 2 == 0 )
      {
        splittedLine.push_back( "" );
        index++;
      }
      else
      {
        splittedLine[ index ].push_back( *it );
      }
    }
    else
    {
      /** Add this character to the element. */
      splittedLine[ index ].push_back( *it );
    }
  }

} // end SplitLine()

/**
 * **************** ThrowException ***************
 */

void
ParameterFileParser
::ThrowException( const std::string & line, const std::string & hint ) const
{
  /** Construct an error message. */
  std::string errorMessage
    = "ERROR: the following line in your parameter file is invalid: \n\""
    + line
    + "\"\n"
    + hint
    + "\nPlease correct you parameter file!";

  /** Throw exception. */
  itkExceptionMacro( << errorMessage );

} // end ThrowException()

/**
 * **************** ReturnParameterFileAsString ***************
 */

std::string
ParameterFileParser
::ReturnParameterFileAsString( void )
{
  /** Perform some basic checks. */
  this->BasicFileChecking();

  /** Open the parameter file for reading. */
  if( this->m_ParameterFile.is_open() )
  {
    this->m_ParameterFile.clear();
    this->m_ParameterFile.close();
  }
  this->m_ParameterFile.open( this->m_ParameterFileName, std::fstream::in );

  /** Check if it opened. */
  if( !this->m_ParameterFile.is_open() )
  {
    itkExceptionMacro( << "ERROR: could not open "
                       << this->m_ParameterFileName
                       << " for reading." );
  }

  /** Loop over the parameter file, line by line. */
  std::string line = "";
  std::string output;
  while( this->m_ParameterFile.good() )
  {
    /** Extract a line. */
    itksys::SystemTools::GetLineFromStream( this->m_ParameterFile, line ); // \todo: returns bool

    output += line + "\n";
  }

  /** Close the parameter file. */
  this->m_ParameterFile.clear();
  this->m_ParameterFile.close();

  /** Return the string. */
  return output;

} // end ReturnParameterFileAsString()

} // end namespace itk

#endif // end __itkParameterFileParser_cxx
<commit_msg>STYLE: Replace comparisons to "" by empty() calls in ParameterFileParser<commit_after>/*=========================================================================
 *
 *  Copyright UMC Utrecht and contributors
 *
 *  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.
 *
 *=========================================================================*/

#ifndef __itkParameterFileParser_cxx
#define __itkParameterFileParser_cxx

#include "itkParameterFileParser.h"

#include <itksys/SystemTools.hxx>
#include <itksys/RegularExpression.hxx>

namespace itk
{

/**
 * **************** Constructor ***************
 */

ParameterFileParser
::ParameterFileParser()
{
  this->m_ParameterFileName = "";
  this->m_ParameterMap.clear();

} // end Constructor()

/**
 * **************** Destructor ***************
 */

ParameterFileParser
::~ParameterFileParser()
{
  if( this->m_ParameterFile.is_open() )
  {
    this->m_ParameterFile.close();
  }

} // end Destructor()

/**
 * **************** GetParameterMap ***************
 */

const ParameterFileParser::ParameterMapType &
ParameterFileParser
::GetParameterMap( void ) const
{
  return this->m_ParameterMap;

} // end GetParameterMap()

/**
 * **************** ReadParameterFile ***************
 */

void
ParameterFileParser
::ReadParameterFile( void )
{
  /** Perform some basic checks. */
  this->BasicFileChecking();

  /** Open the parameter file for reading. */
  if( this->m_ParameterFile.is_open() )
  {
    this->m_ParameterFile.clear();
    this->m_ParameterFile.close();
  }
  this->m_ParameterFile.open( this->m_ParameterFileName, std::fstream::in );

  /** Check if it opened. */
  if( !this->m_ParameterFile.is_open() )
  {
    itkExceptionMacro( << "ERROR: could not open "
                       << this->m_ParameterFileName
                       << " for reading." );
  }

  /** Clear the map. */
  this->m_ParameterMap.clear();

  /** Loop over the parameter file, line by line. */
  std::string lineIn  = "";
  std::string lineOut = "";
  while( this->m_ParameterFile.good() )
  {
    /** Extract a line. */
    itksys::SystemTools::GetLineFromStream( this->m_ParameterFile, lineIn );

    /** Check this line. */
    bool validLine = this->CheckLine( lineIn, lineOut );

    if( validLine )
    {
      /** Get the parameter name from this line and store it. */
      this->GetParameterFromLine( lineIn, lineOut );
    }
    // Otherwise, we simply ignore this line

  }

  /** Close the parameter file. */
  this->m_ParameterFile.clear();
  this->m_ParameterFile.close();

} // end ReadParameterFile()

/**
 * **************** BasicFileChecking ***************
 */

void
ParameterFileParser
::BasicFileChecking( void ) const
{
  /** Check if the file name is given. */
  if( this->m_ParameterFileName.empty() )
  {
    itkExceptionMacro( << "ERROR: FileName has not been set." );
  }

  /** Basic error checking: existence. */
  bool exists = itksys::SystemTools::FileExists(
    this->m_ParameterFileName );
  if( !exists )
  {
    itkExceptionMacro( << "ERROR: the file "
                       << this->m_ParameterFileName
                       << " does not exist." );
  }

  /** Basic error checking: file or directory. */
  bool isDir = itksys::SystemTools::FileIsDirectory(
    this->m_ParameterFileName );
  if( isDir )
  {
    itkExceptionMacro( << "ERROR: the file "
                       << this->m_ParameterFileName
                       << " is a directory." );
  }

  /** Check the extension. */
  std::string ext = itksys::SystemTools::GetFilenameLastExtension(
    this->m_ParameterFileName );
  if( ext != ".txt" )
  {
    itkExceptionMacro( << "ERROR: the file "
                       << this->m_ParameterFileName
                       << " should be a text file (*.txt)." );
  }

} // end BasicFileChecking()

/**
 * **************** CheckLine ***************
 */

bool
ParameterFileParser
::CheckLine( const std::string & lineIn, std::string & lineOut ) const
{
  /** Preprocessing of lineIn:
   * 1) Replace tabs with spaces
   * 2) Remove everything after comment sign //
   * 3) Remove leading spaces
   * 4) Remove trailing spaces
   */
  lineOut = lineIn;
  itksys::SystemTools::ReplaceString( lineOut, "\t", " " );

  itksys::RegularExpression commentPart( "//" );
  if( commentPart.find( lineOut ) )
  {
    lineOut = lineOut.substr( 0, commentPart.start() );
  }

  itksys::RegularExpression leadingSpaces( "^[ ]*(.*)" );
  leadingSpaces.find( lineOut );
  lineOut = leadingSpaces.match( 1 );

  itksys::RegularExpression trailingSpaces( "[ \t]+$" );
  if( trailingSpaces.find( lineOut ) )
  {
    lineOut = lineOut.substr( 0, trailingSpaces.start() );
  }

  /**
   * Checks:
   * 1. Empty line -> false
   * 2. Comment (line starts with "//") -> false
   * 3. Line is not between brackets (...) -> exception
   * 4. Line contains less than two words -> exception
   *
   * Otherwise return true.
   */

  /** 1. Check for non-empty lines. */
  itksys::RegularExpression reNonEmptyLine( "[^ ]+" );
  bool                      match1 = reNonEmptyLine.find( lineOut );
  if( !match1 )
  {
    return false;
  }

  /** 2. Check for comments. */
  itksys::RegularExpression reComment( "^//" );
  bool                      match2 = reComment.find( lineOut );
  if( match2 )
  {
    return false;
  }

  /** 3. Check if line is between brackets. */
  if( !itksys::SystemTools::StringStartsWith( lineOut, "(" )
    || !itksys::SystemTools::StringEndsWith( lineOut, ")" ) )
  {
    std::string hint = "Line is not between brackets: \"(...)\".";
    this->ThrowException( lineIn, hint );
  }

  /** Remove brackets. */
  lineOut = lineOut.substr( 1, lineOut.size() - 2 );

  /** 4. Check: the line should contain at least two words. */
  itksys::RegularExpression reTwoWords( "([ ]+)([^ ]+)" );
  bool                      match4 = reTwoWords.find( lineOut );
  if( !match4 )
  {
    std::string hint = "Line does not contain a parameter name and value.";
    this->ThrowException( lineIn, hint );
  }

  /** At this point we know its at least a line containing a parameter.
   * However, this line can still be invalid, for example:
   * (string &^%^*)
   * This will be checked later.
   */

  return true;

} // end CheckLine()

/**
 * **************** GetParameterFromLine ***************
 */

void
ParameterFileParser
::GetParameterFromLine( const std::string & fullLine,
  const std::string & line )
{
  /** A line has a parameter name followed by one or more parameters.
   * They are all separated by one or more spaces (all tabs have been
   * removed previously) or by quotes in case of strings. So,
   * 1) we split the line at the spaces or quotes
   * 2) the first one is the parameter name
   * 3) the other strings that are not a series of spaces, are parameter values
   */

  /** 1) Split the line. */
  std::vector< std::string > splittedLine;
  this->SplitLine( fullLine, line, splittedLine );

  /** 2) Get the parameter name. */
  std::string parameterName = splittedLine[ 0 ];
  itksys::SystemTools::ReplaceString( parameterName, " ", "" );
  splittedLine.erase( splittedLine.begin() );

  /** 3) Get the parameter values. */
  std::vector< std::string > parameterValues;
  for( unsigned int i = 0; i < splittedLine.size(); ++i )
  {
    if( ! splittedLine[ i ].empty() )
    {
      parameterValues.push_back( splittedLine[ i ] );
    }
  }

  /** 4) Perform some checks on the parameter name. */
  itksys::RegularExpression reInvalidCharacters1( "[.,:;!@#$%^&-+|<>?]" );
  bool                      match = reInvalidCharacters1.find( parameterName );
  if( match )
  {
    std::string hint = "The parameter \""
      + parameterName
      + "\" contains invalid characters (.,:;!@#$%^&-+|<>?).";
    this->ThrowException( fullLine, hint );
  }

  /** 5) Perform checks on the parameter values. */
  itksys::RegularExpression reInvalidCharacters2( "[,;!@#$%&|<>?]" );
  for( unsigned int i = 0; i < parameterValues.size(); ++i )
  {
    /** For all entries some characters are not allowed. */
    if( reInvalidCharacters2.find( parameterValues[ i ] ) )
    {
      std::string hint = "The parameter value \""
        + parameterValues[ i ]
        + "\" contains invalid characters (,;!@#$%&|<>?).";
      this->ThrowException( fullLine, hint );
    }
  }

  /** 6) Insert this combination in the parameter map. */
  if( this->m_ParameterMap.count( parameterName ) )
  {
    std::string hint = "The parameter \""
      + parameterName
      + "\" is specified more than once.";
    this->ThrowException( fullLine, hint );
  }
  else
  {
    this->m_ParameterMap.insert( make_pair( parameterName, parameterValues ) );
  }

} // end GetParameterFromLine()

/**
 * **************** SplitLine ***************
 */

void
ParameterFileParser
::SplitLine( const std::string & fullLine, const std::string & line,
  std::vector< std::string > & splittedLine ) const
{
  splittedLine.clear();
  splittedLine.resize( 1 );

  /** Count the number of quotes in the line. If it is an odd value, the
   * line contains an error; strings should start and end with a quote, so
   * the total number of quotes is even.
   */
  std::size_t numQuotes = itksys::SystemTools::CountChar( line.c_str(), '"' );
  if( numQuotes % 2 == 1 )
  {
    /** An invalid parameter line. */
    std::string hint = "This line has an odd number of quotes (\").";
    this->ThrowException( fullLine, hint );
  }

  /** Loop over the line. */
  std::string::const_iterator it;
  unsigned int                index = 0;
  numQuotes = 0;
  for( it = line.begin(); it < line.end(); ++it )
  {
    if( *it == '"' )
    {
      /** Start a new element. */
      splittedLine.push_back( "" );
      index++;
      numQuotes++;
    }
    else if( *it == ' ' )
    {
      /** Only start a new element if it is not a quote, otherwise just add
       * the space to the string.
       */
      if( numQuotes % 2 == 0 )
      {
        splittedLine.push_back( "" );
        index++;
      }
      else
      {
        splittedLine[ index ].push_back( *it );
      }
    }
    else
    {
      /** Add this character to the element. */
      splittedLine[ index ].push_back( *it );
    }
  }

} // end SplitLine()

/**
 * **************** ThrowException ***************
 */

void
ParameterFileParser
::ThrowException( const std::string & line, const std::string & hint ) const
{
  /** Construct an error message. */
  std::string errorMessage
    = "ERROR: the following line in your parameter file is invalid: \n\""
    + line
    + "\"\n"
    + hint
    + "\nPlease correct you parameter file!";

  /** Throw exception. */
  itkExceptionMacro( << errorMessage );

} // end ThrowException()

/**
 * **************** ReturnParameterFileAsString ***************
 */

std::string
ParameterFileParser
::ReturnParameterFileAsString( void )
{
  /** Perform some basic checks. */
  this->BasicFileChecking();

  /** Open the parameter file for reading. */
  if( this->m_ParameterFile.is_open() )
  {
    this->m_ParameterFile.clear();
    this->m_ParameterFile.close();
  }
  this->m_ParameterFile.open( this->m_ParameterFileName, std::fstream::in );

  /** Check if it opened. */
  if( !this->m_ParameterFile.is_open() )
  {
    itkExceptionMacro( << "ERROR: could not open "
                       << this->m_ParameterFileName
                       << " for reading." );
  }

  /** Loop over the parameter file, line by line. */
  std::string line = "";
  std::string output;
  while( this->m_ParameterFile.good() )
  {
    /** Extract a line. */
    itksys::SystemTools::GetLineFromStream( this->m_ParameterFile, line ); // \todo: returns bool

    output += line + "\n";
  }

  /** Close the parameter file. */
  this->m_ParameterFile.clear();
  this->m_ParameterFile.close();

  /** Return the string. */
  return output;

} // end ReturnParameterFileAsString()

} // end namespace itk

#endif // end __itkParameterFileParser_cxx
<|endoftext|>


<commit_before>// Copyright (C) 2010-2013 Joshua Boyce.
// See the file COPYING for copying permission.

#include <hadesmem/find_pattern.hpp>
#include <hadesmem/find_pattern.hpp>

#include <hadesmem/detail/warning_disable_prefix.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <hadesmem/detail/warning_disable_suffix.hpp>

#include <hadesmem/config.hpp>
#include <hadesmem/error.hpp>
#include <hadesmem/process.hpp>

// TODO: Clean up, expand, fix, etc these tests.

// TODO: Add more tests.

// TODO: Fix this hack properly.
#if defined(HADESMEM_INTEL)
#pragma warning(push)
#pragma warning(disable: 1345)
#endif // #if defined(HADESMEM_INTEL)

void TestFindPattern()
{
  hadesmem::Process const process(::GetCurrentProcessId());

  std::uintptr_t const process_base =
    reinterpret_cast<std::uintptr_t>(::GetModuleHandleW(nullptr));

  void* nop =
    hadesmem::Find(process, L"", L"90", hadesmem::PatternFlags::kNone, 0U);
  BOOST_TEST_NE(nop, static_cast<void*>(nullptr));
  BOOST_TEST(nop > reinterpret_cast<void*>(process_base));

  void* nop_second =
    hadesmem::Find(process,
                   L"",
                   L"90",
                   hadesmem::PatternFlags::kNone,
                   reinterpret_cast<std::uintptr_t>(nop) - process_base);
  BOOST_TEST_NE(nop_second, static_cast<void*>(nullptr));
  BOOST_TEST_NE(nop_second, nop);
  BOOST_TEST(nop_second > nop);
  BOOST_TEST(nop_second > reinterpret_cast<void*>(process_base));

  void* find_pattern_string =
    hadesmem::Find(process,
                   L"",
                   L"46 ?? 6E 64 50 61 74 74 65 72 6E",
                   hadesmem::PatternFlags::kScanData,
                   0U);
  BOOST_TEST_NE(find_pattern_string, static_cast<void*>(nullptr));
  BOOST_TEST_NE(find_pattern_string, nop);
  BOOST_TEST(find_pattern_string > reinterpret_cast<void*>(process_base));

  BOOST_TEST_EQ(hadesmem::Find(process,
                               L"",
                               L"11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF",
                               hadesmem::PatternFlags::kNone,
                               0U),
                static_cast<void*>(nullptr));
  BOOST_TEST_THROWS(
    hadesmem::Find(process,
                   L"",
                   L"11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF",
                   hadesmem::PatternFlags::kThrowOnUnmatch,
                   0U),
    hadesmem::Error);

  void* rtl_random_string =
    hadesmem::Find(process,
                   L"ntdll.dll",
                   L"52 74 6c 52 61 6e ?? 6f 6d",
                   hadesmem::PatternFlags::kRelativeAddress,
                   0U);
  BOOST_TEST_NE(rtl_random_string, static_cast<void*>(nullptr));
  BOOST_TEST_NE(rtl_random_string, find_pattern_string);
  HMODULE const ntdll_mod = ::GetModuleHandleW(L"ntdll");
  std::uintptr_t const ntdll_base = reinterpret_cast<std::uintptr_t>(ntdll_mod);
  BOOST_TEST_NE(ntdll_mod, static_cast<HMODULE>(nullptr));
  std::string const rtlrandom = "RtlRandom";
  void* const rtl_random_string_absolute =
    static_cast<std::uint8_t*>(rtl_random_string) + ntdll_base;
  BOOST_TEST(std::equal(std::begin(rtlrandom),
                        std::end(rtlrandom),
                        static_cast<char const*>(rtl_random_string_absolute)));

  // Todo: Lea test
  std::wstring const pattern_file_data = LR"(
<?xml version="1.0" encoding="utf-8"?>
<HadesMem>
  <FindPattern>
    <Flag Name="RelativeAddress"/>
    <Flag Name="ThrowOnUnmatch"/>
    <Pattern Name="First Call" Data="E8">
      <Manipulator Name="Add" Operand1="1"/>
      <Manipulator Name="Rel" Operand1="5" Operand2="1"/>
    </Pattern>
    <Pattern Name="Zeros New" Data="00 ?? 00">
      <Manipulator Name="Add" Operand1="1"/>
      <Manipulator Name="Sub" Operand1="1"/>
    </Pattern>
    <Pattern Name="Nop Other" Data="90"/>
    <Pattern Name="Nop Second" Data="90" Start="Nop Other"/>
    <Pattern Name="FindPattern String" Data="46 ?? 6E 64 50 61 74 74 65 72 6E">
      <Flag Name="ScanData"/>
    </Pattern>
  </FindPattern>
  <FindPattern Module="ntdll.dll">
    <Flag Name="ThrowOnUnmatch"/>
    <Pattern Name="Int3 Then Nop" Data="CC 90"/>
    <Pattern Name="RtlRandom String" Data="52 74 6c 52 61 6e ?? 6f 6d"/>
    <Pattern Name="Int3 Then Nop 0x1000" Data="CC 90" StartRVA="0x1000"/>
  </FindPattern>
</HadesMem>
)";
  // TODO: Actually validate that the results are correct.
  hadesmem::FindPattern find_pattern(process, pattern_file_data, true);
  find_pattern = hadesmem::FindPattern(process, pattern_file_data, true);
  BOOST_TEST_EQ(find_pattern.GetModuleMap().size(), 2UL);
  BOOST_TEST_EQ(find_pattern.GetPatternMap(L"").size(), 5UL);

  BOOST_TEST_NE(find_pattern.Lookup(L"", L"First Call"),
                static_cast<void*>(nullptr));
  BOOST_TEST_NE(find_pattern.Lookup(L"", L"Zeros New"),
                static_cast<void*>(nullptr));
  BOOST_TEST_NE(find_pattern.Lookup(L"", L"Zeros New"),
                find_pattern.Lookup(L"", L"First Call"));
  BOOST_TEST_NE(find_pattern.Lookup(L"", L"Nop Other"),
                static_cast<void*>(nullptr));
  BOOST_TEST_EQ(
    find_pattern.Lookup(L"", L"Nop Other"),
    static_cast<void*>(static_cast<std::uint8_t*>(nop) - process_base));
  BOOST_TEST_NE(find_pattern.Lookup(L"", L"Nop Other"),
                find_pattern.Lookup(L"", L"First Call"));
  BOOST_TEST_NE(find_pattern.Lookup(L"", L"Nop Other"),
                find_pattern.Lookup(L"", L"Zeros New"));
  BOOST_TEST(find_pattern.Lookup(L"", L"Nop Second") >
             find_pattern.Lookup(L"", L"Nop Other"));
  BOOST_TEST_EQ(
    find_pattern.Lookup(L"", L"Nop Second"),
    static_cast<void*>(static_cast<std::uint8_t*>(nop_second) - process_base));
  BOOST_TEST_NE(find_pattern.Lookup(L"", L"FindPattern String"),
                static_cast<void*>(nullptr));
  BOOST_TEST_EQ(
    find_pattern.Lookup(L"", L"FindPattern String"),
    static_cast<void*>(static_cast<std::uint8_t*>(find_pattern_string) -
                       process_base));
  BOOST_TEST_EQ(find_pattern.GetPatternMap(L"ntdll.dll").size(), 3UL);
  BOOST_TEST_NE(find_pattern.Lookup(L"ntdll.dll", L"Int3 Then Nop"),
                static_cast<void*>(nullptr));
  auto const int3_then_nop =
    find_pattern.Lookup(L"ntdll.dll", L"Int3 Then Nop");
  BOOST_TEST_EQ(*static_cast<char const*>(int3_then_nop), '\xCC');
  BOOST_TEST_EQ(*(static_cast<char const*>(int3_then_nop) + 1), '\x90');
  BOOST_TEST_NE(find_pattern.Lookup(L"ntdll.dll", L"RtlRandom String"),
                static_cast<void*>(nullptr));
  BOOST_TEST(find_pattern.Lookup(L"ntdll.dll", L"RtlRandom String") >
             ntdll_mod);
  BOOST_TEST_EQ(find_pattern.Lookup(L"ntdll.dll", L"RtlRandom String"),
                rtl_random_string_absolute);
  BOOST_TEST_NE(find_pattern.Lookup(L"ntdll.dll", L"RtlRandom String"),
                find_pattern.Lookup(L"", L"FindPattern String"));
  BOOST_TEST_THROWS(find_pattern.Lookup(L"DoesNotExist", L"RtlRandom String"),
                    hadesmem::Error);
  BOOST_TEST_THROWS(find_pattern.Lookup(L"ntdll.dll", L"DoesNotExist"),
    hadesmem::Error);
  auto const int3_then_nop_0x1000 =
    find_pattern.Lookup(L"ntdll.dll", L"Int3 Then Nop 0x1000");
  BOOST_TEST_EQ(*static_cast<char const*>(int3_then_nop_0x1000), '\xCC');
  BOOST_TEST_EQ(*(static_cast<char const*>(int3_then_nop_0x1000)+1), '\x90');
  auto const int3_then_nop_0x1000_rel = reinterpret_cast<std::uintptr_t>(int3_then_nop_0x1000)-ntdll_base;
  BOOST_TEST(int3_then_nop_0x1000_rel >= 0x1000U);

  // TODO: Fix the test to ensure we get the error we're expecting, rather
  // than just any error.
  std::wstring const pattern_file_data_invalid1 = LR"(
<?xml version="1.0" encoding="utf-8"?>
<HadesMem>
  <FindPattern>
    <Flag Name="InvalidFlag"/>
  </FindPattern>
</HadesMem>
)";
  BOOST_TEST_THROWS(
    hadesmem::FindPattern(process, pattern_file_data_invalid1, true),
    hadesmem::Error);

  std::wstring const pattern_file_data_invalid2 = LR"(
<?xml version="1.0" encoding="utf-8"?>
<HadesMem>
  <FindPattern>
    <Flag Name="RelativeAddress"/>
    <Flag Name="ThrowOnUnmatch"/>
    <Pattern Name="Foo2" Data="ZZ"/>
  </FindPattern>
</HadesMem>
)";
  BOOST_TEST_THROWS(
    hadesmem::FindPattern(process, pattern_file_data_invalid2, true),
    hadesmem::Error);

  std::wstring const pattern_file_data_invalid3 = LR"(
<?xml version="1.0" encoding="utf-8"?>
<HadesMem>
  <FindPattern>
    <Flag Name="RelativeAddress"/>
    <Flag Name="ThrowOnUnmatch"/>
    <Pattern/>
  </FindPattern>
</HadesMem>
)";
  BOOST_TEST_THROWS(
    hadesmem::FindPattern(process, pattern_file_data_invalid3, true),
    hadesmem::Error);

  std::wstring const pattern_file_data_invalid4 = LR"(
<?xml version="1.0" encoding="utf-8"?>
<HadesMem>
  <FindPattern>
    <Flag Name="RelativeAddress"/>
    <Flag Name="ThrowOnUnmatch"/>
    <Pattern Name="Foo4" Data="90" Start="DoesNotExist"/>
  </FindPattern>
</HadesMem>
)";
  BOOST_TEST_THROWS(
    hadesmem::FindPattern(process, pattern_file_data_invalid4, true),
    hadesmem::Error);

  // Todo: LoadFile test
}

int main()
{
  TestFindPattern();
  return boost::report_errors();
}

#if defined(HADESMEM_INTEL)
#pragma warning(pop)
#endif // #if defined(HADESMEM_INTEL)
<commit_msg>* [FindPattern] Add another pattern for Start. This time not using RelativeAddress.<commit_after>// Copyright (C) 2010-2013 Joshua Boyce.
// See the file COPYING for copying permission.

#include <hadesmem/find_pattern.hpp>
#include <hadesmem/find_pattern.hpp>

#include <hadesmem/detail/warning_disable_prefix.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <hadesmem/detail/warning_disable_suffix.hpp>

#include <hadesmem/config.hpp>
#include <hadesmem/error.hpp>
#include <hadesmem/process.hpp>

// TODO: Clean up, expand, fix, etc these tests.

// TODO: Add more tests.

// TODO: Fix this hack properly.
#if defined(HADESMEM_INTEL)
#pragma warning(push)
#pragma warning(disable: 1345)
#endif // #if defined(HADESMEM_INTEL)

void TestFindPattern()
{
  hadesmem::Process const process(::GetCurrentProcessId());

  std::uintptr_t const process_base =
    reinterpret_cast<std::uintptr_t>(::GetModuleHandleW(nullptr));

  void* nop =
    hadesmem::Find(process, L"", L"90", hadesmem::PatternFlags::kNone, 0U);
  BOOST_TEST_NE(nop, static_cast<void*>(nullptr));
  BOOST_TEST(nop > reinterpret_cast<void*>(process_base));

  void* nop_second =
    hadesmem::Find(process,
                   L"",
                   L"90",
                   hadesmem::PatternFlags::kNone,
                   reinterpret_cast<std::uintptr_t>(nop) - process_base);
  BOOST_TEST_NE(nop_second, static_cast<void*>(nullptr));
  BOOST_TEST_NE(nop_second, nop);
  BOOST_TEST(nop_second > nop);
  BOOST_TEST(nop_second > reinterpret_cast<void*>(process_base));

  void* find_pattern_string =
    hadesmem::Find(process,
                   L"",
                   L"46 ?? 6E 64 50 61 74 74 65 72 6E",
                   hadesmem::PatternFlags::kScanData,
                   0U);
  BOOST_TEST_NE(find_pattern_string, static_cast<void*>(nullptr));
  BOOST_TEST_NE(find_pattern_string, nop);
  BOOST_TEST(find_pattern_string > reinterpret_cast<void*>(process_base));

  BOOST_TEST_EQ(hadesmem::Find(process,
                               L"",
                               L"11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF",
                               hadesmem::PatternFlags::kNone,
                               0U),
                static_cast<void*>(nullptr));
  BOOST_TEST_THROWS(
    hadesmem::Find(process,
                   L"",
                   L"11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF",
                   hadesmem::PatternFlags::kThrowOnUnmatch,
                   0U),
    hadesmem::Error);

  void* rtl_random_string =
    hadesmem::Find(process,
                   L"ntdll.dll",
                   L"52 74 6c 52 61 6e ?? 6f 6d",
                   hadesmem::PatternFlags::kRelativeAddress,
                   0U);
  BOOST_TEST_NE(rtl_random_string, static_cast<void*>(nullptr));
  BOOST_TEST_NE(rtl_random_string, find_pattern_string);
  HMODULE const ntdll_mod = ::GetModuleHandleW(L"ntdll");
  std::uintptr_t const ntdll_base = reinterpret_cast<std::uintptr_t>(ntdll_mod);
  BOOST_TEST_NE(ntdll_mod, static_cast<HMODULE>(nullptr));
  std::string const rtlrandom = "RtlRandom";
  void* const rtl_random_string_absolute =
    static_cast<std::uint8_t*>(rtl_random_string) + ntdll_base;
  BOOST_TEST(std::equal(std::begin(rtlrandom),
                        std::end(rtlrandom),
                        static_cast<char const*>(rtl_random_string_absolute)));

  // Todo: Lea test
  std::wstring const pattern_file_data = LR"(
<?xml version="1.0" encoding="utf-8"?>
<HadesMem>
  <FindPattern>
    <Flag Name="RelativeAddress"/>
    <Flag Name="ThrowOnUnmatch"/>
    <Pattern Name="First Call" Data="E8">
      <Manipulator Name="Add" Operand1="1"/>
      <Manipulator Name="Rel" Operand1="5" Operand2="1"/>
    </Pattern>
    <Pattern Name="Zeros New" Data="00 ?? 00">
      <Manipulator Name="Add" Operand1="1"/>
      <Manipulator Name="Sub" Operand1="1"/>
    </Pattern>
    <Pattern Name="Nop Other" Data="90"/>
    <Pattern Name="Nop Second" Data="90" Start="Nop Other"/>
    <Pattern Name="FindPattern String" Data="46 ?? 6E 64 50 61 74 74 65 72 6E">
      <Flag Name="ScanData"/>
    </Pattern>
  </FindPattern>
  <FindPattern Module="ntdll.dll">
    <Flag Name="ThrowOnUnmatch"/>
    <Pattern Name="Int3 Then Nop" Data="CC 90"/>
    <Pattern Name="Int3 Then Nop Next" Data="??" Start="Int3 Then Nop"/>
    <Pattern Name="RtlRandom String" Data="52 74 6c 52 61 6e ?? 6f 6d"/>
    <Pattern Name="Int3 Then Nop 0x1000" Data="CC 90" StartRVA="0x1000"/>
  </FindPattern>
</HadesMem>
)";
  // TODO: Actually validate that the results are correct.
  hadesmem::FindPattern find_pattern(process, pattern_file_data, true);
  find_pattern = hadesmem::FindPattern(process, pattern_file_data, true);
  BOOST_TEST_EQ(find_pattern.GetModuleMap().size(), 2UL);
  BOOST_TEST_EQ(find_pattern.GetPatternMap(L"").size(), 5UL);

  BOOST_TEST_NE(find_pattern.Lookup(L"", L"First Call"),
                static_cast<void*>(nullptr));
  BOOST_TEST_NE(find_pattern.Lookup(L"", L"Zeros New"),
                static_cast<void*>(nullptr));
  BOOST_TEST_NE(find_pattern.Lookup(L"", L"Zeros New"),
                find_pattern.Lookup(L"", L"First Call"));
  BOOST_TEST_NE(find_pattern.Lookup(L"", L"Nop Other"),
                static_cast<void*>(nullptr));
  BOOST_TEST_EQ(
    find_pattern.Lookup(L"", L"Nop Other"),
    static_cast<void*>(static_cast<std::uint8_t*>(nop) - process_base));
  BOOST_TEST_NE(find_pattern.Lookup(L"", L"Nop Other"),
                find_pattern.Lookup(L"", L"First Call"));
  BOOST_TEST_NE(find_pattern.Lookup(L"", L"Nop Other"),
                find_pattern.Lookup(L"", L"Zeros New"));
  BOOST_TEST(find_pattern.Lookup(L"", L"Nop Second") >
             find_pattern.Lookup(L"", L"Nop Other"));
  BOOST_TEST_EQ(
    find_pattern.Lookup(L"", L"Nop Second"),
    static_cast<void*>(static_cast<std::uint8_t*>(nop_second) - process_base));
  BOOST_TEST_NE(find_pattern.Lookup(L"", L"FindPattern String"),
                static_cast<void*>(nullptr));
  BOOST_TEST_EQ(
    find_pattern.Lookup(L"", L"FindPattern String"),
    static_cast<void*>(static_cast<std::uint8_t*>(find_pattern_string) -
                       process_base));
  BOOST_TEST_EQ(find_pattern.GetPatternMap(L"ntdll.dll").size(), 4UL);
  BOOST_TEST_NE(find_pattern.Lookup(L"ntdll.dll", L"Int3 Then Nop"),
                static_cast<void*>(nullptr));
  auto const int3_then_nop =
    find_pattern.Lookup(L"ntdll.dll", L"Int3 Then Nop");
  BOOST_TEST_EQ(*static_cast<char const*>(int3_then_nop), '\xCC');
  BOOST_TEST_EQ(*(static_cast<char const*>(int3_then_nop)+1), '\x90');
  BOOST_TEST_NE(find_pattern.Lookup(L"ntdll.dll", L"Int3 Then Nop Next"),
    static_cast<void*>(nullptr));
  BOOST_TEST(find_pattern.Lookup(L"ntdll.dll", L"Int3 Then Nop Next") >
    find_pattern.Lookup(L"ntdll.dll", L"Int3 Then Nop"));
  BOOST_TEST_NE(find_pattern.Lookup(L"ntdll.dll", L"RtlRandom String"),
                static_cast<void*>(nullptr));
  BOOST_TEST(find_pattern.Lookup(L"ntdll.dll", L"RtlRandom String") >
             ntdll_mod);
  BOOST_TEST_EQ(find_pattern.Lookup(L"ntdll.dll", L"RtlRandom String"),
                rtl_random_string_absolute);
  BOOST_TEST_NE(find_pattern.Lookup(L"ntdll.dll", L"RtlRandom String"),
                find_pattern.Lookup(L"", L"FindPattern String"));
  BOOST_TEST_THROWS(find_pattern.Lookup(L"DoesNotExist", L"RtlRandom String"),
                    hadesmem::Error);
  BOOST_TEST_THROWS(find_pattern.Lookup(L"ntdll.dll", L"DoesNotExist"),
    hadesmem::Error);
  auto const int3_then_nop_0x1000 =
    find_pattern.Lookup(L"ntdll.dll", L"Int3 Then Nop 0x1000");
  BOOST_TEST_EQ(*static_cast<char const*>(int3_then_nop_0x1000), '\xCC');
  BOOST_TEST_EQ(*(static_cast<char const*>(int3_then_nop_0x1000)+1), '\x90');
  auto const int3_then_nop_0x1000_rel = reinterpret_cast<std::uintptr_t>(int3_then_nop_0x1000)-ntdll_base;
  BOOST_TEST(int3_then_nop_0x1000_rel >= 0x1000U);

  // TODO: Fix the test to ensure we get the error we're expecting, rather
  // than just any error.
  std::wstring const pattern_file_data_invalid1 = LR"(
<?xml version="1.0" encoding="utf-8"?>
<HadesMem>
  <FindPattern>
    <Flag Name="InvalidFlag"/>
  </FindPattern>
</HadesMem>
)";
  BOOST_TEST_THROWS(
    hadesmem::FindPattern(process, pattern_file_data_invalid1, true),
    hadesmem::Error);

  std::wstring const pattern_file_data_invalid2 = LR"(
<?xml version="1.0" encoding="utf-8"?>
<HadesMem>
  <FindPattern>
    <Flag Name="RelativeAddress"/>
    <Flag Name="ThrowOnUnmatch"/>
    <Pattern Name="Foo2" Data="ZZ"/>
  </FindPattern>
</HadesMem>
)";
  BOOST_TEST_THROWS(
    hadesmem::FindPattern(process, pattern_file_data_invalid2, true),
    hadesmem::Error);

  std::wstring const pattern_file_data_invalid3 = LR"(
<?xml version="1.0" encoding="utf-8"?>
<HadesMem>
  <FindPattern>
    <Flag Name="RelativeAddress"/>
    <Flag Name="ThrowOnUnmatch"/>
    <Pattern/>
  </FindPattern>
</HadesMem>
)";
  BOOST_TEST_THROWS(
    hadesmem::FindPattern(process, pattern_file_data_invalid3, true),
    hadesmem::Error);

  std::wstring const pattern_file_data_invalid4 = LR"(
<?xml version="1.0" encoding="utf-8"?>
<HadesMem>
  <FindPattern>
    <Flag Name="RelativeAddress"/>
    <Flag Name="ThrowOnUnmatch"/>
    <Pattern Name="Foo4" Data="90" Start="DoesNotExist"/>
  </FindPattern>
</HadesMem>
)";
  BOOST_TEST_THROWS(
    hadesmem::FindPattern(process, pattern_file_data_invalid4, true),
    hadesmem::Error);

  // Todo: LoadFile test
}

int main()
{
  TestFindPattern();
  return boost::report_errors();
}

#if defined(HADESMEM_INTEL)
#pragma warning(pop)
#endif // #if defined(HADESMEM_INTEL)
<|endoftext|>


<commit_before>#include <bx/bx.h>
#include <bx/timer.h>
#include <bx/handlealloc.h>
#include <bx/maputil.h>

#include <tinystl/allocator.h>
#include <tinystl/unordered_map.h>

#include <unordered_map>

#include <stdio.h>
#include <assert.h>

int main()
{
	const uint32_t numElements   = 4<<10;
	const uint32_t numIterations = 16;

	//
	{
		int64_t elapsed = -bx::getHPCounter();

		for (uint32_t ii = 0; ii < numIterations; ++ii)
		{
			typedef tinystl::unordered_map<uint64_t, uint16_t> TinyStlUnorderedMap;
			TinyStlUnorderedMap map;
//			map.reserve(numElements);
			for (uint32_t jj = 0; jj < numElements; ++jj)
			{
				tinystl::pair<TinyStlUnorderedMap::iterator, bool> ok = map.insert(tinystl::make_pair(uint64_t(jj), uint16_t(jj) ) );
				assert(ok.second);
			}

			for (uint32_t jj = 0; jj < numElements; ++jj)
			{
				bool ok = bx::mapRemove(map, uint64_t(jj) );
				assert(ok);
			}

			assert(map.size() == 0);
		}

		elapsed += bx::getHPCounter();
		printf("      TinyStl: %15f\n", double(elapsed) );
	}

	///
	{
		int64_t elapsed = -bx::getHPCounter();

		for (uint32_t ii = 0; ii < numIterations; ++ii)
		{
			typedef std::unordered_map<uint64_t, uint16_t> StdUnorderedMap;
			StdUnorderedMap map;
			map.reserve(numElements);
			for (uint32_t jj = 0; jj < numElements; ++jj)
			{
				std::pair<StdUnorderedMap::iterator, bool> ok = map.insert(std::make_pair(uint64_t(jj), uint16_t(jj) ) );
				assert(ok.second);
			}

			for (uint32_t jj = 0; jj < numElements; ++jj)
			{
				bool ok = bx::mapRemove(map, uint64_t(jj) );
				assert(ok);
			}

			assert(map.size() == 0);
		}

		elapsed += bx::getHPCounter();
		printf("          STL: %15f\n", double(elapsed) );
	}

	///
	{
		int64_t elapsed = -bx::getHPCounter();

		for (uint32_t ii = 0; ii < numIterations; ++ii)
		{
			typedef bx::HandleHashMapT<numElements+numElements/2, uint64_t> HandleHashMap;
			HandleHashMap map;
			for (uint32_t jj = 0; jj < numElements; ++jj)
			{
				bool ok = map.insert(jj, uint16_t(jj) );
				assert(ok);
			}

			for (uint32_t jj = 0; jj < numElements; ++jj)
			{
				bool ok = map.removeByKey(uint64_t(jj) );
				assert(ok);
			}

			assert(map.getNumElements() == 0);
		}

		elapsed += bx::getHPCounter();
		printf("HandleHashMap: %15f\n", double(elapsed) );
	}

	return EXIT_SUCCESS;
}
<commit_msg>Fixed build.<commit_after>#include <bx/bx.h>
#include <bx/timer.h>
#include <bx/handlealloc.h>
#include <bx/maputil.h>

#include <tinystl/allocator.h>
#include <tinystl/unordered_map.h>

#include <unordered_map>

#include <stdio.h>
#include <assert.h>

int main()
{
	const uint32_t numElements   = 4<<10;
	const uint32_t numIterations = 16;

	//
	{
		int64_t elapsed = -bx::getHPCounter();

		for (uint32_t ii = 0; ii < numIterations; ++ii)
		{
			typedef tinystl::unordered_map<uint64_t, uint16_t> TinyStlUnorderedMap;
			TinyStlUnorderedMap map;
//			map.reserve(numElements);
			for (uint32_t jj = 0; jj < numElements; ++jj)
			{
				tinystl::pair<TinyStlUnorderedMap::iterator, bool> ok = map.insert(tinystl::make_pair(uint64_t(jj), uint16_t(jj) ) );
				assert(ok.second);
			}

			for (uint32_t jj = 0; jj < numElements; ++jj)
			{
				bool ok = bx::mapRemove(map, uint64_t(jj) );
				assert(ok);
			}

			assert(map.size() == 0);
		}

		elapsed += bx::getHPCounter();
		printf("      TinyStl: %15f\n", double(elapsed) );
	}

	///
	{
		int64_t elapsed = -bx::getHPCounter();

		for (uint32_t ii = 0; ii < numIterations; ++ii)
		{
			typedef std::unordered_map<uint64_t, uint16_t> StdUnorderedMap;
			StdUnorderedMap map;
//			map.reserve(numElements);
			for (uint32_t jj = 0; jj < numElements; ++jj)
			{
				std::pair<StdUnorderedMap::iterator, bool> ok = map.insert(std::make_pair(uint64_t(jj), uint16_t(jj) ) );
				assert(ok.second);
			}

			for (uint32_t jj = 0; jj < numElements; ++jj)
			{
				bool ok = bx::mapRemove(map, uint64_t(jj) );
				assert(ok);
			}

			assert(map.size() == 0);
		}

		elapsed += bx::getHPCounter();
		printf("          STL: %15f\n", double(elapsed) );
	}

	///
	{
		int64_t elapsed = -bx::getHPCounter();

		for (uint32_t ii = 0; ii < numIterations; ++ii)
		{
			typedef bx::HandleHashMapT<numElements+numElements/2, uint64_t> HandleHashMap;
			HandleHashMap map;
			for (uint32_t jj = 0; jj < numElements; ++jj)
			{
				bool ok = map.insert(jj, uint16_t(jj) );
				assert(ok);
			}

			for (uint32_t jj = 0; jj < numElements; ++jj)
			{
				bool ok = map.removeByKey(uint64_t(jj) );
				assert(ok);
			}

			assert(map.getNumElements() == 0);
		}

		elapsed += bx::getHPCounter();
		printf("HandleHashMap: %15f\n", double(elapsed) );
	}

	return EXIT_SUCCESS;
}
<|endoftext|>


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

  This source file is part of the Avogadro project.

  Copyright 2012 Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  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 "iotests.h"

#include <gtest/gtest.h>

#include <avogadro/core/matrix.h>
#include <avogadro/core/molecule.h>

#include <avogadro/io/cjsonformat.h>

using Avogadro::Core::Molecule;
using Avogadro::Core::Atom;
using Avogadro::Core::Bond;
using Avogadro::Io::CjsonFormat;
using Avogadro::MatrixX;

TEST(CjsonTest, readFile)
{
  CjsonFormat cjson;
  Molecule molecule;
  cjson.readFile(std::string(AVOGADRO_DATA) + "/data/ethane.cjson", molecule);

  EXPECT_EQ(molecule.data("name").type(), Avogadro::Core::Variant::String);
  EXPECT_EQ(molecule.data("name").toString(), "Ethane");

  EXPECT_EQ(molecule.data("inchi").type(), Avogadro::Core::Variant::String);
  EXPECT_EQ(molecule.data("inchi").toString(), "1/C2H6/c1-2/h1-2H3");
}

TEST(CjsonTest, atoms)
{
  CjsonFormat cjson;
  Molecule molecule;
  cjson.readFile(std::string(AVOGADRO_DATA) + "/data/ethane.cjson", molecule);

  EXPECT_EQ(molecule.data("name").toString(), "Ethane");
  EXPECT_EQ(molecule.atomCount(), static_cast<size_t>(8));
  Atom atom = molecule.atom(0);
  EXPECT_EQ(atom.atomicNumber(), static_cast<unsigned char>(1));
  atom = molecule.atom(1);
  EXPECT_EQ(atom.atomicNumber(), static_cast<unsigned char>(6));
  EXPECT_EQ(atom.position3d().x(),  0.751621);
  EXPECT_EQ(atom.position3d().y(), -0.022441);
  EXPECT_EQ(atom.position3d().z(), -0.020839);

  atom = molecule.atom(7);
  EXPECT_EQ(atom.atomicNumber(), static_cast<unsigned char>(1));
  EXPECT_EQ(atom.position3d().x(), -1.184988);
  EXPECT_EQ(atom.position3d().y(),  0.004424);
  EXPECT_EQ(atom.position3d().z(), -0.987522);
}

TEST(CjsonTest, bonds)
{
  CjsonFormat cjson;
  Molecule molecule;
  cjson.readFile(std::string(AVOGADRO_DATA) + "/data/ethane.cjson", molecule);

  EXPECT_EQ(molecule.data("name").toString(), "Ethane");
  EXPECT_EQ(molecule.atomCount(), static_cast<size_t>(8));
  EXPECT_EQ(molecule.bondCount(), static_cast<size_t>(7));

  Bond bond = molecule.bond(0);
  EXPECT_EQ(bond.atom1().index(), static_cast<size_t>(0));
  EXPECT_EQ(bond.atom2().index(), static_cast<size_t>(1));
  EXPECT_EQ(bond.order(), static_cast<unsigned char>(1));
  bond = molecule.bond(6);
  EXPECT_EQ(bond.atom1().index(), static_cast<size_t>(4));
  EXPECT_EQ(bond.atom2().index(), static_cast<size_t>(7));
  EXPECT_EQ(bond.order(), static_cast<unsigned char>(1));
}

TEST(CjsonTest, saveFile)
{
  CjsonFormat cjson;
  Molecule savedMolecule, molecule;
  cjson.readFile(std::string(AVOGADRO_DATA) + "/data/ethane.cjson",
                 savedMolecule);
  cjson.writeFile("ethanetmp.cjson", savedMolecule);

  // Now read the file back in and check a few key values are still present.
  cjson.readFile("ethanetmp.cjson", molecule);
  EXPECT_EQ(molecule.data("name").toString(), "Ethane");
  EXPECT_EQ(molecule.atomCount(), static_cast<size_t>(8));
  EXPECT_EQ(molecule.bondCount(), static_cast<size_t>(7));
  Atom atom = molecule.atom(7);
  EXPECT_EQ(atom.atomicNumber(), static_cast<unsigned char>(1));
  EXPECT_EQ(atom.position3d().x(), -1.184988);
  EXPECT_EQ(atom.position3d().y(),  0.004424);
  EXPECT_EQ(atom.position3d().z(), -0.987522);
  Bond bond = molecule.bond(0);
  EXPECT_EQ(bond.atom1().index(), static_cast<size_t>(0));
  EXPECT_EQ(bond.atom2().index(), static_cast<size_t>(1));
  EXPECT_EQ(bond.order(), static_cast<unsigned char>(1));
}
<commit_msg>Check return value from read and write calls<commit_after>/******************************************************************************

  This source file is part of the Avogadro project.

  Copyright 2012 Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  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 "iotests.h"

#include <gtest/gtest.h>

#include <avogadro/core/matrix.h>
#include <avogadro/core/molecule.h>

#include <avogadro/io/cjsonformat.h>

using Avogadro::Core::Molecule;
using Avogadro::Core::Atom;
using Avogadro::Core::Bond;
using Avogadro::Io::CjsonFormat;
using Avogadro::MatrixX;

TEST(CjsonTest, readFile)
{
  CjsonFormat cjson;
  Molecule molecule;
  bool success = cjson.readFile(std::string(AVOGADRO_DATA) +
                                "/data/ethane.cjson", molecule);
  EXPECT_TRUE(success);
  EXPECT_EQ(cjson.error(), "");
  EXPECT_EQ(molecule.data("name").type(), Avogadro::Core::Variant::String);
  EXPECT_EQ(molecule.data("name").toString(), "Ethane");

  EXPECT_EQ(molecule.data("inchi").type(), Avogadro::Core::Variant::String);
  EXPECT_EQ(molecule.data("inchi").toString(), "1/C2H6/c1-2/h1-2H3");
}

TEST(CjsonTest, atoms)
{
  CjsonFormat cjson;
  Molecule molecule;
  bool success = cjson.readFile(std::string(AVOGADRO_DATA) +
                                "/data/ethane.cjson", molecule);
  EXPECT_TRUE(success);
  EXPECT_EQ(cjson.error(), "");
  EXPECT_EQ(molecule.data("name").toString(), "Ethane");
  EXPECT_EQ(molecule.atomCount(), static_cast<size_t>(8));
  Atom atom = molecule.atom(0);
  EXPECT_EQ(atom.atomicNumber(), static_cast<unsigned char>(1));
  atom = molecule.atom(1);
  EXPECT_EQ(atom.atomicNumber(), static_cast<unsigned char>(6));
  EXPECT_EQ(atom.position3d().x(),  0.751621);
  EXPECT_EQ(atom.position3d().y(), -0.022441);
  EXPECT_EQ(atom.position3d().z(), -0.020839);

  atom = molecule.atom(7);
  EXPECT_EQ(atom.atomicNumber(), static_cast<unsigned char>(1));
  EXPECT_EQ(atom.position3d().x(), -1.184988);
  EXPECT_EQ(atom.position3d().y(),  0.004424);
  EXPECT_EQ(atom.position3d().z(), -0.987522);
}

TEST(CjsonTest, bonds)
{
  CjsonFormat cjson;
  Molecule molecule;
  bool success = cjson.readFile(std::string(AVOGADRO_DATA) +
                                "/data/ethane.cjson", molecule);
  EXPECT_TRUE(success);
  EXPECT_EQ(cjson.error(), "");
  EXPECT_EQ(molecule.data("name").toString(), "Ethane");
  EXPECT_EQ(molecule.atomCount(), static_cast<size_t>(8));
  EXPECT_EQ(molecule.bondCount(), static_cast<size_t>(7));

  Bond bond = molecule.bond(0);
  EXPECT_EQ(bond.atom1().index(), static_cast<size_t>(0));
  EXPECT_EQ(bond.atom2().index(), static_cast<size_t>(1));
  EXPECT_EQ(bond.order(), static_cast<unsigned char>(1));
  bond = molecule.bond(6);
  EXPECT_EQ(bond.atom1().index(), static_cast<size_t>(4));
  EXPECT_EQ(bond.atom2().index(), static_cast<size_t>(7));
  EXPECT_EQ(bond.order(), static_cast<unsigned char>(1));
}

TEST(CjsonTest, saveFile)
{
  CjsonFormat cjson;
  Molecule savedMolecule, molecule;
  bool success = cjson.readFile(std::string(AVOGADRO_DATA) +
                                "/data/ethane.cjson",
                                savedMolecule);
  EXPECT_TRUE(success);
  EXPECT_EQ(cjson.error(), "");

  success = cjson.writeFile("ethanetmp.cjson", savedMolecule);
  EXPECT_TRUE(success);
  EXPECT_EQ(cjson.error(), "");

  // Now read the file back in and check a few key values are still present.
  success = cjson.readFile("ethanetmp.cjson", molecule);
  EXPECT_TRUE(success);
  EXPECT_EQ(cjson.error(), "");
  EXPECT_EQ(molecule.data("name").toString(), "Ethane");
  EXPECT_EQ(molecule.atomCount(), static_cast<size_t>(8));
  EXPECT_EQ(molecule.bondCount(), static_cast<size_t>(7));
  Atom atom = molecule.atom(7);
  EXPECT_EQ(atom.atomicNumber(), static_cast<unsigned char>(1));
  EXPECT_EQ(atom.position3d().x(), -1.184988);
  EXPECT_EQ(atom.position3d().y(),  0.004424);
  EXPECT_EQ(atom.position3d().z(), -0.987522);
  Bond bond = molecule.bond(0);
  EXPECT_EQ(bond.atom1().index(), static_cast<size_t>(0));
  EXPECT_EQ(bond.atom2().index(), static_cast<size_t>(1));
  EXPECT_EQ(bond.order(), static_cast<unsigned char>(1));
}
<|endoftext|>


<commit_before>// Begin CVS Header
//   $Source: /Volumes/Home/Users/shoops/cvs/copasi_dev/copasi/UI/CQLayoutsWidget.cpp,v $
//   $Revision: 1.2 $
//   $Name:  $
//   $Author: gauges $
//   $Date: 2008/09/09 03:41:52 $
// End CVS Header

// Copyright (C) 2008 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

#include "CQLayoutsWidget.h"

#include <qlayout.h>
#include <qwidget.h>
#include <qfont.h>
#include <qpushbutton.h>
#include <qaction.h>
#include <qregexp.h>
#include <qvalidator.h>

#include <iostream>

#include "CQMessageBox.h"
#include "listviews.h"
#include "qtUtilities.h"
#include "copasi/layout/CLayout.h"
#include "copasi/layout/CListOfLayouts.h"
#include "copasi/report/CKeyFactory.h"
#include "copasi/CopasiDataModel/CCopasiDataModel.h"
#include "copasi/layoutUI/CQLayoutMainWindow.h"

#define COL_MARK         0
#define COL_NAME         1
#define COL_SHOW         2

std::vector<const CCopasiObject*> CQLayoutsWidget::getObjects() const
  {
    CListOfLayouts* pListOfLayouts = CCopasiDataModel::Global->getListOfLayouts();
    std::vector<const CCopasiObject*> ret;

    C_INT32 i, imax = pListOfLayouts->size();
    for (i = 0; i < imax; ++i)
      ret.push_back((*pListOfLayouts)[i]);

    return ret;
  }

void CQLayoutsWidget::init()
{
  this->btnNew->hide();
  mOT = ListViews::LAYOUT;
  numCols = 3;
  table->setNumCols(numCols);

  //Setting table headers
  QHeader *tableHeader = table->horizontalHeader();
  tableHeader->setLabel(COL_MARK, "Status");
  tableHeader->setLabel(COL_NAME, "Name");
  tableHeader->setLabel(COL_SHOW, "Show");
}

void CQLayoutsWidget::updateHeaderUnits()
{
  // no units, so we do nothing
}

void CQLayoutsWidget::tableLineFromObject(const CCopasiObject* obj, unsigned C_INT32 row)
{
  if (!obj) return;
  const CLayout * pLayout = static_cast< const CLayout * >(obj);

  // Name
  table->setText(row, COL_NAME, FROM_UTF8(pLayout->getObjectName()));
  CQShowLayoutButton* pButton = new CQShowLayoutButton(row, NULL);
  pButton->setText("Show");
  table->setCellWidget(row, COL_SHOW, pButton);
  connect(pButton, SIGNAL(signal_show(int)), this, SLOT(slot_show(int)));
  std::map<std::string, CQLayoutMainWindow*>::iterator pos = this->mLayoutWindowMap.find(obj->getKey());
  // if this layout does not have an entry in the layout window map, add one
  if (pos == this->mLayoutWindowMap.end())
    {
      this->mLayoutWindowMap.insert(std::pair<std::string, CQLayoutMainWindow*>(obj->getKey(), NULL));
    }
}

void CQLayoutsWidget::tableLineToObject(unsigned C_INT32 /*row*/, CCopasiObject* /*obj*/)
{
  // I don't know what this is supposed to do, but right now it does nothing
  //if (!obj) return;
  //CLayout * pLayout = static_cast< CLayout * >(obj);
}

void CQLayoutsWidget::defaultTableLineContent(unsigned C_INT32 /*row*/, unsigned C_INT32 /*exc*/)
{
  // nothin to do here
}

QString CQLayoutsWidget::defaultObjectName() const
  {
    return "layout";
  }

CCopasiObject* CQLayoutsWidget::createNewObject(const std::string & /*name*/)
{
  /*
   * Can't create layouts yet.
  std::string nname = name;
  int i = 0;
  CLayout* playout;
  while (!(pLayout = CCopasiDataModel::Global->createLayout(nname)))
    {
      i++;
      nname = name + "_";
      nname += (const char *)QString::number(i).utf8();
    }

  return pLayout;
  */
  return NULL;
}

void CQLayoutsWidget::deleteObjects(const std::vector<std::string> & keys)
{
  if (keys.size() == 0)
    return;

  QString layoutList = "Are you sure you want to delete listed LAYOUT(S) ?\n";

  unsigned C_INT32 i, imax = keys.size();
  for (i = 0; i < imax; i++) //all compartments
    {
      CLayout* pLayout =
        dynamic_cast< CLayout *>(GlobalKeys.get(keys[i]));

      layoutList.append(FROM_UTF8(pLayout->getObjectName()));
      layoutList.append(", ");
    }

  layoutList.remove(layoutList.length() - 2, 2);

  QString msg = layoutList;

  C_INT32 choice = 0;

  switch (choice)
    {
    case 0:                    // Yes or Enter
      {
        for (i = 0; i < imax; i++)
          {
            CCopasiDataModel::Global->removeLayout(keys[i]);
            std::map<std::string, CQLayoutMainWindow*>::iterator pos = this->mLayoutWindowMap.find(keys[i]);
            if (pos != this->mLayoutWindowMap.end() && pos->second != NULL)
              {
                // close the window
                pos->second->close();
              }
          }

        for (i = 0; i < imax; i++)
          protectedNotify(ListViews::COMPARTMENT, ListViews::DELETE, keys[i]);

        mChanged = true;
        break;
      }

    default:                    // No or Escape
      break;
    }
}

void CQLayoutsWidget::valueChanged(unsigned C_INT32 /*row*/, unsigned C_INT32 /*col*/)
{
  /*
   * Does nothing at the moment.
  switch (col)
    {
    default:
      break;
    }
  */
  return;
}

/**
 * We overwrite the slotDoubleClicked from CopasiTableWidget since we don't
 * want to switch to another folder in the ListView but we want to open or display a layout window.
 */
void CQLayoutsWidget::slotDoubleClicked(int row, int C_UNUSED(col),
                                        int C_UNUSED(m), const QPoint & C_UNUSED(n))
{
  if (row >= table->numRows() || row < 0) return;
  if (mRO && (row == table->numRows() - 1)) return;

  std::string key = mKeys[row];
  bool flagNew = false;

  if (mFlagNew[row])
    {
      saveTable();
      fillTable();
      return;
      //TODO: When double clicking on a new object the object should be created.
    }

  if (mFlagDelete[row])
    {
      return;
    }

  if (row == table->numRows() - 1) //new Object
    {
      flagNew = true;
      resizeTable(table->numRows() + 1);
      mFlagNew[row] = true;
      table->setText(row, 1, createNewName(defaultObjectName()));
      defaultTableLineContent(row, 0);
    }

  saveTable();

  if (flagNew)
    {
      key = mKeys[row];
    }

  fillTable();

  this->slot_show(row);
}

void CQLayoutsWidget::slot_show(int row)
{
  std::string key = mKeys[row];
  CLayout* pLayout = dynamic_cast<CLayout*>(GlobalKeys.get(key));
  if (pLayout != NULL)
    {
      // check if we already have a widget for the layout
      // if yes, open it, else create one and add it to the map
      bool createNew = false;
      std::map<std::string, CQLayoutMainWindow*>::iterator pos = this->mLayoutWindowMap.find(key);
      if (pos != this->mLayoutWindowMap.end())
        {
          if (pos->second == NULL)
            {
              createNew = true;
            }
          else
            {
              pos->second->show();
              pos->second->showNormal();
              pos->second->setActiveWindow();
            }
        }
      else
        {
          createNew = true;
        }
      if (createNew)
        {
          CQLayoutMainWindow* pWin = new CQLayoutMainWindow(pLayout, this, pLayout->getObjectName().c_str());
          pWin->resize(900, 430);
          pWin->show();

          this->mLayoutWindowMap[key] = pWin;
        }
    }
  else
    {
      std::cerr << "Could not find layout." << std::endl;
    }
}

void CQShowLayoutButton::slot_clicked()
{
  emit signal_show(this->mRow);
}

CQShowLayoutButton::CQShowLayoutButton(unsigned int row, QWidget* pParent, const char* name): QToolButton(pParent, name), mRow(row)
{
  this->setTextLabel("Show");
  connect(this, SIGNAL(clicked()), this, SLOT(slot_clicked()));
}
<commit_msg>Changed the default size for the layout windows.<commit_after>// Begin CVS Header
//   $Source: /Volumes/Home/Users/shoops/cvs/copasi_dev/copasi/UI/CQLayoutsWidget.cpp,v $
//   $Revision: 1.3 $
//   $Name:  $
//   $Author: gauges $
//   $Date: 2008/09/09 09:15:16 $
// End CVS Header

// Copyright (C) 2008 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

#include "CQLayoutsWidget.h"

#include <qlayout.h>
#include <qwidget.h>
#include <qfont.h>
#include <qpushbutton.h>
#include <qaction.h>
#include <qregexp.h>
#include <qvalidator.h>

#include <iostream>

#include "CQMessageBox.h"
#include "listviews.h"
#include "qtUtilities.h"
#include "copasi/layout/CLayout.h"
#include "copasi/layout/CListOfLayouts.h"
#include "copasi/report/CKeyFactory.h"
#include "copasi/CopasiDataModel/CCopasiDataModel.h"
#include "copasi/layoutUI/CQLayoutMainWindow.h"

#define COL_MARK         0
#define COL_NAME         1
#define COL_SHOW         2

std::vector<const CCopasiObject*> CQLayoutsWidget::getObjects() const
  {
    CListOfLayouts* pListOfLayouts = CCopasiDataModel::Global->getListOfLayouts();
    std::vector<const CCopasiObject*> ret;

    C_INT32 i, imax = pListOfLayouts->size();
    for (i = 0; i < imax; ++i)
      ret.push_back((*pListOfLayouts)[i]);

    return ret;
  }

void CQLayoutsWidget::init()
{
  this->btnNew->hide();
  mOT = ListViews::LAYOUT;
  numCols = 3;
  table->setNumCols(numCols);

  //Setting table headers
  QHeader *tableHeader = table->horizontalHeader();
  tableHeader->setLabel(COL_MARK, "Status");
  tableHeader->setLabel(COL_NAME, "Name");
  tableHeader->setLabel(COL_SHOW, "Show");
}

void CQLayoutsWidget::updateHeaderUnits()
{
  // no units, so we do nothing
}

void CQLayoutsWidget::tableLineFromObject(const CCopasiObject* obj, unsigned C_INT32 row)
{
  if (!obj) return;
  const CLayout * pLayout = static_cast< const CLayout * >(obj);

  // Name
  table->setText(row, COL_NAME, FROM_UTF8(pLayout->getObjectName()));
  CQShowLayoutButton* pButton = new CQShowLayoutButton(row, NULL);
  pButton->setText("Show");
  table->setCellWidget(row, COL_SHOW, pButton);
  connect(pButton, SIGNAL(signal_show(int)), this, SLOT(slot_show(int)));
  std::map<std::string, CQLayoutMainWindow*>::iterator pos = this->mLayoutWindowMap.find(obj->getKey());
  // if this layout does not have an entry in the layout window map, add one
  if (pos == this->mLayoutWindowMap.end())
    {
      this->mLayoutWindowMap.insert(std::pair<std::string, CQLayoutMainWindow*>(obj->getKey(), NULL));
    }
}

void CQLayoutsWidget::tableLineToObject(unsigned C_INT32 /*row*/, CCopasiObject* /*obj*/)
{
  // I don't know what this is supposed to do, but right now it does nothing
  //if (!obj) return;
  //CLayout * pLayout = static_cast< CLayout * >(obj);
}

void CQLayoutsWidget::defaultTableLineContent(unsigned C_INT32 /*row*/, unsigned C_INT32 /*exc*/)
{
  // nothin to do here
}

QString CQLayoutsWidget::defaultObjectName() const
  {
    return "layout";
  }

CCopasiObject* CQLayoutsWidget::createNewObject(const std::string & /*name*/)
{
  /*
   * Can't create layouts yet.
  std::string nname = name;
  int i = 0;
  CLayout* playout;
  while (!(pLayout = CCopasiDataModel::Global->createLayout(nname)))
    {
      i++;
      nname = name + "_";
      nname += (const char *)QString::number(i).utf8();
    }

  return pLayout;
  */
  return NULL;
}

void CQLayoutsWidget::deleteObjects(const std::vector<std::string> & keys)
{
  if (keys.size() == 0)
    return;

  QString layoutList = "Are you sure you want to delete listed LAYOUT(S) ?\n";

  unsigned C_INT32 i, imax = keys.size();
  for (i = 0; i < imax; i++) //all compartments
    {
      CLayout* pLayout =
        dynamic_cast< CLayout *>(GlobalKeys.get(keys[i]));

      layoutList.append(FROM_UTF8(pLayout->getObjectName()));
      layoutList.append(", ");
    }

  layoutList.remove(layoutList.length() - 2, 2);

  QString msg = layoutList;

  C_INT32 choice = 0;

  switch (choice)
    {
    case 0:                    // Yes or Enter
      {
        for (i = 0; i < imax; i++)
          {
            CCopasiDataModel::Global->removeLayout(keys[i]);
            std::map<std::string, CQLayoutMainWindow*>::iterator pos = this->mLayoutWindowMap.find(keys[i]);
            if (pos != this->mLayoutWindowMap.end() && pos->second != NULL)
              {
                // close the window
                pos->second->close();
              }
          }

        for (i = 0; i < imax; i++)
          protectedNotify(ListViews::COMPARTMENT, ListViews::DELETE, keys[i]);

        mChanged = true;
        break;
      }

    default:                    // No or Escape
      break;
    }
}

void CQLayoutsWidget::valueChanged(unsigned C_INT32 /*row*/, unsigned C_INT32 /*col*/)
{
  /*
   * Does nothing at the moment.
  switch (col)
    {
    default:
      break;
    }
  */
  return;
}

/**
 * We overwrite the slotDoubleClicked from CopasiTableWidget since we don't
 * want to switch to another folder in the ListView but we want to open or display a layout window.
 */
void CQLayoutsWidget::slotDoubleClicked(int row, int C_UNUSED(col),
                                        int C_UNUSED(m), const QPoint & C_UNUSED(n))
{
  if (row >= table->numRows() || row < 0) return;
  if (mRO && (row == table->numRows() - 1)) return;

  std::string key = mKeys[row];
  bool flagNew = false;

  if (mFlagNew[row])
    {
      saveTable();
      fillTable();
      return;
      //TODO: When double clicking on a new object the object should be created.
    }

  if (mFlagDelete[row])
    {
      return;
    }

  if (row == table->numRows() - 1) //new Object
    {
      flagNew = true;
      resizeTable(table->numRows() + 1);
      mFlagNew[row] = true;
      table->setText(row, 1, createNewName(defaultObjectName()));
      defaultTableLineContent(row, 0);
    }

  saveTable();

  if (flagNew)
    {
      key = mKeys[row];
    }

  fillTable();

  this->slot_show(row);
}

void CQLayoutsWidget::slot_show(int row)
{
  std::string key = mKeys[row];
  CLayout* pLayout = dynamic_cast<CLayout*>(GlobalKeys.get(key));
  if (pLayout != NULL)
    {
      // check if we already have a widget for the layout
      // if yes, open it, else create one and add it to the map
      bool createNew = false;
      std::map<std::string, CQLayoutMainWindow*>::iterator pos = this->mLayoutWindowMap.find(key);
      if (pos != this->mLayoutWindowMap.end())
        {
          if (pos->second == NULL)
            {
              createNew = true;
            }
          else
            {
              pos->second->show();
              pos->second->showNormal();
              pos->second->setActiveWindow();
            }
        }
      else
        {
          createNew = true;
        }
      if (createNew)
        {
          CQLayoutMainWindow* pWin = new CQLayoutMainWindow(pLayout, this, pLayout->getObjectName().c_str());
          pWin->resize(900, 600);
          pWin->show();

          this->mLayoutWindowMap[key] = pWin;
        }
    }
  else
    {
      std::cerr << "Could not find layout." << std::endl;
    }
}

void CQShowLayoutButton::slot_clicked()
{
  emit signal_show(this->mRow);
}

CQShowLayoutButton::CQShowLayoutButton(unsigned int row, QWidget* pParent, const char* name): QToolButton(pParent, name), mRow(row)
{
  this->setTextLabel("Show");
  connect(this, SIGNAL(clicked()), this, SLOT(slot_clicked()));
}
<|endoftext|>


<commit_before>// Copyright (C) 2010 - 2016 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

// Copyright (C) 2009 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

#include "CQSpeciesWidget.h"

#include <QtGui/QHeaderView>
#include <QtGui/QClipboard>
#include <QtGui/QKeyEvent>

#include "copasi.h"

#include "qtUtilities.h"
#include "CQMessageBox.h"

#include "model/CModel.h"
#include "CopasiDataModel/CCopasiDataModel.h"
#include "report/CCopasiRootContainer.h"

#include "copasiui3window.h"

/*
 *  Constructs a CQSpeciesWidget which is a child of 'parent', with the
 *  name 'name'.'
 */
CQSpeciesWidget::CQSpeciesWidget(QWidget* parent, const char* name)
  : CopasiWidget(parent, name)
{
  setupUi(this);

  //Create Source Data Model.
  mpSpecieDM = new CQSpecieDM(this);

  //Create the Proxy Model for sorting/filtering and set its properties.
  mpProxyModel = new CQSortFilterProxyModel();
  mpProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
  mpProxyModel->setFilterKeyColumn(-1);
  mpProxyModel->setSourceModel(mpSpecieDM);

  mpTblSpecies->setModel(mpProxyModel);

  //Setting values for Compartment comboBox
  mpCompartmentDelegate = new CQComboDelegate(this, mCompartments);
  mpTblSpecies->setItemDelegateForColumn(COL_COMPARTMENT, mpCompartmentDelegate);

  //Setting values for Types comboBox
  mpTypeDelegate = new CQIndexComboDelegate(this, mpSpecieDM->getTypes());
  mpTblSpecies->setItemDelegateForColumn(COL_TYPE_SPECIES, mpTypeDelegate);

  mpTblSpecies->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
  mpTblSpecies->verticalHeader()->hide();
  mpTblSpecies->sortByColumn(COL_ROW_NUMBER, Qt::AscendingOrder);

  // Connect the table widget
  connect(mpSpecieDM, SIGNAL(notifyGUI(ListViews::ObjectType, ListViews::Action, const std::string)),
          this, SLOT(protectedNotify(ListViews::ObjectType, ListViews::Action, const std::string)));
  connect(mpSpecieDM, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
          this, SLOT(dataChanged(const QModelIndex&, const QModelIndex&)));
  connect(mpLEFilter, SIGNAL(textChanged(const QString &)),
          this, SLOT(slotFilterChanged()));

  CopasiUI3Window *  pWindow = dynamic_cast<CopasiUI3Window * >(parent->parent());
  mpSpecieDM->setUndoStack(pWindow->getUndoStack());
}

/*
 *  Destroys the object and frees any allocated resources
 */
CQSpeciesWidget::~CQSpeciesWidget()
{
  pdelete(mpCompartmentDelegate);
  pdelete(mpTypeDelegate);
  pdelete(mpProxyModel);
  pdelete(mpSpecieDM);
  // no need to delete child widgets, Qt does it all for us
}

void CQSpeciesWidget::slotBtnNewClicked()
{
  mpSpecieDM->insertRow(mpSpecieDM->rowCount() - 1, QModelIndex());
  updateDeleteBtns();
}

void CQSpeciesWidget::slotBtnDeleteClicked()
{
  if (mpTblSpecies->hasFocus())
    {deleteSelectedSpecies();}

  updateDeleteBtns();
}

void CQSpeciesWidget::deleteSelectedSpecies()
{
  const QItemSelectionModel * pSelectionModel = mpTblSpecies->selectionModel();

  QModelIndexList mappedSelRows;
  size_t i, imax = mpSpecieDM->rowCount();

  for (i = 0; i < imax; i++)
    {
      if (pSelectionModel->isRowSelected((int) i, QModelIndex()))
        {
          mappedSelRows.append(mpProxyModel->mapToSource(mpProxyModel->index((int) i, 0)));
        }
    }

  if (mappedSelRows.empty())
    {return;}

  mpSpecieDM->removeRows(mappedSelRows);
}

void CQSpeciesWidget::slotBtnClearClicked()
{

  int ret = CQMessageBox::question(this, tr("Confirm Delete"), "Delete all Species?",
                                   QMessageBox::Yes | QMessageBox::No, QMessageBox::No);

  if (ret == QMessageBox::Yes)
    {
      mpSpecieDM->clear();
    }

  updateDeleteBtns();
}

bool CQSpeciesWidget::update(ListViews::ObjectType C_UNUSED(objectType), ListViews::Action C_UNUSED(action), const std::string & C_UNUSED(key))
{
  if (!mIgnoreUpdates && isVisible())
    {
      enterProtected();
    }

  return true;
}

bool CQSpeciesWidget::leave()
{
  return true;
}

bool CQSpeciesWidget::enterProtected()
{
  if (mpTblSpecies->selectionModel() != NULL)
    {
      disconnect(mpTblSpecies->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
                 this, SLOT(slotSelectionChanged(const QItemSelection&, const QItemSelection&)));
    }

  mpProxyModel->setSourceModel(mpSpecieDM);
  //Set Model for the TableView
  mpTblSpecies->setModel(NULL);
  mpTblSpecies->setModel(mpProxyModel);

  connect(mpTblSpecies->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
          this, SLOT(slotSelectionChanged(const QItemSelection&, const QItemSelection&)));
  updateDeleteBtns();
  mpTblSpecies->resizeColumnsToContents();
  setFramework(mFramework);
  refreshCompartments();

  return true;
}

void CQSpeciesWidget::updateDeleteBtns()
{
  bool selected = false;

  QModelIndexList selRows = mpTblSpecies->selectionModel()->selectedRows();

  if (selRows.size() == 0)
    selected = false;
  else
    {
      if (selRows.size() == 1)
        {
          if (mpSpecieDM->isDefaultRow(mpProxyModel->mapToSource(selRows[0])))
            selected = false;
          else
            selected = true;
        }
      else
        selected = true;
    }

  mpBtnDelete->setEnabled(selected);

  if (mpProxyModel->rowCount() - 1)
    mpBtnClear->setEnabled(true);
  else
    mpBtnClear->setEnabled(false);
}

void CQSpeciesWidget::slotSelectionChanged(const QItemSelection& C_UNUSED(selected),
    const QItemSelection& C_UNUSED(deselected))
{
  updateDeleteBtns();
}

void CQSpeciesWidget::dataChanged(const QModelIndex& C_UNUSED(topLeft),
                                  const QModelIndex& C_UNUSED(bottomRight))
{
  mpTblSpecies->resizeColumnsToContents();
  setFramework(mFramework);
  refreshCompartments();
  updateDeleteBtns();
}

void CQSpeciesWidget::slotDoubleClicked(const QModelIndex proxyIndex)
{
  QModelIndex index = mpProxyModel->mapToSource(proxyIndex);

  if (index.row() < 0)
    return;

  if (mpSpecieDM->isDefaultRow(index))
    {
      slotBtnNewClicked();
    }

  assert(CCopasiRootContainer::getDatamodelList()->size() > 0);
  CCopasiDataModel* pDataModel = &CCopasiRootContainer::getDatamodelList()->operator[](0);
  assert(pDataModel != NULL);
  CModel * pModel = pDataModel->getModel();

  if (pModel == NULL)
    return;

  std::string key = pModel->getMetabolites()[index.row()].getKey();

  if (CCopasiRootContainer::getKeyFactory()->get(key))
    mpListView->switchToOtherWidget(C_INVALID_INDEX, key);
}

void CQSpeciesWidget::keyPressEvent(QKeyEvent* ev)
{
  if (ev->key() == Qt::Key_Delete)
    slotBtnDeleteClicked();
  else if (ev->key() == Qt::Key_C && (ev->modifiers() & Qt::ControlModifier))
    {
      QModelIndexList selRows = mpTblSpecies->selectionModel()->selectedRows(0);

      if (selRows.empty())
        {return;}

      QString str;
      QModelIndexList::const_iterator i;

      for (i = selRows.begin(); i != selRows.end(); ++i)
        {
          for (int x = 0; x < mpSpecieDM->columnCount(); ++x)
            {
              if (!mpTblSpecies->isColumnHidden(x))
                {
                  if (!str.isEmpty())
                    str += "\t";

                  str += mpSpecieDM->index(mpProxyModel->mapToSource(*i).row(), x).data().toString();
                }
            }

          str += "\n";
        }

      QApplication::clipboard()->setText(str);
    }
}

void CQSpeciesWidget::slotFilterChanged()
{
  QRegExp regExp(mpLEFilter->text() + "|New Species", Qt::CaseInsensitive, QRegExp::RegExp);
  mpProxyModel->setFilterRegExp(regExp);
}

void CQSpeciesWidget::setFramework(int framework)
{
  CopasiWidget::setFramework(framework);

  switch (mFramework)
    {
      case 0:
        mpTblSpecies->showColumn(COL_ICONCENTRATION);
        mpTblSpecies->showColumn(COL_CONCENTRATION);
        mpTblSpecies->showColumn(COL_CRATE);

        mpTblSpecies->hideColumn(COL_INUMBER);
        mpTblSpecies->hideColumn(COL_NUMBER);
        mpTblSpecies->hideColumn(COL_NRATE);

        mpSpecieDM->setFlagConc(true);
        break;

      case 1:
        mpTblSpecies->hideColumn(COL_ICONCENTRATION);
        mpTblSpecies->hideColumn(COL_CONCENTRATION);
        mpTblSpecies->hideColumn(COL_CRATE);

        mpTblSpecies->showColumn(COL_INUMBER);
        mpTblSpecies->showColumn(COL_NUMBER);
        mpTblSpecies->showColumn(COL_NRATE);

        mpSpecieDM->setFlagConc(false);
        break;
    }
}

void CQSpeciesWidget::refreshCompartments()
{
  const CCopasiVector < CCompartment > & compartments =
    CCopasiRootContainer::getDatamodelList()->operator[](0).getModel()->getCompartments();
  mCompartments.clear();

  for (unsigned C_INT32 jj = 0; jj < compartments.size(); jj++)
    mCompartments.push_back(FROM_UTF8(compartments[jj].getObjectName()));

  mpCompartmentDelegate->setItems(-1, mCompartments);
}
<commit_msg>- disable commit on select, as otherwise the species will be removed before the editor disapears resulting in two species being assigned the new type.<commit_after>// Copyright (C) 2010 - 2016 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

// Copyright (C) 2009 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

#include "CQSpeciesWidget.h"

#include <QtGui/QHeaderView>
#include <QtGui/QClipboard>
#include <QtGui/QKeyEvent>

#include "copasi.h"

#include "qtUtilities.h"
#include "CQMessageBox.h"

#include "model/CModel.h"
#include "CopasiDataModel/CCopasiDataModel.h"
#include "report/CCopasiRootContainer.h"

#include "copasiui3window.h"

/*
 *  Constructs a CQSpeciesWidget which is a child of 'parent', with the
 *  name 'name'.'
 */
CQSpeciesWidget::CQSpeciesWidget(QWidget* parent, const char* name)
  : CopasiWidget(parent, name)
{
  setupUi(this);

  //Create Source Data Model.
  mpSpecieDM = new CQSpecieDM(this);

  //Create the Proxy Model for sorting/filtering and set its properties.
  mpProxyModel = new CQSortFilterProxyModel();
  mpProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
  mpProxyModel->setFilterKeyColumn(-1);
  mpProxyModel->setSourceModel(mpSpecieDM);

  mpTblSpecies->setModel(mpProxyModel);

  //Setting values for Compartment comboBox
  mpCompartmentDelegate = new CQComboDelegate(this, mCompartments);
  mpTblSpecies->setItemDelegateForColumn(COL_COMPARTMENT, mpCompartmentDelegate);

  //Setting values for Types comboBox
  mpTypeDelegate = new CQIndexComboDelegate(this, mpSpecieDM->getTypes(), false);
  mpTblSpecies->setItemDelegateForColumn(COL_TYPE_SPECIES, mpTypeDelegate);

  mpTblSpecies->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
  mpTblSpecies->verticalHeader()->hide();
  mpTblSpecies->sortByColumn(COL_ROW_NUMBER, Qt::AscendingOrder);

  // Connect the table widget
  connect(mpSpecieDM, SIGNAL(notifyGUI(ListViews::ObjectType, ListViews::Action, const std::string)),
          this, SLOT(protectedNotify(ListViews::ObjectType, ListViews::Action, const std::string)));
  connect(mpSpecieDM, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
          this, SLOT(dataChanged(const QModelIndex&, const QModelIndex&)));
  connect(mpLEFilter, SIGNAL(textChanged(const QString &)),
          this, SLOT(slotFilterChanged()));

  CopasiUI3Window *  pWindow = dynamic_cast<CopasiUI3Window * >(parent->parent());
  mpSpecieDM->setUndoStack(pWindow->getUndoStack());
}

/*
 *  Destroys the object and frees any allocated resources
 */
CQSpeciesWidget::~CQSpeciesWidget()
{
  pdelete(mpCompartmentDelegate);
  pdelete(mpTypeDelegate);
  pdelete(mpProxyModel);
  pdelete(mpSpecieDM);
  // no need to delete child widgets, Qt does it all for us
}

void CQSpeciesWidget::slotBtnNewClicked()
{
  mpSpecieDM->insertRow(mpSpecieDM->rowCount() - 1, QModelIndex());
  updateDeleteBtns();
}

void CQSpeciesWidget::slotBtnDeleteClicked()
{
  if (mpTblSpecies->hasFocus())
    {deleteSelectedSpecies();}

  updateDeleteBtns();
}

void CQSpeciesWidget::deleteSelectedSpecies()
{
  const QItemSelectionModel * pSelectionModel = mpTblSpecies->selectionModel();

  QModelIndexList mappedSelRows;
  size_t i, imax = mpSpecieDM->rowCount();

  for (i = 0; i < imax; i++)
    {
      if (pSelectionModel->isRowSelected((int) i, QModelIndex()))
        {
          mappedSelRows.append(mpProxyModel->mapToSource(mpProxyModel->index((int) i, 0)));
        }
    }

  if (mappedSelRows.empty())
    {return;}

  mpSpecieDM->removeRows(mappedSelRows);
}

void CQSpeciesWidget::slotBtnClearClicked()
{

  int ret = CQMessageBox::question(this, tr("Confirm Delete"), "Delete all Species?",
                                   QMessageBox::Yes | QMessageBox::No, QMessageBox::No);

  if (ret == QMessageBox::Yes)
    {
      mpSpecieDM->clear();
    }

  updateDeleteBtns();
}

bool CQSpeciesWidget::update(ListViews::ObjectType C_UNUSED(objectType), ListViews::Action C_UNUSED(action), const std::string & C_UNUSED(key))
{
  if (!mIgnoreUpdates && isVisible())
    {
      enterProtected();
    }

  return true;
}

bool CQSpeciesWidget::leave()
{
  return true;
}

bool CQSpeciesWidget::enterProtected()
{
  if (mpTblSpecies->selectionModel() != NULL)
    {
      disconnect(mpTblSpecies->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
                 this, SLOT(slotSelectionChanged(const QItemSelection&, const QItemSelection&)));
    }

  mpProxyModel->setSourceModel(mpSpecieDM);
  //Set Model for the TableView
  mpTblSpecies->setModel(NULL);
  mpTblSpecies->setModel(mpProxyModel);

  connect(mpTblSpecies->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
          this, SLOT(slotSelectionChanged(const QItemSelection&, const QItemSelection&)));
  updateDeleteBtns();
  mpTblSpecies->resizeColumnsToContents();
  setFramework(mFramework);
  refreshCompartments();

  return true;
}

void CQSpeciesWidget::updateDeleteBtns()
{
  bool selected = false;

  QModelIndexList selRows = mpTblSpecies->selectionModel()->selectedRows();

  if (selRows.size() == 0)
    selected = false;
  else
    {
      if (selRows.size() == 1)
        {
          if (mpSpecieDM->isDefaultRow(mpProxyModel->mapToSource(selRows[0])))
            selected = false;
          else
            selected = true;
        }
      else
        selected = true;
    }

  mpBtnDelete->setEnabled(selected);

  if (mpProxyModel->rowCount() - 1)
    mpBtnClear->setEnabled(true);
  else
    mpBtnClear->setEnabled(false);
}

void CQSpeciesWidget::slotSelectionChanged(const QItemSelection& C_UNUSED(selected),
    const QItemSelection& C_UNUSED(deselected))
{
  updateDeleteBtns();
}

void CQSpeciesWidget::dataChanged(const QModelIndex& C_UNUSED(topLeft),
                                  const QModelIndex& C_UNUSED(bottomRight))
{
  mpTblSpecies->resizeColumnsToContents();
  setFramework(mFramework);
  refreshCompartments();
  updateDeleteBtns();
}

void CQSpeciesWidget::slotDoubleClicked(const QModelIndex proxyIndex)
{
  QModelIndex index = mpProxyModel->mapToSource(proxyIndex);

  if (index.row() < 0)
    return;

  if (mpSpecieDM->isDefaultRow(index))
    {
      slotBtnNewClicked();
    }

  assert(CCopasiRootContainer::getDatamodelList()->size() > 0);
  CCopasiDataModel* pDataModel = &CCopasiRootContainer::getDatamodelList()->operator[](0);
  assert(pDataModel != NULL);
  CModel * pModel = pDataModel->getModel();

  if (pModel == NULL)
    return;

  std::string key = pModel->getMetabolites()[index.row()].getKey();

  if (CCopasiRootContainer::getKeyFactory()->get(key))
    mpListView->switchToOtherWidget(C_INVALID_INDEX, key);
}

void CQSpeciesWidget::keyPressEvent(QKeyEvent* ev)
{
  if (ev->key() == Qt::Key_Delete)
    slotBtnDeleteClicked();
  else if (ev->key() == Qt::Key_C && (ev->modifiers() & Qt::ControlModifier))
    {
      QModelIndexList selRows = mpTblSpecies->selectionModel()->selectedRows(0);

      if (selRows.empty())
        {return;}

      QString str;
      QModelIndexList::const_iterator i;

      for (i = selRows.begin(); i != selRows.end(); ++i)
        {
          for (int x = 0; x < mpSpecieDM->columnCount(); ++x)
            {
              if (!mpTblSpecies->isColumnHidden(x))
                {
                  if (!str.isEmpty())
                    str += "\t";

                  str += mpSpecieDM->index(mpProxyModel->mapToSource(*i).row(), x).data().toString();
                }
            }

          str += "\n";
        }

      QApplication::clipboard()->setText(str);
    }
}

void CQSpeciesWidget::slotFilterChanged()
{
  QRegExp regExp(mpLEFilter->text() + "|New Species", Qt::CaseInsensitive, QRegExp::RegExp);
  mpProxyModel->setFilterRegExp(regExp);
}

void CQSpeciesWidget::setFramework(int framework)
{
  CopasiWidget::setFramework(framework);

  switch (mFramework)
    {
      case 0:
        mpTblSpecies->showColumn(COL_ICONCENTRATION);
        mpTblSpecies->showColumn(COL_CONCENTRATION);
        mpTblSpecies->showColumn(COL_CRATE);

        mpTblSpecies->hideColumn(COL_INUMBER);
        mpTblSpecies->hideColumn(COL_NUMBER);
        mpTblSpecies->hideColumn(COL_NRATE);

        mpSpecieDM->setFlagConc(true);
        break;

      case 1:
        mpTblSpecies->hideColumn(COL_ICONCENTRATION);
        mpTblSpecies->hideColumn(COL_CONCENTRATION);
        mpTblSpecies->hideColumn(COL_CRATE);

        mpTblSpecies->showColumn(COL_INUMBER);
        mpTblSpecies->showColumn(COL_NUMBER);
        mpTblSpecies->showColumn(COL_NRATE);

        mpSpecieDM->setFlagConc(false);
        break;
    }
}

void CQSpeciesWidget::refreshCompartments()
{
  const CCopasiVector < CCompartment > & compartments =
    CCopasiRootContainer::getDatamodelList()->operator[](0).getModel()->getCompartments();
  mCompartments.clear();

  for (unsigned C_INT32 jj = 0; jj < compartments.size(); jj++)
    mCompartments.push_back(FROM_UTF8(compartments[jj].getObjectName()));

  mpCompartmentDelegate->setItems(-1, mCompartments);
}
<|endoftext|>