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

#include "ui/app_list/views/speech_view.h"

#include "base/strings/utf_string_conversions.h"
#include "third_party/skia/include/core/SkPath.h"
#include "ui/app_list/app_list_constants.h"
#include "ui/app_list/app_list_model.h"
#include "ui/app_list/app_list_view_delegate.h"
#include "ui/app_list/speech_ui_model.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/path.h"
#include "ui/gfx/shadow_value.h"
#include "ui/resources/grit/ui_resources.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/animation/bounds_animator.h"
#include "ui/views/background.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/masked_targeter_delegate.h"
#include "ui/views/shadow_border.h"

namespace app_list {

namespace {

const int kSpeechViewMaxHeight = 300;
const int kMicButtonMargin = 12;
const int kTextMargin = 32;
const int kLogoMarginLeft = 30;
const int kLogoMarginTop = 28;
const int kLogoWidth = 104;
const int kLogoHeight = 36;
const int kIndicatorCenterOffsetY = -1;
const int kIndicatorRadiusMinOffset = -3;
const int kIndicatorRadiusMax = 100;
const int kIndicatorAnimationDuration = 100;
const SkColor kHintTextColor = SkColorSetRGB(119, 119, 119);
const SkColor kResultTextColor = SkColorSetRGB(178, 178, 178);
const SkColor kSoundLevelIndicatorColor = SkColorSetRGB(219, 219, 219);

class SoundLevelIndicator : public views::View {
 public:
  SoundLevelIndicator();
  ~SoundLevelIndicator() override;

 private:
  // Overridden from views::View:
  void OnPaint(gfx::Canvas* canvas) override;

  DISALLOW_COPY_AND_ASSIGN(SoundLevelIndicator);
};

SoundLevelIndicator::SoundLevelIndicator() {}

SoundLevelIndicator::~SoundLevelIndicator() {}

void SoundLevelIndicator::OnPaint(gfx::Canvas* canvas) {
  SkPaint paint;
  paint.setStyle(SkPaint::kFill_Style);
  paint.setColor(kSoundLevelIndicatorColor);
  paint.setAntiAlias(true);
  canvas->DrawCircle(bounds().CenterPoint(), width() / 2, paint);
}

// MicButton is an image button with a circular hit test mask.
class MicButton : public views::ImageButton,
                  public views::MaskedTargeterDelegate {
 public:
  explicit MicButton(views::ButtonListener* listener);
  ~MicButton() override;

 private:
  // views::MaskedTargeterDelegate:
  bool GetHitTestMask(gfx::Path* mask) const override;

  DISALLOW_COPY_AND_ASSIGN(MicButton);
};

MicButton::MicButton(views::ButtonListener* listener)
    : views::ImageButton(listener) {}

MicButton::~MicButton() {}

bool MicButton::GetHitTestMask(gfx::Path* mask) const {
  DCHECK(mask);

  // The mic button icon is a circle.
  gfx::Rect local_bounds = GetLocalBounds();
  int radius = local_bounds.width() / 2 + kIndicatorRadiusMinOffset;
  gfx::Point center = local_bounds.CenterPoint();
  center.set_y(center.y() + kIndicatorCenterOffsetY);
  mask->addCircle(SkIntToScalar(center.x()),
                  SkIntToScalar(center.y()),
                  SkIntToScalar(radius));
  return true;
}

}  // namespace

// static

SpeechView::SpeechView(AppListViewDelegate* delegate)
    : delegate_(delegate),
      logo_(NULL) {
  SetBorder(scoped_ptr<views::Border>(
      new views::ShadowBorder(GetShadowForZHeight(1))));

  // To keep the painting order of the border and the background, this class
  // actually has a single child of 'container' which has white background and
  // contains all components.
  views::View* container = new views::View();
  container->set_background(
      views::Background::CreateSolidBackground(SK_ColorWHITE));

  const gfx::ImageSkia& logo_image = delegate_->GetSpeechUI()->logo();
  if (!logo_image.isNull()) {
    logo_ = new views::ImageView();
    logo_->SetImage(&logo_image);
    container->AddChildView(logo_);
  }

  indicator_ = new SoundLevelIndicator();
  indicator_->SetVisible(false);
  container->AddChildView(indicator_);

  MicButton* mic_button = new MicButton(this);
  mic_button_ = mic_button;
  container->AddChildView(mic_button_);
  mic_button_->SetEventTargeter(
      scoped_ptr<views::ViewTargeter>(new views::ViewTargeter(mic_button)));

  // TODO(mukai): use BoundedLabel to cap 2 lines.
  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
  speech_result_ = new views::Label(
      base::string16(), bundle.GetFontList(ui::ResourceBundle::LargeFont));
  speech_result_->SetHorizontalAlignment(gfx::ALIGN_LEFT);

  speech_result_->SetMultiLine(true);
  container->AddChildView(speech_result_);

  AddChildView(container);

  delegate_->GetSpeechUI()->AddObserver(this);
  indicator_animator_.reset(new views::BoundsAnimator(container));
  indicator_animator_->SetAnimationDuration(kIndicatorAnimationDuration);
  indicator_animator_->set_tween_type(gfx::Tween::LINEAR);

  Reset();
}

SpeechView::~SpeechView() {
  delegate_->GetSpeechUI()->RemoveObserver(this);
}

void SpeechView::Reset() {
  OnSpeechRecognitionStateChanged(delegate_->GetSpeechUI()->state());
}

int SpeechView::GetIndicatorRadius(uint8 level) {
  int radius_min = mic_button_->width() / 2 + kIndicatorRadiusMinOffset;
  int range = kIndicatorRadiusMax - radius_min;
  return level * range / kuint8max + radius_min;
}

void SpeechView::Layout() {
  views::View* container = child_at(0);
  container->SetBoundsRect(GetContentsBounds());

  // Because container is a pure View, this class should layout its children.
  const gfx::Rect contents_bounds = container->GetContentsBounds();
  if (logo_)
    logo_->SetBounds(kLogoMarginLeft, kLogoMarginTop, kLogoWidth, kLogoHeight);
  gfx::Size mic_size = mic_button_->GetPreferredSize();
  gfx::Point mic_origin(
      contents_bounds.right() - kMicButtonMargin - mic_size.width(),
      contents_bounds.y() + kMicButtonMargin);
  mic_button_->SetBoundsRect(gfx::Rect(mic_origin, mic_size));

  int speech_width = contents_bounds.width() - kTextMargin * 2;
  speech_result_->SizeToFit(speech_width);
  int speech_height = speech_result_->GetHeightForWidth(speech_width);
  speech_result_->SetBounds(
      contents_bounds.x() + kTextMargin,
      contents_bounds.bottom() - kTextMargin - speech_height,
      speech_width,
      speech_height);
}

gfx::Size SpeechView::GetPreferredSize() const {
  return gfx::Size(0, kSpeechViewMaxHeight);
}

void SpeechView::ButtonPressed(views::Button* sender, const ui::Event& event) {
  delegate_->ToggleSpeechRecognition();
}

void SpeechView::OnSpeechSoundLevelChanged(uint8 level) {
  if (!visible() ||
      delegate_->GetSpeechUI()->state() == SPEECH_RECOGNITION_NETWORK_ERROR)
    return;

  gfx::Point origin = mic_button_->bounds().CenterPoint();
  int radius = GetIndicatorRadius(level);
  origin.Offset(-radius, -radius + kIndicatorCenterOffsetY);
  gfx::Rect indicator_bounds =
      gfx::Rect(origin, gfx::Size(radius * 2, radius * 2));
  if (indicator_->visible()) {
    indicator_animator_->AnimateViewTo(indicator_, indicator_bounds);
  } else {
    indicator_->SetVisible(true);
    indicator_->SetBoundsRect(indicator_bounds);
  }
}

void SpeechView::OnSpeechResult(const base::string16& result,
                                bool is_final) {
  speech_result_->SetText(result);
  speech_result_->SetEnabledColor(kResultTextColor);
}

void SpeechView::OnSpeechRecognitionStateChanged(
    SpeechRecognitionState new_state) {
  int resource_id = IDR_APP_LIST_SPEECH_MIC_OFF;
  if (new_state == SPEECH_RECOGNITION_RECOGNIZING)
    resource_id = IDR_APP_LIST_SPEECH_MIC_ON;
  else if (new_state == SPEECH_RECOGNITION_IN_SPEECH)
    resource_id = IDR_APP_LIST_SPEECH_MIC_RECORDING;

  int text_resource_id = IDS_APP_LIST_SPEECH_HINT_TEXT;

  if (new_state == SPEECH_RECOGNITION_NETWORK_ERROR) {
    text_resource_id = IDS_APP_LIST_SPEECH_NETWORK_ERROR_HINT_TEXT;
    indicator_->SetVisible(false);
  }
  speech_result_->SetText(l10n_util::GetStringUTF16(text_resource_id));
  speech_result_->SetEnabledColor(kHintTextColor);

  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
  mic_button_->SetImage(views::Button::STATE_NORMAL,
                        bundle.GetImageSkiaNamed(resource_id));
}

}  // namespace app_list
<commit_msg>Add ellipsis to app list speech queries that overflow the search area.<commit_after>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/app_list/views/speech_view.h"

#include "base/strings/utf_string_conversions.h"
#include "third_party/skia/include/core/SkPath.h"
#include "ui/app_list/app_list_constants.h"
#include "ui/app_list/app_list_model.h"
#include "ui/app_list/app_list_view_delegate.h"
#include "ui/app_list/speech_ui_model.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/path.h"
#include "ui/gfx/shadow_value.h"
#include "ui/resources/grit/ui_resources.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/animation/bounds_animator.h"
#include "ui/views/background.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/masked_targeter_delegate.h"
#include "ui/views/shadow_border.h"

