<commit_before>/*********************************************************************
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2012, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *********************************************************************/

/* Author: Ioan Sucan */

#include "move_action_capability.h"

#include <moveit/planning_pipeline/planning_pipeline.h>
#include <moveit/plan_execution/plan_execution.h>
#include <moveit/plan_execution/plan_with_sensing.h>
#include <moveit/trajectory_processing/trajectory_tools.h>
#include <moveit/kinematic_constraints/utils.h>
#include <moveit/utils/message_checks.h>
#include <moveit/move_group/capability_names.h>

namespace move_group
{
MoveGroupMoveAction::MoveGroupMoveAction()
  : MoveGroupCapability("MoveAction"), move_state_(IDLE), preempt_requested_{ false }
{
}

void MoveGroupMoveAction::initialize()
{
  // start the move action server
  move_action_server_ = std::make_unique<actionlib::SimpleActionServer<moveit_msgs::MoveGroupAction>>(
      root_node_handle_, MOVE_ACTION, [this](const auto& goal) { executeMoveCallback(goal); }, false);
  move_action_server_->registerPreemptCallback([this] { preemptMoveCallback(); });
  move_action_server_->start();
}

void MoveGroupMoveAction::executeMoveCallback(const moveit_msgs::MoveGroupGoalConstPtr& goal)
{
  setMoveState(PLANNING);
  // before we start planning, ensure that we have the latest robot state received...
  context_->planning_scene_monitor_->waitForCurrentRobotState(ros::Time::now());
  context_->planning_scene_monitor_->updateFrameTransforms();

  moveit_msgs::MoveGroupResult action_res;
  if (goal->planning_options.plan_only || !context_->allow_trajectory_execution_)
  {
    if (!goal->planning_options.plan_only)
      ROS_WARN_NAMED(getName(), "This instance of MoveGroup is not allowed to execute trajectories "
                                "but the goal request has plan_only set to false. "
                                "Only a motion plan will be computed anyway.");
    executeMoveCallbackPlanOnly(goal, action_res);
  }
  else
    executeMoveCallbackPlanAndExecute(goal, action_res);

  bool planned_trajectory_empty = trajectory_processing::isTrajectoryEmpty(action_res.planned_trajectory);
  std::string response =
      getActionResultString(action_res.error_code, planned_trajectory_empty, goal->planning_options.plan_only);
  if (action_res.error_code.val == moveit_msgs::MoveItErrorCodes::SUCCESS)
    move_action_server_->setSucceeded(action_res, response);
  else
  {
    if (action_res.error_code.val == moveit_msgs::MoveItErrorCodes::PREEMPTED)
      move_action_server_->setPreempted(action_res, response);
    else
      move_action_server_->setAborted(action_res, response);
  }

  setMoveState(IDLE);

  preempt_requested_ = false;
}

void MoveGroupMoveAction::executeMoveCallbackPlanAndExecute(const moveit_msgs::MoveGroupGoalConstPtr& goal,
                                                            moveit_msgs::MoveGroupResult& action_res)
{
  ROS_INFO_NAMED(getName(), "Combined planning and execution request received for MoveGroup action. "
                            "Forwarding to planning and execution pipeline.");

  if (moveit::core::isEmpty(goal->planning_options.planning_scene_diff))
  {
    planning_scene_monitor::LockedPlanningSceneRO lscene(context_->planning_scene_monitor_);
    const moveit::core::RobotState& current_state = lscene->getCurrentState();

    // check to see if the desired constraints are already met
    for (std::size_t i = 0; i < goal->request.goal_constraints.size(); ++i)
      if (lscene->isStateConstrained(current_state,
                                     kinematic_constraints::mergeConstraints(goal->request.goal_constraints[i],
                                                                             goal->request.path_constraints)))
      {
        ROS_INFO_NAMED(getName(), "Goal constraints are already satisfied. No need to plan or execute any motions");
        action_res.error_code.val = moveit_msgs::MoveItErrorCodes::SUCCESS;
        return;
      }
  }

  plan_execution::PlanExecution::Options opt;

  const moveit_msgs::MotionPlanRequest& motion_plan_request =
      moveit::core::isEmpty(goal->request.start_state) ? goal->request : clearRequestStartState(goal->request);
  const moveit_msgs::PlanningScene& planning_scene_diff =
      moveit::core::isEmpty(goal->planning_options.planning_scene_diff.robot_state) ?
          goal->planning_options.planning_scene_diff :
          clearSceneRobotState(goal->planning_options.planning_scene_diff);

  opt.replan_ = goal->planning_options.replan;
  opt.replan_attempts_ = goal->planning_options.replan_attempts;
  opt.replan_delay_ = goal->planning_options.replan_delay;
  opt.before_execution_callback_ = [this] { startMoveExecutionCallback(); };

  opt.plan_callback_ = [this, &motion_plan_request](plan_execution::ExecutableMotionPlan& plan) {
    return planUsingPlanningPipeline(motion_plan_request, plan);
  };
  if (goal->planning_options.look_around && context_->plan_with_sensing_)
  {
    opt.plan_callback_ = [plan_with_sensing = context_->plan_with_sensing_.get(), planner = opt.plan_callback_,
                          attempts = goal->planning_options.look_around_attempts,
                          safe_execution_cost = goal->planning_options.max_safe_execution_cost](
                             plan_execution::ExecutableMotionPlan& plan) {
      return plan_with_sensing->computePlan(plan, planner, attempts, safe_execution_cost);
    };
    context_->plan_with_sensing_->setBeforeLookCallback([this] { return startMoveLookCallback(); });
  }

  plan_execution::ExecutableMotionPlan plan;
  if (preempt_requested_)
  {
    ROS_INFO_NAMED(getName(), "Preempt requested before the goal is planned and executed.");
    action_res.error_code.val = moveit_msgs::MoveItErrorCodes::PREEMPTED;
    return;
  }

  context_->plan_execution_->planAndExecute(plan, planning_scene_diff, opt);

  convertToMsg(plan.plan_components_, action_res.trajectory_start, action_res.planned_trajectory);
  if (plan.executed_trajectory_)
    plan.executed_trajectory_->getRobotTrajectoryMsg(action_res.executed_trajectory);
  action_res.error_code = plan.error_code_;
}

void MoveGroupMoveAction::executeMoveCallbackPlanOnly(const moveit_msgs::MoveGroupGoalConstPtr& goal,
                                                      moveit_msgs::MoveGroupResult& action_res)
{
  ROS_INFO_NAMED(getName(), "Planning request received for MoveGroup action. Forwarding to planning pipeline.");

  // lock the scene so that it does not modify the world representation while diff() is called
  planning_scene_monitor::LockedPlanningSceneRO lscene(context_->planning_scene_monitor_);
  const planning_scene::PlanningSceneConstPtr& the_scene =
      (moveit::core::isEmpty(goal->planning_options.planning_scene_diff)) ?
          static_cast<const planning_scene::PlanningSceneConstPtr&>(lscene) :
          lscene->diff(goal->planning_options.planning_scene_diff);
  planning_interface::MotionPlanResponse res;

  if (preempt_requested_)
  {
    ROS_INFO_NAMED(getName(), "Preempt requested before the goal is planned.");
    action_res.error_code.val = moveit_msgs::MoveItErrorCodes::PREEMPTED;
    return;
  }

  // Select planning_pipeline to handle request
  const planning_pipeline::PlanningPipelinePtr planning_pipeline = resolvePlanningPipeline(goal->request.pipeline_id);
  if (!planning_pipeline)
  {
    action_res.error_code.val = moveit_msgs::MoveItErrorCodes::FAILURE;
    return;
  }

  try
  {
    planning_pipeline->generatePlan(the_scene, goal->request, res);
  }
  catch (std::exception& ex)
  {
    ROS_ERROR_NAMED(getName(), "Planning pipeline threw an exception: %s", ex.what());
    res.error_code_.val = moveit_msgs::MoveItErrorCodes::FAILURE;
  }

  convertToMsg(res.trajectory_, action_res.trajectory_start, action_res.planned_trajectory);
  action_res.error_code = res.error_code_;
  action_res.planning_time = res.planning_time_;
}

bool MoveGroupMoveAction::planUsingPlanningPipeline(const planning_interface::MotionPlanRequest& req,
                                                    plan_execution::ExecutableMotionPlan& plan)
{
  setMoveState(PLANNING);

  bool solved = false;
  planning_interface::MotionPlanResponse res;

  // Select planning_pipeline to handle request
  const planning_pipeline::PlanningPipelinePtr planning_pipeline = resolvePlanningPipeline(req.pipeline_id);
  if (!planning_pipeline)
  {
    res.error_code_.val = moveit_msgs::MoveItErrorCodes::FAILURE;
    return solved;
  }

  planning_scene_monitor::LockedPlanningSceneRO lscene(plan.planning_scene_monitor_);
  try
  {
    solved = planning_pipeline->generatePlan(plan.planning_scene_, req, res);
  }
  catch (std::exception& ex)
  {
    ROS_ERROR_NAMED(getName(), "Planning pipeline threw an exception: %s", ex.what());
    res.error_code_.val = moveit_msgs::MoveItErrorCodes::FAILURE;
  }
  if (res.trajectory_)
  {
    plan.plan_components_.resize(1);
    plan.plan_components_[0].trajectory_ = res.trajectory_;
    plan.plan_components_[0].description_ = "plan";
  }
  plan.error_code_ = res.error_code_;
  return solved;
}

void MoveGroupMoveAction::startMoveExecutionCallback()
{
  setMoveState(MONITOR);
}

void MoveGroupMoveAction::startMoveLookCallback()
{
  setMoveState(LOOK);
}

void MoveGroupMoveAction::preemptMoveCallback()
{
  preempt_requested_ = true;
  context_->plan_execution_->stop();
}

void MoveGroupMoveAction::setMoveState(MoveGroupState state)
{
  move_state_ = state;
  move_feedback_.state = stateToStr(state);
  move_action_server_->publishFeedback(move_feedback_);
}
}  // namespace move_group

