summaryrefslogtreecommitdiffstats
path: root/chrome/browser/views/bookmark_bubble_view.cc
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
commit09911bf300f1a419907a9412154760efd0b7abc3 (patch)
treef131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/views/bookmark_bubble_view.cc
parent586acc5fe142f498261f52c66862fa417c3d52d2 (diff)
downloadchromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/views/bookmark_bubble_view.cc')
-rw-r--r--chrome/browser/views/bookmark_bubble_view.cc390
1 files changed, 390 insertions, 0 deletions
diff --git a/chrome/browser/views/bookmark_bubble_view.cc b/chrome/browser/views/bookmark_bubble_view.cc
new file mode 100644
index 0000000..8d8f34e
--- /dev/null
+++ b/chrome/browser/views/bookmark_bubble_view.cc
@@ -0,0 +1,390 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/browser/views/bookmark_bubble_view.h"
+
+#include "chrome/app/chrome_dll_resource.h"
+#include "chrome/app/theme/theme_resources.h"
+#include "chrome/browser/bookmark_bar_model.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/standard_layout.h"
+#include "chrome/browser/user_metrics.h"
+#include "chrome/browser/views/bookmark_editor_view.h"
+#include "chrome/browser/views/info_bubble.h"
+#include "chrome/common/gfx/chrome_canvas.h"
+#include "chrome/common/l10n_util.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/resource_bundle.h"
+#include "chrome/views/button.h"
+#include "chrome/views/checkbox.h"
+#include "chrome/views/native_button.h"
+#include "chrome/views/text_field.h"
+#include "generated_resources.h"
+
+using ChromeViews::ComboBox;
+using ChromeViews::ColumnSet;
+using ChromeViews::GridLayout;
+using ChromeViews::Label;
+using ChromeViews::Link;
+using ChromeViews::NativeButton;
+using ChromeViews::View;
+
+// Color of the title.
+static const SkColor kTitleColor = SkColorSetRGB(6, 45, 117);
+
+// Padding between "Title:" and the actual title.
+static const int kTitlePadding = 4;
+
+// Minimum width for the fields - they will push out the size of the bubble if
+// necessary. This should be big enough so that the field pushes the right side
+// of the bubble far enough so that the edit button's left edge is to the right
+// of the field's left edge.
+static const int kMinimumFieldSize = 180;
+
+// Max number of most recently used folders.
+static const size_t kMaxMRUFolders = 5;
+
+// Bubble close image.
+static SkBitmap* kCloseImage = NULL;
+
+// RecentlyUsedFoldersModel ---------------------------------------------------
+
+BookmarkBubbleView::RecentlyUsedFoldersModel::RecentlyUsedFoldersModel(
+ BookmarkBarModel* bb_model, BookmarkBarNode* node)
+ // Use + 2 to account for bookmark bar and other node.
+ : nodes_(bb_model->GetMostRecentlyModifiedGroups(kMaxMRUFolders + 2)),
+ node_parent_index_(0) {
+ // TODO(sky): bug 1173415 add a separator in the combobox here.
+
+ // We special case the placement of these, so remove them from the list, then
+ // fix up the order.
+ RemoveNode(bb_model->GetBookmarkBarNode());
+ RemoveNode(bb_model->other_node());
+ RemoveNode(node->GetParent());
+
+ // Make the parent the first item, unless it's the bookmark bar or other node.
+ if (node->GetParent() != bb_model->GetBookmarkBarNode() &&
+ node->GetParent() != bb_model->other_node()) {
+ nodes_.insert(nodes_.begin(), node->GetParent());
+ }
+
+ // Make sure we only have kMaxMRUFolders in the first chunk.
+ if (nodes_.size() > kMaxMRUFolders)
+ nodes_.erase(nodes_.begin() + kMaxMRUFolders, nodes_.end());
+
+ // And put the bookmark bar and other nodes at the end of the list.
+ nodes_.push_back(bb_model->GetBookmarkBarNode());
+ nodes_.push_back(bb_model->other_node());
+
+ node_parent_index_ = static_cast<int>(
+ find(nodes_.begin(), nodes_.end(), node->GetParent()) - nodes_.begin());
+}
+
+int BookmarkBubbleView::RecentlyUsedFoldersModel::GetItemCount(
+ ComboBox* source) {
+ return static_cast<int>(nodes_.size() + 1);
+}
+
+std::wstring BookmarkBubbleView::RecentlyUsedFoldersModel::GetItemAt(
+ ComboBox* source, int index) {
+ if (index == nodes_.size())
+ return l10n_util::GetString(IDS_BOOMARK_BUBBLE_CHOOSER_ANOTHER_FOLDER);
+ return nodes_[index]->GetTitle();
+}
+
+BookmarkBarNode* BookmarkBubbleView::RecentlyUsedFoldersModel::GetNodeAt(
+ int index) {
+ return nodes_[index];
+}
+
+void BookmarkBubbleView::RecentlyUsedFoldersModel::RemoveNode(
+ BookmarkBarNode* node) {
+ std::vector<BookmarkBarNode*>::iterator i =
+ find(nodes_.begin(), nodes_.end(), node);
+ if (i != nodes_.end())
+ nodes_.erase(i);
+}
+
+// BookmarkBubbleView ---------------------------------------------------------
+
+// static
+void BookmarkBubbleView::Show(HWND parent,
+ const gfx::Rect& bounds,
+ InfoBubbleDelegate* delegate,
+ Profile* profile,
+ const GURL& url,
+ bool newly_bookmarked) {
+ BookmarkBubbleView* view = new BookmarkBubbleView(delegate, profile, url,
+ newly_bookmarked);
+ InfoBubble::Show(parent, bounds, view, view);
+ GURL url_ptr(url);
+ NotificationService::current()->Notify(
+ NOTIFY_BOOKMARK_BUBBLE_SHOWN,
+ Source<Profile>(profile->GetOriginalProfile()),
+ Details<GURL>(&url_ptr));
+ view->BubbleShown();
+}
+
+BookmarkBubbleView::~BookmarkBubbleView() {
+ SetNodeTitleFromTextField();
+}
+
+void BookmarkBubbleView::DidChangeBounds(const CRect& previous,
+ const CRect& current) {
+ Layout();
+}
+
+void BookmarkBubbleView::BubbleShown() {
+ DCHECK(GetViewContainer());
+ ChromeViews::FocusManager* focus_manager =
+ ChromeViews::FocusManager::GetFocusManager(GetViewContainer()->GetHWND());
+ focus_manager->RegisterAccelerator(
+ ChromeViews::Accelerator(VK_RETURN, false, false, false), this);
+
+ title_tf_->RequestFocus();
+ title_tf_->SelectAll();
+}
+
+bool BookmarkBubbleView::AcceleratorPressed(
+ const ChromeViews::Accelerator& accelerator) {
+ if (accelerator.GetKeyCode() != VK_RETURN)
+ return false;
+
+ Close();
+ return true;
+}
+
+BookmarkBubbleView::BookmarkBubbleView(InfoBubbleDelegate* delegate,
+ Profile* profile,
+ const GURL& url,
+ bool newly_bookmarked)
+ : delegate_(delegate),
+ profile_(profile),
+ url_(url),
+ newly_bookmarked_(newly_bookmarked),
+ parent_model_(profile_->GetBookmarkBarModel(),
+ profile_->GetBookmarkBarModel()->GetNodeByURL(url)) {
+ Init();
+}
+
+void BookmarkBubbleView::Init() {
+ if (!kCloseImage) {
+ kCloseImage = ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_INFO_BUBBLE_CLOSE);
+ }
+
+ remove_link_ = new Link(l10n_util::GetString(
+ IDS_BOOMARK_BUBBLE_REMOVE_BOOKMARK));
+ remove_link_->SetController(this);
+
+ edit_button_ = new NativeButton(
+ l10n_util::GetString(IDS_BOOMARK_BUBBLE_OPTIONS));
+ edit_button_->SetListener(this);
+
+ close_button_ = new NativeButton(l10n_util::GetString(IDS_CLOSE));
+ close_button_->SetListener(this);
+
+ parent_combobox_ = new ComboBox(&parent_model_);
+ parent_combobox_->SetSelectedItem(parent_model_.node_parent_index());
+ parent_combobox_->SetListener(this);
+
+ Label* title_label = new Label(l10n_util::GetString(
+ newly_bookmarked_ ? IDS_BOOMARK_BUBBLE_PAGE_BOOKMARKED :
+ IDS_BOOMARK_BUBBLE_PAGE_BOOKMARK));
+ title_label->SetFont(
+ ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::MediumFont));
+ title_label->SetColor(kTitleColor);
+
+ GridLayout* layout = new GridLayout(this);
+ SetLayoutManager(layout);
+
+ ColumnSet* cs = layout->AddColumnSet(0);
+
+ // Top (title) row.
+ cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, GridLayout::USE_PREF,
+ 0, 0);
+ cs->AddPaddingColumn(1, kUnrelatedControlHorizontalSpacing);
+ cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, GridLayout::USE_PREF,
+ 0, 0);
+
+ // Middle (input field) rows.
+ cs = layout->AddColumnSet(2);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0,
+ GridLayout::USE_PREF, 0, 0);
+ cs->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
+ cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
+ GridLayout::USE_PREF, 0, kMinimumFieldSize);
+
+ // Bottom (buttons) row.
+ cs = layout->AddColumnSet(3);
+ cs->AddPaddingColumn(1, kRelatedControlHorizontalSpacing);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::TRAILING, 0,
+ GridLayout::USE_PREF, 0, 0);
+ // We subtract 2 to account for the natural button padding, and
+ // to bring the separation visually in line with the row separation
+ // height.
+ cs->AddPaddingColumn(0, kRelatedButtonHSpacing - 2);
+ cs->AddColumn(GridLayout::LEADING, GridLayout::TRAILING, 0,
+ GridLayout::USE_PREF, 0, 0);
+
+ layout->StartRow(0, 0);
+ layout->AddView(title_label);
+ layout->AddView(remove_link_);
+
+ layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
+ layout->StartRow(0, 2);
+ layout->AddView(
+ new Label(l10n_util::GetString(IDS_BOOMARK_BUBBLE_TITLE_TEXT)));
+ title_tf_ = new ChromeViews::TextField();
+ title_tf_->SetText(GetTitle());
+ layout->AddView(title_tf_);
+
+ layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
+
+ layout->StartRow(0, 2);
+ layout->AddView(
+ new Label(l10n_util::GetString(IDS_BOOMARK_BUBBLE_FOLDER_TEXT)));
+ layout->AddView(parent_combobox_);
+ layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
+
+ layout->StartRow(0, 3);
+ layout->AddView(edit_button_);
+ layout->AddView(close_button_);
+}
+
+std::wstring BookmarkBubbleView::GetTitle() {
+ BookmarkBarModel* bookmark_model= profile_->GetBookmarkBarModel();
+ BookmarkBarNode* node = bookmark_model->GetNodeByURL(url_);
+ if (node)
+ return node->GetTitle();
+ else
+ NOTREACHED();
+ return std::wstring();
+}
+
+void BookmarkBubbleView::ButtonPressed(ChromeViews::NativeButton* sender) {
+ if (sender == edit_button_) {
+ UserMetrics::RecordAction(L"BookmarkBubble_Edit", profile_);
+ ShowEditor();
+ } else {
+ DCHECK(sender == close_button_);
+ Close();
+ }
+ // WARNING: we've most likely been deleted when CloseWindow returns.
+}
+
+void BookmarkBubbleView::LinkActivated(Link* source, int event_flags) {
+ DCHECK(source == remove_link_);
+ RemoveBookmark();
+}
+
+void BookmarkBubbleView::ItemChanged(ComboBox* combo_box,
+ int prev_index,
+ int new_index) {
+ if (new_index + 1 == parent_model_.GetItemCount(parent_combobox_)) {
+ UserMetrics::RecordAction(L"BookmarkBubble_EditFromCombobox", profile_);
+
+ ShowEditor();
+ return;
+ }
+ BookmarkBarModel* model = profile_->GetBookmarkBarModel();
+ BookmarkBarNode* node = model->GetNodeByURL(url_);
+ if (node) {
+ BookmarkBarNode* new_parent = parent_model_.GetNodeAt(new_index);
+ if (new_parent != node->GetParent()) {
+ UserMetrics::RecordAction(L"BookmarkBubble_ChangeParent", profile_);
+ model->Move(node, new_parent, new_parent->GetChildCount());
+ }
+ }
+}
+
+void BookmarkBubbleView::InfoBubbleClosing(InfoBubble* info_bubble) {
+ if (delegate_)
+ delegate_->InfoBubbleClosing(info_bubble);
+ NotificationService::current()->Notify(
+ NOTIFY_BOOKMARK_BUBBLE_HIDDEN,
+ Source<Profile>(profile_->GetOriginalProfile()),
+ NotificationService::NoDetails());
+}
+
+bool BookmarkBubbleView::CloseOnEscape() {
+ return delegate_ ? delegate_->CloseOnEscape() : true;
+}
+
+void BookmarkBubbleView::Close() {
+ static_cast<InfoBubble*>(GetViewContainer())->Close();
+}
+
+void BookmarkBubbleView::RemoveBookmark() {
+ UserMetrics::RecordAction(L"BookmarkBubble_Unstar", profile_);
+
+ GURL url = url_;
+ BookmarkBarModel* model = profile_->GetBookmarkBarModel();
+ // Close first, then notify the service. That way we know we won't be
+ // visible and don't have to worry about some other window becoming
+ // activated and deleting us before we invoke Close.
+ Close();
+ // WARNING: we've likely been deleted.
+ if (model)
+ model->SetURLStarred(url, std::wstring(), false);
+}
+
+void BookmarkBubbleView::ShowEditor() {
+ // Parent the editor to our root ancestor (not the root we're in, as that
+ // is the info bubble and will close shortly).
+ HWND parent = GetAncestor(GetViewContainer()->GetHWND(), GA_ROOTOWNER);
+
+ // We're about to show the bookmark editor. When the bookmark editor closes
+ // we want the browser to become active. HWNDViewContainer::Hide() does a
+ // hide in a such way that activation isn't changed, which means when we
+ // close Windows gets confused as to who it should give active status to.
+ // We explicitly hide the bookmark bubble window in such a way that
+ // activation status changes. That way, when the editor closes, activation
+ // is properly restored to the browser.
+ ShowWindow(GetViewContainer()->GetHWND(), SW_HIDE);
+
+ // Even though we just hid the window, we need to invoke Close to schedule
+ // the delete and all that.
+ Close();
+
+ BookmarkEditorView::Show(parent, profile_, url_, title_);
+}
+
+void BookmarkBubbleView::SetNodeTitleFromTextField() {
+ BookmarkBarModel* model = profile_->GetBookmarkBarModel();
+ BookmarkBarNode* node = model->GetNodeByURL(url_);
+ if (node) {
+ const std::wstring new_title = title_tf_->GetText();
+ if (new_title != node->GetTitle()) {
+ model->SetTitle(node, new_title);
+ UserMetrics::RecordAction(L"BookmarkBubble_ChangeTitleInBubble",
+ profile_);
+ }
+ }
+} \ No newline at end of file