namespace app_list {

namespace {

const int kSpeechViewMaxHeight = 300;
const int kMicButtonMargin = 12;
const int kTextMargin = 32;
const int kLogoMarginLeft = 30;
const int kLogoMarginTop = 28;
const int kLogoWidth = 104;
const int kLogoHeight = 36;
const int kIndicatorCenterOffsetY = -1;
const int kIndicatorRadiusMinOffset = -3;
const int kIndicatorRadiusMax = 100;
const int kIndicatorAnimationDuration = 100;
const SkColor kHintTextColor = SkColorSetRGB(119, 119, 119);
const SkColor kResultTextColor = SkColorSetRGB(178, 178, 178);
const SkColor kSoundLevelIndicatorColor = SkColorSetRGB(219, 219, 219);

class SoundLevelIndicator : public views::View {
 public:
  SoundLevelIndicator();
  ~SoundLevelIndicator() override;

 private:
  // Overridden from views::View:
  void OnPaint(gfx::Canvas* canvas) override;

  DISALLOW_COPY_AND_ASSIGN(SoundLevelIndicator);
};

SoundLevelIndicator::SoundLevelIndicator() {}

SoundLevelIndicator::~SoundLevelIndicator() {}

void SoundLevelIndicator::OnPaint(gfx::Canvas* canvas) {
  SkPaint paint;
  paint.setStyle(SkPaint::kFill_Style);
  paint.setColor(kSoundLevelIndicatorColor);
  paint.setAntiAlias(true);
  canvas->DrawCircle(bounds().CenterPoint(), width() / 2, paint);
}

// MicButton is an image button with a circular hit test mask.
class MicButton : public views::ImageButton,
                  public views::MaskedTargeterDelegate {
 public:
  explicit MicButton(views::ButtonListener* listener);
  ~MicButton() override;

 private:
  // views::MaskedTargeterDelegate:
  bool GetHitTestMask(gfx::Path* mask) const override;

  DISALLOW_COPY_AND_ASSIGN(MicButton);
};

MicButton::MicButton(views::ButtonListener* listener)
    : views::ImageButton(listener) {}

MicButton::~MicButton() {}

bool MicButton::GetHitTestMask(gfx::Path* mask) const {
  DCHECK(mask);

  // The mic button icon is a circle.
  gfx::Rect local_bounds = GetLocalBounds();
  int radius = local_bounds.width() / 2 + kIndicatorRadiusMinOffset;
  gfx::Point center = local_bounds.CenterPoint();
  center.set_y(center.y() + kIndicatorCenterOffsetY);
  mask->addCircle(SkIntToScalar(center.x()),
                  SkIntToScalar(center.y()),
                  SkIntToScalar(radius));
  return true;
}

}  // namespace

// static

SpeechView::SpeechView(AppListViewDelegate* delegate)
    : delegate_(delegate),
      logo_(NULL) {
  SetBorder(scoped_ptr<views::Border>(
      new views::ShadowBorder(GetShadowForZHeight(1))));

  // To keep the painting order of the border and the background, this class
  // actually has a single child of 'container' which has white background and
  // contains all components.
  views::View* container = new views::View();
  container->set_background(
      views::Background::CreateSolidBackground(SK_ColorWHITE));

  const gfx::ImageSkia& logo_image = delegate_->GetSpeechUI()->logo();
  if (!logo_image.isNull()) {
    logo_ = new views::ImageView();
    logo_->SetImage(&logo_image);
    container->AddChildView(logo_);
  }

  indicator_ = new SoundLevelIndicator();
  indicator_->SetVisible(false);
  container->AddChildView(indicator_);

  MicButton* mic_button = new MicButton(this);
  mic_button_ = mic_button;
  container->AddChildView(mic_button_);
  mic_button_->SetEventTargeter(
      scoped_ptr<views::ViewTargeter>(new views::ViewTargeter(mic_button)));

  // TODO(mukai): use BoundedLabel to cap 2 lines.
  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
  // TODO(calamity): make this label multiline once Label caches its RenderText.
  // See http://crbug.com/450791.
  speech_result_ = new views::Label(
      base::string16(), bundle.GetFontList(ui::ResourceBundle::LargeFont));
  speech_result_->SetHorizontalAlignment(gfx::ALIGN_LEFT);

  container->AddChildView(speech_result_);

  AddChildView(container);

  delegate_->GetSpeechUI()->AddObserver(this);
  indicator_animator_.reset(new views::BoundsAnimator(container));
  indicator_animator_->SetAnimationDuration(kIndicatorAnimationDuration);
  indicator_animator_->set_tween_type(gfx::Tween::LINEAR);

  Reset();
}

SpeechView::~SpeechView() {
  delegate_->GetSpeechUI()->RemoveObserver(this);
}

void SpeechView::Reset() {
  OnSpeechRecognitionStateChanged(delegate_->GetSpeechUI()->state());
}

int SpeechView::GetIndicatorRadius(uint8 level) {
  int radius_min = mic_button_->width() / 2 + kIndicatorRadiusMinOffset;
  int range = kIndicatorRadiusMax - radius_min;
  return level * range / kuint8max + radius_min;
}

void SpeechView::Layout() {
  views::View* container = child_at(0);
  container->SetBoundsRect(GetContentsBounds());

  // Because container is a pure View, this class should layout its children.
  const gfx::Rect contents_bounds = container->GetContentsBounds();
  if (logo_)
    logo_->SetBounds(kLogoMarginLeft, kLogoMarginTop, kLogoWidth, kLogoHeight);
  gfx::Size mic_size = mic_button_->GetPreferredSize();
  gfx::Point mic_origin(
      contents_bounds.right() - kMicButtonMargin - mic_size.width(),
      contents_bounds.y() + kMicButtonMargin);
  mic_button_->SetBoundsRect(gfx::Rect(mic_origin, mic_size));

  int speech_width = contents_bounds.width() - kTextMargin * 2;
  int speech_height = speech_result_->GetHeightForWidth(speech_width);
  speech_result_->SetBounds(
      contents_bounds.x() + kTextMargin,
      contents_bounds.bottom() - kTextMargin - speech_height,
      speech_width,
      speech_height);
}

gfx::Size SpeechView::GetPreferredSize() const {
  return gfx::Size(0, kSpeechViewMaxHeight);
}

void SpeechView::ButtonPressed(views::Button* sender, const ui::Event& event) {
  delegate_->ToggleSpeechRecognition();
}

void SpeechView::OnSpeechSoundLevelChanged(uint8 level) {
  if (!visible() ||
      delegate_->GetSpeechUI()->state() == SPEECH_RECOGNITION_NETWORK_ERROR)
    return;

  gfx::Point origin = mic_button_->bounds().CenterPoint();
  int radius = GetIndicatorRadius(level);
  origin.Offset(-radius, -radius + kIndicatorCenterOffsetY);
  gfx::Rect indicator_bounds =
      gfx::Rect(origin, gfx::Size(radius * 2, radius * 2));
  if (indicator_->visible()) {
    indicator_animator_->AnimateViewTo(indicator_, indicator_bounds);
  } else {
    indicator_->SetVisible(true);
    indicator_->SetBoundsRect(indicator_bounds);
  }
}

void SpeechView::OnSpeechResult(const base::string16& result,
                                bool is_final) {
  speech_result_->SetText(result);
  speech_result_->SetEnabledColor(kResultTextColor);
}

void SpeechView::OnSpeechRecognitionStateChanged(
    SpeechRecognitionState new_state) {
  int resource_id = IDR_APP_LIST_SPEECH_MIC_OFF;
  if (new_state == SPEECH_RECOGNITION_RECOGNIZING)
    resource_id = IDR_APP_LIST_SPEECH_MIC_ON;
  else if (new_state == SPEECH_RECOGNITION_IN_SPEECH)
    resource_id = IDR_APP_LIST_SPEECH_MIC_RECORDING;

  int text_resource_id = IDS_APP_LIST_SPEECH_HINT_TEXT;

  if (new_state == SPEECH_RECOGNITION_NETWORK_ERROR) {
    text_resource_id = IDS_APP_LIST_SPEECH_NETWORK_ERROR_HINT_TEXT;
    indicator_->SetVisible(false);
  }
  speech_result_->SetText(l10n_util::GetStringUTF16(text_resource_id));
  speech_result_->SetEnabledColor(kHintTextColor);

  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
  mic_button_->SetImage(views::Button::STATE_NORMAL,
                        bundle.GetImageSkiaNamed(resource_id));
}

}  // namespace app_list
<|endoftext|>


<commit_before>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2014 Preferred Networks and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#include "nearest_neighbor_classifier.hpp"

#include <cfloat>
#include <string>
#include <vector>
#include <map>
#include <utility>
#include "../framework/mixable_versioned_table.hpp"
#include "../common/unordered_map.hpp"
#include "../storage/column_table.hpp"
#include "jubatus/util/concurrent/lock.h"
#include "nearest_neighbor_classifier_util.hpp"
#include "jubatus/util/lang/bind.h"
#include "jubatus/util/lang/function.h"

using jubatus::util::lang::shared_ptr;
using jubatus::util::concurrent::scoped_lock;

namespace jubatus {
namespace core {
namespace classifier {

class nearest_neighbor_classifier::unlearning_callback {
 public:
  explicit unlearning_callback(nearest_neighbor_classifier* classifier)
      : classifier_(classifier) {
  }

  void operator()(const std::string& id) {
    classifier_->unlearn_id(id);
    classifier_->decrement_label_counter(get_label_from_id(id));
  }