#include <class_loader/class_loader.hpp>
CLASS_LOADER_REGISTER_CLASS(move_group::MoveGroupMoveAction, move_group::MoveGroupCapability)
<commit_msg>Drop shortcut avoiding planning when all constraints are already met (#3228)<commit_after>/*********************************************************************
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2012, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *********************************************************************/

/* Author: Ioan Sucan */

#include "move_action_capability.h"

#include <moveit/planning_pipeline/planning_pipeline.h>
#include <moveit/plan_execution/plan_execution.h>
#include <moveit/plan_execution/plan_with_sensing.h>
#include <moveit/trajectory_processing/trajectory_tools.h>
#include <moveit/kinematic_constraints/utils.h>
#include <moveit/utils/message_checks.h>
#include <moveit/move_group/capability_names.h>

namespace move_group
{
MoveGroupMoveAction::MoveGroupMoveAction()
  : MoveGroupCapability("MoveAction"), move_state_(IDLE), preempt_requested_{ false }
{
}

void MoveGroupMoveAction::initialize()
{
  // start the move action server
  move_action_server_ = std::make_unique<actionlib::SimpleActionServer<moveit_msgs::MoveGroupAction>>(
      root_node_handle_, MOVE_ACTION, [this](const auto& goal) { executeMoveCallback(goal); }, false);
  move_action_server_->registerPreemptCallback([this] { preemptMoveCallback(); });
  move_action_server_->start();
}

void MoveGroupMoveAction::executeMoveCallback(const moveit_msgs::MoveGroupGoalConstPtr& goal)
{
  setMoveState(PLANNING);
  // before we start planning, ensure that we have the latest robot state received...
  context_->planning_scene_monitor_->waitForCurrentRobotState(ros::Time::now());
  context_->planning_scene_monitor_->updateFrameTransforms();

  moveit_msgs::MoveGroupResult action_res;
  if (goal->planning_options.plan_only || !context_->allow_trajectory_execution_)
  {
    if (!goal->planning_options.plan_only)
      ROS_WARN_NAMED(getName(), "This instance of MoveGroup is not allowed to execute trajectories "
                                "but the goal request has plan_only set to false. "
                                "Only a motion plan will be computed anyway.");
    executeMoveCallbackPlanOnly(goal, action_res);
  }
  else
    executeMoveCallbackPlanAndExecute(goal, action_res);

  bool planned_trajectory_empty = trajectory_processing::isTrajectoryEmpty(action_res.planned_trajectory);
  std::string response =
      getActionResultString(action_res.error_code, planned_trajectory_empty, goal->planning_options.plan_only);
  if (action_res.error_code.val == moveit_msgs::MoveItErrorCodes::SUCCESS)
    move_action_server_->setSucceeded(action_res, response);
  else
  {
    if (action_res.error_code.val == moveit_msgs::MoveItErrorCodes::PREEMPTED)
      move_action_server_->setPreempted(action_res, response);
    else
      move_action_server_->setAborted(action_res, response);
  }

  setMoveState(IDLE);

  preempt_requested_ = false;
}

void MoveGroupMoveAction::executeMoveCallbackPlanAndExecute(const moveit_msgs::MoveGroupGoalConstPtr& goal,
                                                            moveit_msgs::MoveGroupResult& action_res)
{
  ROS_INFO_NAMED(getName(), "Combined planning and execution request received for MoveGroup action. "
                            "Forwarding to planning and execution pipeline.");

  plan_execution::PlanExecution::Options opt;

  const moveit_msgs::MotionPlanRequest& motion_plan_request =
      moveit::core::isEmpty(goal->request.start_state) ? goal->request : clearRequestStartState(goal->request);
  const moveit_msgs::PlanningScene& planning_scene_diff =
      moveit::core::isEmpty(goal->planning_options.planning_scene_diff.robot_state) ?
          goal->planning_options.planning_scene_diff :
          clearSceneRobotState(goal->planning_options.planning_scene_diff);

  opt.replan_ = goal->planning_options.replan;
  opt.replan_attempts_ = goal->planning_options.replan_attempts;
  opt.replan_delay_ = goal->planning_options.replan_delay;
  opt.before_execution_callback_ = [this] { startMoveExecutionCallback(); };

  opt.plan_callback_ = [this, &motion_plan_request](plan_execution::ExecutableMotionPlan& plan) {
    return planUsingPlanningPipeline(motion_plan_request, plan);
  };
  if (goal->planning_options.look_around && context_->plan_with_sensing_)
  {
    opt.plan_callback_ = [plan_with_sensing = context_->plan_with_sensing_.get(), planner = opt.plan_callback_,
                          attempts = goal->planning_options.look_around_attempts,
                          safe_execution_cost = goal->planning_options.max_safe_execution_cost](
                             plan_execution::ExecutableMotionPlan& plan) {
      return plan_with_sensing->computePlan(plan, planner, attempts, safe_execution_cost);
    };
    context_->plan_with_sensing_->setBeforeLookCallback([this] { return startMoveLookCallback(); });
  }

  plan_execution::ExecutableMotionPlan plan;
  if (preempt_requested_)
  {
    ROS_INFO_NAMED(getName(), "Preempt requested before the goal is planned and executed.");
    action_res.error_code.val = moveit_msgs::MoveItErrorCodes::PREEMPTED;
    return;
  }

  context_->plan_execution_->planAndExecute(plan, planning_scene_diff, opt);

  convertToMsg(plan.plan_components_, action_res.trajectory_start, action_res.planned_trajectory);
  if (plan.executed_trajectory_)
    plan.executed_trajectory_->getRobotTrajectoryMsg(action_res.executed_trajectory);
  action_res.error_code = plan.error_code_;
}

void MoveGroupMoveAction::executeMoveCallbackPlanOnly(const moveit_msgs::MoveGroupGoalConstPtr& goal,
                                                      moveit_msgs::MoveGroupResult& action_res)
{
  ROS_INFO_NAMED(getName(), "Planning request received for MoveGroup action. Forwarding to planning pipeline.");

  // lock the scene so that it does not modify the world representation while diff() is called
  planning_scene_monitor::LockedPlanningSceneRO lscene(context_->planning_scene_monitor_);
  const planning_scene::PlanningSceneConstPtr& the_scene =
      (moveit::core::isEmpty(goal->planning_options.planning_scene_diff)) ?
          static_cast<const planning_scene::PlanningSceneConstPtr&>(lscene) :
          lscene->diff(goal->planning_options.planning_scene_diff);
  planning_interface::MotionPlanResponse res;

  if (preempt_requested_)
  {
    ROS_INFO_NAMED(getName(), "Preempt requested before the goal is planned.");
    action_res.error_code.val = moveit_msgs::MoveItErrorCodes::PREEMPTED;
    return;
  }

  // Select planning_pipeline to handle request
  const planning_pipeline::PlanningPipelinePtr planning_pipeline = resolvePlanningPipeline(goal->request.pipeline_id);
  if (!planning_pipeline)
  {
    action_res.error_code.val = moveit_msgs::MoveItErrorCodes::FAILURE;
    return;
  }

  try
  {
    planning_pipeline->generatePlan(the_scene, goal->request, res);
  }
  catch (std::exception& ex)
  {
    ROS_ERROR_NAMED(getName(), "Planning pipeline threw an exception: %s", ex.what());
    res.error_code_.val = moveit_msgs::MoveItErrorCodes::FAILURE;
  }

  convertToMsg(res.trajectory_, action_res.trajectory_start, action_res.planned_trajectory);
  action_res.error_code = res.error_code_;
  action_res.planning_time = res.planning_time_;
}

bool MoveGroupMoveAction::planUsingPlanningPipeline(const planning_interface::MotionPlanRequest& req,
                                                    plan_execution::ExecutableMotionPlan& plan)
{
  setMoveState(PLANNING);

  bool solved = false;
  planning_interface::MotionPlanResponse res;

  // Select planning_pipeline to handle request
  const planning_pipeline::PlanningPipelinePtr planning_pipeline = resolvePlanningPipeline(req.pipeline_id);
  if (!planning_pipeline)
  {
    res.error_code_.val = moveit_msgs::MoveItErrorCodes::FAILURE;
    return solved;
  }

  planning_scene_monitor::LockedPlanningSceneRO lscene(plan.planning_scene_monitor_);
  try
  {
    solved = planning_pipeline->generatePlan(plan.planning_scene_, req, res);
  }
  catch (std::exception& ex)
  {
    ROS_ERROR_NAMED(getName(), "Planning pipeline threw an exception: %s", ex.what());
    res.error_code_.val = moveit_msgs::MoveItErrorCodes::FAILURE;
  }
  if (res.trajectory_)
  {
    plan.plan_components_.resize(1);
    plan.plan_components_[0].trajectory_ = res.trajectory_;
    plan.plan_components_[0].description_ = "plan";
  }
  plan.error_code_ = res.error_code_;
  return solved;
}

void MoveGroupMoveAction::startMoveExecutionCallback()
{
  setMoveState(MONITOR);
}

void MoveGroupMoveAction::startMoveLookCallback()
{
  setMoveState(LOOK);
}

void MoveGroupMoveAction::preemptMoveCallback()
{
  preempt_requested_ = true;
  context_->plan_execution_->stop();
}

void MoveGroupMoveAction::setMoveState(MoveGroupState state)
{
  move_state_ = state;
  move_feedback_.state = stateToStr(state);
  move_action_server_->publishFeedback(move_feedback_);
}
}  // namespace move_group

#include <class_loader/class_loader.hpp>
CLASS_LOADER_REGISTER_CLASS(move_group::MoveGroupMoveAction, move_group::MoveGroupCapability)
<|endoftext|>


<commit_before>// biopore_instant.C --- Instant movement in vertical geometry.
//
// Copyright 2008 Per Abrahamsen and KU.
//
// This file is part of Daisy.
//
// Daisy is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// Daisy is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser Public License for more details.
//
// You should have received a copy of the GNU Lesser Public License
// along with Daisy; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#define BUILD_DLL

#include "tertiary.h"
#include "geometry_vert.h"
#include "plf.h"
#include "check.h"
#include "vcheck.h"
#include "librarian.h"
#include "block.h"

struct TertiaryInstant : public Tertiary
{
  // Parameters.
  const PLF distribution;       // Where they end [cm ->]
  const double height_start;	// Height macropores start [cm]
  const double height_end;	// Height macropores end [cm]
  const double pressure_initiate;// Pressure needed to init pref.flow [cm]
  const double pressure_end;	 // Pressure after pref.flow has been init [cm]
  const double pond_max;	 // Pond height before activating pref.flow [mm]

  // Simulation.
  void tick (const Geometry&, const Soil&, const SoilWater&,
             const double dt,
             std::vector<double>& S_drain,
             std::vector<double>& S_matrix, Treelog& msg);
  void output (Log&) const;

  // Create and Destroy.
public:
  bool initialize (const Geometry&, const Scope& parent_scope,
                   const double pipe_position, Treelog& msg);
  bool check (const Geometry&, Treelog& msg) const;
  TertiaryInstant (Block& al);
};

void
TertiaryInstant::tick (const Geometry& geo, const Soil& soil,
                       const SoilWater& soil_water,
                       const double dt,
                       std::vector<double>& S_drain,
                       std::vector<double>& S_matrix,
                       Treelog& msg)
{
  // TODO
}

void
TertiaryInstant::output (Log&) const
{ }

bool
TertiaryInstant::initialize (const Geometry& geo,
                             const Scope& scope, const double pipe_position,
                             Treelog& msg)
{
  bool ok = true;
  // TODO
  return ok;
}

bool
TertiaryInstant::check (const Geometry& geo, Treelog& msg) const
{

  bool ok = true;
  if (!dynamic_cast<const GeometryVert*> (&geo))
    {
      msg.error ("\
This tertiary water transport model only works with 'vertical' geometries");
      ok = false;
    }

  return ok;
}

TertiaryInstant::TertiaryInstant (Block& al)
  : Tertiary (al),
    distribution (al.plf ("distribution")),
    height_start (al.check ("height_start")
                  ? al.number ("height_start")
                  : distribution.x (distribution.size () - 1)),
    height_end (al.check ("height_end")
                ? al.number ("height_end")
                : distribution.x (0)),
    pressure_initiate (al.number ("pressure_initiate")),
    pressure_end (al.number ("pressure_end")),
    pond_max (al.number ("pond_max"))
{ }

static struct TertiaryInstantSyntax
{
  static Model& make (Block& al)
  { return *new TertiaryInstant (al); }

  TertiaryInstantSyntax ()
  {
    Syntax& syntax = *new Syntax ();
    AttributeList& alist = *new AttributeList ();
    alist.add ("description", "\
The area between 'height_start' and 'height_end' contains macropores,\n\
which are initiated when the water potential reach 'pressure_initiate',\n\
and then immediately emptied down to 'pressure_end'.  The water entering\n\
the macropore is distributed in soil below as a source term, according\n\
to the 'distribution' parameter.");

    syntax.add ("height_start", "cm", Check::non_positive (),
                Syntax::OptionalConst,
                "Macropores starts at this depth (a negative number).\n\
If not specified, use the last point in 'distribution'.");
    syntax.add ("height_end", "cm", Check::non_positive (),
                Syntax::OptionalConst,
                "Macropores ends at this depth (a negative number).\n\
If not specified, use the first point in 'distribution'.");
    syntax.add ("distribution", "cm", Syntax::Fraction (), Syntax::Const, "\
Distribution of macropore end points as a function of height.\n\
The function should start with '1' at 'height_end', and then decrease to\n\
'0' at 'height_start'.  It can be constant, but may never increase.\n\
The value indicates the fraction of macropores which ends at the given\n\
where all macropores is assumed to start at the top.");
    static VCheck::StartValue start (1.0);
    static VCheck::EndValue end (0.0);
    static VCheck::FixedPoint fixpoint (0.0, 0.0);
    static VCheck::All distcheck (start, end, fixpoint,
                                  VCheck::non_increasing ());
    syntax.add_check ("distribution", distcheck);

    syntax.add ("pressure_initiate", "cm", Syntax::Const,
                "Pressure needed to initiate biopore flow.");
    alist.add ("pressure_initiate", -3.0);
    syntax.add ("pressure_end", "cm", Syntax::Const,
                "Pressure after biopore flow has been initiated.");
    alist.add ("pressure_end", -30.0);
    syntax.add ("pond_max", "mm", Check::non_negative (), Syntax::Const, "\
Maximum height of ponding before spilling into instant.\n\
After macropores are activated pond will have this height.");
    alist.add ("pond_max", 0.5);

    Librarian::add_type (Tertiary::component, "instant", alist, syntax, &make);
  }
} TertiaryInstant_syntax;

// tertiary_instant.C ends here.
<commit_msg>x61s<commit_after>// biopore_instant.C --- Instant movement in vertical geometry.
//
// Copyright 2008 Per Abrahamsen and KU.
//
// This file is part of Daisy.
//
// Daisy is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// Daisy is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser Public License for more details.
//
// You should have received a copy of the GNU Lesser Public License
// along with Daisy; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#define BUILD_DLL

#include "tertiary.h"
#include "geometry_vert.h"
#include "plf.h"
#include "check.h"
#include "vcheck.h"
#include "librarian.h"
#include "block.h"

struct TertiaryInstant : public Tertiary
{
  // Parameters.
  const PLF distribution;       // Where they end [cm ->]
  const double height_start;	// Height macropores start [cm]
  const double height_end;	// Height macropores end [cm]
  const double pressure_initiate;// Pressure needed to init pref.flow [cm]
  const double pressure_end;	 // Pressure after pref.flow has been init [cm]
  const double pond_max;	 // Pond height before activating pref.flow [mm]

  // Simulation.
  void tick (const Geometry&, const Soil&, const SoilWater&,
             const double dt,
             std::vector<double>& S_drain,
             std::vector<double>& S_matrix, Treelog& msg);
  void output (Log&) const;

  // Create and Destroy.
public:
  bool initialize (const Geometry&, const Scope& parent_scope,
                   const double pipe_position, Treelog& msg);
  bool check (const Geometry&, Treelog& msg) const;
  TertiaryInstant (Block& al);
};

void
TertiaryInstant::tick (const Geometry& geometry, const Soil& soil,
                       const SoilWater& soil_water,
                       const double dt,
                       std::vector<double>& S_drain,
                       std::vector<double>& S_matrix,
                       Treelog& msg)
{
#if 0
  const GeometryVert& geo = dynamic_cast<const GeometryVert&> (geometry);
  const size_t column_size = geo.column_size ();
  const size_t row_size = geo.row_size ();

  for (size_tt col = 0; col < column_size; col++)
    {
      // row_start and row_end should be set in initialize

    }
#endif
}

void
TertiaryInstant::output (Log&) const
{ }

bool
TertiaryInstant::initialize (const Geometry& geo,
                             const Scope& scope, const double pipe_position,
                             Treelog& msg)
{
  bool ok = true;
  // TODO
  return ok;
}

bool
TertiaryInstant::check (const Geometry& geo, Treelog& msg) const
{

  bool ok = true;
  if (!dynamic_cast<const GeometryVert*> (&geo))
    {
      msg.error ("\
This tertiary water transport model only works with vertical grid geometries");
      ok = false;
    }

  return ok;
}

TertiaryInstant::TertiaryInstant (Block& al)
  : Tertiary (al),
    distribution (al.plf ("distribution")),
    height_start (al.check ("height_start")
                  ? al.number ("height_start")
                  : distribution.x (distribution.size () - 1)),
    height_end (al.check ("height_end")
                ? al.number ("height_end")
                : distribution.x (0)),
    pressure_initiate (al.number ("pressure_initiate")),
    pressure_end (al.number ("pressure_end")),
    pond_max (al.number ("pond_max"))
{ }

static struct TertiaryInstantSyntax
{
  static Model& make (Block& al)
  { return *new TertiaryInstant (al); }

  TertiaryInstantSyntax ()
  {
    Syntax& syntax = *new Syntax ();
    AttributeList& alist = *new AttributeList ();
    alist.add ("description", "\
The area between 'height_start' and 'height_end' contains macropores,\n\
which are initiated when the water potential reach 'pressure_initiate',\n\
and then immediately emptied down to 'pressure_end'.  The water entering\n\
the macropore is distributed in soil below as a source term, according\n\
to the 'distribution' parameter.");

    syntax.add ("height_start", "cm", Check::non_positive (),
                Syntax::OptionalConst,
                "Macropores starts at this depth (a negative number).\n\
If not specified, use the last point in 'distribution'.");
    syntax.add ("height_end", "cm", Check::non_positive (),
                Syntax::OptionalConst,
                "Macropores ends at this depth (a negative number).\n\
If not specified, use the first point in 'distribution'.");
    syntax.add ("distribution", "cm", Syntax::Fraction (), Syntax::Const, "\
Distribution of macropore end points as a function of height.\n\
The function should start with '1' at 'height_end', and then decrease to\n\
'0' at 'height_start'.  It can be constant, but may never increase.\n\
The value indicates the fraction of macropores which ends at the given\n\
where all macropores is assumed to start at the top.");
    static VCheck::StartValue start (1.0);
    static VCheck::EndValue end (0.0);
    static VCheck::FixedPoint fixpoint (0.0, 0.0);
    static VCheck::All distcheck (start, end, fixpoint,
                                  VCheck::non_increasing ());
    syntax.add_check ("distribution", distcheck);

    syntax.add ("pressure_initiate", "cm", Syntax::Const,
                "Pressure needed to initiate biopore flow.");
    alist.add ("pressure_initiate", -3.0);
    syntax.add ("pressure_end", "cm", Syntax::Const,
                "Pressure after biopore flow has been initiated.");
    alist.add ("pressure_end", -30.0);
    syntax.add ("pond_max", "mm", Check::non_negative (), Syntax::Const, "\
Maximum height of ponding before spilling into instant.\n\
After macropores are activated pond will have this height.");
    alist.add ("pond_max", 0.5);

    Librarian::add_type (Tertiary::component, "instant", alist, syntax, &make);
  }
} TertiaryInstant_syntax;

// tertiary_instant.C ends here.
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

// RUN: cat %s | %cling -fno-rtti 2>&1 | FileCheck %s
// Test Interpreter::lookupType()
//
#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/LookupHelper.h"
#include "clang/AST/Type.h"

using namespace std;

//
//  Test Data.
//

.rawInput 1
class A {};
namespace N {
class B {};
namespace M {
class C {};
} // namespace M
} // namespace N
typedef int my_int;
using clang::QualType;
using cling::LookupHelper;
.rawInput 0

const LookupHelper& lookup = gCling->getLookupHelper();

QualType cl_A = lookup.findType("A", LookupHelper::WithDiagnostics);
cl_A.getAsString().c_str()
//CHECK: ({{[^)]+}}) "class A"

QualType cl_B_in_N = lookup.findType("N::B", LookupHelper::WithDiagnostics);
cl_B_in_N.getAsString().c_str()
//CHECK: ({{[^)]+}}) "N::B"

QualType cl_C_in_M = lookup.findType("N::M::C", LookupHelper::WithDiagnostics);
cl_C_in_M.getAsString().c_str()
//CHECK: ({{[^)]+}}) "N::M::C"

QualType builtin_int = lookup.findType("int", LookupHelper::WithDiagnostics);
builtin_int.getAsString().c_str()
//CHECK: ({{[^)]+}}) "int"

QualType typedef_my_int = lookup.findType("my_int", LookupHelper::WithDiagnostics);
typedef_my_int.getAsString().c_str()
//CHECK: ({{[^)]+}}) "my_int"

.q
<commit_msg>Adapt output to tweaked behavior<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

// RUN: cat %s | %cling -fno-rtti 2>&1 | FileCheck %s
// Test Interpreter::lookupType()
//
#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/LookupHelper.h"
#include "clang/AST/Type.h"

using namespace std;

//
//  Test Data.
//

.rawInput 1
class A {};
namespace N {
class B {};
namespace M {
class C {};
} // namespace M
} // namespace N
typedef int my_int;
using clang::QualType;
using cling::LookupHelper;
.rawInput 0

const LookupHelper& lookup = gCling->getLookupHelper();

QualType cl_A = lookup.findType("A", LookupHelper::WithDiagnostics);
cl_A.getAsString().c_str()
//CHECK: ({{[^)]+}}) "class A"

QualType cl_B_in_N = lookup.findType("N::B", LookupHelper::WithDiagnostics);
cl_B_in_N.getAsString().c_str()
//CHECK: ({{[^)]+}}) "class N::B"

QualType cl_C_in_M = lookup.findType("N::M::C", LookupHelper::WithDiagnostics);
cl_C_in_M.getAsString().c_str()
//CHECK: ({{[^)]+}}) "class N::M::C"

QualType builtin_int = lookup.findType("int", LookupHelper::WithDiagnostics);
builtin_int.getAsString().c_str()
//CHECK: ({{[^)]+}}) "int"

QualType typedef_my_int = lookup.findType("my_int", LookupHelper::WithDiagnostics);
typedef_my_int.getAsString().c_str()
//CHECK: ({{[^)]+}}) "my_int"

.q
<|endoftext|>


<commit_before>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include "TestBlock.hpp"

#include <nix/util/util.hpp>

#include <nix/valid/validate.hpp>
#include <nix/Exception.hpp>

#include <ctime>

using namespace std;
using namespace nix;
using namespace valid;

void TestBlock::setUp() {
    startup_time = time(NULL);
    file = File::open("test_block.h5", FileMode::Overwrite);

    section = file.createSection("foo_section", "metadata");

    block = file.createBlock("block_one", "dataset");
    block_other = file.createBlock("block_two", "dataset");
    block_null  = nullptr;
}

void TestBlock::tearDown() {
    file.close();
}

void TestBlock::testValidate() {
    valid::Result result = validate(block);
    CPPUNIT_ASSERT(result.getErrors().size() == 0);
    CPPUNIT_ASSERT(result.getWarnings().size() == 0);
}

void TestBlock::testId() {
    CPPUNIT_ASSERT(block.id().size() == 36);
}

void TestBlock::testName() {
    CPPUNIT_ASSERT(block.name() == "block_one");
}

void TestBlock::testType() {
    CPPUNIT_ASSERT(block.type() == "dataset");
    string typ = util::createId();
    block.type(typ);
    CPPUNIT_ASSERT(block.type() == typ);
}

void TestBlock::testDefinition() {
    string def = util::createId();
    block.definition(def);
    CPPUNIT_ASSERT(*block.definition() == def);
}

void TestBlock::testMetadataAccess() {
    CPPUNIT_ASSERT(!block.metadata());

    block.metadata(section);
    CPPUNIT_ASSERT(block.metadata());

    // test none-unsetter
    block.metadata(none);
    CPPUNIT_ASSERT(!block.metadata());
    // test deleter removing link too
    block.metadata(section);
    file.deleteSection(section.id());
    CPPUNIT_ASSERT(!block.metadata());
    // re-create section
    section = file.createSection("foo_section", "metadata");
}

void TestBlock::testSourceAccess() {
    vector<string> names = { "source_a", "source_b", "source_c", "source_d", "source_e" };

    CPPUNIT_ASSERT(block.sourceCount() == 0);
    CPPUNIT_ASSERT(block.sources().size() == 0);
    CPPUNIT_ASSERT(block.getSource("invalid_id") == false);
    CPPUNIT_ASSERT(!block.hasSource("invalid_id"));

    vector<string> ids;
    for (const auto &name : names) {
        Source src = block.createSource(name, "channel");
        CPPUNIT_ASSERT(src.name() == name);
        CPPUNIT_ASSERT(block.hasSource(name));
        CPPUNIT_ASSERT(block.hasSource(src));

        ids.push_back(src.id());
    }
    CPPUNIT_ASSERT_THROW(block.createSource(names[0], "channel"),
                         DuplicateName);

    CPPUNIT_ASSERT(block.sourceCount() == names.size());
    CPPUNIT_ASSERT(block.sources().size() == names.size());

    for (const auto &id : ids) {
        Source src = block.getSource(id);
        CPPUNIT_ASSERT(block.hasSource(id) == true);
        CPPUNIT_ASSERT(src.id() == id);

        block.deleteSource(id);
    }

    CPPUNIT_ASSERT(block.sourceCount() == 0);
    CPPUNIT_ASSERT(block.sources().size() == 0);
    CPPUNIT_ASSERT(block.getSource("invalid_id") == false);
}

void TestBlock::testDataArrayAccess() {
    vector<string> names = { "data_array_a", "data_array_b", "data_array_c",
                             "data_array_d", "data_array_e" };

    CPPUNIT_ASSERT(block.dataArrayCount() == 0);
    CPPUNIT_ASSERT(block.dataArrays().size() == 0);
    CPPUNIT_ASSERT(block.getDataArray("invalid_id") == false);

    vector<string> ids;
    for (const auto &name : names) {
        DataArray data_array = block.createDataArray(name,
                                                     "channel",
                                                     DataType::Double,
                                                     nix::NDSize({ 0 }));
        CPPUNIT_ASSERT(data_array.name() == name);
        CPPUNIT_ASSERT(data_array.type() == "channel");

        ids.push_back(data_array.id());
    }
    CPPUNIT_ASSERT_THROW(block.createDataArray(names[0], "channel", DataType::Double, nix::NDSize({ 0 })),
                         DuplicateName);

    CPPUNIT_ASSERT(block.dataArrayCount() == names.size());
    CPPUNIT_ASSERT(block.dataArrays().size() == names.size());

    for (const auto &name : names) {
        DataArray da_name = block.getDataArray(name);
        CPPUNIT_ASSERT(da_name);

        DataArray da_id = block.getDataArray(da_name.id());
        CPPUNIT_ASSERT(da_id);
        CPPUNIT_ASSERT_EQUAL(da_name.name(), da_id.name());
    }

    vector<DataArray> filteredArrays = block.dataArrays(util::TypeFilter<DataArray>("channel"));
    CPPUNIT_ASSERT_EQUAL(names.size(), filteredArrays.size());

    filteredArrays = block.dataArrays(util::NameFilter<DataArray>("data_array_c"));
    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), filteredArrays.size());
    if (filteredArrays.size() > 0) {
        boost::optional<std::string> name = filteredArrays[0].name();
        CPPUNIT_ASSERT(name && *name == "data_array_c");
    }

    for (auto it = ids.begin(); it != ids.end(); it++) {
        DataArray data_array = block.getDataArray(*it);
        CPPUNIT_ASSERT(block.hasDataArray(*it) == true);
        CPPUNIT_ASSERT(data_array.id() == *it);

        block.deleteDataArray(*it);
    }

    CPPUNIT_ASSERT(block.dataArrayCount() == 0);
    CPPUNIT_ASSERT(block.dataArrays().size() == 0);
    CPPUNIT_ASSERT(block.getDataArray("invalid_id") == false);

}

