Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(192)

Side by Side Diff: chrome/browser/views/browser_actions_container.cc

Issue 243001: Implement Browser Actions extensions.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/views/browser_actions_container.h"
6
7 #include "base/stl_util-inl.h"
8 #include "chrome/browser/extensions/extension_browser_event_router.h"
9 #include "chrome/browser/extensions/extensions_service.h"
10 #include "chrome/browser/extensions/extension_tabs_module.h"
11 #include "chrome/browser/image_loading_tracker.h"
12 #include "chrome/browser/profile.h"
13 #include "chrome/browser/views/toolbar_view.h"
14 #include "chrome/common/notification_source.h"
15 #include "chrome/common/notification_type.h"
16 #include "chrome/common/page_action.h"
17 #include "third_party/skia/include/core/SkBitmap.h"
18 #include "views/controls/button/image_button.h"
19
20 // The size of the icon for page actions.
21 static const int kIconSize = 16;
22
23 // The padding between icons (pixels between each icon).
24 static const int kIconHorizontalPadding = 10;
25
26 ////////////////////////////////////////////////////////////////////////////////
27 // BrowserActionImageView
28
29 // The BrowserActionImageView is a specialization of the ImageButton class.
30 // It acts on a ContextualAction, in this case a BrowserAction and handles
31 // loading the image for the button asynchronously on the file thread to
32 class BrowserActionImageView : public views::ImageButton,
33 public views::ButtonListener,
34 public ImageLoadingTracker::Observer {
35 public:
36 BrowserActionImageView(ContextualAction* browser_action,
37 Extension* extension,
38 BrowserActionsContainer* panel);
39 ~BrowserActionImageView();
40
41 // Overridden from views::ButtonListener:
42 virtual void ButtonPressed(views::Button* sender, const views::Event& event);
43
44 // Overridden from ImageLoadingTracker.
45 virtual void OnImageLoaded(SkBitmap* image, size_t index);
46
47 private:
48 // The browser action this view represents. The ContextualAction is not owned
49 // by this class.
50 ContextualAction* browser_action_;
51
52 // The icons representing different states for the browser action.
53 std::vector<SkBitmap> browser_action_icons_;
54
55 // The object that is waiting for the image loading to complete
56 // asynchronously. This object can potentially outlive the BrowserActionView,
57 // and takes care of deleting itself.
58 ImageLoadingTracker* tracker_;
59
60 // The browser action shelf.
61 BrowserActionsContainer* panel_;
62
63 DISALLOW_COPY_AND_ASSIGN(BrowserActionImageView);
64 };
65
66 BrowserActionImageView::BrowserActionImageView(
67 ContextualAction* browser_action, Extension* extension,
68 BrowserActionsContainer* panel)
69 : ImageButton(this),
70 browser_action_(browser_action),
71 tracker_(NULL),
72 panel_(panel) {
73 // Load the images this view needs asynchronously on the file thread. We'll
74 // get a call back into OnImageLoaded if the image loads successfully. If not,
75 // the ImageView will have no image and will not appear in the browser chrome.
76 DCHECK(!browser_action->icon_paths().empty());
77 const std::vector<std::string>& icon_paths = browser_action->icon_paths();
78 browser_action_icons_.resize(icon_paths.size());
79 tracker_ = new ImageLoadingTracker(this, icon_paths.size());
80 for (std::vector<std::string>::const_iterator iter = icon_paths.begin();
81 iter != icon_paths.end(); ++iter) {
82 FilePath path = extension->GetResourcePath(*iter);
83 tracker_->PostLoadImageTask(path);
84 }
85 }
86
87 BrowserActionImageView::~BrowserActionImageView() {
88 if (tracker_) {
89 tracker_->StopTrackingImageLoad();
90 tracker_ = NULL; // The tracker object will be deleted when we return.
91 }
92 }
93
94 void BrowserActionImageView::ButtonPressed(
95 views::Button* sender, const views::Event& event) {
96 panel_->OnBrowserActionExecuted(*browser_action_);
97 }
98
99 void BrowserActionImageView::OnImageLoaded(SkBitmap* image, size_t index) {
100 DCHECK(index < browser_action_icons_.size());
101 browser_action_icons_[index] = *image;
102 if (index == 0) {
103 SetImage(views::CustomButton::BS_NORMAL, image);
104 SetImage(views::CustomButton::BS_HOT, image);
105 SetImage(views::CustomButton::BS_PUSHED, image);
106 SetTooltipText(ASCIIToWide(browser_action_->name()));
107 panel_->OnBrowserActionVisibilityChanged();
108 }
109
110 if (index == browser_action_icons_.size() - 1)
111 tracker_ = NULL; // The tracker object will delete itself when we return.
112 }
113
114 ////////////////////////////////////////////////////////////////////////////////
115 // BrowserActionsContainer
116
117 BrowserActionsContainer::BrowserActionsContainer(
118 Profile* profile, ToolbarView* toolbar)
119 : profile_(profile), toolbar_(toolbar) {
120 ExtensionsService* extension_service = profile->GetExtensionsService();
121 registrar_.Add(this, NotificationType::EXTENSION_LOADED,
122 Source<ExtensionsService>(extension_service));
123 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
124 Source<ExtensionsService>(extension_service));
125 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED,
126 Source<ExtensionsService>(extension_service));
127
128 RefreshBrowserActionViews();
129 }
130
131 BrowserActionsContainer::~BrowserActionsContainer() {
132 DeleteBrowserActionViews();
133 }
134
135 void BrowserActionsContainer::RefreshBrowserActionViews() {
136 ExtensionsService* extension_service = profile_->GetExtensionsService();
137 if (!extension_service) // The |extension_service| can be NULL in Incognito.
138 return;
139
140 std::vector<ContextualAction*> browser_actions;
141 browser_actions = extension_service->GetBrowserActions();
142
143 if (browser_action_views_.size() != browser_actions.size()) {
144 DeleteBrowserActionViews();
145
146 for (size_t i = 0; i < browser_actions.size(); ++i) {
147 Extension* extension = extension_service->GetExtensionById(
148 browser_actions[i]->extension_id());
149 DCHECK(extension);
150
151 BrowserActionImageView* view =
152 new BrowserActionImageView(browser_actions[i], extension, this);
153 browser_action_views_.push_back(view);
154 AddChildView(view);
155 }
156 }
157 }
158
159 void BrowserActionsContainer::DeleteBrowserActionViews() {
160 if (!browser_action_views_.empty()) {
161 for (size_t i = 0; i < browser_action_views_.size(); ++i)
162 RemoveChildView(browser_action_views_[i]);
163 STLDeleteContainerPointers(browser_action_views_.begin(),
164 browser_action_views_.end());
165 browser_action_views_.clear();
166 }
167 }
168
169 void BrowserActionsContainer::OnBrowserActionVisibilityChanged() {
170 toolbar_->Layout();
171 }
172
173 void BrowserActionsContainer::OnBrowserActionExecuted(
174 const ContextualAction& browser_action) {
175 int window_id = ExtensionTabUtil::GetWindowId(toolbar_->browser());
176 ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted(
177 profile_, browser_action.extension_id(), window_id);
178 }
179
180 gfx::Size BrowserActionsContainer::GetPreferredSize() {
181 if (browser_action_views_.empty())
182 return gfx::Size(0, 0);
183 int width = kIconHorizontalPadding + browser_action_views_.size() *
184 (kIconSize + kIconHorizontalPadding);
185 return gfx::Size(width, kIconSize);
186 }
187
188 void BrowserActionsContainer::Layout() {
189 for (size_t i = 0; i < browser_action_views_.size(); ++i) {
190 views::ImageButton* view = browser_action_views_[i];
191 gfx::Size sz = view->GetPreferredSize();
192 int x = kIconHorizontalPadding + i * (kIconSize + kIconHorizontalPadding);
193 view->SetBounds(x, (height() - sz.height()) / 2, sz.width(), sz.height());
194 }
195 }
196
197 void BrowserActionsContainer::Observe(NotificationType type,
198 const NotificationSource& source,
199 const NotificationDetails& details) {
200 if (type == NotificationType::EXTENSION_LOADED ||
201 type == NotificationType::EXTENSION_UNLOADED ||
202 type == NotificationType::EXTENSION_UNLOADED_DISABLED) {
203 RefreshBrowserActionViews();
204 } else {
205 NOTREACHED() << L"Received unexpected notification";
206 }
207 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698