summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorsky@google.com <sky@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-11-04 19:29:08 +0000
committersky@google.com <sky@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-11-04 19:29:08 +0000
commitf28cbb7246977eb443650f7d2fc9675b573317b2 (patch)
treedda1262734dd45010df771821e869b687b9d1b6a /chrome/browser
parent431c16ea953a80b9153ba9a8c0b17b07a96f4a24 (diff)
downloadchromium_src-f28cbb7246977eb443650f7d2fc9675b573317b2.zip
chromium_src-f28cbb7246977eb443650f7d2fc9675b573317b2.tar.gz
chromium_src-f28cbb7246977eb443650f7d2fc9675b573317b2.tar.bz2
Adds support for autoscrolling on drag to bookmark tree/table.
BUG=674 TEST=none Review URL: http://codereview.chromium.org/9042 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@4625 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/bookmarks/bookmark_drop_info.cc44
-rw-r--r--chrome/browser/bookmarks/bookmark_drop_info.h85
-rw-r--r--chrome/browser/bookmarks/bookmark_utils.cc5
-rw-r--r--chrome/browser/bookmarks/bookmark_utils.h12
-rw-r--r--chrome/browser/browser.vcproj8
-rw-r--r--chrome/browser/views/bookmark_bar_view.cc12
-rw-r--r--chrome/browser/views/bookmark_folder_tree_view.cc179
-rw-r--r--chrome/browser/views/bookmark_folder_tree_view.h111
-rw-r--r--chrome/browser/views/bookmark_table_view.cc159
-rw-r--r--chrome/browser/views/bookmark_table_view.h87
10 files changed, 437 insertions, 265 deletions
diff --git a/chrome/browser/bookmarks/bookmark_drop_info.cc b/chrome/browser/bookmarks/bookmark_drop_info.cc
new file mode 100644
index 0000000..646b35b
--- /dev/null
+++ b/chrome/browser/bookmarks/bookmark_drop_info.cc
@@ -0,0 +1,44 @@
+// Copyright (c) 2006-2008 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/bookmarks/bookmark_drop_info.h"
+
+#include "chrome/views/event.h"
+#include "chrome/views/view_constants.h"
+
+BookmarkDropInfo::BookmarkDropInfo(HWND hwnd, int top_margin)
+ : source_operations_(0),
+ is_control_down_(false),
+ last_y_(0),
+ drop_operation_(0),
+ hwnd_(hwnd),
+ top_margin_(top_margin),
+ scroll_up_(false) {
+}
+
+void BookmarkDropInfo::Update(const views::DropTargetEvent& event) {
+ source_operations_ = event.GetSourceOperations();
+ is_control_down_ = event.IsControlDown();
+ last_y_ = event.y();
+
+ RECT client_rect;
+ GetClientRect(hwnd_, &client_rect);
+ scroll_up_ = (last_y_ <= top_margin_ + views::kAutoscrollSize);
+ bool scroll_down = (last_y_ >= client_rect.bottom - views::kAutoscrollSize);
+ if (scroll_up_ || scroll_down) {
+ if (!scroll_timer_.IsRunning()) {
+ scroll_timer_.Start(
+ base::TimeDelta::FromMilliseconds(views::kAutoscrollRowTimerMS),
+ this,
+ &BookmarkDropInfo::Scroll);
+ }
+ } else {
+ scroll_timer_.Stop();
+ }
+}
+
+void BookmarkDropInfo::Scroll() {
+ SendMessage(hwnd_, WM_VSCROLL, scroll_up_ ? SB_LINEUP : SB_LINEDOWN, NULL);
+ Scrolled();
+}
diff --git a/chrome/browser/bookmarks/bookmark_drop_info.h b/chrome/browser/bookmarks/bookmark_drop_info.h
new file mode 100644
index 0000000..f4daf89
--- /dev/null
+++ b/chrome/browser/bookmarks/bookmark_drop_info.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2006-2008 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 CHROME_BROWSER_BOOKMARKS_BOOKMARK_DROP_INFO_H_
+#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_DROP_INFO_H_
+
+#include <windows.h>
+
+#include "base/timer.h"
+#include "chrome/browser/bookmarks/bookmark_drag_data.h"
+
+namespace views {
+class DropTargetEvent;
+}
+
+// BookmarkDropInfo is a pure virtual class that provides auto-scrolling
+// behavior and a handful of fields used for managing a bookmark drop.
+// BookmarkDropInfo is used by both BookmarkTableView and
+// BookmarksFolderTreeView.
+class BookmarkDropInfo {
+ public:
+ BookmarkDropInfo(HWND hwnd, int top_margin);
+ virtual ~BookmarkDropInfo() {}
+
+ // Invoke this from OnDragUpdated. It resets source_operations,
+ // is_control_down, last_y and updates the autoscroll timer as necessary.
+ void Update(const views::DropTargetEvent& event);
+
+ // Data from the drag.
+ void SetData(const BookmarkDragData& data) { data_ = data; }
+ BookmarkDragData& data() { return data_; }
+
+ // Value of event.GetSourceOperations when Update was last invoked.
+ int source_operations() const { return source_operations_; }
+
+ // Whether the control key was down last time Update was invoked.
+ bool is_control_down() const { return is_control_down_; }
+
+ // Y position of the event last passed to Update.
+ int last_y() { return last_y_; }
+
+ // The drop operation that should occur. This is not updated by
+ // BookmarkDropInfo, but provided for subclasses.
+ void set_drop_operation(int drop_operation) {
+ drop_operation_ = drop_operation;
+ }
+ int drop_operation() const { return drop_operation_; }
+
+ protected:
+ // Invoked if we autoscroll. When invoked subclasses need to determine
+ // whether the drop is valid again as what is under the mouse has likely
+ // scrolled.
+ virtual void Scrolled() = 0;
+
+ private:
+ // Invoked from the timer. Scrolls up/down a line.
+ void Scroll();
+
+ BookmarkDragData data_;
+
+ int source_operations_;
+
+ bool is_control_down_;
+
+ int last_y_;
+
+ int drop_operation_;
+
+ HWND hwnd_;
+
+ // Margin in addition to views::kAutoscrollSize that the mouse is allowed to
+ // be over before we autoscroll.
+ int top_margin_;
+
+ // When autoscrolling this determines if we're scrolling up or down.
+ bool scroll_up_;
+
+ // Used when autoscrolling.
+ base::RepeatingTimer<BookmarkDropInfo> scroll_timer_;
+
+ DISALLOW_COPY_AND_ASSIGN(BookmarkDropInfo);
+};
+
+#endif // CHROME_BROWSER_BOOKMARKS_BOOKMARK_DROP_INFO_H_
diff --git a/chrome/browser/bookmarks/bookmark_utils.cc b/chrome/browser/bookmarks/bookmark_utils.cc
index d9b0be1..bf2576f 100644
--- a/chrome/browser/bookmarks/bookmark_utils.cc
+++ b/chrome/browser/bookmarks/bookmark_utils.cc
@@ -146,9 +146,8 @@ bool ShouldOpenAll(HWND parent, const std::vector<BookmarkNode*>& nodes) {
namespace bookmark_utils {
-int PreferredDropOperation(const views::DropTargetEvent& event,
- int operation) {
- int common_ops = (event.GetSourceOperations() & operation);
+int PreferredDropOperation(int source_operations, int operations) {
+ int common_ops = (source_operations & operations);
if (!common_ops)
return 0;
if (DragDropTypes::DRAG_COPY & common_ops)
diff --git a/chrome/browser/bookmarks/bookmark_utils.h b/chrome/browser/bookmarks/bookmark_utils.h
index 0711638..281cf8c 100644
--- a/chrome/browser/bookmarks/bookmark_utils.h
+++ b/chrome/browser/bookmarks/bookmark_utils.h
@@ -14,18 +14,14 @@ class BookmarkNode;
class PageNavigator;
class Profile;
-namespace views {
-class DropTargetEvent;
-}
-
// A collection of bookmark utility functions used by various parts of the UI
// that show bookmarks: bookmark manager, bookmark bar view ...
namespace bookmark_utils {
-// Calculates the drop operation given the event and supported set of
-// operations. This prefers the following ordering: COPY, LINK then MOVE.
-int PreferredDropOperation(const views::DropTargetEvent& event,
- int operation);
+// Calculates the drop operation given |source_operations| and the ideal
+// set of drop operations (|operations|). This prefers the following ordering:
+// COPY, LINK then MOVE.
+int PreferredDropOperation(int source_operations, int operations);
// Returns true if the bookmark data can be dropped on |drop_parent| at
// |index|. A drop from a separate profile is always allowed, where as
diff --git a/chrome/browser/browser.vcproj b/chrome/browser/browser.vcproj
index d9daed9..033b3e3 100644
--- a/chrome/browser/browser.vcproj
+++ b/chrome/browser/browser.vcproj
@@ -746,6 +746,14 @@
>
</File>
<File
+ RelativePath=".\bookmarks\bookmark_drop_info.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\bookmarks\bookmark_drop_info.h"
+ >
+ </File>
+ <File
RelativePath=".\bookmarks\bookmark_folder_tree_model.cc"
>
</File>
diff --git a/chrome/browser/views/bookmark_bar_view.cc b/chrome/browser/views/bookmark_bar_view.cc
index 4e2f09f..3e514ba 100644
--- a/chrome/browser/views/bookmark_bar_view.cc
+++ b/chrome/browser/views/bookmark_bar_view.cc
@@ -44,6 +44,7 @@
#include "chrome/views/container.h"
#include "chrome/views/menu_button.h"
#include "chrome/views/tooltip_manager.h"
+#include "chrome/views/view_constants.h"
#include "chrome/views/window.h"
#include "generated_resources.h"
@@ -1669,7 +1670,9 @@ int BookmarkBarView::CalculateDropOperation(const DropTargetEvent& event,
int ops = data.GetFirstNode(profile_)
? DragDropTypes::DRAG_MOVE
: DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK;
- return bookmark_utils::PreferredDropOperation(event, ops);
+ return
+ bookmark_utils::PreferredDropOperation(event.GetSourceOperations(),
+ ops);
}
for (int i = 0; i < GetBookmarkButtonCount() &&
@@ -1681,9 +1684,9 @@ int BookmarkBarView::CalculateDropOperation(const DropTargetEvent& event,
found = true;
BookmarkNode* node = model_->GetBookmarkBarNode()->GetChild(i);
if (node->GetType() != history::StarredEntry::URL) {
- if (button_x <= MenuItemView::kDropBetweenPixels) {
+ if (button_x <= views::kDropBetweenPixels) {
*index = i;
- } else if (button_x < button_w - MenuItemView::kDropBetweenPixels) {
+ } else if (button_x < button_w - views::kDropBetweenPixels) {
*index = i;
*drop_on = true;
} else {
@@ -1759,7 +1762,8 @@ int BookmarkBarView::CalculateDropOperation(const DropTargetEvent& event,
} else {
// User is dragging from another app, copy.
return bookmark_utils::PreferredDropOperation(
- event, DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK);
+ event.GetSourceOperations(),
+ DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK);
}
}
diff --git a/chrome/browser/views/bookmark_folder_tree_view.cc b/chrome/browser/views/bookmark_folder_tree_view.cc
index c068103..29dbceb 100644
--- a/chrome/browser/views/bookmark_folder_tree_view.cc
+++ b/chrome/browser/views/bookmark_folder_tree_view.cc
@@ -11,10 +11,14 @@
#include "chrome/browser/profile.h"
#include "chrome/common/drag_drop_types.h"
#include "chrome/common/os_exchange_data.h"
-#include "chrome/views/chrome_menu.h"
+#include "chrome/views/view_constants.h"
#include "generated_resources.h"
+void BookmarkFolderTreeView::DropInfo::Scrolled() {
+ view_->UpdateDropInfo();
+}
+
BookmarkFolderTreeView::BookmarkFolderTreeView(Profile* profile,
BookmarkFolderTreeModel* model)
: views::TreeView(),
@@ -30,14 +34,18 @@ bool BookmarkFolderTreeView::CanDrop(const OSExchangeData& data) {
if (!profile_->GetBookmarkModel()->IsLoaded())
return false;
- drop_info_.reset(new DropInfo());
- if (!drop_info_->drag_data.Read(data))
+ BookmarkDragData drag_data;
+
+ if (!drag_data.Read(data))
return false;
+ drop_info_.reset(new DropInfo(this));
+ drop_info_->SetData(drag_data);
+
// See if there are any urls being dropped.
- for (size_t i = 0; i < drop_info_->drag_data.size(); ++i) {
- if (drop_info_->drag_data.elements[0].is_url) {
- drop_info_->only_folders = false;
+ for (size_t i = 0; i < drop_info_->data().size(); ++i) {
+ if (drop_info_->data().elements[0].is_url) {
+ drop_info_->set_only_folders(false);
break;
}
}
@@ -50,27 +58,12 @@ void BookmarkFolderTreeView::OnDragEntered(
}
int BookmarkFolderTreeView::OnDragUpdated(const views::DropTargetEvent& event) {
- int drop_index;
- bool drop_on;
- FolderNode* drop_parent =
- CalculateDropParent(event.y(), drop_info_->only_folders, &drop_index,
- &drop_on);
- drop_info_->drop_operation =
- CalculateDropOperation(event, drop_parent, drop_index, drop_on);
-
- if (drop_info_->drop_operation == DragDropTypes::DRAG_NONE) {
- drop_parent = NULL;
- drop_index = -1;
- drop_on = false;
- }
-
- SetDropParent(drop_parent, drop_index, drop_on);
-
- return drop_info_->drop_operation;
+ drop_info_->Update(event);
+ return UpdateDropInfo();
}
void BookmarkFolderTreeView::OnDragExited() {
- SetDropParent(NULL, -1, false);
+ SetDropPosition(DropPosition());
drop_info_.reset();
}
@@ -78,8 +71,8 @@ void BookmarkFolderTreeView::OnDragExited() {
int BookmarkFolderTreeView::OnPerformDrop(const views::DropTargetEvent& event) {
OnPerformDropImpl();
- int drop_operation = drop_info_->drop_operation;
- SetDropParent(NULL, -1, false);
+ int drop_operation = drop_info_->drop_operation();
+ SetDropPosition(DropPosition());
drop_info_.reset();
return drop_operation;
}
@@ -106,6 +99,19 @@ LRESULT BookmarkFolderTreeView::OnNotify(int w_param, LPNMHDR l_param) {
return TreeView::OnNotify(w_param, l_param);
}
+int BookmarkFolderTreeView::UpdateDropInfo() {
+ DropPosition position =
+ CalculateDropPosition(drop_info_->last_y(), drop_info_->only_folders());
+ drop_info_->set_drop_operation(CalculateDropOperation(position));
+
+ if (drop_info_->drop_operation() == DragDropTypes::DRAG_NONE)
+ position = DropPosition();
+
+ SetDropPosition(position);
+
+ return drop_info_->drop_operation();
+}
+
void BookmarkFolderTreeView::BeginDrag(BookmarkNode* node) {
BookmarkModel* model = profile_->GetBookmarkModel();
// Only allow the drag if the user has selected a node of type bookmark and it
@@ -128,12 +134,8 @@ void BookmarkFolderTreeView::BeginDrag(BookmarkNode* node) {
is_dragging_ = false;
}
-FolderNode* BookmarkFolderTreeView::CalculateDropParent(int y,
- bool only_folders,
- int* drop_index,
- bool* drop_on) {
- *drop_on = false;
- *drop_index = -1;
+BookmarkFolderTreeView::DropPosition BookmarkFolderTreeView::
+ CalculateDropPosition(int y, bool only_folders) {
HWND hwnd = GetNativeControlHWND();
HTREEITEM item = TreeView_GetFirstVisible(hwnd);
while (item) {
@@ -144,7 +146,7 @@ FolderNode* BookmarkFolderTreeView::CalculateDropParent(int y,
if (folder_model()->GetNodeType(model_node) !=
BookmarkFolderTreeModel::BOOKMARK) {
// Only allow drops on bookmark nodes.
- return NULL;
+ return DropPosition();
}
FolderNode* node = folder_model()->AsNode(model_node);
@@ -153,59 +155,50 @@ FolderNode* BookmarkFolderTreeView::CalculateDropParent(int y,
// If some of the elements being dropped are urls, then we only allow
// dropping on a folder. Similarly you can't drop between the
// bookmark bar and other folder nodes.
- *drop_on = true;
- *drop_index = node->GetChildCount();
- return node;
+ return DropPosition(node, node->GetChildCount(), true);
}
// Drop contains all folders, allow them to be dropped between
// folders.
- if (y < bounds.top + views::MenuItemView::kDropBetweenPixels) {
- *drop_index = node->GetParent()->IndexOfChild(node);
- return node->GetParent();
+ if (y < bounds.top + views::kDropBetweenPixels) {
+ return DropPosition(node->GetParent(),
+ node->GetParent()->IndexOfChild(node), false);
}
- if (y >= bounds.bottom - views::MenuItemView::kDropBetweenPixels) {
+ if (y >= bounds.bottom - views::kDropBetweenPixels) {
if (IsExpanded(node) && folder_model()->GetChildCount(node) > 0) {
// The node is expanded and has children, treat the drop as occurring
// as the first child. This is done to avoid the selection highlight
// dancing around when dragging over expanded folders. Without this
// the highlight jumps past the last expanded child of node.
- *drop_index = 0;
- return node;
+ return DropPosition(node, 0, false);
}
- *drop_index = node->GetParent()->IndexOfChild(node) + 1;
- return node->GetParent();
+ return DropPosition(node->GetParent(),
+ node->GetParent()->IndexOfChild(node) + 1, false);
}
- *drop_on = true;
- *drop_index = node->GetChildCount();
- return node;
+ return DropPosition(node, node->GetChildCount(), true);
}
item = TreeView_GetNextVisible(hwnd, item);
}
- return NULL;
+ return DropPosition();
}
int BookmarkFolderTreeView::CalculateDropOperation(
- const views::DropTargetEvent& event,
- FolderNode* drop_parent,
- int drop_index,
- bool drop_on) {
- if (!drop_parent)
+ const DropPosition& position) {
+ if (!position.parent)
return DragDropTypes::DRAG_NONE;
- if (drop_info_->drag_data.IsFromProfile(profile_)) {
- int bookmark_model_drop_index =
- FolderIndexToBookmarkIndex(drop_parent, drop_index, drop_on);
+ if (drop_info_->data().IsFromProfile(profile_)) {
+ int bookmark_model_drop_index = FolderIndexToBookmarkIndex(position);
if (!bookmark_utils::IsValidDropLocation(
- profile_, drop_info_->drag_data,
- TreeNodeAsBookmarkNode(drop_parent),
+ profile_, drop_info_->data(),
+ TreeNodeAsBookmarkNode(position.parent),
bookmark_model_drop_index)) {
return DragDropTypes::DRAG_NONE;
}
// Data from the same profile. Prefer move, but do copy if the user wants
// that.
- if (event.IsControlDown())
+ if (drop_info_->is_control_down())
return DragDropTypes::DRAG_COPY;
return DragDropTypes::DRAG_MOVE;
@@ -213,25 +206,26 @@ int BookmarkFolderTreeView::CalculateDropOperation(
// We're going to copy, but return an operation compatible with the source
// operations so that the user can drop.
return bookmark_utils::PreferredDropOperation(
- event, DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK);
+ drop_info_->source_operations(),
+ DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK);
}
void BookmarkFolderTreeView::OnPerformDropImpl() {
- BookmarkNode* parent_node = TreeNodeAsBookmarkNode(drop_info_->drop_parent);
- int drop_index = FolderIndexToBookmarkIndex(
- drop_info_->drop_parent, drop_info_->drop_index, drop_info_->drop_on);
+ BookmarkNode* parent_node =
+ TreeNodeAsBookmarkNode(drop_info_->position().parent);
+ int drop_index = FolderIndexToBookmarkIndex(drop_info_->position());
BookmarkModel* model = profile_->GetBookmarkModel();
// If the data is not from this profile we return an operation compatible
// with the source. As such, we need to need to check the data here too.
- if (!drop_info_->drag_data.IsFromProfile(profile_) ||
- drop_info_->drop_operation == DragDropTypes::DRAG_COPY) {
- bookmark_utils::CloneDragData(model, drop_info_->drag_data.elements,
+ if (!drop_info_->data().IsFromProfile(profile_) ||
+ drop_info_->drop_operation() == DragDropTypes::DRAG_COPY) {
+ bookmark_utils::CloneDragData(model, drop_info_->data().elements,
parent_node, drop_index);
return;
}
// else, move.
- std::vector<BookmarkNode*> nodes = drop_info_->drag_data.GetNodes(profile_);
+ std::vector<BookmarkNode*> nodes = drop_info_->data().GetNodes(profile_);
if (nodes.empty())
return;
@@ -250,46 +244,36 @@ void BookmarkFolderTreeView::OnPerformDropImpl() {
}
}
-void BookmarkFolderTreeView::SetDropParent(FolderNode* node,
- int drop_index,
- bool drop_on) {
- if (drop_info_->drop_parent == node &&
- drop_info_->drop_index == drop_index &&
- drop_info_->drop_on == drop_on) {
+void BookmarkFolderTreeView::SetDropPosition(const DropPosition& position) {
+ if (drop_info_->position().equals(position))
return;
- }
+
// Remove the indicator over the previous location.
- if (drop_info_->drop_on) {
- HTREEITEM item = GetTreeItemForNode(drop_info_->drop_parent);
+ if (drop_info_->position().on) {
+ HTREEITEM item = GetTreeItemForNode(drop_info_->position().parent);
if (item)
TreeView_SetItemState(GetNativeControlHWND(), item, 0, TVIS_DROPHILITED);
- } else if (drop_info_->drop_index != -1) {
+ } else if (drop_info_->position().index != -1) {
TreeView_SetInsertMark(GetNativeControlHWND(), NULL, FALSE);
}
- drop_info_->drop_parent = node;
- drop_info_->drop_index = drop_index;
- drop_info_->drop_on = drop_on;
+ drop_info_->set_position(position);
// And show the new indicator.
- if (drop_info_->drop_on) {
- HTREEITEM item = GetTreeItemForNode(drop_info_->drop_parent);
+ if (position.on) {
+ HTREEITEM item = GetTreeItemForNode(position.parent);
if (item) {
TreeView_SetItemState(GetNativeControlHWND(), item, TVIS_DROPHILITED,
TVIS_DROPHILITED);
}
- } else if (drop_info_->drop_index != -1) {
+ } else if (position.index != -1) {
BOOL after = FALSE;
- if (folder_model()->GetChildCount(drop_info_->drop_parent) ==
- drop_info_->drop_index) {
+ FolderNode* node = position.parent;
+ if (folder_model()->GetChildCount(position.parent) == position.index) {
after = TRUE;
- node =
- folder_model()->GetChild(drop_info_->drop_parent,
- drop_info_->drop_index - 1);
+ node = folder_model()->GetChild(position.parent, position.index - 1);
} else {
- node =
- folder_model()->GetChild(drop_info_->drop_parent,
- drop_info_->drop_index);
+ node = folder_model()->GetChild(position.parent, position.index);
}
HTREEITEM item = GetTreeItemForNode(node);
if (item)
@@ -305,16 +289,15 @@ BookmarkNode* BookmarkFolderTreeView::TreeNodeAsBookmarkNode(FolderNode* node) {
return folder_model()->TreeNodeAsBookmarkNode(node);
}
-int BookmarkFolderTreeView::FolderIndexToBookmarkIndex(FolderNode* node,
- int index,
- bool drop_on) {
- BookmarkNode* parent_node = TreeNodeAsBookmarkNode(node);
- if (drop_on || index == node->GetChildCount())
+int BookmarkFolderTreeView::FolderIndexToBookmarkIndex(
+ const DropPosition& position) {
+ BookmarkNode* parent_node = TreeNodeAsBookmarkNode(position.parent);
+ if (position.on || position.index == position.parent->GetChildCount())
return parent_node->GetChildCount();
- if (index != 0) {
+ if (position.index != 0) {
return parent_node->IndexOfChild(
- TreeNodeAsBookmarkNode(node->GetChild(index)));
+ TreeNodeAsBookmarkNode(position.parent->GetChild(position.index)));
}
return 0;
diff --git a/chrome/browser/views/bookmark_folder_tree_view.h b/chrome/browser/views/bookmark_folder_tree_view.h
index ae12b2c..f024e75 100644
--- a/chrome/browser/views/bookmark_folder_tree_view.h
+++ b/chrome/browser/views/bookmark_folder_tree_view.h
@@ -5,7 +5,9 @@
#ifndef CHROME_BROWSER_VIEWS_BOOKMARK_FOLDER_TREE_VIEW_H_
#define CHROME_BROWSER_VIEWS_BOOKMARK_FOLDER_TREE_VIEW_H_
+#include "base/timer.h"
#include "chrome/browser/bookmarks/bookmark_drag_data.h"
+#include "chrome/browser/bookmarks/bookmark_drop_info.h"
#include "chrome/browser/bookmarks/bookmark_folder_tree_model.h"
#include "chrome/views/tree_view.h"
@@ -37,61 +39,77 @@ class BookmarkFolderTreeView : public views::TreeView {
virtual LRESULT OnNotify(int w_param, LPNMHDR l_param);
private:
+ // DropPosition identifies where the drop should occur. A DropPosition
+ // consists of the following: the parent FolderNode the drop is to occur at,
+ // whether the drop is on the parent, and the index into the parent the drop
+ // should occur at.
+ //
+ // WARNING: the index is in terms of the BookmarkFolderTreeModel, which is
+ // not the same as the BookmarkModel.
+ struct DropPosition {
+ DropPosition() : parent(NULL), index(-1), on(false) {}
+ DropPosition(FolderNode* parent, int index, bool on)
+ : parent(parent),
+ index(index),
+ on(on) {}
+
+ // Returns true if |position| equals this.
+ bool equals(const DropPosition& position) const {
+ return (position.parent == parent && position.index == index &&
+ position.on == on);
+ }
+
+ FolderNode* parent;
+ int index;
+ bool on;
+ };
+
// Provides information used during a drop.
- struct DropInfo {
- DropInfo()
- : drop_parent(NULL),
- only_folders(true),
- drop_index(-1),
- drop_operation(0),
- drop_on(false) {}
-
- // Parent the mouse is over.
- FolderNode* drop_parent;
-
- // Drag data.
- BookmarkDragData drag_data;
-
- // Does drag_data consists of folders only.
- bool only_folders;
-
- // If drop_on is false, this is the index to add the child.
- // WARNING: this index is in terms of the BookmarkFolderTreeModel, which is
- // not the same as the BookmarkModel.
- int drop_index;
-
- // Operation for the drop.
- int drop_operation;
-
- // Is the user dropping on drop_parent? If false, the mouse is positioned
- // such that the drop should insert the data at position drop_index in
- // drop_parent.
- bool drop_on;
+ class DropInfo : public BookmarkDropInfo {
+ public:
+ explicit DropInfo(BookmarkFolderTreeView* view)
+ : BookmarkDropInfo(view->GetNativeControlHWND(), 0),
+ view_(view),
+ only_folders_(true) {}
+
+ virtual void Scrolled();
+
+ // Does drag_data consists of folders only?
+ void set_only_folders(bool only_folders) { only_folders_ = only_folders; }
+ bool only_folders() const { return only_folders_; }
+
+ // Position of the drop.
+ void set_position(const DropPosition& position) { position_ = position; }
+ const DropPosition& position() const { return position_; }
+
+ private:
+ BookmarkFolderTreeView* view_;
+ DropPosition position_;
+ bool only_folders_;
+
+ DISALLOW_COPY_AND_ASSIGN(DropInfo);
};
+ friend class DropInfo;
+
+ // Updates drop info. This is invoked both from OnDragUpdated and when we
+ // autoscroll during a drop.
+ int UpdateDropInfo();
// Starts a drag operation for the specified node.
void BeginDrag(BookmarkNode* node);
- // Calculates the drop parent. Returns NULL if not over a valid drop
- // location. See DropInfos documentation for a description of |drop_index|
- // and |drop_on|.
- FolderNode* CalculateDropParent(int y,
- bool only_folders,
- int* drop_index,
- bool* drop_on);
+ // Calculates the drop position.
+ DropPosition CalculateDropPosition(int y, bool only_folders);
// Determines the appropriate drop operation. This returns DRAG_NONE
- // if the location is not valid.
- int CalculateDropOperation(const views::DropTargetEvent& event,
- FolderNode* drop_parent,
- int drop_index,
- bool drop_on);
+ // if the position is not valid.
+ int CalculateDropOperation(const DropPosition& position);
// Performs the drop operation.
void OnPerformDropImpl();
- // Sets the parent of the drop operation.
- void SetDropParent(FolderNode* node, int drop_index, bool drop_on);
+ // Sets the drop position.
+ void SetDropPosition(const DropPosition& position);
// Returns the model as a BookmarkFolderTreeModel.
BookmarkFolderTreeModel* folder_model() const;
@@ -99,9 +117,10 @@ class BookmarkFolderTreeView : public views::TreeView {
// Converts FolderNode into a BookmarkNode.
BookmarkNode* TreeNodeAsBookmarkNode(FolderNode* node);
- // Converts an index in terms of the BookmarkFolderTreeModel to an index
- // in terms of the BookmarkModel.
- int FolderIndexToBookmarkIndex(FolderNode* node, int index, bool drop_on);
+ // Converts the position in terms of the BookmarkFolderTreeModel to an index
+ // in terms of the BookmarkModel. The returned index is the index the drop
+ // should occur at in terms of the BookmarkModel.
+ int FolderIndexToBookmarkIndex(const DropPosition& position);
Profile* profile_;
diff --git a/chrome/browser/views/bookmark_table_view.cc b/chrome/browser/views/bookmark_table_view.cc
index ffda218..9433976 100644
--- a/chrome/browser/views/bookmark_table_view.cc
+++ b/chrome/browser/views/bookmark_table_view.cc
@@ -13,7 +13,7 @@
#include "chrome/common/os_exchange_data.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
-#include "chrome/views/chrome_menu.h"
+#include "chrome/views/view_constants.h"
#include "generated_resources.h"
@@ -35,6 +35,10 @@ int GetWidthOfColumn(const std::vector<views::TableColumn>& columns,
} // namespace
+void BookmarkTableView::DropInfo::Scrolled() {
+ view_->UpdateDropInfo();
+}
+
BookmarkTableView::BookmarkTableView(Profile* profile,
BookmarkTableModel* model)
: views::TableView(model, std::vector<views::TableColumn>(),
@@ -57,17 +61,20 @@ bool BookmarkTableView::CanDrop(const OSExchangeData& data) {
if (!parent_node_ || !profile_->GetBookmarkModel()->IsLoaded())
return false;
- drop_info_.reset(new DropInfo());
- if (!drop_info_->drag_data.Read(data))
+ BookmarkDragData drag_data;
+ if (!drag_data.Read(data))
return false;
// Don't allow the user to drop an ancestor of the parent node onto the
// parent node. This would create a cycle, which is definitely a no-no.
- std::vector<BookmarkNode*> nodes = drop_info_->drag_data.GetNodes(profile_);
+ std::vector<BookmarkNode*> nodes = drag_data.GetNodes(profile_);
for (size_t i = 0; i < nodes.size(); ++i) {
if (parent_node_->HasAncestor(nodes[i]))
return false;
}
+
+ drop_info_.reset(new DropInfo(this));
+ drop_info_->SetData(drag_data);
return true;
}
@@ -75,40 +82,24 @@ void BookmarkTableView::OnDragEntered(const views::DropTargetEvent& event) {
}
int BookmarkTableView::OnDragUpdated(const views::DropTargetEvent& event) {
- if (!parent_node_)
+ if (!parent_node_ || !drop_info_.get()) {
+ drop_info_.reset(NULL);
return false;
-
- LVHITTESTINFO hit_info = {0};
- hit_info.pt.x = event.x();
- hit_info.pt.y = event.y();
- // TODO(sky): need to support auto-scroll and all that good stuff.
-
- int drop_index;
- bool drop_on;
- drop_index = CalculateDropIndex(event.y(), &drop_on);
-
- drop_info_->drop_operation =
- CalculateDropOperation(event, drop_index, drop_on);
-
- if (drop_info_->drop_operation == DragDropTypes::DRAG_NONE) {
- drop_index = -1;
- drop_on = false;
}
- SetDropIndex(drop_index, drop_on);
-
- return drop_info_->drop_operation;
+ drop_info_->Update(event);
+ return UpdateDropInfo();
}
void BookmarkTableView::OnDragExited() {
- SetDropIndex(-1, false);
+ SetDropPosition(DropPosition());
drop_info_.reset();
}
int BookmarkTableView::OnPerformDrop(const views::DropTargetEvent& event) {
OnPerformDropImpl();
- int drop_operation = drop_info_->drop_operation;
- SetDropIndex(-1, false);
+ int drop_operation = drop_info_->drop_operation();
+ SetDropPosition(DropPosition());
drop_info_.reset();
return drop_operation;
}
@@ -148,12 +139,12 @@ void BookmarkTableView::SetShowPathColumn(bool show_path_column) {
}
void BookmarkTableView::PostPaint() {
- if (!drop_info_.get() || drop_info_->drop_index == -1 ||
- drop_info_->drop_on) {
+ if (!drop_info_.get() || drop_info_->position().index == -1 ||
+ drop_info_->position().on) {
return;
}
- RECT bounds = GetDropBetweenHighlightRect(drop_info_->drop_index);
+ RECT bounds = GetDropBetweenHighlightRect(drop_info_->position().index);
HDC dc = GetDC(GetNativeControlHWND());
HBRUSH brush = CreateSolidBrush(GetSysColor(COLOR_WINDOWTEXT));
FillRect(dc, &bounds, brush);
@@ -171,6 +162,19 @@ LRESULT BookmarkTableView::OnNotify(int w_param, LPNMHDR l_param) {
return TableView::OnNotify(w_param, l_param);
}
+int BookmarkTableView::UpdateDropInfo() {
+ DropPosition position = CalculateDropPosition(drop_info_->last_y());
+
+ drop_info_->set_drop_operation(CalculateDropOperation(position));
+
+ if (drop_info_->drop_operation() == DragDropTypes::DRAG_NONE)
+ position = DropPosition();
+
+ SetDropPosition(position);
+
+ return drop_info_->drop_operation();
+}
+
void BookmarkTableView::BeginDrag() {
std::vector<BookmarkNode*> nodes_to_drag;
for (TableView::iterator i = SelectionBegin(); i != SelectionEnd(); ++i)
@@ -186,21 +190,18 @@ void BookmarkTableView::BeginDrag() {
DROPEFFECT_LINK | DROPEFFECT_COPY | DROPEFFECT_MOVE, &effects);
}
-int BookmarkTableView::CalculateDropOperation(
- const views::DropTargetEvent& event,
- int drop_index,
- bool drop_on) {
- if (drop_info_->drag_data.IsFromProfile(profile_)) {
+int BookmarkTableView::CalculateDropOperation(const DropPosition& position) {
+ if (drop_info_->data().IsFromProfile(profile_)) {
// Data from the same profile. Prefer move, but do copy if the user wants
// that.
- if (event.IsControlDown())
+ if (drop_info_->is_control_down())
return DragDropTypes::DRAG_COPY;
int real_drop_index;
- BookmarkNode* drop_parent = GetDropParentAndIndex(drop_index, drop_on,
+ BookmarkNode* drop_parent = GetDropParentAndIndex(position,
&real_drop_index);
if (!bookmark_utils::IsValidDropLocation(
- profile_, drop_info_->drag_data, drop_parent, real_drop_index)) {
+ profile_, drop_info_->data(), drop_parent, real_drop_index)) {
return DragDropTypes::DRAG_NONE;
}
return DragDropTypes::DRAG_MOVE;
@@ -208,28 +209,29 @@ int BookmarkTableView::CalculateDropOperation(
// We're going to copy, but return an operation compatible with the source
// operations so that the user can drop.
return bookmark_utils::PreferredDropOperation(
- event, DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK);
+ drop_info_->source_operations(),
+ DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK);
}
void BookmarkTableView::OnPerformDropImpl() {
int drop_index;
BookmarkNode* drop_parent = GetDropParentAndIndex(
- drop_info_->drop_index, drop_info_->drop_on, &drop_index);
+ drop_info_->position(), &drop_index);
BookmarkModel* model = profile_->GetBookmarkModel();
int min_selection;
int max_selection;
// If the data is not from this profile we return an operation compatible
// with the source. As such, we need to need to check the data here too.
- if (!drop_info_->drag_data.IsFromProfile(profile_) ||
- drop_info_->drop_operation == DragDropTypes::DRAG_COPY) {
- bookmark_utils::CloneDragData(model, drop_info_->drag_data.elements,
+ if (!drop_info_->data().IsFromProfile(profile_) ||
+ drop_info_->drop_operation() == DragDropTypes::DRAG_COPY) {
+ bookmark_utils::CloneDragData(model, drop_info_->data().elements,
drop_parent, drop_index);
min_selection = drop_index;
max_selection = drop_index +
- static_cast<int>(drop_info_->drag_data.elements.size());
+ static_cast<int>(drop_info_->data().elements.size());
} else {
// else, move.
- std::vector<BookmarkNode*> nodes = drop_info_->drag_data.GetNodes(profile_);
+ std::vector<BookmarkNode*> nodes = drop_info_->data().GetNodes(profile_);
if (nodes.empty())
return;
@@ -241,7 +243,12 @@ void BookmarkTableView::OnPerformDropImpl() {
min_selection = drop_parent->IndexOfChild(nodes[0]);
max_selection = min_selection + static_cast<int>(nodes.size());
}
- if (min_selection < RowCount() && max_selection < RowCount()) {
+ if (drop_info_->position().on) {
+ // The user dropped on a folder, select it.
+ int index = parent_node_->IndexOfChild(drop_parent);
+ if (index != -1)
+ Select(index);
+ } else if (min_selection < RowCount() && max_selection <= RowCount()) {
// Select the moved/copied rows.
Select(min_selection);
if (min_selection + 1 < max_selection) {
@@ -254,70 +261,69 @@ void BookmarkTableView::OnPerformDropImpl() {
}
}
-void BookmarkTableView::SetDropIndex(int index, bool drop_on) {
- if (drop_info_->drop_index == index && drop_info_->drop_on == drop_on)
+void BookmarkTableView::SetDropPosition(const DropPosition& position) {
+ if (drop_info_->position().equals(position))
return;
- UpdateDropIndex(drop_info_->drop_index, drop_info_->drop_on, false);
+ UpdateDropIndicator(drop_info_->position(), false);
- drop_info_->drop_index = index;
- drop_info_->drop_on = drop_on;
+ drop_info_->set_position(position);
- UpdateDropIndex(drop_info_->drop_index, drop_info_->drop_on, true);
+ UpdateDropIndicator(drop_info_->position(), true);
}
-void BookmarkTableView::UpdateDropIndex(int index, bool drop_on, bool turn_on) {
- if (index == -1)
+void BookmarkTableView::UpdateDropIndicator(const DropPosition& position,
+ bool turn_on) {
+ if (position.index == -1)
return;
- if (drop_on) {
- ListView_SetItemState(GetNativeControlHWND(), index,
+ if (position.on) {
+ ListView_SetItemState(GetNativeControlHWND(), position.index,
turn_on ? LVIS_DROPHILITED : 0, LVIS_DROPHILITED);
} else {
- RECT bounds = GetDropBetweenHighlightRect(index);
+ RECT bounds = GetDropBetweenHighlightRect(position.index);
InvalidateRect(GetNativeControlHWND(), &bounds, FALSE);
}
}
-int BookmarkTableView::CalculateDropIndex(int y, bool* drop_on) {
- *drop_on = false;
+BookmarkTableView::DropPosition
+ BookmarkTableView::CalculateDropPosition(int y) {
HWND hwnd = GetNativeControlHWND();
int row_count = RowCount();
int top_index = ListView_GetTopIndex(hwnd);
if (row_count == 0 || top_index < 0)
- return 0;
+ return DropPosition(0, false);
for (int i = top_index; i < row_count; ++i) {
RECT bounds;
ListView_GetItemRect(hwnd, i, &bounds, LVIR_BOUNDS);
if (y < bounds.top)
- return i;
+ return DropPosition(i, false);
if (y < bounds.bottom) {
if (bookmark_table_model()->GetNodeForRow(i)->is_folder()) {
- if (y < bounds.top + views::MenuItemView::kDropBetweenPixels)
- return i;
- if (y >= bounds.bottom - views::MenuItemView::kDropBetweenPixels)
- return i + 1;
- *drop_on = true;
- return i;
+ if (y < bounds.top + views::kDropBetweenPixels)
+ return DropPosition(i, false);
+ if (y >= bounds.bottom - views::kDropBetweenPixels)
+ return DropPosition(i + 1, false);
+ return DropPosition(i, true);
}
if (y < (bounds.bottom - bounds.top) / 2 + bounds.top)
- return i;
- return i + 1;
+ return DropPosition(i, false);
+ return DropPosition(i + 1, false);
}
}
- return row_count;
+ return DropPosition(row_count, false);
}
-BookmarkNode* BookmarkTableView::GetDropParentAndIndex(int visual_drop_index,
- bool drop_on,
- int* index) {
- if (drop_on) {
- BookmarkNode* parent = parent_node_->GetChild(visual_drop_index);
+BookmarkNode* BookmarkTableView::GetDropParentAndIndex(
+ const DropPosition& position,
+ int* index) {
+ if (position.on) {
+ BookmarkNode* parent = parent_node_->GetChild(position.index);
*index = parent->GetChildCount();
return parent;
}
- *index = visual_drop_index;
+ *index = position.index;
return parent_node_;
}
@@ -338,6 +344,7 @@ RECT BookmarkTableView::GetDropBetweenHighlightRect(int index) {
bounds.bottom = bounds.top + kDropHighlightHeight;
return bounds;
}
+
void BookmarkTableView::UpdateColumns() {
PrefService* prefs = profile_->GetPrefs();
views::TableColumn name_column =
diff --git a/chrome/browser/views/bookmark_table_view.h b/chrome/browser/views/bookmark_table_view.h
index a01f1af..40dc81e 100644
--- a/chrome/browser/views/bookmark_table_view.h
+++ b/chrome/browser/views/bookmark_table_view.h
@@ -6,6 +6,7 @@
#define CHROME_BROWSER_VIEWS_BOOKMARK_TABLE_VIEW_H_
#include "chrome/browser/bookmarks/bookmark_drag_data.h"
+#include "chrome/browser/bookmarks/bookmark_drop_info.h"
#include "chrome/views/menu.h"
#include "chrome/views/table_view.h"
@@ -54,49 +55,75 @@ class BookmarkTableView : public views::TableView {
virtual LRESULT OnNotify(int w_param, LPNMHDR l_param);
private:
- // Information used when we're the drop target of a drag and drop operation.
- struct DropInfo {
- DropInfo() : drop_index(-1), drop_operation(0), drop_on(false) {}
-
- BookmarkDragData drag_data;
-
- // Index into the table model of where the drop should occur.
- int drop_index;
-
- // The drop operation that should occur.
- int drop_operation;
+ // DropPosition identifies where the drop should occur.
+ struct DropPosition {
+ DropPosition() : index(-1), on(false) {}
+ DropPosition(int index, bool on) : index(index), on(on) {}
+
+ bool equals(const DropPosition& position) const {
+ return index == position.index && on == position.on;
+ }
+
+ // The index into the table model as to where the drop should occur. This
+ // may == the row count of the table.
+ int index;
+
+ // Whether drop is on the item at the specified index. If false, the drop
+ // is at the specified index.
+ bool on;
+ };
- // Whether the drop is on drop_index or before it.
- bool drop_on;
+ // Information used when we're the drop target of a drag and drop operation.
+ class DropInfo : public BookmarkDropInfo {
+ public:
+ explicit DropInfo(BookmarkTableView* view)
+ : BookmarkDropInfo(view->GetNativeControlHWND(),
+ view->content_offset()),
+ view_(view) {}
+
+ // Overriden to invoke UpdateDropInfo.
+ virtual void Scrolled();
+
+ // The position the drop is to occur at.
+ void set_position(const DropPosition& position) {
+ position_ = position;
+ }
+ const DropPosition& position() { return position_; }
+
+ private:
+ DropPosition position_;
+ BookmarkTableView* view_;
+
+ DISALLOW_COPY_AND_ASSIGN(DropInfo);
};
+ friend class DropInfo;
+
+ // Updates drop info. This is invoked both from OnDragUpdated and when we
+ // autoscroll during a drop.
+ int UpdateDropInfo();
// Starts a drop operation.
void BeginDrag();
- // Returns the drop operation for the specified index.
- int CalculateDropOperation(const views::DropTargetEvent& event,
- int drop_index,
- bool drop_on);
+ // Returns the drop operation for the specified position.
+ int CalculateDropOperation(const DropPosition& position);
// Performs the drop operation.
void OnPerformDropImpl();
- // Sets the drop index. If index differs from the current drop index
- // UpdateDropIndex is invoked for the old and new values.
- void SetDropIndex(int index, bool drop_on);
+ // Sets the position of the drop. If this differs from the current position
+ // UpdateDropIndicator is invoked for old and new values.
+ void SetDropPosition(const DropPosition& position);
- // Invoked from SetDropIndex to update the state for the specified index
- // and schedule a paint. If |turn_on| is true the highlight is being turned
- // on for the specified index, otherwise it is being turned off.
- void UpdateDropIndex(int index, bool drop_on, bool turn_on);
+ // Invoked from SetDropPosition to update the visual indicator. |turn_on|
+ // indicates whether the indicator is to be turned on or off.
+ void UpdateDropIndicator(const DropPosition& position, bool turn_on);
- // Determines the drop index for the specified location.
- int CalculateDropIndex(int y, bool* drop_on);
+ // Determines the drop position for the specified location.
+ DropPosition CalculateDropPosition(int y);
- // Returns the BookmarkNode the drop should occur on, or NULL if not over
- // a valid location.
- BookmarkNode* GetDropParentAndIndex(int visual_drop_index,
- bool drop_on,
+ // Returns the BookmarkNode the drop should occur on.
+ BookmarkNode* GetDropParentAndIndex(const DropPosition& position,
int* index);
// Returns the bounds of drop indicator shown when the drop is to occur