void TestBlock::testTagAccess() {
    vector<string> names = { "tag_a", "tag_b", "tag_c", "tag_d", "tag_e" };
    vector<string> array_names = { "data_array_a", "data_array_b", "data_array_c",
                                   "data_array_d", "data_array_e" };
    vector<DataArray> refs;
    for (const auto &name : array_names) {
        refs.push_back(block.createDataArray(name,
                                             "reference",
                                             DataType::Double,
                                             nix::NDSize({ 0 })));
    }

    CPPUNIT_ASSERT(block.tagCount() == 0);
    CPPUNIT_ASSERT(block.tags().size() == 0);
    CPPUNIT_ASSERT(block.getTag("invalid_id") == false);

    vector<string> ids;
    for (auto it = names.begin(); it != names.end(); ++it) {
        Tag tag = block.createTag(*it, "segment", {0.0, 2.0, 3.4});
        tag.references(refs);
        CPPUNIT_ASSERT(tag.name() == *it);

        ids.push_back(tag.id());
    }
    CPPUNIT_ASSERT_THROW(block.createTag(names[0], "segment", {0.0, 2.0, 3.4}),
                         DuplicateName);

    CPPUNIT_ASSERT(block.tagCount() == names.size());
    CPPUNIT_ASSERT(block.tags().size() == names.size());

    for (auto it = ids.begin(); it != ids.end(); ++it) {
        Tag tag = block.getTag(*it);
        CPPUNIT_ASSERT(block.hasTag(*it) == true);
        CPPUNIT_ASSERT(tag.id() == *it);

        block.deleteTag(*it);
    }

    CPPUNIT_ASSERT(block.tagCount() == 0);
    CPPUNIT_ASSERT(block.tags().size() == 0);
    CPPUNIT_ASSERT(block.getTag("invalid_id") == false);
}

