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

#include <fstream>
#include <iostream>
#include <map>
#include <set>
#include <string>

#include "cartographer/common/histogram.h"
#include "cartographer/common/make_unique.h"
#include "cartographer_ros/msg_conversion.h"
#include "gflags/gflags.h"
#include "glog/logging.h"
#include "nav_msgs/Odometry.h"
#include "ros/ros.h"
#include "ros/time.h"
#include "rosbag/bag.h"
#include "rosbag/view.h"
#include "sensor_msgs/Imu.h"
#include "sensor_msgs/LaserScan.h"
#include "sensor_msgs/MultiEchoLaserScan.h"
#include "sensor_msgs/PointCloud2.h"
#include "tf2_eigen/tf2_eigen.h"
#include "tf2_msgs/TFMessage.h"
#include "tf2_ros/buffer.h"
#include "urdf/model.h"

DEFINE_string(bag_filename, "", "Bag to process.");
DEFINE_bool(dump_timing, false,
            "Dump per-sensor timing information in files called "
            "timing_<frame_id>.csv in the current directory.");

namespace cartographer_ros {
namespace {

struct FrameProperties {
  ros::Time last_timestamp;
  std::string topic;
  std::vector<float> time_deltas;
  std::unique_ptr<std::ofstream> timing_file;
  std::string data_type;
};

const double kMinLinearAcceleration = 3.;
const double kMaxLinearAcceleration = 30.;
const double kTimeDeltaSerializationSensorWarning = 0.1;
const double kTimeDeltaSerializationSensorError = 0.5;
const double kMinAverageAcceleration = 9.5;
const double kMaxAverageAcceleration = 10.5;
const double kMaxGapPointsData = 0.1;
const double kMaxGapImuData = 0.05;
const std::set<std::string> kPointDataTypes = {
    std::string(
        ros::message_traits::DataType<sensor_msgs::PointCloud2>::value()),
    std::string(ros::message_traits::DataType<
                sensor_msgs::MultiEchoLaserScan>::value()),
    std::string(
        ros::message_traits::DataType<sensor_msgs::LaserScan>::value())};

std::unique_ptr<std::ofstream> CreateTimingFile(const std::string& frame_id) {
  auto timing_file = ::cartographer::common::make_unique<std::ofstream>(
      std::string("timing_") + frame_id + ".csv", std::ios_base::out);

  (*timing_file)
      << "# Timing information for sensor with frame id: " << frame_id
      << std::endl
      << "# Columns are in order" << std::endl
      << "# - packet index of the packet in the bag, first packet is 1"
      << std::endl
      << "# - timestamp when rosbag wrote the packet, i.e. "
         "rosbag::MessageInstance::getTime().toNSec()"
      << std::endl
      << "# - timestamp when data was acquired, i.e. "
         "message.header.stamp.toNSec()"
      << std::endl
      << "#" << std::endl
      << "# The data can be read in python using" << std::endl
      << "# import numpy" << std::endl
      << "# np.loadtxt(<filename>, dtype='uint64')" << std::endl;

  return timing_file;
}

void CheckImuMessage(const sensor_msgs::Imu& imu_message) {
  auto linear_acceleration = ToEigen(imu_message.linear_acceleration);
  if (std::isnan(linear_acceleration.norm()) ||
      linear_acceleration.norm() < kMinLinearAcceleration ||
      linear_acceleration.norm() > kMaxLinearAcceleration) {
    LOG_FIRST_N(WARNING, 3)
        << "frame_id " << imu_message.header.frame_id << " time "
        << imu_message.header.stamp.toNSec() << ": IMU linear acceleration is "
        << linear_acceleration.norm() << " m/s^2,"
        << " expected is [" << kMinLinearAcceleration << ", "
        << kMaxLinearAcceleration << "] m/s^2."
        << " (It should include gravity and be given in m/s^2.)"
        << " linear_acceleration " << linear_acceleration.transpose();
  }
}

bool IsValidPose(const geometry_msgs::Pose& pose) {
  return ToRigid3d(pose).IsValid();
}

void CheckOdometryMessage(const nav_msgs::Odometry& message) {
  const auto& pose = message.pose.pose;
  if (!IsValidPose(pose)) {
    LOG_FIRST_N(ERROR, 3) << "frame_id " << message.header.frame_id << " time "
                          << message.header.stamp.toNSec()
                          << ": Odometry pose is invalid."
                          << " pose " << pose;
  }
}

void CheckTfMessage(const tf2_msgs::TFMessage& message) {
  for (const auto& transform : message.transforms) {
    if (transform.header.frame_id == "map") {
      LOG_FIRST_N(ERROR, 1)
          << "Input contains transform message from frame_id \""
          << transform.header.frame_id << "\" to child_frame_id \""
          << transform.child_frame_id
          << "\". This is almost always output published by cartographer and "
             "should not appear as input. (Unless you have some complex "
             "remove_frames configuration, this is will not work. Simplest "
             "solution is to record input without cartographer running.)";
    }
  }
}

bool IsPointDataType(const std::string& data_type) {
  return (kPointDataTypes.count(data_type) != 0);
}

class RangeDataChecker {
 public:
  template <typename MessageType>
  void CheckMessage(const MessageType& message) {
    const std::string& frame_id = message.header.frame_id;
    RangeChecksum current_checksum = ComputeRangeChecksum(message);
    if (current_checksum.first == 0) {
      return;
    }
    auto it = frame_id_to_range_checksum_.find(frame_id);
    if (it != frame_id_to_range_checksum_.end()) {
      RangeChecksum previous_checksum = it->second;
      if (previous_checksum == current_checksum) {
        LOG_FIRST_N(ERROR, 3)
            << "Sensor with frame_id \"" << frame_id
            << "\" sends exactly the same range measurements multiple times. "
            << "Range data at time " << message.header.stamp
            << " equals preceding data.";
      }
    }
    frame_id_to_range_checksum_[frame_id] = current_checksum;
  }

 private:
  typedef std::pair<size_t /* num_points */, Eigen::Vector4f /* points_sum */>
      RangeChecksum;

  template <typename MessageType>
  RangeChecksum ComputeRangeChecksum(const MessageType& message) {
    const cartographer::sensor::TimedPointCloud& point_cloud =
        std::get<0>(ToPointCloudWithIntensities(message)).points;
    Eigen::Vector4f points_sum = Eigen::Vector4f::Zero();
    for (const auto& point : point_cloud) {
      points_sum += point;
    }
    return {point_cloud.size(), points_sum};
  }

  std::map<std::string, RangeChecksum> frame_id_to_range_checksum_;
};

void Run(const std::string& bag_filename, const bool dump_timing) {
  rosbag::Bag bag;
  bag.open(bag_filename, rosbag::bagmode::Read);
  rosbag::View view(bag);

  std::map<std::string, FrameProperties> frame_id_to_properties;
  size_t message_index = 0;
  int num_imu_messages = 0;
  double sum_imu_acceleration = 0.;
  RangeDataChecker range_data_checker;
  for (const rosbag::MessageInstance& message : view) {
    ++message_index;
    std::string frame_id;
    ros::Time time;
    if (message.isType<sensor_msgs::PointCloud2>()) {
      auto msg = message.instantiate<sensor_msgs::PointCloud2>();
      time = msg->header.stamp;
      frame_id = msg->header.frame_id;
      range_data_checker.CheckMessage(*msg);
    } else if (message.isType<sensor_msgs::MultiEchoLaserScan>()) {
      auto msg = message.instantiate<sensor_msgs::MultiEchoLaserScan>();
      time = msg->header.stamp;
      frame_id = msg->header.frame_id;
      range_data_checker.CheckMessage(*msg);
    } else if (message.isType<sensor_msgs::LaserScan>()) {
      auto msg = message.instantiate<sensor_msgs::LaserScan>();
      time = msg->header.stamp;
      frame_id = msg->header.frame_id;
      range_data_checker.CheckMessage(*msg);
    } else if (message.isType<sensor_msgs::Imu>()) {
      auto msg = message.instantiate<sensor_msgs::Imu>();
      time = msg->header.stamp;
      frame_id = msg->header.frame_id;
      CheckImuMessage(*msg);
      num_imu_messages++;
      sum_imu_acceleration += ToEigen(msg->linear_acceleration).norm();
    } else if (message.isType<nav_msgs::Odometry>()) {
      auto msg = message.instantiate<nav_msgs::Odometry>();
      time = msg->header.stamp;
      frame_id = msg->header.frame_id;
      CheckOdometryMessage(*msg);
    } else if (message.isType<tf2_msgs::TFMessage>()) {
      auto msg = message.instantiate<tf2_msgs::TFMessage>();
      CheckTfMessage(*msg);
      continue;
    } else {
      continue;
    }

    bool first_packet = false;
    if (!frame_id_to_properties.count(frame_id)) {
      frame_id_to_properties.emplace(
          frame_id,
          FrameProperties{time, message.getTopic(), std::vector<float>(),
                          dump_timing ? CreateTimingFile(frame_id) : nullptr,
                          message.getDataType()});
      first_packet = true;
    }

    auto& entry = frame_id_to_properties.at(frame_id);
    if (!first_packet) {
      const double delta_t_sec = (time - entry.last_timestamp).toSec();
      if (delta_t_sec < 0) {
        LOG_FIRST_N(ERROR, 3)
            << "Sensor with frame_id \"" << frame_id
            << "\" jumps backwards in time. Make sure that the bag "
               "contains the data for each frame_id sorted by "
               "header.stamp, i.e. the order in which they were "
               "acquired from the sensor.";
      }
      entry.time_deltas.push_back(delta_t_sec);
    }

    if (entry.topic != message.getTopic()) {
      LOG_FIRST_N(ERROR, 3)
          << "frame_id \"" << frame_id
          << "\" is send on multiple topics. It was seen at least on "
          << entry.topic << " and " << message.getTopic();
    }
    entry.last_timestamp = time;

    if (dump_timing) {
      CHECK(entry.timing_file != nullptr);
      (*entry.timing_file) << message_index << "\t"
                           << message.getTime().toNSec() << "\t"
                           << time.toNSec() << std::endl;
    }

    double duration_serialization_sensor = (time - message.getTime()).toSec();
    if (std::abs(duration_serialization_sensor) >
        kTimeDeltaSerializationSensorWarning) {
      std::stringstream stream;
      stream << "frame_id \"" << frame_id << "\" on topic "
             << message.getTopic() << " has serialization time "
             << message.getTime() << " but sensor time " << time
             << " differing by " << duration_serialization_sensor << " s.";
      if (std::abs(duration_serialization_sensor) >
          kTimeDeltaSerializationSensorError) {
        LOG_FIRST_N(ERROR, 3) << stream.str();
      } else {
        LOG_FIRST_N(WARNING, 1) << stream.str();
      }
    }
  }
  bag.close();

  if (num_imu_messages > 0) {
    double average_imu_acceleration = sum_imu_acceleration / num_imu_messages;
    if (std::isnan(average_imu_acceleration) ||
        average_imu_acceleration < kMinAverageAcceleration ||
        average_imu_acceleration > kMaxAverageAcceleration) {
      LOG(ERROR) << "Average IMU linear acceleration is "
                 << average_imu_acceleration << " m/s^2,"
                 << " expected is [" << kMinAverageAcceleration << ", "
                 << kMaxAverageAcceleration
                 << "] m/s^2. Linear acceleration data "
                    "should include gravity and be given in m/s^2.";
    }
  }

  constexpr int kNumBucketsForHistogram = 10;
  for (const auto& entry_pair : frame_id_to_properties) {
    const FrameProperties& frame_properties = entry_pair.second;
    float max_time_delta =
        *std::max_element(frame_properties.time_deltas.begin(),
                          frame_properties.time_deltas.end());
    if (IsPointDataType(frame_properties.data_type) &&
        max_time_delta > kMaxGapPointsData) {
      LOG(ERROR) << "Point data (frame_id: \"" << entry_pair.first
                 << "\") has a large gap, largest is " << max_time_delta
                 << " s, recommended is [0.0005, 0.05] s with no jitter.";
    }
    if (frame_properties.data_type ==
            ros::message_traits::DataType<sensor_msgs::Imu>::value() &&
        max_time_delta > kMaxGapImuData) {
      LOG(ERROR) << "IMU data (frame_id: \"" << entry_pair.first
                 << "\") has a large gap, largest is " << max_time_delta
                 << " s, recommended is [0.0005, 0.005] s with no jitter.";
    }

    cartographer::common::Histogram histogram;
    for (float time_delta : frame_properties.time_deltas) {
      histogram.Add(time_delta);
    }
    LOG(INFO) << "Time delta histogram for consecutive messages on topic \""
              << frame_properties.topic << "\" (frame_id: \""
              << entry_pair.first << "\"):\n"
              << histogram.ToString(kNumBucketsForHistogram);
  }

  if (dump_timing) {
    for (const auto& entry_pair : frame_id_to_properties) {
      entry_pair.second.timing_file->close();
      CHECK(*entry_pair.second.timing_file)
          << "Could not write timing information for \"" << entry_pair.first
          << "\"";
    }
  }
}

}  // namespace
}  // namespace cartographer_ros

