diff options
author | rkc@google.com <rkc@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-19 17:42:20 +0000 |
---|---|---|
committer | rkc@google.com <rkc@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-19 17:42:20 +0000 |
commit | 74a9f9f48c5832f548368eb8b43933f6b2a10e60 (patch) | |
tree | 5067464449bbb6725d8daaec1dc9399eb0866ab2 /chrome | |
parent | 4685af7696690319a792030aafb329169cb93fa2 (diff) | |
download | chromium_src-74a9f9f48c5832f548368eb8b43933f6b2a10e60.zip chromium_src-74a9f9f48c5832f548368eb8b43933f6b2a10e60.tar.gz chromium_src-74a9f9f48c5832f548368eb8b43933f6b2a10e60.tar.bz2 |
Checkin for CL: http://codereview.chromium.org/3061044/show
TEST=Backend: Various reports submitted from Chrome OS and Windows builds
sent to the feedback test server. For Chromium OS, sent reports
with current screenshot and saved screenshots; verified all reports
for data accuracy and completion.
Frontend: Tested the UI features by excersizing various options; tested
not selecting any issue, tested switching between screenshot types.
Review URL: http://codereview.chromium.org/3181027
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@56708 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
30 files changed, 1734 insertions, 909 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index a321950..3ea6fdb 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -4224,27 +4224,59 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_BUGREPORT_TITLE" desc="Dialog title for bug report dialog"> Report Bug or Broken Web Site </message> - <message name="IDS_BUGREPORT_REPORT_PAGE_TITLE" desc="Label showing title of the page that will be reported"> + <message name="IDS_BUGREPORT_REPORT_PAGE_TITLE" desc="Label showing the title of the page that will be reported"> Page title: </message> - <message name="IDS_BUGREPORT_REPORT_URL_LABEL" desc="Label showing URL that will be reported"> + <message name="IDS_BUGREPORT_REPORT_URL_LABEL" desc="Label showing the URL that will be reported"> Page URL: </message> - <message name="IDS_BUGREPORT_USER_EMAIL_LABEL" desc="Label showing URL that will be reported"> + <message name="IDS_BUGREPORT_USER_EMAIL_LABEL" desc="Label showing the e-mail address that will be reported"> User e-mail: </message> - <message name="IDS_BUGREPORT_DESCRIPTION_LABEL" desc="Label for description field"> + <message name="IDS_BUGREPORT_DESCRIPTION_LABEL" desc="Label for the description field"> Description: </message> + <message name="IDS_BUGREPORT_SCREENSHOT_LABEL" desc="Label for the screenshot field"> + Screenshot: + </message> + <!-- For Mac compatibility --> + <message name="IDS_BUGREPORT_SOMETHING_MISSING" desc="In Title Case: Report a bug/problem type: Something's missing"> + Something's Missing + </message> + <message name="IDS_BUGREPORT_BROWSER_CRASH" desc="Report a bug/problem type: Browser crashed"> + Browser crash... go boom + </message> + <message name="IDS_BUGREPORT_OTHER_PROBLEM" desc="Report a bug/problem type: General feedback/other"> + General feedback/other + </message> + <message name="IDS_BUGREPORT_PAGE_LOOKS_ODD" desc="Report a bug/problem type: Page looks odd"> + Page looks odd + </message> + <message name="IDS_BUGREPORT_PAGE_WONT_LOAD" desc="Report a bug/problem type: Page won't load"> + Page won't load + </message> + <message name="IDS_BUGREPORT_CANT_SIGN_IN" desc="Report a bug/problem type: Can't sign in"> + Can't sign in + </message> + <!-- /Mac Compat --> <if expr="pp_ifdef('chromeos')"> - <message name="IDS_BUGREPORT_INCLUDE_NEW_SCREEN_IMAGE" desc="Radio button for including a new screen image on the bug report dialog box"> - Send last active tab screen shot + <message name="IDS_BUGREPORT_NOTIFICATION_TITLE" desc="Title for the notification given to the user on completion (successful or failed) of user feedback"> + Feedback submission status + </message> + <message name="IDS_BUGREPORT_FEEDBACK_STATUS_SUCCESS" desc="Message for the status of a feedback submission on success"> + User Feedback submission succeeded + </message> + <message name="IDS_BUGREPORT_FEEDBACK_STATUS_FAIL" desc="Message for the status of a feedback submission failure"> + User feedback submission failed: $1 </message> <message name="IDS_BUGREPORT_INCLUDE_LAST_SCREEN_IMAGE" desc="Radio button for including the last screen image on the bug report dialog box"> Send last saved screen shot </message> - <message name="IDS_BUGREPORT_INCLUDE_NO_SCREEN_IMAGE" desc="Radio button for not including a screen image on the bug report dialog box"> - Do not send a screen shot + <message name="IDS_BUGREPORT_CURRENT_SCREENSHOTS" desc="Radio button for including the last screen image on the bug report dialog box"> + Send a current page screen shot + </message> + <message name="IDS_BUGREPORT_SAVED_SCREENSHOTS" desc="Radio button for including the last screen image on the bug report dialog box"> + Send a saved screen shot </message> <message name="IDS_BUGREPORT_INCLUDE_SYSTEM_INFORMATION_CHKBOX" desc="Checkbox for including system information on the bug report dialog box"> Send system information @@ -4259,85 +4291,110 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_BUGREPORT_INCLUDE_PAGE_IMAGE_CHKBOX" desc="Checkbox for including page image"> Send screen shot of current page </message> + <message name="IDS_BUGREPORT_INCLUDE_NEW_SCREEN_IMAGE" desc="Radio button for including a new screen image on the bug report dialog box"> + Send last active tab screen shot + </message> + <message name="IDS_BUGREPORT_INCLUDE_NO_SCREENSHOT" desc="Radio button for not including a screen image on the bug report dialog box"> + Do not send a screen shot + </message> <message name="IDS_BUGREPORT_BUG_TYPE" desc="Label for bug type"> Bug type: </message> - <if expr="pp_ifdef('chromeos')"> - <message name="IDS_BUGREPORT_CONNECTIVITY_ISSUE" desc="Report a bug/problem type: Connectivity"> - Connectivity + <message name="IDS_BUGREPORT_PHISHING_PAGE" desc="Report a bug/problem type: Phishing page"> + Phishing page + </message> + <message name="IDS_BUGREPORT_NO_ISSUE_SELECTED" desc="Message shown when no issue is selected before hitting submit"> + Please select an issue type from the drop down before sending the report + </message> + <message name="IDS_BUGREPORT_ISSUE_WITH" desc="Label for issue with"> + I see an issue with: + </message> + <if expr="not pp_ifdef('use_titlecase')"> + <message name="IDS_BUGREPORT_SEND_REPORT" desc="Text for OK button on dialog"> + Send report </message> - <message name="IDS_BUGREPORT_SYNC_ISSUE" desc="Report a bug/problem type: Sync"> - Sync + <message name="IDS_BUGREPORT_SEND_PHISHING_REPORT" desc="Text for report phishing button"> + Open phishing report </message> - <message name="IDS_BUGREPORT_PAGE_FORMATTING" desc="Report a bug/problem type: Page formatting or layout"> - Page formatting + <message name="IDS_BUGREPORT_CHOOSE_ISSUE" desc="In Title Case: Report a bug/problem type: Choose issue with"> + (choose an issue below) </message> - <message name="IDS_BUGREPORT_EXTENSION_ISSUE" desc="Report a bug/problem type: Extensions or apps"> - Extensions or apps + <message name="IDS_BUGREPORT_PAGE_FORMATTING" desc="In Title Case: Report a bug/problem type: Page formatting or layout"> + Page formatting or layout </message> - <message name="IDS_BUGREPORT_SUSPEND_ISSUE" desc="Report a bug/problem type: Suspend or resume"> - Suspend or resume + <message name="IDS_BUGREPORT_PAGE_LOAD" desc="In Title Case: Report a bug/problem type: Pages not loading"> + Pages not loading </message> - <message name="IDS_BUGREPORT_CRASH_ISSUE" desc="Report a bug/problem type: Crash"> - Crash + <message name="IDS_BUGREPORT_PLUGINS" desc="In Title Case: Report a bug/problem type: Plug-ins"> + Plug-ins (e.g. Adobe Flash Player, Quicktime, etc) </message> - </if> - <if expr="not pp_ifdef('use_titlecase')"> - <message name="IDS_BUGREPORT_SEND_REPORT" desc="Text for OK button on dialog"> - Send report + <message name="IDS_BUGREPORT_TABS" desc="In Title Case: Report a bug/problem type: Tabs or windows"> + Tabs or windows </message> - <message name="IDS_BUGREPORT_SEND_PHISHING_REPORT" desc="Text for report phishing button"> - Open phishing report + <message name="IDS_BUGREPORT_NETWORK" desc="In Title Case: Report a bug/problem type: Network connection"> + Network connection </message> - <message name="IDS_BUGREPORT_PAGE_WONT_LOAD" desc="Report a bug/problem type: Page won't load"> - Page won't load + <message name="IDS_BUGREPORT_CONNECTIVITY" desc="In Title Case: Report a bug/problem type: Connectivity issues"> + Network connection </message> - <message name="IDS_BUGREPORT_PAGE_LOOKS_ODD" desc="Report a bug/problem type: Page looks odd"> - Page looks odd + <message name="IDS_BUGREPORT_STANDBY_RESUME" desc="In Title Case: Report a bug/problem type: Standby or Resume"> + Network connection </message> - <message name="IDS_BUGREPORT_PHISHING_PAGE" desc="Report a bug/problem type: Phishing page"> - Phishing page + <message name="IDS_BUGREPORT_SYNC" desc="In Title Case: Report a bug/problem type: Synced preferences"> + Synced preferences </message> - <message name="IDS_BUGREPORT_CANT_SIGN_IN" desc="Report a bug/problem type: Can't sign in"> - Can't sign in + <message name="IDS_BUGREPORT_CRASHES" desc="In Title Case: Report a bug/problem type: Crashes"> + Crashes </message> - <message name="IDS_BUGREPORT_SOMETHING_MISSING" desc="Report a bug/problem type: Something's missing"> - Something's missing + <message name="IDS_BUGREPORT_EXTENSIONS" desc="In Title Case: Report a bug/problem type: Extensions or apps"> + Extensions or apps </message> - <message name="IDS_BUGREPORT_BROWSER_CRASH" desc="Report a bug/problem type: Browser crashed"> - Browser crash... go boom + <message name="IDS_BUGREPORT_OTHER" desc="In Title Case: Report a bug/problem type: Other"> + Other </message> - <message name="IDS_BUGREPORT_OTHER_PROBLEM" desc="Report a bug/problem type: General feedback/other"> + <message name="IDS_BUGREPORT_GENERAL" desc="Report a bug/problem type: General feedback/other"> General feedback/other </message> + <message name="IDS_BUGREPORT_PREVIEW_REPORT" desc="Text for the preview report button on dialog"> + Preview report + </message> </if> <if expr="pp_ifdef('use_titlecase')"> - <message name="IDS_BUGREPORT_SEND_REPORT" desc="In Title Case: Text for OK button on dialog"> - Send Report + <message name="IDS_BUGREPORT_SEND_REPORT" desc="Text for the send report button on dialog"> + Send report </message> - <message name="IDS_BUGREPORT_SEND_PHISHING_REPORT" desc="In Title Case: Text for report phishing button"> - Open Phishing Report + <message name="IDS_BUGREPORT_SEND_PHISHING_REPORT" desc="Text for report phishing button"> + Open phishing report </message> - <message name="IDS_BUGREPORT_PAGE_WONT_LOAD" desc="In Title Case: Report a bug/problem type: Page won't load"> - Page Won't Load + <message name="IDS_BUGREPORT_CHOOSE_ISSUE" desc="In Title Case: Report a bug/problem type: Choose issue with"> + (choose an issue below) </message> - <message name="IDS_BUGREPORT_PAGE_LOOKS_ODD" desc="In Title Case: Report a bug/problem type: Page looks odd"> - Page Looks Odd + <message name="IDS_BUGREPORT_PAGE_FORMATTING" desc="In Title Case: Report a bug/problem type: Page formatting or layout"> + Page formatting or layout </message> - <message name="IDS_BUGREPORT_PHISHING_PAGE" desc="In Title Case: Report a bug/problem type: Phishing page"> - Phishing Page + <message name="IDS_BUGREPORT_PAGE_LOAD" desc="In Title Case: Report a bug/problem type: Pages not loading"> + Pages not loading </message> - <message name="IDS_BUGREPORT_CANT_SIGN_IN" desc="In Title Case: Report a bug/problem type: Can't sign in"> - Can't Sign In + <message name="IDS_BUGREPORT_PLUGINS" desc="In Title Case: Report a bug/problem type: Plug-ins"> + Plug-ins (e.g. Adobe Flash Player, Quicktime, etc) </message> - <message name="IDS_BUGREPORT_SOMETHING_MISSING" desc="In Title Case: Report a bug/problem type: Something's missing"> - Something's Missing + <message name="IDS_BUGREPORT_TABS" desc="In Title Case: Report a bug/problem type: Tabs or windows"> + Tabs or windows </message> - <message name="IDS_BUGREPORT_BROWSER_CRASH" desc="In Title Case: Report a bug/problem type: Browser crashed"> - Browser Crash... Go Boom + <message name="IDS_BUGREPORT_NETWORK" desc="In Title Case: Report a bug/problem type: Network connection"> + Network connection </message> - <message name="IDS_BUGREPORT_OTHER_PROBLEM" desc="In Title Case: Report a bug/problem type: General feedback/other"> - General feedback/other + <message name="IDS_BUGREPORT_SYNC" desc="In Title Case: Report a bug/problem type: Synced preferences"> + Synced preferences + </message> + <message name="IDS_BUGREPORT_CRASHES" desc="In Title Case: Report a bug/problem type: Crashes"> + Crashes + </message> + <message name="IDS_BUGREPORT_EXTENSIONS" desc="In Title Case: Report a bug/problem type: Extensions or apps"> + Extensions or apps + </message> + <message name="IDS_BUGREPORT_OTHER" desc="In Title Case: Report a bug/problem type: Other"> + Other </message> </if> diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index ac91d86..6cad802 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -1728,15 +1728,8 @@ void Browser::OpenTaskManager() { } void Browser::OpenBugReportDialog() { -#if defined(OS_CHROMEOS) UserMetrics::RecordAction(UserMetricsAction("ReportBug"), profile_); window_->ShowReportBugDialog(); -#else - TabContents* contents = GetSelectedTabContents(); - if (!contents) - return; - ShowBrokenPageTab(contents); -#endif } void Browser::ToggleBookmarkBar() { diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd index 3c277f7..22e76d1 100644 --- a/chrome/browser/browser_resources.grd +++ b/chrome/browser/browser_resources.grd @@ -60,9 +60,11 @@ without changes to the corresponding grd file. eadee --> <include name="IDR_REMOTING_SETUP_FLOW_HTML" file="remoting\resources\setup_flow.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_REMOTING_SETUP_DONE_HTML" file="remoting\resources\setup_done.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_TRANSLATE_JS" file="resources\translate.js" type="BINDATA" /> - + <include name="IDR_BUGREPORT_HTML" file="resources\bug_report.html" flattenhtml="true" type="BINDATA" /> + <include name="IDR_BUGREPORT_HTML_INVALID" file="resources\bug_report_invalid.html" flattenhtml="true" type="BINDATA" /> <if expr="pp_ifdef('chromeos')"> <include name="IDR_ABOUT_SYS_HTML" file="resources\about_sys.html" flattenhtml="true" type="BINDATA" /> + <include name="IDR_BUGREPORT_HTML_CHROMEOS" file="resources\bug_report_cros.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_FILEBROWSE_HTML" file="resources\filebrowse.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_HOST_REGISTRATION_PAGE_HTML" file="resources\host_registration_page.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_MEDIAPLAYER_HTML" file="resources\mediaplayer.html" flattenhtml="true" type="BINDATA" /> diff --git a/chrome/browser/bug_report_util.cc b/chrome/browser/bug_report_util.cc index d60ef4e..85f7ac1 100644 --- a/chrome/browser/bug_report_util.cc +++ b/chrome/browser/bug_report_util.cc @@ -4,22 +4,34 @@ #include "chrome/browser/bug_report_util.h" +#include <sstream> #include <string> +#include "app/l10n_util.h" +#include "base/command_line.h" #include "base/file_version_info.h" +#include "base/file_util.h" +#include "base/singleton.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" +#include "chrome/browser/browser_list.h" #include "chrome/browser/browser_process_impl.h" #include "chrome/browser/profile.h" #include "chrome/browser/safe_browsing/safe_browsing_util.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/common/chrome_version_info.h" +#include "chrome/common/chrome_switches.h" #include "chrome/common/net/url_fetcher.h" #include "googleurl/src/gurl.h" #include "grit/locale_settings.h" +#include "grit/theme_resources.h" #include "net/url_request/url_request_status.h" #include "unicode/locid.h" +#if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/notifications/system_notification.h" +#endif + namespace { const int kBugReportVersion = 1; @@ -28,27 +40,60 @@ const char kReportPhishingUrl[] = "http://www.google.com/safebrowsing/report_phish/"; // URL to post bug reports to. -const char* const kBugReportPostUrl = +static char const kBugReportPostUrl[] = "https://www.google.com/tools/feedback/chrome/__submit"; -const char* const kProtBufMimeType = "application/x-protobuf"; -const char* const kPngMimeType = "image/png"; +static char const kProtBufMimeType[] = "application/x-protobuf"; +static char const kPngMimeType[] = "image/png"; // Tags we use in product specific data -const char* const kPageTitleTag = "PAGE TITLE"; -const char* const kProblemTypeIdTag = "PROBLEM TYPE ID"; -const char* const kProblemTypeTag = "PROBLEM TYPE"; -const char* const kChromeVersionTag = "CHROME VERSION"; -const char* const kOsVersionTag = "OS VERSION"; +static char const kPageTitleTag[] = "PAGE TITLE"; +static char const kProblemTypeIdTag[] = "PROBLEM TYPE ID"; +static char const kProblemTypeTag[] = "PROBLEM TYPE"; +static char const kChromeVersionTag[] = "CHROME VERSION"; +static char const kOsVersionTag[] = "OS VERSION"; + +static char const kNotificationId[] = "feedback.chromeos"; + +static int const kHttpPostSuccessNoContent = 204; +static int const kHttpPostFailNoConnection = -1; +static int const kHttpPostFailClientError = 400; +static int const kHttpPostFailServerError = 500; + +} // namespace + +#if defined(OS_CHROMEOS) +class FeedbackNotification { + public: + // Previous notification cleanup is handled by scoped_ptr. + // Note: notification will show only on one profile at a time. + void Show(Profile* profile, const string16& message, bool urgent) { + notification_.reset( + new chromeos::SystemNotification(profile, kNotificationId, + IDR_STATUSBAR_FEEDBACK, + l10n_util::GetStringUTF16( + IDS_BUGREPORT_NOTIFICATION_TITLE))); + notification_->Show(message, urgent); + } -} // namespace + private: + FeedbackNotification() {} + friend struct DefaultSingletonTraits<FeedbackNotification>; + + scoped_ptr<chromeos::SystemNotification> notification_; + DISALLOW_COPY_AND_ASSIGN(FeedbackNotification); +}; +#endif // Simple URLFetcher::Delegate to clean up URLFetcher on completion. class BugReportUtil::PostCleanup : public URLFetcher::Delegate { public: +#if defined(OS_CHROMEOS) + explicit PostCleanup(Profile* profile); +#else PostCleanup(); - +#endif // Overridden from URLFetcher::Delegate. virtual void OnURLFetchComplete(const URLFetcher* source, const GURL& url, @@ -61,10 +106,17 @@ class BugReportUtil::PostCleanup : public URLFetcher::Delegate { virtual ~PostCleanup() {} private: + Profile* profile_; + DISALLOW_COPY_AND_ASSIGN(PostCleanup); }; -BugReportUtil::PostCleanup::PostCleanup() { +#if defined(OS_CHROMEOS) + BugReportUtil::PostCleanup::PostCleanup(Profile* profile) + : profile_(profile) { +#else + BugReportUtil::PostCleanup::PostCleanup() { +#endif } void BugReportUtil::PostCleanup::OnURLFetchComplete( @@ -74,10 +126,38 @@ void BugReportUtil::PostCleanup::OnURLFetchComplete( int response_code, const ResponseCookies& cookies, const std::string& data) { - // if not 204, something went wrong - if (response_code != 204) - LOG(WARNING) << "Submission to feedback server failed. Response code: " << - response_code << std::endl; + + std::stringstream error_stream; + if (response_code == kHttpPostSuccessNoContent) { + error_stream << "Success"; + } else if (response_code == kHttpPostFailNoConnection) { + error_stream << "No connection to server."; + } else if ((response_code > kHttpPostFailClientError) && + (response_code < kHttpPostFailServerError)) { + error_stream << "Client error: HTTP response code " << response_code; + } else if (response_code > kHttpPostFailServerError) { + error_stream << "Server error: HTTP response code " << response_code; + } else { + error_stream << "Unknown error: HTTP response code " << response_code; + } + + LOG(WARNING) << "Submission to feedback server (" << url << + ") status: " << error_stream.str() << std::endl; + +#if defined(OS_CHROMEOS) + // Show the notification to the user; this notification will stay active till + // either the user closes it, or we display another notification. + if (response_code == kHttpPostSuccessNoContent) { + Singleton<FeedbackNotification>()->Show(profile_, l10n_util::GetStringUTF16( + IDS_BUGREPORT_FEEDBACK_STATUS_SUCCESS), false); + } else { + Singleton<FeedbackNotification>()->Show(profile_, + l10n_util::GetStringFUTF16(IDS_BUGREPORT_FEEDBACK_STATUS_FAIL, + ASCIIToUTF16(error_stream.str())), + true); + } +#endif + // Delete the URLFetcher. delete source; // And then delete ourselves. @@ -112,9 +192,20 @@ void BugReportUtil::SetOSVersion(std::string *os_version) { } // static +std::string BugReportUtil::feedback_server_(""); + +// static +void BugReportUtil::SetFeedbackServer(const std::string& server) { + feedback_server_ = server; +} + + +// static void BugReportUtil::AddFeedbackData( userfeedback::ExternalExtensionSubmit* feedback_data, const std::string& key, const std::string& value) { + // We have no reason to log any empty values - gives us no data + if (value == "") return; // Create log_value object and add it to the web_data object userfeedback::ProductSpecificData log_value; log_value.set_key(key); @@ -128,19 +219,25 @@ void BugReportUtil::SendReport(Profile* profile, const std::string& page_title_text, int problem_type, const std::string& page_url_text, - const std::string& user_email_text, const std::string& description, const char* png_data, int png_data_length, int png_width, #if defined(OS_CHROMEOS) int png_height, - const std::string& problem_type_text, + const std::string& user_email_text, const chromeos::LogDictionaryType* const sys_info) { #else int png_height) { #endif - GURL post_url(kBugReportPostUrl); + GURL post_url; + + if (CommandLine::ForCurrentProcess()-> + HasSwitch(switches::kFeedbackServer)) + post_url = GURL(CommandLine::ForCurrentProcess()-> + GetSwitchValueASCII(switches::kFeedbackServer)); + else + post_url = GURL(kBugReportPostUrl); // Create google feedback protocol buffer objects userfeedback::ExternalExtensionSubmit feedback_data; @@ -160,23 +257,17 @@ void BugReportUtil::SendReport(Profile* profile, AddFeedbackData(&feedback_data, std::string(kPageTitleTag), page_title_text); - AddFeedbackData(&feedback_data, std::string(kProblemTypeIdTag), - StringPrintf("%d\r\n", problem_type)); - #if defined(OS_CHROMEOS) - AddFeedbackData(&feedback_data, std::string(kProblemTypeTag), - problem_type_text); -#endif - // Add the user e-mail to the feedback object common_data->set_user_email(user_email_text); +#endif // Add the description to the feedback object common_data->set_description(description); // Add the language std::string chrome_locale = g_browser_process->GetApplicationLocale(); - common_data->set_source_descripton_language(chrome_locale); + common_data->set_source_description_language(chrome_locale); // Set the url web_data->set_url(page_url_text); @@ -222,9 +313,33 @@ void BugReportUtil::SendReport(Profile* profile, *(feedback_data.mutable_screenshot()) = screenshot; } + // Set our Chrome specific data + userfeedback::ChromeData chrome_data; +#if defined(OS_CHROMEOS) + chrome_data.set_chrome_platform( + userfeedback::ChromeData_ChromePlatform_CHROME_OS); + userfeedback::ChromeOsData chrome_os_data; + chrome_os_data.set_category( + (userfeedback::ChromeOsData_ChromeOsCategory) problem_type); + *(chrome_data.mutable_chrome_os_data()) = chrome_os_data; +#else + chrome_data.set_chrome_platform( + userfeedback::ChromeData_ChromePlatform_CHROME_BROWSER); + userfeedback::ChromeBrowserData chrome_browser_data; + chrome_browser_data.set_category( + (userfeedback::ChromeBrowserData_ChromeBrowserCategory) problem_type); + *(chrome_data.mutable_chrome_browser_data()) = chrome_browser_data; +#endif + + *(feedback_data.mutable_chrome_data()) = chrome_data; + // We have the body of our POST, so send it off to the server. URLFetcher* fetcher = new URLFetcher(post_url, URLFetcher::POST, - new BugReportUtil::PostCleanup); +#if defined(OS_CHROMEOS) + new BugReportUtil::PostCleanup(profile)); +#else + new BugReportUtil::PostCleanup()); +#endif fetcher->set_request_context(profile->GetRequestContext()); std::string post_body; diff --git a/chrome/browser/bug_report_util.h b/chrome/browser/bug_report_util.h index d4ffd77..7b51a74 100644 --- a/chrome/browser/bug_report_util.h +++ b/chrome/browser/bug_report_util.h @@ -64,19 +64,21 @@ class BugReportUtil { // all the call sites or making it a wrapper around another util. static void SetOSVersion(std::string *os_version); + // This sets the address of the feedback server to be used by SendReport + static void SetFeedbackServer(const std::string& server); + // Generates bug report data. static void SendReport(Profile* profile, const std::string& page_title_text, int problem_type, const std::string& page_url_text, - const std::string& user_email_text, const std::string& description, const char* png_data, int png_data_length, int png_width, #if defined(OS_CHROMEOS) int png_height, - const std::string& problem_type_text, + const std::string& user_email_text, const chromeos::LogDictionaryType* const sys_info); #else int png_height); @@ -94,6 +96,8 @@ class BugReportUtil { userfeedback::ExternalExtensionSubmit* feedback_data, const std::string& key, const std::string& value); + static std::string feedback_server_; + DISALLOW_IMPLICIT_CONSTRUCTORS(BugReportUtil); }; diff --git a/chrome/browser/cocoa/bug_report_window_controller.mm b/chrome/browser/cocoa/bug_report_window_controller.mm index c7e920da..df29f99 100644 --- a/chrome/browser/cocoa/bug_report_window_controller.mm +++ b/chrome/browser/cocoa/bug_report_window_controller.mm @@ -113,7 +113,6 @@ base::SysNSStringToUTF8(pageTitle_), [self bugTypeFromIndex], base::SysNSStringToUTF8(pageURL_), - std::string(), base::SysNSStringToUTF8(bugDescription_), sendScreenshot_ && !pngData_.empty() ? reinterpret_cast<const char *>(&(pngData_[0])) : NULL, diff --git a/chrome/browser/dom_ui/bug_report_ui.cc b/chrome/browser/dom_ui/bug_report_ui.cc new file mode 100644 index 0000000..45f06e2 --- /dev/null +++ b/chrome/browser/dom_ui/bug_report_ui.cc @@ -0,0 +1,632 @@ +// Copyright (c) 2009 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/dom_ui/bug_report_ui.h" + +#include "app/l10n_util.h" +#include "app/resource_bundle.h" +#include "base/callback.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/message_loop.h" +#include "base/path_service.h" +#include "base/singleton.h" +#include "base/string_piece.h" +#include "base/string_util.h" +#include "base/string_number_conversions.h" +#include "base/thread.h" +#include "base/time.h" +#include "base/values.h" +#include "base/weak_ptr.h" +#include "chrome/browser/bookmarks/bookmark_model.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/browser_window.h" +#include "chrome/browser/bug_report_util.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/dom_ui/dom_ui_screenshot_source.h" +#include "chrome/browser/download/download_manager.h" +#include "chrome/browser/download/download_util.h" +#include "chrome/browser/history/history_types.h" +#include "chrome/browser/metrics/user_metrics.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/tab_contents/thumbnail_generator.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/jstemplate_builder.h" +#include "chrome/common/time_format.h" +#include "chrome/common/url_constants.h" +#include "chrome/common/net/url_fetcher.h" +#include "gfx/codec/png_codec.h" +#include "net/base/escape.h" +#include "views/window/window.h" + +#include "grit/browser_resources.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "grit/locale_settings.h" + +#if defined(OS_LINUX) +#include "app/x11_util.h" +#elif defined(OS_MACOSX) +#include "base/mac_util.h" +#else +#include "app/win_util.h" +#endif + +#if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/cros/syslogs_library.h" +#include "chrome/browser/chromeos/login/user_manager.h" +#endif + +static const char kScreenshotBaseUrl[] = "chrome://screenshots/"; +static const char kCurrentScreenshotUrl[] = "chrome://screenshots/current"; +#if defined(OS_CHROMEOS) +static const char kSavedScreenshotsUrl[] = "chrome://screenshots/saved/"; + +static const char kScreenshotPattern[] = "*.png"; +static const char kScreenshotsRelativePath[] = "/Screenshots"; +#endif + +namespace { +#if defined(OS_CHROMEOS) + +void GetSavedScreenshots(std::vector<std::string>* saved_screenshots, + base::WaitableEvent* done) { + saved_screenshots->clear(); + + FilePath fileshelf_path; + if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS, + &fileshelf_path)) { + done->Signal(); + return; + } + + // TODO(rkc): Change this to use FilePath.Append() once the cros + // issue with it is fixed + FilePath screenshots_path(fileshelf_path.value() + + std::string(kScreenshotsRelativePath)); + file_util::FileEnumerator screenshots(screenshots_path, false, + file_util::FileEnumerator::FILES, + std::string(kScreenshotPattern)); + FilePath screenshot = screenshots.Next(); + while (!screenshot.empty()) { + saved_screenshots->push_back(std::string(kSavedScreenshotsUrl) + + screenshot.BaseName().value()); + screenshot = screenshots.Next(); + } + done->Signal(); +} + +// This fuction posts a task to the file thread to create/list all the current +// and saved screenshots. +void GetScreenshotUrls(std::vector<std::string>* saved_screenshots) { + base::WaitableEvent done(true, false); + ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, + NewRunnableFunction(&GetSavedScreenshots, + saved_screenshots, &done)); + done.Wait(); +} + +std::string GetUserEmail() { + chromeos::UserManager* manager = chromeos::UserManager::Get(); + if (!manager) + return std::string(); + else + return manager->logged_in_user().email(); +} + +chromeos::LogDictionaryType* GetSystemInformation() { + chromeos::LogDictionaryType* sys_info = NULL; + chromeos::SyslogsLibrary* syslogs_lib = + chromeos::CrosLibrary::Get()->GetSyslogsLibrary(); + + if (syslogs_lib) + sys_info = syslogs_lib->GetSyslogs(NULL); + + return sys_info; +} +#endif + + +} // namespace + + +namespace browser { + +// TODO(rkc): Eventually find a better way to do this +std::vector<unsigned char>* last_screenshot_png = 0; +gfx::Rect screen_size; + +void RefreshLastScreenshot(views::Window* parent) { + // Grab an exact snapshot of the window that the user is seeing (i.e. as + // rendered--do not re-render, and include windowed plugins). + if (last_screenshot_png) + last_screenshot_png->clear(); + else + last_screenshot_png = new std::vector<unsigned char>; + +#if defined(OS_LINUX) || defined(OS_CHROMEOS) + screen_size = parent->GetBounds(); + x11_util::GrabWindowSnapshot(parent->GetNativeWindow(), last_screenshot_png); +#elif defined(OS_MACOSX) + int width = 0, height = 0; + mac_util::GrabWindowSnapshot(parent->GetNativeWindow(), last_screenshot_png, + &width, &height); +#else + screen_size = parent->GetBounds(); + win_util::GrabWindowSnapshot(parent->GetNativeWindow(), last_screenshot_png); +#endif +} + +// Global "display this dialog" function declared in browser_dialogs.h. +void ShowHtmlBugReportView(views::Window* parent, Browser* browser) { + std::string bug_report_url = std::string(chrome::kChromeUIBugReportURL) + + base::IntToString(browser->selected_index()); + + RefreshLastScreenshot(parent); + browser->ShowSingletonTab(GURL(bug_report_url)); +} + +} // namespace browser + + +class BugReportUIHTMLSource : public ChromeURLDataManager::DataSource { + public: + explicit BugReportUIHTMLSource(base::StringPiece html); + + // Called when the network layer has requested a resource underneath + // the path we registered. + virtual void StartDataRequest(const std::string& path, + bool is_off_the_record, + int request_id); + virtual std::string GetMimeType(const std::string&) const { + return "text/html"; + } + + private: + base::StringPiece bug_report_html_; + ~BugReportUIHTMLSource() {} + + DISALLOW_COPY_AND_ASSIGN(BugReportUIHTMLSource); +}; + +class TaskProxy; + +// The handler for Javascript messages related to the "bug report" dialog +class BugReportHandler : public DOMMessageHandler, + public base::SupportsWeakPtr<BugReportHandler> { + public: + explicit BugReportHandler(TabContents* tab); + virtual ~BugReportHandler(); + + // Init work after Attach. + base::StringPiece Init(); + + // DOMMessageHandler implementation. + virtual DOMMessageHandler* Attach(DOMUI* dom_ui); + virtual void RegisterMessages(); + void OnURLFetchComplete(const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data); + + void HandleGetDialogDefaults(const Value* value); + void HandleRefreshScreenshots(const Value* value); + void HandleSendReport(const Value* value); + void HandleCancel(const Value* value); + + void SetupScreenshotsSource(); + void ClobberScreenshotsSource(); + + private: + Browser* browser_; + std::string page_url_; + Profile* profile_; + TabContents* tab_; + TabContents* target_tab_; + DOMUIScreenshotSource* screenshot_source_; +#if defined (OS_CHROMEOS) + chromeos::LogDictionaryType* sys_info_; +#endif + + DISALLOW_COPY_AND_ASSIGN(BugReportHandler); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// BugReportHTMLSource +// +//////////////////////////////////////////////////////////////////////////////// + +BugReportUIHTMLSource::BugReportUIHTMLSource(base::StringPiece html) + : DataSource(chrome::kChromeUIBugReportHost, MessageLoop::current()) { + bug_report_html_ = html; +} + +void BugReportUIHTMLSource::StartDataRequest(const std::string& path, + bool is_off_the_record, + int request_id) { + DictionaryValue localized_strings; + localized_strings.SetString(std::string("title"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_TITLE)); + localized_strings.SetString(std::string("issue-with"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_ISSUE_WITH)); + localized_strings.SetString(std::string("page-url"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_REPORT_URL_LABEL)); + localized_strings.SetString(std::string("description"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_DESCRIPTION_LABEL)); + localized_strings.SetString(std::string("screenshot"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_SCREENSHOT_LABEL)); +#if defined(OS_CHROMEOS) + localized_strings.SetString(std::string("user-email"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_USER_EMAIL_LABEL)); + localized_strings.SetString(std::string("currentscreenshots"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_CURRENT_SCREENSHOTS)); + localized_strings.SetString(std::string("savedscreenshots"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_SAVED_SCREENSHOTS)); + localized_strings.SetString(std::string("sysinfo"), + l10n_util::GetStringUTF8( + IDS_BUGREPORT_INCLUDE_SYSTEM_INFORMATION_CHKBOX)); +#else + localized_strings.SetString(std::string("currentscreenshots"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_INCLUDE_NEW_SCREEN_IMAGE)); +#endif + localized_strings.SetString(std::string("noscreenshot"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_INCLUDE_NO_SCREENSHOT)); + + localized_strings.SetString(std::string("send-report"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_SEND_REPORT)); + localized_strings.SetString(std::string("cancel"), + l10n_util::GetStringUTF8(IDS_CANCEL)); + + // Option strings for the "issue with" drop-down. + localized_strings.SetString(std::string("issue-choose"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_CHOOSE_ISSUE)); + + localized_strings.SetString(std::string("no-issue-selected"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_NO_ISSUE_SELECTED)); + + + // TODO(rkc): Find some way to ensure this order of dropdowns is in sync + // with the order in the userfeedback ChromeData proto buffer +#if defined(OS_CHROMEOS) + // Dropdown for ChromeOS: + // + // Connectivity + // Sync + // Crash + // Page Formatting + // Extensions or Apps + // Standby or Resume + // Phishing Page + // General Feedback/Other + + localized_strings.SetString(std::string("issue-connectivity"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_CONNECTIVITY)); + localized_strings.SetString(std::string("issue-sync"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_SYNC)); + localized_strings.SetString(std::string("issue-crashes"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_CRASHES)); + localized_strings.SetString(std::string("issue-page-formatting"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_PAGE_FORMATTING)); + localized_strings.SetString(std::string("issue-extensions"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_EXTENSIONS)); + localized_strings.SetString(std::string("issue-standby"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_STANDBY_RESUME)); + localized_strings.SetString(std::string("issue-phishing"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_PHISHING_PAGE)); + localized_strings.SetString(std::string("issue-other"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_GENERAL)); +#else + // Dropdown for Chrome: + // + // Page formatting or layout + // Pages not loading + // Plug-ins (e.g. Adobe Flash Player, Quicktime, etc) + // Tabs or windows + // Synced preferences + // Crashes + // Extensions or apps + // Phishing + // Other + + localized_strings.SetString(std::string("issue-page-formatting"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_PAGE_FORMATTING)); + localized_strings.SetString(std::string("issue-page-load"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_PAGE_LOAD)); + localized_strings.SetString(std::string("issue-plugins"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_PLUGINS)); + localized_strings.SetString(std::string("issue-tabs"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_TABS)); + localized_strings.SetString(std::string("issue-sync"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_SYNC)); + localized_strings.SetString(std::string("issue-crashes"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_CRASHES)); + localized_strings.SetString(std::string("issue-extensions"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_EXTENSIONS)); + localized_strings.SetString(std::string("issue-phishing"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_PHISHING_PAGE)); + localized_strings.SetString(std::string("issue-other"), + l10n_util::GetStringUTF8(IDS_BUGREPORT_OTHER)); +#endif + + SetFontAndTextDirection(&localized_strings); + + const std::string full_html = jstemplate_builder::GetI18nTemplateHtml( + bug_report_html_, &localized_strings); + + scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes); + html_bytes->data.resize(full_html.size()); + std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin()); + + SendResponse(request_id, html_bytes); +} + +//////////////////////////////////////////////////////////////////////////////// +// +// BugErportHandler +// +//////////////////////////////////////////////////////////////////////////////// +BugReportHandler::BugReportHandler(TabContents* tab) + : profile_(NULL), tab_(tab), screenshot_source_(NULL) { + browser_ = BrowserList::GetLastActive(); +} + +BugReportHandler::~BugReportHandler() { +} + +void BugReportHandler::ClobberScreenshotsSource() { + // Re-create our screenshots data source (this clobbers the last source) + // setting the screenshot to NULL, effectively disabling the source + // TODO(rkc): Once there is a method to 'remove' a source, change this code + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod( + Singleton<ChromeURLDataManager>::get(), + &ChromeURLDataManager::AddDataSource, + make_scoped_refptr(new DOMUIScreenshotSource(NULL)))); + + // clobber last screenshot + if (browser::last_screenshot_png) + browser::last_screenshot_png->clear(); +} + +void BugReportHandler::SetupScreenshotsSource() { + // If we don't already have a screenshot source object created, create one. + if (!screenshot_source_) + screenshot_source_ = new DOMUIScreenshotSource( + browser::last_screenshot_png); + + // Add the source to the data manager. + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod( + Singleton<ChromeURLDataManager>::get(), + &ChromeURLDataManager::AddDataSource, + make_scoped_refptr(screenshot_source_))); +} + +DOMMessageHandler* BugReportHandler::Attach(DOMUI* dom_ui) { + SetupScreenshotsSource(); + return DOMMessageHandler::Attach(dom_ui); +} + +base::StringPiece BugReportHandler::Init() { + std::string page_url; + if (tab_->controller().GetActiveEntry()) { + page_url = tab_->controller().GetActiveEntry()->url().spec(); + } + + std::string params = page_url.substr(strlen(chrome::kChromeUIBugReportURL)); + + int index = 0; + if (!base::StringToInt(params, &index)) { + ClobberScreenshotsSource(); + return base::StringPiece( + ResourceBundle::GetSharedInstance().GetRawDataResource( + IDR_BUGREPORT_HTML_INVALID)); + } + + // Sanity checks. + if (((index == 0) && (params != "0")) || (index >= browser_->tab_count())) { + ClobberScreenshotsSource(); + return base::StringPiece( + ResourceBundle::GetSharedInstance().GetRawDataResource( + IDR_BUGREPORT_HTML_INVALID)); + } + + if (browser_) + target_tab_ = browser_->GetTabContentsAt(index); + else + LOG(FATAL) << "Failed to get last active browser."; + + return base::StringPiece( + ResourceBundle::GetSharedInstance().GetRawDataResource( +#if defined(OS_CHROMEOS) + IDR_BUGREPORT_HTML_CHROMEOS)); +#else + IDR_BUGREPORT_HTML)); +#endif +} + +void BugReportHandler::RegisterMessages() { + dom_ui_->RegisterMessageCallback("getDialogDefaults", + NewCallback(this, &BugReportHandler::HandleGetDialogDefaults)); + dom_ui_->RegisterMessageCallback("refreshScreenshots", + NewCallback(this, &BugReportHandler::HandleRefreshScreenshots)); + dom_ui_->RegisterMessageCallback("sendReport", + NewCallback(this, &BugReportHandler::HandleSendReport)); + dom_ui_->RegisterMessageCallback("cancel", + NewCallback(this, &BugReportHandler::HandleCancel)); +} + +void BugReportHandler::HandleGetDialogDefaults(const Value* value) { + // send back values which the dialog js needs initially + ListValue dialog_defaults; + + // 0: current url + if (target_tab_) + dialog_defaults.Append(new StringValue( + target_tab_->controller().GetActiveEntry()->url().spec())); + else + dialog_defaults.Append(new StringValue("")); + +#if defined(OS_CHROMEOS) + // 1: user e-mail + sys_info_ = GetSystemInformation(); + dialog_defaults.Append(new StringValue(chrome::kAboutSystemURL)); + + // 2: user e-mail + dialog_defaults.Append(new StringValue(GetUserEmail())); +#endif + + dom_ui_->CallJavascriptFunction(L"setupDialogDefaults", dialog_defaults); +} + +void BugReportHandler::HandleRefreshScreenshots(const Value* value) { + ListValue screenshots; + screenshots.Append(new StringValue(std::string(kCurrentScreenshotUrl))); + + +#if defined(OS_CHROMEOS) + std::vector<std::string> saved_screenshots; + GetScreenshotUrls(&saved_screenshots); + + ListValue* saved_screenshot_list = new ListValue(); + for (size_t i = 0; i < saved_screenshots.size(); ++i) + saved_screenshot_list->Append(new StringValue(saved_screenshots[i])); + screenshots.Append(saved_screenshot_list); +#endif + dom_ui_->CallJavascriptFunction(L"setupScreenshots", screenshots); +} + +void BugReportHandler::HandleSendReport(const Value* value) { + if (value && value->GetType() == Value::TYPE_LIST) { + const ListValue* list_value = static_cast<const ListValue*>(value); + + ListValue::const_iterator i = list_value->begin(); + if (i == list_value->end()) { + LOG(ERROR) << "Incorrect data passed to sendReport."; + return; + } + + // #0 - Problem type. + std::string problem_type_str; + int problem_type = 0; + (*i)->GetAsString(&problem_type_str); + if (!base::StringToInt(problem_type_str, &problem_type)) { + LOG(ERROR) << "Incorrect data passed to sendReport."; + return; + } + if (++i == list_value->end()) { + LOG(ERROR) << "Incorrect data passed to sendReport."; + return; + } + + // #1 - Page url. + std::string page_url; + (*i)->GetAsString(&page_url); + if (++i == list_value->end()) { + LOG(ERROR) << "Incorrect data passed to sendReport."; + return; + } + + // #2 - Description. + std::string description; + (*i)->GetAsString(&description); + if (++i == list_value->end()) { + LOG(ERROR) << "Incorrect data passed to sendReport."; + return; + } + + // #3 - Screenshot to send. + std::string screenshot_path; + (*i)->GetAsString(&screenshot_path); + screenshot_path.erase(0, strlen(kScreenshotBaseUrl)); +#if defined(OS_CHROMEOS) + if (++i == list_value->end()) { + LOG(ERROR) << "Incorrect data passed to sendReport."; + return; + } + + // #4 - User e-mail + std::string user_email; + (*i)->GetAsString(&user_email); + if (++i == list_value->end()) { + LOG(ERROR) << "Incorrect data passed to sendReport."; + return; + } + + // #5 - System info checkbox. + std::string sys_info_checkbox; + (*i)->GetAsString(&sys_info_checkbox); +#endif + + // Get the image to send in the report. + char* image_data = NULL; + int image_data_size = 0; + // Make sure this object remains in scope till SendReport returns. + std::vector<unsigned char> image; + if (screenshot_path.size() > 0) { + image = screenshot_source_->GetScreenshot(screenshot_path); + image_data = reinterpret_cast<char*>(&(image.front())); + image_data_size = image.size(); + } + + BugReportUtil::SendReport(browser_->profile(), + UTF16ToUTF8(target_tab_->GetTitle()), + problem_type, + page_url, + description, + image_data, + image_data_size, browser::screen_size.width(), +#if defined(OS_CHROMEOS) + browser::screen_size.height(), + user_email, + ((sys_info_checkbox == "true") ? + GetSystemInformation() : NULL)); +#else + browser::screen_size.height()); +#endif + + } else { + LOG(ERROR) << "Incorrect data passed from bug report dialog."; + } + browser_->CloseTabContents(tab_); + ClobberScreenshotsSource(); +} + +void BugReportHandler::HandleCancel(const Value* value) { + browser_->CloseTabContents(tab_); + ClobberScreenshotsSource(); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// BugReportUI +// +//////////////////////////////////////////////////////////////////////////////// +BugReportUI::BugReportUI(TabContents* tab) : HtmlDialogUI(tab) { + BugReportHandler* handler = new BugReportHandler(tab); + AddMessageHandler((handler)->Attach(this)); + + // The handler's init will specify which html + // resource we'll display to the user + BugReportUIHTMLSource* html_source = + new BugReportUIHTMLSource(handler->Init()); + // Set up the chrome://bugreport/ source. + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod( + Singleton<ChromeURLDataManager>::get(), + &ChromeURLDataManager::AddDataSource, + make_scoped_refptr(html_source))); +} diff --git a/chrome/browser/dom_ui/bug_report_ui.h b/chrome/browser/dom_ui/bug_report_ui.h new file mode 100644 index 0000000..907dbb2 --- /dev/null +++ b/chrome/browser/dom_ui/bug_report_ui.h @@ -0,0 +1,20 @@ +// Copyright (c) 2009 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_DOM_UI_BUG_REPORT_UI_H_ +#define CHROME_BROWSER_DOM_UI_BUG_REPORT_UI_H_ + +#include "chrome/browser/dom_ui/html_dialog_ui.h" + +class TabContents; + +class BugReportUI : public HtmlDialogUI { + public: + explicit BugReportUI(TabContents* contents); + private: + + DISALLOW_COPY_AND_ASSIGN(BugReportUI); +}; + +#endif // CHROME_BROWSER_DOM_UI_BUG_REPORT_UI_H_ diff --git a/chrome/browser/dom_ui/dom_ui_factory.cc b/chrome/browser/dom_ui/dom_ui_factory.cc index 5c50067..3288d08 100644 --- a/chrome/browser/dom_ui/dom_ui_factory.cc +++ b/chrome/browser/dom_ui/dom_ui_factory.cc @@ -7,6 +7,7 @@ #include "base/command_line.h" #include "chrome/browser/chrome_thread.h" #include "chrome/browser/dom_ui/bookmarks_ui.h" +#include "chrome/browser/dom_ui/bug_report_ui.h" #include "chrome/browser/dom_ui/downloads_ui.h" #include "chrome/browser/dom_ui/devtools_ui.h" #include "chrome/browser/dom_ui/history_ui.h" @@ -102,6 +103,8 @@ static DOMUIFactoryFunction GetDOMUIFactoryFunction(const GURL& url) { // after the host name. if (url.host() == chrome::kChromeUIBookmarksHost) return &NewDOMUI<BookmarksUI>; + if (url.host() == chrome::kChromeUIBugReportHost) + return &NewDOMUI<BugReportUI>; if (url.host() == chrome::kChromeUIDevToolsHost) return &NewDOMUI<DevToolsUI>; if (url.host() == chrome::kChromeUIDownloadsHost) diff --git a/chrome/browser/dom_ui/dom_ui_screenshot_source.cc b/chrome/browser/dom_ui/dom_ui_screenshot_source.cc new file mode 100644 index 0000000..3810f4d --- /dev/null +++ b/chrome/browser/dom_ui/dom_ui_screenshot_source.cc @@ -0,0 +1,112 @@ +// Copyright (c) 2009 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/dom_ui/dom_ui_screenshot_source.h" + +#include "base/callback.h" +#include "base/file_util.h" +#include "base/path_service.h" +#include "base/ref_counted_memory.h" +#include "base/task.h" +#include "base/thread.h" +#include "base/waitable_event.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/url_constants.h" +#include "gfx/codec/jpeg_codec.h" +#include "googleurl/src/gurl.h" +#include "third_party/skia/include/core/SkBitmap.h" + +static const char kCurrentScreenshot[] = "current"; +#if defined(OS_CHROMEOS) +static const char kSavedScreenshots[] = "saved/"; +#endif + +static const char kScreenshotsRelativePath[] = "/Screenshots/"; + +#if defined(OS_CHROMEOS) +// Read the file from the screenshots directory into the read_bytes vector. +void ReadScreenshot(const std::string& filename, + std::vector<unsigned char>* read_bytes, + base::WaitableEvent* read_complete) { + read_bytes->clear(); + + FilePath fileshelf_path; + if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS, &fileshelf_path)) { + read_complete->Signal(); + return; + } + + FilePath file(fileshelf_path.value() + std::string(kScreenshotsRelativePath) + + filename); + + int64 file_size = 0; + if (!file_util::GetFileSize(file, &file_size)) { + read_complete->Signal(); + return; + } + + // expand vector to file size + read_bytes->resize(file_size); + // read file into the vector + int bytes_read = 0; + if (!(bytes_read = file_util::ReadFile(file, + reinterpret_cast<char*>( + &read_bytes->front()), + static_cast<int>(file_size)))) + read_bytes->clear(); + + // We're done, if successful, read_bytes will have the data + // otherwise, it'll be empty. + read_complete->Signal(); +} + +// Get a saved screenshot - read on the FILE thread. +std::vector<unsigned char> GetSavedScreenshot(std::string filename) { + base::WaitableEvent read_complete(true, false); + std::vector<unsigned char> bytes; + ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, + NewRunnableFunction(&ReadScreenshot, filename, + &bytes, &read_complete)); + read_complete.Wait(); + return bytes; +} +#endif + +std::vector<unsigned char> DOMUIScreenshotSource::GetScreenshot( + const std::string& path) { + if (path == kCurrentScreenshot) { + return current_screenshot_; +#if defined(OS_CHROMEOS) + } else if (path.compare(0, strlen(kSavedScreenshots), + kSavedScreenshots) == 0) { + // Split the saved screenshot filename from the path + std::string filename = path.substr(strlen(kSavedScreenshots)); + + return GetSavedScreenshot(filename); +#endif + } else { + std::vector<unsigned char> ret; + // TODO(rkc): Weird vc bug, return std::vector<unsigned char>() causes + // the object assigned to the return value of this function magically + // change it's address 0x0; look into this eventually. + return ret; + } +} + +DOMUIScreenshotSource::DOMUIScreenshotSource( + std::vector<unsigned char>* current_screenshot) + : DataSource(chrome::kChromeUIScreenshotPath, MessageLoop::current()) { + // Setup the last screenshot taken. + if (current_screenshot) + current_screenshot_ = *current_screenshot; + else + current_screenshot_.clear(); +} + +void DOMUIScreenshotSource::StartDataRequest(const std::string& path, + bool is_off_the_record, + int request_id) { + SendResponse(request_id, new RefCountedBytes(GetScreenshot(path))); +} diff --git a/chrome/browser/dom_ui/dom_ui_screenshot_source.h b/chrome/browser/dom_ui/dom_ui_screenshot_source.h new file mode 100644 index 0000000..be4e280 --- /dev/null +++ b/chrome/browser/dom_ui/dom_ui_screenshot_source.h @@ -0,0 +1,46 @@ +// Copyright (c) 2009 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_DOM_UI_DOM_UI_SCREENSHOT_SOURCE_H_ +#define CHROME_BROWSER_DOM_UI_DOM_UI_SCREENSHOT_SOURCE_H_ + +#include <string> +#include <utility> +#include <vector> + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" +#include "chrome/browser/dom_ui/chrome_url_data_manager.h" +#include "chrome/browser/dom_ui/html_dialog_ui.h" + +// ScreenshotSource is the data source that serves screenshots (saved +// or current) to the bug report html ui +class DOMUIScreenshotSource : public ChromeURLDataManager::DataSource { + public: + explicit DOMUIScreenshotSource( + std::vector<unsigned char>* current_screenshot); + + // Called when the network layer has requested a resource underneath + // the path we registered. + virtual void StartDataRequest(const std::string& path, + bool is_off_the_record, + int request_id); + + virtual std::string GetMimeType(const std::string&) const { + // We need to explicitly return a mime type, otherwise if the user tries to + // drag the image they get no extension. + return "image/png"; + } + + std::vector<unsigned char> GetScreenshot(const std::string& path); + + private: + ~DOMUIScreenshotSource() {} + +// scoped_refptr<RefCountedBytes> current_screenshot_; + std::vector<unsigned char> current_screenshot_; + DISALLOW_COPY_AND_ASSIGN(DOMUIScreenshotSource); +}; + +#endif // CHROME_BROWSER_DOM_UI_DOM_UI_SCREENSHOT_SOURCE_H_ diff --git a/chrome/browser/resources/bug_report.css b/chrome/browser/resources/bug_report.css new file mode 100644 index 0000000..09230c1 --- /dev/null +++ b/chrome/browser/resources/bug_report.css @@ -0,0 +1,99 @@ +.bug-report-label { + text-align: start; + vertical-align: text-top; +} + +.bug-report-text { + width: 40em; + resize: none; +} + +.bug-report-button { + width: 8em; +} + +hr { + border: none; + height: 1px; + background: #cccccc; + margin-top: 10px; + margin-bottom: 10px; + width: 33.5em; +} + +.thumbnail-list { + -webkit-margin-start: 1em; + width: 33.5em; + display: block; + margin-top: 0.5em; + margin-bottom: 1em; +} + +.image-thumbnail-container { + display: inline-block; + border: 2px solid white; + -webkit-border-radius: 3px; + z-index: 0; +} + +.image-thumbnail-container-selected { + display: inline-block; + border: 2px solid green; + -webkit-border-radius: 3px; + z-index: 0; +} + +.image-thumbnail-container:hover { + border: 2px solid #B8DAB0; + z-index: 0; +} + +.image-popup { + width: 50%; +} + +.image-thumbnail { + position: relative; + z-index: 1; + display: inline-block; + padding: 0px; + border: 2px solid white; +} + +.image-thumbnail:hover { + z-index: 2; +} + +.image-thumbnail div { + display: none; +} + +.image-thumbnail img { + display: block; + width: 75px; +} + +.image-thumbnail:hover div { + display: block; + position: absolute; + top: 130%; + left:0; + padding: 1px; + border: 1px dashed blue; + background-color: transparent; + text-align: center +} + +.image-thumbnail:hover div img { + position: absolute; + width: 400px; +} + +th { + padding-top: 10px; + color: #233478; +} + +body { + -webkit-user-select: none; +} diff --git a/chrome/browser/resources/bug_report.html b/chrome/browser/resources/bug_report.html new file mode 100644 index 0000000..c3b53ce --- /dev/null +++ b/chrome/browser/resources/bug_report.html @@ -0,0 +1,135 @@ +<!DOCTYPE HTML> +<html i18n-values="dir:textdirection;"> +<head> +<meta charset="utf-8"/> +<title i18n-content="title"></title> +<link rel="stylesheet" href="bug_report.css"/> + +<script src="shared/js/local_strings.js"></script> +<script src="shared/js/util.js"></script> +<script src="bug_report.js"></script> +<script> + +/////////////////////////////////////////////////////////////////////////////// +// Document Functions: +/** + * Window onload handler, sets up the page. + */ +function load() {
+ // textContent on description-text textarea seems to default
+ // to several spaces, this resets it to empty.
+ $('description-text').textContent = '';
+
+ $('current-screenshot').nextSibling.textContent =
+ localStrings.getString('currentscreenshots');
+ $('no-screenshot').nextSibling.textContent =
+ localStrings.getString('noscreenshot');
+
+ // Get a list of issues that we allow the user to select from.
+ // Note, the order and the issues types themselves are different
+ // between Chromium and Chromium OS, so this code needs to be
+ // maintained individually between the bug_report.html and
+ // bug_report_cros.html files.
+ var issueTypeText = []; + issueTypeText[0] = localStrings.getString('issue-choose');
+ issueTypeText[1] = localStrings.getString('issue-page-formatting');
+ issueTypeText[2] = localStrings.getString('issue-page-load');
+ issueTypeText[3] = localStrings.getString('issue-plugins');
+ issueTypeText[4] = localStrings.getString('issue-tabs');
+ issueTypeText[5] = localStrings.getString('issue-sync');
+ issueTypeText[6] = localStrings.getString('issue-crashes');
+ issueTypeText[7] = localStrings.getString('issue-extensions');
+ issueTypeText[8] = localStrings.getString('issue-phishing');
+ issueTypeText[9] = localStrings.getString('issue-other');
+
+ // Add all the issues to the selection box.
+ for (var i = 0; i < issueTypeText.length; i++) {
+ var option = document.createElement('option');
+ option.className = 'bug-report-text';
+ option.textContent = issueTypeText[i];
+ $('issue-with-combo').add(option);
+ }
+
+ chrome.send('getDialogDefaults', []);
+ chrome.send('refreshScreenshots', []);
+};
+
+function setupScreenshots(screenshots) { + if (screenshots.length > 0) + addScreenshot('current-screenshots', screenshots[0]); +} + +function setupDialogDefaults(defaults) { + if (defaults.length > 0) + $('page-url-text').value = defaults[0];
+}
+
+window.addEventListener('DOMContentLoaded', load); +</script> +</head> +<body> +<table> + <!-- Issue type dropdown --> + <tr> + <th id="issue-with" class="bug-report-label" i18n-content="issue-with"> + </th> + </tr> + <tr> + <td> + <select id="issue-with-combo" class="bug-report-text"> + </select> + </td> + </tr> + <!-- Page URL text box --> + <tr> + <th colspan="2" id="page-url" class="bug-report-label" + i18n-content="page-url"> + </th> + </tr> + <tr> + <td colspan="2"> + <input id='page-url-text' maxlength=200 class="bug-report-text"> + </td> + </tr> + <!-- Description --> + <tr> + <th id="description" colspan="2" class="bug-report-label" + i18n-content="description"> + </th> + </tr> + <tr> + <td colspan="2"> + <textarea id='description-text' rows="10" class="bug-report-text"> + </textarea> + </td> + </tr> + <!-- Screenshot radio buttons --> + <tr> + <th id="screenshot" class="bug-report-label" i18n-content="screenshot"> + </th> + </tr> + <tr> + <td> + <input id="no-screenshot" type="radio" name="screenshot-group" + value="none" onclick="noneSelected()"> + <br> + <input id="current-screenshot" type="radio" name="screenshot-group" + value="current" checked onclick="currentSelected()"> + <br> + <div id="current-screenshots" class="thumbnail-list"> + </div> + </td> + </tr> + <!-- Buttons --> + <tr> + <td> + <hr> + <input id='send-report-button' type="submit" class="bug-report-button" + i18n-values="value:send-report" onclick="sendReport()"> + <input id='cancel-button' type="submit" class="bug-report-button" + i18n-values="value:cancel" onclick="cancel()"> + </td> + </tr> +</table> +</body> +</html> diff --git a/chrome/browser/resources/bug_report.js b/chrome/browser/resources/bug_report.js new file mode 100644 index 0000000..508a954 --- /dev/null +++ b/chrome/browser/resources/bug_report.js @@ -0,0 +1,152 @@ +// 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. + +// Constants. +var FEEDBACK_LANDING_PAGE = + 'http://www.google.com/support/chrome/go/feedback_confirmation' + +var selectedThumbnailDivId = ''; +var selectedThumbnailId = ''; +var selectedImageUrl; + +var savedThumbnailIds = []; +savedThumbnailIds['current-screenshots'] = ''; +savedThumbnailIds['saved-screenshots'] = ''; + +var localStrings = new LocalStrings(); + +/** + * Selects an image thumbnail in the specified div. + */ +function selectImage(divId, thumbnailId) { + var thumbnailDivs = $(divId).children; + selectedThumbnailDivId = divId; + for (var i = 0; i < thumbnailDivs.length; i++) { + // If the the current div matches the thumbnail id provided, + // or there is no thumbnail id given, and we're at the first thumbnail. + if ((thumbnailDivs[i].id == thumbnailId) || (!thumbnailId && !i)) { + thumbnailDivs[i].className = 'image-thumbnail-container-selected'; + selectedThumbnailId = thumbnailId; + savedThumbnailIds[divId] = thumbnailId; + } else { + thumbnailDivs[i].className = 'image-thumbnail-container'; + } + } +} + +/** + * Adds an image thumbnail to the specified div. + */ +function addScreenshot(divId, screenshot) { + var thumbnailDiv = document.createElement('div'); + thumbnailDiv.className = 'image-thumbnail-container'; + + thumbnailDiv.id = divId + '-thumbnailDiv-' + $(divId).children.length; + thumbnailDiv.onclick = function() { + selectImage(divId, thumbnailDiv.id); + }; + + var innerDiv = document.createElement('div'); + innerDiv.className = 'image-thumbnail'; + + var thumbnail = document.createElement('img'); + thumbnail.id = thumbnailDiv.id + '-image'; + thumbnail.src = screenshot; + innerDiv.appendChild(thumbnail); + + var largeImage = document.createElement('img'); + largeImage.src = screenshot; + + var popupDiv = document.createElement('div'); + popupDiv.appendChild(largeImage); + innerDiv.appendChild(popupDiv); + + thumbnailDiv.appendChild(innerDiv); + $(divId).appendChild(thumbnailDiv); + + if (!selectedThumbnailId) + selectImage(divId, thumbnailDiv.id); +} + +/** + * Send's the report; after the report is sent, we need to be redirected to + * the landing page, but we shouldn't be able to navigate back, hence + * we open the landing page in a new tab and sendReport closes this tab. + */ +function sendReport() { + if (!$('issue-with-combo').selectedIndex) { + alert(localStrings.getString('no-issue-selected')); + return false; + } + + var imagePath = ''; + if (selectedThumbnailId) + imagePath = $(selectedThumbnailId + '-image').src; + + // Note, categories are based from 1 in our protocol buffers, so no + // adjustment is needed on selectedIndex. + var reportArray = [String($('issue-with-combo').selectedIndex), + $('page-url-text').value, + $('description-text').value, + imagePath]; + + // Add chromeos data if it exists. + if ($('user-email-text') && $('sys-info-checkbox')) { + reportArray = reportArray.concat([$('user-email-text').value, + String($('sys-info-checkbox').checked)]); + } + + // open the landing page in a new tab, sendReport will close this one. + window.open(FEEDBACK_LANDING_PAGE, '_blank'); + chrome.send('sendReport', reportArray); + return true; +} + +function cancel() { + chrome.send('cancel', []); + return true; +} + +/** + * Select the current screenshots div, restoring the image that was + * selected when we had this div open previously. + */ +function currentSelected() { + $('current-screenshots').style.display = 'block'; + if ($('saved-screenshots')) + $('saved-screenshots').style.display = 'none'; + + if (selectedThumbnailDivId != 'current-screenshots') + selectImage('current-screenshots', + savedThumbnailIds['current-screenshots']); + + return true; +} + +/** + * Select the saved screenshots div, restoring the image that was + * selected when we had this div open previously. + */ +function savedSelected() { + $('current-screenshots').style.display = 'none'; + $('saved-screenshots').style.display = 'block'; + + if (selectedThumbnailDivId != 'saved-screenshots') + selectImage('saved-screenshots', savedThumbnailIds['saved-screenshots']); + + return true; +} + +/** + * Unselect all screenshots divs. + */ +function noneSelected() { + $('current-screenshots').style.display = 'none'; + if ($('saved-screenshots')) + $('saved-screenshots').style.display = 'none'; + + selectedThumbnailDivId = ''; + selectedThumbnailId = ''; + return true; +} diff --git a/chrome/browser/resources/bug_report_cros.html b/chrome/browser/resources/bug_report_cros.html new file mode 100644 index 0000000..d001c7e --- /dev/null +++ b/chrome/browser/resources/bug_report_cros.html @@ -0,0 +1,169 @@ +<!DOCTYPE HTML> +<html i18n-values="dir:textdirection;"> +<head> +<meta charset="utf-8"/> +<title i18n-content="title"></title> +<link rel="stylesheet" href="bug_report.css"/> + +<script src="shared/js/local_strings.js"></script> +<script src="shared/js/util.js"></script> +<script src="bug_report.js"></script> +<script> + +/////////////////////////////////////////////////////////////////////////////// +// Document Functions: +/** + * Window onload handler, sets up the page. + */ +function load() { + // textContent on description-text textarea seems to default + // to several spaces, this resets it to empty. + $('description-text').textContent = ''; + + $('current-screenshot').nextSibling.textContent = + localStrings.getString('currentscreenshots'); + $('saved-screenshot').nextSibling.textContent = + localStrings.getString('savedscreenshots'); + $('no-screenshot').nextSibling.textContent = + localStrings.getString('noscreenshot'); + + // Get a list of issues that we allow the user to select from. + // Note, the order and the issues types themselves are different + // between Chromium and Chromium OS, so this code needs to be + // maintained individually between the bug_report.html and + // bug_report_cros.html files. + var issueTypeText = []; + issueTypeText[0] = localStrings.getString('issue-choose'); + issueTypeText[1] = localStrings.getString('issue-connectivity'); + issueTypeText[2] = localStrings.getString('issue-sync'); + issueTypeText[3] = localStrings.getString('issue-crashes'); + issueTypeText[4] = localStrings.getString('issue-page-formatting'); + issueTypeText[5] = localStrings.getString('issue-extensions'); + issueTypeText[6] = localStrings.getString('issue-standby'); + issueTypeText[7] = localStrings.getString('issue-phishing'); + issueTypeText[8] = localStrings.getString('issue-other'); + + // Add all the issues to the selection box. + for (var i = 0; i < issueTypeText.length; i++) { + var option = document.createElement('option'); + option.className = 'bug-report-text'; + option.textContent = issueTypeText[i]; + $('issue-with-combo').add(option); + } + + chrome.send('getDialogDefaults', []); + chrome.send('refreshScreenshots', []); +}; + +function setupScreenshots(screenshots) { + if (screenshots.length > 1) { + currentScreenshot = screenshots[0]; + addScreenshot('current-screenshots', currentScreenshot); + + savedScreenshots = screenshots[1]; + for (i = 0; i < savedScreenshots.length; ++i) + addScreenshot('saved-screenshots', savedScreenshots[i]); + } +} + +function setupDialogDefaults(defaults) { + if (defaults.length > 2) { + $('page-url-text').value = defaults[0]; + $('sysinfo-url').href = defaults[1]; + $('user-email-text').value = defaults[2]; + } +} + +window.addEventListener('DOMContentLoaded', load); +</script> +</head> +<body> +<table> + <!-- Issue type dropdown --> + <tr> + <th id="issue-with" class="bug-report-label" i18n-content="issue-with"> + </th> + </tr> + <tr> + <td> + <select id="issue-with-combo" class="bug-report-text"> + </select> + </td> + </tr> + <!-- Page URL text box --> + <tr> + <th colspan="2" id="page-url" class="bug-report-label" + i18n-content="page-url"> + </th> + </tr> + <tr> + <td colspan="2"> + <input id='page-url-text' maxlength=200 class="bug-report-text"> + </td> + </tr> + <!-- Description --> + <tr> + <th id="description" colspan="2" class="bug-report-label" + i18n-content="description"> + </th> + </tr> + <tr> + <td colspan="2"> + <textarea id='description-text' rows="10" class="bug-report-text"> + </textarea> + </td> + </tr> + <!-- System Information checkbox --> + <tr> + <td> + <input id="sys-info-checkbox" type="checkbox" value="sysinfo" checked> + <span id="sysinfo-label"></span> <a href='about:blank' id="sysinfo-url" + target="_blank" i18n-content="sysinfo">></a> + </td> + </tr> + <!-- Page URL text box --> + <tr> + <th id="user-email" class="bug-report-label" i18n-content="user-email"> + </th> + </tr> + <tr> + <td> + <input id='user-email-text' maxlength=200 class="bug-report-text"> + </td> + </tr> + <!-- Screenshot radio buttons --> + <tr> + <th id="screenshot" class="bug-report-label" i18n-content="screenshot"> + </th> + </tr> + <tr> + <td> + <input id="no-screenshot" type="radio" name="screenshot-group" + value="none" onclick="noneSelected()"> + <br> + <input id="saved-screenshot" type="radio" name="screenshot-group" + value="saved" onclick="savedSelected()"> + <br> + <div id="saved-screenshots" style="display: none;" + class="thumbnail-list"> + </div> + <input id="current-screenshot" type="radio" name="screenshot-group" + value="current" checked onclick="currentSelected()"> + <br> + <div id="current-screenshots" class="thumbnail-list"> + </div> + </td> + </tr> + <!-- Buttons --> + <tr> + <td> + <hr> + <input id='send-report-button' type="submit" class="bug-report-button" + i18n-values="value:send-report" onclick="sendReport()"> + <input id='cancel-button' type="submit" class="bug-report-button" + i18n-values="value:cancel" onclick="cancel()"> + </td> + </tr> +</table> +</body> +</html> diff --git a/chrome/browser/resources/bug_report_invalid.html b/chrome/browser/resources/bug_report_invalid.html new file mode 100644 index 0000000..e6b1605 --- /dev/null +++ b/chrome/browser/resources/bug_report_invalid.html @@ -0,0 +1,10 @@ +<!DOCTYPE HTML> +<html> +<head> +<meta charset="utf-8"> +</head> +<title i18n-content="title"></title> +<body onselectstart='return false'> +Invalid BugReport options - please check. +</body> +</html> diff --git a/chrome/browser/userfeedback/proto/chrome.proto b/chrome/browser/userfeedback/proto/chrome.proto new file mode 100644 index 0000000..11b8eff --- /dev/null +++ b/chrome/browser/userfeedback/proto/chrome.proto @@ -0,0 +1,55 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// Author: marcinm@google.com (Marcin Mikosik) + +syntax = "proto2"; + +package userfeedback; + +// Chrome Browser and Chrome OS specific data. +message ChromeData { + // Encapsulates the priorities of Buganizer issues. + enum ChromePlatform { + CHROME_OS = 1; + CHROME_BROWSER = 2; + } + + // What platform has a report been sent from. + optional ChromePlatform chrome_platform = 1 [default = CHROME_OS]; + + optional ChromeOsData chrome_os_data = 2; + + optional ChromeBrowserData chrome_browser_data = 3; +} + +message ChromeOsData { + enum ChromeOsCategory { + CONNECTIVITY = 1; + SYNC = 2; + CRASH = 3; + PAGE_FORMATTING_OR_LAYOUT = 4; + EXTENSIONS_OR_APPS = 5; + STANDBY_OR_RESUME = 6; + PHISHING_PAGE = 7; + OTHER = 8; + } + + optional ChromeOsCategory category = 1 [default = OTHER]; +} + +message ChromeBrowserData{ + + enum ChromeBrowserCategory { + PAGE_FORMATTING_OR_LAYOUT = 1; + PAGES_NOT_LOADING = 2; + PLUGINS = 3; + TABS_OR_WINDOWS = 4; + SYNCED_PREFERENCES = 5; + CRASH = 6; + EXTENSIONS_OR_APPS = 7; + PHISHING_PAGE = 8; + OTHER = 9; + } + + optional ChromeBrowserCategory category = 1 [default = OTHER]; +} + diff --git a/chrome/browser/userfeedback/proto/common.proto b/chrome/browser/userfeedback/proto/common.proto index 97c60fb..291e6a1 100644 --- a/chrome/browser/userfeedback/proto/common.proto +++ b/chrome/browser/userfeedback/proto/common.proto @@ -16,7 +16,13 @@ message CommonData { // Description of the problem entered by user. optional string description = 2; optional string description_translated = 4; - optional string source_descripton_language = 5 [ default = "en" ]; + optional string source_description_language = 5 [ default = "en" ]; + optional string ui_language = 6 [ default = "en_US" ]; optional string user_email = 3; + + // Unique identifier of feedback report. If set than only one report + // with the same identifier is stored in the system. + // If you are not sure how to use it leave it not set. + optional string unique_report_identifier = 7; }; diff --git a/chrome/browser/userfeedback/proto/extension.proto b/chrome/browser/userfeedback/proto/extension.proto index d600f8a..71be3dc 100644 --- a/chrome/browser/userfeedback/proto/extension.proto +++ b/chrome/browser/userfeedback/proto/extension.proto @@ -8,6 +8,7 @@ syntax = "proto2"; package userfeedback; import "common.proto"; +import "chrome.proto"; import "dom.proto"; import "math.proto"; import "web.proto"; @@ -64,6 +65,8 @@ message ExternalExtensionSubmit { optional HtmlDocument html_document_structure = 5; optional ExtensionErrors extension_errors = 13; + + optional ChromeData chrome_data = 14; }; // Sent when user hits final submit button in internal extension. diff --git a/chrome/browser/userfeedback/proto/web.proto b/chrome/browser/userfeedback/proto/web.proto index fb9f6af..71b0b29 100644 --- a/chrome/browser/userfeedback/proto/web.proto +++ b/chrome/browser/userfeedback/proto/web.proto @@ -8,7 +8,6 @@ package userfeedback; // Data present in Web related feedbacks import "annotations.proto"; -import "config.proto"; import "dom.proto"; import "math.proto"; diff --git a/chrome/browser/views/browser_dialogs.h b/chrome/browser/views/browser_dialogs.h index f775d97..8affac9 100644 --- a/chrome/browser/views/browser_dialogs.h +++ b/chrome/browser/views/browser_dialogs.h @@ -45,6 +45,9 @@ void ShowBugReportView(views::Window* parent, Profile* profile, TabContents* tab); +// Shows the "Report a problem with this page" page in a new tab +void ShowHtmlBugReportView(views::Window* parent, Browser* browser); + // Shows the "Clear browsing data" dialog box. See ClearBrowsingDataView. void ShowClearBrowsingDataView(gfx::NativeWindow parent, Profile* profile); diff --git a/chrome/browser/views/bug_report_view.cc b/chrome/browser/views/bug_report_view.cc deleted file mode 100644 index 03cbc76..0000000 --- a/chrome/browser/views/bug_report_view.cc +++ /dev/null @@ -1,627 +0,0 @@ -// 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/bug_report_view.h" - -#include <string> -#include <vector> - -#include "app/combobox_model.h" -#include "app/l10n_util.h" -#include "base/file_path.h" -#include "base/file_util.h" -#include "base/file_version_info.h" -#include "base/path_service.h" -#include "base/utf_string_conversions.h" -#include "base/waitable_event.h" -#include "chrome/browser/bug_report_util.h" -#include "chrome/browser/pref_service.h" -#include "chrome/browser/profile.h" -#include "chrome/browser/browser_list.h" -#include "chrome/browser/chrome_thread.h" -#include "chrome/browser/safe_browsing/safe_browsing_util.h" -#include "chrome/browser/tab_contents/navigation_controller.h" -#include "chrome/browser/tab_contents/navigation_entry.h" -#include "chrome/browser/tab_contents/tab_contents.h" -#include "chrome/common/chrome_paths.h" -#include "chrome/common/chrome_version_info.h" -#include "chrome/common/net/url_fetcher.h" -#include "chrome/common/pref_names.h" -#include "chrome/common/url_constants.h" -#include "grit/chromium_strings.h" -#include "grit/generated_resources.h" -#include "grit/locale_settings.h" -#include "net/base/escape.h" -#include "unicode/locid.h" -#include "views/controls/button/checkbox.h" -#include "views/controls/label.h" -#include "views/grid_layout.h" -#include "views/standard_layout.h" -#include "views/widget/widget.h" -#include "views/window/client_view.h" -#include "views/window/window.h" - -#if defined(OS_LINUX) -#include "app/x11_util.h" -#else -#include "app/win_util.h" -#endif - -#if defined(OS_CHROMEOS) -#include "chrome/browser/chromeos/login/user_manager.h" -#endif - -using views::ColumnSet; -using views::GridLayout; - -// Report a bug data version. -static const int kBugReportVersion = 1; -static const int kScreenImageRadioGroup = 2; -static const char kScreenshotsRelativePath[] = "/Screenshots"; -static const char kScreenshotPattern[] = "*.png"; - -// Number of lines description field can display at one time. -static const int kDescriptionLines = 5; - -class BugReportComboBoxModel : public ComboboxModel { - public: - BugReportComboBoxModel() {} - - // ComboboxModel interface. - virtual int GetItemCount() { - return BugReportUtil::OTHER_PROBLEM + 1; - } - - virtual std::wstring GetItemAt(int index) { - return GetItemAtIndex(index); - } - - static std::wstring GetItemAtIndex(int index) { -#if defined(OS_CHROMEOS) - switch (index) { - case BugReportUtil::CONNECTIVITY_ISSUE: - return l10n_util::GetString(IDS_BUGREPORT_CONNECTIVITY_ISSUE); - case BugReportUtil::SYNC_ISSUE: - return l10n_util::GetString(IDS_BUGREPORT_SYNC_ISSUE); - case BugReportUtil::CRASH_ISSUE: - return l10n_util::GetString(IDS_BUGREPORT_CRASH_ISSUE); - case BugReportUtil::PAGE_FORMATTING: - return l10n_util::GetString(IDS_BUGREPORT_PAGE_FORMATTING); - case BugReportUtil::EXTENSION_ISSUE: - return l10n_util::GetString(IDS_BUGREPORT_EXTENSION_ISSUE); - case BugReportUtil::SUSPEND_ISSUE: - return l10n_util::GetString(IDS_BUGREPORT_SUSPEND_ISSUE); - case BugReportUtil::PHISHING_PAGE: - return l10n_util::GetString(IDS_BUGREPORT_PHISHING_PAGE); - case BugReportUtil::OTHER_PROBLEM: - return l10n_util::GetString(IDS_BUGREPORT_OTHER_PROBLEM); - default: - NOTREACHED(); - return std::wstring(); - } -#else - switch (index) { - case BugReportUtil::PAGE_WONT_LOAD: - return l10n_util::GetString(IDS_BUGREPORT_PAGE_WONT_LOAD); - case BugReportUtil::PAGE_LOOKS_ODD: - return l10n_util::GetString(IDS_BUGREPORT_PAGE_LOOKS_ODD); - case BugReportUtil::PHISHING_PAGE: - return l10n_util::GetString(IDS_BUGREPORT_PHISHING_PAGE); - case BugReportUtil::CANT_SIGN_IN: - return l10n_util::GetString(IDS_BUGREPORT_CANT_SIGN_IN); - case BugReportUtil::CHROME_MISBEHAVES: - return l10n_util::GetString(IDS_BUGREPORT_CHROME_MISBEHAVES); - case BugReportUtil::SOMETHING_MISSING: - return l10n_util::GetString(IDS_BUGREPORT_SOMETHING_MISSING); - case BugReportUtil::BROWSER_CRASH: - return l10n_util::GetString(IDS_BUGREPORT_BROWSER_CRASH); - case BugReportUtil::OTHER_PROBLEM: - return l10n_util::GetString(IDS_BUGREPORT_OTHER_PROBLEM); - default: - NOTREACHED(); - return std::wstring(); - } -#endif - } - - private: - DISALLOW_COPY_AND_ASSIGN(BugReportComboBoxModel); -}; - -namespace { - -#if defined(OS_CHROMEOS) -class LastScreenshotTask : public Task { - public: - LastScreenshotTask(std::string* image_str, - base::WaitableEvent* task_waitable) - : image_str_(image_str), - task_waitable_(task_waitable) { - } - - private: - void Run() { - FilePath fileshelf_path; - // TODO(rkc): Change this to use FilePath.Append() once the cros - // issue with with it is fixed - if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS, - &fileshelf_path)) { - *image_str_ = ""; - task_waitable_->Signal(); - } - - FilePath screenshots_path(fileshelf_path.value() + - std::string(kScreenshotsRelativePath)); - file_util::FileEnumerator screenshots(screenshots_path, false, - file_util::FileEnumerator::FILES, - std::string(kScreenshotPattern)); - FilePath screenshot = screenshots.Next(); - FilePath latest(""); - time_t last_mtime = 0; - while (!screenshot.empty()) { - file_util::FileEnumerator::FindInfo info; - screenshots.GetFindInfo(&info); - if (info.stat.st_mtime > last_mtime) { - last_mtime = info.stat.st_mtime; - latest = screenshot; - } - screenshot = screenshots.Next(); - } - - if (!file_util::ReadFileToString(latest, image_str_)) - *image_str_ = ""; - task_waitable_->Signal(); - } - private: - std::string* image_str_; - base::WaitableEvent* task_waitable_; -}; -#endif - -bool GetLastScreenshot(std::string* image_str) { -#if defined(OS_CHROMEOS) - base::WaitableEvent task_waitable(true, false); - ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, - new LastScreenshotTask(image_str, &task_waitable)); - task_waitable.Wait(); - if (*image_str == "") - return false; - else - return true; -#else - return false; -#endif -} - -} // namespace - -namespace browser { - -// Global "display this dialog" function declared in browser_dialogs.h. -void ShowBugReportView(views::Window* parent, - Profile* profile, - TabContents* tab) { - BugReportView* view = new BugReportView(profile, tab); - - // Get the size of the parent window to capture screenshot dimensions - gfx::Rect screen_size = parent->GetBounds(); - view->set_screen_size(screen_size); - - // Grab an exact snapshot of the window that the user is seeing (i.e. as - // rendered--do not re-render, and include windowed plugins). - std::vector<unsigned char> *screenshot_png = new std::vector<unsigned char>; - -#if defined(OS_LINUX) - x11_util::GrabWindowSnapshot(parent->GetNativeWindow(), screenshot_png); -#else - win_util::GrabWindowSnapshot(parent->GetNativeWindow(), screenshot_png); -#endif - - // The BugReportView takes ownership of the image data, and will dispose of - // it in its destructor - view->set_captured_image(screenshot_png); - -#if defined(OS_CHROMEOS) - // Get last screenshot taken - std::string image_str; - bool have_last_image = false; - if (GetLastScreenshot(&image_str)) { - // reuse screenshot_png; previous pointer now owned by BugReportView - screenshot_png = new std::vector<unsigned char>(image_str.begin(), - image_str.end()); - have_last_image = true; - } else { - // else set it to be an empty vector - screenshot_png = new std::vector<unsigned char>; - } - view->set_last_image(screenshot_png); - - // Create and show the dialog - views::Window::CreateChromeWindow(parent->GetNativeWindow(), gfx::Rect(), - view)->Show(); - if (!have_last_image) - view->DisableLastImageRadio(); -#endif -} - -} // namespace browser - -// BugReportView - create and submit a bug report from the user. -// This is separate from crash reporting, which is handled by Breakpad. -BugReportView::BugReportView(Profile* profile, TabContents* tab) - : include_page_source_checkbox_(NULL), - include_page_image_checkbox_(NULL), - profile_(profile), - tab_(tab), - problem_type_(0) { - DCHECK(profile); - SetupControl(); - - // We want to use the URL of the current committed entry (the current URL may - // actually be the pending one). - if (tab->controller().GetActiveEntry()) { - page_url_text_->SetText(UTF8ToUTF16( - tab->controller().GetActiveEntry()->url().spec())); - } - -#if defined(OS_CHROMEOS) - // Get and set the gaia e-mail - chromeos::UserManager* manager = chromeos::UserManager::Get(); - if (!manager) { - user_email_text_->SetText(UTF8ToUTF16(std::string(""))); - } else { - const std::string& email = manager->logged_in_user().email(); - user_email_text_->SetText(UTF8ToUTF16(email)); - if (!email.empty()) - user_email_text_->SetEnabled(false); - } -#endif - - // Retrieve the application version info. - scoped_ptr<FileVersionInfo> version_info(chrome::GetChromeVersionInfo()); - if (version_info.get()) { - version_ = version_info->product_name() + L" - " + - version_info->file_version() + - L" (" + version_info->last_change() + L")"; - } - - - FilePath tmpfilename; - -#if defined(OS_CHROMEOS) - chromeos::SyslogsLibrary* syslogs_lib = - chromeos::CrosLibrary::Get()->GetSyslogsLibrary(); - if (syslogs_lib) { - sys_info_.reset(syslogs_lib->GetSyslogs(&tmpfilename)); - } -#endif -} - -BugReportView::~BugReportView() { -} - -void BugReportView::SetupControl() { - bug_type_model_.reset(new BugReportComboBoxModel); - - // Adds all controls. - bug_type_label_ = new views::Label( - l10n_util::GetString(IDS_BUGREPORT_BUG_TYPE)); - bug_type_combo_ = new views::Combobox(bug_type_model_.get()); - bug_type_combo_->set_listener(this); - bug_type_combo_->SetAccessibleName(bug_type_label_->GetText()); - - page_title_label_ = new views::Label( - l10n_util::GetString(IDS_BUGREPORT_REPORT_PAGE_TITLE)); - page_title_text_ = new views::Label(UTF16ToWideHack(tab_->GetTitle())); - page_url_label_ = new views::Label( - l10n_util::GetString(IDS_BUGREPORT_REPORT_URL_LABEL)); - // page_url_text_'s text (if any) is filled in after dialog creation. - page_url_text_ = new views::Textfield; - page_url_text_->SetController(this); - page_url_text_->SetAccessibleName(page_url_label_->GetText()); - -#if defined(OS_CHROMEOS) - user_email_label_ = new views::Label( - l10n_util::GetString(IDS_BUGREPORT_USER_EMAIL_LABEL)); - // user_email_text_'s text (if any) is filled in after dialog creation. - user_email_text_ = new views::Textfield; - user_email_text_->SetController(this); - user_email_text_->SetAccessibleName(user_email_label_->GetText()); -#endif - - description_label_ = new views::Label( - l10n_util::GetString(IDS_BUGREPORT_DESCRIPTION_LABEL)); - description_text_ = - new views::Textfield(views::Textfield::STYLE_MULTILINE); - description_text_->SetHeightInLines(kDescriptionLines); - description_text_->SetAccessibleName(description_label_->GetText()); - - include_page_source_checkbox_ = new views::Checkbox( - l10n_util::GetString(IDS_BUGREPORT_INCLUDE_PAGE_SOURCE_CHKBOX)); - include_page_source_checkbox_->SetChecked(true); - -#if defined(OS_CHROMEOS) - include_last_screen_image_radio_ = new views::RadioButton( - l10n_util::GetString(IDS_BUGREPORT_INCLUDE_LAST_SCREEN_IMAGE), - kScreenImageRadioGroup); - - include_new_screen_image_radio_ = new views::RadioButton( - l10n_util::GetString(IDS_BUGREPORT_INCLUDE_NEW_SCREEN_IMAGE), - kScreenImageRadioGroup); - - include_no_screen_image_radio_ = new views::RadioButton( - l10n_util::GetString(IDS_BUGREPORT_INCLUDE_NO_SCREEN_IMAGE), - kScreenImageRadioGroup); - - system_information_url_control_ = new views::Link( - l10n_util::GetString(IDS_BUGREPORT_SYSTEM_INFORMATION_URL_TEXT)); - system_information_url_control_->SetController(this); - - include_new_screen_image_radio_->SetChecked(true); -#endif - include_page_image_checkbox_ = new views::Checkbox( - l10n_util::GetString(IDS_BUGREPORT_INCLUDE_PAGE_IMAGE_CHKBOX)); - include_page_image_checkbox_->SetChecked(true); - - // Arranges controls by using GridLayout. - const int column_set_id = 0; - GridLayout* layout = CreatePanelGridLayout(this); - SetLayoutManager(layout); - ColumnSet* column_set = layout->AddColumnSet(column_set_id); - column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 0, - GridLayout::USE_PREF, 0, 0); - column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing * 2); - column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, - GridLayout::USE_PREF, 0, 0); - - // Page Title and text. - layout->StartRow(0, column_set_id); - layout->AddView(page_title_label_); - layout->AddView(page_title_text_, 1, 1, GridLayout::LEADING, - GridLayout::FILL); - layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); - - // Bug type and combo box. - layout->StartRow(0, column_set_id); - layout->AddView(bug_type_label_, 1, 1, GridLayout::LEADING, GridLayout::FILL); - layout->AddView(bug_type_combo_); - layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); - - // Page URL and text field. - layout->StartRow(0, column_set_id); - layout->AddView(page_url_label_); - layout->AddView(page_url_text_); - layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); - - // Description label and text field. - layout->StartRow(0, column_set_id); - layout->AddView(description_label_, 1, 1, GridLayout::LEADING, - GridLayout::LEADING); - layout->AddView(description_text_, 1, 1, GridLayout::FILL, - GridLayout::LEADING); -#if defined(OS_CHROMEOS) - layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); - // Page URL and text field. - layout->StartRow(0, column_set_id); - layout->AddView(user_email_label_); - layout->AddView(user_email_text_); -#endif - layout->AddPaddingRow(0, kUnrelatedControlVerticalSpacing); - - // Checkboxes. - // The include page source checkbox is hidden until we can make it work. - // layout->StartRow(0, column_set_id); - // layout->SkipColumns(1); - // layout->AddView(include_page_source_checkbox_); - // layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); - layout->StartRow(0, column_set_id); - layout->SkipColumns(1); -#if defined(OS_CHROMEOS) - // Radio boxes to select last screen shot or, - - // new screenshot - layout->AddView(include_new_screen_image_radio_); - layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); - // last screenshot taken - layout->StartRow(0, column_set_id); - layout->SkipColumns(1); - layout->AddView(include_last_screen_image_radio_); - layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); - // no screenshot - layout->StartRow(0, column_set_id); - layout->SkipColumns(1); - layout->AddView(include_no_screen_image_radio_); - layout->AddPaddingRow(0, kUnrelatedControlVerticalSpacing); - - layout->StartRow(0, column_set_id); - layout->SkipColumns(1); - layout->AddView(system_information_url_control_, 1, 1, GridLayout::LEADING, - GridLayout::CENTER); -#else - if (include_page_image_checkbox_) { - layout->StartRow(0, column_set_id); - layout->SkipColumns(1); - layout->AddView(include_page_image_checkbox_); - } -#endif - - layout->AddPaddingRow(0, kUnrelatedControlVerticalSpacing); -} - -gfx::Size BugReportView::GetPreferredSize() { - gfx::Size size = views::Window::GetLocalizedContentsSize( - IDS_BUGREPORT_DIALOG_WIDTH_CHARS, -#if defined(OS_CHROMEOS) - IDS_CHROMEOS_BUGREPORT_DIALOG_HEIGHT_LINES); -#else - IDS_BUGREPORT_DIALOG_HEIGHT_LINES); -#endif - return size; -} - -void BugReportView::UpdateReportingControls(bool is_phishing_report) { - // page source, screen/page images, system information - // are not needed if it's a phishing report - - include_page_source_checkbox_->SetEnabled(!is_phishing_report); - include_page_source_checkbox_->SetChecked(!is_phishing_report); - -#if defined(OS_CHROMEOS) - include_new_screen_image_radio_->SetEnabled(!is_phishing_report); - if (!last_image_->empty()) - include_last_screen_image_radio_->SetEnabled(!is_phishing_report); - include_no_screen_image_radio_->SetEnabled(!is_phishing_report); -#else - if (include_page_image_checkbox_) { - include_page_image_checkbox_->SetEnabled(!is_phishing_report); - include_page_image_checkbox_->SetChecked(!is_phishing_report); - } -#endif -} - -void BugReportView::ItemChanged(views::Combobox* combobox, - int prev_index, - int new_index) { - if (new_index == prev_index) - return; - - problem_type_ = new_index; - bool is_phishing_report = new_index == BugReportUtil::PHISHING_PAGE; - - description_text_->SetEnabled(!is_phishing_report); - description_text_->SetReadOnly(is_phishing_report); - if (is_phishing_report) { - old_report_text_ = UTF16ToWide(description_text_->text()); - description_text_->SetText(string16()); - } else if (!old_report_text_.empty()) { - description_text_->SetText(WideToUTF16Hack(old_report_text_)); - old_report_text_.clear(); - } - - UpdateReportingControls(is_phishing_report); - GetDialogClientView()->UpdateDialogButtons(); -} - -void BugReportView::ContentsChanged(views::Textfield* sender, - const string16& new_contents) { -} - -bool BugReportView::HandleKeystroke(views::Textfield* sender, - const views::Textfield::Keystroke& key) { - return false; -} - -std::wstring BugReportView::GetDialogButtonLabel( - MessageBoxFlags::DialogButton button) const { - if (button == MessageBoxFlags::DIALOGBUTTON_OK) { - if (problem_type_ == BugReportUtil::PHISHING_PAGE) - return l10n_util::GetString(IDS_BUGREPORT_SEND_PHISHING_REPORT); - else - return l10n_util::GetString(IDS_BUGREPORT_SEND_REPORT); - } else { - return std::wstring(); - } -} - -int BugReportView::GetDefaultDialogButton() const { - return MessageBoxFlags::DIALOGBUTTON_NONE; -} - -bool BugReportView::CanResize() const { - return false; -} - -bool BugReportView::CanMaximize() const { - return false; -} - -bool BugReportView::IsAlwaysOnTop() const { - return false; -} - -bool BugReportView::HasAlwaysOnTopMenu() const { - return false; -} - -bool BugReportView::IsModal() const { - return true; -} - -std::wstring BugReportView::GetWindowTitle() const { - return l10n_util::GetString(IDS_BUGREPORT_TITLE); -} - - -bool BugReportView::Accept() { - if (IsDialogButtonEnabled(MessageBoxFlags::DIALOGBUTTON_OK)) { - if (problem_type_ == BugReportUtil::PHISHING_PAGE) { - BugReportUtil::ReportPhishing(tab_, - UTF16ToUTF8(page_url_text_->text())); - } else { - char* image_data = NULL; - size_t image_data_size = 0; -#if defined(OS_CHROMEOS) - if (include_new_screen_image_radio_->checked() && - !captured_image_->empty()) { - image_data = reinterpret_cast<char *>(&captured_image_->front()); - image_data_size = captured_image_->size(); - } else if (include_last_screen_image_radio_->checked() && - !last_image_->empty()) { - image_data = reinterpret_cast<char *>(&last_image_->front()); - image_data_size = last_image_->size(); - } -#else - if (include_page_image_checkbox_->checked() && captured_image_.get() && - !captured_image_->empty()) { - image_data = reinterpret_cast<char *>(&captured_image_->front()); - image_data_size = captured_image_->size(); - } -#endif -#if defined(OS_CHROMEOS) - BugReportUtil::SendReport(profile_, - WideToUTF8(page_title_text_->GetText()), - problem_type_, - UTF16ToUTF8(page_url_text_->text()), - UTF16ToUTF8(user_email_text_->text()), - UTF16ToUTF8(description_text_->text()), - image_data, image_data_size, - screen_size_.width(), screen_size_.height(), - WideToUTF8(bug_type_combo_->model()->GetItemAt(problem_type_)), - sys_info_.get()); -#else - BugReportUtil::SendReport(profile_, - WideToUTF8(page_title_text_->GetText()), - problem_type_, - UTF16ToUTF8(page_url_text_->text()), - std::string(), - UTF16ToUTF8(description_text_->text()), - image_data, image_data_size, - screen_size_.width(), screen_size_.height()); -#endif - } - } - return true; -} - -#if defined(OS_CHROMEOS) -void BugReportView::LinkActivated(views::Link* source, - int event_flags) { - GURL url; - if (source == system_information_url_control_) { - url = GURL(chrome::kAboutSystemURL); - } else { - NOTREACHED() << "Unknown link source"; - return; - } - - Browser* browser = BrowserList::GetLastActive(); - if (browser) - browser->OpenURL(url, GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK); -} -#endif - - -views::View* BugReportView::GetContentsView() { - return this; -} diff --git a/chrome/browser/views/bug_report_view.h b/chrome/browser/views/bug_report_view.h deleted file mode 100644 index da9fe41..0000000 --- a/chrome/browser/views/bug_report_view.h +++ /dev/null @@ -1,173 +0,0 @@ -// 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_BUG_REPORT_VIEW_H_ -#define CHROME_BROWSER_VIEWS_BUG_REPORT_VIEW_H_ -#pragma once - -#include "chrome/common/net/url_fetcher.h" -#include "gfx/rect.h" -#include "googleurl/src/gurl.h" -#include "views/controls/button/radio_button.h" -#include "views/controls/combobox/combobox.h" -#include "views/controls/textfield/textfield.h" -#include "views/controls/link.h" -#include "views/controls/image_view.h" -#include "views/view.h" -#include "views/window/dialog_delegate.h" - -#if defined(OS_CHROMEOS) -#include "chrome/browser/chromeos/cros/syslogs_library.h" -#include "chrome/browser/chromeos/cros/cros_library.h" -#endif - -namespace views { -class Checkbox; -class Label; -class Throbber; -class Window; -class RadioButton; -class Link; -} - -class Profile; -class TabContents; -class BugReportComboBoxModel; - -// BugReportView draws the dialog that allows the user to report a -// bug in rendering a particular page (note: this is not a crash -// report, which are handled separately by Breakpad). It packages -// up the URL, a text description, system information and optionally -// a screenshot; then it submits the info through https to the google -// feedback chrome end-point. -// -// Note: This UI is being used for the Chrome OS dogfood release only -// In the very next iteration, this will be replaced by a HTML -// based UI, which will be common for all platforms -class BugReportView : public views::View, - public views::DialogDelegate, - public views::Combobox::Listener, -#if defined(OS_CHROMEOS) - public views::LinkController, -#endif - public views::Textfield::Controller { - public: - BugReportView(Profile* profile, TabContents* tab); - virtual ~BugReportView(); - - // NOTE: set_captured_image takes ownership of the vector - void set_captured_image(std::vector<unsigned char>* png_data) { - captured_image_.reset(png_data); - } - - void set_screen_size(const gfx::Rect& screen_size) { - screen_size_ = screen_size; - } - - // Set all additional reporting controls to disabled - // if phishing report - void UpdateReportingControls(bool is_phishing_report); - - // Overridden from views::View: - virtual gfx::Size GetPreferredSize(); - - // views::Textfield::Controller implementation: - virtual void ContentsChanged(views::Textfield* sender, - const string16& new_contents); - virtual bool HandleKeystroke(views::Textfield* sender, - const views::Textfield::Keystroke& key); - - // views::Combobox::Listener implementation: - virtual void ItemChanged(views::Combobox* combobox, int prev_index, - int new_index); - -#if defined(OS_CHROMEOS) - // Overridden from views::LinkController: - virtual void LinkActivated(views::Link* source, int event_flags); - - // Disable the include last image radio control - void DisableLastImageRadio() { - include_last_screen_image_radio_->SetEnabled(false); - } - - // NOTE: set_last_image takes ownership of the vector - void set_last_image(std::vector<unsigned char>* png_data) { - last_image_.reset(png_data); - } -#endif - - // Overridden from views::DialogDelegate: - virtual std::wstring GetDialogButtonLabel( - MessageBoxFlags::DialogButton button) const; - virtual int GetDefaultDialogButton() const; - virtual bool CanResize() const; - virtual bool CanMaximize() const; - virtual bool IsAlwaysOnTop() const; - virtual bool HasAlwaysOnTopMenu() const; - virtual bool IsModal() const; - virtual std::wstring GetWindowTitle() const; - virtual bool Accept(); - virtual views::View* GetContentsView(); - - private: - class PostCleanup; - - // Set OS Version information in a string (maj.minor.build SP) - void SetOSVersion(std::string *os_version); - - // Initializes the controls on the dialog. - void SetupControl(); - // helper function to create a MIME part boundary string - void CreateMimeBoundary(std::string *out); - // Sends the data via an HTTP POST - void SendReport(); - - // Redirects the user to Google's phishing reporting page. - void ReportPhishing(); - - views::Label* bug_type_label_; - views::Combobox* bug_type_combo_; - views::Label* page_title_label_; - views::Label* page_title_text_; - views::Label* page_url_label_; - views::Textfield* page_url_text_; - views::Label* description_label_; - views::Textfield* description_text_; - views::Checkbox* include_page_source_checkbox_; -#if defined(OS_CHROMEOS) - views::Label* user_email_label_; - views::Textfield* user_email_text_; - views::RadioButton* include_new_screen_image_radio_; - views::RadioButton* include_last_screen_image_radio_; - views::RadioButton* include_no_screen_image_radio_; - views::Link* system_information_url_control_; - - scoped_ptr<chromeos::LogDictionaryType> sys_info_; - scoped_ptr< std::vector<unsigned char> > last_image_; -#endif - views::Checkbox* include_page_image_checkbox_; - - - scoped_ptr<BugReportComboBoxModel> bug_type_model_; - - Profile* profile_; - - std::wstring version_; - gfx::Rect screen_size_; - scoped_ptr< std::vector<unsigned char> > captured_image_; - - TabContents* tab_; - - // Used to distinguish the report type: Phishing or other. - int problem_type_; - - // Save the description the user types in when we clear the dialog for the - // phishing option. If the user changes the report type back, we reinstate - // their original text so they don't have to type it again. - std::wstring old_report_text_; - - DISALLOW_COPY_AND_ASSIGN(BugReportView); -}; - -#endif // CHROME_BROWSER_VIEWS_BUG_REPORT_VIEW_H_ diff --git a/chrome/browser/views/frame/browser_view.cc b/chrome/browser/views/frame/browser_view.cc index 75c73ed..1e32b5c 100644 --- a/chrome/browser/views/frame/browser_view.cc +++ b/chrome/browser/views/frame/browser_view.cc @@ -20,10 +20,12 @@ #include "chrome/browser/autocomplete/autocomplete_popup_view.h" #include "chrome/browser/automation/ui_controls.h" #include "chrome/browser/bookmarks/bookmark_utils.h" +#include "chrome/browser/browser.h" #include "chrome/browser/browser_list.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_theme_provider.h" #include "chrome/browser/debugger/devtools_window.h" +#include "chrome/browser/dom_ui/bug_report_ui.h" #include "chrome/browser/download/download_manager.h" #include "chrome/browser/ntp_background_util.h" #include "chrome/browser/page_info_window.h" @@ -54,6 +56,7 @@ #include "chrome/common/native_window_notification_source.h" #include "chrome/common/notification_service.h" #include "chrome/common/pref_names.h" +#include "chrome/common/url_constants.h" #include "gfx/canvas_skia.h" #include "grit/app_resources.h" #include "grit/chromium_strings.h" @@ -1115,11 +1118,7 @@ DownloadShelf* BrowserView::GetDownloadShelf() { } void BrowserView::ShowReportBugDialog() { - // Retrieve the URL for the current tab (if any) and tell the BugReportView - TabContents* current_tab = browser_->GetSelectedTabContents(); - if (!current_tab) - return; - browser::ShowBugReportView(GetWindow(), browser_->profile(), current_tab); + browser::ShowHtmlBugReportView(GetWindow(), browser_.get()); } void BrowserView::ShowClearBrowsingDataDialog() { diff --git a/chrome/browser/wrench_menu_model.cc b/chrome/browser/wrench_menu_model.cc index 8dd51e4..ffd1d17 100644 --- a/chrome/browser/wrench_menu_model.cc +++ b/chrome/browser/wrench_menu_model.cc @@ -147,6 +147,8 @@ void ToolsMenuModel::Build(Browser* browser) { AddItemWithStringId(IDC_CLEAR_BROWSING_DATA, IDS_CLEAR_BROWSING_DATA); AddSeparator(); + AddItemWithStringId(IDC_REPORT_BUG, IDS_REPORT_BUG); + AddSeparator(); encoding_menu_model_.reset(new EncodingMenuModel(browser)); AddSubMenuWithStringId(IDC_ENCODING_MENU, IDS_ENCODING_MENU, diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 1d09ef9..59468ab 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -327,8 +327,8 @@ 'browser/bug_report_util.h', # TODO(rkc): Find a better way to include these files '<(protoc_out_dir)/chrome/browser/userfeedback/proto/annotations.pb.cc', + '<(protoc_out_dir)/chrome/browser/userfeedback/proto/chrome.pb.cc', '<(protoc_out_dir)/chrome/browser/userfeedback/proto/common.pb.cc', - '<(protoc_out_dir)/chrome/browser/userfeedback/proto/config.pb.cc', '<(protoc_out_dir)/chrome/browser/userfeedback/proto/dom.pb.cc', '<(protoc_out_dir)/chrome/browser/userfeedback/proto/extension.pb.cc', '<(protoc_out_dir)/chrome/browser/userfeedback/proto/math.pb.cc', @@ -1140,6 +1140,8 @@ 'browser/dom_ui/autofill_options_handler.h', 'browser/dom_ui/bookmarks_ui.cc', 'browser/dom_ui/bookmarks_ui.h', + 'browser/dom_ui/bug_report_ui.cc', + 'browser/dom_ui/bug_report_ui.h', 'browser/dom_ui/chrome_url_data_manager.cc', 'browser/dom_ui/chrome_url_data_manager.h', 'browser/dom_ui/about_page_handler.cc', @@ -1184,6 +1186,8 @@ 'browser/dom_ui/dom_ui_factory.h', 'browser/dom_ui/dom_ui_favicon_source.cc', 'browser/dom_ui/dom_ui_favicon_source.h', + 'browser/dom_ui/dom_ui_screenshot_source.cc', + 'browser/dom_ui/dom_ui_screenshot_source.h', 'browser/dom_ui/dom_ui_theme_source.cc', 'browser/dom_ui/dom_ui_theme_source.h', 'browser/dom_ui/dom_ui_thumbnail_source.cc', @@ -2674,8 +2678,6 @@ 'browser/views/browser_dialogs.h', 'browser/views/bubble_border.cc', 'browser/views/bubble_border.h', - 'browser/views/bug_report_view.cc', - 'browser/views/bug_report_view.h', 'browser/views/certificate_viewer_win.cc', 'browser/views/chrome_views_delegate.cc', 'browser/views/chrome_views_delegate.h', @@ -3395,8 +3397,6 @@ ['include', '^browser/views/browser_bubble.h'], ['include', '^browser/views/bubble_border.cc'], ['include', '^browser/views/bubble_border.h'], - ['include', '^browser/views/bug_report_view.cc'], - ['include', '^browser/views/bug_report_view.h'], ['include', '^browser/views/chrome_views_delegate.cc'], ['include', '^browser/views/clear_browsing_data.cc'], ['include', '^browser/views/clear_browsing_data.h'], @@ -3801,8 +3801,8 @@ 'type': 'none', 'sources': [ 'browser/userfeedback/proto/annotations.proto', + 'browser/userfeedback/proto/chrome.proto', 'browser/userfeedback/proto/common.proto', - 'browser/userfeedback/proto/config.proto', 'browser/userfeedback/proto/dom.proto', 'browser/userfeedback/proto/extension.proto', 'browser/userfeedback/proto/math.proto', diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index bc00a4ef..562e7af4 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -517,6 +517,9 @@ const char kExtensionProcess[] = "extension"; // Frequency in seconds for Extensions auto-update. const char kExtensionsUpdateFrequency[] = "extensions-update-frequency"; +// Alternative feedback server to use when submitting user feedback +const char kFeedbackServer[] = "feedback-server"; + // The file descriptor limit is set to the value of this switch, subject to the // OS hard limits. Useful for testing that file descriptor exhaustion is handled // gracefully. diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 6f0ce67..8b16067 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -163,6 +163,7 @@ extern const char kExperimentalSpellcheckerFeatures[]; extern const char kExplicitlyAllowedPorts[]; extern const char kExtensionProcess[]; extern const char kExtensionsUpdateFrequency[]; +extern const char kFeedbackServer[]; extern const char kFileDescriptorLimit[]; extern const char kFirstRun[]; extern const char kForceFieldTestNameAndValue[]; diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc index 5578981..14c1ea3 100644 --- a/chrome/common/url_constants.cc +++ b/chrome/common/url_constants.cc @@ -65,6 +65,7 @@ const char kAboutBrowserCrash[] = "about:inducebrowsercrashforrealz"; const char kChromeUIAboutURL[] = "chrome://options/about"; const char kChromeUIAppLauncherURL[] = "chrome://newtab/#mode=app-launcher"; const char kChromeUIBookmarksURL[] = "chrome://bookmarks/"; +const char kChromeUIBugReportURL[] = "chrome://bugreport/"; const char kChromeUIDevToolsURL[] = "chrome://devtools/"; const char kChromeUIDownloadsURL[] = "chrome://downloads/"; const char kChromeUIExtensionsURL[] = "chrome://extensions/"; @@ -82,6 +83,7 @@ const char kChromeUIRegisterPageURL[] = "chrome://register/"; const char kChromeUISlideshowURL[] = "chrome://slideshow/"; const char kChromeUIBookmarksHost[] = "bookmarks"; +const char kChromeUIBugReportHost[] = "bugreport"; const char kChromeUIDevToolsHost[] = "devtools"; const char kChromeUIDialogHost[] = "dialog"; const char kChromeUIDownloadsHost[] = "downloads"; @@ -104,6 +106,7 @@ const char kChromeUISlideshowHost[] = "slideshow"; const char kChromeUISyncResourcesHost[] = "syncresources"; const char kChromeUIRemotingResourcesHost[] = "remotingresources"; const char kChromeUIThemePath[] = "theme"; +const char kChromeUIScreenshotPath[] = "screenshots"; const char kChromeUIThumbnailPath[] = "thumb"; const char kAppCacheViewInternalsURL[] = "chrome://appcache-internals/"; diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h index 5834b13..fbaa16d 100644 --- a/chrome/common/url_constants.h +++ b/chrome/common/url_constants.h @@ -58,6 +58,7 @@ extern const char kAboutVersionURL[]; extern const char kChromeUIAboutURL[]; extern const char kChromeUIAppLauncherURL[]; extern const char kChromeUIBookmarksURL[]; +extern const char kChromeUIBugReportURL[]; extern const char kChromeUIDevToolsURL[]; extern const char kChromeUIDownloadsURL[]; extern const char kChromeUIExtensionsURL[]; @@ -77,6 +78,7 @@ extern const char kChromeUISlideshowURL[]; // chrome components of URLs. Should be kept in sync with the full URLs // above. extern const char kChromeUIBookmarksHost[]; +extern const char kChromeUIBugReportHost[]; extern const char kChromeUIDevToolsHost[]; extern const char kChromeUIDialogHost[]; extern const char kChromeUIDownloadsHost[]; @@ -95,6 +97,7 @@ extern const char kChromeUIPrintHost[]; extern const char kChromeUIRegisterPageHost[]; extern const char kChromeUIRemotingHost[]; extern const char kChromeUIResourcesHost[]; +extern const char kChromeUIScreenshotPath[]; extern const char kChromeUISlideshowHost[]; extern const char kChromeUISyncResourcesHost[]; extern const char kChromeUIRemotingResourcesHost[]; |