]> git.sesse.net Git - vlc/blob - modules/gui/macosx/bookmarks.m
* implement the extract-button of the bookmarks-window correctly (refs #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 )
127         return;
128     
129     seekpoint_t bookmark;
130     vlc_value_t pos;
131     bookmark.psz_name = NULL;
132     bookmark.i_byte_offset = 0;
133     bookmark.i_time_offset = 0;
134     
135     var_Get(p_intf, "position", &pos);
136     bookmark.psz_name = _("Untitled");
137     input_Control( p_input, INPUT_GET_BYTE_POSITION, &bookmark.i_byte_offset );
138     var_Get( p_input, "time", &pos );
139     bookmark.i_time_offset = pos.i_time;
140     input_Control( p_input, INPUT_ADD_BOOKMARK, &bookmark );
141     
142     vlc_object_release( p_input );
143     
144     [o_tbl_dataTable reloadData];
145 }
146
147 - (IBAction)clear:(id)sender
148 {
149     /* clear table */
150     intf_thread_t * p_intf = VLCIntf;
151     input_thread_t *p_input = (input_thread_t *)vlc_object_find( p_intf, \
152         VLC_OBJECT_INPUT, FIND_ANYWHERE );
153     
154     if( !p_input )
155         return;
156
157     input_Control( p_input, INPUT_CLEAR_BOOKMARKS );
158
159     vlc_object_release( p_input );
160     
161     [o_tbl_dataTable reloadData];
162 }
163
164 - (IBAction)edit:(id)sender
165 {
166     /* put values to the sheet's fields and show sheet */
167     /* we take the values from the core and not the table, because we cannot
168      * really trust it */
169     intf_thread_t * p_intf = VLCIntf;
170     input_thread_t * p_input = (input_thread_t *)vlc_object_find( p_intf, \
171         VLC_OBJECT_INPUT, FIND_ANYWHERE );
172     seekpoint_t **pp_bookmarks;
173     int i_bookmarks;
174     char * toBeReturned;
175     toBeReturned = "";
176     int i_toBeReturned;
177     i_toBeReturned = 0;
178     int row;
179     row = [o_tbl_dataTable selectedRow];
180     
181     if( !p_input )
182     {
183         return;
184     } 
185     else if( input_Control( p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks, \
186         &i_bookmarks ) != VLC_SUCCESS )
187     {
188         vlc_object_release( p_input );
189         return;
190     } 
191     else if(row < 0)
192     {
193         vlc_object_release( p_input );
194         return;
195     } else {
196         [o_edit_fld_name setStringValue: [NSString stringWithUTF8String: \
197             pp_bookmarks[row]->psz_name]];
198         [o_edit_fld_time setStringValue: [[NSNumber numberWithInt: \
199             (pp_bookmarks[row]->i_time_offset / 1000000)] stringValue]];
200         [o_edit_fld_bytes setStringValue: [[NSNumber numberWithInt: \
201             pp_bookmarks[row]->i_byte_offset] stringValue]];
202     }
203     
204     p_old_input = p_input;
205     vlc_object_release( p_input );
206
207     [NSApp beginSheet: o_edit_window
208         modalForWindow: o_bookmarks_window
209         modalDelegate: o_edit_window
210         didEndSelector: nil
211         contextInfo: nil];
212 }
213
214 - (IBAction)edit_cancel:(id)sender
215 {
216     /* close sheet */
217     [NSApp endSheet:o_edit_window];
218     [o_edit_window close];
219 }
220
221 - (IBAction)edit_ok:(id)sender
222 {
223     /* save field contents and close sheet */
224     
225     intf_thread_t * p_intf = VLCIntf;
226     seekpoint_t **pp_bookmarks;
227     int i_bookmarks, i;
228     input_thread_t *p_input = (input_thread_t *)vlc_object_find( p_intf, \
229         VLC_OBJECT_INPUT, FIND_ANYWHERE );
230     
231     if( !p_input )
232     {
233         NSBeginCriticalAlertSheet(_NS("No input"), _NS("OK"), \
234                 @"", @"", o_bookmarks_window, nil, nil, nil, nil, _NS("No " \
235                 "input found. The stream must be playing or paused for " \
236                 "bookmarks to work."));
237         return;
238     }
239     if( p_old_input != p_input )
240     {
241         NSBeginCriticalAlertSheet(_NS("Input has changed"), _NS("OK"), \
242                 @"", @"", o_bookmarks_window, nil, nil, nil, nil, _NS("Input " \
243                 "has changed, unable to save bookmark. Use \"pause\" while " \
244                 "editing bookmarks to keep the same input."));
245         vlc_object_release( p_input );
246         return;
247     }
248     
249     if( input_Control( p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks, \
250         &i_bookmarks ) != VLC_SUCCESS )
251     {
252         vlc_object_release( p_input );
253         return;
254     } 
255
256     i = [o_tbl_dataTable selectedRow];
257     
258     if( pp_bookmarks[i]->psz_name ) 
259     {
260         free( pp_bookmarks[i]->psz_name );
261     }
262     /* FIXME: putting the name to core does not work!! -- FK*/
263     pp_bookmarks[i]->psz_name = strdup([[o_edit_fld_name stringValue] UTF8String]); 
264     pp_bookmarks[i]->i_byte_offset = [[o_edit_fld_bytes stringValue] intValue];
265     pp_bookmarks[i]->i_time_offset = ([[o_edit_fld_time stringValue] intValue]  * 1000000);
266     
267     if( input_Control( p_input, INPUT_CHANGE_BOOKMARK, pp_bookmarks[i], i ) \
268         != VLC_SUCCESS )
269     {
270         msg_Warn( p_intf, "VLCBookmarks: changing bookmark failed");
271         vlc_object_release( p_input );
272         return;
273     }
274     
275     [o_tbl_dataTable reloadData];
276     vlc_object_release( p_input );
277      
278     
279     [NSApp endSheet: o_edit_window];
280     [o_edit_window close];
281 }
282
283 - (IBAction)extract:(id)sender
284 {
285     /* extract */
286     
287     intf_thread_t * p_intf = VLCIntf;
288     
289     if( [o_tbl_dataTable numberOfSelectedRows] < 2 )
290     {
291         NSBeginAlertSheet(_NS("Invalid selection"), _NS("OK"), \
292                 @"", @"", o_bookmarks_window, nil, nil, nil, nil, _NS("" \
293                 "You must select two bookmarks"));
294         return;
295     }
296     input_thread_t *p_input =
297         (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
298                                            FIND_ANYWHERE );
299     if( !p_input )
300     {
301         NSBeginCriticalAlertSheet(_NS("No input found"), _NS("OK"), \
302                 @"", @"", o_bookmarks_window, nil, nil, nil, nil, _NS("" \
303                 "The stream must be playing or paused for bookmarks to work"));
304         return;
305     }
306     
307     seekpoint_t **pp_bookmarks;
308     int i_bookmarks ;
309     int i_first = -1;
310     int i_second = -1;
311     int x = 0;
312     int c = 0;
313     while (c != 2)
314     {
315         if([o_tbl_dataTable isRowSelected:x])
316         {
317             if (i_first == -1)
318             {
319                 i_first = x;
320                 c = 1;
321             } 
322             else if (i_second == -1)
323             {
324                 i_second = x;
325                 c = 2;
326             }
327         }
328         x = (x + 1);
329     }
330     
331     msg_Dbg(p_intf, "got the bookmark-indexes");
332     
333     if( input_Control( p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks, \
334         &i_bookmarks ) != VLC_SUCCESS )
335     {
336         vlc_object_release( p_input );
337         msg_Err(p_intf, "bookmarks couldn't be retrieved from core");
338         return;
339     }
340     msg_Dbg(p_intf, "calling wizard");
341
342     [[[VLCMain sharedInstance] getWizard] initWithExtractValuesFrom: \
343             [[NSNumber numberWithInt: \
344             (pp_bookmarks[i_first]->i_time_offset/1000000)] stringValue] \
345             to: [[NSNumber numberWithInt: \
346             (pp_bookmarks[i_second]->i_time_offset/1000000)] stringValue] \
347             ofItem: [NSString stringWithUTF8String: \
348             p_input->input.p_item->psz_uri]];
349     vlc_object_release( p_input );
350     msg_Dbg(p_intf, "released input");
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     }
415     else if( input_Control( p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks, \
416                        &i_bookmarks ) != VLC_SUCCESS )
417     {
418         vlc_object_release( p_input );
419         return 0;
420     }
421     else {
422         vlc_object_release( p_input );
423         return i_bookmarks;
424     }
425 }
426
427 - (id)tableView:(NSTableView *)theDataTable objectValueForTableColumn: \
428     (NSTableColumn *)theTableColumn row: (int)row
429 {
430     /* return the corresponding data as NSString */
431     intf_thread_t * p_intf = VLCIntf;
432     input_thread_t * p_input = (input_thread_t *)vlc_object_find( p_intf, \
433         VLC_OBJECT_INPUT, FIND_ANYWHERE );
434     seekpoint_t **pp_bookmarks;
435     int i_bookmarks;
436     char * toBeReturned;
437     toBeReturned = "";
438     int i_toBeReturned;
439     i_toBeReturned = 0;
440     
441     if( !p_input )
442     {
443         return @"";
444     } 
445     else if( input_Control( p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks, \
446                        &i_bookmarks ) != VLC_SUCCESS )
447     {
448         vlc_object_release( p_input );
449         return @"";
450     }
451     else
452     {
453         if ([[theTableColumn identifier] isEqualToString: @"description"])
454         {
455             toBeReturned = pp_bookmarks[row]->psz_name;
456             vlc_object_release( p_input );
457             return [NSString stringWithUTF8String: toBeReturned];
458         } 
459         else if ([[theTableColumn identifier] isEqualToString: @"size_offset"])
460         {
461             i_toBeReturned = pp_bookmarks[row]->i_byte_offset;
462             vlc_object_release( p_input );
463             return [[NSNumber numberWithInt: i_toBeReturned] stringValue];
464         }
465         else if ([[theTableColumn identifier] isEqualToString: @"time_offset"])
466         {
467             i_toBeReturned = pp_bookmarks[row]->i_time_offset;
468             vlc_object_release( p_input );
469             return [[NSNumber numberWithInt: (i_toBeReturned / 1000000)] \
470                 stringValue];
471         }
472         else
473         {
474             /* may not happen, but just in case */
475             vlc_object_release( p_input );
476             msg_Err(p_intf, "VLCBookmarks: unknown table column identifier " \
477                 "(%s) while updating table", [[theTableColumn identifier] \
478                 UTF8String] );
479             return @"unknown identifier";
480         }
481     }
482
483 }
484
485 /*****************************************************************************
486  * delegate methods
487  *****************************************************************************/
488
489 - (void)tableViewSelectionDidChange:(NSNotification *)aNotification
490 {
491     /* check whether a row is selected and en-/disable the edit/remove buttons */
492     if ([o_tbl_dataTable selectedRow] == -1)
493     {
494         /* no row is selected */
495         [o_btn_edit setEnabled: NO];
496         [o_btn_rm setEnabled: NO];
497         [o_btn_extract setEnabled: NO];
498     }
499     else
500     {
501         /* a row is selected */
502         [o_btn_edit setEnabled: YES];
503         [o_btn_rm setEnabled: YES];
504         if ([o_tbl_dataTable numberOfSelectedRows] == 2)
505         {
506             [o_btn_extract setEnabled: YES];
507         }
508     }
509 }
510
511 @end