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/views/bookmark_manager_view.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "app/l10n_util.h" | |
10 #include "app/resource_bundle.h" | |
11 #include "base/keyboard_codes.h" | |
12 #include "base/thread.h" | |
13 #include "chrome/browser/bookmarks/bookmark_folder_tree_model.h" | |
14 #include "chrome/browser/bookmarks/bookmark_html_writer.h" | |
15 #include "chrome/browser/bookmarks/bookmark_manager.h" | |
16 #include "chrome/browser/bookmarks/bookmark_model.h" | |
17 #include "chrome/browser/bookmarks/bookmark_table_model.h" | |
18 #include "chrome/browser/bookmarks/bookmark_utils.h" | |
19 #include "chrome/browser/browser_list.h" | |
20 #include "chrome/browser/browser_process.h" | |
21 #include "chrome/browser/importer/importer.h" | |
22 #include "chrome/browser/importer/importer_data_types.h" | |
23 #include "chrome/browser/metrics/user_metrics.h" | |
24 #include "chrome/browser/pref_service.h" | |
25 #include "chrome/browser/profile.h" | |
26 #include "chrome/browser/sync/sync_ui_util.h" | |
27 #include "chrome/browser/views/bookmark_editor_view.h" | |
28 #include "chrome/browser/views/bookmark_folder_tree_view.h" | |
29 #include "chrome/browser/views/bookmark_table_view.h" | |
30 #include "chrome/common/pref_names.h" | |
31 #include "gfx/canvas.h" | |
32 #include "gfx/color_utils.h" | |
33 #include "gfx/skia_util.h" | |
34 #include "grit/generated_resources.h" | |
35 #include "grit/locale_settings.h" | |
36 #include "grit/theme_resources.h" | |
37 #include "third_party/skia/include/core/SkShader.h" | |
38 #include "views/controls/button/menu_button.h" | |
39 #include "views/controls/label.h" | |
40 #include "views/controls/menu/menu_item_view.h" | |
41 #include "views/controls/single_split_view.h" | |
42 #include "views/grid_layout.h" | |
43 #include "views/standard_layout.h" | |
44 #include "views/widget/widget.h" | |
45 #include "views/window/window.h" | |
46 | |
47 // If non-null, there is an open editor and this is the window it is contained | |
48 // in it. | |
49 static views::Window* open_window = NULL; | |
50 // And this is the manager contained in it. | |
51 static BookmarkManagerView* manager = NULL; | |
52 | |
53 // Delay, in ms, between when the user types and when we run the search. | |
54 static const int kSearchDelayMS = 200; | |
55 | |
56 static const int kOrganizeMenuButtonID = 1; | |
57 static const int kToolsMenuButtonID = 2; | |
58 | |
59 // Background color. | |
60 static const SkColor kBackgroundColorTop = SkColorSetRGB(242, 247, 253); | |
61 static const SkColor kBackgroundColorBottom = SkColorSetRGB(223, 234, 248); | |
62 static const int kBackgroundGradientHeight = 28; | |
63 | |
64 namespace { | |
65 | |
66 // Observer installed on the importer. When done importing the newly created | |
67 // folder is selected in the bookmark manager. | |
68 class ImportObserverImpl : public ImportObserver { | |
69 public: | |
70 explicit ImportObserverImpl(Profile* profile) : profile_(profile) { | |
71 BookmarkModel* model = profile->GetBookmarkModel(); | |
72 initial_other_count_ = model->other_node()->GetChildCount(); | |
73 } | |
74 | |
75 virtual void ImportCanceled() { | |
76 delete this; | |
77 } | |
78 | |
79 virtual void ImportComplete() { | |
80 // We aren't needed anymore. | |
81 MessageLoop::current()->DeleteSoon(FROM_HERE, this); | |
82 | |
83 BookmarkManagerView* manager = BookmarkManagerView::current(); | |
84 if (!manager || manager->profile() != profile_) | |
85 return; | |
86 | |
87 BookmarkModel* model = profile_->GetBookmarkModel(); | |
88 int other_count = model->other_node()->GetChildCount(); | |
89 if (other_count == initial_other_count_ + 1) { | |
90 const BookmarkNode* imported_node = | |
91 model->other_node()->GetChild(initial_other_count_); | |
92 manager->SelectInTree(imported_node); | |
93 manager->ExpandAll(imported_node); | |
94 } | |
95 } | |
96 | |
97 private: | |
98 Profile* profile_; | |
99 // Number of children in the other bookmarks folder at the time we were | |
100 // created. | |
101 int initial_other_count_; | |
102 | |
103 DISALLOW_COPY_AND_ASSIGN(ImportObserverImpl); | |
104 }; | |
105 | |
106 // Converts a virtual keycode into the CutCopyPasteType. | |
107 BookmarkManagerView::CutCopyPasteType KeyCodeToCutCopyPaste( | |
108 base::KeyboardCode keycode) { | |
109 switch (keycode) { | |
110 case base::VKEY_INSERT: | |
111 if (GetKeyState(VK_CONTROL) < 0) | |
112 return BookmarkManagerView::COPY; | |
113 if (GetKeyState(VK_SHIFT) < 0) | |
114 return BookmarkManagerView::PASTE; | |
115 return BookmarkManagerView::NONE; | |
116 | |
117 case base::VKEY_DELETE: | |
118 if (GetKeyState(VK_SHIFT) < 0) | |
119 return BookmarkManagerView::CUT; | |
120 return BookmarkManagerView::NONE; | |
121 | |
122 case base::VKEY_C: | |
123 if (GetKeyState(VK_CONTROL) < 0) | |
124 return BookmarkManagerView::COPY; | |
125 return BookmarkManagerView::NONE; | |
126 | |
127 case base::VKEY_V: | |
128 if (GetKeyState(VK_CONTROL) < 0) | |
129 return BookmarkManagerView::PASTE; | |
130 return BookmarkManagerView::NONE; | |
131 | |
132 case base::VKEY_X: | |
133 if (GetKeyState(VK_CONTROL) < 0) | |
134 return BookmarkManagerView::CUT; | |
135 return BookmarkManagerView::NONE; | |
136 | |
137 default: | |
138 return BookmarkManagerView::NONE; | |
139 } | |
140 } | |
141 | |
142 } // namespace | |
143 | |
144 namespace browser { | |
145 | |
146 // Declared in browser_dialogs.h so others don't need to depend on our header. | |
147 void ShowBookmarkManagerView(Profile* profile) { | |
148 BookmarkManagerView::Show(profile); | |
149 } | |
150 | |
151 } // namespace browser | |
152 | |
153 // BookmarkManager ------------------------------------------------------------- | |
154 | |
155 void BookmarkManager::SelectInTree(Profile* profile, const BookmarkNode* node) { | |
156 if (manager && manager->profile() == profile) | |
157 manager->SelectInTree(node); | |
158 } | |
159 | |
160 void BookmarkManager::Show(Profile* profile) { | |
161 BookmarkManagerView::Show(profile); | |
162 } | |
163 | |
164 // ----------------------------------------------------------------------------- | |
165 | |
166 BookmarkManagerView::BookmarkManagerView(Profile* profile) | |
167 : profile_(profile->GetOriginalProfile()), | |
168 table_view_(NULL), | |
169 tree_view_(NULL), | |
170 sync_status_button_(NULL), | |
171 sync_service_(NULL), | |
172 sync_relogin_required_(false), | |
173 ALLOW_THIS_IN_INITIALIZER_LIST(search_factory_(this)) { | |
174 views::Label* search_label = new views::Label( | |
175 l10n_util::GetString(IDS_BOOKMARK_MANAGER_SEARCH_TITLE)); | |
176 search_tf_ = new views::Textfield(); | |
177 search_tf_->set_default_width_in_chars(30); | |
178 search_tf_->SetAccessibleName(search_label->GetText()); | |
179 | |
180 table_view_ = new BookmarkTableView(profile_, NULL); | |
181 table_view_->SetObserver(this); | |
182 table_view_->SetContextMenuController(this); | |
183 | |
184 tree_view_ = new BookmarkFolderTreeView(profile_, NULL); | |
185 tree_view_->SetController(this); | |
186 tree_view_->SetContextMenuController(this); | |
187 | |
188 views::MenuButton* organize_menu_button = new views::MenuButton( | |
189 NULL, l10n_util::GetString(IDS_BOOKMARK_MANAGER_ORGANIZE_MENU), | |
190 this, true); | |
191 organize_menu_button->SetID(kOrganizeMenuButtonID); | |
192 | |
193 views::MenuButton* tools_menu_button = new views::MenuButton( | |
194 NULL, l10n_util::GetString(IDS_BOOKMARK_MANAGER_TOOLS_MENU), | |
195 this, true); | |
196 tools_menu_button->SetID(kToolsMenuButtonID); | |
197 | |
198 split_view_ = new views::SingleSplitView(tree_view_, table_view_, | |
199 views::SingleSplitView::HORIZONTAL_SPLIT); | |
200 split_view_->set_resize_leading_on_bounds_change(false); | |
201 split_view_->set_background( | |
202 views::Background::CreateSolidBackground(kBackgroundColorBottom)); | |
203 | |
204 views::GridLayout* layout = new views::GridLayout(this); | |
205 SetLayoutManager(layout); | |
206 const int top_id = 1; | |
207 const int split_cs_id = 2; | |
208 layout->SetInsets(2, 0, 0, 0); // 2px padding above content. | |
209 views::ColumnSet* column_set = layout->AddColumnSet(top_id); | |
210 column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, | |
211 0, views::GridLayout::USE_PREF, 0, 0); | |
212 column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, | |
213 0, views::GridLayout::USE_PREF, 0, 0); | |
214 column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, | |
215 0, views::GridLayout::USE_PREF, 0, 0); | |
216 column_set->AddPaddingColumn(1, kUnrelatedControlHorizontalSpacing); | |
217 column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, | |
218 0, views::GridLayout::USE_PREF, 0, 0); | |
219 column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing); | |
220 column_set->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER, | |
221 0, views::GridLayout::USE_PREF, 0, 0); | |
222 column_set->AddPaddingColumn(0, 3); // 3px padding at end of row. | |
223 | |
224 column_set = layout->AddColumnSet(split_cs_id); | |
225 column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1, | |
226 views::GridLayout::USE_PREF, 0, 0); | |
227 | |
228 layout->StartRow(0, top_id); | |
229 layout->AddView(organize_menu_button); | |
230 layout->AddView(tools_menu_button); | |
231 sync_status_button_ = new views::TextButton(this, std::wstring()); | |
232 layout->AddView(sync_status_button_); | |
233 layout->AddView(search_label); | |
234 layout->AddView(search_tf_); | |
235 | |
236 layout->AddPaddingRow(0, 3); // 3px padding between rows. | |
237 | |
238 layout->StartRow(1, split_cs_id); | |
239 layout->AddView(split_view_); | |
240 | |
241 // Press Ctrl-W to close bookmark manager window. | |
242 AddAccelerator(views::Accelerator(base::VKEY_W, false, true, false)); | |
243 | |
244 BookmarkModel* bookmark_model = profile_->GetBookmarkModel(); | |
245 if (!bookmark_model->IsLoaded()) | |
246 bookmark_model->AddObserver(this); | |
247 | |
248 if (profile_->GetProfileSyncService()) { | |
249 sync_service_ = profile_->GetProfileSyncService(); | |
250 sync_service_->AddObserver(this); | |
251 UpdateSyncStatus(); | |
252 } | |
253 } | |
254 | |
255 BookmarkManagerView::~BookmarkManagerView() { | |
256 if (select_file_dialog_.get()) | |
257 select_file_dialog_->ListenerDestroyed(); | |
258 | |
259 if (!GetBookmarkModel()->IsLoaded()) { | |
260 GetBookmarkModel()->RemoveObserver(this); | |
261 } else { | |
262 // The models are deleted before the views. Make sure we set the models of | |
263 // the views to NULL so that they aren't left holding a reference to a | |
264 // deleted model. | |
265 table_view_->SetModel(NULL); | |
266 tree_view_->SetModel(NULL); | |
267 } | |
268 manager = NULL; | |
269 open_window = NULL; | |
270 | |
271 if (sync_service_) | |
272 sync_service_->RemoveObserver(this); | |
273 } | |
274 | |
275 // static | |
276 void BookmarkManagerView::Show(Profile* profile) { | |
277 if (!profile->GetBookmarkModel()) | |
278 return; | |
279 | |
280 if (open_window != NULL) { | |
281 open_window->Activate(); | |
282 return; | |
283 } | |
284 | |
285 // Both of these will be deleted when the dialog closes. | |
286 manager = new BookmarkManagerView(profile); | |
287 | |
288 // Create the window. | |
289 open_window = views::Window::CreateChromeWindow(NULL, gfx::Rect(), manager); | |
290 // Let the manager know it's parented. | |
291 manager->PrepareForShow(); | |
292 // And show it. | |
293 open_window->Show(); | |
294 | |
295 // Give initial focus to the search field. | |
296 manager->search_tf_->RequestFocus(); | |
297 } | |
298 | |
299 // static | |
300 BookmarkManagerView* BookmarkManagerView::current() { | |
301 return manager; | |
302 } | |
303 | |
304 void BookmarkManagerView::SelectInTree(const BookmarkNode* node) { | |
305 if (!node) | |
306 return; | |
307 | |
308 const BookmarkNode* parent = node->is_url() ? node->GetParent() : node; | |
309 FolderNode* folder_node = tree_model_->GetFolderNodeForBookmarkNode(parent); | |
310 if (!folder_node) { | |
311 NOTREACHED(); | |
312 return; | |
313 } | |
314 | |
315 tree_view_->SetSelectedNode(folder_node); | |
316 | |
317 if (node->is_url()) { | |
318 int index = table_model_->IndexOfNode(node); | |
319 if (index != -1) | |
320 table_view_->Select(index); | |
321 // TODO(sky): this doesn't work when invoked from add page. | |
322 table_view_->RequestFocus(); | |
323 } | |
324 } | |
325 | |
326 void BookmarkManagerView::ExpandAll(const BookmarkNode* node) { | |
327 const BookmarkNode* parent = node->is_url() ? node->GetParent() : node; | |
328 FolderNode* folder_node = tree_model_->GetFolderNodeForBookmarkNode(parent); | |
329 if (!folder_node) { | |
330 NOTREACHED(); | |
331 return; | |
332 } | |
333 tree_view_->ExpandAll(folder_node); | |
334 } | |
335 | |
336 const BookmarkNode* BookmarkManagerView::GetSelectedFolder() { | |
337 return tree_view_->GetSelectedBookmarkNode(); | |
338 } | |
339 | |
340 std::vector<const BookmarkNode*> BookmarkManagerView::GetSelectedTableNodes() { | |
341 std::vector<const BookmarkNode*> nodes; | |
342 for (views::TableView::iterator i = table_view_->SelectionBegin(); | |
343 i != table_view_->SelectionEnd(); ++i) { | |
344 nodes.push_back(table_model_->GetNodeForRow(*i)); | |
345 } | |
346 // TableViews iterator iterates in reverse order. Reverse the nodes so they | |
347 // are opened in visual order. | |
348 std::reverse(nodes.begin(), nodes.end()); | |
349 return nodes; | |
350 } | |
351 | |
352 void BookmarkManagerView::PaintBackground(gfx::Canvas* canvas) { | |
353 canvas->drawColor(kBackgroundColorBottom, SkXfermode::kSrc_Mode); | |
354 | |
355 SkPaint paint; | |
356 paint.setShader(gfx::CreateGradientShader(0, kBackgroundGradientHeight, | |
357 kBackgroundColorTop, | |
358 kBackgroundColorBottom))->safeUnref(); | |
359 canvas->FillRectInt(0, 0, width(), kBackgroundGradientHeight, paint); | |
360 } | |
361 | |
362 gfx::Size BookmarkManagerView::GetPreferredSize() { | |
363 return gfx::Size(views::Window::GetLocalizedContentsSize( | |
364 IDS_BOOKMARK_MANAGER_DIALOG_WIDTH_CHARS, | |
365 IDS_BOOKMARK_MANAGER_DIALOG_HEIGHT_LINES)); | |
366 } | |
367 | |
368 std::wstring BookmarkManagerView::GetWindowTitle() const { | |
369 return l10n_util::GetString(IDS_BOOKMARK_MANAGER_TITLE); | |
370 } | |
371 | |
372 std::wstring BookmarkManagerView::GetWindowName() const { | |
373 return prefs::kBookmarkManagerPlacement; | |
374 } | |
375 | |
376 void BookmarkManagerView::WindowClosing() { | |
377 g_browser_process->local_state()->SetInteger( | |
378 prefs::kBookmarkManagerSplitLocation, split_view_->divider_offset()); | |
379 } | |
380 | |
381 void BookmarkManagerView::OnStateChanged() { | |
382 UpdateSyncStatus(); | |
383 } | |
384 | |
385 bool BookmarkManagerView::AcceleratorPressed( | |
386 const views::Accelerator& accelerator) { | |
387 // Ctrl-W to close bookmark manager. | |
388 DCHECK(accelerator.GetKeyCode() == 'W' && accelerator.IsCtrlDown()); | |
389 window()->Close(); | |
390 return true; | |
391 } | |
392 | |
393 void BookmarkManagerView::OnDoubleClick() { | |
394 std::vector<const BookmarkNode*> nodes = GetSelectedTableNodes(); | |
395 if (nodes.empty()) | |
396 return; | |
397 if (nodes.size() == 1 && nodes[0]->is_folder()) { | |
398 // Double click on a folder descends into the folder. | |
399 SelectInTree(nodes[0]); | |
400 return; | |
401 } | |
402 // TODO(sky): OnDoubleClick needs a handle to the current mouse event so that | |
403 // we can use | |
404 // event_utils::DispositionFromEventFlags(sender->mouse_event_flags()) . | |
405 bookmark_utils::OpenAll( | |
406 GetWidget()->GetNativeView(), profile_, NULL, nodes, CURRENT_TAB); | |
407 } | |
408 | |
409 void BookmarkManagerView::OnMiddleClick() { | |
410 std::vector<const BookmarkNode*> nodes = GetSelectedTableNodes(); | |
411 if (nodes.empty()) | |
412 return; | |
413 if (nodes.size() == 1 && nodes[0]->is_folder()) { | |
414 // Middle clicking on a folder results in no action. | |
415 return; | |
416 } | |
417 | |
418 bookmark_utils::OpenAll( | |
419 GetWidget()->GetNativeView(), profile_, NULL, nodes, NEW_FOREGROUND_TAB); | |
420 } | |
421 | |
422 void BookmarkManagerView::OnTableViewDelete(views::TableView* table) { | |
423 std::vector<const BookmarkNode*> nodes = GetSelectedTableNodes(); | |
424 if (nodes.empty()) | |
425 return; | |
426 for (size_t i = 0; i < nodes.size(); ++i) { | |
427 GetBookmarkModel()->Remove(nodes[i]->GetParent(), | |
428 nodes[i]->GetParent()->IndexOfChild(nodes[i])); | |
429 } | |
430 } | |
431 | |
432 void BookmarkManagerView::OnKeyDown(base::KeyboardCode keycode) { | |
433 switch (keycode) { | |
434 case base::VKEY_RETURN: { | |
435 std::vector<const BookmarkNode*> selected_nodes = GetSelectedTableNodes(); | |
436 if (selected_nodes.size() == 1 && selected_nodes[0]->is_folder()) { | |
437 SelectInTree(selected_nodes[0]); | |
438 } else { | |
439 bookmark_utils::OpenAll( | |
440 GetWidget()->GetNativeView(), profile_, NULL, selected_nodes, | |
441 CURRENT_TAB); | |
442 } | |
443 break; | |
444 } | |
445 | |
446 case base::VKEY_BACK: { | |
447 const BookmarkNode* selected_folder = GetSelectedFolder(); | |
448 if (selected_folder != NULL && | |
449 selected_folder->GetParent() != GetBookmarkModel()->root_node()) { | |
450 SelectInTree(selected_folder->GetParent()); | |
451 } | |
452 break; | |
453 } | |
454 | |
455 default: | |
456 OnCutCopyPaste(KeyCodeToCutCopyPaste(keycode), true); | |
457 break; | |
458 } | |
459 } | |
460 | |
461 void BookmarkManagerView::OnTreeViewSelectionChanged( | |
462 views::TreeView* tree_view) { | |
463 TreeModelNode* node = tree_view_->GetSelectedNode(); | |
464 | |
465 BookmarkTableModel* new_table_model = NULL; | |
466 const BookmarkNode* table_parent_node = NULL; | |
467 bool is_search = false; | |
468 | |
469 if (node) { | |
470 switch (tree_model_->GetNodeType(node)) { | |
471 case BookmarkFolderTreeModel::BOOKMARK: | |
472 table_parent_node = tree_model_->TreeNodeAsBookmarkNode(node); | |
473 new_table_model = | |
474 BookmarkTableModel::CreateBookmarkTableModelForFolder( | |
475 profile_->GetBookmarkModel(), | |
476 table_parent_node); | |
477 break; | |
478 | |
479 case BookmarkFolderTreeModel::RECENTLY_BOOKMARKED: | |
480 new_table_model = BookmarkTableModel::CreateRecentlyBookmarkedModel( | |
481 profile_->GetBookmarkModel()); | |
482 break; | |
483 | |
484 case BookmarkFolderTreeModel::SEARCH: | |
485 is_search = true; | |
486 search_factory_.RevokeAll(); | |
487 new_table_model = CreateSearchTableModel(); | |
488 break; | |
489 | |
490 default: | |
491 NOTREACHED(); | |
492 break; | |
493 } | |
494 } | |
495 | |
496 SetTableModel(new_table_model, table_parent_node, is_search); | |
497 } | |
498 | |
499 void BookmarkManagerView::OnTreeViewKeyDown(base::KeyboardCode keycode) { | |
500 switch (keycode) { | |
501 case base::VKEY_DELETE: { | |
502 const BookmarkNode* node = GetSelectedFolder(); | |
503 if (!node || node->GetParent() == GetBookmarkModel()->root_node()) | |
504 return; | |
505 | |
506 const BookmarkNode* parent = node->GetParent(); | |
507 GetBookmarkModel()->Remove(parent, parent->IndexOfChild(node)); | |
508 break; | |
509 } | |
510 | |
511 default: | |
512 OnCutCopyPaste(KeyCodeToCutCopyPaste(keycode), false); | |
513 break; | |
514 } | |
515 } | |
516 | |
517 void BookmarkManagerView::ButtonPressed(views::Button* sender, | |
518 const views::Event& event) { | |
519 if (sender == sync_status_button_) { | |
520 if (sync_relogin_required_) { | |
521 DCHECK(sync_service_); | |
522 sync_service_->ShowLoginDialog(); | |
523 } else { | |
524 UserMetrics::RecordAction(UserMetricsAction("BookmarkManager_Sync"), | |
525 profile_); | |
526 sync_ui_util::OpenSyncMyBookmarksDialog( | |
527 profile_, ProfileSyncService::START_FROM_BOOKMARK_MANAGER); | |
528 } | |
529 } | |
530 } | |
531 | |
532 void BookmarkManagerView::Loaded(BookmarkModel* model) { | |
533 model->RemoveObserver(this); | |
534 LoadedImpl(); | |
535 } | |
536 | |
537 void BookmarkManagerView::ContentsChanged(views::Textfield* sender, | |
538 const std::wstring& new_contents) { | |
539 search_factory_.RevokeAll(); | |
540 MessageLoop::current()->PostDelayedTask(FROM_HERE, | |
541 search_factory_.NewRunnableMethod(&BookmarkManagerView::PerformSearch), | |
542 kSearchDelayMS); | |
543 } | |
544 | |
545 bool BookmarkManagerView::HandleKeystroke( | |
546 views::Textfield* sender, | |
547 const views::Textfield::Keystroke& key) { | |
548 if (key.GetKeyboardCode() == base::VKEY_RETURN) { | |
549 PerformSearch(); | |
550 search_tf_->SelectAll(); | |
551 } | |
552 | |
553 return false; | |
554 } | |
555 | |
556 void BookmarkManagerView::ShowContextMenu(views::View* source, | |
557 const gfx::Point& p, | |
558 bool is_mouse_gesture) { | |
559 DCHECK(source == table_view_ || source == tree_view_); | |
560 bool is_table = (source == table_view_); | |
561 ShowMenu(p, is_table ? | |
562 BookmarkContextMenuControllerViews::BOOKMARK_MANAGER_TABLE : | |
563 BookmarkContextMenuControllerViews::BOOKMARK_MANAGER_TREE); | |
564 } | |
565 | |
566 void BookmarkManagerView::RunMenu(views::View* source, const gfx::Point& pt) { | |
567 // TODO(glen): when you change the buttons around and what not, futz with | |
568 // this to make it look good. If you end up keeping padding numbers make them | |
569 // constants. | |
570 if (!GetBookmarkModel()->IsLoaded()) | |
571 return; | |
572 | |
573 gfx::Point menu_pt(pt); | |
574 menu_pt.Offset(UILayoutIsRightToLeft() ? | |
575 (source->width() - 5) : (-source->width() + 5), 2); | |
576 if (source->GetID() == kOrganizeMenuButtonID) { | |
577 ShowMenu(menu_pt, | |
578 BookmarkContextMenuControllerViews::BOOKMARK_MANAGER_ORGANIZE_MENU); | |
579 } else if (source->GetID() == kToolsMenuButtonID) { | |
580 ShowToolsMenu(menu_pt); | |
581 } else { | |
582 NOTREACHED(); | |
583 } | |
584 } | |
585 | |
586 void BookmarkManagerView::ExecuteCommand(int id) { | |
587 switch (id) { | |
588 case IDS_BOOKMARK_MANAGER_IMPORT_MENU: | |
589 UserMetrics::RecordAction(UserMetricsAction("BookmarkManager_Import"), | |
590 profile_); | |
591 ShowImportBookmarksFileChooser(); | |
592 break; | |
593 | |
594 case IDS_BOOKMARK_MANAGER_EXPORT_MENU: | |
595 UserMetrics::RecordAction(UserMetricsAction("BookmarkManager_Export"), | |
596 profile_); | |
597 ShowExportBookmarksFileChooser(); | |
598 break; | |
599 | |
600 default: | |
601 NOTREACHED(); | |
602 break; | |
603 } | |
604 } | |
605 | |
606 void BookmarkManagerView::FileSelected(const FilePath& path, | |
607 int index, | |
608 void* params) { | |
609 int id = reinterpret_cast<int>(params); | |
610 if (id == IDS_BOOKMARK_MANAGER_IMPORT_MENU) { | |
611 // ImporterHost is ref counted and will delete itself when done. | |
612 ImporterHost* host = new ImporterHost(); | |
613 ProfileInfo profile_info; | |
614 profile_info.browser_type = importer::BOOKMARKS_HTML; | |
615 profile_info.source_path = path.ToWStringHack(); | |
616 StartImportingWithUI(GetWidget()->GetNativeView(), importer::FAVORITES, | |
617 host, profile_info, profile_, | |
618 new ImportObserverImpl(profile()), false); | |
619 } else if (id == IDS_BOOKMARK_MANAGER_EXPORT_MENU) { | |
620 bookmark_html_writer::WriteBookmarks(profile(), path, NULL); | |
621 } else { | |
622 NOTREACHED(); | |
623 } | |
624 } | |
625 | |
626 void BookmarkManagerView::FileSelectionCanceled(void* params) { | |
627 select_file_dialog_ = NULL; | |
628 } | |
629 | |
630 BookmarkTableModel* BookmarkManagerView::CreateSearchTableModel() { | |
631 std::wstring search_text = search_tf_->text(); | |
632 if (search_text.empty()) | |
633 return NULL; | |
634 std::wstring languages = | |
635 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages); | |
636 return BookmarkTableModel::CreateSearchTableModel( | |
637 GetBookmarkModel(), search_text, languages); | |
638 } | |
639 | |
640 void BookmarkManagerView::SetTableModel(BookmarkTableModel* new_table_model, | |
641 const BookmarkNode* parent_node, | |
642 bool is_search) { | |
643 // Be sure and reset the model on the view before updating table_model_. | |
644 // Otherwise the view will attempt to use the deleted model when we set the | |
645 // new one. | |
646 table_view_->SetModel(NULL); | |
647 table_view_->SetShowPathColumn(!parent_node); | |
648 table_view_->SetModel(new_table_model); | |
649 table_view_->set_parent_node(parent_node); | |
650 table_model_.reset(new_table_model); | |
651 if (!is_search || (new_table_model && new_table_model->RowCount() > 0)) { | |
652 table_view_->SetAltText(std::wstring()); | |
653 } else if (search_tf_->text().empty()) { | |
654 table_view_->SetAltText( | |
655 l10n_util::GetString(IDS_BOOKMARK_MANAGER_NO_SEARCH_TEXT)); | |
656 } else { | |
657 table_view_->SetAltText( | |
658 l10n_util::GetStringF(IDS_BOOKMARK_MANAGER_NO_RESULTS, | |
659 search_tf_->text())); | |
660 } | |
661 } | |
662 | |
663 void BookmarkManagerView::PerformSearch() { | |
664 search_factory_.RevokeAll(); | |
665 // Reset the controller, otherwise when we change the selection we'll get | |
666 // notified and update the model twice. | |
667 tree_view_->SetController(NULL); | |
668 tree_view_->SetSelectedNode(tree_model_->search_node()); | |
669 tree_view_->SetController(this); | |
670 SetTableModel(CreateSearchTableModel(), NULL, true); | |
671 } | |
672 | |
673 void BookmarkManagerView::PrepareForShow() { | |
674 // Restore the split location, but don't let it get too small (or big), | |
675 // otherwise users might inadvertently not see the divider. | |
676 int split_x = g_browser_process->local_state()->GetInteger( | |
677 prefs::kBookmarkManagerSplitLocation); | |
678 if (split_x == -1) { | |
679 // First time running the bookmark manager, give a third of the width to | |
680 // the tree. | |
681 split_x = split_view_->width() / 3; | |
682 } | |
683 int min_split_size = split_view_->width() / 8; | |
684 // Make sure the user can see both the tree/table. | |
685 split_x = std::min(split_view_->width() - min_split_size, | |
686 std::max(min_split_size, split_x)); | |
687 split_view_->set_divider_offset(split_x); | |
688 if (!GetBookmarkModel()->IsLoaded()) { | |
689 search_tf_->SetReadOnly(true); | |
690 return; | |
691 } | |
692 | |
693 LoadedImpl(); | |
694 } | |
695 | |
696 void BookmarkManagerView::LoadedImpl() { | |
697 BookmarkModel* bookmark_model = GetBookmarkModel(); | |
698 const BookmarkNode* bookmark_bar_node = bookmark_model->GetBookmarkBarNode(); | |
699 table_model_.reset( | |
700 BookmarkTableModel::CreateBookmarkTableModelForFolder(bookmark_model, | |
701 bookmark_bar_node)); | |
702 table_view_->SetModel(table_model_.get()); | |
703 table_view_->set_parent_node(bookmark_bar_node); | |
704 | |
705 tree_model_.reset(new BookmarkFolderTreeModel(bookmark_model)); | |
706 tree_view_->SetModel(tree_model_.get()); | |
707 | |
708 tree_view_->ExpandAll(); | |
709 | |
710 tree_view_->SetSelectedNode( | |
711 tree_model_->GetFolderNodeForBookmarkNode(bookmark_bar_node)); | |
712 | |
713 search_tf_->SetReadOnly(false); | |
714 search_tf_->SetController(this); | |
715 | |
716 Layout(); | |
717 SchedulePaint(); | |
718 } | |
719 | |
720 BookmarkModel* BookmarkManagerView::GetBookmarkModel() const { | |
721 return profile_->GetBookmarkModel(); | |
722 } | |
723 | |
724 void BookmarkManagerView::ShowMenu( | |
725 const gfx::Point& p, | |
726 BookmarkContextMenuControllerViews::ConfigurationType config) { | |
727 if (!GetBookmarkModel()->IsLoaded()) | |
728 return; | |
729 | |
730 const BookmarkNode* parent = GetSelectedFolder(); | |
731 std::vector<const BookmarkNode*> nodes; | |
732 typedef BookmarkContextMenuControllerViews BCMCV; // Such a long name! | |
733 if (config == BCMCV::BOOKMARK_MANAGER_TABLE || | |
734 (config == BCMCV::BOOKMARK_MANAGER_ORGANIZE_MENU && | |
735 table_view_->HasFocus())) { | |
736 nodes = GetSelectedTableNodes(); | |
737 if (!parent) { | |
738 config = (config == BCMCV::BOOKMARK_MANAGER_TABLE) ? | |
739 BCMCV::BOOKMARK_MANAGER_TABLE_OTHER : | |
740 BCMCV::BOOKMARK_MANAGER_ORGANIZE_MENU_OTHER; | |
741 } | |
742 } else { | |
743 if (parent) | |
744 nodes.push_back(parent); | |
745 } | |
746 BookmarkContextMenu menu(GetWidget()->GetNativeView(), profile_, NULL, parent, | |
747 nodes, config); | |
748 menu.RunMenuAt(p); | |
749 } | |
750 | |
751 void BookmarkManagerView::OnCutCopyPaste(CutCopyPasteType type, | |
752 bool from_table) { | |
753 if (type == CUT || type == COPY) { | |
754 std::vector<const BookmarkNode*> nodes; | |
755 if (from_table) { | |
756 nodes = GetSelectedTableNodes(); | |
757 } else { | |
758 const BookmarkNode* node = GetSelectedFolder(); | |
759 if (!node || node->GetParent() == GetBookmarkModel()->root_node()) | |
760 return; | |
761 nodes.push_back(node); | |
762 } | |
763 if (nodes.empty()) | |
764 return; | |
765 | |
766 bookmark_utils::CopyToClipboard(GetBookmarkModel(), nodes, type == CUT); | |
767 } else if (type == PASTE) { | |
768 int index = from_table ? table_view_->FirstSelectedRow() : -1; | |
769 if (index != -1) | |
770 index++; | |
771 bookmark_utils::PasteFromClipboard(GetBookmarkModel(), GetSelectedFolder(), | |
772 index); | |
773 } | |
774 } | |
775 | |
776 void BookmarkManagerView::ShowToolsMenu(const gfx::Point& p) { | |
777 views::MenuItemView menu(this); | |
778 menu.AppendMenuItemWithLabel( | |
779 IDS_BOOKMARK_MANAGER_IMPORT_MENU, | |
780 l10n_util::GetString(IDS_BOOKMARK_MANAGER_IMPORT_MENU)); | |
781 menu.AppendMenuItemWithLabel( | |
782 IDS_BOOKMARK_MANAGER_EXPORT_MENU, | |
783 l10n_util::GetString(IDS_BOOKMARK_MANAGER_EXPORT_MENU)); | |
784 views::MenuItemView::AnchorPosition anchor = UILayoutIsRightToLeft() ? | |
785 views::MenuItemView::TOPRIGHT : views::MenuItemView::TOPLEFT; | |
786 menu.RunMenuAt(GetWidget()->GetNativeView(), NULL, gfx::Rect(p, gfx::Size()), | |
787 anchor, true); | |
788 } | |
789 | |
790 void BookmarkManagerView::ShowImportBookmarksFileChooser() { | |
791 if (select_file_dialog_.get()) | |
792 select_file_dialog_->ListenerDestroyed(); | |
793 | |
794 SelectFileDialog::FileTypeInfo file_type_info; | |
795 file_type_info.extensions.resize(1); | |
796 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("html")); | |
797 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("htm")); | |
798 file_type_info.include_all_files = true; | |
799 select_file_dialog_ = SelectFileDialog::Create(this); | |
800 select_file_dialog_->SelectFile( | |
801 SelectFileDialog::SELECT_OPEN_FILE, std::wstring(), | |
802 FilePath(FILE_PATH_LITERAL("bookmarks.html")), &file_type_info, 0, | |
803 std::wstring(), GetWidget()->GetNativeView(), | |
804 reinterpret_cast<void*>(IDS_BOOKMARK_MANAGER_IMPORT_MENU)); | |
805 } | |
806 | |
807 void BookmarkManagerView::ShowExportBookmarksFileChooser() { | |
808 if (select_file_dialog_.get()) | |
809 select_file_dialog_->ListenerDestroyed(); | |
810 | |
811 SelectFileDialog::FileTypeInfo file_type_info; | |
812 file_type_info.extensions.resize(1); | |
813 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("html")); | |
814 file_type_info.include_all_files = true; | |
815 select_file_dialog_ = SelectFileDialog::Create(this); | |
816 select_file_dialog_->SelectFile( | |
817 SelectFileDialog::SELECT_SAVEAS_FILE, std::wstring(), | |
818 FilePath(FILE_PATH_LITERAL("bookmarks.html")), &file_type_info, 0, | |
819 L"html", GetWidget()->GetNativeView(), | |
820 reinterpret_cast<void*>(IDS_BOOKMARK_MANAGER_EXPORT_MENU)); | |
821 } | |
822 | |
823 void BookmarkManagerView::UpdateSyncStatus() { | |
824 DCHECK(sync_service_); | |
825 string16 status_label; | |
826 string16 link_label; | |
827 sync_relogin_required_ = sync_ui_util::GetStatusLabels(sync_service_, | |
828 &status_label, &link_label) == sync_ui_util::SYNC_ERROR; | |
829 | |
830 if (sync_relogin_required_) { | |
831 sync_status_button_->SetText( | |
832 l10n_util::GetString(IDS_SYNC_BOOKMARK_BAR_ERROR)); | |
833 // The tooltip is the only way we have to display text explaining the error | |
834 // to the user. | |
835 sync_status_button_->SetTooltipText( | |
836 l10n_util::GetString(IDS_SYNC_BOOKMARK_BAR_ERROR_DESC)); | |
837 sync_status_button_->SetAccessibleName( | |
838 l10n_util::GetString(IDS_ACCNAME_SYNC_ERROR_BUTTON)); | |
839 sync_status_button_->SetIcon( | |
840 *ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_WARNING)); | |
841 sync_status_button_->GetParent()->Layout(); | |
842 return; | |
843 } | |
844 | |
845 if (sync_service_->HasSyncSetupCompleted()) { | |
846 string16 username = sync_service_->GetAuthenticatedUsername(); | |
847 status_label = l10n_util::GetStringFUTF16(IDS_SYNC_NTP_SYNCED_TO, | |
848 username); | |
849 } else if (sync_service_->SetupInProgress()) { | |
850 status_label = l10n_util::GetStringUTF16(IDS_SYNC_NTP_SETUP_IN_PROGRESS); | |
851 } else { | |
852 status_label = l10n_util::GetStringUTF16(IDS_SYNC_START_SYNC_BUTTON_LABEL); | |
853 } | |
854 sync_status_button_->SetText(status_label); | |
855 sync_status_button_->SetTooltipText(L""); | |
856 sync_status_button_->SetAccessibleName(L""); | |
857 sync_status_button_->SetIcon(SkBitmap()); | |
858 sync_status_button_->GetParent()->Layout(); | |
859 } | |
OLD | NEW |