<commit_before>//
// Copyright RIME Developers
// Distributed under the BSD License
//
// 2011-04-24 GONG Chen <chen.sst@gmail.com>
//
#include <cctype>
#include <rime/common.h>
#include <rime/composition.h>
#include <rime/context.h>
#include <rime/engine.h>
#include <rime/filter.h>
#include <rime/formatter.h>
#include <rime/key_event.h>
#include <rime/menu.h>
#include <rime/processor.h>
#include <rime/schema.h>
#include <rime/segmentation.h>
#include <rime/segmentor.h>
#include <rime/switcher.h>
#include <rime/ticket.h>
#include <rime/translation.h>
#include <rime/translator.h>

namespace rime {

class ConcreteEngine : public Engine {
 public:
  ConcreteEngine();
  virtual ~ConcreteEngine();
  virtual bool ProcessKey(const KeyEvent& key_event);
  virtual void ApplySchema(Schema* schema);
  virtual void CommitText(string text);
  virtual void Compose(Context* ctx);

 protected:
  void InitializeComponents();
  void InitializeOptions();
  void CalculateSegmentation(Segmentation* segments);
  void TranslateSegments(Segmentation* segments);
  void FormatText(string* text);
  void OnCommit(Context* ctx);
  void OnSelect(Context* ctx);
  void OnContextUpdate(Context* ctx);
  void OnOptionUpdate(Context* ctx, const string& option);
  void OnPropertyUpdate(Context* ctx, const string& property);

  vector<of<Processor>> processors_;
  vector<of<Segmentor>> segmentors_;
  vector<of<Translator>> translators_;
  vector<of<Filter>> filters_;
  vector<of<Formatter>> formatters_;
  vector<of<Processor>> post_processors_;
};

// implementations

Engine* Engine::Create() {
  return new ConcreteEngine;
}

Engine::Engine() : schema_(new Schema), context_(new Context) {
}

Engine::~Engine() {
  context_.reset();
  schema_.reset();
}

ConcreteEngine::ConcreteEngine() {
  LOG(INFO) << "starting engine.";
  // receive context notifications
  context_->commit_notifier().connect(
      [this](Context* ctx) { OnCommit(ctx); });
  context_->select_notifier().connect(
      [this](Context* ctx) { OnSelect(ctx); });
  context_->update_notifier().connect(
      [this](Context* ctx) { OnContextUpdate(ctx); });
  context_->option_update_notifier().connect(
      [this](Context* ctx, const string& option) {
        OnOptionUpdate(ctx, option);
      });
  context_->property_update_notifier().connect(
      [this](Context* ctx, const string& property) {
        OnPropertyUpdate(ctx, property);
      });
  InitializeComponents();
  InitializeOptions();
}

ConcreteEngine::~ConcreteEngine() {
  LOG(INFO) << "engine disposed.";
  processors_.clear();
  segmentors_.clear();
  translators_.clear();
}

bool ConcreteEngine::ProcessKey(const KeyEvent& key_event) {
  DLOG(INFO) << "process key: " << key_event;
  ProcessResult ret = kNoop;
  for (auto& processor : processors_) {
    ret = processor->ProcessKeyEvent(key_event);
    if (ret == kRejected) break;
    if (ret == kAccepted) return true;
  }
  // record unhandled keys, eg. spaces, numbers, bksp's.
  context_->commit_history().Push(key_event);
  // post-processing
  for (auto& processor : post_processors_) {
    ret = processor->ProcessKeyEvent(key_event);
    if (ret == kRejected) break;
    if (ret == kAccepted) return true;
  }
  // notify interested parties
  context_->unhandled_key_notifier()(context_.get(), key_event);
  return false;
}

void ConcreteEngine::OnContextUpdate(Context* ctx) {
  if (!ctx) return;
  Compose(ctx);
}

void ConcreteEngine::OnOptionUpdate(Context* ctx, const string& option) {
  if (!ctx) return;
  LOG(INFO) << "updated option: " << option;
  // apply new option to active segment
  if (ctx->IsComposing()) {
    ctx->RefreshNonConfirmedComposition();
  }
  // notification
  bool option_is_on = ctx->get_option(option);
  string msg(option_is_on ? option : "!" + option);
  message_sink_("option", msg);
}

void ConcreteEngine::OnPropertyUpdate(Context* ctx, const string& property) {
  if (!ctx) return;
  LOG(INFO) << "updated property: " << property;
  // notification
  string value = ctx->get_property(property);
  string msg(property + "=" + value);
  message_sink_("property", msg);
}

void ConcreteEngine::Compose(Context* ctx) {
  if (!ctx) return;
  Composition& comp = ctx->composition();
  const string active_input = ctx->input().substr(0, ctx->caret_pos());
  DLOG(INFO) << "active input: " << active_input;
  comp.Reset(active_input);
  if (ctx->caret_pos() < ctx->input().length() &&
      ctx->caret_pos() == comp.GetConfirmedPosition()) {
    // translate one segment past caret pos.
    comp.Reset(ctx->input());
  }
  CalculateSegmentation(&comp);
  TranslateSegments(&comp);
  DLOG(INFO) << "composition: " << comp.GetDebugText();
}

void ConcreteEngine::CalculateSegmentation(Segmentation* segments) {
  while (!segments->HasFinishedSegmentation()) {
    size_t start_pos = segments->GetCurrentStartPosition();
    size_t end_pos = segments->GetCurrentEndPosition();
    DLOG(INFO) << "start pos: " << start_pos;
    DLOG(INFO) << "end pos: " << end_pos;
    // recognize a segment by calling the segmentors in turn
    for (auto& segmentor : segmentors_) {
      if (!segmentor->Proceed(segments))
        break;
    }
    DLOG(INFO) << "segmentation: " << *segments;
    // no advancement
    if (start_pos == segments->GetCurrentEndPosition())
      break;
    // only one segment is allowed past caret pos, which is the segment
    // immediately after the caret.
    if (start_pos >= context_->caret_pos())
      break;
    // move onto the next segment...
    if (!segments->HasFinishedSegmentation())
      segments->Forward();
  }
  // start an empty segment only at the end of a confirmed composition.
  segments->Trim();
  if (!segments->empty() && segments->back().status >= Segment::kSelected)
    segments->Forward();
}

void ConcreteEngine::TranslateSegments(Segmentation* segments) {
  for (Segment& segment : *segments) {
    if (segment.status >= Segment::kGuess)
      continue;
    size_t len = segment.end - segment.start;
    if (len == 0)
      continue;
    string input = segments->input().substr(segment.start, len);
    DLOG(INFO) << "translating segment: " << input;
    auto menu = New<Menu>();
    for (auto& translator : translators_) {
      auto translation = translator->Query(input, segment);
      if (!translation)
        continue;
      if (translation->exhausted()) {
        LOG(INFO) << "Oops, got a futile translation.";
        continue;
      }
      menu->AddTranslation(translation);
    }
    for (auto& filter : filters_) {
      if (filter->AppliesToSegment(&segment)) {
        menu->AddFilter(filter.get());
      }
    }
    segment.status = Segment::kGuess;
    segment.menu = menu;
    segment.selected_index = 0;
  }
}

void ConcreteEngine::FormatText(string* text) {
  if (formatters_.empty())
    return;
  DLOG(INFO) << "applying formatters.";
  for (auto& formatter : formatters_) {
    formatter->Format(text);
  }
}

void ConcreteEngine::CommitText(string text) {
  context_->commit_history().Push(CommitRecord{"raw", text});
  FormatText(&text);
  DLOG(INFO) << "committing text: " << text;
  sink_(text);
}

void ConcreteEngine::OnCommit(Context* ctx) {
  context_->commit_history().Push(ctx->composition(), ctx->input());
  string text = ctx->GetCommitText();
  FormatText(&text);
  DLOG(INFO) << "committing composition: " << text;
  sink_(text);
}

void ConcreteEngine::OnSelect(Context* ctx) {
  Segment& seg(ctx->composition().back());
  seg.Close();
  if (seg.end == ctx->input().length()) {
    // composition has finished
    seg.status = Segment::kConfirmed;
    // strategy one: commit directly;
    // strategy two: continue composing with another empty segment.
    if (ctx->get_option("_auto_commit"))
      ctx->Commit();
    else
      ctx->composition().Forward();
  }
  else {
    bool updateCaret = (seg.end >= ctx->caret_pos());
    ctx->composition().Forward();
    if (updateCaret) {
      // finished converting current segment
      // move caret to the end of input
      ctx->set_caret_pos(ctx->input().length());
    }
    else {
      Compose(ctx);
    }
  }
}

void ConcreteEngine::ApplySchema(Schema* schema) {
  if (!schema)
    return;
  schema_.reset(schema);
  context_->Clear();
  context_->ClearTransientOptions();
  InitializeComponents();
  InitializeOptions();
  message_sink_("schema", schema->schema_id() + "/" + schema->schema_name());
}

void ConcreteEngine::InitializeComponents() {
  processors_.clear();
  segmentors_.clear();
  translators_.clear();
  filters_.clear();

  if (auto switcher = New<Switcher>(this)) {
    processors_.push_back(switcher);
    if (schema_->schema_id() == ".default") {
      if (Schema* schema = switcher->CreateSchema()) {
        schema_.reset(schema);
      }
    }
  }

  Config* config = schema_->config();
  if (!config)
    return;
  // create processors
  if (auto processor_list = config->GetList("engine/processors")) {
    size_t n = processor_list->size();
    for (size_t i = 0; i < n; ++i) {
      auto prescription = As<ConfigValue>(processor_list->GetAt(i));
      if (!prescription)
        continue;
      Ticket ticket{this, "processor", prescription->str()};
      if (auto c = Processor::Require(ticket.klass)) {
        an<Processor> p(c->Create(ticket));
        processors_.push_back(p);
      }
      else {
        LOG(ERROR) << "error creating processor: '" << ticket.klass << "'";
      }
    }
  }
  // create segmentors
  if (auto segmentor_list = config->GetList("engine/segmentors")) {
    size_t n = segmentor_list->size();
    for (size_t i = 0; i < n; ++i) {
      auto prescription = As<ConfigValue>(segmentor_list->GetAt(i));
      if (!prescription)
        continue;
      Ticket ticket{this, "segmentor", prescription->str()};
      if (auto c = Segmentor::Require(ticket.klass)) {
        an<Segmentor> s(c->Create(ticket));
        segmentors_.push_back(s);
      }
      else {
        LOG(ERROR) << "error creating segmentor: '" << ticket.klass << "'";
      }
    }
  }
  // create translators
  if (auto translator_list = config->GetList("engine/translators")) {
    size_t n = translator_list->size();
    for (size_t i = 0; i < n; ++i) {
      auto prescription = As<ConfigValue>(translator_list->GetAt(i));
      if (!prescription)
        continue;
      Ticket ticket{this, "translator", prescription->str()};
      if (auto c = Translator::Require(ticket.klass)) {
        an<Translator> t(c->Create(ticket));
        translators_.push_back(t);
      }
      else {
        LOG(ERROR) << "error creating translator: '" << ticket.klass << "'";
      }
    }
  }
  // create filters
  if (auto filter_list = config->GetList("engine/filters")) {
    size_t n = filter_list->size();
    for (size_t i = 0; i < n; ++i) {
      auto prescription = As<ConfigValue>(filter_list->GetAt(i));
      if (!prescription)
        continue;
      Ticket ticket{this, "filter", prescription->str()};
      if (auto c = Filter::Require(ticket.klass)) {
        an<Filter> f(c->Create(ticket));
        filters_.push_back(f);
      }
      else {
        LOG(ERROR) << "error creating filter: '" << ticket.klass << "'";
      }
    }
  }
  // create formatters
  if (auto c = Formatter::Require("shape_formatter")) {
    an<Formatter> f(c->Create(Ticket(this)));
    formatters_.push_back(f);
  }
  else {
    LOG(WARNING) << "shape_formatter not available.";
  }
  // create post-processors
  if (auto c = Processor::Require("shape_processor")) {
    an<Processor> p(c->Create(Ticket(this)));
    post_processors_.push_back(p);
  }
  else {
    LOG(WARNING) << "shape_processor not available.";
  }
}

void ConcreteEngine::InitializeOptions() {
  // reset custom switches
  Config* config = schema_->config();
  if (auto switches = config->GetList("switches")) {
    for (size_t i = 0; i < switches->size(); ++i) {
      auto item = As<ConfigMap>(switches->GetAt(i));
      if (!item)
        continue;
      auto reset_value = item->GetValue("reset");
      if (!reset_value)
        continue;
      int value = 0;
      reset_value->GetInt(&value);
      if (auto option_name = item->GetValue("name")) {
        // toggle
        context_->set_option(option_name->str(), (value != 0));
      }
      else if (auto options = As<ConfigList>(item->Get("options"))) {
        // radio
        for (size_t i = 0; i < options->size(); ++i) {
          if (auto option_name = options->GetValueAt(i)) {
            context_->set_option(option_name->str(),
                                 static_cast<int>(i) == value);
          }
        }
      }
    }
  }
}

}  // namespace rime
<commit_msg>chore(engine.cc): Google code style; more informative name<commit_after>//
// Copyright RIME Developers
// Distributed under the BSD License
//
// 2011-04-24 GONG Chen <chen.sst@gmail.com>
//
#include <cctype>
#include <rime/common.h>
#include <rime/composition.h>
#include <rime/context.h>
#include <rime/engine.h>
#include <rime/filter.h>
#include <rime/formatter.h>
#include <rime/key_event.h>
#include <rime/menu.h>
#include <rime/processor.h>
#include <rime/schema.h>
#include <rime/segmentation.h>
#include <rime/segmentor.h>
#include <rime/switcher.h>
#include <rime/ticket.h>
#include <rime/translation.h>
#include <rime/translator.h>

