<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/ui/views/accelerator_table.h"

#include "base/basictypes.h"
#include "chrome/app/chrome_command_ids.h"
#include "ui/base/keycodes/keyboard_codes.h"

namespace browser {

// NOTE: Keep this list in the same (mostly-alphabetical) order as
// the Windows accelerators in ../../app/chrome_dll.rc.
// Do not use Ctrl-Alt as a shortcut modifier, as it is used by i18n keyboards:
// http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx
const AcceleratorMapping kAcceleratorMap[] = {
  // Keycode                  Shift  Ctrl   Alt    Command ID
  { ui::VKEY_LEFT,           false, false, true,  IDC_BACK },
  { ui::VKEY_BACK,           false, false, false, IDC_BACK },
#if defined(OS_CHROMEOS)
  { ui::VKEY_F1,             false, false, false, IDC_BACK },
  { ui::VKEY_OEM_2,          false, true,  true,  IDC_SHOW_KEYBOARD_OVERLAY },
  { ui::VKEY_OEM_2,          true,  true,  true,  IDC_SHOW_KEYBOARD_OVERLAY },
#endif
  { ui::VKEY_D,              false, true,  false, IDC_BOOKMARK_PAGE },
  { ui::VKEY_D,              true,  true,  false, IDC_BOOKMARK_ALL_TABS },
#if !defined(OS_CHROMEOS)
  { ui::VKEY_DELETE,         true,  true,  false, IDC_CLEAR_BROWSING_DATA },
#else
  { ui::VKEY_BACK,           true,  true,  false, IDC_CLEAR_BROWSING_DATA },
#endif
#if !defined(OS_CHROMEOS)
  { ui::VKEY_F4,             false, true,  false, IDC_CLOSE_TAB },
#endif
  { ui::VKEY_W,              false, true,  false, IDC_CLOSE_TAB },
  { ui::VKEY_W,              true,  true,  false, IDC_CLOSE_WINDOW },
#if !defined(OS_CHROMEOS)
  { ui::VKEY_F4,             false, false, true,  IDC_CLOSE_WINDOW },
#endif
#if !defined(USE_AURA)
  { ui::VKEY_Q,              true,  true,  false, IDC_EXIT },
#endif
  { ui::VKEY_F,              false, true,  false, IDC_FIND },
  { ui::VKEY_G,              false, true,  false, IDC_FIND_NEXT },
#if !defined(OS_CHROMEOS)
  { ui::VKEY_F3,             false, false, false, IDC_FIND_NEXT },
#endif
  { ui::VKEY_G,              true,  true,  false, IDC_FIND_PREVIOUS },
#if !defined(OS_CHROMEOS)
  { ui::VKEY_F3,             true,  false, false, IDC_FIND_PREVIOUS },
#endif
#if defined(OS_CHROMEOS)
  { ui::VKEY_S,              true,  false, true,  IDC_FOCUS_CHROMEOS_STATUS },
#endif
  { ui::VKEY_D,              false, false, true,  IDC_FOCUS_LOCATION },
  { ui::VKEY_L,              false, true,  false, IDC_FOCUS_LOCATION },
#if !defined(OS_CHROMEOS)
  { ui::VKEY_F10,            false, false, false, IDC_FOCUS_MENU_BAR },
#endif
  { ui::VKEY_MENU,           false, false, false, IDC_FOCUS_MENU_BAR },
#if !defined(OS_CHROMEOS)
  { ui::VKEY_F6,             false, false, false, IDC_FOCUS_NEXT_PANE },
#else
  { ui::VKEY_F2,             false, true,  false, IDC_FOCUS_NEXT_PANE },
#endif
#if !defined(OS_CHROMEOS)
  { ui::VKEY_F6,             true,  false, false, IDC_FOCUS_PREVIOUS_PANE },
#else
  { ui::VKEY_F1,             false, true,  false, IDC_FOCUS_PREVIOUS_PANE },
#endif
  { ui::VKEY_K,              false, true,  false, IDC_FOCUS_SEARCH },
  { ui::VKEY_E,              false, true,  false, IDC_FOCUS_SEARCH },
  { ui::VKEY_BROWSER_SEARCH, false, false, false, IDC_FOCUS_SEARCH },
  { ui::VKEY_T,              true,  false, true,  IDC_FOCUS_TOOLBAR },
  { ui::VKEY_B,              true,  false, true,  IDC_FOCUS_BOOKMARKS },
  { ui::VKEY_RIGHT,          false, false, true,  IDC_FORWARD },
  { ui::VKEY_BACK,           true,  false, false, IDC_FORWARD },
#if defined(OS_CHROMEOS)
  { ui::VKEY_F2,             false, false, false, IDC_FORWARD },
#endif
#if !defined(OS_CHROMEOS)
  { ui::VKEY_F11,            false, false, false, IDC_FULLSCREEN },
#else
  { ui::VKEY_F4,             false, false, false, IDC_FULLSCREEN },
#endif
#if !defined(OS_CHROMEOS)
  { ui::VKEY_F1,             false, false, false, IDC_HELP_PAGE },
#else
  { ui::VKEY_OEM_2,          false, true,  false, IDC_HELP_PAGE },
  { ui::VKEY_OEM_2,          true,  true,  false, IDC_HELP_PAGE },
#endif
#if defined(OS_CHROMEOS) && !defined(USE_AURA)
  { ui::VKEY_L,              true,  true,  false, IDC_LOCK_SCREEN },
#endif
  { ui::VKEY_I,              true,  true,  false, IDC_DEV_TOOLS },
#if defined(OS_CHROMEOS)
  { ui::VKEY_I,              false,  true,  true, IDC_FEEDBACK },
#endif
  { ui::VKEY_F12,            false, false, false, IDC_DEV_TOOLS },
  { ui::VKEY_J,              true,  true,  false, IDC_DEV_TOOLS_CONSOLE },
  { ui::VKEY_C,              true,  true,  false, IDC_DEV_TOOLS_INSPECT },
  { ui::VKEY_N,              true,  true,  false, IDC_NEW_INCOGNITO_WINDOW },
  { ui::VKEY_T,              false, true,  false, IDC_NEW_TAB },
  { ui::VKEY_N,              false, true,  false, IDC_NEW_WINDOW },
  { ui::VKEY_O,              false, true,  false, IDC_OPEN_FILE },
  { ui::VKEY_P,              false, true,  false, IDC_PRINT},
  { ui::VKEY_P,              true,  true,  false, IDC_ADVANCED_PRINT},
  { ui::VKEY_R,              false, true,  false, IDC_RELOAD },
  { ui::VKEY_R,              true,  true,  false, IDC_RELOAD_IGNORING_CACHE },
#if !defined(OS_CHROMEOS)
  { ui::VKEY_F5,             false, false, false, IDC_RELOAD },
  { ui::VKEY_F5,             false, true,  false, IDC_RELOAD_IGNORING_CACHE },
  { ui::VKEY_F5,             true,  false, false, IDC_RELOAD_IGNORING_CACHE },
#else
  { ui::VKEY_F3,             false, false, false, IDC_RELOAD },
  { ui::VKEY_F3,             false, true,  false, IDC_RELOAD_IGNORING_CACHE },
  { ui::VKEY_F3,             true,  false, false, IDC_RELOAD_IGNORING_CACHE },
#endif
  { ui::VKEY_HOME,           false, false, true,  IDC_HOME },
  { ui::VKEY_T,              true,  true,  false, IDC_RESTORE_TAB },
  { ui::VKEY_S,              false, true,  false, IDC_SAVE_PAGE },
#if defined(OS_CHROMEOS) && defined(USE_AURA)
  { ui::VKEY_T,              false, true,  true, IDC_NEW_CROSH_TAB },
#endif
#if defined(OS_CHROMEOS)
  { ui::VKEY_M,              false, true,  false, IDC_FILE_MANAGER },
  { ui::VKEY_LWIN,           false, false, false, IDC_SEARCH },
#endif
  { ui::VKEY_9,              false, true,  false, IDC_SELECT_LAST_TAB },
  { ui::VKEY_NUMPAD9,        false, true,  false, IDC_SELECT_LAST_TAB },
  { ui::VKEY_TAB,            false, true,  false, IDC_SELECT_NEXT_TAB },
  { ui::VKEY_NEXT,           false, true,  false, IDC_SELECT_NEXT_TAB },
  { ui::VKEY_TAB,            true,  true,  false, IDC_SELECT_PREVIOUS_TAB },
  { ui::VKEY_PRIOR,          false, true,  false, IDC_SELECT_PREVIOUS_TAB },
  { ui::VKEY_1,              false, true,  false, IDC_SELECT_TAB_0 },
  { ui::VKEY_NUMPAD1,        false, true,  false, IDC_SELECT_TAB_0 },
  { ui::VKEY_2,              false, true,  false, IDC_SELECT_TAB_1 },
  { ui::VKEY_NUMPAD2,        false, true,  false, IDC_SELECT_TAB_1 },
  { ui::VKEY_3,              false, true,  false, IDC_SELECT_TAB_2 },
  { ui::VKEY_NUMPAD3,        false, true,  false, IDC_SELECT_TAB_2 },
  { ui::VKEY_4,              false, true,  false, IDC_SELECT_TAB_3 },
  { ui::VKEY_NUMPAD4,        false, true,  false, IDC_SELECT_TAB_3 },
  { ui::VKEY_5,              false, true,  false, IDC_SELECT_TAB_4 },
  { ui::VKEY_NUMPAD5,        false, true,  false, IDC_SELECT_TAB_4 },
  { ui::VKEY_6,              false, true,  false, IDC_SELECT_TAB_5 },
  { ui::VKEY_NUMPAD6,        false, true,  false, IDC_SELECT_TAB_5 },
  { ui::VKEY_7,              false, true,  false, IDC_SELECT_TAB_6 },
  { ui::VKEY_NUMPAD7,        false, true,  false, IDC_SELECT_TAB_6 },
  { ui::VKEY_8,              false, true,  false, IDC_SELECT_TAB_7 },
  { ui::VKEY_NUMPAD8,        false, true,  false, IDC_SELECT_TAB_7 },
  { ui::VKEY_B,              true,  true,  false, IDC_SHOW_BOOKMARK_BAR },
  { ui::VKEY_O,              true,  true,  false, IDC_SHOW_BOOKMARK_MANAGER },
  { ui::VKEY_J,              false, true,  false, IDC_SHOW_DOWNLOADS },
  { ui::VKEY_H,              false, true,  false, IDC_SHOW_HISTORY },
  { ui::VKEY_F,              false, false, true,  IDC_SHOW_APP_MENU},
  { ui::VKEY_E,              false, false, true,  IDC_SHOW_APP_MENU},
#if !defined(OS_CHROMEOS)
  { ui::VKEY_M,              true,  true,  false, IDC_SHOW_AVATAR_MENU},
#endif
  { ui::VKEY_ESCAPE,         false, false, false, IDC_STOP },
  { ui::VKEY_ESCAPE,         true,  false, false, IDC_TASK_MANAGER },
  { ui::VKEY_OEM_PERIOD,     true,  true,  false, IDC_TOGGLE_SPEECH_INPUT },
  { ui::VKEY_U,              false, true,  false, IDC_VIEW_SOURCE },
  { ui::VKEY_OEM_MINUS,      false, true,  false, IDC_ZOOM_MINUS },
  { ui::VKEY_OEM_MINUS,      true,  true,  false, IDC_ZOOM_MINUS },
  { ui::VKEY_SUBTRACT,       false, true,  false, IDC_ZOOM_MINUS },
  { ui::VKEY_0,              false, true,  false, IDC_ZOOM_NORMAL },
  { ui::VKEY_NUMPAD0,        false, true,  false, IDC_ZOOM_NORMAL },
  { ui::VKEY_OEM_PLUS,       false, true,  false, IDC_ZOOM_PLUS },
  { ui::VKEY_OEM_PLUS,       true,  true,  false, IDC_ZOOM_PLUS },
  { ui::VKEY_ADD,            false, true,  false, IDC_ZOOM_PLUS },
};

const size_t kAcceleratorMapLength = arraysize(kAcceleratorMap);

}  // namespace browser
<commit_msg>Change the shortcut for Feedback. Change the shortcut for Feedback on ChromeOS from Ctrl+Alt+i to Shift+Alt+i.<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/ui/views/accelerator_table.h"