int main(int argc, char** argv) {
  FLAGS_alsologtostderr = true;
  google::InitGoogleLogging(argv[0]);
  google::ParseCommandLineFlags(&argc, &argv, true);

  CHECK(!FLAGS_bag_filename.empty()) << "-bag_filename is missing.";
  ::cartographer_ros::Run(FLAGS_bag_filename, FLAGS_dump_timing);
}
<commit_msg>Fix segfault in rosbag_validate (#685)<commit_after>/*
 * Copyright 2017 The Cartographer Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <fstream>
#include <iostream>
#include <map>
#include <set>
#include <string>

#include "cartographer/common/histogram.h"
#include "cartographer/common/make_unique.h"
#include "cartographer_ros/msg_conversion.h"
#include "gflags/gflags.h"
#include "glog/logging.h"
#include "nav_msgs/Odometry.h"
#include "ros/ros.h"
#include "ros/time.h"
#include "rosbag/bag.h"
#include "rosbag/view.h"
#include "sensor_msgs/Imu.h"
#include "sensor_msgs/LaserScan.h"
#include "sensor_msgs/MultiEchoLaserScan.h"
#include "sensor_msgs/PointCloud2.h"
#include "tf2_eigen/tf2_eigen.h"
#include "tf2_msgs/TFMessage.h"
#include "tf2_ros/buffer.h"
#include "urdf/model.h"

DEFINE_string(bag_filename, "", "Bag to process.");
DEFINE_bool(dump_timing, false,
            "Dump per-sensor timing information in files called "
            "timing_<frame_id>.csv in the current directory.");

namespace cartographer_ros {
namespace {

struct FrameProperties {
  ros::Time last_timestamp;
  std::string topic;
  std::vector<float> time_deltas;
  std::unique_ptr<std::ofstream> timing_file;
  std::string data_type;
};

const double kMinLinearAcceleration = 3.;
const double kMaxLinearAcceleration = 30.;
const double kTimeDeltaSerializationSensorWarning = 0.1;
const double kTimeDeltaSerializationSensorError = 0.5;
const double kMinAverageAcceleration = 9.5;
const double kMaxAverageAcceleration = 10.5;
const double kMaxGapPointsData = 0.1;
const double kMaxGapImuData = 0.05;
const std::set<std::string> kPointDataTypes = {
    std::string(
        ros::message_traits::DataType<sensor_msgs::PointCloud2>::value()),
    std::string(ros::message_traits::DataType<
                sensor_msgs::MultiEchoLaserScan>::value()),
    std::string(
        ros::message_traits::DataType<sensor_msgs::LaserScan>::value())};

std::unique_ptr<std::ofstream> CreateTimingFile(const std::string& frame_id) {
  auto timing_file = ::cartographer::common::make_unique<std::ofstream>(
      std::string("timing_") + frame_id + ".csv", std::ios_base::out);

  (*timing_file)
      << "# Timing information for sensor with frame id: " << frame_id
      << std::endl
      << "# Columns are in order" << std::endl
      << "# - packet index of the packet in the bag, first packet is 1"
      << std::endl
      << "# - timestamp when rosbag wrote the packet, i.e. "
         "rosbag::MessageInstance::getTime().toNSec()"
      << std::endl
      << "# - timestamp when data was acquired, i.e. "
         "message.header.stamp.toNSec()"
      << std::endl
      << "#" << std::endl
      << "# The data can be read in python using" << std::endl
      << "# import numpy" << std::endl
      << "# np.loadtxt(<filename>, dtype='uint64')" << std::endl;

  return timing_file;
}

void CheckImuMessage(const sensor_msgs::Imu& imu_message) {
  auto linear_acceleration = ToEigen(imu_message.linear_acceleration);
  if (std::isnan(linear_acceleration.norm()) ||
      linear_acceleration.norm() < kMinLinearAcceleration ||
      linear_acceleration.norm() > kMaxLinearAcceleration) {
    LOG_FIRST_N(WARNING, 3)
        << "frame_id " << imu_message.header.frame_id << " time "
        << imu_message.header.stamp.toNSec() << ": IMU linear acceleration is "
        << linear_acceleration.norm() << " m/s^2,"
        << " expected is [" << kMinLinearAcceleration << ", "
        << kMaxLinearAcceleration << "] m/s^2."
        << " (It should include gravity and be given in m/s^2.)"
        << " linear_acceleration " << linear_acceleration.transpose();
  }
}

bool IsValidPose(const geometry_msgs::Pose& pose) {
  return ToRigid3d(pose).IsValid();
}

void CheckOdometryMessage(const nav_msgs::Odometry& message) {
  const auto& pose = message.pose.pose;
  if (!IsValidPose(pose)) {
    LOG_FIRST_N(ERROR, 3) << "frame_id " << message.header.frame_id << " time "
                          << message.header.stamp.toNSec()
                          << ": Odometry pose is invalid."
                          << " pose " << pose;
  }
}

void CheckTfMessage(const tf2_msgs::TFMessage& message) {
  for (const auto& transform : message.transforms) {
    if (transform.header.frame_id == "map") {
      LOG_FIRST_N(ERROR, 1)
          << "Input contains transform message from frame_id \""
          << transform.header.frame_id << "\" to child_frame_id \""
          << transform.child_frame_id
          << "\". This is almost always output published by cartographer and "
             "should not appear as input. (Unless you have some complex "
             "remove_frames configuration, this is will not work. Simplest "
             "solution is to record input without cartographer running.)";
    }
  }
}

bool IsPointDataType(const std::string& data_type) {
  return (kPointDataTypes.count(data_type) != 0);
}

class RangeDataChecker {
 public:
  template <typename MessageType>
  void CheckMessage(const MessageType& message) {
    const std::string& frame_id = message.header.frame_id;
    RangeChecksum current_checksum = ComputeRangeChecksum(message);
    if (current_checksum.first == 0) {
      return;
    }
    auto it = frame_id_to_range_checksum_.find(frame_id);
    if (it != frame_id_to_range_checksum_.end()) {
      RangeChecksum previous_checksum = it->second;
      if (previous_checksum == current_checksum) {
        LOG_FIRST_N(ERROR, 3)
            << "Sensor with frame_id \"" << frame_id
            << "\" sends exactly the same range measurements multiple times. "
            << "Range data at time " << message.header.stamp
            << " equals preceding data.";
      }
    }
    frame_id_to_range_checksum_[frame_id] = current_checksum;
  }

 private:
  typedef std::pair<size_t /* num_points */, Eigen::Vector4f /* points_sum */>
      RangeChecksum;

  template <typename MessageType>
  RangeChecksum ComputeRangeChecksum(const MessageType& message) {
    auto point_cloud_with_intensities = ToPointCloudWithIntensities(message);
    const cartographer::sensor::TimedPointCloud& point_cloud =
        std::get<0>(point_cloud_with_intensities).points;
    Eigen::Vector4f points_sum = Eigen::Vector4f::Zero();
    for (const auto& point : point_cloud) {
      points_sum += point;
    }
    return {point_cloud.size(), points_sum};
  }

  std::map<std::string, RangeChecksum> frame_id_to_range_checksum_;
};

void Run(const std::string& bag_filename, const bool dump_timing) {
  rosbag::Bag bag;
  bag.open(bag_filename, rosbag::bagmode::Read);
  rosbag::View view(bag);

  std::map<std::string, FrameProperties> frame_id_to_properties;
  size_t message_index = 0;
  int num_imu_messages = 0;
  double sum_imu_acceleration = 0.;
  RangeDataChecker range_data_checker;
  for (const rosbag::MessageInstance& message : view) {
    ++message_index;
    std::string frame_id;
    ros::Time time;
    if (message.isType<sensor_msgs::PointCloud2>()) {
      auto msg = message.instantiate<sensor_msgs::PointCloud2>();
      time = msg->header.stamp;
      frame_id = msg->header.frame_id;
      range_data_checker.CheckMessage(*msg);
    } else if (message.isType<sensor_msgs::MultiEchoLaserScan>()) {
      auto msg = message.instantiate<sensor_msgs::MultiEchoLaserScan>();
      time = msg->header.stamp;
      frame_id = msg->header.frame_id;
      range_data_checker.CheckMessage(*msg);
    } else if (message.isType<sensor_msgs::LaserScan>()) {
      auto msg = message.instantiate<sensor_msgs::LaserScan>();
      time = msg->header.stamp;
      frame_id = msg->header.frame_id;
      range_data_checker.CheckMessage(*msg);
    } else if (message.isType<sensor_msgs::Imu>()) {
      auto msg = message.instantiate<sensor_msgs::Imu>();
      time = msg->header.stamp;
      frame_id = msg->header.frame_id;
      CheckImuMessage(*msg);
      num_imu_messages++;
      sum_imu_acceleration += ToEigen(msg->linear_acceleration).norm();
    } else if (message.isType<nav_msgs::Odometry>()) {
      auto msg = message.instantiate<nav_msgs::Odometry>();
      time = msg->header.stamp;
      frame_id = msg->header.frame_id;
      CheckOdometryMessage(*msg);
    } else if (message.isType<tf2_msgs::TFMessage>()) {
      auto msg = message.instantiate<tf2_msgs::TFMessage>();
      CheckTfMessage(*msg);
      continue;
    } else {
      continue;
    }

    bool first_packet = false;
    if (!frame_id_to_properties.count(frame_id)) {
      frame_id_to_properties.emplace(
          frame_id,
          FrameProperties{time, message.getTopic(), std::vector<float>(),
                          dump_timing ? CreateTimingFile(frame_id) : nullptr,
                          message.getDataType()});
      first_packet = true;
    }

    auto& entry = frame_id_to_properties.at(frame_id);
    if (!first_packet) {
      const double delta_t_sec = (time - entry.last_timestamp).toSec();
      if (delta_t_sec < 0) {
        LOG_FIRST_N(ERROR, 3)
            << "Sensor with frame_id \"" << frame_id
            << "\" jumps backwards in time. Make sure that the bag "
               "contains the data for each frame_id sorted by "
               "header.stamp, i.e. the order in which they were "
               "acquired from the sensor.";
      }
      entry.time_deltas.push_back(delta_t_sec);
    }

    if (entry.topic != message.getTopic()) {
      LOG_FIRST_N(ERROR, 3)
          << "frame_id \"" << frame_id
          << "\" is send on multiple topics. It was seen at least on "
          << entry.topic << " and " << message.getTopic();
    }
    entry.last_timestamp = time;

    if (dump_timing) {
      CHECK(entry.timing_file != nullptr);
      (*entry.timing_file) << message_index << "\t"
                           << message.getTime().toNSec() << "\t"
                           << time.toNSec() << std::endl;
    }

    double duration_serialization_sensor = (time - message.getTime()).toSec();
    if (std::abs(duration_serialization_sensor) >
        kTimeDeltaSerializationSensorWarning) {
      std::stringstream stream;
      stream << "frame_id \"" << frame_id << "\" on topic "
             << message.getTopic() << " has serialization time "
             << message.getTime() << " but sensor time " << time
             << " differing by " << duration_serialization_sensor << " s.";
      if (std::abs(duration_serialization_sensor) >
          kTimeDeltaSerializationSensorError) {
        LOG_FIRST_N(ERROR, 3) << stream.str();
      } else {
        LOG_FIRST_N(WARNING, 1) << stream.str();
      }
    }
  }
  bag.close();

  if (num_imu_messages > 0) {
    double average_imu_acceleration = sum_imu_acceleration / num_imu_messages;
    if (std::isnan(average_imu_acceleration) ||
        average_imu_acceleration < kMinAverageAcceleration ||
        average_imu_acceleration > kMaxAverageAcceleration) {
      LOG(ERROR) << "Average IMU linear acceleration is "
                 << average_imu_acceleration << " m/s^2,"
                 << " expected is [" << kMinAverageAcceleration << ", "
                 << kMaxAverageAcceleration
                 << "] m/s^2. Linear acceleration data "
                    "should include gravity and be given in m/s^2.";
    }
  }

  constexpr int kNumBucketsForHistogram = 10;
  for (const auto& entry_pair : frame_id_to_properties) {
    const FrameProperties& frame_properties = entry_pair.second;
    float max_time_delta =
        *std::max_element(frame_properties.time_deltas.begin(),
                          frame_properties.time_deltas.end());
    if (IsPointDataType(frame_properties.data_type) &&
        max_time_delta > kMaxGapPointsData) {
      LOG(ERROR) << "Point data (frame_id: \"" << entry_pair.first
                 << "\") has a large gap, largest is " << max_time_delta
                 << " s, recommended is [0.0005, 0.05] s with no jitter.";
    }
    if (frame_properties.data_type ==
            ros::message_traits::DataType<sensor_msgs::Imu>::value() &&
        max_time_delta > kMaxGapImuData) {
      LOG(ERROR) << "IMU data (frame_id: \"" << entry_pair.first
                 << "\") has a large gap, largest is " << max_time_delta
                 << " s, recommended is [0.0005, 0.005] s with no jitter.";
    }

    cartographer::common::Histogram histogram;
    for (float time_delta : frame_properties.time_deltas) {
      histogram.Add(time_delta);
    }
    LOG(INFO) << "Time delta histogram for consecutive messages on topic \""
              << frame_properties.topic << "\" (frame_id: \""
              << entry_pair.first << "\"):\n"
              << histogram.ToString(kNumBucketsForHistogram);
  }

  if (dump_timing) {
    for (const auto& entry_pair : frame_id_to_properties) {
      entry_pair.second.timing_file->close();
      CHECK(*entry_pair.second.timing_file)
          << "Could not write timing information for \"" << entry_pair.first
          << "\"";
    }
  }
}

}  // namespace
}  // namespace cartographer_ros

int main(int argc, char** argv) {
  FLAGS_alsologtostderr = true;
  google::InitGoogleLogging(argv[0]);
  google::ParseCommandLineFlags(&argc, &argv, true);

  CHECK(!FLAGS_bag_filename.empty()) << "-bag_filename is missing.";
  ::cartographer_ros::Run(FLAGS_bag_filename, FLAGS_dump_timing);
}
<|endoftext|>


<commit_before>/*******************************************************************************
 * Copyright (c) 2009-04-24 Joacim Jacobsson.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Joacim Jacobsson - first implementation
 *******************************************************************************/

#include <QtGui/QtGui>

#include "BehaviorTreeList.h"
#include "../standard_resources.h"
#include "../x-node.h"

#include <btree/btree_func.h>

BehaviorTreeList::BehaviorTreeList( QWidget *parent ) :
  QListWidget( parent )
{
  setDragEnabled( true );
  setViewMode( QListView::ListMode );
  setIconSize( QSize( 16, 16 ) );
  setSpacing( 2 );
  setAcceptDrops( false );
  setDropIndicatorShown( false );

  XNodeData node_data;

  {
    QListWidgetItem *nodeItem = new QListWidgetItem( this );
    QPixmap pixmap(32,32);
    pixmap = QPixmap( ":/nodes/tree.svg" ).scaled(
      32, 32, Qt::IgnoreAspectRatio, Qt::SmoothTransformation
    );
    nodeItem->setIcon( QIcon(pixmap) );
    nodeItem->setData( Qt::UserRole + 0, pixmap );

    node_data.m_Type      = E_XNDT_TREE;
    node_data.m_NodeGrist = E_GRIST_UNKOWN;
    node_data.m_FuncId    = 0;

    nodeItem->setData( Qt::UserRole + 1,
      QByteArray( (const char*)(&node_data), sizeof(XNodeData)) );

    nodeItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable
        | Qt::ItemIsDragEnabled );
    nodeItem->setText( tr("Tree") );
  }

  for( int i = 1; i < E_GRIST_DECORATOR; ++i )
  {
    QListWidgetItem *nodeItem = new QListWidgetItem( this );
    QPixmap pixmap(32,32);

    pixmap = QPixmap(g_NodeSVGResourcePaths[i]).scaled(
      32, 32, Qt::IgnoreAspectRatio, Qt::SmoothTransformation
    );

    nodeItem->setIcon( QIcon(pixmap) );
    nodeItem->setData( Qt::UserRole + 0, pixmap );

    node_data.m_Type        = E_XNDT_NODE;
    node_data.m_NodeGrist   = i;
    node_data.m_FuncId      = 0;

    nodeItem->setData( Qt::UserRole + 1,
      QByteArray( (const char*)(&node_data), sizeof(XNodeData)) );

    nodeItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable
        | Qt::ItemIsDragEnabled );
    nodeItem->setText( g_NodeNames[i] );
  }

}