namespace rime {

class ConcreteEngine : public Engine {
 public:
  ConcreteEngine();
  virtual ~ConcreteEngine();
  virtual bool ProcessKey(const KeyEvent& key_event);
  virtual void ApplySchema(Schema* schema);
  virtual void CommitText(string text);
  virtual void Compose(Context* ctx);

 protected:
  void InitializeComponents();
  void InitializeOptions();
  void CalculateSegmentation(Segmentation* segments);
  void TranslateSegments(Segmentation* segments);
  void FormatText(string* text);
  void OnCommit(Context* ctx);
  void OnSelect(Context* ctx);
  void OnContextUpdate(Context* ctx);
  void OnOptionUpdate(Context* ctx, const string& option);
  void OnPropertyUpdate(Context* ctx, const string& property);

  vector<of<Processor>> processors_;
  vector<of<Segmentor>> segmentors_;
  vector<of<Translator>> translators_;
  vector<of<Filter>> filters_;
  vector<of<Formatter>> formatters_;
  vector<of<Processor>> post_processors_;
};

// implementations

Engine* Engine::Create() {
  return new ConcreteEngine;
}

Engine::Engine() : schema_(new Schema), context_(new Context) {
}

Engine::~Engine() {
  context_.reset();
  schema_.reset();
}

ConcreteEngine::ConcreteEngine() {
  LOG(INFO) << "starting engine.";
  // receive context notifications
  context_->commit_notifier().connect(
      [this](Context* ctx) { OnCommit(ctx); });
  context_->select_notifier().connect(
      [this](Context* ctx) { OnSelect(ctx); });
  context_->update_notifier().connect(
      [this](Context* ctx) { OnContextUpdate(ctx); });
  context_->option_update_notifier().connect(
      [this](Context* ctx, const string& option) {
        OnOptionUpdate(ctx, option);
      });
  context_->property_update_notifier().connect(
      [this](Context* ctx, const string& property) {
        OnPropertyUpdate(ctx, property);
      });
  InitializeComponents();
  InitializeOptions();
}

ConcreteEngine::~ConcreteEngine() {
  LOG(INFO) << "engine disposed.";
  processors_.clear();
  segmentors_.clear();
  translators_.clear();
}

bool ConcreteEngine::ProcessKey(const KeyEvent& key_event) {
  DLOG(INFO) << "process key: " << key_event;
  ProcessResult ret = kNoop;
  for (auto& processor : processors_) {
    ret = processor->ProcessKeyEvent(key_event);
    if (ret == kRejected) break;
    if (ret == kAccepted) return true;
  }
  // record unhandled keys, eg. spaces, numbers, bksp's.
  context_->commit_history().Push(key_event);
  // post-processing
  for (auto& processor : post_processors_) {
    ret = processor->ProcessKeyEvent(key_event);
    if (ret == kRejected) break;
    if (ret == kAccepted) return true;
  }
  // notify interested parties
  context_->unhandled_key_notifier()(context_.get(), key_event);
  return false;
}

void ConcreteEngine::OnContextUpdate(Context* ctx) {
  if (!ctx) return;
  Compose(ctx);
}

void ConcreteEngine::OnOptionUpdate(Context* ctx, const string& option) {
  if (!ctx) return;
  LOG(INFO) << "updated option: " << option;
  // apply new option to active segment
  if (ctx->IsComposing()) {
    ctx->RefreshNonConfirmedComposition();
  }
  // notification
  bool option_is_on = ctx->get_option(option);
  string msg(option_is_on ? option : "!" + option);
  message_sink_("option", msg);
}

void ConcreteEngine::OnPropertyUpdate(Context* ctx, const string& property) {
  if (!ctx) return;
  LOG(INFO) << "updated property: " << property;
  // notification
  string value = ctx->get_property(property);
  string msg(property + "=" + value);
  message_sink_("property", msg);
}

void ConcreteEngine::Compose(Context* ctx) {
  if (!ctx) return;
  Composition& comp = ctx->composition();
  const string active_input = ctx->input().substr(0, ctx->caret_pos());
  DLOG(INFO) << "active input: " << active_input;
  comp.Reset(active_input);
  if (ctx->caret_pos() < ctx->input().length() &&
      ctx->caret_pos() == comp.GetConfirmedPosition()) {
    // translate one segment past caret pos.
    comp.Reset(ctx->input());
  }
  CalculateSegmentation(&comp);
  TranslateSegments(&comp);
  DLOG(INFO) << "composition: " << comp.GetDebugText();
}

void ConcreteEngine::CalculateSegmentation(Segmentation* segments) {
  while (!segments->HasFinishedSegmentation()) {
    size_t start_pos = segments->GetCurrentStartPosition();
    size_t end_pos = segments->GetCurrentEndPosition();
    DLOG(INFO) << "start pos: " << start_pos;
    DLOG(INFO) << "end pos: " << end_pos;
    // recognize a segment by calling the segmentors in turn
    for (auto& segmentor : segmentors_) {
      if (!segmentor->Proceed(segments))
        break;
    }
    DLOG(INFO) << "segmentation: " << *segments;
    // no advancement
    if (start_pos == segments->GetCurrentEndPosition())
      break;
    // only one segment is allowed past caret pos, which is the segment
    // immediately after the caret.
    if (start_pos >= context_->caret_pos())
      break;
    // move onto the next segment...
    if (!segments->HasFinishedSegmentation())
      segments->Forward();
  }
  // start an empty segment only at the end of a confirmed composition.
  segments->Trim();
  if (!segments->empty() && segments->back().status >= Segment::kSelected)
    segments->Forward();
}

void ConcreteEngine::TranslateSegments(Segmentation* segments) {
  for (Segment& segment : *segments) {
    if (segment.status >= Segment::kGuess)
      continue;
    size_t len = segment.end - segment.start;
    if (len == 0)
      continue;
    string input = segments->input().substr(segment.start, len);
    DLOG(INFO) << "translating segment: " << input;
    auto menu = New<Menu>();
    for (auto& translator : translators_) {
      auto translation = translator->Query(input, segment);
      if (!translation)
        continue;
      if (translation->exhausted()) {
        LOG(INFO) << "Oops, got a futile translation.";
        continue;
      }
      menu->AddTranslation(translation);
    }
    for (auto& filter : filters_) {
      if (filter->AppliesToSegment(&segment)) {
        menu->AddFilter(filter.get());
      }
    }
    segment.status = Segment::kGuess;
    segment.menu = menu;
    segment.selected_index = 0;
  }
}

void ConcreteEngine::FormatText(string* text) {
  if (formatters_.empty())
    return;
  DLOG(INFO) << "applying formatters.";
  for (auto& formatter : formatters_) {
    formatter->Format(text);
  }
}

void ConcreteEngine::CommitText(string text) {
  context_->commit_history().Push(CommitRecord{"raw", text});
  FormatText(&text);
  DLOG(INFO) << "committing text: " << text;
  sink_(text);
}

void ConcreteEngine::OnCommit(Context* ctx) {
  context_->commit_history().Push(ctx->composition(), ctx->input());
  string text = ctx->GetCommitText();
  FormatText(&text);
  DLOG(INFO) << "committing composition: " << text;
  sink_(text);
}

void ConcreteEngine::OnSelect(Context* ctx) {
  Segment& seg(ctx->composition().back());
  seg.Close();
  if (seg.end == ctx->input().length()) {
    // composition has finished
    seg.status = Segment::kConfirmed;
    // strategy one: commit directly;
    // strategy two: continue composing with another empty segment.
    if (ctx->get_option("_auto_commit"))
      ctx->Commit();
    else
      ctx->composition().Forward();
  }
  else {
    bool reached_caret_pos = (seg.end >= ctx->caret_pos());
    ctx->composition().Forward();
    if (reached_caret_pos) {
      // finished converting current segment
      // move caret to the end of input
      ctx->set_caret_pos(ctx->input().length());
    }
    else {
      Compose(ctx);
    }
  }
}

void ConcreteEngine::ApplySchema(Schema* schema) {
  if (!schema)
    return;
  schema_.reset(schema);
  context_->Clear();
  context_->ClearTransientOptions();
  InitializeComponents();
  InitializeOptions();
  message_sink_("schema", schema->schema_id() + "/" + schema->schema_name());
}

void ConcreteEngine::InitializeComponents() {
  processors_.clear();
  segmentors_.clear();
  translators_.clear();
  filters_.clear();

  if (auto switcher = New<Switcher>(this)) {
    processors_.push_back(switcher);
    if (schema_->schema_id() == ".default") {
      if (Schema* schema = switcher->CreateSchema()) {
        schema_.reset(schema);
      }
    }
  }

  Config* config = schema_->config();
  if (!config)
    return;
  // create processors
  if (auto processor_list = config->GetList("engine/processors")) {
    size_t n = processor_list->size();
    for (size_t i = 0; i < n; ++i) {
      auto prescription = As<ConfigValue>(processor_list->GetAt(i));
      if (!prescription)
        continue;
      Ticket ticket{this, "processor", prescription->str()};
      if (auto c = Processor::Require(ticket.klass)) {
        an<Processor> p(c->Create(ticket));
        processors_.push_back(p);
      }
      else {
        LOG(ERROR) << "error creating processor: '" << ticket.klass << "'";
      }
    }
  }
  // create segmentors
  if (auto segmentor_list = config->GetList("engine/segmentors")) {
    size_t n = segmentor_list->size();
    for (size_t i = 0; i < n; ++i) {
      auto prescription = As<ConfigValue>(segmentor_list->GetAt(i));
      if (!prescription)
        continue;
      Ticket ticket{this, "segmentor", prescription->str()};
      if (auto c = Segmentor::Require(ticket.klass)) {
        an<Segmentor> s(c->Create(ticket));
        segmentors_.push_back(s);
      }
      else {
        LOG(ERROR) << "error creating segmentor: '" << ticket.klass << "'";
      }
    }
  }
  // create translators
  if (auto translator_list = config->GetList("engine/translators")) {
    size_t n = translator_list->size();
    for (size_t i = 0; i < n; ++i) {
      auto prescription = As<ConfigValue>(translator_list->GetAt(i));
      if (!prescription)
        continue;
      Ticket ticket{this, "translator", prescription->str()};
      if (auto c = Translator::Require(ticket.klass)) {
        an<Translator> t(c->Create(ticket));
        translators_.push_back(t);
      }
      else {
        LOG(ERROR) << "error creating translator: '" << ticket.klass << "'";
      }
    }
  }
  // create filters
  if (auto filter_list = config->GetList("engine/filters")) {
    size_t n = filter_list->size();
    for (size_t i = 0; i < n; ++i) {
      auto prescription = As<ConfigValue>(filter_list->GetAt(i));
      if (!prescription)
        continue;
      Ticket ticket{this, "filter", prescription->str()};
      if (auto c = Filter::Require(ticket.klass)) {
        an<Filter> f(c->Create(ticket));
        filters_.push_back(f);
      }
      else {
        LOG(ERROR) << "error creating filter: '" << ticket.klass << "'";
      }
    }
  }
  // create formatters
  if (auto c = Formatter::Require("shape_formatter")) {
    an<Formatter> f(c->Create(Ticket(this)));
    formatters_.push_back(f);
  }
  else {
    LOG(WARNING) << "shape_formatter not available.";
  }
  // create post-processors
  if (auto c = Processor::Require("shape_processor")) {
    an<Processor> p(c->Create(Ticket(this)));
    post_processors_.push_back(p);
  }
  else {
    LOG(WARNING) << "shape_processor not available.";
  }
}

void ConcreteEngine::InitializeOptions() {
  // reset custom switches
  Config* config = schema_->config();
  if (auto switches = config->GetList("switches")) {
    for (size_t i = 0; i < switches->size(); ++i) {
      auto item = As<ConfigMap>(switches->GetAt(i));
      if (!item)
        continue;
      auto reset_value = item->GetValue("reset");
      if (!reset_value)
        continue;
      int value = 0;
      reset_value->GetInt(&value);
      if (auto option_name = item->GetValue("name")) {
        // toggle
        context_->set_option(option_name->str(), (value != 0));
      }
      else if (auto options = As<ConfigList>(item->Get("options"))) {
        // radio
        for (size_t i = 0; i < options->size(); ++i) {
          if (auto option_name = options->GetValueAt(i)) {
            context_->set_option(option_name->str(),
                                 static_cast<int>(i) == value);
          }
        }
      }
    }
  }
}

}  // namespace rime
<|endoftext|>


