1 /*****************************************************************************
2 * bookmarks.m: MacOS X Bookmarks window
3 *****************************************************************************
4 * Copyright (C) 2005 - 2012 VLC authors and VideoLAN
7 * Authors: Felix Paul Kühne <fkuehne at videolan dot org>
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.
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.
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 *****************************************************************************/
25 /*****************************************************************************
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 *****************************************************************************/
33 /*****************************************************************************
35 *****************************************************************************/
39 #import "CompatibilityFixes.h"
41 @interface VLCBookmarks (Internal)
45 @implementation VLCBookmarks
47 static VLCBookmarks *_o_sharedInstance = nil;
49 + (VLCBookmarks *)sharedInstance
51 return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
56 if (_o_sharedInstance)
59 _o_sharedInstance = [super init];
61 return _o_sharedInstance;
64 /*****************************************************************************
66 *****************************************************************************/
70 if (!OSX_SNOW_LEOPARD)
71 [o_bookmarks_window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenAuxiliary];
75 [[NSNotificationCenter defaultCenter] addObserver:self
76 selector:@selector(inputChangedEvent:)
77 name:VLCInputChangedNotification
84 vlc_object_release(p_old_input);
86 [[NSNotificationCenter defaultCenter] removeObserver:self];
93 /* localise the items */
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:@"size_offset"] headerCell]
105 setStringValue: _NS("Position")];
106 [[[o_tbl_dataTable tableColumnWithIdentifier:@"time_offset"] headerCell]
107 setStringValue: _NS("Time")];
110 [o_edit_btn_ok setTitle: _NS("OK")];
111 [o_edit_btn_cancel setTitle: _NS("Cancel")];
112 [o_edit_lbl_name setStringValue: _NS("Name")];
113 [o_edit_lbl_time setStringValue: _NS("Time")];
114 [o_edit_lbl_bytes setStringValue: _NS("Position")];
117 - (void)updateCocoaWindowLevel:(NSInteger)i_level
119 if (o_bookmarks_window && [o_bookmarks_window isVisible] && [o_bookmarks_window level] != i_level)
120 [o_bookmarks_window setLevel: i_level];
123 - (void)showBookmarks
125 /* show the window, called from intf.m */
126 [o_bookmarks_window displayIfNeeded];
127 [o_bookmarks_window setLevel: [[[VLCMain sharedInstance] voutController] currentWindowLevel]];
128 [o_bookmarks_window makeKeyAndOrderFront:nil];
131 -(void)inputChangedEvent:(NSNotification *)o_notification
133 [o_tbl_dataTable reloadData];
136 - (IBAction)add:(id)sender
138 /* add item to list */
139 input_thread_t * p_input = pl_CurrentInput(VLCIntf);
144 seekpoint_t bookmark;
146 if (!input_Control(p_input, INPUT_GET_BOOKMARK, &bookmark)) {
147 bookmark.psz_name = _("Untitled");
148 input_Control(p_input, INPUT_ADD_BOOKMARK, &bookmark);
151 vlc_object_release(p_input);
153 [o_tbl_dataTable reloadData];
156 - (IBAction)clear:(id)sender
159 input_thread_t * p_input = pl_CurrentInput(VLCIntf);
164 input_Control(p_input, INPUT_CLEAR_BOOKMARKS);
166 vlc_object_release(p_input);
168 [o_tbl_dataTable reloadData];
171 - (IBAction)edit:(id)sender
173 /* put values to the sheet's fields and show sheet */
174 /* we take the values from the core and not the table, because we cannot
176 input_thread_t * p_input = pl_CurrentInput(VLCIntf);
177 seekpoint_t **pp_bookmarks;
180 row = [o_tbl_dataTable selectedRow];
186 vlc_object_release(p_input);
190 if (input_Control(p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks, &i_bookmarks) != VLC_SUCCESS) {
191 vlc_object_release(p_input);
195 [o_edit_fld_name setStringValue: toNSStr(pp_bookmarks[row]->psz_name)];
196 int total = pp_bookmarks[row]->i_time_offset/ 1000000;
197 int hour = total / (60*60);
198 int min = (total - hour*60*60) / 60;
199 int sec = total - hour*60*60 - min*60;
200 [o_edit_fld_time setStringValue: [NSString stringWithFormat:@"%02d:%02d:%02d", hour, min, sec]];
201 [o_edit_fld_bytes setStringValue: [NSString stringWithFormat:@"%lli", pp_bookmarks[row]->i_byte_offset]];
203 /* Just keep the pointer value to check if it
204 * changes. Note, we don't need to keep a reference to the object.
205 * so release it now. */
206 p_old_input = p_input;
207 vlc_object_release(p_input);
209 [NSApp beginSheet: o_edit_window modalForWindow: o_bookmarks_window modalDelegate: o_edit_window didEndSelector: nil contextInfo: nil];
211 // Clear the bookmark list
212 for (int i = 0; i < i_bookmarks; i++)
213 vlc_seekpoint_Delete(pp_bookmarks[i]);
217 - (IBAction)edit_cancel:(id)sender
220 [NSApp endSheet:o_edit_window];
221 [o_edit_window close];
224 - (IBAction)edit_ok:(id)sender
226 /* save field contents and close sheet */
227 seekpoint_t **pp_bookmarks;
229 input_thread_t * p_input = pl_CurrentInput(VLCIntf);
232 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."));
235 if (p_old_input != p_input) {
236 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."));
237 vlc_object_release(p_input);
241 if (input_Control(p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks, &i_bookmarks) != VLC_SUCCESS) {
242 vlc_object_release(p_input);
246 i = [o_tbl_dataTable selectedRow];
248 free(pp_bookmarks[i]->psz_name);
250 pp_bookmarks[i]->psz_name = strdup([[o_edit_fld_name stringValue] UTF8String]);
251 pp_bookmarks[i]->i_byte_offset = [[o_edit_fld_bytes stringValue] intValue];
253 NSArray * components = [[o_edit_fld_time stringValue] componentsSeparatedByString:@":"];
254 NSUInteger componentCount = [components count];
255 if (componentCount == 1)
256 pp_bookmarks[i]->i_time_offset = 1000000 * ([[components objectAtIndex:0] intValue]);
257 else if (componentCount == 2)
258 pp_bookmarks[i]->i_time_offset = 1000000 * ([[components objectAtIndex:0] intValue] * 60 + [[components objectAtIndex:1] intValue]);
259 else if (componentCount == 3)
260 pp_bookmarks[i]->i_time_offset = 1000000 * ([[components objectAtIndex:0] intValue] * 3600 + [[components objectAtIndex:1] intValue] * 60 + [[components objectAtIndex:2] intValue]);
262 msg_Err(VLCIntf, "Invalid string format for time");
266 if (input_Control(p_input, INPUT_CHANGE_BOOKMARK, pp_bookmarks[i], i) != VLC_SUCCESS) {
267 msg_Warn(VLCIntf, "Unable to change the bookmark");
271 [o_tbl_dataTable reloadData];
272 vlc_object_release(p_input);
274 [NSApp endSheet: o_edit_window];
275 [o_edit_window close];
278 // Clear the bookmark list
279 for (int i = 0; i < i_bookmarks; i++)
280 vlc_seekpoint_Delete(pp_bookmarks[i]);
284 - (IBAction)extract:(id)sender
286 if ([o_tbl_dataTable numberOfSelectedRows] < 2) {
287 NSBeginAlertSheet(_NS("Invalid selection"), _NS("OK"), @"", @"", o_bookmarks_window, nil, nil, nil, nil, @"%@",_NS("Two bookmarks have to be selected."));
290 input_thread_t * p_input = pl_CurrentInput(VLCIntf);
292 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."));
296 seekpoint_t **pp_bookmarks;
301 for (NSUInteger x = 0; c != 2; x++) {
302 if ([o_tbl_dataTable isRowSelected:x]) {
306 } else if (i_second == -1) {
313 if (input_Control(p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks, &i_bookmarks) != VLC_SUCCESS) {
314 vlc_object_release(p_input);
315 msg_Err(VLCIntf, "already defined bookmarks couldn't be retrieved");
319 char *psz_uri = input_item_GetURI(input_GetItem(p_input));
320 [[[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)];
322 vlc_object_release(p_input);
324 // Clear the bookmark list
325 for (int i = 0; i < i_bookmarks; i++)
326 vlc_seekpoint_Delete(pp_bookmarks[i]);
330 - (IBAction)goToBookmark:(id)sender
332 input_thread_t * p_input = pl_CurrentInput(VLCIntf);
337 input_Control(p_input, INPUT_SET_BOOKMARK, [o_tbl_dataTable selectedRow]);
339 vlc_object_release(p_input);
342 - (IBAction)remove:(id)sender
344 input_thread_t * p_input = pl_CurrentInput(VLCIntf);
349 int i_focused = [o_tbl_dataTable selectedRow];
352 input_Control(p_input, INPUT_DEL_BOOKMARK, i_focused);
354 vlc_object_release(p_input);
356 [o_tbl_dataTable reloadData];
359 /*****************************************************************************
361 *****************************************************************************/
365 return o_tbl_dataTable;
368 /*****************************************************************************
369 * data source methods
370 *****************************************************************************/
372 - (NSInteger)numberOfRowsInTableView:(NSTableView *)theDataTable
374 /* return the number of bookmarks */
375 input_thread_t * p_input = pl_CurrentInput(VLCIntf);
376 seekpoint_t **pp_bookmarks;
382 int returnValue = input_Control(p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks, &i_bookmarks);
383 vlc_object_release(p_input);
385 if (returnValue != VLC_SUCCESS)
388 for (int i = 0; i < i_bookmarks; i++)
389 vlc_seekpoint_Delete(pp_bookmarks[i]);
395 - (id)tableView:(NSTableView *)theDataTable objectValueForTableColumn: (NSTableColumn *)theTableColumn row: (NSInteger)row
397 /* return the corresponding data as NSString */
398 input_thread_t * p_input = pl_CurrentInput(VLCIntf);
399 seekpoint_t **pp_bookmarks;
405 else if (input_Control(p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks, &i_bookmarks) != VLC_SUCCESS)
407 else if (row >= i_bookmarks)
410 NSString * identifier = [theTableColumn identifier];
411 if ([identifier isEqualToString: @"description"])
412 ret = toNSStr(pp_bookmarks[row]->psz_name);
413 else if ([identifier isEqualToString: @"size_offset"])
414 ret = [NSString stringWithFormat:@"%lli", pp_bookmarks[row]->i_byte_offset];
415 else if ([identifier isEqualToString: @"time_offset"]) {
416 int total = pp_bookmarks[row]->i_time_offset/ 1000000;
417 int hour = total / (60*60);
418 int min = (total - hour*60*60) / 60;
419 int sec = total - hour*60*60 - min*60;
420 ret = [NSString stringWithFormat:@"%02d:%02d:%02d", hour, min, sec];
423 // Clear the bookmark list
424 for (int i = 0; i < i_bookmarks; i++)
425 vlc_seekpoint_Delete(pp_bookmarks[i]);
428 vlc_object_release(p_input);
432 /*****************************************************************************
434 *****************************************************************************/
436 - (void)tableViewSelectionDidChange:(NSNotification *)aNotification
438 /* check whether a row is selected and en-/disable the edit/remove buttons */
439 if ([o_tbl_dataTable selectedRow] == -1) {
440 /* no row is selected */
441 [o_btn_edit setEnabled: NO];
442 [o_btn_rm setEnabled: NO];
443 [o_btn_extract setEnabled: NO];
445 /* a row is selected */
446 [o_btn_edit setEnabled: YES];
447 [o_btn_rm setEnabled: YES];
448 if ([o_tbl_dataTable numberOfSelectedRows] == 2)
449 [o_btn_extract setEnabled: YES];