 private:
  nearest_neighbor_classifier* classifier_;
};

nearest_neighbor_classifier::nearest_neighbor_classifier(
    shared_ptr<nearest_neighbor::nearest_neighbor_base> engine,
    size_t k,
    float alpha)
    : nearest_neighbor_engine_(engine), k_(k), alpha_(alpha) {
  if (!(alpha >= 0)) {
    throw JUBATUS_EXCEPTION(common::invalid_parameter(
        "local_sensitivity should >= 0"));
  }
  dynamic_cast<framework::mixable_versioned_table*>
      (nearest_neighbor_engine_->get_mixable())->set_update_callback(
          util::lang::bind(
              &nearest_neighbor_classifier::regenerate_label_counter, this));
}

void nearest_neighbor_classifier::train(
    const common::sfv_t& fv, const std::string& label) {
  std::string id;
  {
    util::concurrent::scoped_lock lk(rand_mutex_);
    id = make_id_from_label(label, rand_);
  }
  if (unlearner_) {
    util::concurrent::scoped_lock unlearner_lk(unlearner_mutex_);
    if (!unlearner_->touch(id)) {
      throw JUBATUS_EXCEPTION(common::exception::runtime_error(
          "cannot add new ID as number of sticky IDs reached "
          "the maximum size of unlearner: " + id));
    }
  }
  nearest_neighbor_engine_->set_row(id, fv);
  set_label(label);

  util::concurrent::scoped_lock lk(label_mutex_);
  labels_[label] += 1;
}

void nearest_neighbor_classifier::set_label_unlearner(
    shared_ptr<unlearner::unlearner_base> label_unlearner) {
  label_unlearner->set_callback(unlearning_callback(this));
  unlearner_ = label_unlearner;
  // Support unlearning in MIX
  dynamic_cast<framework::mixable_versioned_table*>
      (nearest_neighbor_engine_->get_mixable())->set_unlearner(unlearner_);
}

std::string nearest_neighbor_classifier::classify(
    const common::sfv_t& fv) const {
  classify_result result;
  classify_with_scores(fv, result);
  float max_score = -FLT_MAX;
  std::string max_class;
  for (std::vector<classify_result_elem>::const_iterator it = result.begin();
      it != result.end(); ++it) {
    if (it == result.begin() || it->score > max_score) {
      max_score = it->score;
      max_class = it->label;
    }
  }
  return max_class;
}

void nearest_neighbor_classifier::classify_with_scores(
    const common::sfv_t& fv, classify_result& scores) const {
  std::vector<std::pair<std::string, float> > ids;
  nearest_neighbor_engine_->neighbor_row(fv, ids, k_);

  std::map<std::string, float> m;
  {
    util::concurrent::scoped_lock lk(label_mutex_);
    for (labels_t::const_iterator iter = labels_.begin();
         iter != labels_.end(); ++iter) {
      m.insert(std::make_pair(iter->first, 0));
    }
  }
  for (size_t i = 0; i < ids.size(); ++i) {
    std::string label = get_label_from_id(ids[i].first);
    m[label] += std::exp(-alpha_ * ids[i].second);
  }

  scores.clear();
  for (std::map<std::string, float>::const_iterator iter = m.begin();
       iter != m.end(); ++iter) {
    classify_result_elem elem(iter->first, iter->second);
    scores.push_back(elem);
  }
}

bool nearest_neighbor_classifier::delete_label(const std::string& label) {
  {
    util::concurrent::scoped_lock lk(label_mutex_);
    if (labels_.erase(label) == 0) {
      return false;
    }
  }

  shared_ptr<storage::column_table> table =
      nearest_neighbor_engine_->get_table();

  std::vector<std::string> ids_to_be_deleted;
  for (size_t i = 0, n = table->size(); i < n; ++i) {
    std::string id = table->get_key(i);
    std::string l = get_label_from_id(id);
    if (l == label) {
      ids_to_be_deleted.push_back(id);
    }
  }

  for (size_t i = 0, n = ids_to_be_deleted.size(); i < n; ++i) {
    const std::string& id = ids_to_be_deleted[i];
    table->delete_row(id);
    if (unlearner_) {
      unlearner_->remove(id);
    }
  }

  return true;
}

void nearest_neighbor_classifier::clear() {
  nearest_neighbor_engine_->clear();
  {
    util::concurrent::scoped_lock lk(label_mutex_);
    labels_.clear();
  }
  if (unlearner_) {
    unlearner_->clear();
  }
}

std::vector<std::string> nearest_neighbor_classifier::get_labels() const {
  util::concurrent::scoped_lock lk(label_mutex_);
  std::vector<std::string> result;
  for (labels_t::const_iterator iter = labels_.begin();
       iter != labels_.end(); ++iter) {
    result.push_back(iter->first);
  }
  return result;
}

bool nearest_neighbor_classifier::set_label(const std::string& label) {
  util::concurrent::scoped_lock lk(label_mutex_);
  if (labels_.find(label) == labels_.end()) {
    labels_[label] = 0;
    return true;
  } else {
    return false;
  }
}

std::string nearest_neighbor_classifier::name() const {
  return "nearest_neighbor_classifier:" + nearest_neighbor_engine_->type();
}

void nearest_neighbor_classifier::get_status(
    std::map<std::string, std::string>& status) const {
  // unimplemented
}

void nearest_neighbor_classifier::pack(framework::packer& pk) const {
  pk.pack_array(2);
  nearest_neighbor_engine_->pack(pk);

  util::concurrent::scoped_lock lk(label_mutex_);
  pk.pack(labels_);
}

void nearest_neighbor_classifier::unpack(msgpack::object o) {
  if (o.type != msgpack::type::ARRAY || o.via.array.size != 2) {
    throw msgpack::type_error();
  }
  nearest_neighbor_engine_->unpack(o.via.array.ptr[0]);
  util::concurrent::scoped_lock lk(label_mutex_);
  o.via.array.ptr[1].convert(&labels_);
}

framework::mixable* nearest_neighbor_classifier::get_mixable() {
  return nearest_neighbor_engine_->get_mixable();
}

void nearest_neighbor_classifier::unlearn_id(const std::string& id) {
  nearest_neighbor_engine_->get_table()->delete_row(id);
}

void nearest_neighbor_classifier::decrement_label_counter(
    const std::string& label) {
  util::concurrent::scoped_lock lk(label_mutex_);
  labels_[label] -= 1;
  if (labels_[label] <= 0) {
    labels_.erase(label);
  }
}

void nearest_neighbor_classifier::regenerate_label_counter() {
  labels_t new_labels;

  {
    shared_ptr<const storage::column_table> table =
        nearest_neighbor_engine_->get_const_table();
    util::concurrent::scoped_rlock table_lk(table->get_mutex());

    for (size_t i = 0, n = table->size(); i < n; ++i) {
      std::string id = table->get_key(i);
      std::string label = get_label_from_id(id);
      new_labels[label] += 1;
    }
  }

  util::concurrent::scoped_lock lk(label_mutex_);
  for (labels_t::const_iterator iter = labels_.begin();
       iter != labels_.end(); ++iter) {
    if (labels.find(iter->first) == labels.end()) {
      // labels registered by set_label are exist
      new_labels[iter->first] = iter->second;
    }
  }
  labels_.swap(new_labels);
}

}  // namespace classifier
}  // namespace core
}  // namespace jubatus
<commit_msg>Refactor regenerate_label_counter<commit_after>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2014 Preferred Networks and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#include "nearest_neighbor_classifier.hpp"

#include <cfloat>
#include <string>
#include <vector>
#include <map>
#include <utility>
#include "../framework/mixable_versioned_table.hpp"
#include "../common/unordered_map.hpp"
#include "../storage/column_table.hpp"
#include "jubatus/util/concurrent/lock.h"
#include "nearest_neighbor_classifier_util.hpp"
#include "jubatus/util/lang/bind.h"
#include "jubatus/util/lang/function.h"

using jubatus::util::lang::shared_ptr;
using jubatus::util::concurrent::scoped_lock;

namespace jubatus {
namespace core {
namespace classifier {

class nearest_neighbor_classifier::unlearning_callback {
 public:
  explicit unlearning_callback(nearest_neighbor_classifier* classifier)
      : classifier_(classifier) {
  }

  void operator()(const std::string& id) {
    classifier_->unlearn_id(id);
    classifier_->decrement_label_counter(get_label_from_id(id));
  }

