<commit_before>// Copyright (c) 2009 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/gtk/bookmark_editor_gtk.h"

#include <gtk/gtk.h>

#include "app/l10n_util.h"
#include "base/basictypes.h"
#include "base/gfx/gtk_util.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "chrome/browser/gtk/bookmark_tree_model.h"
#include "chrome/browser/gtk/bookmark_utils_gtk.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/common/gtk_util.h"
#include "googleurl/src/gurl.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"

namespace {

// Background color of text field when URL is invalid.
const GdkColor kErrorColor = GDK_COLOR_RGB(0xFF, 0xBC, 0xBC);

// Preferred initial dimensions, in pixels, of the folder tree.
static const int kTreeWidth = 300;
static const int kTreeHeight = 150;

}  // namespace

// static
void BookmarkEditor::Show(gfx::NativeView parent_hwnd,
                          Profile* profile,
                          const BookmarkNode* parent,
                          const BookmarkNode* node,
                          Configuration configuration,
                          Handler* handler) {
  DCHECK(profile);
  BookmarkEditorGtk* editor =
      new BookmarkEditorGtk(GTK_WINDOW(gtk_widget_get_toplevel(parent_hwnd)),
                            profile, parent, node, configuration, handler);
  editor->Show();
}

BookmarkEditorGtk::BookmarkEditorGtk(
    GtkWindow* window,
    Profile* profile,
    const BookmarkNode* parent,
    const BookmarkNode* node,
    BookmarkEditor::Configuration configuration,
    BookmarkEditor::Handler* handler)
    : profile_(profile),
      dialog_(NULL),
      parent_(parent),
      node_(node),
      running_menu_for_root_(false),
      show_tree_(configuration == SHOW_TREE),
      handler_(handler) {
  DCHECK(profile);
  Init(window);
}

BookmarkEditorGtk::~BookmarkEditorGtk() {
  // The tree model is deleted before the view. Reset the model otherwise the
  // tree will reference a deleted model.

  bb_model_->RemoveObserver(this);
}

void BookmarkEditorGtk::Init(GtkWindow* parent_window) {
  bb_model_ = profile_->GetBookmarkModel();
  DCHECK(bb_model_);
  bb_model_->AddObserver(this);

  dialog_ = gtk_dialog_new_with_buttons(
      l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_TITLE).c_str(),
      parent_window,
      GTK_DIALOG_MODAL,
      GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
      GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
      NULL);
  gtk_dialog_set_has_separator(GTK_DIALOG(dialog_), FALSE);

  if (show_tree_) {
    GtkWidget* action_area = GTK_DIALOG(dialog_)->action_area;
    GtkWidget* new_folder_button = gtk_button_new_with_label(
        l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_NEW_FOLDER_BUTTON).c_str());
    g_signal_connect(new_folder_button, "clicked",
                     G_CALLBACK(OnNewFolderClicked), this);
    gtk_container_add(GTK_CONTAINER(action_area), new_folder_button);
    gtk_button_box_set_child_secondary(GTK_BUTTON_BOX(action_area),
                                       new_folder_button, TRUE);
  }

  gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_ACCEPT);

  // The GTK dialog content area layout (overview)
  //
  // +- GtkVBox |vbox| ----------------------------------------------+
  // |+- GtkTable |table| ------------------------------------------+|
  // ||+- GtkLabel ------+ +- GtkEntry |name_entry_| --------------+||
  // |||                 | |                                       |||
  // ||+-----------------+ +---------------------------------------+||
  // ||+- GtkLabel ------+ +- GtkEntry |url_entry_| ---------------+||
  // |||                 | |                                       |||
  // ||+-----------------+ +---------------------------------------+||
  // |+-------------------------------------------------------------+|
  // |+- GtkScrollWindow |scroll_window| ---------------------------+|
  // ||+- GtkTreeView |tree_view_| --------------------------------+||
  // |||+- GtkTreeViewColumn |name_column| -----------------------+|||
  // ||||                                                         ||||
  // ||||                                                         ||||
  // ||||                                                         ||||
  // ||||                                                         ||||
  // |||+---------------------------------------------------------+|||
  // ||+-----------------------------------------------------------+||
  // |+-------------------------------------------------------------+|
  // +---------------------------------------------------------------+
  GtkWidget* content_area = GTK_DIALOG(dialog_)->vbox;
  gtk_box_set_spacing(GTK_BOX(content_area), gtk_util::kContentAreaSpacing);

  GtkWidget* vbox = gtk_vbox_new(FALSE, 12);

  name_entry_ = gtk_entry_new();
  gtk_entry_set_text(GTK_ENTRY(name_entry_),
                     node_ ? WideToUTF8(node_->GetTitle()).c_str() : "");
  g_signal_connect(G_OBJECT(name_entry_), "changed",
                   G_CALLBACK(OnEntryChanged), this);
  gtk_entry_set_activates_default(GTK_ENTRY(name_entry_), TRUE);

  url_entry_ = gtk_entry_new();
  gtk_entry_set_text(GTK_ENTRY(url_entry_),
                     node_ ? node_->GetURL().spec().c_str() : "");
  g_signal_connect(G_OBJECT(url_entry_), "changed",
                   G_CALLBACK(OnEntryChanged), this);
  gtk_entry_set_activates_default(GTK_ENTRY(url_entry_), TRUE);

  GtkWidget* table = gtk_util::CreateLabeledControlsGroup(NULL,
      l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_NAME_LABEL).c_str(),
      name_entry_,
      l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_URL_LABEL).c_str(),
      url_entry_,
      NULL);

  gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);

  if (show_tree_) {
    GtkTreeIter selected_iter;
    int64 selected_id = node_ ? node_->GetParent()->id() : 0;
    tree_store_ = bookmark_utils::MakeFolderTreeStore();
    bookmark_utils::AddToTreeStore(bb_model_, selected_id,
                                   tree_store_, &selected_iter);

    GtkTreeViewColumn* icon_column =
        gtk_tree_view_column_new_with_attributes(
            "", gtk_cell_renderer_pixbuf_new(), "pixbuf",
             bookmark_utils::FOLDER_ICON, NULL);
    GtkTreeViewColumn* name_column =
        gtk_tree_view_column_new_with_attributes(
            "", gtk_cell_renderer_text_new(), "text",
             bookmark_utils::FOLDER_NAME, NULL);

    tree_view_ = gtk_tree_view_new_with_model(GTK_TREE_MODEL(tree_store_));
    // Let |tree_view| own the store.
    g_object_unref(tree_store_);
    gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view_), FALSE);
    gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view_), icon_column);
    gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view_), name_column);
    gtk_widget_set_size_request(tree_view_, kTreeWidth, kTreeHeight);

    tree_selection_ = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view_));

    GtkTreePath* path = NULL;
    if (selected_id) {
      path = gtk_tree_model_get_path(GTK_TREE_MODEL(tree_store_),
                                     &selected_iter);
    } else {
      // We don't have a selected parent (Probably because we're making a new
      // bookmark). Select the first item in the list.
      path = gtk_tree_path_new_from_string("0");
    }

    gtk_tree_view_expand_to_path(GTK_TREE_VIEW(tree_view_), path);
    gtk_tree_selection_select_path(tree_selection_, path);
    gtk_tree_path_free(path);

    GtkWidget* scroll_window = gtk_scrolled_window_new(NULL, NULL);
    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_window),
                                    GTK_POLICY_NEVER,
                                   GTK_POLICY_AUTOMATIC);
    gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll_window),
                                        GTK_SHADOW_ETCHED_IN);
    gtk_container_add(GTK_CONTAINER(scroll_window), tree_view_);

    gtk_box_pack_start(GTK_BOX(vbox), scroll_window, TRUE, TRUE, 0);
  }

  gtk_box_pack_start(GTK_BOX(content_area), vbox, TRUE, TRUE, 0);

  g_signal_connect(dialog_, "response",
                   G_CALLBACK(OnResponse), this);
  g_signal_connect(dialog_, "delete-event",
                   G_CALLBACK(OnWindowDeleteEvent), this);
  g_signal_connect(dialog_, "destroy",
                   G_CALLBACK(OnWindowDestroy), this);
}

void BookmarkEditorGtk::Show() {
  // Manually call our OnEntryChanged handler to set the initial state.
  OnEntryChanged(NULL, this);

  gtk_widget_show_all(dialog_);
}

void BookmarkEditorGtk::Close() {
  // Under the model that we've inherited from Windows, dialogs can receive
  // more than one Close() call inside the current message loop event.
  if (dialog_) {
    gtk_widget_destroy(dialog_);
    dialog_ = NULL;
  }
}

void BookmarkEditorGtk::BookmarkNodeMoved(BookmarkModel* model,
                                          const BookmarkNode* old_parent,
                                          int old_index,
                                          const BookmarkNode* new_parent,
                                          int new_index) {
  Reset();
}

void BookmarkEditorGtk::BookmarkNodeAdded(BookmarkModel* model,
                                          const BookmarkNode* parent,
                                          int index) {
  Reset();
}

void BookmarkEditorGtk::BookmarkNodeRemoved(BookmarkModel* model,
                                            const BookmarkNode* parent,
                                            int index,
                                            const BookmarkNode* node) {
  if ((node_ && node_->HasAncestor(node)) ||
      (parent_ && parent_->HasAncestor(node))) {
    // The node, or its parent was removed. Close the dialog.
    Close();
  } else {
    Reset();
  }
}

void BookmarkEditorGtk::BookmarkNodeChildrenReordered(
    BookmarkModel* model, const BookmarkNode* node) {
  Reset();
}

void BookmarkEditorGtk::Reset() {
  // TODO(erg): The windows implementation tries to be smart. For now, just
  // close the window.
  Close();
}

GURL BookmarkEditorGtk::GetInputURL() const {
  std::wstring input = URLFixerUpper::FixupURL(
      UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(url_entry_))), L"");
  return GURL(WideToUTF8(input));
}

std::wstring BookmarkEditorGtk::GetInputTitle() const {
  return UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(name_entry_)));
}

