]> git.sesse.net Git - vlc/blob - modules/gui/macosx/interaction.m
macosx: Use input_ItemHasErrorWhenReading to display a small icon if there was an...
[vlc] / modules / gui / macosx / interaction.m
1 /*****************************************************************************
2  * interaction.h: Mac OS X interaction dialogs
3  *****************************************************************************
4  * Copyright (C) 2005-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Derk-Jan Hartman <hartman at videolan dot org>
8  *          Felix 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 "interaction.h"
27 #import "misc.h"
28
29 /* for the icons in our custom error panel */
30 #import <ApplicationServices/ApplicationServices.h>
31
32 /*****************************************************************************
33  * VLCInteractionList implementation
34  *****************************************************************************/
35 @implementation VLCInteractionList
36
37 -(id)init
38 {
39     [super init];
40     o_interaction_list = [[NSMutableArray alloc] initWithCapacity:1];
41     [[NSNotificationCenter defaultCenter] addObserver:self
42         selector:@selector(newInteractionEvent:)
43         name: @"VLCNewInteractionEventNotification"
44         object:self];
45
46     o_error_panel = [[VLCErrorInteractionPanel alloc] init];
47
48     return self;
49 }
50
51 -(void)newInteractionEvent: (NSNotification *)o_notification
52 {
53     VLCInteraction *o_interaction;
54     NSValue *o_value = [[o_notification userInfo] objectForKey:@"VLCDialogPointer"];
55     interaction_dialog_t *p_dialog = [o_value pointerValue];
56
57     switch( p_dialog->i_action )
58     {
59     case INTERACT_NEW:
60         [self addInteraction: p_dialog];
61         break;
62     case INTERACT_UPDATE:
63         o_interaction = (VLCInteraction *)p_dialog->p_private;
64         [o_interaction updateDialog];
65         break;
66     case INTERACT_HIDE:
67         o_interaction = (VLCInteraction *)p_dialog->p_private;
68         [o_interaction hideDialog];
69         break;
70     case INTERACT_DESTROY:
71         o_interaction = (VLCInteraction *)p_dialog->p_private;
72         [o_interaction destroyDialog];
73         [self removeInteraction:o_interaction];
74         p_dialog->i_status = DESTROYED_DIALOG;
75         break;
76     }
77 }
78
79 -(void)addInteraction: (interaction_dialog_t *)p_dialog
80 {
81     VLCInteraction *o_interaction = [[VLCInteraction alloc] initDialog: p_dialog];
82  
83     p_dialog->p_private = (void *)o_interaction;
84     [o_interaction_list addObject:[o_interaction autorelease]];
85     [o_interaction runDialog];
86 }
87
88 -(void)removeInteraction: (VLCInteraction *)o_interaction
89 {
90     [o_interaction_list removeObject:o_interaction];
91 }
92
93 -(id)getErrorPanel
94 {
95     return o_error_panel;
96 }
97
98 -(void)dealloc
99 {
100     [[NSNotificationCenter defaultCenter] removeObserver:self];
101     [o_interaction_list removeAllObjects];
102     [o_interaction_list release];
103     [super dealloc];
104 }
105 @end
106
107 /*****************************************************************************
108  * VLCInteraction implementation
109  *****************************************************************************/
110 @implementation VLCInteraction
111
112 -(id)initDialog: (interaction_dialog_t *)_p_dialog
113 {
114     p_intf = VLCIntf;
115     [super init];
116     p_dialog = _p_dialog;
117     return self;
118 }
119
120 -(void)runDialog
121 {
122     id o_window = NULL;
123     if( !p_dialog )
124         msg_Err( p_intf, "no available interaction framework" );
125
126     if( !nib_interact_loaded )
127     {
128         nib_interact_loaded = [NSBundle loadNibNamed:@"Interaction" owner:self];
129         [o_prog_cancel_btn setTitle: _NS("Cancel")];
130         [o_prog_bar setUsesThreadedAnimation: YES];
131         [o_auth_login_txt setStringValue: _NS("Login:")];
132         [o_auth_pw_txt setStringValue: _NS("Password:")];
133         [o_auth_cancel_btn setTitle: _NS("Cancel")];
134         [o_auth_ok_btn setTitle: _NS("OK")];
135         [o_input_ok_btn setTitle: _NS("OK")];
136         [o_input_cancel_btn setTitle: _NS("Cancel")];
137         o_mainIntfPgbar = [[VLCMain sharedInstance] getMainIntfPgbar];
138     }
139
140     NSString *o_title = [NSString stringWithUTF8String:p_dialog->psz_title ? p_dialog->psz_title : _("Error")];
141     NSString *o_description = [NSString stringWithUTF8String:p_dialog->psz_description ? p_dialog->psz_description : ""];
142     NSString *o_defaultButton = p_dialog->psz_default_button ? [NSString stringWithUTF8String:p_dialog->psz_default_button] : nil;
143     NSString *o_alternateButton = p_dialog->psz_alternate_button ? [NSString stringWithUTF8String:p_dialog->psz_alternate_button] : nil;
144     NSString *o_otherButton = p_dialog->psz_other_button ? [NSString stringWithUTF8String:p_dialog->psz_other_button] : nil;
145
146     vout_thread_t *p_vout = vlc_object_find( VLCIntf, VLC_OBJECT_VOUT, FIND_ANYWHERE );
147     if( p_vout != NULL )
148     {
149         NSEnumerator * o_enum = [[NSApp orderedWindows] objectEnumerator];
150
151         while( ( o_window = [o_enum nextObject] ) )
152         {
153             if( [[o_window className] isEqualToString: @"VLCVoutWindow"] )
154             {
155                 vlc_object_release( (vlc_object_t *)p_vout );
156                 break;
157             }
158         }
159         vlc_object_release( (vlc_object_t *)p_vout );
160     }
161     else
162     {
163         o_window = [NSApp mainWindow];
164     }
165
166 #if 0
167     msg_Dbg( p_intf, "Title: %s", [o_title UTF8String] );
168     msg_Dbg( p_intf, "Description: %s", [o_description UTF8String] );
169     msg_Dbg( p_intf, "Delivered flag: %i", p_dialog->i_flags );
170 #endif
171
172     if( p_dialog->i_flags & DIALOG_BLOCKING_ERROR )
173     {
174         msg_Dbg( p_intf, "error panel requested" );
175         NSBeginInformationalAlertSheet( o_title, _NS("OK"), nil, nil,
176             o_window, self, @selector(sheetDidEnd: returnCode: contextInfo:),
177             NULL, nil, o_description );
178     }
179     else if( p_dialog->i_flags & DIALOG_NONBLOCKING_ERROR )
180     {
181         msg_Dbg( p_intf, "addition to non-blocking error panel received" );
182         [[[[VLCMain sharedInstance] getInteractionList] getErrorPanel]
183         addError: o_title withMsg: o_description];
184     }
185     else if( p_dialog->i_flags & DIALOG_WARNING )
186     {
187         msg_Dbg( p_intf, "addition to non-blocking warning panel received" );
188         [[[[VLCMain sharedInstance] getInteractionList] getErrorPanel]
189             addWarning: o_title withMsg: o_description];
190     }
191     else if( p_dialog->i_flags & DIALOG_YES_NO_CANCEL )
192     {
193         msg_Dbg( p_intf, "yes-no-cancel-dialog requested" );
194         NSBeginInformationalAlertSheet( o_title, o_defaultButton,
195             o_alternateButton, o_otherButton, o_window, self,
196             @selector(sheetDidEnd: returnCode: contextInfo:), NULL, nil,
197             o_description );
198     }
199     else if( p_dialog->i_flags & DIALOG_LOGIN_PW_OK_CANCEL )
200     {
201         msg_Dbg( p_intf, "dialog for login and pw requested" );
202         [o_auth_title setStringValue: o_title];
203         [o_auth_description setStringValue: o_description];
204         [o_auth_login_fld setStringValue: @""];
205         [o_auth_pw_fld setStringValue: @""];
206         [NSApp beginSheet: o_auth_win modalForWindow: o_window
207             modalDelegate: self didEndSelector: nil contextInfo: nil];
208         [o_auth_win makeKeyWindow];
209     }
210     else if( p_dialog->i_flags & DIALOG_USER_PROGRESS )
211     {
212         msg_Dbg( p_intf, "user progress dialog requested" );
213         [o_prog_title setStringValue: o_title];
214         [o_prog_description setStringValue: o_description];
215         [o_prog_bar setDoubleValue: (double)p_dialog->val.f_float];
216         if( p_dialog->i_timeToGo < 1 )
217             [o_prog_timeToGo setStringValue: @""];
218         else
219             [o_prog_timeToGo setStringValue: [NSString stringWithFormat:
220                 _NS("Remaining time: %i seconds"), p_dialog->i_timeToGo]];
221         [NSApp beginSheet: o_prog_win modalForWindow: o_window
222             modalDelegate: self didEndSelector: nil contextInfo: nil];
223         [o_prog_win makeKeyWindow];
224     }
225     else if( p_dialog->i_flags & DIALOG_PSZ_INPUT_OK_CANCEL )
226     {
227         msg_Dbg( p_intf, "text input from user requested" );
228         [o_input_title setStringValue: o_title];
229         [o_input_description setStringValue: o_description];
230         [o_input_fld setStringValue: @""];
231         [NSApp beginSheet: o_input_win modalForWindow: o_window
232             modalDelegate: self didEndSelector: nil contextInfo: nil];
233         [o_input_win makeKeyWindow];
234     }
235     else if( p_dialog->i_flags & DIALOG_INTF_PROGRESS )
236     {
237         msg_Dbg( p_intf, "progress-bar in main intf requested" );
238         [[VLCMain sharedInstance] setScrollField: o_description stopAfter: -1];
239         [o_mainIntfPgbar setDoubleValue: (double)p_dialog->val.f_float];
240         [o_mainIntfPgbar setHidden: NO];
241         [[[VLCMain sharedInstance] getControllerWindow] makeKeyWindow];
242         [o_mainIntfPgbar setIndeterminate: NO];
243     }
244     else
245         msg_Err( p_intf, "requested dialog type unknown (%i)", p_dialog->i_flags );
246 }
247
248 - (void)sheetDidEnd:(NSWindow *)o_sheet returnCode:(int)i_return
249     contextInfo:(void *)o_context
250 {
251     vlc_object_lock( p_dialog->p_interaction );
252     if( i_return == NSAlertDefaultReturn )
253     {
254         p_dialog->i_return = DIALOG_OK_YES;
255     }
256     else if( i_return == NSAlertAlternateReturn )
257     {
258         p_dialog->i_return = DIALOG_NO;
259     }
260     else if( i_return == NSAlertOtherReturn )
261     {
262         p_dialog->i_return = DIALOG_CANCELLED;
263     }
264     p_dialog->i_status = ANSWERED_DIALOG;
265     vlc_object_unlock( p_dialog->p_interaction );
266 }
267
268 -(void)updateDialog
269 {
270     if( p_dialog->i_flags & DIALOG_USER_PROGRESS )
271     {
272         [o_prog_description setStringValue:
273             [NSString stringWithUTF8String: p_dialog->psz_description]];
274         [o_prog_bar setDoubleValue: (double)p_dialog->val.f_float];
275
276         if( [o_prog_bar doubleValue] == 100.0 )
277         {
278             /* we are done, let's hide */
279             [self hideDialog];
280         }
281
282         if( p_dialog->i_timeToGo < 1 )
283             [o_prog_timeToGo setStringValue: @""];
284         else
285             [o_prog_timeToGo setStringValue: [NSString stringWithFormat:
286                     _NS("Remaining time: %i seconds"), p_dialog->i_timeToGo]];
287
288         return;
289     }
290     if( p_dialog->i_flags & DIALOG_INTF_PROGRESS )
291     {
292         [[VLCMain sharedInstance] setScrollField:
293             [NSString stringWithUTF8String: p_dialog->psz_description]
294             stopAfter: -1];
295         [o_mainIntfPgbar setDoubleValue: (double)p_dialog->val.f_float];
296
297         if( [o_mainIntfPgbar doubleValue] == 100.0 )
298         {
299             /* we are done, let's hide */
300             [self hideDialog];
301         }
302         return;
303     }
304 }
305
306 -(void)hideDialog
307 {
308     msg_Dbg( p_intf, "hide event %p", self );
309     if( p_dialog->i_flags & DIALOG_USER_PROGRESS )
310     {
311         if([o_prog_win isVisible])
312         {
313             [NSApp endSheet: o_prog_win];
314             [o_prog_win close];
315         }
316     }
317     if( p_dialog->i_flags & DIALOG_LOGIN_PW_OK_CANCEL )
318     {
319         if([o_auth_win isVisible])
320         {
321             [NSApp endSheet: o_auth_win];
322             [o_auth_win close];
323         }
324     }
325     if( p_dialog->i_flags & DIALOG_PSZ_INPUT_OK_CANCEL )
326     {
327         if([o_input_win isVisible])
328         {
329             [NSApp endSheet: o_input_win];
330             [o_input_win close];
331         }
332     }
333     if( p_dialog->i_flags & DIALOG_INTF_PROGRESS )
334     {
335         [o_mainIntfPgbar setIndeterminate: YES];
336         [o_mainIntfPgbar setHidden: YES];
337         [[VLCMain sharedInstance] resetScrollField];
338     }
339 }
340
341 -(void)destroyDialog
342 {
343     msg_Dbg( p_intf, "destroy event" );
344     if( o_mainIntfPgbar )
345         [o_mainIntfPgbar release];
346 }
347
348 - (IBAction)cancelAndClose:(id)sender
349 {
350     /* tell the core that the dialog was cancelled in a yes/no-style dialogue */
351     vlc_object_lock( p_dialog->p_interaction );
352     p_dialog->i_return = DIALOG_CANCELLED;
353     p_dialog->i_status = ANSWERED_DIALOG;
354     vlc_object_unlock( p_dialog->p_interaction );
355     msg_Dbg( p_intf, "dialog cancelled" );
356 }
357
358 - (IBAction)cancelDialog:(id)sender
359 {
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_object_lock( p_dialog->p_interaction );
363     p_dialog->b_cancelled = true;
364     vlc_object_unlock( p_dialog->p_interaction );
365     msg_Dbg( p_intf, "cancelling dialog, will close it later on" );
366 }
367
368 - (IBAction)okayAndClose:(id)sender
369 {
370     msg_Dbg( p_intf, "running okayAndClose" );
371     vlc_object_lock( p_dialog->p_interaction );
372     if( p_dialog->i_flags == DIALOG_LOGIN_PW_OK_CANCEL )
373     {
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] );
376     }
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_object_unlock( p_dialog->p_interaction );
382     msg_Dbg( p_intf, "dialog acknowledged" );
383 }
384
385 @end
386
387 /*****************************************************************************
388  * VLCErrorInteractionPanel implementation
389  *****************************************************************************/
390 @implementation VLCErrorInteractionPanel
391 -(id)init
392 {
393     [super init];
394
395     /* load the nib */
396     nib_interact_errpanel_loaded = [NSBundle loadNibNamed:@"InteractionErrorPanel" owner:self];
397
398     /* init strings */
399     [o_window setTitle: _NS("Errors and Warnings")];
400     [o_cleanup_button setTitle: _NS("Clean up")];
401     [o_messages_btn setTitle: _NS("Show Details")];
402
403     /* init data sources */
404     o_errors = [[NSMutableArray alloc] init];
405     o_icons = [[NSMutableArray alloc] init];
406
407     return self;
408 }
409
410 -(void)dealloc
411 {
412     [o_errors release];
413     [o_icons release];
414     [super dealloc];
415 }
416
417 -(void)showPanel
418 {
419     [o_window makeKeyAndOrderFront: self];
420 }
421
422 -(void)addError: (NSString *)o_error withMsg:(NSString *)o_msg
423 {
424     /* format our string as desired */
425     NSMutableAttributedString * ourError;
426     ourError = [[NSMutableAttributedString alloc] initWithString:
427         [NSString stringWithFormat:@"%@\n%@", o_error, o_msg]
428         attributes:
429         [NSDictionary dictionaryWithObject: [NSFont systemFontOfSize:11] forKey: NSFontAttributeName]];
430     [ourError
431         addAttribute: NSFontAttributeName
432         value: [NSFont boldSystemFontOfSize:11]
433         range: NSMakeRange( 0, [o_error length])];
434     [o_errors addObject: ourError];
435     [ourError release];
436
437     [o_icons addObject: [NSImage imageWithErrorIcon]];
438
439     [o_error_table reloadData];
440 }
441
442 -(void)addWarning: (NSString *)o_warning withMsg:(NSString *)o_msg
443 {
444     /* format our string as desired */
445     NSMutableAttributedString * ourWarning;
446     ourWarning = [[NSMutableAttributedString alloc] initWithString:
447         [NSString stringWithFormat:@"%@\n%@", o_warning, o_msg]
448         attributes:
449         [NSDictionary dictionaryWithObject: [NSFont systemFontOfSize:11] forKey: NSFontAttributeName]];
450     [ourWarning
451         addAttribute: NSFontAttributeName
452         value: [NSFont boldSystemFontOfSize:11]
453         range: NSMakeRange( 0, [o_warning length])];
454     [o_errors addObject: ourWarning];
455     [ourWarning release];
456
457     [o_icons addObject: [NSImage imageWithWarningIcon]];
458  
459     [o_error_table reloadData];
460 }
461
462 -(IBAction)cleanupTable:(id)sender
463 {
464     [o_errors removeAllObjects];
465     [o_icons removeAllObjects];
466     [o_error_table reloadData];
467 }
468
469 -(IBAction)showMessages:(id)sender
470 {
471     [[VLCMain sharedInstance] showMessagesPanel: sender];
472 }
473
474 /*----------------------------------------------------------------------------
475  * data source methods
476  *---------------------------------------------------------------------------*/
477 - (int)numberOfRowsInTableView:(NSTableView *)theDataTable
478 {
479     return [o_errors count];
480 }
481
482 - (id)tableView:(NSTableView *)theDataTable objectValueForTableColumn:
483     (NSTableColumn *)theTableColumn row: (int)row
484 {
485     if( [[theTableColumn identifier] isEqualToString: @"error_msg"] )
486         return [o_errors objectAtIndex: row];
487
488     if( [[theTableColumn identifier] isEqualToString: @"icon"] )
489         return [o_icons objectAtIndex: row];
490
491     return @"unknown identifier";
492 }
493
494 @end