void BehaviorTreeList::loadSymbols( BehaviorTreeContext ctx )
{

  QMessageBox::warning( this, tr( "Calltree Studio" ), tr(
        "The behavior keps has been modified.\n"
          "Do you want to save your changes?" ), QMessageBox::Yes
          | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel
          | QMessageBox::Escape );
  int c;
  NamedSymbol* ns = BehaviorTreeContextAccessSymbols( ctx, &c );

  XNodeData node_data;

  for( int i = 0; i < c; ++i )
  {
    bool set = false;
    const char* name = 0x0;
    switch( ns[i].m_Type )
    {
    case E_ST_ACTION:
      if( ns[i].m_Symbol.m_Action->m_Declared )
      {
        node_data.m_Type = E_XNDT_NODE;
        node_data.m_NodeGrist = E_GRIST_ACTION;
        node_data.m_FuncId = ns[i].m_Symbol.m_Action->m_Id.m_Hash;
        name = ns[i].m_Symbol.m_Action->m_Id.m_Text;
        set = true;
      }
      break;
    case E_ST_DECORATOR:
      if( ns[i].m_Symbol.m_Decorator->m_Declared )
      {
        node_data.m_Type = E_XNDT_NODE;
        node_data.m_NodeGrist = E_GRIST_DECORATOR;
        node_data.m_FuncId = ns[i].m_Symbol.m_Decorator->m_Id.m_Hash;
        name = ns[i].m_Symbol.m_Decorator->m_Id.m_Text;
        set = true;
      }
      break;
    }
    if( !set )
      continue;

    QListWidgetItem *nodeItem = new QListWidgetItem( this );
    QPixmap pixmap(32,32);

    pixmap = QPixmap(g_NodeSVGResourcePaths[node_data.m_NodeGrist]).scaled(
      32, 32, Qt::IgnoreAspectRatio, Qt::SmoothTransformation
    );

    nodeItem->setIcon( QIcon(pixmap) );
    nodeItem->setData( Qt::UserRole + 0, pixmap );
    nodeItem->setData( Qt::UserRole + 1,
      QByteArray( (const char*)(&node_data), sizeof(XNodeData)) );

    nodeItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable
        | Qt::ItemIsDragEnabled );
    nodeItem->setText( name );
  }
}

void BehaviorTreeList::startDrag( Qt::DropActions /*supportedActions*/ )
{
  QListWidgetItem *item = currentItem();

  QPixmap pixmap = qVariantValue<QPixmap> ( item->data( Qt::UserRole + 0 ) );
  QMimeData *mimeData = new QMimeData;
  mimeData->setData( "ctstudio/x-node", item->data( Qt::UserRole + 1 ).toByteArray() );

  QDrag *drag = new QDrag( this );
  drag->setMimeData( mimeData );
  drag->setHotSpot( QPoint( pixmap.width(), pixmap.height() ) );
  //drag->setPixmap( pixmap );

  drag->exec( Qt::CopyAction );
}
<commit_msg>Removed annoying test-popup<commit_after>/*******************************************************************************
 * Copyright (c) 2009-04-24 Joacim Jacobsson.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Joacim Jacobsson - first implementation
 *******************************************************************************/

#include <QtGui/QtGui>

#include "BehaviorTreeList.h"
#include "../standard_resources.h"
#include "../x-node.h"

#include <btree/btree_func.h>

BehaviorTreeList::BehaviorTreeList( QWidget *parent ) :
  QListWidget( parent )
{
  setDragEnabled( true );
  setViewMode( QListView::ListMode );
  setIconSize( QSize( 16, 16 ) );
  setSpacing( 2 );
  setAcceptDrops( false );
  setDropIndicatorShown( false );

  XNodeData node_data;

  {
    QListWidgetItem *nodeItem = new QListWidgetItem( this );
    QPixmap pixmap(32,32);
    pixmap = QPixmap( ":/nodes/tree.svg" ).scaled(
      32, 32, Qt::IgnoreAspectRatio, Qt::SmoothTransformation
    );
    nodeItem->setIcon( QIcon(pixmap) );
    nodeItem->setData( Qt::UserRole + 0, pixmap );

    node_data.m_Type      = E_XNDT_TREE;
    node_data.m_NodeGrist = E_GRIST_UNKOWN;
    node_data.m_FuncId    = 0;

    nodeItem->setData( Qt::UserRole + 1,
      QByteArray( (const char*)(&node_data), sizeof(XNodeData)) );

    nodeItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable
        | Qt::ItemIsDragEnabled );
    nodeItem->setText( tr("Tree") );
  }

  for( int i = 1; i < E_GRIST_DECORATOR; ++i )
  {
    QListWidgetItem *nodeItem = new QListWidgetItem( this );
    QPixmap pixmap(32,32);

    pixmap = QPixmap(g_NodeSVGResourcePaths[i]).scaled(
      32, 32, Qt::IgnoreAspectRatio, Qt::SmoothTransformation
    );

    nodeItem->setIcon( QIcon(pixmap) );
    nodeItem->setData( Qt::UserRole + 0, pixmap );

    node_data.m_Type        = E_XNDT_NODE;
    node_data.m_NodeGrist   = i;
    node_data.m_FuncId      = 0;

    nodeItem->setData( Qt::UserRole + 1,
      QByteArray( (const char*)(&node_data), sizeof(XNodeData)) );

    nodeItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable
        | Qt::ItemIsDragEnabled );
    nodeItem->setText( g_NodeNames[i] );
  }

}