void BookmarkEditorGtk::ApplyEdits() {
  DCHECK(bb_model_->IsLoaded());

  GtkTreeIter currently_selected_iter;
  if (show_tree_) {
    if (!gtk_tree_selection_get_selected(tree_selection_, NULL,
                                         &currently_selected_iter)) {
      NOTREACHED() << "Something should always be selected";
      return;
    }
  }

  ApplyEdits(&currently_selected_iter);
}

void BookmarkEditorGtk::ApplyEdits(GtkTreeIter* selected_parent) {
  // We're going to apply edits to the bookmark bar model, which will call us
  // back. Normally when a structural edit occurs we reset the tree model.
  // We don't want to do that here, so we remove ourselves as an observer.
  bb_model_->RemoveObserver(this);

  GURL new_url(GetInputURL());
  std::wstring new_title(GetInputTitle());

  if (!show_tree_) {
    bookmark_utils::ApplyEditsWithNoGroupChange(
        bb_model_, parent_, node_, new_title, new_url, handler_.get());
    return;
  }

  // Create the new groups and update the titles.
  const BookmarkNode* new_parent =
      bookmark_utils::CommitTreeStoreDifferencesBetween(
      bb_model_, tree_store_, selected_parent);

  if (!new_parent) {
    // Bookmarks must be parented.
    NOTREACHED();
    return;
  }

  bookmark_utils::ApplyEditsWithPossibleGroupChange(
      bb_model_, new_parent, node_, new_title, new_url, handler_.get());
}

void BookmarkEditorGtk::AddNewGroup(GtkTreeIter* parent, GtkTreeIter* child) {
  gtk_tree_store_append(tree_store_, child, parent);
  gtk_tree_store_set(
      tree_store_, child,
      bookmark_utils::FOLDER_ICON,
      bookmark_utils::GetFolderIcon(),
      bookmark_utils::FOLDER_NAME,
      l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME).c_str(),
      bookmark_utils::ITEM_ID, static_cast<int64>(0),
      -1);
}

// static
void BookmarkEditorGtk::OnResponse(GtkDialog* dialog, int response_id,
                                   BookmarkEditorGtk* window) {
  if (response_id == GTK_RESPONSE_ACCEPT) {
    window->ApplyEdits();
  }

  window->Close();
}

// static
gboolean BookmarkEditorGtk::OnWindowDeleteEvent(
    GtkWidget* widget,
    GdkEvent* event,
    BookmarkEditorGtk* dialog) {
  dialog->Close();

  // Return true to prevent the gtk dialog from being destroyed. Close will
  // destroy it for us and the default gtk_dialog_delete_event_handler() will
  // force the destruction without us being able to stop it.
  return TRUE;
}

// static
void BookmarkEditorGtk::OnWindowDestroy(GtkWidget* widget,
                                        BookmarkEditorGtk* dialog) {
  MessageLoop::current()->DeleteSoon(FROM_HERE, dialog);
}

// static
void BookmarkEditorGtk::OnEntryChanged(GtkEditable* entry,
                                       BookmarkEditorGtk* dialog) {
  const GURL url(dialog->GetInputURL());
  if (!url.is_valid()) {
    gtk_widget_modify_base(dialog->url_entry_, GTK_STATE_NORMAL, &kErrorColor);
    gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog->dialog_),
                                      GTK_RESPONSE_ACCEPT, FALSE);
  } else {
    gtk_widget_modify_base(dialog->url_entry_, GTK_STATE_NORMAL, NULL);
    gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog->dialog_),
                                      GTK_RESPONSE_ACCEPT, TRUE);
  }
}

// static
void BookmarkEditorGtk::OnNewFolderClicked(GtkWidget* button,
                                           BookmarkEditorGtk* dialog) {
  // TODO(erg): Make the inserted item here editable and edit it. If that's
  // impossible (it's probably possible), fall back on the folder editor.
  GtkTreeIter iter;
  if (!gtk_tree_selection_get_selected(dialog->tree_selection_,
                                       NULL,
                                       &iter)) {
    NOTREACHED() << "Something should always be selected";
    return;
  }

  GtkTreeIter new_item_iter;
  dialog->AddNewGroup(&iter, &new_item_iter);

  GtkTreePath* path = gtk_tree_model_get_path(
      GTK_TREE_MODEL(dialog->tree_store_), &new_item_iter);
  gtk_tree_view_expand_to_path(GTK_TREE_VIEW(dialog->tree_view_), path);
  gtk_tree_selection_select_path(dialog->tree_selection_, path);
  gtk_tree_path_free(path);
}
<commit_msg>Select correct default folder in bookmark editor gtk.<commit_after>// Copyright (c) 2009 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/gtk/bookmark_editor_gtk.h"

#include <gtk/gtk.h>

#include "app/l10n_util.h"
#include "base/basictypes.h"
#include "base/gfx/gtk_util.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "chrome/browser/gtk/bookmark_tree_model.h"
#include "chrome/browser/gtk/bookmark_utils_gtk.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/common/gtk_util.h"
#include "googleurl/src/gurl.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"

namespace {

// Background color of text field when URL is invalid.
const GdkColor kErrorColor = GDK_COLOR_RGB(0xFF, 0xBC, 0xBC);

// Preferred initial dimensions, in pixels, of the folder tree.
static const int kTreeWidth = 300;
static const int kTreeHeight = 150;

}  // namespace

// static
void BookmarkEditor::Show(gfx::NativeView parent_hwnd,
                          Profile* profile,
                          const BookmarkNode* parent,
                          const BookmarkNode* node,
                          Configuration configuration,
                          Handler* handler) {
  DCHECK(profile);
  BookmarkEditorGtk* editor =
      new BookmarkEditorGtk(GTK_WINDOW(gtk_widget_get_toplevel(parent_hwnd)),
                            profile, parent, node, configuration, handler);
  editor->Show();
}

BookmarkEditorGtk::BookmarkEditorGtk(
    GtkWindow* window,
    Profile* profile,
    const BookmarkNode* parent,
    const BookmarkNode* node,
    BookmarkEditor::Configuration configuration,
    BookmarkEditor::Handler* handler)
    : profile_(profile),
      dialog_(NULL),
      parent_(parent),
      node_(node),
      running_menu_for_root_(false),
      show_tree_(configuration == SHOW_TREE),
      handler_(handler) {
  DCHECK(profile);
  Init(window);
}

BookmarkEditorGtk::~BookmarkEditorGtk() {
  // The tree model is deleted before the view. Reset the model otherwise the
  // tree will reference a deleted model.

  bb_model_->RemoveObserver(this);
}

void BookmarkEditorGtk::Init(GtkWindow* parent_window) {
  bb_model_ = profile_->GetBookmarkModel();
  DCHECK(bb_model_);
  bb_model_->AddObserver(this);

  dialog_ = gtk_dialog_new_with_buttons(
      l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_TITLE).c_str(),
      parent_window,
      GTK_DIALOG_MODAL,
      GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
      GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
      NULL);
  gtk_dialog_set_has_separator(GTK_DIALOG(dialog_), FALSE);

  if (show_tree_) {
    GtkWidget* action_area = GTK_DIALOG(dialog_)->action_area;
    GtkWidget* new_folder_button = gtk_button_new_with_label(
        l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_NEW_FOLDER_BUTTON).c_str());
    g_signal_connect(new_folder_button, "clicked",
                     G_CALLBACK(OnNewFolderClicked), this);
    gtk_container_add(GTK_CONTAINER(action_area), new_folder_button);
    gtk_button_box_set_child_secondary(GTK_BUTTON_BOX(action_area),
                                       new_folder_button, TRUE);
  }

  gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_ACCEPT);

  // The GTK dialog content area layout (overview)
  //
  // +- GtkVBox |vbox| ----------------------------------------------+
  // |+- GtkTable |table| ------------------------------------------+|
  // ||+- GtkLabel ------+ +- GtkEntry |name_entry_| --------------+||
  // |||                 | |                                       |||
  // ||+-----------------+ +---------------------------------------+||
  // ||+- GtkLabel ------+ +- GtkEntry |url_entry_| ---------------+||
  // |||                 | |                                       |||
  // ||+-----------------+ +---------------------------------------+||
  // |+-------------------------------------------------------------+|
  // |+- GtkScrollWindow |scroll_window| ---------------------------+|
  // ||+- GtkTreeView |tree_view_| --------------------------------+||
  // |||+- GtkTreeViewColumn |name_column| -----------------------+|||
  // ||||                                                         ||||
  // ||||                                                         ||||
  // ||||                                                         ||||
  // ||||                                                         ||||
  // |||+---------------------------------------------------------+|||
  // ||+-----------------------------------------------------------+||
  // |+-------------------------------------------------------------+|
  // +---------------------------------------------------------------+
  GtkWidget* content_area = GTK_DIALOG(dialog_)->vbox;
  gtk_box_set_spacing(GTK_BOX(content_area), gtk_util::kContentAreaSpacing);

  GtkWidget* vbox = gtk_vbox_new(FALSE, 12);

  name_entry_ = gtk_entry_new();
  gtk_entry_set_text(GTK_ENTRY(name_entry_),
                     node_ ? WideToUTF8(node_->GetTitle()).c_str() : "");
  g_signal_connect(G_OBJECT(name_entry_), "changed",
                   G_CALLBACK(OnEntryChanged), this);
  gtk_entry_set_activates_default(GTK_ENTRY(name_entry_), TRUE);

  url_entry_ = gtk_entry_new();
  gtk_entry_set_text(GTK_ENTRY(url_entry_),
                     node_ ? node_->GetURL().spec().c_str() : "");
  g_signal_connect(G_OBJECT(url_entry_), "changed",
                   G_CALLBACK(OnEntryChanged), this);
  gtk_entry_set_activates_default(GTK_ENTRY(url_entry_), TRUE);

  GtkWidget* table = gtk_util::CreateLabeledControlsGroup(NULL,
      l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_NAME_LABEL).c_str(),
      name_entry_,
      l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_URL_LABEL).c_str(),
      url_entry_,
      NULL);

  gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);

  if (show_tree_) {
    GtkTreeIter selected_iter;
    int64 selected_id = parent_ ? parent_->id() : 0;
    tree_store_ = bookmark_utils::MakeFolderTreeStore();
    bookmark_utils::AddToTreeStore(bb_model_, selected_id,
                                   tree_store_, &selected_iter);

    GtkTreeViewColumn* icon_column =
        gtk_tree_view_column_new_with_attributes(
            "", gtk_cell_renderer_pixbuf_new(), "pixbuf",
             bookmark_utils::FOLDER_ICON, NULL);
    GtkTreeViewColumn* name_column =
        gtk_tree_view_column_new_with_attributes(
            "", gtk_cell_renderer_text_new(), "text",
             bookmark_utils::FOLDER_NAME, NULL);

    tree_view_ = gtk_tree_view_new_with_model(GTK_TREE_MODEL(tree_store_));
    // Let |tree_view| own the store.
    g_object_unref(tree_store_);
    gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view_), FALSE);
    gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view_), icon_column);
    gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view_), name_column);
    gtk_widget_set_size_request(tree_view_, kTreeWidth, kTreeHeight);

    tree_selection_ = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view_));

    GtkTreePath* path = NULL;
    if (selected_id) {
      path = gtk_tree_model_get_path(GTK_TREE_MODEL(tree_store_),
                                     &selected_iter);
    } else {
      // We don't have a selected parent (Probably because we're making a new
      // bookmark). Select the first item in the list.
      path = gtk_tree_path_new_from_string("0");
    }

    gtk_tree_view_expand_to_path(GTK_TREE_VIEW(tree_view_), path);
    gtk_tree_selection_select_path(tree_selection_, path);
    gtk_tree_path_free(path);

    GtkWidget* scroll_window = gtk_scrolled_window_new(NULL, NULL);
    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_window),
                                    GTK_POLICY_NEVER,
                                   GTK_POLICY_AUTOMATIC);
    gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll_window),
                                        GTK_SHADOW_ETCHED_IN);
    gtk_container_add(GTK_CONTAINER(scroll_window), tree_view_);

    gtk_box_pack_start(GTK_BOX(vbox), scroll_window, TRUE, TRUE, 0);
  }

  gtk_box_pack_start(GTK_BOX(content_area), vbox, TRUE, TRUE, 0);

  g_signal_connect(dialog_, "response",
                   G_CALLBACK(OnResponse), this);
  g_signal_connect(dialog_, "delete-event",
                   G_CALLBACK(OnWindowDeleteEvent), this);
  g_signal_connect(dialog_, "destroy",
                   G_CALLBACK(OnWindowDestroy), this);
}