void TestBlock::testMultiTagAccess() {
    vector<string> names = { "tag_a", "tag_b", "tag_c", "tag_d", "tag_e" };
    // create a valid positions data array below
    typedef boost::multi_array<double, 3>::index index;
    DataArray positions = block.createDataArray("array_one",
                                                "testdata",
                                                DataType::Double,
                                                nix::NDSize({ 3, 4, 2 }));
    boost::multi_array<double, 3> A(boost::extents[3][4][2]);
    int values = 0;
    for(index i = 0; i != 3; ++i)
        for(index j = 0; j != 4; ++j)
            for(index k = 0; k != 2; ++k)
                A[i][j][k] = values++;

    positions.setData(A);

    CPPUNIT_ASSERT(block.multiTagCount() == 0);
    CPPUNIT_ASSERT(block.multiTags().size() == 0);
    CPPUNIT_ASSERT(block.getMultiTag("invalid_id") == false);

    vector<string> ids;
    for (auto it = names.begin(); it != names.end(); it++) {
        MultiTag tag = block.createMultiTag(*it, "segment", positions);
        CPPUNIT_ASSERT(tag.name() == *it);

        ids.push_back(tag.id());
    }
    CPPUNIT_ASSERT_THROW(block.createMultiTag(names[0], "segment", positions),
                         DuplicateName);

    CPPUNIT_ASSERT(block.multiTagCount() == names.size());
    CPPUNIT_ASSERT(block.multiTags().size() == names.size());

    for (auto it = ids.begin(); it != ids.end(); it++) {
        MultiTag tag = block.getMultiTag(*it);
        CPPUNIT_ASSERT(block.hasMultiTag(*it) == true);
        CPPUNIT_ASSERT(tag.id() == *it);

        block.deleteMultiTag(*it);
    }

    CPPUNIT_ASSERT(block.multiTagCount() == 0);
    CPPUNIT_ASSERT(block.multiTags().size() == 0);
    CPPUNIT_ASSERT(block.getMultiTag("invalid_id") == false);
}

