diff options
author | finnur@chromium.org <finnur@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-03 01:17:26 +0000 |
---|---|---|
committer | finnur@chromium.org <finnur@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-03 01:17:26 +0000 |
commit | 44ec9b3b965335d661a144e11894da3cea999bf3 (patch) | |
tree | 549ce1740dda62e2014a75a7f3a6cff430dde45e /chrome | |
parent | 993e6ea820a8b71c8f7767822de3b66bd2bb3c6f (diff) | |
download | chromium_src-44ec9b3b965335d661a144e11894da3cea999bf3.zip chromium_src-44ec9b3b965335d661a144e11894da3cea999bf3.tar.gz chromium_src-44ec9b3b965335d661a144e11894da3cea999bf3.tar.bz2 |
Support reordering of Browser Actions within the container. Currently does not support dragging to/from the chevron menu.
Also fixed two bugs in the same code:
- the container would be 0 width if a value for it hasn't been saved (part of bug 32101).
- the default icon was not used when a tab specific icon was not found (bug 34317).
BUG=http://crbug.com/26990, http://crbug.com/32101, http://crbug.com/34317
TEST=In both LTR and RTL locale, try reordering the browser actions and make sure to test dragging to the ends with and without a chevron visible. Install Send to Gmail extension and make sure it has an icon while in the overflow menu.
Review URL: http://codereview.chromium.org/549224
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@37922 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/bookmarks/bookmark_drag_data.cc | 24 | ||||
-rw-r--r-- | chrome/browser/bookmarks/bookmark_drag_data.h | 9 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_toolbar_model.h | 6 | ||||
-rw-r--r-- | chrome/browser/views/browser_actions_container.cc | 210 | ||||
-rw-r--r-- | chrome/browser/views/browser_actions_container.h | 43 | ||||
-rw-r--r-- | chrome/browser/views/extensions/browser_action_drag_data.cc | 93 | ||||
-rw-r--r-- | chrome/browser/views/extensions/browser_action_drag_data.h | 62 | ||||
-rw-r--r-- | chrome/browser/views/extensions/browser_action_drag_data_unittest.cc | 54 | ||||
-rw-r--r-- | chrome/browser/views/extensions/browser_action_overflow_menu_controller.cc | 6 | ||||
-rwxr-xr-x | chrome/chrome_browser.gypi | 4 | ||||
-rwxr-xr-x | chrome/chrome_tests.gypi | 2 |
11 files changed, 465 insertions, 48 deletions
diff --git a/chrome/browser/bookmarks/bookmark_drag_data.cc b/chrome/browser/bookmarks/bookmark_drag_data.cc index a22f60c..e1897b2 100644 --- a/chrome/browser/bookmarks/bookmark_drag_data.cc +++ b/chrome/browser/bookmarks/bookmark_drag_data.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -190,16 +190,8 @@ bool BookmarkDragData::Read(const OSExchangeData& data) { #endif void BookmarkDragData::WriteToPickle(Profile* profile, Pickle* pickle) const { -#if defined(WCHAR_T_IS_UTF16) - pickle->WriteWString( - profile ? profile->GetPath().ToWStringHack() : std::wstring()); -#elif defined(WCHAR_T_IS_UTF32) - pickle->WriteString( - profile ? profile->GetPath().value() : std::string()); -#else - NOTIMPLEMENTED() << "Impossible encoding situation!"; -#endif - + FilePath path = profile ? profile->GetPath() : FilePath(); + FilePath::WriteStringTypeToPickle(pickle, path.value()); pickle->WriteSize(elements.size()); for (size_t i = 0; i < elements.size(); ++i) @@ -209,14 +201,8 @@ void BookmarkDragData::WriteToPickle(Profile* profile, Pickle* pickle) const { bool BookmarkDragData::ReadFromPickle(Pickle* pickle) { void* data_iterator = NULL; size_t element_count; -#if defined(WCHAR_T_IS_UTF16) - if (pickle->ReadWString(&data_iterator, &profile_path_) && -#elif defined(WCHAR_T_IS_UTF32) - if (pickle->ReadString(&data_iterator, &profile_path_) && -#else - NOTIMPLEMENTED() << "Impossible encoding situation!"; - if (false && -#endif + if (FilePath::ReadStringTypeFromPickle(pickle, &data_iterator, + &profile_path_) && pickle->ReadSize(&data_iterator, &element_count)) { std::vector<Element> tmp_elements; tmp_elements.resize(element_count); diff --git a/chrome/browser/bookmarks/bookmark_drag_data.h b/chrome/browser/bookmarks/bookmark_drag_data.h index 2078bfa..32bf60d 100644 --- a/chrome/browser/bookmarks/bookmark_drag_data.h +++ b/chrome/browser/bookmarks/bookmark_drag_data.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -8,6 +8,7 @@ #include <string> #include <vector> +#include "base/file_path.h" #include "base/string16.h" #include "googleurl/src/gurl.h" @@ -141,11 +142,7 @@ struct BookmarkDragData { private: // Path of the profile we originated from. -#if defined(WCHAR_T_IS_UTF16) - std::wstring profile_path_; -#elif defined(WCHAR_T_IS_UTF32) - std::string profile_path_; -#endif + FilePath::StringType profile_path_; }; #endif // CHROME_BROWSER_BOOKMARKS_BOOKMARK_DRAG_DATA_H_ diff --git a/chrome/browser/extensions/extension_toolbar_model.h b/chrome/browser/extensions/extension_toolbar_model.h index 5b6a8a4..3889f3d 100644 --- a/chrome/browser/extensions/extension_toolbar_model.h +++ b/chrome/browser/extensions/extension_toolbar_model.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -38,6 +38,10 @@ class ExtensionToolbarModel : public NotificationObserver { void RemoveObserver(Observer* observer); void MoveBrowserAction(Extension* extension, int index); + size_t size() const { + return toolitems_.size(); + } + ExtensionList::iterator begin() { return toolitems_.begin(); } diff --git a/chrome/browser/views/browser_actions_container.cc b/chrome/browser/views/browser_actions_container.cc index 7d5686c..3eb1115 100644 --- a/chrome/browser/views/browser_actions_container.cc +++ b/chrome/browser/views/browser_actions_container.cc @@ -19,6 +19,7 @@ #include "chrome/browser/profile.h" #include "chrome/browser/view_ids.h" #include "chrome/browser/views/detachable_toolbar_view.h" +#include "chrome/browser/views/extensions/browser_action_drag_data.h" #include "chrome/browser/views/extensions/browser_action_overflow_menu_controller.h" #include "chrome/browser/views/extensions/extension_popup.h" #include "chrome/browser/views/toolbar_view.h" @@ -40,6 +41,7 @@ static const int kButtonSize = 29; // The padding between the browser actions and the OmniBox/page menu. static const int kHorizontalPadding = 4; +static const int kHorizontalPaddingRtl = 8; // The padding between browser action buttons. Visually, the actual number of // empty (non-drawing) pixels is this value + 2 when adjacent browser icons @@ -66,6 +68,16 @@ static const int kChevronRightMargin = 4; // Extra hit-area for the resize gripper. static const int kExtraResizeArea = 4; +// Width of the drop indicator. +static const int kDropIndicatorWidth = 2; + +// Color of the drop indicator. +static const SkColor kDropIndicatorColor = SK_ColorBLACK; + +// The x offset for the drop indicator (how much we shift it by). +static const int kDropIndicatorOffsetLtr = 3; +static const int kDropIndicatorOffsetRtl = 9; + //////////////////////////////////////////////////////////////////////////////// // BrowserActionButton @@ -258,6 +270,7 @@ BrowserActionView::BrowserActionView(Extension* extension, BrowserActionsContainer* panel) : panel_(panel) { button_ = new BrowserActionButton(extension, panel); + button_->SetDragController(panel_); AddChildView(button_); button_->UpdateState(); } @@ -291,6 +304,7 @@ BrowserActionsContainer::BrowserActionsContainer( suppress_chevron_(false), resize_amount_(0), animation_target_size_(0), + drop_indicator_position_(-1), ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) { SetID(VIEW_ID_BROWSER_ACTION_TOOLBAR); @@ -321,6 +335,12 @@ BrowserActionsContainer::BrowserActionsContainer( int predefined_width = profile_->GetPrefs()->GetInteger(prefs::kBrowserActionContainerWidth); + if (predefined_width == 0) { + // The width will never be 0 (due to container min size restriction) + // except when no width has been saved. So, in that case ask the model + // how many icons we'll show and set initial size to that. + predefined_width = IconCountToWidth(model_->size()); + } container_size_ = gfx::Size(predefined_width, kButtonSize); } @@ -368,6 +388,16 @@ void BrowserActionsContainer::CloseOverflowMenu() { overflow_menu_->CancelMenu(); } +void BrowserActionsContainer::CreateBrowserActionViews() { + DCHECK(browser_action_views_.empty()); + for (ExtensionList::iterator iter = model_->begin(); + iter != model_->end(); ++iter) { + BrowserActionView* view = new BrowserActionView(*iter, this); + browser_action_views_.push_back(view); + AddChildView(view); + } +} + void BrowserActionsContainer::DeleteBrowserActionViews() { if (!browser_action_views_.empty()) { for (size_t i = 0; i < browser_action_views_.size(); ++i) @@ -473,7 +503,7 @@ gfx::Size BrowserActionsContainer::GetPreferredSize() { // other words: ContainerMinSize() < width() - resize < ClampTo(MAX). int width = std::max(ContainerMinSize(), container_size_.width() - resize_amount_); - int max_width = ClampToNearestIconCount(-1); // -1 gives max width. + int max_width = ClampToNearestIconCount(-1, false); // -1 gives max width. width = std::min(width, max_width); return gfx::Size(width, kButtonSize); @@ -498,7 +528,7 @@ void BrowserActionsContainer::Layout() { x += sz.width(); } - x += kHorizontalPadding; + x += UILayoutIsRightToLeft() ? kHorizontalPaddingRtl : kHorizontalPadding; // Calculate if all icons fit without showing the chevron. We need to know // this beforehand, because showing the chevron will decrease the space that @@ -549,6 +579,21 @@ void BrowserActionsContainer::Paint(gfx::Canvas* canvas) { DetachableToolbarView::kEdgeDividerColor, DetachableToolbarView::kMiddleDividerColor, GetThemeProvider()->GetColor(BrowserThemeProvider::COLOR_TOOLBAR)); + + // The two-pixel width drop indicator. + if (drop_indicator_position_ > -1) { + x = drop_indicator_position_; + int y = kDividerVerticalPadding; + gfx::Rect indicator_bounds(x - kDropIndicatorWidth / 2, + y, + kDropIndicatorWidth, + height() - (2 * kDividerVerticalPadding)); + + // TODO(sky/glen): make me pretty! + canvas->FillRectInt(kDropIndicatorColor, indicator_bounds.x(), + indicator_bounds.y(), indicator_bounds.width(), + indicator_bounds.height()); + } } void BrowserActionsContainer::ViewHierarchyChanged(bool is_add, @@ -563,13 +608,107 @@ void BrowserActionsContainer::ViewHierarchyChanged(bool is_add, // We do this here instead of in the constructor because AddBrowserAction // calls Layout on the Toolbar, which needs this object to be constructed // before its Layout function is called. - for (ExtensionList::iterator iter = model_->begin(); - iter != model_->end(); ++iter) { - BrowserActionView* view = new BrowserActionView(*iter, this); - browser_action_views_.push_back(view); - AddChildView(view); + CreateBrowserActionViews(); + } +} + +bool BrowserActionsContainer::GetDropFormats( + int* formats, std::set<OSExchangeData::CustomFormat>* custom_formats) { + custom_formats->insert(BrowserActionDragData::GetBrowserActionCustomFormat()); + return true; +} + +bool BrowserActionsContainer::AreDropTypesRequired() { + return true; +} + +bool BrowserActionsContainer::CanDrop(const OSExchangeData& data) { + BrowserActionDragData drop_data; + if (!drop_data.Read(data)) + return false; + return drop_data.IsFromProfile(profile_); +} + +void BrowserActionsContainer::OnDragEntered( + const views::DropTargetEvent& event) { +} + +int BrowserActionsContainer::OnDragUpdated( + const views::DropTargetEvent& event) { + // Modifying the x value before clamping affects how far you have to drag to + // get the drop indicator to shift to another position. Modifying after + // clamping affects where the drop indicator is drawn. + + // We add half a button size so that when you drag a button to the right and + // you are half-way dragging across a button the drop indicator moves from the + // left of that button to the right of that button. + int x = event.x() + (kButtonSize / 2) + (2 * kBrowserActionButtonPadding); + if (chevron_->IsVisible()) + x += chevron_->bounds().width(); + x = ClampToNearestIconCount(x, false); + + if (!UILayoutIsRightToLeft() && chevron_->IsVisible()) { + // The clamping function includes the chevron width. In LTR locales, the + // chevron is on the right and we never want to account for its width. In + // RTL it is on the left and we always want to count the width. + x -= chevron_->width(); + } + + // Clamping gives us a value where the next button will be drawn, but we want + // to subtract the padding (and then some) to make it appear in-between the + // buttons. + drop_indicator_position_ = x - kBrowserActionButtonPadding - + (UILayoutIsRightToLeft() ? kDropIndicatorOffsetRtl : + kDropIndicatorOffsetLtr); + + SchedulePaint(); + return DragDropTypes::DRAG_MOVE; +} + +void BrowserActionsContainer::OnDragExited() { + drop_indicator_position_ = -1; + SchedulePaint(); +} + +int BrowserActionsContainer::OnPerformDrop( + const views::DropTargetEvent& event) { + BrowserActionDragData data; + if (!data.Read(event.GetData())) + return DragDropTypes::DRAG_NONE; + + // Make sure we have the same view as we started with. + DCHECK(browser_action_views_[data.index()]->button()->extension()->id() == + data.id()); + + Extension* dragging = + browser_action_views_[data.index()]->button()->extension(); + + int target_x = drop_indicator_position_; + + size_t i = 0; + for (; i < browser_action_views_.size(); ++i) { + int view_x = + browser_action_views_[i]->GetBounds(APPLY_MIRRORING_TRANSFORMATION).x(); + if (!browser_action_views_[i]->IsVisible() || + (UILayoutIsRightToLeft() ? view_x < target_x : view_x >= target_x)) { + // We have reached the end of the visible icons or found one that has a + // higher x position than the drop point. + break; } } + + // |i| now points to the item to the right of the drop indicator*, which is + // correct when dragging an icon to the left. When dragging to the right, + // however, we want the icon being dragged to get the index of the item to + // the left of the drop indicator, so we subtract one. + // * Well, it can also point to the end, but not when dragging to the left. :) + if (i > data.index()) + --i; + + model_->MoveBrowserAction(dragging, i); + + OnDragExited(); // Perform clean up after dragging. + return DragDropTypes::DRAG_MOVE; } void BrowserActionsContainer::Observe(NotificationType type, @@ -639,7 +778,31 @@ void BrowserActionsContainer::RunMenu(View* source, const gfx::Point& pt) { } } -int BrowserActionsContainer::ClampToNearestIconCount(int pixelWidth) const { +void BrowserActionsContainer::WriteDragData( + View* sender, int press_x, int press_y, OSExchangeData* data) { + DCHECK(data); + + for (size_t i = 0; i < browser_action_views_.size(); ++i) { + if (browser_action_views_[i]->button() == sender) { + BrowserActionDragData drag_data( + browser_action_views_[i]->button()->extension()->id(), i); + drag_data.Write(profile_, data); + break; + } + } +} + +int BrowserActionsContainer::GetDragOperations(View* sender, int x, int y) { + return DragDropTypes::DRAG_MOVE; +} + +bool BrowserActionsContainer::CanStartDrag( + View* sender, int press_x, int press_y, int x, int y) { + return true; +} + +int BrowserActionsContainer::ClampToNearestIconCount( + int pixelWidth, bool allow_shrink_to_minimum) const { // Calculate the width of one icon. int icon_width = (kButtonSize + kBrowserActionButtonPadding); @@ -660,19 +823,19 @@ int BrowserActionsContainer::ClampToNearestIconCount(int pixelWidth) const { // Count the number of icons that fit within that area. icon_count = icon_area / icon_width; - // No use allowing more than what we have. - if (icon_count > browser_action_views_.size()) - icon_count = browser_action_views_.size(); - else if (icon_count == 0) + if (icon_count == 0 && allow_shrink_to_minimum) { extras = ContainerMinSize(); // Allow very narrow width if no icons. + } else if (icon_count > browser_action_views_.size()) { + // No use allowing more than what we have. + icon_count = browser_action_views_.size(); + } } else { // A negative |pixels| count indicates caller wants to know the max width // that fits all icons; icon_count = browser_action_views_.size(); } - int returning = extras + (icon_count * icon_width); - return returning; + return extras + (icon_count * icon_width); } void BrowserActionsContainer::BrowserActionAdded(Extension* extension, @@ -745,7 +908,7 @@ void BrowserActionsContainer::BrowserActionRemoved(Extension* extension) { // because we want the container to stay the same size (clamping will take // care of shrinking the container if there aren't enough icons to show). animation_target_size_ = - ClampToNearestIconCount(IconCountToWidth(visible_actions)); + ClampToNearestIconCount(IconCountToWidth(visible_actions), true); // Animate! resize_animation_->Reset(); @@ -756,10 +919,21 @@ void BrowserActionsContainer::BrowserActionRemoved(Extension* extension) { } } +void BrowserActionsContainer::BrowserActionMoved(Extension* extension, + int index) { + DCHECK(index >= 0 && index < static_cast<int>(browser_action_views_.size())); + + DeleteBrowserActionViews(); + CreateBrowserActionViews(); + Layout(); +} + int BrowserActionsContainer::WidthOfNonIconArea() const { int chevron_size = (chevron_->IsVisible()) ? chevron_->GetPreferredSize().width() : 0; - return resize_gripper_->GetPreferredSize().width() + kHorizontalPadding + + int padding = UILayoutIsRightToLeft() ? kHorizontalPaddingRtl : + kHorizontalPadding; + return resize_gripper_->GetPreferredSize().width() + padding + chevron_size + kChevronRightMargin + kDividerHorizontalMargin; } @@ -798,14 +972,14 @@ void BrowserActionsContainer::OnResize(int resize_amount, bool done_resizing) { // Clamp lower limit to 0 and upper limit to the amount that allows enough // room for all icons to show. int new_width = std::max(0, container_size_.width() - resize_amount); - int max_width = ClampToNearestIconCount(-1); + int max_width = ClampToNearestIconCount(-1, false); new_width = std::min(new_width, max_width); // Up until now we've only been modifying the resize_amount, but now it is // time to set the container size to the size we have resized to, but then // animate to the nearest icon count size (or down to min size if no icon). container_size_.set_width(new_width); - animation_target_size_ = ClampToNearestIconCount(new_width); + animation_target_size_ = ClampToNearestIconCount(new_width, true); resize_animation_->Reset(); resize_animation_->SetTweenType(SlideAnimation::EASE_OUT); resize_animation_->Show(); diff --git a/chrome/browser/views/browser_actions_container.h b/chrome/browser/views/browser_actions_container.h index 9adb6e7..5f28823 100644 --- a/chrome/browser/views/browser_actions_container.h +++ b/chrome/browser/views/browser_actions_container.h @@ -19,8 +19,8 @@ #include "views/controls/resize_gripper.h" #include "views/view.h" -class BrowserActionsContainer; class BrowserActionOverflowMenuController; +class BrowserActionsContainer; class Extension; class ExtensionAction; class ExtensionPopup; @@ -49,6 +49,9 @@ class BrowserActionButton : public views::MenuButton, // Called to update the display to match the browser action's state. void UpdateState(); + // Returns the default icon, if any. + const SkBitmap& default_icon() const { return default_icon_; } + // Overridden from views::View. Return a 0-inset so the icon can draw all the // way to the edge of the view if it wants. virtual gfx::Insets GetInsets() const; @@ -137,6 +140,8 @@ class BrowserActionView : public views::View { // The button this view contains. BrowserActionButton* button_; + + DISALLOW_COPY_AND_ASSIGN(BrowserActionView); }; //////////////////////////////////////////////////////////////////////////////// @@ -217,6 +222,7 @@ class BrowserActionsContainer public NotificationObserver, public BrowserBubble::Delegate, public views::ViewMenuDelegate, + public views::DragController, public views::ResizeGripper::ResizeGripperDelegate, public AnimationDelegate, public ExtensionToolbarModel::Observer { @@ -249,6 +255,9 @@ class BrowserActionsContainer // Update the views to reflect the state of the browser action icons. void RefreshBrowserActionViews(); + // Sets up the browser action view vector. + void CreateBrowserActionViews(); + // Delete all browser action views. void DeleteBrowserActionViews(); @@ -265,6 +274,14 @@ class BrowserActionsContainer virtual void ViewHierarchyChanged(bool is_add, views::View* parent, views::View* child); + virtual bool GetDropFormats( + int* formats, std::set<OSExchangeData::CustomFormat>* custom_formats); + virtual bool AreDropTypesRequired(); + virtual bool CanDrop(const OSExchangeData& data); + virtual void OnDragEntered(const views::DropTargetEvent& event); + virtual int OnDragUpdated(const views::DropTargetEvent& event); + virtual void OnDragExited(); + virtual int OnPerformDrop(const views::DropTargetEvent& event); // Overridden from NotificationObserver: virtual void Observe(NotificationType type, @@ -281,6 +298,18 @@ class BrowserActionsContainer // Overridden from views::ViewMenuDelegate: virtual void RunMenu(View* source, const gfx::Point& pt); + // Overridden from views::DragController: + virtual void WriteDragData(View* sender, + int press_x, + int press_y, + OSExchangeData* data); + virtual int GetDragOperations(View* sender, int x, int y); + virtual bool CanStartDrag(View* sender, + int press_x, + int press_y, + int x, + int y); + // Overridden from ResizeGripper::ResizeGripperDelegate: virtual void OnResize(int resize_amount, bool done_resizing); @@ -302,14 +331,19 @@ class BrowserActionsContainer // ExtensionToolbarModel::Observer implementation. virtual void BrowserActionAdded(Extension* extension, int index); virtual void BrowserActionRemoved(Extension* extension); + virtual void BrowserActionMoved(Extension* extension, int index); // Closes the overflow menu if open. void CloseOverflowMenu(); // Takes a width in pixels, calculates how many icons fit within that space // (up to the maximum number of icons in our vector) and shaves off the - // excess pixels. - int ClampToNearestIconCount(int pixels) const; + // excess pixels. |allow_shrink_to_minimum| specifies whether this function + // clamps the size down further (down to ContainerMinSize()) if there is not + // room for even one icon. When determining how large the container should be + // this should be |true|. When determining where to place items, such as the + // drop indicator, this should be |false|. + int ClampToNearestIconCount(int pixels, bool allow_shrink_to_minimum) const; // Calculates the width of the container area NOT used to show the icons (the // controls to the left and to the right of the icons). @@ -374,6 +408,9 @@ class BrowserActionsContainer // are done animating. int animation_target_size_; + // The x position for where to draw the drop indicator. -1 if no indicator. + int drop_indicator_position_; + ScopedRunnableMethodFactory<BrowserActionsContainer> task_factory_; DISALLOW_COPY_AND_ASSIGN(BrowserActionsContainer); diff --git a/chrome/browser/views/extensions/browser_action_drag_data.cc b/chrome/browser/views/extensions/browser_action_drag_data.cc new file mode 100644 index 0000000..103738f --- /dev/null +++ b/chrome/browser/views/extensions/browser_action_drag_data.cc @@ -0,0 +1,93 @@ +// Copyright (c) 2010 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/views/extensions/browser_action_drag_data.h" + +#include "base/file_path.h" +#include "base/logging.h" +#include "base/pickle.h" +#include "base/string_util.h" +#include "chrome/browser/profile.h" + +const char* BrowserActionDragData::kClipboardFormatString = + "chromium/x-browser-actions"; + +BrowserActionDragData::BrowserActionDragData() + : index_(-1) { +} + +BrowserActionDragData::BrowserActionDragData( + const std::string& id, int index) + : id_(id), + index_(index) { +} + +bool BrowserActionDragData::IsFromProfile(Profile* profile) const { + // An empty path means the data is not associated with any profile. + return (!profile_path_.empty() && + profile_path_ == profile->GetPath().value()); +} + +#if defined(TOOLKIT_VIEWS) +void BrowserActionDragData::Write( + Profile* profile, OSExchangeData* data) const { + DCHECK(data); + Pickle data_pickle; + WriteToPickle(profile, &data_pickle); + data->SetPickledData(GetBrowserActionCustomFormat(), data_pickle); +} + +bool BrowserActionDragData::Read(const OSExchangeData& data) { + if (!data.HasCustomFormat(GetBrowserActionCustomFormat())) + return false; + + Pickle drag_data_pickle; + if (!data.GetPickledData(GetBrowserActionCustomFormat(), &drag_data_pickle)) + return false; + + if (!ReadFromPickle(&drag_data_pickle)) + return false; + + return true; +} + +// static +OSExchangeData::CustomFormat + BrowserActionDragData::GetBrowserActionCustomFormat() { + static OSExchangeData::CustomFormat format; + static bool format_valid = false; + + if (!format_valid) { + format_valid = true; + format = OSExchangeData::RegisterCustomFormat( + BrowserActionDragData::kClipboardFormatString); + } + return format; +} +#endif + +void BrowserActionDragData::WriteToPickle( + Profile* profile, Pickle* pickle) const { + FilePath::WriteStringTypeToPickle(pickle, profile->GetPath().value()); + pickle->WriteString(id_); + pickle->WriteInt(index_); +} + +bool BrowserActionDragData::ReadFromPickle(Pickle* pickle) { + void* data_iterator = NULL; + if (!FilePath::ReadStringTypeFromPickle(pickle, &data_iterator, + &profile_path_)) { + return false; + } + + if (!pickle->ReadString(&data_iterator, &id_)) + return false; + + int index; + if (!pickle->ReadInt(&data_iterator, &index)) + return false; + + index_ = index; + return true; +} diff --git a/chrome/browser/views/extensions/browser_action_drag_data.h b/chrome/browser/views/extensions/browser_action_drag_data.h new file mode 100644 index 0000000..8d5d514b --- /dev/null +++ b/chrome/browser/views/extensions/browser_action_drag_data.h @@ -0,0 +1,62 @@ +// Copyright (c) 2010 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_VIEWS_EXTENSIONS_BROWSER_ACTION_DRAG_DATA_H_ +#define CHROME_BROWSER_VIEWS_EXTENSIONS_BROWSER_ACTION_DRAG_DATA_H_ + +#include <string> + +#include "base/basictypes.h" + +#if defined(TOOLKIT_VIEWS) +#include "app/os_exchange_data.h" +#endif + +class BrowserActionButton; +class FilePath; +class Pickle; +class Profile; + +class BrowserActionDragData { + public: + BrowserActionDragData(); + BrowserActionDragData(const std::string& id, int index); + + const std::string& id() const { return id_; } + + size_t index() const { return index_; } + + // Returns true if this data is from the specified profile. + bool IsFromProfile(Profile* profile) const; + +#if defined(TOOLKIT_VIEWS) + void Write(Profile* profile, OSExchangeData* data) const; + + // Restores this data from the clipboard, returning true on success. + bool Read(const OSExchangeData& data); + + // Returns the Custom Format this class supports (for Browser Actions). + static OSExchangeData::CustomFormat GetBrowserActionCustomFormat(); +#endif + + private: + void WriteToPickle(Profile* profile, Pickle* pickle) const; + bool ReadFromPickle(Pickle* pickle); + + // Path of the profile we originated from. + FilePath::StringType profile_path_; + + // The id of the view being dragged. + std::string id_; + + // The index of the view being dragged. + size_t index_; + + // The MIME type for the clipboard format for BrowserActionDragData. + static const char* kClipboardFormatString; + + DISALLOW_COPY_AND_ASSIGN(BrowserActionDragData); +}; + +#endif // CHROME_BROWSER_VIEWS_EXTENSIONS_BROWSER_ACTION_DRAG_DATA_H_ diff --git a/chrome/browser/views/extensions/browser_action_drag_data_unittest.cc b/chrome/browser/views/extensions/browser_action_drag_data_unittest.cc new file mode 100644 index 0000000..7f54b0c --- /dev/null +++ b/chrome/browser/views/extensions/browser_action_drag_data_unittest.cc @@ -0,0 +1,54 @@ +// Copyright (c) 2010 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 "app/os_exchange_data.h" +#include "app/os_exchange_data_provider_win.h" +#include "base/pickle.h" +#include "chrome/browser/views/extensions/browser_action_drag_data.h" +#include "chrome/test/testing_profile.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +OSExchangeData::Provider* CloneProvider(const OSExchangeData& data) { + return new OSExchangeDataProviderWin( + OSExchangeDataProviderWin::GetIDataObject(data)); +} + +} // namespace + +typedef testing::Test BrowserActionDragDataTest; + +TEST_F(BrowserActionDragDataTest, ArbitraryFormat) { + TestingProfile profile; + profile.SetID(L"id"); + + OSExchangeData data; + data.SetURL(GURL("http://www.google.com"), L"Title"); + + // We only support our format, so this should not succeed. + BrowserActionDragData drag_data; + EXPECT_FALSE(drag_data.Read(OSExchangeData(CloneProvider(data)))); +} + +TEST_F(BrowserActionDragDataTest, BrowserActionDragDataFormat) { + TestingProfile profile; + profile.SetID(L"id"); + + const std::string extension_id = "42"; + Pickle pickle; + pickle.WriteWString(profile.GetPath().ToWStringHack()); + pickle.WriteString(extension_id); + pickle.WriteInt(42); + + OSExchangeData data; + data.SetPickledData(BrowserActionDragData::GetBrowserActionCustomFormat(), + pickle); + + BrowserActionDragData drag_data; + EXPECT_TRUE(drag_data.Read(OSExchangeData(CloneProvider(data)))); + ASSERT_TRUE(drag_data.IsFromProfile(profile.GetOriginalProfile())); + ASSERT_STREQ(extension_id.c_str(), drag_data.id().c_str()); + ASSERT_EQ(42, drag_data.index()); +} diff --git a/chrome/browser/views/extensions/browser_action_overflow_menu_controller.cc b/chrome/browser/views/extensions/browser_action_overflow_menu_controller.cc index 66b209c..6cb56d8 100644 --- a/chrome/browser/views/extensions/browser_action_overflow_menu_controller.cc +++ b/chrome/browser/views/extensions/browser_action_overflow_menu_controller.cc @@ -29,10 +29,14 @@ BrowserActionOverflowMenuController::BrowserActionOverflowMenuController( size_t command_id = 0; for (size_t i = start_index; i < views_->size(); ++i) { BrowserActionView* view = (*views_)[i]; + SkBitmap icon = + view->button()->extension()->browser_action()->GetIcon(tab_id); + if (icon.isNull()) + icon = view->button()->default_icon(); menu_->AppendMenuItemWithIcon( command_id, UTF8ToWide(view->button()->extension()->name()), - view->button()->extension()->browser_action()->GetIcon(tab_id)); + icon); ++command_id; } } diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index d8bbd9a..d6146c8 100755 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1786,6 +1786,8 @@ 'browser/views/edit_search_engine_dialog.h', 'browser/views/event_utils.cc', 'browser/views/event_utils.h', + 'browser/views/extensions/browser_action_drag_data.cc', + 'browser/views/extensions/browser_action_drag_data.h', 'browser/views/extensions/browser_action_overflow_menu_controller.cc', 'browser/views/extensions/browser_action_overflow_menu_controller.h', 'browser/views/extensions/extension_action_context_menu.cc', @@ -2358,6 +2360,8 @@ ['include', '^browser/views/dropdown_bar_view.h'], ['include', '^browser/views/event_utils.cc'], ['include', '^browser/views/event_utils.h'], + ['include', '^browser/views/extensions/browser_action_drag_data.cc'], + ['include', '^browser/views/extensions/browser_action_drag_data.h'], ['include', '^browser/views/extensions/browser_action_overflow_menu_controller.cc'], ['include', '^browser/views/extensions/browser_action_overflow_menu_controller.h'], ['include', '^browser/views/extensions/extension_action_context_menu.cc'], diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 76b02dc..d7d338f 100755 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -812,6 +812,7 @@ 'browser/theme_resources_util_unittest.cc', 'browser/views/bookmark_context_menu_test.cc', 'browser/views/bookmark_editor_view_unittest.cc', + 'browser/views/extensions/browser_action_drag_data_unittest.cc', 'browser/visitedlink_unittest.cc', 'browser/webdata/web_data_service_unittest.cc', 'browser/webdata/web_database_unittest.cc', @@ -1031,6 +1032,7 @@ 'browser/safe_browsing/safe_browsing_blocking_page_unittest.cc', 'browser/search_engines/template_url_scraper_unittest.cc', 'browser/views/bookmark_editor_view_unittest.cc', + 'browser/views/extensions/browser_action_drag_data_unittest.cc', 'browser/views/find_bar_host_unittest.cc', 'browser/views/keyword_editor_view_unittest.cc', 'common/chrome_plugin_unittest.cc', |