diff options
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/bookmarks/base_bookmark_model_observer.h | 57 | ||||
-rw-r--r-- | chrome/browser/bookmarks/bookmark_menu_controller.cc | 232 | ||||
-rw-r--r-- | chrome/browser/bookmarks/bookmark_menu_controller.h | 137 | ||||
-rw-r--r-- | chrome/browser/bookmarks/bookmark_utils.cc | 57 | ||||
-rw-r--r-- | chrome/browser/bookmarks/bookmark_utils.h | 23 | ||||
-rw-r--r-- | chrome/browser/browser.vcproj | 8 | ||||
-rw-r--r-- | chrome/browser/views/bookmark_bar_view.cc | 408 | ||||
-rw-r--r-- | chrome/browser/views/bookmark_bar_view.h | 31 | ||||
-rw-r--r-- | chrome/views/chrome_menu.cc | 1 |
9 files changed, 570 insertions, 384 deletions
diff --git a/chrome/browser/bookmarks/base_bookmark_model_observer.h b/chrome/browser/bookmarks/base_bookmark_model_observer.h new file mode 100644 index 0000000..34d755f --- /dev/null +++ b/chrome/browser/bookmarks/base_bookmark_model_observer.h @@ -0,0 +1,57 @@ +// Copyright (c) 2009 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_BASE_BOOKMARK_MODEL_OBSERVER_H_ +#define CHROME_BROWSER_BOOKMARKS_BASE_BOOKMARK_MODEL_OBSERVER_H_ + +#include "chrome/browser/bookmarks/bookmark_model.h" + +// Base class for a BookmarkModelObserver implementation. All mutations of the +// model funnel into the method BookmarkModelChanged. +class BaseBookmarkModelObserver : public BookmarkModelObserver { + public: + BaseBookmarkModelObserver() {} + virtual ~BaseBookmarkModelObserver() {} + + virtual void BookmarkModelChanged() = 0; + + virtual void Loaded(BookmarkModel* model) {} + + virtual void BookmarkModelBeingDeleted(BookmarkModel* model) { + BookmarkModelChanged(); + } + virtual void BookmarkNodeMoved(BookmarkModel* model, + BookmarkNode* old_parent, + int old_index, + BookmarkNode* new_parent, + int new_index) { + BookmarkModelChanged(); + } + virtual void BookmarkNodeAdded(BookmarkModel* model, + BookmarkNode* parent, + int index) { + BookmarkModelChanged(); + } + virtual void BookmarkNodeRemoved(BookmarkModel* model, + BookmarkNode* parent, + int index) { + BookmarkModelChanged(); + } + virtual void BookmarkNodeChanged(BookmarkModel* model, + BookmarkNode* node) { + BookmarkModelChanged(); + } + virtual void BookmarkNodeFavIconLoaded(BookmarkModel* model, + BookmarkNode* node) { + } + virtual void BookmarkNodeChildrenReordered(BookmarkModel* model, + BookmarkNode* node) { + BookmarkModelChanged(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(BaseBookmarkModelObserver); +}; + +#endif // CHROME_BROWSER_BOOKMARKS_BASE_BOOKMARK_MODEL_OBSERVER_H_ diff --git a/chrome/browser/bookmarks/bookmark_menu_controller.cc b/chrome/browser/bookmarks/bookmark_menu_controller.cc new file mode 100644 index 0000000..058a2f5 --- /dev/null +++ b/chrome/browser/bookmarks/bookmark_menu_controller.cc @@ -0,0 +1,232 @@ +// Copyright (c) 2009 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_menu_controller.h" + +#include "chrome/browser/bookmarks/bookmark_drag_data.h" +#include "chrome/browser/bookmarks/bookmark_utils.h" +#include "chrome/browser/metrics/user_metrics.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/tab_contents/page_navigator.h" +#include "chrome/browser/views/event_utils.h" +#include "chrome/common/os_exchange_data.h" +#include "chrome/common/page_transition_types.h" +#include "chrome/common/resource_bundle.h" +#include "grit/theme_resources.h" + +BookmarkMenuController::BookmarkMenuController(Browser* browser, + Profile* profile, + PageNavigator* navigator, + HWND hwnd, + BookmarkNode* node, + int start_child_index) + : browser_(browser), + profile_(profile), + page_navigator_(navigator), + hwnd_(hwnd), + node_(node), + observer_(NULL), + for_drop_(false) { + menu_.reset(new views::MenuItemView(this)); + int next_menu_id = 1; + menu_id_to_node_map_[menu_->GetCommand()] = node; + menu_->set_has_icons(true); + BuildMenu(node, start_child_index, menu_.get(), &next_menu_id); +} + +void BookmarkMenuController::RunMenuAt( + const gfx::Rect& bounds, + views::MenuItemView::AnchorPosition position, + bool for_drop) { + for_drop_ = for_drop; + profile_->GetBookmarkModel()->AddObserver(this); + if (for_drop) { + menu_->RunMenuForDropAt(hwnd_, bounds, position); + } else { + menu_->RunMenuAt(hwnd_, bounds, position, false); + delete this; + } +} + +void BookmarkMenuController::Cancel() { + menu_->Cancel(); +} + +bool BookmarkMenuController::IsTriggerableEvent(const views::MouseEvent& e) { + return event_utils::IsPossibleDispositionEvent(e); +} + +void BookmarkMenuController::ExecuteCommand(int id, int mouse_event_flags) { + DCHECK(page_navigator_); + DCHECK(menu_id_to_node_map_.find(id) != menu_id_to_node_map_.end()); + GURL url = menu_id_to_node_map_[id]->GetURL(); + page_navigator_->OpenURL( + url, GURL(), event_utils::DispositionFromEventFlags(mouse_event_flags), + PageTransition::AUTO_BOOKMARK); +} + +bool BookmarkMenuController::CanDrop(views::MenuItemView* menu, + const OSExchangeData& data) { + // Only accept drops of 1 node, which is the case for all data dragged from + // bookmark bar and menus. + + if (!drop_data_.Read(data) || drop_data_.elements.size() != 1) + return false; + + if (drop_data_.has_single_url()) + return true; + + BookmarkNode* drag_node = drop_data_.GetFirstNode(profile_); + if (!drag_node) { + // Dragging a group from another profile, always accept. + return true; + } + + // Drag originated from same profile and is not a URL. Only accept it if + // the dragged node is not a parent of the node menu represents. + BookmarkNode* drop_node = menu_id_to_node_map_[menu->GetCommand()]; + DCHECK(drop_node); + BookmarkNode* node = drop_node; + while (drop_node && drop_node != drag_node) + drop_node = drop_node->GetParent(); + return (drop_node == NULL); +} + +int BookmarkMenuController::GetDropOperation( + views::MenuItemView* item, + const views::DropTargetEvent& event, + DropPosition* position) { + // Should only get here if we have drop data. + DCHECK(drop_data_.is_valid()); + + BookmarkNode* node = menu_id_to_node_map_[item->GetCommand()]; + BookmarkNode* drop_parent = node->GetParent(); + int index_to_drop_at = drop_parent->IndexOfChild(node); + if (*position == DROP_AFTER) { + index_to_drop_at++; + } else if (*position == DROP_ON) { + drop_parent = node; + index_to_drop_at = node->GetChildCount(); + } + DCHECK(drop_parent); + return bookmark_utils::BookmarkDropOperation( + profile_, event, drop_data_, drop_parent, index_to_drop_at); +} + +int BookmarkMenuController::OnPerformDrop(views::MenuItemView* menu, + DropPosition position, + const views::DropTargetEvent& event) { + BookmarkNode* drop_node = menu_id_to_node_map_[menu->GetCommand()]; + DCHECK(drop_node); + BookmarkModel* model = profile_->GetBookmarkModel(); + DCHECK(model); + BookmarkNode* drop_parent = drop_node->GetParent(); + DCHECK(drop_parent); + int index_to_drop_at = drop_parent->IndexOfChild(drop_node); + if (position == DROP_AFTER) { + index_to_drop_at++; + } else if (position == DROP_ON) { + DCHECK(drop_node->is_folder()); + drop_parent = drop_node; + index_to_drop_at = drop_node->GetChildCount(); + } + + int result = bookmark_utils::PerformBookmarkDrop( + profile_, drop_data_, drop_parent, index_to_drop_at); + if (for_drop_) + delete this; + return result; +} + +bool BookmarkMenuController::ShowContextMenu(views::MenuItemView* source, + int id, + int x, + int y, + bool is_mouse_gesture) { + DCHECK(menu_id_to_node_map_.find(id) != menu_id_to_node_map_.end()); + std::vector<BookmarkNode*> nodes; + nodes.push_back(menu_id_to_node_map_[id]); + context_menu_.reset( + new BookmarkContextMenu(hwnd_, + profile_, + browser_, + page_navigator_, + nodes[0]->GetParent(), + nodes, + BookmarkContextMenu::BOOKMARK_BAR)); + context_menu_->RunMenuAt(x, y); + context_menu_.reset(NULL); + return true; +} + +void BookmarkMenuController::DropMenuClosed(views::MenuItemView* menu) { + delete this; +} + +bool BookmarkMenuController::CanDrag(views::MenuItemView* menu) { + return true; +} + +void BookmarkMenuController::WriteDragData(views::MenuItemView* sender, + OSExchangeData* data) { + DCHECK(sender && data); + + UserMetrics::RecordAction(L"BookmarkBar_DragFromFolder", profile_); + + BookmarkDragData drag_data(menu_id_to_node_map_[sender->GetCommand()]); + drag_data.Write(profile_, data); +} + +int BookmarkMenuController::GetDragOperations(views::MenuItemView* sender) { + return bookmark_utils::BookmarkDragOperation( + menu_id_to_node_map_[sender->GetCommand()]); +} + +void BookmarkMenuController::BookmarkModelChanged() { + menu_->Cancel(); +} + +void BookmarkMenuController::BookmarkNodeFavIconLoaded(BookmarkModel* model, + BookmarkNode* node) { + if (node_to_menu_id_map_.find(node) != node_to_menu_id_map_.end()) + menu_->SetIcon(node->GetFavIcon(), node_to_menu_id_map_[node]); +} + +void BookmarkMenuController::BuildMenu(BookmarkNode* parent, + int start_child_index, + views::MenuItemView* menu, + int* next_menu_id) { + DCHECK(!parent->GetChildCount() || + start_child_index < parent->GetChildCount()); + for (int i = start_child_index; i < parent->GetChildCount(); ++i) { + BookmarkNode* node = parent->GetChild(i); + int id = *next_menu_id; + + (*next_menu_id)++; + if (node->is_url()) { + SkBitmap icon = node->GetFavIcon(); + if (icon.width() == 0) { + icon = *ResourceBundle::GetSharedInstance(). + GetBitmapNamed(IDR_DEFAULT_FAVICON); + } + menu->AppendMenuItemWithIcon(id, node->GetTitle(), icon); + node_to_menu_id_map_[node] = id; + } else if (node->is_folder()) { + SkBitmap* folder_icon = ResourceBundle::GetSharedInstance(). + GetBitmapNamed(IDR_BOOKMARK_BAR_FOLDER); + views::MenuItemView* submenu = + menu->AppendSubMenuWithIcon(id, node->GetTitle(), *folder_icon); + BuildMenu(node, 0, submenu, next_menu_id); + } else { + NOTREACHED(); + } + menu_id_to_node_map_[id] = node; + } +} + +BookmarkMenuController::~BookmarkMenuController() { + profile_->GetBookmarkModel()->RemoveObserver(this); + if (observer_) + observer_->BookmarkMenuDeleted(this); +} diff --git a/chrome/browser/bookmarks/bookmark_menu_controller.h b/chrome/browser/bookmarks/bookmark_menu_controller.h new file mode 100644 index 0000000..27636a7 --- /dev/null +++ b/chrome/browser/bookmarks/bookmark_menu_controller.h @@ -0,0 +1,137 @@ +// Copyright (c) 2009 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_MENU_CONTROLLER_H_ +#define CHROME_BROWSER_BOOKMARKS_BOOKMARK_MENU_CONTROLLER_H_ + +#include <map> + +#include "chrome/browser/bookmarks/base_bookmark_model_observer.h" +#include "chrome/browser/bookmarks/bookmark_context_menu.h" +#include "chrome/browser/bookmarks/bookmark_drag_data.h" +#include "chrome/views/chrome_menu.h" + +class BookmarkContextMenu; +class BookmarkNode; +class Browser; +class OSExchangeData; +class PageNavigator; +class Profile; + +// BookmarkMenuController is responsible for showing a menu of bookmarks, +// each item in the menu represents a bookmark. +// BookmarkMenuController deletes itself as necessary, although the menu can +// be explicitly hidden by way of the Cancel method. +class BookmarkMenuController : public BaseBookmarkModelObserver, + public views::MenuDelegate { + public: + // The observer is notified prior to the menu being deleted. + class Observer { + public: + virtual void BookmarkMenuDeleted(BookmarkMenuController* controller) = 0; + }; + + // Creates a BookmarkMenuController showing the children of |node| starting + // at index |start_child_index|. + BookmarkMenuController(Browser* browser, + Profile* profile, + PageNavigator* page_navigator, + HWND hwnd, + BookmarkNode* node, + int start_child_index); + + // Shows the menu. + void RunMenuAt(const gfx::Rect& bounds, + views::MenuItemView::AnchorPosition position, + bool for_drop); + + // Hides the menu. + void Cancel(); + + // Returns the node the menu is showing for. + BookmarkNode* node() const { return node_; } + + // Returns the menu. + views::MenuItemView* menu() const { return menu_.get(); } + + // Returns the context menu, or NULL if the context menu isn't showing. + views::MenuItemView* context_menu() const { + return context_menu_.get() ? context_menu_->menu() : NULL; + } + + void set_observer(Observer* observer) { observer_ = observer; } + + // MenuDelegate methods. + virtual bool IsTriggerableEvent(const views::MouseEvent& e); + virtual void ExecuteCommand(int id, int mouse_event_flags); + virtual bool CanDrop(views::MenuItemView* menu, const OSExchangeData& data); + virtual int GetDropOperation(views::MenuItemView* item, + const views::DropTargetEvent& event, + DropPosition* position); + virtual int OnPerformDrop(views::MenuItemView* menu, + DropPosition position, + const views::DropTargetEvent& event); + virtual bool ShowContextMenu(views::MenuItemView* source, + int id, + int x, + int y, + bool is_mouse_gesture); + virtual void DropMenuClosed(views::MenuItemView* menu); + virtual bool CanDrag(views::MenuItemView* menu); + virtual void WriteDragData(views::MenuItemView* sender, OSExchangeData* data); + virtual int GetDragOperations(views::MenuItemView* sender); + + virtual void BookmarkModelChanged(); + virtual void BookmarkNodeFavIconLoaded(BookmarkModel* model, + BookmarkNode* node); + + private: + // BookmarkMenuController deletes itself as necessary. + ~BookmarkMenuController(); + + // Creates an entry in menu for each child node of |parent| starting at + // |start_child_index|. + void BuildMenu(BookmarkNode* parent, + int start_child_index, + views::MenuItemView* menu, + int* next_menu_id); + + Browser* browser_; + + Profile* profile_; + + PageNavigator* page_navigator_; + + // Parent of menus. + HWND hwnd_; + + // The node we're showing the contents of. + BookmarkNode* node_; + + // Maps from menu id to BookmarkNode. + std::map<int, BookmarkNode*> menu_id_to_node_map_; + + // Mapping from node to menu id. This only contains entries for nodes of type + // URL. + std::map<BookmarkNode*, int> node_to_menu_id_map_; + + // The menu. + scoped_ptr<views::MenuItemView> menu_; + + // Data for the drop. + BookmarkDragData drop_data_; + + // Used when a context menu is shown. + scoped_ptr<BookmarkContextMenu> context_menu_; + + // The observer, may be null. + Observer* observer_; + + // Is the menu being shown for a drop? + bool for_drop_; + + DISALLOW_COPY_AND_ASSIGN(BookmarkMenuController); +}; + +#endif // CHROME_BROWSER_BOOKMARKS_BOOKMARK_MENU_CONTROLLER_H_ diff --git a/chrome/browser/bookmarks/bookmark_utils.cc b/chrome/browser/bookmarks/bookmark_utils.cc index 2d33794..c9214b4 100644 --- a/chrome/browser/bookmarks/bookmark_utils.cc +++ b/chrome/browser/bookmarks/bookmark_utils.cc @@ -201,6 +201,63 @@ int PreferredDropOperation(int source_operations, int operations) { return DragDropTypes::DRAG_NONE; } +int BookmarkDragOperation(BookmarkNode* node) { + if (node->is_url()) { + return DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE | + DragDropTypes::DRAG_LINK; + } + return DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE; +} + +int BookmarkDropOperation(Profile* profile, + const views::DropTargetEvent& event, + const BookmarkDragData& data, + BookmarkNode* parent, + int index) { + if (data.IsFromProfile(profile) && data.size() > 1) + // Currently only accept one dragged node at a time. + return DragDropTypes::DRAG_NONE; + + if (!bookmark_utils::IsValidDropLocation(profile, data, parent, index)) + return DragDropTypes::DRAG_NONE; + + if (data.GetFirstNode(profile)) { + // User is dragging from this profile: move. + return DragDropTypes::DRAG_MOVE; + } + // User is dragging from another app, copy. + return PreferredDropOperation(event.GetSourceOperations(), + DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK); +} + +int PerformBookmarkDrop(Profile* profile, + const BookmarkDragData& data, + BookmarkNode* parent_node, + int index) { + BookmarkNode* dragged_node = data.GetFirstNode(profile); + BookmarkModel* model = profile->GetBookmarkModel(); + if (dragged_node) { + // Drag from same profile, do a move. + model->Move(dragged_node, parent_node, index); + return DragDropTypes::DRAG_MOVE; + } else if (data.has_single_url()) { + // New URL, add it at the specified location. + std::wstring title = data.elements[0].title; + if (title.empty()) { + // No title, use the host. + title = UTF8ToWide(data.elements[0].url.host()); + if (title.empty()) + title = l10n_util::GetString(IDS_BOOMARK_BAR_UNKNOWN_DRAG_TITLE); + } + model->AddURL(parent_node, index, title, data.elements[0].url); + return DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK; + } else { + // Dropping a group from different profile. Always accept. + bookmark_utils::CloneDragData(model, data.elements, parent_node, index); + return DragDropTypes::DRAG_COPY; + } +} + bool IsValidDropLocation(Profile* profile, const BookmarkDragData& data, BookmarkNode* drop_parent, diff --git a/chrome/browser/bookmarks/bookmark_utils.h b/chrome/browser/bookmarks/bookmark_utils.h index 9419731..26e60ef 100644 --- a/chrome/browser/bookmarks/bookmark_utils.h +++ b/chrome/browser/bookmarks/bookmark_utils.h @@ -17,6 +17,10 @@ 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 { @@ -26,6 +30,25 @@ namespace bookmark_utils { // COPY, LINK then MOVE. int PreferredDropOperation(int source_operations, int operations); +// Returns the drag operations for the specified node. +int BookmarkDragOperation(BookmarkNode* node); + +// Returns the preferred drop operation on a bookmark menu/bar. +// |parent| is the parent node the drop is to occur on and |index| the index the +// drop is over. +int BookmarkDropOperation(Profile* profile, + const views::DropTargetEvent& event, + const BookmarkDragData& data, + BookmarkNode* parent, + int index); + +// Performs a drop of bookmark data onto |parent_node| at |index|. Returns the +// type of drop the resulted. +int PerformBookmarkDrop(Profile* profile, + const BookmarkDragData& data, + BookmarkNode* parent_node, + int index); + // 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 // a drop from the same profile is only allowed if none of the nodes in diff --git a/chrome/browser/browser.vcproj b/chrome/browser/browser.vcproj index da8341a..e5c0614 100644 --- a/chrome/browser/browser.vcproj +++ b/chrome/browser/browser.vcproj @@ -602,6 +602,14 @@ > </File> <File + RelativePath=".\bookmarks\bookmark_menu_controller.cc" + > + </File> + <File + RelativePath=".\bookmarks\bookmark_menu_controller.h" + > + </File> + <File RelativePath=".\bookmarks\bookmark_model.cc" > </File> diff --git a/chrome/browser/views/bookmark_bar_view.cc b/chrome/browser/views/bookmark_bar_view.cc index 4705051..dbfb38f 100644 --- a/chrome/browser/views/bookmark_bar_view.cc +++ b/chrome/browser/views/bookmark_bar_view.cc @@ -11,26 +11,17 @@ #include "chrome/browser/bookmarks/bookmark_context_menu.h" #include "chrome/browser/bookmarks/bookmark_utils.h" #include "chrome/browser/browser.h" -#include "chrome/browser/browser_list.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/browser_window.h" #include "chrome/browser/drag_utils.h" -#include "chrome/browser/download/download_util.h" #include "chrome/browser/extensions/extension.h" #include "chrome/browser/extensions/extension_view.h" #include "chrome/browser/extensions/extensions_service.h" -#include "chrome/browser/history/history.h" #include "chrome/browser/metrics/user_metrics.h" #include "chrome/browser/profile.h" #include "chrome/browser/tab_contents/page_navigator.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/view_ids.h" -#include "chrome/browser/views/bookmark_editor_view.h" #include "chrome/browser/views/event_utils.h" -#include "chrome/browser/views/frame/browser_view.h" -#include "chrome/browser/views/input_window.h" #include "chrome/common/gfx/chrome_canvas.h" -#include "chrome/common/gfx/favicon_size.h" #include "chrome/common/gfx/text_elider.h" #include "chrome/common/l10n_util.h" #include "chrome/common/notification_service.h" @@ -83,22 +74,12 @@ static const int kButtonPadding = 0; // Command ids used in the menu allowing the user to choose when we're visible. static const int kAlwaysShowCommandID = 1; -// Whether the pref height has been calculated. -static bool calcedSize = false; - -// The preferred height is the height needed for one button. As it is a constant -// it is calculated once. -static int prefButtonHeight = 0; - // Icon to display when one isn't found for the page. static SkBitmap* kDefaultFavIcon = NULL; // Icon used for folders. static SkBitmap* kFolderIcon = NULL; -// Icon used for most other menu. -static SkBitmap* kBookmarkedOtherIcon = NULL; - // Background color. static const SkColor kBackgroundColor = SkColorSetRGB(237, 244, 252); @@ -203,15 +184,6 @@ static std::wstring CreateToolTipForURLAndTitle(const gfx::Point& screen_loc, return result; } -// Returns the drag operations for the specified node. -static int GetDragOperationsForNode(BookmarkNode* node) { - if (node->GetType() == history::StarredEntry::URL) { - return DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE | - DragDropTypes::DRAG_LINK; - } - return DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE; -} - // BookmarkButton ------------------------------------------------------------- // Buttons used for the bookmarks on the bookmark bar. @@ -386,255 +358,8 @@ struct DropInfo { BookmarkDragData data; }; -// MenuRunner ----------------------------------------------------------------- - -// MenuRunner manages creation and showing of a menu containing BookmarkNodes. -// MenuRunner is used to show the contents of bookmark folders on the -// bookmark bar, other folder, or overflow bookmarks. -// -class MenuRunner : public views::MenuDelegate, - public BookmarkBarView::ModelChangedListener { - public: - // start_child_index is the index of the first child in node to add to the - // menu. - MenuRunner(BookmarkBarView* view, BookmarkNode* node, int start_child_index) - : view_(view), - node_(node), - menu_(this) { - int next_menu_id = 1; - menu_id_to_node_map_[menu_.GetCommand()] = node; - menu_.set_has_icons(true); - BuildMenu(node, start_child_index, &menu_, &next_menu_id); - } - - // Returns the node the menu is being run for. - BookmarkNode* GetNode() { - return node_; - } - - void RunMenuAt(HWND hwnd, - const gfx::Rect& bounds, - MenuItemView::AnchorPosition position, - bool for_drop) { - view_->SetModelChangedListener(this); - if (for_drop) - menu_.RunMenuForDropAt(hwnd, bounds, position); - else - menu_.RunMenuAt(hwnd, bounds, position, false); - view_->ClearModelChangedListenerIfEquals(this); - } - - // Notification that the favicon has finished loading. Reset the icon - // of the menu item. - void FavIconLoaded(BookmarkNode* node) { - if (node_to_menu_id_map_.find(node) != - node_to_menu_id_map_.end()) { - menu_.SetIcon(node->GetFavIcon(), node_to_menu_id_map_[node]); - } - } - - virtual void ModelChanged() { - menu_.Cancel(); - } - - MenuItemView* menu() { return &menu_; } - - MenuItemView* context_menu() { - return context_menu_.get() ? context_menu_->menu() : NULL; - } - - private: - // Creates an entry in menu for each child node of parent starting at - // start_child_index, recursively invoking this for any star groups. - void BuildMenu(BookmarkNode* parent, - int start_child_index, - MenuItemView* menu, - int* next_menu_id) { - DCHECK(!parent->GetChildCount() || - - start_child_index < parent->GetChildCount()); - for (int i = start_child_index; i < parent->GetChildCount(); ++i) { - BookmarkNode* node = parent->GetChild(i); - int id = *next_menu_id; - - (*next_menu_id)++; - if (node->GetType() == history::StarredEntry::URL) { - SkBitmap icon = node->GetFavIcon(); - if (icon.width() == 0) - icon = *kDefaultFavIcon; - menu->AppendMenuItemWithIcon(id, node->GetTitle(), icon); - node_to_menu_id_map_[node] = id; - } else { - SkBitmap* folder_icon = - ResourceBundle::GetSharedInstance().GetBitmapNamed( - IDR_BOOKMARK_BAR_FOLDER); - MenuItemView* submenu = menu->AppendSubMenuWithIcon( - id, node->GetTitle(), *folder_icon); - BuildMenu(node, 0, submenu, next_menu_id); - } - menu_id_to_node_map_[id] = node; - } - } - - // ViewMenuDelegate method. Overridden to forward to the PageNavigator so - // that we accept any events that may trigger opening a url. - virtual bool IsTriggerableEvent(const views::MouseEvent& e) { - return event_utils::IsPossibleDispositionEvent(e); - } - - // Invoked when a menu item is selected. Uses the PageNavigator set on - // the BookmarkBarView to open the URL. - virtual void ExecuteCommand(int id, int mouse_event_flags) { - DCHECK(view_->GetPageNavigator()); - GURL url; - DCHECK(menu_id_to_node_map_.find(id) != menu_id_to_node_map_.end()); - url = menu_id_to_node_map_[id]->GetURL(); - view_->GetPageNavigator()->OpenURL( - url, GURL(), event_utils::DispositionFromEventFlags(mouse_event_flags), - PageTransition::AUTO_BOOKMARK); - } - - virtual bool CanDrop(MenuItemView* menu, const OSExchangeData& data) { - // Only accept drops of 1 node, which is the case for all data dragged from - // bookmark bar and menus. - if (!drop_data_.Read(data) || drop_data_.elements.size() != 1) - return false; - - if (drop_data_.has_single_url()) - return true; - - BookmarkNode* drag_node = drop_data_.GetFirstNode(view_->GetProfile()); - if (!drag_node) { - // Dragging a group from another profile, always accept. - return true; - } - // Drag originated from same profile and is not a URL. Only accept it if - // the dragged node is not a parent of the node menu represents. - BookmarkNode* drop_node = menu_id_to_node_map_[menu->GetCommand()]; - DCHECK(drop_node); - BookmarkNode* node = drop_node; - while (drop_node && drop_node != drag_node) - drop_node = drop_node->GetParent(); - return (drop_node == NULL); - } - - virtual int GetDropOperation(MenuItemView* item, - const views::DropTargetEvent& event, - DropPosition* position) { - DCHECK(drop_data_.is_valid()); - BookmarkNode* node = menu_id_to_node_map_[item->GetCommand()]; - BookmarkNode* drop_parent = node->GetParent(); - int index_to_drop_at = drop_parent->IndexOfChild(node); - if (*position == DROP_AFTER) { - index_to_drop_at++; - } else if (*position == DROP_ON) { - drop_parent = node; - index_to_drop_at = node->GetChildCount(); - } - DCHECK(drop_parent); - return view_->CalculateDropOperation(event, drop_data_, drop_parent, - index_to_drop_at); - } - - virtual int OnPerformDrop(MenuItemView* menu, - DropPosition position, - const DropTargetEvent& event) { - BookmarkNode* drop_node = menu_id_to_node_map_[menu->GetCommand()]; - DCHECK(drop_node); - BookmarkModel* model = view_->GetModel(); - DCHECK(model); - BookmarkNode* drop_parent = drop_node->GetParent(); - DCHECK(drop_parent); - int index_to_drop_at = drop_parent->IndexOfChild(drop_node); - if (position == DROP_AFTER) { - index_to_drop_at++; - } else if (position == DROP_ON) { - DCHECK(drop_node->GetType() != history::StarredEntry::URL); - drop_parent = drop_node; - index_to_drop_at = drop_node->GetChildCount(); - } - - const int result = view_->PerformDropImpl(drop_data_, drop_parent, - index_to_drop_at); - if (view_->drop_menu_runner_.get() == this) - view_->drop_menu_runner_.reset(); - // WARNING: we've been deleted! - return result; - } - - virtual bool ShowContextMenu(MenuItemView* source, - int id, - int x, - int y, - bool is_mouse_gesture) { - DCHECK(menu_id_to_node_map_.find(id) != menu_id_to_node_map_.end()); - std::vector<BookmarkNode*> nodes; - nodes.push_back(menu_id_to_node_map_[id]); - context_menu_.reset( - new BookmarkContextMenu(view_->GetWidget()->GetHWND(), - view_->GetProfile(), - view_->browser(), - view_->GetPageNavigator(), - nodes[0]->GetParent(), - nodes, - BookmarkContextMenu::BOOKMARK_BAR)); - context_menu_->RunMenuAt(x, y); - context_menu_.reset(NULL); - return true; - } - - virtual void DropMenuClosed(MenuItemView* menu) { - if (view_->drop_menu_runner_.get() == this) - view_->drop_menu_runner_.reset(); - } - - virtual bool CanDrag(MenuItemView* menu) { - DCHECK(menu); - return true; - } - - virtual void WriteDragData(MenuItemView* sender, OSExchangeData* data) { - DCHECK(sender && data); - - UserMetrics::RecordAction(L"BookmarkBar_DragFromFolder", - view_->GetProfile()); - - view_->WriteDragData(menu_id_to_node_map_[sender->GetCommand()], data); - } - - virtual int GetDragOperations(MenuItemView* sender) { - return GetDragOperationsForNode( - menu_id_to_node_map_[sender->GetCommand()]); - } - - // The node we're showing the contents of. - BookmarkNode* node_; - - // The view that created us. - BookmarkBarView* view_; - - // The menu. - MenuItemView menu_; - - // Mapping from menu id to the BookmarkNode. - std::map<int, BookmarkNode*> menu_id_to_node_map_; - - // Mapping from node to menu id. This only contains entries for nodes of type - // URL. - std::map<BookmarkNode*, int> node_to_menu_id_map_; - - // Data for the drop. - BookmarkDragData drop_data_; - - scoped_ptr<BookmarkContextMenu> context_menu_; - - DISALLOW_COPY_AND_ASSIGN(MenuRunner); -}; - // ButtonSeparatorView -------------------------------------------------------- -// TODO(sky/glen): this is temporary, need to decide on what this should -// look like. class ButtonSeparatorView : public views::View { public: ButtonSeparatorView() {} @@ -717,6 +442,8 @@ BookmarkBarView::BookmarkBarView(Profile* profile, Browser* browser) browser_(browser), page_navigator_(NULL), model_(NULL), + bookmark_menu_(NULL), + bookmark_drop_menu_(NULL), other_bookmarked_button_(NULL), model_changed_listener_(NULL), show_folder_drop_menu_task_(NULL), @@ -729,7 +456,6 @@ BookmarkBarView::BookmarkBarView(Profile* profile, Browser* browser) Init(); SetProfile(profile); - if (IsAlwaysShown()) { size_animation_->Reset(1); } else { @@ -794,12 +520,6 @@ void BookmarkBarView::SetPageNavigator(PageNavigator* navigator) { } gfx::Size BookmarkBarView::GetPreferredSize() { - if (!prefButtonHeight) { - views::TextButton text_button(L"X"); - gfx::Size text_button_pref = text_button.GetMinimumSize(); - prefButtonHeight = static_cast<int>(text_button_pref.height()); - } - gfx::Size prefsize; if (OnNewTabPage()) { prefsize.set_height(kBarHeight + static_cast<int>(static_cast<double> @@ -1089,7 +809,8 @@ int BookmarkBarView::OnDragUpdated(const DropTargetEvent& event) { drop_info_->is_over_other = is_over_other; if (drop_info_->is_menu_showing) { - drop_menu_runner_.reset(); + if (bookmark_drop_menu_) + bookmark_drop_menu_->Cancel(); drop_info_->is_menu_showing = false; } @@ -1125,7 +846,8 @@ void BookmarkBarView::OnDragExited() { int BookmarkBarView::OnPerformDrop(const DropTargetEvent& event) { StopShowFolderDropMenuTimer(); - drop_menu_runner_.reset(); + if (bookmark_drop_menu_) + bookmark_drop_menu_->Cancel(); if (!drop_info_.get() || !drop_info_->drag_operation) return DragDropTypes::DRAG_NONE; @@ -1154,7 +876,7 @@ int BookmarkBarView::OnPerformDrop(const DropTargetEvent& event) { } else { parent_node = root; } - return PerformDropImpl(data, parent_node, index); + return bookmark_utils::PerformBookmarkDrop(profile_, data, parent_node, index); } void BookmarkBarView::OnFullscreenToggled(bool fullscreen) { @@ -1192,29 +914,33 @@ void BookmarkBarView::AnimationEnded(const Animation* animation) { SchedulePaint(); } +void BookmarkBarView::BookmarkMenuDeleted(BookmarkMenuController* controller) { + if (controller == bookmark_menu_) + bookmark_menu_ = NULL; + else if (controller == bookmark_drop_menu_) + bookmark_drop_menu_ = NULL; +} + views::TextButton* BookmarkBarView::GetBookmarkButton(int index) { DCHECK(index >= 0 && index < GetBookmarkButtonCount()); return static_cast<views::TextButton*>(GetChildViewAt(index)); } views::MenuItemView* BookmarkBarView::GetMenu() { - return menu_runner_.get() ? menu_runner_->menu() : NULL; + return bookmark_menu_ ? bookmark_menu_->menu() : NULL; } views::MenuItemView* BookmarkBarView::GetContextMenu() { - return menu_runner_.get() ? menu_runner_->context_menu() : NULL; + return bookmark_menu_ ? bookmark_menu_->context_menu() : NULL; } views::MenuItemView* BookmarkBarView::GetDropMenu() { - return drop_menu_runner_.get() ? drop_menu_runner_->menu() : NULL; + return bookmark_drop_menu_ ? bookmark_drop_menu_->menu() : NULL; } void BookmarkBarView::Init() { ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - if (!calcedSize) - calcedSize = false; - if (!kDefaultFavIcon) kDefaultFavIcon = rb.GetBitmapNamed(IDR_DEFAULT_FAVICON); @@ -1409,10 +1135,6 @@ void BookmarkBarView::BookmarkNodeChildrenReordered(BookmarkModel* model, void BookmarkBarView::BookmarkNodeFavIconLoaded(BookmarkModel* model, BookmarkNode* node) { - if (menu_runner_.get()) - menu_runner_->FavIconLoaded(node); - if (drop_menu_runner_.get()) - drop_menu_runner_->FavIconLoaded(node); BookmarkNodeChangedImpl(model, node); } @@ -1447,7 +1169,7 @@ void BookmarkBarView::WriteDragData(BookmarkNode* node, int BookmarkBarView::GetDragOperations(View* sender, int x, int y) { for (int i = 0; i < GetBookmarkButtonCount(); ++i) { if (sender == GetBookmarkButton(i)) { - return GetDragOperationsForNode( + return bookmark_utils::BookmarkDragOperation( model_->GetBookmarkBarNode()->GetChild(i)); } } @@ -1501,13 +1223,13 @@ void BookmarkBarView::RunMenu(views::View* view, } gfx::Point screen_loc(x, 0); View::ConvertPointToScreen(this, &screen_loc); - menu_runner_.reset(new MenuRunner(this, node, start_index)); - HWND parent_hwnd = GetWidget()->GetHWND(); - menu_runner_->RunMenuAt(parent_hwnd, - gfx::Rect(screen_loc.x(), screen_loc.y(), - view->width(), bar_height), - anchor_point, - false); + bookmark_menu_ = new BookmarkMenuController( + browser_, profile_, page_navigator_, GetWidget()->GetHWND(), + node, start_index); + bookmark_menu_->set_observer(this); + bookmark_menu_->RunMenuAt(gfx::Rect(screen_loc.x(), screen_loc.y(), + view->width(), bar_height), + anchor_point, false); } void BookmarkBarView::ButtonPressed(views::BaseButton* sender) { @@ -1571,7 +1293,7 @@ void BookmarkBarView::ShowContextMenu(View* source, } views::View* BookmarkBarView::CreateBookmarkButton(BookmarkNode* node) { - if (node->GetType() == history::StarredEntry::URL) { + if (node->is_url()) { BookmarkButton* button = new BookmarkButton(node->GetURL(), node->GetTitle(), GetProfile()); @@ -1594,7 +1316,7 @@ void BookmarkBarView::ConfigureButton(BookmarkNode* node, button->ClearMaxTextSize(); button->SetContextMenuController(this); button->SetDragController(this); - if (node->GetType() == history::StarredEntry::URL) { + if (node->is_url()) { if (node->GetFavIcon().width() != 0) button->SetIcon(node->GetFavIcon()); else @@ -1682,9 +1404,12 @@ void BookmarkBarView::NotifyModelChanged() { } void BookmarkBarView::ShowDropFolderForNode(BookmarkNode* node) { - if (drop_menu_runner_.get() && drop_menu_runner_->GetNode() == node) { - // Already showing for the specified node. - return; + if (bookmark_drop_menu_) { + if (bookmark_drop_menu_->node() == node) { + // Already showing for the specified node. + return; + } + bookmark_drop_menu_->Cancel(); } int start_index = 0; @@ -1723,11 +1448,13 @@ void BookmarkBarView::ShowDropFolderForNode(BookmarkNode* node) { } drop_info_->is_menu_showing = true; - drop_menu_runner_.reset(new MenuRunner(this, node, start_index)); + bookmark_drop_menu_ = new BookmarkMenuController( + browser_, profile_, page_navigator_, GetWidget()->GetHWND(), + node, start_index); + bookmark_drop_menu_->set_observer(this); gfx::Point screen_loc; View::ConvertPointToScreen(view_to_position_menu_from, &screen_loc); - drop_menu_runner_->RunMenuAt( - GetWidget()->GetHWND(), + bookmark_drop_menu_->RunMenuAt( gfx::Rect(screen_loc.x(), screen_loc.y(), view_to_position_menu_from->width(), view_to_position_menu_from->height()), @@ -1811,7 +1538,7 @@ int BookmarkBarView::CalculateDropOperation(const DropTargetEvent& event, if (button_x < button_w) { found = true; BookmarkNode* node = model_->GetBookmarkBarNode()->GetChild(i); - if (node->GetType() != history::StarredEntry::URL) { + if (node->is_folder()) { if (button_x <= views::kDropBetweenPixels) { *index = i; } else if (button_x < button_w - views::kDropBetweenPixels) { @@ -1859,7 +1586,8 @@ int BookmarkBarView::CalculateDropOperation(const DropTargetEvent& event, *is_over_other ? model_->other_node() : model_->GetBookmarkBarNode()->GetChild(*index); int operation = - CalculateDropOperation(event, data, parent, parent->GetChildCount()); + bookmark_utils::BookmarkDropOperation(profile_,event, data, parent, + parent->GetChildCount()); if (!operation && !data.has_single_url() && data.GetFirstNode(profile_) == parent) { // Don't open a menu if the node being dragged is the the menu to @@ -1867,58 +1595,10 @@ int BookmarkBarView::CalculateDropOperation(const DropTargetEvent& event, *drop_on = false; } return operation; - } else { - return CalculateDropOperation(event, data, model_->GetBookmarkBarNode(), - *index); - } -} - -int BookmarkBarView::CalculateDropOperation(const DropTargetEvent& event, - const BookmarkDragData& data, - BookmarkNode* parent, - int index) { - if (data.IsFromProfile(profile_) && data.size() > 1) - // Currently only accept one dragged node at a time. - return DragDropTypes::DRAG_NONE; - - if (!bookmark_utils::IsValidDropLocation(profile_, data, parent, index)) - return DragDropTypes::DRAG_NONE; - - if (data.GetFirstNode(profile_)) { - // User is dragging from this profile: move. - return DragDropTypes::DRAG_MOVE; - } else { - // User is dragging from another app, copy. - return bookmark_utils::PreferredDropOperation( - event.GetSourceOperations(), - DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK); - } -} - -int BookmarkBarView::PerformDropImpl(const BookmarkDragData& data, - BookmarkNode* parent_node, - int index) { - BookmarkNode* dragged_node = data.GetFirstNode(profile_); - if (dragged_node) { - // Drag from same profile, do a move. - model_->Move(dragged_node, parent_node, index); - return DragDropTypes::DRAG_MOVE; - } else if (data.has_single_url()) { - // New URL, add it at the specified location. - std::wstring title = data.elements[0].title; - if (title.empty()) { - // No title, use the host. - title = UTF8ToWide(data.elements[0].url.host()); - if (title.empty()) - title = l10n_util::GetString(IDS_BOOMARK_BAR_UNKNOWN_DRAG_TITLE); - } - model_->AddURL(parent_node, index, title, data.elements[0].url); - return DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_LINK; - } else { - // Dropping a group from different profile. Always accept. - bookmark_utils::CloneDragData(model_, data.elements, parent_node, index); - return DragDropTypes::DRAG_COPY; } + return bookmark_utils::BookmarkDropOperation(profile_, event, data, + model_->GetBookmarkBarNode(), + *index); } int BookmarkBarView::GetFirstHiddenNodeIndex() { diff --git a/chrome/browser/views/bookmark_bar_view.h b/chrome/browser/views/bookmark_bar_view.h index 5982fbf..8b42251 100644 --- a/chrome/browser/views/bookmark_bar_view.h +++ b/chrome/browser/views/bookmark_bar_view.h @@ -6,6 +6,7 @@ #define CHROME_BROWSER_VIEWS_BOOKMARK_BAR_VIEW_H_ #include "chrome/browser/bookmarks/bookmark_drag_data.h" +#include "chrome/browser/bookmarks/bookmark_menu_controller.h" #include "chrome/browser/bookmarks/bookmark_model.h" #include "chrome/browser/extensions/extensions_service.h" #include "chrome/common/slide_animation.h" @@ -44,8 +45,8 @@ class BookmarkBarView : public views::View, public NotificationObserver, public views::ContextMenuController, public views::DragController, - public AnimationDelegate { - friend class MenuRunner; + public AnimationDelegate, + public BookmarkMenuController::Observer { friend class ShowFolderMenuTask; public: @@ -153,6 +154,9 @@ class BookmarkBarView : public views::View, void AnimationProgressed(const Animation* animation); void AnimationEnded(const Animation* animation); + // BookmarkMenuController::Observer + virtual void BookmarkMenuDeleted(BookmarkMenuController* controller); + // Returns the button at the specified index. views::TextButton* GetBookmarkButton(int index); @@ -359,19 +363,6 @@ class BookmarkBarView : public views::View, bool* is_over_overflow, bool* is_over_other); - // Invokes CanDropAt to determine if this is a valid location for the data, - // then returns the appropriate drag operation based on the data. - int CalculateDropOperation(const views::DropTargetEvent& event, - const BookmarkDragData& data, - BookmarkNode* parent, - int index); - - // Performs a drop of the specified data at the specified location. Returns - // the result. - int PerformDropImpl(const BookmarkDragData& data, - BookmarkNode* parent_node, - int index); - // Returns the index of the first hidden bookmark button. If all buttons are // visible, this returns GetBookmarkButtonCount(). int GetFirstHiddenNodeIndex(); @@ -399,14 +390,14 @@ class BookmarkBarView : public views::View, // shown. This is owned by the Profile. BookmarkModel* model_; - // Used to manage showing a Menu: either for the most recently bookmarked + // Used to manage showing a Menu, either for the most recently bookmarked // entries, or for the a starred group. - scoped_ptr<MenuRunner> menu_runner_; + BookmarkMenuController* bookmark_menu_; // Used when showing a menu for drag and drop. That is, if the user drags - // over a group this becomes non-null and is the MenuRunner used to manage - // the menu showing the contents of the node. - scoped_ptr<MenuRunner> drop_menu_runner_; + // over a group this becomes non-null and manages the menu showing the + // contents of the node. + BookmarkMenuController* bookmark_drop_menu_; // Shows the other bookmark entries. views::MenuButton* other_bookmarked_button_; diff --git a/chrome/views/chrome_menu.cc b/chrome/views/chrome_menu.cc index 6c038a5..ef33e6a 100644 --- a/chrome/views/chrome_menu.cc +++ b/chrome/views/chrome_menu.cc @@ -794,6 +794,7 @@ SubmenuView::SubmenuView(MenuItemView* parent) : parent_menu_item_(parent), host_(NULL), drop_item_(NULL), + drop_position_(MenuDelegate::DROP_NONE), scroll_view_container_(NULL) { DCHECK(parent); // We'll delete ourselves, otherwise the ScrollView would delete us on close. |