summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorskuhne@chromium.org <skuhne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-08 21:40:08 +0000
committerskuhne@chromium.org <skuhne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-08 21:40:08 +0000
commit00c8469e26c18b47981a92931acbc209efa8c3e4 (patch)
tree17c1576f6737ce4d49500baf3805b92a6e4e0af0
parent993951d6500d51ee010103c7f8727eaa900bd563 (diff)
downloadchromium_src-00c8469e26c18b47981a92931acbc209efa8c3e4.zip
chromium_src-00c8469e26c18b47981a92931acbc209efa8c3e4.tar.gz
chromium_src-00c8469e26c18b47981a92931acbc209efa8c3e4.tar.bz2
This is the first of two patches to drag and drop items from the app list to the launcher.
Everything basically works with this patch, but two essential things are still missing: 1. The icon which gets dragged should get its own widget so that it can get visually dragged outside the app list. 2. The unit tests. They will be send as a second patch because of: a. The patch is already pretty big as it is. b. I want to make get this "signed off" before continuing this route. BUG=166429 TEST=visual, tests come with second patch Review URL: https://chromiumcodereview.appspot.com/14533006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@199016 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--ash/ash_switches.cc6
-rw-r--r--ash/ash_switches.h1
-rw-r--r--ash/launcher/launcher_button_host.h1
-rw-r--r--ash/launcher/launcher_delegate.h12
-rw-r--r--ash/launcher/launcher_view.cc134
-rw-r--r--ash/launcher/launcher_view.h22
-rw-r--r--ash/shell.cc7
-rw-r--r--ash/shell.h8
-rw-r--r--ash/shell/launcher_delegate_impl.cc11
-rw-r--r--ash/shell/launcher_delegate_impl.h3
-rw-r--r--ash/test/test_launcher_delegate.cc11
-rw-r--r--ash/test/test_launcher_delegate.h3
-rw-r--r--ash/wm/app_list_controller.cc6
-rw-r--r--ash/wm/app_list_controller.h6
-rw-r--r--chrome/app/generated_resources.grd6
-rw-r--r--chrome/browser/about_flags.cc6
-rw-r--r--chrome/browser/ui/app_list/extension_app_item.cc1
-rw-r--r--ui/app_list/app_list.gyp1
-rw-r--r--ui/app_list/app_list_item_model.h4
-rw-r--r--ui/app_list/views/app_list_drag_and_drop_host.h41
-rw-r--r--ui/app_list/views/app_list_main_view.cc5
-rw-r--r--ui/app_list/views/app_list_main_view.h6
-rw-r--r--ui/app_list/views/app_list_view.cc6
-rw-r--r--ui/app_list/views/app_list_view.h9
-rw-r--r--ui/app_list/views/apps_grid_view.cc55
-rw-r--r--ui/app_list/views/apps_grid_view.h21
-rw-r--r--ui/app_list/views/contents_view.cc18
-rw-r--r--ui/app_list/views/contents_view.h9
28 files changed, 378 insertions, 41 deletions
diff --git a/ash/ash_switches.cc b/ash/ash_switches.cc
index 516fa60..24fef79 100644
--- a/ash/ash_switches.cc
+++ b/ash/ash_switches.cc
@@ -141,11 +141,15 @@ const char kAuraLegacyPowerButton[] = "aura-legacy-power-button";
// Force Ash to open its root window on the desktop, even on Windows 8 where
// it would normally end up in metro.
const char kForceAshToDesktop[] = "ash-force-desktop";
+
#endif
+// Allow items to be dragged from the app launcher list into the launcher.
+const char kAshDragAndDropAppListToLauncher[] =
+ "ash-drag-and-drop-applist-to-launcher";
+
// Enables a mode which enforces all browser & application windows to be created
// in maximized mode.
const char kForcedMaximizeMode[] = "forced-maximize-mode";
-
} // namespace switches
} // namespace ash
diff --git a/ash/ash_switches.h b/ash/ash_switches.h
index 003cd35..d11ef8d 100644
--- a/ash/ash_switches.h
+++ b/ash/ash_switches.h
@@ -35,6 +35,7 @@ ASH_EXPORT extern const char kAshDisableNewNetworkStatusArea[];
ASH_EXPORT extern const char kAshDisablePerAppLauncher[];
ASH_EXPORT extern const char kAshDisableUIScaling[];
ASH_EXPORT extern const char kAshDisableDisplayRotation[];
+ASH_EXPORT extern const char kAshDragAndDropAppListToLauncher[];
ASH_EXPORT extern const char kAshEnableAudioDeviceMenu[];
ASH_EXPORT extern const char kAshEnableAdvancedGestures[];
ASH_EXPORT extern const char kAshEnableBrightnessControl[];
diff --git a/ash/launcher/launcher_button_host.h b/ash/launcher/launcher_button_host.h
index ecb76a3..c867a68c 100644
--- a/ash/launcher/launcher_button_host.h
+++ b/ash/launcher/launcher_button_host.h
@@ -25,6 +25,7 @@ class ASH_EXPORT LauncherButtonHost {
public:
enum Pointer {
NONE,
+ DRAG_AND_DROP,
MOUSE,
TOUCH,
};
diff --git a/ash/launcher/launcher_delegate.h b/ash/launcher/launcher_delegate.h
index 45109e8..0bd8ec6 100644
--- a/ash/launcher/launcher_delegate.h
+++ b/ash/launcher/launcher_delegate.h
@@ -106,6 +106,18 @@ class ASH_EXPORT LauncherDelegate {
// True if the running launcher is the per application launcher.
virtual bool IsPerAppLauncher() = 0;
+
+ // Get the launcher ID from an application ID.
+ virtual LauncherID GetLauncherIDForAppID(const std::string& app_id) = 0;
+
+ // Pins an app with |app_id| to launcher. A running instance will get pinned.
+ // In case there is no running instance a new launcher item is created and
+ // pinned.
+ virtual void PinAppWithID(const std::string& app_id) = 0;
+
+ // Unpins any app item(s) whose id is |app_id|. The new launcher will collect
+ // all items under one item, the old launcher might have multiple items.
+ virtual void UnpinAppsWithID(const std::string& app_id) = 0;
};
} // namespace ash
diff --git a/ash/launcher/launcher_view.cc b/ash/launcher/launcher_view.cc
index 32e20ec..f0b4bf5 100644
--- a/ash/launcher/launcher_view.cc
+++ b/ash/launcher/launcher_view.cc
@@ -22,6 +22,7 @@
#include "ash/shelf/shelf_widget.h"
#include "ash/shell_delegate.h"
#include "base/auto_reset.h"
+#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
#include "grit/ash_resources.h"
#include "grit/ash_strings.h"
@@ -377,7 +378,9 @@ LauncherView::LauncherView(LauncherModel* model,
cancelling_drag_model_changed_(false),
last_hidden_index_(0),
closing_event_time_(base::TimeDelta()),
- got_deleted_(NULL) {
+ got_deleted_(NULL),
+ drag_and_drop_item_created_(false),
+ drag_and_drop_launcher_id_(0) {
DCHECK(model_);
bounds_animator_.reset(new views::BoundsAnimator(this));
bounds_animator_->AddObserver(this);
@@ -523,6 +526,83 @@ View* LauncherView::GetFocusTraversableParentView() {
return this;
}
+bool LauncherView::StartDrag(const std::string& app_id,
+ const gfx::Point& location_in_screen_coordinates) {
+ // Bail if an operation is already going on - or the cursor is not inside.
+ // This could happen if mouse / touch operations overlap.
+ if (drag_and_drop_launcher_id_ ||
+ !GetBoundsInScreen().Contains(location_in_screen_coordinates))
+ return false;
+
+ // If the AppsGridView (which was dispatching this event) was opened by our
+ // button, LauncherView dragging operations are locked and we have to unlock.
+ CancelDrag(-1);
+ drag_and_drop_item_created_ = false;
+ drag_and_drop_app_id_ = app_id;
+ drag_and_drop_launcher_id_ =
+ delegate_->GetLauncherIDForAppID(drag_and_drop_app_id_);
+
+ if (!drag_and_drop_launcher_id_) {
+ delegate_->PinAppWithID(app_id);
+ drag_and_drop_launcher_id_ =
+ delegate_->GetLauncherIDForAppID(drag_and_drop_app_id_);
+ if (!drag_and_drop_launcher_id_)
+ return false;
+ drag_and_drop_item_created_ = true;
+ }
+ views::View* drag_and_drop_view = view_model_->view_at(
+ model_->ItemIndexByID(drag_and_drop_launcher_id_));
+ DCHECK(drag_and_drop_view);
+
+ // Since there is already an icon presented, we hide this one for now.
+ drag_and_drop_view->SetVisible(false);
+ // First we have to center the mouse cursor over the item.
+ gfx::Point pt = drag_and_drop_view->GetBoundsInScreen().CenterPoint();
+ views::View::ConvertPointFromScreen(drag_and_drop_view, &pt);
+ ui::MouseEvent event(ui::ET_MOUSE_PRESSED,
+ pt, location_in_screen_coordinates, 0);
+ PointerPressedOnButton(
+ drag_and_drop_view, LauncherButtonHost::DRAG_AND_DROP, event);
+
+ // Drag the item where it really belongs.
+ Drag(location_in_screen_coordinates);
+ return true;
+}
+
+bool LauncherView::Drag(const gfx::Point& location_in_screen_coordinates) {
+ if (!drag_and_drop_launcher_id_ ||
+ !GetBoundsInScreen().Contains(location_in_screen_coordinates))
+ return false;
+
+ gfx::Point pt = location_in_screen_coordinates;
+ views::View* drag_and_drop_view = view_model_->view_at(
+ model_->ItemIndexByID(drag_and_drop_launcher_id_));
+ views::View::ConvertPointFromScreen(drag_and_drop_view, &pt);
+
+ ui::MouseEvent event(ui::ET_MOUSE_DRAGGED, pt, gfx::Point(), 0);
+ PointerDraggedOnButton(
+ drag_and_drop_view, LauncherButtonHost::DRAG_AND_DROP, event);
+ return true;
+}
+
+void LauncherView::EndDrag(bool cancel) {
+ if (!drag_and_drop_launcher_id_)
+ return;
+
+ views::View* drag_and_drop_view = view_model_->view_at(
+ model_->ItemIndexByID(drag_and_drop_launcher_id_));
+ PointerReleasedOnButton(
+ drag_and_drop_view, LauncherButtonHost::DRAG_AND_DROP, cancel);
+
+ if (drag_and_drop_item_created_ && cancel)
+ delegate_->UnpinAppsWithID(drag_and_drop_app_id_);
+
+ if (drag_and_drop_view)
+ drag_and_drop_view->SetVisible(true);
+
+ drag_and_drop_launcher_id_ = 0;
+}
+
void LauncherView::LayoutToIdealBounds() {
IdealBounds ideal_bounds;
CalculateIdealBounds(&ideal_bounds);
@@ -1340,31 +1420,37 @@ void LauncherView::ButtonPressed(views::Button* sender,
ui::ScopedAnimationDurationScaleMode::SLOW_DURATION));
}
- // Collect usage statistics before we decide what to do with the click.
- switch (model_->items()[view_index].type) {
- case TYPE_APP_SHORTCUT:
- case TYPE_WINDOWED_APP:
- case TYPE_PLATFORM_APP:
- Shell::GetInstance()->delegate()->RecordUserMetricsAction(
- UMA_LAUNCHER_CLICK_ON_APP);
- // Fallthrough
- case TYPE_TABBED:
- case TYPE_APP_PANEL:
- delegate_->ItemSelected(model_->items()[view_index], event);
- break;
+ // Collect usage statistics before we decide what to do with the click.
+ switch (model_->items()[view_index].type) {
+ case TYPE_APP_SHORTCUT:
+ case TYPE_WINDOWED_APP:
+ case TYPE_PLATFORM_APP:
+ Shell::GetInstance()->delegate()->RecordUserMetricsAction(
+ UMA_LAUNCHER_CLICK_ON_APP);
+ // Fallthrough
+ case TYPE_TABBED:
+ case TYPE_APP_PANEL:
+ delegate_->ItemSelected(model_->items()[view_index], event);
+ break;
- case TYPE_APP_LIST:
- Shell::GetInstance()->delegate()->RecordUserMetricsAction(
- UMA_LAUNCHER_CLICK_ON_APPLIST_BUTTON);
- Shell::GetInstance()->ToggleAppList(GetWidget()->GetNativeView());
- break;
+ case TYPE_APP_LIST:
+ Shell::GetInstance()->delegate()->RecordUserMetricsAction(
+ UMA_LAUNCHER_CLICK_ON_APPLIST_BUTTON);
+ Shell::GetInstance()->ToggleAppList(GetWidget()->GetNativeView());
+ // By setting us as DnD recipient, the app list knows that we can
+ // handle items.
+ // TODO(skuhne): Invert the flag
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ ash::switches::kAshDragAndDropAppListToLauncher))
+ Shell::GetInstance()->SetDragAndDropHostOfCurrentAppList(this);
+ break;
- case TYPE_BROWSER_SHORTCUT:
- // Click on browser icon is counted in app clicks.
- Shell::GetInstance()->delegate()->RecordUserMetricsAction(
- UMA_LAUNCHER_CLICK_ON_APP);
- delegate_->OnBrowserShortcutClicked(event.flags());
- break;
+ case TYPE_BROWSER_SHORTCUT:
+ // Click on browser icon is counted in app clicks.
+ Shell::GetInstance()->delegate()->RecordUserMetricsAction(
+ UMA_LAUNCHER_CLICK_ON_APP);
+ delegate_->OnBrowserShortcutClicked(event.flags());
+ break;
}
}
diff --git a/ash/launcher/launcher_view.h b/ash/launcher/launcher_view.h
index 3b1f0f3..b7b8c93 100644
--- a/ash/launcher/launcher_view.h
+++ b/ash/launcher/launcher_view.h
@@ -12,6 +12,7 @@
#include "ash/launcher/launcher_model_observer.h"
#include "ash/wm/gestures/shelf_gesture_handler.h"
#include "base/observer_list.h"
+#include "ui/app_list/views/app_list_drag_and_drop_host.h"
#include "ui/views/animation/bounds_animator_observer.h"
#include "ui/views/context_menu_controller.h"
#include "ui/views/controls/button/button.h"
@@ -50,7 +51,8 @@ class ASH_EXPORT LauncherView : public views::View,
public LauncherButtonHost,
public views::ContextMenuController,
public views::FocusTraversable,
- public views::BoundsAnimatorObserver {
+ public views::BoundsAnimatorObserver,
+ public app_list::ApplicationDragAndDropHost {
public:
LauncherView(LauncherModel* model,
LauncherDelegate* delegate,
@@ -97,6 +99,13 @@ class ASH_EXPORT LauncherView : public views::View,
virtual FocusTraversable* GetFocusTraversableParent() OVERRIDE;
virtual View* GetFocusTraversableParentView() OVERRIDE;
+ // Overridden from app_list::ApplicationDragAndDropHost:
+ virtual bool StartDrag(
+ const std::string& app_id,
+ const gfx::Point& location_in_screen_coordinates) OVERRIDE;
+ virtual bool Drag(const gfx::Point& location_in_screen_coordinates) OVERRIDE;
+ virtual void EndDrag(bool cancel) OVERRIDE;
+
private:
friend class ash::test::LauncherViewTestAPI;
@@ -320,6 +329,17 @@ class ASH_EXPORT LauncherView : public views::View,
// element will be set to false.
bool* got_deleted_;
+ // True if a drag and drop operation created the item in the launcher and it
+ // needs to be deleted again if the operation gets cancelled.
+ bool drag_and_drop_item_created_;
+
+ // The launcher item which is currently used for a drag and a drop operation
+ // or 0 otherwise.
+ LauncherID drag_and_drop_launcher_id_;
+
+ // The application ID of the application which we drag and drop.
+ std::string drag_and_drop_app_id_;
+
DISALLOW_COPY_AND_ASSIGN(LauncherView);
};
diff --git a/ash/shell.cc b/ash/shell.cc
index 4be78a2..4f6e936 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -650,6 +650,13 @@ void Shell::ToggleAppList(aura::Window* window) {
app_list_controller_->SetVisible(!app_list_controller_->IsVisible(), window);
}
+void Shell::SetDragAndDropHostOfCurrentAppList(
+ app_list::ApplicationDragAndDropHost* drag_and_drop_host) {
+ if (app_list_controller_.get())
+ app_list_controller_->SetDragAndDropHostOfCurrentAppList(
+ drag_and_drop_host);
+}
+
bool Shell::GetAppListTargetVisibility() const {
return app_list_controller_.get() &&
app_list_controller_->GetTargetVisibility();
diff --git a/ash/shell.h b/ash/shell.h
index b8a0ce9..cb96ee6 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -26,6 +26,9 @@
class CommandLine;
+namespace app_list {
+class ApplicationDragAndDropHost;
+}
namespace aura {
class EventFilter;
class RootWindow;
@@ -217,6 +220,11 @@ class ASH_EXPORT Shell
// will be used.
void ToggleAppList(aura::Window* anchor);
+ // If |drag_and_drop_host| is not NULL it will be called upon drag and drop
+ // operations outside the application list.
+ void SetDragAndDropHostOfCurrentAppList(
+ app_list::ApplicationDragAndDropHost* drag_and_drop_host);
+
// Returns app list target visibility.
bool GetAppListTargetVisibility() const;
diff --git a/ash/shell/launcher_delegate_impl.cc b/ash/shell/launcher_delegate_impl.cc
index b38dee3..601adac 100644
--- a/ash/shell/launcher_delegate_impl.cc
+++ b/ash/shell/launcher_delegate_impl.cc
@@ -80,5 +80,16 @@ bool LauncherDelegateImpl::IsPerAppLauncher() {
return false;
}
+LauncherID LauncherDelegateImpl::GetLauncherIDForAppID(
+ const std::string& app_id) {
+ return 0;
+}
+
+void LauncherDelegateImpl::PinAppWithID(const std::string& app_id) {
+}
+
+void LauncherDelegateImpl::UnpinAppsWithID(const std::string& app_id) {
+}
+
} // namespace shell
} // namespace ash
diff --git a/ash/shell/launcher_delegate_impl.h b/ash/shell/launcher_delegate_impl.h
index e57b5b4..26b1dfd 100644
--- a/ash/shell/launcher_delegate_impl.h
+++ b/ash/shell/launcher_delegate_impl.h
@@ -42,6 +42,9 @@ class LauncherDelegateImpl : public ash::LauncherDelegate {
virtual void OnLauncherCreated(Launcher* launcher) OVERRIDE;
virtual void OnLauncherDestroyed(Launcher* launcher) OVERRIDE;
virtual bool IsPerAppLauncher() OVERRIDE;
+ virtual LauncherID GetLauncherIDForAppID(const std::string& app_id) OVERRIDE;
+ virtual void PinAppWithID(const std::string& app_id) OVERRIDE;
+ virtual void UnpinAppsWithID(const std::string& app_id) OVERRIDE;
private:
// Used to update Launcher. Owned by main.
diff --git a/ash/test/test_launcher_delegate.cc b/ash/test/test_launcher_delegate.cc
index 16422e3..3a4fccd 100644
--- a/ash/test/test_launcher_delegate.cc
+++ b/ash/test/test_launcher_delegate.cc
@@ -131,5 +131,16 @@ bool TestLauncherDelegate::IsPerAppLauncher() {
return true;
}
+LauncherID TestLauncherDelegate::GetLauncherIDForAppID(
+ const std::string& app_id) {
+ return 0;
+}
+
+void TestLauncherDelegate::PinAppWithID(const std::string& app_id) {
+}
+
+void TestLauncherDelegate::UnpinAppsWithID(const std::string& app_id) {
+}
+
} // namespace test
} // namespace ash
diff --git a/ash/test/test_launcher_delegate.h b/ash/test/test_launcher_delegate.h
index b86b1e1..65dc634 100644
--- a/ash/test/test_launcher_delegate.h
+++ b/ash/test/test_launcher_delegate.h
@@ -51,6 +51,9 @@ class TestLauncherDelegate : public LauncherDelegate,
virtual void OnLauncherCreated(Launcher* launcher) OVERRIDE;
virtual void OnLauncherDestroyed(Launcher* launcher) OVERRIDE;
virtual bool IsPerAppLauncher() OVERRIDE;
+ virtual LauncherID GetLauncherIDForAppID(const std::string& app_id) OVERRIDE;
+ virtual void PinAppWithID(const std::string& app_id) OVERRIDE;
+ virtual void UnpinAppsWithID(const std::string& app_id) OVERRIDE;
private:
typedef std::map<aura::Window*, ash::LauncherID> WindowToID;
diff --git a/ash/wm/app_list_controller.cc b/ash/wm/app_list_controller.cc
index 7fcf76c..02afc69 100644
--- a/ash/wm/app_list_controller.cc
+++ b/ash/wm/app_list_controller.cc
@@ -139,6 +139,12 @@ aura::Window* AppListController::GetWindow() {
return is_visible_ && view_ ? view_->GetWidget()->GetNativeWindow() : NULL;
}
+void AppListController::SetDragAndDropHostOfCurrentAppList(
+ app_list::ApplicationDragAndDropHost* drag_and_drop_host) {
+ if (view_ && is_visible_)
+ view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
+}
+
////////////////////////////////////////////////////////////////////////////////
// AppListController, private:
diff --git a/ash/wm/app_list_controller.h b/ash/wm/app_list_controller.h
index d2408d8..6f05d6a 100644
--- a/ash/wm/app_list_controller.h
+++ b/ash/wm/app_list_controller.h
@@ -19,6 +19,7 @@
#include "ui/views/widget/widget_observer.h"
namespace app_list {
+class ApplicationDragAndDropHost;
class AppListView;
class PaginationModel;
}
@@ -61,6 +62,11 @@ class AppListController : public ui::EventHandler,
// Returns app list window or NULL if it is not visible.
aura::Window* GetWindow();
+ // If |drag_and_drop_host| is not NULL it will be called upon drag and drop
+ // operations outside the application list.
+ void SetDragAndDropHostOfCurrentAppList(
+ app_list::ApplicationDragAndDropHost* drag_and_drop_host);
+
private:
// Sets the app list view and attempts to show it.
void SetView(app_list::AppListView* view);
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index e83b7d5..2f68e34 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -6774,6 +6774,12 @@ Keep your key file in a safe place. You will need it to create new versions of y
<message name="IDS_FLAGS_ENABLE_WORKSPACE_SCRUBBING_DESCRIPTION" desc="Description for the flag to enable workspace scrubbing.">
Enables workspace switching via 3 finger vertical scroll.
</message>
+ <message name="IDS_FLAGS_DND_APPLIST_TO_LAUNCHER_NAME" desc="Title for the flag to enable drag and drop from the app list menu to the launcher.">
+ Drag and drop from the app list menu to the launcher
+ </message>
+ <message name="IDS_FLAGS_DND_APPLIST_TO_LAUNCHER_DESCRIPTION" desc="Description for the flag to enable drag and drop opertions from the app list menu to the launcher.">
+ Allows drag and drop from the app list menu to the launcher.
+ </message>
<message name="IDS_FLAGS_ASH_IMMERSIVE_FULLSCREEN_NAME" desc="Title for the flag for immersive fullscreen mode.">
Immersive fullscreen
</message>
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 8dbe099..f9291db 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1156,6 +1156,12 @@ const Experiment kExperiments[] = {
kOsCrOS,
SINGLE_VALUE_TYPE(switches::kAshDisableTabScrubbing),
},
+ { "ash-drag-and-drop-applist-to-launcher",
+ IDS_FLAGS_DND_APPLIST_TO_LAUNCHER_NAME,
+ IDS_FLAGS_DND_APPLIST_TO_LAUNCHER_DESCRIPTION,
+ kOsCrOS,
+ SINGLE_VALUE_TYPE(ash::switches::kAshDragAndDropAppListToLauncher),
+ },
{ "ash-enable-workspace-scrubbing",
IDS_FLAGS_ENABLE_WORKSPACE_SCRUBBING_NAME,
IDS_FLAGS_ENABLE_WORKSPACE_SCRUBBING_DESCRIPTION,
diff --git a/chrome/browser/ui/app_list/extension_app_item.cc b/chrome/browser/ui/app_list/extension_app_item.cc
index a8b0856..152d379d 100644
--- a/chrome/browser/ui/app_list/extension_app_item.cc
+++ b/chrome/browser/ui/app_list/extension_app_item.cc
@@ -209,6 +209,7 @@ void ExtensionAppItem::Reload() {
const Extension* extension = GetExtension();
bool is_installing = !extension;
SetIsInstalling(is_installing);
+ set_app_id(extension_id_);
if (is_installing) {
SetTitle(extension_name_);
UpdateIcon();
diff --git a/ui/app_list/app_list.gyp b/ui/app_list/app_list.gyp
index e42f52a..ba86a6c 100644
--- a/ui/app_list/app_list.gyp
+++ b/ui/app_list/app_list.gyp
@@ -69,6 +69,7 @@
'signin_delegate_observer.h',
'views/app_list_background.cc',
'views/app_list_background.h',
+ 'views/app_list_drag_and_drop_host.h',
'views/app_list_item_view.cc',
'views/app_list_item_view.h',
'views/app_list_main_view.cc',
diff --git a/ui/app_list/app_list_item_model.h b/ui/app_list/app_list_item_model.h
index d0acd76..d437564 100644
--- a/ui/app_list/app_list_item_model.h
+++ b/ui/app_list/app_list_item_model.h
@@ -43,6 +43,9 @@ class APP_LIST_EXPORT AppListItemModel {
void SetPercentDownloaded(int percent_downloaded);
int percent_downloaded() const { return percent_downloaded_; }
+ void set_app_id(const std::string& app_id) { app_id_ = app_id; }
+ const std::string& app_id() { return app_id_; }
+
void AddObserver(AppListItemModelObserver* observer);
void RemoveObserver(AppListItemModelObserver* observer);
@@ -57,6 +60,7 @@ class APP_LIST_EXPORT AppListItemModel {
bool highlighted_;
bool is_installing_;
int percent_downloaded_;
+ std::string app_id_;
ObserverList<AppListItemModelObserver> observers_;
diff --git a/ui/app_list/views/app_list_drag_and_drop_host.h b/ui/app_list/views/app_list_drag_and_drop_host.h
new file mode 100644
index 0000000..3da9cf7
--- /dev/null
+++ b/ui/app_list/views/app_list_drag_and_drop_host.h
@@ -0,0 +1,41 @@
+// 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 UI_APP_LIST_VIEWS_APP_LIST_DRAG_AND_DROP_HOST_H_
+#define UI_APP_LIST_VIEWS_APP_LIST_DRAG_AND_DROP_HOST_H_
+
+#include <string>
+
+namespace gfx {
+class Point;
+} // namespace gfx
+
+namespace app_list {
+
+// This class will get used by the AppListView to drag and drop Application
+// shortcuts onto another host (the launcher).
+class ApplicationDragAndDropHost {
+ public:
+ // A drag operation could get started. The recipient has to return true if
+ // he wants to take it - e.g. |location_in_screen_poordinates| is over a
+ // target area. The passed |app_id| identifies the application which should
+ // get dropped.
+ virtual bool StartDrag(const std::string& app_id,
+ const gfx::Point& location_in_screen_coordinates) = 0;
+
+ // This gets only called when the |StartDrag| function returned true and it
+ // dispatches the mouse coordinate change accordingly. When the function
+ // returns false it requests that the operation be aborted since the event
+ // location is out of bounds.
+ virtual bool Drag(const gfx::Point& location_in_screen_coordinates) = 0;
+
+ // Once |StartDrag| returned true, this function is guaranteed to be called
+ // when the mouse / touch events stop. If |cancel| is set, the drag operation
+ // was aborted, otherwise the change should be kept.
+ virtual void EndDrag(bool cancel) = 0;
+};
+
+} // namespace app_list
+
+#endif // UI_APP_LIST_VIEWS_APP_LIST_DRAG_AND_DROP_HOST_H_
diff --git a/ui/app_list/views/app_list_main_view.cc b/ui/app_list/views/app_list_main_view.cc
index e966ec9..c7b11d10 100644
--- a/ui/app_list/views/app_list_main_view.cc
+++ b/ui/app_list/views/app_list_main_view.cc
@@ -134,6 +134,11 @@ void AppListMainView::Prerender() {
contents_view_->Prerender();
}
+void AppListMainView::SetDragAndDropHostOfCurrentAppList(
+ app_list::ApplicationDragAndDropHost* drag_and_drop_host) {
+ contents_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
+}
+
void AppListMainView::PreloadIcons(PaginationModel* pagination_model,
views::View* anchor) {
ui::ScaleFactor scale_factor = ui::SCALE_FACTOR_100P;
diff --git a/ui/app_list/views/app_list_main_view.h b/ui/app_list/views/app_list_main_view.h
index 6225b31..9206f20 100644
--- a/ui/app_list/views/app_list_main_view.h
+++ b/ui/app_list/views/app_list_main_view.h
@@ -18,6 +18,7 @@ class Widget;
namespace app_list {
+class ApplicationDragAndDropHost;
class AppListModel;
class AppListItemModel;
class AppListViewDelegate;
@@ -47,6 +48,11 @@ class AppListMainView : public views::View,
SearchBoxView* search_box_view() { return search_box_view_; }
+ // If |drag_and_drop_host| is not NULL it will be called upon drag and drop
+ // operations outside the application list.
+ void SetDragAndDropHostOfCurrentAppList(
+ ApplicationDragAndDropHost* drag_and_drop_host);
+
private:
class IconLoader;
diff --git a/ui/app_list/views/app_list_view.cc b/ui/app_list/views/app_list_view.cc
index e81bfdf..5f94919 100644
--- a/ui/app_list/views/app_list_view.cc
+++ b/ui/app_list/views/app_list_view.cc
@@ -128,13 +128,17 @@ void AppListView::SetAnchorPoint(const gfx::Point& anchor_point) {
SizeToContents(); // Repositions view relative to the anchor.
}
+void AppListView::SetDragAndDropHostOfCurrentAppList(
+ app_list::ApplicationDragAndDropHost* drag_and_drop_host) {
+ app_list_main_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
+}
+
void AppListView::ShowWhenReady() {
app_list_main_view_->ShowAppListWhenReady();
}
void AppListView::Close() {
app_list_main_view_->Close();
-
if (delegate_)
delegate_->Dismiss();
else
diff --git a/ui/app_list/views/app_list_view.h b/ui/app_list/views/app_list_view.h
index 486dfce..eb21ceb 100644
--- a/ui/app_list/views/app_list_view.h
+++ b/ui/app_list/views/app_list_view.h
@@ -15,7 +15,7 @@ class Widget;
}
namespace app_list {
-
+class ApplicationDragAndDropHost;
class AppListMainView;
class AppListModel;
class AppListViewDelegate;
@@ -44,6 +44,13 @@ class APP_LIST_EXPORT AppListView : public views::BubbleDelegateView,
void SetAnchorPoint(const gfx::Point& anchor_point);
+ // If |drag_and_drop_host| is not NULL it will be called upon drag and drop
+ // operations outside the application list. This has to be called after
+ // InitAsBubble was called since the app list object needs to exist so that
+ // it can set the host.
+ void SetDragAndDropHostOfCurrentAppList(
+ app_list::ApplicationDragAndDropHost* drag_and_drop_host);
+
// Shows the UI when there are no pending icon loads. Otherwise, starts a
// timer to show the UI when a maximum allowed wait time has expired.
void ShowWhenReady();
diff --git a/ui/app_list/views/apps_grid_view.cc b/ui/app_list/views/apps_grid_view.cc
index 9cfe08e..21719da 100644
--- a/ui/app_list/views/apps_grid_view.cc
+++ b/ui/app_list/views/apps_grid_view.cc
@@ -6,8 +6,10 @@
#include <algorithm>
+#include "ui/app_list/app_list_item_model.h"
#include "ui/app_list/apps_grid_view_delegate.h"
#include "ui/app_list/pagination_model.h"
+#include "ui/app_list/views/app_list_drag_and_drop_host.h"
#include "ui/app_list/views/app_list_item_view.h"
#include "ui/app_list/views/page_switcher.h"
#include "ui/app_list/views/pulsing_block_view.h"
@@ -108,6 +110,8 @@ AppsGridView::AppsGridView(AppsGridViewDelegate* delegate,
selected_view_(NULL),
drag_view_(NULL),
drag_pointer_(NONE),
+ drag_and_drop_host_(NULL),
+ forward_events_to_drag_and_drop_host_(false),
page_flip_target_(-1),
page_flip_delay_in_ms_(kPageFlipDelayInMs),
bounds_animator_(this) {
@@ -177,7 +181,7 @@ void AppsGridView::EnsureViewVisible(const views::View* view) {
pagination_model_->SelectPage(index.page, false);
}
-void AppsGridView::InitiateDrag(views::View* view,
+void AppsGridView::InitiateDrag(AppListItemView* view,
Pointer pointer,
const ui::LocatedEvent& event) {
if (drag_view_ || pulsing_blocks_model_.view_size())
@@ -187,7 +191,7 @@ void AppsGridView::InitiateDrag(views::View* view,
drag_start_ = event.location();
}
-void AppsGridView::UpdateDrag(views::View* view,
+void AppsGridView::UpdateDrag(AppListItemView* view,
Pointer pointer,
const ui::LocatedEvent& event) {
if (!dragging() && drag_view_ &&
@@ -200,6 +204,9 @@ void AppsGridView::UpdateDrag(views::View* view,
if (drag_pointer_ != pointer)
return;
+ // If a drag and drop host is provided, see if the drag operation needs to be
+ // forwarded.
+ DispatchDragEventToDragAndDropHost(event);
ExtractDragLocation(event, &last_drag_point_);
const Index last_drop_target = drop_target_;
@@ -218,7 +225,10 @@ void AppsGridView::UpdateDrag(views::View* view,
}
void AppsGridView::EndDrag(bool cancel) {
- if (!cancel && dragging() && drag_view_) {
+ if (forward_events_to_drag_and_drop_host_) {
+ forward_events_to_drag_and_drop_host_ = false;
+ drag_and_drop_host_->EndDrag(cancel);
+ } else if (!cancel && dragging() && drag_view_) {
CalculateDropTarget(last_drag_point_, true);
if (IsValidIndex(drop_target_))
MoveItemInModel(drag_view_, drop_target_);
@@ -239,6 +249,11 @@ bool AppsGridView::IsDraggedView(const views::View* view) const {
return drag_view_ == view;
}
+void AppsGridView::SetDragAndDropHostOfCurrentAppList(
+ ApplicationDragAndDropHost* drag_and_drop_host) {
+ drag_and_drop_host_ = drag_and_drop_host;
+}
+
void AppsGridView::Prerender(int page_index) {
Layout();
int start = std::max(0, (page_index - kPrerenderPages) * tiles_per_page());
@@ -659,6 +674,40 @@ void AppsGridView::CalculateDropTarget(const gfx::Point& drag_point,
}
}
+void AppsGridView::DispatchDragEventToDragAndDropHost(
+ const ui::LocatedEvent& event) {
+ if (!drag_view_ || !drag_and_drop_host_)
+ return;
+ if (bounds().Contains(last_drag_point_)) {
+ // The event was issued inside the app menu and we should get all events.
+ if (forward_events_to_drag_and_drop_host_) {
+ // The DnD host was previously called and needs to be informed that the
+ // session returns to the owner.
+ forward_events_to_drag_and_drop_host_ = false;
+ drag_and_drop_host_->EndDrag(true);
+ }
+ } else {
+ // The event happened outside our app menu and we might need to dispatch.
+ if (forward_events_to_drag_and_drop_host_) {
+ // Dispatch since we have already started.
+ if (!drag_and_drop_host_->Drag(event.root_location())) {
+ // The host is not active any longer and we cancel the operation.
+ forward_events_to_drag_and_drop_host_ = false;
+ drag_and_drop_host_->EndDrag(true);
+ }
+ } else {
+ if (drag_and_drop_host_->StartDrag(drag_view_->model()->app_id(),
+ event.root_location())) {
+ // From now on we forward the drag events.
+ forward_events_to_drag_and_drop_host_ = true;
+ // Any flip operations are stopped.
+ page_flip_timer_.Stop();
+ page_flip_target_ = -1;
+ }
+ }
+ }
+}
+
void AppsGridView::MaybeStartPageFlipTimer(const gfx::Point& drag_point) {
int new_page_flip_target = -1;
diff --git a/ui/app_list/views/apps_grid_view.h b/ui/app_list/views/apps_grid_view.h
index b91ba64..f62e9af 100644
--- a/ui/app_list/views/apps_grid_view.h
+++ b/ui/app_list/views/apps_grid_view.h
@@ -28,6 +28,7 @@ namespace test {
class AppsGridViewTestApi;
}
+class ApplicationDragAndDropHost;
class AppListItemView;
class AppsGridViewDelegate;
class PageSwitcher;
@@ -65,15 +66,19 @@ class APP_LIST_EXPORT AppsGridView : public views::View,
// transition, this does nothing.
void EnsureViewVisible(const views::View* view);
- void InitiateDrag(views::View* view,
+ void InitiateDrag(AppListItemView* view,
Pointer pointer,
const ui::LocatedEvent& event);
- void UpdateDrag(views::View* view,
+ void UpdateDrag(AppListItemView* view,
Pointer pointer,
const ui::LocatedEvent& event);
void EndDrag(bool cancel);
bool IsDraggedView(const views::View* view) const;
+ // Set the drag and drop host for application links.
+ void SetDragAndDropHostOfCurrentAppList(
+ ApplicationDragAndDropHost* drag_and_drop_host);
+
// Prerenders the icons on and around |page_index|.
void Prerender(int page_index);
@@ -157,6 +162,9 @@ class APP_LIST_EXPORT AppsGridView : public views::View,
void CalculateDropTarget(const gfx::Point& drag_point,
bool use_page_button_hovering);
+ // Dispatch the drag and drop update event to the dnd host (if needed).
+ void DispatchDragEventToDragAndDropHost(const ui::LocatedEvent& event);
+
// Starts the page flip timer if |drag_point| is in left/right side page flip
// zone or is over page switcher.
void MaybeStartPageFlipTimer(const gfx::Point& drag_point);
@@ -202,11 +210,18 @@ class APP_LIST_EXPORT AppsGridView : public views::View,
views::View* selected_view_;
- views::View* drag_view_;
+ AppListItemView* drag_view_;
gfx::Point drag_start_;
Pointer drag_pointer_;
Index drop_target_;
+ // An application target drag and drop host which accepts dnd operations.
+ ApplicationDragAndDropHost* drag_and_drop_host_;
+
+ // The drag operation is currently inside the dnd host and events get
+ // forwarded.
+ bool forward_events_to_drag_and_drop_host_;
+
// Last mouse drag location in this view's coordinates.
gfx::Point last_drag_point_;
diff --git a/ui/app_list/views/contents_view.cc b/ui/app_list/views/contents_view.cc
index e256f4b..77c8fb0 100644
--- a/ui/app_list/views/contents_view.cc
+++ b/ui/app_list/views/contents_view.cc
@@ -54,13 +54,12 @@ ContentsView::ContentsView(AppListMainView* app_list_main_view,
kPageTransitionDurationInMs,
kOverscrollPageTransitionDurationMs);
- AppsGridView* apps_grid_view = new AppsGridView(app_list_main_view,
- pagination_model);
- apps_grid_view->SetLayout(kPreferredIconDimension,
- kPreferredCols,
- kPreferredRows);
- AddChildView(apps_grid_view);
- view_model_->Add(apps_grid_view, kIndexAppsGrid);
+ apps_grid_view_ = new AppsGridView(app_list_main_view, pagination_model);
+ apps_grid_view_->SetLayout(kPreferredIconDimension,
+ kPreferredCols,
+ kPreferredRows);
+ AddChildView(apps_grid_view_);
+ view_model_->Add(apps_grid_view_, kIndexAppsGrid);
SearchResultListView* search_results_view = new SearchResultListView(
app_list_main_view);
@@ -81,6 +80,11 @@ void ContentsView::SetModel(AppListModel* model) {
}
}
+void ContentsView::SetDragAndDropHostOfCurrentAppList(
+ app_list::ApplicationDragAndDropHost* drag_and_drop_host) {
+ apps_grid_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
+}
+
void ContentsView::SetShowState(ShowState show_state) {
if (show_state_ == show_state)
return;
diff --git a/ui/app_list/views/contents_view.h b/ui/app_list/views/contents_view.h
index 131481c..f9f31ab 100644
--- a/ui/app_list/views/contents_view.h
+++ b/ui/app_list/views/contents_view.h
@@ -17,6 +17,8 @@ class ViewModel;
namespace app_list {
+class AppsGridView;
+class ApplicationDragAndDropHost;
class AppListMainView;
class AppListModel;
class PaginationModel;
@@ -33,6 +35,11 @@ class ContentsView : public views::View {
void SetModel(AppListModel* model);
+ // If |drag_and_drop| is not NULL it will be called upon drag and drop
+ // operations outside the application list.
+ void SetDragAndDropHostOfCurrentAppList(
+ app_list::ApplicationDragAndDropHost* drag_and_drop_host);
+
void ShowSearchResults(bool show);
void Prerender();
@@ -65,6 +72,8 @@ class ContentsView : public views::View {
ShowState show_state_;
PaginationModel* pagination_model_; // Owned by AppListController.
+ AppsGridView* apps_grid_view_; // Owned by the view.
+
scoped_ptr<views::ViewModel> view_model_;
scoped_ptr<views::BoundsAnimator> bounds_animator_;