<commit_before>#include "gcscpp_runner.h"

#include <string>
#include <thread>

#include "absl/random/random.h"
#include "absl/time/time.h"
#include "google/cloud/storage/client.h"
#include "google/cloud/storage/grpc_plugin.h"

GcscppRunner::GcscppRunner(Parameters parameters,
                           std::shared_ptr<RunnerWatcher> watcher)
    : parameters_(parameters),
      object_resolver_(parameters_.object, parameters_.object_format,
                       parameters_.object_start, parameters_.object_stop),
      watcher_(watcher) {}

static google::cloud::storage::Client CreateClient(
    const Parameters& parameters) {
  auto opts = google::cloud::Options{};
  if (parameters.client == "gcscpp-grpc") {
    std::string target = parameters.host;
    if (parameters.td) {
      // TODO(veblush): Remove experimental suffix once this code is proven
      // stable.
      target = "google-c2p-experimental:///" + target;
    }
    return ::google::cloud::storage_experimental::DefaultGrpcClient(
        opts.set<google::cloud::storage_experimental::GrpcPluginOption>("media")
            .set<google::cloud::EndpointOption>(target));
  } else {
    return ::google::cloud::storage::Client();
  }
}

bool GcscppRunner::Run() {
  auto client = CreateClient(parameters_);

  // Spawns benchmark threads and waits until they're done.
  std::vector<std::thread> threads;
  std::vector<bool> returns(parameters_.threads);
  for (int i = 1; i <= parameters_.threads; i++) {
    int thread_id = i;
    threads.emplace_back([thread_id, client, &returns, this]() {
      returns[thread_id - 1] = this->DoOperation(thread_id, client);
    });
  }
  std::for_each(threads.begin(), threads.end(),
                [](std::thread& t) { t.join(); });
  return std::all_of(returns.begin(), returns.end(), [](bool v) { return v; });
}

bool GcscppRunner::DoOperation(int thread_id,
                               google::cloud::storage::Client storage_client) {
  switch (parameters_.operation_type) {
    case OperationType::Read:
      return DoRead(thread_id, storage_client);
    case OperationType::RandomRead:
      return DoRandomRead(thread_id, storage_client);
    case OperationType::Write:
      return DoWrite(thread_id, storage_client);
    default:
      return false;
  }
}

std::string ExtractPeer(
    std::multimap<std::string, std::string> const& headers) {
  auto p = headers.find(":grpc-context-peer");
  if (p == headers.end()) {
    p = headers.find(":curl-peer");
  }
  return p == headers.end() ? "" : p->second;
}

bool GcscppRunner::DoRead(int thread_id,
                          google::cloud::storage::Client storage_client) {
  std::vector<char> buffer(4 * 1024 * 1024);
  auto const buffer_size = static_cast<std::streamsize>(buffer.size());
  for (int run = 0; run < parameters_.runs; run++) {
    std::string object = object_resolver_.Resolve(thread_id, run);

    absl::Time run_start = absl::Now();
    auto reader = storage_client.ReadObject(parameters_.bucket, object);
    if (!reader) {
      std::cerr << "Error reading object: " << reader.status() << "\n";
      return false;
    }
    int64_t total_bytes = 0;
    std::vector<RunnerWatcher::Chunk> chunks;
    chunks.reserve(256);
    while (!reader.eof()) {
      reader.read(buffer.data(), buffer_size);
      int64_t content_size = reader.gcount();
      RunnerWatcher::Chunk chunk = {absl::Now(), content_size};
      chunks.push_back(chunk);
      total_bytes += content_size;
    }
    reader.Close();
    absl::Time run_end = absl::Now();

    watcher_->NotifyCompleted(OperationType::Read, thread_id, 0,
                              ExtractPeer(reader.headers()), parameters_.bucket,
                              object, grpc::Status::OK, total_bytes, run_start,
                              run_end - run_start, chunks);
  }
  return true;
}

bool GcscppRunner::DoRandomRead(int thread_id,
                                google::cloud::storage::Client storage_client) {
  if (parameters_.read_limit <= 0) {
    std::cerr << "read_limit should be greater than 0." << std::endl;
    return false;
  }
  int64_t read_span =
      parameters_.read_limit - std::max(int64_t(0), parameters_.read_offset);
  if (read_span <= 0) {
    std::cerr << "read_limit should be greater than read_offset." << std::endl;
    return false;
  }
  if (parameters_.chunk_size == 0) {
    std::cerr << "chunk_size should be greater than 0." << std::endl;
    return false;
  }
  int64_t chunks = read_span / parameters_.chunk_size;
  if (chunks <= 0) {
    std::cerr
        << "read_limit should be greater than or equal to readable window."
        << std::endl;
    return false;
  }

  std::string object = object_resolver_.Resolve(thread_id, 0);
  absl::BitGen gen;
  std::vector<char> buffer(4 * 1024 * 1024);
  for (int run = 0; run < parameters_.runs; run++) {
    int64_t offset = absl::Uniform(gen, 0, chunks) * parameters_.chunk_size;
    absl::Time run_start = absl::Now();
    auto reader =
        storage_client.ReadObject(parameters_.bucket, object,
                                  google::cloud::storage::ReadRange(
                                      offset, offset + parameters_.chunk_size));
    if (!reader) {
      std::cerr << "Error reading object: " << reader.status() << "\n";
      return false;
    }
    int64_t total_bytes = 0;
    std::vector<RunnerWatcher::Chunk> chunks;
    chunks.reserve(256);
    while (total_bytes < parameters_.chunk_size) {
      reader.read(buffer.data(),
                  std::min(buffer.size(), (size_t)parameters_.chunk_size));
      int64_t content_size = reader.gcount();
      RunnerWatcher::Chunk chunk = {absl::Now(), content_size};
      chunks.push_back(chunk);
      total_bytes += content_size;
    }
    reader.Close();
    absl::Time run_end = absl::Now();

    watcher_->NotifyCompleted(OperationType::Read, thread_id, 0,
                              ExtractPeer(reader.headers()), parameters_.bucket,
                              object, grpc::Status::OK, total_bytes, run_start,
                              run_end - run_start, chunks);
  }

  return true;
}

static std::vector<char> GetRandomData(size_t size) {
  std::vector<char> content(size);
  int* const s = reinterpret_cast<int*>(&(*content.begin()));
  int* const e = reinterpret_cast<int*>(&(*content.rbegin()));
  for (int* c = s; c < e; c += 1) {
    *c = rand();
  }
  return content;
}

bool GcscppRunner::DoWrite(int thread_id,
                           google::cloud::storage::Client storage_client) {
  const int64_t max_chunk_size =
      (parameters_.chunk_size < 0) ? 2097152 : parameters_.chunk_size;
  const std::vector<char> content = GetRandomData(max_chunk_size);

  if (parameters_.object_stop > 0) {
    std::cerr << "write doesn't support object_stop" << std::endl;
    return false;
  }
  if (parameters_.write_size <= 0) {
    std::cerr << "write_size should be greater than 0." << std::endl;
    return false;
  }

  for (int run = 0; run < parameters_.runs; run++) {
    std::string object = object_resolver_.Resolve(thread_id, run);
    absl::Time run_start = absl::Now();

    int64_t total_bytes = 0;
    std::vector<RunnerWatcher::Chunk> chunks;
    chunks.reserve(256);

    auto writer = storage_client.WriteObject(parameters_.bucket, object);
    for (int64_t o = 0; o < parameters_.write_size; o += max_chunk_size) {
      int64_t chunk_size = std::min(max_chunk_size, parameters_.write_size - o);
      writer.write(content.data(), static_cast<std::streamsize>(chunk_size));

      RunnerWatcher::Chunk chunk = {absl::Now(), chunk_size};
      chunks.push_back(chunk);
      total_bytes += chunk_size;
    }
    writer.Close();
    absl::Time run_end = absl::Now();

    watcher_->NotifyCompleted(OperationType::Write, thread_id, 0,
                              ExtractPeer(writer.headers()), parameters_.bucket,
                              object, grpc::Status::OK, total_bytes, run_start,
                              run_end - run_start, std::move(chunks));
  }

  return true;
}
<commit_msg>Added UploadBufferSizeOption><commit_after>#include "gcscpp_runner.h"

#include <string>
#include <thread>

#include "absl/random/random.h"
#include "absl/time/time.h"
#include "google/cloud/storage/client.h"
#include "google/cloud/storage/grpc_plugin.h"

GcscppRunner::GcscppRunner(Parameters parameters,
                           std::shared_ptr<RunnerWatcher> watcher)
    : parameters_(parameters),
      object_resolver_(parameters_.object, parameters_.object_format,
                       parameters_.object_start, parameters_.object_stop),
      watcher_(watcher) {}

static google::cloud::storage::Client CreateClient(
    const Parameters& parameters) {
  auto opts = google::cloud::Options{};
  if (parameters.write_size > 0) {
    // Make a upload buffer big enough to make it done in a single rpc call.
    std::size_t upload_buffer_size = std::min<std::size_t>(
        128 * 1024 * 1024, (std::size_t)parameters.write_size);
    opts.set<google::cloud::storage::UploadBufferSizeOption>(
        upload_buffer_size + 1);
  }
  if (parameters.client == "gcscpp-grpc") {
    std::string target = parameters.host;
    if (parameters.td) {
      // TODO(veblush): Remove experimental suffix once this code is proven
      // stable.
      target = "google-c2p-experimental:///" + target;
    }
    return ::google::cloud::storage_experimental::DefaultGrpcClient(
        opts.set<google::cloud::storage_experimental::GrpcPluginOption>("media")
            .set<google::cloud::EndpointOption>(target));
  } else {
    return ::google::cloud::storage::Client();
  }
}

bool GcscppRunner::Run() {
  auto client = CreateClient(parameters_);

  // Spawns benchmark threads and waits until they're done.
  std::vector<std::thread> threads;
  std::vector<bool> returns(parameters_.threads);
  for (int i = 1; i <= parameters_.threads; i++) {
    int thread_id = i;
    threads.emplace_back([thread_id, client, &returns, this]() {
      returns[thread_id - 1] = this->DoOperation(thread_id, client);
    });
  }
  std::for_each(threads.begin(), threads.end(),
                [](std::thread& t) { t.join(); });
  return std::all_of(returns.begin(), returns.end(), [](bool v) { return v; });
}

bool GcscppRunner::DoOperation(int thread_id,
                               google::cloud::storage::Client storage_client) {
  switch (parameters_.operation_type) {
    case OperationType::Read:
      return DoRead(thread_id, storage_client);
    case OperationType::RandomRead:
      return DoRandomRead(thread_id, storage_client);
    case OperationType::Write:
      return DoWrite(thread_id, storage_client);
    default:
      return false;
  }
}

std::string ExtractPeer(
    std::multimap<std::string, std::string> const& headers) {
  auto p = headers.find(":grpc-context-peer");
  if (p == headers.end()) {
    p = headers.find(":curl-peer");
  }
  return p == headers.end() ? "" : p->second;
}

