Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2010 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/speech/speech_input_bubble.h" | |
| 6 | |
| 7 #include "app/l10n_util.h" | |
| 8 #include "app/resource_bundle.h" | |
| 9 #include "base/message_loop.h" | |
| 10 #include "chrome/browser/browser.h" | |
| 11 #include "chrome/browser/browser_window.h" | |
| 12 #include "chrome/browser/tab_contents/tab_contents.h" | |
| 13 #include "chrome/browser/tab_contents/tab_contents_view.h" | |
| 14 #include "chrome/browser/views/info_bubble.h" | |
| 15 #include "chrome/common/notification_observer.h" | |
| 16 #include "chrome/common/notification_registrar.h" | |
| 17 #include "chrome/common/notification_service.h" | |
| 18 #include "chrome/common/notification_type.h" | |
| 19 #include "gfx/canvas.h" | |
| 20 #include "grit/generated_resources.h" | |
| 21 #include "grit/theme_resources.h" | |
| 22 #include "views/controls/image_view.h" | |
| 23 #include "views/controls/label.h" | |
| 24 #include "views/controls/link.h" | |
| 25 #include "views/standard_layout.h" | |
| 26 #include "views/view.h" | |
| 27 | |
| 28 namespace { | |
| 29 | |
| 30 // The speech bubble's arrow is so many pixels from the left of html element. | |
| 31 const int kBubbleTargetOffsetX = 5; | |
| 32 const int kBubbleHorizMargin = 40; | |
| 33 const int kBubbleVertMargin = 0; | |
| 34 | |
| 35 // This is the content view which is placed inside a SpeechInputBubble. | |
| 36 class ContentView | |
| 37 : public views::View, | |
| 38 public views::LinkController { | |
| 39 public: | |
| 40 explicit ContentView(SpeechInputBubbleDelegate* delegate); | |
| 41 | |
| 42 void SetRecognizingMode(); | |
| 43 | |
| 44 // views::LinkController methods. | |
| 45 virtual void LinkActivated(views::Link* source, int event_flags); | |
| 46 | |
| 47 // views::View overrides. | |
| 48 virtual gfx::Size GetPreferredSize(); | |
| 49 virtual void Layout(); | |
| 50 | |
| 51 private: | |
| 52 SpeechInputBubbleDelegate* delegate_; | |
| 53 views::ImageView* icon_; | |
| 54 views::Label* heading_; | |
| 55 views::Link* cancel_; | |
| 56 | |
| 57 DISALLOW_COPY_AND_ASSIGN(ContentView); | |
| 58 }; | |
| 59 | |
| 60 ContentView::ContentView(SpeechInputBubbleDelegate* delegate) | |
| 61 : delegate_(delegate) { | |
| 62 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
| 63 const gfx::Font& font = rb.GetFont(ResourceBundle::BaseFont); | |
| 64 | |
| 65 heading_ = new views::Label( | |
| 66 l10n_util::GetString(IDS_SPEECH_INPUT_BUBBLE_HEADING)); | |
| 67 heading_->SetFont(font.DeriveFont(3, gfx::Font::NORMAL)); | |
| 68 heading_->SetHorizontalAlignment(views::Label::ALIGN_CENTER); | |
| 69 AddChildView(heading_); | |
| 70 | |
| 71 icon_ = new views::ImageView(); | |
| 72 icon_->SetImage(*ResourceBundle::GetSharedInstance().GetBitmapNamed( | |
| 73 IDR_SPEECH_INPUT_RECORDING)); | |
| 74 icon_->SetHorizontalAlignment(views::ImageView::CENTER); | |
| 75 AddChildView(icon_); | |
| 76 | |
| 77 cancel_ = new views::Link(l10n_util::GetString(IDS_CANCEL)); | |
| 78 cancel_->SetController(this); | |
| 79 cancel_->SetFont(font.DeriveFont(3, gfx::Font::NORMAL)); | |
| 80 cancel_->SetHorizontalAlignment(views::Label::ALIGN_CENTER); | |
| 81 AddChildView(cancel_); | |
| 82 } | |
| 83 | |
| 84 void ContentView::SetRecognizingMode() { | |
| 85 icon_->SetImage(*ResourceBundle::GetSharedInstance().GetBitmapNamed( | |
| 86 IDR_SPEECH_INPUT_PROCESSING)); | |
| 87 } | |
| 88 | |
| 89 void ContentView::LinkActivated(views::Link* source, int event_flags) { | |
| 90 if (source == cancel_) { | |
| 91 delegate_->RecognitionCancelled(); | |
| 92 } else { | |
| 93 NOTREACHED() << "Unknown view"; | |
| 94 } | |
| 95 } | |
| 96 | |
| 97 gfx::Size ContentView::GetPreferredSize() { | |
| 98 int width = heading_->GetPreferredSize().width(); | |
| 99 int control_width = cancel_->GetPreferredSize().width(); | |
| 100 if (control_width > width) | |
| 101 width = control_width; | |
| 102 control_width = icon_->GetPreferredSize().width(); | |
| 103 if (control_width > width) | |
| 104 width = control_width; | |
| 105 width += kBubbleHorizMargin * 2; | |
| 106 | |
| 107 int height = kBubbleVertMargin * 2 + | |
| 108 heading_->GetPreferredSize().height() + | |
| 109 cancel_->GetPreferredSize().height() + | |
| 110 icon_->GetImage().height(); | |
| 111 return gfx::Size(width, height); | |
| 112 } | |
| 113 | |
| 114 void ContentView::Layout() { | |
| 115 int x = kBubbleHorizMargin; | |
| 116 int y = kBubbleVertMargin; | |
| 117 int control_width = width() - kBubbleHorizMargin * 2; | |
| 118 | |
| 119 int height = heading_->GetPreferredSize().height(); | |
| 120 heading_->SetBounds(x, y, control_width, height); | |
| 121 y += height; | |
| 122 | |
| 123 height = icon_->GetImage().height(); | |
| 124 icon_->SetBounds(x, y, control_width, height); | |
| 125 y += height; | |
| 126 | |
| 127 height = cancel_->GetPreferredSize().height(); | |
| 128 cancel_->SetBounds(x, y, control_width, height); | |
| 129 } | |
| 130 | |
| 131 // Implementation of SpeechInputBubble. | |
| 132 class SpeechInputBubbleImpl | |
| 133 : public SpeechInputBubble, | |
| 134 public InfoBubbleDelegate, | |
| 135 public NotificationObserver { | |
| 136 public: | |
| 137 SpeechInputBubbleImpl(TabContents* tab_contents, | |
| 138 Delegate* delegate, | |
|
sky
2010/08/24 16:08:28
align with ( on previous line.
| |
| 139 const gfx::Rect& element_rect); | |
| 140 ~SpeechInputBubbleImpl(); | |
|
sky
2010/08/24 16:08:28
virtual
| |
| 141 | |
| 142 virtual void SetRecognizingMode(); | |
| 143 | |
| 144 // Returns the screen rectangle to use as the info bubble's target. | |
| 145 // |element_rect| is the html element's bounds in page coordinates. | |
| 146 gfx::Rect GetInfoBubbleTarget(const gfx::Rect& element_rect); | |
| 147 | |
| 148 // NotificationObserver implementation. | |
| 149 virtual void Observe(NotificationType type, | |
| 150 const NotificationSource& source, | |
| 151 const NotificationDetails& details); | |
| 152 | |
| 153 // InfoBubbleDelegate | |
| 154 virtual void InfoBubbleClosing(InfoBubble* info_bubble, | |
| 155 bool closed_by_escape); | |
| 156 virtual bool CloseOnEscape(); | |
| 157 virtual bool FadeInOnShow(); | |
| 158 | |
| 159 private: | |
| 160 Delegate* delegate_; | |
| 161 InfoBubble* info_bubble_; | |
| 162 TabContents* tab_contents_; | |
| 163 ContentView* bubble_content_; | |
| 164 NotificationRegistrar registrar_; | |
| 165 bool did_close_; // Set to true if |Close()| was invoked by caller. | |
|
sky
2010/08/24 16:08:28
Update comment.
| |
| 166 | |
| 167 DISALLOW_COPY_AND_ASSIGN(SpeechInputBubbleImpl); | |
| 168 }; | |
| 169 | |
| 170 SpeechInputBubbleImpl::SpeechInputBubbleImpl(TabContents* tab_contents, | |
| 171 Delegate* delegate, | |
| 172 const gfx::Rect& element_rect) | |
| 173 : delegate_(delegate), | |
| 174 info_bubble_(NULL), | |
| 175 tab_contents_(tab_contents), | |
| 176 bubble_content_(NULL), | |
| 177 did_close_(false) { | |
| 178 bubble_content_ = new ContentView(delegate_); | |
| 179 | |
| 180 views::Widget* parent = views::Widget::GetWidgetFromNativeWindow( | |
| 181 tab_contents_->view()->GetTopLevelNativeWindow()); | |
| 182 info_bubble_ = InfoBubble::Show(parent, | |
| 183 GetInfoBubbleTarget(element_rect), | |
| 184 BubbleBorder::TOP_LEFT, bubble_content_, | |
| 185 this); | |
| 186 | |
| 187 // We don't want fade outs when closing because it makes speech recognition | |
| 188 // appear slower than it is. Also setting it to false allows |Close| to | |
| 189 // destroy the bubble immediately instead of waiting for the fade animation | |
| 190 // to end so the caller can manage this object's life cycle like a normal | |
| 191 // stack based or member variable object. | |
| 192 info_bubble_->set_fade_away_on_close(false); | |
| 193 | |
| 194 registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED, | |
| 195 Source<TabContents>(tab_contents_)); | |
| 196 } | |
| 197 | |
| 198 SpeechInputBubbleImpl::~SpeechInputBubbleImpl() { | |
| 199 if (info_bubble_) { | |
| 200 did_close_ = true; | |
| 201 info_bubble_->Close(); | |
| 202 } | |
| 203 } | |
| 204 | |
| 205 void SpeechInputBubbleImpl::SetRecognizingMode() { | |
| 206 DCHECK(info_bubble_); | |
| 207 DCHECK(bubble_content_); | |
| 208 bubble_content_->SetRecognizingMode(); | |
| 209 } | |
| 210 | |
| 211 gfx::Rect SpeechInputBubbleImpl::GetInfoBubbleTarget( | |
| 212 const gfx::Rect& element_rect) { | |
| 213 gfx::Rect container_rect; | |
| 214 tab_contents_->GetContainerBounds(&container_rect); | |
| 215 return gfx::Rect( | |
| 216 container_rect.x() + element_rect.x() + kBubbleTargetOffsetX, | |
| 217 container_rect.y() + element_rect.y() + element_rect.height(), 1, 1); | |
|
sky
2010/08/24 16:08:28
Sounds the size be that of element_rect?
Satish
2010/08/24 16:22:04
We want the bubble's arrow to point at x, y positi
| |
| 218 } | |
| 219 | |
| 220 void SpeechInputBubbleImpl::Observe(NotificationType type, | |
| 221 const NotificationSource& source, | |
| 222 const NotificationDetails& details) { | |
| 223 if (type == NotificationType::TAB_CONTENTS_DESTROYED) { | |
| 224 delegate_->RecognitionCancelled(); | |
| 225 } else { | |
| 226 NOTREACHED() << "Unknown notification"; | |
| 227 } | |
| 228 } | |
| 229 | |
| 230 void SpeechInputBubbleImpl::InfoBubbleClosing(InfoBubble* info_bubble, | |
| 231 bool closed_by_escape) { | |
| 232 registrar_.Remove(this, NotificationType::TAB_CONTENTS_DESTROYED, | |
| 233 Source<TabContents>(tab_contents_)); | |
| 234 info_bubble_ = NULL; | |
| 235 bubble_content_ = NULL; | |
| 236 if (!did_close_) | |
| 237 delegate_->InfoBubbleClosed(); | |
| 238 } | |
| 239 | |
| 240 bool SpeechInputBubbleImpl::CloseOnEscape() { | |
| 241 return false; | |
| 242 } | |
| 243 | |
| 244 bool SpeechInputBubbleImpl::FadeInOnShow() { | |
| 245 return false; | |
| 246 } | |
| 247 | |
| 248 } // namespace | |
| 249 | |
| 250 SpeechInputBubble* SpeechInputBubble::Create( | |
| 251 TabContents* tab_contents, | |
| 252 SpeechInputBubble::Delegate* delegate, | |
| 253 const gfx::Rect& element_rect) { | |
| 254 return new SpeechInputBubbleImpl(tab_contents, delegate, element_rect); | |
| 255 } | |
| OLD | NEW |