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/bookmark_bar_gtk.h" | 5 #include "chrome/browser/gtk/bookmark_bar_gtk.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "app/gfx/text_elider.h" | 9 #include "app/gfx/text_elider.h" |
10 #include "app/gtk_dnd_util.h" | 10 #include "app/gtk_dnd_util.h" |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
94 BrowserWindowGtk* window) | 94 BrowserWindowGtk* window) |
95 : profile_(NULL), | 95 : profile_(NULL), |
96 page_navigator_(NULL), | 96 page_navigator_(NULL), |
97 browser_(browser), | 97 browser_(browser), |
98 window_(window), | 98 window_(window), |
99 model_(NULL), | 99 model_(NULL), |
100 instructions_(NULL), | 100 instructions_(NULL), |
101 dragged_node_(NULL), | 101 dragged_node_(NULL), |
102 toolbar_drop_item_(NULL), | 102 toolbar_drop_item_(NULL), |
103 theme_provider_(GtkThemeProvider::GetFrom(profile)), | 103 theme_provider_(GtkThemeProvider::GetFrom(profile)), |
104 show_instructions_(true) { | 104 show_instructions_(true), |
| 105 menu_bar_helper_(this) { |
105 Init(profile); | 106 Init(profile); |
106 SetProfile(profile); | 107 SetProfile(profile); |
107 | 108 |
108 registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, | 109 registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, |
109 NotificationService::AllSources()); | 110 NotificationService::AllSources()); |
110 } | 111 } |
111 | 112 |
112 BookmarkBarGtk::~BookmarkBarGtk() { | 113 BookmarkBarGtk::~BookmarkBarGtk() { |
113 if (model_) | 114 if (model_) |
114 model_->RemoveObserver(this); | 115 model_->RemoveObserver(this); |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
302 | 303 |
303 void BookmarkBarGtk::BookmarkNodeAdded(BookmarkModel* model, | 304 void BookmarkBarGtk::BookmarkNodeAdded(BookmarkModel* model, |
304 const BookmarkNode* parent, | 305 const BookmarkNode* parent, |
305 int index) { | 306 int index) { |
306 if (parent != model_->GetBookmarkBarNode()) { | 307 if (parent != model_->GetBookmarkBarNode()) { |
307 // We only care about nodes on the bookmark bar. | 308 // We only care about nodes on the bookmark bar. |
308 return; | 309 return; |
309 } | 310 } |
310 DCHECK(index >= 0 && index <= GetBookmarkButtonCount()); | 311 DCHECK(index >= 0 && index <= GetBookmarkButtonCount()); |
311 | 312 |
312 GtkToolItem* item = CreateBookmarkToolItem(parent->GetChild(index)); | 313 const BookmarkNode* node = parent->GetChild(index); |
| 314 GtkToolItem* item = CreateBookmarkToolItem(node); |
313 gtk_toolbar_insert(GTK_TOOLBAR(bookmark_toolbar_.get()), | 315 gtk_toolbar_insert(GTK_TOOLBAR(bookmark_toolbar_.get()), |
314 item, index); | 316 item, index); |
| 317 if (node->is_folder()) |
| 318 menu_bar_helper_.Add(gtk_bin_get_child(GTK_BIN(item))); |
315 | 319 |
316 SetInstructionState(); | 320 SetInstructionState(); |
317 SetChevronState(); | 321 SetChevronState(); |
318 } | 322 } |
319 | 323 |
320 void BookmarkBarGtk::BookmarkNodeRemoved(BookmarkModel* model, | 324 void BookmarkBarGtk::BookmarkNodeRemoved(BookmarkModel* model, |
321 const BookmarkNode* parent, | 325 const BookmarkNode* parent, |
322 int old_index, | 326 int old_index, |
323 const BookmarkNode* node) { | 327 const BookmarkNode* node) { |
324 if (parent != model_->GetBookmarkBarNode()) { | 328 if (parent != model_->GetBookmarkBarNode()) { |
325 // We only care about nodes on the bookmark bar. | 329 // We only care about nodes on the bookmark bar. |
326 return; | 330 return; |
327 } | 331 } |
328 DCHECK(old_index >= 0 && old_index < GetBookmarkButtonCount()); | 332 DCHECK(old_index >= 0 && old_index < GetBookmarkButtonCount()); |
329 | 333 |
330 GtkWidget* to_remove = GTK_WIDGET(gtk_toolbar_get_nth_item( | 334 GtkWidget* to_remove = GTK_WIDGET(gtk_toolbar_get_nth_item( |
331 GTK_TOOLBAR(bookmark_toolbar_.get()), old_index)); | 335 GTK_TOOLBAR(bookmark_toolbar_.get()), old_index)); |
| 336 menu_bar_helper_.Remove(gtk_bin_get_child(GTK_BIN(to_remove))); |
332 gtk_container_remove(GTK_CONTAINER(bookmark_toolbar_.get()), | 337 gtk_container_remove(GTK_CONTAINER(bookmark_toolbar_.get()), |
333 to_remove); | 338 to_remove); |
334 | 339 |
335 SetInstructionState(); | 340 SetInstructionState(); |
336 SetChevronState(); | 341 SetChevronState(); |
337 } | 342 } |
338 | 343 |
339 void BookmarkBarGtk::BookmarkNodeChanged(BookmarkModel* model, | 344 void BookmarkBarGtk::BookmarkNodeChanged(BookmarkModel* model, |
340 const BookmarkNode* node) { | 345 const BookmarkNode* node) { |
341 if (node->GetParent() != model_->GetBookmarkBarNode()) { | 346 if (node->GetParent() != model_->GetBookmarkBarNode()) { |
(...skipping 26 matching lines...) Expand all Loading... |
368 } | 373 } |
369 | 374 |
370 void BookmarkBarGtk::CreateAllBookmarkButtons() { | 375 void BookmarkBarGtk::CreateAllBookmarkButtons() { |
371 const BookmarkNode* node = model_->GetBookmarkBarNode(); | 376 const BookmarkNode* node = model_->GetBookmarkBarNode(); |
372 DCHECK(node && model_->other_node()); | 377 DCHECK(node && model_->other_node()); |
373 | 378 |
374 // Create a button for each of the children on the bookmark bar. | 379 // Create a button for each of the children on the bookmark bar. |
375 for (int i = 0; i < node->GetChildCount(); ++i) { | 380 for (int i = 0; i < node->GetChildCount(); ++i) { |
376 GtkToolItem* item = CreateBookmarkToolItem(node->GetChild(i)); | 381 GtkToolItem* item = CreateBookmarkToolItem(node->GetChild(i)); |
377 gtk_toolbar_insert(GTK_TOOLBAR(bookmark_toolbar_.get()), item, -1); | 382 gtk_toolbar_insert(GTK_TOOLBAR(bookmark_toolbar_.get()), item, -1); |
| 383 if (node->is_folder()) |
| 384 menu_bar_helper_.Add(gtk_bin_get_child(GTK_BIN(item))); |
378 } | 385 } |
379 | 386 |
380 bookmark_utils::ConfigureButtonForNode(model_->other_node(), | 387 bookmark_utils::ConfigureButtonForNode(model_->other_node(), |
381 model_, other_bookmarks_button_, theme_provider_); | 388 model_, other_bookmarks_button_, theme_provider_); |
382 | 389 |
383 SetInstructionState(); | 390 SetInstructionState(); |
384 SetChevronState(); | 391 SetChevronState(); |
385 } | 392 } |
386 | 393 |
387 void BookmarkBarGtk::SetInstructionState() { | 394 void BookmarkBarGtk::SetInstructionState() { |
388 show_instructions_ = (model_->GetBookmarkBarNode()->GetChildCount() == 0); | 395 show_instructions_ = (model_->GetBookmarkBarNode()->GetChildCount() == 0); |
389 if (show_instructions_) { | 396 if (show_instructions_) { |
390 gtk_widget_show_all(instructions_); | 397 gtk_widget_show_all(instructions_); |
391 } else { | 398 } else { |
392 gtk_widget_hide(instructions_); | 399 gtk_widget_hide(instructions_); |
393 } | 400 } |
394 } | 401 } |
395 | 402 |
396 void BookmarkBarGtk::SetChevronState() { | 403 void BookmarkBarGtk::SetChevronState() { |
397 int extra_space = 0; | 404 int extra_space = 0; |
398 | 405 |
399 if (GTK_WIDGET_VISIBLE(overflow_button_)) | 406 if (GTK_WIDGET_VISIBLE(overflow_button_)) |
400 extra_space = overflow_button_->allocation.width; | 407 extra_space = overflow_button_->allocation.width; |
401 | 408 |
402 int overflow_idx = GetFirstHiddenBookmark(extra_space); | 409 int overflow_idx = GetFirstHiddenBookmark(extra_space, NULL); |
403 if (overflow_idx == -1) | 410 if (overflow_idx == -1) |
404 gtk_widget_hide(overflow_button_); | 411 gtk_widget_hide(overflow_button_); |
405 else | 412 else |
406 gtk_widget_show_all(overflow_button_); | 413 gtk_widget_show_all(overflow_button_); |
407 } | 414 } |
408 | 415 |
409 void BookmarkBarGtk::RemoveAllBookmarkButtons() { | 416 void BookmarkBarGtk::RemoveAllBookmarkButtons() { |
410 gtk_util::RemoveAllChildren(bookmark_toolbar_.get()); | 417 gtk_util::RemoveAllChildren(bookmark_toolbar_.get()); |
| 418 menu_bar_helper_.Clear(); |
| 419 menu_bar_helper_.Add(other_bookmarks_button_); |
| 420 menu_bar_helper_.Add(overflow_button_); |
411 } | 421 } |
412 | 422 |
413 int BookmarkBarGtk::GetBookmarkButtonCount() { | 423 int BookmarkBarGtk::GetBookmarkButtonCount() { |
414 GList* children = gtk_container_get_children( | 424 GList* children = gtk_container_get_children( |
415 GTK_CONTAINER(bookmark_toolbar_.get())); | 425 GTK_CONTAINER(bookmark_toolbar_.get())); |
416 int count = g_list_length(children); | 426 int count = g_list_length(children); |
417 g_list_free(children); | 427 g_list_free(children); |
418 return count; | 428 return count; |
419 } | 429 } |
420 | 430 |
421 void BookmarkBarGtk::SetOverflowButtonAppearance() { | 431 void BookmarkBarGtk::SetOverflowButtonAppearance() { |
422 GtkWidget* former_child = gtk_bin_get_child(GTK_BIN(overflow_button_)); | 432 GtkWidget* former_child = gtk_bin_get_child(GTK_BIN(overflow_button_)); |
423 if (former_child) | 433 if (former_child) |
424 gtk_widget_destroy(former_child); | 434 gtk_widget_destroy(former_child); |
425 | 435 |
426 GtkWidget* new_child = theme_provider_->UseGtkTheme() ? | 436 GtkWidget* new_child = theme_provider_->UseGtkTheme() ? |
427 gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE) : | 437 gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE) : |
428 gtk_image_new_from_pixbuf(ResourceBundle::GetSharedInstance(). | 438 gtk_image_new_from_pixbuf(ResourceBundle::GetSharedInstance(). |
429 GetRTLEnabledPixbufNamed(IDR_BOOKMARK_BAR_CHEVRONS)); | 439 GetRTLEnabledPixbufNamed(IDR_BOOKMARK_BAR_CHEVRONS)); |
430 | 440 |
431 gtk_container_add(GTK_CONTAINER(overflow_button_), new_child); | 441 gtk_container_add(GTK_CONTAINER(overflow_button_), new_child); |
432 SetChevronState(); | 442 SetChevronState(); |
433 } | 443 } |
434 | 444 |
435 int BookmarkBarGtk::GetFirstHiddenBookmark(int extra_space) { | 445 int BookmarkBarGtk::GetFirstHiddenBookmark( |
| 446 int extra_space, std::vector<GtkWidget*>* showing_folders) { |
436 int rv = 0; | 447 int rv = 0; |
437 bool overflow = false; | 448 bool overflow = false; |
438 GList* toolbar_items = | 449 GList* toolbar_items = |
439 gtk_container_get_children(GTK_CONTAINER(bookmark_toolbar_.get())); | 450 gtk_container_get_children(GTK_CONTAINER(bookmark_toolbar_.get())); |
440 for (GList* iter = toolbar_items; iter; iter = g_list_next(iter)) { | 451 for (GList* iter = toolbar_items; iter; iter = g_list_next(iter)) { |
441 GtkWidget* tool_item = reinterpret_cast<GtkWidget*>(iter->data); | 452 GtkWidget* tool_item = reinterpret_cast<GtkWidget*>(iter->data); |
442 if (tool_item->allocation.x + tool_item->allocation.width > | 453 if (tool_item->allocation.x + tool_item->allocation.width > |
443 bookmark_toolbar_.get()->allocation.width + extra_space) { | 454 bookmark_toolbar_.get()->allocation.width + extra_space) { |
444 overflow = true; | 455 overflow = true; |
445 break; | 456 break; |
446 } | 457 } |
| 458 if (showing_folders && |
| 459 model_->GetBookmarkBarNode()->GetChild(rv)->is_folder()) { |
| 460 showing_folders->push_back(gtk_bin_get_child(GTK_BIN(tool_item))); |
| 461 } |
447 rv++; | 462 rv++; |
448 } | 463 } |
449 | 464 |
450 g_list_free(toolbar_items); | 465 g_list_free(toolbar_items); |
451 | 466 |
452 if (!overflow) | 467 if (!overflow) |
453 return -1; | 468 return -1; |
454 | 469 |
455 return rv; | 470 return rv; |
456 } | 471 } |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
523 if (node->is_url()) { | 538 if (node->is_url()) { |
524 // Connect to 'button-release-event' instead of 'clicked' because we need | 539 // Connect to 'button-release-event' instead of 'clicked' because we need |
525 // access to the modifier keys and we do different things on each | 540 // access to the modifier keys and we do different things on each |
526 // button. | 541 // button. |
527 g_signal_connect(G_OBJECT(button), "button-press-event", | 542 g_signal_connect(G_OBJECT(button), "button-press-event", |
528 G_CALLBACK(OnButtonPressed), this); | 543 G_CALLBACK(OnButtonPressed), this); |
529 g_signal_connect(G_OBJECT(button), "clicked", | 544 g_signal_connect(G_OBJECT(button), "clicked", |
530 G_CALLBACK(OnClicked), this); | 545 G_CALLBACK(OnClicked), this); |
531 gtk_util::SetButtonTriggersNavigation(button); | 546 gtk_util::SetButtonTriggersNavigation(button); |
532 } else { | 547 } else { |
533 // TODO(erg): This button can also be a drop target. | |
534 ConnectFolderButtonEvents(button); | 548 ConnectFolderButtonEvents(button); |
535 } | 549 } |
536 | 550 |
537 return button; | 551 return button; |
538 } | 552 } |
539 | 553 |
540 GtkToolItem* BookmarkBarGtk::CreateBookmarkToolItem(const BookmarkNode* node) { | 554 GtkToolItem* BookmarkBarGtk::CreateBookmarkToolItem(const BookmarkNode* node) { |
541 GtkWidget* button = CreateBookmarkButton(node); | 555 GtkWidget* button = CreateBookmarkButton(node); |
542 g_object_set_data(G_OBJECT(button), "left-align-popup", | 556 g_object_set_data(G_OBJECT(button), "left-align-popup", |
543 reinterpret_cast<void*>(true)); | 557 reinterpret_cast<void*>(true)); |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
706 guint target_type, guint time, | 720 guint target_type, guint time, |
707 BookmarkBarGtk* bar) { | 721 BookmarkBarGtk* bar) { |
708 const BookmarkNode* node = bookmark_utils::BookmarkNodeForWidget(widget); | 722 const BookmarkNode* node = bookmark_utils::BookmarkNodeForWidget(widget); |
709 bookmark_utils::WriteBookmarkToSelection(node, selection_data, target_type, | 723 bookmark_utils::WriteBookmarkToSelection(node, selection_data, target_type, |
710 bar->profile_); | 724 bar->profile_); |
711 } | 725 } |
712 | 726 |
713 // static | 727 // static |
714 void BookmarkBarGtk::OnFolderClicked(GtkWidget* sender, | 728 void BookmarkBarGtk::OnFolderClicked(GtkWidget* sender, |
715 BookmarkBarGtk* bar) { | 729 BookmarkBarGtk* bar) { |
716 const BookmarkNode* node = bar->GetNodeForToolButton(sender); | 730 bar->PopupForButton(sender); |
717 DCHECK(node); | |
718 DCHECK(bar->page_navigator_); | |
719 | |
720 int start_child_idx = 0; | |
721 if (sender == bar->overflow_button_) | |
722 start_child_idx = bar->GetFirstHiddenBookmark(0); | |
723 | |
724 bar->current_menu_.reset( | |
725 new BookmarkMenuController(bar->browser_, bar->profile_, | |
726 bar->page_navigator_, | |
727 GTK_WINDOW(gtk_widget_get_toplevel(sender)), | |
728 node, | |
729 start_child_idx, | |
730 false)); | |
731 GdkEventButton* event = | |
732 reinterpret_cast<GdkEventButton*>(gtk_get_current_event()); | |
733 bar->current_menu_->Popup(sender, event->button, event->time); | |
734 } | 731 } |
735 | 732 |
736 // static | 733 // static |
737 gboolean BookmarkBarGtk::OnToolbarExpose(GtkWidget* widget, | 734 gboolean BookmarkBarGtk::OnToolbarExpose(GtkWidget* widget, |
738 GdkEventExpose* event, | 735 GdkEventExpose* event, |
739 BookmarkBarGtk* bar) { | 736 BookmarkBarGtk* bar) { |
740 // A GtkToolbar's expose handler first draws a box. We don't want that so we | 737 // A GtkToolbar's expose handler first draws a box. We don't want that so we |
741 // need to propagate the expose event to all the container's children. | 738 // need to propagate the expose event to all the container's children. |
742 GList* children = gtk_container_get_children(GTK_CONTAINER(widget)); | 739 GList* children = gtk_container_get_children(GTK_CONTAINER(widget)); |
743 for (GList* item = children; item; item = item->next) { | 740 for (GList* item = children; item; item = item->next) { |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
957 cairo_set_line_width(cr, 1.0); | 954 cairo_set_line_width(cr, 1.0); |
958 cairo_move_to(cr, start_x, widget->allocation.y); | 955 cairo_move_to(cr, start_x, widget->allocation.y); |
959 cairo_line_to(cr, start_x, | 956 cairo_line_to(cr, start_x, |
960 widget->allocation.y + widget->allocation.height); | 957 widget->allocation.y + widget->allocation.height); |
961 cairo_stroke(cr); | 958 cairo_stroke(cr); |
962 cairo_destroy(cr); | 959 cairo_destroy(cr); |
963 cairo_pattern_destroy(pattern); | 960 cairo_pattern_destroy(pattern); |
964 | 961 |
965 return TRUE; | 962 return TRUE; |
966 } | 963 } |
| 964 |
| 965 // MenuBarHelper::Delegate implementation -------------------------------------- |
| 966 void BookmarkBarGtk::PopupForButton(GtkWidget* button) { |
| 967 const BookmarkNode* node = GetNodeForToolButton(button); |
| 968 DCHECK(node); |
| 969 DCHECK(page_navigator_); |
| 970 |
| 971 int first_hidden = GetFirstHiddenBookmark(0, NULL); |
| 972 if (button != overflow_button_ && button != other_bookmarks_button_ && |
| 973 node->GetParent()->IndexOfChild(node) >= first_hidden) { |
| 974 return; |
| 975 } |
| 976 |
| 977 current_menu_.reset( |
| 978 new BookmarkMenuController(browser_, profile_, |
| 979 page_navigator_, |
| 980 GTK_WINDOW(gtk_widget_get_toplevel(button)), |
| 981 node, |
| 982 button == overflow_button_ ? |
| 983 first_hidden : 0, |
| 984 false)); |
| 985 menu_bar_helper_.MenuStartedShowing(button, current_menu_->widget()); |
| 986 GdkEventButton* event = |
| 987 reinterpret_cast<GdkEventButton*>(gtk_get_current_event()); |
| 988 current_menu_->Popup(button, event->button, event->time); |
| 989 } |
| 990 |
| 991 void BookmarkBarGtk::PopupForButtonNextTo(GtkWidget* button, |
| 992 GtkMenuDirectionType dir) { |
| 993 const BookmarkNode* relative_node = GetNodeForToolButton(button); |
| 994 DCHECK(relative_node); |
| 995 |
| 996 // Find out the order of the buttons. |
| 997 std::vector<GtkWidget*> folder_list; |
| 998 const int first_hidden = GetFirstHiddenBookmark(0, &folder_list); |
| 999 if (first_hidden != -1) |
| 1000 folder_list.push_back(overflow_button_); |
| 1001 folder_list.push_back(other_bookmarks_button_); |
| 1002 |
| 1003 // Find the position of |button|. |
| 1004 int button_idx = -1; |
| 1005 for (size_t i = 0; i < folder_list.size(); ++i) { |
| 1006 if (folder_list[i] == button) { |
| 1007 button_idx = i; |
| 1008 break; |
| 1009 } |
| 1010 } |
| 1011 DCHECK_NE(button_idx, -1); |
| 1012 |
| 1013 // Find the GtkWidget* for the actual target button. |
| 1014 int shift = dir == GTK_MENU_DIR_PARENT ? -1 : 1; |
| 1015 button_idx = (button_idx + shift + folder_list.size()) % folder_list.size(); |
| 1016 PopupForButton(folder_list[button_idx]); |
| 1017 } |
OLD | NEW |