<commit_before>/*-------------------------------------------------------------------------
 *
 * table.cpp
 * file description
 *
 * Copyright(c) 2015, CMU
 *
 * /n-store/src/storage/table.cpp
 *
 *-------------------------------------------------------------------------
 */

#include "backend/storage/data_table.h"
#include "backend/storage/database.h"

#include "backend/common/exception.h"
#include "backend/index/index.h"
#include "backend/common/logger.h"

#include <mutex>

namespace peloton {
namespace storage {

DataTable::DataTable(catalog::Schema *schema,
                     AbstractBackend *backend,
                     std::string table_name,
                     oid_t table_oid,
                     size_t tuples_per_tilegroup)
: AbstractTable(table_oid, table_name, schema),
  backend(backend),
  tuples_per_tilegroup(tuples_per_tilegroup) {

  // Create a tile group.
  AddDefaultTileGroup();

}

DataTable::~DataTable() {

  // clean up tile groups
  oid_t tile_group_count = GetTileGroupCount();
  for(oid_t tile_group_itr = 0 ; tile_group_itr < tile_group_count; tile_group_itr++){
    auto tile_group = GetTileGroup(tile_group_itr);
    delete tile_group;
  }

  // clean up indices
  for (auto index : indexes) {
    delete index;
  }

  // clean up foreign keys
  for (auto foreign_key : foreign_keys) {
    delete foreign_key;
  }

  // table owns its backend
  // TODO: Should we really be doing this here?
  delete backend;

  // AbstractTable cleans up the schema
}

//===--------------------------------------------------------------------===//
// TUPLE OPERATIONS
//===--------------------------------------------------------------------===//

ItemPointer DataTable::InsertTuple(txn_id_t transaction_id,
                                   const storage::Tuple *tuple,
                                   bool update) {

  assert(tuple);

  // (A) Not NULL checks
  if (CheckNulls(tuple) == false) {
    throw ConstraintException("Not NULL constraint violated : " + tuple->GetInfo());
    return ItemPointer();
  }

  TileGroup *tile_group = nullptr;
  oid_t tuple_slot = INVALID_OID;
  oid_t tile_group_offset = INVALID_OID;

  while (tuple_slot == INVALID_OID) {

    // (B) Figure out last tile group
    {
      std::lock_guard<std::mutex> lock(table_mutex);
      tile_group_offset = GetTileGroupCount()-1;
      LOG_TRACE("Tile group offset :: %d \n", tile_group_offset);
    }

    // (C) Try to insert
    tile_group = GetTileGroup(tile_group_offset);
    tuple_slot = tile_group->InsertTuple(transaction_id, tuple);
    if (tuple_slot == INVALID_OID) {
      AddDefaultTileGroup();
    }
  }

  // Return Location
  ItemPointer location = ItemPointer(tile_group->GetTileGroupId(), tuple_slot);

  // Index checks and updates
  if (update == false) {
    if (TryInsertInIndexes(tuple, location) == false) {
      tile_group->ReclaimTuple(tuple_slot);
      LOG_WARN("Index constraint violated : %s\n", tuple->GetInfo().c_str());
      return INVALID_ITEMPOINTER;
    }
  }
  else {
    // just do a blind insert
    InsertInIndexes(tuple, location);
    return location;
  }

 return location;
}

void DataTable::InsertInIndexes(const storage::Tuple *tuple, ItemPointer location) {
  for (auto index : indexes) {
    auto index_schema = index->GetKeySchema();
    auto indexed_columns = index_schema->GetIndexedColumns();
    storage::Tuple *key = new storage::Tuple(index_schema, true);
    key->SetFromTuple(tuple, indexed_columns);

    if (index->InsertEntry(key, location) == false) {
      location = INVALID_ITEMPOINTER;
      LOG_ERROR("Failed to insert key into index : %s \n",  key->GetInfo().c_str());
      delete key;
      break;
    }

    delete key;
  }
}

bool DataTable::TryInsertInIndexes(const storage::Tuple *tuple, ItemPointer location) {

  int index_count = GetIndexCount();
  for (int index_itr = index_count - 1; index_itr >= 0; --index_itr) {
    auto index = GetIndex(index_itr);
    auto index_schema = index->GetKeySchema();
    auto indexed_columns = index_schema->GetIndexedColumns();
    storage::Tuple *key = new storage::Tuple(index_schema, true);
    key->SetFromTuple(tuple, indexed_columns);

    // No need to check if it does not have unique keys
    if(index->HasUniqueKeys() == false) {
      bool status = index->InsertEntry(key, location);
      if (status == true) {
        delete key;
        continue;
      }
    }

    // Check if key already exists
    if (index->Exists(key) == true) {
      LOG_ERROR("Failed to insert into index %s.%s [%s]",
                GetName().c_str(), index->GetName().c_str(),
                index->GetTypeName().c_str());
    }
    else {
      bool status = index->InsertEntry(key, location);
      if (status == true) {
        delete key;
        continue;
      }
    }

    // Undo insert in other indexes as well
    for (int prev_index_itr = index_itr + 1; prev_index_itr < index_count; ++prev_index_itr) {
      auto prev_index = GetIndex(prev_index_itr);
      prev_index->DeleteEntry(key);
    }

    delete key;
    return false;
  }

  return true;
}

void DataTable::DeleteInIndexes(const storage::Tuple *tuple) {
  for (auto index : indexes) {
    auto index_schema = index->GetKeySchema();
    auto indexed_columns = index_schema->GetIndexedColumns();
    storage::Tuple *key = new storage::Tuple(index_schema, true);
    key->SetFromTuple(tuple, indexed_columns);

    if (index->DeleteEntry(key) == false) {
      delete key;
      LOG_WARN("Failed to delete tuple from index %s . %s %s",
               GetName().c_str(), index->GetName().c_str(),
               index->GetTypeName().c_str());
    }

    delete key;
  }

}

bool DataTable::CheckNulls(const storage::Tuple *tuple) const {
  assert (schema->GetColumnCount() == tuple->GetColumnCount());

  oid_t column_count = schema->GetColumnCount();
  for (int column_itr = column_count - 1; column_itr >= 0; --column_itr) {
    if (tuple->IsNull(column_itr) && schema->AllowNull(column_itr) == false) {
      LOG_TRACE ("%d th attribute in the tuple was NULL. It is non-nullable attribute.", column_itr);
      return false;
    }
  }

  return true;
}

/**
 * @brief Increase the number of tuples in this table
 * @param amount amount to increase
 */
void DataTable::IncreaseNumberOfTuplesBy(const float amount){
  number_of_tuples += amount;
}

/**
 * @brief Decrease the number of tuples in this table
 * @param amount amount to decrease
 */
void DataTable::DecreaseNumberOfTuplesBy(const float amount){
  number_of_tuples -= amount;
}

/**
 * @brief Set the number of tuples in this table
 * @param num_tuples number of tuples
 */
void DataTable::SetNumberOfTuples(const float num_tuples){
  number_of_tuples = num_tuples;
}

/**
 * @brief Get the number of tuples in this table
 * @return number of tuples
 */
float DataTable::GetNumberOfTuples() const{
  return number_of_tuples;
}

//===--------------------------------------------------------------------===//
// TILE GROUP
//===--------------------------------------------------------------------===//

oid_t DataTable::AddDefaultTileGroup() {
  oid_t tile_group_id = INVALID_OID;

  std::vector<catalog::Schema> schemas;
  std::vector<std::vector<std::string> > column_names;

  tile_group_id = catalog::Manager::GetInstance().GetNextOid();
  schemas.push_back(*schema);

  TileGroup* tile_group = TileGroupFactory::GetTileGroup(database_oid, table_oid, tile_group_id,
                                                         this, backend,
                                                         schemas, tuples_per_tilegroup);

  LOG_TRACE("Trying to add a tile group \n");
  {
    std::lock_guard<std::mutex> lock(table_mutex);

    // Check if we actually need to allocate a tile group

    // (A) no tile groups in table
    if (tile_groups.empty()) {
      LOG_TRACE("Added first tile group \n");
      tile_groups.push_back(tile_group->GetTileGroupId());
      // add tile group metadata in locator
      catalog::Manager::GetInstance().SetLocation(tile_group_id, tile_group);
      LOG_TRACE("Recording tile group : %d \n", tile_group_id);
      return tile_group_id;
    }

    // (B) no slots in last tile group in table
    auto last_tile_group_offset = GetTileGroupCount() - 1;
    auto last_tile_group = GetTileGroup(last_tile_group_offset);

    oid_t active_tuple_count = last_tile_group->GetNextTupleSlot();
    oid_t allocated_tuple_count = last_tile_group->GetAllocatedTupleCount();
    if (active_tuple_count < allocated_tuple_count) {
      LOG_TRACE("Slot exists in last tile group :: %d %d \n", active_tuple_count, allocated_tuple_count);
      delete tile_group;
      return INVALID_OID;
    }

    LOG_TRACE("Added a tile group \n");
    tile_groups.push_back(tile_group->GetTileGroupId());

    // add tile group metadata in locator
    catalog::Manager::GetInstance().SetLocation(tile_group_id, tile_group);
    LOG_TRACE("Recording tile group : %d \n", tile_group_id);
  }

  return tile_group_id;
}

void DataTable::AddTileGroup(TileGroup *tile_group) {

  {
    std::lock_guard<std::mutex> lock(table_mutex);

    tile_groups.push_back(tile_group->GetTileGroupId());
    oid_t tile_group_id = tile_group->GetTileGroupId();

    // add tile group metadata in locator
    catalog::Manager::GetInstance().SetLocation(tile_group_id, tile_group);
    LOG_TRACE("Recording tile group : %d \n", tile_group_id);
  }

}

size_t DataTable::GetTileGroupCount() const {
  size_t size = tile_groups.size();
  return size;
}

TileGroup *DataTable::GetTileGroup(oid_t tile_group_id) const {
  assert(tile_group_id < GetTileGroupCount());

  auto& manager = catalog::Manager::GetInstance();
  storage::TileGroup *tile_group = static_cast<storage::TileGroup *>(manager.GetLocation(tile_groups[tile_group_id]));
  assert(tile_group);

  return tile_group;
}

std::ostream& operator<<(std::ostream& os, const DataTable& table) {
  os << "=====================================================\n";
  os << "TABLE :\n";

  oid_t tile_group_count = table.GetTileGroupCount();
  os << "Tile Group Count : " << tile_group_count << "\n";

  oid_t tuple_count = 0;
  for (oid_t tile_group_itr = 0 ; tile_group_itr < tile_group_count ; tile_group_itr++) {
    auto tile_group = table.GetTileGroup(tile_group_itr);
    auto tile_tuple_count = tile_group->GetNextTupleSlot();

    os << "Tile Group Id  : " << tile_group_itr << " Tuple Count : " << tile_tuple_count << "\n";
    os << (*tile_group);

    tuple_count += tile_tuple_count;
  }

  os << "Table Tuple Count :: " << tuple_count << "\n";

  os << "=====================================================\n";

  return os;
}

//===--------------------------------------------------------------------===//
// INDEX
//===--------------------------------------------------------------------===//

void DataTable::AddIndex(index::Index *index) {
  {
    std::lock_guard<std::mutex> lock(table_mutex);
    indexes.push_back(index);
  }

  // Update index stats
  auto index_type = index->GetIndexType();
  if(index_type == INDEX_CONSTRAINT_TYPE_PRIMARY_KEY) {
    has_primary_key = true;
  }
  else if(index_type == INDEX_CONSTRAINT_TYPE_UNIQUE) {
    unique_constraint_count++;
  }

}

index::Index* DataTable::GetIndexWithOid(const oid_t index_oid) const {
  for(auto index : indexes)
    if(index->GetOid() == index_oid)
      return index;

  return nullptr;
}

void DataTable::DropIndexWithOid(const oid_t index_id) {
  {
    std::lock_guard<std::mutex> lock(table_mutex);

    oid_t index_offset = 0;
    for(auto index : indexes) {
      if(index->GetOid() == index_id)
        break;
      index_offset++;
    }
    assert(index_offset < indexes.size());

    // Drop the index
    indexes.erase(indexes.begin() + index_offset);
  }
}

index::Index *DataTable::GetIndex(const oid_t index_offset) const {
  assert(index_offset < indexes.size());
  auto index = indexes.at(index_offset);
  return index;
}

oid_t DataTable::GetIndexCount() const {
  return indexes.size();
}

//===--------------------------------------------------------------------===//
// FOREIGN KEYS
//===--------------------------------------------------------------------===//

void DataTable::AddForeignKey(catalog::ForeignKey *key) {
  {
    std::lock_guard<std::mutex> lock(table_mutex);
    catalog::Schema * schema = this->GetSchema();
    catalog::Constraint constraint( CONSTRAINT_TYPE_FOREIGN, key->GetConstraintName());
    constraint.SetForeignKeyListOffset(GetForeignKeyCount());
    for( auto fk_column : key->GetFKColumnNames()){
      schema->AddConstraint(fk_column, constraint);
    }
    //TODO :: We need this one..
    catalog::ForeignKey* fk = new catalog::ForeignKey( *key );
    foreign_keys.push_back(fk);
  }
}

catalog::ForeignKey *DataTable::GetForeignKey(const oid_t key_offset) const {
  catalog::ForeignKey *key = nullptr;
  key = foreign_keys.at(key_offset);
  return key;
}

void DataTable::DropForeignKey(const oid_t key_offset) {
  {
    std::lock_guard<std::mutex> lock(table_mutex);
    assert(key_offset < foreign_keys.size());
    foreign_keys.erase(foreign_keys.begin() + key_offset);
  }
}

oid_t DataTable::GetForeignKeyCount() const {
  return foreign_keys.size();
}

} // End storage namespace
} // End peloton namespace