void BookmarkEditorGtk::Show() {
  // Manually call our OnEntryChanged handler to set the initial state.
  OnEntryChanged(NULL, this);

  gtk_widget_show_all(dialog_);
}

void BookmarkEditorGtk::Close() {
  // Under the model that we've inherited from Windows, dialogs can receive
  // more than one Close() call inside the current message loop event.
  if (dialog_) {
    gtk_widget_destroy(dialog_);
    dialog_ = NULL;
  }
}

void BookmarkEditorGtk::BookmarkNodeMoved(BookmarkModel* model,
                                          const BookmarkNode* old_parent,
                                          int old_index,
                                          const BookmarkNode* new_parent,
                                          int new_index) {
  Reset();
}

void BookmarkEditorGtk::BookmarkNodeAdded(BookmarkModel* model,
                                          const BookmarkNode* parent,
                                          int index) {
  Reset();
}

void BookmarkEditorGtk::BookmarkNodeRemoved(BookmarkModel* model,
                                            const BookmarkNode* parent,
                                            int index,
                                            const BookmarkNode* node) {
  if ((node_ && node_->HasAncestor(node)) ||
      (parent_ && parent_->HasAncestor(node))) {
    // The node, or its parent was removed. Close the dialog.
    Close();
  } else {
    Reset();
  }
}

void BookmarkEditorGtk::BookmarkNodeChildrenReordered(
    BookmarkModel* model, const BookmarkNode* node) {
  Reset();
}

void BookmarkEditorGtk::Reset() {
  // TODO(erg): The windows implementation tries to be smart. For now, just
  // close the window.
  Close();
}

GURL BookmarkEditorGtk::GetInputURL() const {
  std::wstring input = URLFixerUpper::FixupURL(
      UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(url_entry_))), L"");
  return GURL(WideToUTF8(input));
}

std::wstring BookmarkEditorGtk::GetInputTitle() const {
  return UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(name_entry_)));
}

void BookmarkEditorGtk::ApplyEdits() {
  DCHECK(bb_model_->IsLoaded());

  GtkTreeIter currently_selected_iter;
  if (show_tree_) {
    if (!gtk_tree_selection_get_selected(tree_selection_, NULL,
                                         &currently_selected_iter)) {
      NOTREACHED() << "Something should always be selected";
      return;
    }
  }

  ApplyEdits(&currently_selected_iter);
}

void BookmarkEditorGtk::ApplyEdits(GtkTreeIter* selected_parent) {
  // We're going to apply edits to the bookmark bar model, which will call us
  // back. Normally when a structural edit occurs we reset the tree model.
  // We don't want to do that here, so we remove ourselves as an observer.
  bb_model_->RemoveObserver(this);

  GURL new_url(GetInputURL());
  std::wstring new_title(GetInputTitle());

  if (!show_tree_) {
    bookmark_utils::ApplyEditsWithNoGroupChange(
        bb_model_, parent_, node_, new_title, new_url, handler_.get());
    return;
  }

  // Create the new groups and update the titles.
  const BookmarkNode* new_parent =
      bookmark_utils::CommitTreeStoreDifferencesBetween(
      bb_model_, tree_store_, selected_parent);

  if (!new_parent) {
    // Bookmarks must be parented.
    NOTREACHED();
    return;
  }

  bookmark_utils::ApplyEditsWithPossibleGroupChange(
      bb_model_, new_parent, node_, new_title, new_url, handler_.get());
}

void BookmarkEditorGtk::AddNewGroup(GtkTreeIter* parent, GtkTreeIter* child) {
  gtk_tree_store_append(tree_store_, child, parent);
  gtk_tree_store_set(
      tree_store_, child,
      bookmark_utils::FOLDER_ICON,
      bookmark_utils::GetFolderIcon(),
      bookmark_utils::FOLDER_NAME,
      l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME).c_str(),
      bookmark_utils::ITEM_ID, static_cast<int64>(0),
      -1);
}

// static
void BookmarkEditorGtk::OnResponse(GtkDialog* dialog, int response_id,
                                   BookmarkEditorGtk* window) {
  if (response_id == GTK_RESPONSE_ACCEPT) {
    window->ApplyEdits();
  }

  window->Close();
}

// static
gboolean BookmarkEditorGtk::OnWindowDeleteEvent(
    GtkWidget* widget,
    GdkEvent* event,
    BookmarkEditorGtk* dialog) {
  dialog->Close();

  // Return true to prevent the gtk dialog from being destroyed. Close will
  // destroy it for us and the default gtk_dialog_delete_event_handler() will
  // force the destruction without us being able to stop it.
  return TRUE;
}

// static
void BookmarkEditorGtk::OnWindowDestroy(GtkWidget* widget,
                                        BookmarkEditorGtk* dialog) {
  MessageLoop::current()->DeleteSoon(FROM_HERE, dialog);
}

// static
void BookmarkEditorGtk::OnEntryChanged(GtkEditable* entry,
                                       BookmarkEditorGtk* dialog) {
  const GURL url(dialog->GetInputURL());
  if (!url.is_valid()) {
    gtk_widget_modify_base(dialog->url_entry_, GTK_STATE_NORMAL, &kErrorColor);
    gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog->dialog_),
                                      GTK_RESPONSE_ACCEPT, FALSE);
  } else {
    gtk_widget_modify_base(dialog->url_entry_, GTK_STATE_NORMAL, NULL);
    gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog->dialog_),
                                      GTK_RESPONSE_ACCEPT, TRUE);
  }
}

// static
void BookmarkEditorGtk::OnNewFolderClicked(GtkWidget* button,
                                           BookmarkEditorGtk* dialog) {
  // TODO(erg): Make the inserted item here editable and edit it. If that's
  // impossible (it's probably possible), fall back on the folder editor.
  GtkTreeIter iter;
  if (!gtk_tree_selection_get_selected(dialog->tree_selection_,
                                       NULL,
                                       &iter)) {
    NOTREACHED() << "Something should always be selected";
    return;
  }

  GtkTreeIter new_item_iter;
  dialog->AddNewGroup(&iter, &new_item_iter);

  GtkTreePath* path = gtk_tree_model_get_path(
      GTK_TREE_MODEL(dialog->tree_store_), &new_item_iter);
  gtk_tree_view_expand_to_path(GTK_TREE_VIEW(dialog->tree_view_), path);
  gtk_tree_selection_select_path(dialog->tree_selection_, path);
  gtk_tree_path_free(path);
}
<|endoftext|>


<commit_before>#include <chrono>
#include <cstdint>
#include <iostream>
#include <memory>
#include <stdexcept>

#include "Eigen/Dense"

#include "falconn/lsh_nn_table.h"

using std::chrono::duration;
using std::chrono::duration_cast;
using std::chrono::high_resolution_clock;
using std::cerr;
using std::cout;
using std::endl;
using std::exception;
using std::fixed;
using std::scientific;
using std::unique_ptr;
using std::vector;

using falconn::construct_table;
using falconn::DenseVector;
using falconn::DistanceFunction;
using falconn::LSHConstructionParameters;
using falconn::LSHFamily;
using falconn::LSHNearestNeighborTable;
using falconn::QueryStatistics;
using falconn::StorageHashTable;

typedef falconn::DenseVector<float> Vec;

class Timer {
 public:
  Timer() {
    start_time = high_resolution_clock::now();
  }

  double elapsed_seconds() {
    auto end_time = high_resolution_clock::now();
    auto elapsed = duration_cast<duration<double>>(end_time - start_time);
    return elapsed.count();
  }

 private:
  decltype(high_resolution_clock::now()) start_time;
};