<commit_before>/// HEADER
#include <csapex_ml/features_message.h>

/// PROJECT
#include <csapex/utility/assert.h>
#include <csapex/utility/register_msg.h>

CSAPEX_REGISTER_MESSAGE(csapex::connection_types::FeaturesMessage)

using namespace csapex;
using namespace connection_types;

FeaturesMessage::FeaturesMessage(Message::Stamp stamp)
    : Message("FeaturesMessage", "/", stamp), classification(0)
{}

ConnectionType::Ptr FeaturesMessage::clone() const
{
    Ptr new_msg(new FeaturesMessage);
    new_msg->value = value;
    new_msg->classification = classification;
    return new_msg;
}

ConnectionType::Ptr FeaturesMessage::toType() const
{
    Ptr new_msg(new FeaturesMessage);
    return new_msg;
}

/// YAML
namespace YAML {
Node convert<csapex::connection_types::FeaturesMessage>::encode(const csapex::connection_types::FeaturesMessage& rhs)
{
    Node node = convert<csapex::connection_types::Message>::encode(rhs);
    node["features"] = rhs.value;
    node["classification"] = rhs.classification;
    node["confidence"] = rhs.confidence;
    return node;
}

bool convert<csapex::connection_types::FeaturesMessage>::decode(const Node& node, csapex::connection_types::FeaturesMessage& rhs)
{
    if(!node.IsMap()) {
        return false;
    }
    convert<csapex::connection_types::Message>::decode(node, rhs);
    rhs.value = node["features"].as<std::vector<float> >();
    rhs.classification = node["classification"].as<int>();
    if(node["confidence"].IsDefined())
        rhs.confidence = node["confidence"].as<float>();
    else
        rhs.confidence = 1.f;

    return true;
}
}
<commit_msg>feature msg: copy confidence<commit_after>/// HEADER
#include <csapex_ml/features_message.h>

/// PROJECT
#include <csapex/utility/assert.h>
#include <csapex/utility/register_msg.h>

CSAPEX_REGISTER_MESSAGE(csapex::connection_types::FeaturesMessage)

using namespace csapex;
using namespace connection_types;

FeaturesMessage::FeaturesMessage(Message::Stamp stamp)
    : Message("FeaturesMessage", "/", stamp), classification(0)
{}

ConnectionType::Ptr FeaturesMessage::clone() const
{
    Ptr new_msg(new FeaturesMessage);
    new_msg->value = value;
    new_msg->classification = classification;
    new_msg->confidence = confidence;
    return new_msg;
}

ConnectionType::Ptr FeaturesMessage::toType() const
{
    Ptr new_msg(new FeaturesMessage);
    return new_msg;
}

/// YAML
namespace YAML {
Node convert<csapex::connection_types::FeaturesMessage>::encode(const csapex::connection_types::FeaturesMessage& rhs)
{
    Node node = convert<csapex::connection_types::Message>::encode(rhs);
    node["features"] = rhs.value;
    node["classification"] = rhs.classification;
    node["confidence"] = rhs.confidence;
    return node;
}

bool convert<csapex::connection_types::FeaturesMessage>::decode(const Node& node, csapex::connection_types::FeaturesMessage& rhs)
{
    if(!node.IsMap()) {
        return false;
    }
    convert<csapex::connection_types::Message>::decode(node, rhs);
    rhs.value = node["features"].as<std::vector<float> >();
    rhs.classification = node["classification"].as<int>();
    if(node["confidence"].IsDefined())
        rhs.confidence = node["confidence"].as<float>();
    else
        rhs.confidence = 1.f;

    return true;
}
}
<|endoftext|>


<commit_before>/*
Highly Optimized Object-oriented Many-particle Dynamics -- Blue Edition
(HOOMD-blue) Open Source Software License Copyright 2008-2011 Ames Laboratory
Iowa State University and The Regents of the University of Michigan All rights
reserved.

HOOMD-blue may contain modifications ("Contributions") provided, and to which
copyright is held, by various Contributors who have granted The Regents of the
University of Michigan the right to modify and/or distribute such Contributions.

You may redistribute, use, and create derivate works of HOOMD-blue, in source
and binary forms, provided you abide by the following conditions:

* Redistributions of source code must retain the above copyright notice, this
list of conditions, and the following disclaimer both in the code and
prominently in any materials provided with the distribution.

* 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.

* All publications and presentations based on HOOMD-blue, including any reports
or published results obtained, in whole or in part, with HOOMD-blue, will
acknowledge its use according to the terms posted at the time of submission on:
http://codeblue.umich.edu/hoomd-blue/citations.html

* Any electronic documents citing HOOMD-Blue will link to the HOOMD-Blue website:
http://codeblue.umich.edu/hoomd-blue/

* Apart from the above required attributions, neither the name of the copyright
holder nor the names of HOOMD-blue's contributors may be used to endorse or
promote products derived from this software without specific prior written
permission.

Disclaimer

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND/OR ANY
WARRANTIES THAT THIS SOFTWARE IS FREE OF INFRINGEMENT ARE DISCLAIMED.

IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
*/

// Maintainer: joaander

/*! \file MSDAnalyzer.cc
    \brief Defines the MSDAnalyzer class
*/

#ifdef WIN32
#pragma warning( push )
#pragma warning( disable : 4244 )
#endif

#include "MSDAnalyzer.h"
#include "HOOMDInitializer.h"

#ifdef ENABLE_MPI
#include "Communicator.h"
#endif

#include <boost/python.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>
using namespace boost::python;
using namespace boost::filesystem;

#include <iomanip>
using namespace std;

/*! \param sysdef SystemDefinition containing the Particle data to analyze
    \param fname File name to write output to
    \param header_prefix String to print before the file header
    \param overwrite Will overwite an exiting file if true (default is to append)

    On construction, the initial coordinates of all parrticles in the system are recoreded. The file is opened
    (and overwritten if told to). Nothing is initially written to the file, that will occur on the first call to
    analyze()
*/
MSDAnalyzer::MSDAnalyzer(boost::shared_ptr<SystemDefinition> sysdef,
                         std::string fname,
                         const std::string& header_prefix,
                         bool overwrite)
    : Analyzer(sysdef), m_delimiter("\t"), m_header_prefix(header_prefix), m_appending(false),
      m_columns_changed(false)
    {
    m_exec_conf->msg->notice(5) << "Constructing MSDAnalyzer: " << fname << " " << header_prefix << " " << overwrite << endl;

    SnapshotParticleData snapshot(m_pdata->getNGlobal());

    m_pdata->takeSnapshot(snapshot);

#ifdef ENABLE_MPI
    // if we are not the root processor, do not perform file I/O
    if (m_comm && !m_exec_conf->isRoot())
        {
        return;
        }
#endif

    // open the file
    if (exists(fname) && !overwrite)
        {
        m_exec_conf->msg->notice(3) << "analyze.msd: Appending msd to existing file \"" << fname << "\"" << endl;
        m_file.open(fname.c_str(), ios_base::in | ios_base::out | ios_base::ate);
        m_appending = true;
        }
    else
        {
        m_exec_conf->msg->notice(3) << "analyze.msd: Creating new msd in file \"" << fname << "\"" << endl;
        m_file.open(fname.c_str(), ios_base::out);
        }

    if (!m_file.good())
        {
        m_exec_conf->msg->error() << "analyze.msd: Unable to open file " << fname << endl;
        throw runtime_error("Error initializing analyze.msd");
        }

    // record the initial particle positions by tag
    m_initial_x.resize(m_pdata->getNGlobal());
    m_initial_y.resize(m_pdata->getNGlobal());
    m_initial_z.resize(m_pdata->getNGlobal());

    BoxDim box = m_pdata->getGlobalBox();

    // for each particle in the data
    for (unsigned int tag = 0; tag < snapshot.size; tag++)
        {
        // save its initial position
        Scalar3 pos = snapshot.pos[tag];
        Scalar3 unwrapped = box.shift(pos, snapshot.image[tag]);
        m_initial_x[tag] = unwrapped.x;
        m_initial_y[tag] = unwrapped.y;
        m_initial_z[tag] = unwrapped.z;
        }
    }