 private:
  nearest_neighbor_classifier* classifier_;
};

nearest_neighbor_classifier::nearest_neighbor_classifier(
    shared_ptr<nearest_neighbor::nearest_neighbor_base> engine,
    size_t k,
    float alpha)
    : nearest_neighbor_engine_(engine), k_(k), alpha_(alpha) {
  if (!(alpha >= 0)) {
    throw JUBATUS_EXCEPTION(common::invalid_parameter(
        "local_sensitivity should >= 0"));
  }
  dynamic_cast<framework::mixable_versioned_table*>
      (nearest_neighbor_engine_->get_mixable())->set_update_callback(
          util::lang::bind(
              &nearest_neighbor_classifier::regenerate_label_counter, this));
}

void nearest_neighbor_classifier::train(
    const common::sfv_t& fv, const std::string& label) {
  std::string id;
  {
    util::concurrent::scoped_lock lk(rand_mutex_);
    id = make_id_from_label(label, rand_);
  }
  if (unlearner_) {
    util::concurrent::scoped_lock unlearner_lk(unlearner_mutex_);
    if (!unlearner_->touch(id)) {
      throw JUBATUS_EXCEPTION(common::exception::runtime_error(
          "cannot add new ID as number of sticky IDs reached "
          "the maximum size of unlearner: " + id));
    }
  }
  nearest_neighbor_engine_->set_row(id, fv);
  set_label(label);

  util::concurrent::scoped_lock lk(label_mutex_);
  labels_[label] += 1;
}

void nearest_neighbor_classifier::set_label_unlearner(
    shared_ptr<unlearner::unlearner_base> label_unlearner) {
  label_unlearner->set_callback(unlearning_callback(this));
  unlearner_ = label_unlearner;
  // Support unlearning in MIX
  dynamic_cast<framework::mixable_versioned_table*>
      (nearest_neighbor_engine_->get_mixable())->set_unlearner(unlearner_);
}

std::string nearest_neighbor_classifier::classify(
    const common::sfv_t& fv) const {
  classify_result result;
  classify_with_scores(fv, result);
  float max_score = -FLT_MAX;
  std::string max_class;
  for (std::vector<classify_result_elem>::const_iterator it = result.begin();
      it != result.end(); ++it) {
    if (it == result.begin() || it->score > max_score) {
      max_score = it->score;
      max_class = it->label;
    }
  }
  return max_class;
}

void nearest_neighbor_classifier::classify_with_scores(
    const common::sfv_t& fv, classify_result& scores) const {
  std::vector<std::pair<std::string, float> > ids;
  nearest_neighbor_engine_->neighbor_row(fv, ids, k_);

  std::map<std::string, float> m;
  {
    util::concurrent::scoped_lock lk(label_mutex_);
    for (labels_t::const_iterator iter = labels_.begin();
         iter != labels_.end(); ++iter) {
      m.insert(std::make_pair(iter->first, 0));
    }
  }
  for (size_t i = 0; i < ids.size(); ++i) {
    std::string label = get_label_from_id(ids[i].first);
    m[label] += std::exp(-alpha_ * ids[i].second);
  }

  scores.clear();
  for (std::map<std::string, float>::const_iterator iter = m.begin();
       iter != m.end(); ++iter) {
    classify_result_elem elem(iter->first, iter->second);
    scores.push_back(elem);
  }
}

bool nearest_neighbor_classifier::delete_label(const std::string& label) {
  {
    util::concurrent::scoped_lock lk(label_mutex_);
    if (labels_.erase(label) == 0) {
      return false;
    }
  }

  shared_ptr<storage::column_table> table =
      nearest_neighbor_engine_->get_table();

  std::vector<std::string> ids_to_be_deleted;
  for (size_t i = 0, n = table->size(); i < n; ++i) {
    std::string id = table->get_key(i);
    std::string l = get_label_from_id(id);
    if (l == label) {
      ids_to_be_deleted.push_back(id);
    }
  }

  for (size_t i = 0, n = ids_to_be_deleted.size(); i < n; ++i) {
    const std::string& id = ids_to_be_deleted[i];
    table->delete_row(id);
    if (unlearner_) {
      unlearner_->remove(id);
    }
  }

  return true;
}

void nearest_neighbor_classifier::clear() {
  nearest_neighbor_engine_->clear();
  {
    util::concurrent::scoped_lock lk(label_mutex_);
    labels_.clear();
  }
  if (unlearner_) {
    unlearner_->clear();
  }
}

std::vector<std::string> nearest_neighbor_classifier::get_labels() const {
  util::concurrent::scoped_lock lk(label_mutex_);
  std::vector<std::string> result;
  for (labels_t::const_iterator iter = labels_.begin();
       iter != labels_.end(); ++iter) {
    result.push_back(iter->first);
  }
  return result;
}

bool nearest_neighbor_classifier::set_label(const std::string& label) {
  util::concurrent::scoped_lock lk(label_mutex_);
  if (labels_.find(label) == labels_.end()) {
    labels_[label] = 0;
    return true;
  } else {
    return false;
  }
}

std::string nearest_neighbor_classifier::name() const {
  return "nearest_neighbor_classifier:" + nearest_neighbor_engine_->type();
}

void nearest_neighbor_classifier::get_status(
    std::map<std::string, std::string>& status) const {
  // unimplemented
}

void nearest_neighbor_classifier::pack(framework::packer& pk) const {
  pk.pack_array(2);
  nearest_neighbor_engine_->pack(pk);

  util::concurrent::scoped_lock lk(label_mutex_);
  pk.pack(labels_);
}

void nearest_neighbor_classifier::unpack(msgpack::object o) {
  if (o.type != msgpack::type::ARRAY || o.via.array.size != 2) {
    throw msgpack::type_error();
  }
  nearest_neighbor_engine_->unpack(o.via.array.ptr[0]);
  util::concurrent::scoped_lock lk(label_mutex_);
  o.via.array.ptr[1].convert(&labels_);
}

framework::mixable* nearest_neighbor_classifier::get_mixable() {
  return nearest_neighbor_engine_->get_mixable();
}

void nearest_neighbor_classifier::unlearn_id(const std::string& id) {
  nearest_neighbor_engine_->get_table()->delete_row(id);
}

void nearest_neighbor_classifier::decrement_label_counter(
    const std::string& label) {
  util::concurrent::scoped_lock lk(label_mutex_);
  labels_[label] -= 1;
  if (labels_[label] <= 0) {
    labels_.erase(label);
  }
}

void nearest_neighbor_classifier::regenerate_label_counter() {
  labels_t new_labels;

  {
    // Copy keyset of labels_ to new labels.
    // labels_ contains labels that registered by set_label.
    util::concurrent::scoped_lock lk(label_mutex_);
    for (labels_t::const_iterator iter = labels_.begin();
         iter != labels_.end(); ++iter) {
      new_labels[iter->first] = 0;
    }
  }

  {
    // Count id for each label
    shared_ptr<const storage::column_table> table =
        nearest_neighbor_engine_->get_const_table();
    util::concurrent::scoped_rlock table_lk(table->get_mutex());

    for (size_t i = 0, n = table->size(); i < n; ++i) {
      std::string id = table->get_key(i);
      std::string label = get_label_from_id(id);
      new_labels[label] += 1;
    }
  }

  labels_.swap(new_labels);
}

}  // namespace classifier
}  // namespace core
}  // namespace jubatus
<|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 <accessibility/standard/vclxaccessiblemenubar.hxx>

#include <com/sun/star/accessibility/AccessibleRole.hpp>
#include <vcl/svapp.hxx>
#include <vcl/window.hxx>
#include <vcl/menu.hxx>

using namespace ::com::sun::star::accessibility;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star;
using namespace ::comphelper;

// -----------------------------------------------------------------------------
// class VCLXAccessibleMenuBar
// -----------------------------------------------------------------------------

VCLXAccessibleMenuBar::VCLXAccessibleMenuBar( Menu* pMenu )
    :OAccessibleMenuComponent( pMenu )
{
    if ( pMenu )
    {
        m_pWindow = pMenu->GetWindow();

        if ( m_pWindow )
            m_pWindow->AddEventListener( LINK( this, VCLXAccessibleMenuBar, WindowEventListener ) );
    }
}

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

VCLXAccessibleMenuBar::~VCLXAccessibleMenuBar()
{
    if ( m_pWindow )
        m_pWindow->RemoveEventListener( LINK( this, VCLXAccessibleMenuBar, WindowEventListener ) );
}

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

sal_Bool VCLXAccessibleMenuBar::IsFocused()
{
    sal_Bool bFocused = sal_False;

    if ( m_pWindow && m_pWindow->HasFocus() && !IsChildHighlighted() )
        bFocused = sal_True;

    return bFocused;
}

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

IMPL_LINK( VCLXAccessibleMenuBar, WindowEventListener, VclSimpleEvent*, pEvent )
{
    OSL_ENSURE( pEvent && pEvent->ISA( VclWindowEvent ), "VCLXAccessibleMenuBar::WindowEventListener: unknown window event!" );
    if ( pEvent && pEvent->ISA( VclWindowEvent ) )
    {
        OSL_ENSURE( ((VclWindowEvent*)pEvent)->GetWindow(), "VCLXAccessibleMenuBar::WindowEventListener: no window!" );
        if ( !((VclWindowEvent*)pEvent)->GetWindow()->IsAccessibilityEventsSuppressed() || ( pEvent->GetId() == VCLEVENT_OBJECT_DYING ) )
        {
            ProcessWindowEvent( *(VclWindowEvent*)pEvent );
        }
    }
    return 0;
}

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

void VCLXAccessibleMenuBar::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
{
    switch ( rVclWindowEvent.GetId() )
    {
        case VCLEVENT_WINDOW_GETFOCUS:
        case VCLEVENT_WINDOW_LOSEFOCUS:
        {
            SetFocused( rVclWindowEvent.GetId() == VCLEVENT_WINDOW_GETFOCUS );
        }
        break;
        case VCLEVENT_OBJECT_DYING:
        {
            if ( m_pWindow )
            {
                m_pWindow->RemoveEventListener( LINK( this, VCLXAccessibleMenuBar, WindowEventListener ) );
                m_pWindow = NULL;
            }
        }
        break;
        default:
        {
        }
        break;
    }
}

// -----------------------------------------------------------------------------
// XComponent
// -----------------------------------------------------------------------------

void VCLXAccessibleMenuBar::disposing()
{
    OAccessibleMenuComponent::disposing();

    if ( m_pWindow )
    {
        m_pWindow->RemoveEventListener( LINK( this, VCLXAccessibleMenuBar, WindowEventListener ) );
        m_pWindow = NULL;
    }
}

// -----------------------------------------------------------------------------
// XServiceInfo
// -----------------------------------------------------------------------------

OUString VCLXAccessibleMenuBar::getImplementationName() throw (RuntimeException)
{
    return OUString( "com.sun.star.comp.toolkit.AccessibleMenuBar" );
}

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

Sequence< OUString > VCLXAccessibleMenuBar::getSupportedServiceNames() throw (RuntimeException)
{
    Sequence< OUString > aNames(1);
    aNames[0] = "com.sun.star.awt.AccessibleMenuBar";
    return aNames;
}

// -----------------------------------------------------------------------------
// XAccessibleContext
// -----------------------------------------------------------------------------

sal_Int32 VCLXAccessibleMenuBar::getAccessibleIndexInParent(  ) throw (RuntimeException)
{
    OExternalLockGuard aGuard( this );

    sal_Int32 nIndexInParent = -1;

    if ( m_pMenu )
    {
        Window* pWindow = m_pMenu->GetWindow();
        if ( pWindow )
        {
            Window* pParent = pWindow->GetAccessibleParentWindow();
            if ( pParent )
            {
                for ( sal_uInt16 n = pParent->GetAccessibleChildWindowCount(); n; )
                {
                    Window* pChild = pParent->GetAccessibleChildWindow( --n );
                    if ( pChild == pWindow )
                    {
                        nIndexInParent = n;
                        break;
                    }
                }
            }
        }
    }

    return nIndexInParent;
}

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

sal_Int16 VCLXAccessibleMenuBar::getAccessibleRole(  ) throw (RuntimeException)
{
    OExternalLockGuard aGuard( this );

    return AccessibleRole::MENU_BAR;
}

// -----------------------------------------------------------------------------
// XAccessibleExtendedComponent
// -----------------------------------------------------------------------------

sal_Int32 VCLXAccessibleMenuBar::getBackground(  ) throw (RuntimeException)
{
    OExternalLockGuard aGuard( this );

    return Application::GetSettings().GetStyleSettings().GetMenuBarColor().GetColor();
}

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

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>coverity#707601 Uninitialized pointer field<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 <accessibility/standard/vclxaccessiblemenubar.hxx>

#include <com/sun/star/accessibility/AccessibleRole.hpp>
#include <vcl/svapp.hxx>
#include <vcl/window.hxx>
#include <vcl/menu.hxx>