void BehaviorTreeList::loadSymbols( BehaviorTreeContext ctx )
{
  int c;
  NamedSymbol* ns = BehaviorTreeContextAccessSymbols( ctx, &c );

  XNodeData node_data;

  for( int i = 0; i < c; ++i )
  {
    bool set = false;
    const char* name = 0x0;
    switch( ns[i].m_Type )
    {
    case E_ST_ACTION:
      if( ns[i].m_Symbol.m_Action->m_Declared )
      {
        node_data.m_Type = E_XNDT_NODE;
        node_data.m_NodeGrist = E_GRIST_ACTION;
        node_data.m_FuncId = ns[i].m_Symbol.m_Action->m_Id.m_Hash;
        name = ns[i].m_Symbol.m_Action->m_Id.m_Text;
        set = true;
      }
      break;
    case E_ST_DECORATOR:
      if( ns[i].m_Symbol.m_Decorator->m_Declared )
      {
        node_data.m_Type = E_XNDT_NODE;
        node_data.m_NodeGrist = E_GRIST_DECORATOR;
        node_data.m_FuncId = ns[i].m_Symbol.m_Decorator->m_Id.m_Hash;
        name = ns[i].m_Symbol.m_Decorator->m_Id.m_Text;
        set = true;
      }
      break;
    }
    if( !set )
      continue;

    QListWidgetItem *nodeItem = new QListWidgetItem( this );
    QPixmap pixmap(32,32);

    pixmap = QPixmap(g_NodeSVGResourcePaths[node_data.m_NodeGrist]).scaled(
      32, 32, Qt::IgnoreAspectRatio, Qt::SmoothTransformation
    );

    nodeItem->setIcon( QIcon(pixmap) );
    nodeItem->setData( Qt::UserRole + 0, pixmap );
    nodeItem->setData( Qt::UserRole + 1,
      QByteArray( (const char*)(&node_data), sizeof(XNodeData)) );

    nodeItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable
        | Qt::ItemIsDragEnabled );
    nodeItem->setText( name );
  }
}

void BehaviorTreeList::startDrag( Qt::DropActions /*supportedActions*/ )
{
  QListWidgetItem *item = currentItem();

  QPixmap pixmap = qVariantValue<QPixmap> ( item->data( Qt::UserRole + 0 ) );
  QMimeData *mimeData = new QMimeData;
  mimeData->setData( "ctstudio/x-node", item->data( Qt::UserRole + 1 ).toByteArray() );

  QDrag *drag = new QDrag( this );
  drag->setMimeData( mimeData );
  drag->setHotSpot( QPoint( pixmap.width(), pixmap.height() ) );
  //drag->setPixmap( pixmap );

  drag->exec( Qt::CopyAction );
}
<|endoftext|>


<commit_before><commit_msg>Trim the lsb_release output in GetLinuxDistro.<commit_after><|endoftext|>


<commit_before>#include "stdafx.h"

#include "SendIpUpdate.h"

#include "MiscUtil.h"
#include "Http.h"
#include "JsonParser.h"
#include "Prefs.h"
#include "StrUtil.h"

char* SendIpUpdate()
{
	assert(CanSendIPUpdates());
	if (!CanSendIPUpdates())
		return NULL;

	char *res = NULL;

	// host = updates.opendns.com or website.dev6.sfo.opendns.com
	// url: /nic/update?token=mytoken&api_key=mykey?hostname=
	// responses:
	//  "badauth"
	//  "nohost"
	//  "good ${ip-addr}"
	if (!g_pref_token)
		return NULL;
	assert(g_pref_hostname);

	const char *urlTxt = GetIpUpdateUrl(TRUE);
	const char *host = GetIpUpdateHost();

	HttpResult *httpResult = HttpGet(host, urlTxt, INTERNET_DEFAULT_HTTPS_PORT);
	free((void*)urlTxt);
	if (httpResult && httpResult->IsValid()) {
		res = (char*)httpResult->data.getData(NULL);
	}
	delete httpResult;
	return res;
}

char *SendDnsOmaticUpdate()
{
	assert(CanSendIPUpdates());
	if (!CanSendIPUpdates())
		return NULL;

	char *res = NULL;

	// TODO: do I need to append the following in url from GetIpUpdateUrl()?
	/*URL$ = SetURLPart(URL$, "myip", ip$)
	URL$ = SetURLPart(URL$, "wildcard", "NOCHG")
	URL$ = SetURLPart(URL$, "mx", "NOCHG")
	URL$ = SetURLPart(URL$, "backmx", "NOCHG")*/

	const char *urlTxt = GetIpUpdateUrl(TRUE);
	const char *host = GetIpUpdateDnsOMaticHost();

	HttpResult *httpResult = HttpGet(host, urlTxt, INTERNET_DEFAULT_HTTPS_PORT);
	free((void*)urlTxt);
	if (httpResult && httpResult->IsValid()) {
		res = (char*)httpResult->data.getData(NULL);
	}
	delete httpResult;
	return res;
}

IpUpdateResult IpUpdateResultFromString(const char *s)
{
	if (StrStartsWithI(s, "The service is not available"))
		return IpUpdateNotAvailable;
	if (StrStartsWithI(s, "good"))
		return IpUpdateOk;
	if (StrStartsWithI(s, "nochg"))
		return IpUpdateOk;
	if (StrStartsWithI(s, "!yours"))
		return IpUpdateNotYours;
	if (StrStartsWithI(s, "badauth"))
		return IpUpdateBadAuth;
	if (StrStartsWithI(s, "nohost"))
		return IpUpdateNoHost;

	// not sure if those really happen, they're supported by 1.3 client
	if (StrStartsWithI(s, "dnserr"))
		return IpUpdateDnsErr;

	if (StrStartsWithI(s, "911"))
		return IpUpdateDnsErr;

	if (StrStartsWithI(s, "abuse"))
		return IpUpdateMiscErr;

	if (StrStartsWithI(s, "notfqdn"))
		return IpUpdateMiscErr;

	if (StrStartsWithI(s, "numhost"))
		return IpUpdateMiscErr;

	if (StrStartsWithI(s, "badagent"))
		return IpUpdateMiscErr;

	if (StrStartsWithI(s, "!donator"))
		return IpUpdateMiscErr;

	assert(0);
	return IpUpdateOk;
}

#if 0
// another way is to use username/password and http basic auth
char* SendIpUpdate()
{
	// host = "updates.opendns.com"
	// url = "/nic/update?hostname=" + network
	// responses:
	//  "badauth"
	//  "nohost"
	//  "good ${ip-addr}"
	const char *userName = "";
	const char *pwd = "";
	HttpResult *httpResult = HttpGetWithBasicAuth("updates.opendns.com", "/nic/update", userName, pwd, true);
	if (httpResult && httpResult->IsValid()) {
		DWORD dataLen;
		char *data = (char*)httpResult->data.getData(&dataLen);
		free(data);
	}
	delete httpResult;
}
#endif

TCHAR *DownloadUpdateIfNotDownloaded(const char *url)
{
	const TCHAR *filePathStr = NULL;
	const char *fileName = StrFindLastChar(url, '/');
	if (!fileName)
		return NULL;
	++fileName;
	CString filePath = AppDataDir();
	filePath += PATH_SEP_STR;
	filePath += fileName;

	filePathStr = filePath;
	if (FileOrDirExists(filePathStr))
		return tstrdup(filePathStr);

	HttpResult *httpResult = HttpGet(url);
	if (!httpResult || !httpResult->IsValid())
		goto Error;

	DWORD size;
	void *s = httpResult->data.getData(&size);
	if (!s)
		goto Error;

	BOOL ok = FileWriteAll(filePathStr, (const char*)s, size);
	if (!ok)
		goto Error;

	return tstrdup(filePathStr);
Error:
	free((void*)filePathStr);
	return NULL;
}

// sends auto-update check. Returns url of the new version to download
// if an update is available or NULL if update is not available
// (or there was an error getting the upgrade info)
// Caller needs to free() the result.
// TODO: we ignore (and don't propagate) 'force' field in json response
char *GetUpdateUrl(const TCHAR *version, VersionUpdateCheckType type)
{
	char *downloadUrl = NULL;
	JsonEl *json = NULL;

	char *typeStr = "c";
	if (UpdateCheckInstall == type)
		typeStr = "i";
	else if (UpdateCheckUninstall == type)
		typeStr = "u";
	else if (UpdateCheckVersionCheck == type)
		typeStr = "c";
	else
		assert(0);

	CString url = AutoUpdateUrl(version, typeStr);
	HttpResult *res = HttpGet(AUTO_UPDATE_HOST, url);
	if (!res || !res->IsValid())
		return NULL;
	char *s = (char *)res->data.getData(NULL);
	json = ParseJsonToDoc(s);
	JsonEl *upgradeAvailable = GetMapElByName(json, "upgrade");
	JsonElBool *upgradeAvailableBool = JsonElAsBool(upgradeAvailable);
	if (!upgradeAvailableBool || !upgradeAvailableBool->boolVal)
		goto Exit;
	JsonEl *updateUrl = GetMapElByName(json, "download");
	if (!updateUrl)
		goto Exit;
	downloadUrl = StrDupSafe(JsonElAsStringVal(updateUrl));
Exit:
	JsonElFree(json);
	free(s);
	return downloadUrl;
}
<commit_msg>make it possible to test updates using local server<commit_after>#include "stdafx.h"

#include "SendIpUpdate.h"

#include "MiscUtil.h"
#include "Http.h"
#include "JsonParser.h"
#include "Prefs.h"
#include "StrUtil.h"

char* SendIpUpdate()
{
	assert(CanSendIPUpdates());
	if (!CanSendIPUpdates())
		return NULL;

	char *res = NULL;

	// host = updates.opendns.com or website.dev6.sfo.opendns.com
	// url: /nic/update?token=mytoken&api_key=mykey?hostname=
	// responses:
	//  "badauth"
	//  "nohost"
	//  "good ${ip-addr}"
	if (!g_pref_token)
		return NULL;
	assert(g_pref_hostname);

	const char *urlTxt = GetIpUpdateUrl(TRUE);
	const char *host = GetIpUpdateHost();

	HttpResult *httpResult = HttpGet(host, urlTxt, INTERNET_DEFAULT_HTTPS_PORT);
	free((void*)urlTxt);
	if (httpResult && httpResult->IsValid()) {
		res = (char*)httpResult->data.getData(NULL);
	}
	delete httpResult;
	return res;
}

char *SendDnsOmaticUpdate()
{
	assert(CanSendIPUpdates());
	if (!CanSendIPUpdates())
		return NULL;

	char *res = NULL;

	// TODO: do I need to append the following in url from GetIpUpdateUrl()?
	/*URL$ = SetURLPart(URL$, "myip", ip$)
	URL$ = SetURLPart(URL$, "wildcard", "NOCHG")
	URL$ = SetURLPart(URL$, "mx", "NOCHG")
	URL$ = SetURLPart(URL$, "backmx", "NOCHG")*/

	const char *urlTxt = GetIpUpdateUrl(TRUE);
	const char *host = GetIpUpdateDnsOMaticHost();

	HttpResult *httpResult = HttpGet(host, urlTxt, INTERNET_DEFAULT_HTTPS_PORT);
	free((void*)urlTxt);
	if (httpResult && httpResult->IsValid()) {
		res = (char*)httpResult->data.getData(NULL);
	}
	delete httpResult;
	return res;
}

IpUpdateResult IpUpdateResultFromString(const char *s)
{
	if (StrStartsWithI(s, "The service is not available"))
		return IpUpdateNotAvailable;
	if (StrStartsWithI(s, "good"))
		return IpUpdateOk;
	if (StrStartsWithI(s, "nochg"))
		return IpUpdateOk;
	if (StrStartsWithI(s, "!yours"))
		return IpUpdateNotYours;
	if (StrStartsWithI(s, "badauth"))
		return IpUpdateBadAuth;
	if (StrStartsWithI(s, "nohost"))
		return IpUpdateNoHost;

	// not sure if those really happen, they're supported by 1.3 client
	if (StrStartsWithI(s, "dnserr"))
		return IpUpdateDnsErr;

	if (StrStartsWithI(s, "911"))
		return IpUpdateDnsErr;

	if (StrStartsWithI(s, "abuse"))
		return IpUpdateMiscErr;

	if (StrStartsWithI(s, "notfqdn"))
		return IpUpdateMiscErr;

	if (StrStartsWithI(s, "numhost"))
		return IpUpdateMiscErr;

	if (StrStartsWithI(s, "badagent"))
		return IpUpdateMiscErr;

	if (StrStartsWithI(s, "!donator"))
		return IpUpdateMiscErr;

	assert(0);
	return IpUpdateOk;
}

