]> git.sesse.net Git - vlc/blob - modules/gui/wxwindows/bookmarks.cpp
0415668b31c7874334f50876db9b942f373cf590
[vlc] / modules / gui / wxwindows / bookmarks.cpp
1 /*****************************************************************************
2  * bookmarks.cpp : wxWindows plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2004 VideoLAN
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28 #include <errno.h>                                                 /* ENOMEM */
29 #include <string.h>                                            /* strerror() */
30 #include <stdio.h>
31
32 #include <vlc/vlc.h>
33 #include <vlc/intf.h>
34
35 #include "wxwindows.h"
36 #include <wx/dialog.h>
37
38 /* Callback prototype */
39 static int PlaylistChanged( vlc_object_t *, const char *,
40                             vlc_value_t, vlc_value_t, void * );
41
42 /*****************************************************************************
43  * Class declaration.
44  *****************************************************************************/
45
46 /* IDs for the controls and the menu commands */
47 enum
48 {
49     /* menu items */
50     ButtonAdd_Event = wxID_HIGHEST + 1,
51     ButtonDel_Event,
52     ButtonClear_Event,
53     ButtonExtract_Event,
54     ButtonEdit_Event
55 };
56
57 class BookmarksDialog: public wxFrame
58 {
59 public:
60     /* Constructor */
61     BookmarksDialog( intf_thread_t *p_intf, wxWindow *p_parent );
62     virtual ~BookmarksDialog();
63
64     bool Show( bool );
65
66 private:
67
68     void Update();
69
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 );
79
80     DECLARE_EVENT_TABLE();
81
82     intf_thread_t *p_intf;
83     wxWindow *p_parent;
84
85     wxListView *list_ctrl;
86 };
87 DEFINE_LOCAL_EVENT_TYPE( wxEVT_BOOKMARKS );
88
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 )
97
98     EVT_LIST_ITEM_ACTIVATED( -1, BookmarksDialog::OnActivateItem )
99
100     EVT_COMMAND( -1, wxEVT_BOOKMARKS, BookmarksDialog::OnUpdate )
101 END_EVENT_TABLE()
102
103 /* Declaration of class BookmarkEditDialog */
104 class BookmarkEditDialog : public wxDialog
105 {
106 public:
107     /* Constructor */
108     BookmarkEditDialog( intf_thread_t *p_intf, wxWindow *p_parent,
109                   seekpoint_t *p_seekpoint );
110     virtual ~BookmarkEditDialog();
111     seekpoint_t *p_seekpoint;
112 private:
113
114     wxTextCtrl *name_text, *time_text, *bytes_text;
115
116     void OnOK( wxCommandEvent& event);
117     void OnCancel( wxCommandEvent& event);
118
119     DECLARE_EVENT_TABLE();
120
121     intf_thread_t *p_intf;
122 };
123
124 BEGIN_EVENT_TABLE( BookmarkEditDialog, wxDialog)
125             EVT_BUTTON( wxID_OK, BookmarkEditDialog::OnOK)
126 END_EVENT_TABLE()
127 /****************************************************************************
128  * BookmarkEditDialog
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 )
134 {
135     /* Initializations */
136     p_intf = _p_intf;
137     p_seekpoint = _p_seekpoint;
138     SetIcon( *p_intf->p_sys->p_icon );
139
140     /* Create a panel to put everything in*/
141     wxBoxSizer *panel_sizer = new wxBoxSizer( wxVERTICAL );
142
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) );
153
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);
160
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") ) ) );
164
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 );
169 }
170
171 BookmarkEditDialog::~BookmarkEditDialog()
172 {
173 }
174 void BookmarkEditDialog::OnOK( wxCommandEvent &event )
175 {
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() ) ;
181     EndModal( wxID_OK );
182 }
183
184 void BookmarkEditDialog::OnCancel( wxCommandEvent &event )
185 {
186     EndModal( wxID_CANCEL );
187 }
188
189 /*****************************************************************************
190  * Constructor.
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 ),
199              wxSize( 500, -1 ),
200              wxDEFAULT_FRAME_STYLE | wxFRAME_FLOAT_ON_PARENT )
201 {
202     /* Initializations */
203     p_intf = _p_intf;
204     SetIcon( *p_intf->p_sys->p_icon );
205
206     wxPanel *main_panel = new wxPanel( this, -1 );
207     wxBoxSizer *main_sizer = new wxBoxSizer( wxHORIZONTAL );
208
209     wxBoxSizer *sizer = new wxBoxSizer( wxHORIZONTAL );
210
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")) );
223
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 ) ) );
236
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 );
244
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")) );
252
253     sizer->Add( panel, 0, wxEXPAND | wxALL, 1 );
254     sizer->Add( list_ctrl, 1, wxEXPAND | wxALL, 1 );
255     main_panel->SetSizer( sizer );
256
257     main_sizer->Add( main_panel, 1, wxEXPAND );
258     SetSizer( main_sizer );
259
260     playlist_t *p_playlist =
261         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
262                                        FIND_ANYWHERE );
263     if( p_playlist )
264     {
265        /* Some global changes happened -> Rebuild all */
266        var_AddCallback( p_playlist, "playlist-current",
267                         PlaylistChanged, this );
268        vlc_object_release( p_playlist );
269     }
270 }
271
272 BookmarksDialog::~BookmarksDialog()
273 {
274     playlist_t *p_playlist =
275         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
276                                        FIND_ANYWHERE );
277     if( p_playlist )
278     {
279        var_DelCallback( p_playlist, "playlist-current",
280                         PlaylistChanged, this );
281        vlc_object_release( p_playlist );
282     }
283 }
284
285 /*****************************************************************************
286  * Private methods.
287  *****************************************************************************/
288 wxWindow *BookmarksDialog( intf_thread_t *p_intf, wxWindow *p_parent )
289 {
290     return new BookmarksDialog::BookmarksDialog( p_intf, p_parent );
291 }
292
293 void BookmarksDialog::Update()
294 {
295     input_thread_t *p_input =
296         (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
297                                            FIND_ANYWHERE );
298     if( !p_input ) return;
299
300     seekpoint_t **pp_bookmarks;
301     int i_bookmarks;
302
303     list_ctrl->DeleteAllItems();
304     if( input_Control( p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks,
305                        &i_bookmarks ) != VLC_SUCCESS )
306     {
307         vlc_object_release( p_input );
308         return;
309     }
310
311     for( int i = 0; i < i_bookmarks; i++ )
312     {
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) ) );
319     }
320
321     vlc_object_release( p_input );
322 }
323
324 bool BookmarksDialog::Show( bool show )
325 {
326     Update();
327     return wxFrame::Show( show );
328 }
329
330 void BookmarksDialog::OnClose( wxCommandEvent& event )
331 {
332     Hide();
333 }
334
335 void BookmarksDialog::OnAdd( wxCommandEvent& event )
336 {
337     input_thread_t *p_input =
338         (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
339                                            FIND_ANYWHERE );
340     if( !p_input ) return;
341
342     seekpoint_t bookmark;
343     vlc_value_t pos;
344     bookmark.psz_name = NULL;
345     bookmark.i_byte_offset = 0;
346     bookmark.i_time_offset = 0;
347
348
349     /* FIXME --fenrir
350      * - stream_Tell can't be use (not reentrant)
351      * - nobody except src/input/ could touch p_input
352      *   -> create new INPUT_CONTROL ...
353      */
354 #if 0
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 );
362 #endif
363     vlc_object_release( p_input );
364
365     Update();
366 }
367
368 void BookmarksDialog::OnDel( wxCommandEvent& event )
369 {
370     input_thread_t *p_input =
371         (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
372                                            FIND_ANYWHERE );
373     if( !p_input ) return;
374
375     int i_focused = list_ctrl->GetFocusedItem();
376     if( i_focused >= 0 )
377     {
378         input_Control( p_input, INPUT_DEL_BOOKMARK, i_focused );
379     }
380
381     vlc_object_release( p_input );
382
383     Update();
384 }
385
386 void BookmarksDialog::OnClear( wxCommandEvent& event )
387 {
388     input_thread_t *p_input =
389         (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
390                                            FIND_ANYWHERE );
391     if( !p_input ) return;
392
393     input_Control( p_input, INPUT_CLEAR_BOOKMARKS );
394
395     vlc_object_release( p_input );
396
397     Update();
398 }
399
400 void BookmarksDialog::OnExtract( wxCommandEvent& event )
401 {
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 );
406
407     if( i_first == -1 || i_second == -1 )
408     {
409         wxMessageBox( wxU(_("You must select two bookmarks") ),
410                       wxU(_("Invalid selection") ), wxICON_WARNING | wxOK,
411                       this );
412         return;
413     }
414     input_thread_t *p_input =
415         (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
416                                            FIND_ANYWHERE );
417     if( !p_input )
418     {
419         wxMessageBox( wxU(_("The stream must be playing or paused for "
420                             "bookmarks to work" ) ), wxU(_("No input found")),
421                             wxICON_WARNING | wxOK,
422                             this );
423         return;
424     }
425
426     seekpoint_t **pp_bookmarks;
427     int i_bookmarks ;
428
429     if( input_Control( p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks,
430                        &i_bookmarks ) != VLC_SUCCESS )
431     {
432         vlc_object_release( p_input );
433         return;
434     }
435
436     if( i_first < i_bookmarks && i_second <= i_bookmarks )
437     {
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 )
444         {
445             p_wizard_dialog->Run();
446             delete p_wizard_dialog;
447         }
448     }
449     else
450     {
451         vlc_object_release( p_input );
452     }
453 }
454
455 void BookmarksDialog::OnActivateItem( wxListEvent& event )
456 {
457     input_thread_t *p_input =
458         (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
459                                            FIND_ANYWHERE );
460     if( !p_input ) return;
461
462     input_Control( p_input, INPUT_SET_BOOKMARK, event.GetIndex() );
463
464     vlc_object_release( p_input );
465 }
466
467 void BookmarksDialog::OnEdit( wxCommandEvent& event )
468 {
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,
472                                                    FIND_ANYWHERE );
473     if( !p_input ) return;
474
475
476     seekpoint_t **pp_bookmarks;
477     int i_bookmarks;
478
479     if( input_Control( p_input, INPUT_GET_BOOKMARKS, &pp_bookmarks,
480                        &i_bookmarks ) != VLC_SUCCESS )
481     {
482         vlc_object_release( p_input );
483         return;
484     }
485     p_old_input = p_input;
486     vlc_object_release( p_input );
487
488     long i_first = list_ctrl->GetNextItem( -1, wxLIST_NEXT_ALL,
489                                                wxLIST_STATE_SELECTED );
490
491     if( i_first > -1 && i_first <= i_bookmarks )
492     {
493         BookmarkEditDialog *p_bmk_edit;
494         p_bmk_edit = new BookmarkEditDialog( p_intf, this,
495                                pp_bookmarks[i_first]);
496
497         if( p_bmk_edit->ShowModal() == wxID_OK )
498         {
499             p_input =(input_thread_t *)vlc_object_find( p_intf,
500                             VLC_OBJECT_INPUT, FIND_ANYWHERE );
501            if( !p_input )
502            {
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,
506                                this );
507                 return;
508            }
509            if( p_old_input != p_input )
510            {
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 );
517                 return;
518
519            }
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 ) !=
523                VLC_SUCCESS )
524            {
525                vlc_object_release( p_input );
526                return;
527            }
528            Update();
529            vlc_object_release( p_input );
530         }
531     }
532 }
533
534
535 void BookmarksDialog::OnUpdate( wxCommandEvent &event )
536 {
537     Update();
538 }
539
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 )
547 {
548     BookmarksDialog::BookmarksDialog *p_dialog =
549         (BookmarksDialog::BookmarksDialog *)param;
550
551     wxCommandEvent bookmarks_event( wxEVT_BOOKMARKS, 0 );
552     p_dialog->AddPendingEvent( bookmarks_event );
553
554     return VLC_SUCCESS;
555 }