MSDAnalyzer::~MSDAnalyzer()
    {
    m_exec_conf->msg->notice(5) << "Destroying MSDAnalyzer" << endl;
    }

/*!\param timestep Current time step of the simulation

    analyze() will first write out the file header if the columns have changed.

    On every call, analyze() will write calculate the MSD for each group and write out a row in the file.
*/
void MSDAnalyzer::analyze(unsigned int timestep)
    {
    if (m_prof)
        m_prof->push("Analyze MSD");

    // take particle data snapshot
    SnapshotParticleData snapshot(m_pdata->getNGlobal());

    m_pdata->takeSnapshot(snapshot);

#ifdef ENABLE_MPI
    // if we are not the root processor, do not perform file I/O
    if (m_comm && !m_exec_conf->isRoot())
        {
        if (m_prof) m_prof->pop();
        return;
        }
#endif

    // error check
    if (m_columns.size() == 0)
        {
        m_exec_conf->msg->warning() << "analyze.msd: No columns specified in the MSD analysis" << endl;
        return;
        }

    // ignore writing the header on the first call when appending the file
    if (m_columns_changed && m_appending)
        {
        m_appending = false;
        m_columns_changed = false;
        }

    // write out the header only once if the columns change
    if (m_columns_changed)
        {
        writeHeader();
        m_columns_changed = false;
        }

    // write out the row every time
    writeRow(timestep, snapshot);

    if (m_prof)
        m_prof->pop();
    }

/*! \param delimiter New delimiter to set

    The delimiter is printed between every element in the row of the output
*/
void MSDAnalyzer::setDelimiter(const std::string& delimiter)
    {
    m_delimiter = delimiter;
    }

/*! \param group Particle group to calculate the MSD of
    \param name Name to print in the header of the file

    After a column is added with addColumn(), future calls to analyze() will calculate the MSD of the particles defined
    in \a group and print out an entry under the \a name header in the file.
*/
void MSDAnalyzer::addColumn(boost::shared_ptr<ParticleGroup> group, const std::string& name)
    {
    m_columns.push_back(column(group, name));
    m_columns_changed = true;
    }

/*! \param xml_fname Name of the XML file to read in to the r0 positions

    \post \a xml_fname is read and all initial r0 positions are assigned from that file.
*/
void MSDAnalyzer::setR0(const std::string& xml_fname)
    {
    // read in the xml file
    HOOMDInitializer xml(m_exec_conf,xml_fname);

    // take particle data snapshot
    SnapshotParticleData snapshot(m_pdata->getNGlobal());

    m_pdata->takeSnapshot(snapshot);

#ifdef ENABLE_MPI
    // if we are not the root processor, do not perform file I/O
    if (m_comm && !m_exec_conf->isRoot())
        {
        return;
        }
#endif

    // verify that the input matches the current system size
    unsigned int nparticles = m_pdata->getNGlobal();
    if (nparticles != xml.getPos().size())
        {
        m_exec_conf->msg->error() << "analyze.msd: Found " << xml.getPos().size() << " particles in "
             << xml_fname << ", but there are " << nparticles << " in the current simulation." << endl;
        throw runtime_error("Error setting r0 in analyze.msd");
        }

    // determine if we have image data
    bool have_image = (xml.getImage().size() == nparticles);
    if (!have_image)
        {
        m_exec_conf->msg->warning() << "analyze.msd: Image data missing or corrupt in " << xml_fname
             << ". Computed msd values will not be correct." << endl;
        }

    // reset the initial positions
    BoxDim box = m_pdata->getGlobalBox();

    // for each particle in the data
    for (unsigned int tag = 0; tag < nparticles; tag++)
        {
        // save its initial position
        HOOMDInitializer::vec pos = xml.getPos()[tag];
        m_initial_x[tag] = pos.x;
        m_initial_y[tag] = pos.y;
        m_initial_z[tag] = pos.z;

        // adjust the positions by the image flags if we have them
        if (have_image)
            {
            HOOMDInitializer::vec_int image = xml.getImage()[tag];
            Scalar3 pos = make_scalar3(m_initial_x[tag], m_initial_y[tag], m_initial_z[tag]);
            int3 image_i = make_int3(image.x, image.y, image.z);
            Scalar3 unwrapped = box.shift(pos, image_i);
            m_initial_x[tag] += unwrapped.x;
            m_initial_y[tag] += unwrapped.y;
            m_initial_z[tag] += unwrapped.z;
            }
        }
    }

/*! The entire header row is written to the file. First, timestep is written as every file includes it and then the
    columns are looped through and their names printed, separated by the delimiter.
*/
void MSDAnalyzer::writeHeader()
    {
    // write out the header prefix
    m_file << m_header_prefix;

    // timestep is always output
    m_file << "timestep";

    if (m_columns.size() == 0)
        {
        m_exec_conf->msg->warning() << "analyze.msd: No columns specified in the MSD analysis" << endl;
        return;
        }

    // only print the delimiter after the timestep if there are more columns
    m_file << m_delimiter;

    // write all but the last of the quantities separated by the delimiter
    for (unsigned int i = 0; i < m_columns.size()-1; i++)
        m_file << m_columns[i].m_name << m_delimiter;
    // write the last one with no delimiter after it
    m_file << m_columns[m_columns.size()-1].m_name << endl;
    m_file.flush();
    }

/*! \param group Particle group to calculate the MSD of
    Loop through all particles in the given group and calculate the MSD over them.
    \returns The calculated MSD
*/
Scalar MSDAnalyzer::calcMSD(boost::shared_ptr<ParticleGroup const> group, const SnapshotParticleData& snapshot)
    {
    BoxDim box = m_pdata->getGlobalBox();
    Scalar3 l_origin = m_pdata->getOrigin();
    int3 image = m_pdata->getOriginImage();
    Scalar3 origin = box.shift(l_origin, image);

    // initial sum for the average
    Scalar msd = Scalar(0.0);

    // handle the case where there are 0 members gracefully
    if (group->getNumMembers() == 0)
        {
        m_exec_conf->msg->warning() << "analyze.msd: Group has 0 members, reporting a calculated msd of 0.0" << endl;
        return Scalar(0.0);
        }

    // for each particle in the group
    for (unsigned int group_idx = 0; group_idx < group->getNumMembers(); group_idx++)
        {
        // get the tag for the current group member from the group
        unsigned int tag = group->getMemberTag(group_idx);
        Scalar3 pos = snapshot.pos[tag] + l_origin;
        int3 image = snapshot.image[tag];
        Scalar3 unwrapped = box.shift(pos, image);
        pos -= origin;
        Scalar dx = unwrapped.x - m_initial_x[tag];
        Scalar dy = unwrapped.y - m_initial_y[tag];
        Scalar dz = unwrapped.z - m_initial_z[tag];

        msd += dx*dx + dy*dy + dz*dz;
        }

    // divide to complete the average
    msd /= Scalar(group->getNumMembers());
    return msd;
    }

/*! \param timestep current time step of the simulation

    Performs all the steps needed in order to calculate the MSDs for all the groups in the columns and writes out an
    entire row to the file.
*/
void MSDAnalyzer::writeRow(unsigned int timestep, const SnapshotParticleData& snapshot)
    {
    if (m_prof) m_prof->push("MSD");

//     // take particle data snapshot
//     SnapshotParticleData snapshot(m_pdata->getNGlobal());

//     m_pdata->takeSnapshot(snapshot);

//     // This will need to be changed based on calling function
// #ifdef ENABLE_MPI
//     // if we are not the root processor, do not perform file I/O
//     if (m_comm && !m_exec_conf->isRoot())
//         {
//         if (m_prof) m_prof->pop();
//         return;
//         }
// #endif

    // The timestep is always output
    m_file << setprecision(10) << timestep;

    // quit now if there is nothing to log
    if (m_columns.size() == 0)
        {
        return;
        }

    // only print the delimiter after the timestep if there are more columns
    m_file << m_delimiter;

    // write all but the last of the columns separated by the delimiter
    for (unsigned int i = 0; i < m_columns.size()-1; i++)
        m_file << setprecision(10) << calcMSD(m_columns[i].m_group, snapshot) << m_delimiter;
    // write the last one with no delimiter after it
    m_file << setprecision(10) << calcMSD(m_columns[m_columns.size()-1].m_group, snapshot) << endl;
    m_file.flush();

    if (!m_file.good())
        {
        m_exec_conf->msg->error() << "analyze.msd: I/O error while writing file" << endl;
        throw runtime_error("Error writting msd file");
        }

    if (m_prof) m_prof->pop();
    }

void export_MSDAnalyzer()
    {
    class_<MSDAnalyzer, boost::shared_ptr<MSDAnalyzer>, bases<Analyzer>, boost::noncopyable>
    ("MSDAnalyzer", init< boost::shared_ptr<SystemDefinition>, const std::string&, const std::string&, bool >())
    .def("setDelimiter", &MSDAnalyzer::setDelimiter)
    .def("addColumn", &MSDAnalyzer::addColumn)
    .def("setR0", &MSDAnalyzer::setR0)
    ;
    }

#ifdef WIN32
#pragma warning( pop )
#endif

<commit_msg>-= is not allowed.<commit_after>/*
Highly Optimized Object-oriented Many-particle Dynamics -- Blue Edition
(HOOMD-blue) Open Source Software License Copyright 2008-2011 Ames Laboratory
Iowa State University and The Regents of the University of Michigan All rights
reserved.

HOOMD-blue may contain modifications ("Contributions") provided, and to which
copyright is held, by various Contributors who have granted The Regents of the
University of Michigan the right to modify and/or distribute such Contributions.

You may redistribute, use, and create derivate works of HOOMD-blue, in source
and binary forms, provided you abide by the following conditions:

* Redistributions of source code must retain the above copyright notice, this
list of conditions, and the following disclaimer both in the code and
prominently in any materials provided with the distribution.

* 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.

* All publications and presentations based on HOOMD-blue, including any reports
or published results obtained, in whole or in part, with HOOMD-blue, will
acknowledge its use according to the terms posted at the time of submission on:
http://codeblue.umich.edu/hoomd-blue/citations.html

* Any electronic documents citing HOOMD-Blue will link to the HOOMD-Blue website:
http://codeblue.umich.edu/hoomd-blue/

* Apart from the above required attributions, neither the name of the copyright
holder nor the names of HOOMD-blue's contributors may be used to endorse or
promote products derived from this software without specific prior written
permission.

Disclaimer

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND/OR ANY
WARRANTIES THAT THIS SOFTWARE IS FREE OF INFRINGEMENT ARE DISCLAIMED.

IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
*/

// Maintainer: joaander

/*! \file MSDAnalyzer.cc
    \brief Defines the MSDAnalyzer class
*/

#ifdef WIN32
#pragma warning( push )
#pragma warning( disable : 4244 )
#endif