#include "base/basictypes.h"
#include "chrome/app/chrome_command_ids.h"
#include "ui/base/keycodes/keyboard_codes.h"

namespace browser {

// NOTE: Keep this list in the same (mostly-alphabetical) order as
// the Windows accelerators in ../../app/chrome_dll.rc.
// Do not use Ctrl-Alt as a shortcut modifier, as it is used by i18n keyboards:
// http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx
const AcceleratorMapping kAcceleratorMap[] = {
  // Keycode                  Shift  Ctrl   Alt    Command ID
  { ui::VKEY_LEFT,           false, false, true,  IDC_BACK },
  { ui::VKEY_BACK,           false, false, false, IDC_BACK },
#if defined(OS_CHROMEOS)
  { ui::VKEY_F1,             false, false, false, IDC_BACK },
  { ui::VKEY_OEM_2,          false, true,  true,  IDC_SHOW_KEYBOARD_OVERLAY },
  { ui::VKEY_OEM_2,          true,  true,  true,  IDC_SHOW_KEYBOARD_OVERLAY },
#endif
  { ui::VKEY_D,              false, true,  false, IDC_BOOKMARK_PAGE },
  { ui::VKEY_D,              true,  true,  false, IDC_BOOKMARK_ALL_TABS },
#if !defined(OS_CHROMEOS)
  { ui::VKEY_DELETE,         true,  true,  false, IDC_CLEAR_BROWSING_DATA },
#else
  { ui::VKEY_BACK,           true,  true,  false, IDC_CLEAR_BROWSING_DATA },
#endif
#if !defined(OS_CHROMEOS)
  { ui::VKEY_F4,             false, true,  false, IDC_CLOSE_TAB },
#endif
  { ui::VKEY_W,              false, true,  false, IDC_CLOSE_TAB },
  { ui::VKEY_W,              true,  true,  false, IDC_CLOSE_WINDOW },
#if !defined(OS_CHROMEOS)
  { ui::VKEY_F4,             false, false, true,  IDC_CLOSE_WINDOW },
#endif
#if !defined(USE_AURA)
  { ui::VKEY_Q,              true,  true,  false, IDC_EXIT },
#endif
  { ui::VKEY_F,              false, true,  false, IDC_FIND },
  { ui::VKEY_G,              false, true,  false, IDC_FIND_NEXT },
#if !defined(OS_CHROMEOS)
  { ui::VKEY_F3,             false, false, false, IDC_FIND_NEXT },
#endif
  { ui::VKEY_G,              true,  true,  false, IDC_FIND_PREVIOUS },
#if !defined(OS_CHROMEOS)
  { ui::VKEY_F3,             true,  false, false, IDC_FIND_PREVIOUS },
#endif
#if defined(OS_CHROMEOS)
  { ui::VKEY_S,              true,  false, true,  IDC_FOCUS_CHROMEOS_STATUS },
#endif
  { ui::VKEY_D,              false, false, true,  IDC_FOCUS_LOCATION },
  { ui::VKEY_L,              false, true,  false, IDC_FOCUS_LOCATION },
#if !defined(OS_CHROMEOS)
  { ui::VKEY_F10,            false, false, false, IDC_FOCUS_MENU_BAR },
#endif
  { ui::VKEY_MENU,           false, false, false, IDC_FOCUS_MENU_BAR },
#if !defined(OS_CHROMEOS)
  { ui::VKEY_F6,             false, false, false, IDC_FOCUS_NEXT_PANE },
#else
  { ui::VKEY_F2,             false, true,  false, IDC_FOCUS_NEXT_PANE },
#endif
#if !defined(OS_CHROMEOS)
  { ui::VKEY_F6,             true,  false, false, IDC_FOCUS_PREVIOUS_PANE },
#else
  { ui::VKEY_F1,             false, true,  false, IDC_FOCUS_PREVIOUS_PANE },
#endif
  { ui::VKEY_K,              false, true,  false, IDC_FOCUS_SEARCH },
  { ui::VKEY_E,              false, true,  false, IDC_FOCUS_SEARCH },
  { ui::VKEY_BROWSER_SEARCH, false, false, false, IDC_FOCUS_SEARCH },
  { ui::VKEY_T,              true,  false, true,  IDC_FOCUS_TOOLBAR },
  { ui::VKEY_B,              true,  false, true,  IDC_FOCUS_BOOKMARKS },
  { ui::VKEY_RIGHT,          false, false, true,  IDC_FORWARD },
  { ui::VKEY_BACK,           true,  false, false, IDC_FORWARD },
#if defined(OS_CHROMEOS)
  { ui::VKEY_F2,             false, false, false, IDC_FORWARD },
#endif
#if !defined(OS_CHROMEOS)
  { ui::VKEY_F11,            false, false, false, IDC_FULLSCREEN },
#else
  { ui::VKEY_F4,             false, false, false, IDC_FULLSCREEN },
#endif
#if !defined(OS_CHROMEOS)
  { ui::VKEY_F1,             false, false, false, IDC_HELP_PAGE },
#else
  { ui::VKEY_OEM_2,          false, true,  false, IDC_HELP_PAGE },
  { ui::VKEY_OEM_2,          true,  true,  false, IDC_HELP_PAGE },
#endif
#if defined(OS_CHROMEOS) && !defined(USE_AURA)
  { ui::VKEY_L,              true,  true,  false, IDC_LOCK_SCREEN },
#endif
  { ui::VKEY_I,              true,  true,  false, IDC_DEV_TOOLS },
#if defined(OS_CHROMEOS)
  { ui::VKEY_I,              true,  false,  true, IDC_FEEDBACK },
#endif
  { ui::VKEY_F12,            false, false, false, IDC_DEV_TOOLS },
  { ui::VKEY_J,              true,  true,  false, IDC_DEV_TOOLS_CONSOLE },
  { ui::VKEY_C,              true,  true,  false, IDC_DEV_TOOLS_INSPECT },
  { ui::VKEY_N,              true,  true,  false, IDC_NEW_INCOGNITO_WINDOW },
  { ui::VKEY_T,              false, true,  false, IDC_NEW_TAB },
  { ui::VKEY_N,              false, true,  false, IDC_NEW_WINDOW },
  { ui::VKEY_O,              false, true,  false, IDC_OPEN_FILE },
  { ui::VKEY_P,              false, true,  false, IDC_PRINT},
  { ui::VKEY_P,              true,  true,  false, IDC_ADVANCED_PRINT},
  { ui::VKEY_R,              false, true,  false, IDC_RELOAD },
  { ui::VKEY_R,              true,  true,  false, IDC_RELOAD_IGNORING_CACHE },
#if !defined(OS_CHROMEOS)
  { ui::VKEY_F5,             false, false, false, IDC_RELOAD },
  { ui::VKEY_F5,             false, true,  false, IDC_RELOAD_IGNORING_CACHE },
  { ui::VKEY_F5,             true,  false, false, IDC_RELOAD_IGNORING_CACHE },
#else
  { ui::VKEY_F3,             false, false, false, IDC_RELOAD },
  { ui::VKEY_F3,             false, true,  false, IDC_RELOAD_IGNORING_CACHE },
  { ui::VKEY_F3,             true,  false, false, IDC_RELOAD_IGNORING_CACHE },
#endif
  { ui::VKEY_HOME,           false, false, true,  IDC_HOME },
  { ui::VKEY_T,              true,  true,  false, IDC_RESTORE_TAB },
  { ui::VKEY_S,              false, true,  false, IDC_SAVE_PAGE },
#if defined(OS_CHROMEOS) && defined(USE_AURA)
  { ui::VKEY_T,              false, true,  true, IDC_NEW_CROSH_TAB },
#endif
#if defined(OS_CHROMEOS)
  { ui::VKEY_M,              false, true,  false, IDC_FILE_MANAGER },
  { ui::VKEY_LWIN,           false, false, false, IDC_SEARCH },
#endif
  { ui::VKEY_9,              false, true,  false, IDC_SELECT_LAST_TAB },
  { ui::VKEY_NUMPAD9,        false, true,  false, IDC_SELECT_LAST_TAB },
  { ui::VKEY_TAB,            false, true,  false, IDC_SELECT_NEXT_TAB },
  { ui::VKEY_NEXT,           false, true,  false, IDC_SELECT_NEXT_TAB },
  { ui::VKEY_TAB,            true,  true,  false, IDC_SELECT_PREVIOUS_TAB },
  { ui::VKEY_PRIOR,          false, true,  false, IDC_SELECT_PREVIOUS_TAB },
  { ui::VKEY_1,              false, true,  false, IDC_SELECT_TAB_0 },
  { ui::VKEY_NUMPAD1,        false, true,  false, IDC_SELECT_TAB_0 },
  { ui::VKEY_2,              false, true,  false, IDC_SELECT_TAB_1 },
  { ui::VKEY_NUMPAD2,        false, true,  false, IDC_SELECT_TAB_1 },
  { ui::VKEY_3,              false, true,  false, IDC_SELECT_TAB_2 },
  { ui::VKEY_NUMPAD3,        false, true,  false, IDC_SELECT_TAB_2 },
  { ui::VKEY_4,              false, true,  false, IDC_SELECT_TAB_3 },
  { ui::VKEY_NUMPAD4,        false, true,  false, IDC_SELECT_TAB_3 },
  { ui::VKEY_5,              false, true,  false, IDC_SELECT_TAB_4 },
  { ui::VKEY_NUMPAD5,        false, true,  false, IDC_SELECT_TAB_4 },
  { ui::VKEY_6,              false, true,  false, IDC_SELECT_TAB_5 },
  { ui::VKEY_NUMPAD6,        false, true,  false, IDC_SELECT_TAB_5 },
  { ui::VKEY_7,              false, true,  false, IDC_SELECT_TAB_6 },
  { ui::VKEY_NUMPAD7,        false, true,  false, IDC_SELECT_TAB_6 },
  { ui::VKEY_8,              false, true,  false, IDC_SELECT_TAB_7 },
  { ui::VKEY_NUMPAD8,        false, true,  false, IDC_SELECT_TAB_7 },
  { ui::VKEY_B,              true,  true,  false, IDC_SHOW_BOOKMARK_BAR },
  { ui::VKEY_O,              true,  true,  false, IDC_SHOW_BOOKMARK_MANAGER },
  { ui::VKEY_J,              false, true,  false, IDC_SHOW_DOWNLOADS },
  { ui::VKEY_H,              false, true,  false, IDC_SHOW_HISTORY },
  { ui::VKEY_F,              false, false, true,  IDC_SHOW_APP_MENU},
  { ui::VKEY_E,              false, false, true,  IDC_SHOW_APP_MENU},
#if !defined(OS_CHROMEOS)
  { ui::VKEY_M,              true,  true,  false, IDC_SHOW_AVATAR_MENU},
#endif
  { ui::VKEY_ESCAPE,         false, false, false, IDC_STOP },
  { ui::VKEY_ESCAPE,         true,  false, false, IDC_TASK_MANAGER },
  { ui::VKEY_OEM_PERIOD,     true,  true,  false, IDC_TOGGLE_SPEECH_INPUT },
  { ui::VKEY_U,              false, true,  false, IDC_VIEW_SOURCE },
  { ui::VKEY_OEM_MINUS,      false, true,  false, IDC_ZOOM_MINUS },
  { ui::VKEY_OEM_MINUS,      true,  true,  false, IDC_ZOOM_MINUS },
  { ui::VKEY_SUBTRACT,       false, true,  false, IDC_ZOOM_MINUS },
  { ui::VKEY_0,              false, true,  false, IDC_ZOOM_NORMAL },
  { ui::VKEY_NUMPAD0,        false, true,  false, IDC_ZOOM_NORMAL },
  { ui::VKEY_OEM_PLUS,       false, true,  false, IDC_ZOOM_PLUS },
  { ui::VKEY_OEM_PLUS,       true,  true,  false, IDC_ZOOM_PLUS },
  { ui::VKEY_ADD,            false, true,  false, IDC_ZOOM_PLUS },
};

const size_t kAcceleratorMapLength = arraysize(kAcceleratorMap);

}  // namespace browser
<|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/views/bookmark_bubble_view.h"

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/keyboard_codes.h"
#include "base/string_util.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/bookmarks/bookmark_editor.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/views/info_bubble.h"
#include "chrome/common/notification_service.h"
#include "gfx/canvas.h"
#include "gfx/color_utils.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "views/event.h"
#include "views/standard_layout.h"
#include "views/controls/button/native_button.h"
#include "views/controls/textfield/textfield.h"
#include "views/focus/focus_manager.h"
#include "views/window/client_view.h"
#include "views/window/window.h"

