1 /*****************************************************************************
2 * interaction.h: Mac OS X interaction dialogs
3 *****************************************************************************
4 * Copyright (C) 2005-2007 the VideoLAN team
7 * Authors: Derk-Jan Hartman <hartman at videolan dot org>
8 * Felix Kühne <fkuehne at videolan dot org>
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.
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.
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 *****************************************************************************/
26 #import "interaction.h"
28 /* for the icons in our custom error panel */
29 #import <ApplicationServices/ApplicationServices.h>
31 /*****************************************************************************
32 * VLCInteractionList implementation
33 *****************************************************************************/
34 @implementation VLCInteractionList
39 o_interaction_list = [[NSMutableArray alloc] initWithCapacity:1];
40 [[NSNotificationCenter defaultCenter] addObserver:self
41 selector:@selector(newInteractionEvent:)
42 name: @"VLCNewInteractionEventNotification"
45 o_error_panel = [[VLCErrorInteractionPanel alloc] init];
50 -(void)newInteractionEvent: (NSNotification *)o_notification
52 VLCInteraction *o_interaction;
53 NSValue *o_value = [[o_notification userInfo] objectForKey:@"VLCDialogPointer"];
54 interaction_dialog_t *p_dialog = [o_value pointerValue];
56 switch( p_dialog->i_action )
59 [self addInteraction: p_dialog];
62 o_interaction = (VLCInteraction *)p_dialog->p_private;
63 [o_interaction updateDialog];
66 o_interaction = (VLCInteraction *)p_dialog->p_private;
67 [o_interaction hideDialog];
69 case INTERACT_DESTROY:
70 o_interaction = (VLCInteraction *)p_dialog->p_private;
71 [o_interaction destroyDialog];
72 [self removeInteraction:o_interaction];
73 p_dialog->i_status = DESTROYED_DIALOG;
78 -(void)addInteraction: (interaction_dialog_t *)p_dialog
80 VLCInteraction *o_interaction = [[VLCInteraction alloc] initDialog: p_dialog];
82 p_dialog->p_private = (void *)o_interaction;
83 [o_interaction_list addObject:[o_interaction autorelease]];
84 [o_interaction runDialog];
87 -(void)removeInteraction: (VLCInteraction *)o_interaction
89 [o_interaction_list removeObject:o_interaction];
100 /* dealloc doesn't get called on 10.5 if GC is enabled, so we need to provide the basic functionality here */
101 [[NSNotificationCenter defaultCenter] removeObserver:self];
102 [o_interaction_list removeAllObjects];
109 [[NSNotificationCenter defaultCenter] removeObserver:self];
110 [o_interaction_list removeAllObjects];
111 [o_interaction_list release];
116 /*****************************************************************************
117 * VLCInteraction implementation
118 *****************************************************************************/
119 @implementation VLCInteraction
121 -(id)initDialog: (interaction_dialog_t *)_p_dialog
125 p_dialog = _p_dialog;
133 msg_Err( p_intf, "no available interaction framework" );
135 if( !nib_interact_loaded )
137 nib_interact_loaded = [NSBundle loadNibNamed:@"Interaction" owner:self];
138 [o_prog_cancel_btn setTitle: _NS("Cancel")];
139 [o_prog_bar setUsesThreadedAnimation: YES];
140 [o_auth_login_txt setStringValue: _NS("Login:")];
141 [o_auth_pw_txt setStringValue: _NS("Password:")];
142 [o_auth_cancel_btn setTitle: _NS("Cancel")];
143 [o_auth_ok_btn setTitle: _NS("OK")];
144 [o_input_ok_btn setTitle: _NS("OK")];
145 [o_input_cancel_btn setTitle: _NS("Cancel")];
146 o_mainIntfPgbar = [[VLCMain sharedInstance] getMainIntfPgbar];
149 NSString *o_title = [NSString stringWithUTF8String:p_dialog->psz_title ? p_dialog->psz_title : _("Error")];
150 NSString *o_description = [NSString stringWithUTF8String:p_dialog->psz_description ? p_dialog->psz_description : ""];
151 NSString *o_defaultButton = p_dialog->psz_default_button ? [NSString stringWithUTF8String:p_dialog->psz_default_button] : nil;
152 NSString *o_alternateButton = p_dialog->psz_alternate_button ? [NSString stringWithUTF8String:p_dialog->psz_alternate_button] : nil;
153 NSString *o_otherButton = p_dialog->psz_other_button ? [NSString stringWithUTF8String:p_dialog->psz_other_button] : nil;
155 vout_thread_t *p_vout = vlc_object_find( VLCIntf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
158 NSEnumerator * o_enum = [[NSApp orderedWindows] objectEnumerator];
160 while( ( o_window = [o_enum nextObject] ) )
162 if( [[o_window className] isEqualToString: @"VLCVoutWindow"] )
164 vlc_object_release( (vlc_object_t *)p_vout );
168 vlc_object_release( (vlc_object_t *)p_vout );
172 o_window = [NSApp mainWindow];
176 msg_Dbg( p_intf, "Title: %s", [o_title UTF8String] );
177 msg_Dbg( p_intf, "Description: %s", [o_description UTF8String] );
178 msg_Dbg( p_intf, "Delivered flag: %i", p_dialog->i_flags );
181 if( p_dialog->i_flags & DIALOG_BLOCKING_ERROR )
183 msg_Dbg( p_intf, "error panel requested" );
184 NSBeginInformationalAlertSheet( o_title, _NS("OK"), nil, nil,
185 o_window, self, @selector(sheetDidEnd: returnCode: contextInfo:),
186 NULL, nil, o_description );
188 else if( p_dialog->i_flags & DIALOG_NONBLOCKING_ERROR )
190 msg_Dbg( p_intf, "addition to non-blocking error panel received" );
191 [[[[VLCMain sharedInstance] getInteractionList] getErrorPanel]
192 addError: o_title withMsg: o_description];
194 else if( p_dialog->i_flags & DIALOG_WARNING )
196 msg_Dbg( p_intf, "addition to non-blocking warning panel received" );
197 [[[[VLCMain sharedInstance] getInteractionList] getErrorPanel]
198 addWarning: o_title withMsg: o_description];
200 else if( p_dialog->i_flags & DIALOG_YES_NO_CANCEL )
202 msg_Dbg( p_intf, "yes-no-cancel-dialog requested" );
203 NSBeginInformationalAlertSheet( o_title, o_defaultButton,
204 o_alternateButton, o_otherButton, o_window, self,
205 @selector(sheetDidEnd: returnCode: contextInfo:), NULL, nil,
208 else if( p_dialog->i_flags & DIALOG_LOGIN_PW_OK_CANCEL )
210 msg_Dbg( p_intf, "dialog for login and pw requested" );
211 [o_auth_title setStringValue: o_title];
212 [o_auth_description setStringValue: o_description];
213 [o_auth_login_fld setStringValue: @""];
214 [o_auth_pw_fld setStringValue: @""];
215 [NSApp beginSheet: o_auth_win modalForWindow: o_window
216 modalDelegate: self didEndSelector: nil contextInfo: nil];
217 [o_auth_win makeKeyWindow];
219 else if( p_dialog->i_flags & DIALOG_USER_PROGRESS )
221 msg_Dbg( p_intf, "user progress dialog requested" );
222 [o_prog_title setStringValue: o_title];
223 [o_prog_description setStringValue: o_description];
224 [o_prog_bar setDoubleValue: (double)p_dialog->val.f_float];
225 if( p_dialog->i_timeToGo < 1 )
226 [o_prog_timeToGo setStringValue: @""];
228 [o_prog_timeToGo setStringValue: [NSString stringWithFormat:
229 _NS("Remaining time: %i seconds"), p_dialog->i_timeToGo]];
230 [NSApp beginSheet: o_prog_win modalForWindow: o_window
231 modalDelegate: self didEndSelector: nil contextInfo: nil];
232 [o_prog_win makeKeyWindow];
234 else if( p_dialog->i_flags & DIALOG_PSZ_INPUT_OK_CANCEL )
236 msg_Dbg( p_intf, "text input from user requested" );
237 [o_input_title setStringValue: o_title];
238 [o_input_description setStringValue: o_description];
239 [o_input_fld setStringValue: @""];
240 [NSApp beginSheet: o_input_win modalForWindow: o_window
241 modalDelegate: self didEndSelector: nil contextInfo: nil];
242 [o_input_win makeKeyWindow];
244 else if( p_dialog->i_flags & DIALOG_INTF_PROGRESS )
246 msg_Dbg( p_intf, "progress-bar in main intf requested" );
247 [[VLCMain sharedInstance] setScrollField: o_description stopAfter: -1];
248 [o_mainIntfPgbar setDoubleValue: (double)p_dialog->val.f_float];
249 [o_mainIntfPgbar setHidden: NO];
250 [[[VLCMain sharedInstance] getControllerWindow] makeKeyWindow];
251 [o_mainIntfPgbar setIndeterminate: NO];
254 msg_Err( p_intf, "requested dialog type unknown (%i)", p_dialog->i_flags );
257 - (void)sheetDidEnd:(NSWindow *)o_sheet returnCode:(int)i_return
258 contextInfo:(void *)o_context
260 vlc_mutex_lock( &p_dialog->p_interaction->object_lock );
261 if( i_return == NSAlertDefaultReturn )
263 p_dialog->i_return = DIALOG_OK_YES;
265 else if( i_return == NSAlertAlternateReturn )
267 p_dialog->i_return = DIALOG_NO;
269 else if( i_return == NSAlertOtherReturn )
271 p_dialog->i_return = DIALOG_CANCELLED;
273 p_dialog->i_status = ANSWERED_DIALOG;
274 vlc_mutex_unlock( &p_dialog->p_interaction->object_lock );
279 if( p_dialog->i_flags & DIALOG_USER_PROGRESS )
281 [o_prog_description setStringValue: \
282 [NSString stringWithUTF8String: p_dialog->psz_description]];
283 [o_prog_bar setDoubleValue: (double)p_dialog->val.f_float];
285 if( [o_prog_bar doubleValue] == 100.0 )
287 /* we are done, let's hide */
291 if( p_dialog->i_timeToGo < 1 )
292 [o_prog_timeToGo setStringValue: @""];
294 [o_prog_timeToGo setStringValue: [NSString stringWithFormat:
295 _NS("Remaining time: %i seconds"), p_dialog->i_timeToGo]];
299 if( p_dialog->i_flags & DIALOG_INTF_PROGRESS )
301 [[VLCMain sharedInstance] setScrollField:
302 [NSString stringWithUTF8String: p_dialog->psz_description]
304 [o_mainIntfPgbar setDoubleValue: (double)p_dialog->val.f_float];
306 if( [o_mainIntfPgbar doubleValue] == 100.0 )
308 /* we are done, let's hide */
317 msg_Dbg( p_intf, "hide event" );
318 if( p_dialog->i_flags & DIALOG_USER_PROGRESS )
320 [NSApp endSheet: o_prog_win];
323 if( p_dialog->i_flags & DIALOG_LOGIN_PW_OK_CANCEL )
325 [NSApp endSheet: o_auth_win];
328 if( p_dialog->i_flags & DIALOG_PSZ_INPUT_OK_CANCEL )
330 [NSApp endSheet: o_input_win];
333 if( p_dialog->i_flags & DIALOG_INTF_PROGRESS )
335 [o_mainIntfPgbar setIndeterminate: YES];
336 [o_mainIntfPgbar setHidden: YES];
337 [[VLCMain sharedInstance] resetScrollField];
343 msg_Dbg( p_intf, "destroy event" );
344 if( o_mainIntfPgbar )
345 [o_mainIntfPgbar release];
348 - (IBAction)cancelAndClose:(id)sender
350 /* tell the core that the dialog was cancelled in a yes/no-style dialogue */
351 vlc_mutex_lock( &p_dialog->p_interaction->object_lock );
352 p_dialog->i_return = DIALOG_CANCELLED;
353 p_dialog->i_status = ANSWERED_DIALOG;
354 vlc_mutex_unlock( &p_dialog->p_interaction->object_lock );
355 msg_Dbg( p_intf, "dialog cancelled" );
358 - (IBAction)cancelDialog:(id)sender
360 /* tell core that the user wishes to cancel the dialogue
361 * Use this function if cancelling is optionally like in the progress-dialogue */
362 vlc_mutex_lock( &p_dialog->p_interaction->object_lock );
363 p_dialog->b_cancelled = VLC_TRUE;
364 vlc_mutex_unlock( &p_dialog->p_interaction->object_lock );
365 msg_Dbg( p_intf, "cancelling dialog, will close it later on" );
368 - (IBAction)okayAndClose:(id)sender
370 msg_Dbg( p_intf, "running okayAndClose" );
371 vlc_mutex_lock( &p_dialog->p_interaction->object_lock );
372 if( p_dialog->i_flags == DIALOG_LOGIN_PW_OK_CANCEL )
374 p_dialog->psz_returned[0] = strdup( [[o_auth_login_fld stringValue] UTF8String] );
375 p_dialog->psz_returned[1] = strdup( [[o_auth_pw_fld stringValue] UTF8String] );
377 else if( p_dialog->i_flags == DIALOG_PSZ_INPUT_OK_CANCEL )
378 p_dialog->psz_returned[0] = strdup( [[o_input_fld stringValue] UTF8String] );
379 p_dialog->i_return = DIALOG_OK_YES;
380 p_dialog->i_status = ANSWERED_DIALOG;
381 vlc_mutex_unlock( &p_dialog->p_interaction->object_lock );
382 msg_Dbg( p_intf, "dialog acknowledged" );
387 /*****************************************************************************
388 * VLCErrorInteractionPanel implementation
389 *****************************************************************************/
390 @implementation VLCErrorInteractionPanel
396 nib_interact_errpanel_loaded = [NSBundle loadNibNamed:@"InteractionErrorPanel" owner:self];
399 [o_window setTitle: _NS("Errors and Warnings")];
400 [o_cleanup_button setTitle: _NS("Clean up")];
401 [o_messages_btn setTitle: _NS("Show Details")];
403 /* init data sources */
404 o_errors = [[NSMutableArray alloc] init];
405 o_icons = [[NSMutableArray alloc] init];
407 /* ugly Carbon stuff following...
408 * regrettably, you can't get the icons through clean Cocoa */
410 /* retrieve our error icon */
413 returnValue = GetIconRef(kOnSystemDisk, 'macs', 'stop', &ourIconRef);
414 errorIcon = [[NSImage alloc] initWithSize:NSMakeSize(32,32)];
415 [errorIcon lockFocus];
416 CGRect rect = CGRectMake(0,0,32,32);
417 PlotIconRefInContext((CGContextRef)[[NSGraphicsContext currentContext]
422 NULL /*inLabelColor*/,
423 kPlotIconRefNormalFlags,
424 (IconRef)ourIconRef);
425 [errorIcon unlockFocus];
426 returnValue = ReleaseIconRef(ourIconRef);
428 /* retrieve our caution icon */
429 returnValue = GetIconRef(kOnSystemDisk, 'macs', 'caut', &ourIconRef);
430 warnIcon = [[NSImage alloc] initWithSize:NSMakeSize(32,32)];
431 [warnIcon lockFocus];
432 PlotIconRefInContext((CGContextRef)[[NSGraphicsContext currentContext]
437 NULL /*inLabelColor*/,
438 kPlotIconRefNormalFlags,
439 (IconRef)ourIconRef);
440 [warnIcon unlockFocus];
441 returnValue = ReleaseIconRef(ourIconRef);
457 [o_window makeKeyAndOrderFront: self];
460 -(void)addError: (NSString *)o_error withMsg:(NSString *)o_msg
462 /* format our string as desired */
463 NSMutableAttributedString * ourError;
464 ourError = [[NSMutableAttributedString alloc] initWithString:
465 [NSString stringWithFormat:@"%@\n%@", o_error, o_msg]
467 [NSDictionary dictionaryWithObject: [NSFont systemFontOfSize:11] forKey: NSFontAttributeName]];
469 addAttribute: NSFontAttributeName
470 value: [NSFont boldSystemFontOfSize:11]
471 range: NSMakeRange( 0, [o_error length])];
472 [o_errors addObject: ourError];
475 [o_icons addObject: errorIcon];
477 [o_error_table reloadData];
481 -(void)addWarning: (NSString *)o_warning withMsg:(NSString *)o_msg
483 /* format our string as desired */
484 NSMutableAttributedString * ourWarning;
485 ourWarning = [[NSMutableAttributedString alloc] initWithString:
486 [NSString stringWithFormat:@"%@\n%@", o_warning, o_msg]
488 [NSDictionary dictionaryWithObject: [NSFont systemFontOfSize:11] forKey: NSFontAttributeName]];
490 addAttribute: NSFontAttributeName
491 value: [NSFont boldSystemFontOfSize:11]
492 range: NSMakeRange( 0, [o_warning length])];
493 [o_errors addObject: ourWarning];
494 [ourWarning release];
496 [o_icons addObject: warnIcon];
498 [o_error_table reloadData];
503 -(IBAction)cleanupTable:(id)sender
505 [o_errors removeAllObjects];
506 [o_icons removeAllObjects];
507 [o_error_table reloadData];
510 -(IBAction)showMessages:(id)sender
512 [[VLCMain sharedInstance] showMessagesPanel: sender];
515 /*----------------------------------------------------------------------------
516 * data source methods
517 *---------------------------------------------------------------------------*/
518 - (int)numberOfRowsInTableView:(NSTableView *)theDataTable
520 return [o_errors count];
523 - (id)tableView:(NSTableView *)theDataTable objectValueForTableColumn:
524 (NSTableColumn *)theTableColumn row: (int)row
526 if( [[theTableColumn identifier] isEqualToString: @"error_msg"] )
527 return [o_errors objectAtIndex: row];
529 if( [[theTableColumn identifier] isEqualToString: @"icon"] )
530 return [o_icons objectAtIndex: row];
532 return @"unknown identifier";