bool GcscppRunner::DoRead(int thread_id,
                          google::cloud::storage::Client storage_client) {
  std::vector<char> buffer(4 * 1024 * 1024);
  auto const buffer_size = static_cast<std::streamsize>(buffer.size());
  for (int run = 0; run < parameters_.runs; run++) {
    std::string object = object_resolver_.Resolve(thread_id, run);

    absl::Time run_start = absl::Now();
    auto reader = storage_client.ReadObject(parameters_.bucket, object);
    if (!reader) {
      std::cerr << "Error reading object: " << reader.status() << "\n";
      return false;
    }
    int64_t total_bytes = 0;
    std::vector<RunnerWatcher::Chunk> chunks;
    chunks.reserve(256);
    while (!reader.eof()) {
      reader.read(buffer.data(), buffer_size);
      int64_t content_size = reader.gcount();
      RunnerWatcher::Chunk chunk = {absl::Now(), content_size};
      chunks.push_back(chunk);
      total_bytes += content_size;
    }
    reader.Close();
    absl::Time run_end = absl::Now();

    watcher_->NotifyCompleted(OperationType::Read, thread_id, 0,
                              ExtractPeer(reader.headers()), parameters_.bucket,
                              object, grpc::Status::OK, total_bytes, run_start,
                              run_end - run_start, chunks);
  }
  return true;
}

bool GcscppRunner::DoRandomRead(int thread_id,
                                google::cloud::storage::Client storage_client) {
  if (parameters_.read_limit <= 0) {
    std::cerr << "read_limit should be greater than 0." << std::endl;
    return false;
  }
  int64_t read_span =
      parameters_.read_limit - std::max(int64_t(0), parameters_.read_offset);
  if (read_span <= 0) {
    std::cerr << "read_limit should be greater than read_offset." << std::endl;
    return false;
  }
  if (parameters_.chunk_size == 0) {
    std::cerr << "chunk_size should be greater than 0." << std::endl;
    return false;
  }
  int64_t chunks = read_span / parameters_.chunk_size;
  if (chunks <= 0) {
    std::cerr
        << "read_limit should be greater than or equal to readable window."
        << std::endl;
    return false;
  }

  std::string object = object_resolver_.Resolve(thread_id, 0);
  absl::BitGen gen;
  std::vector<char> buffer(4 * 1024 * 1024);
  for (int run = 0; run < parameters_.runs; run++) {
    int64_t offset = absl::Uniform(gen, 0, chunks) * parameters_.chunk_size;
    absl::Time run_start = absl::Now();
    auto reader =
        storage_client.ReadObject(parameters_.bucket, object,
                                  google::cloud::storage::ReadRange(
                                      offset, offset + parameters_.chunk_size));
    if (!reader) {
      std::cerr << "Error reading object: " << reader.status() << "\n";
      return false;
    }
    int64_t total_bytes = 0;
    std::vector<RunnerWatcher::Chunk> chunks;
    chunks.reserve(256);
    while (total_bytes < parameters_.chunk_size) {
      reader.read(buffer.data(),
                  std::min(buffer.size(), (size_t)parameters_.chunk_size));
      int64_t content_size = reader.gcount();
      RunnerWatcher::Chunk chunk = {absl::Now(), content_size};
      chunks.push_back(chunk);
      total_bytes += content_size;
    }
    reader.Close();
    absl::Time run_end = absl::Now();

    watcher_->NotifyCompleted(OperationType::Read, thread_id, 0,
                              ExtractPeer(reader.headers()), parameters_.bucket,
                              object, grpc::Status::OK, total_bytes, run_start,
                              run_end - run_start, chunks);
  }

  return true;
}

static std::vector<char> GetRandomData(size_t size) {
  std::vector<char> content(size);
  int* const s = reinterpret_cast<int*>(&(*content.begin()));
  int* const e = reinterpret_cast<int*>(&(*content.rbegin()));
  for (int* c = s; c < e; c += 1) {
    *c = rand();
  }
  return content;
}

bool GcscppRunner::DoWrite(int thread_id,
                           google::cloud::storage::Client storage_client) {
  const int64_t max_chunk_size =
      (parameters_.chunk_size < 0) ? 2097152 : parameters_.chunk_size;
  const std::vector<char> content = GetRandomData(max_chunk_size);

  if (parameters_.object_stop > 0) {
    std::cerr << "write doesn't support object_stop" << std::endl;
    return false;
  }
  if (parameters_.write_size <= 0) {
    std::cerr << "write_size should be greater than 0." << std::endl;
    return false;
  }

  for (int run = 0; run < parameters_.runs; run++) {
    std::string object = object_resolver_.Resolve(thread_id, run);
    absl::Time run_start = absl::Now();

    int64_t total_bytes = 0;
    std::vector<RunnerWatcher::Chunk> chunks;
    chunks.reserve(256);

    auto writer = storage_client.WriteObject(parameters_.bucket, object);
    for (int64_t o = 0; o < parameters_.write_size; o += max_chunk_size) {
      int64_t chunk_size = std::min(max_chunk_size, parameters_.write_size - o);
      writer.write(content.data(), static_cast<std::streamsize>(chunk_size));

      RunnerWatcher::Chunk chunk = {absl::Now(), chunk_size};
      chunks.push_back(chunk);
      total_bytes += chunk_size;
    }
    writer.Close();
    absl::Time run_end = absl::Now();

    watcher_->NotifyCompleted(OperationType::Write, thread_id, 0,
                              ExtractPeer(writer.headers()), parameters_.bucket,
                              object, grpc::Status::OK, total_bytes, run_start,
                              run_end - run_start, std::move(chunks));
  }

  return true;
}
<|endoftext|>


<commit_before>// This may look like C code, but it is really -*- C++ -*-
//
// Copyright Bob Friesenhahn, 1999, 2000, 2001, 2002, 2003
//
// Pixels Implementation
//

#define MAGICKCORE_IMPLEMENTATION  1
#define MAGICK_PLUSPLUS_IMPLEMENTATION 1

#include <cstring>
#include "Magick++/Include.h"
#include <string> // This is here to compile with Visual C++
#include "Magick++/Thread.h"
#include "Magick++/Exception.h"
#include "Magick++/Pixels.h"

Magick::Pixels::Pixels(Magick::Image &image_)
  : _image(image_),
    _x(0),
    _y(0),
    _columns(0),
    _rows(0)
{
  GetPPException;
    _view=AcquireVirtualCacheView(_image.image(),exceptionInfo),
  ThrowPPException;
}

Magick::Pixels::~Pixels(void)
{
  if (_view)
    _view=DestroyCacheView(_view);
}

Magick::Quantum* Magick::Pixels::get(const ssize_t x_,const ssize_t y_,
  const size_t columns_,const size_t rows_)
{
  _x=x_;
  _y=y_;
  _columns=columns_;
  _rows=rows_;

  GetPPException;
  Quantum* pixels=GetCacheViewAuthenticPixels(_view,x_,y_,columns_,rows_,
    exceptionInfo);
  ThrowPPException;

  return pixels;
}

const Magick::Quantum* Magick::Pixels::getConst(const ssize_t x_,
  const ssize_t y_,const size_t columns_,const size_t rows_)
{
  _x=x_;
  _y=y_;
  _columns=columns_;
  _rows=rows_;

  GetPPException;
  const Quantum* pixels=GetCacheViewVirtualPixels(_view,x_,y_,columns_,rows_,
    exceptionInfo);
  ThrowPPException;

  return pixels;
}

ssize_t Magick::Pixels::offset(PixelChannel channel) const
{
  if (_image.constImage()->channel_map[channel].traits == UndefinedPixelTrait)
    return -1;
  return _image.constImage()->channel_map[channel].offset;
}

Magick::Quantum* Magick::Pixels::set(const ssize_t x_,const ssize_t y_,
  const size_t columns_,const size_t rows_)
{
  _x=x_;
  _y=y_;
  _columns=columns_;
  _rows=rows_;

  GetPPException;
  Quantum* pixels=QueueCacheViewAuthenticPixels(_view,x_,y_,columns_,rows_,
    exceptionInfo);
  ThrowPPException;

  return pixels;
}

void Magick::Pixels::sync(void)
{
  GetPPException;
  SyncCacheViewAuthenticPixels(_view,exceptionInfo);
  ThrowPPException;
}

// Return pixel colormap index array
/*
Magick::void* Magick::Pixels::metacontent(void)
{
  void* pixel_metacontent=GetCacheViewAuthenticMetacontent(_view);

  if (!pixel_metacontent)
    _image.throwImageException();

  return pixel_metacontent;
}
*/

Magick::PixelData::PixelData(Magick::Image &image_,std::string map_,
  const StorageType type_)
{
  init(image_,0,0,image_.columns(),image_.rows(),map_,type_);
}

Magick::PixelData::PixelData(Magick::Image &image_,const ::ssize_t x_,
  const ::ssize_t y_,const size_t width_,const size_t height_,std::string map_,
  const StorageType type_)
{
  init(image_,x_,y_,width_,height_,map_,type_);
}

Magick::PixelData::~PixelData(void)
{
  relinquish();
}

const void *Magick::PixelData::data(void) const
{
  return(_data);
}

const ::ssize_t Magick::PixelData::length(void) const
{
  return(_length);
}

const ::ssize_t Magick::PixelData::size(void) const
{
  return(_size);
}

void Magick::PixelData::init(Magick::Image &image_,const ::ssize_t x_,
  const ::ssize_t y_,const size_t width_,const size_t height_,
  std::string map_,const StorageType type_)
{
  size_t
    size;

  _data=(void *) NULL;
  _length=0;
  _size=0;
  if ((x_ < 0) || (width_ == 0) || (y_ < 0) || (height_ == 0) ||
      (x_ > image_.columns()) || ((width_ + x_) > (::ssize_t)image_.columns())
      || (y_ > image_.rows()) || ((height_ + y_) > (::ssize_t)image_.rows())
      || (map_.length() == 0))
    return;

  switch(type_)
  {
    case CharPixel:
      size=sizeof(unsigned char);
      break;
    case DoublePixel:
      size=sizeof(double);
      break;
    case FloatPixel:
      size=sizeof(float);
      break;
    case LongPixel:
      size=sizeof(unsigned int);
      break;
    case LongLongPixel:
      size=sizeof(MagickSizeType);
      break;
    case QuantumPixel:
      size=sizeof(Quantum);
      break;
    case ShortPixel:
      size=sizeof(unsigned short);
      break;
    default:
      throwExceptionExplicit(OptionError,"Invalid type");
      return;
  }

  _length=width_*height_*map_.length();
  _size=_length*size;
  _data=AcquireMagickMemory(_size);

  GetPPException;
  MagickCore::ExportImagePixels(image_.image(),x_,y_,width_,height_,
    map_.c_str(),type_,_data,exceptionInfo);
  if (exceptionInfo->severity != UndefinedException)
    relinquish();
  ThrowPPException;
}