#if 0
// another way is to use username/password and http basic auth
char* SendIpUpdate()
{
	// host = "updates.opendns.com"
	// url = "/nic/update?hostname=" + network
	// responses:
	//  "badauth"
	//  "nohost"
	//  "good ${ip-addr}"
	const char *userName = "";
	const char *pwd = "";
	HttpResult *httpResult = HttpGetWithBasicAuth("updates.opendns.com", "/nic/update", userName, pwd, true);
	if (httpResult && httpResult->IsValid()) {
		DWORD dataLen;
		char *data = (char*)httpResult->data.getData(&dataLen);
		free(data);
	}
	delete httpResult;
}
#endif

TCHAR *DownloadUpdateIfNotDownloaded(const char *url)
{
	const TCHAR *filePathStr = NULL;
	const char *fileName = StrFindLastChar(url, '/');
	if (!fileName)
		return NULL;
	++fileName;
	CString filePath = AppDataDir();
	filePath += PATH_SEP_STR;
	filePath += fileName;

	filePathStr = filePath;
	if (FileOrDirExists(filePathStr))
		return tstrdup(filePathStr);

	HttpResult *httpResult = HttpGet(url);
	if (!httpResult || !httpResult->IsValid())
		goto Error;

	DWORD size;
	void *s = httpResult->data.getData(&size);
	if (!s)
		goto Error;

	BOOL ok = FileWriteAll(filePathStr, (const char*)s, size);
	if (!ok)
		goto Error;

	return tstrdup(filePathStr);
Error:
	free((void*)filePathStr);
	return NULL;
}

#define TEST_UPDATE_LOCALLY 0

// sends auto-update check. Returns url of the new version to download
// if an update is available or NULL if update is not available
// (or there was an error getting the upgrade info)
// Caller needs to free() the result.
// TODO: we ignore (and don't propagate) 'force' field in json response
char *GetUpdateUrl(const TCHAR *version, VersionUpdateCheckType type)
{
	char *downloadUrl = NULL;
	JsonEl *json = NULL;

	char *typeStr = "c";
	if (UpdateCheckInstall == type)
		typeStr = "i";
	else if (UpdateCheckUninstall == type)
		typeStr = "u";
	else if (UpdateCheckVersionCheck == type)
		typeStr = "c";
	else
		assert(0);

	CString url = AutoUpdateUrl(version, typeStr);
#if TEST_UPDATE_LOCALLY
	HttpResult *res = HttpGet("127.0.0.1", url, 8080);
#else
	HttpResult *res = HttpGet(AUTO_UPDATE_HOST, url);
#endif
	if (!res || !res->IsValid())
		return NULL;
	char *s = (char *)res->data.getData(NULL);
	json = ParseJsonToDoc(s);
	JsonEl *upgradeAvailable = GetMapElByName(json, "upgrade");
	JsonElBool *upgradeAvailableBool = JsonElAsBool(upgradeAvailable);
	if (!upgradeAvailableBool || !upgradeAvailableBool->boolVal)
		goto Exit;
	JsonEl *updateUrl = GetMapElByName(json, "download");
	if (!updateUrl)
		goto Exit;
	downloadUrl = StrDupSafe(JsonElAsStringVal(updateUrl));
Exit:
	JsonElFree(json);
	free(s);
	return downloadUrl;
}
<|endoftext|>


<commit_before>/*
    Copyright 2010 Google Inc.

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
 */

#include "SkBitmapCache.h"

struct SkBitmapCache::Entry {
    Entry*      fPrev;
    Entry*      fNext;

    void*       fBuffer;
    size_t      fSize;
    SkBitmap    fBitmap;

    Entry(const void* buffer, size_t size, const SkBitmap& bm) : fBitmap(bm) {
        fBuffer = sk_malloc_throw(size);
        fSize = size;
        memcpy(fBuffer, buffer, size);
    }

    ~Entry() { sk_free(fBuffer); }

    bool equals(const void* buffer, size_t size) const {
        return (fSize == size) && !memcmp(fBuffer, buffer, size);
    }
};

SkBitmapCache::SkBitmapCache(int max) : fMaxEntries(max) {
    fEntryCount = 0;
    fHead = fTail = NULL;

    this->validate();
}

SkBitmapCache::~SkBitmapCache() {
    this->validate();

    Entry* entry = fHead;
    while (entry) {
        Entry* next = entry->fNext;
        delete entry;
        entry = next;
    }
}

SkBitmapCache::Entry* SkBitmapCache::detach(Entry* entry) const {
    if (entry->fPrev) {
        SkASSERT(fHead != entry);
        entry->fPrev->fNext = entry->fNext;
    } else {
        SkASSERT(fHead == entry);
        fHead = entry->fNext;
    }
    if (entry->fNext) {
        SkASSERT(fTail != entry);
        entry->fNext->fPrev = entry->fPrev;
    } else {
        SkASSERT(fTail == entry);
        fTail = entry->fPrev;
    }
    return entry;
}

void SkBitmapCache::attachToHead(Entry* entry) const {
    entry->fPrev = NULL;
    entry->fNext = fHead;
    if (fHead) {
        fHead->fPrev = entry;
    } else {
        fTail = entry;
    }
    fHead = entry;
}

bool SkBitmapCache::find(const void* buffer, size_t size, SkBitmap* bm) const {
    AutoValidate av(this);

    Entry* entry = fHead;
    while (entry) {
        if (entry->equals(buffer, size)) {
            if (bm) {
                *bm = entry->fBitmap;
            }
            // move to the head of our list, so we purge it last
            this->detach(entry);
            this->attachToHead(entry);
            return true;
        }
        entry = entry->fNext;
    }
    return false;
}

void SkBitmapCache::add(const void* buffer, size_t len, const SkBitmap& bm) {
    AutoValidate av(this);

    if (fEntryCount == fMaxEntries) {
        if (fTail) {
            delete this->detach(fTail);
        }
    }

    Entry* entry = new Entry(buffer, len, bm);
    this->attachToHead(entry);
    fEntryCount += 1;
}

///////////////////////////////////////////////////////////////////////////////

#ifdef SK_DEBUG

void SkBitmapCache::validate() const {
    SkASSERT(fEntryCount >= 0 && fEntryCount <= fMaxEntries);

    if (fEntryCount > 0) {
        SkASSERT(NULL == fHead->fPrev);
        SkASSERT(NULL == fTail->fNext);

        if (fEntryCount == 1) {
            SkASSERT(fHead == fTail);
        } else {
            SkASSERT(fHead != fTail);
        }

        Entry* entry = fHead;
        int count = 0;
        while (entry) {
            count += 1;
            entry = entry->fNext;
        }
        SkASSERT(count == fEntryCount);

        entry = fTail;
        while (entry) {
            count -= 1;
            entry = entry->fPrev;
        }
        SkASSERT(0 == count);
    } else {
        SkASSERT(NULL == fHead);
        SkASSERT(NULL == fTail);
    }
}

#endif

<commit_msg>fix fEntryCount when we purge a cache entry (bug caught by our validate())<commit_after>/*
    Copyright 2010 Google Inc.

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
 */

#include "SkBitmapCache.h"

struct SkBitmapCache::Entry {
    Entry*      fPrev;
    Entry*      fNext;

    void*       fBuffer;
    size_t      fSize;
    SkBitmap    fBitmap;

    Entry(const void* buffer, size_t size, const SkBitmap& bm) : fBitmap(bm) {
        fBuffer = sk_malloc_throw(size);
        fSize = size;
        memcpy(fBuffer, buffer, size);
    }

    ~Entry() { sk_free(fBuffer); }

    bool equals(const void* buffer, size_t size) const {
        return (fSize == size) && !memcmp(fBuffer, buffer, size);
    }
};

SkBitmapCache::SkBitmapCache(int max) : fMaxEntries(max) {
    fEntryCount = 0;
    fHead = fTail = NULL;

    this->validate();
}

SkBitmapCache::~SkBitmapCache() {
    this->validate();

    Entry* entry = fHead;
    while (entry) {
        Entry* next = entry->fNext;
        delete entry;
        entry = next;
    }
}

SkBitmapCache::Entry* SkBitmapCache::detach(Entry* entry) const {
    if (entry->fPrev) {
        SkASSERT(fHead != entry);
        entry->fPrev->fNext = entry->fNext;
    } else {
        SkASSERT(fHead == entry);
        fHead = entry->fNext;
    }
    if (entry->fNext) {
        SkASSERT(fTail != entry);
        entry->fNext->fPrev = entry->fPrev;
    } else {
        SkASSERT(fTail == entry);
        fTail = entry->fPrev;
    }
    return entry;
}

void SkBitmapCache::attachToHead(Entry* entry) const {
    entry->fPrev = NULL;
    entry->fNext = fHead;
    if (fHead) {
        fHead->fPrev = entry;
    } else {
        fTail = entry;
    }
    fHead = entry;
}

bool SkBitmapCache::find(const void* buffer, size_t size, SkBitmap* bm) const {
    AutoValidate av(this);

    Entry* entry = fHead;
    while (entry) {
        if (entry->equals(buffer, size)) {
            if (bm) {
                *bm = entry->fBitmap;
            }
            // move to the head of our list, so we purge it last
            this->detach(entry);
            this->attachToHead(entry);
            return true;
        }
        entry = entry->fNext;
    }
    return false;
}

void SkBitmapCache::add(const void* buffer, size_t len, const SkBitmap& bm) {
    AutoValidate av(this);

    if (fEntryCount == fMaxEntries) {
        SkASSERT(fTail);
        delete this->detach(fTail);
        fEntryCount -= 1;
    }

    Entry* entry = new Entry(buffer, len, bm);
    this->attachToHead(entry);
    fEntryCount += 1;
}

///////////////////////////////////////////////////////////////////////////////

#ifdef SK_DEBUG

void SkBitmapCache::validate() const {
    SkASSERT(fEntryCount >= 0 && fEntryCount <= fMaxEntries);

    if (fEntryCount > 0) {
        SkASSERT(NULL == fHead->fPrev);
        SkASSERT(NULL == fTail->fNext);

        if (fEntryCount == 1) {
            SkASSERT(fHead == fTail);
        } else {
            SkASSERT(fHead != fTail);
        }

        Entry* entry = fHead;
        int count = 0;
        while (entry) {
            count += 1;
            entry = entry->fNext;
        }
        SkASSERT(count == fEntryCount);

        entry = fTail;
        while (entry) {
            count -= 1;
            entry = entry->fPrev;
        }
        SkASSERT(0 == count);
    } else {
        SkASSERT(NULL == fHead);
        SkASSERT(NULL == fTail);
    }
}

#endif

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ChartController_EditData.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: vg $ $Date: 2007-05-22 18:03:19 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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 General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_chart2.hxx"
#include "ChartController.hxx"
#include "macros.hxx"

#include "dlg_DataEditor.hxx"
#include "DataSourceHelper.hxx"
#include "DiagramHelper.hxx"
#include "ControllerLockGuard.hxx"
#include "UndoGuard.hxx"
#include "ResId.hxx"
#include "Strings.hrc"

// for RET_OK
#ifndef _SV_MSGBOX_HXX
#include <vcl/msgbox.hxx>
#endif

#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif
#ifndef _VOS_MUTEX_HXX_
#include <vos/mutex.hxx>
#endif

#ifndef _COM_SUN_STAR_CHART2_XCHARTDOCUMENT_HPP_
#include <com/sun/star/chart2/XChartDocument.hpp>
#endif

using namespace ::com::sun::star;

using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Sequence;

namespace chart
{

void ChartController::executeDispatch_EditData()
{
    Reference< chart2::XChartDocument > xChartDoc( m_aModel->getModel(), uno::UNO_QUERY );
    if( xChartDoc.is())
    {
        Window* pParent( NULL );

        Reference< ::com::sun::star::chart2::data::XDataProvider > xDataProvider( xChartDoc->getDataProvider());

        {
            // /--
            ::vos::OGuard aSolarGuard( Application::GetSolarMutex());
            UndoLiveUpdateGuardWithData aUndoGuard(
                ::rtl::OUString( String( SchResId( STR_ACTION_EDIT_CHART_DATA ))),
                m_aUndoManager, m_aModel->getModel());
            DataEditor aDataEditorDialog( pParent, xChartDoc, m_xCC );
            // the dialog has no OK/Cancel
            aDataEditorDialog.Execute();
            aUndoGuard.commitAction();
            // \--
        }
    }
}

} //  namespace chart
<commit_msg>INTEGRATION: CWS chart07 (1.5.12); FILE MERGED 2007/06/26 11:09:57 bm 1.5.12.2: #i78790# fix for (broken) gcc 3.3 for Mac OS/X Panther applied 2007/06/25 12:52:11 bm 1.5.12.1: #i74653# store undo manager at model to be able to do an undo even after inplace re-activation<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ChartController_EditData.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: rt $ $Date: 2007-07-25 08:42:58 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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 General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_chart2.hxx"
#include "ChartController.hxx"
#include "macros.hxx"