<commit_msg>Increase/Decrease number of tuples for table and index<commit_after>/*-------------------------------------------------------------------------
 *
 * table.cpp
 * file description
 *
 * Copyright(c) 2015, CMU
 *
 * /n-store/src/storage/table.cpp
 *
 *-------------------------------------------------------------------------
 */

#include "backend/storage/data_table.h"
#include "backend/storage/database.h"

#include "backend/common/exception.h"
#include "backend/index/index.h"
#include "backend/common/logger.h"

#include <mutex>

namespace peloton {
namespace storage {

DataTable::DataTable(catalog::Schema *schema,
                     AbstractBackend *backend,
                     std::string table_name,
                     oid_t table_oid,
                     size_t tuples_per_tilegroup)
: AbstractTable(table_oid, table_name, schema),
  backend(backend),
  tuples_per_tilegroup(tuples_per_tilegroup) {

  // Create a tile group.
  AddDefaultTileGroup();

}

DataTable::~DataTable() {

  // clean up tile groups
  oid_t tile_group_count = GetTileGroupCount();
  for(oid_t tile_group_itr = 0 ; tile_group_itr < tile_group_count; tile_group_itr++){
    auto tile_group = GetTileGroup(tile_group_itr);
    delete tile_group;
  }

  // clean up indices
  for (auto index : indexes) {
    delete index;
  }

  // clean up foreign keys
  for (auto foreign_key : foreign_keys) {
    delete foreign_key;
  }

  // table owns its backend
  // TODO: Should we really be doing this here?
  delete backend;

  // AbstractTable cleans up the schema
}

//===--------------------------------------------------------------------===//
// TUPLE OPERATIONS
//===--------------------------------------------------------------------===//

ItemPointer DataTable::InsertTuple(txn_id_t transaction_id,
                                   const storage::Tuple *tuple,
                                   bool update) {

  assert(tuple);

  // Increase the table's number of tuples by 1
  IncreaseNumberOfTuplesBy(1);
  // Increase the indexes' number of tuples by 1 as well
  for(auto index : indexes)
    index->IncreaseNumberOfTuplesBy(1);

  // (A) Not NULL checks
  if (CheckNulls(tuple) == false) {
    throw ConstraintException("Not NULL constraint violated : " + tuple->GetInfo());
    return ItemPointer();
  }

  TileGroup *tile_group = nullptr;
  oid_t tuple_slot = INVALID_OID;
  oid_t tile_group_offset = INVALID_OID;

  while (tuple_slot == INVALID_OID) {

    // (B) Figure out last tile group
    {
      std::lock_guard<std::mutex> lock(table_mutex);
      tile_group_offset = GetTileGroupCount()-1;
      LOG_TRACE("Tile group offset :: %d \n", tile_group_offset);
    }

    // (C) Try to insert
    tile_group = GetTileGroup(tile_group_offset);
    tuple_slot = tile_group->InsertTuple(transaction_id, tuple);
    if (tuple_slot == INVALID_OID) {
      AddDefaultTileGroup();
    }
  }

  // Return Location
  ItemPointer location = ItemPointer(tile_group->GetTileGroupId(), tuple_slot);

  // Index checks and updates
  if (update == false) {
    if (TryInsertInIndexes(tuple, location) == false) {
      tile_group->ReclaimTuple(tuple_slot);
      LOG_WARN("Index constraint violated : %s\n", tuple->GetInfo().c_str());
      return INVALID_ITEMPOINTER;
    }
  }
  else {
    // just do a blind insert
    InsertInIndexes(tuple, location);
    return location;
  }

 return location;
}

void DataTable::InsertInIndexes(const storage::Tuple *tuple, ItemPointer location) {
  for (auto index : indexes) {
    auto index_schema = index->GetKeySchema();
    auto indexed_columns = index_schema->GetIndexedColumns();
    storage::Tuple *key = new storage::Tuple(index_schema, true);
    key->SetFromTuple(tuple, indexed_columns);

    if (index->InsertEntry(key, location) == false) {
      location = INVALID_ITEMPOINTER;
      LOG_ERROR("Failed to insert key into index : %s \n",  key->GetInfo().c_str());
      delete key;
      break;
    }

    delete key;
  }
}

bool DataTable::TryInsertInIndexes(const storage::Tuple *tuple, ItemPointer location) {

  int index_count = GetIndexCount();
  for (int index_itr = index_count - 1; index_itr >= 0; --index_itr) {
    auto index = GetIndex(index_itr);
    auto index_schema = index->GetKeySchema();
    auto indexed_columns = index_schema->GetIndexedColumns();
    storage::Tuple *key = new storage::Tuple(index_schema, true);
    key->SetFromTuple(tuple, indexed_columns);

    // No need to check if it does not have unique keys
    if(index->HasUniqueKeys() == false) {
      bool status = index->InsertEntry(key, location);
      if (status == true) {
        delete key;
        continue;
      }
    }

    // Check if key already exists
    if (index->Exists(key) == true) {
      LOG_ERROR("Failed to insert into index %s.%s [%s]",
                GetName().c_str(), index->GetName().c_str(),
                index->GetTypeName().c_str());
    }
    else {
      bool status = index->InsertEntry(key, location);
      if (status == true) {
        delete key;
        continue;
      }
    }

    // Undo insert in other indexes as well
    for (int prev_index_itr = index_itr + 1; prev_index_itr < index_count; ++prev_index_itr) {
      auto prev_index = GetIndex(prev_index_itr);
      prev_index->DeleteEntry(key);
    }

    delete key;
    return false;
  }

  return true;
}

void DataTable::DeleteInIndexes(const storage::Tuple *tuple) {
  for (auto index : indexes) {
    auto index_schema = index->GetKeySchema();
    auto indexed_columns = index_schema->GetIndexedColumns();
    storage::Tuple *key = new storage::Tuple(index_schema, true);
    key->SetFromTuple(tuple, indexed_columns);

    if (index->DeleteEntry(key) == false) {
      delete key;
      LOG_WARN("Failed to delete tuple from index %s . %s %s",
               GetName().c_str(), index->GetName().c_str(),
               index->GetTypeName().c_str());
    }

    delete key;

    // Decrease the indexes' number of tuples by 1
    for(auto index : indexes)
      index->DecreaseNumberOfTuplesBy(1);
  }
  // Decrease the table's number of tuples by 1 as well
  DecreaseNumberOfTuplesBy(1);
}

bool DataTable::CheckNulls(const storage::Tuple *tuple) const {
  assert (schema->GetColumnCount() == tuple->GetColumnCount());

  oid_t column_count = schema->GetColumnCount();
  for (int column_itr = column_count - 1; column_itr >= 0; --column_itr) {
    if (tuple->IsNull(column_itr) && schema->AllowNull(column_itr) == false) {
      LOG_TRACE ("%d th attribute in the tuple was NULL. It is non-nullable attribute.", column_itr);
      return false;
    }
  }

  return true;
}

/**
 * @brief Increase the number of tuples in this table
 * @param amount amount to increase
 */
void DataTable::IncreaseNumberOfTuplesBy(const float amount){
  number_of_tuples += amount;
}

/**
 * @brief Decrease the number of tuples in this table
 * @param amount amount to decrease
 */
void DataTable::DecreaseNumberOfTuplesBy(const float amount){
  number_of_tuples -= amount;
}

/**
 * @brief Set the number of tuples in this table
 * @param num_tuples number of tuples
 */
void DataTable::SetNumberOfTuples(const float num_tuples){
  number_of_tuples = num_tuples;
}

/**
 * @brief Get the number of tuples in this table
 * @return number of tuples
 */
float DataTable::GetNumberOfTuples() const{
  return number_of_tuples;
}

//===--------------------------------------------------------------------===//
// TILE GROUP
//===--------------------------------------------------------------------===//

oid_t DataTable::AddDefaultTileGroup() {
  oid_t tile_group_id = INVALID_OID;

  std::vector<catalog::Schema> schemas;
  std::vector<std::vector<std::string> > column_names;

  tile_group_id = catalog::Manager::GetInstance().GetNextOid();
  schemas.push_back(*schema);

  TileGroup* tile_group = TileGroupFactory::GetTileGroup(database_oid, table_oid, tile_group_id,
                                                         this, backend,
                                                         schemas, tuples_per_tilegroup);

  LOG_TRACE("Trying to add a tile group \n");
  {
    std::lock_guard<std::mutex> lock(table_mutex);

    // Check if we actually need to allocate a tile group

    // (A) no tile groups in table
    if (tile_groups.empty()) {
      LOG_TRACE("Added first tile group \n");
      tile_groups.push_back(tile_group->GetTileGroupId());
      // add tile group metadata in locator
      catalog::Manager::GetInstance().SetLocation(tile_group_id, tile_group);
      LOG_TRACE("Recording tile group : %d \n", tile_group_id);
      return tile_group_id;
    }

    // (B) no slots in last tile group in table
    auto last_tile_group_offset = GetTileGroupCount() - 1;
    auto last_tile_group = GetTileGroup(last_tile_group_offset);

    oid_t active_tuple_count = last_tile_group->GetNextTupleSlot();
    oid_t allocated_tuple_count = last_tile_group->GetAllocatedTupleCount();
    if (active_tuple_count < allocated_tuple_count) {
      LOG_TRACE("Slot exists in last tile group :: %d %d \n", active_tuple_count, allocated_tuple_count);
      delete tile_group;
      return INVALID_OID;
    }

    LOG_TRACE("Added a tile group \n");
    tile_groups.push_back(tile_group->GetTileGroupId());

    // add tile group metadata in locator
    catalog::Manager::GetInstance().SetLocation(tile_group_id, tile_group);
    LOG_TRACE("Recording tile group : %d \n", tile_group_id);
  }

  return tile_group_id;
}

void DataTable::AddTileGroup(TileGroup *tile_group) {

  {
    std::lock_guard<std::mutex> lock(table_mutex);

    tile_groups.push_back(tile_group->GetTileGroupId());
    oid_t tile_group_id = tile_group->GetTileGroupId();

    // add tile group metadata in locator
    catalog::Manager::GetInstance().SetLocation(tile_group_id, tile_group);
    LOG_TRACE("Recording tile group : %d \n", tile_group_id);
  }

}

size_t DataTable::GetTileGroupCount() const {
  size_t size = tile_groups.size();
  return size;
}

TileGroup *DataTable::GetTileGroup(oid_t tile_group_id) const {
  assert(tile_group_id < GetTileGroupCount());

  auto& manager = catalog::Manager::GetInstance();
  storage::TileGroup *tile_group = static_cast<storage::TileGroup *>(manager.GetLocation(tile_groups[tile_group_id]));
  assert(tile_group);

  return tile_group;
}

std::ostream& operator<<(std::ostream& os, const DataTable& table) {
  os << "=====================================================\n";
  os << "TABLE :\n";

  oid_t tile_group_count = table.GetTileGroupCount();
  os << "Tile Group Count : " << tile_group_count << "\n";

  oid_t tuple_count = 0;
  for (oid_t tile_group_itr = 0 ; tile_group_itr < tile_group_count ; tile_group_itr++) {
    auto tile_group = table.GetTileGroup(tile_group_itr);
    auto tile_tuple_count = tile_group->GetNextTupleSlot();

    os << "Tile Group Id  : " << tile_group_itr << " Tuple Count : " << tile_tuple_count << "\n";
    os << (*tile_group);

    tuple_count += tile_tuple_count;
  }

  os << "Table Tuple Count :: " << tuple_count << "\n";

  os << "=====================================================\n";

  return os;
}

//===--------------------------------------------------------------------===//
// INDEX
//===--------------------------------------------------------------------===//

void DataTable::AddIndex(index::Index *index) {
  {
    std::lock_guard<std::mutex> lock(table_mutex);
    indexes.push_back(index);
  }

  // Update index stats
  auto index_type = index->GetIndexType();
  if(index_type == INDEX_CONSTRAINT_TYPE_PRIMARY_KEY) {
    has_primary_key = true;
  }
  else if(index_type == INDEX_CONSTRAINT_TYPE_UNIQUE) {
    unique_constraint_count++;
  }

}

index::Index* DataTable::GetIndexWithOid(const oid_t index_oid) const {
  for(auto index : indexes)
    if(index->GetOid() == index_oid)
      return index;

  return nullptr;
}

void DataTable::DropIndexWithOid(const oid_t index_id) {
  {
    std::lock_guard<std::mutex> lock(table_mutex);

    oid_t index_offset = 0;
    for(auto index : indexes) {
      if(index->GetOid() == index_id)
        break;
      index_offset++;
    }
    assert(index_offset < indexes.size());

    // Drop the index
    indexes.erase(indexes.begin() + index_offset);
  }
}

index::Index *DataTable::GetIndex(const oid_t index_offset) const {
  assert(index_offset < indexes.size());
  auto index = indexes.at(index_offset);
  return index;
}

oid_t DataTable::GetIndexCount() const {
  return indexes.size();
}

//===--------------------------------------------------------------------===//
// FOREIGN KEYS
//===--------------------------------------------------------------------===//

void DataTable::AddForeignKey(catalog::ForeignKey *key) {
  {
    std::lock_guard<std::mutex> lock(table_mutex);
    catalog::Schema * schema = this->GetSchema();
    catalog::Constraint constraint( CONSTRAINT_TYPE_FOREIGN, key->GetConstraintName());
    constraint.SetForeignKeyListOffset(GetForeignKeyCount());
    for( auto fk_column : key->GetFKColumnNames()){
      schema->AddConstraint(fk_column, constraint);
    }
    //TODO :: We need this one..
    catalog::ForeignKey* fk = new catalog::ForeignKey( *key );
    foreign_keys.push_back(fk);
  }
}

catalog::ForeignKey *DataTable::GetForeignKey(const oid_t key_offset) const {
  catalog::ForeignKey *key = nullptr;
  key = foreign_keys.at(key_offset);
  return key;
}

void DataTable::DropForeignKey(const oid_t key_offset) {
  {
    std::lock_guard<std::mutex> lock(table_mutex);
    assert(key_offset < foreign_keys.size());
    foreign_keys.erase(foreign_keys.begin() + key_offset);
  }
}

oid_t DataTable::GetForeignKeyCount() const {
  return foreign_keys.size();
}

} // End storage namespace
} // End peloton namespace

