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