summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/background/background_mode_manager.cc70
-rw-r--r--chrome/browser/background/background_mode_manager.h26
-rw-r--r--chrome/browser/media/media_stream_capture_indicator.cc25
-rw-r--r--chrome/browser/media/media_stream_capture_indicator.h11
-rw-r--r--chrome/browser/notifications/message_center_notification_manager.cc1
-rw-r--r--chrome/browser/status_icons/status_icon.cc9
-rw-r--r--chrome/browser/status_icons/status_icon.h11
-rw-r--r--chrome/browser/status_icons/status_icon_menu_model.cc181
-rw-r--r--chrome/browser/status_icons/status_icon_menu_model.h119
-rw-r--r--chrome/browser/status_icons/status_icon_menu_model_unittest.cc118
-rw-r--r--chrome/browser/status_icons/status_icon_unittest.cc3
-rw-r--r--chrome/browser/status_icons/status_tray_unittest.cc3
-rw-r--r--chrome/browser/ui/cocoa/status_icons/status_icon_mac.h3
-rw-r--r--chrome/browser/ui/cocoa/status_icons/status_icon_mac.mm2
-rw-r--r--chrome/browser/ui/cocoa/status_icons/status_icon_mac_unittest.mm6
-rw-r--r--chrome/browser/ui/gtk/status_icons/status_icon_gtk.cc2
-rw-r--r--chrome/browser/ui/gtk/status_icons/status_icon_gtk.h3
-rw-r--r--chrome/browser/ui/gtk/status_icons/status_tray_gtk_unittest.cc6
-rw-r--r--chrome/browser/ui/libgtk2ui/app_indicator_icon.cc18
-rw-r--r--chrome/browser/ui/libgtk2ui/app_indicator_icon.h10
-rw-r--r--chrome/browser/ui/views/message_center/web_notification_tray.cc45
-rw-r--r--chrome/browser/ui/views/message_center/web_notification_tray.h9
-rw-r--r--chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.cc24
-rw-r--r--chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.h12
-rw-r--r--chrome/browser/ui/views/status_icons/status_icon_win.cc4
-rw-r--r--chrome/browser/ui/views/status_icons/status_icon_win.h6
-rw-r--r--chrome/browser/ui/views/status_icons/status_tray_win_unittest.cc6
27 files changed, 582 insertions, 151 deletions
diff --git a/chrome/browser/background/background_mode_manager.cc b/chrome/browser/background/background_mode_manager.cc
index 579f031..7dc5c5e 100644
--- a/chrome/browser/background/background_mode_manager.cc
+++ b/chrome/browser/background/background_mode_manager.cc
@@ -63,24 +63,7 @@ BackgroundModeManager::BackgroundModeData::~BackgroundModeData() {
}
///////////////////////////////////////////////////////////////////////////////
-// BackgroundModeManager::BackgroundModeData, ui::SimpleMenuModel overrides
-bool BackgroundModeManager::BackgroundModeData::IsCommandIdChecked(
- int command_id) const {
- NOTREACHED() << "There are no checked items in the profile submenu.";
- return false;
-}
-
-bool BackgroundModeManager::BackgroundModeData::IsCommandIdEnabled(
- int command_id) const {
- return command_id != IDC_MinimumLabelValue;
-}
-
-bool BackgroundModeManager::BackgroundModeData::GetAcceleratorForCommandId(
- int command_id, ui::Accelerator* accelerator) {
- // No accelerators for status icon context menus.
- return false;
-}
-
+// BackgroundModeManager::BackgroundModeData, StatusIconMenuModel overrides
void BackgroundModeManager::BackgroundModeData::ExecuteCommand(
int item,
int event_flags) {
@@ -110,14 +93,15 @@ int BackgroundModeManager::BackgroundModeData::GetBackgroundAppCount() const {
}
void BackgroundModeManager::BackgroundModeData::BuildProfileMenu(
- ui::SimpleMenuModel* menu,
- ui::SimpleMenuModel* containing_menu) {
+ StatusIconMenuModel* menu,
+ StatusIconMenuModel* containing_menu) {
int position = 0;
// When there are no background applications, we want to display
// just a label stating that none are running.
if (applications_->size() < 1) {
menu->AddItemWithStringId(IDC_MinimumLabelValue,
IDS_BACKGROUND_APP_NOT_INSTALLED);
+ menu->SetCommandIdEnabled(IDC_MinimumLabelValue, false);
} else {
for (extensions::ExtensionList::const_iterator cursor =
applications_->begin();
@@ -459,29 +443,7 @@ void BackgroundModeManager::OnProfileNameChanged(
}
///////////////////////////////////////////////////////////////////////////////
-// BackgroundModeManager::BackgroundModeData, ui::SimpleMenuModel overrides
-bool BackgroundModeManager::IsCommandIdChecked(
- int command_id) const {
- DCHECK(command_id == IDC_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND);
- return true;
-}
-
-bool BackgroundModeManager::IsCommandIdEnabled(
- int command_id) const {
- if (command_id == IDC_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND) {
- PrefService* service = g_browser_process->local_state();
- DCHECK(service);
- return service->IsUserModifiablePreference(prefs::kBackgroundModeEnabled);
- }
- return command_id != IDC_MinimumLabelValue;
-}
-
-bool BackgroundModeManager::GetAcceleratorForCommandId(
- int command_id, ui::Accelerator* accelerator) {
- // No accelerators for status icon context menus.
- return false;
-}
-
+// BackgroundModeManager::BackgroundModeData, StatusIconMenuModel overrides
void BackgroundModeManager::ExecuteCommand(int command_id, int event_flags) {
// When a browser window is necessary, we use the first profile. The windows
// opened for these commands are not profile-specific, so any profile would
@@ -699,7 +661,7 @@ void BackgroundModeManager::UpdateStatusTrayIconContextMenu() {
// TODO(rlp): Add current profile color or indicator.
// Create a context menu item for Chrome.
- ui::SimpleMenuModel* menu = new ui::SimpleMenuModel(this);
+ scoped_ptr<StatusIconMenuModel> menu(new StatusIconMenuModel(this));
// Add About item
menu->AddItem(IDC_ABOUT, l10n_util::GetStringUTF16(IDS_ABOUT));
menu->AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER);
@@ -724,8 +686,8 @@ void BackgroundModeManager::UpdateStatusTrayIconContextMenu() {
// We should only display the profile in the status icon if it has at
// least one background app.
if (bmd->GetBackgroundAppCount() > 0) {
- ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(bmd);
- bmd->BuildProfileMenu(submenu, menu);
+ StatusIconMenuModel* submenu = new StatusIconMenuModel(bmd);
+ bmd->BuildProfileMenu(submenu, menu.get());
profiles_with_apps++;
}
}
@@ -738,17 +700,27 @@ void BackgroundModeManager::UpdateStatusTrayIconContextMenu() {
// have any profiles in the cache.
DCHECK(profile_cache_->GetNumberOfProfiles() == size_t(1) ||
keep_alive_for_test_);
- background_mode_data_.begin()->second->BuildProfileMenu(menu, NULL);
+ background_mode_data_.begin()->second->BuildProfileMenu(menu.get(), NULL);
}
menu->AddSeparator(ui::NORMAL_SEPARATOR);
menu->AddCheckItemWithStringId(
IDC_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND,
IDS_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND);
+ menu->SetCommandIdChecked(IDC_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND,
+ true);
+
+ PrefService* service = g_browser_process->local_state();
+ DCHECK(service);
+ bool enabled =
+ service->IsUserModifiablePreference(prefs::kBackgroundModeEnabled);
+ menu->SetCommandIdEnabled(IDC_STATUS_TRAY_KEEP_CHROME_RUNNING_IN_BACKGROUND,
+ enabled);
+
menu->AddItemWithStringId(IDC_EXIT, IDS_EXIT);
- context_menu_ = menu;
- status_icon_->SetContextMenu(menu);
+ context_menu_ = menu.get();
+ status_icon_->SetContextMenu(menu.Pass());
}
void BackgroundModeManager::RemoveStatusTrayIcon() {
diff --git a/chrome/browser/background/background_mode_manager.h b/chrome/browser/background/background_mode_manager.h
index e1c8051..118d386 100644
--- a/chrome/browser/background/background_mode_manager.h
+++ b/chrome/browser/background/background_mode_manager.h
@@ -12,10 +12,10 @@
#include "chrome/browser/background/background_application_list_model.h"
#include "chrome/browser/profiles/profile_info_cache_observer.h"
#include "chrome/browser/status_icons/status_icon.h"
+#include "chrome/browser/status_icons/status_icon_menu_model.h"
#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
-#include "ui/base/models/simple_menu_model.h"
class Browser;
class CommandLine;
@@ -47,7 +47,7 @@ class BackgroundModeManager
: public content::NotificationObserver,
public BackgroundApplicationListModel::Observer,
public ProfileInfoCacheObserver,
- public ui::SimpleMenuModel::Delegate {
+ public StatusIconMenuModel::Delegate {
public:
BackgroundModeManager(CommandLine* command_line,
ProfileInfoCache* profile_cache);
@@ -88,7 +88,7 @@ class BackgroundModeManager
FRIEND_TEST_ALL_PREFIXES(BackgroundAppBrowserTest,
ReloadBackgroundApp);
- class BackgroundModeData : public ui::SimpleMenuModel::Delegate {
+ class BackgroundModeData : public StatusIconMenuModel::Delegate {
public:
explicit BackgroundModeData(
int command_id,
@@ -98,12 +98,7 @@ class BackgroundModeManager
// The cached list of BackgroundApplications.
scoped_ptr<BackgroundApplicationListModel> applications_;
- // Overrides from SimpleMenuModel::Delegate implementation.
- virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
- virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
- virtual bool GetAcceleratorForCommandId(int command_id,
- ui::Accelerator* accelerator)
- OVERRIDE;
+ // Overrides from StatusIconMenuModel::Delegate implementation.
virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
// Returns a browser window, or creates one if none are open. Used by
@@ -118,8 +113,8 @@ class BackgroundModeManager
// be a submenu in the case of multi-profiles or the main menu in the case
// of the single profile case. If containing_menu is valid, we will add
// menu as a submenu to it.
- void BuildProfileMenu(ui::SimpleMenuModel* menu,
- ui::SimpleMenuModel* containing_menu);
+ void BuildProfileMenu(StatusIconMenuModel* menu,
+ StatusIconMenuModel* containing_menu);
// Set the name associated with this background mode data for displaying in
// the status tray.
@@ -175,12 +170,7 @@ class BackgroundModeManager
virtual void OnProfileNameChanged(const base::FilePath& profile_path,
const string16& old_profile_name) OVERRIDE;
- // Overrides from SimpleMenuModel::Delegate implementation.
- virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
- virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
- virtual bool GetAcceleratorForCommandId(int command_id,
- ui::Accelerator* accelerator)
- OVERRIDE;
+ // Overrides from StatusIconMenuModel::Delegate implementation.
virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
// Invoked when an extension is installed so we can ensure that
@@ -295,7 +285,7 @@ class BackgroundModeManager
// Reference to our status icon's context menu (if any) - owned by the
// status_icon_.
- ui::SimpleMenuModel* context_menu_;
+ StatusIconMenuModel* context_menu_;
// Set to true when we are running in background mode. Allows us to track our
// current background state so we can take the appropriate action when the
diff --git a/chrome/browser/media/media_stream_capture_indicator.cc b/chrome/browser/media/media_stream_capture_indicator.cc
index e92304a..6a375d3 100644
--- a/chrome/browser/media/media_stream_capture_indicator.cc
+++ b/chrome/browser/media/media_stream_capture_indicator.cc
@@ -279,23 +279,6 @@ MediaStreamCaptureIndicator::RegisterMediaStream(
return usage->RegisterMediaStream(devices);
}
-bool MediaStreamCaptureIndicator::IsCommandIdChecked(
- int command_id) const {
- NOTIMPLEMENTED() << "There are no checked items in the MediaStream menu.";
- return false;
-}
-
-bool MediaStreamCaptureIndicator::IsCommandIdEnabled(
- int command_id) const {
- return command_id != IDC_MinimumLabelValue;
-}
-
-bool MediaStreamCaptureIndicator::GetAcceleratorForCommandId(
- int command_id, ui::Accelerator* accelerator) {
- // No accelerators for status icon context menu.
- return false;
-}
-
void MediaStreamCaptureIndicator::ExecuteCommand(int command_id,
int event_flags) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -409,7 +392,7 @@ void MediaStreamCaptureIndicator::MaybeDestroyStatusTrayIcon() {
void MediaStreamCaptureIndicator::UpdateNotificationUserInterface() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- scoped_ptr<ui::SimpleMenuModel> menu(new ui::SimpleMenuModel(this));
+ scoped_ptr<StatusIconMenuModel> menu(new StatusIconMenuModel(this));
bool audio = false;
bool video = false;
@@ -435,6 +418,10 @@ void MediaStreamCaptureIndicator::UpdateNotificationUserInterface() {
command_targets_.push_back(web_contents);
menu->AddItem(command_id, GetTitle(web_contents));
+ // If the menu item is not a label, enable it.
+ menu->SetCommandIdEnabled(command_id,
+ command_id != IDC_MinimumLabelValue);
+
// If reaching the maximum number, no more item will be added to the menu.
if (command_id == IDC_MEDIA_CONTEXT_MEDIA_STREAM_CAPTURE_LIST_LAST)
break;
@@ -450,7 +437,7 @@ void MediaStreamCaptureIndicator::UpdateNotificationUserInterface() {
// The icon will take the ownership of the passed context menu.
MaybeCreateStatusTrayIcon(audio, video);
if (status_icon_) {
- status_icon_->SetContextMenu(menu.release());
+ status_icon_->SetContextMenu(menu.Pass());
}
}
diff --git a/chrome/browser/media/media_stream_capture_indicator.h b/chrome/browser/media/media_stream_capture_indicator.h
index 0d9d369..30eb338 100644
--- a/chrome/browser/media/media_stream_capture_indicator.h
+++ b/chrome/browser/media/media_stream_capture_indicator.h
@@ -12,8 +12,8 @@
#include "base/callback_forward.h"
#include "base/memory/ref_counted.h"
+#include "chrome/browser/status_icons/status_icon_menu_model.h"
#include "content/public/common/media_stream_request.h"
-#include "ui/base/models/simple_menu_model.h"
namespace content {
class WebContents;
@@ -30,7 +30,7 @@ class StatusTray;
// (MediaCaptureDevicesDispatcher is a singleton).
class MediaStreamCaptureIndicator
: public base::RefCountedThreadSafe<MediaStreamCaptureIndicator>,
- public ui::SimpleMenuModel::Delegate {
+ public StatusIconMenuModel::Delegate {
public:
MediaStreamCaptureIndicator();
@@ -40,12 +40,7 @@ class MediaStreamCaptureIndicator
content::WebContents* web_contents,
const content::MediaStreamDevices& devices);
- // Overrides from SimpleMenuModel::Delegate implementation.
- virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
- virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
- virtual bool GetAcceleratorForCommandId(
- int command_id,
- ui::Accelerator* accelerator) OVERRIDE;
+ // Overrides from StatusIconMenuModel::Delegate implementation.
virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
// Returns true if the |web_contents| is capturing user media (e.g., webcam or
diff --git a/chrome/browser/notifications/message_center_notification_manager.cc b/chrome/browser/notifications/message_center_notification_manager.cc
index 21e902c..86b741f 100644
--- a/chrome/browser/notifications/message_center_notification_manager.cc
+++ b/chrome/browser/notifications/message_center_notification_manager.cc
@@ -24,6 +24,7 @@
#include "content/public/browser/user_metrics.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/url_constants.h"
+#include "ui/gfx/image/image_skia.h"
#include "ui/message_center/message_center_style.h"
#include "ui/message_center/message_center_tray.h"
#include "ui/message_center/notifier_settings.h"
diff --git a/chrome/browser/status_icons/status_icon.cc b/chrome/browser/status_icons/status_icon.cc
index 52a36ab..458fb35 100644
--- a/chrome/browser/status_icons/status_icon.cc
+++ b/chrome/browser/status_icons/status_icon.cc
@@ -5,7 +5,6 @@
#include "chrome/browser/status_icons/status_icon.h"
#include "chrome/browser/status_icons/status_icon_observer.h"
-#include "ui/base/models/menu_model.h"
StatusIcon::StatusIcon() {
}
@@ -35,10 +34,10 @@ void StatusIcon::DispatchBalloonClickEvent() {
}
#endif
-void StatusIcon::SetContextMenu(ui::MenuModel* menu) {
+void StatusIcon::SetContextMenu(scoped_ptr<StatusIconMenuModel> menu) {
// The UI may been showing a menu for the current model, don't destroy it
// until we've notified the UI of the change.
- scoped_ptr<ui::MenuModel> old_menu = context_menu_contents_.Pass();
- context_menu_contents_.reset(menu);
- UpdatePlatformContextMenu(menu);
+ scoped_ptr<StatusIconMenuModel> old_menu = context_menu_contents_.Pass();
+ context_menu_contents_ = menu.Pass();
+ UpdatePlatformContextMenu(context_menu_contents_.get());
}
diff --git a/chrome/browser/status_icons/status_icon.h b/chrome/browser/status_icons/status_icon.h
index ccc8c2e..5e50961 100644
--- a/chrome/browser/status_icons/status_icon.h
+++ b/chrome/browser/status_icons/status_icon.h
@@ -9,15 +9,12 @@
#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
#include "base/strings/string16.h"
+#include "chrome/browser/status_icons/status_icon_menu_model.h"
namespace gfx {
class ImageSkia;
}
-namespace ui {
-class MenuModel;
-}
-
class StatusIconObserver;
class StatusIcon {
@@ -45,7 +42,7 @@ class StatusIcon {
// Set the context menu for this icon. The icon takes ownership of the passed
// context menu. Passing NULL results in no menu at all.
- void SetContextMenu(ui::MenuModel* menu);
+ void SetContextMenu(scoped_ptr<StatusIconMenuModel> menu);
// Adds/Removes an observer for clicks on the status icon. If an observer is
// registered, then left clicks on the status icon will result in the observer
@@ -67,13 +64,13 @@ class StatusIcon {
// Invoked after a call to SetContextMenu() to let the platform-specific
// subclass update the native context menu based on the new model. If NULL is
// passed, subclass should destroy the native context menu.
- virtual void UpdatePlatformContextMenu(ui::MenuModel* model) = 0;
+ virtual void UpdatePlatformContextMenu(StatusIconMenuModel* model) = 0;
private:
ObserverList<StatusIconObserver> observers_;
// Context menu, if any.
- scoped_ptr<ui::MenuModel> context_menu_contents_;
+ scoped_ptr<StatusIconMenuModel> context_menu_contents_;
DISALLOW_COPY_AND_ASSIGN(StatusIcon);
};
diff --git a/chrome/browser/status_icons/status_icon_menu_model.cc b/chrome/browser/status_icons/status_icon_menu_model.cc
new file mode 100644
index 0000000..bfb7a4b
--- /dev/null
+++ b/chrome/browser/status_icons/status_icon_menu_model.cc
@@ -0,0 +1,181 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/status_icons/status_icon_menu_model.h"
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/image/image.h"
+
+struct StatusIconMenuModel::ItemState {
+ ItemState()
+ : checked(false),
+ enabled(true),
+ visible(true),
+ is_dynamic(false) {}
+ bool checked;
+ bool enabled;
+ bool visible;
+ bool is_dynamic;
+ ui::Accelerator accelerator;
+ base::string16 label;
+ base::string16 sublabel;
+ gfx::Image icon;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// StatusIconMenuModel::Delegate, public:
+
+void StatusIconMenuModel::Delegate::CommandIdHighlighted(int command_id) {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// StatusIconMenuModel, public:
+
+StatusIconMenuModel::StatusIconMenuModel(Delegate* delegate)
+ : ui::SimpleMenuModel(this), delegate_(delegate) {
+}
+
+StatusIconMenuModel::~StatusIconMenuModel() {
+}
+
+void StatusIconMenuModel::SetCommandIdChecked(int command_id, bool checked) {
+ item_states_[command_id].checked = checked;
+ NotifyMenuStateChanged();
+}
+
+void StatusIconMenuModel::SetCommandIdEnabled(int command_id, bool enabled) {
+ item_states_[command_id].enabled = enabled;
+ NotifyMenuStateChanged();
+}
+
+void StatusIconMenuModel::SetCommandIdVisible(int command_id, bool visible) {
+ item_states_[command_id].visible = visible;
+ NotifyMenuStateChanged();
+}
+
+void StatusIconMenuModel::SetAcceleratorForCommandId(
+ int command_id, const ui::Accelerator* accelerator) {
+ item_states_[command_id].accelerator = *accelerator;
+ NotifyMenuStateChanged();
+}
+
+void StatusIconMenuModel::ChangeLabelForCommandId(int command_id,
+ const base::string16& label) {
+ item_states_[command_id].is_dynamic = true;
+ item_states_[command_id].label = label;
+ NotifyMenuStateChanged();
+}
+
+void StatusIconMenuModel::ChangeSublabelForCommandId(
+ int command_id, const base::string16& sublabel) {
+ item_states_[command_id].is_dynamic = true;
+ item_states_[command_id].sublabel = sublabel;
+ NotifyMenuStateChanged();
+}
+
+void StatusIconMenuModel::ChangeIconForCommandId(
+ int command_id, const gfx::Image& icon) {
+ item_states_[command_id].is_dynamic = true;
+ item_states_[command_id].icon = icon;
+ NotifyMenuStateChanged();
+}
+
+void StatusIconMenuModel::AddObserver(Observer* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void StatusIconMenuModel::RemoveObserver(Observer* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
+bool StatusIconMenuModel::IsCommandIdChecked(int command_id) const {
+ ItemStateMap::const_iterator iter = item_states_.find(command_id);
+ if (iter != item_states_.end())
+ return iter->second.checked;
+ return false;
+}
+
+bool StatusIconMenuModel::IsCommandIdEnabled(int command_id) const {
+ ItemStateMap::const_iterator iter = item_states_.find(command_id);
+ if (iter != item_states_.end())
+ return iter->second.enabled;
+ return true;
+}
+
+bool StatusIconMenuModel::IsCommandIdVisible(int command_id) const {
+ ItemStateMap::const_iterator iter = item_states_.find(command_id);
+ if (iter != item_states_.end())
+ return iter->second.visible;
+ return true;
+}
+
+bool StatusIconMenuModel::GetAcceleratorForCommandId(
+ int command_id, ui::Accelerator* accelerator) {
+ ItemStateMap::const_iterator iter = item_states_.find(command_id);
+ if (iter != item_states_.end() &&
+ iter->second.accelerator.key_code() != ui::VKEY_UNKNOWN) {
+ *accelerator = iter->second.accelerator;
+ return true;
+ }
+ return false;
+}
+
+bool StatusIconMenuModel::IsItemForCommandIdDynamic(int command_id) const {
+ ItemStateMap::const_iterator iter = item_states_.find(command_id);
+ if (iter != item_states_.end())
+ return iter->second.is_dynamic;
+ return false;
+}
+
+base::string16 StatusIconMenuModel::GetLabelForCommandId(int command_id) const {
+ ItemStateMap::const_iterator iter = item_states_.find(command_id);
+ if (iter != item_states_.end())
+ return iter->second.label;
+ return base::string16();
+}
+
+base::string16 StatusIconMenuModel::GetSublabelForCommandId(
+ int command_id) const {
+ ItemStateMap::const_iterator iter = item_states_.find(command_id);
+ if (iter != item_states_.end())
+ return iter->second.sublabel;
+ return base::string16();
+}
+
+bool StatusIconMenuModel::GetIconForCommandId(int command_id,
+ gfx::Image* image_skia) const {
+ ItemStateMap::const_iterator iter = item_states_.find(command_id);
+ if (iter != item_states_.end() && !iter->second.icon.IsEmpty()) {
+ *image_skia = iter->second.icon;
+ return true;
+ }
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// StatusIconMenuModel, protected:
+
+void StatusIconMenuModel::MenuItemsChanged() {
+ NotifyMenuStateChanged();
+}
+
+void StatusIconMenuModel::NotifyMenuStateChanged() {
+ FOR_EACH_OBSERVER(Observer, observer_list_, OnMenuStateChanged());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// StatusIconMenuModel, private:
+
+void StatusIconMenuModel::CommandIdHighlighted(int command_id) {
+ if (delegate_)
+ delegate_->CommandIdHighlighted(command_id);
+}
+
+void StatusIconMenuModel::ExecuteCommand(int command_id, int event_flags) {
+ if (delegate_)
+ delegate_->ExecuteCommand(command_id, event_flags);
+}
diff --git a/chrome/browser/status_icons/status_icon_menu_model.h b/chrome/browser/status_icons/status_icon_menu_model.h
new file mode 100644
index 0000000..fa43874
--- /dev/null
+++ b/chrome/browser/status_icons/status_icon_menu_model.h
@@ -0,0 +1,119 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_STATUS_ICONS_STATUS_ICON_MENU_MODEL_H_
+#define CHROME_BROWSER_STATUS_ICONS_STATUS_ICON_MENU_MODEL_H_
+
+#include <map>
+
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "ui/base/models/simple_menu_model.h"
+
+namespace gfx {
+class Image;
+}
+
+class StatusIconMenuModelTest;
+
+// StatusIconMenuModel contains the state of the SimpleMenuModel as well as that
+// of its delegate. This is done so that we can easily identify when the menu
+// model state has changed and can tell the status icon to update the menu. This
+// is necessary some platforms which do not notify us before showing the menu
+// (like Ubuntu Unity).
+class StatusIconMenuModel
+ : public ui::SimpleMenuModel,
+ public ui::SimpleMenuModel::Delegate,
+ public base::SupportsWeakPtr<StatusIconMenuModel> {
+ public:
+ class Delegate {
+ public:
+ // Notifies the delegate that the item with the specified command id was
+ // visually highlighted within the menu.
+ virtual void CommandIdHighlighted(int command_id);
+
+ // Performs the action associates with the specified command id.
+ // The passed |event_flags| are the flags from the event which issued this
+ // command and they can be examined to find modifier keys.
+ virtual void ExecuteCommand(int command_id, int event_flags) = 0;
+
+ protected:
+ virtual ~Delegate() {}
+ };
+
+ class Observer {
+ public:
+ // Invoked when the menu model has changed.
+ virtual void OnMenuStateChanged() {}
+
+ protected:
+ virtual ~Observer() {}
+ };
+
+ // The Delegate can be NULL.
+ explicit StatusIconMenuModel(Delegate* delegate);
+ virtual ~StatusIconMenuModel();
+
+ // Methods for seting the state of specific command ids.
+ void SetCommandIdChecked(int command_id, bool checked);
+ void SetCommandIdEnabled(int command_id, bool enabled);
+ void SetCommandIdVisible(int command_id, bool visible);
+
+ // Sets the accelerator for the specified command id.
+ void SetAcceleratorForCommandId(
+ int command_id, const ui::Accelerator* accelerator);
+
+ // Calling any of these "change" methods will mark the menu item as "dynamic"
+ // (see menu_model.h:IsItemDynamicAt) which many platforms take as a cue to
+ // refresh the label, sublabel and icon of the menu item each time the menu is
+ // shown.
+ void ChangeLabelForCommandId(int command_id, const base::string16& label);
+ void ChangeSublabelForCommandId(
+ int command_id, const base::string16& sublabel);
+ void ChangeIconForCommandId(int command_id, const gfx::Image& icon);
+
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ // Overridden from ui::SimpleMenuModel::Delegate:
+ virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
+ virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
+ virtual bool IsCommandIdVisible(int command_id) const OVERRIDE;
+ virtual bool GetAcceleratorForCommandId(
+ int command_id, ui::Accelerator* accelerator) OVERRIDE;
+ virtual bool IsItemForCommandIdDynamic(int command_id) const OVERRIDE;
+ virtual base::string16 GetLabelForCommandId(int command_id) const OVERRIDE;
+ virtual base::string16 GetSublabelForCommandId(int command_id) const OVERRIDE;
+ virtual bool GetIconForCommandId(int command_id, gfx::Image* icon) const
+ OVERRIDE;
+
+ protected:
+ // Overriden from ui::SimpleMenuModel:
+ virtual void MenuItemsChanged() OVERRIDE;
+
+ void NotifyMenuStateChanged();
+
+ void set_delegate(Delegate* delegate) { delegate_ = delegate; }
+ Delegate* delegate() { return delegate_; }
+
+ private:
+ // Overridden from ui::SimpleMenuModel::Delegate:
+ virtual void CommandIdHighlighted(int command_id) OVERRIDE;
+ virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
+
+ struct ItemState;
+
+ // Map the properties to the command id (used as key).
+ typedef std::map<int, ItemState> ItemStateMap;
+
+ ItemStateMap item_states_;
+
+ ObserverList<Observer> observer_list_;
+
+ Delegate* delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(StatusIconMenuModel);
+};
+
+#endif // CHROME_BROWSER_STATUS_ICONS_STATUS_ICON_MENU_MODEL_H_
diff --git a/chrome/browser/status_icons/status_icon_menu_model_unittest.cc b/chrome/browser/status_icons/status_icon_menu_model_unittest.cc
new file mode 100644
index 0000000..a81d0fa
--- /dev/null
+++ b/chrome/browser/status_icons/status_icon_menu_model_unittest.cc
@@ -0,0 +1,118 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/status_icons/status_icon_menu_model.h"
+
+#include "base/compiler_specific.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/status_icons/status_icon.h"
+#include "chrome/browser/status_icons/status_tray.h"
+#include "grit/chrome_unscaled_resources.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/image/image.h"
+
+class StatusIconMenuModelTest : public testing::Test,
+ public StatusIconMenuModel::Observer {
+ public:
+ virtual void SetUp() OVERRIDE {
+ menu_.reset(new StatusIconMenuModel(NULL));
+ menu_->AddObserver(this);
+ changed_count_ = 0;
+ }
+
+ virtual void TearDown() OVERRIDE {
+ menu_->RemoveObserver(this);
+ }
+
+ virtual int changed_count() {
+ return changed_count_;
+ }
+
+ StatusIconMenuModel* menu_model() {
+ return menu_.get();
+ }
+
+ private:
+ virtual void OnMenuStateChanged() OVERRIDE {
+ ++changed_count_;
+ }
+
+ scoped_ptr<StatusIconMenuModel> menu_;
+ int changed_count_;
+};
+
+TEST_F(StatusIconMenuModelTest, ToggleBooleanProperties) {
+ menu_model()->AddItem(0, ASCIIToUTF16("foo"));
+
+ menu_model()->SetCommandIdChecked(0, true);
+ EXPECT_TRUE(menu_model()->IsCommandIdChecked(0));
+ menu_model()->SetCommandIdChecked(0, false);
+ EXPECT_FALSE(menu_model()->IsCommandIdChecked(0));
+
+ menu_model()->SetCommandIdEnabled(0, true);
+ EXPECT_TRUE(menu_model()->IsCommandIdEnabled(0));
+ menu_model()->SetCommandIdEnabled(0, false);
+ EXPECT_FALSE(menu_model()->IsCommandIdEnabled(0));
+
+ menu_model()->SetCommandIdVisible(0, true);
+ EXPECT_TRUE(menu_model()->IsCommandIdVisible(0));
+ menu_model()->SetCommandIdVisible(0, false);
+ EXPECT_FALSE(menu_model()->IsCommandIdVisible(0));
+
+ // Menu state should have changed 7 times in this test.
+ EXPECT_EQ(7, changed_count());
+}
+
+TEST_F(StatusIconMenuModelTest, SetProperties) {
+ menu_model()->AddItem(0, ASCIIToUTF16("foo1"));
+ menu_model()->AddItem(1, ASCIIToUTF16("foo2"));
+
+ ui::Accelerator test_accel(ui::VKEY_A, ui::EF_NONE);
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+ gfx::Image test_image1(*rb.GetImageSkiaNamed(IDR_STATUS_TRAY_ICON));
+ gfx::Image test_image2(*rb.GetImageSkiaNamed(IDR_STATUS_TRAY_ICON_PRESSED));
+ ui::Accelerator accel_arg;
+ gfx::Image image_arg;
+
+ EXPECT_FALSE(menu_model()->GetAcceleratorForCommandId(0, &accel_arg));
+ EXPECT_FALSE(menu_model()->GetIconForCommandId(0, &image_arg));
+ EXPECT_FALSE(menu_model()->IsItemForCommandIdDynamic(0));
+
+ // Set the accelerator and label for the first menu item.
+ menu_model()->SetAcceleratorForCommandId(0, &test_accel);
+ EXPECT_TRUE(menu_model()->GetAcceleratorForCommandId(0, &accel_arg));
+ EXPECT_EQ(test_accel, accel_arg);
+
+ // Try setting label and changing it. Also ensure that menu item is marked
+ // dynamic since the label has changed.
+ menu_model()->ChangeLabelForCommandId(0, ASCIIToUTF16("label1"));
+ EXPECT_TRUE(menu_model()->IsItemForCommandIdDynamic(0));
+ EXPECT_EQ(ASCIIToUTF16("label1"), menu_model()->GetLabelForCommandId(0));
+ menu_model()->ChangeLabelForCommandId(0, ASCIIToUTF16("label2"));
+ EXPECT_EQ(ASCIIToUTF16("label2"), menu_model()->GetLabelForCommandId(0));
+
+ // Set the sublabel and icon image for the second menu item.
+ menu_model()->ChangeSublabelForCommandId(1, ASCIIToUTF16("sublabel"));
+ EXPECT_EQ(ASCIIToUTF16("sublabel"), menu_model()->GetSublabelForCommandId(1));
+
+ // Try setting icon image and changing it.
+ menu_model()->ChangeIconForCommandId(1, test_image1);
+ EXPECT_TRUE(menu_model()->GetIconForCommandId(1, &image_arg));
+ EXPECT_EQ(image_arg.ToImageSkia(), test_image1.ToImageSkia());
+ menu_model()->ChangeIconForCommandId(1, test_image2);
+ EXPECT_TRUE(menu_model()->GetIconForCommandId(1, &image_arg));
+ EXPECT_EQ(image_arg.ToImageSkia(), test_image2.ToImageSkia());
+
+ // Ensure changes to one menu item does not affect the other menu item.
+ EXPECT_FALSE(menu_model()->GetAcceleratorForCommandId(1, &accel_arg));
+ EXPECT_EQ(string16(), menu_model()->GetLabelForCommandId(1));
+ EXPECT_EQ(string16(), menu_model()->GetSublabelForCommandId(0));
+ EXPECT_FALSE(menu_model()->GetIconForCommandId(0, &image_arg));
+
+ // Menu state should have changed 8 times in this test.
+ EXPECT_EQ(8, changed_count());
+}
diff --git a/chrome/browser/status_icons/status_icon_unittest.cc b/chrome/browser/status_icons/status_icon_unittest.cc
index 8078665..cdc22b7 100644
--- a/chrome/browser/status_icons/status_icon_unittest.cc
+++ b/chrome/browser/status_icons/status_icon_unittest.cc
@@ -21,7 +21,8 @@ class TestStatusIcon : public StatusIcon {
virtual void SetImage(const gfx::ImageSkia& image) OVERRIDE {}
virtual void SetPressedImage(const gfx::ImageSkia& image) OVERRIDE {}
virtual void SetToolTip(const string16& tool_tip) OVERRIDE {}
- virtual void UpdatePlatformContextMenu(ui::MenuModel* menu) OVERRIDE {}
+ virtual void UpdatePlatformContextMenu(
+ StatusIconMenuModel* menu) OVERRIDE {}
virtual void DisplayBalloon(const gfx::ImageSkia& icon,
const string16& title,
const string16& contents) OVERRIDE {}
diff --git a/chrome/browser/status_icons/status_tray_unittest.cc b/chrome/browser/status_icons/status_tray_unittest.cc
index 238d8b7..674c8fc 100644
--- a/chrome/browser/status_icons/status_tray_unittest.cc
+++ b/chrome/browser/status_icons/status_tray_unittest.cc
@@ -19,7 +19,8 @@ class MockStatusIcon : public StatusIcon {
virtual void DisplayBalloon(const gfx::ImageSkia& icon,
const string16& title,
const string16& contents) OVERRIDE {}
- virtual void UpdatePlatformContextMenu(ui::MenuModel* menu) OVERRIDE {}
+ virtual void UpdatePlatformContextMenu(
+ StatusIconMenuModel* menu) OVERRIDE {}
};
class TestStatusTray : public StatusTray {
diff --git a/chrome/browser/ui/cocoa/status_icons/status_icon_mac.h b/chrome/browser/ui/cocoa/status_icons/status_icon_mac.h
index 8b380c4..6bd6570 100644
--- a/chrome/browser/ui/cocoa/status_icons/status_icon_mac.h
+++ b/chrome/browser/ui/cocoa/status_icons/status_icon_mac.h
@@ -35,7 +35,8 @@ class StatusIconMac : public StatusIcon {
protected:
// Overridden from StatusIcon.
- virtual void UpdatePlatformContextMenu(ui::MenuModel* model) OVERRIDE;
+ virtual void UpdatePlatformContextMenu(
+ StatusIconMenuModel* model) OVERRIDE;
private:
FRIEND_TEST_ALL_PREFIXES(StatusIconMacTest, CreateMenu);
diff --git a/chrome/browser/ui/cocoa/status_icons/status_icon_mac.mm b/chrome/browser/ui/cocoa/status_icons/status_icon_mac.mm
index d02c792..cc79fc6 100644
--- a/chrome/browser/ui/cocoa/status_icons/status_icon_mac.mm
+++ b/chrome/browser/ui/cocoa/status_icons/status_icon_mac.mm
@@ -101,7 +101,7 @@ bool StatusIconMac::HasStatusIconMenu() {
return menu_.get() != nil;
}
-void StatusIconMac::UpdatePlatformContextMenu(ui::MenuModel* model) {
+void StatusIconMac::UpdatePlatformContextMenu(StatusIconMenuModel* model) {
if (!model) {
menu_.reset();
} else {
diff --git a/chrome/browser/ui/cocoa/status_icons/status_icon_mac_unittest.mm b/chrome/browser/ui/cocoa/status_icons/status_icon_mac_unittest.mm
index 7675b98..c3ae23d 100644
--- a/chrome/browser/ui/cocoa/status_icons/status_icon_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/status_icons/status_icon_mac_unittest.mm
@@ -5,12 +5,12 @@
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/status_icons/status_icon_menu_model.h"
#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
#include "chrome/browser/ui/cocoa/status_icons/status_icon_mac.h"
#include "grit/chrome_unscaled_resources.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/models/simple_menu_model.h"
#include "ui/base/resource/resource_bundle.h"
class SkBitmap;
@@ -32,7 +32,7 @@ TEST_F(StatusIconMacTest, Create) {
TEST_F(StatusIconMacTest, CreateMenu) {
// Create a menu and verify by getting the title of the first menu item.
const char* menu_title = "Menu Title";
- scoped_ptr<ui::SimpleMenuModel> model(new ui::SimpleMenuModel(NULL));
+ scoped_ptr<StatusIconMenuModel> model(new StatusIconMenuModel(NULL));
model->AddItem(0, ASCIIToUTF16(menu_title));
scoped_ptr<StatusIconMac> icon(new StatusIconMac());
@@ -48,7 +48,7 @@ TEST_F(StatusIconMacTest, MenuToolTip) {
// first menu item.
const char* menu_title = "Menu Title";
const char* tool_tip = "Tool tip";
- scoped_ptr<ui::SimpleMenuModel> model(new ui::SimpleMenuModel(NULL));
+ scoped_ptr<StatusIconMenuModel> model(new StatusIconMenuModel(NULL));
model->AddItem(0, ASCIIToUTF16(menu_title));
scoped_ptr<StatusIconMac> icon(new StatusIconMac());
diff --git a/chrome/browser/ui/gtk/status_icons/status_icon_gtk.cc b/chrome/browser/ui/gtk/status_icons/status_icon_gtk.cc
index 185f93d..8916cdd 100644
--- a/chrome/browser/ui/gtk/status_icons/status_icon_gtk.cc
+++ b/chrome/browser/ui/gtk/status_icons/status_icon_gtk.cc
@@ -54,7 +54,7 @@ void StatusIconGtk::OnClick(GtkWidget* widget) {
DispatchClickEvent();
}
-void StatusIconGtk::UpdatePlatformContextMenu(ui::MenuModel* model) {
+void StatusIconGtk::UpdatePlatformContextMenu(StatusIconMenuModel* model) {
if (!model)
menu_.reset();
else
diff --git a/chrome/browser/ui/gtk/status_icons/status_icon_gtk.h b/chrome/browser/ui/gtk/status_icons/status_icon_gtk.h
index b85edde..2e7f010 100644
--- a/chrome/browser/ui/gtk/status_icons/status_icon_gtk.h
+++ b/chrome/browser/ui/gtk/status_icons/status_icon_gtk.h
@@ -32,7 +32,8 @@ class StatusIconGtk : public StatusIcon {
protected:
// Overridden from StatusIcon.
- virtual void UpdatePlatformContextMenu(ui::MenuModel* menu) OVERRIDE;
+ virtual void UpdatePlatformContextMenu(
+ StatusIconMenuModel* menu) OVERRIDE;
private:
// Callback invoked when user right-clicks on the status icon.
diff --git a/chrome/browser/ui/gtk/status_icons/status_tray_gtk_unittest.cc b/chrome/browser/ui/gtk/status_icons/status_tray_gtk_unittest.cc
index 3ca1df2..e548db6 100644
--- a/chrome/browser/ui/gtk/status_icons/status_tray_gtk_unittest.cc
+++ b/chrome/browser/ui/gtk/status_icons/status_tray_gtk_unittest.cc
@@ -6,12 +6,12 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/status_icons/status_icon_menu_model.h"
#include "chrome/browser/status_icons/status_icon_observer.h"
#include "chrome/browser/ui/gtk/status_icons/status_icon_gtk.h"
#include "grit/chrome_unscaled_resources.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/models/simple_menu_model.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/image/image_skia.h"
@@ -35,9 +35,9 @@ TEST(StatusTrayGtkTest, CreateIcon) {
StatusIcon* icon = tray.CreateStatusIcon(
StatusTray::OTHER_ICON, *image, ASCIIToUTF16("tool tip"));
icon->SetPressedImage(*image);
- ui::SimpleMenuModel* menu = new ui::SimpleMenuModel(NULL);
+ scoped_ptr<StatusIconMenuModel> menu(new StatusIconMenuModel(NULL));
menu->AddItem(0, ASCIIToUTF16("foo"));
- icon->SetContextMenu(menu);
+ icon->SetContextMenu(menu.Pass());
}
TEST(StatusTrayGtkTest, ClickOnIcon) {
diff --git a/chrome/browser/ui/libgtk2ui/app_indicator_icon.cc b/chrome/browser/ui/libgtk2ui/app_indicator_icon.cc
index 1e4a7bb..326149e 100644
--- a/chrome/browser/ui/libgtk2ui/app_indicator_icon.cc
+++ b/chrome/browser/ui/libgtk2ui/app_indicator_icon.cc
@@ -140,8 +140,6 @@ AppIndicatorIcon::AppIndicatorIcon(std::string id,
AppIndicatorIcon::~AppIndicatorIcon() {
if (icon_) {
app_indicator_set_status(icon_, APP_INDICATOR_STATUS_PASSIVE);
- if (menu_model_)
- menu_model_->MenuClosed();
if (gtk_menu_)
DestroyMenu();
g_object_unref(icon_);
@@ -218,6 +216,11 @@ void AppIndicatorIcon::UpdatePlatformContextMenu(ui::MenuModel* model) {
SetMenu();
}
+void AppIndicatorIcon::RefreshPlatformContextMenu() {
+ gtk_container_foreach(
+ GTK_CONTAINER(gtk_menu_), SetMenuItemInfo, &block_activation_);
+}
+
void AppIndicatorIcon::SetImageFromFile(base::FilePath icon_file_path) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
if (!icon_file_path.empty()) {
@@ -268,8 +271,7 @@ void AppIndicatorIcon::SetMenu() {
G_CALLBACK(OnMenuItemActivatedThunk),
&block_activation_,
this);
- UpdateMenu();
- menu_model_->MenuWillShow();
+ RefreshPlatformContextMenu();
}
app_indicator_set_menu(icon_, GTK_MENU(gtk_menu_));
}
@@ -287,8 +289,6 @@ void AppIndicatorIcon::CreateClickActionReplacement() {
}
void AppIndicatorIcon::DestroyMenu() {
- if (menu_model_)
- menu_model_->MenuClosed();
gtk_widget_destroy(gtk_menu_);
gtk_menu_ = NULL;
menu_model_ = NULL;
@@ -335,11 +335,6 @@ void AppIndicatorIcon::DeletePath(base::FilePath icon_file_path) {
}
}
-void AppIndicatorIcon::UpdateMenu() {
- gtk_container_foreach(
- GTK_CONTAINER(gtk_menu_), SetMenuItemInfo, &block_activation_);
-}
-
void AppIndicatorIcon::OnClick(GtkWidget* menu_item) {
if (delegate())
delegate()->OnClick();
@@ -373,7 +368,6 @@ void AppIndicatorIcon::OnMenuItemActivated(GtkWidget* menu_item) {
// The menu item can still be activated by hotkeys even if it is disabled.
if (menu_model_->IsEnabledAt(id))
ExecuteCommand(model, id);
- UpdateMenu();
}
} // namespace libgtk2ui
diff --git a/chrome/browser/ui/libgtk2ui/app_indicator_icon.h b/chrome/browser/ui/libgtk2ui/app_indicator_icon.h
index 5e2e60c..840f579 100644
--- a/chrome/browser/ui/libgtk2ui/app_indicator_icon.h
+++ b/chrome/browser/ui/libgtk2ui/app_indicator_icon.h
@@ -8,6 +8,7 @@
#include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h"
+#include "ui/base/models/menu_model.h"
#include "ui/linux_ui/status_icon_linux.h"
typedef struct _AppIndicator AppIndicator;
@@ -31,14 +32,12 @@ class AppIndicatorIcon : public StatusIconLinux {
// Indicates whether libappindicator so could be opened.
static bool CouldOpen();
- // Overridden from StatusIcon:
+ // Overridden from StatusIconLinux:
virtual void SetImage(const gfx::ImageSkia& image) OVERRIDE;
virtual void SetPressedImage(const gfx::ImageSkia& image) OVERRIDE;
virtual void SetToolTip(const string16& tool_tip) OVERRIDE;
-
- protected:
- // Overridden from StatusIcon.
virtual void UpdatePlatformContextMenu(ui::MenuModel* menu) OVERRIDE;
+ virtual void RefreshPlatformContextMenu() OVERRIDE;
private:
void SetImageFromFile(base::FilePath icon_file_path);
@@ -56,9 +55,6 @@ class AppIndicatorIcon : public StatusIconLinux {
std::string id);
static void DeletePath(base::FilePath icon_file_path);
- // Updates all the enabled/checked states and the dynamic labels.
- void UpdateMenu();
-
// Callback for when the status icon click replacement menu item is clicked.
CHROMEGTK_CALLBACK_0(AppIndicatorIcon, void, OnClick);
diff --git a/chrome/browser/ui/views/message_center/web_notification_tray.cc b/chrome/browser/ui/views/message_center/web_notification_tray.cc
index 5fcf10a..ac31aa9 100644
--- a/chrome/browser/ui/views/message_center/web_notification_tray.cc
+++ b/chrome/browser/ui/views/message_center/web_notification_tray.cc
@@ -9,6 +9,7 @@
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/status_icons/status_icon.h"
+#include "chrome/browser/status_icons/status_icon_menu_model.h"
#include "chrome/browser/status_icons/status_tray.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/user_metrics.h"
@@ -39,6 +40,11 @@ const int kNumberOfSystemTraySprites = 10;
// Number of pixels the message center is offset from the mouse.
const int kMouseOffset = 5;
+// Menu commands
+const int kToggleQuietMode = 0;
+const int kEnableQuietModeHour = 1;
+const int kEnableQuietModeDay = 2;
+
gfx::ImageSkia* GetIcon(int unread_count, bool is_quiet_mode) {
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
int resource_id = IDR_NOTIFICATION_TRAY_EMPTY;
@@ -128,10 +134,12 @@ MessageCenterTrayDelegate* CreateMessageCenterTray() {
WebNotificationTray::WebNotificationTray()
: message_center_delegate_(NULL),
status_icon_(NULL),
+ status_icon_menu_(NULL),
message_center_visible_(false),
should_update_tray_content_(true) {
message_center_tray_.reset(
new MessageCenterTray(this, g_browser_process->message_center()));
+ last_quiet_mode_state_ = message_center()->IsQuietMode();
}
WebNotificationTray::~WebNotificationTray() {
@@ -189,6 +197,17 @@ bool WebNotificationTray::ShowNotifierSettings() {
}
void WebNotificationTray::OnMessageCenterTrayChanged() {
+ if (status_icon_) {
+ bool quiet_mode_state = message_center()->IsQuietMode();
+ if (last_quiet_mode_state_ != quiet_mode_state) {
+ last_quiet_mode_state_ = quiet_mode_state;
+
+ // Quiet mode has changed, update the quiet mode menu.
+ status_icon_menu_->SetCommandIdChecked(kToggleQuietMode,
+ quiet_mode_state);
+ }
+ }
+
// See the comments in ash/system/web_notification/web_notification_tray.cc
// for why PostTask.
should_update_tray_content_ = true;
@@ -204,6 +223,18 @@ void WebNotificationTray::OnStatusIconClicked() {
message_center_tray_->ToggleMessageCenterBubble();
}
+void WebNotificationTray::ExecuteCommand(int command_id, int event_flags) {
+ if (command_id == kToggleQuietMode) {
+ bool in_quiet_mode = message_center()->IsQuietMode();
+ message_center()->SetQuietMode(!in_quiet_mode);
+ return;
+ }
+ base::TimeDelta expires_in = command_id == kEnableQuietModeDay
+ ? base::TimeDelta::FromDays(1)
+ : base::TimeDelta::FromHours(1);
+ message_center()->EnterQuietModeWithExpire(expires_in);
+}
+
void WebNotificationTray::UpdateStatusIcon() {
if (!should_update_tray_content_)
return;
@@ -319,12 +350,24 @@ void WebNotificationTray::DestroyStatusIcon() {
StatusTray* status_tray = g_browser_process->status_tray();
if (status_tray)
status_tray->RemoveStatusIcon(status_icon_);
+ status_icon_menu_ = NULL;
status_icon_ = NULL;
}
void WebNotificationTray::AddQuietModeMenu(StatusIcon* status_icon) {
DCHECK(status_icon);
- status_icon->SetContextMenu(message_center_tray_->CreateQuietModeMenu());
+
+ scoped_ptr<StatusIconMenuModel> menu(new StatusIconMenuModel(this));
+ menu->AddCheckItem(kToggleQuietMode,
+ l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_QUIET_MODE));
+ menu->SetCommandIdChecked(kToggleQuietMode, message_center()->IsQuietMode());
+ menu->AddItem(kEnableQuietModeHour,
+ l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_QUIET_MODE_1HOUR));
+ menu->AddItem(kEnableQuietModeDay,
+ l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_QUIET_MODE_1DAY));
+
+ status_icon_menu_ = menu.get();
+ status_icon->SetContextMenu(menu.Pass());
}
MessageCenterWidgetDelegate*
diff --git a/chrome/browser/ui/views/message_center/web_notification_tray.h b/chrome/browser/ui/views/message_center/web_notification_tray.h
index 040f9a6..a37dd9e 100644
--- a/chrome/browser/ui/views/message_center/web_notification_tray.h
+++ b/chrome/browser/ui/views/message_center/web_notification_tray.h
@@ -6,6 +6,7 @@
#define CHROME_BROWSER_UI_VIEWS_MESSAGE_CENTER_WEB_NOTIFICATION_TRAY_H_
#include "base/memory/weak_ptr.h"
+#include "chrome/browser/status_icons/status_icon_menu_model.h"
#include "chrome/browser/status_icons/status_icon_observer.h"
#include "chrome/browser/ui/views/message_center/message_center_widget_delegate.h"
#include "content/public/browser/notification_observer.h"
@@ -39,7 +40,8 @@ class MessageCenterWidgetDelegate;
// tray icon on click.
class WebNotificationTray : public message_center::MessageCenterTrayDelegate,
public StatusIconObserver,
- public base::SupportsWeakPtr<WebNotificationTray> {
+ public base::SupportsWeakPtr<WebNotificationTray>,
+ public StatusIconMenuModel::Delegate {
public:
WebNotificationTray();
virtual ~WebNotificationTray();
@@ -64,6 +66,9 @@ class WebNotificationTray : public message_center::MessageCenterTrayDelegate,
void DisplayFirstRunBalloon();
#endif
+ // StatusIconMenuModel::Delegate implementation.
+ virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
+
// Changes the icon and hovertext based on number of unread notifications.
void UpdateStatusIcon();
void SendHideMessageCenter();
@@ -96,11 +101,13 @@ class WebNotificationTray : public message_center::MessageCenterTrayDelegate,
scoped_ptr<message_center::MessagePopupCollection> popup_collection_;
StatusIcon* status_icon_;
+ StatusIconMenuModel* status_icon_menu_;
bool message_center_visible_;
scoped_ptr<MessageCenterTray> message_center_tray_;
gfx::Point mouse_click_point_;
bool should_update_tray_content_;
+ bool last_quiet_mode_state_;
DISALLOW_COPY_AND_ASSIGN(WebNotificationTray);
};
diff --git a/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.cc b/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.cc
index 931abef..3656bd5 100644
--- a/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.cc
+++ b/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.cc
@@ -1,15 +1,20 @@
+
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.h"
-StatusIconLinuxWrapper::StatusIconLinuxWrapper(StatusIconLinux* status_icon) {
+StatusIconLinuxWrapper::StatusIconLinuxWrapper(StatusIconLinux* status_icon)
+ : menu_model_(NULL) {
status_icon_.reset(status_icon);
status_icon_->set_delegate(this);
}
-StatusIconLinuxWrapper::~StatusIconLinuxWrapper() {}
+StatusIconLinuxWrapper::~StatusIconLinuxWrapper() {
+ if (menu_model_)
+ menu_model_->RemoveObserver(this);
+}
void StatusIconLinuxWrapper::SetImage(const gfx::ImageSkia& image) {
status_icon_->SetImage(image);
@@ -37,6 +42,10 @@ bool StatusIconLinuxWrapper::HasClickAction() {
return HasObservers();
}
+void StatusIconLinuxWrapper::OnMenuStateChanged() {
+ status_icon_->RefreshPlatformContextMenu();
+}
+
StatusIconLinuxWrapper* StatusIconLinuxWrapper::CreateWrappedStatusIcon(
const gfx::ImageSkia& image,
const string16& tool_tip) {
@@ -50,6 +59,15 @@ StatusIconLinuxWrapper* StatusIconLinuxWrapper::CreateWrappedStatusIcon(
return NULL;
}
-void StatusIconLinuxWrapper::UpdatePlatformContextMenu(ui::MenuModel* model) {
+void StatusIconLinuxWrapper::UpdatePlatformContextMenu(
+ StatusIconMenuModel* model) {
+ // If a menu already exists, remove ourself from its oberver list.
+ if (menu_model_)
+ menu_model_->RemoveObserver(this);
+
status_icon_->UpdatePlatformContextMenu(model);
+ menu_model_ = model;
+
+ if (model)
+ model->AddObserver(this);
}
diff --git a/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.h b/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.h
index 153ce37..30ccf1f 100644
--- a/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.h
+++ b/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.h
@@ -13,7 +13,8 @@
// Wrapper class for StatusIconLinux that implements the standard StatusIcon
// interface. Also handles callbacks from StatusIconLinux.
class StatusIconLinuxWrapper : public StatusIcon,
- public StatusIconLinux::Delegate {
+ public StatusIconLinux::Delegate,
+ public StatusIconMenuModel::Observer {
public:
virtual ~StatusIconLinuxWrapper();
@@ -29,6 +30,9 @@ class StatusIconLinuxWrapper : public StatusIcon,
virtual void OnClick() OVERRIDE;
virtual bool HasClickAction() OVERRIDE;
+ // StatusIconMenuModel::Observer overrides:
+ virtual void OnMenuStateChanged() OVERRIDE;
+
static StatusIconLinuxWrapper* CreateWrappedStatusIcon(
const gfx::ImageSkia& image,
const string16& tool_tip);
@@ -38,7 +42,8 @@ class StatusIconLinuxWrapper : public StatusIcon,
// Invoked after a call to SetContextMenu() to let the platform-specific
// subclass update the native context menu based on the new model. If NULL is
// passed, subclass should destroy the native context menu.
- virtual void UpdatePlatformContextMenu(ui::MenuModel* model) OVERRIDE;
+ virtual void UpdatePlatformContextMenu(
+ StatusIconMenuModel* model) OVERRIDE;
private:
// A status icon wrapper should only be created by calling
@@ -47,8 +52,11 @@ class StatusIconLinuxWrapper : public StatusIcon,
// Notification balloon.
DesktopNotificationBalloon notification_;
+
scoped_ptr<StatusIconLinux> status_icon_;
+ StatusIconMenuModel* menu_model_;
+
DISALLOW_COPY_AND_ASSIGN(StatusIconLinuxWrapper);
};
diff --git a/chrome/browser/ui/views/status_icons/status_icon_win.cc b/chrome/browser/ui/views/status_icons/status_icon_win.cc
index a5af417..f49642e 100644
--- a/chrome/browser/ui/views/status_icons/status_icon_win.cc
+++ b/chrome/browser/ui/views/status_icons/status_icon_win.cc
@@ -147,7 +147,7 @@ void StatusIconWin::DisplayBalloon(const gfx::ImageSkia& icon,
////////////////////////////////////////////////////////////////////////////////
// StatusIconWin, private:
-void StatusIconWin::UpdatePlatformContextMenu(ui::MenuModel* menu) {
+void StatusIconWin::UpdatePlatformContextMenu(StatusIconMenuModel* menu) {
// |menu_model_| is about to be destroyed. Destroy the menu (which closes it)
// so that it doesn't attempt to continue using |menu_model_|.
menu_runner_.reset();
@@ -210,7 +210,7 @@ void StatusIconMetro::DisplayBalloon(const gfx::ImageSkia& icon,
}
}
-void StatusIconMetro::UpdatePlatformContextMenu(ui::MenuModel* menu) {
+void StatusIconMetro::UpdatePlatformContextMenu(StatusIconMenuModel* menu) {
DVLOG(1) << __FUNCTION__
<< " This functionality is not supported in Windows 8 metro";
}
diff --git a/chrome/browser/ui/views/status_icons/status_icon_win.h b/chrome/browser/ui/views/status_icons/status_icon_win.h
index 8f4cf1b..8576f5d 100644
--- a/chrome/browser/ui/views/status_icons/status_icon_win.h
+++ b/chrome/browser/ui/views/status_icons/status_icon_win.h
@@ -52,7 +52,8 @@ class StatusIconWin : public StatusIcon {
protected:
// Overridden from StatusIcon:
- virtual void UpdatePlatformContextMenu(ui::MenuModel* menu) OVERRIDE;
+ virtual void UpdatePlatformContextMenu(
+ StatusIconMenuModel* menu) OVERRIDE;
private:
void InitIconData(NOTIFYICONDATA* icon_data);
@@ -96,7 +97,8 @@ class StatusIconMetro : public StatusIcon {
const string16& title,
const string16& contents) OVERRIDE;
protected:
- virtual void UpdatePlatformContextMenu(ui::MenuModel* menu) OVERRIDE;
+ virtual void UpdatePlatformContextMenu(
+ StatusIconMenuModel* menu) OVERRIDE;
private:
string16 tool_tip_;
diff --git a/chrome/browser/ui/views/status_icons/status_tray_win_unittest.cc b/chrome/browser/ui/views/status_icons/status_tray_win_unittest.cc
index 15ce2f8..cbff6d1 100644
--- a/chrome/browser/ui/views/status_icons/status_tray_win_unittest.cc
+++ b/chrome/browser/ui/views/status_icons/status_tray_win_unittest.cc
@@ -8,11 +8,11 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/status_icons/status_icon_menu_model.h"
#include "chrome/browser/status_icons/status_icon_observer.h"
#include "chrome/browser/ui/views/status_icons/status_icon_win.h"
#include "grit/chrome_unscaled_resources.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/models/simple_menu_model.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/image/image_skia.h"
@@ -49,9 +49,9 @@ TEST(StatusTrayWinTest, CreateIconAndMenu) {
StatusIcon* icon = tray.CreateStatusIcon(
StatusTray::OTHER_ICON, *image, ASCIIToUTF16("tool tip"));
icon->SetPressedImage(*image);
- ui::SimpleMenuModel* menu = new ui::SimpleMenuModel(NULL);
+ scoped_ptr<StatusIconMenuModel> menu(new StatusIconMenuModel(NULL));
menu->AddItem(0, L"foo");
- icon->SetContextMenu(menu);
+ icon->SetContextMenu(menu.Pass());
}
#if !defined(USE_AURA) // http://crbug.com/156370