| 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/gtk/bookmark_editor_gtk.h" | |
| 6 | |
| 7 #include <gtk/gtk.h> | |
| 8 | |
| 9 #include "app/l10n_util.h" | |
| 10 #include "app/menus/simple_menu_model.h" | |
| 11 #include "base/basictypes.h" | |
| 12 #include "base/logging.h" | |
| 13 #include "base/string_util.h" | |
| 14 #include "base/utf_string_conversions.h" | |
| 15 #include "chrome/browser/bookmarks/bookmark_model.h" | |
| 16 #include "chrome/browser/bookmarks/bookmark_utils.h" | |
| 17 #include "chrome/browser/gtk/bookmark_tree_model.h" | |
| 18 #include "chrome/browser/gtk/bookmark_utils_gtk.h" | |
| 19 #include "chrome/browser/gtk/gtk_theme_provider.h" | |
| 20 #include "chrome/browser/gtk/gtk_util.h" | |
| 21 #include "chrome/browser/history/history.h" | |
| 22 #include "chrome/browser/net/url_fixer_upper.h" | |
| 23 #include "chrome/browser/profiles/profile.h" | |
| 24 #include "gfx/gtk_util.h" | |
| 25 #include "gfx/point.h" | |
| 26 #include "googleurl/src/gurl.h" | |
| 27 #include "grit/chromium_strings.h" | |
| 28 #include "grit/generated_resources.h" | |
| 29 #include "grit/locale_settings.h" | |
| 30 | |
| 31 #if defined(TOOLKIT_VIEWS) | |
| 32 #include "views/controls/menu/menu_2.h" | |
| 33 #else | |
| 34 #include "chrome/browser/gtk/menu_gtk.h" | |
| 35 #endif | |
| 36 | |
| 37 namespace { | |
| 38 | |
| 39 // Background color of text field when URL is invalid. | |
| 40 const GdkColor kErrorColor = GDK_COLOR_RGB(0xFF, 0xBC, 0xBC); | |
| 41 | |
| 42 // Preferred initial dimensions, in pixels, of the folder tree. | |
| 43 static const int kTreeWidth = 300; | |
| 44 static const int kTreeHeight = 150; | |
| 45 | |
| 46 } // namespace | |
| 47 | |
| 48 class BookmarkEditorGtk::ContextMenuController | |
| 49 : public menus::SimpleMenuModel::Delegate { | |
| 50 public: | |
| 51 explicit ContextMenuController(BookmarkEditorGtk* editor) | |
| 52 : editor_(editor), | |
| 53 running_menu_for_root_(false) { | |
| 54 menu_model_.reset(new menus::SimpleMenuModel(this)); | |
| 55 menu_model_->AddItemWithStringId(COMMAND_EDIT, IDS_EDIT); | |
| 56 menu_model_->AddItemWithStringId( | |
| 57 COMMAND_NEW_FOLDER, | |
| 58 IDS_BOOMARK_EDITOR_NEW_FOLDER_MENU_ITEM); | |
| 59 #if defined(TOOLKIT_VIEWS) | |
| 60 menu_.reset(new views::Menu2(menu_model_.get())); | |
| 61 #else | |
| 62 menu_.reset(new MenuGtk(NULL, menu_model_.get())); | |
| 63 #endif | |
| 64 } | |
| 65 virtual ~ContextMenuController() {} | |
| 66 | |
| 67 void RunMenu(const gfx::Point& point) { | |
| 68 const BookmarkNode* selected_node = GetSelectedNode(); | |
| 69 if (selected_node) | |
| 70 running_menu_for_root_ = selected_node->GetParent()->IsRoot(); | |
| 71 #if defined(TOOLKIT_VIEWS) | |
| 72 menu_->RunContextMenuAt(point); | |
| 73 #else | |
| 74 menu_->PopupAsContextAt(gtk_get_current_event_time(), point); | |
| 75 #endif | |
| 76 } | |
| 77 | |
| 78 void Cancel() { | |
| 79 editor_ = NULL; | |
| 80 #if defined(TOOLKIT_VIEWS) | |
| 81 menu_->CancelMenu(); | |
| 82 #else | |
| 83 menu_->Cancel(); | |
| 84 #endif | |
| 85 } | |
| 86 | |
| 87 private: | |
| 88 enum ContextMenuCommand { | |
| 89 COMMAND_EDIT, | |
| 90 COMMAND_NEW_FOLDER | |
| 91 }; | |
| 92 | |
| 93 // Overridden from menus::SimpleMenuModel::Delegate: | |
| 94 virtual bool IsCommandIdEnabled(int command_id) const { | |
| 95 return !(command_id == COMMAND_EDIT && running_menu_for_root_) && | |
| 96 (editor_ != NULL); | |
| 97 } | |
| 98 | |
| 99 virtual bool IsCommandIdChecked(int command_id) const { | |
| 100 return false; | |
| 101 } | |
| 102 | |
| 103 virtual bool GetAcceleratorForCommandId(int command_id, | |
| 104 menus::Accelerator* accelerator) { | |
| 105 return false; | |
| 106 } | |
| 107 | |
| 108 virtual void ExecuteCommand(int command_id) { | |
| 109 if (!editor_) | |
| 110 return; | |
| 111 | |
| 112 switch (command_id) { | |
| 113 case COMMAND_EDIT: { | |
| 114 GtkTreeIter iter; | |
| 115 if (!gtk_tree_selection_get_selected(editor_->tree_selection_, | |
| 116 NULL, | |
| 117 &iter)) { | |
| 118 return; | |
| 119 } | |
| 120 | |
| 121 GtkTreePath* path = gtk_tree_model_get_path( | |
| 122 GTK_TREE_MODEL(editor_->tree_store_), &iter); | |
| 123 gtk_tree_view_expand_to_path(GTK_TREE_VIEW(editor_->tree_view_), path); | |
| 124 | |
| 125 // Make the folder name editable. | |
| 126 gtk_tree_view_set_cursor(GTK_TREE_VIEW(editor_->tree_view_), path, | |
| 127 gtk_tree_view_get_column(GTK_TREE_VIEW(editor_->tree_view_), 0), | |
| 128 TRUE); | |
| 129 | |
| 130 gtk_tree_path_free(path); | |
| 131 break; | |
| 132 } | |
| 133 case COMMAND_NEW_FOLDER: | |
| 134 editor_->NewFolder(); | |
| 135 break; | |
| 136 default: | |
| 137 NOTREACHED(); | |
| 138 break; | |
| 139 } | |
| 140 } | |
| 141 | |
| 142 int64 GetRowIdAt(GtkTreeModel* model, GtkTreeIter* iter) { | |
| 143 GValue value = { 0, }; | |
| 144 gtk_tree_model_get_value(model, iter, bookmark_utils::ITEM_ID, &value); | |
| 145 int64 id = g_value_get_int64(&value); | |
| 146 g_value_unset(&value); | |
| 147 return id; | |
| 148 } | |
| 149 | |
| 150 const BookmarkNode* GetNodeAt(GtkTreeModel* model, GtkTreeIter* iter) { | |
| 151 int64 id = GetRowIdAt(model, iter); | |
| 152 return (id > 0) ? editor_->bb_model_->GetNodeByID(id) : NULL; | |
| 153 } | |
| 154 | |
| 155 const BookmarkNode* GetSelectedNode() { | |
| 156 GtkTreeModel* model; | |
| 157 GtkTreeIter iter; | |
| 158 if (!gtk_tree_selection_get_selected(editor_->tree_selection_, | |
| 159 &model, | |
| 160 &iter)) { | |
| 161 return NULL; | |
| 162 } | |
| 163 | |
| 164 return GetNodeAt(model, &iter); | |
| 165 } | |
| 166 | |
| 167 // The model and view for the right click context menu. | |
| 168 scoped_ptr<menus::SimpleMenuModel> menu_model_; | |
| 169 #if defined(TOOLKIT_VIEWS) | |
| 170 scoped_ptr<views::Menu2> menu_; | |
| 171 #else | |
| 172 scoped_ptr<MenuGtk> menu_; | |
| 173 #endif | |
| 174 | |
| 175 // The context menu was brought up for. Set to NULL when the menu is canceled. | |
| 176 BookmarkEditorGtk* editor_; | |
| 177 | |
| 178 // If true, we're running the menu for the bookmark bar or other bookmarks | |
| 179 // nodes. | |
| 180 bool running_menu_for_root_; | |
| 181 | |
| 182 DISALLOW_COPY_AND_ASSIGN(ContextMenuController); | |
| 183 }; | |
| 184 | |
| 185 // static | |
| 186 void BookmarkEditor::Show(gfx::NativeWindow parent_hwnd, | |
| 187 Profile* profile, | |
| 188 const BookmarkNode* parent, | |
| 189 const EditDetails& details, | |
| 190 Configuration configuration) { | |
| 191 DCHECK(profile); | |
| 192 BookmarkEditorGtk* editor = | |
| 193 new BookmarkEditorGtk(parent_hwnd, profile, parent, details, | |
| 194 configuration); | |
| 195 editor->Show(); | |
| 196 } | |
| 197 | |
| 198 BookmarkEditorGtk::BookmarkEditorGtk( | |
| 199 GtkWindow* window, | |
| 200 Profile* profile, | |
| 201 const BookmarkNode* parent, | |
| 202 const EditDetails& details, | |
| 203 BookmarkEditor::Configuration configuration) | |
| 204 : profile_(profile), | |
| 205 dialog_(NULL), | |
| 206 parent_(parent), | |
| 207 details_(details), | |
| 208 running_menu_for_root_(false), | |
| 209 show_tree_(configuration == SHOW_TREE) { | |
| 210 DCHECK(profile); | |
| 211 Init(window); | |
| 212 } | |
| 213 | |
| 214 BookmarkEditorGtk::~BookmarkEditorGtk() { | |
| 215 // The tree model is deleted before the view. Reset the model otherwise the | |
| 216 // tree will reference a deleted model. | |
| 217 | |
| 218 bb_model_->RemoveObserver(this); | |
| 219 } | |
| 220 | |
| 221 void BookmarkEditorGtk::Init(GtkWindow* parent_window) { | |
| 222 bb_model_ = profile_->GetBookmarkModel(); | |
| 223 DCHECK(bb_model_); | |
| 224 bb_model_->AddObserver(this); | |
| 225 | |
| 226 dialog_ = gtk_dialog_new_with_buttons( | |
| 227 l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_TITLE).c_str(), | |
| 228 parent_window, | |
| 229 GTK_DIALOG_MODAL, | |
| 230 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, | |
| 231 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, | |
| 232 NULL); | |
| 233 gtk_dialog_set_has_separator(GTK_DIALOG(dialog_), FALSE); | |
| 234 | |
| 235 if (show_tree_) { | |
| 236 GtkWidget* action_area = GTK_DIALOG(dialog_)->action_area; | |
| 237 new_folder_button_ = gtk_button_new_with_label( | |
| 238 l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_NEW_FOLDER_BUTTON).c_str()); | |
| 239 g_signal_connect(new_folder_button_, "clicked", | |
| 240 G_CALLBACK(OnNewFolderClickedThunk), this); | |
| 241 gtk_container_add(GTK_CONTAINER(action_area), new_folder_button_); | |
| 242 gtk_button_box_set_child_secondary(GTK_BUTTON_BOX(action_area), | |
| 243 new_folder_button_, TRUE); | |
| 244 } | |
| 245 | |
| 246 gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_ACCEPT); | |
| 247 | |
| 248 // The GTK dialog content area layout (overview) | |
| 249 // | |
| 250 // +- GtkVBox |vbox| ----------------------------------------------+ | |
| 251 // |+- GtkTable |table| ------------------------------------------+| | |
| 252 // ||+- GtkLabel ------+ +- GtkEntry |name_entry_| --------------+|| | |
| 253 // ||| | | ||| | |
| 254 // ||+-----------------+ +---------------------------------------+|| | |
| 255 // ||+- GtkLabel ------+ +- GtkEntry |url_entry_| ---------------+|| * | |
| 256 // ||| | | ||| | |
| 257 // ||+-----------------+ +---------------------------------------+|| | |
| 258 // |+-------------------------------------------------------------+| | |
| 259 // |+- GtkScrollWindow |scroll_window| ---------------------------+| | |
| 260 // ||+- GtkTreeView |tree_view_| --------------------------------+|| | |
| 261 // |||+- GtkTreeViewColumn |name_column| -----------------------+||| | |
| 262 // |||| |||| | |
| 263 // |||| |||| | |
| 264 // |||| |||| | |
| 265 // |||| |||| | |
| 266 // |||+---------------------------------------------------------+||| | |
| 267 // ||+-----------------------------------------------------------+|| | |
| 268 // |+-------------------------------------------------------------+| | |
| 269 // +---------------------------------------------------------------+ | |
| 270 // | |
| 271 // * The url and corresponding label are not shown if creating a new folder. | |
| 272 GtkWidget* content_area = GTK_DIALOG(dialog_)->vbox; | |
| 273 gtk_box_set_spacing(GTK_BOX(content_area), gtk_util::kContentAreaSpacing); | |
| 274 | |
| 275 GtkWidget* vbox = gtk_vbox_new(FALSE, 12); | |
| 276 | |
| 277 name_entry_ = gtk_entry_new(); | |
| 278 std::string title; | |
| 279 if (details_.type == EditDetails::EXISTING_NODE) { | |
| 280 title = UTF16ToUTF8(details_.existing_node->GetTitle()); | |
| 281 } else if (details_.type == EditDetails::NEW_FOLDER) { | |
| 282 title = l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME); | |
| 283 } | |
| 284 gtk_entry_set_text(GTK_ENTRY(name_entry_), title.c_str()); | |
| 285 g_signal_connect(name_entry_, "changed", | |
| 286 G_CALLBACK(OnEntryChangedThunk), this); | |
| 287 gtk_entry_set_activates_default(GTK_ENTRY(name_entry_), TRUE); | |
| 288 | |
| 289 GtkWidget* table; | |
| 290 if (details_.type != EditDetails::NEW_FOLDER) { | |
| 291 url_entry_ = gtk_entry_new(); | |
| 292 std::string url_spec; | |
| 293 if (details_.type == EditDetails::EXISTING_NODE) | |
| 294 url_spec = details_.existing_node->GetURL().spec(); | |
| 295 gtk_entry_set_text(GTK_ENTRY(url_entry_), url_spec.c_str()); | |
| 296 g_signal_connect(url_entry_, "changed", | |
| 297 G_CALLBACK(OnEntryChangedThunk), this); | |
| 298 gtk_entry_set_activates_default(GTK_ENTRY(url_entry_), TRUE); | |
| 299 table = gtk_util::CreateLabeledControlsGroup(NULL, | |
| 300 l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_NAME_LABEL).c_str(), | |
| 301 name_entry_, | |
| 302 l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_URL_LABEL).c_str(), | |
| 303 url_entry_, | |
| 304 NULL); | |
| 305 | |
| 306 } else { | |
| 307 url_entry_ = NULL; | |
| 308 table = gtk_util::CreateLabeledControlsGroup(NULL, | |
| 309 l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_NAME_LABEL).c_str(), | |
| 310 name_entry_, | |
| 311 NULL); | |
| 312 } | |
| 313 | |
| 314 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); | |
| 315 | |
| 316 if (show_tree_) { | |
| 317 GtkTreeIter selected_iter; | |
| 318 int64 selected_id = 0; | |
| 319 if (details_.type == EditDetails::EXISTING_NODE) | |
| 320 selected_id = details_.existing_node->GetParent()->id(); | |
| 321 else if (parent_) | |
| 322 selected_id = parent_->id(); | |
| 323 tree_store_ = bookmark_utils::MakeFolderTreeStore(); | |
| 324 bookmark_utils::AddToTreeStore(bb_model_, selected_id, tree_store_, | |
| 325 &selected_iter); | |
| 326 tree_view_ = bookmark_utils::MakeTreeViewForStore(tree_store_); | |
| 327 gtk_widget_set_size_request(tree_view_, kTreeWidth, kTreeHeight); | |
| 328 tree_selection_ = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view_)); | |
| 329 g_signal_connect(tree_view_, "button-press-event", | |
| 330 G_CALLBACK(OnTreeViewButtonPressEventThunk), this); | |
| 331 | |
| 332 GtkTreePath* path = NULL; | |
| 333 if (selected_id) { | |
| 334 path = gtk_tree_model_get_path(GTK_TREE_MODEL(tree_store_), | |
| 335 &selected_iter); | |
| 336 } else { | |
| 337 // We don't have a selected parent (Probably because we're making a new | |
| 338 // bookmark). Select the first item in the list. | |
| 339 path = gtk_tree_path_new_from_string("0"); | |
| 340 } | |
| 341 | |
| 342 gtk_tree_view_expand_to_path(GTK_TREE_VIEW(tree_view_), path); | |
| 343 gtk_tree_selection_select_path(tree_selection_, path); | |
| 344 gtk_tree_path_free(path); | |
| 345 | |
| 346 GtkWidget* scroll_window = gtk_scrolled_window_new(NULL, NULL); | |
| 347 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_window), | |
| 348 GTK_POLICY_NEVER, | |
| 349 GTK_POLICY_AUTOMATIC); | |
| 350 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll_window), | |
| 351 GTK_SHADOW_ETCHED_IN); | |
| 352 gtk_container_add(GTK_CONTAINER(scroll_window), tree_view_); | |
| 353 | |
| 354 gtk_box_pack_start(GTK_BOX(vbox), scroll_window, TRUE, TRUE, 0); | |
| 355 | |
| 356 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view_)), | |
| 357 "changed", G_CALLBACK(OnSelectionChangedThunk), this); | |
| 358 } | |
| 359 | |
| 360 gtk_box_pack_start(GTK_BOX(content_area), vbox, TRUE, TRUE, 0); | |
| 361 | |
| 362 g_signal_connect(dialog_, "response", | |
| 363 G_CALLBACK(OnResponseThunk), this); | |
| 364 g_signal_connect(dialog_, "delete-event", | |
| 365 G_CALLBACK(OnWindowDeleteEventThunk), this); | |
| 366 g_signal_connect(dialog_, "destroy", | |
| 367 G_CALLBACK(OnWindowDestroyThunk), this); | |
| 368 } | |
| 369 | |
| 370 void BookmarkEditorGtk::Show() { | |
| 371 // Manually call our OnEntryChanged handler to set the initial state. | |
| 372 OnEntryChanged(NULL); | |
| 373 | |
| 374 gtk_util::ShowDialog(dialog_); | |
| 375 } | |
| 376 | |
| 377 void BookmarkEditorGtk::Close() { | |
| 378 // Under the model that we've inherited from Windows, dialogs can receive | |
| 379 // more than one Close() call inside the current message loop event. | |
| 380 if (dialog_) { | |
| 381 gtk_widget_destroy(dialog_); | |
| 382 dialog_ = NULL; | |
| 383 } | |
| 384 } | |
| 385 | |
| 386 void BookmarkEditorGtk::BookmarkNodeMoved(BookmarkModel* model, | |
| 387 const BookmarkNode* old_parent, | |
| 388 int old_index, | |
| 389 const BookmarkNode* new_parent, | |
| 390 int new_index) { | |
| 391 Reset(); | |
| 392 } | |
| 393 | |
| 394 void BookmarkEditorGtk::BookmarkNodeAdded(BookmarkModel* model, | |
| 395 const BookmarkNode* parent, | |
| 396 int index) { | |
| 397 Reset(); | |
| 398 } | |
| 399 | |
| 400 void BookmarkEditorGtk::BookmarkNodeRemoved(BookmarkModel* model, | |
| 401 const BookmarkNode* parent, | |
| 402 int index, | |
| 403 const BookmarkNode* node) { | |
| 404 if ((details_.type == EditDetails::EXISTING_NODE && | |
| 405 details_.existing_node->HasAncestor(node)) || | |
| 406 (parent_ && parent_->HasAncestor(node))) { | |
| 407 // The node, or its parent was removed. Close the dialog. | |
| 408 Close(); | |
| 409 } else { | |
| 410 Reset(); | |
| 411 } | |
| 412 } | |
| 413 | |
| 414 void BookmarkEditorGtk::BookmarkNodeChildrenReordered( | |
| 415 BookmarkModel* model, const BookmarkNode* node) { | |
| 416 Reset(); | |
| 417 } | |
| 418 | |
| 419 void BookmarkEditorGtk::Reset() { | |
| 420 // TODO(erg): The windows implementation tries to be smart. For now, just | |
| 421 // close the window. | |
| 422 Close(); | |
| 423 } | |
| 424 | |
| 425 GURL BookmarkEditorGtk::GetInputURL() const { | |
| 426 if (!url_entry_) | |
| 427 return GURL(); // Happens when we're editing a folder. | |
| 428 return URLFixerUpper::FixupURL(gtk_entry_get_text(GTK_ENTRY(url_entry_)), | |
| 429 std::string()); | |
| 430 } | |
| 431 | |
| 432 string16 BookmarkEditorGtk::GetInputTitle() const { | |
| 433 return UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(name_entry_))); | |
| 434 } | |
| 435 | |
| 436 void BookmarkEditorGtk::ApplyEdits() { | |
| 437 DCHECK(bb_model_->IsLoaded()); | |
| 438 | |
| 439 GtkTreeIter currently_selected_iter; | |
| 440 if (show_tree_) { | |
| 441 if (!gtk_tree_selection_get_selected(tree_selection_, NULL, | |
| 442 ¤tly_selected_iter)) { | |
| 443 ApplyEdits(NULL); | |
| 444 return; | |
| 445 } | |
| 446 } | |
| 447 | |
| 448 ApplyEdits(¤tly_selected_iter); | |
| 449 } | |
| 450 | |
| 451 void BookmarkEditorGtk::ApplyEdits(GtkTreeIter* selected_parent) { | |
| 452 // We're going to apply edits to the bookmark bar model, which will call us | |
| 453 // back. Normally when a structural edit occurs we reset the tree model. | |
| 454 // We don't want to do that here, so we remove ourselves as an observer. | |
| 455 bb_model_->RemoveObserver(this); | |
| 456 | |
| 457 GURL new_url(GetInputURL()); | |
| 458 string16 new_title(GetInputTitle()); | |
| 459 | |
| 460 if (!show_tree_ || !selected_parent) { | |
| 461 bookmark_utils::ApplyEditsWithNoGroupChange( | |
| 462 bb_model_, parent_, details_, new_title, new_url); | |
| 463 return; | |
| 464 } | |
| 465 | |
| 466 // Create the new groups and update the titles. | |
| 467 const BookmarkNode* new_parent = | |
| 468 bookmark_utils::CommitTreeStoreDifferencesBetween( | |
| 469 bb_model_, tree_store_, selected_parent); | |
| 470 | |
| 471 if (!new_parent) { | |
| 472 // Bookmarks must be parented. | |
| 473 NOTREACHED(); | |
| 474 return; | |
| 475 } | |
| 476 | |
| 477 bookmark_utils::ApplyEditsWithPossibleGroupChange( | |
| 478 bb_model_, new_parent, details_, new_title, new_url); | |
| 479 } | |
| 480 | |
| 481 void BookmarkEditorGtk::AddNewGroup(GtkTreeIter* parent, GtkTreeIter* child) { | |
| 482 gtk_tree_store_append(tree_store_, child, parent); | |
| 483 gtk_tree_store_set( | |
| 484 tree_store_, child, | |
| 485 bookmark_utils::FOLDER_ICON, GtkThemeProvider::GetFolderIcon(true), | |
| 486 bookmark_utils::FOLDER_NAME, | |
| 487 l10n_util::GetStringUTF8(IDS_BOOMARK_EDITOR_NEW_FOLDER_NAME).c_str(), | |
| 488 bookmark_utils::ITEM_ID, static_cast<int64>(0), | |
| 489 bookmark_utils::IS_EDITABLE, TRUE, | |
| 490 -1); | |
| 491 } | |
| 492 | |
| 493 void BookmarkEditorGtk::OnSelectionChanged(GtkWidget* selection) { | |
| 494 if (!gtk_tree_selection_get_selected(tree_selection_, NULL, NULL)) | |
| 495 gtk_widget_set_sensitive(new_folder_button_, FALSE); | |
| 496 else | |
| 497 gtk_widget_set_sensitive(new_folder_button_, TRUE); | |
| 498 } | |
| 499 | |
| 500 void BookmarkEditorGtk::OnResponse(GtkWidget* dialog, int response_id) { | |
| 501 if (response_id == GTK_RESPONSE_ACCEPT) | |
| 502 ApplyEdits(); | |
| 503 | |
| 504 Close(); | |
| 505 } | |
| 506 | |
| 507 gboolean BookmarkEditorGtk::OnWindowDeleteEvent(GtkWidget* widget, | |
| 508 GdkEvent* event) { | |
| 509 Close(); | |
| 510 | |
| 511 // Return true to prevent the gtk dialog from being destroyed. Close will | |
| 512 // destroy it for us and the default gtk_dialog_delete_event_handler() will | |
| 513 // force the destruction without us being able to stop it. | |
| 514 return TRUE; | |
| 515 } | |
| 516 | |
| 517 void BookmarkEditorGtk::OnWindowDestroy(GtkWidget* widget) { | |
| 518 MessageLoop::current()->DeleteSoon(FROM_HERE, this); | |
| 519 } | |
| 520 | |
| 521 void BookmarkEditorGtk::OnEntryChanged(GtkWidget* entry) { | |
| 522 gboolean can_close = TRUE; | |
| 523 if (details_.type == EditDetails::NEW_FOLDER) { | |
| 524 if (GetInputTitle().empty()) { | |
| 525 gtk_widget_modify_base(name_entry_, GTK_STATE_NORMAL, | |
| 526 &kErrorColor); | |
| 527 can_close = FALSE; | |
| 528 } else { | |
| 529 gtk_widget_modify_base(name_entry_, GTK_STATE_NORMAL, NULL); | |
| 530 } | |
| 531 } else { | |
| 532 GURL url(GetInputURL()); | |
| 533 if (!url.is_valid()) { | |
| 534 gtk_widget_modify_base(url_entry_, GTK_STATE_NORMAL, | |
| 535 &kErrorColor); | |
| 536 can_close = FALSE; | |
| 537 } else { | |
| 538 gtk_widget_modify_base(url_entry_, GTK_STATE_NORMAL, NULL); | |
| 539 } | |
| 540 } | |
| 541 gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog_), | |
| 542 GTK_RESPONSE_ACCEPT, can_close); | |
| 543 } | |
| 544 | |
| 545 void BookmarkEditorGtk::OnNewFolderClicked(GtkWidget* button) { | |
| 546 NewFolder(); | |
| 547 } | |
| 548 | |
| 549 gboolean BookmarkEditorGtk::OnTreeViewButtonPressEvent(GtkWidget* widget, | |
| 550 GdkEventButton* event) { | |
| 551 if (event->button == 3) { | |
| 552 gfx::Point pt(event->x_root, event->y_root); | |
| 553 ShowContextMenu(pt); | |
| 554 } | |
| 555 | |
| 556 return FALSE; | |
| 557 } | |
| 558 | |
| 559 void BookmarkEditorGtk::ShowContextMenu(const gfx::Point& point) { | |
| 560 if (!menu_controller_.get()) | |
| 561 menu_controller_.reset(new ContextMenuController(this)); | |
| 562 | |
| 563 menu_controller_->RunMenu(point); | |
| 564 } | |
| 565 | |
| 566 void BookmarkEditorGtk::NewFolder() { | |
| 567 GtkTreeIter iter; | |
| 568 if (!gtk_tree_selection_get_selected(tree_selection_, | |
| 569 NULL, | |
| 570 &iter)) { | |
| 571 NOTREACHED() << "Something should always be selected if New Folder " << | |
| 572 "is clicked"; | |
| 573 return; | |
| 574 } | |
| 575 | |
| 576 GtkTreeIter new_item_iter; | |
| 577 AddNewGroup(&iter, &new_item_iter); | |
| 578 | |
| 579 GtkTreePath* path = gtk_tree_model_get_path( | |
| 580 GTK_TREE_MODEL(tree_store_), &new_item_iter); | |
| 581 gtk_tree_view_expand_to_path(GTK_TREE_VIEW(tree_view_), path); | |
| 582 | |
| 583 // Make the folder name editable. | |
| 584 gtk_tree_view_set_cursor(GTK_TREE_VIEW(tree_view_), path, | |
| 585 gtk_tree_view_get_column(GTK_TREE_VIEW(tree_view_), 0), | |
| 586 TRUE); | |
| 587 | |
| 588 gtk_tree_path_free(path); | |
| 589 } | |
| OLD | NEW |