]> git.sesse.net Git - vlc/blob - modules/gui/macosx/coredialogs.m
macosx: Update progress dialog on the main thread, make check thread safe
[vlc] / modules / gui / macosx / coredialogs.m
1 /*****************************************************************************
2  * coredialogs.m: Mac OS X Core Dialogs
3  *****************************************************************************
4  * Copyright (C) 2005-2012 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Derk-Jan Hartman <hartman at videolan dot org>
8  *          Felix Paul Kühne <fkuehne at videolan dot org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #import "intf.h"
26 #import "coredialogs.h"
27 #import "misc.h"
28
29 /* for the icon in our custom error panel */
30 #import <ApplicationServices/ApplicationServices.h>
31
32 /*****************************************************************************
33  * VLCCoreDialogProvider implementation
34  *****************************************************************************/
35 @implementation VLCCoreDialogProvider
36
37 static VLCCoreDialogProvider *_o_sharedInstance = nil;
38
39 @synthesize progressCancelled=b_progress_cancelled;
40
41 + (VLCCoreDialogProvider *)sharedInstance
42 {
43     return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
44 }
45
46 -(id)init
47 {
48     if (_o_sharedInstance)
49         [self dealloc];
50     else {
51         _o_sharedInstance = [super init];
52         o_error_panel = [[VLCErrorPanel alloc] init];
53         b_progress_cancelled = NO;
54     }
55
56     return _o_sharedInstance;
57 }
58
59 -(void)awakeFromNib
60 {
61     [o_auth_login_txt setStringValue: _NS("Username")];
62     [o_auth_pw_txt setStringValue: _NS("Password")];
63     [o_auth_cancel_btn setTitle: _NS("Cancel")];
64     [o_auth_ok_btn setTitle: _NS("OK")];
65     [o_prog_cancel_btn setTitle: _NS("Cancel")];
66     [o_prog_bar setUsesThreadedAnimation: YES];
67
68 }
69
70 -(void)performEventWithObject: (NSValue *)o_value ofType: (const char*)type
71 {
72     NSString *o_type = [NSString stringWithUTF8String:type];
73
74     if ([o_type isEqualToString: @"dialog-error"])
75         [self performSelectorOnMainThread:@selector(showFatalDialog:) withObject:o_value waitUntilDone:YES];
76     else if ([o_type isEqualToString: @"dialog-critical"])
77         [self performSelectorOnMainThread:@selector(showFatalWaitDialog:) withObject:o_value waitUntilDone:YES];
78     else if ([o_type isEqualToString: @"dialog-question"])
79         [self performSelectorOnMainThread:@selector(showQuestionDialog:) withObject:o_value waitUntilDone:YES];
80     else if ([o_type isEqualToString: @"dialog-login"])
81         [self performSelectorOnMainThread:@selector(showLoginDialog:) withObject:o_value waitUntilDone:YES];
82     else if ([o_type isEqualToString: @"dialog-progress-bar"])
83         [self performSelectorOnMainThread:@selector(showProgressDialogOnMainThread:) withObject: o_value waitUntilDone:YES];
84     else
85         msg_Err(VLCIntf, "unhandled dialog type: '%s'", type);
86 }
87
88 -(void)showFatalDialog: (NSValue *)o_value
89 {
90     dialog_fatal_t *p_dialog = [o_value pointerValue];
91
92     [o_error_panel addError: toNSStr(p_dialog->title) withMsg: toNSStr(p_dialog->message)];
93     [o_error_panel showPanel];
94 }
95
96 -(void)showFatalWaitDialog: (NSValue *)o_value
97 {
98     dialog_fatal_t *p_dialog = [o_value pointerValue];
99     NSAlert *o_alert;
100
101     o_alert = [NSAlert alertWithMessageText: toNSStr(p_dialog->title) defaultButton: _NS("OK") alternateButton: nil otherButton: nil informativeTextWithFormat: @"%@", toNSStr(p_dialog->message)];
102     [o_alert setAlertStyle: NSCriticalAlertStyle];
103     [o_alert runModal];
104 }
105
106 -(void)showQuestionDialog: (NSValue *)o_value
107 {
108     dialog_question_t *p_dialog = [o_value pointerValue];
109     NSAlert *o_alert;
110     NSInteger i_returnValue = 0;
111   
112     o_alert = [NSAlert alertWithMessageText: toNSStr(p_dialog->title) defaultButton: toNSStr(p_dialog->yes) alternateButton: toNSStr(p_dialog->no) otherButton: toNSStr(p_dialog->cancel) informativeTextWithFormat:@"%@", toNSStr(p_dialog->message)];
113     [o_alert setAlertStyle: NSInformationalAlertStyle];
114     i_returnValue = [o_alert runModal];
115
116     if (i_returnValue == NSAlertDefaultReturn)
117         p_dialog->answer = 1;
118     if (i_returnValue == NSAlertAlternateReturn)
119         p_dialog->answer = 2;
120     if (i_returnValue == NSAlertOtherReturn)
121         p_dialog->answer = 3;
122 }
123
124 -(void)showLoginDialog: (NSValue *)o_value
125 {
126     dialog_login_t *p_dialog = [o_value pointerValue];
127     NSInteger i_returnValue = 0;
128
129     [o_auth_title_txt setStringValue: toNSStr(p_dialog->title)];
130     [o_auth_win setTitle: toNSStr(p_dialog->title)];
131     [o_auth_description_txt setStringValue: toNSStr(p_dialog->message)];
132     [o_auth_login_fld setStringValue: @""];
133     [o_auth_pw_fld setStringValue: @""];
134
135     [o_auth_win center];
136     i_returnValue = [NSApp runModalForWindow: o_auth_win];
137     [o_auth_win close];
138     if (i_returnValue)
139     {
140         *p_dialog->username = strdup([[o_auth_login_fld stringValue] UTF8String]);
141         *p_dialog->password = strdup([[o_auth_pw_fld stringValue] UTF8String]);
142     } else
143         *p_dialog->username = *p_dialog->password = NULL;
144 }
145
146 -(IBAction)loginDialogAction:(id)sender
147 {
148     if ([[sender title] isEqualToString: _NS("OK")])
149         [NSApp stopModalWithCode: 1];
150     else
151         [NSApp stopModalWithCode: 0];
152 }
153
154 -(void)showProgressDialogOnMainThread: (NSValue *)o_value
155 {
156     /* we work-around a Cocoa limitation here, since you cannot delay an execution
157      * on the main thread within a single call */
158     [self setProgressCancelled:NO];
159
160     dialog_progress_bar_t *p_dialog = [o_value pointerValue];
161     if (!p_dialog)
162         return;
163
164     [o_prog_win setTitle: toNSStr(p_dialog->title)];
165     [o_prog_title_txt setStringValue: toNSStr(p_dialog->title)];
166
167     if (p_dialog->cancel != NULL)
168         [o_prog_cancel_btn setTitle: [NSString stringWithUTF8String:p_dialog->cancel]];
169     else
170         [o_prog_cancel_btn setTitle: _NS("Cancel")];
171
172     [o_prog_description_txt setStringValue: toNSStr(p_dialog->message)];
173
174     if (VLCIntf)
175         [self performSelector:@selector(showProgressDialog:) withObject: o_value afterDelay:3.00];
176 }
177
178 -(void)showProgressDialog: (NSValue *)o_value
179 {
180     dialog_progress_bar_t *p_dialog = [o_value pointerValue];
181
182     if (!p_dialog || [self progressCancelled])
183         return;
184
185     [o_prog_bar setDoubleValue: 0];
186     [o_prog_bar setIndeterminate: YES];
187     [o_prog_bar startAnimation: self];
188
189     [o_prog_win makeKeyAndOrderFront: self];
190 }
191
192 -(void)updateProgressPanelWithText: (NSString *)string andNumber: (double)d_number
193 {
194     [o_prog_description_txt setStringValue: string];
195     if (d_number > 0)
196         [o_prog_bar setIndeterminate: NO];
197     [o_prog_bar setDoubleValue: d_number];
198 }
199
200 -(void)destroyProgressPanel
201 {
202     [self setProgressCancelled:YES];
203     [o_prog_bar performSelectorOnMainThread:@selector(stopAnimation:) withObject:self waitUntilDone:YES];
204     [o_prog_win performSelectorOnMainThread:@selector(close) withObject:nil waitUntilDone:YES];
205 }
206
207 -(IBAction)progDialogAction:(id)sender
208 {
209     [self setProgressCancelled:YES];
210 }
211
212 -(id)errorPanel
213 {
214     return o_error_panel;
215 }
216
217 @end
218
219 /*****************************************************************************
220  * VLCErrorPanel implementation
221  *****************************************************************************/
222 @implementation VLCErrorPanel
223 -(id)init
224 {
225     [super init];
226
227     if (!b_nib_loaded)
228         b_nib_loaded = [NSBundle loadNibNamed:@"ErrorPanel" owner:self];
229
230     /* init data sources */
231     o_errors = [[NSMutableArray alloc] init];
232     o_icons = [[NSMutableArray alloc] init];
233
234     return self;
235 }
236
237 - (void)awakeFromNib
238 {
239     /* init strings */
240     [o_window setTitle: _NS("Errors and Warnings")];
241     [o_cleanup_button setTitle: _NS("Clean up")];
242 }
243
244 -(void)dealloc
245 {
246     [o_errors release];
247     [o_icons release];
248     [super dealloc];
249 }
250
251 -(void)showPanel
252 {
253     [o_window makeKeyAndOrderFront: self];
254 }
255
256 -(void)addError: (NSString *)o_error withMsg:(NSString *)o_msg
257 {
258     /* format our string as desired */
259     NSMutableAttributedString * ourError;
260     ourError = [[NSMutableAttributedString alloc] initWithString:
261         [NSString stringWithFormat:@"%@\n%@", o_error, o_msg]
262         attributes:
263         [NSDictionary dictionaryWithObject: [NSFont systemFontOfSize:11] forKey: NSFontAttributeName]];
264     [ourError
265         addAttribute: NSFontAttributeName
266         value: [NSFont boldSystemFontOfSize:11]
267         range: NSMakeRange(0, [o_error length])];
268     [o_errors addObject: ourError];
269     [ourError release];
270
271     [o_icons addObject: [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kAlertStopIcon)]];
272
273     [o_error_table reloadData];
274 }
275
276 -(IBAction)cleanupTable:(id)sender
277 {
278     [o_errors removeAllObjects];
279     [o_icons removeAllObjects];
280     [o_error_table reloadData];
281 }
282
283 /*----------------------------------------------------------------------------
284  * data source methods
285  *---------------------------------------------------------------------------*/
286 - (NSInteger)numberOfRowsInTableView:(NSTableView *)theDataTable
287 {
288     return [o_errors count];
289 }
290
291 - (id)tableView:(NSTableView *)theDataTable objectValueForTableColumn:
292     (NSTableColumn *)theTableColumn row: (NSInteger)row
293 {
294     if ([[theTableColumn identifier] isEqualToString: @"error_msg"])
295         return [o_errors objectAtIndex:row];
296
297     if ([[theTableColumn identifier] isEqualToString: @"icon"])
298         return [o_icons objectAtIndex:row];
299
300     return @"unknown identifier";
301 }
302
303 @end