#include "MSDAnalyzer.h"
#include "HOOMDInitializer.h"

#ifdef ENABLE_MPI
#include "Communicator.h"
#endif

#include <boost/python.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>
using namespace boost::python;
using namespace boost::filesystem;

#include <iomanip>
using namespace std;

/*! \param sysdef SystemDefinition containing the Particle data to analyze
    \param fname File name to write output to
    \param header_prefix String to print before the file header
    \param overwrite Will overwite an exiting file if true (default is to append)

    On construction, the initial coordinates of all parrticles in the system are recoreded. The file is opened
    (and overwritten if told to). Nothing is initially written to the file, that will occur on the first call to
    analyze()
*/
MSDAnalyzer::MSDAnalyzer(boost::shared_ptr<SystemDefinition> sysdef,
                         std::string fname,
                         const std::string& header_prefix,
                         bool overwrite)
    : Analyzer(sysdef), m_delimiter("\t"), m_header_prefix(header_prefix), m_appending(false),
      m_columns_changed(false)
    {
    m_exec_conf->msg->notice(5) << "Constructing MSDAnalyzer: " << fname << " " << header_prefix << " " << overwrite << endl;

    SnapshotParticleData snapshot(m_pdata->getNGlobal());

    m_pdata->takeSnapshot(snapshot);

#ifdef ENABLE_MPI
    // if we are not the root processor, do not perform file I/O
    if (m_comm && !m_exec_conf->isRoot())
        {
        return;
        }
#endif

    // open the file
    if (exists(fname) && !overwrite)
        {
        m_exec_conf->msg->notice(3) << "analyze.msd: Appending msd to existing file \"" << fname << "\"" << endl;
        m_file.open(fname.c_str(), ios_base::in | ios_base::out | ios_base::ate);
        m_appending = true;
        }
    else
        {
        m_exec_conf->msg->notice(3) << "analyze.msd: Creating new msd in file \"" << fname << "\"" << endl;
        m_file.open(fname.c_str(), ios_base::out);
        }

    if (!m_file.good())
        {
        m_exec_conf->msg->error() << "analyze.msd: Unable to open file " << fname << endl;
        throw runtime_error("Error initializing analyze.msd");
        }

    // record the initial particle positions by tag
    m_initial_x.resize(m_pdata->getNGlobal());
    m_initial_y.resize(m_pdata->getNGlobal());
    m_initial_z.resize(m_pdata->getNGlobal());

    BoxDim box = m_pdata->getGlobalBox();

    // for each particle in the data
    for (unsigned int tag = 0; tag < snapshot.size; tag++)
        {
        // save its initial position
        Scalar3 pos = snapshot.pos[tag];
        Scalar3 unwrapped = box.shift(pos, snapshot.image[tag]);
        m_initial_x[tag] = unwrapped.x;
        m_initial_y[tag] = unwrapped.y;
        m_initial_z[tag] = unwrapped.z;
        }
    }

MSDAnalyzer::~MSDAnalyzer()
    {
    m_exec_conf->msg->notice(5) << "Destroying MSDAnalyzer" << endl;
    }

/*!\param timestep Current time step of the simulation

    analyze() will first write out the file header if the columns have changed.

    On every call, analyze() will write calculate the MSD for each group and write out a row in the file.
*/
void MSDAnalyzer::analyze(unsigned int timestep)
    {
    if (m_prof)
        m_prof->push("Analyze MSD");

    // take particle data snapshot
    SnapshotParticleData snapshot(m_pdata->getNGlobal());

    m_pdata->takeSnapshot(snapshot);

#ifdef ENABLE_MPI
    // if we are not the root processor, do not perform file I/O
    if (m_comm && !m_exec_conf->isRoot())
        {
        if (m_prof) m_prof->pop();
        return;
        }
#endif

    // error check
    if (m_columns.size() == 0)
        {
        m_exec_conf->msg->warning() << "analyze.msd: No columns specified in the MSD analysis" << endl;
        return;
        }

    // ignore writing the header on the first call when appending the file
    if (m_columns_changed && m_appending)
        {
        m_appending = false;
        m_columns_changed = false;
        }

    // write out the header only once if the columns change
    if (m_columns_changed)
        {
        writeHeader();
        m_columns_changed = false;
        }

    // write out the row every time
    writeRow(timestep, snapshot);

    if (m_prof)
        m_prof->pop();
    }

/*! \param delimiter New delimiter to set

    The delimiter is printed between every element in the row of the output
*/
void MSDAnalyzer::setDelimiter(const std::string& delimiter)
    {
    m_delimiter = delimiter;
    }

/*! \param group Particle group to calculate the MSD of
    \param name Name to print in the header of the file

    After a column is added with addColumn(), future calls to analyze() will calculate the MSD of the particles defined
    in \a group and print out an entry under the \a name header in the file.
*/
void MSDAnalyzer::addColumn(boost::shared_ptr<ParticleGroup> group, const std::string& name)
    {
    m_columns.push_back(column(group, name));
    m_columns_changed = true;
    }

/*! \param xml_fname Name of the XML file to read in to the r0 positions

    \post \a xml_fname is read and all initial r0 positions are assigned from that file.
*/
void MSDAnalyzer::setR0(const std::string& xml_fname)
    {
    // read in the xml file
    HOOMDInitializer xml(m_exec_conf,xml_fname);

    // take particle data snapshot
    SnapshotParticleData snapshot(m_pdata->getNGlobal());

    m_pdata->takeSnapshot(snapshot);

#ifdef ENABLE_MPI
    // if we are not the root processor, do not perform file I/O
    if (m_comm && !m_exec_conf->isRoot())
        {
        return;
        }
#endif

    // verify that the input matches the current system size
    unsigned int nparticles = m_pdata->getNGlobal();
    if (nparticles != xml.getPos().size())
        {
        m_exec_conf->msg->error() << "analyze.msd: Found " << xml.getPos().size() << " particles in "
             << xml_fname << ", but there are " << nparticles << " in the current simulation." << endl;
        throw runtime_error("Error setting r0 in analyze.msd");
        }

    // determine if we have image data
    bool have_image = (xml.getImage().size() == nparticles);
    if (!have_image)
        {
        m_exec_conf->msg->warning() << "analyze.msd: Image data missing or corrupt in " << xml_fname
             << ". Computed msd values will not be correct." << endl;
        }

    // reset the initial positions
    BoxDim box = m_pdata->getGlobalBox();

    // for each particle in the data
    for (unsigned int tag = 0; tag < nparticles; tag++)
        {
        // save its initial position
        HOOMDInitializer::vec pos = xml.getPos()[tag];
        m_initial_x[tag] = pos.x;
        m_initial_y[tag] = pos.y;
        m_initial_z[tag] = pos.z;

        // adjust the positions by the image flags if we have them
        if (have_image)
            {
            HOOMDInitializer::vec_int image = xml.getImage()[tag];
            Scalar3 pos = make_scalar3(m_initial_x[tag], m_initial_y[tag], m_initial_z[tag]);
            int3 image_i = make_int3(image.x, image.y, image.z);
            Scalar3 unwrapped = box.shift(pos, image_i);
            m_initial_x[tag] += unwrapped.x;
            m_initial_y[tag] += unwrapped.y;
            m_initial_z[tag] += unwrapped.z;
            }
        }
    }

/*! The entire header row is written to the file. First, timestep is written as every file includes it and then the
    columns are looped through and their names printed, separated by the delimiter.
*/
void MSDAnalyzer::writeHeader()
    {
    // write out the header prefix
    m_file << m_header_prefix;

    // timestep is always output
    m_file << "timestep";

    if (m_columns.size() == 0)
        {
        m_exec_conf->msg->warning() << "analyze.msd: No columns specified in the MSD analysis" << endl;
        return;
        }

    // only print the delimiter after the timestep if there are more columns
    m_file << m_delimiter;

    // write all but the last of the quantities separated by the delimiter
    for (unsigned int i = 0; i < m_columns.size()-1; i++)
        m_file << m_columns[i].m_name << m_delimiter;
    // write the last one with no delimiter after it
    m_file << m_columns[m_columns.size()-1].m_name << endl;
    m_file.flush();
    }

/*! \param group Particle group to calculate the MSD of
    Loop through all particles in the given group and calculate the MSD over them.
    \returns The calculated MSD
*/
Scalar MSDAnalyzer::calcMSD(boost::shared_ptr<ParticleGroup const> group, const SnapshotParticleData& snapshot)
    {
    BoxDim box = m_pdata->getGlobalBox();
    Scalar3 l_origin = m_pdata->getOrigin();
    int3 image = m_pdata->getOriginImage();
    Scalar3 origin = box.shift(l_origin, image);

    // initial sum for the average
    Scalar msd = Scalar(0.0);

    // handle the case where there are 0 members gracefully
    if (group->getNumMembers() == 0)
        {
        m_exec_conf->msg->warning() << "analyze.msd: Group has 0 members, reporting a calculated msd of 0.0" << endl;
        return Scalar(0.0);
        }

    // for each particle in the group
    for (unsigned int group_idx = 0; group_idx < group->getNumMembers(); group_idx++)
        {
        // get the tag for the current group member from the group
        unsigned int tag = group->getMemberTag(group_idx);
        Scalar3 pos = snapshot.pos[tag] + l_origin;
        int3 image = snapshot.image[tag];
        Scalar3 unwrapped = box.shift(pos, image);
        pos = pos - origin;
        Scalar dx = unwrapped.x - m_initial_x[tag];
        Scalar dy = unwrapped.y - m_initial_y[tag];
        Scalar dz = unwrapped.z - m_initial_z[tag];

        msd += dx*dx + dy*dy + dz*dz;
        }

    // divide to complete the average
    msd /= Scalar(group->getNumMembers());
    return msd;
    }

/*! \param timestep current time step of the simulation

    Performs all the steps needed in order to calculate the MSDs for all the groups in the columns and writes out an
    entire row to the file.
*/
void MSDAnalyzer::writeRow(unsigned int timestep, const SnapshotParticleData& snapshot)
    {
    if (m_prof) m_prof->push("MSD");

//     // take particle data snapshot
//     SnapshotParticleData snapshot(m_pdata->getNGlobal());

//     m_pdata->takeSnapshot(snapshot);

//     // This will need to be changed based on calling function
// #ifdef ENABLE_MPI
//     // if we are not the root processor, do not perform file I/O
//     if (m_comm && !m_exec_conf->isRoot())
//         {
//         if (m_prof) m_prof->pop();
//         return;
//         }
// #endif

    // The timestep is always output
    m_file << setprecision(10) << timestep;

    // quit now if there is nothing to log
    if (m_columns.size() == 0)
        {
        return;
        }

    // only print the delimiter after the timestep if there are more columns
    m_file << m_delimiter;

    // write all but the last of the columns separated by the delimiter
    for (unsigned int i = 0; i < m_columns.size()-1; i++)
        m_file << setprecision(10) << calcMSD(m_columns[i].m_group, snapshot) << m_delimiter;
    // write the last one with no delimiter after it
    m_file << setprecision(10) << calcMSD(m_columns[m_columns.size()-1].m_group, snapshot) << endl;
    m_file.flush();

    if (!m_file.good())
        {
        m_exec_conf->msg->error() << "analyze.msd: I/O error while writing file" << endl;
        throw runtime_error("Error writting msd file");
        }

    if (m_prof) m_prof->pop();
    }

