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

Side by Side Diff: chrome/browser/ui/gtk/global_bookmarks_menu.cc

Issue 6980011: GTK: Implement the global bookmarks menu. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remove show Created 9 years, 7 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
OLDNEW
(Empty)
1 // Copyright (c) 2011 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/ui/gtk/global_bookmarks_menu.h"
6
7 #include <gtk/gtk.h>
8
9 #include "base/logging.h"
10 #include "base/utf_string_conversions.h"
11 #include "chrome/browser/bookmarks/bookmark_model.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/browser/ui/gtk/global_bookmarks_menu.h"
15 #include "chrome/browser/ui/gtk/global_menu_bar.h"
16 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
17 #include "chrome/browser/ui/gtk/gtk_util.h"
18 #include "content/common/notification_service.h"
19 #include "grit/generated_resources.h"
20 #include "ui/base/l10n/l10n_util.h"
21 #include "ui/gfx/gtk_util.h"
22
23 namespace {
24
25 const int kMaxChars = 50;
26
27 } // namespace
28
29 GlobalBookmarksMenu::GlobalBookmarksMenu(Browser* browser)
30 : browser_(browser),
31 profile_(browser->profile()),
32 default_favicon_(NULL) {
33 DCHECK(profile_);
34
35 // Move to Init(GtkWidget* bookmark_menu);
36 default_favicon_ = GtkThemeService::GetDefaultFavicon(true);
37 default_folder_ = GtkThemeService::GetFolderIcon(true);
38 registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
39 Source<Profile>(profile_));
40 }
41
42 GlobalBookmarksMenu::~GlobalBookmarksMenu() {
43 profile_->GetBookmarkModel()->RemoveObserver(this);
44 }
45
46 void GlobalBookmarksMenu::Init(GtkWidget* bookmark_menu) {
47 bookmark_menu_ = bookmark_menu;
48
49 BookmarkModel* model = profile_->GetBookmarkModel();
50 model->AddObserver(this);
51 if (model->IsLoaded())
52 Loaded(model);
53 }
54
55 void GlobalBookmarksMenu::RebuildMenuInFuture() {
56 menu_build_timer_.Stop();
57 menu_build_timer_.Start(base::TimeDelta::FromMilliseconds(10), this,
58 &GlobalBookmarksMenu::RebuildMenu);
59 }
60
61 void GlobalBookmarksMenu::RebuildMenu() {
62 BookmarkModel* model = profile_->GetBookmarkModel();
63 DCHECK(model);
64 DCHECK(model->IsLoaded());
65
66 ClearBookmarkMenu();
67
68 const BookmarkNode* bar_node = model->GetBookmarkBarNode();
69 if (bar_node->child_count()) {
70 AddBookmarkMenuItem(bookmark_menu_, gtk_separator_menu_item_new());
71 AddNodeToMenu(bar_node, bookmark_menu_);
72 }
73
74 // Only display the other bookmarks folder in the menu if it has items in it.
Evan Stade 2011/05/10 17:09:18 wouldn't this make it impossible to add thing #1 t
Elliot Glaysher 2011/05/10 18:29:28 "Other Bookmarks" won't be shown when empty for lo
75 const BookmarkNode* other_node = model->other_node();
76 if (other_node->child_count()) {
77 GtkWidget* submenu = gtk_menu_new();
78 AddNodeToMenu(other_node, submenu);
79
80 AddBookmarkMenuItem(bookmark_menu_, gtk_separator_menu_item_new());
81
82 GtkWidget* menu_item = gtk_image_menu_item_new_with_label(
83 l10n_util::GetStringUTF8(IDS_BOOMARK_BAR_OTHER_FOLDER_NAME).c_str());
84 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu);
85 gtk_image_menu_item_set_image(
86 GTK_IMAGE_MENU_ITEM(menu_item),
87 gtk_image_new_from_pixbuf(default_folder_));
88
89 AddBookmarkMenuItem(bookmark_menu_, menu_item);
90 }
91 }
92
93 void GlobalBookmarksMenu::AddBookmarkMenuItem(GtkWidget* menu,
94 GtkWidget* menu_item) {
95 g_object_set_data(G_OBJECT(menu_item), "type-tag",
96 GINT_TO_POINTER(GlobalMenuBar::TAG_BOOKMARK_CLEARABLE));
97 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
98 gtk_widget_show(menu_item);
99 }
100
101 void GlobalBookmarksMenu::AddNodeToMenu(const BookmarkNode* node,
102 GtkWidget* menu) {
103 int child_count = node->child_count();
104 if (!child_count) {
105 GtkWidget* item = gtk_menu_item_new_with_label(
106 l10n_util::GetStringUTF8(IDS_MENU_EMPTY_SUBMENU).c_str());
107 gtk_widget_set_sensitive(item, FALSE);
108 AddBookmarkMenuItem(menu, item);
109 } else {
110 for (int i = 0; i < child_count; i++) {
111 const BookmarkNode* child = node->GetChild(i);
112 GtkWidget* item = gtk_image_menu_item_new();
113 ConfigureMenuItem(child, item);
114 bookmark_nodes_[child] = item;
115
116 if (child->is_folder()) {
117 GtkWidget* submenu = gtk_menu_new();
118 AddNodeToMenu(child, submenu);
119 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
120 } else {
121 g_object_set_data(G_OBJECT(item), "bookmark-node",
122 const_cast<BookmarkNode*>(child));
123 g_signal_connect(item, "activate",
124 G_CALLBACK(OnBookmarkItemActivatedThunk), this);
125 }
126
127 AddBookmarkMenuItem(menu, item);
128 }
129 }
130 }
131
132 void GlobalBookmarksMenu::ConfigureMenuItem(const BookmarkNode* node,
133 GtkWidget* menu_item) {
134 string16 elided_name = l10n_util::TruncateString(node->GetTitle(), kMaxChars);
135 gtk_menu_item_set_label(GTK_MENU_ITEM(menu_item),
136 UTF16ToUTF8(elided_name).c_str());
137
138 if (node->is_url()) {
139 std::string tooltip = gtk_util::BuildTooltipTitleFor(node->GetTitle(),
140 node->GetURL());
141 gtk_widget_set_tooltip_markup(menu_item, tooltip.c_str());
142 }
143
144 const SkBitmap& bitmap = profile_->GetBookmarkModel()->GetFavicon(node);
145 if (!bitmap.isNull()) {
146 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&bitmap);
147 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
148 gtk_image_new_from_pixbuf(pixbuf));
149 g_object_unref(pixbuf);
150 } else {
151 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
152 gtk_image_new_from_pixbuf(
153 node->is_url() ? default_favicon_ :
154 default_folder_));
155 }
156 }
157
158 GtkWidget* GlobalBookmarksMenu::MenuItemForNode(const BookmarkNode* node) {
159 if (!node)
160 return NULL;
161 std::map<const BookmarkNode*, GtkWidget*>::iterator it =
162 bookmark_nodes_.find(node);
163 if (it == bookmark_nodes_.end())
164 return NULL;
165 return it->second;
166 }
167
168 void GlobalBookmarksMenu::ClearBookmarkMenu() {
169 bookmark_nodes_.clear();
170
171 gtk_container_foreach(GTK_CONTAINER(bookmark_menu_),
172 &ClearBookmarkItemCallback,
173 NULL);
174 }
175
176 // static
177 void GlobalBookmarksMenu::ClearBookmarkItemCallback(GtkWidget* menu_item,
178 void* /*unused*/) {
Evan Stade 2011/05/10 17:09:18 I don't think this is within style guidelines
179 int tag = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu_item), "type-tag"));
180 if (tag == GlobalMenuBar::TAG_BOOKMARK_CLEARABLE)
181 gtk_widget_destroy(menu_item);
182 }
183
184 void GlobalBookmarksMenu::Observe(NotificationType type,
185 const NotificationSource& source,
186 const NotificationDetails& details) {
187 DCHECK(type.value == NotificationType::BROWSER_THEME_CHANGED);
188
189 // Change the icon and invalidate the menu.
190 default_favicon_ = GtkThemeService::GetDefaultFavicon(true);
191 default_folder_ = GtkThemeService::GetFolderIcon(true);
192 RebuildMenuInFuture();
193 }
194
195 void GlobalBookmarksMenu::Loaded(BookmarkModel* model) {
196 // If we have a Loaded() event, then we need to build the menu immediately
197 // for the first time.
198 RebuildMenu();
199 }
200
201 void GlobalBookmarksMenu::BookmarkModelBeingDeleted(BookmarkModel* model) {
202 ClearBookmarkMenu();
203 }
204
205 void GlobalBookmarksMenu::BookmarkNodeMoved(BookmarkModel* model,
206 const BookmarkNode* old_parent,
207 int old_index,
208 const BookmarkNode* new_parent,
209 int new_index) {
210 RebuildMenuInFuture();
Evan Stade 2011/05/10 17:09:18 when you get a batch of NodeMoved/Added calls, are
211 }
212
213 void GlobalBookmarksMenu::BookmarkNodeAdded(BookmarkModel* model,
214 const BookmarkNode* parent,
215 int index) {
216 RebuildMenuInFuture();
217 }
218
219 void GlobalBookmarksMenu::BookmarkNodeRemoved(BookmarkModel* model,
220 const BookmarkNode* parent,
221 int old_index,
222 const BookmarkNode* node) {
223 GtkWidget* item = MenuItemForNode(node);
224 if (item) {
225 gtk_widget_destroy(item);
226 bookmark_nodes_.erase(node);
227 }
228 }
229
230 void GlobalBookmarksMenu::BookmarkNodeChanged(BookmarkModel* model,
231 const BookmarkNode* node) {
232 GtkWidget* item = MenuItemForNode(node);
233 if (item)
234 ConfigureMenuItem(node, item);
235 }
236
237 void GlobalBookmarksMenu::BookmarkNodeFaviconLoaded(BookmarkModel* model,
238 const BookmarkNode* node) {
239 GtkWidget* item = MenuItemForNode(node);
240 if (item)
241 ConfigureMenuItem(node, item);
242 }
243
244 void GlobalBookmarksMenu::BookmarkNodeChildrenReordered(
245 BookmarkModel* model,
246 const BookmarkNode* node) {
247 RebuildMenuInFuture();
248 }
249
250 void GlobalBookmarksMenu::OnBookmarkItemActivated(GtkWidget* menu_item) {
251 // The actual mouse event that generated this activated event was in a
252 // different process. Go with something default.
253 const BookmarkNode* node = static_cast<const BookmarkNode*>(
254 g_object_get_data(G_OBJECT(menu_item), "bookmark-node"));
255
256 browser_->OpenURL(node->GetURL(), GURL(), NEW_FOREGROUND_TAB,
257 PageTransition::AUTO_BOOKMARK);
258 }
259
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698