void TestBlock::testOperators() {
    CPPUNIT_ASSERT(block_null == false);
    CPPUNIT_ASSERT(block_null == none);

    CPPUNIT_ASSERT(block != false);
    CPPUNIT_ASSERT(block != none);

    CPPUNIT_ASSERT(block == block);
    CPPUNIT_ASSERT(block != block_other);

    block_other = block;
    CPPUNIT_ASSERT(block == block_other);

    block_other = none;
    CPPUNIT_ASSERT(block_null == false);
    CPPUNIT_ASSERT(block_null == none);
}

void TestBlock::testCreatedAt() {
    CPPUNIT_ASSERT(block.createdAt() >= startup_time);
    time_t past_time = time(NULL) - 10000000;
    block.forceCreatedAt(past_time);
    CPPUNIT_ASSERT(block.createdAt() == past_time);
}

void TestBlock::testUpdatedAt() {
    CPPUNIT_ASSERT(block.updatedAt() >= startup_time);
}
<commit_msg>[testBlock] extend source access tests<commit_after>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include "TestBlock.hpp"

#include <nix/util/util.hpp>

#include <nix/valid/validate.hpp>
#include <nix/Exception.hpp>

#include <ctime>

using namespace std;
using namespace nix;
using namespace valid;

void TestBlock::setUp() {
    startup_time = time(NULL);
    file = File::open("test_block.h5", FileMode::Overwrite);

    section = file.createSection("foo_section", "metadata");

    block = file.createBlock("block_one", "dataset");
    block_other = file.createBlock("block_two", "dataset");
    block_null  = nullptr;
}

void TestBlock::tearDown() {
    file.close();
}

void TestBlock::testValidate() {
    valid::Result result = validate(block);
    CPPUNIT_ASSERT(result.getErrors().size() == 0);
    CPPUNIT_ASSERT(result.getWarnings().size() == 0);
}

void TestBlock::testId() {
    CPPUNIT_ASSERT(block.id().size() == 36);
}

void TestBlock::testName() {
    CPPUNIT_ASSERT(block.name() == "block_one");
}

void TestBlock::testType() {
    CPPUNIT_ASSERT(block.type() == "dataset");
    string typ = util::createId();
    block.type(typ);
    CPPUNIT_ASSERT(block.type() == typ);
}

void TestBlock::testDefinition() {
    string def = util::createId();
    block.definition(def);
    CPPUNIT_ASSERT(*block.definition() == def);
}

void TestBlock::testMetadataAccess() {
    CPPUNIT_ASSERT(!block.metadata());

    block.metadata(section);
    CPPUNIT_ASSERT(block.metadata());

    // test none-unsetter
    block.metadata(none);
    CPPUNIT_ASSERT(!block.metadata());
    // test deleter removing link too
    block.metadata(section);
    file.deleteSection(section.id());
    CPPUNIT_ASSERT(!block.metadata());
    // re-create section
    section = file.createSection("foo_section", "metadata");
}

void TestBlock::testSourceAccess() {
    vector<string> names = { "source_a", "source_b", "source_c", "source_d", "source_e" };
    Source s;
    CPPUNIT_ASSERT_THROW(block.hasSource(s), std::runtime_error);
    CPPUNIT_ASSERT(block.sourceCount() == 0);
    CPPUNIT_ASSERT(block.sources().size() == 0);
    CPPUNIT_ASSERT(block.getSource("invalid_id") == false);
    CPPUNIT_ASSERT(!block.hasSource("invalid_id"));

    vector<string> ids;
    for (const auto &name : names) {
        Source src = block.createSource(name, "channel");
        CPPUNIT_ASSERT(src.name() == name);
        CPPUNIT_ASSERT(block.hasSource(name));
        CPPUNIT_ASSERT(block.hasSource(src));

        ids.push_back(src.id());
    }
    CPPUNIT_ASSERT_THROW(block.createSource(names[0], "channel"),
                         DuplicateName);

    CPPUNIT_ASSERT(block.sourceCount() == names.size());
    CPPUNIT_ASSERT(block.sources().size() == names.size());

    for (const auto &id : ids) {
        Source src = block.getSource(id);
        CPPUNIT_ASSERT(block.hasSource(id) == true);
        CPPUNIT_ASSERT(src.id() == id);
        block.deleteSource(id);
    }

    s = block.createSource("test", "test");
    CPPUNIT_ASSERT(block.sourceCount() == 1);
    CPPUNIT_ASSERT_NO_THROW(block.deleteSource(s));

    CPPUNIT_ASSERT(block.sourceCount() == 0);
    CPPUNIT_ASSERT(block.sources().size() == 0);
    CPPUNIT_ASSERT(block.getSource("invalid_id") == false);
}

void TestBlock::testDataArrayAccess() {
    vector<string> names = { "data_array_a", "data_array_b", "data_array_c",
                             "data_array_d", "data_array_e" };

    CPPUNIT_ASSERT(block.dataArrayCount() == 0);
    CPPUNIT_ASSERT(block.dataArrays().size() == 0);
    CPPUNIT_ASSERT(block.getDataArray("invalid_id") == false);

    vector<string> ids;
    for (const auto &name : names) {
        DataArray data_array = block.createDataArray(name,
                                                     "channel",
                                                     DataType::Double,
                                                     nix::NDSize({ 0 }));
        CPPUNIT_ASSERT(data_array.name() == name);
        CPPUNIT_ASSERT(data_array.type() == "channel");

        ids.push_back(data_array.id());
    }
    CPPUNIT_ASSERT_THROW(block.createDataArray(names[0], "channel", DataType::Double, nix::NDSize({ 0 })),
                         DuplicateName);

    CPPUNIT_ASSERT(block.dataArrayCount() == names.size());
    CPPUNIT_ASSERT(block.dataArrays().size() == names.size());

    for (const auto &name : names) {
        DataArray da_name = block.getDataArray(name);
        CPPUNIT_ASSERT(da_name);

        DataArray da_id = block.getDataArray(da_name.id());
        CPPUNIT_ASSERT(da_id);
        CPPUNIT_ASSERT_EQUAL(da_name.name(), da_id.name());
    }

    vector<DataArray> filteredArrays = block.dataArrays(util::TypeFilter<DataArray>("channel"));
    CPPUNIT_ASSERT_EQUAL(names.size(), filteredArrays.size());

    filteredArrays = block.dataArrays(util::NameFilter<DataArray>("data_array_c"));
    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), filteredArrays.size());
    if (filteredArrays.size() > 0) {
        boost::optional<std::string> name = filteredArrays[0].name();
        CPPUNIT_ASSERT(name && *name == "data_array_c");
    }

    for (auto it = ids.begin(); it != ids.end(); it++) {
        DataArray data_array = block.getDataArray(*it);
        CPPUNIT_ASSERT(block.hasDataArray(*it) == true);
        CPPUNIT_ASSERT(data_array.id() == *it);

        block.deleteDataArray(*it);
    }

    CPPUNIT_ASSERT(block.dataArrayCount() == 0);
    CPPUNIT_ASSERT(block.dataArrays().size() == 0);
    CPPUNIT_ASSERT(block.getDataArray("invalid_id") == false);

}