<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2015 kellymorse for more information contact (khelifa.baizid@mines-douai.fr, baizid.khelifa@gmail.com)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#include <ros/ros.h>
#include <tf/transform_broadcaster.h>
#include <turtlesim/Pose.h>
#include <geometry_msgs/PoseStamped.h>
#include <nav_msgs/Odometry.h>

//odometry topic name
std::string odometry_topic_name;
//position for the laser in base_link frame
double x_laser, y_laser, z_laser;
//orientation for the laser in base_link frame
double roll_laser, pitch_laser, yaw_laser;
void odometryCallback(const nav_msgs::Odometry::ConstPtr& msg){
  //transform from the base_link to odom frame
  static tf::TransformBroadcaster br;
  tf::Transform transform;
  transform.setOrigin( tf::Vector3(msg->pose.pose.position.x, msg->pose.pose.position.y, 0.0) );
  tf::Quaternion q(0,0,msg->pose.pose.orientation.z,msg->pose.pose.orientation.w);

  transform.setRotation(q);
  br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "/odom", "/base_link"));

  //transform from the laser to base_link frame
  static tf::TransformBroadcaster br2;
  tf::Transform transform2;
  transform2.setOrigin(tf::Vector3(x_laser, y_laser, z_laser) );
  tf::Quaternion q2;
  q2.setRPY(roll_laser, pitch_laser, yaw_laser);
  transform2.setRotation(q2);
  br2.sendTransform(tf::StampedTransform(transform2, ros::Time::now(), "/base_link", "/laser"));

}

