| Index: ui/app_list/views/apps_grid_view.cc
|
| diff --git a/ui/app_list/views/apps_grid_view.cc b/ui/app_list/views/apps_grid_view.cc
|
| index d371ed90cf3fcde99ec0346fef9ec865d881b169..5625c6d4ad0626093849bbf1aff6338f9f471d00 100644
|
| --- a/ui/app_list/views/apps_grid_view.cc
|
| +++ b/ui/app_list/views/apps_grid_view.cc
|
| @@ -21,6 +21,7 @@
|
| #include "ui/app_list/views/apps_grid_view_delegate.h"
|
| #include "ui/app_list/views/page_switcher.h"
|
| #include "ui/app_list/views/pulsing_block_view.h"
|
| +#include "ui/app_list/views/top_icon_animation_view.h"
|
| #include "ui/compositor/scoped_layer_animation_settings.h"
|
| #include "ui/events/event.h"
|
| #include "ui/gfx/animation/animation.h"
|
| @@ -86,6 +87,9 @@ const int kFolderDroppingDelay = 250;
|
| // Delays in milliseconds to show re-order preview.
|
| const int kReorderDelay = 50;
|
|
|
| +// Delays in milliseconds to show folder item reparent UI.
|
| +const int kFolderItemReparentDealy = 50;
|
| +
|
| // Radius of the circle, in which if entered, show folder dropping preview
|
| // UI.
|
| const int kFolderDroppingCircleRadius = 15;
|
| @@ -316,7 +320,8 @@ AppsGridView::AppsGridView(AppsGridViewDelegate* delegate,
|
| page_flip_delay_in_ms_(kPageFlipDelayInMs),
|
| bounds_animator_(this),
|
| is_root_level_(true),
|
| - activated_item_view_(NULL) {
|
| + activated_item_view_(NULL),
|
| + dragging_for_reparent_item_(false) {
|
| SetPaintToLayer(true);
|
| SetFillsBoundsOpaquely(false);
|
|
|
| @@ -478,6 +483,9 @@ void AppsGridView::UpdateDragFromItem(Pointer pointer,
|
| const ui::LocatedEvent& event) {
|
| DCHECK(drag_view_);
|
|
|
| + if (!is_root_level_)
|
| + UpdateDragStateInsideFolder(pointer, event);
|
| +
|
| gfx::Point drag_point_in_grid_view;
|
| ExtractDragLocation(event, &drag_point_in_grid_view);
|
| UpdateDrag(pointer, drag_point_in_grid_view);
|
| @@ -508,7 +516,8 @@ void AppsGridView::UpdateDrag(Pointer pointer, const gfx::Point& point) {
|
| ReorderChildView(drag_view_, -1);
|
| bounds_animator_.StopAnimatingView(drag_view_);
|
| StartSettingUpSynchronousDrag();
|
| - StartDragAndDropHostDrag(point);
|
| + if (!dragging_for_reparent_item_)
|
| + StartDragAndDropHostDrag(point);
|
| }
|
|
|
| if (drag_pointer_ != pointer)
|
| @@ -562,21 +571,36 @@ void AppsGridView::EndDrag(bool cancel) {
|
| // EndDrag was called before if |drag_view_| is NULL.
|
| if (!drag_view_)
|
| return;
|
| +
|
| // Coming here a drag and drop was in progress.
|
| bool landed_in_drag_and_drop_host = forward_events_to_drag_and_drop_host_;
|
| if (forward_events_to_drag_and_drop_host_) {
|
| + DCHECK(!IsDraggingForReparentInRootLevelGridView());
|
| forward_events_to_drag_and_drop_host_ = false;
|
| drag_and_drop_host_->EndDrag(cancel);
|
| + if (IsDraggingForReprentInHiddenGridView()) {
|
| + static_cast<AppListFolderView*>(parent())->
|
| + DispatchEndDragEventForReparent(true);
|
| + }
|
| } else if (!cancel && dragging()) {
|
| - CalculateDropTarget(last_drag_point_, true);
|
| - if (IsValidIndex(drop_target_)) {
|
| - if (!EnableFolderDragDropUI()) {
|
| - MoveItemInModel(drag_view_, drop_target_);
|
| - } else {
|
| - if (drop_attempt_ == DROP_FOR_REORDER)
|
| - MoveItemInModel(drag_view_, drop_target_);
|
| - else if (drop_attempt_ == DROP_FOR_FOLDER)
|
| - MoveItemToFolder(drag_view_, drop_target_);
|
| + if (IsDraggingForReprentInHiddenGridView()) {
|
| + // Forward the EndDrag event to the root level grid view.
|
| + static_cast<AppListFolderView*>(parent())->
|
| + DispatchEndDragEventForReparent(false);
|
| + EndDragForReparentInHiddenFolderGridView();
|
| + return;
|
| + } else {
|
| + // Regular drag ending path, ie, not for reparenting.
|
| + CalculateDropTarget(last_drag_point_, true);
|
| + if (IsValidIndex(drop_target_)) {
|
| + if (!EnableFolderDragDropUI()) {
|
| + MoveItemInModel(drag_view_, drop_target_);
|
| + } else {
|
| + if (drop_attempt_ == DROP_FOR_REORDER)
|
| + MoveItemInModel(drag_view_, drop_target_);
|
| + else if (drop_attempt_ == DROP_FOR_FOLDER)
|
| + MoveItemToFolder(drag_view_, drop_target_);
|
| + }
|
| }
|
| }
|
| }
|
| @@ -594,8 +618,8 @@ void AppsGridView::EndDrag(bool cancel) {
|
| }
|
| // Fade in slowly if it landed in the shelf.
|
| SetViewHidden(drag_view_,
|
| - false /* hide */,
|
| - !landed_in_drag_and_drop_host /* animate */);
|
| + false /* show */,
|
| + !landed_in_drag_and_drop_host /* animate */);
|
| }
|
|
|
| // The drag can be ended after the synchronous drag is created but before it
|
| @@ -611,9 +635,18 @@ void AppsGridView::EndDrag(bool cancel) {
|
| drag_start_grid_view_ = gfx::Point();
|
| drag_start_page_ = -1;
|
| drag_view_offset_ = gfx::Point();
|
| + if (IsDraggingForReprentInHiddenGridView())
|
| + dragging_for_reparent_item_ = false;
|
| AnimateToIdealBounds();
|
|
|
| StopPageFlipTimer();
|
| +
|
| + // If user releases mouse inside a folder's grid view, burst the folder
|
| + // container ink bubble.
|
| + if (!is_root_level_ && !IsDraggingForReprentInHiddenGridView()) {
|
| + static_cast<AppListFolderView*>(parent())->
|
| + UpdateFolderViewBackground(false);
|
| + }
|
| }
|
|
|
| void AppsGridView::StopPageFlipTimer() {
|
| @@ -650,6 +683,54 @@ void AppsGridView::ScheduleShowHideAnimation(bool show) {
|
| layer()->SetOpacity(show ? 1.0f : 0.0f);
|
| }
|
|
|
| +void AppsGridView::InitiateDragFromReparentItemInRootLevelGridView(
|
| + AppListItemView* original_drag_view,
|
| + const gfx::Rect& drag_view_rect,
|
| + const gfx::Point& drag_point) {
|
| + DCHECK(original_drag_view && !drag_view_);
|
| + DCHECK(!dragging_for_reparent_item_);
|
| +
|
| + // Create a new AppListItemView to duplicate the original_drag_view in the
|
| + // folder's grid view.
|
| + AppListItemView* view = new AppListItemView(this, original_drag_view->item());
|
| + AddChildView(view);
|
| + drag_view_ = view;
|
| + drag_view_->SetPaintToLayer(true);
|
| + // Note: For testing purpose, SetFillsBoundsOpaquely can be set to true to
|
| + // show the gray background.
|
| + drag_view_->SetFillsBoundsOpaquely(false);
|
| + drag_view_->SetIconSize(icon_size_);
|
| + drag_view_->SetBoundsRect(drag_view_rect);
|
| + drag_view_->SetDragUIState(); // Hide the title of the drag_view_.
|
| +
|
| + // Hide the drag_view_ for drag icon proxy.
|
| + SetViewHidden(drag_view_,
|
| + true /* hide */,
|
| + true /* no animate */);
|
| +
|
| + // Add drag_view_ to the end of the view_model_.
|
| + view_model_.Add(drag_view_, view_model_.view_size());
|
| +
|
| + drag_start_page_ = pagination_model_->selected_page();
|
| + drag_start_grid_view_ = drag_point;
|
| +
|
| + drag_view_start_ = gfx::Point(drag_view_->x(), drag_view_->y());
|
| +
|
| + // Set the flag in root level grid view.
|
| + dragging_for_reparent_item_ = true;
|
| +}
|
| +
|
| +void AppsGridView::UpdateDragFromReparentItem(
|
| + Pointer pointer,
|
| + const ui::LocatedEvent& event) {
|
| + DCHECK(drag_view_);
|
| + DCHECK(IsDraggingForReparentInRootLevelGridView());
|
| +
|
| + gfx::Point drag_point_in_grid_view;
|
| + ExtractDragLocation(event, &drag_point_in_grid_view);
|
| + UpdateDrag(pointer, drag_point_in_grid_view);
|
| +}
|
| +
|
| bool AppsGridView::IsDraggedView(const views::View* view) const {
|
| return drag_view_ == view;
|
| }
|
| @@ -1202,11 +1283,173 @@ void AppsGridView::OnReorderTimer() {
|
| AnimateToIdealBounds();
|
| }
|
|
|
| +void AppsGridView::OnFolderItemReparentTimer() {
|
| + DCHECK(!is_root_level_);
|
| + if (drag_out_of_folder_container_) {
|
| + static_cast<AppListFolderView*>(parent())->ReparentItem(
|
| + drag_view_, last_drag_point_);
|
| +
|
| + // Set the flag in the folder's grid view.
|
| + dragging_for_reparent_item_ = true;
|
| +
|
| + // Do not observe any data change since it is going to be hidden.
|
| + item_list_->RemoveObserver(this);
|
| + item_list_ = NULL;
|
| + }
|
| +}
|
| +
|
| void AppsGridView::OnFolderDroppingTimer() {
|
| if (drop_attempt_ == DROP_FOR_FOLDER)
|
| SetAsFolderDroppingTarget(drop_target_, true);
|
| }
|
|
|
| +void AppsGridView::UpdateDragStateInsideFolder(
|
| + Pointer pointer,
|
| + const ui::LocatedEvent& event) {
|
| + if (IsDraggingForReprentInHiddenGridView()) {
|
| + // Dispatch drag event to root level grid view for re-parenting folder
|
| + // folder item purpose.
|
| + DispatchDragEventForReparent(pointer, event);
|
| + return;
|
| + }
|
| +
|
| + // Regular drag and drop in a folder's grid view.
|
| + AppListFolderView* folder_view = static_cast<AppListFolderView*>(parent());
|
| + folder_view->UpdateFolderViewBackground(true);
|
| +
|
| + // Calculate if the drag_view_ is dragged out of the folder's container
|
| + // ink bubble.
|
| + gfx::Rect bounds_to_folder_view = ConvertRectToParent(drag_view_->bounds());
|
| + gfx::Point pt = bounds_to_folder_view.CenterPoint();
|
| + bool is_item_dragged_out_of_folder =
|
| + folder_view->IsPointOutsideOfFolderBoundray(pt);
|
| + if (is_item_dragged_out_of_folder) {
|
| + if (!drag_out_of_folder_container_) {
|
| + folder_item_reparent_timer_.Start(FROM_HERE,
|
| + base::TimeDelta::FromMilliseconds(kFolderItemReparentDealy),
|
| + this, &AppsGridView::OnFolderItemReparentTimer);
|
| + drag_out_of_folder_container_ = true;
|
| + }
|
| + } else {
|
| + folder_item_reparent_timer_.Stop();
|
| + drag_out_of_folder_container_ = false;
|
| + }
|
| +}
|
| +
|
| +bool AppsGridView::IsDraggingForReparentInRootLevelGridView() const {
|
| + return (is_root_level_ && dragging_for_reparent_item_);
|
| +}
|
| +
|
| +bool AppsGridView::IsDraggingForReprentInHiddenGridView() const {
|
| + return (!is_root_level_ && dragging_for_reparent_item_);
|
| +}
|
| +
|
| +gfx::Rect AppsGridView::GetTargetIconRectInFolder(
|
| + AppListItemView* drag_item_view,
|
| + AppListItemView* folder_item_view) {
|
| + gfx::Rect view_ideal_bounds = view_model_.ideal_bounds(
|
| + view_model_.GetIndexOfView(folder_item_view));
|
| + gfx::Rect icon_ideal_bounds =
|
| + folder_item_view->GetIconBoundsForTargetViewBounds(view_ideal_bounds);
|
| + AppListFolderItem* folder_item =
|
| + static_cast<AppListFolderItem*>(folder_item_view->item());
|
| + return folder_item->GetTargetIconRectInFolderForItem(
|
| + drag_item_view->item(), icon_ideal_bounds);
|
| +}
|
| +
|
| +void AppsGridView::DispatchDragEventForReparent(
|
| + Pointer pointer,
|
| + const ui::LocatedEvent& event) {
|
| + static_cast<AppListFolderView*>(parent())->
|
| + DispatchDragEventForReparent(pointer, event);
|
| +}
|
| +
|
| +void AppsGridView::EndDragFromReparentItemInRootLevel(
|
| + bool events_forwarded_to_drag_drop_host) {
|
| + // EndDrag was called before if |drag_view_| is NULL.
|
| + if (!drag_view_)
|
| + return;
|
| +
|
| + DCHECK(IsDraggingForReparentInRootLevelGridView());
|
| + bool cancel_reparent = false;
|
| + scoped_ptr<AppListItemView> cached_drag_view;
|
| + if (!events_forwarded_to_drag_drop_host) {
|
| + CalculateDropTarget(last_drag_point_, true);
|
| + if (IsValidIndex(drop_target_)) {
|
| + if (drop_attempt_ == DROP_FOR_REORDER)
|
| + ReparentItemForReorder(drag_view_, drop_target_);
|
| + else if (drop_attempt_ == DROP_FOR_FOLDER)
|
| + ReparentItemToAnotherFolder(drag_view_, drop_target_);
|
| + else { // DROP_FOR_NONE_
|
| + cancel_reparent = true;
|
| + // Note(jennyz): cached_drag_view makes sure drag_view_ will be deleted
|
| + // after AnimateToIdealBounds() is called.
|
| + // There is a problem in layer() animation which cause DCHECK failure
|
| + // if a child view is deleted immediately before re-creating layer in
|
| + // layer animation. The layer tree seems marked dirty, and complaining
|
| + // when we try to re-create layer in AnimationBetweenRows when calling
|
| + // AnimateToIdealBounds.
|
| + cached_drag_view.reset(drag_view_);
|
| + }
|
| + }
|
| +
|
| + if (!cancel_reparent) {
|
| + SetViewHidden(drag_view_,
|
| + false /* show */,
|
| + true /* no animate */);
|
| + }
|
| + }
|
| +
|
| + // The drag can be ended after the synchronous drag is created but before it
|
| + // is Run().
|
| + CleanUpSynchronousDrag();
|
| +
|
| + SetAsFolderDroppingTarget(drop_target_, false);
|
| + drop_attempt_ = DROP_FOR_NONE;
|
| + drag_pointer_ = NONE;
|
| + drop_target_ = Index();
|
| + if (!cancel_reparent)
|
| + drag_view_->OnDragEnded();
|
| + drag_view_ = NULL;
|
| + drag_start_grid_view_ = gfx::Point();
|
| + drag_start_page_ = -1;
|
| + drag_view_offset_ = gfx::Point();
|
| + dragging_for_reparent_item_ = false;
|
| + if (cancel_reparent)
|
| + CancelFolderItemReparent(cached_drag_view.get());
|
| + AnimateToIdealBounds();
|
| +
|
| + StopPageFlipTimer();
|
| +}
|
| +
|
| +void AppsGridView::EndDragForReparentInHiddenFolderGridView() {
|
| + if (drag_and_drop_host_) {
|
| + // If we had a drag and drop proxy icon, we delete it and make the real
|
| + // item visible again.
|
| + drag_and_drop_host_->DestroyDragIconProxy();
|
| + }
|
| +
|
| + // The drag can be ended after the synchronous drag is created but before it
|
| + // is Run().
|
| + CleanUpSynchronousDrag();
|
| +
|
| + SetAsFolderDroppingTarget(drop_target_, false);
|
| + drop_attempt_ = DROP_FOR_NONE;
|
| + drag_pointer_ = NONE;
|
| + drop_target_ = Index();
|
| + drag_view_->OnDragEnded();
|
| + drag_view_ = NULL;
|
| + drag_start_grid_view_ = gfx::Point();
|
| + drag_start_page_ = -1;
|
| + drag_view_offset_ = gfx::Point();
|
| + dragging_for_reparent_item_ = false;
|
| +}
|
| +
|
| +void AppsGridView::OnFolderItemRemoved() {
|
| + DCHECK(!is_root_level_);
|
| + item_list_ = NULL;
|
| +}
|
| +
|
| void AppsGridView::StartDragAndDropHostDrag(const gfx::Point& grid_location) {
|
| // When a drag and drop host is given, the item can be dragged out of the app
|
| // list window. In that case a proxy widget needs to be used.
|
| @@ -1226,6 +1469,7 @@ void AppsGridView::StartDragAndDropHostDrag(const gfx::Point& grid_location) {
|
|
|
| // We have to hide the original item since the drag and drop host will do
|
| // the OS dependent code to "lift off the dragged item".
|
| + DCHECK(!IsDraggingForReparentInRootLevelGridView());
|
| drag_and_drop_host_->CreateDragIconProxy(screen_location,
|
| drag_view_->item()->icon(),
|
| drag_view_,
|
| @@ -1240,7 +1484,8 @@ void AppsGridView::DispatchDragEventToDragAndDropHost(
|
| const gfx::Point& location_in_screen_coordinates) {
|
| if (!drag_view_ || !drag_and_drop_host_)
|
| return;
|
| - if (bounds().Contains(last_drag_point_)) {
|
| +
|
| + if (GetLocalBounds().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
|
| @@ -1331,30 +1576,33 @@ void AppsGridView::MoveItemInModel(views::View* item_view,
|
|
|
| void AppsGridView::MoveItemToFolder(views::View* item_view,
|
| const Index& target) {
|
| - const std::string& source_id =
|
| + const std::string& source_item_id =
|
| static_cast<AppListItemView*>(item_view)->item()->id();
|
| AppListItemView* target_view =
|
| static_cast<AppListItemView*>(GetViewAtSlotOnCurrentPage(target.slot));
|
| - const std::string& target_id = target_view->item()->id();
|
| + const std::string& target_view_item_id = target_view->item()->id();
|
|
|
| // Make change to data model.
|
| item_list_->RemoveObserver(this);
|
| - std::string folder_id = model_->MergeItems(target_id, source_id);
|
| +
|
| + std::string folder_item_id =
|
| + model_->MergeItems(target_view_item_id, source_item_id);
|
| item_list_->AddObserver(this);
|
|
|
| - if (folder_id != target_id) {
|
| + if (folder_item_id != target_view_item_id) {
|
| // New folder was created, change the view model to replace the old target
|
| // view with the new folder item view.
|
| - size_t folder_index;
|
| - if (item_list_->FindItemIndex(folder_id, &folder_index)) {
|
| - int target_index = view_model_.GetIndexOfView(target_view);
|
| - view_model_.Remove(target_index);
|
| + size_t folder_item_index;
|
| + if (item_list_->FindItemIndex(folder_item_id, &folder_item_index)) {
|
| + int target_view_index = view_model_.GetIndexOfView(target_view);
|
| + view_model_.Remove(target_view_index);
|
| delete target_view;
|
| - views::View* target_folder_view = CreateViewForItemAtIndex(folder_index);
|
| - view_model_.Add(target_folder_view, target_index);
|
| + views::View* target_folder_view =
|
| + CreateViewForItemAtIndex(folder_item_index);
|
| + view_model_.Add(target_folder_view, target_view_index);
|
| AddChildView(target_folder_view);
|
| } else {
|
| - LOG(ERROR) << "Folder no longer in item_list: " << folder_id;
|
| + LOG(ERROR) << "Folder no longer in item_list: " << folder_item_id;
|
| }
|
| }
|
|
|
| @@ -1364,10 +1612,141 @@ void AppsGridView::MoveItemToFolder(views::View* item_view,
|
| bounds_animator_.AnimateViewTo(drag_view_, drag_view_->bounds());
|
| bounds_animator_.SetAnimationDelegate(
|
| drag_view_, new ItemRemoveAnimationDelegate(drag_view_), true);
|
| + UpdatePaging();
|
| +}
|
| +
|
| +void AppsGridView::ReparentItemForReorder(views::View* item_view,
|
| + const Index& target) {
|
| + item_list_->RemoveObserver(this);
|
| + model_->RemoveObserver(this);
|
| +
|
| + AppListItem* reparent_item = static_cast<AppListItemView*>(item_view)->item();
|
| + DCHECK(reparent_item->IsInFolder());
|
| + AppListFolderItem* source_folder = static_cast<AppListFolderItem*>(
|
| + item_list_->FindItem(reparent_item->folder_id()));
|
|
|
| + // Move the item from its parent folder to top level item list.
|
| + // Must move to target_model_index, the location we expect the target item
|
| + // to be, not the item location we want to insert before.
|
| + int target_model_index = GetModelIndexFromIndex(target);
|
| + int current_model_index = view_model_.GetIndexOfView(item_view);
|
| + syncer::StringOrdinal target_position;
|
| + if (target_model_index < static_cast<int>(item_list_->item_count()))
|
| + target_position = item_list_->item_at(target_model_index)->position();
|
| + model_->MoveItemToFolderAt(reparent_item, "", target_position);
|
| + view_model_.Move(current_model_index, target_model_index);
|
| +
|
| + if (source_folder->ChildItemCount() == 1)
|
| + RemoveLastItemFromReparentItemFolder(source_folder);
|
| +
|
| + item_list_->AddObserver(this);
|
| + model_->AddObserver(this);
|
| UpdatePaging();
|
| }
|
|
|
| +void AppsGridView::ReparentItemToAnotherFolder(views::View* item_view,
|
| + const Index& target) {
|
| + DCHECK(IsDraggingForReparentInRootLevelGridView());
|
| +
|
| + // Make change to data model.
|
| + item_list_->RemoveObserver(this);
|
| +
|
| + AppListItem* reparent_item = static_cast<AppListItemView*>(item_view)->item();
|
| + DCHECK(reparent_item->IsInFolder());
|
| + AppListFolderItem* source_folder = static_cast<AppListFolderItem*>(
|
| + item_list_->FindItem(reparent_item->folder_id()));
|
| +
|
| + AppListItemView* target_view =
|
| + static_cast<AppListItemView*>(GetViewAtSlotOnCurrentPage(target.slot));
|
| + AppListItem* target_item = target_view->item();
|
| +
|
| + // Move item to the target folder.
|
| + const std::string& target_id_after_merge =
|
| + model_->MergeItems(target_item->id(), reparent_item->id());
|
| +
|
| + if (target_id_after_merge != target_item->id()) {
|
| + // New folder was created, change the view model to replace the old target
|
| + // view with the new folder item view.
|
| + const std::string& new_folder_id = reparent_item->folder_id();
|
| + size_t new_folder_index;
|
| + if (item_list_->FindItemIndex(new_folder_id, &new_folder_index)) {
|
| + int target_view_index = view_model_.GetIndexOfView(target_view);
|
| + view_model_.Remove(target_view_index);
|
| + delete target_view;
|
| + views::View* new_folder_view =
|
| + CreateViewForItemAtIndex(new_folder_index);
|
| + view_model_.Add(new_folder_view, target_view_index);
|
| + AddChildView(new_folder_view);
|
| + } else {
|
| + LOG(ERROR) << "Folder no longer in item_list: " << new_folder_id;
|
| + }
|
| + }
|
| +
|
| + if (source_folder->ChildItemCount() == 1)
|
| + RemoveLastItemFromReparentItemFolder(source_folder);
|
| +
|
| + item_list_->AddObserver(this);
|
| +
|
| + // Fade out the drag_view_ and delete it when animation ends.
|
| + int drag_view_index = view_model_.GetIndexOfView(drag_view_);
|
| + view_model_.Remove(drag_view_index);
|
| + bounds_animator_.AnimateViewTo(drag_view_, drag_view_->bounds());
|
| + bounds_animator_.SetAnimationDelegate(
|
| + drag_view_, new ItemRemoveAnimationDelegate(drag_view_), true);
|
| + UpdatePaging();
|
| +}
|
| +
|
| +// After moving the re-parenting item out of the folder, if there is only 1 item
|
| +// left, remove the last item out of the folder, delete the folder and insert it
|
| +// to the data model at the same position. Make the same change to view_model_
|
| +// accordingly.
|
| +void AppsGridView::RemoveLastItemFromReparentItemFolder(
|
| + AppListFolderItem* source_folder) {
|
| + DCHECK(source_folder->ChildItemCount() == 1);
|
| +
|
| + // Delete view associated with the folder item to be removed.
|
| + AppListItemView* folder_item_view = activated_item_view();
|
| + int folder_model_index = view_model_.GetIndexOfView(folder_item_view);
|
| + view_model_.Remove(folder_model_index);
|
| + delete folder_item_view;
|
| +
|
| + // Now make the data change to remove the folder item in model.
|
| + AppListItem* last_item = source_folder->item_list()->item_at(0);
|
| + model_->MoveItemToFolderAt(last_item, "", source_folder->position());
|
| +
|
| + // Create a new item view for the last item in folder.
|
| + size_t last_item_index;
|
| + item_list_->FindItemIndex(last_item->id(), &last_item_index);
|
| + views::View* last_item_view = CreateViewForItemAtIndex(last_item_index);
|
| + view_model_.Add(last_item_view, last_item_index);
|
| + AddChildView(last_item_view);
|
| +}
|
| +
|
| +void AppsGridView::CancelFolderItemReparent(AppListItemView* drag_item_view) {
|
| + // The icon of the dragged item must target to its final ideal bounds after
|
| + // the animation completes.
|
| + CalculateIdealBounds();
|
| +
|
| + // Remove drag_view_ from view_model_, it will be deleted after the animation.
|
| + int drag_view_index = view_model_.GetIndexOfView(drag_item_view);
|
| + view_model_.Remove(drag_view_index);
|
| +
|
| + gfx::Rect target_icon_rect =
|
| + GetTargetIconRectInFolder(drag_item_view, activated_item_view_);
|
| +
|
| + gfx::Rect drag_view_icon_to_grid =
|
| + drag_item_view->ConvertRectToParent(drag_item_view->GetIconBounds());
|
| + drag_view_icon_to_grid.ClampToCenteredSize(
|
| + gfx::Size(kPreferredIconDimension, kPreferredIconDimension));
|
| + TopIconAnimationView* icon_view = new TopIconAnimationView(
|
| + drag_item_view->item()->icon(),
|
| + target_icon_rect,
|
| + false); /* animate like closing folder */
|
| + AddChildView(icon_view);
|
| + icon_view->SetBoundsRect(drag_view_icon_to_grid);
|
| + icon_view->TransformView();
|
| +}
|
| +
|
| void AppsGridView::CancelContextMenusOnCurrentPage() {
|
| int start = pagination_model_->selected_page() * tiles_per_page();
|
| int end = std::min(view_model_.view_size(), start + tiles_per_page());
|
| @@ -1582,6 +1961,14 @@ AppsGridView::Index AppsGridView::GetNearestTileForDragView() {
|
| drop_attempt_ = DROP_FOR_NONE;
|
| reorder_timer_.Stop();
|
| folder_dropping_timer_.Stop();
|
| +
|
| + // When dragging for reparent a folder item, it should go back to its parent
|
| + // folder item if there is no drop target.
|
| + if (IsDraggingForReparentInRootLevelGridView()) {
|
| + DCHECK(activated_item_view_);
|
| + return GetIndexOfView(activated_item_view_);
|
| + }
|
| +
|
| return GetIndexOfView(drag_view_);
|
| }
|
|
|
|
|