using namespace ::com::sun::star::accessibility;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star;
using namespace ::comphelper;

// -----------------------------------------------------------------------------
// class VCLXAccessibleMenuBar
// -----------------------------------------------------------------------------

VCLXAccessibleMenuBar::VCLXAccessibleMenuBar( Menu* pMenu )
    :OAccessibleMenuComponent( pMenu )
{
    if ( pMenu )
    {
        m_pWindow = pMenu->GetWindow();

        if ( m_pWindow )
            m_pWindow->AddEventListener( LINK( this, VCLXAccessibleMenuBar, WindowEventListener ) );
    }
    else
    {
        m_pWindow = 0;
    }
}

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

VCLXAccessibleMenuBar::~VCLXAccessibleMenuBar()
{
    if ( m_pWindow )
        m_pWindow->RemoveEventListener( LINK( this, VCLXAccessibleMenuBar, WindowEventListener ) );
}

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

sal_Bool VCLXAccessibleMenuBar::IsFocused()
{
    sal_Bool bFocused = sal_False;

    if ( m_pWindow && m_pWindow->HasFocus() && !IsChildHighlighted() )
        bFocused = sal_True;

    return bFocused;
}

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

IMPL_LINK( VCLXAccessibleMenuBar, WindowEventListener, VclSimpleEvent*, pEvent )
{
    OSL_ENSURE( pEvent && pEvent->ISA( VclWindowEvent ), "VCLXAccessibleMenuBar::WindowEventListener: unknown window event!" );
    if ( pEvent && pEvent->ISA( VclWindowEvent ) )
    {
        OSL_ENSURE( ((VclWindowEvent*)pEvent)->GetWindow(), "VCLXAccessibleMenuBar::WindowEventListener: no window!" );
        if ( !((VclWindowEvent*)pEvent)->GetWindow()->IsAccessibilityEventsSuppressed() || ( pEvent->GetId() == VCLEVENT_OBJECT_DYING ) )
        {
            ProcessWindowEvent( *(VclWindowEvent*)pEvent );
        }
    }
    return 0;
}

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

void VCLXAccessibleMenuBar::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
{
    switch ( rVclWindowEvent.GetId() )
    {
        case VCLEVENT_WINDOW_GETFOCUS:
        case VCLEVENT_WINDOW_LOSEFOCUS:
        {
            SetFocused( rVclWindowEvent.GetId() == VCLEVENT_WINDOW_GETFOCUS );
        }
        break;
        case VCLEVENT_OBJECT_DYING:
        {
            if ( m_pWindow )
            {
                m_pWindow->RemoveEventListener( LINK( this, VCLXAccessibleMenuBar, WindowEventListener ) );
                m_pWindow = NULL;
            }
        }
        break;
        default:
        {
        }
        break;
    }
}

// -----------------------------------------------------------------------------
// XComponent
// -----------------------------------------------------------------------------

void VCLXAccessibleMenuBar::disposing()
{
    OAccessibleMenuComponent::disposing();

    if ( m_pWindow )
    {
        m_pWindow->RemoveEventListener( LINK( this, VCLXAccessibleMenuBar, WindowEventListener ) );
        m_pWindow = NULL;
    }
}

// -----------------------------------------------------------------------------
// XServiceInfo
// -----------------------------------------------------------------------------

OUString VCLXAccessibleMenuBar::getImplementationName() throw (RuntimeException)
{
    return OUString( "com.sun.star.comp.toolkit.AccessibleMenuBar" );
}

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

Sequence< OUString > VCLXAccessibleMenuBar::getSupportedServiceNames() throw (RuntimeException)
{
    Sequence< OUString > aNames(1);
    aNames[0] = "com.sun.star.awt.AccessibleMenuBar";
    return aNames;
}

// -----------------------------------------------------------------------------
// XAccessibleContext
// -----------------------------------------------------------------------------

sal_Int32 VCLXAccessibleMenuBar::getAccessibleIndexInParent(  ) throw (RuntimeException)
{
    OExternalLockGuard aGuard( this );

    sal_Int32 nIndexInParent = -1;

    if ( m_pMenu )
    {
        Window* pWindow = m_pMenu->GetWindow();
        if ( pWindow )
        {
            Window* pParent = pWindow->GetAccessibleParentWindow();
            if ( pParent )
            {
                for ( sal_uInt16 n = pParent->GetAccessibleChildWindowCount(); n; )
                {
                    Window* pChild = pParent->GetAccessibleChildWindow( --n );
                    if ( pChild == pWindow )
                    {
                        nIndexInParent = n;
                        break;
                    }
                }
            }
        }
    }

    return nIndexInParent;
}

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

sal_Int16 VCLXAccessibleMenuBar::getAccessibleRole(  ) throw (RuntimeException)
{
    OExternalLockGuard aGuard( this );

    return AccessibleRole::MENU_BAR;
}

// -----------------------------------------------------------------------------
// XAccessibleExtendedComponent
// -----------------------------------------------------------------------------

sal_Int32 VCLXAccessibleMenuBar::getBackground(  ) throw (RuntimeException)
{
    OExternalLockGuard aGuard( this );

    return Application::GetSettings().GetStyleSettings().GetMenuBarColor().GetColor();
}

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

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


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

#include "chrome/browser/speech/speech_recognition_bubble_controller.h"

#include "base/bind.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"

using content::BrowserThread;
using content::WebContents;

namespace {
const int kInvalidSessionId = 0;
}

namespace speech {

SpeechRecognitionBubbleController::SpeechRecognitionBubbleController(
    Delegate* delegate)
    : delegate_(delegate),
      current_bubble_session_id_(kInvalidSessionId),
      current_bubble_render_process_id_(0),
      current_bubble_render_view_id_(0),
      last_request_issued_(REQUEST_CLOSE) {
}

SpeechRecognitionBubbleController::~SpeechRecognitionBubbleController() {
  DCHECK_EQ(kInvalidSessionId, current_bubble_session_id_);
}

void SpeechRecognitionBubbleController::CreateBubble(
    int session_id,
    int render_process_id,
    int render_view_id,
    const gfx::Rect& element_rect) {
  current_bubble_session_id_ = session_id;
  current_bubble_render_process_id_ = render_process_id;
  current_bubble_render_view_id_ = render_view_id;

  UIRequest request(REQUEST_CREATE);
  request.render_process_id = render_process_id;
  request.render_view_id = render_view_id;
  request.element_rect = element_rect;
  ProcessRequestInUiThread(request);
}

void SpeechRecognitionBubbleController::SetBubbleRecordingMode() {
  ProcessRequestInUiThread(UIRequest(REQUEST_SET_RECORDING_MODE));
}

void SpeechRecognitionBubbleController::SetBubbleRecognizingMode() {
  ProcessRequestInUiThread(UIRequest(REQUEST_SET_RECOGNIZING_MODE));
}

void SpeechRecognitionBubbleController::SetBubbleMessage(const string16& text) {
  UIRequest request(REQUEST_SET_MESSAGE);
  request.message = text;
  ProcessRequestInUiThread(request);
}

bool SpeechRecognitionBubbleController::IsShowingMessage() const {
  return last_request_issued_ == REQUEST_SET_MESSAGE;
}

void SpeechRecognitionBubbleController::SetBubbleInputVolume(
    float volume,
    float noise_volume) {
  UIRequest request(REQUEST_SET_INPUT_VOLUME);
  request.volume = volume;
  request.noise_volume = noise_volume;
  ProcessRequestInUiThread(request);
}

void SpeechRecognitionBubbleController::CloseBubble() {
  current_bubble_session_id_ = kInvalidSessionId;
  ProcessRequestInUiThread(UIRequest(REQUEST_CLOSE));
}

int SpeechRecognitionBubbleController::GetActiveSessionID() const {
  return current_bubble_session_id_;
}

bool SpeechRecognitionBubbleController::IsShowingBubbleForRenderView(
    int render_process_id,
    int render_view_id) {
  return (current_bubble_session_id_ != kInvalidSessionId) &&
      (current_bubble_render_process_id_ == render_process_id) &&
      (current_bubble_render_view_id_ == render_view_id);
}

void SpeechRecognitionBubbleController::InfoBubbleButtonClicked(
    SpeechRecognitionBubble::Button button) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
      base::Bind(
          &SpeechRecognitionBubbleController::InvokeDelegateButtonClicked, this,
          button));
}

void SpeechRecognitionBubbleController::InfoBubbleFocusChanged() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
      base::Bind(&SpeechRecognitionBubbleController::InvokeDelegateFocusChanged,
                 this));
}

void SpeechRecognitionBubbleController::InvokeDelegateButtonClicked(
    SpeechRecognitionBubble::Button button) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  DCHECK_NE(kInvalidSessionId, current_bubble_session_id_);
  delegate_->InfoBubbleButtonClicked(current_bubble_session_id_, button);
}

void SpeechRecognitionBubbleController::InvokeDelegateFocusChanged() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  DCHECK_NE(kInvalidSessionId, current_bubble_session_id_);
  delegate_->InfoBubbleFocusChanged(current_bubble_session_id_);
}

void SpeechRecognitionBubbleController::ProcessRequestInUiThread(
    const UIRequest& request) {
  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    last_request_issued_ = request.type;
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
        base::Bind(&SpeechRecognitionBubbleController::ProcessRequestInUiThread,
                   this, request));
    return;
  }

  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  switch (request.type) {
    case REQUEST_CREATE:
      bubble_.reset(SpeechRecognitionBubble::Create(
          tab_util::GetWebContentsByID(request.render_process_id,
                                       request.render_view_id),
          this, request.element_rect));

      if (!bubble_.get()) {
        // Could be null if tab or display rect were invalid.
        // Simulate the cancel button being clicked to inform the delegate.
        BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
            base::Bind(
                &SpeechRecognitionBubbleController::InvokeDelegateButtonClicked,
                this, SpeechRecognitionBubble::BUTTON_CANCEL));
        return;
      }
      bubble_->Show();
      bubble_->SetWarmUpMode();
      break;
    case REQUEST_SET_RECORDING_MODE:
      DCHECK(bubble_.get());
      bubble_->SetRecordingMode();
      break;
    case REQUEST_SET_RECOGNIZING_MODE:
      DCHECK(bubble_.get());
      bubble_->SetRecognizingMode();
      break;
    case REQUEST_SET_MESSAGE:
      DCHECK(bubble_.get());
      bubble_->SetMessage(request.message);
      break;
    case REQUEST_SET_INPUT_VOLUME:
      DCHECK(bubble_.get());
      bubble_->SetInputVolume(request.volume, request.noise_volume);
      break;
    case REQUEST_CLOSE:
      bubble_.reset();
      break;
    default:
      NOTREACHED();
      break;
  }
}