int main(int argc, char** argv){
  ros::init(argc, argv, "turtlebot_tf");

  ros::NodeHandle nh;
  ros::NodeHandle private_nh("~");

  //we get the name of the odometry topic
  private_nh.getParam("odometry_topic_name", odometry_topic_name);

  //we get paramaters that define the pose of the URG
  //position
  x_laser=0.0;  y_laser=0.0;  z_laser=0.0;
  private_nh.getParam("x_laser", x_laser);private_nh.getParam("y_laser", y_laser);private_nh.getParam("z_laser", z_laser);

  //orientation
  roll_laser=0.0;  pitch_laser=0.0;  yaw_laser=0.0;
  private_nh.getParam("roll_laser", roll_laser);private_nh.getParam("pitch_laser", pitch_laser);private_nh.getParam("yaw_laser", yaw_laser);

  //we define the subscriber to odometry
  ros::Subscriber sub = nh.subscribe<nav_msgs::Odometry>(odometry_topic_name, 10, &odometryCallback);

  std::cout<<"***************[ STARING turtlebot_tf_node]***************** "std::endl;

  ros::spin();
  return 0;
};
<commit_msg>Update turtlebot_tf_node.cpp<commit_after>/*
The MIT License (MIT)

Copyright (c) 2015 kellymorse for more information contact (khelifa.baizid@mines-douai.fr, baizid.khelifa@gmail.com)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#include <ros/ros.h>
#include <tf/transform_broadcaster.h>
#include <turtlesim/Pose.h>
#include <geometry_msgs/PoseStamped.h>
#include <nav_msgs/Odometry.h>

//odometry topic name
std::string odometry_topic_name;
//position for the laser in base_link frame
double x_laser, y_laser, z_laser;
//orientation for the laser in base_link frame
double roll_laser, pitch_laser, yaw_laser;
void odometryCallback(const nav_msgs::Odometry::ConstPtr& msg){
  //transform from the base_link to odom frame
  static tf::TransformBroadcaster br;
  tf::Transform transform;
  transform.setOrigin( tf::Vector3(msg->pose.pose.position.x, msg->pose.pose.position.y, 0.0) );
  tf::Quaternion q(0,0,msg->pose.pose.orientation.z,msg->pose.pose.orientation.w);

  transform.setRotation(q);
  br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "/odom", "/base_link"));

  //transform from the laser to base_link frame
  static tf::TransformBroadcaster br2;
  tf::Transform transform2;
  transform2.setOrigin(tf::Vector3(x_laser, y_laser, z_laser) );
  tf::Quaternion q2;
  q2.setRPY(roll_laser, pitch_laser, yaw_laser);
  transform2.setRotation(q2);
  br2.sendTransform(tf::StampedTransform(transform2, ros::Time::now(), "/base_link", "/laser"));

}

int main(int argc, char** argv){
  ros::init(argc, argv, "turtlebot_tf");

  ros::NodeHandle nh;
  ros::NodeHandle private_nh("~");

  //we get the name of the odometry topic
  private_nh.getParam("odometry_topic_name", odometry_topic_name);

  //we get paramaters that define the pose of the URG
  //position
  x_laser=0.0;  y_laser=0.0;  z_laser=0.0;
  private_nh.getParam("x_laser", x_laser);private_nh.getParam("y_laser", y_laser);private_nh.getParam("z_laser", z_laser);

  //orientation
  roll_laser=0.0;  pitch_laser=0.0;  yaw_laser=0.0;
  private_nh.getParam("roll_laser", roll_laser);private_nh.getParam("pitch_laser", pitch_laser);private_nh.getParam("yaw_laser", yaw_laser);

  //we define the subscriber to odometry
  ros::Subscriber sub = nh.subscribe<nav_msgs::Odometry>(odometry_topic_name, 10, &odometryCallback);

  std::cout<<"***************[ STARING turtlebot_tf_node]***************** "<<std::endl;

  ros::spin();
  return 0;
};
<|endoftext|>


<commit_before>#include "ros/ros.h"
#include "geometry_msgs/Twist.h"
#include "turtlesim/Pose.h"
#include <sstream>

using namespace std;

ros::Publisher velocity_publisher;
ros::Subscriber pose_subscriber;
turtlesim::Pose turtlesim_pose;

const double PI = 3.14159265359;

void move(double speed, double distance, bool isForward);
void rotate(double angular_speed, double angle, bool cloclwise);
void poseCallback(const turtlesim::Pose::ConstPtr & pose_message);
//void moveGoal(turtlesim::Pose goal_pose, double distance_tolerance);

int main(int argc, char **argv)
{
    // Initiate new ROS node named "robosys_turtle"
    ros::init(argc, argv, "robosys_turtle");
    ros::NodeHandle n;
    double speed, angular_speed;
    double distance, angle;
    bool isForward, clockwise;

    velocity_publisher = n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel", 1000);
    pose_subscriber = n.subscribe("/turtle1/pose", 10, poseCallback);
    ros::Rate loop_rate(0.5);

        for(int i = 0; i < 10; i++){

        rotate(2, 2/PI, 0);
        move(3, 10, 1);

    }

    ros::spin();

    return 0;
}
void move(double speed, double distance, bool isForward)
{
    geometry_msgs::Twist vel_msg;
    //set a random linear velocity in the x-axis
    if (isForward)
        vel_msg.linear.x =abs(speed);
    else
        vel_msg.linear.x =-abs(speed);
    vel_msg.linear.y =0;
    vel_msg.linear.z =0;
    //set a random angular velocity in the y-axis
    vel_msg.angular.x = 0;
    vel_msg.angular.y = 0;
    vel_msg.angular.z =0;

    double t0 = ros::Time::now().toSec();
    double current_distance = 0.0;
    ros::Rate loop_rate(100);
    do{
        velocity_publisher.publish(vel_msg);
        double t1 = ros::Time::now().toSec();
        current_distance = speed * (t1-t0);
        ros::spinOnce();
        loop_rate.sleep();

    }while(current_distance<distance);

    vel_msg.linear.x =0;
    velocity_publisher.publish(vel_msg);
}

void rotate (double angular_speed, double relative_angle, bool clockwise)
{
    geometry_msgs::Twist vel_msg;
    //set a random linear velocity in the x-axis
    vel_msg.linear.x =0;
    vel_msg.linear.y =0;
    vel_msg.linear.z =0;
    //set a random angular velocity in the y-axis
    vel_msg.angular.x = 0;
    vel_msg.angular.y = 0;
    if (clockwise)
        vel_msg.angular.z =-abs(angular_speed);
    else
         vel_msg.angular.z =abs(angular_speed);

    double t0 = ros::Time::now().toSec();
    double current_angle = 0.0;
    ros::Rate loop_rate(1000);
    do{
        velocity_publisher.publish(vel_msg);
        double t1 = ros::Time::now().toSec();
        current_angle = angular_speed * (t1-t0);
        ros::spinOnce();
        loop_rate.sleep();
        //cout<<(t1-t0)<<", "<<current_angle <<", "<<relative_angle<<endl;
    }while(current_angle<relative_angle);
    vel_msg.angular.z =0;
    velocity_publisher.publish(vel_msg);
}

/*
void moveGoal(turtlesim::Pose goal_pose, double distance_tolerance)
{
    //We implement a Proportional Controller. We need to go from (x,y) to (x',y'). Then, linear velocity v' = K ((x'-x)^2 + (y'-y)^2)^0.5 where K is the constant and ((x'-x)^2 + (y'-y)^2)^0.5 is the Euclidian distance. The steering angle theta = tan^-1(y'-y)/(x'-x) is the angle between these 2 points.
    geometry_msgs::Twist vel_msg;

    ros::Rate loop_rate(10);
    do{
        //linear velocity
        vel_msg.linear.x = 1.5*getDistance(turtlesim_pose.x, turtlesim_pose.y, goal_pose.x, goal_pose.y);
        vel_msg.linear.y = 0;
        vel_msg.linear.z = 0;
        //angular velocity
        vel_msg.angular.x = 0;
        vel_msg.angular.y = 0;
        vel_msg.angular.z = 4*(atan2(goal_pose.y - turtlesim_pose.y, goal_pose.x - turtlesim_pose.x)-turtlesim_pose.theta);

        velocity_publisher.publish(vel_msg);

        ros::spinOnce();
        loop_rate.sleep();

    }while(getDistance(turtlesim_pose.x, turtlesim_pose.y, goal_pose.x, goal_pose.y)>distance_tolerance);
    cout<<"end move goal"<<endl;
    vel_msg.linear.x = 0;
    vel_msg.angular.z = 0;
    velocity_publisher.publish(vel_msg);

}*/
void poseCallback(const turtlesim::Pose::ConstPtr & pose_message)
{
    turtlesim_pose.x=pose_message->x;
    turtlesim_pose.y=pose_message->y;    turtlesim_pose.theta=pose_message->theta;
}
<commit_msg>Revert "test2"<commit_after>
<|endoftext|>


<commit_before>#include "bitmapimage.h"

BitmapImage::BitmapImage()
{
    m_Image = NULL;
    visible = true;
    m_ScaleFactor = 1.0;
    qDebug() << "Image drawn!" << endl;
    m_ScaleFactorInv = 1.0;
}

BitmapImage::BitmapImage(const BitmapImage &image)
{
    m_pixmap = image.m_pixmap;
    boundaries = image.boundaries;
    m_Color = image.m_Color;
    m_ScaleFactor = 1.0;
    m_ScaleFactorInv = 1.0;
    visible = true;
}

BitmapImage::BitmapImage(Object *parent, QRect boundaries, QColor color)
{
    myParent = parent;
    this->boundaries = boundaries;
    m_Image = new QImage(boundaries.size(), QImage::Format_ARGB32_Premultiplied);
    m_Image->fill(color.rgba());
    m_ScaleFactor = 1.0;
    m_ScaleFactorInv = 1.0;
    visible = true;
}

BitmapImage::BitmapImage(Object *parent, QRect boundaries, QImage image)
{
    myParent = parent;
    this->boundaries = boundaries;
    m_Image = new QImage(image);
    if(m_Image->width() != boundaries.width() && m_Image->height() != boundaries.height()) qDebug() << "Error 0001: Failed to load Image" << endl;
    visible = true;
    m_ScaleFactor = 1.0;
    m_ScaleFactorInv = 1.0;
}

BitmapImage::BitmapImage(QRect boundaries, QColor color)
{
    this->boundaries = boundaries;
    QPixmap temp(boundaries.width(), boundaries.height());
    temp.fill(color);
    QPainter painter(&temp);
    if(!temp.isNull())
    {
        painter.drawPixmap(0, 0, temp);
    }
    painter.end();
    m_pixmap = temp;
    visible = true;
    m_ScaleFactor = 1.0;
    m_ScaleFactorInv = 1.0;
}

BitmapImage::BitmapImage(QRect boundaries, QPixmap pixMap)
{
    this->boundaries = boundaries;
    m_pixmap = pixMap;
    visible = true;
    m_ScaleFactor = 1.0;
    m_ScaleFactorInv = 1.0;
}

void BitmapImage::paintImage(QPainter &painter)
{
    painter.drawPixmap(0, 0, m_pixmap);
}

void BitmapImage::paintImage(QPainterPath painterPath, Brush brush)
{
    QPainter painter(&m_pixmap);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setBrush(Qt::NoBrush);
    QPen copyPen = brush.getPen();
    if(brush.getSize() > 0)
    {
        copyPen.setBrush(brush.getBrush());
        copyPen.setWidth(brush.getSize());
        painter.setPen(copyPen);
    }else{
        copyPen.setBrush(Qt::NoBrush);
        copyPen.setWidth(0);
        painter.setPen(copyPen);
    }
    painter.drawPath(painterPath);
}

void BitmapImage::paintImage(QPoint point, Brush brush){
    int brushWidth = brush.getSize() + (brush.getPressureVal() * brush.getTransferSize());
    brushWidth += m_ScaleFactor;
    QImage stencilBase = brush.getStencil().toImage();
    stencilBase.invertPixels(QImage::InvertRgb);
    stencilBase.createAlphaMask();
    stencilBase.convertToFormat(QImage::Format_ARGB32, Qt::AutoColor);
    QImage stencilImage = QImage(stencilBase);
    QColor color = brush.getColor();
    color.setAlpha(brush.getOpacity() + (brush.getPressureVal() * brush.getTransferOpacity()));
    stencilImage.fill(color);
    QPixmap stencil = QPixmap::fromImage(stencilImage.scaled(brushWidth, brushWidth, Qt::IgnoreAspectRatio, Qt::FastTransformation));
    QPainter p(&m_pixmap);
    p.setRenderHint(QPainter::Antialiasing);
    p.drawPixmap(QPoint(point.x() - stencil.width()/2, point.y() - stencil.height()/2), stencil);
}

