1 /*****************************************************************************
2 * bookmarks.cpp : wxWindows plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2000-2004 VideoLAN
7 * Authors: Gildas Bazin <gbazin@videolan.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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <stdlib.h> /* malloc(), free() */
28 #include <errno.h> /* ENOMEM */
29 #include <string.h> /* strerror() */
35 #include "wxwindows.h"
36 #include <wx/dialog.h>
38 /* Callback prototype */
39 static int PlaylistChanged( vlc_object_t *, const char *,
40 vlc_value_t, vlc_value_t, void * );
42 /*****************************************************************************
44 *****************************************************************************/
46 /* IDs for the controls and the menu commands */
50 ButtonAdd_Event = wxID_HIGHEST + 1,
57 class BookmarksDialog: public wxFrame
61 BookmarksDialog( intf_thread_t *p_intf, wxWindow *p_parent );
62 virtual ~BookmarksDialog();
70 /* Event handlers (these functions should _not_ be virtual) */
71 void OnClose( wxCommandEvent& event );
72 void OnAdd( wxCommandEvent& event );
73 void OnDel( wxCommandEvent& event );
74 void OnClear( wxCommandEvent& event );
75 void OnActivateItem( wxListEvent& event );
76 void OnUpdate( wxCommandEvent &event );
77 void OnEdit( wxCommandEvent& event );
78 void OnExtract( wxCommandEvent& event );
80 DECLARE_EVENT_TABLE();
82 intf_thread_t *p_intf;
85 wxListView *list_ctrl;
87 DEFINE_LOCAL_EVENT_TYPE( wxEVT_BOOKMARKS );
89 BEGIN_EVENT_TABLE(BookmarksDialog, wxFrame)
90 /* Hide the window when the user closes the window */
91 EVT_CLOSE(BookmarksDialog::OnClose )
92 EVT_BUTTON( ButtonAdd_Event, BookmarksDialog::OnAdd )
93 EVT_BUTTON( ButtonDel_Event, BookmarksDialog::OnDel )
94 EVT_BUTTON( ButtonClear_Event, BookmarksDialog::OnClear )
95 EVT_BUTTON( ButtonExtract_Event, BookmarksDialog::OnExtract )
96 EVT_BUTTON( ButtonEdit_Event, BookmarksDialog::OnEdit )
98 EVT_LIST_ITEM_ACTIVATED( -1, BookmarksDialog::OnActivateItem )
100 EVT_COMMAND( -1, wxEVT_BOOKMARKS, BookmarksDialog::OnUpdate )
103 /* Declaration of class BookmarkEditDialog */
104 class BookmarkEditDialog : public wxDialog
108 BookmarkEditDialog( intf_thread_t *p_intf, wxWindow *p_parent,
109 seekpoint_t *p_seekpoint );
110 virtual ~BookmarkEditDialog();
111 seekpoint_t *p_seekpoint;
114 wxTextCtrl *name_text, *time_text, *bytes_text;
116 void OnOK( wxCommandEvent& event);
117 void OnCancel( wxCommandEvent& event);
119 DECLARE_EVENT_TABLE();
121 intf_thread_t *p_intf;
124 BEGIN_EVENT_TABLE( BookmarkEditDialog, wxDialog)
125 EVT_BUTTON( wxID_OK, BookmarkEditDialog::OnOK)
127 /****************************************************************************
129 ***************************************************************************/
130 BookmarkEditDialog::BookmarkEditDialog( intf_thread_t *_p_intf,
131 wxWindow *_p_parent, seekpoint_t *_p_seekpoint ):wxDialog(
132 _p_parent, -1, wxU(_("Edit bookmark")), wxDefaultPosition,
133 wxDefaultSize, wxDEFAULT_FRAME_STYLE )
135 /* Initializations */
137 p_seekpoint = _p_seekpoint;
138 SetIcon( *p_intf->p_sys->p_icon );
140 /* Create a panel to put everything in*/
141 wxBoxSizer *panel_sizer = new wxBoxSizer( wxVERTICAL );
143 wxFlexGridSizer * sizer = new wxFlexGridSizer( 2 , 3 , 1 );
144 name_text = new wxTextCtrl( this, -1, wxU( p_seekpoint->psz_name ?
145 p_seekpoint->psz_name : "" ),
146 wxDefaultPosition, wxSize( 100, 20) );
147 time_text = new wxTextCtrl( this, -1, wxString::Format(wxT("%d"),
148 (int)(p_seekpoint->i_time_offset / 1000000) ),
149 wxDefaultPosition, wxSize( 100, 20) );
150 bytes_text = new wxTextCtrl( this, -1, wxString::Format(wxT("%d"),
151 (int)p_seekpoint->i_byte_offset ),
152 wxDefaultPosition, wxSize( 100, 20) );
154 sizer->Add( new wxStaticText( this, -1, wxU(_("Name") ) ), 0, wxLEFT, 5 );
155 sizer->Add( name_text, 0, wxEXPAND|wxRIGHT , 5 );
156 sizer->Add( new wxStaticText( this, -1, wxU(_("Time") ) ), 0, wxLEFT, 5 );
157 sizer->Add( time_text , 0, wxEXPAND|wxRIGHT , 5);
158 sizer->Add( new wxStaticText( this, -1, wxU(_("Bytes") ) ), 0, wxLEFT, 5 );
159 sizer->Add( bytes_text, 0, wxEXPAND|wxRIGHT, 5);
161 wxBoxSizer *button_sizer = new wxBoxSizer( wxHORIZONTAL );
162 button_sizer->Add( new wxButton( this, wxID_OK, wxU(_("OK") ) ) );
163 button_sizer->Add( new wxButton( this, wxID_CANCEL, wxU(_("Cancel") ) ) );
165 panel_sizer->Add( sizer, 0, wxEXPAND | wxTOP|wxBOTTOM, 5 );
166 panel_sizer->Add( button_sizer, 0, wxEXPAND | wxBOTTOM, 5 );
167 panel_sizer->Layout();
168 SetSizerAndFit( panel_sizer );
171 BookmarkEditDialog::~BookmarkEditDialog()
174 void BookmarkEditDialog::OnOK( wxCommandEvent &event )
176 if( p_seekpoint->psz_name ) free( p_seekpoint->psz_name );
177 p_seekpoint->psz_name = strdup( name_text->GetValue().mb_str() );
178 p_seekpoint->i_byte_offset = atoi( bytes_text->GetValue().mb_str() );
179 p_seekpoint->i_time_offset = 1000000 *
180 atoll( time_text->GetValue().mb_str() ) ;
184 void BookmarkEditDialog::OnCancel( wxCommandEvent &event )
186 EndModal( wxID_CANCEL );
189 /*****************************************************************************
191 *****************************************************************************/
192 BookmarksDialog::BookmarksDialog( intf_thread_t *_p_intf, wxWindow *p_parent )
193 : wxFrame( p_parent->GetParent() ? p_parent->GetParent() : p_parent,
194 -1, wxU(_("Bookmarks")),
195 !p_parent->GetParent() ? wxDefaultPosition :
196 wxPoint( p_parent->GetParent()->GetRect().GetX(),
197 p_parent->GetParent()->GetRect().GetY() +
198 p_parent->GetParent()->GetRect().GetHeight() + 40 ),
200 wxDEFAULT_FRAME_STYLE | wxFRAME_FLOAT_ON_PARENT )
202 /* Initializations */
204 SetIcon( *p_intf->p_sys->p_icon );
206 wxPanel *main_panel = new wxPanel( this, -1 );
207 wxBoxSizer *main_sizer = new wxBoxSizer( wxHORIZONTAL );
209 wxBoxSizer *sizer = new wxBoxSizer( wxHORIZONTAL );
211 wxPanel *panel = new wxPanel( main_panel, -1 );
212 wxBoxSizer *panel_sizer = new wxBoxSizer( wxVERTICAL );
213 wxButton *button_add =
214 new wxButton( panel, ButtonAdd_Event, wxU(_("Add")) );
215 wxButton *button_del =
216 new wxButton( panel, ButtonDel_Event, wxU(_("Remove")) );
217 wxButton *button_clear =
218 new wxButton( panel, ButtonClear_Event, wxU(_("Clear")) );
219 wxButton *button_edit =
220 new wxButton( panel, ButtonEdit_Event, wxU(_("Edit")) );
221 wxButton *button_extract =
222 new wxButton( panel, ButtonExtract_Event, wxU(_("Extract")) );
224 #define ADD_TEXT "Adds a bookmark at the current position in the stream"
225 #define REMOVE_TEXT "Removes the selected bookmarks"
226 #define CLEAR_TEXT "Removes all the bookmarks for that stream"
227 #define EDIT_TEXT "Edit the properties of a bookmark"
228 #define EXTRACT_TEXT "If you select two or more bookmarks, this will " \
229 "launch the streaming/transcoding wizard to allow you to " \
230 "stream or save the part of the stream between these bookmarks"
231 button_add->SetToolTip( wxU(_( ADD_TEXT ) ) );
232 button_del->SetToolTip( wxU(_( REMOVE_TEXT ) ) );
233 button_clear->SetToolTip( wxU(_( CLEAR_TEXT ) ) );
234 button_edit->SetToolTip( wxU(_( EDIT_TEXT ) ) );
235 button_extract->SetToolTip( wxU(_( EXTRACT_TEXT ) ) );
237 panel_sizer->Add( button_add, 0, wxEXPAND );
238 panel_sizer->Add( button_del, 0, wxEXPAND );
239 panel_sizer->Add( button_clear, 0, wxEXPAND );
240 panel_sizer->Add( button_edit, 0, wxEXPAND );
241 panel_sizer->Add( 0, 0, 1 );
242 panel_sizer->Add( button_extract, 0, wxEXPAND );
243 panel->SetSizerAndFit( panel_sizer );
245 list_ctrl = new wxListView( main_panel, -1,
246 wxDefaultPosition, wxDefaultSize,
247 wxLC_REPORT | wxSUNKEN_BORDER );
248 list_ctrl->InsertColumn( 0, wxU(_("Description")) );
249 list_ctrl->SetColumnWidth( 0, 240 );
250 list_ctrl->InsertColumn( 1, wxU(_("Size offset")) );
251 list_ctrl->InsertColumn( 2, wxU(_("Time offset")) );
253 sizer->Add( panel, 0, wxEXPAND | wxALL, 1 );
254 sizer->Add( list_ctrl, 1, wxEXPAND | wxALL, 1 );
255 main_panel->SetSizer( sizer );
257 main_sizer->Add( main_panel, 1, wxEXPAND );
258 SetSizer( main_sizer );
260 playlist_t *p_playlist =
261 (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
265 /* Some global changes happened -> Rebuild all */
266 var_AddCallback( p_playlist, "playlist-current",
267 PlaylistChanged, this );
268 vlc_object_release( p_playlist );
272 BookmarksDialog::~BookmarksDialog()
274 playlist_t *p_playlist =
275 (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
279 var_DelCallback( p_playlist, "playlist-current",
280 PlaylistChanged, this );
281 vlc_object_release( p_playlist );
285 /*****************************************************************************
287 *****************************************************************************/
288 wxWindow *BookmarksDialog( intf_thread_t *p_intf, wxWindow *p_parent )
290 return new BookmarksDialog::BookmarksDialog( p_intf, p_parent );
293 void BookmarksDialog::Update()
295 input_thread_t *p_input =
296 (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
298 if( !p_input ) return;
300 seekpoint_t **pp_bookmarks;
303 list_ctrl->DeleteAllItems();
304 if( input_Control( p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks,
305 &i_bookmarks ) != VLC_SUCCESS )
307 vlc_object_release( p_input );
311 for( int i = 0; i < i_bookmarks; i++ )
313 list_ctrl->InsertItem( i, wxL2U( pp_bookmarks[i]->psz_name ) );
314 /* FIXME: see if we can use the 64 bits integer format string */
315 list_ctrl->SetItem( i, 1, wxString::Format(wxT("%d"),
316 (int)(pp_bookmarks[i]->i_byte_offset) ) );
317 list_ctrl->SetItem( i, 2, wxString::Format(wxT("%d"),
318 (int)(pp_bookmarks[i]->i_time_offset / 1000000) ) );
321 vlc_object_release( p_input );
324 bool BookmarksDialog::Show( bool show )
327 return wxFrame::Show( show );
330 void BookmarksDialog::OnClose( wxCommandEvent& event )
335 void BookmarksDialog::OnAdd( wxCommandEvent& event )
337 input_thread_t *p_input =
338 (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
340 if( !p_input ) return;
342 seekpoint_t bookmark;
344 bookmark.psz_name = NULL;
345 bookmark.i_byte_offset = 0;
346 bookmark.i_time_offset = 0;
350 * - stream_Tell can't be use (not reentrant)
351 * - nobody except src/input/ could touch p_input
352 * -> create new INPUT_CONTROL ...
355 var_Get( p_input, "position", &pos );
356 bookmark.psz_name = NULL;
357 bookmark.i_byte_offset = stream_Tell( p_input->input.p_stream );
358 (int64_t)((double)pos.f_float * p_input->input.p_access->info.i_size);
359 var_Get( p_input, "time", &pos );
360 bookmark.i_time_offset = pos.i_time;
361 input_Control( p_input, INPUT_ADD_BOOKMARK, &bookmark );
363 vlc_object_release( p_input );
368 void BookmarksDialog::OnDel( wxCommandEvent& event )
370 input_thread_t *p_input =
371 (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
373 if( !p_input ) return;
375 int i_focused = list_ctrl->GetFocusedItem();
378 input_Control( p_input, INPUT_DEL_BOOKMARK, i_focused );
381 vlc_object_release( p_input );
386 void BookmarksDialog::OnClear( wxCommandEvent& event )
388 input_thread_t *p_input =
389 (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
391 if( !p_input ) return;
393 input_Control( p_input, INPUT_CLEAR_BOOKMARKS );
395 vlc_object_release( p_input );
400 void BookmarksDialog::OnExtract( wxCommandEvent& event )
402 long i_first = list_ctrl->GetNextItem( -1, wxLIST_NEXT_ALL,
403 wxLIST_STATE_SELECTED );
404 long i_second = list_ctrl->GetNextItem( i_first, wxLIST_NEXT_ALL,
405 wxLIST_STATE_SELECTED );
407 if( i_first == -1 || i_second == -1 )
409 wxMessageBox( wxU(_("You must select two bookmarks") ),
410 wxU(_("Invalid selection") ), wxICON_WARNING | wxOK,
414 input_thread_t *p_input =
415 (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
419 wxMessageBox( wxU(_("The stream must be playing or paused for "
420 "bookmarks to work" ) ), wxU(_("No input found")),
421 wxICON_WARNING | wxOK,
426 seekpoint_t **pp_bookmarks;
429 if( input_Control( p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks,
430 &i_bookmarks ) != VLC_SUCCESS )
432 vlc_object_release( p_input );
436 if( i_first < i_bookmarks && i_second <= i_bookmarks )
438 WizardDialog *p_wizard_dialog = new WizardDialog( p_intf, this,
439 p_input->input.p_item->psz_uri,
440 pp_bookmarks[i_first]->i_time_offset/1000000,
441 pp_bookmarks[i_second]->i_time_offset/1000000 );
442 vlc_object_release( p_input );
443 if( p_wizard_dialog )
445 p_wizard_dialog->Run();
446 delete p_wizard_dialog;
451 vlc_object_release( p_input );
455 void BookmarksDialog::OnActivateItem( wxListEvent& event )
457 input_thread_t *p_input =
458 (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
460 if( !p_input ) return;
462 input_Control( p_input, INPUT_SET_BOOKMARK, event.GetIndex() );
464 vlc_object_release( p_input );
467 void BookmarksDialog::OnEdit( wxCommandEvent& event )
469 input_thread_t *p_old_input;
470 input_thread_t *p_input =
471 (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
473 if( !p_input ) return;
476 seekpoint_t **pp_bookmarks;
479 if( input_Control( p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks,
480 &i_bookmarks ) != VLC_SUCCESS )
482 vlc_object_release( p_input );
485 p_old_input = p_input;
486 vlc_object_release( p_input );
488 long i_first = list_ctrl->GetNextItem( -1, wxLIST_NEXT_ALL,
489 wxLIST_STATE_SELECTED );
491 if( i_first > -1 && i_first <= i_bookmarks )
493 BookmarkEditDialog *p_bmk_edit;
494 p_bmk_edit = new BookmarkEditDialog( p_intf, this,
495 pp_bookmarks[i_first]);
497 if( p_bmk_edit->ShowModal() == wxID_OK )
499 p_input =(input_thread_t *)vlc_object_find( p_intf,
500 VLC_OBJECT_INPUT, FIND_ANYWHERE );
503 wxMessageBox( wxU( _("No input found. The stream must be "
504 "playing or paused for bookmarks to work") ),
505 wxU( _("No input") ), wxICON_WARNING | wxOK,
509 if( p_old_input != p_input )
511 wxMessageBox( wxU( _("Input has changed, unable to save "
512 "bookmark. Use \"pause\" while editing "
513 "bookmarks to keep the same input.") ),
514 wxU( _("Input has changed ") ),
515 wxICON_WARNING | wxOK, this );
516 vlc_object_release( p_input );
520 fprintf(stderr,"Changing %i\n",i_first );
521 if( input_Control( p_input, INPUT_CHANGE_BOOKMARK,
522 p_bmk_edit->p_seekpoint, i_first ) !=
525 vlc_object_release( p_input );
529 vlc_object_release( p_input );
535 void BookmarksDialog::OnUpdate( wxCommandEvent &event )
540 /*****************************************************************************
541 * PlaylistChanged: callback triggered by the intf-change playlist variable
542 * We don't rebuild the playlist directly here because we don't want the
543 * caller to block for a too long time.
544 *****************************************************************************/
545 static int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable,
546 vlc_value_t oval, vlc_value_t nval, void *param )
548 BookmarksDialog::BookmarksDialog *p_dialog =
549 (BookmarksDialog::BookmarksDialog *)param;
551 wxCommandEvent bookmarks_event( wxEVT_BOOKMARKS, 0 );
552 p_dialog->AddPendingEvent( bookmarks_event );