#include "dlg_DataEditor.hxx"
#include "DataSourceHelper.hxx"
#include "DiagramHelper.hxx"
#include "ControllerLockGuard.hxx"
#include "UndoGuard.hxx"
#include "ResId.hxx"
#include "Strings.hrc"

// for RET_OK
#ifndef _SV_MSGBOX_HXX
#include <vcl/msgbox.hxx>
#endif

#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif
#ifndef _VOS_MUTEX_HXX_
#include <vos/mutex.hxx>
#endif

#ifndef _COM_SUN_STAR_CHART2_XCHARTDOCUMENT_HPP_
#include <com/sun/star/chart2/XChartDocument.hpp>
#endif

using namespace ::com::sun::star;

using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Sequence;

namespace chart
{

void ChartController::executeDispatch_EditData()
{
    Reference< chart2::XChartDocument > xChartDoc( m_aModel->getModel(), uno::UNO_QUERY );
    if( xChartDoc.is())
    {
        Window* pParent( NULL );

        Reference< ::com::sun::star::chart2::data::XDataProvider > xDataProvider( xChartDoc->getDataProvider());

        {
            // /--
            ::vos::OGuard aSolarGuard( Application::GetSolarMutex());
            // using assignment for broken gcc 3.3
            UndoLiveUpdateGuardWithData aUndoGuard = UndoLiveUpdateGuardWithData(
                ::rtl::OUString( String( SchResId( STR_ACTION_EDIT_CHART_DATA ))),
                m_xUndoManager, m_aModel->getModel());
            DataEditor aDataEditorDialog( pParent, xChartDoc, m_xCC );
            // the dialog has no OK/Cancel
            aDataEditorDialog.Execute();
            aUndoGuard.commitAction();
            // \--
        }
    }
}

} //  namespace chart
<|endoftext|>


<commit_before>#include <iostream>
#include <exception>
using namespace std;

class QUEUE_FULL_EXCEPTION : public exception {
  const char * what() const throw() {
    return "Queue is full\n";
  }
};

class QUEUE_EMPTY_EXCEPTION : public exception {
  const char * what() const throw() {
    return "Queue is empty\n";
  }
};

template <class T>
class s_queue {
  T *arr;
  unsigned long long size;
  unsigned long long head;
  unsigned long long tail;
  unsigned long long items;

public:
  s_queue(unsigned long long size) {
    this-> size = size;
    arr = new T[size];
    head = 0;
    tail = 0;
    items = 0;
  }

  ~s_queue() {
    delete[] arr;
  }

  bool is_empty() {
    return items == 0;
  }

  void enqueue(T x) {
    // if queue is full, throw exception
    if (items == size) throw QUEUE_FULL_EXCEPTION();

    // when the queue is empty, set head to 0, tail to 1
    // and insert the new item
    if (is_empty()) {
      arr[0] = x;
      head = 0;
      tail = 1;
      items++;
      return;
    }

    // insert the item at current tail (tail is always empty)
    arr[tail] = x;

    // calculate new tail, if it goes beyond queue size, set it to start (0)
    if (++tail >= size) {
      tail = 0;
    }

    // increase the number of items
    items++;
  }

  T dequeue() {
    // if queue is empty, throw exception
    if (is_empty()) throw QUEUE_EMPTY_EXCEPTION();

    // hold the current element at 'head', this will be returned
    T item = arr[head];

    // calculate new head, if it goes beyond queue size, set it to start (0)
    if (++head >= size) {
      head = 0;
    }

    // decrease the number of items
    items--;

    return item;
  }
};

int main() {
  s_queue<int> queue(5);
  queue.enqueue(1);
  queue.enqueue(2);
  queue.enqueue(3);
  queue.enqueue(4);
  queue.enqueue(5);
  cout << queue.dequeue() << endl;
  cout << queue.dequeue() << endl;
  cout << queue.dequeue() << endl;
  cout << queue.dequeue() << endl;
  cout << queue.dequeue() << endl;

  s_queue<string> string_queue(5);
  string_queue.enqueue("hello!");
  cout << string_queue.dequeue() << endl;

  return 0;
}<commit_msg>Add ability to fetch item at head in circular queue<commit_after>#include <iostream>
#include <exception>
using namespace std;

class QUEUE_FULL_EXCEPTION : public exception {
  const char * what() const throw() {
    return "Queue is full\n";
  }
};

class QUEUE_EMPTY_EXCEPTION : public exception {
  const char * what() const throw() {
    return "Queue is empty\n";
  }
};

template <class T>
class s_queue {
  T *arr;
  unsigned long long size;
  unsigned long long head;
  unsigned long long tail;
  unsigned long long items;

public:
  s_queue(unsigned long long size) {
    this-> size = size;
    arr = new T[size];
    head = 0;
    tail = 0;
    items = 0;
  }

  ~s_queue() {
    delete[] arr;
  }

  bool is_empty() {
    return items == 0;
  }

  // returns the item at the head
  T front() {
    if (is_empty()) throw QUEUE_EMPTY_EXCEPTION();
    return arr[head];
  }

  void enqueue(T x) {
    // if queue is full, throw exception
    if (items == size) throw QUEUE_FULL_EXCEPTION();

    // when the queue is empty, set head to 0, tail to 1
    // and insert the new item
    if (is_empty()) {
      arr[0] = x;
      head = 0;
      tail = 1;
      items++;
      return;
    }

    // insert the item at current tail (tail is always empty)
    arr[tail] = x;

    // calculate new tail, if it goes beyond queue size, set it to start (0)
    if (++tail >= size) {
      tail = 0;
    }

    // increase the number of items
    items++;
  }

  T dequeue() {
    // if queue is empty, throw exception
    if (is_empty()) throw QUEUE_EMPTY_EXCEPTION();

    // hold the current element at 'head', this will be returned
    T item = arr[head];

    // calculate new head, if it goes beyond queue size, set it to start (0)
    if (++head >= size) {
      head = 0;
    }

    // decrease the number of items
    items--;

    return item;
  }
};

int main() {
  s_queue<int> queue(5);
  queue.enqueue(1);
  queue.enqueue(2);
  queue.enqueue(3);
  queue.enqueue(4);
  queue.enqueue(5);
  cout << queue.dequeue() << endl;
  cout << queue.dequeue() << endl;
  cout << queue.dequeue() << endl;
  cout << queue.dequeue() << endl;
  cout << queue.dequeue() << endl;

  s_queue<string> string_queue(5);
  string_queue.enqueue("hello!");
  cout << string_queue.dequeue() << endl;

  return 0;
}<|endoftext|>


<commit_before>/*
    Copyright (c) 2008 Tobias Koenig <tokoe@kde.org>
    Copyright (c) 2010 Volker Krause <vkrause@kde.org>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    This library 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 Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
*/

#include "nepomuksearchengine.h"

#include <akdebug.h>
#include "src/nepomuk/result.h"

#include "entities.h"
#include "storage/notificationcollector.h"
#include "storage/selectquerybuilder.h"
#include "notificationmanager.h"
#include "libs/xdgbasedirs_p.h"

#include <QtCore/QDebug>
#include <QtCore/QUrl>
#include <QMetaObject>
#include <qdbusservicewatcher.h>
#include <qdbusconnection.h>
#include <QSettings>

using namespace Akonadi;

static qint64 resultToId( const Nepomuk::Query::Result &result )
{
  const Soprano::Node &property = result.requestProperty(QUrl( QLatin1String( "http://akonadi-project.org/ontologies/aneo#akonadiItemId" ) ));
  if (!(property.isValid() && property.isLiteral() && property.literal().isString())) {
    qWarning() << "Failed to get requested akonadiItemId property";
    qDebug() << "AkonadiItemId missing in query results!" << result.resourceUri() << property.isValid() << property.isLiteral() << property.literal().isString() << property.literal().type() << result.requestProperties().size();
//    qDebug() << result.requestProperties().values().first().toString();
    return -1;
  }
  return property.literal().toString().toLongLong();
}

NepomukSearchEngine::NepomukSearchEngine( QObject* parent )
  : QObject( parent ),
    mCollector( new NotificationCollector( this ) ),
    m_liveSearchEnabled( true )
{
  NotificationManager::self()->connectNotificationCollector( mCollector );

  QDBusServiceWatcher *watcher =
    new QDBusServiceWatcher( QLatin1String("org.kde.nepomuk.services.nepomukqueryservice"),
                             QDBusConnection::sessionBus(),
                             QDBusServiceWatcher::WatchForRegistration, this );
  connect( watcher, SIGNAL(serviceRegistered(QString)), SLOT(reloadSearches()) );

  if ( Nepomuk::Query::QueryServiceClient::serviceAvailable() ) {
    reloadSearches();
  } else {
    // FIXME: try to start the nepomuk server
    akError() << "Nepomuk Query Server not available";
  }

  const QSettings settings(XdgBaseDirs::akonadiServerConfigFile(), QSettings::IniFormat);
  m_liveSearchEnabled = settings.value(QLatin1String("Nepomuk/LiveSearchEnabled"), false).toBool();
}

NepomukSearchEngine::~NepomukSearchEngine()
{
  stopSearches();
}

void NepomukSearchEngine::addSearch( const Collection &collection )
{
  if ( collection.queryLanguage() != QLatin1String( "SPARQL" ) )
    return;
  const QString &q = collection.queryString();

  if ( q.size() >= 32768 ) {
    qWarning() << "The query is at least 32768 chars long, which is the maximum size supported by the akonadi db schema. The query is therefore most likely truncated and will not be executed.";
    return;
  }

  //FIXME the requested property must be passed to here from the calling code
  //Ideally the Query is passed as object so we can check here for the akonadiItemId property, and add it if missing
  if (!q.contains(QString::fromLatin1("reqProp1")) || !q.contains(QString::fromLatin1("http://akonadi-project.org/ontologies/aneo#akonadiItemId"))) {
    qWarning() << "The query MUST contain exactly one required property (http://akonadi-project.org/ontologies/aneo#akonadiItemId), if another property is additionally requested or the akonadiItemId is missing the search will fail (due to this hack)";
    qWarning() << q;
    return;
  }

  Nepomuk::Query::QueryServiceClient *query = new Nepomuk::Query::QueryServiceClient( this );

  connect( query, SIGNAL(newEntries(QList<Nepomuk::Query::Result>)),
           this, SLOT(hitsAdded(QList<Nepomuk::Query::Result>)) );
  connect( query, SIGNAL(entriesRemoved(QList<Nepomuk::Query::Result>)),
           this, SLOT(hitsRemoved(QList<Nepomuk::Query::Result>)) );
  connect( query, SIGNAL(finishedListing()),
           this, SLOT(finishedListing()) );

  mMutex.lock();
  mQueryMap.insert( query, collection.id() );
  mQueryInvMap.insert( collection.id(), query ); // needed for fast lookup in removeSearch()
  mMutex.unlock();

  QHash<QString, QString> encodedRps;
  encodedRps.insert( QString::fromLatin1( "reqProp1" ), QUrl(QString::fromLatin1("http://akonadi-project.org/ontologies/aneo#akonadiItemId")).toString() ); //FIXME hack because the reqProp is not passed to here by the caller
  query->query( collection.queryString(), encodedRps );
}