void BitmapImage::paintImage(QVector<QPointF> pointInfo, Brush brush)
{
    int brushWidth = brush.getSize() + (brush.getPressureVal() * brush.getTransferSize());
    brushWidth *= m_ScaleFactor;
    /*-Prepare Stencil-*/
    QImage stencilBase = brush.getStencil().toImage();
    stencilBase.invertPixels(QImage::InvertRgb);
    stencilBase.createAlphaMask();
    stencilBase.convertToFormat(QImage::Format_ARGB32, Qt::AutoColor);
    QImage stencilImage = QImage(stencilBase);
    QColor color = brush.getColor();
    color.setAlpha(brush.getOpacity() + (brush.getPressureVal() * brush.getTransferOpacity()));
    stencilImage.fill(color);
    stencilImage.setAlphaChannel(stencilBase);
    QPixmap stencil = QPixmap::fromImage(stencilImage.scaled(brushWidth, brushWidth, Qt::IgnoreAspectRatio, Qt::FastTransformation));

    QPainter painter(&m_pixmap);
    painter.setRenderHint(QPainter::Antialiasing);

    /*Calculate incrementation value*/
    qreal inc = 0.01;

    QPainterPath path;
    path.moveTo(pointInfo.first());
    path.lineTo(pointInfo.last());

    inc = getIncrement(pointInfo.first(), pointInfo.last());

    /* Automatically adjust the incrementing value */
    for(qreal i = 0; i < 1; i+= inc * brush.getSpacing()){
        painter.drawPixmap(QPoint(path.pointAtPercent(i).x() - stencil.width()/2, path.pointAtPercent(i).y() - stencil.width()/2), stencil);
    }

    /*-Old Method-*/

//    QPointF point, drawPoint;
//    point = pointInfo.last() - pointInfo.first();
//    int length = point.manhattanLength();
//    double xInc, yInc;
//    xInc = point.x() / (double)length;
//    yInc = point.y() / (double)length;
//    drawPoint = pointInfo.first();

//    for(int i = 0; i < length; i++){
//        if(drawPoint != pointInfo.last() || drawPoint != pointInfo.first()){
//            drawPoint.setX(drawPoint.x() + (xInc / (double)brush.getSpacing() ));
//            drawPoint.setY(drawPoint.y() + (yInc / (double)brush.getSpacing() ));
//            painter.drawPixmap(QPoint(drawPoint.x() - stencil.width() / 2, drawPoint.y() - stencil.height()/2) / m_ScaleFactor, stencil);
//        }
//    }
}

void BitmapImage::paintImage(QVector<QPointF> pointInfo, Brush brush, qreal tabPress, int amt)
{
    int brushWidth = brush.getSize() + (amt * tabPress);
    /*-Prepare Stencil-*/
    QImage stencilBase = brush.getStencil().toImage();
    stencilBase.invertPixels(QImage::InvertRgb);
    stencilBase.createAlphaMask();
    stencilBase.convertToFormat(QImage::Format_RGB888, Qt::AutoColor);
    QImage stencilImage = QImage(stencilBase);
    QColor color = brush.getColor();
    color.setAlpha(brush.getOpacity());
    stencilImage.fill(color);
    stencilImage.setAlphaChannel(stencilBase);
    QPixmap stencil = QPixmap::fromImage(stencilImage.scaled(brushWidth, brushWidth, Qt::IgnoreAspectRatio, Qt::FastTransformation));

    QPainter painter(&m_pixmap);
    painter.setRenderHint(QPainter::Antialiasing);

    QPointF point, drawPoint;
    point = pointInfo.last() - pointInfo.first();
    int length = point.manhattanLength();
    double xInc, yInc;
    xInc = point.x() / length;
    yInc = point.y() / length;
    drawPoint = pointInfo.first();
    for(int i = 0; i < length; i++){
        drawPoint.setX(drawPoint.x() + (xInc * brush.getSpacing() ));
        drawPoint.setY(drawPoint.y() + (yInc * brush.getSpacing() ));
        painter.drawPixmap(QPoint(drawPoint.x() - stencil.width() / 2, drawPoint.y() - stencil.height()/2), stencil);
    }
}

void BitmapImage::fillImage(QPoint point, Brush brush){

    QImage img = m_pixmap.toImage();
    QRgb oldColor = img.pixel(point);
    QRgb newColor = brush.getColor().rgb();
    fillRecurs(point, img, oldColor, newColor);

    m_pixmap = QPixmap::fromImage(img);
}

void BitmapImage::scale(double s){
    m_ScaleFactor = s;
}

void BitmapImage::commitChanges(QPoint drawPoint, QPixmap pixmap){
    QPainter p(&m_pixmap);
    p.drawPixmap(drawPoint, pixmap);
}

/*
*
*   Implementation of this function is as close to the version in EasyPaint.
*
*/
void BitmapImage::fillRecurs(QPoint pos, QImage& img, QRgb oldColor, QRgb newColor){
    int temp_x(pos.x());
    int left_x = 0;
    while(true){
        if(img.pixel(temp_x, pos.y()) != oldColor){
            break;
        }
        img.setPixel(temp_x, pos.y(), newColor);
        if(temp_x > 0){
            temp_x--;
            left_x = temp_x;
        }else{
            break;
        }
    }

    int right_x(0);
    temp_x = pos.x() + 1;
    while(true){
        if(img.pixel(temp_x, pos.y()) != oldColor){
            break;
        }
        img.setPixel(temp_x, pos.y(), newColor);
        if(temp_x < img.width() -1){
            temp_x++;
            right_x = temp_x;
        }else{
            break;
        }
    }

    for(int x = left_x+1; x < right_x; x++){
        if(pos.y() < 1 || pos.y() >= img.height() - 1){
            break;
        }
        if(right_x > img.width()){ break; }
        QRgb currentColor = img.pixel(x, pos.y()-1);
        if(currentColor == oldColor && currentColor != newColor){
            fillRecurs(QPoint(x, pos.y() -1), img, oldColor, newColor);
        }
        currentColor = img.pixel(x, pos.y() + 1);
        if(currentColor == oldColor && currentColor != newColor){
            fillRecurs(QPoint(x, pos.y() + 1), img, oldColor, newColor);
        }
    }
}

void BitmapImage::cutImgOp(QRect rect, BitmapImage &img){
    QPainter p(&m_pixmap);

}

void BitmapImage::cutImgOp(QRect rect, QColor col){
    QPainter p(&m_pixmap);
    p.setBrush(QBrush(col));
    p.setPen(QPen(col));
    p.fillRect(rect, col);
    p.end();
}

qreal BitmapImage::getIncrement(QPointF p1, QPointF p2){
    return calculateMidpoint(p1, p2, 1.0);
}

qreal BitmapImage::calculateMidpoint(QPointF p1, QPointF p2, qreal inc){
    QPointF point = p2 + p1;
    if(point.manhattanLength() > 1){
        QPointF hP1(p1.x() / 2.0, p2.y() / 2.0);
        QPointF hP2(p2.x() / 2.0, p2.y() / 2.0);
        calculateMidpoint(hP1, hP2, inc / 2.0);
    }else{
        return inc;
    }
}

QPixmap BitmapImage::getCompositeImage()
{
    QPixmap temp = m_pixmap;
    QPainter painter(&temp);
    painter.setOpacity(0.5);
    painter.drawPixmap(0, 0, temp);
    painter.end();
    m_pixmap = temp;
    return m_pixmap;
}
<commit_msg>0.0.90.5<commit_after>#include "bitmapimage.h"

BitmapImage::BitmapImage()
{
    m_Image = NULL;
    visible = true;
    m_ScaleFactor = 1.0;
    qDebug() << "Image drawn!" << endl;
    m_ScaleFactorInv = 1.0;
}

BitmapImage::BitmapImage(const BitmapImage &image)
{
    m_pixmap = image.m_pixmap;
    boundaries = image.boundaries;
    m_Color = image.m_Color;
    m_ScaleFactor = 1.0;
    m_ScaleFactorInv = 1.0;
    visible = true;
}

BitmapImage::BitmapImage(Object *parent, QRect boundaries, QColor color)
{
    myParent = parent;
    this->boundaries = boundaries;
    m_Image = new QImage(boundaries.size(), QImage::Format_ARGB32_Premultiplied);
    m_Image->fill(color.rgba());
    m_ScaleFactor = 1.0;
    m_ScaleFactorInv = 1.0;
    visible = true;
}

BitmapImage::BitmapImage(Object *parent, QRect boundaries, QImage image)
{
    myParent = parent;
    this->boundaries = boundaries;
    m_Image = new QImage(image);
    if(m_Image->width() != boundaries.width() && m_Image->height() != boundaries.height()) qDebug() << "Error 0001: Failed to load Image" << endl;
    visible = true;
    m_ScaleFactor = 1.0;
    m_ScaleFactorInv = 1.0;
}

BitmapImage::BitmapImage(QRect boundaries, QColor color)
{
    this->boundaries = boundaries;
    QPixmap temp(boundaries.width(), boundaries.height());
    temp.fill(color);
    QPainter painter(&temp);
    if(!temp.isNull())
    {
        painter.drawPixmap(0, 0, temp);
    }
    painter.end();
    m_pixmap = temp;
    visible = true;
    m_ScaleFactor = 1.0;
    m_ScaleFactorInv = 1.0;
}

BitmapImage::BitmapImage(QRect boundaries, QPixmap pixMap)
{
    this->boundaries = boundaries;
    m_pixmap = pixMap;
    visible = true;
    m_ScaleFactor = 1.0;
    m_ScaleFactorInv = 1.0;
}

void BitmapImage::paintImage(QPainter &painter)
{
    painter.drawPixmap(0, 0, m_pixmap);
}

void BitmapImage::paintImage(QPainterPath painterPath, Brush brush)
{
    QPainter painter(&m_pixmap);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setBrush(Qt::NoBrush);
    QPen copyPen = brush.getPen();
    if(brush.getSize() > 0)
    {
        copyPen.setBrush(brush.getBrush());
        copyPen.setWidth(brush.getSize());
        painter.setPen(copyPen);
    }else{
        copyPen.setBrush(Qt::NoBrush);
        copyPen.setWidth(0);
        painter.setPen(copyPen);
    }
    painter.drawPath(painterPath);
}