template<typename PointType>
void run_experiment(LSHNearestNeighborTable<PointType>* table,
                    const std::vector<PointType> queries,
                    const std::vector<int> true_nns,
                    double* avg_query_time,
                    double* success_probability) {
  double average_query_time_outside = 0.0;
  int num_correct = 0;

  for (int ii = 0; ii < static_cast<int>(queries.size()); ++ii) {
    Timer query_time;

    int32_t res = table->find_nearest_neighbor(queries[ii]);

    average_query_time_outside += query_time.elapsed_seconds();
    if (res == true_nns[ii]) {
      num_correct += 1;
    }
  }

  average_query_time_outside /= queries.size();
  *avg_query_time = average_query_time_outside;
  *success_probability = static_cast<double>(num_correct) / queries.size();
  cout << "Average query time (measured outside): "
       << scientific << average_query_time_outside << " seconds" << endl;
  cout << "Empirical success probability: " << fixed
       << *success_probability << endl << endl;
  cout << "Query statistics:" << endl;
  QueryStatistics stats = table->get_query_statistics();
  cout << "Average total query time: " << scientific
       << stats.average_total_query_time << " seconds" << endl;
  cout << "Average LSH time:         "
       << stats.average_lsh_time << " seconds" << endl;
  cout << "Average hash table time:  "
       << stats.average_hash_table_time << " seconds" << endl;
  cout << "Average distance time:    "
       << stats.average_distance_time << " seconds" << endl;
  cout << "Average number of candidates:        " << fixed
       << stats.average_num_candidates << endl;
  cout << "Average number of unique candidates: "
       << stats.average_num_unique_candidates << endl << endl;
  cout << "Diagnostics:" << endl;
  double mismatch = average_query_time_outside - stats.average_total_query_time;
  cout << "Outside - inside average total query time: " << scientific
       << mismatch << " seconds (" << fixed
       << 100.0 * mismatch / average_query_time_outside << " %)" << endl;
  double unaccounted = stats.average_total_query_time - stats.average_lsh_time
      - stats.average_hash_table_time - stats.average_distance_time;
  cout << "Unaccounted inside query time: " << scientific << unaccounted
       << " seconds (" << fixed
       << 100.0 * unaccounted / stats.average_total_query_time << " %)" << endl;
}

int main() {
  try {
    const char* sepline =
      "-----------------------------------------------------------------------";

    // Data set parameters
    int n = 1000000;    // number of data points
    int d = 128;      // dimension
    int num_queries = 1000;    // number of query points
    double r = std::sqrt(2.0) / 2.0;    // distance to planted query
    uint64_t seed = 119417657;

    // Common LSH parameters
    int num_tables = 10;
    int num_setup_threads = 0;
    StorageHashTable storage_hash_table = StorageHashTable::FlatHashTable;
    DistanceFunction distance_function = DistanceFunction::NegativeInnerProduct;

    cout << sepline << endl;
    cout << "FALCONN C++ random data benchmark" << endl;
    cout << "Data set parameters: " << endl;
    cout << "n = " << n << endl;
    cout << "d = " << d << endl;
    cout << "num_queries = " << num_queries << endl;
    cout << "r = " << r << endl;
    cout << "seed = " << seed << endl << sepline << endl;

    std::mt19937_64 gen(seed);
    std::normal_distribution<float> dist_normal(0.0, 1.0);
    std::uniform_int_distribution<int> dist_uniform(0, n - 1);

    // Generate random data
    cout << "Generating data set ..." << endl;
    std::vector<Vec> data;
    for (int ii = 0; ii < n; ++ii) {
      Vec v(d);
      for (int jj = 0; jj < d; ++jj) {
        v[jj] = dist_normal(gen);
      }
      v.normalize();
      data.push_back(v);
    }

    // Generate queries
    cout << "Generating queries ..." << endl << endl;
    std::vector<Vec> queries;
    for (int ii = 0; ii < num_queries; ++ii) {
      Vec q(d);
      q = data[dist_uniform(gen)];

      Vec dir(d);
      for (int jj = 0; jj < d; ++jj) {
        dir[jj] = dist_normal(gen);
      }
      dir.normalize();
      dir = dir - dir.dot(q) * q;
      dir.normalize();
      double alpha = 1.0 - r * r / 2.0;
      double beta = std::sqrt(1.0 - alpha * alpha);
      q = alpha * q + beta * dir;

      queries.push_back(q);
    }

    // Compute true nearest neighbors
    cout << "Computing true nearest neighbors via a linear scan ..." << endl;
    std::vector<int> true_nn(num_queries);
    double average_scan_time = 0.0;
    for (int ii = 0; ii < num_queries; ++ii) {
      const Vec& q = queries[ii];

      Timer query_time;

      int best_index = 0;
      float best_ip = q.dot(data[0]);
      for (int jj = 1; jj < n; ++jj) {
        float cur_ip = q.dot(data[jj]);
        if (cur_ip > best_ip) {
          best_index = jj;
          best_ip = cur_ip;
        }
      }
      true_nn[ii] = best_index;

      average_scan_time += query_time.elapsed_seconds();

    }
    average_scan_time /= num_queries;
    cout << "Average query time: " << average_scan_time << " seconds" << endl
         << sepline << endl;

    // Hyperplane hashing
    LSHConstructionParameters params_hp;
    params_hp.dimension = d;
    params_hp.lsh_family = LSHFamily::Hyperplane;
    params_hp.distance_function = distance_function;
    params_hp.storage_hash_table = storage_hash_table;
    params_hp.k = 19;
    params_hp.l = num_tables;
    params_hp.num_setup_threads = num_setup_threads;
    params_hp.seed = seed ^ 833840234;

    cout << "Hyperplane hash" << endl << endl;

    Timer hp_construction;

    unique_ptr<LSHNearestNeighborTable<Vec>> hptable(std::move(
        construct_table<Vec>(data, params_hp)));
    hptable->set_num_probes(2464);

    double hp_construction_time = hp_construction.elapsed_seconds();

    cout << "k = " << params_hp.k << endl;
    cout << "l = " << params_hp.l << endl;
    cout << "Number of probes = " << hptable->get_num_probes() << endl;
    cout << "Construction time: " << hp_construction_time << " seconds" << endl
         << endl;

    double hp_avg_time;
    double hp_success_prob;
    run_experiment(hptable.get(), queries, true_nn, &hp_avg_time,
        &hp_success_prob);
    cout << sepline << endl;
    hptable.reset(nullptr);

    // Cross polytope hashing
    LSHConstructionParameters params_cp;
    params_cp.dimension = d;
    params_cp.lsh_family = LSHFamily::CrossPolytope;
    params_cp.distance_function = distance_function;
    params_cp.storage_hash_table = storage_hash_table;
    params_cp.k = 3;
    params_cp.l = num_tables;
    params_cp.last_cp_dimension = 16;
    params_cp.num_rotations = 3;
    params_cp.num_setup_threads = num_setup_threads;
    params_cp.seed = seed ^ 833840234;

    cout << "Cross polytope hash" << endl << endl;

    Timer cp_construction;

    unique_ptr<LSHNearestNeighborTable<Vec>> cptable(std::move(
							       construct_table<Vec>(data, params_cp)));
    cptable->set_num_probes(896);

    double cp_construction_time = cp_construction.elapsed_seconds();

    cout << "k = " << params_cp.k << endl;
    cout << "last_cp_dim = " << params_cp.last_cp_dimension << endl;
    cout << "num_rotations = " << params_cp.num_rotations << endl;
    cout << "l = " << params_cp.l << endl;
    cout << "Number of probes = " << cptable->get_num_probes() << endl;
    cout << "Construction time: " << cp_construction_time << " seconds" << endl
         << endl;

    double cp_avg_time;
    double cp_success_prob;
    run_experiment(cptable.get(), queries, true_nn, &cp_avg_time,
		   &cp_success_prob);

    cout << sepline << endl << "Summary:" << endl;
    cout << "Success probabilities:" << endl;
    cout << "  HP: " << fixed << hp_success_prob << endl;
    cout << "  CP: " << cp_success_prob << endl;
    cout << "Average query times (seconds):" << endl;
    cout << "  Linear scan time: " << scientific << average_scan_time << endl;
    cout << "  HP time: " << hp_avg_time << endl;
    cout << "  CP time: " << cp_avg_time << endl;
    cout << "Speed-ups:" << endl;
    cout << "  HP vs linear scan: " << fixed << average_scan_time / hp_avg_time
	 << endl;
    cout << "  CP vs linear scan: " << fixed << average_scan_time / cp_avg_time
	 << endl;
    cout << "  CP vs HP: " << fixed << hp_avg_time / cp_avg_time << endl;
  }
  catch (std::exception &e) {
    cerr << "exception: " << e.what() << endl;
    return 1;
  }
  catch (...) {
    cerr << "Unknown error" << endl;
    return 1;
  }
  return 0;
}
<commit_msg>added a smart Eigen include to random_benchmark<commit_after>#include <chrono>
#include <cstdint>
#include <iostream>
#include <memory>
#include <stdexcept>

#include "falconn/eigen_wrapper.h"
#include "falconn/lsh_nn_table.h"

using std::chrono::duration;
using std::chrono::duration_cast;
using std::chrono::high_resolution_clock;
using std::cerr;
using std::cout;
using std::endl;
using std::exception;
using std::fixed;
using std::scientific;
using std::unique_ptr;
using std::vector;

using falconn::construct_table;
using falconn::DenseVector;
using falconn::DistanceFunction;
using falconn::LSHConstructionParameters;
using falconn::LSHFamily;
using falconn::LSHNearestNeighborTable;
using falconn::QueryStatistics;
using falconn::StorageHashTable;

typedef falconn::DenseVector<float> Vec;

class Timer {
 public:
  Timer() {
    start_time = high_resolution_clock::now();
  }

  double elapsed_seconds() {
    auto end_time = high_resolution_clock::now();
    auto elapsed = duration_cast<duration<double>>(end_time - start_time);
    return elapsed.count();
  }

 private:
  decltype(high_resolution_clock::now()) start_time;
};

