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