void BitmapImage::paintImage(QPoint point, Brush brush){
    int brushWidth = brush.getSize() + (brush.getPressureVal() * brush.getTransferSize());
    brushWidth += m_ScaleFactor;
    QImage stencilBase = brush.getStencil().toImage();
    stencilBase.invertPixels(QImage::InvertRgb);
    stencilBase.createAlphaMask();
    stencilBase.convertToFormat(QImage::Format_ARGB32, Qt::AutoColor);
    QImage stencilImage = QImage(stencilBase);
    QColor color = brush.getColor();
    color.setAlpha(brush.getOpacity() + (brush.getPressureVal() * brush.getTransferOpacity()));
    stencilImage.fill(color);
    QPixmap stencil = QPixmap::fromImage(stencilImage.scaled(brushWidth, brushWidth, Qt::IgnoreAspectRatio, Qt::FastTransformation));
    QPainter p(&m_pixmap);
    p.setRenderHint(QPainter::Antialiasing);
    p.drawPixmap(QPoint(point.x() - stencil.width()/2, point.y() - stencil.height()/2), stencil);
}

void BitmapImage::paintImage(QVector<QPointF> pointInfo, Brush brush)
{
    int brushWidth = brush.getSize() + (brush.getPressureVal() * brush.getTransferSize());
    brushWidth *= m_ScaleFactor;
    /*-Prepare Stencil-*/
    QImage stencilBase = brush.getStencil().toImage();
    stencilBase.invertPixels(QImage::InvertRgb);
    stencilBase.createAlphaMask();
    stencilBase.convertToFormat(QImage::Format_ARGB32, Qt::AutoColor);
    QImage stencilImage = QImage(stencilBase);
    QColor color = brush.getColor();
    color.setAlpha(brush.getOpacity() + (brush.getPressureVal() * brush.getTransferOpacity()));
    stencilImage.fill(color);
    stencilImage.setAlphaChannel(stencilBase);
    QPixmap stencil = QPixmap::fromImage(stencilImage.scaled(brushWidth, brushWidth, Qt::IgnoreAspectRatio, Qt::FastTransformation));

    QPainter painter(&m_pixmap);
    painter.setRenderHint(QPainter::Antialiasing);

    /*Calculate incrementation value*/
    qreal inc = 0.01;

    QPainterPath path;
    path.moveTo(pointInfo.first());
    path.lineTo(pointInfo.last());

    inc = getIncrement(pointInfo.first(), pointInfo.last());

    /* Automatically adjust the incrementing value */
    for(qreal i = 0; i < 1; i+= inc * brush.getSpacing()){
        painter.drawPixmap(QPoint(path.pointAtPercent(i).x() - stencil.width()/2, path.pointAtPercent(i).y() - stencil.width()/2), stencil);
    }

    /*-Old Method-*/

//    QPointF point, drawPoint;
//    point = pointInfo.last() - pointInfo.first();
//    int length = point.manhattanLength();
//    double xInc, yInc;
//    xInc = point.x() / (double)length;
//    yInc = point.y() / (double)length;
//    drawPoint = pointInfo.first();

//    for(int i = 0; i < length; i++){
//        if(drawPoint != pointInfo.last() || drawPoint != pointInfo.first()){
//            drawPoint.setX(drawPoint.x() + (xInc / (double)brush.getSpacing() ));
//            drawPoint.setY(drawPoint.y() + (yInc / (double)brush.getSpacing() ));
//            painter.drawPixmap(QPoint(drawPoint.x() - stencil.width() / 2, drawPoint.y() - stencil.height()/2) / m_ScaleFactor, stencil);
//        }
//    }
}

void BitmapImage::paintImage(QVector<QPointF> pointInfo, Brush brush, qreal tabPress, int amt)
{
    int brushWidth = brush.getSize() + (amt * tabPress);
    /*-Prepare Stencil-*/
    QImage stencilBase = brush.getStencil().toImage();
    stencilBase.invertPixels(QImage::InvertRgb);
    stencilBase.createAlphaMask();
    stencilBase.convertToFormat(QImage::Format_RGB888, Qt::AutoColor);
    QImage stencilImage = QImage(stencilBase);
    QColor color = brush.getColor();
    color.setAlpha(brush.getOpacity());
    stencilImage.fill(color);
    stencilImage.setAlphaChannel(stencilBase);
    QPixmap stencil = QPixmap::fromImage(stencilImage.scaled(brushWidth, brushWidth, Qt::IgnoreAspectRatio, Qt::FastTransformation));

    QPainter painter(&m_pixmap);
    painter.setRenderHint(QPainter::Antialiasing);

    QPointF point, drawPoint;
    point = pointInfo.last() - pointInfo.first();
    int length = point.manhattanLength();
    double xInc, yInc;
    xInc = point.x() / length;
    yInc = point.y() / length;
    drawPoint = pointInfo.first();
    for(int i = 0; i < length; i++){
        drawPoint.setX(drawPoint.x() + (xInc * brush.getSpacing() ));
        drawPoint.setY(drawPoint.y() + (yInc * brush.getSpacing() ));
        painter.drawPixmap(QPoint(drawPoint.x() - stencil.width() / 2, drawPoint.y() - stencil.height()/2), stencil);
    }
}

void BitmapImage::fillImage(QPoint point, Brush brush){

    QImage img = m_pixmap.toImage();
    QRgb oldColor = img.pixel(point);
    QRgb newColor = brush.getColor().rgb();
    fillRecurs(point, img, oldColor, newColor);

    m_pixmap = QPixmap::fromImage(img);
}

void BitmapImage::scale(double s){
    m_ScaleFactor = s;
}

void BitmapImage::commitChanges(QPoint drawPoint, QPixmap pixmap){
    QPainter p(&m_pixmap);
    p.drawPixmap(drawPoint, pixmap);
}

/*
*
*   Implementation of this function is as close to the version in EasyPaint.
*
*/
void BitmapImage::fillRecurs(QPoint pos, QImage& img, QRgb oldColor, QRgb newColor){
    int temp_x(pos.x());
    int left_x = 0;
    while(true){
        if(img.pixel(temp_x, pos.y()) != oldColor){
            break;
        }
        img.setPixel(temp_x, pos.y(), newColor);
        if(temp_x > 0){
            temp_x--;
            left_x = temp_x;
        }else{
            break;
        }
    }

    int right_x(0);
    temp_x = pos.x() + 1;
    while(true){
        if(img.pixel(temp_x, pos.y()) != oldColor){
            break;
        }
        img.setPixel(temp_x, pos.y(), newColor);
        if(temp_x < img.width() -1){
            temp_x++;
            right_x = temp_x;
        }else{
            break;
        }
    }

    for(int x = left_x+1; x < right_x; x++){
        if(pos.y() < 1 || pos.y() >= img.height() - 1){
            break;
        }
        if(right_x > img.width()){ break; }
        QRgb currentColor = img.pixel(x, pos.y()-1);
        if(currentColor == oldColor && currentColor != newColor){
            fillRecurs(QPoint(x, pos.y() -1), img, oldColor, newColor);
        }
        currentColor = img.pixel(x, pos.y() + 1);
        if(currentColor == oldColor && currentColor != newColor){
            fillRecurs(QPoint(x, pos.y() + 1), img, oldColor, newColor);
        }
    }
}

void BitmapImage::cutImgOp(QRect rect, BitmapImage &img){
    QPainter p(&m_pixmap);

}

void BitmapImage::cutImgOp(QRect rect, QColor col){
    QPainter p(&m_pixmap);
    p.setBrush(QBrush(col));
    p.setPen(QPen(col));
    p.fillRect(rect, col);
    p.end();
}

qreal BitmapImage::getIncrement(QPointF p1, QPointF p2){
    return calculateMidpoint(p1, p2, 1.0);
}

qreal BitmapImage::calculateMidpoint(QPointF p1, QPointF p2, qreal inc){
    QPointF point = p2 + p1;
    if(point.manhattanLength() > 1){
        QPointF hP1(p1.x() / 2.0, p1.y() / 2.0);
        QPointF hP2(p2.x() / 2.0, p2.y() / 2.0);
        calculateMidpoint(hP1, hP2, inc / 2.0);
    }else{
        return inc;
    }
}

QPixmap BitmapImage::getCompositeImage()
{
    QPixmap temp = m_pixmap;
    QPainter painter(&temp);
    painter.setOpacity(0.5);
    painter.drawPixmap(0, 0, temp);
    painter.end();
    m_pixmap = temp;
    return m_pixmap;
}
<|endoftext|>