SpeechRecognitionBubbleController::UIRequest::UIRequest(RequestType type_value)
    : type(type_value),
      volume(0.0F),
      noise_volume(0.0F),
      render_process_id(0),
      render_view_id(0) {
}

SpeechRecognitionBubbleController::UIRequest::~UIRequest() {
}

}  // namespace speech
<commit_msg>Simple fix for what seems to have been a problem for a while. Check for NULL bubble_.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/speech/speech_recognition_bubble_controller.h"

#include "base/bind.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"

using content::BrowserThread;
using content::WebContents;

namespace {
const int kInvalidSessionId = 0;
}

namespace speech {

SpeechRecognitionBubbleController::SpeechRecognitionBubbleController(
    Delegate* delegate)
    : delegate_(delegate),
      current_bubble_session_id_(kInvalidSessionId),
      current_bubble_render_process_id_(0),
      current_bubble_render_view_id_(0),
      last_request_issued_(REQUEST_CLOSE) {
}

SpeechRecognitionBubbleController::~SpeechRecognitionBubbleController() {
  DCHECK_EQ(kInvalidSessionId, current_bubble_session_id_);
}

void SpeechRecognitionBubbleController::CreateBubble(
    int session_id,
    int render_process_id,
    int render_view_id,
    const gfx::Rect& element_rect) {
  current_bubble_session_id_ = session_id;
  current_bubble_render_process_id_ = render_process_id;
  current_bubble_render_view_id_ = render_view_id;

  UIRequest request(REQUEST_CREATE);
  request.render_process_id = render_process_id;
  request.render_view_id = render_view_id;
  request.element_rect = element_rect;
  ProcessRequestInUiThread(request);
}

void SpeechRecognitionBubbleController::SetBubbleRecordingMode() {
  ProcessRequestInUiThread(UIRequest(REQUEST_SET_RECORDING_MODE));
}

void SpeechRecognitionBubbleController::SetBubbleRecognizingMode() {
  ProcessRequestInUiThread(UIRequest(REQUEST_SET_RECOGNIZING_MODE));
}

void SpeechRecognitionBubbleController::SetBubbleMessage(const string16& text) {
  UIRequest request(REQUEST_SET_MESSAGE);
  request.message = text;
  ProcessRequestInUiThread(request);
}

bool SpeechRecognitionBubbleController::IsShowingMessage() const {
  return last_request_issued_ == REQUEST_SET_MESSAGE;
}

void SpeechRecognitionBubbleController::SetBubbleInputVolume(
    float volume,
    float noise_volume) {
  UIRequest request(REQUEST_SET_INPUT_VOLUME);
  request.volume = volume;
  request.noise_volume = noise_volume;
  ProcessRequestInUiThread(request);
}

void SpeechRecognitionBubbleController::CloseBubble() {
  current_bubble_session_id_ = kInvalidSessionId;
  ProcessRequestInUiThread(UIRequest(REQUEST_CLOSE));
}

int SpeechRecognitionBubbleController::GetActiveSessionID() const {
  return current_bubble_session_id_;
}

bool SpeechRecognitionBubbleController::IsShowingBubbleForRenderView(
    int render_process_id,
    int render_view_id) {
  return (current_bubble_session_id_ != kInvalidSessionId) &&
      (current_bubble_render_process_id_ == render_process_id) &&
      (current_bubble_render_view_id_ == render_view_id);
}

void SpeechRecognitionBubbleController::InfoBubbleButtonClicked(
    SpeechRecognitionBubble::Button button) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
      base::Bind(
          &SpeechRecognitionBubbleController::InvokeDelegateButtonClicked, this,
          button));
}

void SpeechRecognitionBubbleController::InfoBubbleFocusChanged() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
      base::Bind(&SpeechRecognitionBubbleController::InvokeDelegateFocusChanged,
                 this));
}

void SpeechRecognitionBubbleController::InvokeDelegateButtonClicked(
    SpeechRecognitionBubble::Button button) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  DCHECK_NE(kInvalidSessionId, current_bubble_session_id_);
  delegate_->InfoBubbleButtonClicked(current_bubble_session_id_, button);
}

void SpeechRecognitionBubbleController::InvokeDelegateFocusChanged() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  DCHECK_NE(kInvalidSessionId, current_bubble_session_id_);
  delegate_->InfoBubbleFocusChanged(current_bubble_session_id_);
}

void SpeechRecognitionBubbleController::ProcessRequestInUiThread(
    const UIRequest& request) {
  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    last_request_issued_ = request.type;
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
        base::Bind(&SpeechRecognitionBubbleController::ProcessRequestInUiThread,
                   this, request));
    return;
  }

  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  switch (request.type) {
    case REQUEST_CREATE:
      bubble_.reset(SpeechRecognitionBubble::Create(
          tab_util::GetWebContentsByID(request.render_process_id,
                                       request.render_view_id),
          this, request.element_rect));

      if (!bubble_.get()) {
        // Could be null if tab or display rect were invalid.
        // Simulate the cancel button being clicked to inform the delegate.
        BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
            base::Bind(
                &SpeechRecognitionBubbleController::InvokeDelegateButtonClicked,
                this, SpeechRecognitionBubble::BUTTON_CANCEL));
        return;
      }
      bubble_->Show();
      bubble_->SetWarmUpMode();
      break;
    case REQUEST_SET_RECORDING_MODE:
      if (!bubble_.get()) {
        // We've seen this on crash/ but don't yet understand why this happen.
        // TODO(tommi): It would be nice to figure this out properly and fix
        // but since this feature is being deprecated, removing the code
        // altogether is probably a simpler and more permanent fix :)
        DLOG(ERROR) << "NULL bubble in REQUEST_SET_RECORDING_MODE!";
      } else {
        bubble_->SetRecordingMode();
      }
      break;
    case REQUEST_SET_RECOGNIZING_MODE:
      DCHECK(bubble_.get());
      bubble_->SetRecognizingMode();
      break;
    case REQUEST_SET_MESSAGE:
      DCHECK(bubble_.get());
      bubble_->SetMessage(request.message);
      break;
    case REQUEST_SET_INPUT_VOLUME:
      DCHECK(bubble_.get());
      bubble_->SetInputVolume(request.volume, request.noise_volume);
      break;
    case REQUEST_CLOSE:
      bubble_.reset();
      break;
    default:
      NOTREACHED();
      break;
  }
}

SpeechRecognitionBubbleController::UIRequest::UIRequest(RequestType type_value)
    : type(type_value),
      volume(0.0F),
      noise_volume(0.0F),
      render_process_id(0),
      render_view_id(0) {
}

SpeechRecognitionBubbleController::UIRequest::~UIRequest() {
}

}  // namespace speech
<|endoftext|>


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

#include <vector>

#include "testing/gtest/include/gtest/gtest.h"

#include "base/ref_counted.h"
#include "base/string16.h"
#include "base/time.h"
#include "base/waitable_event.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/autofill_change_processor.h"
#include "chrome/browser/sync/glue/autofill_data_type_controller.h"
#include "chrome/browser/sync/glue/autofill_model_associator.h"
#include "chrome/browser/sync/glue/sync_backend_host.h"
#include "chrome/browser/sync/profile_sync_factory.h"
#include "chrome/browser/sync/profile_sync_factory_mock.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/profile_sync_test_util.h"
#include "chrome/browser/sync/protocol/autofill_specifics.pb.h"
#include "chrome/browser/sync/test_profile_sync_service.h"
#include "chrome/browser/webdata/autofill_entry.h"
#include "chrome/browser/webdata/web_database.h"
#include "chrome/common/notification_service.h"
#include "chrome/test/testing_profile.h"
#include "testing/gmock/include/gmock/gmock.h"

using base::Time;
using base::WaitableEvent;
using browser_sync::AutofillChangeProcessor;
using browser_sync::AutofillDataTypeController;
using browser_sync::AutofillModelAssociator;
using browser_sync::SyncBackendHost;
using browser_sync::UnrecoverableErrorHandler;
using sync_api::SyncManager;
using testing::_;
using testing::DoAll;
using testing::DoDefault;
using testing::Return;
using testing::SetArgumentPointee;

class TestAutofillModelAssociator
    : public TestModelAssociator<AutofillModelAssociator> {
 public:
  TestAutofillModelAssociator(ProfileSyncService* service,
                              WebDatabase* web_database,
                              UnrecoverableErrorHandler* error_handler)
      : TestModelAssociator<AutofillModelAssociator>(
          service, web_database, error_handler) {
  }
};

class WebDatabaseMock : public WebDatabase {
 public:
  MOCK_METHOD2(RemoveFormElement,
               bool(const string16& name, const string16& value));
  MOCK_METHOD1(GetAllAutofillEntries,
               bool(std::vector<AutofillEntry>* entries));
  MOCK_METHOD3(GetAutofillTimestamps,
               bool(const string16& name,
                    const string16& value,
                    std::vector<base::Time>* timestamps));
  MOCK_METHOD1(UpdateAutofillEntries,
               bool(const std::vector<AutofillEntry>& entries));
};

class ProfileMock : public TestingProfile {
 public:
  MOCK_METHOD1(GetWebDataService, WebDataService*(ServiceAccessType access));
};

