blob: 5fb4b6788a72df3ef0d57ce68994beef9fe924a4 [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/ash/launcher/browser_launcher_item_controller.h"
#include "ash/launcher/launcher.h"
#include "ash/launcher/launcher_model.h"
#include "ash/shell.h"
#include "ash/wm/window_util.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/browser/favicon/favicon_tab_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tab_contents/tab_contents.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/web_applications/web_app.h"
#include "content/public/browser/web_contents.h"
#include "grit/ui_resources.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/views/widget/widget.h"
using extensions::Extension;
BrowserLauncherItemController::BrowserLauncherItemController(
Type type,
aura::Window* window,
TabStripModel* tab_model,
ChromeLauncherController* launcher_controller,
const std::string& app_id)
: LauncherItemController(type, app_id, launcher_controller),
window_(window),
tab_model_(tab_model),
is_incognito_(tab_model->profile()->GetOriginalProfile() !=
tab_model->profile() && !Profile::IsGuestSession()) {
window_->AddObserver(this);
}
BrowserLauncherItemController::~BrowserLauncherItemController() {
tab_model_->RemoveObserver(this);
window_->RemoveObserver(this);
if (launcher_id() > 0)
launcher_controller()->CloseLauncherItem(launcher_id());
}
void BrowserLauncherItemController::Init() {
tab_model_->AddObserver(this);
ash::LauncherItemStatus app_status =
ash::wm::IsActiveWindow(window_) ?
ash::STATUS_ACTIVE : ash::STATUS_RUNNING;
if (type() != TYPE_TABBED) {
launcher_controller()->CreateAppLauncherItem(this, app_id(), app_status);
} else {
launcher_controller()->CreateTabbedLauncherItem(
this,
is_incognito_ ? ChromeLauncherController::STATE_INCOGNITO :
ChromeLauncherController::STATE_NOT_INCOGNITO,
app_status);
}
// In testing scenarios we can get tab strips with no active contents.
if (tab_model_->GetActiveTabContents())
UpdateLauncher(tab_model_->GetActiveTabContents());
}
// static
BrowserLauncherItemController* BrowserLauncherItemController::Create(
Browser* browser) {
// Under testing this can be called before the controller is created.
if (!ChromeLauncherController::instance())
return NULL;
Type type;
std::string app_id;
if (browser->type() == Browser::TYPE_TABBED ||
browser->type() == Browser::TYPE_POPUP) {
type = TYPE_TABBED;
} else if (browser->is_app()) {
if (browser->is_type_panel()) {
if (browser->app_type() == Browser::APP_TYPE_CHILD)
type = TYPE_EXTENSION_PANEL;
else
type = TYPE_APP_PANEL;
} else {
type = TYPE_TABBED;
}
app_id = web_app::GetExtensionIdFromApplicationName(browser->app_name());
} else {
return NULL;
}
BrowserLauncherItemController* controller =
new BrowserLauncherItemController(type,
browser->window()->GetNativeWindow(),
browser->tab_strip_model(),
ChromeLauncherController::instance(),
app_id);
controller->Init();
return controller;
}
void BrowserLauncherItemController::BrowserActivationStateChanged() {
if (tab_model_->GetActiveTabContents())
UpdateAppState(tab_model_->GetActiveTabContents());
UpdateItemStatus();
}
string16 BrowserLauncherItemController::GetTitle() {
if (type() == TYPE_TABBED || type() == TYPE_EXTENSION_PANEL) {
const content::WebContents* contents =
tab_model_->GetActiveTabContents()->web_contents();
if (contents)
return contents->GetTitle();
}
return GetAppTitle();
}
bool BrowserLauncherItemController::HasWindow(aura::Window* window) const {
return window_ == window;
}
bool BrowserLauncherItemController::IsOpen() const {
return window_ != NULL;
}
void BrowserLauncherItemController::Open(int event_flags) {
window_->Show();
ash::wm::ActivateWindow(window_);
}
void BrowserLauncherItemController::Close() {
views::Widget* widget = views::Widget::GetWidgetForNativeView(window_);
if (widget)
widget->Close();
}
void BrowserLauncherItemController::Clicked() {
views::Widget* widget =
views::Widget::GetWidgetForNativeView(window_);
if (widget && widget->IsActive())
widget->Minimize();
else
Open(ui::EF_NONE);
}
void BrowserLauncherItemController::OnRemoved() {
}
void BrowserLauncherItemController::ActiveTabChanged(
TabContents* old_contents,
TabContents* new_contents,
int index,
bool user_gesture) {
// Update immediately on a tab change.
if (old_contents)
UpdateAppState(old_contents);
UpdateAppState(new_contents);
UpdateLauncher(new_contents);
}
void BrowserLauncherItemController::TabInsertedAt(TabContents* contents,
int index,
bool foreground) {
UpdateAppState(contents);
}
void BrowserLauncherItemController::TabDetachedAt(TabContents* contents,
int index) {
launcher_controller()->UpdateAppState(
contents, ChromeLauncherController::APP_STATE_REMOVED);
}
void BrowserLauncherItemController::TabChangedAt(
TabContents* tab,
int index,
TabStripModelObserver::TabChangeType change_type) {
UpdateAppState(tab);
if (index != tab_model_->active_index() ||
!(change_type != TabStripModelObserver::LOADING_ONLY &&
change_type != TabStripModelObserver::TITLE_NOT_LOADING)) {
return;
}
if (tab->favicon_tab_helper()->FaviconIsValid() ||
!tab->favicon_tab_helper()->ShouldDisplayFavicon()) {
// We have the favicon, update immediately.
UpdateLauncher(tab);
} else {
int item_index = launcher_model()->ItemIndexByID(launcher_id());
if (item_index == -1)
return;
ash::LauncherItem item = launcher_model()->items()[item_index];
item.image = SkBitmap();
launcher_model()->Set(item_index, item);
}
}
void BrowserLauncherItemController::TabReplacedAt(
TabStripModel* tab_strip_model,
TabContents* old_contents,
TabContents* new_contents,
int index) {
launcher_controller()->UpdateAppState(
old_contents, ChromeLauncherController::APP_STATE_REMOVED);
UpdateAppState(new_contents);
}
void BrowserLauncherItemController::FaviconUpdated() {
UpdateLauncher(tab_model_->GetActiveTabContents());
}
void BrowserLauncherItemController::OnWindowPropertyChanged(
aura::Window* window,
const void* key,
intptr_t old) {
if (key == aura::client::kDrawAttentionKey)
UpdateItemStatus();
}
void BrowserLauncherItemController::UpdateItemStatus() {
ash::LauncherItemStatus status;
if (ash::wm::IsActiveWindow(window_)) {
// Clear attention state if active.
if (window_->GetProperty(aura::client::kDrawAttentionKey))
window_->SetProperty(aura::client::kDrawAttentionKey, false);
status = ash::STATUS_ACTIVE;
} else if (window_->GetProperty(aura::client::kDrawAttentionKey)) {
status = ash::STATUS_ATTENTION;
} else {
status = ash::STATUS_RUNNING;
}
launcher_controller()->SetItemStatus(launcher_id(), status);
}
void BrowserLauncherItemController::UpdateLauncher(TabContents* tab) {
if (type() == TYPE_APP_PANEL)
return; // Maintained entirely by ChromeLauncherController.
if (!tab)
return; // Assume the window is going to be closed if there are no tabs.
int item_index = launcher_model()->ItemIndexByID(launcher_id());
if (item_index == -1)
return;
ash::LauncherItem item = launcher_model()->items()[item_index];
if (type() == TYPE_EXTENSION_PANEL) {
if (!favicon_loader_.get() ||
favicon_loader_->web_contents() != tab->web_contents()) {
favicon_loader_.reset(
new LauncherFaviconLoader(this, tab->web_contents()));
}
// Update the icon for extension panels.
extensions::TabHelper* extensions_tab_helper =
extensions::TabHelper::FromWebContents(tab->web_contents());
SkBitmap new_image = favicon_loader_->GetFavicon();
if (new_image.isNull() && extensions_tab_helper->GetExtensionAppIcon())
new_image = *extensions_tab_helper->GetExtensionAppIcon();
// Only update the icon if we have a new image, or none has been set yet.
// This avoids flickering to an empty image when a pinned app is opened.
if (!new_image.isNull())
item.image = new_image;
else if (item.image.isNull())
item.image = extensions::Extension::GetDefaultIcon(true);
} else {
DCHECK_EQ(TYPE_TABBED, type());
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
if (tab->favicon_tab_helper()->ShouldDisplayFavicon()) {
item.image = tab->favicon_tab_helper()->GetFavicon().AsImageSkia();
if (item.image.isNull()) {
item.image = *rb.GetImageSkiaNamed(IDR_DEFAULT_FAVICON);
}
} else {
item.image = *rb.GetImageSkiaNamed(IDR_DEFAULT_FAVICON);
}
}
launcher_model()->Set(item_index, item);
}
void BrowserLauncherItemController::UpdateAppState(TabContents* tab) {
ChromeLauncherController::AppState app_state;
if (tab_model_->GetIndexOfTabContents(tab) == TabStripModel::kNoTab) {
app_state = ChromeLauncherController::APP_STATE_REMOVED;
} else if (tab_model_->GetActiveTabContents() == tab) {
if (ash::wm::IsActiveWindow(window_))
app_state = ChromeLauncherController::APP_STATE_WINDOW_ACTIVE;
else
app_state = ChromeLauncherController::APP_STATE_ACTIVE;
} else {
app_state = ChromeLauncherController::APP_STATE_INACTIVE;
}
launcher_controller()->UpdateAppState(tab, app_state);
}
ash::LauncherModel* BrowserLauncherItemController::launcher_model() {
return launcher_controller()->model();
}