diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
commit | 09911bf300f1a419907a9412154760efd0b7abc3 (patch) | |
tree | f131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/views/bookmark_bubble_view.cc | |
parent | 586acc5fe142f498261f52c66862fa417c3d52d2 (diff) | |
download | chromium_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.cc | 390 |
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 |