class DBThreadNotificationService :
    public base::RefCountedThreadSafe<DBThreadNotificationService> {
 public:
  DBThreadNotificationService() : done_event_(false, false) {}

  void Init() {
    DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
    ChromeThread::PostTask(
        ChromeThread::DB,
        FROM_HERE,
        NewRunnableMethod(this, &DBThreadNotificationService::InitTask));
    done_event_.Wait();
  }

  void TearDown() {
    DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
    ChromeThread::PostTask(
        ChromeThread::DB,
        FROM_HERE,
        NewRunnableMethod(this, &DBThreadNotificationService::TearDownTask));
    done_event_.Wait();
  }

 private:
  friend class base::RefCountedThreadSafe<DBThreadNotificationService>;

  void InitTask() {
    service_.reset(new NotificationService());
    done_event_.Signal();
  }

  void TearDownTask() {
    service_.reset(NULL);
    done_event_.Signal();
  }

  WaitableEvent done_event_;
  scoped_ptr<NotificationService> service_;
};

class WebDataServiceFake : public WebDataService {
 public:
  virtual bool IsDatabaseLoaded() {
    return true;
  }

  // Note that we inject the WebDatabase through the
  // ProfileSyncFactory mock.
  virtual WebDatabase* GetDatabase() {
    return NULL;
  }
};

ACTION(QuitUIMessageLoop) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
  MessageLoop::current()->Quit();
}

ACTION_P3(MakeAutofillSyncComponents, service, wd, dtc) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB));
  AutofillModelAssociator* model_associator =
      new TestAutofillModelAssociator(service, wd, dtc);
  AutofillChangeProcessor* change_processor =
      new AutofillChangeProcessor(model_associator, wd, service);
  return ProfileSyncFactory::SyncComponents(model_associator, change_processor);
}

class ProfileSyncServiceAutofillTest : public testing::Test {
 protected:
  ProfileSyncServiceAutofillTest()
      : ui_thread_(ChromeThread::UI, &message_loop_),
        db_thread_(ChromeThread::DB),
        done_event_(false, false) {
  }

  virtual void SetUp() {
    web_data_service_ = new WebDataServiceFake();
    db_thread_.Start();

    notification_service_ = new DBThreadNotificationService();
    notification_service_->Init();
  }

  virtual void TearDown() {
    service_.reset();
    notification_service_->TearDown();
    db_thread_.Stop();
    MessageLoop::current()->RunAllPending();
  }

  void StartSyncService() {
    if (!service_.get()) {
      service_.reset(new TestProfileSyncService(&factory_, &profile_, false));
      service_->AddObserver(&observer_);
      AutofillDataTypeController* data_type_controller =
          new AutofillDataTypeController(&factory_,
                                         &profile_,
                                         service_.get());

      EXPECT_CALL(factory_, CreateAutofillSyncComponents(_, _, _)).
          WillOnce(MakeAutofillSyncComponents(service_.get(),
                                              &web_database_,
                                              data_type_controller));
      EXPECT_CALL(factory_, CreateDataTypeManager(_)).
          WillOnce(MakeDataTypeManager());

      EXPECT_CALL(profile_, GetWebDataService(_)).
          WillOnce(Return(web_data_service_.get()));

      // State changes once for the backend init and once for startup done.
      EXPECT_CALL(observer_, OnStateChanged()).
          WillOnce(DoDefault()).
          WillOnce(QuitUIMessageLoop());
      service_->RegisterDataTypeController(data_type_controller);
      service_->Initialize();
      MessageLoop::current()->Run();
    }
  }

  void GetAutofillEntriesFromSyncDB(std::vector<AutofillEntry>* entries) {
    sync_api::ReadTransaction trans(service_->backend()->GetUserShareHandle());
    int64 autofill_root_id =
        GetFakeServerTaggedNode(&trans, "google_chrome_autofill");
    if (autofill_root_id == sync_api::kInvalidId)
      return;

    sync_api::ReadNode autofill_root(&trans);
    if (!autofill_root.InitByIdLookup(autofill_root_id))
      return;

    int64 child_id = autofill_root.GetFirstChildId();
    while (child_id != sync_api::kInvalidId) {
      sync_api::ReadNode child_node(&trans);
      if (!child_node.InitByIdLookup(child_id))
        return;

      const sync_pb::AutofillSpecifics& autofill(
          child_node.GetAutofillSpecifics());
      AutofillKey key(UTF8ToUTF16(autofill.name()),
                      UTF8ToUTF16(autofill.value()));
      std::vector<base::Time> timestamps;
      int timestamps_count = autofill.usage_timestamp_size();
      for (int i = 0; i < timestamps_count; ++i) {
        timestamps.push_back(Time::FromInternalValue(
            autofill.usage_timestamp(i)));
      }
      entries->push_back(AutofillEntry(key, timestamps));
      child_id = child_node.GetSuccessorId();
    }
  }

  int64 GetFakeServerTaggedNode(sync_api::ReadTransaction* trans,
                                const std::string& tag) {
    std::wstring tag_wide;
    if (!UTF8ToWide(tag.c_str(), tag.length(), &tag_wide))
      return sync_api::kInvalidId;

    sync_api::ReadNode root(trans);
    root.InitByRootLookup();

    int64 last_child_id = sync_api::kInvalidId;
    for (int64 id = root.GetFirstChildId(); id != sync_api::kInvalidId; /***/) {
      sync_api::ReadNode child(trans);
      child.InitByIdLookup(id);
      last_child_id = id;
      if (tag_wide == child.GetTitle()) {
        return id;
      }
      id = child.GetSuccessorId();
    }

    return sync_api::kInvalidId;
  }

  void SetIdleChangeProcessorExpectations() {
    EXPECT_CALL(web_database_, RemoveFormElement(_, _)).Times(0);
    EXPECT_CALL(web_database_, GetAutofillTimestamps(_, _, _)).Times(0);
    EXPECT_CALL(web_database_, UpdateAutofillEntries(_)).Times(0);
  }

  static AutofillEntry MakeAutofillEntry(const char* name,
                                         const char* value,
                                         time_t timestamp) {
    std::vector<Time> timestamps;
    timestamps.push_back(Time::FromTimeT(timestamp));
    return AutofillEntry(
        AutofillKey(ASCIIToUTF16(name), ASCIIToUTF16(value)), timestamps);
  }

  MessageLoopForUI message_loop_;
  ChromeThread ui_thread_;
  ChromeThread db_thread_;
  WaitableEvent done_event_;
  scoped_refptr<DBThreadNotificationService> notification_service_;

  scoped_ptr<TestProfileSyncService> service_;
  ProfileMock profile_;
  ProfileSyncFactoryMock factory_;
  ProfileSyncServiceObserverMock observer_;
  WebDatabaseMock web_database_;
  scoped_refptr<WebDataService> web_data_service_;
};

// TODO(sync): Test unrecoverable error during MA.

TEST_F(ProfileSyncServiceAutofillTest, EmptyNativeEmptySync) {
  EXPECT_CALL(web_database_, GetAllAutofillEntries(_)).WillOnce(Return(true));
  SetIdleChangeProcessorExpectations();
  StartSyncService();
  std::vector<AutofillEntry> sync_entries;
  GetAutofillEntriesFromSyncDB(&sync_entries);
  EXPECT_EQ(0U, sync_entries.size());
}

TEST_F(ProfileSyncServiceAutofillTest, HasNativeEmptySync) {
  std::vector<AutofillEntry> entries;
  entries.push_back(MakeAutofillEntry("foo", "bar", 1));
  EXPECT_CALL(web_database_, GetAllAutofillEntries(_)).
      WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
  SetIdleChangeProcessorExpectations();
  StartSyncService();
  std::vector<AutofillEntry> sync_entries;
  GetAutofillEntriesFromSyncDB(&sync_entries);
  ASSERT_EQ(1U, entries.size());
  EXPECT_TRUE(entries[0] == sync_entries[0]);
}

TEST_F(ProfileSyncServiceAutofillTest, HasNativeWithDuplicatesEmptySync) {
  // There is buggy autofill code that allows duplicate name/value
  // pairs to exist in the database with separate pair_ids.
  std::vector<AutofillEntry> entries;
  entries.push_back(MakeAutofillEntry("foo", "bar", 1));
  entries.push_back(MakeAutofillEntry("dup", "", 2));
  entries.push_back(MakeAutofillEntry("dup", "", 3));
  EXPECT_CALL(web_database_, GetAllAutofillEntries(_)).
      WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
  SetIdleChangeProcessorExpectations();
  StartSyncService();
  std::vector<AutofillEntry> sync_entries;
  GetAutofillEntriesFromSyncDB(&sync_entries);
  EXPECT_EQ(2U, sync_entries.size());
}
<commit_msg>Disable ProfileSyncServiceAutofillTest since they're causing hangs.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <vector>

#include "testing/gtest/include/gtest/gtest.h"

#include "base/ref_counted.h"
#include "base/string16.h"
#include "base/time.h"
#include "base/waitable_event.h"
#include "chrome/browser/sync/engine/syncapi.h"
#include "chrome/browser/sync/glue/autofill_change_processor.h"
#include "chrome/browser/sync/glue/autofill_data_type_controller.h"
#include "chrome/browser/sync/glue/autofill_model_associator.h"
#include "chrome/browser/sync/glue/sync_backend_host.h"
#include "chrome/browser/sync/profile_sync_factory.h"
#include "chrome/browser/sync/profile_sync_factory_mock.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/profile_sync_test_util.h"
#include "chrome/browser/sync/protocol/autofill_specifics.pb.h"
#include "chrome/browser/sync/test_profile_sync_service.h"
#include "chrome/browser/webdata/autofill_entry.h"
#include "chrome/browser/webdata/web_database.h"
#include "chrome/common/notification_service.h"
#include "chrome/test/testing_profile.h"
#include "testing/gmock/include/gmock/gmock.h"

using base::Time;
using base::WaitableEvent;
using browser_sync::AutofillChangeProcessor;
using browser_sync::AutofillDataTypeController;
using browser_sync::AutofillModelAssociator;
using browser_sync::SyncBackendHost;
using browser_sync::UnrecoverableErrorHandler;
using sync_api::SyncManager;
using testing::_;
using testing::DoAll;
using testing::DoDefault;
using testing::Return;
using testing::SetArgumentPointee;

