blob: 191814d9f23374656ba4ca0c678a396f8b0ebca1 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/create_application_shortcut_view.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "build/build_config.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/views/chrome_layout_provider.h"
#include "chrome/browser/web_applications/components/os_integration_manager.h"
#include "chrome/browser/web_applications/extensions/web_app_extension_shortcut.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/common/pref_names.h"
#include "chrome/grit/generated_resources.h"
#include "components/constrained_window/constrained_window_views.h"
#include "components/prefs/pref_service.h"
#include "extensions/common/extension.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/grid_layout.h"
#if defined(OS_WIN)
#include "base/win/shortcut.h"
#include "base/win/windows_version.h"
#endif // defined(OS_WIN)
namespace chrome {
void ShowCreateChromeAppShortcutsDialog(
gfx::NativeWindow parent_window,
Profile* profile,
const extensions::Extension* app,
base::OnceCallback<void(bool)> close_callback) {
constrained_window::CreateBrowserModalDialogViews(
new CreateChromeApplicationShortcutView(profile, app,
std::move(close_callback)),
parent_window)
->Show();
}
void ShowCreateChromeAppShortcutsDialog(
gfx::NativeWindow parent_window,
Profile* profile,
const std::string& web_app_id,
base::OnceCallback<void(bool)> close_callback) {
constrained_window::CreateBrowserModalDialogViews(
new CreateChromeApplicationShortcutView(profile, web_app_id,
std::move(close_callback)),
parent_window)
->Show();
}
} // namespace chrome
CreateChromeApplicationShortcutView::CreateChromeApplicationShortcutView(
Profile* profile,
const extensions::Extension* app,
base::OnceCallback<void(bool)> close_callback)
: CreateChromeApplicationShortcutView(profile, std::move(close_callback)) {
// Get shortcut and icon information; needed for creating the shortcut.
web_app::GetShortcutInfoForApp(
app, profile,
base::BindRepeating(&CreateChromeApplicationShortcutView::OnAppInfoLoaded,
weak_ptr_factory_.GetWeakPtr()));
}
CreateChromeApplicationShortcutView::CreateChromeApplicationShortcutView(
Profile* profile,
const std::string& web_app_id,
base::OnceCallback<void(bool)> close_callback)
: CreateChromeApplicationShortcutView(profile, std::move(close_callback)) {
web_app::WebAppProvider* provider = web_app::WebAppProvider::Get(profile);
provider->os_integration_manager().GetShortcutInfoForApp(
web_app_id,
base::BindRepeating(&CreateChromeApplicationShortcutView::OnAppInfoLoaded,
weak_ptr_factory_.GetWeakPtr()));
}
CreateChromeApplicationShortcutView::CreateChromeApplicationShortcutView(
Profile* profile,
base::OnceCallback<void(bool)> close_callback)
: profile_(profile), close_callback_(std::move(close_callback)) {
SetModalType(ui::MODAL_TYPE_WINDOW);
SetButtonLabel(ui::DIALOG_BUTTON_OK,
l10n_util::GetStringUTF16(IDS_CREATE_SHORTCUTS_COMMIT));
set_margins(ChromeLayoutProvider::Get()->GetDialogInsetsForContentType(
views::DialogContentType::kText, views::DialogContentType::kText));
SetAcceptCallback(
base::BindOnce(&CreateChromeApplicationShortcutView::OnDialogAccepted,
base::Unretained(this)));
auto canceled = [](CreateChromeApplicationShortcutView* dialog) {
if (!dialog->close_callback_.is_null())
std::move(dialog->close_callback_).Run(false);
};
SetCancelCallback(base::BindOnce(canceled, base::Unretained(this)));
SetCloseCallback(base::BindOnce(canceled, base::Unretained(this)));
InitControls();
chrome::RecordDialogCreation(
chrome::DialogIdentifier::CREATE_CHROME_APPLICATION_SHORTCUT);
}
CreateChromeApplicationShortcutView::~CreateChromeApplicationShortcutView() {}
void CreateChromeApplicationShortcutView::InitControls() {
auto create_shortcuts_label = std::make_unique<views::Label>(
l10n_util::GetStringUTF16(IDS_CREATE_SHORTCUTS_LABEL));
create_shortcuts_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
create_shortcuts_label->SetMultiLine(true);
std::unique_ptr<views::Checkbox> desktop_check_box = AddCheckbox(
l10n_util::GetStringUTF16(IDS_CREATE_SHORTCUTS_DESKTOP_CHKBOX),
prefs::kWebAppCreateOnDesktop);
std::unique_ptr<views::Checkbox> menu_check_box;
std::unique_ptr<views::Checkbox> quick_launch_check_box;
#if defined(OS_WIN)
base::win::Version version = base::win::GetVersion();
// Do not allow creating shortcuts on the Start Screen for Windows 8.
if (version != base::win::Version::WIN8 &&
version != base::win::Version::WIN8_1) {
menu_check_box = AddCheckbox(
l10n_util::GetStringUTF16(IDS_CREATE_SHORTCUTS_START_MENU_CHKBOX),
prefs::kWebAppCreateInAppsMenu);
}
// Win10 actively prevents creating shortcuts on the taskbar so we eliminate
// that option from the dialog.
if (base::win::CanPinShortcutToTaskbar()) {
quick_launch_check_box =
AddCheckbox((version >= base::win::Version::WIN7)
? l10n_util::GetStringUTF16(IDS_PIN_TO_TASKBAR_CHKBOX)
: l10n_util::GetStringUTF16(
IDS_CREATE_SHORTCUTS_QUICK_LAUNCH_BAR_CHKBOX),
prefs::kWebAppCreateInQuickLaunchBar);
}
#elif defined(OS_POSIX)
menu_check_box =
AddCheckbox(l10n_util::GetStringUTF16(IDS_CREATE_SHORTCUTS_MENU_CHKBOX),
prefs::kWebAppCreateInAppsMenu);
#endif
ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
// Layout controls
views::GridLayout* layout =
SetLayoutManager(std::make_unique<views::GridLayout>());
static const int kHeaderColumnSetId = 0;
views::ColumnSet* column_set = layout->AddColumnSet(kHeaderColumnSetId);
column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER, 1.0,
views::GridLayout::ColumnSize::kFixed, 0, 0);
static const int kTableColumnSetId = 1;
column_set = layout->AddColumnSet(kTableColumnSetId);
column_set->AddPaddingColumn(
views::GridLayout::kFixedSize,
provider->GetDistanceMetric(DISTANCE_SUBSECTION_HORIZONTAL_INDENT));
column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1.0,
views::GridLayout::ColumnSize::kUsePreferred, 0, 0);
layout->StartRow(views::GridLayout::kFixedSize, kHeaderColumnSetId);
layout->AddView(std::move(create_shortcuts_label));
layout->AddPaddingRow(
views::GridLayout::kFixedSize,
provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_VERTICAL));
layout->StartRow(views::GridLayout::kFixedSize, kTableColumnSetId);
desktop_check_box_ = layout->AddView(std::move(desktop_check_box));
const int vertical_spacing =
provider->GetDistanceMetric(DISTANCE_RELATED_CONTROL_VERTICAL_SMALL);
if (menu_check_box) {
layout->AddPaddingRow(views::GridLayout::kFixedSize, vertical_spacing);
layout->StartRow(views::GridLayout::kFixedSize, kTableColumnSetId);
menu_check_box_ = layout->AddView(std::move(menu_check_box));
}
if (quick_launch_check_box) {
layout->AddPaddingRow(views::GridLayout::kFixedSize, vertical_spacing);
layout->StartRow(views::GridLayout::kFixedSize, kTableColumnSetId);
quick_launch_check_box_ =
layout->AddView(std::move(quick_launch_check_box));
}
}
gfx::Size CreateChromeApplicationShortcutView::CalculatePreferredSize() const {
static const int kDialogWidth = 360;
int height = GetLayoutManager()->GetPreferredHeightForWidth(this,
kDialogWidth);
return gfx::Size(kDialogWidth, height);
}
bool CreateChromeApplicationShortcutView::IsDialogButtonEnabled(
ui::DialogButton button) const {
if (button != ui::DIALOG_BUTTON_OK)
return true; // It's always possible to cancel out of creating a shortcut.
if (!shortcut_info_)
return false; // Dialog's not ready because app info hasn't been loaded.
// One of the three location checkboxes must be checked:
return desktop_check_box_->GetChecked() ||
(menu_check_box_ && menu_check_box_->GetChecked()) ||
(quick_launch_check_box_ && quick_launch_check_box_->GetChecked());
}
std::u16string CreateChromeApplicationShortcutView::GetWindowTitle() const {
return l10n_util::GetStringUTF16(IDS_CREATE_SHORTCUTS_TITLE);
}
void CreateChromeApplicationShortcutView::OnDialogAccepted() {
DCHECK(IsDialogButtonEnabled(ui::DIALOG_BUTTON_OK));
if (!close_callback_.is_null())
std::move(close_callback_).Run(/*success=*/shortcut_info_ != nullptr);
// Shortcut can't be created because app info hasn't been loaded.
if (!shortcut_info_)
return;
web_app::ShortcutLocations creation_locations;
creation_locations.on_desktop = desktop_check_box_->GetChecked();
if (menu_check_box_ && menu_check_box_->GetChecked()) {
creation_locations.applications_menu_location =
web_app::APP_MENU_LOCATION_SUBDIR_CHROMEAPPS;
}
#if defined(OS_WIN)
creation_locations.in_quick_launch_bar =
quick_launch_check_box_ && quick_launch_check_box_->GetChecked();
#elif defined(OS_POSIX)
// Create shortcut in Mac dock or as Linux (gnome/kde) application launcher
// are not implemented yet.
creation_locations.in_quick_launch_bar = false;
#endif
web_app::CreateShortcutsWithInfo(web_app::SHORTCUT_CREATION_BY_USER,
creation_locations, base::DoNothing(),
std::move(shortcut_info_));
}
std::unique_ptr<views::Checkbox>
CreateChromeApplicationShortcutView::AddCheckbox(const std::u16string& text,
const std::string& pref_path) {
auto checkbox =
std::make_unique<views::Checkbox>(text, views::Button::PressedCallback());
checkbox->SetCallback(base::BindRepeating(
&CreateChromeApplicationShortcutView::CheckboxPressed,
base::Unretained(this), pref_path, base::Unretained(checkbox.get())));
checkbox->SetChecked(profile_->GetPrefs()->GetBoolean(pref_path));
return checkbox;
}
void CreateChromeApplicationShortcutView::CheckboxPressed(
std::string pref_path,
views::Checkbox* checkbox) {
profile_->GetPrefs()->SetBoolean(pref_path, checkbox->GetChecked());
DialogModelChanged();
}
void CreateChromeApplicationShortcutView::OnAppInfoLoaded(
std::unique_ptr<web_app::ShortcutInfo> shortcut_info) {
// GetShortcutInfoForApp request may return nullptr |shortcut_info| to this
// callback if web app was uninstalled during that asynchronous request.
shortcut_info_ = std::move(shortcut_info);
// This may cause there to be shortcut info when there was none before, so
// make sure the accept button gets enabled.
DialogModelChanged();
}
BEGIN_METADATA(CreateChromeApplicationShortcutView, views::DialogDelegateView)
END_METADATA