summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorsidharthms@chromium.org <sidharthms@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-28 08:23:59 +0000
committersidharthms@chromium.org <sidharthms@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-28 08:23:59 +0000
commitf528059f1c18b4f5b29509d6270bed5812d8b467 (patch)
treef73e32df4235f022055f2376a16718ccaa00532f /chrome
parentafd7186b06526ff947e6df14ce25a51c7297ff47 (diff)
downloadchromium_src-f528059f1c18b4f5b29509d6270bed5812d8b467.zip
chromium_src-f528059f1c18b4f5b29509d6270bed5812d8b467.tar.gz
chromium_src-f528059f1c18b4f5b29509d6270bed5812d8b467.tar.bz2
Update Status Icon menu when menu model changes (Linux Aura)
Status icon context menus currently do not update themselves when the menu model changes or when the check state of a menu item changes. This patch fixes that behavior. BUG=263926,262395 Review URL: https://chromiumcodereview.appspot.com/20728003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@219964 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-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
-rw-r--r--chrome/chrome_browser.gypi2
-rw-r--r--chrome/chrome_tests_unit.gypi1
29 files changed, 585 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
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 926a329..b7f99b90 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2012,6 +2012,8 @@
'browser/status_icons/desktop_notification_balloon.h',
'browser/status_icons/status_icon.cc',
'browser/status_icons/status_icon.h',
+ 'browser/status_icons/status_icon_menu_model.cc',
+ 'browser/status_icons/status_icon_menu_model.h',
'browser/status_icons/status_icon_observer.h',
'browser/status_icons/status_tray.cc',
'browser/status_icons/status_tray.h',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index f49c7a7..80b080d 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -1208,6 +1208,7 @@
'browser/spellchecker/spellcheck_service_unittest.cc',
'browser/spellchecker/spelling_service_client_unittest.cc',
'browser/spellchecker/word_trimmer_unittest.cc',
+ 'browser/status_icons/status_icon_menu_model_unittest.cc',
'browser/status_icons/status_icon_unittest.cc',
'browser/status_icons/status_tray_unittest.cc',
'browser/storage_monitor/image_capture_device_manager_unittest.mm',