class TestAutofillModelAssociator
    : public TestModelAssociator<AutofillModelAssociator> {
 public:
  TestAutofillModelAssociator(ProfileSyncService* service,
                              WebDatabase* web_database,
                              UnrecoverableErrorHandler* error_handler)
      : TestModelAssociator<AutofillModelAssociator>(
          service, web_database, error_handler) {
  }
};

class WebDatabaseMock : public WebDatabase {
 public:
  MOCK_METHOD2(RemoveFormElement,
               bool(const string16& name, const string16& value));
  MOCK_METHOD1(GetAllAutofillEntries,
               bool(std::vector<AutofillEntry>* entries));
  MOCK_METHOD3(GetAutofillTimestamps,
               bool(const string16& name,
                    const string16& value,
                    std::vector<base::Time>* timestamps));
  MOCK_METHOD1(UpdateAutofillEntries,
               bool(const std::vector<AutofillEntry>& entries));
};

class ProfileMock : public TestingProfile {
 public:
  MOCK_METHOD1(GetWebDataService, WebDataService*(ServiceAccessType access));
};

class DBThreadNotificationService :
    public base::RefCountedThreadSafe<DBThreadNotificationService> {
 public:
  DBThreadNotificationService() : done_event_(false, false) {}

  void Init() {
    DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
    ChromeThread::PostTask(
        ChromeThread::DB,
        FROM_HERE,
        NewRunnableMethod(this, &DBThreadNotificationService::InitTask));
    done_event_.Wait();
  }

  void TearDown() {
    DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
    ChromeThread::PostTask(
        ChromeThread::DB,
        FROM_HERE,
        NewRunnableMethod(this, &DBThreadNotificationService::TearDownTask));
    done_event_.Wait();
  }

 private:
  friend class base::RefCountedThreadSafe<DBThreadNotificationService>;

  void InitTask() {
    service_.reset(new NotificationService());
    done_event_.Signal();
  }

  void TearDownTask() {
    service_.reset(NULL);
    done_event_.Signal();
  }

  WaitableEvent done_event_;
  scoped_ptr<NotificationService> service_;
};

class WebDataServiceFake : public WebDataService {
 public:
  virtual bool IsDatabaseLoaded() {
    return true;
  }

  // Note that we inject the WebDatabase through the
  // ProfileSyncFactory mock.
  virtual WebDatabase* GetDatabase() {
    return NULL;
  }
};

ACTION(QuitUIMessageLoop) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
  MessageLoop::current()->Quit();
}

ACTION_P3(MakeAutofillSyncComponents, service, wd, dtc) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB));
  AutofillModelAssociator* model_associator =
      new TestAutofillModelAssociator(service, wd, dtc);
  AutofillChangeProcessor* change_processor =
      new AutofillChangeProcessor(model_associator, wd, service);
  return ProfileSyncFactory::SyncComponents(model_associator, change_processor);
}

class ProfileSyncServiceAutofillTest : public testing::Test {
 protected:
  ProfileSyncServiceAutofillTest()
      : ui_thread_(ChromeThread::UI, &message_loop_),
        db_thread_(ChromeThread::DB),
        done_event_(false, false) {
  }

  virtual void SetUp() {
    web_data_service_ = new WebDataServiceFake();
    db_thread_.Start();

    notification_service_ = new DBThreadNotificationService();
    notification_service_->Init();
  }

  virtual void TearDown() {
    service_.reset();
    notification_service_->TearDown();
    db_thread_.Stop();
    MessageLoop::current()->RunAllPending();
  }

  void StartSyncService() {
    if (!service_.get()) {
      service_.reset(new TestProfileSyncService(&factory_, &profile_, false));
      service_->AddObserver(&observer_);
      AutofillDataTypeController* data_type_controller =
          new AutofillDataTypeController(&factory_,
                                         &profile_,
                                         service_.get());

      EXPECT_CALL(factory_, CreateAutofillSyncComponents(_, _, _)).
          WillOnce(MakeAutofillSyncComponents(service_.get(),
                                              &web_database_,
                                              data_type_controller));
      EXPECT_CALL(factory_, CreateDataTypeManager(_)).
          WillOnce(MakeDataTypeManager());

      EXPECT_CALL(profile_, GetWebDataService(_)).
          WillOnce(Return(web_data_service_.get()));

      // State changes once for the backend init and once for startup done.
      EXPECT_CALL(observer_, OnStateChanged()).
          WillOnce(DoDefault()).
          WillOnce(QuitUIMessageLoop());
      service_->RegisterDataTypeController(data_type_controller);
      service_->Initialize();
      MessageLoop::current()->Run();
    }
  }

  void GetAutofillEntriesFromSyncDB(std::vector<AutofillEntry>* entries) {
    sync_api::ReadTransaction trans(service_->backend()->GetUserShareHandle());
    int64 autofill_root_id =
        GetFakeServerTaggedNode(&trans, "google_chrome_autofill");
    if (autofill_root_id == sync_api::kInvalidId)
      return;

    sync_api::ReadNode autofill_root(&trans);
    if (!autofill_root.InitByIdLookup(autofill_root_id))
      return;

    int64 child_id = autofill_root.GetFirstChildId();
    while (child_id != sync_api::kInvalidId) {
      sync_api::ReadNode child_node(&trans);
      if (!child_node.InitByIdLookup(child_id))
        return;

      const sync_pb::AutofillSpecifics& autofill(
          child_node.GetAutofillSpecifics());
      AutofillKey key(UTF8ToUTF16(autofill.name()),
                      UTF8ToUTF16(autofill.value()));
      std::vector<base::Time> timestamps;
      int timestamps_count = autofill.usage_timestamp_size();
      for (int i = 0; i < timestamps_count; ++i) {
        timestamps.push_back(Time::FromInternalValue(
            autofill.usage_timestamp(i)));
      }
      entries->push_back(AutofillEntry(key, timestamps));
      child_id = child_node.GetSuccessorId();
    }
  }

  int64 GetFakeServerTaggedNode(sync_api::ReadTransaction* trans,
                                const std::string& tag) {
    std::wstring tag_wide;
    if (!UTF8ToWide(tag.c_str(), tag.length(), &tag_wide))
      return sync_api::kInvalidId;

    sync_api::ReadNode root(trans);
    root.InitByRootLookup();

    int64 last_child_id = sync_api::kInvalidId;
    for (int64 id = root.GetFirstChildId(); id != sync_api::kInvalidId; /***/) {
      sync_api::ReadNode child(trans);
      child.InitByIdLookup(id);
      last_child_id = id;
      if (tag_wide == child.GetTitle()) {
        return id;
      }
      id = child.GetSuccessorId();
    }

    return sync_api::kInvalidId;
  }

  void SetIdleChangeProcessorExpectations() {
    EXPECT_CALL(web_database_, RemoveFormElement(_, _)).Times(0);
    EXPECT_CALL(web_database_, GetAutofillTimestamps(_, _, _)).Times(0);
    EXPECT_CALL(web_database_, UpdateAutofillEntries(_)).Times(0);
  }

  static AutofillEntry MakeAutofillEntry(const char* name,
                                         const char* value,
                                         time_t timestamp) {
    std::vector<Time> timestamps;
    timestamps.push_back(Time::FromTimeT(timestamp));
    return AutofillEntry(
        AutofillKey(ASCIIToUTF16(name), ASCIIToUTF16(value)), timestamps);
  }

  MessageLoopForUI message_loop_;
  ChromeThread ui_thread_;
  ChromeThread db_thread_;
  WaitableEvent done_event_;
  scoped_refptr<DBThreadNotificationService> notification_service_;

  scoped_ptr<TestProfileSyncService> service_;
  ProfileMock profile_;
  ProfileSyncFactoryMock factory_;
  ProfileSyncServiceObserverMock observer_;
  WebDatabaseMock web_database_;
  scoped_refptr<WebDataService> web_data_service_;
};

// TODO(sync): Test unrecoverable error during MA.

// http://code.google.com/p/chromium/issues/detail?id=37244
TEST_F(ProfileSyncServiceAutofillTest, DISABLED_EmptyNativeEmptySync) {
  EXPECT_CALL(web_database_, GetAllAutofillEntries(_)).WillOnce(Return(true));
  SetIdleChangeProcessorExpectations();
  StartSyncService();
  std::vector<AutofillEntry> sync_entries;
  GetAutofillEntriesFromSyncDB(&sync_entries);
  EXPECT_EQ(0U, sync_entries.size());
}

// http://code.google.com/p/chromium/issues/detail?id=37244
TEST_F(ProfileSyncServiceAutofillTest, DISABLED_HasNativeEmptySync) {
  std::vector<AutofillEntry> entries;
  entries.push_back(MakeAutofillEntry("foo", "bar", 1));
  EXPECT_CALL(web_database_, GetAllAutofillEntries(_)).
      WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
  SetIdleChangeProcessorExpectations();
  StartSyncService();
  std::vector<AutofillEntry> sync_entries;
  GetAutofillEntriesFromSyncDB(&sync_entries);
  ASSERT_EQ(1U, entries.size());
  EXPECT_TRUE(entries[0] == sync_entries[0]);
}

// http://code.google.com/p/chromium/issues/detail?id=37244
TEST_F(ProfileSyncServiceAutofillTest, DISABLED_HasNativeWithDuplicatesEmptySync) {
  // There is buggy autofill code that allows duplicate name/value
  // pairs to exist in the database with separate pair_ids.
  std::vector<AutofillEntry> entries;
  entries.push_back(MakeAutofillEntry("foo", "bar", 1));
  entries.push_back(MakeAutofillEntry("dup", "", 2));
  entries.push_back(MakeAutofillEntry("dup", "", 3));
  EXPECT_CALL(web_database_, GetAllAutofillEntries(_)).
      WillOnce(DoAll(SetArgumentPointee<0>(entries), Return(true)));
  SetIdleChangeProcessorExpectations();
  StartSyncService();
  std::vector<AutofillEntry> sync_entries;
  GetAutofillEntriesFromSyncDB(&sync_entries);
  EXPECT_EQ(2U, sync_entries.size());
}
<|endoftext|>


<commit_before><commit_msg>Initializing the struct before using it, as mandated by our Coverity overlord.<commit_after><|endoftext|>