using views::Combobox;
using views::ColumnSet;
using views::GridLayout;
using views::Label;
using views::Link;
using views::NativeButton;
using views::View;

// Padding between "Title:" and the actual title.
static const int kTitlePadding = 4;

// Minimum width for the fields - they will push out the size of the bubble if
// necessary. This should be big enough so that the field pushes the right side
// of the bubble far enough so that the edit button's left edge is to the right
// of the field's left edge.
static const int kMinimumFieldSize = 180;

// Bubble close image.
static SkBitmap* kCloseImage = NULL;

// Declared in browser_dialogs.h so callers don't have to depend on our header.

namespace browser {

void ShowBookmarkBubbleView(views::Window* parent,
                            const gfx::Rect& bounds,
                            InfoBubbleDelegate* delegate,
                            Profile* profile,
                            const GURL& url,
                            bool newly_bookmarked) {
  BookmarkBubbleView::Show(parent, bounds, delegate, profile, url,
                           newly_bookmarked);
}

void HideBookmarkBubbleView() {
  BookmarkBubbleView::Hide();
}

bool IsBookmarkBubbleViewShowing() {
  return BookmarkBubbleView::IsShowing();
}

}  // namespace browser

// BookmarkBubbleView ---------------------------------------------------------

BookmarkBubbleView* BookmarkBubbleView::bubble_ = NULL;

// static
void BookmarkBubbleView::Show(views::Window* parent,
                              const gfx::Rect& bounds,
                              InfoBubbleDelegate* delegate,
                              Profile* profile,
                              const GURL& url,
                              bool newly_bookmarked) {
  if (IsShowing())
    return;

  bubble_ = new BookmarkBubbleView(delegate, profile, url, newly_bookmarked);
  InfoBubble* info_bubble =
      InfoBubble::Show(parent->GetClientView()->GetWidget(), bounds,
                   BubbleBorder::TOP_LEFT, bubble_, bubble_);
  bubble_->set_info_bubble(info_bubble);
  GURL url_ptr(url);
  NotificationService::current()->Notify(
      NotificationType::BOOKMARK_BUBBLE_SHOWN,
      Source<Profile>(profile->GetOriginalProfile()),
      Details<GURL>(&url_ptr));
  bubble_->BubbleShown();
}

// static
bool BookmarkBubbleView::IsShowing() {
  return bubble_ != NULL;
}

void BookmarkBubbleView::Hide() {
  if (IsShowing())
    bubble_->Close();
}

BookmarkBubbleView::~BookmarkBubbleView() {
  if (apply_edits_) {
    ApplyEdits();
  } else if (remove_bookmark_) {
    BookmarkModel* model = profile_->GetBookmarkModel();
    const BookmarkNode* node = model->GetMostRecentlyAddedNodeForURL(url_);
    if (node)
      model->Remove(node->GetParent(), node->GetParent()->IndexOfChild(node));
  }
}

void BookmarkBubbleView::DidChangeBounds(const gfx::Rect& previous,
                                         const gfx::Rect& current) {
  Layout();
}

void BookmarkBubbleView::BubbleShown() {
  DCHECK(GetWidget());
  GetFocusManager()->RegisterAccelerator(
      views::Accelerator(base::VKEY_RETURN, false, false, false), this);

  title_tf_->RequestFocus();
  title_tf_->SelectAll();
}

bool BookmarkBubbleView::AcceleratorPressed(
    const views::Accelerator& accelerator) {
  if (accelerator.GetKeyCode() != base::VKEY_RETURN)
    return false;

  if (edit_button_->HasFocus())
    HandleButtonPressed(edit_button_);
  else
    HandleButtonPressed(close_button_);
  return true;
}

void BookmarkBubbleView::ViewHierarchyChanged(bool is_add, View* parent,
                                              View* child) {
  if (is_add && child == this)
    Init();
}

BookmarkBubbleView::BookmarkBubbleView(InfoBubbleDelegate* delegate,
                                       Profile* profile,
                                       const GURL& url,
                                       bool newly_bookmarked)
    : delegate_(delegate),
      profile_(profile),
      url_(url),
      newly_bookmarked_(newly_bookmarked),
      parent_model_(
          profile_->GetBookmarkModel(),
          profile_->GetBookmarkModel()->GetMostRecentlyAddedNodeForURL(url)),
      remove_bookmark_(false),
      apply_edits_(true) {
}

void BookmarkBubbleView::Init() {
  static SkColor kTitleColor;
  static bool initialized = false;
  if (!initialized) {
    kTitleColor = color_utils::GetReadableColor(SkColorSetRGB(6, 45, 117),
                                                InfoBubble::kBackgroundColor);
    kCloseImage = ResourceBundle::GetSharedInstance().GetBitmapNamed(
      IDR_INFO_BUBBLE_CLOSE);

    initialized = true;
  }

  remove_link_ = new Link(l10n_util::GetString(
      IDS_BOOMARK_BUBBLE_REMOVE_BOOKMARK));
  remove_link_->SetController(this);

  edit_button_ = new NativeButton(
      this, l10n_util::GetString(IDS_BOOMARK_BUBBLE_OPTIONS));

  close_button_ = new NativeButton(this, l10n_util::GetString(IDS_DONE));
  close_button_->SetIsDefault(true);

  Label* combobox_label = new Label(
      l10n_util::GetString(IDS_BOOMARK_BUBBLE_FOLDER_TEXT));

  parent_combobox_ = new Combobox(&parent_model_);
  parent_combobox_->SetSelectedItem(parent_model_.node_parent_index());
  parent_combobox_->set_listener(this);
  parent_combobox_->SetAccessibleName(combobox_label->GetText());

  Label* title_label = new Label(l10n_util::GetString(
      newly_bookmarked_ ? IDS_BOOMARK_BUBBLE_PAGE_BOOKMARKED :
                          IDS_BOOMARK_BUBBLE_PAGE_BOOKMARK));
  title_label->SetFont(
      ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::MediumFont));
  title_label->SetColor(kTitleColor);

  GridLayout* layout = new GridLayout(this);
  SetLayoutManager(layout);

  ColumnSet* cs = layout->AddColumnSet(0);

  // Top (title) row.
  cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, GridLayout::USE_PREF,
                0, 0);
  cs->AddPaddingColumn(1, kUnrelatedControlHorizontalSpacing);
  cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, GridLayout::USE_PREF,
                0, 0);

  // Middle (input field) rows.
  cs = layout->AddColumnSet(2);
  cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
                GridLayout::USE_PREF, 0, 0);
  cs->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
  cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
                GridLayout::USE_PREF, 0, kMinimumFieldSize);

  // Bottom (buttons) row.
  cs = layout->AddColumnSet(3);
  cs->AddPaddingColumn(1, kRelatedControlHorizontalSpacing);
  cs->AddColumn(GridLayout::LEADING, GridLayout::TRAILING, 0,
                GridLayout::USE_PREF, 0, 0);
  // We subtract 2 to account for the natural button padding, and
  // to bring the separation visually in line with the row separation
  // height.
  cs->AddPaddingColumn(0, kRelatedButtonHSpacing - 2);
  cs->AddColumn(GridLayout::LEADING, GridLayout::TRAILING, 0,
                GridLayout::USE_PREF, 0, 0);

  layout->StartRow(0, 0);
  layout->AddView(title_label);
  layout->AddView(remove_link_);

  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
  layout->StartRow(0, 2);
  layout->AddView(
      new Label(l10n_util::GetString(IDS_BOOMARK_BUBBLE_TITLE_TEXT)));
  title_tf_ = new views::Textfield();
  title_tf_->SetText(WideToUTF16(GetTitle()));
  layout->AddView(title_tf_);

  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);

  layout->StartRow(0, 2);
  layout->AddView(combobox_label);
  layout->AddView(parent_combobox_);
  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);

  layout->StartRow(0, 3);
  layout->AddView(edit_button_);
  layout->AddView(close_button_);
}

std::wstring BookmarkBubbleView::GetTitle() {
  BookmarkModel* bookmark_model= profile_->GetBookmarkModel();
  const BookmarkNode* node =
      bookmark_model->GetMostRecentlyAddedNodeForURL(url_);
  if (node)
    return node->GetTitle();
  else
    NOTREACHED();
  return std::wstring();
}

void BookmarkBubbleView::ButtonPressed(
    views::Button* sender, const views::Event& event) {
  HandleButtonPressed(sender);
}

void BookmarkBubbleView::LinkActivated(Link* source, int event_flags) {
  DCHECK(source == remove_link_);
  UserMetrics::RecordAction(UserMetricsAction("BookmarkBubble_Unstar"),
                            profile_);

  // Set this so we remove the bookmark after the window closes.
  remove_bookmark_ = true;
  apply_edits_ = false;

  info_bubble_->set_fade_away_on_close(true);
  Close();
}

void BookmarkBubbleView::ItemChanged(Combobox* combobox,
                                     int prev_index,
                                     int new_index) {
  if (new_index + 1 == parent_model_.GetItemCount()) {
    UserMetrics::RecordAction(
              UserMetricsAction("BookmarkBubble_EditFromCombobox"), profile_);

    ShowEditor();
    return;
  }
}

void BookmarkBubbleView::InfoBubbleClosing(InfoBubble* info_bubble,
                                           bool closed_by_escape) {
  if (closed_by_escape) {
    remove_bookmark_ = newly_bookmarked_;
    apply_edits_ = false;
  }

  // We have to reset |bubble_| here, not in our destructor, because we'll be
  // destroyed asynchronously and the shown state will be checked before then.
  DCHECK(bubble_ == this);
  bubble_ = NULL;

  if (delegate_)
    delegate_->InfoBubbleClosing(info_bubble, closed_by_escape);
  NotificationService::current()->Notify(
      NotificationType::BOOKMARK_BUBBLE_HIDDEN,
      Source<Profile>(profile_->GetOriginalProfile()),
      NotificationService::NoDetails());
}

bool BookmarkBubbleView::CloseOnEscape() {
  return delegate_ ? delegate_->CloseOnEscape() : true;
}

std::wstring BookmarkBubbleView::accessible_name() {
  return l10n_util::GetString(IDS_BOOMARK_BUBBLE_ADD_BOOKMARK);
}

void BookmarkBubbleView::Close() {
  static_cast<InfoBubble*>(GetWidget())->Close();
}

void BookmarkBubbleView::HandleButtonPressed(views::Button* sender) {
  if (sender == edit_button_) {
    UserMetrics::RecordAction(UserMetricsAction("BookmarkBubble_Edit"),
                              profile_);
    info_bubble_->set_fade_away_on_close(true);
    ShowEditor();
  } else {
    DCHECK(sender == close_button_);
    info_bubble_->set_fade_away_on_close(true);
    Close();
  }
  // WARNING: we've most likely been deleted when CloseWindow returns.
}

void BookmarkBubbleView::ShowEditor() {
  const BookmarkNode* node =
      profile_->GetBookmarkModel()->GetMostRecentlyAddedNodeForURL(url_);

  // Commit any edits now.
  ApplyEdits();

#if defined(OS_WIN)
  // Parent the editor to our root ancestor (not the root we're in, as that
  // is the info bubble and will close shortly).
  HWND parent = GetAncestor(GetWidget()->GetNativeView(), GA_ROOTOWNER);

  // We're about to show the bookmark editor. When the bookmark editor closes
  // we want the browser to become active. WidgetWin::Hide() does a hide in
  // a such way that activation isn't changed, which means when we close
  // Windows gets confused as to who it should give active status to. We
  // explicitly hide the bookmark bubble window in such a way that activation
  // status changes. That way, when the editor closes, activation is properly
  // restored to the browser.
  ShowWindow(GetWidget()->GetNativeView(), SW_HIDE);
#else
  gfx::NativeWindow parent = GTK_WINDOW(
      static_cast<views::WidgetGtk*>(GetWidget())->GetTransientParent());
#endif

  // Even though we just hid the window, we need to invoke Close to schedule
  // the delete and all that.
  Close();

  if (node) {
    BookmarkEditor::Show(parent, profile_, NULL,
                         BookmarkEditor::EditDetails(node),
                         BookmarkEditor::SHOW_TREE);
  }
}

