blob: 9a4003773adc43d2be02f15f471296d7dab4d479 [file] [log] [blame]
// Copyright 2017 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 "ash/shelf/shelf_context_menu_model.h"
#include <memory>
#include <string>
#include <utility>
#include "ash/public/cpp/app_menu_constants.h"
#include "ash/public/cpp/ash_pref_names.h"
#include "ash/public/cpp/menu_utils.h"
#include "ash/public/cpp/shelf_item_delegate.h"
#include "ash/public/cpp/shelf_prefs.h"
#include "ash/public/cpp/shelf_types.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/root_window_controller.h"
#include "ash/session/session_controller.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/wallpaper/wallpaper_controller.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "base/metrics/user_metrics.h"
#include "base/numerics/safe_conversions.h"
#include "components/prefs/pref_service.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/controls/menu/menu_config.h"
using l10n_util::GetStringUTF16;
using SubmenuList = std::vector<std::unique_ptr<ui::MenuModel>>;
namespace ash {
namespace {
// Returns true if the user can modify the shelf's auto-hide behavior pref.
bool CanUserModifyShelfAutoHide(PrefService* prefs) {
return prefs && prefs->FindPreference(prefs::kShelfAutoHideBehaviorLocal)
->IsUserModifiable();
}
// Returns true if the display is showing a fullscreen window.
// NOTE: This duplicates the functionality of Chrome's IsFullScreenMode.
bool IsFullScreenMode(int64_t display_id) {
auto* controller = Shell::GetRootWindowControllerWithDisplayId(display_id);
return controller && controller->GetWindowForFullscreenMode();
}
// Add the context menu items to change shelf auto-hide and alignment settings
// and to change the wallpaper for the display with the given |display_id|.
void AddLocalMenuItems(MenuItemList* menu, int64_t display_id) {
PrefService* prefs =
Shell::Get()->session_controller()->GetLastActiveUserPrefService();
if (!prefs) // Null during startup.
return;
const bool is_tablet_mode = Shell::Get()
->tablet_mode_controller()
->IsTabletModeWindowManagerEnabled();
const views::MenuConfig& menu_config = views::MenuConfig::instance();
// In fullscreen, the shelf is either hidden or auto-hidden, depending on
// the type of fullscreen. Do not show the auto-hide menu item while in
// fullscreen because it is confusing when the preference appears not to
// apply.
if (CanUserModifyShelfAutoHide(prefs) && !IsFullScreenMode(display_id)) {
mojom::MenuItemPtr auto_hide(mojom::MenuItem::New());
const bool is_autohide_set =
GetShelfAutoHideBehaviorPref(prefs, display_id) ==
SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS;
auto_hide->type = ui::MenuModel::TYPE_COMMAND;
auto_hide->image = gfx::CreateVectorIcon(
is_autohide_set ? kAlwaysShowShelfIcon : kAutoHideIcon,
menu_config.touchable_icon_size, menu_config.touchable_icon_color);
auto_hide->label = GetStringUTF16(
is_autohide_set ? IDS_ASH_SHELF_CONTEXT_MENU_ALWAYS_SHOW_SHELF
: IDS_ASH_SHELF_CONTEXT_MENU_AUTO_HIDE);
auto_hide->command_id = ShelfContextMenuModel::MENU_AUTO_HIDE;
auto_hide->enabled = true;
menu->push_back(std::move(auto_hide));
}
// Only allow shelf alignment modifications by the owner or user. In tablet
// mode, the shelf alignment option is not shown.
LoginStatus status = Shell::Get()->session_controller()->login_status();
if ((status == LoginStatus::USER || status == LoginStatus::OWNER) &&
!is_tablet_mode) {
const ShelfAlignment alignment = GetShelfAlignmentPref(prefs, display_id);
mojom::MenuItemPtr alignment_menu(mojom::MenuItem::New());
alignment_menu->type = ui::MenuModel::TYPE_SUBMENU;
alignment_menu->command_id = ShelfContextMenuModel::MENU_ALIGNMENT_MENU;
alignment_menu->label = GetStringUTF16(IDS_ASH_SHELF_CONTEXT_MENU_POSITION);
alignment_menu->submenu = MenuItemList();
alignment_menu->enabled = !is_tablet_mode;
alignment_menu->image = gfx::CreateVectorIcon(
kShelfPositionIcon, menu_config.touchable_icon_size,
menu_config.touchable_icon_color);
mojom::MenuItemPtr left(mojom::MenuItem::New());
left->type = ui::MenuModel::TYPE_RADIO;
left->command_id = ShelfContextMenuModel::MENU_ALIGNMENT_LEFT;
left->label = GetStringUTF16(IDS_ASH_SHELF_CONTEXT_MENU_ALIGN_LEFT);
left->checked = alignment == SHELF_ALIGNMENT_LEFT;
left->enabled = true;
alignment_menu->submenu->push_back(std::move(left));
mojom::MenuItemPtr bottom(mojom::MenuItem::New());
bottom->type = ui::MenuModel::TYPE_RADIO;
bottom->command_id = ShelfContextMenuModel::MENU_ALIGNMENT_BOTTOM;
bottom->label = GetStringUTF16(IDS_ASH_SHELF_CONTEXT_MENU_ALIGN_BOTTOM);
bottom->checked = alignment == SHELF_ALIGNMENT_BOTTOM ||
alignment == SHELF_ALIGNMENT_BOTTOM_LOCKED;
bottom->enabled = true;
alignment_menu->submenu->push_back(std::move(bottom));
mojom::MenuItemPtr right(mojom::MenuItem::New());
right->type = ui::MenuModel::TYPE_RADIO;
right->command_id = ShelfContextMenuModel::MENU_ALIGNMENT_RIGHT;
right->label = GetStringUTF16(IDS_ASH_SHELF_CONTEXT_MENU_ALIGN_RIGHT);
right->checked = alignment == SHELF_ALIGNMENT_RIGHT;
right->enabled = true;
alignment_menu->submenu->push_back(std::move(right));
menu->push_back(std::move(alignment_menu));
}
if (Shell::Get()->wallpaper_controller()->CanOpenWallpaperPicker()) {
mojom::MenuItemPtr wallpaper(mojom::MenuItem::New());
wallpaper->command_id = ShelfContextMenuModel::MENU_CHANGE_WALLPAPER;
wallpaper->label = GetStringUTF16(IDS_AURA_SET_DESKTOP_WALLPAPER);
wallpaper->enabled = true;
wallpaper->image =
gfx::CreateVectorIcon(kWallpaperIcon, menu_config.touchable_icon_size,
menu_config.touchable_icon_color);
menu->push_back(std::move(wallpaper));
}
}
} // namespace
ShelfContextMenuModel::ShelfContextMenuModel(MenuItemList menu_items,
ShelfItemDelegate* delegate,
int64_t display_id)
: ui::SimpleMenuModel(this),
menu_items_(std::move(menu_items)),
delegate_(delegate),
display_id_(display_id) {
// Append shelf settings and wallpaper items if no shelf item was selected.
if (!delegate)
AddLocalMenuItems(&menu_items_, display_id);
menu_utils::PopulateMenuFromMojoMenuItems(this, this, menu_items_,
&submenus_);
}
ShelfContextMenuModel::~ShelfContextMenuModel() = default;
bool ShelfContextMenuModel::IsCommandIdChecked(int command_id) const {
return menu_utils::GetMenuItemByCommandId(menu_items_, command_id)->checked;
}
bool ShelfContextMenuModel::IsCommandIdEnabled(int command_id) const {
// NOTIFICATION_CONTAINER is always enabled. It is added to this model by
// NotificationMenuController, but it is not added to |menu_items_|, so check
// for it first.
if (command_id == ash::NOTIFICATION_CONTAINER)
return true;
return menu_utils::GetMenuItemByCommandId(menu_items_, command_id)->enabled;
}
void ShelfContextMenuModel::ExecuteCommand(int command_id, int event_flags) {
DCHECK(IsCommandIdEnabled(command_id));
PrefService* prefs =
Shell::Get()->session_controller()->GetLastActiveUserPrefService();
if (!prefs) // Null during startup.
return;
UserMetricsRecorder* metrics = Shell::Get()->metrics();
// Clamshell mode only options should not activate in tablet mode.
const bool is_tablet_mode = Shell::Get()
->tablet_mode_controller()
->IsTabletModeWindowManagerEnabled();
switch (command_id) {
case MENU_AUTO_HIDE:
SetShelfAutoHideBehaviorPref(
prefs, display_id_,
GetShelfAutoHideBehaviorPref(prefs, display_id_) ==
SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS
? SHELF_AUTO_HIDE_BEHAVIOR_NEVER
: SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
break;
case MENU_ALIGNMENT_LEFT:
DCHECK(!is_tablet_mode);
metrics->RecordUserMetricsAction(UMA_SHELF_ALIGNMENT_SET_LEFT);
SetShelfAlignmentPref(prefs, display_id_, SHELF_ALIGNMENT_LEFT);
break;
case MENU_ALIGNMENT_RIGHT:
DCHECK(!is_tablet_mode);
metrics->RecordUserMetricsAction(UMA_SHELF_ALIGNMENT_SET_RIGHT);
SetShelfAlignmentPref(prefs, display_id_, SHELF_ALIGNMENT_RIGHT);
break;
case MENU_ALIGNMENT_BOTTOM:
DCHECK(!is_tablet_mode);
metrics->RecordUserMetricsAction(UMA_SHELF_ALIGNMENT_SET_BOTTOM);
SetShelfAlignmentPref(prefs, display_id_, SHELF_ALIGNMENT_BOTTOM);
break;
case MENU_CHANGE_WALLPAPER:
Shell::Get()->wallpaper_controller()->OpenWallpaperPickerIfAllowed();
break;
default:
// Have the shelf item delegate execute the context menu command.
if (delegate_)
delegate_->ExecuteCommand(true, command_id, event_flags, display_id_);
break;
}
}
} // namespace ash