diff options
Diffstat (limited to 'chrome/browser/views/options/cookies_view.cc')
-rw-r--r-- | chrome/browser/views/options/cookies_view.cc | 791 |
1 files changed, 791 insertions, 0 deletions
diff --git a/chrome/browser/views/options/cookies_view.cc b/chrome/browser/views/options/cookies_view.cc new file mode 100644 index 0000000..3b59198 --- /dev/null +++ b/chrome/browser/views/options/cookies_view.cc @@ -0,0 +1,791 @@ +// 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 <algorithm> + +#include "chrome/browser/views/options/cookies_view.h" + +#include "base/string_util.h" +#include "chrome/app/locales/locale_settings.h" +#include "chrome/app/theme/theme_resources.h" +#include "chrome/browser/standard_layout.h" +#include "chrome/browser/profile.h" +#include "chrome/common/gfx/color_utils.h" +#include "chrome/common/l10n_util.h" +#include "chrome/common/resource_bundle.h" +#include "chrome/common/time_format.h" +#include "chrome/common/win_util.h" +#include "chrome/views/border.h" +#include "chrome/views/grid_layout.h" +#include "chrome/views/label.h" +#include "chrome/views/text_field.h" +#include "chrome/views/table_view.h" +#include "generated_resources.h" +#include "net/base/cookie_monster.h" +#include "net/url_request/url_request_context.h" + +// static +ChromeViews::Window* CookiesView::instance_ = NULL; +static const int kCookieInfoViewBorderSize = 1; +static const int kCookieInfoViewInsetSize = 3; +static const int kSearchFilterDelayMs = 500; + +/////////////////////////////////////////////////////////////////////////////// +// CookiesTableModel + +class CookiesTableModel : public ChromeViews::TableModel { + public: + explicit CookiesTableModel(Profile* profile); + virtual ~CookiesTableModel() {} + + // Returns information about the Cookie at the specified index. + std::string GetDomainAt(int index); + CookieMonster::CanonicalCookie& GetCookieAt(int index); + + // Remove the specified cookies from the Cookie Monster and update the view. + void RemoveCookies(int start_index, int remove_count); + void RemoveAllShownCookies(); + + // ChromeViews::TableModel implementation: + virtual int RowCount(); + virtual std::wstring GetText(int row, int column_id); + virtual SkBitmap GetIcon(int row); + virtual void SetObserver(ChromeViews::TableModelObserver* observer); + + // Filter the cookies to only display matched results. + void UpdateSearchResults(const std::wstring& filter); + + private: + void LoadCookies(); + void DoFilter(); + + std::wstring filter_; + + // The profile from which this model sources cookies. + Profile* profile_; + + typedef CookieMonster::CookieList CookieList; + typedef std::vector<CookieMonster::CookieListPair*> CookiePtrList; + CookieList all_cookies_; + CookiePtrList shown_cookies_; + + ChromeViews::TableModelObserver* observer_; + + // Static resources for this object. + static SkBitmap cookie_icon_; + static void InitClass(); + + DISALLOW_EVIL_CONSTRUCTORS(CookiesTableModel); +}; + +// static +SkBitmap CookiesTableModel::cookie_icon_; + +/////////////////////////////////////////////////////////////////////////////// +// CookiesTableModel, public: + +CookiesTableModel::CookiesTableModel(Profile* profile) + : profile_(profile) { + InitClass(); + LoadCookies(); +} + +std::string CookiesTableModel::GetDomainAt(int index) { + DCHECK(index >= 0 && index < RowCount()); + return shown_cookies_.at(index)->first; +} + +CookieMonster::CanonicalCookie& CookiesTableModel::GetCookieAt(int index) { + DCHECK(index >= 0 && index < RowCount()); + return shown_cookies_.at(index)->second; +} + +void CookiesTableModel::RemoveCookies(int start_index, int remove_count) { + if (remove_count <= 0) { + NOTREACHED(); + return; + } + + CookieMonster* monster = profile_->GetRequestContext()->cookie_store(); + + // We need to update the searched results list, the full cookie list, + // and the view. We walk through the search results list (which is what + // is displayed) and map these back to the full cookie list. They should + // be in the same sort order, and always exist, so we can just walk once. + // We can't delete any entries from all_cookies_ without invaliding all of + // our pointers after it (which are in shown_cookies), so we go backwards. + CookiePtrList::iterator first = shown_cookies_.begin() + start_index; + CookiePtrList::iterator last = first + remove_count; + CookieList::iterator all_it = all_cookies_.end(); + while (last != first) { + --last; + --all_it; + // Seek to the corresponding entry in all_cookies_ + while (&*all_it != *last) --all_it; + // Delete the cookie from the monster + monster->DeleteCookie(all_it->first, all_it->second, true); + all_it = all_cookies_.erase(all_it); + } + + // By deleting entries from all_cookies, we just possibly moved stuff around + // and have thus invalidated all of our pointers, so rebuild shown_cookies. + // We could do this all better if there was a way to mark elements of + // all_cookies as dead instead of deleting, but this should be fine for now. + DoFilter(); + observer_->OnItemsRemoved(start_index, remove_count); +} + +void CookiesTableModel::RemoveAllShownCookies() { + RemoveCookies(0, RowCount()); +} + +/////////////////////////////////////////////////////////////////////////////// +// CookiesTableModel, ChromeViews::TableModel implementation: + +int CookiesTableModel::RowCount() { + return static_cast<int>(shown_cookies_.size()); +} + +std::wstring CookiesTableModel::GetText(int row, int column_id) { + DCHECK(row >= 0 && row < RowCount()); + switch (column_id) { + case IDS_COOKIES_DOMAIN_COLUMN_HEADER: + { + // Domain cookies start with a trailing dot, but we will show this + // in the cookie details, show it without the dot in the list. + std::string& domain = shown_cookies_.at(row)->first; + if (!domain.empty() && domain[0] == '.') + return UTF8ToWide(domain.substr(1)); + return UTF8ToWide(domain); + } + break; + case IDS_COOKIES_NAME_COLUMN_HEADER: + return UTF8ToWide(shown_cookies_.at(row)->second.Name()); + break; + } + NOTREACHED(); + return L""; +} + +SkBitmap CookiesTableModel::GetIcon(int row) { + return cookie_icon_; +} + +void CookiesTableModel::SetObserver(ChromeViews::TableModelObserver* observer) { + observer_ = observer; +} + +/////////////////////////////////////////////////////////////////////////////// +// CookiesTableModel, private: + +// Returns true if |cookie| matches the specified filter, where "match" is +// defined as the cookie's domain, name and value contains filter text +// somewhere. +static bool ContainsFilterText(const std::string& domain, + const CookieMonster::CanonicalCookie& cookie, + const std::string& filter) { + return domain.find(filter) != std::string::npos || + cookie.Name().find(filter) != std::string::npos || + cookie.Value().find(filter) != std::string::npos; +} + +// Sort ignore the '.' prefix for domain cookies. +static bool CookieSorter(const CookieMonster::CookieListPair& cp1, + const CookieMonster::CookieListPair& cp2) { + bool is1domain = !cp1.first.empty() && cp1.first[0] == '.'; + bool is2domain = !cp2.first.empty() && cp2.first[0] == '.'; + + // They are both either domain or host cookies, sort them normally. + if (is1domain == is2domain) + return cp1.first < cp2.first; + + // One (but only one) is a domain cookie, skip the beginning '.'. + int comp = is1domain ? + cp1.first.compare(1, cp1.first.length() - 1, cp2.first) : + -cp2.first.compare(1, cp2.first.length() - 1, cp1.first); + + return comp < 0; +} + +void CookiesTableModel::LoadCookies() { + // mmargh mmargh mmargh! + CookieMonster* cookie_monster = + profile_->GetRequestContext()->cookie_store(); + all_cookies_ = cookie_monster->GetAllCookies(); + std::sort(all_cookies_.begin(), all_cookies_.end(), CookieSorter); + DoFilter(); +} + +void CookiesTableModel::DoFilter() { + std::string utf8_filter = WideToUTF8(filter_); + bool has_filter = !utf8_filter.empty(); + + shown_cookies_.clear(); + + CookieList::iterator iter = all_cookies_.begin(); + for (; iter != all_cookies_.end(); ++iter) { + if (!has_filter || + ContainsFilterText(iter->first, iter->second, utf8_filter)) { + shown_cookies_.push_back(&*iter); + } + } +} + +void CookiesTableModel::UpdateSearchResults(const std::wstring& filter) { + filter_ = filter; + DoFilter(); + observer_->OnModelChanged(); +} + +// static +void CookiesTableModel::InitClass() { + static bool initialized = false; + if (!initialized) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + cookie_icon_ = *rb.GetBitmapNamed(IDR_COOKIE_ICON); + initialized = true; + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// CookiesTableView +// Overridden to handle Delete key presses + +class CookiesTableView : public ChromeViews::TableView { + public: + CookiesTableView(CookiesTableModel* cookies_model, + std::vector<ChromeViews::TableColumn> columns); + virtual ~CookiesTableView() {} + + // Removes the cookies associated with the selected rows in the TableView. + void RemoveSelectedCookies(); + + protected: + // ChromeViews::TableView implementation: + virtual void OnKeyDown(unsigned short virtual_keycode); + + private: + // Our model, as a CookiesTableModel. + CookiesTableModel* cookies_model_; + + DISALLOW_EVIL_CONSTRUCTORS(CookiesTableView); +}; + +CookiesTableView::CookiesTableView( + CookiesTableModel* cookies_model, + std::vector<ChromeViews::TableColumn> columns) + : ChromeViews::TableView(cookies_model, columns, + ChromeViews::ICON_AND_TEXT, false, true, true), + cookies_model_(cookies_model) { +} + +void CookiesTableView::RemoveSelectedCookies() { + // It's possible that we don't have anything selected. + if (SelectedRowCount() <= 0) + return; + + // Remove the selected cookies. + int selected_row = FirstSelectedRow(); + cookies_model_->RemoveCookies(selected_row, SelectedRowCount()); + // Keep an element selected + if (RowCount() > 0) + Select(std::min(RowCount() - 1, selected_row)); +} + +void CookiesTableView::OnKeyDown(unsigned short virtual_keycode) { + if (virtual_keycode == VK_DELETE) + RemoveSelectedCookies(); +} + +/////////////////////////////////////////////////////////////////////////////// +// CookieInfoView +// +// Responsible for displaying a tabular grid of Cookie information. +class CookieInfoView : public ChromeViews::View { + public: + CookieInfoView(); + virtual ~CookieInfoView(); + + // Update the display from the specified CookieNode. + void SetCookie(const std::string& domain, + const CookieMonster::CanonicalCookie& cookie_node); + + // Clears the cookie display to indicate that no or multiple cookies are + // selected. + void ClearCookieDisplay(); + + protected: + // ChromeViews::View overrides: + virtual void ViewHierarchyChanged(bool is_add, + ChromeViews::View* parent, + ChromeViews::View* child); + + private: + // Set up the view layout + void Init(); + + // Individual property labels + ChromeViews::Label* name_label_; + ChromeViews::TextField* name_value_field_; + ChromeViews::Label* content_label_; + ChromeViews::TextField* content_value_field_; + ChromeViews::Label* domain_label_; + ChromeViews::TextField* domain_value_field_; + ChromeViews::Label* path_label_; + ChromeViews::TextField* path_value_field_; + ChromeViews::Label* send_for_label_; + ChromeViews::TextField* send_for_value_field_; + ChromeViews::Label* created_label_; + ChromeViews::TextField* created_value_field_; + ChromeViews::Label* expires_label_; + ChromeViews::TextField* expires_value_field_; + + DISALLOW_EVIL_CONSTRUCTORS(CookieInfoView); +}; + +/////////////////////////////////////////////////////////////////////////////// +// CookieInfoView, public: + +CookieInfoView::CookieInfoView() + : name_label_(NULL), + name_value_field_(NULL), + content_label_(NULL), + content_value_field_(NULL), + domain_label_(NULL), + domain_value_field_(NULL), + path_label_(NULL), + path_value_field_(NULL), + send_for_label_(NULL), + send_for_value_field_(NULL), + created_label_(NULL), + created_value_field_(NULL), + expires_label_(NULL), + expires_value_field_(NULL) { +} + +CookieInfoView::~CookieInfoView() { +} + +void CookieInfoView::SetCookie(const std::string& domain, + const CookieMonster::CanonicalCookie& cookie) { + name_value_field_->SetText(UTF8ToWide(cookie.Name())); + content_value_field_->SetText(UTF8ToWide(cookie.Value())); + domain_value_field_->SetText(UTF8ToWide(domain)); + path_value_field_->SetText(UTF8ToWide(cookie.Path())); + created_value_field_->SetText( + TimeFormat::FriendlyDateAndTime(cookie.CreationDate())); + + if (cookie.DoesExpire()) { + expires_value_field_->SetText( + TimeFormat::FriendlyDateAndTime(cookie.ExpiryDate())); + } else { + // TODO(deanm) need a string that the average user can understand + // "When you quit or restart your browser" ? + expires_value_field_->SetText( + l10n_util::GetString(IDS_COOKIES_COOKIE_EXPIRES_SESSION)); + } + + std::wstring sendfor_text; + if (cookie.IsSecure()) { + sendfor_text = l10n_util::GetString(IDS_COOKIES_COOKIE_SENDFOR_SECURE); + } else { + sendfor_text = l10n_util::GetString(IDS_COOKIES_COOKIE_SENDFOR_ANY); + } + send_for_value_field_->SetText(sendfor_text); +} + +void CookieInfoView::ClearCookieDisplay() { + std::wstring no_cookie_string = + l10n_util::GetString(IDS_COOKIES_COOKIE_NONESELECTED); + name_value_field_->SetText(no_cookie_string); + name_value_field_->SetEnabled(false); + content_value_field_->SetText(no_cookie_string); + content_value_field_->SetEnabled(false); + domain_value_field_->SetText(no_cookie_string); + domain_value_field_->SetEnabled(false); + path_value_field_->SetText(no_cookie_string); + path_value_field_->SetEnabled(false); + send_for_value_field_->SetText(no_cookie_string); + send_for_value_field_->SetEnabled(false); + created_value_field_->SetText(no_cookie_string); + created_value_field_->SetEnabled(false); + expires_value_field_->SetText(no_cookie_string); + expires_value_field_->SetEnabled(false); +} + +/////////////////////////////////////////////////////////////////////////////// +// CookieInfoView, ChromeViews::View overrides: + +void CookieInfoView::ViewHierarchyChanged(bool is_add, + ChromeViews::View* parent, + ChromeViews::View* child) { + if (is_add && child == this) + Init(); +} + +/////////////////////////////////////////////////////////////////////////////// +// CookieInfoView, private: + +void CookieInfoView::Init() { + SkColor border_color = color_utils::GetSysSkColor(COLOR_3DSHADOW); + ChromeViews::Border* border = ChromeViews::Border::CreateSolidBorder( + kCookieInfoViewBorderSize, border_color); + SetBorder(border); + + name_label_ = new ChromeViews::Label( + l10n_util::GetString(IDS_COOKIES_COOKIE_NAME_LABEL)); + name_value_field_ = new ChromeViews::TextField; + content_label_ = new ChromeViews::Label( + l10n_util::GetString(IDS_COOKIES_COOKIE_CONTENT_LABEL)); + content_value_field_ = new ChromeViews::TextField; + domain_label_ = new ChromeViews::Label( + l10n_util::GetString(IDS_COOKIES_COOKIE_DOMAIN_LABEL)); + domain_value_field_ = new ChromeViews::TextField; + path_label_ = new ChromeViews::Label( + l10n_util::GetString(IDS_COOKIES_COOKIE_PATH_LABEL)); + path_value_field_ = new ChromeViews::TextField; + send_for_label_ = new ChromeViews::Label( + l10n_util::GetString(IDS_COOKIES_COOKIE_SENDFOR_LABEL)); + send_for_value_field_ = new ChromeViews::TextField; + created_label_ = new ChromeViews::Label( + l10n_util::GetString(IDS_COOKIES_COOKIE_CREATED_LABEL)); + created_value_field_ = new ChromeViews::TextField; + expires_label_ = new ChromeViews::Label( + l10n_util::GetString(IDS_COOKIES_COOKIE_EXPIRES_LABEL)); + expires_value_field_ = new ChromeViews::TextField; + + using ChromeViews::GridLayout; + using ChromeViews::ColumnSet; + + GridLayout* layout = new GridLayout(this); + layout->SetInsets(kCookieInfoViewInsetSize, + kCookieInfoViewInsetSize, + kCookieInfoViewInsetSize, + kCookieInfoViewInsetSize); + SetLayoutManager(layout); + + int three_column_layout_id = 0; + ColumnSet* column_set = layout->AddColumnSet(three_column_layout_id); + column_set->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0, + GridLayout::USE_PREF, 0, 0); + column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing); + column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, + GridLayout::USE_PREF, 0, 0); + + layout->StartRow(0, three_column_layout_id); + layout->AddView(name_label_); + layout->AddView(name_value_field_); + layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing); + layout->StartRow(0, three_column_layout_id); + layout->AddView(content_label_); + layout->AddView(content_value_field_); + layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing); + layout->StartRow(0, three_column_layout_id); + layout->AddView(domain_label_); + layout->AddView(domain_value_field_); + layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing); + layout->StartRow(0, three_column_layout_id); + layout->AddView(path_label_); + layout->AddView(path_value_field_); + layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing); + layout->StartRow(0, three_column_layout_id); + layout->AddView(send_for_label_); + layout->AddView(send_for_value_field_); + layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing); + layout->StartRow(0, three_column_layout_id); + layout->AddView(created_label_); + layout->AddView(created_value_field_); + layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing); + layout->StartRow(0, three_column_layout_id); + layout->AddView(expires_label_); + layout->AddView(expires_value_field_); + + // Color these borderless text areas the same as the containing dialog. + SkColor text_area_background = color_utils::GetSysSkColor(COLOR_3DFACE); + // Now that the TextFields are in the view hierarchy, we can initialize them. + name_value_field_->SetReadOnly(true); + name_value_field_->RemoveBorder(); + name_value_field_->SetBackgroundColor(text_area_background); + content_value_field_->SetReadOnly(true); + content_value_field_->RemoveBorder(); + content_value_field_->SetBackgroundColor(text_area_background); + domain_value_field_->SetReadOnly(true); + domain_value_field_->RemoveBorder(); + domain_value_field_->SetBackgroundColor(text_area_background); + path_value_field_->SetReadOnly(true); + path_value_field_->RemoveBorder(); + path_value_field_->SetBackgroundColor(text_area_background); + send_for_value_field_->SetReadOnly(true); + send_for_value_field_->RemoveBorder(); + send_for_value_field_->SetBackgroundColor(text_area_background); + created_value_field_->SetReadOnly(true); + created_value_field_->RemoveBorder(); + created_value_field_->SetBackgroundColor(text_area_background); + expires_value_field_->SetReadOnly(true); + expires_value_field_->RemoveBorder(); + expires_value_field_->SetBackgroundColor(text_area_background); +} + +/////////////////////////////////////////////////////////////////////////////// +// CookiesView, public: + +// static +void CookiesView::ShowCookiesWindow(Profile* profile) { + if (!instance_) { + CookiesView* cookies_view = new CookiesView(profile); + instance_ = ChromeViews::Window::CreateChromeWindow( + NULL, gfx::Rect(), cookies_view, cookies_view); + } + if (!instance_->IsVisible()) { + instance_->Show(); + } else { + instance_->Activate(); + } +} + +CookiesView::~CookiesView() { + cookies_table_->SetModel(NULL); +} + +void CookiesView::UpdateSearchResults() { + cookies_table_model_->UpdateSearchResults(search_field_->GetText()); + remove_all_button_->SetEnabled(cookies_table_model_->RowCount() > 0); +} + +/////////////////////////////////////////////////////////////////////////////// +// CookiesView, ChromeViews::NativeButton::listener implementation: + +void CookiesView::ButtonPressed(ChromeViews::NativeButton* sender) { + if (sender == remove_button_) { + cookies_table_->RemoveSelectedCookies(); + } else if (sender == remove_all_button_) { + // Delete all the Cookies shown. + cookies_table_model_->RemoveAllShownCookies(); + UpdateForEmptyState(); + } else if (sender == clear_search_button_) { + ResetSearchQuery(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// CookiesView, ChromeViews::TableViewObserver implementation: +void CookiesView::OnSelectionChanged() { + int selected_row_count = cookies_table_->SelectedRowCount(); + if (selected_row_count == 1) { + int selected_index = cookies_table_->FirstSelectedRow(); + if (selected_index >= 0 && + selected_index < cookies_table_model_->RowCount()) { + info_view_->SetCookie(cookies_table_model_->GetDomainAt(selected_index), + cookies_table_model_->GetCookieAt(selected_index)); + } + } else { + info_view_->ClearCookieDisplay(); + } + remove_button_->SetEnabled(selected_row_count != 0); + if (cookies_table_->RowCount() == 0) + UpdateForEmptyState(); +} + +/////////////////////////////////////////////////////////////////////////////// +// CookiesView, ChromeViews::TextField::Controller implementation: + +void CookiesView::ContentsChanged(ChromeViews::TextField* sender, + const std::wstring& new_contents) { + search_update_factory_.RevokeAll(); + MessageLoop::current()->PostDelayedTask(FROM_HERE, + search_update_factory_.NewRunnableMethod( + &CookiesView::UpdateSearchResults), kSearchFilterDelayMs); +} + +void CookiesView::HandleKeystroke(ChromeViews::TextField* sender, + UINT message, TCHAR key, UINT repeat_count, + UINT flags) { + switch (key) { + case VK_ESCAPE: + ResetSearchQuery(); + break; + case VK_RETURN: + search_update_factory_.RevokeAll(); + UpdateSearchResults(); + break; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// CookiesView, ChromeViews::DialogDelegate implementation: + +std::wstring CookiesView::GetWindowTitle() const { + return l10n_util::GetString(IDS_COOKIES_WINDOW_TITLE); +} + +void CookiesView::WindowClosing() { + instance_ = NULL; +} + +/////////////////////////////////////////////////////////////////////////////// +// CookiesView, ChromeViews::View overrides: + +void CookiesView::Layout() { + // Lay out the Remove/Remove All buttons in the parent view. + CSize ps; + remove_button_->GetPreferredSize(&ps); + CRect parent_bounds; + GetParent()->GetLocalBounds(&parent_bounds, false); + int y_buttons = parent_bounds.bottom - ps.cy - kButtonVEdgeMargin; + + remove_button_->SetBounds(kPanelHorizMargin, y_buttons, ps.cx, ps.cy); + + remove_all_button_->GetPreferredSize(&ps); + int remove_all_x = remove_button_->GetX() + remove_button_->GetWidth() + + kRelatedControlHorizontalSpacing; + remove_all_button_->SetBounds(remove_all_x, y_buttons, ps.cx, ps.cy); + + // Lay out this View + View::Layout(); +} + +void CookiesView::GetPreferredSize(CSize* out) { + DCHECK(out); + *out = ChromeViews::Window::GetLocalizedContentsSize( + IDS_COOKIES_DIALOG_WIDTH_CHARS, + IDS_COOKIES_DIALOG_HEIGHT_LINES).ToSIZE(); +} + +void CookiesView::ViewHierarchyChanged(bool is_add, + ChromeViews::View* parent, + ChromeViews::View* child) { + if (is_add && child == this) + Init(); +} + +/////////////////////////////////////////////////////////////////////////////// +// CookiesView, private: + +CookiesView::CookiesView(Profile* profile) + : search_label_(NULL), + search_field_(NULL), + clear_search_button_(NULL), + description_label_(NULL), + cookies_table_(NULL), + info_view_(NULL), + remove_button_(NULL), + remove_all_button_(NULL), + profile_(profile), + search_update_factory_(this) { +} + +void CookiesView::Init() { + search_label_ = new ChromeViews::Label( + l10n_util::GetString(IDS_COOKIES_SEARCH_LABEL)); + search_field_ = new ChromeViews::TextField; + search_field_->SetController(this); + clear_search_button_ = new ChromeViews::NativeButton( + l10n_util::GetString(IDS_COOKIES_CLEAR_SEARCH_LABEL)); + clear_search_button_->SetListener(this); + description_label_ = new ChromeViews::Label( + l10n_util::GetString(IDS_COOKIES_INFO_LABEL)); + description_label_->SetHorizontalAlignment(ChromeViews::Label::ALIGN_LEFT); + + cookies_table_model_.reset(new CookiesTableModel(profile_)); + info_view_ = new CookieInfoView; + std::vector<ChromeViews::TableColumn> columns; + columns.push_back(ChromeViews::TableColumn(IDS_COOKIES_DOMAIN_COLUMN_HEADER, + ChromeViews::TableColumn::LEFT, + 200, 0.5f)); + columns.push_back(ChromeViews::TableColumn(IDS_COOKIES_NAME_COLUMN_HEADER, + ChromeViews::TableColumn::LEFT, + 150, 0.5f)); + cookies_table_ = new CookiesTableView(cookies_table_model_.get(), columns); + cookies_table_->SetObserver(this); + remove_button_ = new ChromeViews::NativeButton( + l10n_util::GetString(IDS_COOKIES_REMOVE_LABEL)); + remove_button_->SetListener(this); + remove_all_button_ = new ChromeViews::NativeButton( + l10n_util::GetString(IDS_COOKIES_REMOVE_ALL_LABEL)); + remove_all_button_->SetListener(this); + + using ChromeViews::GridLayout; + using ChromeViews::ColumnSet; + + GridLayout* layout = CreatePanelGridLayout(this); + SetLayoutManager(layout); + + const int five_column_layout_id = 0; + ColumnSet* column_set = layout->AddColumnSet(five_column_layout_id); + column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 0, + GridLayout::USE_PREF, 0, 0); + column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing); + column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, + GridLayout::USE_PREF, 0, 0); + column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing); + column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0, + GridLayout::USE_PREF, 0, 0); + + const int single_column_layout_id = 1; + column_set = layout->AddColumnSet(single_column_layout_id); + column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, + GridLayout::USE_PREF, 0, 0); + + layout->StartRow(0, five_column_layout_id); + layout->AddView(search_label_); + layout->AddView(search_field_); + layout->AddView(clear_search_button_); + layout->AddPaddingRow(0, kUnrelatedControlVerticalSpacing); + layout->StartRow(0, single_column_layout_id); + layout->AddView(description_label_); + layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); + layout->StartRow(1, single_column_layout_id); + layout->AddView(cookies_table_); + layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); + layout->StartRow(0, single_column_layout_id); + layout->AddView(info_view_); + + // Add the Remove/Remove All buttons to the ClientView + View* parent = GetParent(); + parent->AddChildView(remove_button_); + parent->AddChildView(remove_all_button_); + + if (cookies_table_->RowCount() > 0) { + cookies_table_->Select(0); + } else { + UpdateForEmptyState(); + } +} + +void CookiesView::ResetSearchQuery() { + search_field_->SetText(EmptyWString()); + UpdateSearchResults(); +} + +void CookiesView::UpdateForEmptyState() { + info_view_->ClearCookieDisplay(); + remove_button_->SetEnabled(false); + remove_all_button_->SetEnabled(false); +} |