void export_MSDAnalyzer()
    {
    class_<MSDAnalyzer, boost::shared_ptr<MSDAnalyzer>, bases<Analyzer>, boost::noncopyable>
    ("MSDAnalyzer", init< boost::shared_ptr<SystemDefinition>, const std::string&, const std::string&, bool >())
    .def("setDelimiter", &MSDAnalyzer::setDelimiter)
    .def("addColumn", &MSDAnalyzer::addColumn)
    .def("setR0", &MSDAnalyzer::setR0)
    ;
    }

#ifdef WIN32
#pragma warning( pop )
#endif

<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you 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 .
 */

#include <sal/config.h>

#include <boost/noncopyable.hpp>
#include <sdr/contact/viewcontactofunocontrol.hxx>
#include <sdr/contact/viewobjectcontactofunocontrol.hxx>
#include <sdr/contact/objectcontactofpageview.hxx>
#include <svx/sdr/contact/displayinfo.hxx>
#include <svx/svdouno.hxx>
#include <svx/svdpagv.hxx>
#include <svx/svdview.hxx>
#include <svx/sdrpagewindow.hxx>

#include <com/sun/star/awt/XWindow2.hpp>

#include "svx/sdrpaintwindow.hxx"
#include <tools/diagnose_ex.h>
#include <vcl/pdfextoutdevdata.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <drawinglayer/primitive2d/controlprimitive2d.hxx>
#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>

namespace sdr { namespace contact {

    using ::com::sun::star::awt::XControl;
    using ::com::sun::star::uno::Reference;
    using ::com::sun::star::awt::XControlContainer;
    using ::com::sun::star::awt::XControlModel;
    using ::com::sun::star::awt::XWindow2;
    using ::com::sun::star::uno::UNO_QUERY;
    using ::com::sun::star::uno::Exception;

    //= ViewContactOfUnoControl

    class ViewContactOfUnoControl_Impl: private boost::noncopyable
    {
    public:
        ViewContactOfUnoControl_Impl();
        ~ViewContactOfUnoControl_Impl();
    };

    ViewContactOfUnoControl_Impl::ViewContactOfUnoControl_Impl()
    {
    }

    ViewContactOfUnoControl_Impl::~ViewContactOfUnoControl_Impl()
    {
    }

    //= ViewContactOfUnoControl

    ViewContactOfUnoControl::ViewContactOfUnoControl( SdrUnoObj& _rUnoObject )
        :ViewContactOfSdrObj( _rUnoObject )
        ,m_pImpl( new ViewContactOfUnoControl_Impl )
    {
    }

    ViewContactOfUnoControl::~ViewContactOfUnoControl()
    {
    }

    Reference< XControl > ViewContactOfUnoControl::getTemporaryControlForWindow(
        const Window& _rWindow, Reference< XControlContainer >& _inout_ControlContainer ) const
    {
        SdrUnoObj* pUnoObject = dynamic_cast< SdrUnoObj* >( TryToGetSdrObject() );
        OSL_ENSURE( pUnoObject, "ViewContactOfUnoControl::getTemporaryControlForDevice: no SdrUnoObj!" );
        if ( !pUnoObject )
            return NULL;
        return ViewObjectContactOfUnoControl::getTemporaryControlForWindow( _rWindow, _inout_ControlContainer, *pUnoObject );
    }

    ViewObjectContact& ViewContactOfUnoControl::CreateObjectSpecificViewObjectContact( ObjectContact& _rObjectContact )
    {
        // print or print preview requires special handling
        const OutputDevice* pDevice = _rObjectContact.TryToGetOutputDevice();
        bool bPrintOrPreview = ( pDevice != NULL ) && ( pDevice->GetOutDevType() == OUTDEV_PRINTER );

        ObjectContactOfPageView* pPageViewContact = dynamic_cast< ObjectContactOfPageView* >( &_rObjectContact  );
        bPrintOrPreview |= ( pPageViewContact != NULL ) && pPageViewContact->GetPageWindow().GetPageView().GetView().IsPrintPreview();

        if ( bPrintOrPreview )
            return *new UnoControlPrintOrPreviewContact( *pPageViewContact, *this );

        // all others are nowadays served by the same implementation
        return *new ViewObjectContactOfUnoControl( _rObjectContact, *this );
    }

    drawinglayer::primitive2d::Primitive2DSequence ViewContactOfUnoControl::createViewIndependentPrimitive2DSequence() const
    {
        // create range. Use model data directly, not getBoundRect()/getSnapRect; these will use
        // the primitive data themselves in the long run. Use SdrUnoObj's (which is a SdrRectObj)
        // call to GetGeoRect() to access SdrTextObj::aRect directly and without executing anything
        Rectangle aRectangle(GetSdrUnoObj().GetGeoRect());
        // Hack for calc, transform position of object according
        // to current zoom so as objects relative position to grid
        // appears stable
        Point aGridOffset = GetSdrUnoObj().GetGridOffset();
        aRectangle += aGridOffset;
        const basegfx::B2DRange aRange(
            aRectangle.Left(), aRectangle.Top(),
            aRectangle.Right(), aRectangle.Bottom());

        // create object transform
        basegfx::B2DHomMatrix aTransform;

        aTransform.set(0, 0, aRange.getWidth());
        aTransform.set(1, 1, aRange.getHeight());
        aTransform.set(0, 2, aRange.getMinX());
        aTransform.set(1, 2, aRange.getMinY());

        Reference< XControlModel > xControlModel = GetSdrUnoObj().GetUnoControlModel();

        if(xControlModel.is())
        {
            // create control primitive WITHOUT possibly existing XControl; this would be done in
            // the VOC in createPrimitive2DSequence()
            const drawinglayer::primitive2d::Primitive2DReference xRetval(
                new drawinglayer::primitive2d::ControlPrimitive2D(
                    aTransform,
                    xControlModel));

            return drawinglayer::primitive2d::Primitive2DSequence(&xRetval, 1);
        }
        else
        {
            // always append an invisible outline for the cases where no visible content exists
            const drawinglayer::primitive2d::Primitive2DReference xRetval(
                drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
                    false, aTransform));

            return drawinglayer::primitive2d::Primitive2DSequence(&xRetval, 1);
        }
    }

} } // namespace sdr::contact

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>fdo#79883 the page view object contact must exist<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you 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 .
 */

#include <sal/config.h>

#include <boost/noncopyable.hpp>
#include <sdr/contact/viewcontactofunocontrol.hxx>
#include <sdr/contact/viewobjectcontactofunocontrol.hxx>
#include <sdr/contact/objectcontactofpageview.hxx>
#include <svx/sdr/contact/displayinfo.hxx>
#include <svx/svdouno.hxx>
#include <svx/svdpagv.hxx>
#include <svx/svdview.hxx>
#include <svx/sdrpagewindow.hxx>

#include <com/sun/star/awt/XWindow2.hpp>

#include "svx/sdrpaintwindow.hxx"
#include <tools/diagnose_ex.h>
#include <vcl/pdfextoutdevdata.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <drawinglayer/primitive2d/controlprimitive2d.hxx>
#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>

namespace sdr { namespace contact {

    using ::com::sun::star::awt::XControl;
    using ::com::sun::star::uno::Reference;
    using ::com::sun::star::awt::XControlContainer;
    using ::com::sun::star::awt::XControlModel;
    using ::com::sun::star::awt::XWindow2;
    using ::com::sun::star::uno::UNO_QUERY;
    using ::com::sun::star::uno::Exception;

    //= ViewContactOfUnoControl

    class ViewContactOfUnoControl_Impl: private boost::noncopyable
    {
    public:
        ViewContactOfUnoControl_Impl();
        ~ViewContactOfUnoControl_Impl();
    };

    ViewContactOfUnoControl_Impl::ViewContactOfUnoControl_Impl()
    {
    }

    ViewContactOfUnoControl_Impl::~ViewContactOfUnoControl_Impl()
    {
    }

    //= ViewContactOfUnoControl

    ViewContactOfUnoControl::ViewContactOfUnoControl( SdrUnoObj& _rUnoObject )
        :ViewContactOfSdrObj( _rUnoObject )
        ,m_pImpl( new ViewContactOfUnoControl_Impl )
    {
    }

    ViewContactOfUnoControl::~ViewContactOfUnoControl()
    {
    }

    Reference< XControl > ViewContactOfUnoControl::getTemporaryControlForWindow(
        const Window& _rWindow, Reference< XControlContainer >& _inout_ControlContainer ) const
    {
        SdrUnoObj* pUnoObject = dynamic_cast< SdrUnoObj* >( TryToGetSdrObject() );
        OSL_ENSURE( pUnoObject, "ViewContactOfUnoControl::getTemporaryControlForDevice: no SdrUnoObj!" );
        if ( !pUnoObject )
            return NULL;
        return ViewObjectContactOfUnoControl::getTemporaryControlForWindow( _rWindow, _inout_ControlContainer, *pUnoObject );
    }

    ViewObjectContact& ViewContactOfUnoControl::CreateObjectSpecificViewObjectContact( ObjectContact& _rObjectContact )
    {
        // print or print preview requires special handling
        const OutputDevice* pDevice = _rObjectContact.TryToGetOutputDevice();
        ObjectContactOfPageView* const pPageViewContact = dynamic_cast< ObjectContactOfPageView* >( &_rObjectContact  );

        const bool bPrintOrPreview = pPageViewContact
            && ( ( ( pDevice != NULL ) && ( pDevice->GetOutDevType() == OUTDEV_PRINTER ) )
                    || pPageViewContact->GetPageWindow().GetPageView().GetView().IsPrintPreview()
               )
            ;

        if ( bPrintOrPreview )
            return *new UnoControlPrintOrPreviewContact( *pPageViewContact, *this );

        // all others are nowadays served by the same implementation
        return *new ViewObjectContactOfUnoControl( _rObjectContact, *this );
    }

    drawinglayer::primitive2d::Primitive2DSequence ViewContactOfUnoControl::createViewIndependentPrimitive2DSequence() const
    {
        // create range. Use model data directly, not getBoundRect()/getSnapRect; these will use
        // the primitive data themselves in the long run. Use SdrUnoObj's (which is a SdrRectObj)
        // call to GetGeoRect() to access SdrTextObj::aRect directly and without executing anything
        Rectangle aRectangle(GetSdrUnoObj().GetGeoRect());
        // Hack for calc, transform position of object according
        // to current zoom so as objects relative position to grid
        // appears stable
        Point aGridOffset = GetSdrUnoObj().GetGridOffset();
        aRectangle += aGridOffset;
        const basegfx::B2DRange aRange(
            aRectangle.Left(), aRectangle.Top(),
            aRectangle.Right(), aRectangle.Bottom());

        // create object transform
        basegfx::B2DHomMatrix aTransform;

        aTransform.set(0, 0, aRange.getWidth());
        aTransform.set(1, 1, aRange.getHeight());
        aTransform.set(0, 2, aRange.getMinX());
        aTransform.set(1, 2, aRange.getMinY());

        Reference< XControlModel > xControlModel = GetSdrUnoObj().GetUnoControlModel();

        if(xControlModel.is())
        {
            // create control primitive WITHOUT possibly existing XControl; this would be done in
            // the VOC in createPrimitive2DSequence()
            const drawinglayer::primitive2d::Primitive2DReference xRetval(
                new drawinglayer::primitive2d::ControlPrimitive2D(
                    aTransform,
                    xControlModel));

            return drawinglayer::primitive2d::Primitive2DSequence(&xRetval, 1);
        }
        else
        {
            // always append an invisible outline for the cases where no visible content exists
            const drawinglayer::primitive2d::Primitive2DReference xRetval(
                drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
                    false, aTransform));

            return drawinglayer::primitive2d::Primitive2DSequence(&xRetval, 1);
        }
    }

} } // namespace sdr::contact

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>#include "kincidenceformatter.h"
#include <kstaticdeleter.h>
#include <kglobal.h>
#include <klocale.h>
#include <kiconloader.h>
#ifndef KORG_NOKABC
#include <kabc/stdaddressbook.h>
#define size count
#endif