void TestBlock::testTagAccess() {
    vector<string> names = { "tag_a", "tag_b", "tag_c", "tag_d", "tag_e" };
    vector<string> array_names = { "data_array_a", "data_array_b", "data_array_c",
                                   "data_array_d", "data_array_e" };
    vector<DataArray> refs;
    for (const auto &name : array_names) {
        refs.push_back(block.createDataArray(name,
                                             "reference",
                                             DataType::Double,
                                             nix::NDSize({ 0 })));
    }

    CPPUNIT_ASSERT(block.tagCount() == 0);
    CPPUNIT_ASSERT(block.tags().size() == 0);
    CPPUNIT_ASSERT(block.getTag("invalid_id") == false);

    vector<string> ids;
    for (auto it = names.begin(); it != names.end(); ++it) {
        Tag tag = block.createTag(*it, "segment", {0.0, 2.0, 3.4});
        tag.references(refs);
        CPPUNIT_ASSERT(tag.name() == *it);

        ids.push_back(tag.id());
    }
    CPPUNIT_ASSERT_THROW(block.createTag(names[0], "segment", {0.0, 2.0, 3.4}),
                         DuplicateName);

    CPPUNIT_ASSERT(block.tagCount() == names.size());
    CPPUNIT_ASSERT(block.tags().size() == names.size());

    for (auto it = ids.begin(); it != ids.end(); ++it) {
        Tag tag = block.getTag(*it);
        CPPUNIT_ASSERT(block.hasTag(*it) == true);
        CPPUNIT_ASSERT(tag.id() == *it);

        block.deleteTag(*it);
    }

    CPPUNIT_ASSERT(block.tagCount() == 0);
    CPPUNIT_ASSERT(block.tags().size() == 0);
    CPPUNIT_ASSERT(block.getTag("invalid_id") == false);
}

void TestBlock::testMultiTagAccess() {
    vector<string> names = { "tag_a", "tag_b", "tag_c", "tag_d", "tag_e" };
    // create a valid positions data array below
    typedef boost::multi_array<double, 3>::index index;
    DataArray positions = block.createDataArray("array_one",
                                                "testdata",
                                                DataType::Double,
                                                nix::NDSize({ 3, 4, 2 }));
    boost::multi_array<double, 3> A(boost::extents[3][4][2]);
    int values = 0;
    for(index i = 0; i != 3; ++i)
        for(index j = 0; j != 4; ++j)
            for(index k = 0; k != 2; ++k)
                A[i][j][k] = values++;

    positions.setData(A);

    CPPUNIT_ASSERT(block.multiTagCount() == 0);
    CPPUNIT_ASSERT(block.multiTags().size() == 0);
    CPPUNIT_ASSERT(block.getMultiTag("invalid_id") == false);

    vector<string> ids;
    for (auto it = names.begin(); it != names.end(); it++) {
        MultiTag tag = block.createMultiTag(*it, "segment", positions);
        CPPUNIT_ASSERT(tag.name() == *it);

        ids.push_back(tag.id());
    }
    CPPUNIT_ASSERT_THROW(block.createMultiTag(names[0], "segment", positions),
                         DuplicateName);

    CPPUNIT_ASSERT(block.multiTagCount() == names.size());
    CPPUNIT_ASSERT(block.multiTags().size() == names.size());

    for (auto it = ids.begin(); it != ids.end(); it++) {
        MultiTag tag = block.getMultiTag(*it);
        CPPUNIT_ASSERT(block.hasMultiTag(*it) == true);
        CPPUNIT_ASSERT(tag.id() == *it);

        block.deleteMultiTag(*it);
    }

    CPPUNIT_ASSERT(block.multiTagCount() == 0);
    CPPUNIT_ASSERT(block.multiTags().size() == 0);
    CPPUNIT_ASSERT(block.getMultiTag("invalid_id") == false);
}

void TestBlock::testOperators() {
    CPPUNIT_ASSERT(block_null == false);
    CPPUNIT_ASSERT(block_null == none);

    CPPUNIT_ASSERT(block != false);
    CPPUNIT_ASSERT(block != none);

    CPPUNIT_ASSERT(block == block);
    CPPUNIT_ASSERT(block != block_other);

    block_other = block;
    CPPUNIT_ASSERT(block == block_other);

    block_other = none;
    CPPUNIT_ASSERT(block_null == false);
    CPPUNIT_ASSERT(block_null == none);
}

void TestBlock::testCreatedAt() {
    CPPUNIT_ASSERT(block.createdAt() >= startup_time);
    time_t past_time = time(NULL) - 10000000;
    block.forceCreatedAt(past_time);
    CPPUNIT_ASSERT(block.createdAt() == past_time);
}

void TestBlock::testUpdatedAt() {
    CPPUNIT_ASSERT(block.updatedAt() >= startup_time);
}
<|endoftext|>


