]> git.sesse.net Git - vlc/blob - modules/gui/macosx/bookmarks.m
macosx: we need to import intf.h before any import of vlc/vlc.h, because it includes...
[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     if( pp_bookmarks[i]->psz_name )
253         free( pp_bookmarks[i]->psz_name );
254
255     pp_bookmarks[i]->psz_name = strdup([[o_edit_fld_name stringValue] UTF8String]);
256     pp_bookmarks[i]->i_byte_offset = [[o_edit_fld_bytes stringValue] intValue];
257     pp_bookmarks[i]->i_time_offset = ([[o_edit_fld_time stringValue] intValue]  * 1000000);
258  
259     if( input_Control( p_input, INPUT_CHANGE_BOOKMARK, pp_bookmarks[i], i )
260         != VLC_SUCCESS )
261     {
262         msg_Warn( p_intf, "Unable to change the bookmark");
263         vlc_object_release( p_input );
264         return;
265     }
266  
267     [o_tbl_dataTable reloadData];
268     vlc_object_release( p_input );
269  
270  
271     [NSApp endSheet: o_edit_window];
272     [o_edit_window close];
273 }
274
275 - (IBAction)extract:(id)sender
276 {
277     /* extract */
278  
279     intf_thread_t * p_intf = VLCIntf;
280  
281     if( [o_tbl_dataTable numberOfSelectedRows] < 2 )
282     {
283         NSBeginAlertSheet(_NS("Invalid selection"), _NS("OK"),
284             @"", @"", o_bookmarks_window, nil, nil, nil, nil,
285             _NS("Two bookmarks have to be selected."));
286         return;
287     }
288     input_thread_t *p_input =
289         (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
290                                            FIND_ANYWHERE );
291     if( !p_input )
292     {
293         NSBeginCriticalAlertSheet(_NS("No input found"), _NS("OK"),
294             @"", @"", o_bookmarks_window, nil, nil, nil, nil,
295             _NS("The stream must be playing or paused for bookmarks to work."));
296         return;
297     }
298  
299     seekpoint_t **pp_bookmarks;
300     int i_bookmarks ;
301     int i_first = -1;
302     int i_second = -1;
303     int x = 0;
304     int c = 0;
305     while (c != 2)
306     {
307         if([o_tbl_dataTable isRowSelected:x])
308         {
309             if (i_first == -1)
310             {
311                 i_first = x;
312                 c = 1;
313             }
314             else if (i_second == -1)
315             {
316                 i_second = x;
317                 c = 2;
318             }
319         }
320         x = (x + 1);
321     }
322  
323     msg_Dbg(p_intf, "got the bookmark-indexes");
324  
325     if( input_Control( p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks,
326         &i_bookmarks ) != VLC_SUCCESS )
327     {
328         vlc_object_release( p_input );
329         msg_Err(p_intf, "already defined bookmarks couldn't be retrieved");
330         return;
331     }
332     msg_Dbg(p_intf, "calling wizard");
333
334     char *psz_uri = input_item_GetURI( input_GetItem( p_input ) );
335     [[[VLCMain sharedInstance] getWizard] initWithExtractValuesFrom:
336             [[NSNumber numberWithInt:
337             (pp_bookmarks[i_first]->i_time_offset/1000000)] stringValue]
338             to: [[NSNumber numberWithInt:
339             (pp_bookmarks[i_second]->i_time_offset/1000000)] stringValue]
340             ofItem: [NSString stringWithUTF8String: psz_uri]];
341     free( psz_uri );
342     vlc_object_release( p_input );
343     msg_Dbg(p_intf, "released input");
344 }
345
346 - (IBAction)goToBookmark:(id)sender
347 {
348     intf_thread_t * p_intf = VLCIntf;
349     input_thread_t *p_input =
350     (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
351         FIND_ANYWHERE );
352  
353     if( !p_input ) return;
354
355     input_Control( p_input, INPUT_SET_BOOKMARK, [o_tbl_dataTable selectedRow] );
356
357     vlc_object_release( p_input );
358 }
359
360 - (IBAction)remove:(id)sender
361 {
362     /* remove selected item */
363     intf_thread_t * p_intf = VLCIntf;
364     input_thread_t *p_input =
365     (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
366         FIND_ANYWHERE );
367  
368     if( !p_input ) return;
369
370     int i_focused = [o_tbl_dataTable selectedRow];
371
372     if( i_focused >= 0 )
373         input_Control( p_input, INPUT_DEL_BOOKMARK, i_focused );
374
375     vlc_object_release( p_input );
376  
377     [o_tbl_dataTable reloadData];
378 }
379
380 /*****************************************************************************
381  * callback stuff
382  *****************************************************************************/
383
384 -(id)getDataTable
385 {
386     return o_tbl_dataTable;
387 }
388
389 /*****************************************************************************
390  * data source methods
391  *****************************************************************************/
392
393 - (int)numberOfRowsInTableView:(NSTableView *)theDataTable
394 {
395     /* return the number of bookmarks */
396     intf_thread_t * p_intf = VLCIntf;
397     input_thread_t * p_input = (input_thread_t *)vlc_object_find( p_intf,
398         VLC_OBJECT_INPUT, FIND_ANYWHERE );
399     seekpoint_t **pp_bookmarks;
400     int i_bookmarks;
401  
402     if( !p_input ) return 0;
403     else if( input_Control( p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks,
404                        &i_bookmarks ) != VLC_SUCCESS )
405     {
406         vlc_object_release( p_input );
407         return 0;
408     }
409     else {
410         vlc_object_release( p_input );
411         return i_bookmarks;
412     }
413 }
414
415 - (id)tableView:(NSTableView *)theDataTable objectValueForTableColumn:
416     (NSTableColumn *)theTableColumn row: (int)row
417 {
418     /* return the corresponding data as NSString */
419     intf_thread_t * p_intf = VLCIntf;
420     input_thread_t * p_input = (input_thread_t *)vlc_object_find( p_intf,
421         VLC_OBJECT_INPUT, FIND_ANYWHERE );
422     seekpoint_t **pp_bookmarks;
423     int i_bookmarks;
424     char *toBeReturned;
425     int i_toBeReturned = 0;
426  
427     if( !p_input ) return @"";
428     else if( input_Control( p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks,
429                        &i_bookmarks ) != VLC_SUCCESS )
430     {
431         vlc_object_release( p_input );
432         return @"";
433     }
434     else
435     {
436         if ([[theTableColumn identifier] isEqualToString: @"description"])
437         {
438             toBeReturned = pp_bookmarks[row]->psz_name;
439             vlc_object_release( p_input );
440             return [NSString stringWithUTF8String: toBeReturned];
441         }
442         else if ([[theTableColumn identifier] isEqualToString: @"size_offset"])
443         {
444             i_toBeReturned = pp_bookmarks[row]->i_byte_offset;
445             vlc_object_release( p_input );
446             return [[NSNumber numberWithInt: i_toBeReturned] stringValue];
447         }
448         else if ([[theTableColumn identifier] isEqualToString: @"time_offset"])
449         {
450             i_toBeReturned = pp_bookmarks[row]->i_time_offset;
451             vlc_object_release( p_input );
452             return [[NSNumber numberWithInt: (i_toBeReturned / 1000000)]
453                 stringValue];
454         }
455         else
456         {
457             /* may not happen, just in case */
458             vlc_object_release( p_input );
459             msg_Err(p_intf, "unknown table column identifier (%s) while "
460                 "updating the bookmark table", [[theTableColumn identifier]
461                 UTF8String] );
462             return @"unknown identifier";
463         }
464     }
465
466 }
467
468 /*****************************************************************************
469  * delegate methods
470  *****************************************************************************/
471
472 - (void)tableViewSelectionDidChange:(NSNotification *)aNotification
473 {
474     /* check whether a row is selected and en-/disable the edit/remove buttons */
475     if ([o_tbl_dataTable selectedRow] == -1)
476     {
477         /* no row is selected */
478         [o_btn_edit setEnabled: NO];
479         [o_btn_rm setEnabled: NO];
480         [o_btn_extract setEnabled: NO];
481     }
482     else
483     {
484         /* a row is selected */
485         [o_btn_edit setEnabled: YES];
486         [o_btn_rm setEnabled: YES];
487         if ([o_tbl_dataTable numberOfSelectedRows] == 2)
488         {
489             [o_btn_extract setEnabled: YES];
490         }
491     }
492 }
493
494 @end