void NepomukSearchEngine::removeSearch( qint64 collectionId )
{
  Nepomuk::Query::QueryServiceClient *query = mQueryInvMap.value( collectionId );
  if ( !query ) {
    qWarning() << "Nepomuk QueryServer: Query could not be removed!";
    return;
  }

  query->close();

  // cleanup mappings
  mMutex.lock();
  mQueryInvMap.remove( collectionId );
  mQueryMap.remove( query );
  mMutex.unlock();

  query->deleteLater();
}

void NepomukSearchEngine::reloadSearches()
{
  akDebug() << this << sender();
  SelectQueryBuilder<Collection> qb;
  qb.addValueCondition( Collection::queryLanguageFullColumnName(), Query::Equals, QLatin1String( "SPARQL" ) );
  if ( !qb.exec() ) {
    qWarning() << "Nepomuk QueryServer: Unable to execute query!";
    return;
  }

  Q_FOREACH ( const Collection &collection, qb.result() ) {
    mMutex.lock();
    if ( mQueryInvMap.contains( collection.id() ) ) {
      mMutex.unlock();
      akDebug() << "updating search" << collection.name();
      removeSearch( collection.id() );
    } else  {
      mMutex.unlock();
      akDebug() << "adding search" << collection.name();
    }
    addSearch( collection );
  }
}

void NepomukSearchEngine::stopSearches()
{
  SelectQueryBuilder<Collection> qb;
  qb.addValueCondition( Collection::queryLanguageFullColumnName(), Query::Equals, QLatin1String( "SPARQL" ) );
  if ( !qb.exec() ) {
    qWarning() << "Nepomuk QueryServer: Unable to execute query!";
    return;
  }

  Q_FOREACH ( const Collection &collection, qb.result() ) {
    akDebug() << "removing search" << collection.name();
    removeSearch( collection.id() );
  }
}

void NepomukSearchEngine::hitsAdded( const QList<Nepomuk::Query::Result>& entries )
{
  Nepomuk::Query::QueryServiceClient *query = qobject_cast<Nepomuk::Query::QueryServiceClient*>( sender() );
  if ( !query ) {
    qWarning() << "Nepomuk QueryServer: Got signal from non-existing search query!";
    return;
  }

  mMutex.lock();
  qint64 collectionId = mQueryMap.value( query );
  mMutex.unlock();
  const Collection collection = Collection::retrieveById( collectionId );

  PimItem::List items;
  Q_FOREACH( const Nepomuk::Query::Result &result, entries ) {
    const qint64 itemId = resultToId( result );

    if ( itemId == -1 )
      continue;

    Entity::addToRelation<CollectionPimItemRelation>( collectionId, itemId );
    items << PimItem::retrieveById( itemId );
  }
  mCollector->itemsLinked( items, collection );
  mCollector->dispatchNotifications();
}

void NepomukSearchEngine::hitsRemoved( const QList<Nepomuk::Query::Result>& entries )
{
  Nepomuk::Query::QueryServiceClient *query = qobject_cast<Nepomuk::Query::QueryServiceClient*>( sender() );
  if ( !query ) {
    qWarning() << "Nepomuk QueryServer: Got signal from non-existing search query!";
    return;
  }

  mMutex.lock();
  qint64 collectionId = mQueryMap.value( query );
  mMutex.unlock();
  const Collection collection = Collection::retrieveById( collectionId );
  PimItem::List items;
  Q_FOREACH( const Nepomuk::Query::Result &result, entries ) {
    const qint64 itemId = resultToId( result );

    if ( itemId == -1 )
      continue;

    Entity::removeFromRelation<CollectionPimItemRelation>( collectionId, itemId );
    items << PimItem::retrieveById( itemId );
  }

  mCollector->itemsUnlinked( items, collection );
  mCollector->dispatchNotifications();
}

void NepomukSearchEngine::finishedListing()
{
  if (m_liveSearchEnabled)
    return;

  Nepomuk::Query::QueryServiceClient *query = qobject_cast<Nepomuk::Query::QueryServiceClient*>( sender() );
  if ( !query ) {
    qWarning() << Q_FUNC_INFO << "Nepomuk QueryServer: Got signal from non-existing search query!";
    return;
  }

  mMutex.lock();
  qint64 collectionId = mQueryMap.value( query );
  mMutex.unlock();

  removeSearch(collectionId);
}
<commit_msg>coding style for nepomuksearchengine.cpp<commit_after>/*
    Copyright (c) 2008 Tobias Koenig <tokoe@kde.org>
    Copyright (c) 2010 Volker Krause <vkrause@kde.org>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    This library 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 Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
*/

#include "nepomuksearchengine.h"

#include <akdebug.h>
#include "src/nepomuk/result.h"

#include "entities.h"
#include "storage/notificationcollector.h"
#include "storage/selectquerybuilder.h"
#include "notificationmanager.h"
#include "libs/xdgbasedirs_p.h"

#include <QtCore/QDebug>
#include <QtCore/QUrl>
#include <QMetaObject>
#include <qdbusservicewatcher.h>
#include <qdbusconnection.h>
#include <QSettings>

using namespace Akonadi;

static qint64 resultToId( const Nepomuk::Query::Result &result )
{
  const Soprano::Node &property = result.requestProperty(QUrl( QLatin1String( "http://akonadi-project.org/ontologies/aneo#akonadiItemId" ) ));
  if (!(property.isValid() && property.isLiteral() && property.literal().isString())) {
    qWarning() << "Failed to get requested akonadiItemId property";
    qDebug() << "AkonadiItemId missing in query results!" << result.resourceUri() << property.isValid() << property.isLiteral() << property.literal().isString() << property.literal().type() << result.requestProperties().size();
//    qDebug() << result.requestProperties().values().first().toString();
    return -1;
  }
  return property.literal().toString().toLongLong();
}

NepomukSearchEngine::NepomukSearchEngine( QObject* parent )
  : QObject( parent ),
    mCollector( new NotificationCollector( this ) ),
    m_liveSearchEnabled( true )
{
  NotificationManager::self()->connectNotificationCollector( mCollector );

  QDBusServiceWatcher *watcher =
    new QDBusServiceWatcher( QLatin1String("org.kde.nepomuk.services.nepomukqueryservice"),
                             QDBusConnection::sessionBus(),
                             QDBusServiceWatcher::WatchForRegistration, this );
  connect( watcher, SIGNAL(serviceRegistered(QString)), SLOT(reloadSearches()) );

  if ( Nepomuk::Query::QueryServiceClient::serviceAvailable() ) {
    reloadSearches();
  } else {
    // FIXME: try to start the nepomuk server
    akError() << "Nepomuk Query Server not available";
  }

  const QSettings settings(XdgBaseDirs::akonadiServerConfigFile(), QSettings::IniFormat);
  m_liveSearchEnabled = settings.value(QLatin1String("Nepomuk/LiveSearchEnabled"), false).toBool();
}

NepomukSearchEngine::~NepomukSearchEngine()
{
  stopSearches();
}

void NepomukSearchEngine::addSearch( const Collection &collection )
{
  if ( collection.queryLanguage() != QLatin1String( "SPARQL" ) ) {
    return;
  }
  const QString &q = collection.queryString();

  if ( q.size() >= 32768 ) {
    qWarning() << "The query is at least 32768 chars long, which is the maximum size supported by the akonadi db schema. The query is therefore most likely truncated and will not be executed.";
    return;
  }

  //FIXME the requested property must be passed to here from the calling code
  //Ideally the Query is passed as object so we can check here for the akonadiItemId property, and add it if missing
  if (!q.contains(QString::fromLatin1("reqProp1")) || !q.contains(QString::fromLatin1("http://akonadi-project.org/ontologies/aneo#akonadiItemId"))) {
    qWarning() << "The query MUST contain exactly one required property (http://akonadi-project.org/ontologies/aneo#akonadiItemId), if another property is additionally requested or the akonadiItemId is missing the search will fail (due to this hack)";
    qWarning() << q;
    return;
  }

  Nepomuk::Query::QueryServiceClient *query = new Nepomuk::Query::QueryServiceClient( this );

  connect( query, SIGNAL(newEntries(QList<Nepomuk::Query::Result>)),
           this, SLOT(hitsAdded(QList<Nepomuk::Query::Result>)) );
  connect( query, SIGNAL(entriesRemoved(QList<Nepomuk::Query::Result>)),
           this, SLOT(hitsRemoved(QList<Nepomuk::Query::Result>)) );
  connect( query, SIGNAL(finishedListing()),
           this, SLOT(finishedListing()) );

  mMutex.lock();
  mQueryMap.insert( query, collection.id() );
  mQueryInvMap.insert( collection.id(), query ); // needed for fast lookup in removeSearch()
  mMutex.unlock();

  QHash<QString, QString> encodedRps;
  encodedRps.insert( QString::fromLatin1( "reqProp1" ), QUrl(QString::fromLatin1("http://akonadi-project.org/ontologies/aneo#akonadiItemId")).toString() ); //FIXME hack because the reqProp is not passed to here by the caller
  query->query( collection.queryString(), encodedRps );
}

void NepomukSearchEngine::removeSearch( qint64 collectionId )
{
  Nepomuk::Query::QueryServiceClient *query = mQueryInvMap.value( collectionId );
  if ( !query ) {
    qWarning() << "Nepomuk QueryServer: Query could not be removed!";
    return;
  }

  query->close();

  // cleanup mappings
  mMutex.lock();
  mQueryInvMap.remove( collectionId );
  mQueryMap.remove( query );
  mMutex.unlock();

  query->deleteLater();
}

void NepomukSearchEngine::reloadSearches()
{
  akDebug() << this << sender();
  SelectQueryBuilder<Collection> qb;
  qb.addValueCondition( Collection::queryLanguageFullColumnName(), Query::Equals, QLatin1String( "SPARQL" ) );
  if ( !qb.exec() ) {
    qWarning() << "Nepomuk QueryServer: Unable to execute query!";
    return;
  }

  Q_FOREACH ( const Collection &collection, qb.result() ) {
    mMutex.lock();
    if ( mQueryInvMap.contains( collection.id() ) ) {
      mMutex.unlock();
      akDebug() << "updating search" << collection.name();
      removeSearch( collection.id() );
    } else {
      mMutex.unlock();
      akDebug() << "adding search" << collection.name();
    }
    addSearch( collection );
  }
}

void NepomukSearchEngine::stopSearches()
{
  SelectQueryBuilder<Collection> qb;
  qb.addValueCondition( Collection::queryLanguageFullColumnName(), Query::Equals, QLatin1String( "SPARQL" ) );
  if ( !qb.exec() ) {
    qWarning() << "Nepomuk QueryServer: Unable to execute query!";
    return;
  }

  Q_FOREACH ( const Collection &collection, qb.result() ) {
    akDebug() << "removing search" << collection.name();
    removeSearch( collection.id() );
  }
}

void NepomukSearchEngine::hitsAdded( const QList<Nepomuk::Query::Result>& entries )
{
  Nepomuk::Query::QueryServiceClient *query = qobject_cast<Nepomuk::Query::QueryServiceClient*>( sender() );
  if ( !query ) {
    qWarning() << "Nepomuk QueryServer: Got signal from non-existing search query!";
    return;
  }

  mMutex.lock();
  qint64 collectionId = mQueryMap.value( query );
  mMutex.unlock();
  const Collection collection = Collection::retrieveById( collectionId );

  PimItem::List items;
  Q_FOREACH( const Nepomuk::Query::Result &result, entries ) {
    const qint64 itemId = resultToId( result );

    if ( itemId == -1 ) {
      continue;
    }

    Entity::addToRelation<CollectionPimItemRelation>( collectionId, itemId );
    items << PimItem::retrieveById( itemId );
  }
  mCollector->itemsLinked( items, collection );
  mCollector->dispatchNotifications();
}

