summaryrefslogtreecommitdiffstats
path: root/mmc_updater/src/UpdateDialogCocoa.mm
blob: f24f3c4dd7912e76bb9cfee2ae1903f7573edd42 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#include "UpdateDialogCocoa.h"

#include <Cocoa/Cocoa.h>
#include <Carbon/Carbon.h>

#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];
}