Bug 358082 - Improve Mac Crashreporter UI, patch by dcamp, r=luser+me

This commit is contained in:
benjamin@smedbergs.us 2007-05-29 03:54:26 -07:00
Родитель a6cd41a0b1
Коммит a446792916
14 изменённых файлов: 1050 добавлений и 418 удалений

Просмотреть файл

@ -39,8 +39,11 @@
#include "crashreporter.h"
#ifdef _MSC_VER
// Disable exception handler warnings.
#pragma warning( disable : 4530 )
# pragma warning( disable : 4530 )
#endif
#include <fstream>
#include <sstream>
@ -48,8 +51,10 @@ using std::string;
using std::istream;
using std::ifstream;
using std::istringstream;
using std::ostringstream;
using std::ostream;
using std::ofstream;
using std::vector;
StringTable gStrings;
int gArgc;
@ -61,7 +66,30 @@ static string gSettingsPath;
static string kExtraDataExtension = ".extra";
static bool ReadStrings(istream &in, StringTable &strings)
static string Unescape(const string& str)
{
string ret;
for (string::const_iterator iter = str.begin();
iter != str.end();
iter++) {
if (*iter == '\\') {
iter++;
if (*iter == '\\'){
ret.push_back('\\');
} else if (*iter == 'n') {
ret.push_back('\n');
} else if (*iter == 't') {
ret.push_back('\t');
}
} else {
ret.push_back(*iter);
}
}
return ret;
}
static bool ReadStrings(istream& in, StringTable& strings, bool unescape)
{
string currentSection;
while (!in.eof()) {
@ -72,6 +100,8 @@ static bool ReadStrings(istream &in, StringTable &strings)
string key, value;
key = line.substr(0, sep);
value = line.substr(sep + 1);
if (unescape)
value = Unescape(value);
strings[key] = value;
}
}
@ -80,12 +110,13 @@ static bool ReadStrings(istream &in, StringTable &strings)
}
static bool ReadStringsFromFile(const string& path,
StringTable& strings)
StringTable& strings,
bool unescape)
{
ifstream f(path.c_str(), std::ios::in);
if (!f.is_open()) return false;
return ReadStrings(f, strings);
return ReadStrings(f, strings, unescape);
}
static bool ReadConfig()
@ -94,7 +125,7 @@ static bool ReadConfig()
if (!UIGetIniPath(iniPath))
return false;
if (!ReadStringsFromFile(iniPath, gStrings))
if (!ReadStringsFromFile(iniPath, gStrings, true))
return false;
return true;
@ -125,7 +156,6 @@ static bool MoveCrashData(const string& toDir,
string& extrafile)
{
if (!UIEnsurePathExists(toDir)) {
UIError(toDir.c_str());
return false;
}
@ -134,8 +164,6 @@ static bool MoveCrashData(const string& toDir,
if (!UIMoveFile(dumpfile, newDump) ||
!UIMoveFile(extrafile, newExtra)) {
UIError(dumpfile.c_str());
UIError(newDump.c_str());
return false;
}
@ -149,7 +177,7 @@ static bool AddSubmittedReport(const string& serverResponse)
{
StringTable responseItems;
istringstream in(serverResponse);
ReadStrings(in, responseItems);
ReadStrings(in, responseItems, false);
if (responseItems.find("CrashID") == responseItems.end())
return false;
@ -190,10 +218,13 @@ bool CrashReporterSendCompleted(bool success,
const string& serverResponse)
{
if (success) {
if (!gDumpFile.empty())
UIDeleteFile(gDumpFile);
if (!gExtraFile.empty())
UIDeleteFile(gExtraFile);
const char* noDelete = getenv("MOZ_CRASHREPORTER_NO_DELETE_DUMP");
if (!noDelete || *noDelete == '\0') {
if (!gDumpFile.empty())
UIDeleteFile(gDumpFile);
if (!gExtraFile.empty())
UIDeleteFile(gExtraFile);
}
return AddSubmittedReport(serverResponse);
}
@ -228,7 +259,7 @@ int main(int argc, const char** argv)
}
StringTable queryParameters;
if (!ReadStringsFromFile(gExtraFile, queryParameters)) {
if (!ReadStringsFromFile(gExtraFile, queryParameters, true)) {
UIError("Couldn't read extra data");
return 0;
}
@ -260,6 +291,19 @@ int main(int argc, const char** argv)
// we don't need to actually send this
queryParameters.erase("ServerURL");
vector<string> restartArgs;
ostringstream paramName;
int i = 0;
paramName << "MOZ_CRASHREPORTER_RESTART_ARG_" << i++;
const char *param = getenv(paramName.str().c_str());
while (param && *param) {
restartArgs.push_back(param);
paramName << "MOZ_CRASHREPORTER_RESTART_ARG_" << i++;
param = getenv(paramName.str().c_str());
};
// allow override of the server url via environment variable
//XXX: remove this in the far future when our robot
// masters force everyone to use XULRunner
@ -268,7 +312,29 @@ int main(int argc, const char** argv)
sendURL = urlEnv;
}
UIShowCrashUI(gDumpFile, queryParameters, sendURL);
// rewrite some UI strings with the values from the query parameters
char buf[4096];
UI_SNPRINTF(buf, sizeof(buf),
gStrings[ST_RESTART].c_str(),
product.c_str());
gStrings[ST_RESTART] = buf;
UI_SNPRINTF(buf, sizeof(buf),
gStrings[ST_CRASHREPORTERDESCRIPTION].c_str(),
product.c_str());
gStrings[ST_CRASHREPORTERDESCRIPTION] = buf;
UI_SNPRINTF(buf, sizeof(buf),
gStrings[ST_CHECKSUBMIT].c_str(),
vendor.empty() ? "Mozilla" : vendor.c_str());
gStrings[ST_CHECKSUBMIT] = buf;
UI_SNPRINTF(buf, sizeof(buf),
gStrings[ST_CRASHREPORTERTITLE].c_str(),
vendor.empty() ? "Mozilla" : vendor.c_str());
gStrings[ST_CRASHREPORTERTITLE] = buf;
UIShowCrashUI(gDumpFile, queryParameters, sendURL, restartArgs);
}
UIShutdown();

Просмотреть файл

@ -1,11 +1,15 @@
#ifndef CRASHREPORTER_H__
#define CRASHREPORTER_H__
#pragma warning( push )
#ifdef _MSC_VER
# pragma warning( push )
// Disable exception handler warnings.
#pragma warning( disable : 4530 )
# pragma warning( disable : 4530 )
#endif
#include <string>
#include <map>
#include <vector>
#include <stdlib.h>
#include <stdio.h>
@ -24,17 +28,16 @@
typedef std::map<std::string, std::string> StringTable;
#define ST_OK "Ok"
#define ST_CANCEL "Cancel"
#define ST_SEND "Send"
#define ST_DONTSEND "DontSend"
#define ST_CLOSE "Close"
#define ST_CRASHREPORTERTITLE "CrashReporterTitle"
#define ST_CRASHREPORTERHEADER "CrashReporterHeader"
#define ST_CRASHREPORTERDESCRIPTION "CrashReporterDescription"
#define ST_RADIOENABLE "RadioEnable"
#define ST_RADIODISABLE "RadioDisable"
#define ST_SENDTITLE "SendTitle"
#define ST_SUBMITSUCCESS "SubmitSuccess"
#define ST_CRASHREPORTERDEFAULT "CrashReporterDefault"
#define ST_VIEWREPORT "ViewReport"
#define ST_EXTRAREPORTINFO "ExtraReportInfo"
#define ST_CHECKSUBMIT "CheckSubmit"
#define ST_CHECKEMAIL "CheckEmail"
#define ST_CLOSE "Close"
#define ST_RESTART "Restart"
#define ST_SUBMITFAILED "SubmitFailed"
//=============================================================================
@ -62,7 +65,8 @@ void UIShowDefaultUI();
// Run the UI for when the app was launched with a dump file
void UIShowCrashUI(const std::string& dumpfile,
const StringTable& queryParameters,
const std::string& sendURL);
const std::string& sendURL,
const std::vector<std::string>& restartArgs);
void UIError(const std::string& message);
@ -74,5 +78,8 @@ bool UIEnsurePathExists(const std::string& path);
bool UIMoveFile(const std::string& oldfile, const std::string& newfile);
bool UIDeleteFile(const std::string& oldfile);
#pragma warning( pop )
#ifdef _MSC_VER
# pragma warning( pop )
#endif
#endif

Просмотреть файл

@ -1,16 +1,15 @@
; This file is in the UTF-8 encoding
[Strings]
Ok=Ok
Cancel=Cancel
Send=Send
DontSend=Don't Send
CrashReporterTitle=%s Crash Reporter
CrashReporterHeader=Crash! Bang! Boom!
CrashReporterDescription=We're sorry, but %s hit an unexpected problem and crashed. We'll try to restore your tabs and windows when it restarts.\n\nTo help us diagnose and repair this problem, you can send us a crash report.
CrashReporterDefault=This application is run after a crash to report the problem to the application vendor. It should not be run directly.
ViewReport=View Report
ExtraReportInfo=This report also contains information about the state of the application when it crashed.
CheckSubmit=Submit crash report to %s
CheckEmail=Email me when the problem is fixed
Close=Close
CrashReporterTitle=Mozilla Crash Reporter
CrashReporterDescription=Crash reporting blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah
RadioEnable=Enable Crash Reporting
RadioDisable=Disable Crash Reporting
SendTitle=Sending Crash Report...
SubmitSuccess=Crash report submitted successfully
Restart=Restart %s
SubmitFailed=Failed to submit crash report
CrashID=Crash ID: %s
CrashDetailsURL=You can view details of this crash at %s

Просмотреть файл

@ -1,124 +1,114 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winresrc.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winresrc.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
IDI_DIALOG ICON "crashreporter.ico"
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_ENABLEDIALOG DIALOGEX 0, 0, 322, 140
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP |
WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Crash Reporter"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CONTROL "",IDC_DESCRIPTIONTEXT,"RichEdit20W",
ES_AUTOHSCROLL | ES_READONLY | WS_BORDER | WS_TABSTOP | ES_MULTILINE,
62,7,179,47
CONTROL "Enable Crash Reporting",IDC_RADIOENABLE,"Button",
BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,73,72,158,13
CONTROL "Disable Crash Reporting",IDC_RADIODISABLE,"Button",
BS_AUTORADIOBUTTON | WS_TABSTOP,73,86,158,13
DEFPUSHBUTTON "OK",IDOK,125,119,50,14,WS_GROUP
END
IDD_SENDDIALOG DIALOGEX 0, 0, 186, 46
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP |
WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Sending Crash Report..."
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
PUSHBUTTON "Cancel",IDCANCEL,67,25,50,14
CONTROL "",IDC_PROGRESS,"msctls_progress32",WS_BORDER,7,7,172,14
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_ENABLEDIALOG, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 315
TOPMARGIN, 7
BOTTOMMARGIN, 133
END
IDD_SENDDIALOG, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 179
TOPMARGIN, 7
BOTTOMMARGIN, 39
END
END
#endif // APSTUDIO_INVOKED
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winresrc.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winresrc.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_DIALOG ICON "crashreporter.ico"
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_SENDDIALOG DIALOGEX 0, 0, 239, 105
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Sending Crash Report..."
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CONTROL "",IDC_DESCRIPTIONTEXT,"RichEdit20A",ES_MULTILINE | ES_READONLY,7,7,226,12,WS_EX_TRANSPARENT
CONTROL "view report",IDC_VIEWREPORTCHECK,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,12,24,54,12
CONTROL "",IDC_VIEWREPORTTEXT,"RichEdit20A",ES_MULTILINE | ES_READONLY | NOT WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_TABSTOP,12,42,222,56
CONTROL "submit a crash report to mozilla",IDC_SUBMITREPORTCHECK,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,42,222,10
CONTROL "email me when the problem is fixed",IDC_EMAILMECHECK,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,54,222,10
EDITTEXT IDC_EMAILTEXT,24,66,208,14,ES_AUTOHSCROLL
PUSHBUTTON "close",IDC_CLOSEBUTTON,111,84,50,14
DEFPUSHBUTTON "restart firefox",IDC_RESTARTBUTTON,165,84,68,14
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_SENDDIALOG, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 232
TOPMARGIN, 7
BOTTOMMARGIN, 98
END
END
#endif // APSTUDIO_INVOKED
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

Просмотреть файл

@ -47,39 +47,48 @@
{
IBOutlet NSWindow* window;
/* Enabled view */
IBOutlet NSView* enableView;
/* Crash reporter view */
IBOutlet NSTextField* headerLabel;
IBOutlet NSTextField* descriptionLabel;
IBOutlet NSButton* disableReportingButton;
IBOutlet NSButton* dontSendButton;
IBOutlet NSButton* sendButton;
/* Upload progress view */
IBOutlet NSView* uploadingView;
IBOutlet NSTextField* progressLabel;
IBOutlet NSProgressIndicator* progressBar;
IBOutlet NSButton* viewReportButton;
IBOutlet NSTextField* viewReportLabel;
IBOutlet NSScrollView* viewReportScrollView;
IBOutlet NSTextView* viewReportTextView;
IBOutlet NSButton* submitReportButton;
IBOutlet NSButton* emailMeButton;
IBOutlet NSTextField* emailText;
IBOutlet NSButton* closeButton;
IBOutlet NSButton* restartButton;
/* Error view */
IBOutlet NSView* errorView;
IBOutlet NSTextField* errorHeaderLabel;
IBOutlet NSTextField* errorLabel;
IBOutlet NSButton* errorCloseButton;
HTTPMultipartUpload *mPost;
}
- (void)showDefaultUI;
- (void)showCrashUI:(const std::string&)dumpfile
queryParameters:(const StringTable&)queryParameters
sendURL:(const std::string&)sendURL;
- (void)showErrorUI:(const std::string&)dumpfile;
- (void)showReportInfo;
- (IBAction)viewReportClicked:(id)sender;
- (IBAction)closeClicked:(id)sender;
- (IBAction)sendClicked:(id)sender;
- (IBAction)closeAndSendClicked:(id)sender;
- (IBAction)restartClicked:(id)sender;
- (IBAction)emailMeClicked:(id)sender;
- (void)setView:(NSWindow *)w newView: (NSView *)v animate: (BOOL) animate;
- (void)controlTextDidChange:(NSNotification *)note;
- (float)setStringFitVertically:(NSControl*)control
string:(NSString*)str
resizeWindow:(BOOL)resizeWindow;
- (void)setView:(NSView*)v animate: (BOOL) animate;
- (void)updateEmail;
- (void)sendReport;
- (bool)setupPost;
- (void)uploadThread:(id)post;
- (void)uploadComplete:(id)data;

Просмотреть файл

@ -45,24 +45,50 @@
#include <fcntl.h>
using std::string;
using std::vector;
static NSAutoreleasePool* gMainPool;
static CrashReporterUI* gUI = 0;
static string gDumpFile;
static StringTable gQueryParameters;
static string gSendURL;
static vector<string> gRestartArgs;
#define NSSTR(s) [NSString stringWithUTF8String:(s).c_str()]
static NSString *
Str(const char* aName)
static NSString* Str(const char* aName)
{
string str = gStrings[aName];
if (str.empty()) str = "?";
return NSSTR(str);
}
static bool RestartApplication()
{
char** argv = reinterpret_cast<char**>(
malloc(sizeof(char*) * (gRestartArgs.size() + 1)));
if (!argv) return false;
unsigned int i;
for (i = 0; i < gRestartArgs.size(); i++) {
argv[i] = (char*)gRestartArgs[i].c_str();
}
argv[i] = 0;
pid_t pid = fork();
if (pid == -1)
return false;
else if (pid == 0) {
(void)execv(argv[0], argv);
_exit(1);
}
free(argv);
return true;
}
@implementation CrashReporterUI
-(void)awakeFromNib
@ -71,22 +97,7 @@ Str(const char* aName)
[window center];
[window setTitle:[[NSBundle mainBundle]
objectForInfoDictionaryKey:@"CFBundleName"]];
[descriptionLabel setStringValue:Str(ST_CRASHREPORTERDESCRIPTION)];
[disableReportingButton setTitle:Str(ST_RADIODISABLE)];
[closeButton setTitle:Str(ST_CLOSE)];
[errorCloseButton setTitle:Str(ST_CLOSE)];
}
-(void)showDefaultUI
{
[dontSendButton setFrame:[sendButton frame]];
[dontSendButton setTitle:Str(ST_CLOSE)];
[dontSendButton setKeyEquivalent:@"\r"];
[sendButton removeFromSuperview];
[window makeKeyAndOrderFront:nil];
objectForInfoDictionaryKey:@"CFBundleName"]];
}
-(void)showCrashUI:(const string&)dumpfile
@ -97,45 +108,197 @@ Str(const char* aName)
gQueryParameters = queryParameters;
gSendURL = sendURL;
[sendButton setTitle:Str(ST_SEND)];
[sendButton setKeyEquivalent:@"\r"];
[dontSendButton setTitle:Str(ST_DONTSEND)];
[headerLabel setStringValue:Str(ST_CRASHREPORTERHEADER)];
[self setStringFitVertically:descriptionLabel
string:Str(ST_CRASHREPORTERDESCRIPTION)
resizeWindow:YES];
[viewReportLabel setStringValue:Str(ST_VIEWREPORT)];
[submitReportButton setTitle:Str(ST_CHECKSUBMIT)];
[emailMeButton setTitle:Str(ST_CHECKEMAIL)];
[closeButton setTitle:Str(ST_CLOSE)];
[viewReportScrollView retain];
[viewReportScrollView removeFromSuperview];
if (gRestartArgs.size() == 0) {
NSRect restartFrame = [restartButton frame];
[restartButton removeFromSuperview];
NSRect closeFrame = [closeButton frame];
closeFrame.origin.x = restartFrame.origin.x +
(restartFrame.size.width - closeFrame.size.width);
[closeButton setFrame: closeFrame];
[closeButton setKeyEquivalent:@"\r"];
} else {
[restartButton setTitle:Str(ST_RESTART)];
[restartButton setKeyEquivalent:@"\r"];
}
[self updateEmail];
[self showReportInfo];
[window makeKeyAndOrderFront:nil];
}
-(void)showErrorUI:(const string&)message
{
[errorLabel setStringValue: NSSTR(message)];
[self setView: errorView animate: NO];
[errorHeaderLabel setStringValue:Str(ST_CRASHREPORTERHEADER)];
[self setStringFitVertically:errorLabel
string:NSSTR(message)
resizeWindow:YES];
[errorCloseButton setTitle:Str(ST_CLOSE)];
[self setView: window newView: errorView animate: NO];
[window makeKeyAndOrderFront:nil];
}
-(void)showReportInfo
{
NSDictionary* boldAttr = [NSDictionary
dictionaryWithObject:[NSFont boldSystemFontOfSize:0]
forKey:NSFontAttributeName];
NSDictionary* normalAttr = [NSDictionary
dictionaryWithObject:[NSFont systemFontOfSize:0]
forKey:NSFontAttributeName];
[viewReportTextView setString:@""];
for (StringTable::iterator iter = gQueryParameters.begin();
iter != gQueryParameters.end();
iter++) {
[[viewReportTextView textStorage]
appendAttributedString: [[NSAttributedString alloc]
initWithString:NSSTR(iter->first + ": ")
attributes:boldAttr]];
[[viewReportTextView textStorage]
appendAttributedString: [[NSAttributedString alloc]
initWithString:NSSTR(iter->second + "\n")
attributes:normalAttr]];
}
[[viewReportTextView textStorage]
appendAttributedString: [[NSAttributedString alloc]
initWithString:NSSTR("\n" + gStrings[ST_EXTRAREPORTINFO])
attributes:normalAttr]];
}
-(IBAction)viewReportClicked:(id)sender
{
NSRect frame = [window frame];
NSRect scrolledFrame = [viewReportScrollView frame];
float delta = scrolledFrame.size.height + 5; // FIXME
if ([viewReportButton state] == NSOnState) {
[[window contentView] addSubview:viewReportScrollView];
} else {
delta = 0 - delta;
}
frame.origin.y -= delta;
frame.size.height += delta;
int buttonMask = [viewReportButton autoresizingMask];
int textMask = [viewReportLabel autoresizingMask];
int reportMask = [viewReportScrollView autoresizingMask];
[viewReportButton setAutoresizingMask:NSViewMinYMargin];
[viewReportLabel setAutoresizingMask:NSViewMinYMargin];
[viewReportScrollView setAutoresizingMask:NSViewMinYMargin];
[window setFrame: frame display: true animate: NO];
if ([viewReportButton state] == NSOffState) {
[viewReportScrollView removeFromSuperview];
}
[viewReportButton setAutoresizingMask:buttonMask];
[viewReportLabel setAutoresizingMask:textMask];
[viewReportScrollView setAutoresizingMask:reportMask];
}
-(IBAction)closeClicked:(id)sender
{
[NSApp terminate: self];
}
-(IBAction)sendClicked:(id)sender
-(IBAction)closeAndSendClicked:(id)sender
{
[self setView: window newView: uploadingView animate: YES];
[progressBar startAnimation: self];
[progressLabel setStringValue:Str(ST_SENDTITLE)];
if (![self setupPost])
[NSApp terminate];
[NSThread detachNewThreadSelector:@selector(uploadThread:)
toTarget:self
withObject:mPost];
if ([submitReportButton state] == NSOnState) {
// Hide the dialog after "closing", but leave it around to coordinate
// with the upload thread
[window orderOut:nil];
[self sendReport];
} else {
[NSApp terminate:self];
}
}
-(void)setView:(NSWindow*)w newView: (NSView*)v animate: (BOOL)animate
-(IBAction)restartClicked:(id)sender
{
NSRect frame = [w frame];
RestartApplication();
if ([submitReportButton state] == NSOnState) {
// Hide the dialog after "closing", but leave it around to coordinate
// with the upload thread
[window orderOut:nil];
[self sendReport];
} else {
[NSApp terminate:self];
}
}
NSRect oldViewFrame = [[w contentView] frame];
-(IBAction)emailMeClicked:(id)sender
{
[self updateEmail];
[self showReportInfo];
}
-(void)controlTextDidChange:(NSNotification *)note
{
// Email text changed, assume they want the "Email me" checkbox
// updated appropriately
if ([[emailText stringValue] length] > 0)
[emailMeButton setState:NSOnState];
else
[emailMeButton setState:NSOffState];
[self updateEmail];
[self showReportInfo];
}
-(float)setStringFitVertically:(NSControl*)control
string:(NSString*)str
resizeWindow:(BOOL)resizeWindow
{
// hack to make the text field grow vertically
NSRect frame = [control frame];
float oldHeight = frame.size.height;
frame.size.height = 10000;
NSSize oldCellSize = [[control cell] cellSizeForBounds: frame];
[control setStringValue: str];
NSSize newCellSize = [[control cell] cellSizeForBounds: frame];
float delta = newCellSize.height - oldCellSize.height;
frame.origin.y -= delta;
frame.size.height = oldHeight + delta;
[control setFrame: frame];
if (resizeWindow) {
NSRect frame = [window frame];
frame.origin.y -= delta;
frame.size.height += delta;
[window setFrame:frame display: true animate: NO];
}
return delta;
}
-(void)setView: (NSView*)v animate: (BOOL)animate
{
NSRect frame = [window frame];
NSRect oldViewFrame = [[window contentView] frame];
NSRect newViewFrame = [v frame];
frame.origin.y += oldViewFrame.size.height - newViewFrame.size.height;
@ -144,8 +307,28 @@ Str(const char* aName)
frame.origin.x += oldViewFrame.size.width - newViewFrame.size.width;
frame.size.width -= oldViewFrame.size.width - newViewFrame.size.width;
[w setContentView: v];
[w setFrame: frame display: true animate: animate];
[window setContentView:v];
[window setFrame:frame display:true animate:animate];
}
-(void)updateEmail
{
if ([emailMeButton state] == NSOnState) {
NSString* email = [emailText stringValue];
gQueryParameters["Email"] = [email UTF8String];
} else {
gQueryParameters.erase("Email");
}
}
-(void)sendReport
{
if (![self setupPost])
[NSApp terminate:self];
[NSThread detachNewThreadSelector:@selector(uploadThread:)
toTarget:self
withObject:mPost];
}
-(bool)setupPost
@ -177,19 +360,14 @@ Str(const char* aName)
-(void)uploadComplete:(id)data
{
[progressBar stopAnimation: self];
NSHTTPURLResponse* response = [mPost response];
NSString* status;
bool success;
string reply;
if (!data || !response || [response statusCode] != 200) {
status = Str(ST_SUBMITFAILED);
success = false;
reply = "";
} else {
status = Str(ST_SUBMITSUCCESS);
success = true;
NSString* encodingName = [response textEncodingName];
@ -204,11 +382,13 @@ Str(const char* aName)
reply = [r UTF8String];
}
[progressLabel setStringValue: status];
[closeButton setEnabled: true];
[closeButton setKeyEquivalent:@"\r"];
CrashReporterSendCompleted(success, reply);
if (success) {
[NSApp terminate:self];
} else {
[self showErrorUI:gStrings[ST_SUBMITFAILED]];
}
}
-(void)uploadThread:(id)post
@ -246,14 +426,16 @@ void UIShutdown()
void UIShowDefaultUI()
{
[gUI showDefaultUI];
[NSApp run];
UIError(gStrings[ST_CRASHREPORTERDEFAULT]);
}
void UIShowCrashUI(const string& dumpfile,
const StringTable& queryParameters,
const string& sendURL)
const string& sendURL,
const vector<string>& restartArgs)
{
gRestartArgs = restartArgs;
[gUI showCrashUI: dumpfile
queryParameters: queryParameters
sendURL: sendURL];

Просмотреть файл

@ -20,6 +20,8 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ted Mielczarek <ted.mielczarek@gmail.com>
* Dave Camp <dcamp@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -47,226 +49,553 @@
#include <shellapi.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <set>
#include "resource.h"
#include "client/windows/sender/crash_report_sender.h"
#include "common/windows/string_utils-inl.h"
#define CRASH_REPORTER_KEY L"Software\\Mozilla\\Crash Reporter"
#define CRASH_REPORTER_VALUE L"Enabled"
#define SUBMIT_REPORT_VALUE L"SubmitReport"
#define EMAIL_ME_VALUE L"EmailMe"
#define EMAIL_VALUE L"Email"
#define MAX_EMAIL_LENGTH 1024
#define WM_UPLOADCOMPLETE WM_APP
using std::string;
using std::wstring;
using std::map;
static wstring UTF8ToWide(const string& utf8, bool *success = 0);
static string WideToUTF8(const wstring& wide, bool *success = 0);
static DWORD WINAPI SendThreadProc(LPVOID param);
using std::vector;
using std::set;
typedef struct {
HWND hDlg;
wstring dumpFile;
const StringTable* query_parameters;
wstring send_url;
wstring* server_response;
} SENDTHREADDATA;
map<wstring,wstring> queryParameters;
wstring sendURL;
wstring serverResponse;
} SendThreadData;
static HANDLE gThreadHandle;
static SendThreadData gSendData = { 0, };
static vector<string> gRestartArgs;
static map<wstring,wstring> gQueryParameters;
static wstring gCrashReporterKey(L"Software\\Mozilla\\Crash Reporter");
// When vertically resizing the dialog, these items should move down
static set<UINT> gAttachedBottom;
// Default set of items for gAttachedBottom
static const UINT kDefaultAttachedBottom[] = {
IDC_VIEWREPORTCHECK,
IDC_VIEWREPORTTEXT,
IDC_SUBMITCRASHCHECK,
IDC_EMAILMECHECK,
IDC_EMAILTEXT,
IDC_CLOSEBUTTON,
IDC_RESTARTBUTTON,
};
static wstring UTF8ToWide(const string& utf8, bool *success = 0);
static string WideToUTF8(const wstring& wide, bool *success = 0);
static DWORD WINAPI SendThreadProc(LPVOID param);
static wstring Str(const char* key)
{
return UTF8ToWide(gStrings[key]);
}
/* === win32 helper functions === */
static void DoInitCommonControls()
{
INITCOMMONCONTROLSEX ic;
ic.dwSize = sizeof(INITCOMMONCONTROLSEX);
ic.dwICC = ICC_PROGRESS_CLASS;
InitCommonControlsEx(&ic);
INITCOMMONCONTROLSEX ic;
ic.dwSize = sizeof(INITCOMMONCONTROLSEX);
ic.dwICC = ICC_PROGRESS_CLASS;
InitCommonControlsEx(&ic);
// also get the rich edit control
LoadLibrary(L"riched20.dll");
}
static BOOL CALLBACK EnableDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_INITDIALOG:
SetWindowText(hwndDlg, Str(ST_CRASHREPORTERTITLE).c_str());
SetDlgItemText(hwndDlg, IDOK, Str(ST_OK).c_str());
SetDlgItemText(hwndDlg, IDC_RADIOENABLE, Str(ST_RADIOENABLE).c_str());
SetDlgItemText(hwndDlg, IDC_RADIODISABLE, Str(ST_RADIODISABLE).c_str());
SetDlgItemText(hwndDlg, IDC_DESCRIPTIONTEXT, Str(ST_CRASHREPORTERDESCRIPTION).c_str());
SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT, EM_SETTARGETDEVICE, (WPARAM)NULL, 0);
SetFocus(GetDlgItem(hwndDlg, IDC_RADIOENABLE));
CheckRadioButton(hwndDlg, IDC_RADIOENABLE, IDC_RADIODISABLE, lParam ? IDC_RADIOENABLE : IDC_RADIODISABLE);
return FALSE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK && HIWORD(wParam) == BN_CLICKED)
{
UINT enableChecked = IsDlgButtonChecked(hwndDlg, IDC_RADIOENABLE);
EndDialog(hwndDlg, (enableChecked > 0) ? 1 : 0);
}
return FALSE;
default:
return FALSE;
}
}
static bool GetRegValue(HKEY hRegKey, LPCTSTR valueName, DWORD* value)
static bool GetBoolValue(HKEY hRegKey, LPCTSTR valueName, DWORD* value)
{
DWORD type, dataSize;
dataSize = sizeof(DWORD);
if (RegQueryValueEx(hRegKey, valueName, NULL, &type, (LPBYTE)value, &dataSize) == ERROR_SUCCESS
&& type == REG_DWORD)
return true;
DWORD type, dataSize;
dataSize = sizeof(DWORD);
if (RegQueryValueEx(hRegKey, valueName, NULL, &type, (LPBYTE)value, &dataSize) == ERROR_SUCCESS
&& type == REG_DWORD)
return true;
return false;
return false;
}
static bool CheckCrashReporterEnabled(bool* enabled)
static bool CheckBoolKey(const wchar_t* key,
const wchar_t* valueName,
bool* enabled)
{
*enabled = false;
bool found = false;
HKEY hRegKey;
DWORD val;
// see if our reg key is set globally
if (RegOpenKey(HKEY_LOCAL_MACHINE, CRASH_REPORTER_KEY, &hRegKey) == ERROR_SUCCESS)
{
if (GetRegValue(hRegKey, CRASH_REPORTER_VALUE, &val))
{
*enabled = (val == 1);
found = true;
}
if (RegOpenKey(HKEY_LOCAL_MACHINE, key, &hRegKey) == ERROR_SUCCESS) {
if (GetBoolValue(hRegKey, valueName, &val)) {
*enabled = (val == 1);
found = true;
}
RegCloseKey(hRegKey);
} else {
// look for it in user settings
if (RegOpenKey(HKEY_CURRENT_USER, key, &hRegKey) == ERROR_SUCCESS) {
if (GetBoolValue(hRegKey, valueName, &val)) {
*enabled = (val == 1);
found = true;
}
RegCloseKey(hRegKey);
}
else
{
// look for it in user settings
if (RegOpenKey(HKEY_CURRENT_USER, CRASH_REPORTER_KEY, &hRegKey) == ERROR_SUCCESS)
{
if (GetRegValue(hRegKey, CRASH_REPORTER_VALUE, &val))
{
*enabled = (val == 1);
found = true;
}
RegCloseKey(hRegKey);
}
}
}
// didn't find our reg key, ask user
return found;
}
static void SetCrashReporterEnabled(bool enabled)
static void SetBoolKey(const wchar_t* key, const wchar_t* value, bool enabled)
{
HKEY hRegKey;
if (RegCreateKey(HKEY_CURRENT_USER, CRASH_REPORTER_KEY, &hRegKey) == ERROR_SUCCESS) {
if (RegCreateKey(HKEY_CURRENT_USER, key, &hRegKey) == ERROR_SUCCESS) {
DWORD data = (enabled ? 1 : 0);
RegSetValueEx(hRegKey, CRASH_REPORTER_VALUE, 0, REG_DWORD, (LPBYTE)&data, sizeof(data));
RegSetValueEx(hRegKey, value, 0, REG_DWORD, (LPBYTE)&data, sizeof(data));
RegCloseKey(hRegKey);
}
}
static BOOL CALLBACK SendDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
static bool GetStringValue(HKEY hRegKey, LPCTSTR valueName, wstring& value)
{
static bool finishedOk = false;
static HANDLE hThread = NULL;
DWORD type, dataSize;
wchar_t buf[2048];
dataSize = sizeof(buf);
if (RegQueryValueEx(hRegKey, valueName, NULL, &type, (LPBYTE)buf, &dataSize) == ERROR_SUCCESS
&& type == REG_SZ) {
value = buf;
return true;
}
switch (message) {
case WM_INITDIALOG:
{
//init strings
SetWindowText(hwndDlg, Str(ST_SENDTITLE).c_str());
SetDlgItemText(hwndDlg, IDCANCEL, Str(ST_CANCEL).c_str());
// init progressmeter
SendDlgItemMessage(hwndDlg, IDC_PROGRESS, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
SendDlgItemMessage(hwndDlg, IDC_PROGRESS, PBM_SETPOS, 0, 0);
// now create a thread to actually do the sending
SENDTHREADDATA* td = (SENDTHREADDATA*)lParam;
td->hDlg = hwndDlg;
CreateThread(NULL, 0, SendThreadProc, td, 0, NULL);
}
return TRUE;
case WM_UPLOADCOMPLETE:
WaitForSingleObject(hThread, INFINITE);
finishedOk = (wParam == 1);
if (finishedOk) {
SendDlgItemMessage(hwndDlg, IDC_PROGRESS, PBM_SETPOS, 100, 0);
MessageBox(hwndDlg,
Str(ST_SUBMITSUCCESS).c_str(),
Str(ST_CRASHREPORTERTITLE).c_str(),
MB_OK | MB_ICONINFORMATION);
}
else {
MessageBox(hwndDlg,
Str(ST_SUBMITFAILED).c_str(),
Str(ST_CRASHREPORTERTITLE).c_str(),
MB_OK | MB_ICONERROR);
}
EndDialog(hwndDlg, finishedOk ? 1 : 0);
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDCANCEL && HIWORD(wParam) == BN_CLICKED) {
EndDialog(hwndDlg, finishedOk ? 1 : 0);
}
return TRUE;
default:
return FALSE;
}
return false;
}
static bool SendCrashReport(wstring dumpFile,
const StringTable* query_parameters,
wstring send_url,
wstring* server_response)
static bool GetStringKey(const wchar_t* key,
const wchar_t* valueName,
wstring& value)
{
SENDTHREADDATA td;
td.hDlg = NULL;
td.dumpFile = dumpFile;
td.query_parameters = query_parameters;
td.send_url = send_url;
td.server_response = server_response;
value = L"";
bool found = false;
HKEY hRegKey;
// see if our reg key is set globally
if (RegOpenKey(HKEY_LOCAL_MACHINE, key, &hRegKey) == ERROR_SUCCESS) {
if (GetStringValue(hRegKey, valueName, value)) {
found = true;
}
RegCloseKey(hRegKey);
} else {
// look for it in user settings
if (RegOpenKey(HKEY_CURRENT_USER, key, &hRegKey) == ERROR_SUCCESS) {
if (GetStringValue(hRegKey, valueName, value)) {
found = true;
}
RegCloseKey(hRegKey);
}
}
int res = (int)DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_SENDDIALOG), NULL,
(DLGPROC)SendDialogProc, (LPARAM)&td);
return found;
}
return (res >= 0);
static void SetStringKey(const wchar_t* key,
const wchar_t* valueName,
const wstring& value)
{
HKEY hRegKey;
if (RegCreateKey(HKEY_CURRENT_USER, key, &hRegKey) == ERROR_SUCCESS) {
RegSetValueEx(hRegKey, valueName, 0, REG_SZ,
(LPBYTE)value.c_str(),
(value.length() + 1) * sizeof(wchar_t));
RegCloseKey(hRegKey);
}
}
// Gets the position of a window relative to another window's client area
static void GetRelativeRect(HWND hwnd, HWND hwndParent, RECT* r)
{
GetWindowRect(hwnd, r);
ScreenToClient(hwndParent, (POINT*)&(r->left));
ScreenToClient(hwndParent, (POINT*)&(r->right));
}
static void SetDlgItemVisible(HWND hwndDlg, UINT item, bool visible)
{
HWND hwnd = GetDlgItem(hwndDlg, item);
LONG style = GetWindowLong(hwnd, GWL_STYLE);
if (visible)
style |= WS_VISIBLE;
else
style &= ~WS_VISIBLE;
SetWindowLong(hwnd, GWL_STYLE, style);
}
static void SetDlgItemDisabled(HWND hwndDlg, UINT item, bool disabled)
{
HWND hwnd = GetDlgItem(hwndDlg, item);
LONG style = GetWindowLong(hwnd, GWL_STYLE);
if (!disabled)
style |= WS_DISABLED;
else
style &= ~WS_DISABLED;
SetWindowLong(hwnd, GWL_STYLE, style);
}
/* === Crash Reporting Dialog === */
static void StretchDialog(HWND hwndDlg, int ydiff)
{
RECT r;
GetWindowRect(hwndDlg, &r);
r.bottom += ydiff;
MoveWindow(hwndDlg, r.left, r.top,
r.right - r.left, r.bottom - r.top, TRUE);
}
static void ReflowDialog(HWND hwndDlg, int ydiff)
{
// Move items attached to the bottom down/up by as much as
// the window resize
for (set<UINT>::const_iterator item = gAttachedBottom.begin();
item != gAttachedBottom.end();
item++) {
RECT r;
HWND hwnd = GetDlgItem(hwndDlg, *item);
GetRelativeRect(hwnd, hwndDlg, &r);
r.top += ydiff;
r.bottom += ydiff;
MoveWindow(hwnd, r.left, r.top,
r.right - r.left, r.bottom - r.top, TRUE);
}
}
static DWORD WINAPI SendThreadProc(LPVOID param)
{
bool finishedOk;
SENDTHREADDATA* td = (SENDTHREADDATA*)param;
SendThreadData* td = (SendThreadData*)param;
if (td->send_url.empty()) {
if (td->sendURL.empty()) {
finishedOk = false;
}
else {
map<wstring,wstring>query_parameters;
StringTable::const_iterator end = td->query_parameters->end();
for (StringTable::const_iterator i = td->query_parameters->begin();
i != end;
i++) {
query_parameters[UTF8ToWide(i->first)] = UTF8ToWide(i->second);
}
} else {
google_breakpad::CrashReportSender sender(L"");
finishedOk = (sender.SendCrashReport(td->send_url,
query_parameters,
finishedOk = (sender.SendCrashReport(td->sendURL,
td->queryParameters,
td->dumpFile,
td->server_response)
&td->serverResponse)
== google_breakpad::RESULT_SUCCEEDED);
}
PostMessage(td->hDlg, WM_UPLOADCOMPLETE, finishedOk ? 1 : 0, 0);
return 0;
}
static void EndCrashReporterDialog(HWND hwndDlg, int code)
{
// Save the current values to the registry
wchar_t email[MAX_EMAIL_LENGTH];
GetDlgItemText(hwndDlg, IDC_EMAILTEXT, email, sizeof(email));
SetStringKey(gCrashReporterKey.c_str(), EMAIL_VALUE, email);
SetBoolKey(gCrashReporterKey.c_str(), EMAIL_ME_VALUE,
IsDlgButtonChecked(hwndDlg, IDC_EMAILMECHECK) != 0);
SetBoolKey(gCrashReporterKey.c_str(), SUBMIT_REPORT_VALUE,
IsDlgButtonChecked(hwndDlg, IDC_SUBMITREPORTCHECK) != 0);
EndDialog(hwndDlg, code);
}
static void MaybeSendReport(HWND hwndDlg)
{
if (!IsDlgButtonChecked(hwndDlg, IDC_SUBMITREPORTCHECK)) {
EndCrashReporterDialog(hwndDlg, 0);
return;
}
gThreadHandle = NULL;
gSendData.hDlg = hwndDlg;
gSendData.queryParameters = gQueryParameters;
gThreadHandle = CreateThread(NULL, 0, SendThreadProc, &gSendData, 0, NULL);
}
static void RestartApplication()
{
wstring cmdLine;
for (unsigned int i = 0; i < gRestartArgs.size(); i++) {
cmdLine += L"\"" + UTF8ToWide(gRestartArgs[i]) + L"\" ";
}
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWNORMAL;
ZeroMemory(&pi, sizeof(pi));
if (CreateProcess(NULL, (LPWSTR)cmdLine.c_str(), NULL, NULL, FALSE, 0,
NULL, NULL, &si, &pi)) {
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}
static void ShowReportInfo(HWND hwndDlg)
{
wstring description;
for (map<wstring,wstring>::const_iterator i = gQueryParameters.begin();
i != gQueryParameters.end();
i++) {
description += i->first;
description += L": ";
description += i->second;
description += L"\n";
}
description += L"\n";
description += Str(ST_EXTRAREPORTINFO);
SetDlgItemText(hwndDlg, IDC_VIEWREPORTTEXT, description.c_str());
}
static void ShowHideReport(HWND hwndDlg)
{
// When resizing the dialog to show the report, these items should
// stay put
gAttachedBottom.erase(IDC_VIEWREPORTCHECK);
gAttachedBottom.erase(IDC_VIEWREPORTTEXT);
RECT r;
HWND hwnd = GetDlgItem(hwndDlg, IDC_VIEWREPORTTEXT);
GetWindowRect(hwnd, &r);
int diff = (r.bottom - r.top) + 10;
if (IsDlgButtonChecked(hwndDlg, IDC_VIEWREPORTCHECK)) {
SetDlgItemVisible(hwndDlg, IDC_VIEWREPORTTEXT, true);
} else {
SetDlgItemVisible(hwndDlg, IDC_VIEWREPORTTEXT, false);
diff = -diff;
}
StretchDialog(hwndDlg, diff);
// set these back to normal
gAttachedBottom.insert(IDC_VIEWREPORTCHECK);
gAttachedBottom.insert(IDC_VIEWREPORTTEXT);
}
static void UpdateEmail(HWND hwndDlg)
{
if (IsDlgButtonChecked(hwndDlg, IDC_EMAILMECHECK)) {
wchar_t email[MAX_EMAIL_LENGTH];
GetDlgItemText(hwndDlg, IDC_EMAILTEXT, email, sizeof(email));
gQueryParameters[L"Email"] = email;
} else {
gQueryParameters.erase(L"Email");
}
}
static BOOL CALLBACK CrashReporterDialogProc(HWND hwndDlg, UINT message,
WPARAM wParam, LPARAM lParam)
{
static int sHeight = 0;
bool success;
bool enabled;
switch (message) {
case WM_INITDIALOG: {
RECT r;
GetClientRect(hwndDlg, &r);
sHeight = r.bottom - r.top;
SetWindowText(hwndDlg, Str(ST_CRASHREPORTERTITLE).c_str());
SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT,
EM_SETEVENTMASK, (WPARAM)NULL,
ENM_REQUESTRESIZE);
wstring description = Str(ST_CRASHREPORTERHEADER);
description += L"\n\n";
description += Str(ST_CRASHREPORTERDESCRIPTION);
SetDlgItemText(hwndDlg, IDC_DESCRIPTIONTEXT, description.c_str());
// Make the title bold.
CHARFORMAT fmt = { 0, };
fmt.cbSize = sizeof(fmt);
fmt.dwMask = CFM_BOLD;
fmt.dwEffects = CFE_BOLD;
SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT, EM_SETSEL,
0, Str(ST_CRASHREPORTERHEADER).length());
SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT, EM_SETCHARFORMAT,
SCF_SELECTION, (LPARAM)&fmt);
SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT, EM_SETSEL, 0, 0);
SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT,
EM_SETTARGETDEVICE, (WPARAM)NULL, 0);
SetDlgItemText(hwndDlg, IDC_VIEWREPORTCHECK, Str(ST_VIEWREPORT).c_str());
SendDlgItemMessage(hwndDlg, IDC_VIEWREPORTTEXT,
EM_SETTARGETDEVICE, (WPARAM)NULL, 0);
SetDlgItemText(hwndDlg, IDC_SUBMITREPORTCHECK,
Str(ST_CHECKSUBMIT).c_str());
if (CheckBoolKey(gCrashReporterKey.c_str(),
SUBMIT_REPORT_VALUE, &enabled) &&
!enabled) {
CheckDlgButton(hwndDlg, IDC_SUBMITREPORTCHECK, BST_UNCHECKED);
EnableWindow(GetDlgItem(hwndDlg, IDC_EMAILMECHECK), enabled);
EnableWindow(GetDlgItem(hwndDlg, IDC_EMAILTEXT), enabled);
} else {
CheckDlgButton(hwndDlg, IDC_SUBMITREPORTCHECK, BST_CHECKED);
}
SetDlgItemText(hwndDlg, IDC_EMAILMECHECK, Str(ST_CHECKEMAIL).c_str());
if (CheckBoolKey(gCrashReporterKey.c_str(), EMAIL_ME_VALUE, &enabled) &&
enabled) {
CheckDlgButton(hwndDlg, IDC_EMAILMECHECK, BST_CHECKED);
} else {
CheckDlgButton(hwndDlg, IDC_EMAILMECHECK, BST_UNCHECKED);
}
wstring email;
if (GetStringKey(gCrashReporterKey.c_str(), EMAIL_VALUE, email)) {
SetDlgItemText(hwndDlg, IDC_EMAILTEXT, email.c_str());
}
SetDlgItemText(hwndDlg, IDC_CLOSEBUTTON, Str(ST_CLOSE).c_str());
if (gRestartArgs.size() > 0) {
SetDlgItemText(hwndDlg, IDC_RESTARTBUTTON, Str(ST_RESTART).c_str());
} else {
// No restart arguments, move the close button over to the side
// and hide the restart button
SetDlgItemVisible(hwndDlg, IDC_RESTARTBUTTON, false);
RECT closeRect;
HWND hwndClose = GetDlgItem(hwndDlg, IDC_CLOSEBUTTON);
GetRelativeRect(hwndClose, hwndDlg, &closeRect);
RECT restartRect;
HWND hwndRestart = GetDlgItem(hwndDlg, IDC_RESTARTBUTTON);
GetRelativeRect(hwndRestart, hwndDlg, &restartRect);
int size = closeRect.right - closeRect.left;
closeRect.right = restartRect.right;
closeRect.left = closeRect.right - size;
MoveWindow(hwndClose, closeRect.left, closeRect.top,
closeRect.right - closeRect.left,
closeRect.bottom - closeRect.top,
TRUE);
}
UpdateEmail(hwndDlg);
ShowReportInfo(hwndDlg);
SetFocus(GetDlgItem(hwndDlg, IDC_EMAILTEXT));
return FALSE;
}
case WM_SIZE: {
ReflowDialog(hwndDlg, HIWORD(lParam) - sHeight);
sHeight = HIWORD(lParam);
InvalidateRect(hwndDlg, NULL, TRUE);
return FALSE;
}
case WM_NOTIFY: {
NMHDR* notification = reinterpret_cast<NMHDR*>(lParam);
if (notification->code == EN_REQUESTRESIZE) {
// Resizing the rich edit control to fit the description text.
REQRESIZE* reqresize = reinterpret_cast<REQRESIZE*>(lParam);
RECT newSize = reqresize->rc;
RECT oldSize;
GetRelativeRect(notification->hwndFrom, hwndDlg, &oldSize);
// resize the text box as requested
MoveWindow(notification->hwndFrom, newSize.left, newSize.top,
newSize.right - newSize.left, newSize.bottom - newSize.top,
TRUE);
// Resize the dialog to fit (the WM_SIZE handler will move the controls)
StretchDialog(hwndDlg, newSize.bottom - oldSize.bottom);
}
return FALSE;
}
case WM_COMMAND: {
if (HIWORD(wParam) == BN_CLICKED) {
switch(LOWORD(wParam)) {
case IDC_VIEWREPORTCHECK:
ShowHideReport(hwndDlg);
break;
case IDC_SUBMITREPORTCHECK:
enabled = (IsDlgButtonChecked(hwndDlg, IDC_SUBMITREPORTCHECK) != 0);
EnableWindow(GetDlgItem(hwndDlg, IDC_EMAILMECHECK), enabled);
EnableWindow(GetDlgItem(hwndDlg, IDC_EMAILTEXT), enabled);
break;
case IDC_EMAILMECHECK:
UpdateEmail(hwndDlg);
ShowReportInfo(hwndDlg);
break;
case IDC_CLOSEBUTTON:
// Hide the dialog after "closing", but leave it around to coordinate
// with the upload thread
ShowWindow(hwndDlg, SW_HIDE);
MaybeSendReport(hwndDlg);
break;
case IDC_RESTARTBUTTON:
// Hide the dialog after "closing", but leave it around to coordinate
// with the upload thread
ShowWindow(hwndDlg, SW_HIDE);
RestartApplication();
MaybeSendReport(hwndDlg);
break;
}
} else if (HIWORD(wParam) == EN_CHANGE) {
switch(LOWORD(wParam)) {
case IDC_EMAILTEXT:
wchar_t email[MAX_EMAIL_LENGTH];
if (GetDlgItemText(hwndDlg, IDC_EMAILTEXT, email, sizeof(email)) > 0)
CheckDlgButton(hwndDlg, IDC_EMAILMECHECK, BST_CHECKED);
else
CheckDlgButton(hwndDlg, IDC_EMAILMECHECK, BST_UNCHECKED);
UpdateEmail(hwndDlg);
ShowReportInfo(hwndDlg);
}
}
return FALSE;
}
case WM_UPLOADCOMPLETE: {
WaitForSingleObject(gThreadHandle, INFINITE);
success = (wParam == 1);
CrashReporterSendCompleted(success, WideToUTF8(gSendData.serverResponse));
if (!success) {
MessageBox(hwndDlg,
Str(ST_SUBMITFAILED).c_str(),
Str(ST_CRASHREPORTERTITLE).c_str(),
MB_OK | MB_ICONERROR);
}
EndCrashReporterDialog(hwndDlg, success ? 1 : 0);
return TRUE;
}
}
return FALSE;
}
static wstring UTF8ToWide(const string& utf8, bool *success)
{
wchar_t* buffer = NULL;
@ -329,6 +658,10 @@ static string WideToUTF8(const wstring& wide, bool *success)
bool UIInit()
{
for (int i = 0; i < sizeof(kDefaultAttachedBottom) / sizeof(UINT); i++) {
gAttachedBottom.insert(kDefaultAttachedBottom[i]);
}
DoInitCommonControls();
return true;
}
@ -339,34 +672,36 @@ void UIShutdown()
void UIShowDefaultUI()
{
bool enabled;
// no dump file specified, just ask about enabling
if (!CheckCrashReporterEnabled(&enabled))
enabled = true;
enabled = (1 == DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_ENABLEDIALOG), NULL, (DLGPROC)EnableDialogProc, (LPARAM)enabled));
SetCrashReporterEnabled(enabled);
MessageBox(NULL, Str(ST_CRASHREPORTERDEFAULT).c_str(),
L"Crash Reporter",
MB_OK | MB_ICONSTOP);
}
void UIShowCrashUI(const string& dumpfile,
const StringTable& query_parameters,
const string& send_url)
void UIShowCrashUI(const string& dumpFile,
const StringTable& queryParameters,
const string& sendURL,
const vector<string>& restartArgs)
{
bool enabled;
if (!CheckCrashReporterEnabled(&enabled)) {
//ask user if crash reporter should be enabled
enabled = (1 == DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_ENABLEDIALOG), NULL, (DLGPROC)EnableDialogProc, (LPARAM)true));
SetCrashReporterEnabled(enabled);
gSendData.hDlg = NULL;
gSendData.dumpFile = UTF8ToWide(dumpFile);
gSendData.sendURL = UTF8ToWide(sendURL);
for (StringTable::const_iterator i = queryParameters.begin();
i != queryParameters.end();
i++) {
gQueryParameters[UTF8ToWide(i->first)] = UTF8ToWide(i->second);
}
// if enabled, send crash report
if (enabled) {
wstring server_response;
bool success = SendCrashReport(UTF8ToWide(dumpfile),
&query_parameters,
UTF8ToWide(send_url),
&server_response);
CrashReporterSendCompleted(success, WideToUTF8(server_response));
if (gQueryParameters.find(L"Vendor") != gQueryParameters.end()) {
gCrashReporterKey = L"Software\\" +
gQueryParameters[L"Vendor"] +
L"\\Crash Reporter";
}
gRestartArgs = restartArgs;
DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_SENDDIALOG), NULL,
(DLGPROC)CrashReporterDialogProc, 0);
}
void UIError(const string& message)
@ -430,6 +765,9 @@ bool UIEnsurePathExists(const string& path)
bool UIMoveFile(const string& oldfile, const string& newfile)
{
if (oldfile == newfile)
return true;
return MoveFile(UTF8ToWide(oldfile).c_str(), UTF8ToWide(newfile).c_str())
== TRUE;
}

