diff options
author | michaeln@chromium.org <michaeln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-24 20:38:29 +0000 |
---|---|---|
committer | michaeln@chromium.org <michaeln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-24 20:38:29 +0000 |
commit | 3868baed7247f13ac96e2f14f09121d43b59aab2 (patch) | |
tree | 46f15ba8f29d762b99a20c83b7011e3bb965396d | |
parent | 2b8e7ca060b5c7cae81676c233039c33c5ce080f (diff) | |
download | chromium_src-3868baed7247f13ac96e2f14f09121d43b59aab2.zip chromium_src-3868baed7247f13ac96e2f14f09121d43b59aab2.tar.gz chromium_src-3868baed7247f13ac96e2f14f09121d43b59aab2.tar.bz2 |
Put up a prompt to create appcaches if the Content Settings indicate to do so. Done for windows and linux (sorry mac, you're out of luck). Also put in place a GenericInfoView class.
BUG=38362
TEST=manual and generic_info_view_unittest.cc
Review URL: http://codereview.chromium.org/1115005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@42525 0039d316-1c4b-4281-b951-d872f2087c98
19 files changed, 470 insertions, 168 deletions
diff --git a/chrome/browser/appcache/chrome_appcache_service.cc b/chrome/browser/appcache/chrome_appcache_service.cc index 2fb7772..6e94f25 100644 --- a/chrome/browser/appcache/chrome_appcache_service.cc +++ b/chrome/browser/appcache/chrome_appcache_service.cc @@ -6,7 +6,9 @@ #include "base/file_path.h" #include "base/file_util.h" -#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/cookie_prompt_modal_dialog_delegate.h" +#include "chrome/browser/message_box_handler.h" #include "chrome/browser/net/chrome_url_request_context.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/notification_service.h" @@ -15,6 +17,34 @@ static bool has_initialized_thread_ids; +// ChromeAppCacheService cannot just subclass the delegate interface +// because we may have several prompts pending. +class ChromeAppCacheService::PromptDelegate + : public CookiePromptModalDialogDelegate { + public: + PromptDelegate(ChromeAppCacheService* service, + const GURL& manifest_url, net::CompletionCallback* callback) + : service_(service), manifest_url_(manifest_url), callback_(callback) { + } + + virtual void AllowSiteData(bool session_expire) { + service_->DidPrompt(net::OK, manifest_url_, callback_); + delete this; + } + + virtual void BlockSiteData() { + service_->DidPrompt(net::ERR_ACCESS_DENIED, manifest_url_, callback_); + delete this; + } + + private: + scoped_refptr<ChromeAppCacheService> service_; + GURL manifest_url_; + net::CompletionCallback* callback_; +}; + +// ---------------------------------------------------------------------------- + ChromeAppCacheService::ChromeAppCacheService( const FilePath& profile_path, ChromeURLRequestContext* request_context) { @@ -48,6 +78,7 @@ void ChromeAppCacheService::ClearLocalState(const FilePath& profile_path) { } bool ChromeAppCacheService::CanLoadAppCache(const GURL& manifest_url) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); ContentSetting setting = host_contents_settings_map_->GetContentSetting( manifest_url, CONTENT_SETTINGS_TYPE_COOKIES); DCHECK(setting != CONTENT_SETTING_DEFAULT); @@ -57,23 +88,72 @@ bool ChromeAppCacheService::CanLoadAppCache(const GURL& manifest_url) { int ChromeAppCacheService::CanCreateAppCache( const GURL& manifest_url, net::CompletionCallback* callback) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); ContentSetting setting = host_contents_settings_map_->GetContentSetting( manifest_url, CONTENT_SETTINGS_TYPE_COOKIES); DCHECK(setting != CONTENT_SETTING_DEFAULT); if (setting == CONTENT_SETTING_ASK) { - // TODO(michaeln): prompt the user, for now we block - setting = CONTENT_SETTING_BLOCK; + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, &ChromeAppCacheService::DoPrompt, + manifest_url, callback)); + return net::ERR_IO_PENDING; } - return (setting != CONTENT_SETTING_BLOCK) ? net::OK : net::ERR_ACCESS_DENIED; + return (setting != CONTENT_SETTING_BLOCK) ? net::OK : + net::ERR_ACCESS_DENIED; +} + +void ChromeAppCacheService::DoPrompt( + const GURL& manifest_url, net::CompletionCallback* callback) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + + // The setting may have changed (due to the "remember" option) + ContentSetting setting = host_contents_settings_map_->GetContentSetting( + manifest_url, CONTENT_SETTINGS_TYPE_COOKIES); + if (setting != CONTENT_SETTING_ASK) { + int rv = (setting != CONTENT_SETTING_BLOCK) ? net::OK : + net::ERR_ACCESS_DENIED; + DidPrompt(rv, manifest_url, callback); + return; + } + + // Show the prompt on top of the current tab. + Browser* browser = BrowserList::GetLastActive(); + if (!browser || !browser->GetSelectedTabContents()) { + DidPrompt(net::ERR_ACCESS_DENIED, manifest_url, callback); + return; + } + + RunAppCachePrompt(browser->GetSelectedTabContents(), + host_contents_settings_map_, manifest_url, + new PromptDelegate(this, manifest_url, callback)); +} + +void ChromeAppCacheService::DidPrompt( + int rv, const GURL& manifest_url, net::CompletionCallback* callback) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod(this, &ChromeAppCacheService::CallCallback, + rv, callback)); +} + +void ChromeAppCacheService::CallCallback( + int rv, net::CompletionCallback* callback) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + callback->Run(rv); } void ChromeAppCacheService::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); DCHECK(type == NotificationType::PURGE_MEMORY); PurgeMemory(); } +// ---------------------------------------------------------------------------- + static ChromeThread::ID ToChromeThreadID(int id) { DCHECK(has_initialized_thread_ids); DCHECK(id == ChromeThread::DB || id == ChromeThread::IO); diff --git a/chrome/browser/appcache/chrome_appcache_service.h b/chrome/browser/appcache/chrome_appcache_service.h index 848a83f..888b672 100644 --- a/chrome/browser/appcache/chrome_appcache_service.h +++ b/chrome/browser/appcache/chrome_appcache_service.h @@ -6,6 +6,7 @@ #define CHROME_BROWSER_APPCACHE_CHROME_APPCACHE_SERVICE_H_ #include "base/ref_counted.h" +#include "chrome/browser/chrome_thread.h" #include "chrome/browser/host_content_settings_map.h" #include "chrome/common/notification_registrar.h" #include "webkit/appcache/appcache_policy.h" @@ -21,9 +22,10 @@ class FilePath; // owning profile. // // All methods, including the ctor and dtor, are expected to be called on -// the IO thread. +// the IO thread (unless specifically called out in doc comments). class ChromeAppCacheService - : public base::RefCounted<ChromeAppCacheService>, + : public base::RefCountedThreadSafe<ChromeAppCacheService, + ChromeThread::DeleteOnIOThread>, public appcache::AppCacheService, public appcache::AppCachePolicy, public NotificationObserver { @@ -34,7 +36,11 @@ class ChromeAppCacheService static void ClearLocalState(const FilePath& profile_path); private: - friend class base::RefCounted<ChromeAppCacheService>; + friend class ChromeThread; + friend class DeleteTask<ChromeAppCacheService>; + + class PromptDelegate; + virtual ~ChromeAppCacheService(); // AppCachePolicy overrides @@ -42,6 +48,13 @@ class ChromeAppCacheService virtual int CanCreateAppCache(const GURL& manifest_url, net::CompletionCallback* callback); + // The DoPrompt and DidPrrompt methods are called on the UI thread, and + // the following CallCallback method is called on the IO thread. + void DoPrompt(const GURL& manifest_url, net::CompletionCallback* callback); + void DidPrompt(int rv, const GURL& manifest_url, + net::CompletionCallback* callback); + void CallCallback(int rv, net::CompletionCallback* callback); + // NotificationObserver override virtual void Observe(NotificationType type, const NotificationSource& source, diff --git a/chrome/browser/cocoa/cookie_details.mm b/chrome/browser/cocoa/cookie_details.mm index 7552c7f..8f5a5d3 100644 --- a/chrome/browser/cocoa/cookie_details.mm +++ b/chrome/browser/cocoa/cookie_details.mm @@ -212,6 +212,12 @@ details = [[CocoaCookieDetails alloc] initWithDatabase:dialog->origin().host() name:dialog->database_name()]; + } else if (type == CookiePromptModalDialog::DIALOG_TYPE_APPCACHE) { + // TODO(michaeln): Show an appropiate details view, for now we + // overload the database details view. + details = [[CocoaCookieDetails alloc] + initWithDatabase:dialog->origin().host() + name:UTF8ToUTF16(dialog->appcache_manifest_url().spec())]; } else { NOTIMPLEMENTED(); } diff --git a/chrome/browser/cocoa/cookie_prompt_window_controller.mm b/chrome/browser/cocoa/cookie_prompt_window_controller.mm index 833423b..8881e93 100644 --- a/chrome/browser/cocoa/cookie_prompt_window_controller.mm +++ b/chrome/browser/cocoa/cookie_prompt_window_controller.mm @@ -79,9 +79,8 @@ descriptionStringId = IDS_COOKIE_ALERT_LABEL; break; case CookiePromptModalDialog::DIALOG_TYPE_LOCAL_STORAGE: - descriptionStringId = IDS_DATA_ALERT_LABEL; - break; case CookiePromptModalDialog::DIALOG_TYPE_DATABASE: + case CookiePromptModalDialog::DIALOG_TYPE_APPCACHE: descriptionStringId = IDS_DATA_ALERT_LABEL; break; default: diff --git a/chrome/browser/cookie_modal_dialog.cc b/chrome/browser/cookie_modal_dialog.cc index 99378dc..45347dc 100644 --- a/chrome/browser/cookie_modal_dialog.cc +++ b/chrome/browser/cookie_modal_dialog.cc @@ -59,6 +59,20 @@ CookiePromptModalDialog::CookiePromptModalDialog( delegate_(delegate) { } +// AppCache +CookiePromptModalDialog::CookiePromptModalDialog( + TabContents* tab_contents, + HostContentSettingsMap* host_content_settings_map, + const GURL& appcache_manifest_url, + CookiePromptModalDialogDelegate* delegate) + : AppModalDialog(tab_contents, std::wstring()), + host_content_settings_map_(host_content_settings_map), + dialog_type_(DIALOG_TYPE_APPCACHE), + origin_(appcache_manifest_url.GetOrigin()), + appcache_manifest_url_(appcache_manifest_url), + delegate_(delegate) { +} + CookiePromptModalDialog::~CookiePromptModalDialog() { } diff --git a/chrome/browser/cookie_modal_dialog.h b/chrome/browser/cookie_modal_dialog.h index 997dd7f..9a2ce77 100644 --- a/chrome/browser/cookie_modal_dialog.h +++ b/chrome/browser/cookie_modal_dialog.h @@ -31,8 +31,8 @@ class CookiePromptModalDialog : public AppModalDialog { enum DialogType { DIALOG_TYPE_COOKIE = 0, DIALOG_TYPE_LOCAL_STORAGE, - DIALOG_TYPE_DATABASE - // TODO(michaeln): AppCache + DIALOG_TYPE_DATABASE, + DIALOG_TYPE_APPCACHE }; // A union of data necessary to determine the type of message box to @@ -53,6 +53,10 @@ class CookiePromptModalDialog : public AppModalDialog { const GURL& origin, const string16& database_name, CookiePromptModalDialogDelegate* delegate); + CookiePromptModalDialog(TabContents* tab_contents, + HostContentSettingsMap* host_content_settings_map, + const GURL& appcache_manifest_url, + CookiePromptModalDialogDelegate* delegate); virtual ~CookiePromptModalDialog(); static void RegisterPrefs(PrefService* prefs); @@ -76,6 +80,7 @@ class CookiePromptModalDialog : public AppModalDialog { const string16& local_storage_key() const { return local_storage_key_; } const string16& local_storage_value() const { return local_storage_value_; } const string16& database_name() const { return database_name_; } + const GURL& appcache_manifest_url() const { return appcache_manifest_url_; } TabContents* tab_contents() const { return tab_contents_; } // Implement CookiePromptModalDialogDelegate. @@ -102,19 +107,16 @@ class CookiePromptModalDialog : public AppModalDialog { const DialogType dialog_type_; // The origin connected to this request. - GURL origin_; + const GURL origin_; - // Cookie to display. + // Which data members are relevant depends on the dialog_type. const std::string cookie_line_; - - // LocalStorage key/value. const string16 local_storage_key_; const string16 local_storage_value_; - - // Database name. const string16 database_name_; + const GURL appcache_manifest_url_; - // Delegate. The caller should provide one in order to receive results + // The caller should provide a delegate in order to receive results // from this delegate. Any time after calling one of these methods, the // delegate could be deleted CookiePromptModalDialogDelegate* delegate_; diff --git a/chrome/browser/cookie_modal_dialog_gtk.cc b/chrome/browser/cookie_modal_dialog_gtk.cc index 4ff08f6..700236a 100644 --- a/chrome/browser/cookie_modal_dialog_gtk.cc +++ b/chrome/browser/cookie_modal_dialog_gtk.cc @@ -119,6 +119,10 @@ NativeDialog CookiePromptModalDialog::CreateNativeDialog() { cookie_view, origin().host(), database_name()); + } else if (type == CookiePromptModalDialog::DIALOG_TYPE_APPCACHE) { + gtk_chrome_cookie_view_display_appcache_created( + cookie_view, + appcache_manifest_url()); } else { NOTIMPLEMENTED(); } diff --git a/chrome/browser/gtk/gtk_chrome_cookie_view.cc b/chrome/browser/gtk/gtk_chrome_cookie_view.cc index 1abb6d2..b4a823d 100644 --- a/chrome/browser/gtk/gtk_chrome_cookie_view.cc +++ b/chrome/browser/gtk/gtk_chrome_cookie_view.cc @@ -101,6 +101,10 @@ void InitStyles(GtkChromeCookieView *self) { dialog_style); InitBrowserDetailStyle(self->database_accessed_name_entry_, label_style, dialog_style); + + // AppCache created item. + InitBrowserDetailStyle(self->appcache_created_manifest_entry_, label_style, + dialog_style); } void SetCookieDetailsSensitivity(GtkChromeCookieView *self, @@ -150,6 +154,11 @@ void SetDatabaseAccessedSensitivity(GtkChromeCookieView* self, gtk_widget_set_sensitive(self->database_accessed_name_entry_, enabled); } +void SetAppCacheCreatedSensitivity(GtkChromeCookieView* self, + gboolean enabled) { + gtk_widget_set_sensitive(self->appcache_created_manifest_entry_, enabled); +} + void ClearCookieDetails(GtkChromeCookieView *self) { std::string no_cookie = l10n_util::GetStringUTF8(IDS_COOKIES_COOKIE_NONESELECTED); @@ -180,6 +189,9 @@ void UpdateVisibleDetailedInfo(GtkChromeCookieView *self, GtkWidget* table) { table == self->local_storage_item_table_); SetDatabaseAccessedSensitivity(self, table == self->database_accessed_table_); + SetAppCacheCreatedSensitivity(self, + table == self->appcache_created_table_); + // Display everything gtk_widget_show(self->table_box_); gtk_widget_show_all(table); @@ -196,6 +208,8 @@ void UpdateVisibleDetailedInfo(GtkChromeCookieView *self, GtkWidget* table) { gtk_widget_hide(self->local_storage_item_table_); if (table != self->database_accessed_table_) gtk_widget_hide(self->database_accessed_table_); + if (table != self->appcache_created_table_) + gtk_widget_hide(self->appcache_created_table_); } } // namespace @@ -305,7 +319,7 @@ static void gtk_chrome_cookie_view_init(GtkChromeCookieView *self) { self->local_storage_item_table_, &self->local_storage_item_value_entry_); - // Database accessed item. + // Database accessed prompt. self->database_accessed_table_ = gtk_table_new(2, 2, FALSE); gtk_container_add(GTK_CONTAINER(self->table_box_), self->database_accessed_table_); @@ -320,6 +334,17 @@ static void gtk_chrome_cookie_view_init(GtkChromeCookieView *self) { self->database_accessed_table_, &self->database_accessed_name_entry_); + // AppCache created prompt. + self->appcache_created_table_ = gtk_table_new(1, 2, FALSE); + gtk_container_add(GTK_CONTAINER(self->table_box_), + self->appcache_created_table_); + gtk_table_set_col_spacing(GTK_TABLE(self->appcache_created_table_), 0, + gtk_util::kLabelSpacing); + row = 0; + InitDetailRow(row++, IDS_COOKIES_APPLICATION_CACHE_MANIFEST_LABEL, + self->appcache_created_table_, + &self->appcache_created_manifest_entry_); + gtk_frame_set_shadow_type(GTK_FRAME(self), GTK_SHADOW_ETCHED_IN); gtk_container_add(GTK_CONTAINER(self), self->table_box_); } @@ -479,3 +504,12 @@ void gtk_chrome_cookie_view_display_database_accessed( UTF16ToUTF8(database_name).c_str()); SetDatabaseAccessedSensitivity(self, TRUE); } + +void gtk_chrome_cookie_view_display_appcache_created( + GtkChromeCookieView* self, + const GURL& manifest_url) { + UpdateVisibleDetailedInfo(self, self->appcache_created_table_); + gtk_entry_set_text(GTK_ENTRY(self->appcache_created_manifest_entry_), + manifest_url.spec().c_str()); + SetAppCacheCreatedSensitivity(self, TRUE); +} diff --git a/chrome/browser/gtk/gtk_chrome_cookie_view.h b/chrome/browser/gtk/gtk_chrome_cookie_view.h index ce157bf..73706f3 100644 --- a/chrome/browser/gtk/gtk_chrome_cookie_view.h +++ b/chrome/browser/gtk/gtk_chrome_cookie_view.h @@ -95,6 +95,10 @@ typedef struct { GtkWidget* database_accessed_table_; GtkWidget* database_accessed_origin_entry_; GtkWidget* database_accessed_name_entry_; + + // The appcache created widgets. + GtkWidget* appcache_created_table_; + GtkWidget* appcache_created_manifest_entry_; } GtkChromeCookieView; typedef struct { @@ -155,4 +159,8 @@ void gtk_chrome_cookie_view_display_database_accessed( const std::string& host, const string16& database_name); +void gtk_chrome_cookie_view_display_appcache_created( + GtkChromeCookieView* self, + const GURL& manifest_url); + #endif // CHROME_BROWSER_GTK_GTK_CHROME_COOKIE_VIEW_H_ diff --git a/chrome/browser/message_box_handler.cc b/chrome/browser/message_box_handler.cc index 0f5b63c..e004a0e 100644 --- a/chrome/browser/message_box_handler.cc +++ b/chrome/browser/message_box_handler.cc @@ -75,3 +75,13 @@ void RunDatabasePrompt( new CookiePromptModalDialog(tab_contents, host_content_settings_map, origin, database_name, delegate)); } + +void RunAppCachePrompt( + TabContents* tab_contents, + HostContentSettingsMap* host_content_settings_map, + const GURL& manifest_url, + CookiePromptModalDialogDelegate* delegate) { + Singleton<AppModalDialogQueue>()->AddDialog( + new CookiePromptModalDialog(tab_contents, host_content_settings_map, + manifest_url, delegate)); +} diff --git a/chrome/browser/message_box_handler.h b/chrome/browser/message_box_handler.h index cf08804..be821f7 100644 --- a/chrome/browser/message_box_handler.h +++ b/chrome/browser/message_box_handler.h @@ -71,5 +71,14 @@ void RunDatabasePrompt( const string16& database_name, CookiePromptModalDialogDelegate* delegate); +// This will display a modal dialog box with the |manifest_url| and ask the +// user to accept or reject it. The caller should pass |delegate| that will +// handle the reply from the dialog. +void RunAppCachePrompt( + TabContents* tab_contents, + HostContentSettingsMap* host_content_settings_map, + const GURL& manifest_url, + CookiePromptModalDialogDelegate* delegate); + #endif // CHROME_BROWSER_MESSAGE_BOX_HANDLER_H_ diff --git a/chrome/browser/views/appcache_info_view.cc b/chrome/browser/views/appcache_info_view.cc index ade35f8..55973ec 100644 --- a/chrome/browser/views/appcache_info_view.cc +++ b/chrome/browser/views/appcache_info_view.cc @@ -4,132 +4,37 @@ #include "chrome/browser/views/appcache_info_view.h" -#include <algorithm> - #include "app/l10n_util.h" #include "base/i18n/time_formatting.h" #include "base/utf_string_conversions.h" -#include "gfx/color_utils.h" #include "grit/generated_resources.h" -#include "views/grid_layout.h" -#include "views/controls/label.h" -#include "views/controls/textfield/textfield.h" -#include "views/standard_layout.h" -/////////////////////////////////////////////////////////////////////////////// -// AppCacheInfoView, public: +namespace { +const int kInfoLabelIds[] = { + IDS_COOKIES_APPLICATION_CACHE_MANIFEST_LABEL, + IDS_COOKIES_SIZE_LABEL, + IDS_COOKIES_COOKIE_CREATED_LABEL, + IDS_COOKIES_LAST_ACCESSED_LABEL +}; +} // namespace AppCacheInfoView::AppCacheInfoView() - : manifest_url_field_(NULL), - size_field_(NULL), - creation_date_field_(NULL), - last_access_field_(NULL) { -} - -AppCacheInfoView::~AppCacheInfoView() { + : GenericInfoView(ARRAYSIZE(kInfoLabelIds), kInfoLabelIds) { } void AppCacheInfoView::SetAppCacheInfo(const appcache::AppCacheInfo* info) { DCHECK(info); - manifest_url_field_->SetText(UTF8ToWide(info->manifest_url.spec())); - size_field_->SetText( - FormatBytes(info->size, GetByteDisplayUnits(info->size), true)); - creation_date_field_->SetText( - base::TimeFormatFriendlyDateAndTime(info->creation_time)); - last_access_field_->SetText( - base::TimeFormatFriendlyDateAndTime(info->last_access_time)); - EnableAppCacheDisplay(true); -} - -void AppCacheInfoView::EnableAppCacheDisplay(bool enabled) { - manifest_url_field_->SetEnabled(enabled); - size_field_->SetEnabled(enabled); - creation_date_field_->SetEnabled(enabled); - last_access_field_->SetEnabled(enabled); -} - -void AppCacheInfoView::ClearAppCacheDisplay() { - const string16 kEmpty; - manifest_url_field_->SetText(kEmpty); - size_field_->SetText(kEmpty); - creation_date_field_->SetText(kEmpty); - last_access_field_->SetText(kEmpty); - EnableAppCacheDisplay(false); -} - -/////////////////////////////////////////////////////////////////////////////// -// AppCacheInfoView, views::View overrides: - -void AppCacheInfoView::ViewHierarchyChanged(bool is_add, - views::View* parent, - views::View* child) { - if (is_add && child == this) - Init(); -} - -/////////////////////////////////////////////////////////////////////////////// -// AppCacheInfoView, private: - - -void AppCacheInfoView::Init() { - const int kInfoViewBorderSize = 1; - const int kInfoViewInsetSize = 3; - const int kLayoutId = 0; - - SkColor border_color = color_utils::GetSysSkColor(COLOR_3DSHADOW); - views::Border* border = views::Border::CreateSolidBorder( - kInfoViewBorderSize, border_color); - set_border(border); - - views::Label* manifest_url_label = new views::Label( - l10n_util::GetString(IDS_COOKIES_APPLICATION_CACHE_MANIFEST_LABEL)); - manifest_url_field_ = new views::Textfield; - views::Label* size_label = new views::Label( - l10n_util::GetString(IDS_COOKIES_SIZE_LABEL)); - size_field_ = new views::Textfield; - views::Label* creation_date_label = new views::Label( - l10n_util::GetString(IDS_COOKIES_COOKIE_CREATED_LABEL)); - creation_date_field_ = new views::Textfield; - views::Label* last_access_label = new views::Label( - l10n_util::GetString(IDS_COOKIES_LAST_ACCESSED_LABEL)); - last_access_field_ = new views::Textfield; - - using views::GridLayout; - - GridLayout* layout = new GridLayout(this); - layout->SetInsets(kInfoViewInsetSize, kInfoViewInsetSize, - kInfoViewInsetSize, kInfoViewInsetSize); - SetLayoutManager(layout); - - views::ColumnSet* column_set = layout->AddColumnSet(kLayoutId); - 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); - - AddRow(kLayoutId, layout, manifest_url_label, manifest_url_field_, true); - AddRow(kLayoutId, layout, size_label, size_field_, true); - AddRow(kLayoutId, layout, creation_date_label, creation_date_field_, true); - AddRow(kLayoutId, layout, last_access_label, last_access_field_, false); -} - -void AppCacheInfoView::AddRow( - int layout_id, views::GridLayout* layout, views::Label* label, - views::Textfield* field, bool add_padding_row) { - // Add to the view hierarchy. - layout->StartRow(0, layout_id); - layout->AddView(label); - layout->AddView(field); - - // Color these borderless text areas the same as the containing dialog. - SkColor text_area_background = color_utils::GetSysSkColor(COLOR_3DFACE); - - // Init them now that they're in the view heirarchy. - field->SetReadOnly(true); - field->RemoveBorder(); - field->SetBackgroundColor(text_area_background); - - if (add_padding_row) - layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing); + string16 manifest_url = + UTF8ToUTF16(info->manifest_url.spec()); + string16 size = + FormatBytes(info->size, GetByteDisplayUnits(info->size), true); + string16 creation_date = + base::TimeFormatFriendlyDateAndTime(info->creation_time); + string16 last_access_date = + base::TimeFormatFriendlyDateAndTime(info->last_access_time); + int row = 0; + SetValue(row++, manifest_url); + SetValue(row++, size); + SetValue(row++, creation_date); + SetValue(row++, last_access_date); } diff --git a/chrome/browser/views/appcache_info_view.h b/chrome/browser/views/appcache_info_view.h index 25db5dd..f78162f 100644 --- a/chrome/browser/views/appcache_info_view.h +++ b/chrome/browser/views/appcache_info_view.h @@ -5,46 +5,17 @@ #ifndef CHROME_BROWSER_VIEWS_APPCACHE_INFO_VIEW_H_ #define CHROME_BROWSER_VIEWS_APPCACHE_INFO_VIEW_H_ -#include <string> -#include <vector> - -#include "views/view.h" +#include "chrome/browser/views/generic_info_view.h" #include "chrome/browser/browsing_data_appcache_helper.h" -namespace views { -class GridLayout; -class Label; -class Textfield; -} - -/////////////////////////////////////////////////////////////////////////////// // AppCacheInfoView -// -// Responsible for displaying a tabular grid of AppCache information. -class AppCacheInfoView : public views::View { +// Displays a tabular grid of AppCache information. +class AppCacheInfoView : public GenericInfoView { public: AppCacheInfoView(); - virtual ~AppCacheInfoView(); - void SetAppCacheInfo(const appcache::AppCacheInfo* info); - void ClearAppCacheDisplay(); - void EnableAppCacheDisplay(bool enabled); - - protected: - // views::View overrides: - virtual void ViewHierarchyChanged( - bool is_add, views::View* parent, views::View* child); private: - void Init(); - void AddRow(int layout_id, views::GridLayout* layout, views::Label* label, - views::Textfield* field, bool add_padding_row); - - views::Textfield* manifest_url_field_; - views::Textfield* size_field_; - views::Textfield* creation_date_field_; - views::Textfield* last_access_field_; - DISALLOW_COPY_AND_ASSIGN(AppCacheInfoView); }; diff --git a/chrome/browser/views/cookie_prompt_view.cc b/chrome/browser/views/cookie_prompt_view.cc index 16e2b94..dacc169 100644 --- a/chrome/browser/views/cookie_prompt_view.cc +++ b/chrome/browser/views/cookie_prompt_view.cc @@ -17,6 +17,7 @@ #include "chrome/browser/views/browser_dialogs.h" #include "chrome/browser/views/cookie_info_view.h" #include "chrome/browser/views/database_open_info_view.h" +#include "chrome/browser/views/generic_info_view.h" #include "chrome/browser/views/local_storage_set_item_info_view.h" #include "chrome/browser/views/options/content_settings_window_view.h" #include "chrome/common/pref_names.h" @@ -251,6 +252,15 @@ void CookiePromptView::Init() { view->SetFields(parent_->origin().host(), parent_->database_name()); info_view_ = view; + } else if (type == CookiePromptModalDialog::DIALOG_TYPE_APPCACHE) { + static const int kAppCacheInfoLabels[] = { + IDS_COOKIES_APPLICATION_CACHE_MANIFEST_LABEL + }; + GenericInfoView* view = new GenericInfoView(ARRAYSIZE(kAppCacheInfoLabels), + kAppCacheInfoLabels); + layout->AddView(view, 1, 1, GridLayout::FILL, GridLayout::CENTER); + view->SetValue(0, UTF8ToUTF16(parent_->appcache_manifest_url().spec())); + info_view_ = view; } else { NOTIMPLEMENTED(); } diff --git a/chrome/browser/views/generic_info_view.cc b/chrome/browser/views/generic_info_view.cc new file mode 100644 index 0000000..edd8492 --- /dev/null +++ b/chrome/browser/views/generic_info_view.cc @@ -0,0 +1,105 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/views/generic_info_view.h" + +#include "app/l10n_util.h" +#include "gfx/color_utils.h" +#include "base/logging.h" +#include "views/grid_layout.h" +#include "views/controls/label.h" +#include "views/controls/textfield/textfield.h" +#include "views/standard_layout.h" + +GenericInfoView::GenericInfoView(int number_of_rows) + : number_of_rows_(number_of_rows), name_string_ids_(NULL) { + DCHECK(number_of_rows_ > 0); +} + +GenericInfoView::GenericInfoView( + int number_of_rows, const int name_string_ids[]) + : number_of_rows_(number_of_rows), name_string_ids_(name_string_ids) { + DCHECK(number_of_rows_ > 0); +} + +void GenericInfoView::SetNameByStringId(int row, int name_string_id) { + SetName(row, l10n_util::GetString(name_string_id)); +} + +void GenericInfoView::SetName(int row, const string16& name) { + DCHECK(name_views_.get()); // Can only be called after Init time. + DCHECK(row >= 0 && row < number_of_rows_); + name_views_[row]->SetText(name); +} + +void GenericInfoView::SetValue(int row, const string16& name) { + DCHECK(value_views_.get()); // Can only be called after Init time. + DCHECK(row >= 0 && row < number_of_rows_); + value_views_[row]->SetText(name); +} + +void GenericInfoView::ViewHierarchyChanged(bool is_add, + views::View* parent, + views::View* child) { + if (is_add && child == this) { + InitGenericInfoView(); + if (name_string_ids_) { + for (int i = 0; i < number_of_rows_; ++i) + SetNameByStringId(i, name_string_ids_[i]); + } + } +} + +void GenericInfoView::InitGenericInfoView() { + const int kInfoViewBorderSize = 1; + const int kInfoViewInsetSize = 3; + const int kLayoutId = 0; + + SkColor border_color = color_utils::GetSysSkColor(COLOR_3DSHADOW); + views::Border* border = views::Border::CreateSolidBorder( + kInfoViewBorderSize, border_color); + set_border(border); + + using views::GridLayout; + + GridLayout* layout = new GridLayout(this); + layout->SetInsets(kInfoViewInsetSize, kInfoViewInsetSize, + kInfoViewInsetSize, kInfoViewInsetSize); + SetLayoutManager(layout); + + views::ColumnSet* column_set = layout->AddColumnSet(kLayoutId); + 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); + + name_views_.reset(new views::Label* [number_of_rows_]); + value_views_.reset(new views::Textfield* [number_of_rows_]); + + for (int i = 0; i < number_of_rows_; ++i) { + if (i) + layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing); + name_views_[i] = new views::Label; + value_views_[i] = new views::Textfield; + AddRow(kLayoutId, layout, name_views_[i], value_views_[i]); + } +} + +void GenericInfoView::AddRow( + int layout_id, views::GridLayout* layout, views::Label* name, + views::Textfield* value) { + // Add to the view hierarchy. + layout->StartRow(0, layout_id); + layout->AddView(name); + layout->AddView(value); + + // Color these borderless text areas the same as the containing dialog. + SkColor text_area_background = color_utils::GetSysSkColor(COLOR_3DFACE); + + // Init them now that they're in the view heirarchy. + value->SetReadOnly(true); + value->RemoveBorder(); + value->SetBackgroundColor(text_area_background); +} diff --git a/chrome/browser/views/generic_info_view.h b/chrome/browser/views/generic_info_view.h new file mode 100644 index 0000000..ff03b14 --- /dev/null +++ b/chrome/browser/views/generic_info_view.h @@ -0,0 +1,66 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_VIEWS_GENERIC_INFO_VIEW_H_ +#define CHROME_BROWSER_VIEWS_GENERIC_INFO_VIEW_H_ + +#include "base/scoped_ptr.h" +#include "base/string16.h" +#include "testing/gtest/include/gtest/gtest_prod.h" +#include "views/view.h" + +namespace views { +class GridLayout; +class Label; +class Textfield; +} + +// GenericInfoView, displays a tabular grid of read-only textual information, +// <name, value> pairs. The fixed number of rows must be known at the time of +// construction. +class GenericInfoView : public views::View { + public: + // Constructs a info view with |number_of_rows| and populated with + // empty strings. + explicit GenericInfoView(int number_of_rows); + + // Constructs a info view with |number_of_rows|, and populates + // the name column with localized strings having the given + // |name_string_ids|. The array of ids should contain |number_of_rows| + // values and should remain valid for the life of the view. + GenericInfoView(int number_of_rows, const int name_string_ids[]); + + // The following methods should only be called after + // the view has been added to a view hierarchy. + void SetNameByStringId(int row, int id); + void SetName(int row, const string16& name); + void SetValue(int row, const string16& value); + void ClearValues() { + const string16 kEmptyString; + for (int i = 0; i < number_of_rows_; ++i) + SetValue(i, kEmptyString); + } + + protected: + // views::View override + virtual void ViewHierarchyChanged( + bool is_add, views::View* parent, views::View* child); + + private: + FRIEND_TEST(GenericInfoViewTest, GenericInfoView); + + void InitGenericInfoView(); + void AddRow(int layout_id, views::GridLayout* layout, + views::Label* name, views::Textfield* value); + + const int number_of_rows_; + const int* name_string_ids_; + scoped_array<views::Label*> name_views_; + scoped_array<views::Textfield*> value_views_; + + DISALLOW_COPY_AND_ASSIGN(GenericInfoView); +}; + +#endif // CHROME_BROWSER_VIEWS_GENERIC_INFO_VIEW_H_ + diff --git a/chrome/browser/views/generic_info_view_unittest.cc b/chrome/browser/views/generic_info_view_unittest.cc new file mode 100644 index 0000000..ca0a030 --- /dev/null +++ b/chrome/browser/views/generic_info_view_unittest.cc @@ -0,0 +1,62 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "app/l10n_util.h" +#include "chrome/browser/views/generic_info_view.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "views/controls/label.h" +#include "views/controls/textfield/textfield.h" +#include "views/widget/root_view.h" +#if defined(OS_WIN) +#include "views/widget/widget_win.h" +#endif +#include "views/window/window.h" + +// This class is only used on windows for now. +#if defined(OS_WIN) + +using namespace views; + +class GenericInfoViewTest : public testing::Test { + public: + Widget* CreateWidget() { + return new WidgetWin(); + } + private: + MessageLoopForUI message_loop_; +}; + +TEST_F(GenericInfoViewTest, GenericInfoView) { + const string16 kName = ASCIIToUTF16("Name"); + const string16 kValue = ASCIIToUTF16("Value"); + + Widget* window = CreateWidget(); + static_cast<WidgetWin*>(window)->Init(NULL, gfx::Rect(0, 0, 100, 100)); + RootView* root_view = window->GetRootView(); + + GenericInfoView* view1 = new GenericInfoView(1); + root_view->AddChildView(view1); + view1->SetName(0, kName); + view1->SetValue(0, kValue); + EXPECT_EQ(kName, view1->name_views_[0]->GetText()); + EXPECT_EQ(kValue, view1->value_views_[0]->text()); + view1->ClearValues(); + EXPECT_TRUE(view1->value_views_[0]->text().empty()); + + // Test setting values by localized string id. + static int kNameIds[] = { + IDS_PRODUCT_NAME, + IDS_PRODUCT_DESCRIPTION + }; + GenericInfoView* view2 = new GenericInfoView(ARRAYSIZE(kNameIds), kNameIds); + root_view->AddChildView(view2); + + string16 product_name = l10n_util::GetString(IDS_PRODUCT_NAME); + string16 product_desc = l10n_util::GetString(IDS_PRODUCT_DESCRIPTION); + EXPECT_EQ(product_name, view2->name_views_[0]->GetText()); + EXPECT_EQ(product_desc, view2->name_views_[1]->GetText()); +} +#endif // OS_WIN diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index a0596e6..8c13b7f 100755 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2188,6 +2188,8 @@ 'browser/views/frame/opaque_browser_frame_view.h', 'browser/views/fullscreen_exit_bubble.cc', 'browser/views/fullscreen_exit_bubble.h', + 'browser/views/generic_info_view.cc', + 'browser/views/generic_info_view.h', 'browser/views/go_button.cc', 'browser/views/go_button.h', 'browser/views/html_dialog_view.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index b641527..afa4f7a 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -908,6 +908,7 @@ 'browser/views/bookmark_context_menu_test.cc', 'browser/views/bookmark_editor_view_unittest.cc', 'browser/views/extensions/browser_action_drag_data_unittest.cc', + 'browser/views/generic_info_view_unittest.cc', 'browser/visitedlink_unittest.cc', 'browser/webdata/web_data_service_unittest.cc', 'browser/webdata/web_database_unittest.cc', @@ -1145,6 +1146,7 @@ 'browser/views/bookmark_editor_view_unittest.cc', 'browser/views/extensions/browser_action_drag_data_unittest.cc', 'browser/views/find_bar_host_unittest.cc', + 'browser/views/generic_info_view_unittest.cc', 'browser/views/keyword_editor_view_unittest.cc', 'common/net/url_util_unittest.cc', ], |