template<typename PointType>
void run_experiment(LSHNearestNeighborTable<PointType>* table,
                    const std::vector<PointType> queries,
                    const std::vector<int> true_nns,
                    double* avg_query_time,
                    double* success_probability) {
  double average_query_time_outside = 0.0;
  int num_correct = 0;

  for (int ii = 0; ii < static_cast<int>(queries.size()); ++ii) {
    Timer query_time;

    int32_t res = table->find_nearest_neighbor(queries[ii]);

    average_query_time_outside += query_time.elapsed_seconds();
    if (res == true_nns[ii]) {
      num_correct += 1;
    }
  }

  average_query_time_outside /= queries.size();
  *avg_query_time = average_query_time_outside;
  *success_probability = static_cast<double>(num_correct) / queries.size();
  cout << "Average query time (measured outside): "
       << scientific << average_query_time_outside << " seconds" << endl;
  cout << "Empirical success probability: " << fixed
       << *success_probability << endl << endl;
  cout << "Query statistics:" << endl;
  QueryStatistics stats = table->get_query_statistics();
  cout << "Average total query time: " << scientific
       << stats.average_total_query_time << " seconds" << endl;
  cout << "Average LSH time:         "
       << stats.average_lsh_time << " seconds" << endl;
  cout << "Average hash table time:  "
       << stats.average_hash_table_time << " seconds" << endl;
  cout << "Average distance time:    "
       << stats.average_distance_time << " seconds" << endl;
  cout << "Average number of candidates:        " << fixed
       << stats.average_num_candidates << endl;
  cout << "Average number of unique candidates: "
       << stats.average_num_unique_candidates << endl << endl;
  cout << "Diagnostics:" << endl;
  double mismatch = average_query_time_outside - stats.average_total_query_time;
  cout << "Outside - inside average total query time: " << scientific
       << mismatch << " seconds (" << fixed
       << 100.0 * mismatch / average_query_time_outside << " %)" << endl;
  double unaccounted = stats.average_total_query_time - stats.average_lsh_time
      - stats.average_hash_table_time - stats.average_distance_time;
  cout << "Unaccounted inside query time: " << scientific << unaccounted
       << " seconds (" << fixed
       << 100.0 * unaccounted / stats.average_total_query_time << " %)" << endl;
}

int main() {
  try {
    const char* sepline =
      "-----------------------------------------------------------------------";

    // Data set parameters
    int n = 1000000;    // number of data points
    int d = 128;      // dimension
    int num_queries = 1000;    // number of query points
    double r = std::sqrt(2.0) / 2.0;    // distance to planted query
    uint64_t seed = 119417657;

    // Common LSH parameters
    int num_tables = 10;
    int num_setup_threads = 0;
    StorageHashTable storage_hash_table = StorageHashTable::FlatHashTable;
    DistanceFunction distance_function = DistanceFunction::NegativeInnerProduct;

    cout << sepline << endl;
    cout << "FALCONN C++ random data benchmark" << endl;
    cout << "Data set parameters: " << endl;
    cout << "n = " << n << endl;
    cout << "d = " << d << endl;
    cout << "num_queries = " << num_queries << endl;
    cout << "r = " << r << endl;
    cout << "seed = " << seed << endl << sepline << endl;

    std::mt19937_64 gen(seed);
    std::normal_distribution<float> dist_normal(0.0, 1.0);
    std::uniform_int_distribution<int> dist_uniform(0, n - 1);

    // Generate random data
    cout << "Generating data set ..." << endl;
    std::vector<Vec> data;
    for (int ii = 0; ii < n; ++ii) {
      Vec v(d);
      for (int jj = 0; jj < d; ++jj) {
        v[jj] = dist_normal(gen);
      }
      v.normalize();
      data.push_back(v);
    }

    // Generate queries
    cout << "Generating queries ..." << endl << endl;
    std::vector<Vec> queries;
    for (int ii = 0; ii < num_queries; ++ii) {
      Vec q(d);
      q = data[dist_uniform(gen)];

      Vec dir(d);
      for (int jj = 0; jj < d; ++jj) {
        dir[jj] = dist_normal(gen);
      }
      dir.normalize();
      dir = dir - dir.dot(q) * q;
      dir.normalize();
      double alpha = 1.0 - r * r / 2.0;
      double beta = std::sqrt(1.0 - alpha * alpha);
      q = alpha * q + beta * dir;

      queries.push_back(q);
    }

    // Compute true nearest neighbors
    cout << "Computing true nearest neighbors via a linear scan ..." << endl;
    std::vector<int> true_nn(num_queries);
    double average_scan_time = 0.0;
    for (int ii = 0; ii < num_queries; ++ii) {
      const Vec& q = queries[ii];

      Timer query_time;

      int best_index = 0;
      float best_ip = q.dot(data[0]);
      for (int jj = 1; jj < n; ++jj) {
        float cur_ip = q.dot(data[jj]);
        if (cur_ip > best_ip) {
          best_index = jj;
          best_ip = cur_ip;
        }
      }
      true_nn[ii] = best_index;

      average_scan_time += query_time.elapsed_seconds();

    }
    average_scan_time /= num_queries;
    cout << "Average query time: " << average_scan_time << " seconds" << endl
         << sepline << endl;

    // Hyperplane hashing
    LSHConstructionParameters params_hp;
    params_hp.dimension = d;
    params_hp.lsh_family = LSHFamily::Hyperplane;
    params_hp.distance_function = distance_function;
    params_hp.storage_hash_table = storage_hash_table;
    params_hp.k = 19;
    params_hp.l = num_tables;
    params_hp.num_setup_threads = num_setup_threads;
    params_hp.seed = seed ^ 833840234;

    cout << "Hyperplane hash" << endl << endl;

    Timer hp_construction;

    unique_ptr<LSHNearestNeighborTable<Vec>> hptable(std::move(
        construct_table<Vec>(data, params_hp)));
    hptable->set_num_probes(2464);

    double hp_construction_time = hp_construction.elapsed_seconds();

    cout << "k = " << params_hp.k << endl;
    cout << "l = " << params_hp.l << endl;
    cout << "Number of probes = " << hptable->get_num_probes() << endl;
    cout << "Construction time: " << hp_construction_time << " seconds" << endl
         << endl;

    double hp_avg_time;
    double hp_success_prob;
    run_experiment(hptable.get(), queries, true_nn, &hp_avg_time,
        &hp_success_prob);
    cout << sepline << endl;
    hptable.reset(nullptr);

    // Cross polytope hashing
    LSHConstructionParameters params_cp;
    params_cp.dimension = d;
    params_cp.lsh_family = LSHFamily::CrossPolytope;
    params_cp.distance_function = distance_function;
    params_cp.storage_hash_table = storage_hash_table;
    params_cp.k = 3;
    params_cp.l = num_tables;
    params_cp.last_cp_dimension = 16;
    params_cp.num_rotations = 3;
    params_cp.num_setup_threads = num_setup_threads;
    params_cp.seed = seed ^ 833840234;

    cout << "Cross polytope hash" << endl << endl;

    Timer cp_construction;

    unique_ptr<LSHNearestNeighborTable<Vec>> cptable(std::move(
							       construct_table<Vec>(data, params_cp)));
    cptable->set_num_probes(896);

    double cp_construction_time = cp_construction.elapsed_seconds();

    cout << "k = " << params_cp.k << endl;
    cout << "last_cp_dim = " << params_cp.last_cp_dimension << endl;
    cout << "num_rotations = " << params_cp.num_rotations << endl;
    cout << "l = " << params_cp.l << endl;
    cout << "Number of probes = " << cptable->get_num_probes() << endl;
    cout << "Construction time: " << cp_construction_time << " seconds" << endl
         << endl;

    double cp_avg_time;
    double cp_success_prob;
    run_experiment(cptable.get(), queries, true_nn, &cp_avg_time,
		   &cp_success_prob);

    cout << sepline << endl << "Summary:" << endl;
    cout << "Success probabilities:" << endl;
    cout << "  HP: " << fixed << hp_success_prob << endl;
    cout << "  CP: " << cp_success_prob << endl;
    cout << "Average query times (seconds):" << endl;
    cout << "  Linear scan time: " << scientific << average_scan_time << endl;
    cout << "  HP time: " << hp_avg_time << endl;
    cout << "  CP time: " << cp_avg_time << endl;
    cout << "Speed-ups:" << endl;
    cout << "  HP vs linear scan: " << fixed << average_scan_time / hp_avg_time
	 << endl;
    cout << "  CP vs linear scan: " << fixed << average_scan_time / cp_avg_time
	 << endl;
    cout << "  CP vs HP: " << fixed << hp_avg_time / cp_avg_time << endl;
  }
  catch (std::exception &e) {
    cerr << "exception: " << e.what() << endl;
    return 1;
  }
  catch (...) {
    cerr << "Unknown error" << endl;
    return 1;
  }
  return 0;
}
<|endoftext|>


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

#include "chrome/browser/diagnostics/diagnostics_model.h"

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

// Basic harness to adquire and release the Diagnostic model object.
class DiagnosticsModelTest : public testing::Test {
 protected:
  DiagnosticsModelTest()
      : model_(NULL),
        cmdline_(CommandLine::ARGUMENTS_ONLY) {
  }

  virtual ~DiagnosticsModelTest() { }

  virtual void SetUp() {
    model_ = MakeDiagnosticsModel(cmdline_);
    ASSERT_TRUE(model_ != NULL);
  }

  virtual void TearDown() {
    delete model_;
  }

  DiagnosticsModel* model_;
  CommandLine cmdline_;
};

// The test observer is used to know if the callbacks are being called.
class UTObserver: public DiagnosticsModel::Observer {
 public:
  UTObserver()
      : done_(false),
        progress_called_(0),
        finished_(0),
        id_of_failed_stop_test(-1) {
  }

  virtual void OnProgress(int id, int percent, DiagnosticsModel* model) {
    EXPECT_TRUE(model != NULL);
    ++progress_called_;
  }

  virtual void OnSkipped(int id, DiagnosticsModel* model) {
    EXPECT_TRUE(model != NULL);
  }

  virtual void OnFinished(int id, DiagnosticsModel* model) {
    EXPECT_TRUE(model != NULL);
    ++finished_;
    if (model->GetTest(id).GetResult() == DiagnosticsModel::TEST_FAIL_STOP) {
      id_of_failed_stop_test = id;
      ASSERT_TRUE(false);
    }
  }

  virtual void OnDoneAll(DiagnosticsModel* model) {
    done_ = true;
    EXPECT_TRUE(model != NULL);
  }

  bool done() const { return done_; }