<commit_before>/***********************************************************************
    filename:   CEGUIRenderedString.cpp
    created:    25/05/2009
    author:     Paul Turner
 *************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2009 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 "CEGUIRenderedString.h"
#include "CEGUIRenderedStringComponent.h"
#include "CEGUIExceptions.h"

// Start of CEGUI namespace section
namespace CEGUI
{
//----------------------------------------------------------------------------//
RenderedString::RenderedString()
{
    // set up initial line info
    appendLineBreak();
}

//----------------------------------------------------------------------------//
RenderedString::~RenderedString()
{
    clearComponents();
}

//----------------------------------------------------------------------------//
void RenderedString::appendComponent(const RenderedStringComponent& component)
{
    d_components.push_back(component.clone());
    ++d_lines.back().second;
}

//----------------------------------------------------------------------------//
void RenderedString::clearComponents()
{
    clearComponentList(d_components);
    d_lines.clear();
}

//----------------------------------------------------------------------------//
size_t RenderedString::getComponentCount() const
{
    return d_components.size();
}

//----------------------------------------------------------------------------//
RenderedString::RenderedString(const RenderedString& other)
{
    cloneComponentList(other.d_components);
    d_lines = other.d_lines;
}

//----------------------------------------------------------------------------//
RenderedString& RenderedString::operator=(const RenderedString& rhs)
{
    cloneComponentList(rhs.d_components);
    d_lines = rhs.d_lines;
    return *this;
}

//----------------------------------------------------------------------------//
void RenderedString::cloneComponentList(const ComponentList& list)
{
    clearComponentList(d_components);

    for (size_t i = 0; i < list.size(); ++i)
        d_components.push_back(list[i]->clone());
}

//----------------------------------------------------------------------------//
void RenderedString::clearComponentList(ComponentList& list)
{
    for (size_t i = 0; i < list.size(); ++i)
        delete list[i];

    list.clear();
}

//----------------------------------------------------------------------------//
void RenderedString::split(const size_t line, float split_point,
                           RenderedString& left)
{
    // FIXME: This function is big and nasty; it breaks all the rules for a
    // 'good' function and desperately needs some refactoring work done to it.
    // On the plus side, it does seem to work though ;)

    if (line >= getLineCount())
        throw InvalidRequestException("RenderedString::split: "
            "line number specified is invalid.");

    left.clearComponents();

    if (d_components.empty())
        return;

    // move all components in lines prior to the line being split to the left
    if (line > 0)
    {
        // calculate size of range
        const size_t sz = d_lines[line - 1].first + d_lines[line - 1].second;
        // range start
        ComponentList::iterator cb = d_components.begin();
        // range end (exclusive)
        ComponentList::iterator ce = cb + sz;
        // copy components to left side
        left.d_components.assign(cb, ce);
        // erase components from this side.
        d_components.erase(cb, ce);

        LineList::iterator lb = d_lines.begin();
        LineList::iterator le = lb + line;
        // copy lines to left side
        left.d_lines.assign(lb, le);
        // erase lines from this side
        d_lines.erase(lb, le);
    }

    // find the component where the requested split point lies.
    float partial_extent = 0;

    size_t idx = 0;
    const size_t last_component = d_lines[0].second;
    for (; idx < last_component; ++idx)
    {
        partial_extent += d_components[idx]->getPixelSize().d_width;

        if (split_point <= partial_extent)
            break;
    }

    // case where split point is past the end
    if (idx >= last_component)
    {
        // transfer this line's components to the 'left' string.
        //
        // calculate size of range
        const size_t sz = d_lines[0].second;
        // range start
        ComponentList::iterator cb = d_components.begin();
        // range end (exclusive)
        ComponentList::iterator ce = cb + sz;
        // copy components to left side
        left.d_components.insert(left.d_components.end(), cb, ce);
        // erase components from this side.
        d_components.erase(cb, ce);

        // copy line info to left side
        left.d_lines.push_back(d_lines[0]);
        // erase line from this side
        d_lines.erase(d_lines.begin());

        // fix up lines in this object
        for (size_t comp = 0, i = 0; i < d_lines.size(); ++i)
        {
            d_lines[i].first = comp;
            comp += d_lines[i].second;
        }

        return;
    }

    left.appendLineBreak();
    const size_t left_line = left.getLineCount() - 1;
    // Everything up to 'idx' is xfered to 'left'
    for (size_t i = 0; i < idx; ++i)
    {
        left.d_components.push_back(d_components[0]);
        d_components.erase(d_components.begin());
        ++left.d_lines[left_line].second;
        --d_lines[0].second;
    }

    // now to split item 'idx' putting half in left and leaving half in this.
    RenderedStringComponent* c = d_components[0];
    if (c->canSplit())
    {
        RenderedStringComponent* lc =
            c->split(split_point - (partial_extent - c->getPixelSize().d_width),
                     idx == 0);

        if (lc)
        {
            left.d_components.push_back(lc);
            ++left.d_lines[left_line].second;
        }
    }
    // can't split, so xfer the whole component to the left (FIX #306)
    else
    {
        left.d_components.push_back(d_components[0]);
        d_components.erase(d_components.begin());
        ++left.d_lines[left_line].second;
        --d_lines[0].second;
    }

    // fix up lines in this object
    for (size_t comp = 0, i = 0; i < d_lines.size(); ++i)
    {
        d_lines[i].first = comp;
        comp += d_lines[i].second;
    }
}

//----------------------------------------------------------------------------//
void RenderedString::appendLineBreak()
{
    const size_t first_component = d_lines.empty() ? 0 :
        d_lines.back().first + d_lines.back().second;

    d_lines.push_back(LineInfo(first_component, 0));
}

//----------------------------------------------------------------------------//
size_t RenderedString::getLineCount() const
{
    return d_lines.size();
}

//----------------------------------------------------------------------------//
Size RenderedString::getPixelSize(const size_t line) const
{
    if (line >= getLineCount())
        throw InvalidRequestException("RenderedString::getPixelSize: "
            "line number specified is invalid.");

    Size sz(0, 0);

    const size_t end_component = d_lines[line].first + d_lines[line].second;
    for (size_t i = d_lines[line].first; i < end_component; ++i)
    {
        const Size comp_sz(d_components[i]->getPixelSize());
        sz.d_width += comp_sz.d_width;

        if (comp_sz.d_height > sz.d_height)
            sz.d_height = comp_sz.d_height;
    }

    return sz;
}

//----------------------------------------------------------------------------//
size_t RenderedString::getSpaceCount(const size_t line) const
{
    if (line >= getLineCount())
        throw InvalidRequestException("RenderedString::getSpaceCount: "
            "line number specified is invalid.");

    size_t space_count = 0;

    const size_t end_component = d_lines[line].first + d_lines[line].second;
    for (size_t i = d_lines[line].first; i < end_component; ++i)
        space_count += d_components[i]->getSpaceCount();

    return space_count;
}

//----------------------------------------------------------------------------//
void RenderedString::draw(const size_t line, GeometryBuffer& buffer,
                          const Vector2& position,
                          const ColourRect* mod_colours, const Rect* clip_rect,
                          const float space_extra) const
{
    if (line >= getLineCount())
        throw InvalidRequestException("RenderedString::draw: "
            "line number specified is invalid.");

    const float render_height = getPixelSize(line).d_height;

    Vector2 comp_pos(position);

    const size_t end_component = d_lines[line].first + d_lines[line].second;
    for (size_t i = d_lines[line].first; i < end_component; ++i)
    {
        d_components[i]->draw(buffer, comp_pos, mod_colours, clip_rect,
                              render_height, space_extra);
        comp_pos.d_x += d_components[i]->getPixelSize().d_width;
    }
}

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

} // End of  CEGUI namespace section
<commit_msg>Fix the fix that fixed the hang in the wordwrapping, so that long items are wrapped onto their own line.<commit_after>/***********************************************************************
    filename:   CEGUIRenderedString.cpp
    created:    25/05/2009
    author:     Paul Turner
 *************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2009 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 "CEGUIRenderedString.h"
#include "CEGUIRenderedStringComponent.h"
#include "CEGUIExceptions.h"

// Start of CEGUI namespace section
namespace CEGUI
{
//----------------------------------------------------------------------------//
RenderedString::RenderedString()
{
    // set up initial line info
    appendLineBreak();
}

//----------------------------------------------------------------------------//
RenderedString::~RenderedString()
{
    clearComponents();
}

//----------------------------------------------------------------------------//
void RenderedString::appendComponent(const RenderedStringComponent& component)
{
    d_components.push_back(component.clone());
    ++d_lines.back().second;
}

//----------------------------------------------------------------------------//
void RenderedString::clearComponents()
{
    clearComponentList(d_components);
    d_lines.clear();
}

//----------------------------------------------------------------------------//
size_t RenderedString::getComponentCount() const
{
    return d_components.size();
}

//----------------------------------------------------------------------------//
RenderedString::RenderedString(const RenderedString& other)
{
    cloneComponentList(other.d_components);
    d_lines = other.d_lines;
}

//----------------------------------------------------------------------------//
RenderedString& RenderedString::operator=(const RenderedString& rhs)
{
    cloneComponentList(rhs.d_components);
    d_lines = rhs.d_lines;
    return *this;
}

//----------------------------------------------------------------------------//
void RenderedString::cloneComponentList(const ComponentList& list)
{
    clearComponentList(d_components);

    for (size_t i = 0; i < list.size(); ++i)
        d_components.push_back(list[i]->clone());
}

//----------------------------------------------------------------------------//
void RenderedString::clearComponentList(ComponentList& list)
{
    for (size_t i = 0; i < list.size(); ++i)
        delete list[i];

    list.clear();
}

//----------------------------------------------------------------------------//
void RenderedString::split(const size_t line, float split_point,
                           RenderedString& left)
{
    // FIXME: This function is big and nasty; it breaks all the rules for a
    // 'good' function and desperately needs some refactoring work done to it.
    // On the plus side, it does seem to work though ;)

    if (line >= getLineCount())
        throw InvalidRequestException("RenderedString::split: "
            "line number specified is invalid.");

    left.clearComponents();

    if (d_components.empty())
        return;

    // move all components in lines prior to the line being split to the left
    if (line > 0)
    {
        // calculate size of range
        const size_t sz = d_lines[line - 1].first + d_lines[line - 1].second;
        // range start
        ComponentList::iterator cb = d_components.begin();
        // range end (exclusive)
        ComponentList::iterator ce = cb + sz;
        // copy components to left side
        left.d_components.assign(cb, ce);
        // erase components from this side.
        d_components.erase(cb, ce);

        LineList::iterator lb = d_lines.begin();
        LineList::iterator le = lb + line;
        // copy lines to left side
        left.d_lines.assign(lb, le);
        // erase lines from this side
        d_lines.erase(lb, le);
    }

    // find the component where the requested split point lies.
    float partial_extent = 0;

    size_t idx = 0;
    const size_t last_component = d_lines[0].second;
    for (; idx < last_component; ++idx)
    {
        partial_extent += d_components[idx]->getPixelSize().d_width;

        if (split_point <= partial_extent)
            break;
    }

    // case where split point is past the end
    if (idx >= last_component)
    {
        // transfer this line's components to the 'left' string.
        //
        // calculate size of range
        const size_t sz = d_lines[0].second;
        // range start
        ComponentList::iterator cb = d_components.begin();
        // range end (exclusive)
        ComponentList::iterator ce = cb + sz;
        // copy components to left side
        left.d_components.insert(left.d_components.end(), cb, ce);
        // erase components from this side.
        d_components.erase(cb, ce);

        // copy line info to left side
        left.d_lines.push_back(d_lines[0]);
        // erase line from this side
        d_lines.erase(d_lines.begin());

        // fix up lines in this object
        for (size_t comp = 0, i = 0; i < d_lines.size(); ++i)
        {
            d_lines[i].first = comp;
            comp += d_lines[i].second;
        }

        return;
    }

    left.appendLineBreak();
    const size_t left_line = left.getLineCount() - 1;
    // Everything up to 'idx' is xfered to 'left'
    for (size_t i = 0; i < idx; ++i)
    {
        left.d_components.push_back(d_components[0]);
        d_components.erase(d_components.begin());
        ++left.d_lines[left_line].second;
        --d_lines[0].second;
    }

    // now to split item 'idx' putting half in left and leaving half in this.
    RenderedStringComponent* c = d_components[0];
    if (c->canSplit())
    {
        RenderedStringComponent* lc =
            c->split(split_point - (partial_extent - c->getPixelSize().d_width),
                     idx == 0);

        if (lc)
        {
            left.d_components.push_back(lc);
            ++left.d_lines[left_line].second;
        }
    }
    // can't split, if component width is >= split_point xfer the whole
    // component to it's own line in the left part (FIX #306)
    else if (c->getPixelSize().d_width >= split_point)
    {
        left.appendLineBreak();
        left.d_components.push_back(d_components[0]);
        d_components.erase(d_components.begin());
        ++left.d_lines[left_line + 1].second;
        --d_lines[0].second;
    }

    // fix up lines in this object
    for (size_t comp = 0, i = 0; i < d_lines.size(); ++i)
    {
        d_lines[i].first = comp;
        comp += d_lines[i].second;
    }
}

//----------------------------------------------------------------------------//
void RenderedString::appendLineBreak()
{
    const size_t first_component = d_lines.empty() ? 0 :
        d_lines.back().first + d_lines.back().second;

    d_lines.push_back(LineInfo(first_component, 0));
}

//----------------------------------------------------------------------------//
size_t RenderedString::getLineCount() const
{
    return d_lines.size();
}

//----------------------------------------------------------------------------//
Size RenderedString::getPixelSize(const size_t line) const
{
    if (line >= getLineCount())
        throw InvalidRequestException("RenderedString::getPixelSize: "
            "line number specified is invalid.");

    Size sz(0, 0);

    const size_t end_component = d_lines[line].first + d_lines[line].second;
    for (size_t i = d_lines[line].first; i < end_component; ++i)
    {
        const Size comp_sz(d_components[i]->getPixelSize());
        sz.d_width += comp_sz.d_width;

        if (comp_sz.d_height > sz.d_height)
            sz.d_height = comp_sz.d_height;
    }

    return sz;
}

//----------------------------------------------------------------------------//
size_t RenderedString::getSpaceCount(const size_t line) const
{
    if (line >= getLineCount())
        throw InvalidRequestException("RenderedString::getSpaceCount: "
            "line number specified is invalid.");

    size_t space_count = 0;

    const size_t end_component = d_lines[line].first + d_lines[line].second;
    for (size_t i = d_lines[line].first; i < end_component; ++i)
        space_count += d_components[i]->getSpaceCount();

    return space_count;
}

//----------------------------------------------------------------------------//
void RenderedString::draw(const size_t line, GeometryBuffer& buffer,
                          const Vector2& position,
                          const ColourRect* mod_colours, const Rect* clip_rect,
                          const float space_extra) const
{
    if (line >= getLineCount())
        throw InvalidRequestException("RenderedString::draw: "
            "line number specified is invalid.");

    const float render_height = getPixelSize(line).d_height;

    Vector2 comp_pos(position);

    const size_t end_component = d_lines[line].first + d_lines[line].second;
    for (size_t i = d_lines[line].first; i < end_component; ++i)
    {
        d_components[i]->draw(buffer, comp_pos, mod_colours, clip_rect,
                              render_height, space_extra);
        comp_pos.d_x += d_components[i]->getPixelSize().d_width;
    }
}

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

} // End of  CEGUI namespace section
<|endoftext|>


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

#include "chrome/browser/js_modal_dialog.h"

#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "ipc/ipc_message.h"

JavaScriptAppModalDialog::JavaScriptAppModalDialog(
    JavaScriptMessageBoxClient* client,
    const std::wstring& title,
    int dialog_flags,
    const std::wstring& message_text,
    const std::wstring& default_prompt_text,
    bool display_suppress_checkbox,
    bool is_before_unload_dialog,
    IPC::Message* reply_msg)
    : AppModalDialog(client->AsTabContents(), title),
      client_(client),
      extension_host_(client->AsExtensionHost()),
      dialog_flags_(dialog_flags),
      message_text_(message_text),
      default_prompt_text_(default_prompt_text),
      display_suppress_checkbox_(display_suppress_checkbox),
      is_before_unload_dialog_(is_before_unload_dialog),
      reply_msg_(reply_msg) {
  DCHECK((tab_contents_ != NULL) != (extension_host_ != NULL));
  InitNotifications();
}

JavaScriptAppModalDialog::~JavaScriptAppModalDialog() {
}

void JavaScriptAppModalDialog::Observe(NotificationType type,
                                       const NotificationSource& source,
                                       const NotificationDetails& details) {
  if (skip_this_dialog_)
    return;

  if (NotificationType::EXTENSION_HOST_DESTROYED == type &&
      Details<ExtensionHost>(extension_host_) != details)
    return;

  // If we reach here, we know the notification is relevant to us, either
  // because we're only observing applicable sources or because we passed the
  // check above. Both of those indicate that we should ignore this dialog.
  // Also clear the client, since it's now invalid.
  skip_this_dialog_ = true;
  client_ = NULL;
  CloseModalDialog();
}

void JavaScriptAppModalDialog::InitNotifications() {
  // Make sure we get relevant navigation notifications so we know when our
  // parent contents will disappear or navigate to a different page.
  if (tab_contents_) {
    registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
                   Source<NavigationController>(&tab_contents_->controller()));
    registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
                   Source<TabContents>(tab_contents_));
  } else if (extension_host_) {
    // EXTENSION_HOST_DESTROYED uses the Profile as its source, but we care
    // about the ExtensionHost (which is passed in the details).
    registrar_.Add(this, NotificationType::EXTENSION_HOST_DESTROYED,
                   NotificationService::AllSources());
  } else {
    NOTREACHED();
  }
}

void JavaScriptAppModalDialog::OnCancel() {
  // We need to do this before WM_DESTROY (WindowClosing()) as any parent frame
  // will receive its activation messages before this dialog receives
  // WM_DESTROY. The parent frame would then try to activate any modal dialogs
  // that were still open in the ModalDialogQueue, which would send activation
  // back to this one. The framework should be improved to handle this, so this
  // is a temporary workaround.
  CompleteDialog();

  if (!skip_this_dialog_) {
    client_->OnMessageBoxClosed(reply_msg_, false, std::wstring());
  }

  Cleanup();
}

void JavaScriptAppModalDialog::OnAccept(const std::wstring& prompt_text,
                                        bool suppress_js_messages) {
  CompleteDialog();

  if (!skip_this_dialog_) {
    client_->OnMessageBoxClosed(reply_msg_, true, prompt_text);
    if (suppress_js_messages)
      client_->SetSuppressMessageBoxes(true);
  }

  Cleanup();
}

void JavaScriptAppModalDialog::OnClose() {
  Cleanup();
}

void JavaScriptAppModalDialog::Cleanup() {
  if (skip_this_dialog_) {
    // We can't use the client_, because we might be in the process of
    // destroying it.
    if (tab_contents_)
      tab_contents_->OnMessageBoxClosed(reply_msg_, false, L"");
// The extension_host_ will always be a dirty pointer on OS X because the alert
// window will cause the extension popup to close since it is resigning its key
// state, destroying the host. http://crbug.com/29355
#if !defined(OS_MACOSX)
    else if (extension_host_)
      extension_host_->OnMessageBoxClosed(reply_msg_, false, L"");
    else
      NOTREACHED();
#endif
  }
  AppModalDialog::Cleanup();
}

<commit_msg>Truncate very long javascript alert messages. They can overflow the UI and on Linux cause crashes.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/js_modal_dialog.h"

#include "base/string_util.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "ipc/ipc_message.h"

namespace {

// The maximum sizes of various texts passed to us from javascript.
const int kMessageTextMaxSize = 3000;
const int kDefaultPromptTextSize = 2000;

}  // namespace

JavaScriptAppModalDialog::JavaScriptAppModalDialog(
    JavaScriptMessageBoxClient* client,
    const std::wstring& title,
    int dialog_flags,
    const std::wstring& message_text,
    const std::wstring& default_prompt_text,
    bool display_suppress_checkbox,
    bool is_before_unload_dialog,
    IPC::Message* reply_msg)
    : AppModalDialog(client->AsTabContents(), title),
      client_(client),
      extension_host_(client->AsExtensionHost()),
      dialog_flags_(dialog_flags),
      display_suppress_checkbox_(display_suppress_checkbox),
      is_before_unload_dialog_(is_before_unload_dialog),
      reply_msg_(reply_msg) {
  // We trim the various parts of the message dialog because otherwise we can
  // overflow the message dialog (and crash/hang the GTK+ version).
  ElideString(message_text, kMessageTextMaxSize, &message_text_);
  ElideString(default_prompt_text, kDefaultPromptTextSize,
              &default_prompt_text_);

  DCHECK((tab_contents_ != NULL) != (extension_host_ != NULL));
  InitNotifications();
}

JavaScriptAppModalDialog::~JavaScriptAppModalDialog() {
}

void JavaScriptAppModalDialog::Observe(NotificationType type,
                                       const NotificationSource& source,
                                       const NotificationDetails& details) {
  if (skip_this_dialog_)
    return;

  if (NotificationType::EXTENSION_HOST_DESTROYED == type &&
      Details<ExtensionHost>(extension_host_) != details)
    return;

  // If we reach here, we know the notification is relevant to us, either
  // because we're only observing applicable sources or because we passed the
  // check above. Both of those indicate that we should ignore this dialog.
  // Also clear the client, since it's now invalid.
  skip_this_dialog_ = true;
  client_ = NULL;
  CloseModalDialog();
}

void JavaScriptAppModalDialog::InitNotifications() {
  // Make sure we get relevant navigation notifications so we know when our
  // parent contents will disappear or navigate to a different page.
  if (tab_contents_) {
    registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
                   Source<NavigationController>(&tab_contents_->controller()));
    registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
                   Source<TabContents>(tab_contents_));
  } else if (extension_host_) {
    // EXTENSION_HOST_DESTROYED uses the Profile as its source, but we care
    // about the ExtensionHost (which is passed in the details).
    registrar_.Add(this, NotificationType::EXTENSION_HOST_DESTROYED,
                   NotificationService::AllSources());
  } else {
    NOTREACHED();
  }
}

void JavaScriptAppModalDialog::OnCancel() {
  // We need to do this before WM_DESTROY (WindowClosing()) as any parent frame
  // will receive its activation messages before this dialog receives
  // WM_DESTROY. The parent frame would then try to activate any modal dialogs
  // that were still open in the ModalDialogQueue, which would send activation
  // back to this one. The framework should be improved to handle this, so this
  // is a temporary workaround.
  CompleteDialog();

  if (!skip_this_dialog_) {
    client_->OnMessageBoxClosed(reply_msg_, false, std::wstring());
  }

  Cleanup();
}

void JavaScriptAppModalDialog::OnAccept(const std::wstring& prompt_text,
                                        bool suppress_js_messages) {
  CompleteDialog();

  if (!skip_this_dialog_) {
    client_->OnMessageBoxClosed(reply_msg_, true, prompt_text);
    if (suppress_js_messages)
      client_->SetSuppressMessageBoxes(true);
  }

  Cleanup();
}

void JavaScriptAppModalDialog::OnClose() {
  Cleanup();
}

void JavaScriptAppModalDialog::Cleanup() {
  if (skip_this_dialog_) {
    // We can't use the client_, because we might be in the process of
    // destroying it.
    if (tab_contents_)
      tab_contents_->OnMessageBoxClosed(reply_msg_, false, L"");
// The extension_host_ will always be a dirty pointer on OS X because the alert
// window will cause the extension popup to close since it is resigning its key
// state, destroying the host. http://crbug.com/29355
#if !defined(OS_MACOSX)
    else if (extension_host_)
      extension_host_->OnMessageBoxClosed(reply_msg_, false, L"");
    else
      NOTREACHED();
#endif
  }
  AppModalDialog::Cleanup();
}

<|endoftext|>