void Magick::PixelData::relinquish(void) throw()
{
  if (_data != (void *)NULL)
    _data=RelinquishMagickMemory(_data);
  _length=0;
  _size=0;
}
<commit_msg>Build fix.<commit_after>// This may look like C code, but it is really -*- C++ -*-
//
// Copyright Bob Friesenhahn, 1999, 2000, 2001, 2002, 2003
//
// Pixels Implementation
//

#define MAGICKCORE_IMPLEMENTATION  1
#define MAGICK_PLUSPLUS_IMPLEMENTATION 1

#include <cstring>
#include "Magick++/Include.h"
#include <string> // This is here to compile with Visual C++
#include "Magick++/Thread.h"
#include "Magick++/Exception.h"
#include "Magick++/Pixels.h"

Magick::Pixels::Pixels(Magick::Image &image_)
  : _image(image_),
    _x(0),
    _y(0),
    _columns(0),
    _rows(0)
{
  GetPPException;
    _view=AcquireVirtualCacheView(_image.image(),exceptionInfo),
  ThrowPPException;
}

Magick::Pixels::~Pixels(void)
{
  if (_view)
    _view=DestroyCacheView(_view);
}

Magick::Quantum* Magick::Pixels::get(const ssize_t x_,const ssize_t y_,
  const size_t columns_,const size_t rows_)
{
  _x=x_;
  _y=y_;
  _columns=columns_;
  _rows=rows_;

  GetPPException;
  Quantum* pixels=GetCacheViewAuthenticPixels(_view,x_,y_,columns_,rows_,
    exceptionInfo);
  ThrowPPException;

  return pixels;
}

const Magick::Quantum* Magick::Pixels::getConst(const ssize_t x_,
  const ssize_t y_,const size_t columns_,const size_t rows_)
{
  _x=x_;
  _y=y_;
  _columns=columns_;
  _rows=rows_;

  GetPPException;
  const Quantum* pixels=GetCacheViewVirtualPixels(_view,x_,y_,columns_,rows_,
    exceptionInfo);
  ThrowPPException;

  return pixels;
}

ssize_t Magick::Pixels::offset(PixelChannel channel) const
{
  if (_image.constImage()->channel_map[channel].traits == UndefinedPixelTrait)
    return -1;
  return _image.constImage()->channel_map[channel].offset;
}

Magick::Quantum* Magick::Pixels::set(const ssize_t x_,const ssize_t y_,
  const size_t columns_,const size_t rows_)
{
  _x=x_;
  _y=y_;
  _columns=columns_;
  _rows=rows_;

  GetPPException;
  Quantum* pixels=QueueCacheViewAuthenticPixels(_view,x_,y_,columns_,rows_,
    exceptionInfo);
  ThrowPPException;

  return pixels;
}

void Magick::Pixels::sync(void)
{
  GetPPException;
  SyncCacheViewAuthenticPixels(_view,exceptionInfo);
  ThrowPPException;
}

// Return pixel colormap index array
/*
Magick::void* Magick::Pixels::metacontent(void)
{
  void* pixel_metacontent=GetCacheViewAuthenticMetacontent(_view);

  if (!pixel_metacontent)
    _image.throwImageException();

  return pixel_metacontent;
}
*/

Magick::PixelData::PixelData(Magick::Image &image_,std::string map_,
  const StorageType type_)
{
  init(image_,0,0,image_.columns(),image_.rows(),map_,type_);
}

Magick::PixelData::PixelData(Magick::Image &image_,const ::ssize_t x_,
  const ::ssize_t y_,const size_t width_,const size_t height_,std::string map_,
  const StorageType type_)
{
  init(image_,x_,y_,width_,height_,map_,type_);
}

Magick::PixelData::~PixelData(void)
{
  relinquish();
}

const void *Magick::PixelData::data(void) const
{
  return(_data);
}

::ssize_t Magick::PixelData::length(void) const
{
  return(_length);
}

::ssize_t Magick::PixelData::size(void) const
{
  return(_size);
}

void Magick::PixelData::init(Magick::Image &image_,const ::ssize_t x_,
  const ::ssize_t y_,const size_t width_,const size_t height_,
  std::string map_,const StorageType type_)
{
  size_t
    size;

  _data=(void *) NULL;
  _length=0;
  _size=0;
  if ((x_ < 0) || (width_ == 0) || (y_ < 0) || (height_ == 0) ||
      (x_ > image_.columns()) || ((width_ + x_) > (::ssize_t)image_.columns())
      || (y_ > image_.rows()) || ((height_ + y_) > (::ssize_t)image_.rows())
      || (map_.length() == 0))
    return;

  switch(type_)
  {
    case CharPixel:
      size=sizeof(unsigned char);
      break;
    case DoublePixel:
      size=sizeof(double);
      break;
    case FloatPixel:
      size=sizeof(float);
      break;
    case LongPixel:
      size=sizeof(unsigned int);
      break;
    case LongLongPixel:
      size=sizeof(MagickSizeType);
      break;
    case QuantumPixel:
      size=sizeof(Quantum);
      break;
    case ShortPixel:
      size=sizeof(unsigned short);
      break;
    default:
      throwExceptionExplicit(OptionError,"Invalid type");
      return;
  }

  _length=width_*height_*map_.length();
  _size=_length*size;
  _data=AcquireMagickMemory(_size);

  GetPPException;
  MagickCore::ExportImagePixels(image_.image(),x_,y_,width_,height_,
    map_.c_str(),type_,_data,exceptionInfo);
  if (exceptionInfo->severity != UndefinedException)
    relinquish();
  ThrowPPException;
}

void Magick::PixelData::relinquish(void) throw()
{
  if (_data != (void *)NULL)
    _data=RelinquishMagickMemory(_data);
  _length=0;
  _size=0;
}
<|endoftext|>


<commit_before>#include <UWP/UWP.hpp>

#include <Windows.h>
#include <ShlObj.h>
#include <appmodel.h>
#include <AppxPackaging.h>

#include <memory>

namespace
{
template< typename T >
void FreeDeleter(T* Data)
{
	free(Data);
}

std::unique_ptr<PACKAGE_ID, decltype(&FreeDeleter<PACKAGE_ID>)> GetPackageIdentifier()
{
	std::uint32_t Size = 0;
	GetCurrentPackageId(&Size, nullptr);

	if( Size )
	{
		std::unique_ptr<PACKAGE_ID, decltype(&FreeDeleter<PACKAGE_ID>)> PackageID(
			reinterpret_cast<PACKAGE_ID*>(malloc(Size)),
			FreeDeleter<PACKAGE_ID>
		);
		GetCurrentPackageId(
			&Size,
			reinterpret_cast<std::uint8_t*>(PackageID.get())
		);
		return PackageID;
	}
	return std::unique_ptr<PACKAGE_ID, decltype(&FreeDeleter<PACKAGE_ID>)>(
		nullptr,
		FreeDeleter<PACKAGE_ID>
	);
}

std::unique_ptr<PACKAGE_INFO, decltype(&FreeDeleter<PACKAGE_INFO>)> GetPackageInfo()
{
	std::uint32_t Size = 0;
	std::uint32_t Count = 0;
	GetCurrentPackageInfo(PACKAGE_FILTER_HEAD, &Size, nullptr, &Count);

	if( Size )
	{
		std::unique_ptr<PACKAGE_INFO, decltype(&FreeDeleter<PACKAGE_INFO>)> PackageInfo(
			reinterpret_cast<PACKAGE_INFO*>(malloc(Size)),
			[](PACKAGE_INFO* PackageID)
			{
				free(PackageID);
			}
		);

		GetCurrentPackageInfo(
			PACKAGE_FILTER_HEAD,
			&Size,
			reinterpret_cast<std::uint8_t*>(PackageInfo.get()),
			&Count
		);
		return PackageInfo;
	}

	return std::unique_ptr<PACKAGE_INFO, decltype(&FreeDeleter<PACKAGE_INFO>)>(
		nullptr,
		FreeDeleter<PACKAGE_INFO>
	);
}
}

std::wstring UWP::Current::GetFamilyName()
{
	std::wstring FamilyName;
	std::uint32_t FamilyNameSize = 0;

	GetCurrentPackageFamilyName(&FamilyNameSize, nullptr);
	FamilyName.resize(FamilyNameSize - 1);
	GetCurrentPackageFamilyName(&FamilyNameSize, &FamilyName[0]);

	return FamilyName;
}

std::wstring UWP::Current::GetFullName()
{
	std::wstring FullName;
	std::uint32_t FullNameSize = 0;

	GetCurrentPackageFullName(&FullNameSize, nullptr);
	FullName.resize(FullNameSize - 1);
	GetCurrentPackageFullName(&FullNameSize, &FullName[0]);

	return FullName;
}

std::wstring UWP::Current::GetArchitecture()
{
	auto PackageID = GetPackageIdentifier();
	if( PackageID )
	{
		switch( PackageID->processorArchitecture )
		{
		case APPX_PACKAGE_ARCHITECTURE_ARM:
		{
			return L"ARM";
		}
		case APPX_PACKAGE_ARCHITECTURE_X86:
		{
			return L"x86";
		}
		case APPX_PACKAGE_ARCHITECTURE_X64:
		{
			return L"x64";
		}
		case APPX_PACKAGE_ARCHITECTURE_NEUTRAL:
		{
			return L"Neutral";
		}
		}
	}
	return L"";
}

std::wstring UWP::Current::GetPublisher()
{
	auto PackageID = GetPackageIdentifier();
	if( PackageID )
	{
		return std::wstring(PackageID->publisher);
	}
	return L"";
}

std::wstring UWP::Current::GetPublisherID()
{
	auto PackageID = GetPackageIdentifier();
	if( PackageID )
	{
		return std::wstring(PackageID->publisherId);
	}
	return L"";
}

std::wstring UWP::Current::GetPackagePath()
{
	std::wstring Path;
	std::uint32_t PathSize = 0;

	GetCurrentPackagePath(&PathSize, nullptr);
	Path.resize(PathSize - 1);
	GetCurrentPackagePath(&PathSize, &Path[0]);

	return Path;
}

std::wstring UWP::Current::Storage::GetPublisherPath()
{
	auto PackageID = GetPackageIdentifier();
	if( PackageID )
	{
		wchar_t UserPath[MAX_PATH] = {0};
		SHGetSpecialFolderPathW(nullptr, UserPath, CSIDL_PROFILE, false);

		std::wstring PublisherPath(UserPath);

		PublisherPath += L"\\AppData\\Local\\Publishers\\";
		PublisherPath += PackageID->publisherId;

		return PublisherPath;
	}
	return L"";
}

std::wstring UWP::Current::Storage::GetStoragePath()
{
	wchar_t UserPath[MAX_PATH] = {0};
	SHGetSpecialFolderPathW(nullptr, UserPath, CSIDL_PROFILE, false);

	std::wstring StoragePath(UserPath);

	StoragePath += L"\\AppData\\Local\\Packages\\" + GetFamilyName();

	return StoragePath;
}

