reload_button.cc revision 23730a6e56a168d1879203e4b3819bb36e3d8f1f
1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/ui/views/toolbar/reload_button.h" 6 7#include "base/strings/utf_string_conversions.h" 8#include "chrome/app/chrome_command_ids.h" 9#include "chrome/browser/command_updater.h" 10#include "chrome/browser/search/search.h" 11#include "chrome/browser/ui/search/search_model.h" 12#include "chrome/browser/ui/views/location_bar/location_bar_view.h" 13#include "grit/generated_resources.h" 14#include "grit/theme_resources.h" 15#include "ui/base/l10n/l10n_util.h" 16#include "ui/base/models/simple_menu_model.h" 17#include "ui/base/theme_provider.h" 18#include "ui/base/window_open_disposition.h" 19#include "ui/views/metrics.h" 20#include "ui/views/widget/widget.h" 21 22 23namespace { 24 25// Contents of the Reload drop-down menu. 26const int kReloadMenuItems[] = { 27 IDS_RELOAD_MENU_NORMAL_RELOAD_ITEM, 28 IDS_RELOAD_MENU_HARD_RELOAD_ITEM, 29 IDS_RELOAD_MENU_EMPTY_AND_HARD_RELOAD_ITEM, 30}; 31 32} // namespace 33 34 35// ReloadButton --------------------------------------------------------------- 36 37// static 38const char ReloadButton::kViewClassName[] = "ReloadButton"; 39 40ReloadButton::ReloadButton(LocationBarView* location_bar, 41 CommandUpdater* command_updater) 42 : ToolbarButton(this, CreateMenuModel()), 43 location_bar_(location_bar), 44 command_updater_(command_updater), 45 intended_mode_(MODE_RELOAD), 46 visible_mode_(MODE_RELOAD), 47 double_click_timer_delay_( 48 base::TimeDelta::FromMilliseconds(views::GetDoubleClickInterval())), 49 stop_to_reload_timer_delay_(base::TimeDelta::FromMilliseconds(1350)), 50 menu_enabled_(false), 51 testing_mouse_hovered_(false), 52 testing_reload_count_(0) { 53} 54 55ReloadButton::~ReloadButton() { 56} 57 58void ReloadButton::ChangeMode(Mode mode, bool force) { 59 intended_mode_ = mode; 60 61 // If the change is forced, or the user isn't hovering the icon, or it's safe 62 // to change it to the other image type, make the change immediately; 63 // otherwise we'll let it happen later. 64 if (force || (!IsMouseHovered() && !testing_mouse_hovered_) || 65 ((mode == MODE_STOP) ? 66 !double_click_timer_.IsRunning() : (visible_mode_ != MODE_STOP))) { 67 double_click_timer_.Stop(); 68 stop_to_reload_timer_.Stop(); 69 if (mode != visible_mode_) 70 ChangeModeInternal(mode); 71 SetEnabled(true); 72 73 // We want to disable the button if we're preventing a change from stop to 74 // reload due to hovering, but not if we're preventing a change from reload to 75 // stop due to the double-click timer running. (Disabled reload state is only 76 // applicable when instant extended API is enabled and mode is NTP, which is 77 // handled just above.) 78 } else if (visible_mode_ != MODE_RELOAD) { 79 SetEnabled(false); 80 81 // Go ahead and change to reload after a bit, which allows repeated reloads 82 // without moving the mouse. 83 if (!stop_to_reload_timer_.IsRunning()) { 84 stop_to_reload_timer_.Start(FROM_HERE, stop_to_reload_timer_delay_, this, 85 &ReloadButton::OnStopToReloadTimer); 86 } 87 } 88} 89 90void ReloadButton::LoadImages() { 91 ChangeModeInternal(visible_mode_); 92 93 SchedulePaint(); 94 PreferredSizeChanged(); 95} 96 97void ReloadButton::OnMouseExited(const ui::MouseEvent& event) { 98 ToolbarButton::OnMouseExited(event); 99 if (!IsMenuShowing()) 100 ChangeMode(intended_mode_, true); 101} 102 103bool ReloadButton::GetTooltipText(const gfx::Point& p, 104 base::string16* tooltip) const { 105 int reload_tooltip = menu_enabled_ ? 106 IDS_TOOLTIP_RELOAD_WITH_MENU : IDS_TOOLTIP_RELOAD; 107 int text_id = (visible_mode_ == MODE_RELOAD) ? 108 reload_tooltip : IDS_TOOLTIP_STOP; 109 tooltip->assign(l10n_util::GetStringUTF16(text_id)); 110 return true; 111} 112 113const char* ReloadButton::GetClassName() const { 114 return kViewClassName; 115} 116 117void ReloadButton::GetAccessibleState(ui::AXViewState* state) { 118 if (menu_enabled_) 119 ToolbarButton::GetAccessibleState(state); 120 else 121 CustomButton::GetAccessibleState(state); 122} 123 124bool ReloadButton::ShouldShowMenu() { 125 return menu_enabled_ && (visible_mode_ == MODE_RELOAD); 126} 127 128void ReloadButton::ShowDropDownMenu(ui::MenuSourceType source_type) { 129 ToolbarButton::ShowDropDownMenu(source_type); // Blocks. 130 ChangeMode(intended_mode_, true); 131} 132 133void ReloadButton::ButtonPressed(views::Button* /* button */, 134 const ui::Event& event) { 135 ClearPendingMenu(); 136 137 if (visible_mode_ == MODE_STOP) { 138 if (command_updater_) 139 command_updater_->ExecuteCommandWithDisposition(IDC_STOP, CURRENT_TAB); 140 // The user has clicked, so we can feel free to update the button, 141 // even if the mouse is still hovering. 142 ChangeMode(MODE_RELOAD, true); 143 } else if (!double_click_timer_.IsRunning()) { 144 // Shift-clicking or ctrl-clicking the reload button means we should ignore 145 // any cached content. 146 int command; 147 int flags = event.flags(); 148 if (event.IsShiftDown() || event.IsControlDown()) { 149 command = IDC_RELOAD_IGNORING_CACHE; 150 // Mask off Shift and Control so they don't affect the disposition below. 151 flags &= ~(ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN); 152 } else { 153 command = IDC_RELOAD; 154 } 155 156 // Start a timer - while this timer is running, the reload button cannot be 157 // changed to a stop button. We do not set |intended_mode_| to MODE_STOP 158 // here as the browser will do that when it actually starts loading (which 159 // may happen synchronously, thus the need to do this before telling the 160 // browser to execute the reload command). 161 double_click_timer_.Start(FROM_HERE, double_click_timer_delay_, this, 162 &ReloadButton::OnDoubleClickTimer); 163 164 ExecuteBrowserCommand(command, flags); 165 ++testing_reload_count_; 166 } 167} 168 169bool ReloadButton::IsCommandIdChecked(int command_id) const { 170 return false; 171} 172 173bool ReloadButton::IsCommandIdEnabled(int command_id) const { 174 return true; 175} 176 177bool ReloadButton::IsCommandIdVisible(int command_id) const { 178 return true; 179} 180 181bool ReloadButton::GetAcceleratorForCommandId(int command_id, 182 ui::Accelerator* accelerator) { 183 switch (command_id) { 184 case IDS_RELOAD_MENU_NORMAL_RELOAD_ITEM: 185 GetWidget()->GetAccelerator(IDC_RELOAD, accelerator); 186 return true; 187 case IDS_RELOAD_MENU_HARD_RELOAD_ITEM: 188 GetWidget()->GetAccelerator(IDC_RELOAD_IGNORING_CACHE, accelerator); 189 return true; 190 } 191 return GetWidget()->GetAccelerator(command_id, accelerator); 192} 193 194void ReloadButton::ExecuteCommand(int command_id, int event_flags) { 195 int browser_command = 0; 196 switch (command_id) { 197 case IDS_RELOAD_MENU_NORMAL_RELOAD_ITEM: 198 browser_command = IDC_RELOAD; 199 break; 200 case IDS_RELOAD_MENU_HARD_RELOAD_ITEM: 201 browser_command = IDC_RELOAD_IGNORING_CACHE; 202 break; 203 case IDS_RELOAD_MENU_EMPTY_AND_HARD_RELOAD_ITEM: 204 browser_command = IDC_RELOAD_CLEARING_CACHE; 205 break; 206 default: 207 NOTREACHED(); 208 } 209 ExecuteBrowserCommand(browser_command, event_flags); 210} 211 212ui::SimpleMenuModel* ReloadButton::CreateMenuModel() { 213 ui::SimpleMenuModel* menu_model = new ui::SimpleMenuModel(this); 214 for (size_t i = 0; i < arraysize(kReloadMenuItems); ++i) 215 menu_model->AddItemWithStringId(kReloadMenuItems[i], kReloadMenuItems[i]); 216 217 return menu_model; 218} 219 220void ReloadButton::ExecuteBrowserCommand(int command, int event_flags) { 221 if (!command_updater_) 222 return; 223 command_updater_->ExecuteCommandWithDisposition( 224 command, ui::DispositionFromEventFlags(event_flags)); 225} 226 227void ReloadButton::ChangeModeInternal(Mode mode) { 228 ui::ThemeProvider* tp = GetThemeProvider(); 229 // |tp| can be NULL in unit tests. 230 if (tp) { 231 SetImage(views::Button::STATE_NORMAL, *(tp->GetImageSkiaNamed( 232 (mode == MODE_RELOAD) ? IDR_RELOAD : IDR_STOP))); 233 SetImage(views::Button::STATE_DISABLED, *(tp->GetImageSkiaNamed( 234 (mode == MODE_RELOAD) ? IDR_RELOAD_D : IDR_STOP_D))); 235 } 236 237 visible_mode_ = mode; 238 SchedulePaint(); 239} 240 241void ReloadButton::OnDoubleClickTimer() { 242 if (!IsMenuShowing()) 243 ChangeMode(intended_mode_, false); 244} 245 246void ReloadButton::OnStopToReloadTimer() { 247 DCHECK(!IsMenuShowing()); 248 ChangeMode(intended_mode_, true); 249} 250