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