]> git.sesse.net Git - vlc/blob - modules/gui/macosx/bookmarks.m
macosx: vlc object handling improvements (refs #6883)
[vlc] / modules / gui / macosx / bookmarks.m
1 /*****************************************************************************
2  * bookmarks.m: MacOS X Bookmarks window
3  *****************************************************************************
4  * Copyright (C) 2005 - 2012 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Felix Paul Kühne <fkuehne at videolan dot org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24
25 /*****************************************************************************
26  * Note:
27  * the code used to bind with VLC's modules is heavily based upon
28  * ../wxwidgets/bookmarks.cpp, written by Gildas Bazin.
29  * (he is a member of the VideoLAN team)
30  *****************************************************************************/
31
32
33 /*****************************************************************************
34  * Preamble
35  *****************************************************************************/
36
37 #import "bookmarks.h"
38 #import "wizard.h"
39 #import <vlc_interface.h>
40 #import "CompatibilityFixes.h"
41
42 @implementation VLCBookmarks
43
44 static VLCBookmarks *_o_sharedInstance = nil;
45
46 + (VLCBookmarks *)sharedInstance
47 {
48     return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
49 }
50
51 - (id)init
52 {
53     if (_o_sharedInstance) {
54         [self dealloc];
55     } else {
56         _o_sharedInstance = [super init];
57     }
58
59     return _o_sharedInstance;
60 }
61
62 /*****************************************************************************
63  * GUI methods
64  *****************************************************************************/
65
66 - (void)awakeFromNib
67 {
68     if (OSX_LION)
69         [o_bookmarks_window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenAuxiliary];
70
71     [self initStrings];
72 }
73
74 - (void)dealloc
75 {
76     if (p_old_input)
77         vlc_object_release( p_old_input );
78
79     [super dealloc];
80 }
81
82 - (void)initStrings
83 {
84     /* localise the items */
85
86     /* main window */
87     [o_bookmarks_window setTitle: _NS("Bookmarks")];
88     [o_btn_add setTitle: _NS("Add")];
89     [o_btn_clear setTitle: _NS("Clear")];
90     [o_btn_edit setTitle: _NS("Edit")];
91     [o_btn_extract setTitle: _NS("Extract")];
92     [o_btn_rm setTitle: _NS("Remove")];
93     [[[o_tbl_dataTable tableColumnWithIdentifier:@"description"] headerCell]
94         setStringValue: _NS("Description")];
95     [[[o_tbl_dataTable tableColumnWithIdentifier:@"size_offset"] headerCell]
96         setStringValue: _NS("Position")];
97     [[[o_tbl_dataTable tableColumnWithIdentifier:@"time_offset"] headerCell]
98         setStringValue: _NS("Time")];
99
100     /* edit window */
101     [o_edit_btn_ok setTitle: _NS("OK")];
102     [o_edit_btn_cancel setTitle: _NS("Cancel")];
103     [o_edit_lbl_name setStringValue: _NS("Name")];
104     [o_edit_lbl_time setStringValue: _NS("Time")];
105     [o_edit_lbl_bytes setStringValue: _NS("Position")];
106 }
107
108 - (void)showBookmarks
109 {
110     /* show the window, called from intf.m */
111     [o_bookmarks_window displayIfNeeded];
112     [o_bookmarks_window makeKeyAndOrderFront:nil];
113 }
114
115 - (IBAction)add:(id)sender
116 {
117     /* add item to list */
118     input_thread_t * p_input = pl_CurrentInput( VLCIntf );
119
120     if( !p_input ) return;
121
122     seekpoint_t bookmark;
123
124     if( !input_Control( p_input, INPUT_GET_BOOKMARK, &bookmark ) )
125     {
126         bookmark.psz_name = _("Untitled");
127         input_Control( p_input, INPUT_ADD_BOOKMARK, &bookmark );
128     }
129
130     vlc_object_release( p_input );
131
132     [o_tbl_dataTable reloadData];
133 }
134
135 - (IBAction)clear:(id)sender
136 {
137     /* clear table */
138     input_thread_t * p_input = pl_CurrentInput( VLCIntf );
139
140     if( !p_input )
141         return;
142
143     input_Control( p_input, INPUT_CLEAR_BOOKMARKS );
144
145     vlc_object_release( p_input );
146
147     [o_tbl_dataTable reloadData];
148 }
149
150 - (IBAction)edit:(id)sender
151 {
152     /* put values to the sheet's fields and show sheet */
153     /* we take the values from the core and not the table, because we cannot
154      * really trust it */
155     input_thread_t * p_input = pl_CurrentInput( VLCIntf );
156     seekpoint_t **pp_bookmarks;
157     int i_bookmarks;
158     int row;
159     row = [o_tbl_dataTable selectedRow];
160
161     if( !p_input )
162         return;
163
164     if( row < 0 )
165     {
166         vlc_object_release( p_input );
167         return;
168     }
169
170     if( input_Control( p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks,
171         &i_bookmarks ) != VLC_SUCCESS )
172     {
173         vlc_object_release( p_input );
174         return;
175     }
176
177     [o_edit_fld_name setStringValue: [NSString stringWithUTF8String:
178             pp_bookmarks[row]->psz_name]];
179     [o_edit_fld_time setStringValue: [[NSNumber numberWithInt:
180             (pp_bookmarks[row]->i_time_offset / 1000000)] stringValue]];
181     [o_edit_fld_bytes setStringValue: [[NSNumber numberWithInt:
182             pp_bookmarks[row]->i_byte_offset] stringValue]];
183
184     /* Just keep the pointer value to check if it
185      * changes. Note, we don't need to keep a reference to the object.
186      * so release it now. */
187     p_old_input = p_input;
188     vlc_object_release( p_input );
189
190     [NSApp beginSheet: o_edit_window
191         modalForWindow: o_bookmarks_window
192         modalDelegate: o_edit_window
193         didEndSelector: nil
194         contextInfo: nil];
195
196     // Clear the bookmark list
197     for( int i = 0; i < i_bookmarks; i++)
198         vlc_seekpoint_Delete( pp_bookmarks[i] );
199     free( pp_bookmarks );
200
201 }
202
203 - (IBAction)edit_cancel:(id)sender
204 {
205     /* close sheet */
206     [NSApp endSheet:o_edit_window];
207     [o_edit_window close];
208 }
209
210 - (IBAction)edit_ok:(id)sender
211 {
212     /* save field contents and close sheet */
213      seekpoint_t **pp_bookmarks;
214     int i_bookmarks, i;
215     input_thread_t * p_input = pl_CurrentInput( VLCIntf );
216
217     if( !p_input )
218     {
219         NSBeginCriticalAlertSheet(_NS("No input"), _NS("OK"),
220                 @"", @"", o_bookmarks_window, nil, nil, nil, nil, _NS("No "
221                 "input found. A stream must be playing or paused for "
222                 "bookmarks to work."));
223         return;
224     }
225     if( p_old_input != p_input )
226     {
227         NSBeginCriticalAlertSheet(_NS("Input has changed"), _NS("OK"),
228             @"", @"", o_bookmarks_window, nil, nil, nil, nil, _NS("Input "
229             "has changed, unable to save bookmark. Suspending playback with "
230             "\"Pause\" while editing bookmarks to ensure to keep the same "
231             "input."));
232         vlc_object_release( p_input );
233         return;
234     }
235
236     if( input_Control( p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks,
237         &i_bookmarks ) != VLC_SUCCESS )
238     {
239         vlc_object_release( p_input );
240         return;
241     }
242
243     i = [o_tbl_dataTable selectedRow];
244
245     free( pp_bookmarks[i]->psz_name );
246
247     pp_bookmarks[i]->psz_name = strdup([[o_edit_fld_name stringValue] UTF8String]);
248     pp_bookmarks[i]->i_byte_offset = [[o_edit_fld_bytes stringValue] intValue];
249     pp_bookmarks[i]->i_time_offset = ([[o_edit_fld_time stringValue] intValue]  * 1000000);
250
251     if( input_Control( p_input, INPUT_CHANGE_BOOKMARK, pp_bookmarks[i], i )
252         != VLC_SUCCESS )
253     {
254         msg_Warn( VLCIntf, "Unable to change the bookmark");
255         goto clear;
256     }
257
258     [o_tbl_dataTable reloadData];
259     vlc_object_release( p_input );
260
261
262     [NSApp endSheet: o_edit_window];
263     [o_edit_window close];
264
265 clear:
266     // Clear the bookmark list
267     for( int i = 0; i < i_bookmarks; i++)
268         vlc_seekpoint_Delete( pp_bookmarks[i] );
269     free( pp_bookmarks );
270 }
271
272 - (IBAction)extract:(id)sender
273 {
274     /* extract */
275     if( [o_tbl_dataTable numberOfSelectedRows] < 2 )
276     {
277         NSBeginAlertSheet(_NS("Invalid selection"), _NS("OK"),
278             @"", @"", o_bookmarks_window, nil, nil, nil, nil,
279             _NS("Two bookmarks have to be selected."));
280         return;
281     }
282     input_thread_t * p_input = pl_CurrentInput( VLCIntf );
283     if( !p_input )
284     {
285         NSBeginCriticalAlertSheet(_NS("No input found"), _NS("OK"),
286             @"", @"", o_bookmarks_window, nil, nil, nil, nil,
287             _NS("The stream must be playing or paused for bookmarks to work."));
288         return;
289     }
290
291     seekpoint_t **pp_bookmarks;
292     int i_bookmarks ;
293     int i_first = -1;
294     int i_second = -1;
295     int c = 0;
296     for (NSUInteger x = 0; c != 2; x++)
297     {
298         if([o_tbl_dataTable isRowSelected:x])
299         {
300             if (i_first == -1)
301             {
302                 i_first = x;
303                 c = 1;
304             }
305             else if (i_second == -1)
306             {
307                 i_second = x;
308                 c = 2;
309             }
310         }
311     }
312
313     msg_Dbg( VLCIntf, "got the bookmark-indexes");
314
315     if( input_Control( p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks,
316         &i_bookmarks ) != VLC_SUCCESS )
317     {
318         vlc_object_release( p_input );
319         msg_Err( VLCIntf, "already defined bookmarks couldn't be retrieved");
320         return;
321     }
322     msg_Dbg( VLCIntf, "calling wizard");
323
324     char *psz_uri = input_item_GetURI( input_GetItem( p_input ) );
325     [[[VLCMain sharedInstance] wizard] initWithExtractValuesFrom:
326             [[NSNumber numberWithInt:
327             (pp_bookmarks[i_first]->i_time_offset/1000000)] stringValue]
328             to: [[NSNumber numberWithInt:
329             (pp_bookmarks[i_second]->i_time_offset/1000000)] stringValue]
330             ofItem: [NSString stringWithUTF8String: psz_uri]];
331     free( psz_uri );
332     vlc_object_release( p_input );
333     msg_Dbg( VLCIntf, "released input");
334
335     // Clear the bookmark list
336     for( int i = 0; i < i_bookmarks; i++)
337         vlc_seekpoint_Delete( pp_bookmarks[i] );
338     free( pp_bookmarks );
339 }
340
341 - (IBAction)goToBookmark:(id)sender
342 {
343     input_thread_t * p_input = pl_CurrentInput( VLCIntf );
344
345     if( !p_input ) return;
346
347     input_Control( p_input, INPUT_SET_BOOKMARK, [o_tbl_dataTable selectedRow] );
348
349     vlc_object_release( p_input );
350 }
351
352 - (IBAction)remove:(id)sender
353 {
354     /* remove selected item */
355     input_thread_t * p_input = pl_CurrentInput( VLCIntf );
356
357     if( !p_input ) return;
358
359     int i_focused = [o_tbl_dataTable selectedRow];
360
361     if( i_focused >= 0 )
362         input_Control( p_input, INPUT_DEL_BOOKMARK, i_focused );
363
364     vlc_object_release( p_input );
365
366     [o_tbl_dataTable reloadData];
367 }
368
369 /*****************************************************************************
370  * callback stuff
371  *****************************************************************************/
372
373 -(id)dataTable
374 {
375     return o_tbl_dataTable;
376 }
377
378 /*****************************************************************************
379  * data source methods
380  *****************************************************************************/
381
382 - (NSInteger)numberOfRowsInTableView:(NSTableView *)theDataTable
383 {
384     /* return the number of bookmarks */
385     input_thread_t * p_input = pl_CurrentInput( VLCIntf );
386     seekpoint_t **pp_bookmarks;
387     int i_bookmarks;
388
389     if( !p_input ) return 0;
390     else if( input_Control( p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks,
391                        &i_bookmarks ) != VLC_SUCCESS )
392     {
393         vlc_object_release( p_input );
394         return 0;
395     }
396     else {
397         vlc_object_release( p_input );
398         // Clear the bookmark list
399         for( int i = 0; i < i_bookmarks; i++)
400             vlc_seekpoint_Delete( pp_bookmarks[i] );
401         free( pp_bookmarks );
402         return i_bookmarks;
403     }
404 }
405
406 - (id)tableView:(NSTableView *)theDataTable objectValueForTableColumn:
407     (NSTableColumn *)theTableColumn row: (NSInteger)row
408 {
409     /* return the corresponding data as NSString */
410     input_thread_t * p_input = pl_CurrentInput( VLCIntf );
411     seekpoint_t **pp_bookmarks;
412     int i_bookmarks;
413     char *toBeReturned;
414     int i_toBeReturned = 0;
415     id ret;
416
417     if( !p_input ) return @"";
418     else if( input_Control( p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks,
419                        &i_bookmarks ) != VLC_SUCCESS )
420     {
421         ret = @"";
422     }
423     else
424     {
425         NSString * identifier = [theTableColumn identifier];
426         if ([identifier isEqualToString: @"description"])
427         {
428             toBeReturned = pp_bookmarks[row]->psz_name;
429             ret = [NSString stringWithUTF8String: toBeReturned];
430         }
431         else if ([identifier isEqualToString: @"size_offset"])
432         {
433             i_toBeReturned = pp_bookmarks[row]->i_byte_offset;
434             ret = [[NSNumber numberWithInt: i_toBeReturned] stringValue];
435         }
436         else if ([identifier isEqualToString: @"time_offset"])
437         {
438             i_toBeReturned = pp_bookmarks[row]->i_time_offset;
439             ret = [[NSNumber numberWithInt: (i_toBeReturned / 1000000)]
440                 stringValue];
441         }
442         else
443         {
444             /* may not happen, just in case */
445             msg_Err( VLCIntf, "unknown table column identifier (%s) while "
446                 "updating the bookmark table", [identifier UTF8String] );
447             ret = @"unknown identifier";
448         }
449
450         // Clear the bookmark list
451         for( int i = 0; i < i_bookmarks; i++)
452             vlc_seekpoint_Delete( pp_bookmarks[i] );
453         free( pp_bookmarks );
454     }
455     vlc_object_release( p_input );
456     return ret;
457 }
458
459 /*****************************************************************************
460  * delegate methods
461  *****************************************************************************/
462
463 - (void)tableViewSelectionDidChange:(NSNotification *)aNotification
464 {
465     /* check whether a row is selected and en-/disable the edit/remove buttons */
466     if ([o_tbl_dataTable selectedRow] == -1)
467     {
468         /* no row is selected */
469         [o_btn_edit setEnabled: NO];
470         [o_btn_rm setEnabled: NO];
471         [o_btn_extract setEnabled: NO];
472     }
473     else
474     {
475         /* a row is selected */
476         [o_btn_edit setEnabled: YES];
477         [o_btn_rm setEnabled: YES];
478         if ([o_tbl_dataTable numberOfSelectedRows] == 2)
479         {
480             [o_btn_extract setEnabled: YES];
481         }
482     }
483 }
484
485 @end