| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/gtk/infobar_gtk.h" | 5 #include "chrome/browser/gtk/infobar_gtk.h" |
| 6 | 6 |
| 7 #include <gtk/gtk.h> | 7 #include <gtk/gtk.h> |
| 8 | 8 |
| 9 #include "base/utf_string_conversions.h" | 9 #include "base/utf_string_conversions.h" |
| 10 #include "chrome/browser/gtk/custom_button.h" | 10 #include "chrome/browser/gtk/custom_button.h" |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 160 NotificationService::AllSources()); | 160 NotificationService::AllSources()); |
| 161 UpdateBorderColor(); | 161 UpdateBorderColor(); |
| 162 } | 162 } |
| 163 | 163 |
| 164 void InfoBar::Observe(NotificationType type, | 164 void InfoBar::Observe(NotificationType type, |
| 165 const NotificationSource& source, | 165 const NotificationSource& source, |
| 166 const NotificationDetails& details) { | 166 const NotificationDetails& details) { |
| 167 UpdateBorderColor(); | 167 UpdateBorderColor(); |
| 168 } | 168 } |
| 169 | 169 |
| 170 // TODO(joth): This method factors out some common functionality between the |
| 171 // various derived infobar classes, however the class hierarchy itself could |
| 172 // use refactoring to reduce this duplication. http://crbug.com/38924 |
| 173 void InfoBar::AddLabelAndLink(const std::wstring& display_text, |
| 174 const std::wstring& link_text, |
| 175 size_t link_offset, |
| 176 guint link_padding, |
| 177 GCallback callback) { |
| 178 GtkWidget* link_button = NULL; |
| 179 if (link_text.empty()) { |
| 180 // No link text, so skip creating the link and splitting display_text. |
| 181 link_offset = std::wstring::npos; |
| 182 } else { |
| 183 // If we have some link text, create the link button. |
| 184 link_button = gtk_chrome_link_button_new(WideToUTF8(link_text).c_str()); |
| 185 gtk_chrome_link_button_set_use_gtk_theme( |
| 186 GTK_CHROME_LINK_BUTTON(link_button), FALSE); |
| 187 DCHECK(callback); |
| 188 g_signal_connect(link_button, "clicked", callback, this); |
| 189 gtk_util::SetButtonTriggersNavigation(link_button); |
| 190 } |
| 191 |
| 192 GtkWidget* hbox = gtk_hbox_new(FALSE, 0); |
| 193 // We want the link to be horizontally shrinkable, so that the Chrome |
| 194 // window can be resized freely even with a very long link. |
| 195 gtk_widget_set_size_request(hbox, 0, -1); |
| 196 gtk_box_pack_start(GTK_BOX(hbox_), hbox, TRUE, TRUE, 0); |
| 197 |
| 198 // If link_offset is npos, we right-align the link instead of embedding it |
| 199 // in the text. |
| 200 if (link_offset == std::wstring::npos) { |
| 201 if (link_button) |
| 202 gtk_box_pack_end(GTK_BOX(hbox), link_button, FALSE, FALSE, 0); |
| 203 GtkWidget* label = gtk_label_new(WideToUTF8(display_text).c_str()); |
| 204 // In order to avoid the link_button and the label overlapping with each |
| 205 // other, we make the label shrinkable. |
| 206 gtk_widget_set_size_request(label, 0, -1); |
| 207 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END); |
| 208 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); |
| 209 gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &gfx::kGdkBlack); |
| 210 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); |
| 211 } else { |
| 212 DCHECK(link_button); |
| 213 // Need to insert the link inside the display text. |
| 214 GtkWidget* initial_label = gtk_label_new( |
| 215 WideToUTF8(display_text.substr(0, link_offset)).c_str()); |
| 216 GtkWidget* trailing_label = gtk_label_new( |
| 217 WideToUTF8(display_text.substr(link_offset)).c_str()); |
| 218 |
| 219 // TODO(joth): Unlike the right-align case above, none of the label widgets |
| 220 // are set as shrinkable here, meaning the text will run under the close |
| 221 // button etc. when the width is restricted, rather than eliding. |
| 222 gtk_widget_modify_fg(initial_label, GTK_STATE_NORMAL, &gfx::kGdkBlack); |
| 223 gtk_widget_modify_fg(trailing_label, GTK_STATE_NORMAL, &gfx::kGdkBlack); |
| 224 |
| 225 // We don't want any spacing between the elements, so we pack them into |
| 226 // this hbox that doesn't use kElementPadding. |
| 227 gtk_box_pack_start(GTK_BOX(hbox), initial_label, FALSE, FALSE, 0); |
| 228 gtk_util::CenterWidgetInHBox(hbox, link_button, false, link_padding); |
| 229 gtk_box_pack_start(GTK_BOX(hbox), trailing_label, FALSE, FALSE, 0); |
| 230 } |
| 231 } |
| 232 |
| 170 void InfoBar::UpdateBorderColor() { | 233 void InfoBar::UpdateBorderColor() { |
| 171 GdkColor border_color = theme_provider_->GetBorderColor(); | 234 GdkColor border_color = theme_provider_->GetBorderColor(); |
| 172 gtk_widget_modify_bg(border_bin_.get(), GTK_STATE_NORMAL, &border_color); | 235 gtk_widget_modify_bg(border_bin_.get(), GTK_STATE_NORMAL, &border_color); |
| 173 } | 236 } |
| 174 | 237 |
| 175 // static | 238 // static |
| 176 void InfoBar::OnCloseButton(GtkWidget* button, InfoBar* info_bar) { | 239 void InfoBar::OnCloseButton(GtkWidget* button, InfoBar* info_bar) { |
| 177 if (info_bar->delegate_) | 240 if (info_bar->delegate_) |
| 178 info_bar->delegate_->InfoBarDismissed(); | 241 info_bar->delegate_->InfoBarDismissed(); |
| 179 info_bar->RemoveInfoBar(); | 242 info_bar->RemoveInfoBar(); |
| 180 } | 243 } |
| 181 | 244 |
| 182 // AlertInfoBar ---------------------------------------------------------------- | 245 // AlertInfoBar ---------------------------------------------------------------- |
| 183 | 246 |
| 184 class AlertInfoBar : public InfoBar { | 247 class AlertInfoBar : public InfoBar { |
| 185 public: | 248 public: |
| 186 explicit AlertInfoBar(AlertInfoBarDelegate* delegate) | 249 explicit AlertInfoBar(AlertInfoBarDelegate* delegate) |
| 187 : InfoBar(delegate) { | 250 : InfoBar(delegate) { |
| 188 std::wstring text = delegate->GetMessageText(); | 251 AddLabelAndLink(delegate->GetMessageText(), std::wstring(), 0, 0, NULL); |
| 189 GtkWidget* label = gtk_label_new(WideToUTF8(text).c_str()); | |
| 190 // We want the label to be horizontally shrinkable, so that the Chrome | |
| 191 // window can be resized freely even with a very long message. | |
| 192 gtk_widget_set_size_request(label, 0, -1); | |
| 193 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END); | |
| 194 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); | |
| 195 gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &gfx::kGdkBlack); | |
| 196 gtk_box_pack_start(GTK_BOX(hbox_), label, TRUE, TRUE, 0); | |
| 197 | |
| 198 gtk_widget_show_all(border_bin_.get()); | 252 gtk_widget_show_all(border_bin_.get()); |
| 199 } | 253 } |
| 200 }; | 254 }; |
| 201 | 255 |
| 202 // LinkInfoBar ----------------------------------------------------------------- | 256 // LinkInfoBar ----------------------------------------------------------------- |
| 203 | 257 |
| 204 class LinkInfoBar : public InfoBar { | 258 class LinkInfoBar : public InfoBar { |
| 205 public: | 259 public: |
| 206 explicit LinkInfoBar(LinkInfoBarDelegate* delegate) | 260 explicit LinkInfoBar(LinkInfoBarDelegate* delegate) |
| 207 : InfoBar(delegate) { | 261 : InfoBar(delegate) { |
| 208 size_t link_offset; | 262 size_t link_offset; |
| 209 std::wstring display_text = | 263 std::wstring display_text = |
| 210 delegate->GetMessageTextWithOffset(&link_offset); | 264 delegate->GetMessageTextWithOffset(&link_offset); |
| 211 std::wstring link_text = delegate->GetLinkText(); | 265 std::wstring link_text = delegate->GetLinkText(); |
| 212 | 266 AddLabelAndLink(display_text, link_text, link_offset, 0, |
| 213 // Create the link button. | 267 G_CALLBACK(OnLinkClick)); |
| 214 GtkWidget* link_button = | |
| 215 gtk_chrome_link_button_new(WideToUTF8(link_text).c_str()); | |
| 216 gtk_chrome_link_button_set_use_gtk_theme( | |
| 217 GTK_CHROME_LINK_BUTTON(link_button), FALSE); | |
| 218 g_signal_connect(link_button, "clicked", | |
| 219 G_CALLBACK(OnLinkClick), this); | |
| 220 gtk_util::SetButtonTriggersNavigation(link_button); | |
| 221 | |
| 222 GtkWidget* hbox = gtk_hbox_new(FALSE, 0); | |
| 223 // We want the link to be horizontally shrinkable, so that the Chrome | |
| 224 // window can be resized freely even with a very long link. | |
| 225 gtk_widget_set_size_request(hbox, 0, -1); | |
| 226 gtk_box_pack_start(GTK_BOX(hbox_), hbox, TRUE, TRUE, 0); | |
| 227 // If link_offset is npos, we right-align the link instead of embedding it | |
| 228 // in the text. | |
| 229 if (link_offset == std::wstring::npos) { | |
| 230 gtk_box_pack_end(GTK_BOX(hbox), link_button, FALSE, FALSE, 0); | |
| 231 GtkWidget* label = gtk_label_new(WideToUTF8(display_text).c_str()); | |
| 232 // In order to avoid the link_button and the label overlapping with each | |
| 233 // other, we make the label shrinkable. | |
| 234 gtk_widget_set_size_request(label, 0, -1); | |
| 235 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END); | |
| 236 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); | |
| 237 gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &gfx::kGdkBlack); | |
| 238 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); | |
| 239 } else { | |
| 240 GtkWidget* initial_label = gtk_label_new( | |
| 241 WideToUTF8(display_text.substr(0, link_offset)).c_str()); | |
| 242 GtkWidget* trailing_label = gtk_label_new( | |
| 243 WideToUTF8(display_text.substr(link_offset)).c_str()); | |
| 244 | |
| 245 gtk_widget_modify_fg(initial_label, GTK_STATE_NORMAL, &gfx::kGdkBlack); | |
| 246 gtk_widget_modify_fg(trailing_label, GTK_STATE_NORMAL, &gfx::kGdkBlack); | |
| 247 | |
| 248 // We don't want any spacing between the elements, so we pack them into | |
| 249 // this hbox that doesn't use kElementPadding. | |
| 250 gtk_box_pack_start(GTK_BOX(hbox), initial_label, FALSE, FALSE, 0); | |
| 251 gtk_util::CenterWidgetInHBox(hbox, link_button, false, 0); | |
| 252 gtk_box_pack_start(GTK_BOX(hbox), trailing_label, FALSE, FALSE, 0); | |
| 253 } | |
| 254 | |
| 255 gtk_widget_show_all(border_bin_.get()); | 268 gtk_widget_show_all(border_bin_.get()); |
| 256 } | 269 } |
| 257 | 270 |
| 258 private: | 271 private: |
| 259 static void OnLinkClick(GtkWidget* button, LinkInfoBar* link_info_bar) { | 272 static void OnLinkClick(GtkWidget* button, LinkInfoBar* link_info_bar) { |
| 260 if (link_info_bar->delegate_->AsLinkInfoBarDelegate()-> | 273 if (link_info_bar->delegate_->AsLinkInfoBarDelegate()-> |
| 261 LinkClicked(gtk_util::DispositionForCurrentButtonPressEvent())) { | 274 LinkClicked(gtk_util::DispositionForCurrentButtonPressEvent())) { |
| 262 link_info_bar->RemoveInfoBar(); | 275 link_info_bar->RemoveInfoBar(); |
| 263 } | 276 } |
| 264 } | 277 } |
| 265 }; | 278 }; |
| 266 | 279 |
| 267 // ConfirmInfoBar -------------------------------------------------------------- | 280 // ConfirmInfoBar -------------------------------------------------------------- |
| 268 | 281 |
| 269 class ConfirmInfoBar : public AlertInfoBar { | 282 class ConfirmInfoBar : public InfoBar { |
| 270 public: | 283 public: |
| 271 explicit ConfirmInfoBar(ConfirmInfoBarDelegate* delegate) | 284 explicit ConfirmInfoBar(ConfirmInfoBarDelegate* delegate) |
| 272 : AlertInfoBar(delegate) { | 285 : InfoBar(delegate) { |
| 273 AddConfirmButton(ConfirmInfoBarDelegate::BUTTON_CANCEL); | 286 AddConfirmButton(ConfirmInfoBarDelegate::BUTTON_CANCEL); |
| 274 AddConfirmButton(ConfirmInfoBarDelegate::BUTTON_OK); | 287 AddConfirmButton(ConfirmInfoBarDelegate::BUTTON_OK); |
| 275 | 288 std::wstring display_text = delegate->GetMessageText(); |
| 289 std::wstring link_text = delegate->GetLinkText(); |
| 290 AddLabelAndLink(display_text, link_text, display_text.size(), |
| 291 kElementPadding, G_CALLBACK(OnLinkClick)); |
| 276 gtk_widget_show_all(border_bin_.get()); | 292 gtk_widget_show_all(border_bin_.get()); |
| 277 } | 293 } |
| 278 | 294 |
| 279 private: | 295 private: |
| 280 // Adds a button to the info bar by type. It will do nothing if the delegate | 296 // Adds a button to the info bar by type. It will do nothing if the delegate |
| 281 // doesn't specify a button of the given type. | 297 // doesn't specify a button of the given type. |
| 282 void AddConfirmButton(ConfirmInfoBarDelegate::InfoBarButton type) { | 298 void AddConfirmButton(ConfirmInfoBarDelegate::InfoBarButton type) { |
| 283 if (delegate_->AsConfirmInfoBarDelegate()->GetButtons() & type) { | 299 if (delegate_->AsConfirmInfoBarDelegate()->GetButtons() & type) { |
| 284 GtkWidget* button = gtk_button_new_with_label(WideToUTF8( | 300 GtkWidget* button = gtk_button_new_with_label(WideToUTF8( |
| 285 delegate_->AsConfirmInfoBarDelegate()->GetButtonLabel(type)).c_str()); | 301 delegate_->AsConfirmInfoBarDelegate()->GetButtonLabel(type)).c_str()); |
| 286 gtk_util::CenterWidgetInHBox(hbox_, button, true, 0); | 302 gtk_util::CenterWidgetInHBox(hbox_, button, true, 0); |
| 287 g_signal_connect(button, "clicked", | 303 g_signal_connect(button, "clicked", |
| 288 G_CALLBACK(type == ConfirmInfoBarDelegate::BUTTON_OK ? | 304 G_CALLBACK(type == ConfirmInfoBarDelegate::BUTTON_OK ? |
| 289 OnOkButton : OnCancelButton), | 305 OnOkButton : OnCancelButton), |
| 290 this); | 306 this); |
| 291 } | 307 } |
| 292 } | 308 } |
| 293 | 309 |
| 294 static void OnCancelButton(GtkWidget* button, ConfirmInfoBar* info_bar) { | 310 static void OnCancelButton(GtkWidget* button, ConfirmInfoBar* info_bar) { |
| 295 if (info_bar->delegate_->AsConfirmInfoBarDelegate()->Cancel()) | 311 if (info_bar->delegate_->AsConfirmInfoBarDelegate()->Cancel()) |
| 296 info_bar->RemoveInfoBar(); | 312 info_bar->RemoveInfoBar(); |
| 297 } | 313 } |
| 298 | 314 |
| 299 static void OnOkButton(GtkWidget* button, ConfirmInfoBar* info_bar) { | 315 static void OnOkButton(GtkWidget* button, ConfirmInfoBar* info_bar) { |
| 300 if (info_bar->delegate_->AsConfirmInfoBarDelegate()->Accept()) | 316 if (info_bar->delegate_->AsConfirmInfoBarDelegate()->Accept()) |
| 301 info_bar->RemoveInfoBar(); | 317 info_bar->RemoveInfoBar(); |
| 302 } | 318 } |
| 319 |
| 320 static void OnLinkClick(GtkWidget* button, ConfirmInfoBar* link_info_bar) { |
| 321 if (link_info_bar->delegate_->AsConfirmInfoBarDelegate()-> |
| 322 LinkClicked(gtk_util::DispositionForCurrentButtonPressEvent())) { |
| 323 link_info_bar->RemoveInfoBar(); |
| 324 } |
| 325 } |
| 303 }; | 326 }; |
| 304 | 327 |
| 305 // AlertInfoBarDelegate, InfoBarDelegate overrides: ---------------------------- | 328 // AlertInfoBarDelegate, InfoBarDelegate overrides: ---------------------------- |
| 306 | 329 |
| 307 InfoBar* AlertInfoBarDelegate::CreateInfoBar() { | 330 InfoBar* AlertInfoBarDelegate::CreateInfoBar() { |
| 308 return new AlertInfoBar(this); | 331 return new AlertInfoBar(this); |
| 309 } | 332 } |
| 310 | 333 |
| 311 // LinkInfoBarDelegate, InfoBarDelegate overrides: ----------------------------- | 334 // LinkInfoBarDelegate, InfoBarDelegate overrides: ----------------------------- |
| 312 | 335 |
| 313 InfoBar* LinkInfoBarDelegate::CreateInfoBar() { | 336 InfoBar* LinkInfoBarDelegate::CreateInfoBar() { |
| 314 return new LinkInfoBar(this); | 337 return new LinkInfoBar(this); |
| 315 } | 338 } |
| 316 | 339 |
| 317 // ConfirmInfoBarDelegate, InfoBarDelegate overrides: -------------------------- | 340 // ConfirmInfoBarDelegate, InfoBarDelegate overrides: -------------------------- |
| 318 | 341 |
| 319 InfoBar* ConfirmInfoBarDelegate::CreateInfoBar() { | 342 InfoBar* ConfirmInfoBarDelegate::CreateInfoBar() { |
| 320 return new ConfirmInfoBar(this); | 343 return new ConfirmInfoBar(this); |
| 321 } | 344 } |
| OLD | NEW |