void BookmarkBubbleView::ApplyEdits() {
  // Set this to make sure we don't attempt to apply edits again.
  apply_edits_ = false;

  BookmarkModel* model = profile_->GetBookmarkModel();
  const BookmarkNode* node = model->GetMostRecentlyAddedNodeForURL(url_);
  if (node) {
    const std::wstring new_title = UTF16ToWide(title_tf_->text());
    if (new_title != node->GetTitle()) {
      model->SetTitle(node, new_title);
      UserMetrics::RecordAction(
          UserMetricsAction("BookmarkBubble_ChangeTitleInBubble"),
          profile_);
    }
    // Last index means 'Choose another folder...'
    if (parent_combobox_->selected_item() <
        parent_model_.GetItemCount() - 1) {
      const BookmarkNode* new_parent =
          parent_model_.GetNodeAt(parent_combobox_->selected_item());
      if (new_parent != node->GetParent()) {
        UserMetrics::RecordAction(
            UserMetricsAction("BookmarkBubble_ChangeParent"), profile_);
        model->Move(node, new_parent, new_parent->GetChildCount());
      }
    }
  }
}
<commit_msg>Makes the bookmark bubble right aligned.<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/views/bookmark_bubble_view.h"

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/keyboard_codes.h"
#include "base/string_util.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/bookmarks/bookmark_editor.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_utils.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/views/info_bubble.h"
#include "chrome/common/notification_service.h"
#include "gfx/canvas.h"
#include "gfx/color_utils.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "views/event.h"
#include "views/standard_layout.h"
#include "views/controls/button/native_button.h"
#include "views/controls/textfield/textfield.h"
#include "views/focus/focus_manager.h"
#include "views/window/client_view.h"
#include "views/window/window.h"

using views::Combobox;
using views::ColumnSet;
using views::GridLayout;
using views::Label;
using views::Link;
using views::NativeButton;
using views::View;

// Padding between "Title:" and the actual title.
static const int kTitlePadding = 4;

// Minimum width for the fields - they will push out the size of the bubble if
// necessary. This should be big enough so that the field pushes the right side
// of the bubble far enough so that the edit button's left edge is to the right
// of the field's left edge.
static const int kMinimumFieldSize = 180;

// Bubble close image.
static SkBitmap* kCloseImage = NULL;

// Declared in browser_dialogs.h so callers don't have to depend on our header.

namespace browser {

void ShowBookmarkBubbleView(views::Window* parent,
                            const gfx::Rect& bounds,
                            InfoBubbleDelegate* delegate,
                            Profile* profile,
                            const GURL& url,
                            bool newly_bookmarked) {
  BookmarkBubbleView::Show(parent, bounds, delegate, profile, url,
                           newly_bookmarked);
}

void HideBookmarkBubbleView() {
  BookmarkBubbleView::Hide();
}

bool IsBookmarkBubbleViewShowing() {
  return BookmarkBubbleView::IsShowing();
}

}  // namespace browser

// BookmarkBubbleView ---------------------------------------------------------

BookmarkBubbleView* BookmarkBubbleView::bubble_ = NULL;

// static
void BookmarkBubbleView::Show(views::Window* parent,
                              const gfx::Rect& bounds,
                              InfoBubbleDelegate* delegate,
                              Profile* profile,
                              const GURL& url,
                              bool newly_bookmarked) {
  if (IsShowing())
    return;

  bubble_ = new BookmarkBubbleView(delegate, profile, url, newly_bookmarked);
  InfoBubble* info_bubble =
      InfoBubble::Show(parent->GetClientView()->GetWidget(), bounds,
                   BubbleBorder::TOP_RIGHT, bubble_, bubble_);
  bubble_->set_info_bubble(info_bubble);
  GURL url_ptr(url);
  NotificationService::current()->Notify(
      NotificationType::BOOKMARK_BUBBLE_SHOWN,
      Source<Profile>(profile->GetOriginalProfile()),
      Details<GURL>(&url_ptr));
  bubble_->BubbleShown();
}

// static
bool BookmarkBubbleView::IsShowing() {
  return bubble_ != NULL;
}

void BookmarkBubbleView::Hide() {
  if (IsShowing())
    bubble_->Close();
}

BookmarkBubbleView::~BookmarkBubbleView() {
  if (apply_edits_) {
    ApplyEdits();
  } else if (remove_bookmark_) {
    BookmarkModel* model = profile_->GetBookmarkModel();
    const BookmarkNode* node = model->GetMostRecentlyAddedNodeForURL(url_);
    if (node)
      model->Remove(node->GetParent(), node->GetParent()->IndexOfChild(node));
  }
}

void BookmarkBubbleView::DidChangeBounds(const gfx::Rect& previous,
                                         const gfx::Rect& current) {
  Layout();
}

void BookmarkBubbleView::BubbleShown() {
  DCHECK(GetWidget());
  GetFocusManager()->RegisterAccelerator(
      views::Accelerator(base::VKEY_RETURN, false, false, false), this);

  title_tf_->RequestFocus();
  title_tf_->SelectAll();
}

bool BookmarkBubbleView::AcceleratorPressed(
    const views::Accelerator& accelerator) {
  if (accelerator.GetKeyCode() != base::VKEY_RETURN)
    return false;

  if (edit_button_->HasFocus())
    HandleButtonPressed(edit_button_);
  else
    HandleButtonPressed(close_button_);
  return true;
}

void BookmarkBubbleView::ViewHierarchyChanged(bool is_add, View* parent,
                                              View* child) {
  if (is_add && child == this)
    Init();
}

BookmarkBubbleView::BookmarkBubbleView(InfoBubbleDelegate* delegate,
                                       Profile* profile,
                                       const GURL& url,
                                       bool newly_bookmarked)
    : delegate_(delegate),
      profile_(profile),
      url_(url),
      newly_bookmarked_(newly_bookmarked),
      parent_model_(
          profile_->GetBookmarkModel(),
          profile_->GetBookmarkModel()->GetMostRecentlyAddedNodeForURL(url)),
      remove_bookmark_(false),
      apply_edits_(true) {
}

void BookmarkBubbleView::Init() {
  static SkColor kTitleColor;
  static bool initialized = false;
  if (!initialized) {
    kTitleColor = color_utils::GetReadableColor(SkColorSetRGB(6, 45, 117),
                                                InfoBubble::kBackgroundColor);
    kCloseImage = ResourceBundle::GetSharedInstance().GetBitmapNamed(
      IDR_INFO_BUBBLE_CLOSE);

    initialized = true;
  }

  remove_link_ = new Link(l10n_util::GetString(
      IDS_BOOMARK_BUBBLE_REMOVE_BOOKMARK));
  remove_link_->SetController(this);

  edit_button_ = new NativeButton(
      this, l10n_util::GetString(IDS_BOOMARK_BUBBLE_OPTIONS));

  close_button_ = new NativeButton(this, l10n_util::GetString(IDS_DONE));
  close_button_->SetIsDefault(true);

  Label* combobox_label = new Label(
      l10n_util::GetString(IDS_BOOMARK_BUBBLE_FOLDER_TEXT));

  parent_combobox_ = new Combobox(&parent_model_);
  parent_combobox_->SetSelectedItem(parent_model_.node_parent_index());
  parent_combobox_->set_listener(this);
  parent_combobox_->SetAccessibleName(combobox_label->GetText());

  Label* title_label = new Label(l10n_util::GetString(
      newly_bookmarked_ ? IDS_BOOMARK_BUBBLE_PAGE_BOOKMARKED :
                          IDS_BOOMARK_BUBBLE_PAGE_BOOKMARK));
  title_label->SetFont(
      ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::MediumFont));
  title_label->SetColor(kTitleColor);

  GridLayout* layout = new GridLayout(this);
  SetLayoutManager(layout);

  ColumnSet* cs = layout->AddColumnSet(0);

  // Top (title) row.
  cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, GridLayout::USE_PREF,
                0, 0);
  cs->AddPaddingColumn(1, kUnrelatedControlHorizontalSpacing);
  cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, GridLayout::USE_PREF,
                0, 0);

  // Middle (input field) rows.
  cs = layout->AddColumnSet(2);
  cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
                GridLayout::USE_PREF, 0, 0);
  cs->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
  cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
                GridLayout::USE_PREF, 0, kMinimumFieldSize);

  // Bottom (buttons) row.
  cs = layout->AddColumnSet(3);
  cs->AddPaddingColumn(1, kRelatedControlHorizontalSpacing);
  cs->AddColumn(GridLayout::LEADING, GridLayout::TRAILING, 0,
                GridLayout::USE_PREF, 0, 0);
  // We subtract 2 to account for the natural button padding, and
  // to bring the separation visually in line with the row separation
  // height.
  cs->AddPaddingColumn(0, kRelatedButtonHSpacing - 2);
  cs->AddColumn(GridLayout::LEADING, GridLayout::TRAILING, 0,
                GridLayout::USE_PREF, 0, 0);

  layout->StartRow(0, 0);
  layout->AddView(title_label);
  layout->AddView(remove_link_);

  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
  layout->StartRow(0, 2);
  layout->AddView(
      new Label(l10n_util::GetString(IDS_BOOMARK_BUBBLE_TITLE_TEXT)));
  title_tf_ = new views::Textfield();
  title_tf_->SetText(WideToUTF16(GetTitle()));
  layout->AddView(title_tf_);

  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);

  layout->StartRow(0, 2);
  layout->AddView(combobox_label);
  layout->AddView(parent_combobox_);
  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);

  layout->StartRow(0, 3);
  layout->AddView(edit_button_);
  layout->AddView(close_button_);
}

std::wstring BookmarkBubbleView::GetTitle() {
  BookmarkModel* bookmark_model= profile_->GetBookmarkModel();
  const BookmarkNode* node =
      bookmark_model->GetMostRecentlyAddedNodeForURL(url_);
  if (node)
    return node->GetTitle();
  else
    NOTREACHED();
  return std::wstring();
}

void BookmarkBubbleView::ButtonPressed(
    views::Button* sender, const views::Event& event) {
  HandleButtonPressed(sender);
}

void BookmarkBubbleView::LinkActivated(Link* source, int event_flags) {
  DCHECK(source == remove_link_);
  UserMetrics::RecordAction(UserMetricsAction("BookmarkBubble_Unstar"),
                            profile_);

  // Set this so we remove the bookmark after the window closes.
  remove_bookmark_ = true;
  apply_edits_ = false;

  info_bubble_->set_fade_away_on_close(true);
  Close();
}

void BookmarkBubbleView::ItemChanged(Combobox* combobox,
                                     int prev_index,
                                     int new_index) {
  if (new_index + 1 == parent_model_.GetItemCount()) {
    UserMetrics::RecordAction(
              UserMetricsAction("BookmarkBubble_EditFromCombobox"), profile_);

    ShowEditor();
    return;
  }
}

void BookmarkBubbleView::InfoBubbleClosing(InfoBubble* info_bubble,
                                           bool closed_by_escape) {
  if (closed_by_escape) {
    remove_bookmark_ = newly_bookmarked_;
    apply_edits_ = false;
  }

  // We have to reset |bubble_| here, not in our destructor, because we'll be
  // destroyed asynchronously and the shown state will be checked before then.
  DCHECK(bubble_ == this);
  bubble_ = NULL;

  if (delegate_)
    delegate_->InfoBubbleClosing(info_bubble, closed_by_escape);
  NotificationService::current()->Notify(
      NotificationType::BOOKMARK_BUBBLE_HIDDEN,
      Source<Profile>(profile_->GetOriginalProfile()),
      NotificationService::NoDetails());
}

bool BookmarkBubbleView::CloseOnEscape() {
  return delegate_ ? delegate_->CloseOnEscape() : true;
}

std::wstring BookmarkBubbleView::accessible_name() {
  return l10n_util::GetString(IDS_BOOMARK_BUBBLE_ADD_BOOKMARK);
}

void BookmarkBubbleView::Close() {
  static_cast<InfoBubble*>(GetWidget())->Close();
}

void BookmarkBubbleView::HandleButtonPressed(views::Button* sender) {
  if (sender == edit_button_) {
    UserMetrics::RecordAction(UserMetricsAction("BookmarkBubble_Edit"),
                              profile_);
    info_bubble_->set_fade_away_on_close(true);
    ShowEditor();
  } else {
    DCHECK(sender == close_button_);
    info_bubble_->set_fade_away_on_close(true);
    Close();
  }
  // WARNING: we've most likely been deleted when CloseWindow returns.
}