<commit_before>/***********************************************************************
 *    filename:   InputInjection.cpp
 *    created:    21/5/2013
 *    author:     Timotei Dolean
 *************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2013 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/

#include <boost/test/unit_test.hpp>

#include <vector>
#include <iostream>

#include "CEGUI/CEGUI.h"

using namespace CEGUI;

struct InputInjectionFixture
{
    InputInjectionFixture()
        : d_buttonHandledCount(0)
        , d_windowHandledCount(0)
    {
        System::getSingleton().notifyDisplaySizeChanged(Sizef(100, 100));
        Rectf constraint_area(0, 0, 100, 100);
        System::getSingleton().getDefaultGUIContext().getMouseCursor().setConstraintArea(&constraint_area);

        d_window = WindowManager::getSingleton().createWindow("DefaultWindow");
        d_window->setPosition(UVector2(cegui_reldim(0.0f), cegui_reldim(0.0f)));
        d_window->setSize(USize(cegui_reldim(1.0f), cegui_reldim(1.0f)));

        d_button = WindowManager::getSingleton().createWindow("CEGUI/PushButton");
        d_button->setPosition(UVector2(cegui_reldim(0.2f), cegui_reldim(0.2f)));
        d_button->setSize(USize(cegui_reldim(0.2f), cegui_reldim(0.2f)));

        d_editbox = WindowManager::getSingleton().createWindow("TaharezLook/Editbox");
        d_editbox->setPosition(UVector2(cegui_reldim(0.9f), cegui_reldim(0.9f)));
        d_editbox->setSize(USize(cegui_reldim(0.1f), cegui_reldim(0.1f)));

        d_window->addChild(d_editbox);
        d_window->addChild(d_button);

        System::getSingleton().getDefaultGUIContext().setRootWindow(d_window);

        d_windowConnections.push_back(
            d_window->subscribeEvent(Window::EventMouseClick,
                Event::Subscriber(&InputInjectionFixture::handleWindowEvent, this))
            );
        d_buttonConnections.push_back(
            d_button->subscribeEvent(PushButton::EventClicked,
                Event::Subscriber(&InputInjectionFixture::handleButtonEvent, this))
            );
    }

    ~InputInjectionFixture()
    {
        disconnectConnections(d_windowConnections);
        disconnectConnections(d_buttonConnections);

        System::getSingleton().getDefaultGUIContext().setRootWindow(0);

        WindowManager::getSingleton().destroyWindow(d_window);
    }

    bool handleButtonEvent(const EventArgs& e)
    {
        ++d_buttonHandledCount;
        return true;
    }

    bool handleWindowEvent(const EventArgs& e)
    {
        ++d_windowHandledCount;
        return true;
    }

    void disconnectConnections(std::vector<Event::Connection>& connections)
    {
        for(std::vector<Event::Connection>::iterator itor = connections.begin();
            itor != connections.end(); ++itor)
        {
            (*itor)->disconnect();
        }
    }

    int d_buttonHandledCount;
    int d_windowHandledCount;

    Window* d_window;
    Window* d_button;
    Window* d_editbox;

    std::vector<Event::Connection> d_windowConnections;
    std::vector<Event::Connection> d_buttonConnections;
};

//----------------------------------------------------------------------------//
static inline GUIContext& getGUIContext()
{
    return System::getSingleton().getDefaultGUIContext();
}

static void doClick(float position_x, float position_y)
{
    getGUIContext().injectMousePosition(position_x, position_y);
    getGUIContext().injectMouseButtonDown(LeftButton);
    getGUIContext().injectMouseButtonUp(LeftButton);
}
//----------------------------------------------------------------------------//

BOOST_FIXTURE_TEST_SUITE(InputInjection, InputInjectionFixture)

BOOST_AUTO_TEST_CASE(OneClickOnWindow)
{
    // we check for both: a) being handled, b) have the expected final result
    BOOST_REQUIRE_EQUAL(getGUIContext().injectMouseButtonClick(LeftButton), true);

    BOOST_REQUIRE_EQUAL(d_windowHandledCount, 1);
    BOOST_REQUIRE_EQUAL(d_buttonHandledCount, 0);
}

BOOST_AUTO_TEST_CASE(MultipleClicksOnWindow)
{
    BOOST_REQUIRE_EQUAL(getGUIContext().injectMouseButtonClick(LeftButton), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectMouseButtonClick(LeftButton), true);

    BOOST_REQUIRE_EQUAL(d_windowHandledCount, 2);
    BOOST_REQUIRE_EQUAL(d_buttonHandledCount, 0);
}

BOOST_AUTO_TEST_CASE(OneClickOnButton)
{
    doClick(30.0f, 30.0f);

    BOOST_REQUIRE_EQUAL(d_windowHandledCount, 0);
    BOOST_REQUIRE_EQUAL(d_buttonHandledCount, 1);
}

BOOST_AUTO_TEST_CASE(InsertSimpleText)
{
    // focus the editbox
    doClick(91.0f, 91.0f);

    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('o'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);

    BOOST_REQUIRE_EQUAL(d_editbox->getText(), "WoW");
}

BOOST_AUTO_TEST_CASE(DeleteTextWithBackspace)
{
    // focus the editbox
    doClick(91.0f, 91.0f);

    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('o'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('k'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectKeyDown(Key::Backspace), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);

    BOOST_REQUIRE_EQUAL(d_editbox->getText(), "WoW");
}

BOOST_AUTO_TEST_CASE(DeleteTextWithDelete)
{
    // focus the editbox
    doClick(91.0f, 91.0f);

    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('o'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('k'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);

    BOOST_REQUIRE_EQUAL(getGUIContext().injectKeyDown(Key::ArrowLeft), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectKeyDown(Key::ArrowLeft), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectKeyDown(Key::Delete), true);

    BOOST_REQUIRE_EQUAL(d_editbox->getText(), "WoW");
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Fix the line ending for 'InputInjection' tests<commit_after>/***********************************************************************
 *    filename:   InputInjection.cpp
 *    created:    21/5/2013
 *    author:     Timotei Dolean
 *************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2013 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/

#include <boost/test/unit_test.hpp>

#include <vector>
#include <iostream>

#include "CEGUI/CEGUI.h"

using namespace CEGUI;

struct InputInjectionFixture
{
    InputInjectionFixture()
        : d_buttonHandledCount(0)
        , d_windowHandledCount(0)
    {
        System::getSingleton().notifyDisplaySizeChanged(Sizef(100, 100));
        Rectf constraint_area(0, 0, 100, 100);
        System::getSingleton().getDefaultGUIContext().getMouseCursor().setConstraintArea(&constraint_area);

        d_window = WindowManager::getSingleton().createWindow("DefaultWindow");
        d_window->setPosition(UVector2(cegui_reldim(0.0f), cegui_reldim(0.0f)));
        d_window->setSize(USize(cegui_reldim(1.0f), cegui_reldim(1.0f)));

        d_button = WindowManager::getSingleton().createWindow("CEGUI/PushButton");
        d_button->setPosition(UVector2(cegui_reldim(0.2f), cegui_reldim(0.2f)));
        d_button->setSize(USize(cegui_reldim(0.2f), cegui_reldim(0.2f)));

        d_editbox = WindowManager::getSingleton().createWindow("TaharezLook/Editbox");
        d_editbox->setPosition(UVector2(cegui_reldim(0.9f), cegui_reldim(0.9f)));
        d_editbox->setSize(USize(cegui_reldim(0.1f), cegui_reldim(0.1f)));

        d_window->addChild(d_editbox);
        d_window->addChild(d_button);

        System::getSingleton().getDefaultGUIContext().setRootWindow(d_window);

        d_windowConnections.push_back(
            d_window->subscribeEvent(Window::EventMouseClick,
                Event::Subscriber(&InputInjectionFixture::handleWindowEvent, this))
            );
        d_buttonConnections.push_back(
            d_button->subscribeEvent(PushButton::EventClicked,
                Event::Subscriber(&InputInjectionFixture::handleButtonEvent, this))
            );
    }

    ~InputInjectionFixture()
    {
        disconnectConnections(d_windowConnections);
        disconnectConnections(d_buttonConnections);

        System::getSingleton().getDefaultGUIContext().setRootWindow(0);

        WindowManager::getSingleton().destroyWindow(d_window);
    }

    bool handleButtonEvent(const EventArgs& e)
    {
        ++d_buttonHandledCount;
        return true;
    }

    bool handleWindowEvent(const EventArgs& e)
    {
        ++d_windowHandledCount;
        return true;
    }

    void disconnectConnections(std::vector<Event::Connection>& connections)
    {
        for(std::vector<Event::Connection>::iterator itor = connections.begin();
            itor != connections.end(); ++itor)
        {
            (*itor)->disconnect();
        }
    }

    int d_buttonHandledCount;
    int d_windowHandledCount;

    Window* d_window;
    Window* d_button;
    Window* d_editbox;

    std::vector<Event::Connection> d_windowConnections;
    std::vector<Event::Connection> d_buttonConnections;
};

//----------------------------------------------------------------------------//
static inline GUIContext& getGUIContext()
{
    return System::getSingleton().getDefaultGUIContext();
}

static void doClick(float position_x, float position_y)
{
    getGUIContext().injectMousePosition(position_x, position_y);
    getGUIContext().injectMouseButtonDown(LeftButton);
    getGUIContext().injectMouseButtonUp(LeftButton);
}
//----------------------------------------------------------------------------//

BOOST_FIXTURE_TEST_SUITE(InputInjection, InputInjectionFixture)

BOOST_AUTO_TEST_CASE(OneClickOnWindow)
{
    // we check for both: a) being handled, b) have the expected final result
    BOOST_REQUIRE_EQUAL(getGUIContext().injectMouseButtonClick(LeftButton), true);

    BOOST_REQUIRE_EQUAL(d_windowHandledCount, 1);
    BOOST_REQUIRE_EQUAL(d_buttonHandledCount, 0);
}

BOOST_AUTO_TEST_CASE(MultipleClicksOnWindow)
{
    BOOST_REQUIRE_EQUAL(getGUIContext().injectMouseButtonClick(LeftButton), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectMouseButtonClick(LeftButton), true);

    BOOST_REQUIRE_EQUAL(d_windowHandledCount, 2);
    BOOST_REQUIRE_EQUAL(d_buttonHandledCount, 0);
}

BOOST_AUTO_TEST_CASE(OneClickOnButton)
{
    doClick(30.0f, 30.0f);

    BOOST_REQUIRE_EQUAL(d_windowHandledCount, 0);
    BOOST_REQUIRE_EQUAL(d_buttonHandledCount, 1);
}

BOOST_AUTO_TEST_CASE(InsertSimpleText)
{
    // focus the editbox
    doClick(91.0f, 91.0f);

    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('o'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);

    BOOST_REQUIRE_EQUAL(d_editbox->getText(), "WoW");
}

BOOST_AUTO_TEST_CASE(DeleteTextWithBackspace)
{
    // focus the editbox
    doClick(91.0f, 91.0f);

    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('o'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('k'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectKeyDown(Key::Backspace), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);

    BOOST_REQUIRE_EQUAL(d_editbox->getText(), "WoW");
}

BOOST_AUTO_TEST_CASE(DeleteTextWithDelete)
{
    // focus the editbox
    doClick(91.0f, 91.0f);

    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('o'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('k'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);

    BOOST_REQUIRE_EQUAL(getGUIContext().injectKeyDown(Key::ArrowLeft), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectKeyDown(Key::ArrowLeft), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectKeyDown(Key::Delete), true);

    BOOST_REQUIRE_EQUAL(d_editbox->getText(), "WoW");
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>/***********************************************************************
 *    filename:   InputInjection.cpp
 *    created:    21/5/2013
 *    author:     Timotei Dolean
 *************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2013 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/

#include <boost/test/unit_test.hpp>

#include <vector>
#include <iostream>

#include "CEGUI/CEGUI.h"

using namespace CEGUI;

struct InputInjectionFixture
{
    InputInjectionFixture()
        : d_buttonHandledCount(0)
        , d_windowHandledCount(0)
    {
        d_window = WindowManager::getSingleton().createWindow("DefaultWindow");
        d_window->setPosition(UVector2(cegui_reldim(0.0f), cegui_reldim(0.0f)));
        d_window->setSize(USize(cegui_reldim(1.0f), cegui_reldim(1.0f)));

        d_button = WindowManager::getSingleton().createWindow("CEGUI/PushButton");
        d_button->setPosition(UVector2(cegui_reldim(0.2f), cegui_reldim(0.2f)));
        d_button->setSize(USize(cegui_reldim(0.2f), cegui_reldim(0.2f)));

        d_editbox = WindowManager::getSingleton().createWindow("TaharezLook/Editbox");
        d_editbox->setPosition(UVector2(cegui_reldim(0.9f), cegui_reldim(0.9f)));
        d_editbox->setSize(USize(cegui_reldim(0.1f), cegui_reldim(0.1f)));

        d_window->addChild(d_editbox);
        d_window->addChild(d_button);

        System::getSingleton().getDefaultGUIContext().setRootWindow(d_window);
        System::getSingleton().notifyDisplaySizeChanged(Sizef(100, 100));

        d_windowConnections.push_back(
            d_window->subscribeEvent(Window::EventMouseClick,
                Event::Subscriber(&InputInjectionFixture::handleWindowEvent, this))
            );
        d_buttonConnections.push_back(
            d_button->subscribeEvent(PushButton::EventClicked,
                Event::Subscriber(&InputInjectionFixture::handleButtonEvent, this))
            );
    }

    ~InputInjectionFixture()
    {
        disconnectConnections(d_windowConnections);
        disconnectConnections(d_buttonConnections);

        System::getSingleton().getDefaultGUIContext().setRootWindow(0);

        WindowManager::getSingleton().destroyWindow(d_window);
    }

    bool handleButtonEvent(const EventArgs& e)
    {
        ++d_buttonHandledCount;
        return true;
    }

    bool handleWindowEvent(const EventArgs& e)
    {
        ++d_windowHandledCount;
        return true;
    }

    void disconnectConnections(std::vector<Event::Connection>& connections)
    {
        for(std::vector<Event::Connection>::iterator itor = connections.begin();
            itor != connections.end(); ++itor)
        {
            (*itor)->disconnect();
        }
    }

    int d_buttonHandledCount;
    int d_windowHandledCount;

    Window* d_window;
    Window* d_button;
    Window* d_editbox;

    std::vector<Event::Connection> d_windowConnections;
    std::vector<Event::Connection> d_buttonConnections;
};

//----------------------------------------------------------------------------//
static inline GUIContext& getGUIContext()
{
    return System::getSingleton().getDefaultGUIContext();
}

static void doClick(float position_x, float position_y)
{
    getGUIContext().injectMousePosition(position_x, position_y);
    getGUIContext().injectMouseButtonDown(LeftButton);
    getGUIContext().injectMouseButtonUp(LeftButton);
}
//----------------------------------------------------------------------------//

BOOST_FIXTURE_TEST_SUITE(InputInjection, InputInjectionFixture)

BOOST_AUTO_TEST_CASE(OneClickOnWindow)
{
    // we check for both: a) being handled, b) have the expected final result
    BOOST_REQUIRE_EQUAL(getGUIContext().injectMouseButtonClick(LeftButton), true);

    BOOST_REQUIRE_EQUAL(d_windowHandledCount, 1);
    BOOST_REQUIRE_EQUAL(d_buttonHandledCount, 0);
}

BOOST_AUTO_TEST_CASE(MultipleClicksOnWindow)
{
    BOOST_REQUIRE_EQUAL(getGUIContext().injectMouseButtonClick(LeftButton), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectMouseButtonClick(LeftButton), true);

    BOOST_REQUIRE_EQUAL(d_windowHandledCount, 2);
    BOOST_REQUIRE_EQUAL(d_buttonHandledCount, 0);
}

BOOST_AUTO_TEST_CASE(OneClickOnButton)
{
    doClick(30.0f, 30.0f);

    BOOST_REQUIRE_EQUAL(d_windowHandledCount, 0);
    BOOST_REQUIRE_EQUAL(d_buttonHandledCount, 1);
}

BOOST_AUTO_TEST_CASE(InsertSimpleText)
{
    // focus the editbox
    doClick(91.0f, 91.0f);

    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('o'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);

    BOOST_REQUIRE_EQUAL(d_editbox->getText(), "WoW");
}

BOOST_AUTO_TEST_CASE(DeleteTextWithBackspace)
{
    // focus the editbox
    doClick(91.0f, 91.0f);

    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('o'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('k'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectKeyDown(Key::Backspace), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);

    BOOST_REQUIRE_EQUAL(d_editbox->getText(), "WoW");
}

BOOST_AUTO_TEST_CASE(DeleteTextWithDelete)
{
    // focus the editbox
    doClick(91.0f, 91.0f);

    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('o'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('k'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);

    BOOST_REQUIRE_EQUAL(getGUIContext().injectKeyDown(Key::ArrowLeft), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectKeyDown(Key::ArrowLeft), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectKeyDown(Key::Delete), true);

    BOOST_REQUIRE_EQUAL(d_editbox->getText(), "WoW");
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Manually set mouse cursor's constraint area in 'InputInjection' tests<commit_after>/***********************************************************************
 *    filename:   InputInjection.cpp
 *    created:    21/5/2013
 *    author:     Timotei Dolean
 *************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2013 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/

#include <boost/test/unit_test.hpp>

#include <vector>
#include <iostream>

#include "CEGUI/CEGUI.h"

using namespace CEGUI;

struct InputInjectionFixture
{
    InputInjectionFixture()
        : d_buttonHandledCount(0)
        , d_windowHandledCount(0)
    {
        System::getSingleton().notifyDisplaySizeChanged(Sizef(100, 100));
        Rectf constraint_area(0, 0, 100, 100);
        System::getSingleton().getDefaultGUIContext().getMouseCursor().setConstraintArea(&constraint_area);

        d_window = WindowManager::getSingleton().createWindow("DefaultWindow");
        d_window->setPosition(UVector2(cegui_reldim(0.0f), cegui_reldim(0.0f)));
        d_window->setSize(USize(cegui_reldim(1.0f), cegui_reldim(1.0f)));

        d_button = WindowManager::getSingleton().createWindow("CEGUI/PushButton");
        d_button->setPosition(UVector2(cegui_reldim(0.2f), cegui_reldim(0.2f)));
        d_button->setSize(USize(cegui_reldim(0.2f), cegui_reldim(0.2f)));

        d_editbox = WindowManager::getSingleton().createWindow("TaharezLook/Editbox");
        d_editbox->setPosition(UVector2(cegui_reldim(0.9f), cegui_reldim(0.9f)));
        d_editbox->setSize(USize(cegui_reldim(0.1f), cegui_reldim(0.1f)));

        d_window->addChild(d_editbox);
        d_window->addChild(d_button);

        System::getSingleton().getDefaultGUIContext().setRootWindow(d_window);

        d_windowConnections.push_back(
            d_window->subscribeEvent(Window::EventMouseClick,
                Event::Subscriber(&InputInjectionFixture::handleWindowEvent, this))
            );
        d_buttonConnections.push_back(
            d_button->subscribeEvent(PushButton::EventClicked,
                Event::Subscriber(&InputInjectionFixture::handleButtonEvent, this))
            );
    }

    ~InputInjectionFixture()
    {
        disconnectConnections(d_windowConnections);
        disconnectConnections(d_buttonConnections);

        System::getSingleton().getDefaultGUIContext().setRootWindow(0);

        WindowManager::getSingleton().destroyWindow(d_window);
    }

    bool handleButtonEvent(const EventArgs& e)
    {
        ++d_buttonHandledCount;
        return true;
    }

    bool handleWindowEvent(const EventArgs& e)
    {
        ++d_windowHandledCount;
        return true;
    }

    void disconnectConnections(std::vector<Event::Connection>& connections)
    {
        for(std::vector<Event::Connection>::iterator itor = connections.begin();
            itor != connections.end(); ++itor)
        {
            (*itor)->disconnect();
        }
    }

    int d_buttonHandledCount;
    int d_windowHandledCount;

    Window* d_window;
    Window* d_button;
    Window* d_editbox;

    std::vector<Event::Connection> d_windowConnections;
    std::vector<Event::Connection> d_buttonConnections;
};

//----------------------------------------------------------------------------//
static inline GUIContext& getGUIContext()
{
    return System::getSingleton().getDefaultGUIContext();
}

static void doClick(float position_x, float position_y)
{
    getGUIContext().injectMousePosition(position_x, position_y);
    getGUIContext().injectMouseButtonDown(LeftButton);
    getGUIContext().injectMouseButtonUp(LeftButton);
}
//----------------------------------------------------------------------------//

BOOST_FIXTURE_TEST_SUITE(InputInjection, InputInjectionFixture)

BOOST_AUTO_TEST_CASE(OneClickOnWindow)
{
    // we check for both: a) being handled, b) have the expected final result
    BOOST_REQUIRE_EQUAL(getGUIContext().injectMouseButtonClick(LeftButton), true);

    BOOST_REQUIRE_EQUAL(d_windowHandledCount, 1);
    BOOST_REQUIRE_EQUAL(d_buttonHandledCount, 0);
}

BOOST_AUTO_TEST_CASE(MultipleClicksOnWindow)
{
    BOOST_REQUIRE_EQUAL(getGUIContext().injectMouseButtonClick(LeftButton), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectMouseButtonClick(LeftButton), true);

    BOOST_REQUIRE_EQUAL(d_windowHandledCount, 2);
    BOOST_REQUIRE_EQUAL(d_buttonHandledCount, 0);
}

BOOST_AUTO_TEST_CASE(OneClickOnButton)
{
    doClick(30.0f, 30.0f);

    BOOST_REQUIRE_EQUAL(d_windowHandledCount, 0);
    BOOST_REQUIRE_EQUAL(d_buttonHandledCount, 1);
}

BOOST_AUTO_TEST_CASE(InsertSimpleText)
{
    // focus the editbox
    doClick(91.0f, 91.0f);

    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('o'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);

    BOOST_REQUIRE_EQUAL(d_editbox->getText(), "WoW");
}

BOOST_AUTO_TEST_CASE(DeleteTextWithBackspace)
{
    // focus the editbox
    doClick(91.0f, 91.0f);

    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('o'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('k'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectKeyDown(Key::Backspace), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);

    BOOST_REQUIRE_EQUAL(d_editbox->getText(), "WoW");
}

BOOST_AUTO_TEST_CASE(DeleteTextWithDelete)
{
    // focus the editbox
    doClick(91.0f, 91.0f);

    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('o'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('k'), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectChar('W'), true);

    BOOST_REQUIRE_EQUAL(getGUIContext().injectKeyDown(Key::ArrowLeft), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectKeyDown(Key::ArrowLeft), true);
    BOOST_REQUIRE_EQUAL(getGUIContext().injectKeyDown(Key::Delete), true);

    BOOST_REQUIRE_EQUAL(d_editbox->getText(), "WoW");
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>