void NepomukSearchEngine::hitsRemoved( const QList<Nepomuk::Query::Result>& entries )
{
  Nepomuk::Query::QueryServiceClient *query = qobject_cast<Nepomuk::Query::QueryServiceClient*>( sender() );
  if ( !query ) {
    qWarning() << "Nepomuk QueryServer: Got signal from non-existing search query!";
    return;
  }

  mMutex.lock();
  qint64 collectionId = mQueryMap.value( query );
  mMutex.unlock();
  const Collection collection = Collection::retrieveById( collectionId );
  PimItem::List items;
  Q_FOREACH( const Nepomuk::Query::Result &result, entries ) {
    const qint64 itemId = resultToId( result );

    if ( itemId == -1 ) {
      continue;
    }

    Entity::removeFromRelation<CollectionPimItemRelation>( collectionId, itemId );
    items << PimItem::retrieveById( itemId );
  }

  mCollector->itemsUnlinked( items, collection );
  mCollector->dispatchNotifications();
}

void NepomukSearchEngine::finishedListing()
{
  if (m_liveSearchEnabled) {
    return;
  }

  Nepomuk::Query::QueryServiceClient *query = qobject_cast<Nepomuk::Query::QueryServiceClient*>( sender() );
  if ( !query ) {
    qWarning() << Q_FUNC_INFO << "Nepomuk QueryServer: Got signal from non-existing search query!";
    return;
  }

  mMutex.lock();
  qint64 collectionId = mQueryMap.value( query );
  mMutex.unlock();

  removeSearch(collectionId);
}
<|endoftext|>


<commit_before>#include "browser/win/inspectable_web_contents_view_win.h"

#include "browser/browser_client.h"
#include "browser/inspectable_web_contents_impl.h"
#include "browser/win/devtools_window.h"

#include "content/public/browser/web_contents_view.h"
#include "ui/gfx/win/hwnd_util.h"
#include "ui/views/controls/single_split_view.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/view.h"

namespace brightray {

namespace {

const int kWindowInset = 100;

}

class ContainerView : public views::View {
 public:
  explicit ContainerView(InspectableWebContentsViewWin* web_contents_view)
      : container_view_created_(false),
        web_view_(new views::WebView(NULL)),
        web_contents_view_(web_contents_view) {
    set_owned_by_client();
    web_view_->set_owned_by_client();
    web_view_->SetWebContents(
        web_contents_view_->inspectable_web_contents()->GetWebContents());
  }

  views::View* GetWebView() const {
    return web_view_.get();
  }

  void ShowDevTools() {
    if (IsDevToolsViewShowing())
      return;

    RemoveChildView(web_view_.get());
    devtools_view_ = new views::WebView(NULL);
    devtools_view_->SetWebContents(web_contents_view_->
        inspectable_web_contents()->devtools_web_contents());
    split_view_.reset(new views::SingleSplitView(
        web_view_.get(),
        devtools_view_,
        views::SingleSplitView::VERTICAL_SPLIT,
        NULL));
    AddChildView(split_view_.get());
    Layout();
    devtools_view_->RequestFocus();
  }

  void CloseDevTools() {
    if (!IsDevToolsViewShowing())
      return;

    RemoveChildView(split_view_.get());
    split_view_.reset();
    AddChildView(web_view_.get());
    Layout();
  }

  bool IsDevToolsViewShowing() {
    return split_view_;
  }

 private:
  // views::View:
  virtual void Layout() OVERRIDE {
    if (split_view_)
      split_view_->SetBounds(0, 0, width(), height());
    else
      web_view_->SetBounds(0, 0, width(), height());
  }

  virtual void ViewHierarchyChanged(
      const ViewHierarchyChangedDetails& details) OVERRIDE {
    View::ViewHierarchyChanged(details);
    // We're not using child == this because a Widget may not be
    // available when this is added to the hierarchy.
    if (details.is_add && GetWidget() && !container_view_created_) {
      container_view_created_ = true;
      AddChildView(web_view_.get());
    }
  }

  // True if the container view has already been created, or false otherwise.
  bool container_view_created_;

  scoped_ptr<views::WebView> web_view_;
  scoped_ptr<views::SingleSplitView> split_view_;
  views::WebView* devtools_view_;  // Owned by split_view_.

  InspectableWebContentsViewWin* web_contents_view_;
};

InspectableWebContentsView* CreateInspectableContentsView(
    InspectableWebContentsImpl* inspectable_web_contents) {
  return new InspectableWebContentsViewWin(inspectable_web_contents);
}

InspectableWebContentsViewWin::InspectableWebContentsViewWin(
    InspectableWebContentsImpl* inspectable_web_contents)
    : inspectable_web_contents_(inspectable_web_contents),
      container_(new ContainerView(this)) {
}

InspectableWebContentsViewWin::~InspectableWebContentsViewWin() {
  if (devtools_window_)
    DestroyWindow(devtools_window_->hwnd());
}

views::View* InspectableWebContentsViewWin::GetView() const {
  return container_.get();
}

views::View* InspectableWebContentsViewWin::GetWebView() const {
  return container_->GetWebView();
}

gfx::NativeView InspectableWebContentsViewWin::GetNativeView() const {
  auto web_contents = inspectable_web_contents_->GetWebContents();
  return web_contents->GetView()->GetNativeView();
}

void InspectableWebContentsViewWin::ShowDevTools() {
  container_->ShowDevTools();
  return;

  if (!devtools_window_) {
    devtools_window_ = DevToolsWindow::Create(this)->AsWeakPtr();
    devtools_window_->Init(HWND_DESKTOP, gfx::Rect());
  }

  auto contents_view = inspectable_web_contents_->GetWebContents()->GetView();
  auto size = contents_view->GetContainerSize();
  size.Enlarge(-kWindowInset, -kWindowInset);
  gfx::CenterAndSizeWindow(contents_view->GetNativeView(),
                           devtools_window_->hwnd(),
                           size);

  ShowWindow(devtools_window_->hwnd(), SW_SHOWNORMAL);
}

void InspectableWebContentsViewWin::CloseDevTools() {
  container_->CloseDevTools();
  return;

  if (!devtools_window_)
    return;
  SendMessage(devtools_window_->hwnd(), WM_CLOSE, 0, 0);
}

bool InspectableWebContentsViewWin::IsDevToolsViewShowing() {
  return container_->IsDevToolsViewShowing() || devtools_window_;
}

bool InspectableWebContentsViewWin::SetDockSide(const std::string& side) {
  return false;
}

}  // namespace brightray
<commit_msg>Implement setting dock side.<commit_after>#include "browser/win/inspectable_web_contents_view_win.h"

#include "browser/browser_client.h"
#include "browser/inspectable_web_contents_impl.h"
#include "browser/win/devtools_window.h"

#include "content/public/browser/web_contents_view.h"
#include "ui/gfx/win/hwnd_util.h"
#include "ui/views/controls/single_split_view.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/view.h"

namespace brightray {

namespace {

const int kWindowInset = 100;

}

class ContainerView : public views::View {
 public:
  explicit ContainerView(InspectableWebContentsViewWin* web_contents_view)
      : container_view_created_(false),
        dockside_("bottom"),
        web_view_(new views::WebView(NULL)),
        web_contents_view_(web_contents_view) {
    set_owned_by_client();
    web_view_->set_owned_by_client();
    web_view_->SetWebContents(
        web_contents_view_->inspectable_web_contents()->GetWebContents());
  }

  views::View* GetWebView() const {
    return web_view_.get();
  }

  void ShowDevTools() {
    if (IsDevToolsViewShowing())
      return;

    RemoveChildView(web_view_.get());
    devtools_view_ = new views::WebView(NULL);
    devtools_view_->SetWebContents(web_contents_view_->
        inspectable_web_contents()->devtools_web_contents());
    split_view_.reset(new views::SingleSplitView(
        web_view_.get(),
        devtools_view_,
        GetSplitViewOrientation(),
        NULL));
    split_view_->set_divider_offset(GetSplitVievDividerOffset());
    AddChildView(split_view_.get());
    Layout();

    devtools_view_->RequestFocus();
  }

  void CloseDevTools() {
    if (!IsDevToolsViewShowing())
      return;

    RemoveChildView(split_view_.get());
    split_view_.reset();
    AddChildView(web_view_.get());
    Layout();
  }

  bool IsDevToolsViewShowing() {
    return split_view_;
  }

  bool SetDockSide(const std::string& side) {
    if (side != "bottom" && side != "right")
      return false;  // unsupported display location
    if (dockside_ == side)
      return true;  // no change from current location

    dockside_ = side;
    if (!IsDevToolsViewShowing())
      return true;

    split_view_->set_orientation(GetSplitViewOrientation());
    split_view_->set_divider_offset(GetSplitVievDividerOffset());
    split_view_->Layout();
    return true;
  }

 private:
  // views::View:
  virtual void Layout() OVERRIDE {
    if (split_view_)
      split_view_->SetBounds(0, 0, width(), height());
    else
      web_view_->SetBounds(0, 0, width(), height());
  }

  virtual void ViewHierarchyChanged(
      const ViewHierarchyChangedDetails& details) OVERRIDE {
    View::ViewHierarchyChanged(details);
    // We're not using child == this because a Widget may not be
    // available when this is added to the hierarchy.
    if (details.is_add && GetWidget() && !container_view_created_) {
      container_view_created_ = true;
      AddChildView(web_view_.get());
    }
  }

  views::SingleSplitView::Orientation GetSplitViewOrientation() const {
    if (dockside_ == "bottom")
      return views::SingleSplitView::VERTICAL_SPLIT;
    else
      return views::SingleSplitView::HORIZONTAL_SPLIT;
  }

  int GetSplitVievDividerOffset() const {
    if (dockside_ == "bottom")
      return height() * 2 / 3;
    else
      return width() * 2 / 3;
  }

  // True if the container view has already been created, or false otherwise.
  bool container_view_created_;

  std::string dockside_;

  scoped_ptr<views::WebView> web_view_;
  scoped_ptr<views::SingleSplitView> split_view_;
  views::WebView* devtools_view_;  // Owned by split_view_.

  InspectableWebContentsViewWin* web_contents_view_;
};

InspectableWebContentsView* CreateInspectableContentsView(
    InspectableWebContentsImpl* inspectable_web_contents) {
  return new InspectableWebContentsViewWin(inspectable_web_contents);
}

InspectableWebContentsViewWin::InspectableWebContentsViewWin(
    InspectableWebContentsImpl* inspectable_web_contents)
    : inspectable_web_contents_(inspectable_web_contents),
      container_(new ContainerView(this)) {
}

InspectableWebContentsViewWin::~InspectableWebContentsViewWin() {
  if (devtools_window_)
    DestroyWindow(devtools_window_->hwnd());
}

views::View* InspectableWebContentsViewWin::GetView() const {
  return container_.get();
}

views::View* InspectableWebContentsViewWin::GetWebView() const {
  return container_->GetWebView();
}

gfx::NativeView InspectableWebContentsViewWin::GetNativeView() const {
  auto web_contents = inspectable_web_contents_->GetWebContents();
  return web_contents->GetView()->GetNativeView();
}

void InspectableWebContentsViewWin::ShowDevTools() {
  container_->ShowDevTools();
  return;

  if (!devtools_window_) {
    devtools_window_ = DevToolsWindow::Create(this)->AsWeakPtr();
    devtools_window_->Init(HWND_DESKTOP, gfx::Rect());
  }

  auto contents_view = inspectable_web_contents_->GetWebContents()->GetView();
  auto size = contents_view->GetContainerSize();
  size.Enlarge(-kWindowInset, -kWindowInset);
  gfx::CenterAndSizeWindow(contents_view->GetNativeView(),
                           devtools_window_->hwnd(),
                           size);

  ShowWindow(devtools_window_->hwnd(), SW_SHOWNORMAL);
}

void InspectableWebContentsViewWin::CloseDevTools() {
  container_->CloseDevTools();
  return;

  if (!devtools_window_)
    return;
  SendMessage(devtools_window_->hwnd(), WM_CLOSE, 0, 0);
}

bool InspectableWebContentsViewWin::IsDevToolsViewShowing() {
  return container_->IsDevToolsViewShowing() || devtools_window_;
}

bool InspectableWebContentsViewWin::SetDockSide(const std::string& side) {
  return container_->SetDockSide(side);
}

}  // namespace brightray
<|endoftext|>