Просмотреть файл

@ -1,22 +1,31 @@
{
IBClasses = (
{
ACTIONS = {closeClicked = id; sendClicked = id; };
ACTIONS = {
closeAndSendClicked = id;
closeClicked = id;
emailMeClicked = id;
restartClicked = id;
viewReportClicked = id;
};
CLASS = CrashReporterUI;
LANGUAGE = ObjC;
OUTLETS = {
closeButton = NSButton;
descriptionLabel = NSTextField;
disableReportingButton = NSButton;
dontSendButton = NSButton;
enableView = NSView;
emailMeButton = NSButton;
emailText = NSTextField;
errorCloseButton = NSButton;
errorHeaderLabel = NSTextField;
errorLabel = NSTextField;
errorView = NSView;
progressBar = NSProgressIndicator;
progressLabel = NSTextField;
sendButton = NSButton;
uploadingView = NSView;
headerLabel = NSTextField;
restartButton = NSButton;
submitReportButton = NSButton;
viewReportButton = NSButton;
viewReportLabel = NSTextField;
viewReportScrollView = NSScrollView;
viewReportTextView = NSTextView;
window = NSWindow;
};
SUPERCLASS = NSObject;

Просмотреть файл

@ -3,17 +3,17 @@
<plist version="1.0">
<dict>
<key>IBDocumentLocation</key>
<string>299 87 356 240 0 0 1440 878 </string>
<string>128 190 504 836 0 0 1920 1178 </string>
<key>IBEditorPositions</key>
<dict>
<key>282</key>
<string>24 681 550 163 0 0 1440 878 </string>
<string>685 720 550 163 0 0 1920 1178 </string>
<key>29</key>
<string>447 315 137 44 0 0 1440 878 </string>
<key>356</key>
<string>643 213 551 213 0 0 1440 878 </string>
<string>684 695 551 213 0 0 1920 1178 </string>
<key>386</key>
<string>23 537 456 145 0 0 1440 878 </string>
<string>492 520 456 164 0 0 1440 878 </string>
</dict>
<key>IBFramework Version</key>
<string>446.1</string>
@ -26,9 +26,8 @@
<integer>2</integer>
<key>IBOpenObjects</key>
<array>
<integer>386</integer>
<integer>282</integer>
<integer>29</integer>
<integer>386</integer>
<integer>21</integer>
</array>
<key>IBSystem Version</key>

Двоичные данные
toolkit/airbag/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib сгенерированный

Двоичный файл не отображается.

Просмотреть файл

@ -1,13 +1,22 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by CrashReporter.rc
// Used by crashreporter.rc
//
#define IDD_ENABLEDIALOG 101
#define IDD_SENDDIALOG 102
#define IDC_RADIOENABLE 1001
#define IDC_RADIODISABLE 1002
#define IDC_PROGRESS 1003
#define IDC_DESCRIPTIONTEXT 1004
#define IDC_CLOSEBUTTON 1005
#define IDC_VIEWREPORTBUTTON 1006
#define IDC_SUBMITCRASHCHECK 1007
#define IDC_SUBMITREPORTCHECK 1007
#define IDC_EMAILMECHECK 1008
#define IDC_EMAILTEXT 1009
#define IDC_HEADERLABEL 1010
#define IDC_RESTARTBUTTON 1012
#define IDC_DESCRIPTIONLABEL 1013
#define IDC_VIEWREPORTTEXT 1015
#define IDC_VIEWREPORTCHECK 1016
#define IDC_PROGRESSLABEL -1
// Next default values for new objects
//
@ -15,7 +24,7 @@
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 103
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1005
#define _APS_NEXT_CONTROL_VALUE 1017
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

Просмотреть файл

@ -414,4 +414,26 @@ nsresult AnnotateCrashReport(const nsACString &key, const nsACString &data)
return NS_OK;
}
nsresult
SetRestartArgs(int argc, char **argv)
{
int i;
nsCAutoString envVar;
for (i = 0; i < argc; i++) {
envVar = "MOZ_CRASHREPORTER_RESTART_ARG_";
envVar.AppendInt(i);
envVar += "=";
envVar += argv[i];
PR_SetEnv(envVar.get());
}
// make sure the arg list is terminated
envVar = "MOZ_CRASHREPORTER_RESTART_ARG_";
envVar.AppendInt(i);
envVar += "=";
PR_SetEnv(envVar.get());
return NS_OK;
}
} // namespace CrashReporter

Просмотреть файл

@ -48,6 +48,7 @@ nsresult SetExceptionHandler(nsILocalFile* aXREDirectory,
nsresult SetMinidumpPath(const nsAString& aPath);
nsresult UnsetExceptionHandler();
nsresult AnnotateCrashReport(const nsACString &key, const nsACString &data);
nsresult SetRestartArgs(int argc, char **argv);
}
#endif /* nsAirbagExceptionHandler_h__ */

Просмотреть файл

@ -2328,6 +2328,7 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
if (appData.buildID)
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BuildID"),
nsDependentCString(appData.buildID));
CrashReporter::SetRestartArgs(argc, argv);
}
#endif