void BookmarkBubbleView::ShowEditor() {
  const BookmarkNode* node =
      profile_->GetBookmarkModel()->GetMostRecentlyAddedNodeForURL(url_);

  // Commit any edits now.
  ApplyEdits();

#if defined(OS_WIN)
  // Parent the editor to our root ancestor (not the root we're in, as that
  // is the info bubble and will close shortly).
  HWND parent = GetAncestor(GetWidget()->GetNativeView(), GA_ROOTOWNER);

  // We're about to show the bookmark editor. When the bookmark editor closes
  // we want the browser to become active. WidgetWin::Hide() does a hide in
  // a such way that activation isn't changed, which means when we close
  // Windows gets confused as to who it should give active status to. We
  // explicitly hide the bookmark bubble window in such a way that activation
  // status changes. That way, when the editor closes, activation is properly
  // restored to the browser.
  ShowWindow(GetWidget()->GetNativeView(), SW_HIDE);
#else
  gfx::NativeWindow parent = GTK_WINDOW(
      static_cast<views::WidgetGtk*>(GetWidget())->GetTransientParent());
#endif

  // Even though we just hid the window, we need to invoke Close to schedule
  // the delete and all that.
  Close();

  if (node) {
    BookmarkEditor::Show(parent, profile_, NULL,
                         BookmarkEditor::EditDetails(node),
                         BookmarkEditor::SHOW_TREE);
  }
}

void BookmarkBubbleView::ApplyEdits() {
  // Set this to make sure we don't attempt to apply edits again.
  apply_edits_ = false;

  BookmarkModel* model = profile_->GetBookmarkModel();
  const BookmarkNode* node = model->GetMostRecentlyAddedNodeForURL(url_);
  if (node) {
    const std::wstring new_title = UTF16ToWide(title_tf_->text());
    if (new_title != node->GetTitle()) {
      model->SetTitle(node, new_title);
      UserMetrics::RecordAction(
          UserMetricsAction("BookmarkBubble_ChangeTitleInBubble"),
          profile_);
    }
    // Last index means 'Choose another folder...'
    if (parent_combobox_->selected_item() <
        parent_model_.GetItemCount() - 1) {
      const BookmarkNode* new_parent =
          parent_model_.GetNodeAt(parent_combobox_->selected_item());
      if (new_parent != node->GetParent()) {
        UserMetrics::RecordAction(
            UserMetricsAction("BookmarkBubble_ChangeParent"), profile_);
        model->Move(node, new_parent, new_parent->GetChildCount());
      }
    }
  }
}
<|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 "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/test/test_timeouts.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chrome/test/perf/perf_test.h"
#include "chrome/test/ui/javascript_test_util.h"
#include "chrome/test/ui/ui_perf_test.h"
#include "content/public/test/browser_test_utils.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_util.h"

namespace {

const char kRunDromaeo[] = "run-dromaeo-benchmark";

class DromaeoTest : public UIPerfTest {
 public:
  typedef std::map<std::string, std::string> ResultsMap;

  DromaeoTest() : reference_(false) {
    dom_automation_enabled_ = true;
    show_window_ = true;
  }

  void RunTest(const std::string& suite) {
    if (!CommandLine::ForCurrentProcess()->HasSwitch(kRunDromaeo))
      return;
    FilePath test_path = GetDromaeoDir();
    std::string query_string = suite + "&automated";
    test_path = test_path.Append(FILE_PATH_LITERAL("index.html"));
    GURL test_url(content::GetFileUrlWithQuery(test_path, query_string));

    scoped_refptr<TabProxy> tab(GetActiveTab());
    ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, tab->NavigateToURL(test_url));

    // Wait for the test to finish.
    ASSERT_TRUE(WaitUntilTestCompletes(tab.get(), test_url));

    PrintResults(tab.get());
  }

 protected:
  bool reference_;  // True if this is a reference build.

 private:
  // Return the path to the dromaeo benchmark directory on the local filesystem.
  FilePath GetDromaeoDir() {
    FilePath test_dir;
    PathService::Get(chrome::DIR_TEST_DATA, &test_dir);
    return test_dir.AppendASCII("dromaeo");
  }

  bool WaitUntilTestCompletes(TabProxy* tab, const GURL& test_url) {
    return WaitUntilCookieValue(tab, test_url, "__done",
                                TestTimeouts::large_test_timeout(), "1");
  }

  bool GetScore(TabProxy* tab, std::string* score) {
    std::wstring score_wide;
    bool succeeded = tab->ExecuteAndExtractString(L"",
        L"window.domAutomationController.send(automation.GetScore());",
        &score_wide);

    // Note that we don't use ASSERT_TRUE here (and in some other places) as it
    // doesn't work inside a function with a return type other than void.
    EXPECT_TRUE(succeeded);
    if (!succeeded)
      return false;

    score->assign(WideToUTF8(score_wide));
    return true;
  }

  bool GetResults(TabProxy* tab, ResultsMap* results) {
    std::wstring json_wide;
    bool succeeded = tab->ExecuteAndExtractString(L"",
        L"window.domAutomationController.send("
        L"    JSON.stringify(automation.GetResults()));",
        &json_wide);

    EXPECT_TRUE(succeeded);
    if (!succeeded)
      return false;

    std::string json = WideToUTF8(json_wide);
    return JsonDictionaryToMap(json, results);
  }

  void PrintResults(TabProxy* tab) {
    std::string score;
    ASSERT_TRUE(GetScore(tab, &score));

    ResultsMap results;
    ASSERT_TRUE(GetResults(tab, &results));

    std::string trace_name = reference_ ? "score_ref" : "score";
    std::string unit_name = "runs/s";

    ResultsMap::const_iterator it = results.begin();
    // First result is overall score and thus "important".
    bool important = true;
    for (; it != results.end(); ++it) {
      std::string test_name = it->first;
      for (size_t i = 0; i < test_name.length(); i++)
        if (!isalnum(test_name[i]))
          test_name[i] = '_';
      perf_test::PrintResult(test_name, "", trace_name, it->second, unit_name,
                             important);
      important = false;  // All others are not overall scores.
    }
  }

  DISALLOW_COPY_AND_ASSIGN(DromaeoTest);
};

class DromaeoReferenceTest : public DromaeoTest {
 public:
  DromaeoReferenceTest() : DromaeoTest() {
    reference_ = true;
  }

  void SetUp() {
    UseReferenceBuild();
    DromaeoTest::SetUp();
  }
};

#if defined(OS_WIN)
// http://crbug.com/134570 - is flaky on Win7 perf bot
#define MAYBE_DOMCorePerf DISABLED_DOMCorePerf
#define MAYBE_DOMCoreModifyPerf DISABLED_DOMCoreModifyPerf
#else
#define MAYBE_DOMCorePerf DOMCorePerf
#define MAYBE_DOMCoreModifyPerf DOMCoreModifyPerf
#endif
TEST_F(DromaeoTest, MAYBE_DOMCorePerf) {
  RunTest("dom");
}

TEST_F(DromaeoTest, DOMCoreAttrPerf) {
  RunTest("dom-attr");
}

TEST_F(DromaeoTest, MAYBE_DOMCoreModifyPerf) {
  RunTest("dom-modify");
}

TEST_F(DromaeoTest, DOMCoreQueryPerf) {
  RunTest("dom-query");
}

TEST_F(DromaeoTest, DOMCoreTraversePerf) {
  RunTest("dom-traverse");
}

TEST_F(DromaeoTest, JSLibPerf) {
  RunTest("jslib");
}

TEST_F(DromaeoTest, JSLibAttrJqueryPerf) {
  RunTest("jslib-attr-jquery");
}

TEST_F(DromaeoTest, JSLibAttrPrototypePerf) {
  RunTest("jslib-attr-prototype");
}

TEST_F(DromaeoTest, JSLibEventJqueryPerf) {
  RunTest("jslib-event-jquery");
}

TEST_F(DromaeoTest, JSLibEventPrototypePerf) {
  RunTest("jslib-event-prototype");
}

TEST_F(DromaeoTest, JSLibModifyJqueryPerf) {
  RunTest("jslib-modify-jquery");
}

TEST_F(DromaeoTest, JSLibModifyPrototypePerf) {
  RunTest("jslib-modify-prototype");
}

TEST_F(DromaeoTest, JSLibTraverseJqueryPerf) {
  RunTest("jslib-traverse-jquery");
}

TEST_F(DromaeoTest, JSLibTraversePrototypePerf) {
  RunTest("jslib-traverse-prototype");
}

TEST_F(DromaeoTest, JSLibStyleJqueryPerf) {
  RunTest("jslib-style-jquery");
}

TEST_F(DromaeoTest, JSLibStylePrototypePerf) {
  RunTest("jslib-style-prototype");
}

TEST_F(DromaeoReferenceTest, MAYBE_DOMCorePerf) {
  RunTest("dom");
}

TEST_F(DromaeoReferenceTest, DOMCoreAttrPerf) {
  RunTest("dom-attr");
}

TEST_F(DromaeoReferenceTest, DOMCoreModifyPerf) {
  RunTest("dom-modify");
}

TEST_F(DromaeoReferenceTest, DOMCoreQueryPerf) {
  RunTest("dom-query");
}

TEST_F(DromaeoReferenceTest, DOMCoreTraversePerf) {
  RunTest("dom-traverse");
}

TEST_F(DromaeoReferenceTest, JSLibPerf) {
  RunTest("jslib");
}

TEST_F(DromaeoReferenceTest, JSLibAttrJqueryPerf) {
  RunTest("jslib-attr-jquery");
}

TEST_F(DromaeoReferenceTest, JSLibAttrPrototypePerf) {
  RunTest("jslib-attr-prototype");
}

TEST_F(DromaeoReferenceTest, JSLibEventJqueryPerf) {
  RunTest("jslib-event-jquery");
}

TEST_F(DromaeoReferenceTest, JSLibEventPrototypePerf) {
  RunTest("jslib-event-prototype");
}

TEST_F(DromaeoReferenceTest, JSLibModifyJqueryPerf) {
  RunTest("jslib-modify-jquery");
}

TEST_F(DromaeoReferenceTest, JSLibModifyPrototypePerf) {
  RunTest("jslib-modify-prototype");
}

TEST_F(DromaeoReferenceTest, JSLibTraverseJqueryPerf) {
  RunTest("jslib-traverse-jquery");
}

TEST_F(DromaeoReferenceTest, JSLibTraversePrototypePerf) {
  RunTest("jslib-traverse-prototype");
}

TEST_F(DromaeoReferenceTest, JSLibStyleJqueryPerf) {
  RunTest("jslib-style-jquery");
}

TEST_F(DromaeoReferenceTest, JSLibStylePrototypePerf) {
  RunTest("jslib-style-prototype");
}

}  // namespace
<commit_msg>Disabled reference build for Dromeao DOMCore Modify too.<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 "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/test/test_timeouts.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chrome/test/perf/perf_test.h"
#include "chrome/test/ui/javascript_test_util.h"
#include "chrome/test/ui/ui_perf_test.h"
#include "content/public/test/browser_test_utils.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_util.h"

namespace {

const char kRunDromaeo[] = "run-dromaeo-benchmark";

class DromaeoTest : public UIPerfTest {
 public:
  typedef std::map<std::string, std::string> ResultsMap;

  DromaeoTest() : reference_(false) {
    dom_automation_enabled_ = true;
    show_window_ = true;
  }

  void RunTest(const std::string& suite) {
    if (!CommandLine::ForCurrentProcess()->HasSwitch(kRunDromaeo))
      return;
    FilePath test_path = GetDromaeoDir();
    std::string query_string = suite + "&automated";
    test_path = test_path.Append(FILE_PATH_LITERAL("index.html"));
    GURL test_url(content::GetFileUrlWithQuery(test_path, query_string));

    scoped_refptr<TabProxy> tab(GetActiveTab());
    ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, tab->NavigateToURL(test_url));

    // Wait for the test to finish.
    ASSERT_TRUE(WaitUntilTestCompletes(tab.get(), test_url));

    PrintResults(tab.get());
  }

 protected:
  bool reference_;  // True if this is a reference build.

