#include "UpdateDialogCocoa.h" #include #include #include "AppInfo.h" #include "Log.h" #include "StringUtils.h" @interface UpdateDialogDelegate : NSObject { @public UpdateDialogPrivate* dialog; } - (void) finishClicked; - (void) reportUpdateError:(id)arg; - (void) reportUpdateProgress:(id)arg; - (void) reportUpdateFinished:(id)arg; @end class UpdateDialogPrivate { public: UpdateDialogPrivate() : hadError(false) { } UpdateDialogDelegate* delegate; NSAutoreleasePool* pool; NSWindow* window; NSButton* finishButton; NSTextField* progressLabel; NSProgressIndicator* progressBar; bool hadError; }; @implementation UpdateDialogDelegate - (void) finishClicked { [NSApp stop:self]; } - (void) reportUpdateError: (id)arg { dialog->hadError = true; NSAlert* alert = [NSAlert alertWithMessageText: @"Update Problem" defaultButton: nil alternateButton: nil otherButton: nil informativeTextWithFormat: @"There was a problem installing the update:\n\n%@", arg]; [alert runModal]; } - (void) reportUpdateProgress: (id)arg { int percentage = [arg intValue]; [dialog->progressBar setDoubleValue:(percentage/100.0)]; } - (void) reportUpdateFinished: (id)arg { NSMutableString* message = [[NSMutableString alloc] init]; if (!dialog->hadError) { [message appendString:@"Updates installed."]; } else { [message appendString:@"Update failed."]; } [message appendString:@" Click 'Finish' to restart the application."]; [dialog->progressLabel setTitleWithMnemonic:message]; [message release]; } @end UpdateDialogCocoa::UpdateDialogCocoa() : d(new UpdateDialogPrivate) { [NSApplication sharedApplication]; d->pool = [[NSAutoreleasePool alloc] init]; } UpdateDialogCocoa::~UpdateDialogCocoa() { [d->pool release]; } void UpdateDialogCocoa::enableDockIcon() { // convert the application to a foreground application and in // the process, enable the dock icon // the reverse transformation is not possible, according to // http://stackoverflow.com/questions/2832961/is-it-possible-to-hide-the-dock-icon-programmatically ProcessSerialNumber psn; GetCurrentProcess(&psn); TransformProcessType(&psn,kProcessTransformToForegroundApplication); } void UpdateDialogCocoa::init(int /* argc */, char** /* argv */) { enableDockIcon(); // make the updater the active application. This does not // happen automatically because the updater starts as a // background application [NSApp activateIgnoringOtherApps:YES]; d->delegate = [[UpdateDialogDelegate alloc] init]; d->delegate->dialog = d; int width = 370; int height = 100; d->window = [[NSWindow alloc] initWithContentRect:NSMakeRect(200, 200, width, height) styleMask:NSTitledWindowMask | NSMiniaturizableWindowMask backing:NSBackingStoreBuffered defer:NO]; [d->window setTitle:[NSString stringWithUTF8String:AppInfo::name().c_str()]]; d->finishButton = [[NSButton alloc] init]; [d->finishButton setTitle:@"Finish"]; [d->finishButton setButtonType:NSMomentaryLightButton]; [d->finishButton setBezelStyle:NSRoundedBezelStyle]; [d->finishButton setTarget:d->delegate]; [d->finishButton setAction:@selector(finishClicked)]; d->progressBar = [[NSProgressIndicator alloc] init]; [d->progressBar setIndeterminate:false]; [d->progressBar setMinValue:0.0]; [d->progressBar setMaxValue:1.0]; d->progressLabel = [[NSTextField alloc] init]; [d->progressLabel setEditable:false]; [d->progressLabel setSelectable:false]; [d->progressLabel setTitleWithMnemonic:@"Installing Updates"]; [d->progressLabel setBezeled:false]; [d->progressLabel setDrawsBackground:false]; NSView* windowContent = [d->window contentView]; [windowContent addSubview:d->progressLabel]; [windowContent addSubview:d->progressBar]; [windowContent addSubview:d->finishButton]; [d->progressLabel setFrame:NSMakeRect(10,70,width - 10,20)]; [d->progressBar setFrame:NSMakeRect(10,40,width - 20,20)]; [d->finishButton setFrame:NSMakeRect(width - 85,5,80,30)]; } void UpdateDialogCocoa::exec() { [d->window makeKeyAndOrderFront:d->window]; [d->window center]; [NSApp run]; } void UpdateDialogCocoa::updateError(const std::string& errorMessage) { [d->delegate performSelectorOnMainThread:@selector(reportUpdateError:) withObject:[NSString stringWithUTF8String:errorMessage.c_str()] waitUntilDone:false]; } void UpdateDialogCocoa::updateProgress(int percentage) { [d->delegate performSelectorOnMainThread:@selector(reportUpdateProgress:) withObject:[NSNumber numberWithInt:percentage] waitUntilDone:false]; } void UpdateDialogCocoa::updateFinished() { [d->delegate performSelectorOnMainThread:@selector(reportUpdateFinished:) withObject:nil waitUntilDone:false]; UpdateDialog::updateFinished(); } void* UpdateDialogCocoa::createAutoreleasePool() { return [[NSAutoreleasePool alloc] init]; } void UpdateDialogCocoa::releaseAutoreleasePool(void* arg) { [(id)arg release]; } void UpdateDialogCocoa::quit() { [NSApp performSelectorOnMainThread:@selector(stop:) withObject:d->delegate waitUntilDone:false]; }