KIncidenceFormatter* KIncidenceFormatter::mInstance = 0;
static KStaticDeleter<KIncidenceFormatter> insd;

QString KIncidenceFormatter::getFormattedText( Incidence * inc )
{

    mText = "";
    if ( inc->type() == "Event" )
        setEvent((Event *) inc );
    else if ( inc->type() == "Todo" )
        setTodo((Todo *) inc );
    else if ( inc->type() == "Journal" )
        mText = inc->description();
    return mText;
}

KIncidenceFormatter* KIncidenceFormatter::instance()
{
    if (!mInstance) {
    insd.setObject( mInstance, new KIncidenceFormatter());
  }
  return mInstance;
}
KIncidenceFormatter::~KIncidenceFormatter()
{

}
KIncidenceFormatter::KIncidenceFormatter()
{
    mColorMode = 0;
}
void KIncidenceFormatter::setEvent(Event *event)
{
    int mode = 0;
    mCurrentIncidence = event;
    bool shortDate = true;
    if ( mode == 0 ) {
        addTag("h3",event->summary());
    }
    else {
        if ( mColorMode == 1 ) {
            mText +="";
        }
        if ( mColorMode == 2 ) {
            mText +="";
        }
        // mText +="" + i18n("O-due!") + "";
        if ( mode == 1 ) {
            addTag("h2",i18n( "Local: " ) +event->summary());
        } else {
            addTag("h2",i18n( "Remote: " ) +event->summary());
        }
        addTag("h3",i18n( "Last modified: " ) + KGlobal::locale()->formatDateTime(event->lastModified(),shortDate, true ) );
        if ( mColorMode )
            mText += "";
    }
#if 0
    if (event->cancelled ()) {
        mText +="";
        addTag("i",i18n("This event has been cancelled!"));
        mText.append("
");
        mText += "";
    }
#endif
    if (!event->location().isEmpty()) {
        addTag("b",i18n("Location: "));
        mText.append(event->location()+"
");
    }
    if (event->doesFloat()) {
        if (event->isMultiDay()) {
            mText.append(i18n("
From: %1

To: %2
")
                         .arg(event->dtStartDateStr(shortDate))
                         .arg(event->dtEndDateStr(shortDate)));
        } else {
            mText.append(i18n("
On: %1
").arg(event->dtStartDateStr( shortDate )));
        }
    } else {
        if (event->isMultiDay()) {
            mText.append(i18n("
From: %1
 ")
                         .arg(event->dtStartStr()));
            mText.append(i18n("
To: %1
")
                         .arg(event->dtEndStr()));
        } else {
            mText.append(i18n("
On: %1
 ")
                         .arg(event->dtStartDateStr( shortDate )));
            mText.append(i18n("
From: %1 To: %2
")
                         .arg(event->dtStartTimeStr())
                         .arg(event->dtEndTimeStr()));
        }
    }

    if (event->recurrence()->doesRecur()) {

        QString recurText = i18n("No");
        short recurs = event->recurrence()->doesRecur();
        if ( recurs == Recurrence::rMinutely  )
            recurText = i18n("minutely");
        else if ( recurs == Recurrence::rHourly  )
            recurText = i18n("hourly");
        else if ( recurs == Recurrence::rDaily  )
            recurText = i18n("daily");
        else if ( recurs ==  Recurrence::rWeekly )
            recurText = i18n("weekly");
        else if ( recurs == Recurrence::rMonthlyPos  )
            recurText = i18n("monthly");
        else if ( recurs ==  Recurrence::rMonthlyDay )
            recurText = i18n("day-monthly");
        else if ( recurs ==  Recurrence::rYearlyMonth )
            recurText = i18n("month-yearly");
        else if ( recurs ==  Recurrence::rYearlyDay )
            recurText = i18n("day-yearly");
        else if ( recurs ==  Recurrence::rYearlyPos )
            recurText = i18n("position-yearly");
        addTag("p","" + i18n("This is a %1 recurring event.").arg(recurText ) + "");
        bool last;
        QDate start = QDate::currentDate();
        QDate next;
        next = event->recurrence()->getPreviousDate( start , &last );
        if ( !last ) {
            next = event->recurrence()->getNextDate( start.addDays( - 1 ) );
            addTag("p",i18n("Next recurrence is on: ")+ KGlobal::locale()->formatDate( next, shortDate ) );
            //addTag("p", KGlobal::locale()->formatDate( next, shortDate ));
        } else {
            addTag("p",i18n("Last recurrence was on:")  );
            addTag("p", KGlobal::locale()->formatDate( next, shortDate ));
        }
    }

    if (event->isAlarmEnabled()) {
        Alarm *alarm =event->alarms().first() ;
        QDateTime t = alarm->time();
        int min = t.secsTo( event->dtStart() )/60;
        QString s =i18n("(%1 min before)").arg( min );
        addTag("p",i18n("Alarm on:  ")  + s  + ": "+KGlobal::locale()->formatDateTime( t, shortDate ));
        //addTag("p", KGlobal::locale()->formatDateTime( t, shortDate ));
        //addTag("p",s);
    }

    addTag("p",i18n("Access: ") +event->secrecyStr() );
    // mText.append(event->secrecyStr()+"
");
    formatCategories(event);
    if (!event->description().isEmpty()) {
        addTag("p",i18n("Details: "));
        addTag("p",event->description());
    }

    formatReadOnly(event);
    formatAttendees(event);

}

void KIncidenceFormatter::setTodo(Todo *event )
{
    int mode = 0;
    mCurrentIncidence = event;
    bool shortDate = true;
    if (mode == 0 )
        addTag("h3",event->summary());
    else {
        if ( mColorMode == 1 ) {
            mText +="";
        }
        if ( mColorMode == 2 ) {
            mText +="";
        }
        if ( mode == 1 ) {
            addTag("h2",i18n( "Local: " ) +event->summary());
        } else {
            addTag("h2",i18n( "Remote: " ) +event->summary());
        }
        addTag("h3",i18n( "Last modified: " ) + KGlobal::locale()->formatDateTime(event->lastModified(),shortDate, true ) );
        if ( mColorMode )
            mText += "";
    }
#if 0
    if (event->cancelled ()) {
        mText +="";
        addTag("i",i18n("This todo has been cancelled!"));
        mText.append("
");
        mText += "";
    }
#endif
    if (!event->location().isEmpty()) {
        addTag("b",i18n("Location: "));
        mText.append(event->location()+"
");
    }
    if (event->hasDueDate()) {
        mText.append(i18n("
Due on: %1
").arg(event->dtDueStr()));
    }
    mText.append(i18n("
Priority: %2
")
                 .arg(QString::number(event->priority())));

    mText.append(i18n("
%1 % completed
")
                 .arg(event->percentComplete()));
     addTag("p",i18n("Access: ") +event->secrecyStr() );
    formatCategories(event);
    if (!event->description().isEmpty()) {
        addTag("p",i18n("Details: "));
        addTag("p",event->description());
    }

    formatReadOnly(event);
    formatAttendees(event);

}

void KIncidenceFormatter::setJournal(Journal*  )
{

}

void KIncidenceFormatter::formatCategories(Incidence *event)
{
 if (!event->categoriesStr().isEmpty()) {
     addTag("p",i18n("Categories: ")+event->categoriesStr() );
     //mText.append(event->categoriesStr());
 }
}
void KIncidenceFormatter::addTag(const QString & tag,const QString & text)
{
  int number=text.contains("\n");
    QString str = "<" + tag + ">";
    QString tmpText=text;
    QString tmpStr=str;
    if(number !=-1)
        {
            if (number > 0) {
                int pos=0;
                QString tmp;
                for(int i=0;i<=number;i++) {
                    pos=tmpText.find("\n");
                    tmp=tmpText.left(pos);
                    tmpText=tmpText.right(tmpText.length()-pos-1);
                    tmpStr+=tmp+"
";
                }
            }
            else tmpStr += tmpText;
            tmpStr+="</" + tag + ">";
            mText.append(tmpStr);
        }
    else
        {
            str += text + "</" + tag + ">";
            mText.append(str);
        }
}

void KIncidenceFormatter::formatAttendees(Incidence *event)
{
 Attendee::List attendees = event->attendees();
  if ( attendees.count() ) {
    KIconLoader* iconLoader = new KIconLoader();
    QString iconPath = iconLoader->iconPath( "mail_generic", KIcon::Small );
    addTag( "h3", i18n("Organizer") );
    mText.append( "

" );
#ifndef KORG_NOKABC
    KABC::AddressBook *add_book = KABC::StdAddressBook::self();
    KABC::Addressee::List addressList;
    addressList = add_book->findByEmail( event->organizer() );
    KABC::Addressee o = addressList.first();
    if ( !o.isEmpty() && addressList.size() < 2 ) {
      addLink( "uid" + o.uid(), o.formattedName() );
    } else {
      mText.append( event->organizer() );
    }
#else
    mText.append( event->organizer() );
#endif
    if ( !iconPath.isNull() ) {
      addLink( "mailto:" + event->organizer(),
               "" );
    }
    mText.append( "

" );

    addTag( "h3", i18n("Attendees") );
    mText.append( "
" );
    Attendee::List::ConstIterator it;
    for( it = attendees.begin(); it != attendees.end(); ++it ) {
      Attendee *a = *it;
#ifndef KORG_NOKABC
      if ( a->name().isEmpty() ) {
        addressList = add_book->findByEmail( a->email() );
        KABC::Addressee o = addressList.first();
        if ( !o.isEmpty() && addressList.size() < 2 ) {
          addLink( "uid" + o.uid(), o.formattedName() );
        } else {
          mText += "
";
          mText.append( a->email() );
          mText += "\n";
        }
      } else {
        mText += "
uid() + "\">";
        if ( !a->name().isEmpty() ) mText += a->name();
        else mText += a->email();
        mText += "\n";
      }
#else
      mText += "
uid() + "\">";
      if ( !a->name().isEmpty() ) mText += a->name();
      else mText += a->email();
      mText += "\n";
#endif
      kdDebug(5850) << "formatAttendees: uid = " <uid() << endl;

      if ( !a->email().isEmpty() ) {
        if ( !iconPath.isNull() ) {
          mText += "name() +" "+ "<" + a->email() + ">" + "\">";
          mText += "";
          mText += "\n";
        }
      }
    }
    mText.append( "

" );
  }
}

void KIncidenceFormatter::formatReadOnly(Incidence *event)
{
 if (event->isReadOnly()) {
        addTag("p","(" + i18n("read-only") + ")");
    }
}
void KIncidenceFormatter::addLink( const QString &ref, const QString &text,
                             bool newline )
{
  mText += "" + text + "";
  if ( newline ) mText += "\n";
}
<commit_msg>Fixed compilation<commit_after>#include "kincidenceformatter.h"
#include <kstaticdeleter.h>
#include <kglobal.h>
#include <klocale.h>
#include <kiconloader.h>
#ifndef KORG_NOKABC
#include <kabc/stdaddressbook.h>
#define size count
#endif

KIncidenceFormatter* KIncidenceFormatter::mInstance = 0;
static KStaticDeleter<KIncidenceFormatter> insd;

QString KIncidenceFormatter::getFormattedText( Incidence * inc )
{

    mText = "";
    if ( inc->type() == "Event" )
        setEvent((Event *) inc );
    else if ( inc->type() == "Todo" )
        setTodo((Todo *) inc );
    else if ( inc->type() == "Journal" )
        mText = inc->description();
    return mText;
}

KIncidenceFormatter* KIncidenceFormatter::instance()
{
    if (!mInstance) {
    insd.setObject( mInstance, new KIncidenceFormatter());
  }
  return mInstance;
}
KIncidenceFormatter::~KIncidenceFormatter()
{

}
KIncidenceFormatter::KIncidenceFormatter()
{
    mColorMode = 0;
}
void KIncidenceFormatter::setEvent(Event *event)
{
    int mode = 0;
    mCurrentIncidence = event;
    bool shortDate = true;
    if ( mode == 0 ) {
        addTag("h3",event->summary());
    }
    else {
        if ( mColorMode == 1 ) {
            mText +="";
        }
        if ( mColorMode == 2 ) {
            mText +="";
        }
        // mText +="" + i18n("O-due!") + "";
        if ( mode == 1 ) {
            addTag("h2",i18n( "Local: " ) +event->summary());
        } else {
            addTag("h2",i18n( "Remote: " ) +event->summary());
        }
        addTag("h3",i18n( "Last modified: " ) + KGlobal::locale()->formatDateTime(event->lastModified(),shortDate, true ) );
        if ( mColorMode )
            mText += "";
    }
#if 0
    if (event->cancelled ()) {
        mText +="";
        addTag("i",i18n("This event has been cancelled!"));
        mText.append("
");
        mText += "";
    }
#endif
    if (!event->location().isEmpty()) {
        addTag("b",i18n("Location: "));
        mText.append(event->location()+"
");
    }
    if (event->doesFloat()) {
        if (event->isMultiDay()) {
            mText.append(i18n("
From: %1

To: %2
")
                         .arg(event->dtStartDateStr(shortDate))
                         .arg(event->dtEndDateStr(shortDate)));
        } else {
            mText.append(i18n("
On: %1
").arg(event->dtStartDateStr( shortDate )));
        }
    } else {
        if (event->isMultiDay()) {
            mText.append(i18n("
From: %1
 ")
                         .arg(event->dtStartStr()));
            mText.append(i18n("
To: %1
")
                         .arg(event->dtEndStr()));
        } else {
            mText.append(i18n("
On: %1
 ")
                         .arg(event->dtStartDateStr( shortDate )));
            mText.append(i18n("
From: %1 To: %2
")
                         .arg(event->dtStartTimeStr())
                         .arg(event->dtEndTimeStr()));
        }
    }

    if (event->recurrence()->doesRecur()) {

        QString recurText = i18n("No");
        short recurs = event->recurrence()->doesRecur();
        if ( recurs == Recurrence::rMinutely  )
            recurText = i18n("minutely");
        else if ( recurs == Recurrence::rHourly  )
            recurText = i18n("hourly");
        else if ( recurs == Recurrence::rDaily  )
            recurText = i18n("daily");
        else if ( recurs ==  Recurrence::rWeekly )
            recurText = i18n("weekly");
        else if ( recurs == Recurrence::rMonthlyPos  )
            recurText = i18n("monthly");
        else if ( recurs ==  Recurrence::rMonthlyDay )
            recurText = i18n("day-monthly");
        else if ( recurs ==  Recurrence::rYearlyMonth )
            recurText = i18n("month-yearly");
        else if ( recurs ==  Recurrence::rYearlyDay )
            recurText = i18n("day-yearly");
        else if ( recurs ==  Recurrence::rYearlyPos )
            recurText = i18n("position-yearly");
        addTag("p","" + i18n("This is a %1 recurring event.").arg(recurText ) + "");
        bool last;
        QDate start = QDate::currentDate();
        QDate next;
        next = event->recurrence()->getPreviousDate( start , &last );
        if ( !last ) {
            next = event->recurrence()->getNextDate( start.addDays( - 1 ) );
            addTag("p",i18n("Next recurrence is on: ")+ KGlobal::locale()->formatDate( next, shortDate ) );
            //addTag("p", KGlobal::locale()->formatDate( next, shortDate ));
        } else {
            addTag("p",i18n("Last recurrence was on:")  );
            addTag("p", KGlobal::locale()->formatDate( next, shortDate ));
        }
    }

    if (event->isAlarmEnabled()) {
        Alarm *alarm =event->alarms().first() ;
        QDateTime t = alarm->time();
        int min = t.secsTo( event->dtStart() )/60;
        QString s =i18n("(%1 min before)").arg( min );
        addTag("p",i18n("Alarm on:  ")  + s  + ": "+KGlobal::locale()->formatDateTime( t, shortDate ));
        //addTag("p", KGlobal::locale()->formatDateTime( t, shortDate ));
        //addTag("p",s);
    }

    addTag("p",i18n("Access: ") +event->secrecyStr() );
    // mText.append(event->secrecyStr()+"
");
    formatCategories(event);
    if (!event->description().isEmpty()) {
        addTag("p",i18n("Details: "));
        addTag("p",event->description());
    }

    formatReadOnly(event);
    formatAttendees(event);

}

void KIncidenceFormatter::setTodo(Todo *event )
{
    int mode = 0;
    mCurrentIncidence = event;
    bool shortDate = true;
    if (mode == 0 )
        addTag("h3",event->summary());
    else {
        if ( mColorMode == 1 ) {
            mText +="";
        }
        if ( mColorMode == 2 ) {
            mText +="";
        }
        if ( mode == 1 ) {
            addTag("h2",i18n( "Local: " ) +event->summary());
        } else {
            addTag("h2",i18n( "Remote: " ) +event->summary());
        }
        addTag("h3",i18n( "Last modified: " ) + KGlobal::locale()->formatDateTime(event->lastModified(),shortDate, true ) );
        if ( mColorMode )
            mText += "";
    }
#if 0
    if (event->cancelled ()) {
        mText +="";
        addTag("i",i18n("This todo has been cancelled!"));
        mText.append("
");
        mText += "";
    }
#endif
    if (!event->location().isEmpty()) {
        addTag("b",i18n("Location: "));
        mText.append(event->location()+"
");
    }
    if (event->hasDueDate()) {
        mText.append(i18n("
Due on: %1
").arg(event->dtDueStr()));
    }
    mText.append(i18n("
Priority: %2
")
                 .arg(QString::number(event->priority())));

    mText.append(i18n("
%1 % completed
")
                 .arg(event->percentComplete()));
     addTag("p",i18n("Access: ") +event->secrecyStr() );
    formatCategories(event);
    if (!event->description().isEmpty()) {
        addTag("p",i18n("Details: "));
        addTag("p",event->description());
    }

    formatReadOnly(event);
    formatAttendees(event);

}

void KIncidenceFormatter::setJournal(Journal*  )
{

}

void KIncidenceFormatter::formatCategories(Incidence *event)
{
 if (!event->categoriesStr().isEmpty()) {
     addTag("p",i18n("Categories: ")+event->categoriesStr() );
     //mText.append(event->categoriesStr());
 }
}
void KIncidenceFormatter::addTag(const QString & tag,const QString & text)
{
  int number=text.contains("\n");
    QString str = "<" + tag + ">";
    QString tmpText=text;
    QString tmpStr=str;
    if(number !=-1)
        {
            if (number > 0) {
                int pos=0;
                QString tmp;
                for(int i=0;i<=number;i++) {
                    pos=tmpText.find("\n");
                    tmp=tmpText.left(pos);
                    tmpText=tmpText.right(tmpText.length()-pos-1);
                    tmpStr+=tmp+"
";
                }
            }
            else tmpStr += tmpText;
            tmpStr+="</" + tag + ">";
            mText.append(tmpStr);
        }
    else
        {
            str += text + "</" + tag + ">";
            mText.append(str);
        }
}

void KIncidenceFormatter::formatAttendees(Incidence *event)
{
 Attendee::List attendees = event->attendees();
  if ( attendees.count() ) {
    KIconLoader* iconLoader = new KIconLoader();
    QString iconPath = iconLoader->iconPath( "mail_generic", KIcon::Small );
    addTag( "h3", i18n("Organizer") );
    mText.append( "

" );
#ifndef KORG_NOKABC
    KABC::AddressBook *add_book = KABC::StdAddressBook::self();
    KABC::Addressee::List addressList;
    addressList = add_book->findByEmail( event->organizer().email() );
    KABC::Addressee o = addressList.first();
    if ( !o.isEmpty() && addressList.size() < 2 ) {
      addLink( "uid" + o.uid(), o.formattedName() );
    } else {
      mText.append( event->organizer().fullName() );
    }
#else
    mText.append( event->organizer().fullName() );
#endif
    if ( !iconPath.isNull() ) {
      addLink( "mailto:" + event->organizer().email(), // fullName would look nicer, but needs escaping
               "" );
    }
    mText.append( "

" );

    addTag( "h3", i18n("Attendees") );
    mText.append( "
" );
    Attendee::List::ConstIterator it;
    for( it = attendees.begin(); it != attendees.end(); ++it ) {
      Attendee *a = *it;
#ifndef KORG_NOKABC
      if ( a->name().isEmpty() ) {
        addressList = add_book->findByEmail( a->email() );
        KABC::Addressee o = addressList.first();
        if ( !o.isEmpty() && addressList.size() < 2 ) {
          addLink( "uid" + o.uid(), o.formattedName() );
        } else {
          mText += "
";
          mText.append( a->email() );
          mText += "\n";
        }
      } else {
        mText += "
uid() + "\">";
        if ( !a->name().isEmpty() ) mText += a->name();
        else mText += a->email();
        mText += "\n";
      }
#else
      mText += "
uid() + "\">";
      if ( !a->name().isEmpty() ) mText += a->name();
      else mText += a->email();
      mText += "\n";
#endif
      kdDebug(5850) << "formatAttendees: uid = " <uid() << endl;

      if ( !a->email().isEmpty() ) {
        if ( !iconPath.isNull() ) {
          mText += "name() +" "+ "<" + a->email() + ">" + "\">";
          mText += "";
          mText += "\n";
        }
      }
    }
    mText.append( "

" );
  }
}

void KIncidenceFormatter::formatReadOnly(Incidence *event)
{
 if (event->isReadOnly()) {
        addTag("p","(" + i18n("read-only") + ")");
    }
}
void KIncidenceFormatter::addLink( const QString &ref, const QString &text,
                             bool newline )
{
  mText += "" + text + "";
  if ( newline ) mText += "\n";
}
<|endoftext|>