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