summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsky@google.com <sky@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-11-07 17:53:09 +0000
committersky@google.com <sky@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-11-07 17:53:09 +0000
commitfafc8a4203d4308251f17fc18a61cfec71a9a27c (patch)
treedfee81ebce10c148f4dfa13b4621bc8fd40473fb
parent8bc886faa6a178f51bf094efe491ab1da9595d14 (diff)
downloadchromium_src-fafc8a4203d4308251f17fc18a61cfec71a9a27c.zip
chromium_src-fafc8a4203d4308251f17fc18a61cfec71a9a27c.tar.gz
chromium_src-fafc8a4203d4308251f17fc18a61cfec71a9a27c.tar.bz2
Adds cut/copy/paste support to the bookmark manager tree/table and
context menus. BUG=4186 TEST=try cut/copy/paste from table/tree in the bookmark manager as well as context menus in bookmark manager. Review URL: http://codereview.chromium.org/9481 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@4993 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/bookmarks/bookmark_context_menu.cc42
-rw-r--r--chrome/browser/bookmarks/bookmark_drag_data.cc5
-rw-r--r--chrome/browser/bookmarks/bookmark_drag_data.h2
-rw-r--r--chrome/browser/bookmarks/bookmark_utils.cc53
-rw-r--r--chrome/browser/bookmarks/bookmark_utils.h17
-rw-r--r--chrome/browser/views/bookmark_manager_view.cc98
-rw-r--r--chrome/browser/views/bookmark_manager_view.h16
-rw-r--r--chrome/views/tree_view.cc8
-rw-r--r--chrome/views/tree_view.h3
9 files changed, 239 insertions, 5 deletions
diff --git a/chrome/browser/bookmarks/bookmark_context_menu.cc b/chrome/browser/bookmarks/bookmark_context_menu.cc
index 1841f2b..9cdacbf 100644
--- a/chrome/browser/bookmarks/bookmark_context_menu.cc
+++ b/chrome/browser/bookmarks/bookmark_context_menu.cc
@@ -269,6 +269,20 @@ BookmarkContextMenu::BookmarkContextMenu(
l10n_util::GetString(IDS_BOOKMARK_MANAGER_SHOW_IN_FOLDER));
}
+ if (configuration == BOOKMARK_MANAGER_TABLE ||
+ configuration == BOOKMARK_MANAGER_TABLE_OTHER ||
+ configuration == BOOKMARK_MANAGER_TREE ||
+ configuration == BOOKMARK_MANAGER_ORGANIZE_MENU ||
+ configuration == BOOKMARK_MANAGER_ORGANIZE_MENU_OTHER) {
+ menu_->AppendSeparator();
+ menu_->AppendMenuItemWithLabel(
+ IDS_CUT, l10n_util::GetString(IDS_CUT));
+ menu_->AppendMenuItemWithLabel(
+ IDS_COPY, l10n_util::GetString(IDS_COPY));
+ menu_->AppendMenuItemWithLabel(
+ IDS_PASTE, l10n_util::GetString(IDS_PASTE));
+ }
+
menu_->AppendSeparator();
menu_->AppendMenuItemWithLabel(
@@ -413,6 +427,26 @@ void BookmarkContextMenu::ExecuteCommand(int id) {
BookmarkManagerView::Show(profile_);
break;
+ case IDS_COPY:
+ case IDS_CUT:
+ bookmark_utils::CopyToClipboard(profile_->GetBookmarkModel(),
+ selection_, id == IDS_CUT);
+ break;
+
+ case IDS_PASTE: {
+ // Always paste to parent.
+ if (!parent_)
+ return;
+
+ int index = (selection_.size() == 1) ?
+ parent_->IndexOfChild(selection_[0]) : -1;
+ if (index != -1)
+ index++;
+ bookmark_utils::PasteFromClipboard(profile_->GetBookmarkModel(),
+ parent_, index);
+ break;
+ }
+
default:
NOTREACHED();
}
@@ -452,6 +486,14 @@ bool BookmarkContextMenu::IsCommandEnabled(int id) const {
case IDS_BOOMARK_BAR_NEW_FOLDER:
case IDS_BOOMARK_BAR_ADD_NEW_BOOKMARK:
return GetParentForNewNodes() != NULL;
+
+ case IDS_COPY:
+ case IDS_CUT:
+ return selection_.size() > 0 && !is_root_node;
+
+ case IDS_PASTE:
+ // Always paste to parent.
+ return bookmark_utils::CanPasteFromClipboard(parent_);
}
return true;
}
diff --git a/chrome/browser/bookmarks/bookmark_drag_data.cc b/chrome/browser/bookmarks/bookmark_drag_data.cc
index c55d24f..2e7285a 100644
--- a/chrome/browser/bookmarks/bookmark_drag_data.cc
+++ b/chrome/browser/bookmarks/bookmark_drag_data.cc
@@ -92,7 +92,7 @@ void BookmarkDragData::Write(Profile* profile, OSExchangeData* data) const {
}
Pickle data_pickle;
- data_pickle.WriteWString(profile->GetPath());
+ data_pickle.WriteWString(profile ? profile->GetPath() : std::wstring());
data_pickle.WriteSize(elements.size());
for (size_t i = 0; i < elements.size(); ++i)
@@ -162,5 +162,6 @@ BookmarkNode* BookmarkDragData::GetFirstNode(Profile* profile) const {
}
bool BookmarkDragData::IsFromProfile(Profile* profile) const {
- return (profile->GetPath() == profile_path_);
+ // An empty path means the data is not associated with any profile.
+ return (!profile_path_.empty() && profile->GetPath() == profile_path_);
}
diff --git a/chrome/browser/bookmarks/bookmark_drag_data.h b/chrome/browser/bookmarks/bookmark_drag_data.h
index 263bf8d..b02be0c 100644
--- a/chrome/browser/bookmarks/bookmark_drag_data.h
+++ b/chrome/browser/bookmarks/bookmark_drag_data.h
@@ -74,6 +74,8 @@ struct BookmarkDragData {
// Writes elements to data. If there is only one element and it is a URL
// the URL and title are written to the clipboard in a format other apps can
// use.
+ // |profile| is used to identify which profile the data came from. Use a
+ // value of null to indicate the data is not associated with any profile.
void Write(Profile* profile, OSExchangeData* data) const;
// Restores this data from the clipboard, returning true on success.
diff --git a/chrome/browser/bookmarks/bookmark_utils.cc b/chrome/browser/bookmarks/bookmark_utils.cc
index bf2576f..8aad4f1 100644
--- a/chrome/browser/bookmarks/bookmark_utils.cc
+++ b/chrome/browser/bookmarks/bookmark_utils.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/tab_contents.h"
#include "chrome/common/drag_drop_types.h"
#include "chrome/common/l10n_util.h"
+#include "chrome/common/os_exchange_data.h"
#include "chrome/views/event.h"
#include "chromium_strings.h"
@@ -237,4 +238,56 @@ void OpenAll(HWND parent,
OpenAll(parent, profile, navigator, nodes, initial_disposition);
}
+void CopyToClipboard(BookmarkModel* model,
+ const std::vector<BookmarkNode*>& nodes,
+ bool remove_nodes) {
+ if (nodes.empty())
+ return;
+
+ OSExchangeData* data = new OSExchangeData();
+ BookmarkDragData(nodes).Write(NULL, data);
+ OleSetClipboard(data);
+ // OLE takes ownership of OSExchangeData.
+
+ if (remove_nodes) {
+ for (size_t i = 0; i < nodes.size(); ++i) {
+ model->Remove(nodes[i]->GetParent(),
+ nodes[i]->GetParent()->IndexOfChild(nodes[i]));
+ }
+ }
+}
+
+void PasteFromClipboard(BookmarkModel* model,
+ BookmarkNode* parent,
+ int index) {
+ if (!parent)
+ return;
+
+ IDataObject* data;
+ if (OleGetClipboard(&data) != S_OK)
+ return;
+
+ OSExchangeData data_wrapper(data);
+ BookmarkDragData bookmark_data;
+ if (!bookmark_data.Read(data_wrapper))
+ return;
+
+ if (index == -1)
+ index = parent->GetChildCount();
+ bookmark_utils::CloneDragData(model, bookmark_data.elements, parent, index);
+}
+
+bool CanPasteFromClipboard(BookmarkNode* node) {
+ if (!node)
+ return false;
+
+ IDataObject* data;
+ if (OleGetClipboard(&data) != S_OK)
+ return false;
+
+ OSExchangeData data_wrapper(data);
+ BookmarkDragData bookmark_data;
+ return bookmark_data.Read(data_wrapper);
+}
+
} // namespace bookmark_utils
diff --git a/chrome/browser/bookmarks/bookmark_utils.h b/chrome/browser/bookmarks/bookmark_utils.h
index 281cf8c..3a72fbb 100644
--- a/chrome/browser/bookmarks/bookmark_utils.h
+++ b/chrome/browser/bookmarks/bookmark_utils.h
@@ -58,6 +58,23 @@ void OpenAll(HWND parent,
BookmarkNode* node,
WindowOpenDisposition initial_disposition);
+// Copies nodes onto the clipboard. If |remove_nodes| is true the nodes are
+// removed after copied to the clipboard. The nodes are copied in such a way
+// that if pasted again copies are made.
+void CopyToClipboard(BookmarkModel* model,
+ const std::vector<BookmarkNode*>& nodes,
+ bool remove_nodes);
+
+// Pastes from the clipboard. The new nodes are added to |parent|, unless
+// |parent| is null in which case this does nothing. The nodes are inserted
+// at |index|. If |index| is -1 the nodes are added to the end.
+void PasteFromClipboard(BookmarkModel* model,
+ BookmarkNode* parent,
+ int index);
+
+// Returns true if the user can copy from the pasteboard.
+bool CanPasteFromClipboard(BookmarkNode* node);
+
} // namespace bookmark_utils
#endif // CHROME_BROWSER_BOOKMARKS_BOOKMARK_UTILS_H_
diff --git a/chrome/browser/views/bookmark_manager_view.cc b/chrome/browser/views/bookmark_manager_view.cc
index 76ac3d7..0c967a5 100644
--- a/chrome/browser/views/bookmark_manager_view.cc
+++ b/chrome/browser/views/bookmark_manager_view.cc
@@ -88,6 +88,42 @@ class ImportObserverImpl : public ImportObserver {
DISALLOW_COPY_AND_ASSIGN(ImportObserverImpl);
};
+// Converts a virtual keycode into the CutCopyPasteType.
+BookmarkManagerView::CutCopyPasteType KeyCodeToCutCopyPaste(
+ unsigned short virtual_keycode) {
+ switch (virtual_keycode) {
+ case VK_INSERT:
+ if (GetKeyState(VK_CONTROL) < 0)
+ return BookmarkManagerView::COPY;
+ if (GetKeyState(VK_SHIFT) < 0)
+ return BookmarkManagerView::PASTE;
+ return BookmarkManagerView::NONE;
+
+ case VK_DELETE:
+ if (GetKeyState(VK_SHIFT) < 0)
+ return BookmarkManagerView::CUT;
+ return BookmarkManagerView::NONE;
+
+ case 'C':
+ if (GetKeyState(VK_CONTROL) < 0)
+ return BookmarkManagerView::COPY;
+ return BookmarkManagerView::NONE;
+
+ case 'V':
+ if (GetKeyState(VK_CONTROL) < 0)
+ return BookmarkManagerView::PASTE;
+ return BookmarkManagerView::NONE;
+
+ case 'X':
+ if (GetKeyState(VK_CONTROL) < 0)
+ return BookmarkManagerView::CUT;
+ return BookmarkManagerView::NONE;
+
+ default:
+ return BookmarkManagerView::NONE;
+ }
+}
+
} // namespace
BookmarkManagerView::BookmarkManagerView(Profile* profile)
@@ -320,8 +356,13 @@ void BookmarkManagerView::OnKeyDown(unsigned short virtual_keycode) {
switch (virtual_keycode) {
case VK_RETURN: {
std::vector<BookmarkNode*> selected_nodes = GetSelectedTableNodes();
- if (selected_nodes.size() == 1 && selected_nodes[0]->is_folder())
+ if (selected_nodes.size() == 1 && selected_nodes[0]->is_folder()) {
SelectInTree(selected_nodes[0]);
+ } else {
+ bookmark_utils::OpenAll(
+ GetContainer()->GetHWND(), profile_, NULL, selected_nodes,
+ CURRENT_TAB);
+ }
break;
}
@@ -333,6 +374,10 @@ void BookmarkManagerView::OnKeyDown(unsigned short virtual_keycode) {
}
break;
}
+
+ default:
+ OnCutCopyPaste(KeyCodeToCutCopyPaste(virtual_keycode), true);
+ break;
}
}
@@ -372,6 +417,24 @@ void BookmarkManagerView::OnTreeViewSelectionChanged(
SetTableModel(new_table_model, table_parent_node);
}
+void BookmarkManagerView::OnTreeViewKeyDown(unsigned short virtual_keycode) {
+ switch (virtual_keycode) {
+ case VK_DELETE: {
+ BookmarkNode* node = GetSelectedFolder();
+ if (!node || node->GetParent() == GetBookmarkModel()->root_node())
+ return;
+
+ BookmarkNode* parent = node->GetParent();
+ GetBookmarkModel()->Remove(parent, parent->IndexOfChild(node));
+ break;
+ }
+
+ default:
+ OnCutCopyPaste(KeyCodeToCutCopyPaste(virtual_keycode), false);
+ break;
+ }
+}
+
void BookmarkManagerView::Loaded(BookmarkModel* model) {
model->RemoveObserver(this);
LoadedImpl();
@@ -401,6 +464,14 @@ void BookmarkManagerView::ShowContextMenu(views::View* source,
bool is_mouse_gesture) {
DCHECK(source == table_view_ || source == tree_view_);
bool is_table = (source == table_view_);
+ if (is_table && x == -1 && y == -1) {
+ // TODO(sky): promote code to tableview that determines the location based
+ // on the selection. This is temporary until I fix that.
+ gfx::Point location(table_view_->width() / 2, table_view_->height() / 2);
+ View::ConvertPointToScreen(table_view_, &location);
+ x = location.x();
+ y = location.y();
+ }
ShowMenu(GetContainer()->GetHWND(), x, y,
is_table ? BookmarkContextMenu::BOOKMARK_MANAGER_TABLE :
BookmarkContextMenu::BOOKMARK_MANAGER_TREE);
@@ -584,6 +655,31 @@ void BookmarkManagerView::ShowMenu(
}
}
+void BookmarkManagerView::OnCutCopyPaste(CutCopyPasteType type,
+ bool from_table) {
+ if (type == CUT || type == COPY) {
+ std::vector<BookmarkNode*> nodes;
+ if (from_table) {
+ nodes = GetSelectedTableNodes();
+ } else {
+ BookmarkNode* node = GetSelectedFolder();
+ if (!node || node->GetParent() == GetBookmarkModel()->root_node())
+ return;
+ nodes.push_back(node);
+ }
+ if (nodes.empty())
+ return;
+
+ bookmark_utils::CopyToClipboard(GetBookmarkModel(), nodes, type == CUT);
+ } else if (type == PASTE) {
+ int index = from_table ? table_view_->FirstSelectedRow() : -1;
+ if (index != -1)
+ index++;
+ bookmark_utils::PasteFromClipboard(GetBookmarkModel(), GetSelectedFolder(),
+ index);
+ }
+}
+
void BookmarkManagerView::ShowToolsMenu(HWND host, int x, int y) {
views::MenuItemView menu(this);
menu.AppendMenuItemWithLabel(
diff --git a/chrome/browser/views/bookmark_manager_view.h b/chrome/browser/views/bookmark_manager_view.h
index 0aa83dd..be99a16 100644
--- a/chrome/browser/views/bookmark_manager_view.h
+++ b/chrome/browser/views/bookmark_manager_view.h
@@ -45,6 +45,13 @@ class BookmarkManagerView : public views::View,
public views::MenuDelegate,
public SelectFileDialog::Listener {
public:
+ enum CutCopyPasteType {
+ CUT,
+ COPY,
+ PASTE,
+ NONE
+ };
+
explicit BookmarkManagerView(Profile* profile);
virtual ~BookmarkManagerView();
@@ -63,7 +70,7 @@ class BookmarkManagerView : public views::View,
// Expands all the children of the selected folder.
void ExpandAll(BookmarkNode* node);
- // Returns the selected folder, which may be null.
+ // Returns the selected folder in the tree, which may be null.
BookmarkNode* GetSelectedFolder();
// Returns the selection of the table.
@@ -99,8 +106,9 @@ class BookmarkManagerView : public views::View,
virtual void OnTableViewDelete(views::TableView* table);
virtual void OnKeyDown(unsigned short virtual_keycode);
- // TreeViewController method.
+ // TreeViewController methods.
virtual void OnTreeViewSelectionChanged(views::TreeView* tree_view);
+ virtual void OnTreeViewKeyDown(unsigned short virtual_keycode);
// BookmarkModelObserver. We're only installed as an observer until the
// bookmarks are loaded.
@@ -181,6 +189,10 @@ class BookmarkManagerView : public views::View,
int y,
BookmarkContextMenu::ConfigurationType config);
+ // Invoked to handle cut/copy/paste from the table or tree. If |from_table|
+ // is true the source is the table.
+ void OnCutCopyPaste(CutCopyPasteType type, bool from_table);
+
// Shows the tools menu.
void ShowToolsMenu(HWND host, int x, int y);
diff --git a/chrome/views/tree_view.cc b/chrome/views/tree_view.cc
index 913b845..cbf577a 100644
--- a/chrome/views/tree_view.cc
+++ b/chrome/views/tree_view.cc
@@ -395,6 +395,14 @@ LRESULT TreeView::OnNotify(int w_param, LPNMHDR l_param) {
return 0;
}
+ case TVN_KEYDOWN:
+ if (controller_) {
+ NMTVKEYDOWN* key_down_message =
+ reinterpret_cast<NMTVKEYDOWN*>(l_param);
+ controller_->OnTreeViewKeyDown(key_down_message->wVKey);
+ }
+ break;
+
default:
break;
}
diff --git a/chrome/views/tree_view.h b/chrome/views/tree_view.h
index d0d083e..a385c60 100644
--- a/chrome/views/tree_view.h
+++ b/chrome/views/tree_view.h
@@ -97,6 +97,9 @@ class TreeViewController {
virtual bool CanEdit(TreeView* tree_view, TreeModelNode* node) {
return true;
}
+
+ // Invoked when a key is pressed on the tree view.
+ virtual void OnTreeViewKeyDown(unsigned short virtual_keycode) {}
};
// TreeView -------------------------------------------------------------------