 private:
  // Return the path to the dromaeo benchmark directory on the local filesystem.
  FilePath GetDromaeoDir() {
    FilePath test_dir;
    PathService::Get(chrome::DIR_TEST_DATA, &test_dir);
    return test_dir.AppendASCII("dromaeo");
  }

  bool WaitUntilTestCompletes(TabProxy* tab, const GURL& test_url) {
    return WaitUntilCookieValue(tab, test_url, "__done",
                                TestTimeouts::large_test_timeout(), "1");
  }

  bool GetScore(TabProxy* tab, std::string* score) {
    std::wstring score_wide;
    bool succeeded = tab->ExecuteAndExtractString(L"",
        L"window.domAutomationController.send(automation.GetScore());",
        &score_wide);

    // Note that we don't use ASSERT_TRUE here (and in some other places) as it
    // doesn't work inside a function with a return type other than void.
    EXPECT_TRUE(succeeded);
    if (!succeeded)
      return false;

    score->assign(WideToUTF8(score_wide));
    return true;
  }

  bool GetResults(TabProxy* tab, ResultsMap* results) {
    std::wstring json_wide;
    bool succeeded = tab->ExecuteAndExtractString(L"",
        L"window.domAutomationController.send("
        L"    JSON.stringify(automation.GetResults()));",
        &json_wide);

    EXPECT_TRUE(succeeded);
    if (!succeeded)
      return false;

    std::string json = WideToUTF8(json_wide);
    return JsonDictionaryToMap(json, results);
  }

  void PrintResults(TabProxy* tab) {
    std::string score;
    ASSERT_TRUE(GetScore(tab, &score));

    ResultsMap results;
    ASSERT_TRUE(GetResults(tab, &results));

    std::string trace_name = reference_ ? "score_ref" : "score";
    std::string unit_name = "runs/s";

    ResultsMap::const_iterator it = results.begin();
    // First result is overall score and thus "important".
    bool important = true;
    for (; it != results.end(); ++it) {
      std::string test_name = it->first;
      for (size_t i = 0; i < test_name.length(); i++)
        if (!isalnum(test_name[i]))
          test_name[i] = '_';
      perf_test::PrintResult(test_name, "", trace_name, it->second, unit_name,
                             important);
      important = false;  // All others are not overall scores.
    }
  }

  DISALLOW_COPY_AND_ASSIGN(DromaeoTest);
};

class DromaeoReferenceTest : public DromaeoTest {
 public:
  DromaeoReferenceTest() : DromaeoTest() {
    reference_ = true;
  }

  void SetUp() {
    UseReferenceBuild();
    DromaeoTest::SetUp();
  }
};

#if defined(OS_WIN)
// http://crbug.com/134570 - is flaky on Win7 perf bot
#define MAYBE_DOMCorePerf DISABLED_DOMCorePerf
#define MAYBE_DOMCoreModifyPerf DISABLED_DOMCoreModifyPerf
#else
#define MAYBE_DOMCorePerf DOMCorePerf
#define MAYBE_DOMCoreModifyPerf DOMCoreModifyPerf
#endif
TEST_F(DromaeoTest, MAYBE_DOMCorePerf) {
  RunTest("dom");
}

TEST_F(DromaeoTest, DOMCoreAttrPerf) {
  RunTest("dom-attr");
}

TEST_F(DromaeoTest, MAYBE_DOMCoreModifyPerf) {
  RunTest("dom-modify");
}

TEST_F(DromaeoTest, DOMCoreQueryPerf) {
  RunTest("dom-query");
}

TEST_F(DromaeoTest, DOMCoreTraversePerf) {
  RunTest("dom-traverse");
}

TEST_F(DromaeoTest, JSLibPerf) {
  RunTest("jslib");
}

TEST_F(DromaeoTest, JSLibAttrJqueryPerf) {
  RunTest("jslib-attr-jquery");
}

TEST_F(DromaeoTest, JSLibAttrPrototypePerf) {
  RunTest("jslib-attr-prototype");
}

TEST_F(DromaeoTest, JSLibEventJqueryPerf) {
  RunTest("jslib-event-jquery");
}

TEST_F(DromaeoTest, JSLibEventPrototypePerf) {
  RunTest("jslib-event-prototype");
}

TEST_F(DromaeoTest, JSLibModifyJqueryPerf) {
  RunTest("jslib-modify-jquery");
}

TEST_F(DromaeoTest, JSLibModifyPrototypePerf) {
  RunTest("jslib-modify-prototype");
}

TEST_F(DromaeoTest, JSLibTraverseJqueryPerf) {
  RunTest("jslib-traverse-jquery");
}

TEST_F(DromaeoTest, JSLibTraversePrototypePerf) {
  RunTest("jslib-traverse-prototype");
}

TEST_F(DromaeoTest, JSLibStyleJqueryPerf) {
  RunTest("jslib-style-jquery");
}

TEST_F(DromaeoTest, JSLibStylePrototypePerf) {
  RunTest("jslib-style-prototype");
}

TEST_F(DromaeoReferenceTest, MAYBE_DOMCorePerf) {
  RunTest("dom");
}

TEST_F(DromaeoReferenceTest, DOMCoreAttrPerf) {
  RunTest("dom-attr");
}

TEST_F(DromaeoReferenceTest, MAYBE_DOMCoreModifyPerf) {
  RunTest("dom-modify");
}

TEST_F(DromaeoReferenceTest, DOMCoreQueryPerf) {
  RunTest("dom-query");
}

TEST_F(DromaeoReferenceTest, DOMCoreTraversePerf) {
  RunTest("dom-traverse");
}

TEST_F(DromaeoReferenceTest, JSLibPerf) {
  RunTest("jslib");
}

TEST_F(DromaeoReferenceTest, JSLibAttrJqueryPerf) {
  RunTest("jslib-attr-jquery");
}

TEST_F(DromaeoReferenceTest, JSLibAttrPrototypePerf) {
  RunTest("jslib-attr-prototype");
}

TEST_F(DromaeoReferenceTest, JSLibEventJqueryPerf) {
  RunTest("jslib-event-jquery");
}

TEST_F(DromaeoReferenceTest, JSLibEventPrototypePerf) {
  RunTest("jslib-event-prototype");
}

TEST_F(DromaeoReferenceTest, JSLibModifyJqueryPerf) {
  RunTest("jslib-modify-jquery");
}

TEST_F(DromaeoReferenceTest, JSLibModifyPrototypePerf) {
  RunTest("jslib-modify-prototype");
}

TEST_F(DromaeoReferenceTest, JSLibTraverseJqueryPerf) {
  RunTest("jslib-traverse-jquery");
}

TEST_F(DromaeoReferenceTest, JSLibTraversePrototypePerf) {
  RunTest("jslib-traverse-prototype");
}

TEST_F(DromaeoReferenceTest, JSLibStyleJqueryPerf) {
  RunTest("jslib-style-jquery");
}

TEST_F(DromaeoReferenceTest, JSLibStylePrototypePerf) {
  RunTest("jslib-style-prototype");
}

}  // namespace
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2005, Peter Sommerlad and IFS Institute for Software at HSR Rapperswil, Switzerland
 * All rights reserved.
 *
 * This library/application is free software; you can redistribute and/or modify it under the terms of
 * the license that is included with this library/application in the file license.txt.
 */

//--- interface include --------------------------------------------------------
#include "AnyBuiltInSortTest.h"

//--- test modules used --------------------------------------------------------
#include "TestSuite.h"

//--- module under test --------------------------------------------------------
#include "Anything.h"
//--- standard modules used ----------------------------------------------------
#include "Dbg.h"
#include "DiffTimer.h"
#include "StringStream.h"
//--- c-modules used -----------------------------------------------------------
#include <stdlib.h>

//---- AnyBuiltInSortTest ----------------------------------------------------------------
AnyBuiltInSortTest::AnyBuiltInSortTest(TString name) : TestCase(name)
{
	StartTrace(AnyBuiltInSortTest.Ctor);
}

AnyBuiltInSortTest::~AnyBuiltInSortTest()
{
	StartTrace(AnyBuiltInSortTest.Dtor);
}

// setup for this TestCase
void AnyBuiltInSortTest::setUp ()
{
	StartTrace(AnyBuiltInSortTest.setUp);
}

void AnyBuiltInSortTest::tearDown ()
{
	StartTrace(AnyBuiltInSortTest.tearDown);
}
bool AnyBuiltInSortTest::checksorted(const Anything &a, bool shouldfail)
{
	for (long i = 0; i < a.GetSize() - 1; i++) {
		const char *s = a.SlotName(i);
		const char *t = a.SlotName(i + 1);
		if (strcmp(NotNull(s), NotNull(t)) > 0) {
			if (!shouldfail) {
				TString msg("slots unsorted ");
				msg.Append(s).Append(" > ").Append(t);
				t_assertm(false, msg);
			}
			return shouldfail;
		}
	}
	return !shouldfail;
}
bool AnyBuiltInSortTest::checksortedbyvalue(const Anything &a, bool shouldfail)
{
	for (long i = 0; i < a.GetSize() - 1; i++) {
		const char *s = a[i].AsCharPtr();
		const char *t = a[i+1].AsCharPtr();
		if (strcmp(NotNull(s), NotNull(t)) > 0) {
			if (!shouldfail) {
				TString msg("slots unsorted ");
				msg.Append(s).Append(" > ").Append(t);
				t_assertm(false, msg);
			}
			return shouldfail;
		}
	}
	return !shouldfail;
}
void AnyBuiltInSortTest::SortEmpty()
{
	StartTrace(AnyBuiltInSortTest.SortEmpty);
	Anything a;
	Anything b(a);
	b.SortByKey();
	assertAnyEqual(a, b);
}

void AnyBuiltInSortTest::SortOne()
{
	StartTrace(AnyBuiltInSortTest.SortOne);
	Anything a("foo");
	Anything b(a);
	b.SortByKey();
	assertAnyEqual(a, b);

}
void AnyBuiltInSortTest::SortTwo()
{
	StartTrace(AnyBuiltInSortTest.SortTwo);
	Anything b;
	b["b"] = 1;
	b["a"] = 2;
	assertEqual(1, b[0].AsLong());
	assertEqual(2, b[1].AsLong());
	b.SortByKey();
	t_assert(checksorted(b));
	assertEqual("a", b.SlotName(0));
	assertEqual("b", b.SlotName(1));
	assertEqual(1, b[1].AsLong());
	assertEqual(2, b[0].AsLong());
	assertEqual(2, b["a"].AsLong());
	assertEqual(1, b["b"].AsLong());
	b.SortByKey(); // should be same!
	t_assert(checksorted(b));
	assertEqual("a", b.SlotName(0));
	assertEqual("b", b.SlotName(1));
	assertEqual(1, b[1].AsLong());
	assertEqual(2, b[0].AsLong());
	assertEqual(2, b["a"].AsLong());
	assertEqual(1, b["b"].AsLong());
}

void AnyBuiltInSortTest::SortThree()
{
	StartTrace(AnyBuiltInSortTest.SortThree);
	Anything b;
	b["c"] = 1;
	b["a"] = 2;
	b["b"] = 3;
	assertEqual(1, b[0].AsLong());
	assertEqual(2, b[1].AsLong());
	assertEqual(3, b[2].AsLong());
	b.SortByKey();
	t_assert(checksorted(b));
	b.SortByKey();
	t_assert(checksorted(b));

}

void AnyBuiltInSortTest::SortMany()
{
	StartTrace(AnyBuiltInSortTest.SortMany);
	Anything a;
	Anything b;
	const long size = 1000;
	for (long i = 0; i < size; i++) {
		long r = random();
		String sr;
		sr << i << "bar" << r << "foo"; // needs i to make it unique
		a[sr] = i;
		b[sr] = i;
	}
	assertEqual(size, a.GetSize());
	assertEqual(size, b.GetSize());
	t_assertm(checksorted(a, true), "should be random");
	DiffTimer dt;
	a.SortByKey();
	cerr << "sorting of " << size << " took " << dt.Diff() << " ms.\n";
	t_assertm(checksorted(a), "should be sorted");
	assertEqual(size, a.GetSize());
	for (long i = 0; i < size; i++) {
		if (!assertEqualm(i, a[b.SlotName(i)].AsLong(), TString("in slot i : ") << i)) {
			break;
		}
	}
	dt.Reset();
	a.SortByKey();
	cerr << "sorting of sorted " << size << " took " << dt.Diff() << " ms.\n";
	// now sort b by using the legacy SlotNameSorter...several orders of magnitude slower.
	dt.Reset();
	SlotnameSorter::Sort(b);
	cerr << "Slogname sorting of " << size << " took " << dt.Diff() << " ms.\n";
	assertAnyEqual(a, b);

}

