d83e3dacbd1415d2eb31b2a2d56752739d55ee7e
[vlc.git] / modules / gui / kde / interface.cpp
1 /***************************************************************************
2                           interface.cpp  -  description
3                              -------------------
4     begin                : Sun Mar 25 2001
5     copyright            : (C) 2001 by andres
6     email                : dae@chez.com
7  ***************************************************************************/
8
9 #include "disc.h"
10 #include "info.h"
11 #include "interface.h"
12 #include "net.h"
13 #include "menu.h"
14 #include "slider.h"
15 #include "preferences.h"
16 #include "languagemenu.h"
17
18 #include <iostream>
19
20 #include <kaction.h>
21 #include <kfiledialog.h>
22 #include <klocale.h>
23 #include <kstdaction.h>
24 #include <kurl.h>
25 #include <kurldrag.h>
26 #include <qcursor.h>
27 #include <qdragobject.h>
28 #include <qtimer.h>
29 #include <kdialog.h>
30 #include <kstatusbar.h>
31
32 #define ID_STATUS_MSG       1
33 #define ID_DATE             2
34 #define ID_STREAM_SOURCE    3
35
36 KInterface::KInterface( intf_thread_t *p_intf, QWidget *parent,
37         const char *name ) : KMainWindow(parent,name)
38 {
39     setAcceptDrops(true);
40
41     this->p_intf = p_intf;
42     p_messagesWindow = new KMessagesWindow( p_intf, p_intf->p_sys->p_msg );
43     fDiskDialog = new KDiskDialog( this );
44     fNetDialog = new KNetDialog( this );
45     fTitleMenu = new KTitleMenu( p_intf, this );
46
47     fSlider = new KVLCSlider( QSlider::Horizontal, this );
48     fSlider->setMaxValue(10000);
49     connect( fSlider, SIGNAL( userChanged( int ) ), this,
50              SLOT( slotSliderMoved( int ) ) );
51     connect( fSlider, SIGNAL( valueChanged( int ) ), this,
52              SLOT( slotSliderChanged( int ) ) );
53     connect( fSlider, SIGNAL( sliderMoved( int ) ), this,
54              SLOT( slotSliderChanged( int ) ) );
55     setCentralWidget(fSlider);
56
57     fTimer = new QTimer( this );
58     connect( fTimer, SIGNAL( timeout() ), this, SLOT( slotManage() ) );
59
60     resize( 400, 30 );
61     ///////////////////////////////////////////////////////////////////
62     // call inits to invoke all other construction parts
63     // XXX could we move this up ?
64     initStatusBar();
65     initActions();
66
67     // add certain calls to the popup menu
68     fileOpen->plug( fTitleMenu );
69     fileOpenRecent->plug( fTitleMenu );
70     diskOpen->plug( fTitleMenu );
71     streamOpen->plug( fTitleMenu );
72     play->plug( fTitleMenu );
73     pause->plug( fTitleMenu );
74     slow->plug( fTitleMenu );
75     fast->plug( fTitleMenu );
76     fileQuit->plug( fTitleMenu );
77     fTimer->start( 0, FALSE );
78
79 }
80
81 KInterface::~KInterface()
82 {
83     ;
84 }
85
86 void KInterface::initActions()
87 {
88     languages = new KActionMenu( _( "Languages" ), actionCollection(),
89                                  "language" );
90     languages->setEnabled( false );
91     languageCollection = new KActionCollection( this );
92     subtitleCollection = new KActionCollection( this );
93     subtitles = new KActionMenu( _( "Subtitles" ), actionCollection(),
94                                  "subtitles" );
95     subtitles->setEnabled( false );
96     fileOpen =
97         KStdAction::open(this, SLOT(slotFileOpen()), actionCollection());
98     fileOpenRecent =
99         KStdAction::openRecent(this, SLOT(slotFileOpenRecent(const KURL&)),
100                                actionCollection());
101     preferences = KStdAction::preferences(this, SLOT(slotShowPreferences()),
102                                           actionCollection());
103     fileQuit = KStdAction::quit(this, SLOT(slotFileQuit()),
104                                 actionCollection());
105     viewToolBar = KStdAction::showToolbar(this, SLOT(slotViewToolBar()),
106                                           actionCollection());
107     viewStatusBar = KStdAction::showStatusbar(this, SLOT(slotViewStatusBar()),
108                                               actionCollection());
109
110     diskOpen = new KAction( i18n( "Open &Disk" ), 0, 0, this,
111                             SLOT( slotOpenDisk() ), actionCollection(),
112                             "open_disk" );
113     streamOpen = new KAction( i18n( "Open &Stream" ), 0, 0, this,
114                               SLOT( slotOpenStream() ), actionCollection(),
115                               "open_stream" );
116     backward = new KAction( i18n( "&Backward" ), 0, 0, this,
117                             SLOT( slotBackward() ), actionCollection(),
118                             "backward" );
119     stop = new KAction( i18n( "&Stop" ), 0, 0, this,
120                         SLOT( slotStop() ), actionCollection(), "stop" );
121     play = new KAction( i18n( "&Play" ), 0, 0, this,
122                         SLOT( slotPlay() ), actionCollection(), "play" );
123     pause = new KAction( i18n( "P&ause" ), 0, 0, this,
124                          SLOT( slotPause() ), actionCollection(), "pause" );
125     slow = new KAction( i18n( "&Slow" ), 0, 0, this,
126                         SLOT( slotSlow() ), actionCollection(), "slow" );
127     fast = new KAction( i18n( "Fas&t" ), 0, 0, this,
128                         SLOT( slotFast() ), actionCollection(), "fast" );
129     prev = new KAction( i18n( "Prev" ), 0, 0, this,
130                         SLOT( slotPrev() ), actionCollection(), "prev" );
131     next = new KAction( i18n( "Next" ), 0, 0, this,
132                         SLOT( slotNext() ), actionCollection(), "next" );
133     messages = new KAction( _( "Messages..." ), 0, 0, this,
134                             SLOT( slotShowMessages() ), actionCollection(),
135                             "view_messages");
136     
137     info = new KAction( _( "Stream info..." ), 0, 0, this,
138                         SLOT( slotShowInfo() ), actionCollection(),
139                         "view_stream_info");
140
141     info->setEnabled( false );
142     program = new KActionMenu( _( "Program" ), actionCollection(), "program" );
143     program->setEnabled( false );
144     title = new KActionMenu( _( "Title" ), actionCollection(), "title" );
145     title->setEnabled( false );
146     chapter = new KActionMenu( _( "Chapter" ), actionCollection(), "chapter" );
147     chapter->setEnabled( false );
148     fileOpen->setStatusText(i18n("Opens an existing document"));
149     fileOpenRecent->setStatusText(i18n("Opens a recently used file"));
150     fileQuit->setStatusText(i18n("Quits the application"));
151     viewToolBar->setStatusText(i18n("Enables/disables the toolbar"));
152     viewStatusBar->setStatusText(i18n("Enables/disables the statusbar"));
153
154     diskOpen->setStatusText( i18n( "Opens a disk") );
155     streamOpen->setStatusText( i18n( "Opens a network stream" ) );
156     backward->setStatusText( i18n( "Backward" ) );
157     stop->setStatusText( i18n( "Stops playback" ) );
158     play->setStatusText( i18n( "Starts playback" ) );
159     pause->setStatusText( i18n( "Pauses playback" ) );
160     slow->setStatusText( i18n( "Slow" ) );
161     fast->setStatusText( i18n( "Fast" ) );
162     prev->setStatusText( i18n( "Prev" ) );
163     next->setStatusText( i18n( "Next" ) );
164     // use the absolute path to your ktestui.rc file for testing purpose in createGUI();
165     char *uifile = config_GetPsz( p_intf, "kdeuirc" );
166     createGUI( uifile );
167 //    createGUI( "./modules/gui/kde/ui.rc" );
168 }
169
170 void KInterface::initStatusBar()
171 {
172   ///////////////////////////////////////////////////////////////////
173   // STATUSBAR
174   // TODO: add your own items you need for displaying current application status.
175     statusBar()->insertItem(i18n("Ready."), ID_STATUS_MSG, 1, false);
176     statusBar()->setItemAlignment( ID_STATUS_MSG, AlignLeft | AlignVCenter );
177     statusBar()->insertItem( "0:00:00", ID_DATE, 0, true );
178 }
179
180 /////////////////////////////////////////////////////////////////////
181 // SLOT IMPLEMENTATION
182 /////////////////////////////////////////////////////////////////////
183 void KInterface::slotShowMessages()
184 {
185     p_messagesWindow->show();
186 }
187
188 void KInterface::slotShowInfo()
189 {
190     if ( p_intf->p_sys->p_input )
191     {
192         new KInfoWindow(p_intf, p_intf->p_sys->p_input);
193     }
194 }
195
196 void KInterface::slotFileOpen()
197 {
198     playlist_t *p_playlist;
199
200     slotStatusMsg( i18n( "Opening file..." ) );
201     KURL url=KFileDialog::getOpenURL( QString::null,
202             i18n( "*|All files" ), this, i18n( "Open File..." ) );
203
204     if( !url.isEmpty() )
205     {
206         p_playlist = (playlist_t *)
207             vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
208         if( p_playlist )
209         {
210             fileOpenRecent->addURL( url );
211             playlist_Add( p_playlist, url.path(),
212                           PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );
213             vlc_object_release( p_playlist );
214         }
215     }
216
217     slotStatusMsg( i18n( "Ready." ) );
218 }
219
220 void KInterface::slotFileOpenRecent(const KURL& url)
221 {
222   slotStatusMsg(i18n("Opening file..."));
223   slotStatusMsg(i18n("Ready."));
224 }
225
226 void KInterface::slotFileQuit()
227 {
228     slotStatusMsg(i18n("Exiting..."));
229     p_intf->p_vlc->b_die = VLC_TRUE;
230     slotStatusMsg(i18n("Ready."));
231 }
232
233 void KInterface::slotViewToolBar()
234 {
235   slotStatusMsg(i18n("Toggling toolbar..."));
236   ///////////////////////////////////////////////////////////////////
237   // turn Toolbar on or off
238   if(!viewToolBar->isChecked())
239   {
240     toolBar("mainToolBar")->hide();
241   }
242   else
243   {
244     toolBar("mainToolBar")->show();
245   }        
246
247   slotStatusMsg(i18n("Ready."));
248 }
249
250 void KInterface::slotViewStatusBar()
251 {
252   slotStatusMsg(i18n("Toggle the statusbar..."));
253   ///////////////////////////////////////////////////////////////////
254   //turn Statusbar on or off
255   if(!viewStatusBar->isChecked())
256   {
257     statusBar()->hide();
258   }
259   else
260   {
261     statusBar()->show();
262   }
263
264   slotStatusMsg(i18n("Ready."));
265 }
266
267 void KInterface::slotShowPreferences()
268 {
269     // Do something
270     KPreferences(this->p_intf, "main", this, "preferences");
271 }
272
273 void KInterface::slotStatusMsg(const QString &text)
274 {
275   ///////////////////////////////////////////////////////////////////
276   // change status message permanently
277   statusBar()->clear();
278   statusBar()->changeItem(text, ID_STATUS_MSG);
279 }
280
281 void KInterface::slotManage()
282 {
283     p_messagesWindow->update();
284 //    p_intf->p_sys->p_app->processEvents();
285     vlc_mutex_lock( &p_intf->change_lock );
286
287     /* Update the input */
288     if( p_intf->p_sys->p_input == NULL )
289     {
290         p_intf->p_sys->p_input = (input_thread_t *)
291                 vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
292         if ( p_intf->p_sys->p_input )
293         {
294             languages->setEnabled( true );
295             subtitles->setEnabled( true );
296             info->setEnabled( true );
297         }
298             
299     }
300     else if( p_intf->p_sys->p_input->b_dead )
301     {
302         vlc_object_release( p_intf->p_sys->p_input );
303         p_intf->p_sys->p_input = NULL;
304         languages->setEnabled( false );
305         subtitles->setEnabled( false );
306         info->setEnabled( false );
307     }
308
309     /* If the "display popup" flag has changed */
310     if( p_intf->b_menu_change )
311     {
312         fTitleMenu->popup( ( QCursor::pos() ) );
313         p_intf->b_menu_change = 0;
314     }
315
316     if( p_intf->p_sys->p_input )
317     {
318         input_thread_t *p_input = p_intf->p_sys->p_input;
319                 
320         vlc_mutex_lock( &p_input->stream.stream_lock );
321         if( !p_input->b_die )
322         {
323             /* New input or stream map change */
324             if( p_input->stream.b_changed )
325             {
326                 //            E_(GtkModeManage)( p_intf );
327                 //GtkSetupMenus( p_intf );
328                 slotUpdateLanguages();
329
330                 p_intf->p_sys->b_playing = 1;
331                 p_input->stream.b_changed = 0;
332             }
333
334             /* Manage the slider. fSlider->setValue triggers
335              * slotSliderChanged which needs to grab the stream lock*/
336 #define p_area p_input->stream.p_selected_area
337             if( p_area->i_size ) {
338                 vlc_mutex_unlock( &p_input->stream.stream_lock );
339                 fSlider->setValue( ( 10000 * p_area->i_tell )
340                                    / p_area->i_size );
341                 vlc_mutex_lock( &p_input->stream.stream_lock );
342
343             }
344 #undef p_area
345             
346             //         if( p_intf->p_sys->i_part !=
347             //    p_input->stream.p_selected_area->i_part )
348             //{
349                 //      p_intf->p_sys->b_chapter_update = 1;
350                 //GtkSetupMenus( p_intf );
351             //}
352         }
353         vlc_mutex_unlock( &p_input->stream.stream_lock );
354
355     }
356     
357     else if( p_intf->p_sys->b_playing && !p_intf->b_die )
358     {
359         //E_(GtkModeManage)( p_intf );
360         p_intf->p_sys->b_playing = 0;
361     }
362
363     if( p_intf->b_die )
364     {
365         p_intf->p_sys->p_app->quit();
366     }
367
368     vlc_mutex_unlock( &p_intf->change_lock );
369     msleep( 100 );
370
371 }
372
373 void KInterface::slotSliderMoved( int position )
374 {
375     if( p_intf->p_sys->p_input )
376     {
377         // XXX is this locking really useful ?
378         vlc_mutex_lock( &p_intf->change_lock );
379
380         off_t i_seek = ( position * p_intf->p_sys->p_input->stream.p_selected_area->i_size ) / 10000;
381         input_Seek( p_intf->p_sys->p_input, i_seek, INPUT_SEEK_SET );
382
383         vlc_mutex_unlock( &p_intf->change_lock );
384     }
385 }
386
387 void KInterface::slotUpdateLanguages()
388 {
389
390     es_descriptor_t *   p_spu_es;
391     es_descriptor_t *   p_audio_es;
392     /* look for selected ES */
393     p_audio_es = NULL;
394     p_spu_es = NULL;
395
396     for( unsigned int i = 0 ;
397          i < p_intf->p_sys->p_input->stream.i_selected_es_number ;
398          i++
399         )
400     {
401         if( p_intf->p_sys->p_input->stream.pp_selected_es[i]->i_cat
402             == AUDIO_ES )
403         {
404             p_audio_es = p_intf->p_sys->p_input->stream.pp_selected_es[i];
405         }
406
407         if( p_intf->p_sys->p_input->stream.pp_selected_es[i]->i_cat == SPU_ES )
408         {
409             p_spu_es = p_intf->p_sys->p_input->stream.pp_selected_es[i];
410         }
411     }
412     languages->setEnabled( false );
413     subtitles->setEnabled( false );
414     languageCollection->clear();
415     subtitleCollection->clear();
416     languages->popupMenu()->clear();
417     subtitles->popupMenu()->clear();
418     /* audio menus */
419     /* find audio root menu */
420     languageMenus( languages, p_audio_es, AUDIO_ES );
421
422     /* sub picture menus */
423     /* find spu root menu */
424     languageMenus( subtitles, p_spu_es, SPU_ES );
425
426 }
427
428
429 /*
430  * called with stream lock
431  */
432 void KInterface::languageMenus(KActionMenu *root, es_descriptor_t *p_es,
433                           int i_cat)
434 {
435     int i_item = 0;
436     if ( i_cat != AUDIO_ES )
437     {
438         KLanguageMenuAction *p_item =
439             new KLanguageMenuAction( p_intf, _( "Off" ), 0, this );
440         subtitleCollection->insert( p_item );
441         root->insert( p_item );
442         root->insert( new KActionSeparator( this ) );
443         p_item->setExclusiveGroup( QString().sprintf( "%d", i_cat ) );
444         p_item->setChecked( p_es == 0 );
445     }
446     
447 #define ES p_intf->p_sys->p_input->stream.pp_es[i]
448     /* create a set of language buttons and append them to the container */
449     for( unsigned int i = 0 ;
450          i < p_intf->p_sys->p_input->stream.i_es_number ;
451          i++ )
452     {
453         if( ( ES->i_cat == i_cat ) &&
454             ( !ES->p_pgrm ||
455               ES->p_pgrm ==
456                  p_intf->p_sys->p_input->stream.p_selected_program ) )
457         {
458             i_item++;
459             QString name = p_intf->p_sys->p_input->stream.pp_es[i]->psz_desc;
460             if( name.isEmpty() )
461             {
462                 name.sprintf( "Language %d", i_item );
463             }
464             KLanguageMenuAction *p_item;
465             if ( i_cat == AUDIO_ES )
466             {
467                 p_item = new KLanguageMenuAction( p_intf, name, ES,
468                                                   this );
469                 languageCollection->insert(p_item);
470             }
471             else
472             {
473                 p_item = new KLanguageMenuAction( p_intf, name, ES,
474                                                   this );
475                 subtitleCollection->insert(p_item);
476             }
477             p_item->setExclusiveGroup( QString().sprintf( "%d", i_cat ) );
478             root->insert( p_item );
479             
480             if( p_es == p_intf->p_sys->p_input->stream.pp_es[i] )
481             {
482                 /* don't lose p_item when we append into menu */
483                 //p_item_active = p_item;
484                 p_item->setChecked( true );
485             }
486             connect( p_item, SIGNAL( toggled( bool, es_descriptor_t * ) ),
487                      this, SLOT( slotSetLanguage( bool, es_descriptor_t * ) ));
488
489         }
490     }
491
492     root->setEnabled( true );
493 }
494
495
496 void KInterface::slotSetLanguage( bool on, es_descriptor_t *p_es )
497 {
498     input_ToggleES( p_intf->p_sys->p_input, p_es, on );
499 }
500
501 void KInterface::slotSliderChanged( int position )
502 {
503     if( p_intf->p_sys->p_input != NULL )
504     {
505         char psz_time[ OFFSETTOTIME_MAX_SIZE ];
506
507         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
508
509 #define p_area p_intf->p_sys->p_input->stream.p_selected_area
510         statusBar()->changeItem( input_OffsetToTime( p_intf->p_sys->p_input, psz_time, ( p_area->i_size * position ) / 10000 ), ID_DATE );
511 #undef p_area
512
513         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
514      }
515 }
516
517 void KInterface::slotOpenDisk()
518 {
519     playlist_t *p_playlist;
520     int r = fDiskDialog->exec();
521     if ( r )
522     {
523         // Build source name
524         QString source;
525         source += fDiskDialog->type();
526         source += ':';
527         source += fDiskDialog->device();
528
529         source += '@';
530         source += fDiskDialog->title();
531         source += ',';
532         source += fDiskDialog->chapter();
533
534         p_playlist = (playlist_t *)
535             vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
536         if( p_playlist )
537         {
538             // add it to playlist
539             playlist_Add( p_playlist, source.latin1(),
540                           PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );
541             vlc_object_release( p_playlist );
542         }
543     }
544 }
545
546 void KInterface::slotOpenStream()
547 {
548     playlist_t *p_playlist;
549     int r = fNetDialog->exec();
550     if ( r )
551     {
552         // Build source name
553         QString source;
554         source += fNetDialog->protocol();
555         source += "://";
556         source += fNetDialog->server();
557         source += ":";
558         source += QString().setNum( fNetDialog->port() );
559
560         p_playlist = (playlist_t *)
561             vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
562         if( p_playlist )
563         {
564             // add it to playlist
565             playlist_Add( p_playlist, source.latin1(),
566                           PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );
567             vlc_object_release( p_playlist );
568         }
569     }
570 }
571
572 void KInterface::slotPlay()
573 {
574     if( p_intf->p_sys->p_input )
575     {
576         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
577     }
578 }
579
580 void KInterface::slotPause()
581 {
582     if ( p_intf->p_sys->p_input )
583     {
584         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PAUSE );
585     }
586 }
587
588 void KInterface::slotStop()
589 {
590     playlist_t *p_playlist = (playlist_t *)
591             vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
592     if( p_playlist )
593     {
594         playlist_Stop( p_playlist );
595         vlc_object_release( p_playlist );
596     }
597 }
598
599 void KInterface::slotBackward()
600 {
601     msg_Err( p_intf, "KInterface::slotBackward() - Unimplemented" );
602 }
603
604 void KInterface::slotPrev()
605 {
606     playlist_t *p_playlist = (playlist_t *)
607             vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
608     if( p_playlist )
609     {
610         playlist_Prev( p_playlist );
611         vlc_object_release( p_playlist );
612     }
613 }
614
615 void KInterface::slotNext()
616 {
617     playlist_t *p_playlist = (playlist_t *)
618             vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
619     if( p_playlist )
620     {
621         playlist_Next( p_playlist );
622         vlc_object_release( p_playlist );
623     }
624 }
625
626 void KInterface::slotSlow()
627 {
628     if( p_intf->p_sys->p_input != NULL )
629     {
630         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_SLOWER );
631     }
632 }
633
634 void KInterface::slotFast()
635 {
636     if( p_intf->p_sys->p_input != NULL )
637     {
638         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_FASTER );
639     }
640 }
641
642 void KInterface::dragEnterEvent( QDragEnterEvent *event )
643 {
644     event->accept( QUriDrag::canDecode( event ) );
645 }
646
647 void KInterface::dropEvent( QDropEvent *event )
648 {
649     KURL::List urlList;
650
651     playlist_t *p_playlist = (playlist_t *)
652             vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
653     if( p_playlist == NULL )
654     {
655         return;
656     }
657
658     if ( KURLDrag::decode( event, urlList ) )
659     {
660         for ( KURL::List::ConstIterator i = urlList.begin(); i != urlList.end(); i++ )
661         {
662             // XXX add a private function to add a KURL with checking
663             // actually a whole class for core abstraction would be neat
664             if( !(*i).isEmpty() )
665             {
666                 fileOpenRecent->addURL( *i );
667                 playlist_Add( p_playlist, (*i).path(),
668                           PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );
669             }
670         }
671     }
672
673     vlc_object_release( p_playlist );
674 }