  int progress_called() const { return progress_called_; }

  int finished() const { return finished_;}

 private:
  bool done_;
  int progress_called_;
  int finished_;
  int id_of_failed_stop_test;
};

// We currently have more tests operational on windows.
#if defined(OS_WIN)
const int kDiagnosticsTestCount = 18;
#elif defined(OS_MACOSX)
const int kDiagnosticsTestCount = 16;
#elif defined(OS_POSIX)
const int kDiagnosticsTestCount = 17;
#endif

// Test that the initial state is correct.
TEST_F(DiagnosticsModelTest, BeforeRun) {
  int available = model_->GetTestAvailableCount();
  EXPECT_EQ(kDiagnosticsTestCount, available);
  EXPECT_EQ(0, model_->GetTestRunCount());
  EXPECT_EQ(DiagnosticsModel::TEST_NOT_RUN, model_->GetTest(0).GetResult());
}

// Run all the tests, verify that the basic callbacks are run and that the
// final state is correct.
// DISABLED by agl because it's crashing the builder.
TEST_F(DiagnosticsModelTest, DISABLED_RunAll) {
  UTObserver observer;
  EXPECT_FALSE(observer.done());
  model_->RunAll(&observer);
  EXPECT_TRUE(observer.done());
  EXPECT_GT(observer.progress_called(), 0);
  EXPECT_EQ(kDiagnosticsTestCount, model_->GetTestRunCount());
  EXPECT_EQ(kDiagnosticsTestCount, observer.finished());
}
<commit_msg>Revert "Disable DiagnosticsModelTest.RunAll."<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/diagnostics/diagnostics_model.h"

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

// Basic harness to adquire and release the Diagnostic model object.
class DiagnosticsModelTest : public testing::Test {
 protected:
  DiagnosticsModelTest()
      : model_(NULL),
        cmdline_(CommandLine::ARGUMENTS_ONLY) {
  }

  virtual ~DiagnosticsModelTest() { }

  virtual void SetUp() {
    model_ = MakeDiagnosticsModel(cmdline_);
    ASSERT_TRUE(model_ != NULL);
  }

  virtual void TearDown() {
    delete model_;
  }

  DiagnosticsModel* model_;
  CommandLine cmdline_;
};

// The test observer is used to know if the callbacks are being called.
class UTObserver: public DiagnosticsModel::Observer {
 public:
  UTObserver()
      : done_(false),
        progress_called_(0),
        finished_(0),
        id_of_failed_stop_test(-1) {
  }

  virtual void OnProgress(int id, int percent, DiagnosticsModel* model) {
    EXPECT_TRUE(model != NULL);
    ++progress_called_;
  }

  virtual void OnSkipped(int id, DiagnosticsModel* model) {
    EXPECT_TRUE(model != NULL);
  }

  virtual void OnFinished(int id, DiagnosticsModel* model) {
    EXPECT_TRUE(model != NULL);
    ++finished_;
    if (model->GetTest(id).GetResult() == DiagnosticsModel::TEST_FAIL_STOP) {
      id_of_failed_stop_test = id;
      ASSERT_TRUE(false);
    }
  }

  virtual void OnDoneAll(DiagnosticsModel* model) {
    done_ = true;
    EXPECT_TRUE(model != NULL);
  }

  bool done() const { return done_; }

  int progress_called() const { return progress_called_; }

  int finished() const { return finished_;}

 private:
  bool done_;
  int progress_called_;
  int finished_;
  int id_of_failed_stop_test;
};

// We currently have more tests operational on windows.
#if defined(OS_WIN)
const int kDiagnosticsTestCount = 18;
#elif defined(OS_MACOSX)
const int kDiagnosticsTestCount = 16;
#elif defined(OS_POSIX)
const int kDiagnosticsTestCount = 17;
#endif

// Test that the initial state is correct.
TEST_F(DiagnosticsModelTest, BeforeRun) {
  int available = model_->GetTestAvailableCount();
  EXPECT_EQ(kDiagnosticsTestCount, available);
  EXPECT_EQ(0, model_->GetTestRunCount());
  EXPECT_EQ(DiagnosticsModel::TEST_NOT_RUN, model_->GetTest(0).GetResult());
}