void AnyBuiltInSortTest::SortManyStringValues()
{
	StartTrace(AnyBuiltInSortTest.SortManyStringValues);
	Anything a;
	Anything b;
	const long size = 1000;
	for (long i = 0; i < size; i++) {
		long r = random();
		String sr;
		sr << "bar" << r << "foo"; // needs i to make it unique
		a.Append(sr);;
	}
	assertEqual(size, a.GetSize());
	t_assertm(checksortedbyvalue(a, true), "should be random");
	DiffTimer dt;
	a.SortByStringValues();
	cerr << "sorting of " << size << " took " << dt.Diff() << " ms.\n";
	t_assertm(checksortedbyvalue(a), "should be sorted");
	assertEqual(size, a.GetSize());
}
void AnyBuiltInSortTest::SortIsStable()
{
	StartTrace(AnyBuiltInSortTest.SortIsStable);
	Anything a;
	a["d"] = 1;
	a["c"] = 2;
	a["a"] = 3;
	for (long i = 4; i < 10; i++) {
		a.Append(i);
	}
	t_assertm(checksorted(a, true), "should be unsorted");
	a.SortByKey();
	for (long i = 0; i < a.GetSize() - 1; i++)
		if (!a.SlotName(i) && !a.SlotName(i + 1)) {
			t_assertm(a[i].AsLong() < a[i+1].AsLong(), TString("unstable at: ") << i << ":" << a[i].AsLong() << " not less than " << a[i+1].AsLong());
		}

}
void AnyBuiltInSortTest::testCase()
{
	StartTrace(AnyBuiltInSortTest.testCase);
//	t_assertm(false, "test me!");
}
// builds up a suite of testcases, add a line for each testmethod
Test *AnyBuiltInSortTest::suite ()
{
	StartTrace(AnyBuiltInSortTest.suite);
	TestSuite *testSuite = new TestSuite;

	ADD_CASE(testSuite, AnyBuiltInSortTest, SortEmpty);
	ADD_CASE(testSuite, AnyBuiltInSortTest, SortOne);
	ADD_CASE(testSuite, AnyBuiltInSortTest, SortTwo);
	ADD_CASE(testSuite, AnyBuiltInSortTest, SortThree);
	ADD_CASE(testSuite, AnyBuiltInSortTest, SortMany);
	ADD_CASE(testSuite, AnyBuiltInSortTest, SortManyStringValues);
	ADD_CASE(testSuite, AnyBuiltInSortTest, SortIsStable);
	ADD_CASE(testSuite, AnyBuiltInSortTest, testCase);

	return testSuite;
}
<commit_msg>corrected duplicate definition/usage of variables corrected WIN32 version of random<commit_after>/*
 * Copyright (c) 2005, Peter Sommerlad and IFS Institute for Software at HSR Rapperswil, Switzerland
 * All rights reserved.
 *
 * This library/application is free software; you can redistribute and/or modify it under the terms of
 * the license that is included with this library/application in the file license.txt.
 */

//--- interface include --------------------------------------------------------
#include "AnyBuiltInSortTest.h"

//--- test modules used --------------------------------------------------------
#include "TestSuite.h"

//--- module under test --------------------------------------------------------
#include "Anything.h"
//--- standard modules used ----------------------------------------------------
#include "Dbg.h"
#include "DiffTimer.h"
#include "StringStream.h"
//--- c-modules used -----------------------------------------------------------
#include <stdlib.h>

//---- AnyBuiltInSortTest ----------------------------------------------------------------
AnyBuiltInSortTest::AnyBuiltInSortTest(TString name) : TestCase(name)
{
	StartTrace(AnyBuiltInSortTest.Ctor);
}

AnyBuiltInSortTest::~AnyBuiltInSortTest()
{
	StartTrace(AnyBuiltInSortTest.Dtor);
}

// setup for this TestCase
void AnyBuiltInSortTest::setUp ()
{
	StartTrace(AnyBuiltInSortTest.setUp);
}

void AnyBuiltInSortTest::tearDown ()
{
	StartTrace(AnyBuiltInSortTest.tearDown);
}
bool AnyBuiltInSortTest::checksorted(const Anything &a, bool shouldfail)
{
	for (long i = 0; i < a.GetSize() - 1; i++) {
		const char *s = a.SlotName(i);
		const char *t = a.SlotName(i + 1);
		if (strcmp(NotNull(s), NotNull(t)) > 0) {
			if (!shouldfail) {
				TString msg("slots unsorted ");
				msg.Append(s).Append(" > ").Append(t);
				t_assertm(false, msg);
			}
			return shouldfail;
		}
	}
	return !shouldfail;
}
bool AnyBuiltInSortTest::checksortedbyvalue(const Anything &a, bool shouldfail)
{
	for (long i = 0; i < a.GetSize() - 1; i++) {
		const char *s = a[i].AsCharPtr();
		const char *t = a[i+1].AsCharPtr();
		if (strcmp(NotNull(s), NotNull(t)) > 0) {
			if (!shouldfail) {
				TString msg("slots unsorted ");
				msg.Append(s).Append(" > ").Append(t);
				t_assertm(false, msg);
			}
			return shouldfail;
		}
	}
	return !shouldfail;
}
void AnyBuiltInSortTest::SortEmpty()
{
	StartTrace(AnyBuiltInSortTest.SortEmpty);
	Anything a;
	Anything b(a);
	b.SortByKey();
	assertAnyEqual(a, b);
}

void AnyBuiltInSortTest::SortOne()
{
	StartTrace(AnyBuiltInSortTest.SortOne);
	Anything a("foo");
	Anything b(a);
	b.SortByKey();
	assertAnyEqual(a, b);

}
void AnyBuiltInSortTest::SortTwo()
{
	StartTrace(AnyBuiltInSortTest.SortTwo);
	Anything b;
	b["b"] = 1;
	b["a"] = 2;
	assertEqual(1, b[0].AsLong());
	assertEqual(2, b[1].AsLong());
	b.SortByKey();
	t_assert(checksorted(b));
	assertEqual("a", b.SlotName(0));
	assertEqual("b", b.SlotName(1));
	assertEqual(1, b[1].AsLong());
	assertEqual(2, b[0].AsLong());
	assertEqual(2, b["a"].AsLong());
	assertEqual(1, b["b"].AsLong());
	b.SortByKey(); // should be same!
	t_assert(checksorted(b));
	assertEqual("a", b.SlotName(0));
	assertEqual("b", b.SlotName(1));
	assertEqual(1, b[1].AsLong());
	assertEqual(2, b[0].AsLong());
	assertEqual(2, b["a"].AsLong());
	assertEqual(1, b["b"].AsLong());
}

void AnyBuiltInSortTest::SortThree()
{
	StartTrace(AnyBuiltInSortTest.SortThree);
	Anything b;
	b["c"] = 1;
	b["a"] = 2;
	b["b"] = 3;
	assertEqual(1, b[0].AsLong());
	assertEqual(2, b[1].AsLong());
	assertEqual(3, b[2].AsLong());
	b.SortByKey();
	t_assert(checksorted(b));
	b.SortByKey();
	t_assert(checksorted(b));
}

void AnyBuiltInSortTest::SortMany()
{
	StartTrace(AnyBuiltInSortTest.SortMany);
	Anything a;
	Anything b;
	const long size = 1000;
	long i;
	for (i = 0; i < size; i++) {
#if defined(WIN32)
		long r = rand();
#else
		long r = random();
#endif
		String sr;
		sr << i << "bar" << r << "foo"; // needs i to make it unique
		a[sr] = i;
		b[sr] = i;
	}
	assertEqual(size, a.GetSize());
	assertEqual(size, b.GetSize());
	t_assertm(checksorted(a, true), "should be random");
	DiffTimer dt;
	a.SortByKey();
	cerr << "sorting of " << size << " took " << dt.Diff() << " ms.\n";
	t_assertm(checksorted(a), "should be sorted");
	assertEqual(size, a.GetSize());
	for (i = 0; i < size; i++) {
		if (!assertEqualm(i, a[b.SlotName(i)].AsLong(), TString("in slot i : ") << i)) {
			break;
		}
	}
	dt.Reset();
	a.SortByKey();
	cerr << "sorting of sorted " << size << " took " << dt.Diff() << " ms.\n";
	// now sort b by using the legacy SlotNameSorter...several orders of magnitude slower.
	dt.Reset();
	SlotnameSorter::Sort(b);
	cerr << "Slogname sorting of " << size << " took " << dt.Diff() << " ms.\n";
	assertAnyEqual(a, b);
}

void AnyBuiltInSortTest::SortManyStringValues()
{
	StartTrace(AnyBuiltInSortTest.SortManyStringValues);
	Anything a;
	Anything b;
	const long size = 1000;
	for (long i = 0; i < size; i++) {
#if defined(WIN32)
		long r = rand();
#else
		long r = random();
#endif
		String sr;
		sr << "bar" << r << "foo"; // needs i to make it unique
		a.Append(sr);;
	}
	assertEqual(size, a.GetSize());
	t_assertm(checksortedbyvalue(a, true), "should be random");
	DiffTimer dt;
	a.SortByStringValues();
	cerr << "sorting of " << size << " took " << dt.Diff() << " ms.\n";
	t_assertm(checksortedbyvalue(a), "should be sorted");
	assertEqual(size, a.GetSize());
}

void AnyBuiltInSortTest::SortIsStable()
{
	StartTrace(AnyBuiltInSortTest.SortIsStable);
	Anything a;
	a["d"] = 1;
	a["c"] = 2;
	a["a"] = 3;
	long i;
	for (i = 4; i < 10; i++) {
		a.Append(i);
	}
	t_assertm(checksorted(a, true), "should be unsorted");
	a.SortByKey();
	for (i = 0; i < a.GetSize() - 1; i++)
		if (!a.SlotName(i) && !a.SlotName(i + 1)) {
			t_assertm(a[i].AsLong() < a[i+1].AsLong(), TString("unstable at: ") << i << ":" << a[i].AsLong() << " not less than " << a[i+1].AsLong());
		}

}
void AnyBuiltInSortTest::testCase()
{
	StartTrace(AnyBuiltInSortTest.testCase);
//	t_assertm(false, "test me!");
}
// builds up a suite of testcases, add a line for each testmethod
Test *AnyBuiltInSortTest::suite ()
{
	StartTrace(AnyBuiltInSortTest.suite);
	TestSuite *testSuite = new TestSuite;

	ADD_CASE(testSuite, AnyBuiltInSortTest, SortEmpty);
	ADD_CASE(testSuite, AnyBuiltInSortTest, SortOne);
	ADD_CASE(testSuite, AnyBuiltInSortTest, SortTwo);
	ADD_CASE(testSuite, AnyBuiltInSortTest, SortThree);
	ADD_CASE(testSuite, AnyBuiltInSortTest, SortMany);
	ADD_CASE(testSuite, AnyBuiltInSortTest, SortManyStringValues);
	ADD_CASE(testSuite, AnyBuiltInSortTest, SortIsStable);
	ADD_CASE(testSuite, AnyBuiltInSortTest, testCase);

	return testSuite;
}
<|endoftext|>


<commit_before>/*************************************************************************/
/*  resource_importer_ogg_vorbis.cpp                                     */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)    */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/

#include "resource_importer_ogg_vorbis.h"

#include "io/resource_saver.h"
#include "os/file_access.h"
#include "scene/resources/texture.h"

String ResourceImporterOGGVorbis::get_importer_name() const {

	return "ogg_vorbis";
}

String ResourceImporterOGGVorbis::get_visible_name() const {

	return "OGGVorbis";
}
void ResourceImporterOGGVorbis::get_recognized_extensions(List<String> *p_extensions) const {

	p_extensions->push_back("ogg");
}

String ResourceImporterOGGVorbis::get_save_extension() const {
	return "oggstr";
}

String ResourceImporterOGGVorbis::get_resource_type() const {

	return "AudioStreamOGGVorbis";
}

bool ResourceImporterOGGVorbis::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {

	return true;
}

int ResourceImporterOGGVorbis::get_preset_count() const {
	return 0;
}
String ResourceImporterOGGVorbis::get_preset_name(int p_idx) const {

	return String();
}