std::wstring UWP::Current::Storage::GetLocalCachePath()
{
	return GetStoragePath() + L"\\LocalCache";
}

std::wstring UWP::Current::Storage::GetLocalPath()
{
	return GetStoragePath() + L"\\LocalState";
}

std::wstring UWP::Current::Storage::GetRoamingPath()
{
	return GetStoragePath() + L"\\RoamingState";
}

std::wstring UWP::Current::Storage::GetTempStatePath()
{
	return GetStoragePath() + L"\\TempState";
}
<commit_msg>Add template FreeDeleter to for PACKAGE_INFO<commit_after>#include <UWP/UWP.hpp>

#include <Windows.h>
#include <ShlObj.h>
#include <appmodel.h>
#include <AppxPackaging.h>

#include <memory>

namespace
{
template< typename T >
void FreeDeleter(T* Data)
{
	free(Data);
}

std::unique_ptr<PACKAGE_ID, decltype(&FreeDeleter<PACKAGE_ID>)> GetPackageIdentifier()
{
	std::uint32_t Size = 0;
	GetCurrentPackageId(&Size, nullptr);

	if( Size )
	{
		std::unique_ptr<PACKAGE_ID, decltype(&FreeDeleter<PACKAGE_ID>)> PackageID(
			reinterpret_cast<PACKAGE_ID*>(malloc(Size)),
			FreeDeleter<PACKAGE_ID>
		);
		GetCurrentPackageId(
			&Size,
			reinterpret_cast<std::uint8_t*>(PackageID.get())
		);
		return PackageID;
	}
	return std::unique_ptr<PACKAGE_ID, decltype(&FreeDeleter<PACKAGE_ID>)>(
		nullptr,
		FreeDeleter<PACKAGE_ID>
	);
}

std::unique_ptr<PACKAGE_INFO, decltype(&FreeDeleter<PACKAGE_INFO>)> GetPackageInfo()
{
	std::uint32_t Size = 0;
	std::uint32_t Count = 0;
	GetCurrentPackageInfo(PACKAGE_FILTER_HEAD, &Size, nullptr, &Count);

	if( Size )
	{
		std::unique_ptr<PACKAGE_INFO, decltype(&FreeDeleter<PACKAGE_INFO>)> PackageInfo(
			reinterpret_cast<PACKAGE_INFO*>(malloc(Size)),
			FreeDeleter<PACKAGE_INFO>
		);

		GetCurrentPackageInfo(
			PACKAGE_FILTER_HEAD,
			&Size,
			reinterpret_cast<std::uint8_t*>(PackageInfo.get()),
			&Count
		);
		return PackageInfo;
	}

	return std::unique_ptr<PACKAGE_INFO, decltype(&FreeDeleter<PACKAGE_INFO>)>(
		nullptr,
		FreeDeleter<PACKAGE_INFO>
	);
}
}

std::wstring UWP::Current::GetFamilyName()
{
	std::wstring FamilyName;
	std::uint32_t FamilyNameSize = 0;

	GetCurrentPackageFamilyName(&FamilyNameSize, nullptr);
	FamilyName.resize(FamilyNameSize - 1);
	GetCurrentPackageFamilyName(&FamilyNameSize, &FamilyName[0]);

	return FamilyName;
}

std::wstring UWP::Current::GetFullName()
{
	std::wstring FullName;
	std::uint32_t FullNameSize = 0;

	GetCurrentPackageFullName(&FullNameSize, nullptr);
	FullName.resize(FullNameSize - 1);
	GetCurrentPackageFullName(&FullNameSize, &FullName[0]);

	return FullName;
}

std::wstring UWP::Current::GetArchitecture()
{
	auto PackageID = GetPackageIdentifier();
	if( PackageID )
	{
		switch( PackageID->processorArchitecture )
		{
		case APPX_PACKAGE_ARCHITECTURE_ARM:
		{
			return L"ARM";
		}
		case APPX_PACKAGE_ARCHITECTURE_X86:
		{
			return L"x86";
		}
		case APPX_PACKAGE_ARCHITECTURE_X64:
		{
			return L"x64";
		}
		case APPX_PACKAGE_ARCHITECTURE_NEUTRAL:
		{
			return L"Neutral";
		}
		}
	}
	return L"";
}

std::wstring UWP::Current::GetPublisher()
{
	auto PackageID = GetPackageIdentifier();
	if( PackageID )
	{
		return std::wstring(PackageID->publisher);
	}
	return L"";
}

std::wstring UWP::Current::GetPublisherID()
{
	auto PackageID = GetPackageIdentifier();
	if( PackageID )
	{
		return std::wstring(PackageID->publisherId);
	}
	return L"";
}

std::wstring UWP::Current::GetPackagePath()
{
	std::wstring Path;
	std::uint32_t PathSize = 0;

	GetCurrentPackagePath(&PathSize, nullptr);
	Path.resize(PathSize - 1);
	GetCurrentPackagePath(&PathSize, &Path[0]);

	return Path;
}

std::wstring UWP::Current::Storage::GetPublisherPath()
{
	auto PackageID = GetPackageIdentifier();
	if( PackageID )
	{
		wchar_t UserPath[MAX_PATH] = {0};
		SHGetSpecialFolderPathW(nullptr, UserPath, CSIDL_PROFILE, false);

		std::wstring PublisherPath(UserPath);

		PublisherPath += L"\\AppData\\Local\\Publishers\\";
		PublisherPath += PackageID->publisherId;

		return PublisherPath;
	}
	return L"";
}

std::wstring UWP::Current::Storage::GetStoragePath()
{
	wchar_t UserPath[MAX_PATH] = {0};
	SHGetSpecialFolderPathW(nullptr, UserPath, CSIDL_PROFILE, false);

	std::wstring StoragePath(UserPath);

	StoragePath += L"\\AppData\\Local\\Packages\\" + GetFamilyName();

	return StoragePath;
}

std::wstring UWP::Current::Storage::GetLocalCachePath()
{
	return GetStoragePath() + L"\\LocalCache";
}

std::wstring UWP::Current::Storage::GetLocalPath()
{
	return GetStoragePath() + L"\\LocalState";
}

std::wstring UWP::Current::Storage::GetRoamingPath()
{
	return GetStoragePath() + L"\\RoamingState";
}

std::wstring UWP::Current::Storage::GetTempStatePath()
{
	return GetStoragePath() + L"\\TempState";
}
<|endoftext|>


