macosx: bookmarks: remove byte field from table view and edit dialog
[vlc.git] / modules / gui / macosx / bookmarks.m
1 /*****************************************************************************
2  * bookmarks.m: MacOS X Bookmarks window
3  *****************************************************************************
4  * Copyright (C) 2005 - 2012 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Felix Paul K├╝hne <fkuehne at videolan dot org>
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 "CompatibilityFixes.h"
40
41 @interface VLCBookmarks (Internal)
42 - (void)initStrings;
43 @end
44
45 @implementation VLCBookmarks
46
47 static VLCBookmarks *_o_sharedInstance = nil;
48
49 + (VLCBookmarks *)sharedInstance
50 {
51     return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
52 }
53
54 - (id)init
55 {
56     if (_o_sharedInstance)
57         [self dealloc];
58     else
59         _o_sharedInstance = [super init];
60
61     return _o_sharedInstance;
62 }
63
64 /*****************************************************************************
65  * GUI methods
66  *****************************************************************************/
67
68 - (void)awakeFromNib
69 {
70     if (!OSX_SNOW_LEOPARD)
71         [o_bookmarks_window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenAuxiliary];
72
73     [self initStrings];
74
75     [[NSNotificationCenter defaultCenter] addObserver:self
76                                              selector:@selector(inputChangedEvent:)
77                                                  name:VLCInputChangedNotification
78                                                object:nil];
79 }
80
81 - (void)dealloc
82 {
83     if (p_old_input)
84         vlc_object_release(p_old_input);
85
86     [[NSNotificationCenter defaultCenter] removeObserver:self];
87
88     [super dealloc];
89 }
90
91 - (void)initStrings
92 {
93     /* localise the items */
94
95     /* main window */
96     [o_bookmarks_window setTitle: _NS("Bookmarks")];
97     [o_btn_add setTitle: _NS("Add")];
98     [o_btn_clear setTitle: _NS("Clear")];
99     [o_btn_edit setTitle: _NS("Edit")];
100     [o_btn_extract setTitle: _NS("Extract")];
101     [o_btn_rm setTitle: _NS("Remove")];
102     [[[o_tbl_dataTable tableColumnWithIdentifier:@"description"] headerCell]
103         setStringValue: _NS("Description")];
104     [[[o_tbl_dataTable tableColumnWithIdentifier:@"time_offset"] headerCell]
105         setStringValue: _NS("Time")];
106
107     /* edit window */
108     [o_edit_btn_ok setTitle: _NS("OK")];
109     [o_edit_btn_cancel setTitle: _NS("Cancel")];
110     [o_edit_lbl_name setStringValue: _NS("Name")];
111     [o_edit_lbl_time setStringValue: _NS("Time")];
112 }
113
114 - (void)updateCocoaWindowLevel:(NSInteger)i_level
115 {
116     if (o_bookmarks_window && [o_bookmarks_window isVisible] && [o_bookmarks_window level] != i_level)
117         [o_bookmarks_window setLevel: i_level];
118 }
119
120 - (void)showBookmarks
121 {
122     /* show the window, called from intf.m */
123     [o_bookmarks_window displayIfNeeded];
124     [o_bookmarks_window setLevel: [[[VLCMain sharedInstance] voutController] currentStatusWindowLevel]];
125     [o_bookmarks_window makeKeyAndOrderFront:nil];
126 }
127
128 -(void)inputChangedEvent:(NSNotification *)o_notification
129 {
130     [o_tbl_dataTable reloadData];
131 }
132
133 - (IBAction)add:(id)sender
134 {
135     /* add item to list */
136     input_thread_t * p_input = pl_CurrentInput(VLCIntf);
137
138     if (!p_input)
139         return;
140
141     seekpoint_t bookmark;
142
143     if (!input_Control(p_input, INPUT_GET_BOOKMARK, &bookmark)) {
144         bookmark.psz_name = _("Untitled");
145         input_Control(p_input, INPUT_ADD_BOOKMARK, &bookmark);
146     }
147
148     vlc_object_release(p_input);
149
150     [o_tbl_dataTable reloadData];
151 }
152
153 - (IBAction)clear:(id)sender
154 {
155     /* clear table */
156     input_thread_t * p_input = pl_CurrentInput(VLCIntf);
157
158     if (!p_input)
159         return;
160
161     input_Control(p_input, INPUT_CLEAR_BOOKMARKS);
162
163     vlc_object_release(p_input);
164
165     [o_tbl_dataTable reloadData];
166 }
167
168 - (IBAction)edit:(id)sender
169 {
170     /* put values to the sheet's fields and show sheet */
171     /* we take the values from the core and not the table, because we cannot
172      * really trust it */
173     input_thread_t * p_input = pl_CurrentInput(VLCIntf);
174     seekpoint_t **pp_bookmarks;
175     int i_bookmarks;
176     int row;
177     row = [o_tbl_dataTable selectedRow];
178
179     if (!p_input)
180         return;
181
182     if (row < 0) {
183         vlc_object_release(p_input);
184         return;
185     }
186
187     if (input_Control(p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks, &i_bookmarks) != VLC_SUCCESS) {
188         vlc_object_release(p_input);
189         return;
190     }
191
192     [o_edit_fld_name setStringValue: toNSStr(pp_bookmarks[row]->psz_name)];
193     int total = pp_bookmarks[row]->i_time_offset/ 1000000;
194     int hour = total / (60*60);
195     int min = (total - hour*60*60) / 60;
196     int sec = total - hour*60*60 - min*60;
197     [o_edit_fld_time setStringValue: [NSString stringWithFormat:@"%02d:%02d:%02d", hour, min, sec]];
198
199     /* Just keep the pointer value to check if it
200      * changes. Note, we don't need to keep a reference to the object.
201      * so release it now. */
202     p_old_input = p_input;
203     vlc_object_release(p_input);
204
205     [NSApp beginSheet: o_edit_window modalForWindow: o_bookmarks_window modalDelegate: o_edit_window didEndSelector: nil contextInfo: nil];
206
207     // Clear the bookmark list
208     for (int i = 0; i < i_bookmarks; i++)
209         vlc_seekpoint_Delete(pp_bookmarks[i]);
210     free(pp_bookmarks);
211 }
212
213 - (IBAction)edit_cancel:(id)sender
214 {
215     /* close sheet */
216     [NSApp endSheet:o_edit_window];
217     [o_edit_window close];
218 }
219
220 - (IBAction)edit_ok:(id)sender
221 {
222     /* save field contents and close sheet */
223      seekpoint_t **pp_bookmarks;
224     int i_bookmarks, i;
225     input_thread_t * p_input = pl_CurrentInput(VLCIntf);
226
227     if (!p_input) {
228         NSBeginCriticalAlertSheet(_NS("No input"), _NS("OK"), @"", @"", o_bookmarks_window, nil, nil, nil, nil, @"%@",_NS("No input found. A stream must be playing or paused for bookmarks to work."));
229         return;
230     }
231     if (p_old_input != p_input) {
232         NSBeginCriticalAlertSheet(_NS("Input has changed"), _NS("OK"), @"", @"", o_bookmarks_window, nil, nil, nil, nil, @"%@",_NS("Input has changed, unable to save bookmark. Suspending playback with \"Pause\" while editing bookmarks to ensure to keep the same input."));
233         vlc_object_release(p_input);
234         return;
235     }
236
237     if (input_Control(p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks, &i_bookmarks) != VLC_SUCCESS) {
238         vlc_object_release(p_input);
239         return;
240     }
241
242     i = [o_tbl_dataTable selectedRow];
243
244     free(pp_bookmarks[i]->psz_name);
245
246     pp_bookmarks[i]->psz_name = strdup([[o_edit_fld_name stringValue] UTF8String]);
247
248     NSArray * components = [[o_edit_fld_time stringValue] componentsSeparatedByString:@":"];
249     NSUInteger componentCount = [components count];
250     if (componentCount == 1)
251         pp_bookmarks[i]->i_time_offset = 1000000LL * ([[components objectAtIndex:0] longLongValue]);
252     else if (componentCount == 2)
253         pp_bookmarks[i]->i_time_offset = 1000000LL * ([[components objectAtIndex:0] longLongValue] * 60 + [[components objectAtIndex:1] longLongValue]);
254     else if (componentCount == 3)
255         pp_bookmarks[i]->i_time_offset = 1000000LL * ([[components objectAtIndex:0] longLongValue] * 3600 + [[components objectAtIndex:1] longLongValue] * 60 + [[components objectAtIndex:2] longLongValue]);
256     else {
257         msg_Err(VLCIntf, "Invalid string format for time");
258         goto clear;
259     }
260
261     if (input_Control(p_input, INPUT_CHANGE_BOOKMARK, pp_bookmarks[i], i) != VLC_SUCCESS) {
262         msg_Warn(VLCIntf, "Unable to change the bookmark");
263         goto clear;
264     }
265
266     [o_tbl_dataTable reloadData];
267     vlc_object_release(p_input);
268
269     [NSApp endSheet: o_edit_window];
270     [o_edit_window close];
271
272 clear:
273     // Clear the bookmark list
274     for (int i = 0; i < i_bookmarks; i++)
275         vlc_seekpoint_Delete(pp_bookmarks[i]);
276     free(pp_bookmarks);
277 }
278
279 - (IBAction)extract:(id)sender
280 {
281     if ([o_tbl_dataTable numberOfSelectedRows] < 2) {
282         NSBeginAlertSheet(_NS("Invalid selection"), _NS("OK"), @"", @"", o_bookmarks_window, nil, nil, nil, nil, @"%@",_NS("Two bookmarks have to be selected."));
283         return;
284     }
285     input_thread_t * p_input = pl_CurrentInput(VLCIntf);
286     if (!p_input) {
287         NSBeginCriticalAlertSheet(_NS("No input found"), _NS("OK"), @"", @"", o_bookmarks_window, nil, nil, nil, nil, @"%@",_NS("The stream must be playing or paused for bookmarks to work."));
288         return;
289     }
290
291     seekpoint_t **pp_bookmarks;
292     int i_bookmarks ;
293     int i_first = -1;
294     int i_second = -1;
295     int c = 0;
296     for (NSUInteger x = 0; c != 2; x++) {
297         if ([o_tbl_dataTable isRowSelected:x]) {
298             if (i_first == -1) {
299                 i_first = x;
300                 c = 1;
301             } else if (i_second == -1) {
302                 i_second = x;
303                 c = 2;
304             }
305         }
306     }
307
308     if (input_Control(p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks, &i_bookmarks) != VLC_SUCCESS) {
309         vlc_object_release(p_input);
310         msg_Err(VLCIntf, "already defined bookmarks couldn't be retrieved");
311         return;
312     }
313
314     char *psz_uri = input_item_GetURI(input_GetItem(p_input));
315     [[[VLCMain sharedInstance] wizard] initWithExtractValuesFrom: [NSString stringWithFormat:@"%lli", pp_bookmarks[i_first]->i_time_offset/1000000] to: [NSString stringWithFormat:@"%lli", pp_bookmarks[i_second]->i_time_offset/1000000] ofItem: toNSStr(psz_uri)];
316     free(psz_uri);
317     vlc_object_release(p_input);
318
319     // Clear the bookmark list
320     for (int i = 0; i < i_bookmarks; i++)
321         vlc_seekpoint_Delete(pp_bookmarks[i]);
322     free(pp_bookmarks);
323 }
324
325 - (IBAction)goToBookmark:(id)sender
326 {
327     input_thread_t * p_input = pl_CurrentInput(VLCIntf);
328
329     if (!p_input)
330         return;
331
332     input_Control(p_input, INPUT_SET_BOOKMARK, [o_tbl_dataTable selectedRow]);
333
334     vlc_object_release(p_input);
335 }
336
337 - (IBAction)remove:(id)sender
338 {
339     input_thread_t * p_input = pl_CurrentInput(VLCIntf);
340
341     if (!p_input)
342         return;
343
344     int i_focused = [o_tbl_dataTable selectedRow];
345
346     if (i_focused >= 0)
347         input_Control(p_input, INPUT_DEL_BOOKMARK, i_focused);
348
349     vlc_object_release(p_input);
350
351     [o_tbl_dataTable reloadData];
352 }
353
354 /*****************************************************************************
355  * data source methods
356  *****************************************************************************/
357
358 - (NSInteger)numberOfRowsInTableView:(NSTableView *)theDataTable
359 {
360     /* return the number of bookmarks */
361     input_thread_t * p_input = pl_CurrentInput(VLCIntf);
362     seekpoint_t **pp_bookmarks;
363     int i_bookmarks;
364
365     if (!p_input)
366         return 0;
367
368     int returnValue = input_Control(p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks, &i_bookmarks);
369     vlc_object_release(p_input);
370
371     if (returnValue != VLC_SUCCESS)
372         return 0;
373
374     for (int i = 0; i < i_bookmarks; i++)
375         vlc_seekpoint_Delete(pp_bookmarks[i]);
376     free(pp_bookmarks);
377
378     return i_bookmarks;
379 }
380
381 - (id)tableView:(NSTableView *)theDataTable objectValueForTableColumn: (NSTableColumn *)theTableColumn row: (NSInteger)row
382 {
383     /* return the corresponding data as NSString */
384     input_thread_t * p_input = pl_CurrentInput(VLCIntf);
385     seekpoint_t **pp_bookmarks;
386     int i_bookmarks;
387     id ret = @"";
388
389     if (!p_input)
390         return @"";
391     else if (input_Control(p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks, &i_bookmarks) != VLC_SUCCESS)
392         ret = @"";
393     else if (row >= i_bookmarks)
394         ret = @"";
395     else {
396         NSString * identifier = [theTableColumn identifier];
397         if ([identifier isEqualToString: @"description"])
398             ret = toNSStr(pp_bookmarks[row]->psz_name);
399                 else if ([identifier isEqualToString: @"time_offset"]) {
400             int total = pp_bookmarks[row]->i_time_offset/ 1000000;
401             int hour = total / (60*60);
402             int min = (total - hour*60*60) / 60;
403             int sec = total - hour*60*60 - min*60;
404             ret = [NSString stringWithFormat:@"%02d:%02d:%02d", hour, min, sec];
405         }
406
407         // Clear the bookmark list
408         for (int i = 0; i < i_bookmarks; i++)
409             vlc_seekpoint_Delete(pp_bookmarks[i]);
410         free(pp_bookmarks);
411     }
412     vlc_object_release(p_input);
413     return ret;
414 }
415
416 /*****************************************************************************
417  * delegate methods
418  *****************************************************************************/
419
420 - (void)tableViewSelectionDidChange:(NSNotification *)aNotification
421 {
422     /* check whether a row is selected and en-/disable the edit/remove buttons */
423     if ([o_tbl_dataTable selectedRow] == -1) {
424         /* no row is selected */
425         [o_btn_edit setEnabled: NO];
426         [o_btn_rm setEnabled: NO];
427         [o_btn_extract setEnabled: NO];
428     } else {
429         /* a row is selected */
430         [o_btn_edit setEnabled: YES];
431         [o_btn_rm setEnabled: YES];
432         if ([o_tbl_dataTable numberOfSelectedRows] == 2)
433             [o_btn_extract setEnabled: YES];
434     }
435 }
436
437 @end