// Run all the tests, verify that the basic callbacks are run and that the
// final state is correct.
TEST_F(DiagnosticsModelTest, RunAll) {
  UTObserver observer;
  EXPECT_FALSE(observer.done());
  model_->RunAll(&observer);
  EXPECT_TRUE(observer.done());
  EXPECT_GT(observer.progress_called(), 0);
  EXPECT_EQ(kDiagnosticsTestCount, model_->GetTestRunCount());
  EXPECT_EQ(kDiagnosticsTestCount, observer.finished());
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 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/extensions/extension_apitest.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"

class DownloadsApiTest : public ExtensionApiTest {
 public:
  void SetUpCommandLine(CommandLine* command_line) {
    ExtensionApiTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
  }

  void SetUpTempDownloadsDir() {
    ASSERT_TRUE(tmpdir.CreateUniqueTempDir());
    browser()->profile()->GetPrefs()->SetFilePath(
        prefs::kDownloadDefaultDirectory, tmpdir.path());
  }

 private:
  ScopedTempDir tmpdir;
};

IN_PROC_BROWSER_TEST_F(DownloadsApiTest, Downloads) {
  SetUpTempDownloadsDir();
  ASSERT_TRUE(StartTestServer());
  ASSERT_TRUE(RunExtensionTest("downloads")) << message_;
}
<commit_msg>Re-disable DownloadsApiTest.<commit_after>// Copyright (c) 2011 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/extensions/extension_apitest.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"

class DownloadsApiTest : public ExtensionApiTest {
 public:
  void SetUpCommandLine(CommandLine* command_line) {
    ExtensionApiTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
  }

  void SetUpTempDownloadsDir() {
    ASSERT_TRUE(tmpdir.CreateUniqueTempDir());
    browser()->profile()->GetPrefs()->SetFilePath(
        prefs::kDownloadDefaultDirectory, tmpdir.path());
  }

 private:
  ScopedTempDir tmpdir;
};

IN_PROC_BROWSER_TEST_F(DownloadsApiTest, DISABLED_Downloads) {
  SetUpTempDownloadsDir();
  ASSERT_TRUE(StartTestServer());
  ASSERT_TRUE(RunExtensionTest("downloads")) << message_;
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 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/extensions/extension_apitest.h"

// TODO(rafaelw,erikkay) disabled due to flakiness
// BUG=22668 (probably the same bug)
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_Toolstrip) {
  ASSERT_TRUE(RunExtensionTest("toolstrip")) << message_;
}
<commit_msg>Enable ExtensionApiTest.Toolstrip<commit_after>// Copyright (c) 2009 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/extensions/extension_apitest.h"

// TODO(rafaelw,erikkay) disabled due to flakiness
// BUG=22668 (probably the same bug)
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Toolstrip) {
  ASSERT_TRUE(RunExtensionTest("toolstrip")) << message_;
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2009 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/shell_integration.h"

#include <stdlib.h>

#include <vector>

#include "base/process_util.h"

#if defined(GOOGLE_CHROME_BUILD)
#define DESKTOP_APP_NAME "google-chrome.desktop"
#else  // CHROMIUM_BUILD
#define DESKTOP_APP_NAME "chromium-browser.desktop"
#endif

// We delegate the difficult of setting the default browser in Linux desktop
// environments to a new xdg utility, xdg-settings. We'll have to include a copy
// of it for this to work, obviously, but that's actually the suggested approach
// for xdg utilities anyway.

bool ShellIntegration::SetAsDefaultBrowser() {
  std::vector<std::string> argv;
  argv.push_back("xdg-settings");
  argv.push_back("set");
  argv.push_back("default-web-browser");
  argv.push_back(DESKTOP_APP_NAME);

  int success_code;
  base::ProcessHandle handle;
  base::file_handle_mapping_vector no_files;
  if (!base::LaunchApp(argv, no_files, false, &handle))
    return false;

  base::WaitForExitCode(handle, &success_code);
  return success_code == EXIT_SUCCESS;
}

static std::string getDefaultBrowser() {
  std::vector<std::string> argv;
  argv.push_back("xdg-settings");
  argv.push_back("get");
  argv.push_back("default-web-browser");
  std::string output;
  base::GetAppOutput(CommandLine(argv), &output);
  // If GetAppOutput() fails, we'll return the empty string.
  return output;
}

bool ShellIntegration::IsDefaultBrowser() {
  std::string browser = getDefaultBrowser();
  // Allow for an optional newline at the end.
  if (browser.length() > 0 && browser[browser.length() - 1] == '\n')
    browser.resize(browser.length() - 1);
  if (!browser.length()) {
    // We don't know what the default browser is; chances are, we can't
    // set it either. So, check to see if we were run in the wrapper
    // and pretend that we are the default unless we were run from it,
    // to avoid warning that we aren't the default when it's useless.
    return !getenv("CHROME_WRAPPER");
  }
  return !browser.compare(DESKTOP_APP_NAME);
}

bool ShellIntegration::IsFirefoxDefaultBrowser() {
  return getDefaultBrowser().find("irefox") != std::string::npos;
}
<commit_msg>Pretend we're the default browser when xdg-settings fails. BUG=16981 TEST=use an unsupported desktop environment (like awesome) and start chrome; it should not ask about setting itself as the default<commit_after>// Copyright (c) 2006-2009 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/shell_integration.h"

#include <stdlib.h>

#include <vector>

#include "base/process_util.h"

#if defined(GOOGLE_CHROME_BUILD)
#define DESKTOP_APP_NAME "google-chrome.desktop"
#else  // CHROMIUM_BUILD
#define DESKTOP_APP_NAME "chromium-browser.desktop"
#endif

// We delegate the difficult of setting the default browser in Linux desktop
// environments to a new xdg utility, xdg-settings. We'll have to include a copy
// of it for this to work, obviously, but that's actually the suggested approach
// for xdg utilities anyway.

bool ShellIntegration::SetAsDefaultBrowser() {
  std::vector<std::string> argv;
  argv.push_back("xdg-settings");
  argv.push_back("set");
  argv.push_back("default-web-browser");
  argv.push_back(DESKTOP_APP_NAME);

  int success_code;
  base::ProcessHandle handle;
  base::file_handle_mapping_vector no_files;
  if (!base::LaunchApp(argv, no_files, false, &handle))
    return false;

  base::WaitForExitCode(handle, &success_code);
  return success_code == EXIT_SUCCESS;
}

static bool GetDefaultBrowser(std::string* result) {
  std::vector<std::string> argv;
  argv.push_back("xdg-settings");
  argv.push_back("get");
  argv.push_back("default-web-browser");
  return base::GetAppOutput(CommandLine(argv), result);
}

bool ShellIntegration::IsDefaultBrowser() {
  std::string browser;
  if (!GetDefaultBrowser(&browser)) {
    // If GetDefaultBrowser() fails, we assume xdg-settings does not work for
    // some reason, and that we should pretend we're the default browser to
    // avoid giving repeated prompts to set ourselves as the default browser.
    // TODO: Really, being the default browser should be a ternary query: yes,
    // no, and "don't know" so that the UI can reflect this more accurately.
    return true;
  }
  // Allow for an optional newline at the end.
  if (browser.length() > 0 && browser[browser.length() - 1] == '\n')
    browser.resize(browser.length() - 1);
  return !browser.compare(DESKTOP_APP_NAME);
}

bool ShellIntegration::IsFirefoxDefaultBrowser() {
  std::string browser;
  // We don't care about the return value here.
  GetDefaultBrowser(&browser);
  return browser.find("irefox") != std::string::npos;
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 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/ui/touch/tabs/touch_tab.h"

#include "chrome/browser/themes/browser_theme_provider.h"
#include "grit/app_resources.h"
#include "grit/theme_resources.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas_skia.h"
#include "ui/gfx/favicon_size.h"
#include "ui/gfx/path.h"
#include "ui/gfx/skbitmap_operations.h"

static const int kLeftPadding = 16;
static const int kRightPadding = 15;
static const int kDropShadowHeight = 2;
static const int kTouchFaviconSize = 32;

TouchTab::TouchTabImage TouchTab::tab_alpha = {0};
TouchTab::TouchTabImage TouchTab::tab_active = {0};
TouchTab::TouchTabImage TouchTab::tab_inactive = {0};

////////////////////////////////////////////////////////////////////////////////
// TouchTab, public:

TouchTab::TouchTab(TabController* controller)
    : BaseTab(controller) {
  InitTabResources();
}

TouchTab::~TouchTab() {
}

// static
gfx::Size TouchTab::GetMinimumUnselectedSize() {
  InitTabResources();

  gfx::Size minimum_size;
  minimum_size.set_width(kLeftPadding + kRightPadding);
  minimum_size.set_height(32);
  return minimum_size;
}

////////////////////////////////////////////////////////////////////////////////
// TouchTab, protected:
const gfx::Rect& TouchTab::GetTitleBounds() const {
  return title_bounds_;
}

const gfx::Rect& TouchTab::GetIconBounds() const {
  return favicon_bounds_;
}

////////////////////////////////////////////////////////////////////////////////
// TouchTab, views::View overrides:

void TouchTab::OnPaint(gfx::Canvas* canvas) {
  // Don't paint if we're narrower than we can render correctly. (This should
  // only happen during animations).
  if (width() < GetMinimumUnselectedSize().width() && !data().mini)
    return;

  PaintTabBackground(canvas);

  SkColor title_color = GetThemeProvider()->
      GetColor(IsSelected() ?
          BrowserThemeProvider::COLOR_TAB_TEXT :
          BrowserThemeProvider::COLOR_BACKGROUND_TAB_TEXT);

  PaintTitle(canvas, title_color);
  PaintIcon(canvas);
}

void TouchTab::Layout() {
  gfx::Rect local_bounds = GetContentsBounds();
  TouchTabImage* tab_image = &tab_active;
  TouchTabImage* alpha = &tab_alpha;
  int image_height = alpha->image_l->height();
  int x_base = tab_image->image_l->width();
  int y_base = height() - image_height;
  int center_width = width() - tab_image->l_width - tab_image->r_width;
  if (center_width < 0)
    center_width = 0;
  title_bounds_ = gfx::Rect(x_base, y_base, center_width, image_height);
  favicon_bounds_ = local_bounds;
}

bool TouchTab::HasHitTestMask() const {
  return true;
}

void TouchTab::GetHitTestMask(gfx::Path* path) const {
  DCHECK(path);

  SkScalar h = SkIntToScalar(height());
  SkScalar w = SkIntToScalar(width());

  path->moveTo(0, h);
  path->lineTo(0, 0);
  path->lineTo(w, 0);
  path->lineTo(w, h);
  path->lineTo(0, h);
  path->close();
}

////////////////////////////////////////////////////////////////////////////////
// TouchTab, private:

void TouchTab::PaintTabBackground(gfx::Canvas* canvas) {
  if (IsSelected()) {
    PaintActiveTabBackground(canvas);
  }
}

void TouchTab::PaintActiveTabBackground(gfx::Canvas* canvas) {
  int offset = GetMirroredX() + background_offset_.x();
  ThemeProvider* tp = GetThemeProvider();
  if (!tp)
    NOTREACHED() << "Unable to get theme provider";

  SkBitmap* tab_bg = GetThemeProvider()->GetBitmapNamed(IDR_THEME_TOOLBAR);

  TouchTabImage* tab_image = &tab_active;
  TouchTabImage* alpha = &tab_alpha;

  // Draw left edge.
  int image_height = alpha->image_l->height();
  int y_base = height() - image_height;
  SkBitmap tab_l = SkBitmapOperations::CreateTiledBitmap(
      *tab_bg, offset, 0, tab_image->l_width, image_height);
  SkBitmap theme_l =
      SkBitmapOperations::CreateMaskedBitmap(tab_l, *alpha->image_l);
  canvas->DrawBitmapInt(theme_l, 0, y_base);

  // Draw right edge.
  SkBitmap tab_r = SkBitmapOperations::CreateTiledBitmap(*tab_bg,
      offset + width() - tab_image->r_width, 0,
      tab_image->r_width, image_height);
  SkBitmap theme_r =
      SkBitmapOperations::CreateMaskedBitmap(tab_r, *alpha->image_r);
  canvas->DrawBitmapInt(theme_r, width() - tab_image->r_width, y_base);

  // Draw center.  Instead of masking out the top portion we simply skip over it
  // by incrementing by kDropShadowHeight, since it's a simple rectangle.
  canvas->TileImageInt(*tab_bg,
     offset + tab_image->l_width,
     kDropShadowHeight + tab_image->y_offset,
     tab_image->l_width,
     y_base + kDropShadowHeight + tab_image->y_offset,
     width() - tab_image->l_width - tab_image->r_width,
     height() - kDropShadowHeight - tab_image->y_offset);

  // Now draw the highlights/shadows around the tab edge.
  canvas->DrawBitmapInt(*tab_image->image_l, 0, y_base);
  canvas->TileImageInt(*tab_image->image_c, tab_image->l_width, y_base,
      width() - tab_image->l_width - tab_image->r_width, image_height);
  canvas->DrawBitmapInt(*tab_image->image_r, width() - tab_image->r_width,
                        y_base);
}

void TouchTab::PaintIcon(gfx::Canvas* canvas) {
  // TODO(wyck): use thumbnailer to get better page images
  int x = favicon_bounds_.x();
  int y = favicon_bounds_.y();

  TouchTabImage* tab_image = &tab_active;
  int x_base = tab_image->image_l->width();

  x += x_base;

  if (base::i18n::IsRTL()) {
    x = width() - x -
        (data().favicon.isNull() ? kFaviconSize : data().favicon.width());
  }

  int favicon_x = x;
  if (!data().favicon.isNull() && data().favicon.width() != kFaviconSize)
    favicon_x += (data().favicon.width() - kFaviconSize) / 2;

  if (data().network_state != TabRendererData::NETWORK_STATE_NONE) {
    ThemeProvider* tp = GetThemeProvider();
    SkBitmap frames(*tp->GetBitmapNamed(
        (data().network_state == TabRendererData::NETWORK_STATE_WAITING) ?
        IDR_THROBBER_WAITING : IDR_THROBBER));
    int image_size = frames.height();
    int image_offset = loading_animation_frame() * image_size;
    canvas->DrawBitmapInt(frames, image_offset, 0, image_size, image_size, x, y,
                          kTouchFaviconSize, kTouchFaviconSize, false);
  } else {
    canvas->Save();
    canvas->ClipRectInt(0, 0, width(), height());
    if (should_display_crashed_favicon()) {
      ResourceBundle& rb = ResourceBundle::GetSharedInstance();
      SkBitmap crashed_favicon(*rb.GetBitmapNamed(IDR_SAD_FAVICON));
      canvas->DrawBitmapInt(crashed_favicon, 0, 0, crashed_favicon.width(),
          crashed_favicon.height(), x, y + favicon_hiding_offset(),
          kTouchFaviconSize, kTouchFaviconSize, true);
    } else {
      if (!data().favicon.isNull()) {
        canvas->DrawBitmapInt(data().favicon, 0, 0,
                              data().favicon.width(), data().favicon.height(),
                              x, y + favicon_hiding_offset(),
                              kTouchFaviconSize, kTouchFaviconSize, true);
      }
    }
    canvas->Restore();
  }
}

// static
void TouchTab::InitTabResources() {
  static bool initialized = false;
  if (initialized)
    return;

  initialized = true;

  // Load the tab images once now, and maybe again later if the theme changes.
  LoadTabImages();
}

// static
void TouchTab::LoadTabImages() {
  // We're not letting people override tab images just yet.
  ResourceBundle& rb = ResourceBundle::GetSharedInstance();

  tab_alpha.image_l = rb.GetBitmapNamed(IDR_TAB_ALPHA_LEFT);
  tab_alpha.image_r = rb.GetBitmapNamed(IDR_TAB_ALPHA_RIGHT);

  tab_active.image_l = rb.GetBitmapNamed(IDR_TAB_ACTIVE_LEFT);
  tab_active.image_c = rb.GetBitmapNamed(IDR_TAB_ACTIVE_CENTER);
  tab_active.image_r = rb.GetBitmapNamed(IDR_TAB_ACTIVE_RIGHT);
  tab_active.l_width = tab_active.image_l->width();
  tab_active.r_width = tab_active.image_r->width();

  tab_inactive.image_l = rb.GetBitmapNamed(IDR_TAB_INACTIVE_LEFT);
  tab_inactive.image_c = rb.GetBitmapNamed(IDR_TAB_INACTIVE_CENTER);
  tab_inactive.image_r = rb.GetBitmapNamed(IDR_TAB_INACTIVE_RIGHT);
  tab_inactive.l_width = tab_inactive.image_l->width();
  tab_inactive.r_width = tab_inactive.image_r->width();
}
<commit_msg>Real touch build fix.<commit_after>// Copyright (c) 2011 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/ui/touch/tabs/touch_tab.h"

#include "base/logging.h"
#include "chrome/browser/themes/browser_theme_provider.h"
#include "grit/app_resources.h"
#include "grit/theme_resources.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas_skia.h"
#include "ui/gfx/favicon_size.h"
#include "ui/gfx/path.h"
#include "ui/gfx/skbitmap_operations.h"

static const int kLeftPadding = 16;
static const int kRightPadding = 15;
static const int kDropShadowHeight = 2;
static const int kTouchFaviconSize = 32;

TouchTab::TouchTabImage TouchTab::tab_alpha = {0};
TouchTab::TouchTabImage TouchTab::tab_active = {0};
TouchTab::TouchTabImage TouchTab::tab_inactive = {0};

////////////////////////////////////////////////////////////////////////////////
// TouchTab, public:

TouchTab::TouchTab(TabController* controller)
    : BaseTab(controller) {
  InitTabResources();
}

TouchTab::~TouchTab() {
}

// static
gfx::Size TouchTab::GetMinimumUnselectedSize() {
  InitTabResources();

  gfx::Size minimum_size;
  minimum_size.set_width(kLeftPadding + kRightPadding);
  minimum_size.set_height(32);
  return minimum_size;
}

////////////////////////////////////////////////////////////////////////////////
// TouchTab, protected:
const gfx::Rect& TouchTab::GetTitleBounds() const {
  return title_bounds_;
}

const gfx::Rect& TouchTab::GetIconBounds() const {
  return favicon_bounds_;
}

////////////////////////////////////////////////////////////////////////////////
// TouchTab, views::View overrides:

void TouchTab::OnPaint(gfx::Canvas* canvas) {
  // Don't paint if we're narrower than we can render correctly. (This should
  // only happen during animations).
  if (width() < GetMinimumUnselectedSize().width() && !data().mini)
    return;

  PaintTabBackground(canvas);

  SkColor title_color = GetThemeProvider()->
      GetColor(IsSelected() ?
          BrowserThemeProvider::COLOR_TAB_TEXT :
          BrowserThemeProvider::COLOR_BACKGROUND_TAB_TEXT);

  PaintTitle(canvas, title_color);
  PaintIcon(canvas);
}

void TouchTab::Layout() {
  gfx::Rect local_bounds = GetContentsBounds();
  TouchTabImage* tab_image = &tab_active;
  TouchTabImage* alpha = &tab_alpha;
  int image_height = alpha->image_l->height();
  int x_base = tab_image->image_l->width();
  int y_base = height() - image_height;
  int center_width = width() - tab_image->l_width - tab_image->r_width;
  if (center_width < 0)
    center_width = 0;
  title_bounds_ = gfx::Rect(x_base, y_base, center_width, image_height);
  favicon_bounds_ = local_bounds;
}

bool TouchTab::HasHitTestMask() const {
  return true;
}

void TouchTab::GetHitTestMask(gfx::Path* path) const {
  DCHECK(path);

  SkScalar h = SkIntToScalar(height());
  SkScalar w = SkIntToScalar(width());

  path->moveTo(0, h);
  path->lineTo(0, 0);
  path->lineTo(w, 0);
  path->lineTo(w, h);
  path->lineTo(0, h);
  path->close();
}

////////////////////////////////////////////////////////////////////////////////
// TouchTab, private:

void TouchTab::PaintTabBackground(gfx::Canvas* canvas) {
  if (IsSelected()) {
    PaintActiveTabBackground(canvas);
  }
}

void TouchTab::PaintActiveTabBackground(gfx::Canvas* canvas) {
  int offset = GetMirroredX() + background_offset_.x();
  ThemeProvider* tp = GetThemeProvider();
  if (!tp)
    NOTREACHED() << "Unable to get theme provider";

  SkBitmap* tab_bg = GetThemeProvider()->GetBitmapNamed(IDR_THEME_TOOLBAR);

  TouchTabImage* tab_image = &tab_active;
  TouchTabImage* alpha = &tab_alpha;

  // Draw left edge.
  int image_height = alpha->image_l->height();
  int y_base = height() - image_height;
  SkBitmap tab_l = SkBitmapOperations::CreateTiledBitmap(
      *tab_bg, offset, 0, tab_image->l_width, image_height);
  SkBitmap theme_l =
      SkBitmapOperations::CreateMaskedBitmap(tab_l, *alpha->image_l);
  canvas->DrawBitmapInt(theme_l, 0, y_base);

  // Draw right edge.
  SkBitmap tab_r = SkBitmapOperations::CreateTiledBitmap(*tab_bg,
      offset + width() - tab_image->r_width, 0,
      tab_image->r_width, image_height);
  SkBitmap theme_r =
      SkBitmapOperations::CreateMaskedBitmap(tab_r, *alpha->image_r);
  canvas->DrawBitmapInt(theme_r, width() - tab_image->r_width, y_base);

  // Draw center.  Instead of masking out the top portion we simply skip over it
  // by incrementing by kDropShadowHeight, since it's a simple rectangle.
  canvas->TileImageInt(*tab_bg,
     offset + tab_image->l_width,
     kDropShadowHeight + tab_image->y_offset,
     tab_image->l_width,
     y_base + kDropShadowHeight + tab_image->y_offset,
     width() - tab_image->l_width - tab_image->r_width,
     height() - kDropShadowHeight - tab_image->y_offset);

  // Now draw the highlights/shadows around the tab edge.
  canvas->DrawBitmapInt(*tab_image->image_l, 0, y_base);
  canvas->TileImageInt(*tab_image->image_c, tab_image->l_width, y_base,
      width() - tab_image->l_width - tab_image->r_width, image_height);
  canvas->DrawBitmapInt(*tab_image->image_r, width() - tab_image->r_width,
                        y_base);
}

void TouchTab::PaintIcon(gfx::Canvas* canvas) {
  // TODO(wyck): use thumbnailer to get better page images
  int x = favicon_bounds_.x();
  int y = favicon_bounds_.y();

  TouchTabImage* tab_image = &tab_active;
  int x_base = tab_image->image_l->width();

  x += x_base;

  if (base::i18n::IsRTL()) {
    x = width() - x -
        (data().favicon.isNull() ? kFaviconSize : data().favicon.width());
  }

  int favicon_x = x;
  if (!data().favicon.isNull() && data().favicon.width() != kFaviconSize)
    favicon_x += (data().favicon.width() - kFaviconSize) / 2;

  if (data().network_state != TabRendererData::NETWORK_STATE_NONE) {
    ThemeProvider* tp = GetThemeProvider();
    SkBitmap frames(*tp->GetBitmapNamed(
        (data().network_state == TabRendererData::NETWORK_STATE_WAITING) ?
        IDR_THROBBER_WAITING : IDR_THROBBER));
    int image_size = frames.height();
    int image_offset = loading_animation_frame() * image_size;
    canvas->DrawBitmapInt(frames, image_offset, 0, image_size, image_size, x, y,
                          kTouchFaviconSize, kTouchFaviconSize, false);
  } else {
    canvas->Save();
    canvas->ClipRectInt(0, 0, width(), height());
    if (should_display_crashed_favicon()) {
      ResourceBundle& rb = ResourceBundle::GetSharedInstance();
      SkBitmap crashed_favicon(*rb.GetBitmapNamed(IDR_SAD_FAVICON));
      canvas->DrawBitmapInt(crashed_favicon, 0, 0, crashed_favicon.width(),
          crashed_favicon.height(), x, y + favicon_hiding_offset(),
          kTouchFaviconSize, kTouchFaviconSize, true);
    } else {
      if (!data().favicon.isNull()) {
        canvas->DrawBitmapInt(data().favicon, 0, 0,
                              data().favicon.width(), data().favicon.height(),
                              x, y + favicon_hiding_offset(),
                              kTouchFaviconSize, kTouchFaviconSize, true);
      }
    }
    canvas->Restore();
  }
}

// static
void TouchTab::InitTabResources() {
  static bool initialized = false;
  if (initialized)
    return;

  initialized = true;

  // Load the tab images once now, and maybe again later if the theme changes.
  LoadTabImages();
}

// static
void TouchTab::LoadTabImages() {
  // We're not letting people override tab images just yet.
  ResourceBundle& rb = ResourceBundle::GetSharedInstance();

  tab_alpha.image_l = rb.GetBitmapNamed(IDR_TAB_ALPHA_LEFT);
  tab_alpha.image_r = rb.GetBitmapNamed(IDR_TAB_ALPHA_RIGHT);

  tab_active.image_l = rb.GetBitmapNamed(IDR_TAB_ACTIVE_LEFT);
  tab_active.image_c = rb.GetBitmapNamed(IDR_TAB_ACTIVE_CENTER);
  tab_active.image_r = rb.GetBitmapNamed(IDR_TAB_ACTIVE_RIGHT);
  tab_active.l_width = tab_active.image_l->width();
  tab_active.r_width = tab_active.image_r->width();

  tab_inactive.image_l = rb.GetBitmapNamed(IDR_TAB_INACTIVE_LEFT);
  tab_inactive.image_c = rb.GetBitmapNamed(IDR_TAB_INACTIVE_CENTER);
  tab_inactive.image_r = rb.GetBitmapNamed(IDR_TAB_INACTIVE_RIGHT);
  tab_inactive.l_width = tab_inactive.image_l->width();
  tab_inactive.r_width = tab_inactive.image_r->width();
}
<|endoftext|>