<commit_before>/* Copyright 2013-2016 CyberTech Labs Ltd.
 *
 * 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 "trikKitInterpreterCommon/trikKitInterpreterPluginBase.h"

#include <QtWidgets/QApplication>
#include <QtWidgets/QLineEdit>

#include <twoDModel/engine/twoDModelEngineFacade.h>
#include <qrkernel/settingsManager.h>
#include <qrkernel/settingsListener.h>

#include <qrgui/textEditor/qscintillaTextEdit.h>
#include <qrgui/textEditor/languageInfo.h>

using namespace trik;
using namespace qReal;

const Id robotDiagramType = Id("RobotsMetamodel", "RobotsDiagram", "RobotsDiagramNode");
const Id subprogramDiagramType = Id("RobotsMetamodel", "RobotsDiagram", "SubprogramDiagram");

TrikKitInterpreterPluginBase::TrikKitInterpreterPluginBase() :
	mStart(tr("Start QTS"), nullptr), mStop(tr("Stop QTS"), nullptr)
{
}

TrikKitInterpreterPluginBase::~TrikKitInterpreterPluginBase()
{
	if (mOwnsAdditionalPreferences) {
		delete mAdditionalPreferences;
	}

	if (mOwnsBlocksFactory) {
		delete mBlocksFactory;
	}
}

void TrikKitInterpreterPluginBase::initKitInterpreterPluginBase
		(robotModel::TrikRobotModelBase * const realRobotModel
		, robotModel::twoD::TrikTwoDRobotModel * const twoDRobotModel
		, blocks::TrikBlocksFactoryBase * const blocksFactory
		)
{
	mRealRobotModel.reset(realRobotModel);
	mTwoDRobotModel.reset(twoDRobotModel);
	mBlocksFactory = blocksFactory;

	const auto modelEngine = new twoDModel::engine::TwoDModelEngineFacade(*mTwoDRobotModel);

	mTwoDRobotModel->setEngine(modelEngine->engine());
	mTwoDModel.reset(modelEngine);

	connectDevicesConfigurationProvider(devicesConfigurationProvider()); // ... =(

	mAdditionalPreferences = new TrikAdditionalPreferences({ mRealRobotModel->name() });

	mQtsInterpreter.reset(new TrikQtsInterpreter(mTwoDRobotModel));
}

void TrikKitInterpreterPluginBase::startJSInterpretation(const QString &code)
{
	emit codeInterpretationStarted(code);

	auto model = mTwoDRobotModel;
	model->stopRobot(); // testStop?
	const QString modelName = model->robotId();

	for (const kitBase::robotModel::PortInfo &port : model->configurablePorts()) {
		const kitBase::robotModel::DeviceInfo deviceInfo = currentConfiguration(modelName, port);
		model->configureDevice(port, deviceInfo);
	}

	model->applyConfiguration();

	qtsInterpreter()->init();

	qtsInterpreter()->setCurrentDir(mProjectManager->saveFilePath());
	qtsInterpreter()->setRunning(true);
	emit started();
	qtsInterpreter()->interpretScript(code);
}

void TrikKitInterpreterPluginBase::startJSInterpretation(const QString &code, const QString &inputs)
{
	// we are in exercise mode (maybe rename it later)
	emit codeInterpretationStarted(code);

	auto model = mTwoDRobotModel;
	model->stopRobot(); // testStop?
	const QString modelName = model->robotId();

	for (const kitBase::robotModel::PortInfo &port : model->configurablePorts()) {
		const kitBase::robotModel::DeviceInfo deviceInfo = currentConfiguration(modelName, port);
		model->configureDevice(port, deviceInfo);
	}

	model->applyConfiguration();

	qtsInterpreter()->init();

	qtsInterpreter()->setCurrentDir(mProjectManager->saveFilePath());
	qtsInterpreter()->setRunning(true);
	emit started();
	qtsInterpreter()->interpretScriptExercise(code, inputs);
}

TrikQtsInterpreter * TrikKitInterpreterPluginBase::qtsInterpreter() const
{
	return mQtsInterpreter.data();
}

void TrikKitInterpreterPluginBase::init(const kitBase::KitPluginConfigurator &configurer)
{
	connect(&configurer.eventsForKitPlugin()
			, &kitBase::EventsForKitPluginInterface::robotModelChanged
			, [this](const QString &modelName) { mCurrentlySelectedModelName = modelName; });

	qReal::gui::MainWindowInterpretersInterface &interpretersInterface
			= configurer.qRealConfigurator().mainWindowInterpretersInterface();

	mProjectManager = &configurer.qRealConfigurator().projectManager();

	mTwoDModel->init(configurer.eventsForKitPlugin()
			, configurer.qRealConfigurator().systemEvents()
			, configurer.qRealConfigurator().logicalModelApi()
			, configurer.qRealConfigurator().controller()
			, interpretersInterface
			, configurer.qRealConfigurator().mainWindowDockInterface()
			, configurer.qRealConfigurator().projectManager()
			, configurer.interpreterControl());

	mRealRobotModel->setErrorReporter(*interpretersInterface.errorReporter());
	mTwoDRobotModel->setErrorReporter(*interpretersInterface.errorReporter());

	mQtsInterpreter->setErrorReporter(*interpretersInterface.errorReporter());

	mMainWindow = &configurer.qRealConfigurator().mainWindowInterpretersInterface();

	mSystemEvents = &configurer.qRealConfigurator().systemEvents();

	/// @todo: refactor?
	mStart.setObjectName("runQts");
	mStart.setText(tr("Run program"));
	mStart.setIcon(QIcon(":/trik/qts/images/run.png"));

	mStop.setObjectName("stopQts");
	mStop.setText(tr("Stop robot"));
	mStop.setIcon(QIcon(":/trik/qts/images/stop.png"));

	mStop.setVisible(false);
	mStart.setVisible(false);

	connect(&configurer.eventsForKitPlugin()
			, &kitBase::EventsForKitPluginInterface::interpretCode
			, [this](const QString &code, const QString &inputs){
		if (mIsModelSelected) {
			startJSInterpretation(code, inputs);
		}
	});

	connect(&configurer.robotModelManager()
			, &kitBase::robotModel::RobotModelManagerInterface::robotModelChanged
			, [this](kitBase::robotModel::RobotModelInterface &model){
		mIsModelSelected = robotModels().contains(&model);
		/// @todo: would probably make sense to make the current opened tab info available globally somewhere
		bool isCodeTabOpen = dynamic_cast<qReal::text::QScintillaTextEdit *>(mMainWindow->currentTab());
		mStart.setVisible(mIsModelSelected && isCodeTabOpen);
		mStop.setVisible(false); // interpretation should always stop when switching models?
	});

	connect(&configurer.interpreterControl()
			, &kitBase::InterpreterControlInterface::stopAllInterpretation
			, [this](qReal::interpretation::StopReason) {
		if (mQtsInterpreter->isRunning()) {
			testStop();
		}
	});

	connect(&configurer.interpreterControl()
			, &kitBase::InterpreterControlInterface::startJsInterpretation
			, [this]() {
		if (!mQtsInterpreter->isRunning() && mIsModelSelected) { // temporary
			testStart();
		}
	});

	connect(&mStart, &QAction::triggered, this, &TrikKitInterpreterPluginBase::testStart);
	connect(&mStop, &QAction::triggered, this, &TrikKitInterpreterPluginBase::testStop);
	connect(mQtsInterpreter.data()
			, &TrikQtsInterpreter::completed
			, this
			, &TrikKitInterpreterPluginBase::testStop);
	// refactor?
	connect(this
			, &TrikKitInterpreterPluginBase::started
			, &configurer.eventsForKitPlugin()
			, &kitBase::EventsForKitPluginInterface::interpretationStarted
			);

	connect(this
			, &TrikKitInterpreterPluginBase::stopped
			, &configurer.eventsForKitPlugin()
			, &kitBase::EventsForKitPluginInterface::interpretationStopped
			);

//	connect(&configurer.qRealConfigurator().systemEvents(),
//			&kitBase::EventsForKitPluginInterface:)

	connect(&configurer.eventsForKitPlugin()
			, &kitBase::EventsForKitPluginInterface::interpretationStarted
			, [this](){ /// @todo
		const bool isQtsInt = mQtsInterpreter->isRunning();
		mStart.setEnabled(isQtsInt);
		mStop.setEnabled(isQtsInt);
	}
	);

	QObject::connect(
				this
				, &TrikKitInterpreterPluginBase::codeInterpretationStarted
				, &configurer.eventsForKitPlugin()
				, &kitBase::EventsForKitPluginInterface::codeInterpretationStarted
				);

	QObject::connect(
				&configurer.eventsForKitPlugin()
				, &kitBase::EventsForKitPluginInterface::interpretationStopped
				, [this](qReal::interpretation::StopReason reason){ /// @todo
		Q_UNUSED(reason);
		mStart.setEnabled(true);
		mStop.setEnabled(true);
	}
	);

	connect(mSystemEvents
			, &qReal::SystemEvents::activeTabChanged
			, this
			, &TrikKitInterpreterPluginBase::onTabChanged);

	connect(mAdditionalPreferences, &TrikAdditionalPreferences::settingsChanged
			, mRealRobotModel.data(), &robotModel::TrikRobotModelBase::rereadSettings);

	connect(mAdditionalPreferences, &TrikAdditionalPreferences::settingsChanged
			, mTwoDRobotModel.data(), &robotModel::twoD::TrikTwoDRobotModel::rereadSettings);
}

QList<kitBase::robotModel::RobotModelInterface *> TrikKitInterpreterPluginBase::robotModels()
{
	return {mRealRobotModel.data(), mTwoDRobotModel.data()};
}

kitBase::blocksBase::BlocksFactoryInterface *TrikKitInterpreterPluginBase::blocksFactoryFor(
		const kitBase::robotModel::RobotModelInterface *model)
{
	Q_UNUSED(model);

	mOwnsBlocksFactory = false;
	return mBlocksFactory;
}

kitBase::robotModel::RobotModelInterface *TrikKitInterpreterPluginBase::defaultRobotModel()
{
	return mTwoDRobotModel.data();
}

QList<kitBase::AdditionalPreferences *> TrikKitInterpreterPluginBase::settingsWidgets()
{
	mOwnsAdditionalPreferences = false;
	return {mAdditionalPreferences};
}

QWidget *TrikKitInterpreterPluginBase::quickPreferencesFor(const kitBase::robotModel::RobotModelInterface &model)
{
	return model.name().toLower().contains("twod")
			? nullptr
			: produceIpAddressConfigurer();
}

QList<qReal::ActionInfo> TrikKitInterpreterPluginBase::customActions()
{
	return { qReal::ActionInfo(&mStart, "interpreters", "tools"), qReal::ActionInfo(&mStop, "interpreters", "tools") };
}

QList<HotKeyActionInfo> TrikKitInterpreterPluginBase::hotKeyActions()
{
	return {};
}

QString TrikKitInterpreterPluginBase::defaultSettingsFile() const
{
	return ":/trikDefaultSettings.ini";
}

QIcon TrikKitInterpreterPluginBase::iconForFastSelector(
		const kitBase::robotModel::RobotModelInterface &robotModel) const
{
	return &robotModel == mRealRobotModel.data()
			? QIcon(":/icons/switch-real-trik.svg")
			: &robotModel == mTwoDRobotModel.data()
					? QIcon(":/icons/switch-2d.svg")
					: QIcon();
}

kitBase::DevicesConfigurationProvider *TrikKitInterpreterPluginBase::devicesConfigurationProvider()
{
	return &mTwoDModel->devicesConfigurationProvider();
}

QWidget *TrikKitInterpreterPluginBase::produceIpAddressConfigurer()
{
	QLineEdit * const quickPreferences = new QLineEdit;
	quickPreferences->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
	quickPreferences->setPlaceholderText(tr("Enter robot`s IP-address here..."));
	const auto updateQuickPreferences = [quickPreferences]() {
		const QString ip = qReal::SettingsManager::value("TrikTcpServer").toString();
		if (quickPreferences->text() != ip) {
			quickPreferences->setText(ip);
		}
	};

	updateQuickPreferences();
	connect(mAdditionalPreferences, &TrikAdditionalPreferences::settingsChanged, updateQuickPreferences);
	qReal::SettingsListener::listen("TrikTcpServer", updateQuickPreferences, this);
	connect(quickPreferences, &QLineEdit::textChanged, [](const QString &text) {
		qReal::SettingsManager::setValue("TrikTcpServer", text);
	});

	connect(this, &QObject::destroyed, [quickPreferences]() { delete quickPreferences; });
	return quickPreferences;
}

void TrikKitInterpreterPluginBase::testStart()
{
	mStop.setVisible(true);
	mStart.setVisible(false);
	/// todo: bad

	auto texttab = dynamic_cast<qReal::text::QScintillaTextEdit *>(mMainWindow->currentTab());
	auto isJS = [](const QString &ext){ return ext == "js" || ext == "qts"; };

	if (texttab && isJS(texttab->currentLanguage().extension)) {
		startJSInterpretation(texttab->text());
	} else {
		qDebug("wrong tab selected");
		mStop.setVisible(false);
		mStart.setVisible(true);
		/// todo: refactor the whole button shenanigans
	}
}

void TrikKitInterpreterPluginBase::testStop()
{
	mStop.setVisible(false);
	mStart.setVisible(true);

	qtsInterpreter()->abort();
	mTwoDRobotModel->stopRobot();
	emit stopped(qReal::interpretation::StopReason::userStop);
}

void TrikKitInterpreterPluginBase::onTabChanged(const TabInfo &info)
{
	if (!mIsModelSelected) {
		return;
	}
	const bool isCodeTab = info.type() == qReal::TabInfo::TabType::code;
	mStart.setEnabled(isCodeTab);
	mStop.setEnabled(isCodeTab);
	if (mQtsInterpreter->isRunning()) {
		mStop.trigger(); // Should interpretation should always stops at the change of tabs or not?
	}
	if (isCodeTab) {
		mStart.setVisible(true);
		mStop.setVisible(false);
	} else {
		mStart.setVisible(false);
		mStop.setVisible(false);
	}
}
<commit_msg>Fix crash on exit<commit_after>/* Copyright 2013-2016 CyberTech Labs Ltd.
 *
 * 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 "trikKitInterpreterCommon/trikKitInterpreterPluginBase.h"

#include <QtWidgets/QApplication>
#include <QtWidgets/QLineEdit>

#include <twoDModel/engine/twoDModelEngineFacade.h>
#include <qrkernel/settingsManager.h>
#include <qrkernel/settingsListener.h>

#include <qrgui/textEditor/qscintillaTextEdit.h>
#include <qrgui/textEditor/languageInfo.h>

using namespace trik;
using namespace qReal;

const Id robotDiagramType = Id("RobotsMetamodel", "RobotsDiagram", "RobotsDiagramNode");
const Id subprogramDiagramType = Id("RobotsMetamodel", "RobotsDiagram", "SubprogramDiagram");

TrikKitInterpreterPluginBase::TrikKitInterpreterPluginBase() :
	mStart(tr("Start QTS"), nullptr), mStop(tr("Stop QTS"), nullptr)
{
}

TrikKitInterpreterPluginBase::~TrikKitInterpreterPluginBase()
{
	if (mOwnsAdditionalPreferences) {
		delete mAdditionalPreferences;
	}

	if (mOwnsBlocksFactory) {
		delete mBlocksFactory;
	}
}

void TrikKitInterpreterPluginBase::initKitInterpreterPluginBase
		(robotModel::TrikRobotModelBase * const realRobotModel
		, robotModel::twoD::TrikTwoDRobotModel * const twoDRobotModel
		, blocks::TrikBlocksFactoryBase * const blocksFactory
		)
{
	mRealRobotModel.reset(realRobotModel);
	mTwoDRobotModel.reset(twoDRobotModel);
	mBlocksFactory = blocksFactory;

	const auto modelEngine = new twoDModel::engine::TwoDModelEngineFacade(*mTwoDRobotModel);

	mTwoDRobotModel->setEngine(modelEngine->engine());
	mTwoDModel.reset(modelEngine);

	connectDevicesConfigurationProvider(devicesConfigurationProvider()); // ... =(

	mAdditionalPreferences = new TrikAdditionalPreferences({ mRealRobotModel->name() });

	mQtsInterpreter.reset(new TrikQtsInterpreter(mTwoDRobotModel));
}

void TrikKitInterpreterPluginBase::startJSInterpretation(const QString &code)
{
	emit codeInterpretationStarted(code);

	auto model = mTwoDRobotModel;
	model->stopRobot(); // testStop?
	const QString modelName = model->robotId();

	for (const kitBase::robotModel::PortInfo &port : model->configurablePorts()) {
		const kitBase::robotModel::DeviceInfo deviceInfo = currentConfiguration(modelName, port);
		model->configureDevice(port, deviceInfo);
	}

	model->applyConfiguration();

	qtsInterpreter()->init();

	qtsInterpreter()->setCurrentDir(mProjectManager->saveFilePath());
	qtsInterpreter()->setRunning(true);
	emit started();
	qtsInterpreter()->interpretScript(code);
}

void TrikKitInterpreterPluginBase::startJSInterpretation(const QString &code, const QString &inputs)
{
	// we are in exercise mode (maybe rename it later)
	emit codeInterpretationStarted(code);

	auto model = mTwoDRobotModel;
	model->stopRobot(); // testStop?
	const QString modelName = model->robotId();

	for (const kitBase::robotModel::PortInfo &port : model->configurablePorts()) {
		const kitBase::robotModel::DeviceInfo deviceInfo = currentConfiguration(modelName, port);
		model->configureDevice(port, deviceInfo);
	}

	model->applyConfiguration();

	qtsInterpreter()->init();

	qtsInterpreter()->setCurrentDir(mProjectManager->saveFilePath());
	qtsInterpreter()->setRunning(true);
	emit started();
	qtsInterpreter()->interpretScriptExercise(code, inputs);
}

TrikQtsInterpreter * TrikKitInterpreterPluginBase::qtsInterpreter() const
{
	return mQtsInterpreter.data();
}

void TrikKitInterpreterPluginBase::init(const kitBase::KitPluginConfigurator &configurer)
{
	connect(&configurer.eventsForKitPlugin()
			, &kitBase::EventsForKitPluginInterface::robotModelChanged
			, [this](const QString &modelName) { mCurrentlySelectedModelName = modelName; });

	qReal::gui::MainWindowInterpretersInterface &interpretersInterface
			= configurer.qRealConfigurator().mainWindowInterpretersInterface();

	mProjectManager = &configurer.qRealConfigurator().projectManager();

	mTwoDModel->init(configurer.eventsForKitPlugin()
			, configurer.qRealConfigurator().systemEvents()
			, configurer.qRealConfigurator().logicalModelApi()
			, configurer.qRealConfigurator().controller()
			, interpretersInterface
			, configurer.qRealConfigurator().mainWindowDockInterface()
			, configurer.qRealConfigurator().projectManager()
			, configurer.interpreterControl());

	mRealRobotModel->setErrorReporter(*interpretersInterface.errorReporter());
	mTwoDRobotModel->setErrorReporter(*interpretersInterface.errorReporter());

	mQtsInterpreter->setErrorReporter(*interpretersInterface.errorReporter());

	mMainWindow = &configurer.qRealConfigurator().mainWindowInterpretersInterface();

	mSystemEvents = &configurer.qRealConfigurator().systemEvents();

	/// @todo: refactor?
	mStart.setObjectName("runQts");
	mStart.setText(tr("Run program"));
	mStart.setIcon(QIcon(":/trik/qts/images/run.png"));

	mStop.setObjectName("stopQts");
	mStop.setText(tr("Stop robot"));
	mStop.setIcon(QIcon(":/trik/qts/images/stop.png"));

	mStop.setVisible(false);
	mStart.setVisible(false);

	connect(&configurer.eventsForKitPlugin()
			, &kitBase::EventsForKitPluginInterface::interpretCode
			, [this](const QString &code, const QString &inputs){
		if (mIsModelSelected) {
			startJSInterpretation(code, inputs);
		}
	});

	connect(&configurer.robotModelManager()
			, &kitBase::robotModel::RobotModelManagerInterface::robotModelChanged
			, [this](kitBase::robotModel::RobotModelInterface &model){
		mIsModelSelected = robotModels().contains(&model);
		/// @todo: would probably make sense to make the current opened tab info available globally somewhere
		bool isCodeTabOpen = dynamic_cast<qReal::text::QScintillaTextEdit *>(mMainWindow->currentTab());
		mStart.setVisible(mIsModelSelected && isCodeTabOpen);
		mStop.setVisible(false); // interpretation should always stop when switching models?
	});

	connect(&configurer.interpreterControl()
			, &kitBase::InterpreterControlInterface::stopAllInterpretation
			, this
			, [this](qReal::interpretation::StopReason) {
		if (mQtsInterpreter->isRunning()) {
			testStop();
		}
	});

	connect(&configurer.interpreterControl()
			, &kitBase::InterpreterControlInterface::startJsInterpretation
			, this
			, [this]() {
		if (!mQtsInterpreter->isRunning() && mIsModelSelected) { // temporary
			testStart();
		}
	});

	connect(&mStart, &QAction::triggered, this, &TrikKitInterpreterPluginBase::testStart);
	connect(&mStop, &QAction::triggered, this, &TrikKitInterpreterPluginBase::testStop);
	connect(mQtsInterpreter.data()
			, &TrikQtsInterpreter::completed
			, this
			, &TrikKitInterpreterPluginBase::testStop);
	// refactor?
	connect(this
			, &TrikKitInterpreterPluginBase::started
			, &configurer.eventsForKitPlugin()
			, &kitBase::EventsForKitPluginInterface::interpretationStarted
			);

	connect(this
			, &TrikKitInterpreterPluginBase::stopped
			, &configurer.eventsForKitPlugin()
			, &kitBase::EventsForKitPluginInterface::interpretationStopped
			);

//	connect(&configurer.qRealConfigurator().systemEvents(),
//			&kitBase::EventsForKitPluginInterface:)

	connect(&configurer.eventsForKitPlugin()
			, &kitBase::EventsForKitPluginInterface::interpretationStarted
			, [this](){ /// @todo
		const bool isQtsInt = mQtsInterpreter->isRunning();
		mStart.setEnabled(isQtsInt);
		mStop.setEnabled(isQtsInt);
	}
	);

	QObject::connect(
				this
				, &TrikKitInterpreterPluginBase::codeInterpretationStarted
				, &configurer.eventsForKitPlugin()
				, &kitBase::EventsForKitPluginInterface::codeInterpretationStarted
				);

	QObject::connect(
				&configurer.eventsForKitPlugin()
				, &kitBase::EventsForKitPluginInterface::interpretationStopped
				, [this](qReal::interpretation::StopReason reason){ /// @todo
		Q_UNUSED(reason);
		mStart.setEnabled(true);
		mStop.setEnabled(true);
	}
	);

	connect(mSystemEvents
			, &qReal::SystemEvents::activeTabChanged
			, this
			, &TrikKitInterpreterPluginBase::onTabChanged);

	connect(mAdditionalPreferences, &TrikAdditionalPreferences::settingsChanged
			, mRealRobotModel.data(), &robotModel::TrikRobotModelBase::rereadSettings);

	connect(mAdditionalPreferences, &TrikAdditionalPreferences::settingsChanged
			, mTwoDRobotModel.data(), &robotModel::twoD::TrikTwoDRobotModel::rereadSettings);
}

QList<kitBase::robotModel::RobotModelInterface *> TrikKitInterpreterPluginBase::robotModels()
{
	return {mRealRobotModel.data(), mTwoDRobotModel.data()};
}

kitBase::blocksBase::BlocksFactoryInterface *TrikKitInterpreterPluginBase::blocksFactoryFor(
		const kitBase::robotModel::RobotModelInterface *model)
{
	Q_UNUSED(model);

	mOwnsBlocksFactory = false;
	return mBlocksFactory;
}

kitBase::robotModel::RobotModelInterface *TrikKitInterpreterPluginBase::defaultRobotModel()
{
	return mTwoDRobotModel.data();
}

QList<kitBase::AdditionalPreferences *> TrikKitInterpreterPluginBase::settingsWidgets()
{
	mOwnsAdditionalPreferences = false;
	return {mAdditionalPreferences};
}

QWidget *TrikKitInterpreterPluginBase::quickPreferencesFor(const kitBase::robotModel::RobotModelInterface &model)
{
	return model.name().toLower().contains("twod")
			? nullptr
			: produceIpAddressConfigurer();
}

QList<qReal::ActionInfo> TrikKitInterpreterPluginBase::customActions()
{
	return { qReal::ActionInfo(&mStart, "interpreters", "tools"), qReal::ActionInfo(&mStop, "interpreters", "tools") };
}

QList<HotKeyActionInfo> TrikKitInterpreterPluginBase::hotKeyActions()
{
	return {};
}

QString TrikKitInterpreterPluginBase::defaultSettingsFile() const
{
	return ":/trikDefaultSettings.ini";
}

QIcon TrikKitInterpreterPluginBase::iconForFastSelector(
		const kitBase::robotModel::RobotModelInterface &robotModel) const
{
	return &robotModel == mRealRobotModel.data()
			? QIcon(":/icons/switch-real-trik.svg")
			: &robotModel == mTwoDRobotModel.data()
					? QIcon(":/icons/switch-2d.svg")
					: QIcon();
}

kitBase::DevicesConfigurationProvider *TrikKitInterpreterPluginBase::devicesConfigurationProvider()
{
	return &mTwoDModel->devicesConfigurationProvider();
}

QWidget *TrikKitInterpreterPluginBase::produceIpAddressConfigurer()
{
	QLineEdit * const quickPreferences = new QLineEdit;
	quickPreferences->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
	quickPreferences->setPlaceholderText(tr("Enter robot`s IP-address here..."));
	const auto updateQuickPreferences = [quickPreferences]() {
		const QString ip = qReal::SettingsManager::value("TrikTcpServer").toString();
		if (quickPreferences->text() != ip) {
			quickPreferences->setText(ip);
		}
	};

	updateQuickPreferences();
	connect(mAdditionalPreferences, &TrikAdditionalPreferences::settingsChanged, updateQuickPreferences);
	qReal::SettingsListener::listen("TrikTcpServer", updateQuickPreferences, this);
	connect(quickPreferences, &QLineEdit::textChanged, [](const QString &text) {
		qReal::SettingsManager::setValue("TrikTcpServer", text);
	});

	connect(this, &QObject::destroyed, [quickPreferences]() { delete quickPreferences; });
	return quickPreferences;
}

void TrikKitInterpreterPluginBase::testStart()
{
	mStop.setVisible(true);
	mStart.setVisible(false);
	/// todo: bad

	auto texttab = dynamic_cast<qReal::text::QScintillaTextEdit *>(mMainWindow->currentTab());
	auto isJS = [](const QString &ext){ return ext == "js" || ext == "qts"; };

	if (texttab && isJS(texttab->currentLanguage().extension)) {
		startJSInterpretation(texttab->text());
	} else {
		qDebug("wrong tab selected");
		mStop.setVisible(false);
		mStart.setVisible(true);
		/// todo: refactor the whole button shenanigans
	}
}

void TrikKitInterpreterPluginBase::testStop()
{
	mStop.setVisible(false);
	mStart.setVisible(true);

	qtsInterpreter()->abort();
	mTwoDRobotModel->stopRobot();
	emit stopped(qReal::interpretation::StopReason::userStop);
}

void TrikKitInterpreterPluginBase::onTabChanged(const TabInfo &info)
{
	if (!mIsModelSelected) {
		return;
	}
	const bool isCodeTab = info.type() == qReal::TabInfo::TabType::code;
	mStart.setEnabled(isCodeTab);
	mStop.setEnabled(isCodeTab);
	if (mQtsInterpreter->isRunning()) {
		mStop.trigger(); // Should interpretation should always stops at the change of tabs or not?
	}
	if (isCodeTab) {
		mStart.setVisible(true);
		mStop.setVisible(false);
	} else {
		mStart.setVisible(false);
		mStop.setVisible(false);
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2006 George Staikos <staikos@kde.org>
 * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
 * Copyright (C) 2006 Zack Rusin <zack@kde.org>
 * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org>
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include <qwebpage.h>
#include <qwebframe.h>
#include <qwebsettings.h>

#include <QtGui>
#include <QDebug>

class InfoWidget :public QProgressBar {
    Q_OBJECT
public:
    InfoWidget(QWidget *parent)
        : QProgressBar(parent), m_progress(0)
    {
        setMinimum(0);
        setMaximum(100);
    }
    QSize sizeHint() const
    {
        QSize size(100, 20);
        return size;
    }
public slots:
    void startLoad()
    {
        setValue(m_progress);
        show();
    }
    void changeLoad(int change)
    {
        m_progress = change;
        setValue(change);
    }
    void endLoad()
    {
        QTimer::singleShot(1000, this, SLOT(hide()));
        m_progress = 0;
    }

protected:
    int m_progress;
};

class HoverLabel : public QWidget {
    Q_OBJECT
public:
    HoverLabel(QWidget *parent=0)
        : QWidget(parent),
          m_animating(false),
          m_percent(0)
    {
        m_timer.setInterval(1000/30);
        m_hideTimer.setInterval(500);
        m_hideTimer.setSingleShot(true);
        connect(&m_timer, SIGNAL(timeout()),
                this, SLOT(update()));
        connect(&m_hideTimer, SIGNAL(timeout()),
                this, SLOT(hide()));
    }

public slots:
    void setHoverLink(const QString &link) {
        m_link = link;
        if (m_link.isEmpty()) {
            m_hideTimer.start();
        } else {
            m_hideTimer.stop();
            m_oldSize = m_newSize;
            m_newSize = sizeForFont();
            resetAnimation();
            updateSize();
            show();
            repaint();
        }
    }
    QSize sizeForFont() const {
        QFont f = font();
        QFontMetrics fm(f);
        return QSize(fm.width(m_link) + 10, fm.height() + 6);
    }
    QSize sizeHint() const {
        if (!m_animating)
            return sizeForFont();
        else
            return (m_newSize.width() > m_oldSize.width()) ? m_newSize : m_oldSize;
    }
    void updateSize() {
        QRect r = geometry();
        QSize newSize = sizeHint();
        r = QRect(r.x(), r.y(), newSize.width(), newSize.height());
        setGeometry(r);
    }
    void resetAnimation() {
        m_animating = true;
        m_percent = 0;
        if (!m_timer.isActive())
            m_timer.start();
    }
protected:
    void paintEvent(QPaintEvent *e) {
        QPainter p(this);
        p.setClipRect(e->rect());
        p.setPen(QPen(Qt::black, 1));
        QLinearGradient gradient(rect().topLeft(), rect().bottomLeft());
        gradient.setColorAt(0, QColor(255, 255, 255, 220));
        gradient.setColorAt(1, QColor(193, 193, 193, 220));
        p.setBrush(QBrush(gradient));
        QSize size;
        {
            //draw a nicely rounded corner rectangle. to avoid unwanted
            // borders we move the coordinates outsize the our clip region
            size = interpolate(m_oldSize, m_newSize, m_percent);
            QRect r(-1, 0, size.width(), size.height()+2);
            const int roundness = 20;
            QPainterPath path;
            path.moveTo(r.x(), r.y());
            path.lineTo(r.topRight().x()-roundness, r.topRight().y());
            path.cubicTo(r.topRight().x(), r.topRight().y(),
                         r.topRight().x(), r.topRight().y(),
                         r.topRight().x(), r.topRight().y() + roundness);
            path.lineTo(r.bottomRight());
            path.lineTo(r.bottomLeft());
            path.closeSubpath();
            p.setRenderHint(QPainter::Antialiasing);
            p.drawPath(path);
        }
        if (m_animating) {
            if (qFuzzyCompare(m_percent, 1)) {
                m_animating = false;
                m_percent = 0;
                m_timer.stop();
            } else {
                m_percent += 0.1;
                if (m_percent >= 0.99) {
                    m_percent = 1;
                }
            }
        }

        QString txt;
        QFontMetrics fm(fontMetrics());
        txt = fm.elidedText(m_link, Qt::ElideRight, size.width()-5);
        p.drawText(5, height()-6, txt);
    }

private:
    QSize interpolate(const QSize &src, const QSize &dst, qreal percent) {
        int widthDiff  = int((dst.width() - src.width())  * percent);
        int heightDiff = int((dst.height() - src.height()) * percent);
        return QSize(src.width()  + widthDiff,
                     src.height() + heightDiff);
    }
    QString m_link;
    bool    m_animating;
    QTimer  m_timer;
    QTimer  m_hideTimer;
    QSize   m_oldSize;
    QSize   m_newSize;
    qreal   m_percent;
};

class SearchEdit;

class ClearButton : public QPushButton {
    Q_OBJECT
public:
    ClearButton(QWidget *w)
        : QPushButton(w)
    {
        setMinimumSize(24, 24);
        setFixedSize(24, 24);
        setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    }
    void paintEvent(QPaintEvent *event)
    {
        Q_UNUSED(event);
        QPainter painter(this);
        int height = parentWidget()->geometry().height();
        int width = height; //parentWidget()->geometry().width();

        painter.setRenderHint(QPainter::Antialiasing, true);
        painter.setPen(Qt::lightGray);
        painter.setBrush(isDown() ?
                         QColor(140, 140, 190) :
                         underMouse() ? QColor(220, 220, 255) : QColor(200, 200, 230)
            );
        painter.drawEllipse(4, 4, width - 8, height - 8);
        painter.setPen(Qt::white);
        int border = 8;
        painter.drawLine(border, border, width - border, height - border);
        painter.drawLine(border, height - border, width - border, border);
    }
};

class SearchEdit : public QLineEdit
{
    Q_OBJECT
public:
    SearchEdit(const QString &str, QWidget *parent = 0)
        : QLineEdit(str, parent)
    {
        setMinimumSize(QSize(400, 24));
        setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

        setStyleSheet(":enabled { padding-right: 27px }");
        clearButton = new ClearButton(this);
        clearButton->setGeometry(QRect(geometry().right() - 27,
                                       geometry().top() - 2,
                                       geometry().right(), geometry().bottom()));
        clearButton->setVisible(true);
        clearButton->setCursor(Qt::ArrowCursor);
        connect(clearButton, SIGNAL(clicked()), this, SLOT(clear()));
        clearButton->setToolTip("Clear");
    }
    ~SearchEdit() { }
protected:
    virtual void paintEvent(QPaintEvent *e) {
        QLineEdit::paintEvent(e);
        if(text().isEmpty())
            clearButton->setVisible(false);
        else
            clearButton->setVisible(true);
    }
    virtual void resizeEvent(QResizeEvent *) {
        clearButton->setParent(this);
        clearButton->setGeometry(QRect(width()-27,
                                       0,
                                       24, 24));
    }
    virtual void moveEvent(QMoveEvent *) {
        clearButton->setParent(this);
        clearButton->setGeometry(QRect(width()-27, 1,
                                       24, 24));
    }

    QPushButton *clearButton;
};

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(const QUrl &url)
    {
        page = new QWebPage(this);
        InfoWidget *info = new InfoWidget(page);
        info->setGeometry(20, 20, info->sizeHint().width(),
                          info->sizeHint().height());
        connect(page, SIGNAL(loadStarted(QWebFrame*)),
                info, SLOT(startLoad()));
        connect(page, SIGNAL(loadProgressChanged(int)),
                info, SLOT(changeLoad(int)));
        connect(page, SIGNAL(loadFinished(QWebFrame*)),
                info, SLOT(endLoad()));
        connect(page, SIGNAL(loadFinished(QWebFrame*)),
                this, SLOT(loadFinished()));
        connect(page, SIGNAL(titleChanged(const QString&)),
                this, SLOT(setWindowTitle(const QString&)));
        connect(page, SIGNAL(hoveringOverLink(const QString&, const QString&)),
                this, SLOT(showLinkHover(const QString&, const QString&)));

        setCentralWidget(page);

        QToolBar *bar = addToolBar("Navigation");
        urlEdit = new SearchEdit(url.toString());
        connect(urlEdit, SIGNAL(returnPressed()),
                SLOT(changeLocation()));
        bar->addAction("Go back", page, SLOT(goBack()));
        bar->addAction("Stop", page, SLOT(stop()));
        bar->addAction("Go forward", page, SLOT(goForward()));
        bar->addWidget(urlEdit);

        hoverLabel = new HoverLabel(this);
        hoverLabel->hide();

        page->open(url);

        info->raise();
    }
protected slots:
    void changeLocation()
    {
        QUrl url(urlEdit->text());
        page->open(url);
    }
    void loadFinished()
    {
        urlEdit->setText(page->url().toString());
    }
    void showLinkHover(const QString &link, const QString &toolTip)
    {
        //statusBar()->showMessage(link);
        hoverLabel->setHoverLink(link);
        if (!toolTip.isEmpty())
            QToolTip::showText(QCursor::pos(), toolTip);
    }
protected:
    void resizeEvent(QResizeEvent *) {
        QSize hoverSize = hoverLabel->sizeHint();
        hoverLabel->setGeometry(0, height()-hoverSize.height(),
                                300, hoverSize.height());
    }
private:
    QWebPage *page;
    QLineEdit *urlEdit;
    HoverLabel *hoverLabel;
};

#include "main.moc"

int main(int argc, char **argv)
{
    QString url = QString("%1/%2").arg(QDir::homePath()).arg(QLatin1String("index.html"));
    QApplication app(argc, argv);

    QWebSettings settings = QWebSettings::global();
    settings.setAttribute(QWebSettings::PluginsEnabled);
    QWebSettings::setGlobal(settings);

    const QStringList args = app.arguments();
    if (args.count() > 1)
        url = args.at(1);

    MainWindow window(url);
    window.show();

    return app.exec();
}
<commit_msg>Missed this file as part of #23832<commit_after>/*
 * Copyright (C) 2006 George Staikos <staikos@kde.org>
 * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
 * Copyright (C) 2006 Zack Rusin <zack@kde.org>
 * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org>
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include <qwebpage.h>
#include <qwebframe.h>
#include <qwebsettings.h>

#include <QtGui>
#include <QDebug>

class InfoWidget :public QProgressBar {
    Q_OBJECT
public:
    InfoWidget(QWidget *parent)
        : QProgressBar(parent), m_progress(0)
    {
        setMinimum(0);
        setMaximum(100);
    }
    QSize sizeHint() const
    {
        QSize size(100, 20);
        return size;
    }
public slots:
    void startLoad()
    {
        setValue(m_progress);
        show();
    }
    void changeLoad(int change)
    {
        m_progress = change;
        setValue(change);
    }
    void endLoad()
    {
        QTimer::singleShot(1000, this, SLOT(hide()));
        m_progress = 0;
    }

protected:
    int m_progress;
};

class HoverLabel : public QWidget {
    Q_OBJECT
public:
    HoverLabel(QWidget *parent=0)
        : QWidget(parent),
          m_animating(false),
          m_percent(0)
    {
        m_timer.setInterval(1000/30);
        m_hideTimer.setInterval(500);
        m_hideTimer.setSingleShot(true);
        connect(&m_timer, SIGNAL(timeout()),
                this, SLOT(update()));
        connect(&m_hideTimer, SIGNAL(timeout()),
                this, SLOT(hide()));
    }

public slots:
    void setHoverLink(const QString &link) {
        m_link = link;
        if (m_link.isEmpty()) {
            m_hideTimer.start();
        } else {
            m_hideTimer.stop();
            m_oldSize = m_newSize;
            m_newSize = sizeForFont();
            resetAnimation();
            updateSize();
            show();
            repaint();
        }
    }
    QSize sizeForFont() const {
        QFont f = font();
        QFontMetrics fm(f);
        return QSize(fm.width(m_link) + 10, fm.height() + 6);
    }
    QSize sizeHint() const {
        if (!m_animating)
            return sizeForFont();
        else
            return (m_newSize.width() > m_oldSize.width()) ? m_newSize : m_oldSize;
    }
    void updateSize() {
        QRect r = geometry();
        QSize newSize = sizeHint();
        r = QRect(r.x(), r.y(), newSize.width(), newSize.height());
        setGeometry(r);
    }
    void resetAnimation() {
        m_animating = true;
        m_percent = 0;
        if (!m_timer.isActive())
            m_timer.start();
    }
protected:
    void paintEvent(QPaintEvent *e) {
        QPainter p(this);
        p.setClipRect(e->rect());
        p.setPen(QPen(Qt::black, 1));
        QLinearGradient gradient(rect().topLeft(), rect().bottomLeft());
        gradient.setColorAt(0, QColor(255, 255, 255, 220));
        gradient.setColorAt(1, QColor(193, 193, 193, 220));
        p.setBrush(QBrush(gradient));
        QSize size;
        {
            //draw a nicely rounded corner rectangle. to avoid unwanted
            // borders we move the coordinates outsize the our clip region
            size = interpolate(m_oldSize, m_newSize, m_percent);
            QRect r(-1, 0, size.width(), size.height()+2);
            const int roundness = 20;
            QPainterPath path;
            path.moveTo(r.x(), r.y());
            path.lineTo(r.topRight().x()-roundness, r.topRight().y());
            path.cubicTo(r.topRight().x(), r.topRight().y(),
                         r.topRight().x(), r.topRight().y(),
                         r.topRight().x(), r.topRight().y() + roundness);
            path.lineTo(r.bottomRight());
            path.lineTo(r.bottomLeft());
            path.closeSubpath();
            p.setRenderHint(QPainter::Antialiasing);
            p.drawPath(path);
        }
        if (m_animating) {
            if (qFuzzyCompare(m_percent, 1)) {
                m_animating = false;
                m_percent = 0;
                m_timer.stop();
            } else {
                m_percent += 0.1;
                if (m_percent >= 0.99) {
                    m_percent = 1;
                }
            }
        }

        QString txt;
        QFontMetrics fm(fontMetrics());
        txt = fm.elidedText(m_link, Qt::ElideRight, size.width()-5);
        p.drawText(5, height()-6, txt);
    }

private:
    QSize interpolate(const QSize &src, const QSize &dst, qreal percent) {
        int widthDiff  = int((dst.width() - src.width())  * percent);
        int heightDiff = int((dst.height() - src.height()) * percent);
        return QSize(src.width()  + widthDiff,
                     src.height() + heightDiff);
    }
    QString m_link;
    bool    m_animating;
    QTimer  m_timer;
    QTimer  m_hideTimer;
    QSize   m_oldSize;
    QSize   m_newSize;
    qreal   m_percent;
};

class SearchEdit;

class ClearButton : public QPushButton {
    Q_OBJECT
public:
    ClearButton(QWidget *w)
        : QPushButton(w)
    {
        setMinimumSize(24, 24);
        setFixedSize(24, 24);
        setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    }
    void paintEvent(QPaintEvent *event)
    {
        Q_UNUSED(event);
        QPainter painter(this);
        int height = parentWidget()->geometry().height();
        int width = height; //parentWidget()->geometry().width();

        painter.setRenderHint(QPainter::Antialiasing, true);
        painter.setPen(Qt::lightGray);
        painter.setBrush(isDown() ?
                         QColor(140, 140, 190) :
                         underMouse() ? QColor(220, 220, 255) : QColor(200, 200, 230)
            );
        painter.drawEllipse(4, 4, width - 8, height - 8);
        painter.setPen(Qt::white);
        int border = 8;
        painter.drawLine(border, border, width - border, height - border);
        painter.drawLine(border, height - border, width - border, border);
    }
};

class SearchEdit : public QLineEdit
{
    Q_OBJECT
public:
    SearchEdit(const QString &str, QWidget *parent = 0)
        : QLineEdit(str, parent)
    {
        setMinimumSize(QSize(400, 24));
        setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

        setStyleSheet(":enabled { padding-right: 27px }");
        clearButton = new ClearButton(this);
        clearButton->setGeometry(QRect(geometry().right() - 27,
                                       geometry().top() - 2,
                                       geometry().right(), geometry().bottom()));
        clearButton->setVisible(true);
#ifndef QT_NO_CURSOR
        clearButton->setCursor(Qt::ArrowCursor);
#endif
#ifndef QT_NO_TOOLTIP
        clearButton->setToolTip("Clear");
#endif
        connect(clearButton, SIGNAL(clicked()), this, SLOT(clear()));
    }
    ~SearchEdit() { }
protected:
    virtual void paintEvent(QPaintEvent *e) {
        QLineEdit::paintEvent(e);
        if(text().isEmpty())
            clearButton->setVisible(false);
        else
            clearButton->setVisible(true);
    }
    virtual void resizeEvent(QResizeEvent *) {
        clearButton->setParent(this);
        clearButton->setGeometry(QRect(width()-27,
                                       0,
                                       24, 24));
    }
    virtual void moveEvent(QMoveEvent *) {
        clearButton->setParent(this);
        clearButton->setGeometry(QRect(width()-27, 1,
                                       24, 24));
    }

    QPushButton *clearButton;
};

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(const QUrl &url)
    {
        page = new QWebPage(this);
        InfoWidget *info = new InfoWidget(page);
        info->setGeometry(20, 20, info->sizeHint().width(),
                          info->sizeHint().height());
        connect(page, SIGNAL(loadStarted(QWebFrame*)),
                info, SLOT(startLoad()));
        connect(page, SIGNAL(loadProgressChanged(int)),
                info, SLOT(changeLoad(int)));
        connect(page, SIGNAL(loadFinished(QWebFrame*)),
                info, SLOT(endLoad()));
        connect(page, SIGNAL(loadFinished(QWebFrame*)),
                this, SLOT(loadFinished()));
        connect(page, SIGNAL(titleChanged(const QString&)),
                this, SLOT(setWindowTitle(const QString&)));
        connect(page, SIGNAL(hoveringOverLink(const QString&, const QString&)),
                this, SLOT(showLinkHover(const QString&, const QString&)));

        setCentralWidget(page);

        QToolBar *bar = addToolBar("Navigation");
        urlEdit = new SearchEdit(url.toString());
        connect(urlEdit, SIGNAL(returnPressed()),
                SLOT(changeLocation()));
        bar->addAction("Go back", page, SLOT(goBack()));
        bar->addAction("Stop", page, SLOT(stop()));
        bar->addAction("Go forward", page, SLOT(goForward()));
        bar->addWidget(urlEdit);

        hoverLabel = new HoverLabel(this);
        hoverLabel->hide();

        page->open(url);

        info->raise();
    }
protected slots:
    void changeLocation()
    {
        QUrl url(urlEdit->text());
        page->open(url);
    }
    void loadFinished()
    {
        urlEdit->setText(page->url().toString());
    }
    void showLinkHover(const QString &link, const QString &toolTip)
    {
        //statusBar()->showMessage(link);
        hoverLabel->setHoverLink(link);
#ifndef QT_NO_TOOLTIP
        if (!toolTip.isEmpty())
            QToolTip::showText(QCursor::pos(), toolTip);
#endif
    }
protected:
    void resizeEvent(QResizeEvent *) {
        QSize hoverSize = hoverLabel->sizeHint();
        hoverLabel->setGeometry(0, height()-hoverSize.height(),
                                300, hoverSize.height());
    }
private:
    QWebPage *page;
    QLineEdit *urlEdit;
    HoverLabel *hoverLabel;
};

#include "main.moc"

int main(int argc, char **argv)
{
    QString url = QString("%1/%2").arg(QDir::homePath()).arg(QLatin1String("index.html"));
    QApplication app(argc, argv);

    QWebSettings settings = QWebSettings::global();
    settings.setAttribute(QWebSettings::PluginsEnabled);
    QWebSettings::setGlobal(settings);

    const QStringList args = app.arguments();
    if (args.count() > 1)
        url = args.at(1);

    MainWindow window(url);
    window.show();

    return app.exec();
}
<|endoftext|>