void ResourceImporterOGGVorbis::get_import_options(List<ImportOption> *r_options, int p_preset) const {

	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "loop"), true));
	r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "loop_offset"), 0));
}

Error ResourceImporterOGGVorbis::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) {

	bool loop = p_options["loop"];
	float loop_offset = p_options["loop_offset"];

	FileAccess *f = FileAccess::open(p_source_file, FileAccess::READ);
	if (!f) {
		ERR_FAIL_COND_V(!f, ERR_CANT_OPEN);
	}

	size_t len = f->get_len();

	PoolVector<uint8_t> data;
	data.resize(len);
	PoolVector<uint8_t>::Write w = data.write();

	f->get_buffer(w.ptr(), len);

	memdelete(f);

	Ref<AudioStreamOGGVorbis> ogg_stream;
	ogg_stream.instance();

	ogg_stream->set_data(data);
	ogg_stream->set_loop(loop);
	ogg_stream->set_loop_offset(loop_offset);

	return ResourceSaver::save(p_save_path + ".oggstr", ogg_stream);
}

ResourceImporterOGGVorbis::ResourceImporterOGGVorbis() {
}
<commit_msg>Fix silent failure of importing OGG Vorbis files<commit_after>/*************************************************************************/
/*  resource_importer_ogg_vorbis.cpp                                     */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)    */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/

#include "resource_importer_ogg_vorbis.h"

#include "io/resource_saver.h"
#include "os/file_access.h"
#include "scene/resources/texture.h"

String ResourceImporterOGGVorbis::get_importer_name() const {

	return "ogg_vorbis";
}

String ResourceImporterOGGVorbis::get_visible_name() const {

	return "OGGVorbis";
}
void ResourceImporterOGGVorbis::get_recognized_extensions(List<String> *p_extensions) const {

	p_extensions->push_back("ogg");
}

String ResourceImporterOGGVorbis::get_save_extension() const {
	return "oggstr";
}

String ResourceImporterOGGVorbis::get_resource_type() const {

	return "AudioStreamOGGVorbis";
}

bool ResourceImporterOGGVorbis::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {

	return true;
}

int ResourceImporterOGGVorbis::get_preset_count() const {
	return 0;
}
String ResourceImporterOGGVorbis::get_preset_name(int p_idx) const {

	return String();
}

void ResourceImporterOGGVorbis::get_import_options(List<ImportOption> *r_options, int p_preset) const {

	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "loop"), true));
	r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "loop_offset"), 0));
}

Error ResourceImporterOGGVorbis::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) {

	bool loop = p_options["loop"];
	float loop_offset = p_options["loop_offset"];

	FileAccess *f = FileAccess::open(p_source_file, FileAccess::READ);
	if (!f) {
		ERR_FAIL_COND_V(!f, ERR_CANT_OPEN);
	}

	size_t len = f->get_len();

	PoolVector<uint8_t> data;
	data.resize(len);
	PoolVector<uint8_t>::Write w = data.write();

	f->get_buffer(w.ptr(), len);

	memdelete(f);

	Ref<AudioStreamOGGVorbis> ogg_stream;
	ogg_stream.instance();

	ogg_stream->set_data(data);
	ERR_FAIL_COND_V(!ogg_stream->get_data().size(), ERR_FILE_CORRUPT);
	ogg_stream->set_loop(loop);
	ogg_stream->set_loop_offset(loop_offset);

	return ResourceSaver::save(p_save_path + ".oggstr", ogg_stream);
}

ResourceImporterOGGVorbis::ResourceImporterOGGVorbis() {
}
<|endoftext|>


<commit_before>#include <iostream>
#include <StringObserverImpl.h>

void StringObserverImpl::update()
{
   char* cur_value = mSubject->getValue();

   std::cout << "Current string value is now '" << cur_value << "'\n";
   delete cur_value;
}
<commit_msg>Use vprDEBUG instead of std::cout to print the current string value.<commit_after>#include <vpr/Util/Debug.h>
#include <StringObserverImpl.h>

void StringObserverImpl::update()
{
   char* cur_value = mSubject->getValue();

   vprDEBUG(vprDBG_ALL, vprDBG_CRITICAL_LVL)
      << "Current string value is now '" << cur_value << "'\n"
      << vprDEBUG_FLUSH;
   delete cur_value;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2021-present ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "mutation_writer/partition_based_splitting_writer.hh"

#include <seastar/core/coroutine.hh>

namespace mutation_writer {

class partition_based_splitting_mutation_writer {
    struct bucket {
        bucket_writer writer;
        dht::decorated_key last_key;
        size_t data_size = 0;
    };

private:
    schema_ptr _schema;
    reader_permit _permit;
    reader_consumer _consumer;
    unsigned _max_buckets;
    std::vector<bucket> _buckets;
    bucket* _current_bucket = nullptr;

    future<> write_to_bucket(mutation_fragment&& mf) {
        _current_bucket->data_size += mf.memory_usage();
        return _current_bucket->writer.consume(std::move(mf));
    }

    future<bucket*> create_bucket_for(const dht::decorated_key& key) {
        if (_buckets.size() < _max_buckets) {
            co_return &_buckets.emplace_back(bucket{bucket_writer(_schema, _permit, _consumer), key});
        }
        auto it = std::max_element(_buckets.begin(), _buckets.end(), [] (const bucket& a, const bucket& b) {
            return a.data_size < b.data_size;
        });
        it->writer.consume_end_of_stream();
        co_await it->writer.close();
        *it = bucket{bucket_writer(_schema, _permit, _consumer), key};
        co_return &*it;
    }
public:
    partition_based_splitting_mutation_writer(schema_ptr schema, reader_permit permit, reader_consumer consumer, unsigned max_buckets)
        : _schema(std::move(schema))
        , _permit(std::move(permit))
        , _consumer(std::move(consumer))
        , _max_buckets(max_buckets)
    {}

    future<> consume(partition_start ps) {
        if (_buckets.empty()) {
            _current_bucket = co_await create_bucket_for(ps.key());
        } else if (dht::ring_position_tri_compare(*_schema, _current_bucket->last_key, ps.key()) < 0) {
            // No need to change bucket, just update the last key.
            _current_bucket->last_key = ps.key();
        } else {
            // Find the first bucket where this partition doesn't cause
            // monotonicity violations. Prefer the buckets towards the head of the list.
            auto it = std::find_if(_buckets.begin(), _buckets.end(), [this, &ps] (const bucket& b) {
                return dht::ring_position_tri_compare(*_schema, b.last_key, ps.key()) < 0;
            });
            if (it == _buckets.end()) {
                _current_bucket = co_await create_bucket_for(ps.key());
            } else {
                _current_bucket = &*it;
                _current_bucket->last_key = ps.key();
            }
        }
        co_return co_await write_to_bucket(mutation_fragment(*_schema, _permit, std::move(ps)));
    }

    future<> consume(static_row&& sr) {
        return write_to_bucket(mutation_fragment(*_schema, _permit, std::move(sr)));
    }

    future<> consume(clustering_row&& cr) {
        return write_to_bucket(mutation_fragment(*_schema, _permit, std::move(cr)));
    }

    future<> consume(range_tombstone&& rt) {
        return write_to_bucket(mutation_fragment(*_schema, _permit, std::move(rt)));
    }

    future<> consume(partition_end&& pe) {
        return write_to_bucket(mutation_fragment(*_schema, _permit, std::move(pe)));
    }

    void consume_end_of_stream() {
        for (auto& bucket : _buckets) {
            bucket.writer.consume_end_of_stream();
        }
    }
    void abort(std::exception_ptr ep) {
        for (auto& bucket : _buckets) {
            bucket.writer.abort(ep);
        }
    }
    future<> close() noexcept {
        return parallel_for_each(_buckets, [] (bucket& bucket) {
            return bucket.writer.close();
        });
    }
};

future<> segregate_by_partition(flat_mutation_reader producer, unsigned max_buckets, reader_consumer consumer) {
    auto schema = producer.schema();
    auto permit = producer.permit();
    return feed_writer(std::move(producer),
            partition_based_splitting_mutation_writer(std::move(schema), std::move(permit), std::move(consumer), max_buckets));
}

} // namespace mutation_writer
<commit_msg>mutation_writer: partition_based_splitting_writer: erase old bucket if we fail to create replacement<commit_after>/*
 * Copyright (C) 2021-present ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "mutation_writer/partition_based_splitting_writer.hh"

#include <seastar/core/coroutine.hh>

namespace mutation_writer {

class partition_based_splitting_mutation_writer {
    struct bucket {
        bucket_writer writer;
        dht::decorated_key last_key;
        size_t data_size = 0;
    };

private:
    schema_ptr _schema;
    reader_permit _permit;
    reader_consumer _consumer;
    unsigned _max_buckets;
    std::vector<bucket> _buckets;
    bucket* _current_bucket = nullptr;

    future<> write_to_bucket(mutation_fragment&& mf) {
        _current_bucket->data_size += mf.memory_usage();
        return _current_bucket->writer.consume(std::move(mf));
    }

    future<bucket*> create_bucket_for(const dht::decorated_key& key) {
        if (_buckets.size() < _max_buckets) {
            co_return &_buckets.emplace_back(bucket{bucket_writer(_schema, _permit, _consumer), key});
        }
        auto it = std::max_element(_buckets.begin(), _buckets.end(), [] (const bucket& a, const bucket& b) {
            return a.data_size < b.data_size;
        });
        it->writer.consume_end_of_stream();
        co_await it->writer.close();
        try {
            *it = bucket{bucket_writer(_schema, _permit, _consumer), key};
        } catch (...) {
            _buckets.erase(it);
            throw;
        }
        co_return &*it;
    }
public:
    partition_based_splitting_mutation_writer(schema_ptr schema, reader_permit permit, reader_consumer consumer, unsigned max_buckets)
        : _schema(std::move(schema))
        , _permit(std::move(permit))
        , _consumer(std::move(consumer))
        , _max_buckets(max_buckets)
    {}

    future<> consume(partition_start ps) {
        if (_buckets.empty()) {
            _current_bucket = co_await create_bucket_for(ps.key());
        } else if (dht::ring_position_tri_compare(*_schema, _current_bucket->last_key, ps.key()) < 0) {
            // No need to change bucket, just update the last key.
            _current_bucket->last_key = ps.key();
        } else {
            // Find the first bucket where this partition doesn't cause
            // monotonicity violations. Prefer the buckets towards the head of the list.
            auto it = std::find_if(_buckets.begin(), _buckets.end(), [this, &ps] (const bucket& b) {
                return dht::ring_position_tri_compare(*_schema, b.last_key, ps.key()) < 0;
            });
            if (it == _buckets.end()) {
                _current_bucket = co_await create_bucket_for(ps.key());
            } else {
                _current_bucket = &*it;
                _current_bucket->last_key = ps.key();
            }
        }
        co_return co_await write_to_bucket(mutation_fragment(*_schema, _permit, std::move(ps)));
    }

    future<> consume(static_row&& sr) {
        return write_to_bucket(mutation_fragment(*_schema, _permit, std::move(sr)));
    }

    future<> consume(clustering_row&& cr) {
        return write_to_bucket(mutation_fragment(*_schema, _permit, std::move(cr)));
    }

    future<> consume(range_tombstone&& rt) {
        return write_to_bucket(mutation_fragment(*_schema, _permit, std::move(rt)));
    }

    future<> consume(partition_end&& pe) {
        return write_to_bucket(mutation_fragment(*_schema, _permit, std::move(pe)));
    }

    void consume_end_of_stream() {
        for (auto& bucket : _buckets) {
            bucket.writer.consume_end_of_stream();
        }
    }
    void abort(std::exception_ptr ep) {
        for (auto& bucket : _buckets) {
            bucket.writer.abort(ep);
        }
    }
    future<> close() noexcept {
        return parallel_for_each(_buckets, [] (bucket& bucket) {
            return bucket.writer.close();
        });
    }
};

future<> segregate_by_partition(flat_mutation_reader producer, unsigned max_buckets, reader_consumer consumer) {
    auto schema = producer.schema();
    auto permit = producer.permit();
    return feed_writer(std::move(producer),
            partition_based_splitting_mutation_writer(std::move(schema), std::move(permit), std::move(consumer), max_buckets));
}

} // namespace mutation_writer
<|endoftext|>