]> git.sesse.net Git - vlc/blob - modules/gui/qt4/menus.cpp
Qt: addons manager: add search box
[vlc] / modules / gui / qt4 / menus.cpp
1 /*****************************************************************************
2  * menus.cpp : Qt menus
3  *****************************************************************************
4  * Copyright © 2006-2011 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Clément Stenac <zorglub@videolan.org>
8  *          Jean-Baptiste Kempf <jb@videolan.org>
9  *          Jean-Philippe André <jpeg@videolan.org>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * ( at your option ) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 /** \todo
27  * - Remove static currentGroup
28  */
29
30 #define __STDC_FORMAT_MACROS 1
31 #define __STDC_CONSTANT_MACROS 1
32
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #include <vlc_common.h>
38 #include <vlc_intf_strings.h>
39 #include <vlc_vout.h>                             /* vout_thread_t */
40 #include <vlc_aout.h>                             /* audio_output_t */
41
42 #include "menus.hpp"
43
44 #include "main_interface.hpp"                     /* View modifications */
45 #include "dialogs_provider.hpp"                   /* Dialogs display */
46 #include "input_manager.hpp"                      /* Input Management */
47 #include "recents.hpp"                            /* Recent Items */
48 #include "actions_manager.hpp"                    /* Actions Management: play+volume */
49 #include "extensions_manager.hpp"                 /* Extensions menu */
50 #include "util/qmenuview.hpp"                     /* Simple Playlist menu */
51 #include "components/playlist/playlist_model.hpp" /* PLModel getter */
52 #include "components/playlist/standardpanel.hpp"  /* PLView getter */
53
54 #include <QMenu>
55 #include <QMenuBar>
56 #include <QAction>
57 #include <QActionGroup>
58 #include <QSignalMapper>
59 #include <QStatusBar>
60
61 /*
62   This file defines the main menus and the pop-up menu (right-click menu)
63   and the systray menu (in that order in the file)
64
65   There are 4 menus that have to be rebuilt everytime there are called:
66   Audio, Video, Navigation, view
67   4 functions are building those menus: AudioMenu, VideoMenu, NavigMenu, View
68   and 3 functions associated are collecting the objects :
69   InputAutoMenuBuilder, AudioAutoMenuBuilder, VideoAutoMenuBuilder.
70
71   A QSignalMapper decides when to rebuild those menus cf MenuFunc in the .hpp
72   Just before one of those menus are aboutToShow(), they are rebuild.
73   */
74
75 enum
76 {
77     ITEM_NORMAL, /* not a checkbox, nor a radio */
78     ITEM_CHECK,  /* Checkbox */
79     ITEM_RADIO   /* Radiobox */
80 };
81
82 static QActionGroup *currentGroup;
83
84 QMenu *VLCMenuBar::recentsMenu = NULL;
85 QMenu *VLCMenuBar::audioDeviceMenu = NULL;
86
87 /**
88  * @brief Add static entries to DP in menus
89  **/
90 QAction *addDPStaticEntry( QMenu *menu,
91                        const QString& text,
92                        const char *icon,
93                        const char *member,
94                        const char *shortcut = NULL,
95                        QAction::MenuRole role = QAction::NoRole
96                        )
97 {
98     QAction *action = NULL;
99 #ifndef __APPLE__ /* We don't set icons in menus in MacOS X */
100     if( !EMPTY_STR( icon ) )
101     {
102         if( !EMPTY_STR( shortcut ) )
103             action = menu->addAction( QIcon( icon ), text, THEDP,
104                                       member, qtr( shortcut ) );
105         else
106             action = menu->addAction( QIcon( icon ), text, THEDP, member );
107     }
108     else
109 #endif
110     {
111         if( !EMPTY_STR( shortcut ) )
112             action = menu->addAction( text, THEDP, member, qtr( shortcut ) );
113         else
114             action = menu->addAction( text, THEDP, member );
115     }
116 #ifdef __APPLE__
117     action->setMenuRole( role );
118 #else
119     Q_UNUSED( role );
120 #endif
121     action->setData( VLCMenuBar::ACTION_STATIC );
122     return action;
123 }
124
125 /**
126  * @brief Add static entries to MIM in menus
127  **/
128 QAction* addMIMStaticEntry( intf_thread_t *p_intf,
129                             QMenu *menu,
130                             const QString& text,
131                             const char *icon,
132                             const char *member,
133                             bool bStatic = false )
134 {
135     QAction *action;
136 #ifndef __APPLE__ /* We don't set icons in menus in MacOS X */
137     if( !EMPTY_STR( icon ) )
138     {
139         action = menu->addAction( text, THEMIM,  member );
140         action->setIcon( QIcon( icon ) );
141     }
142     else
143 #endif
144     {
145         action = menu->addAction( text, THEMIM, member );
146     }
147     action->setData( VLCMenuBar::ACTION_STATIC |
148                      ( bStatic ) ? VLCMenuBar::ACTION_ALWAYS_ENABLED
149                                  : VLCMenuBar::ACTION_NONE
150                    );
151     return action;
152 }
153
154 /**
155  * @brief Enable all static entries of a menu, disable the others
156  * @param menu the menu in which the entries will be disabled
157  * @param enable if false, disable all entries
158  **/
159 void VLCMenuBar::EnableStaticEntries( QMenu *menu, bool enable = true )
160 {
161     if( !menu ) return;
162
163     QList< QAction* > actions = menu->actions();
164     for( int i = 0; i < actions.count(); ++i )
165     {
166         int actionflags = actions[i]->data().toInt();
167         if ( actionflags & ACTION_MANAGED )
168             actions[i]->setEnabled(
169                 ( actionflags & ACTION_ALWAYS_ENABLED )
170                 ||
171                 enable
172             );
173     }
174 }
175
176 /**
177  * \return Number of static entries
178  **/
179 inline int DeleteNonStaticEntries( QMenu *menu )
180 {
181     if( !menu ) return VLC_EGENERIC;
182
183     int i_ret = 0;
184
185     QList< QAction* > actions = menu->actions();
186     for( int i = 0; i < actions.count(); ++i )
187     {
188         if( actions[i]->data().toInt() & VLCMenuBar::ACTION_NO_CLEANUP )
189             i_ret++;
190         else
191             delete actions[i];
192     }
193     return i_ret;
194 }
195
196 /**
197  * \return QAction associated to psz_var variable
198  **/
199 static QAction * FindActionWithVar( QMenu *menu, const char *psz_var )
200 {
201     QList< QAction* > actions = menu->actions();
202     for( int i = 0; i < actions.count(); ++i )
203     {
204         if( actions[i]->data().toString() == psz_var )
205             return actions[i];
206     }
207     return NULL;
208 }
209
210 /*****************************************************************************
211  * Definitions of variables for the dynamic menus
212  *****************************************************************************/
213 #define PUSH_OBJVAR(object,var) \
214     do { \
215         varnames.append(var); \
216         objects.append(VLC_OBJECT(object)); \
217     } while (0)
218
219 #define PUSH_VAR(var) PUSH_OBJVAR(p_object, var)
220 #define PUSH_INPUTVAR(var) PUSH_OBJVAR(p_input, var)
221 #define PUSH_PLVAR(var) PUSH_OBJVAR(pl, var)
222
223 static int InputAutoMenuBuilder( input_thread_t *p_input,
224         QVector<vlc_object_t *> &objects, QVector<const char *> &varnames )
225 {
226     PUSH_INPUTVAR( "bookmark" );
227     PUSH_INPUTVAR( "title" );
228     PUSH_INPUTVAR( "chapter" );
229     PUSH_INPUTVAR( "program" );
230
231     return VLC_SUCCESS;
232 }
233
234 static int VideoAutoMenuBuilder( playlist_t *pl, input_thread_t *p_input,
235         QVector<vlc_object_t *> &objects, QVector<const char *> &varnames )
236 {
237     vout_thread_t *p_object = p_input ? input_GetVout( p_input ) : NULL;
238
239     PUSH_INPUTVAR( "video-es" );
240     PUSH_PLVAR( "fullscreen" );
241     PUSH_PLVAR( "video-on-top" );
242     PUSH_PLVAR( "video-wallpaper" );
243     PUSH_VAR( "video-snapshot" );
244     PUSH_VAR( "zoom" );
245     PUSH_VAR( "autoscale" );
246     PUSH_VAR( "aspect-ratio" );
247     PUSH_VAR( "crop" );
248     PUSH_VAR( "deinterlace" );
249     PUSH_VAR( "deinterlace-mode" );
250     PUSH_VAR( "postprocess" );
251
252     if( p_object )
253         vlc_object_release( p_object );
254     return VLC_SUCCESS;
255 }
256
257 static int SubsAutoMenuBuilder( input_thread_t *p_input,
258         QVector<vlc_object_t *> &objects, QVector<const char *> &varnames )
259 {
260     PUSH_INPUTVAR( "spu-es" );
261
262     return VLC_SUCCESS;
263 }
264
265 static int AudioAutoMenuBuilder( input_thread_t *p_input,
266         QVector<vlc_object_t *> &objects, QVector<const char *> &varnames )
267 {
268     audio_output_t *p_object = p_input ? input_GetAout( p_input ) : NULL;
269
270     PUSH_INPUTVAR( "audio-es" );
271     PUSH_VAR( "stereo-mode" );
272     PUSH_VAR( "visual" );
273
274     if( p_object )
275         vlc_object_release( p_object );
276     return VLC_SUCCESS;
277 }
278
279 /*****************************************************************************
280  * All normal menus
281  * Simple Code
282  *****************************************************************************/
283
284 // Static menu
285 static inline void addMenuToMainbar( QMenu *func, QString title, QMenuBar *bar ) {
286     func->setTitle( title );
287     bar->addMenu( func);
288 }
289
290 // Dynamic menu
291 #define BAR_DADD( func, title, id ) { \
292     QMenu *_menu = func; _menu->setTitle( title ); bar->addMenu( _menu ); \
293     MenuFunc *f = new MenuFunc( _menu, id ); \
294     CONNECT( _menu, aboutToShow(), THEDP->menusUpdateMapper, map() ); \
295     THEDP->menusUpdateMapper->setMapping( _menu, f ); }
296
297 // Add a simple action
298 static inline void addAction( QMenu *_menu, QVariant val, QString title ) {
299     QAction *_action = new QAction( title, _menu );
300     _action->setData( val );
301     _menu->addAction( _action );
302 }
303
304 // Add an action with a submenu
305 static inline QMenu *addActionWithSubmenu( QMenu *_menu, QVariant val, QString title ) {
306     QAction *_action = new QAction( title, _menu );
307     QMenu *_submenu = new QMenu( _menu );
308     _action->setData( val );
309     _action->setMenu( _submenu );
310     _menu->addAction( _action );
311     return _submenu;
312 }
313
314 // Add an action that is a checkbox
315 static inline void addActionWithCheckbox( QMenu *_menu, QVariant val, QString title ) {
316     QAction *_action = new QAction( title, _menu );
317     _action->setData( val );
318     _action->setCheckable( true );
319     _menu->addAction( _action );
320 }
321
322 /**
323  * Main Menu Bar Creation
324  **/
325 void VLCMenuBar::createMenuBar( MainInterface *mi,
326                               intf_thread_t *p_intf )
327 {
328     /* QMainWindows->menuBar()
329        gives the QProcess::destroyed timeout issue on Cleanlooks style with
330        setDesktopAware set to false */
331     QMenuBar *bar = mi->menuBar();
332
333     addMenuToMainbar( FileMenu( p_intf, bar, mi ), qtr( "&Media" ), bar );
334
335     /* Dynamic menus, rebuilt before being showed */
336     BAR_DADD( NavigMenu( p_intf, bar ), qtr( "P&layback" ), 3 );
337     BAR_DADD( AudioMenu( p_intf, bar ), qtr( "&Audio" ), 1 );
338     BAR_DADD( VideoMenu( p_intf, bar ), qtr( "&Video" ), 2 );
339     BAR_DADD( SubtitleMenu( p_intf, bar ), qtr( "Subti&tle" ), 5 );
340
341     addMenuToMainbar( ToolsMenu( p_intf, bar ), qtr( "T&ools" ), bar );
342
343     /* View menu, a bit different */
344     BAR_DADD( ViewMenu( p_intf, NULL, mi ), qtr( "V&iew" ), 4 );
345
346     addMenuToMainbar( HelpMenu( bar ), qtr( "&Help" ), bar );
347
348 }
349
350 /**
351  * Media ( File ) Menu
352  * Opening, streaming and quit
353  **/
354 QMenu *VLCMenuBar::FileMenu( intf_thread_t *p_intf, QWidget *parent, MainInterface *mi )
355 {
356     QMenu *menu = new QMenu( parent );
357     QAction *action;
358
359     addDPStaticEntry( menu, qtr( "Open &File..." ),
360         ":/type/file-asym", SLOT( simpleOpenDialog() ), "Ctrl+O" );
361     addDPStaticEntry( menu, qtr( "&Open Multiple Files..." ),
362         ":/type/file-asym", SLOT( openFileDialog() ), "Ctrl+Shift+O" );
363     addDPStaticEntry( menu, qtr( I_OP_OPDIR ),
364         ":/type/folder-grey", SLOT( PLOpenDir() ), "Ctrl+F" );
365     addDPStaticEntry( menu, qtr( "Open &Disc..." ),
366         ":/type/disc", SLOT( openDiscDialog() ), "Ctrl+D" );
367     addDPStaticEntry( menu, qtr( "Open &Network Stream..." ),
368         ":/type/network", SLOT( openNetDialog() ), "Ctrl+N" );
369     addDPStaticEntry( menu, qtr( "Open &Capture Device..." ),
370         ":/type/capture-card", SLOT( openCaptureDialog() ), "Ctrl+C" );
371
372     addDPStaticEntry( menu, qtr( "Open &Location from clipboard" ),
373                       NULL, SLOT( openUrlDialog() ), "Ctrl+V" );
374
375     if( var_InheritBool( p_intf, "qt-recentplay" ) )
376     {
377         recentsMenu = new QMenu( qtr( "Open &Recent Media" ), menu );
378         updateRecents( p_intf );
379         menu->addMenu( recentsMenu );
380     }
381     menu->addSeparator();
382
383     addDPStaticEntry( menu, qtr( I_PL_SAVE ), "", SLOT( savePlayingToPlaylist() ),
384         "Ctrl+Y" );
385
386 #ifdef ENABLE_SOUT
387     addDPStaticEntry( menu, qtr( "Conve&rt / Save..." ), "",
388         SLOT( openAndTranscodingDialogs() ), "Ctrl+R" );
389     addDPStaticEntry( menu, qtr( "&Stream..." ),
390         ":/menu/stream", SLOT( openAndStreamingDialogs() ), "Ctrl+S" );
391     menu->addSeparator();
392 #endif
393
394     action = addMIMStaticEntry( p_intf, menu, qtr( "Quit at the end of playlist" ), "",
395                                SLOT( activatePlayQuit( bool ) ) );
396     action->setCheckable( true );
397     action->setChecked( THEMIM->getPlayExitState() );
398
399     if( mi->getSysTray() )
400     {
401         action = menu->addAction( qtr( "Close to systray"), mi,
402                                  SLOT( toggleUpdateSystrayMenu() ) );
403     }
404
405     addDPStaticEntry( menu, qtr( "&Quit" ) ,
406         ":/menu/exit", SLOT( quit() ), "Ctrl+Q" );
407     return menu;
408 }
409
410 /**
411  * Tools, like Media Information, Preferences or Messages
412  **/
413 QMenu *VLCMenuBar::ToolsMenu( intf_thread_t *p_intf, QMenu *menu )
414 {
415     addDPStaticEntry( menu, qtr( "&Effects and Filters"), ":/menu/settings",
416             SLOT( extendedDialog() ), "Ctrl+E" );
417
418     addDPStaticEntry( menu, qtr( "&Track Synchronization"), ":/menu/settings",
419             SLOT( synchroDialog() ), "" );
420
421     addDPStaticEntry( menu, qtr( I_MENU_INFO ) , ":/menu/info",
422         SLOT( mediaInfoDialog() ), "Ctrl+I" );
423     addDPStaticEntry( menu, qtr( I_MENU_CODECINFO ) ,
424         ":/menu/info", SLOT( mediaCodecDialog() ), "Ctrl+J" );
425
426 #ifdef ENABLE_VLM
427     addDPStaticEntry( menu, qtr( I_MENU_VLM ), "", SLOT( vlmDialog() ),
428         "Ctrl+Shift+W" );
429 #endif
430
431     addDPStaticEntry( menu, qtr( "Program Guide" ), "", SLOT( epgDialog() ),
432         "" );
433
434     addDPStaticEntry( menu, qtr( I_MENU_MSG ),
435         ":/menu/messages", SLOT( messagesDialog() ), "Ctrl+M" );
436
437     addDPStaticEntry( menu, qtr( "Plu&gins and extensions" ),
438         "", SLOT( pluginDialog() ) );
439     menu->addSeparator();
440
441     if( !p_intf->p_sys->b_isDialogProvider )
442         addDPStaticEntry( menu, qtr( "Customi&ze Interface..." ),
443             ":/menu/preferences", SLOT( toolbarDialog() ) );
444
445     addDPStaticEntry( menu, qtr( "&Preferences" ),
446         ":/menu/preferences", SLOT( prefsDialog() ), "Ctrl+P", QAction::PreferencesRole );
447
448     return menu;
449 }
450
451 /**
452  * View Menu
453  * Interface modification, load other interfaces, activate Extensions
454  * \param current, set to NULL for menu creation, else for menu update
455  **/
456 QMenu *VLCMenuBar::ViewMenu( intf_thread_t *p_intf, QMenu *current, MainInterface *_mi )
457 {
458     QAction *action;
459     QMenu *menu;
460
461     MainInterface *mi = _mi ? _mi : p_intf->p_sys->p_mi;
462     assert( mi );
463
464     if( !current )
465     {
466         menu = new QMenu( qtr( "&View" ), mi );
467     }
468     else
469     {
470         menu = current;
471         //menu->clear();
472         //HACK menu->clear() does not delete submenus
473         QList<QAction*> actions = menu->actions();
474         foreach( QAction *a, actions )
475         {
476             QMenu *m = a->menu();
477             if( a->parent() == menu ) delete a;
478             else menu->removeAction( a );
479             if( m && m->parent() == menu ) delete m;
480         }
481     }
482
483     menu->addAction(
484 #ifndef __APPLE__
485             QIcon( ":/menu/playlist_menu" ),
486 #endif
487             qtr( "Play&list" ), mi,
488             SLOT( togglePlaylist() ), qtr( "Ctrl+L" ) );
489
490     /* Docked Playlist */
491     action = menu->addAction( qtr( "Docked Playlist" ) );
492     action->setCheckable( true );
493     action->setChecked( mi->isPlDocked() );
494     CONNECT( action, triggered( bool ), mi, dockPlaylist( bool ) );
495
496     if( mi->getPlaylistView() )
497         menu->addMenu( StandardPLPanel::viewSelectionMenu( mi->getPlaylistView() ) );
498
499     menu->addSeparator();
500
501     /* Minimal View */
502     action = menu->addAction( qtr( "Mi&nimal Interface" ) );
503     action->setShortcut( qtr( "Ctrl+H" ) );
504     action->setCheckable( true );
505     action->setChecked( (mi->getControlsVisibilityStatus()
506                          & MainInterface::CONTROLS_HIDDEN ) );
507
508     CONNECT( action, triggered( bool ), mi, toggleMinimalView( bool ) );
509     CONNECT( mi, minimalViewToggled( bool ), action, setChecked( bool ) );
510
511     /* FullScreen View */
512     action = menu->addAction( qtr( "&Fullscreen Interface" ), mi,
513             SLOT( toggleInterfaceFullScreen() ), QString( "F11" ) );
514     action->setCheckable( true );
515     action->setChecked( mi->isInterfaceFullScreen() );
516     CONNECT( mi, fullscreenInterfaceToggled( bool ),
517              action, setChecked( bool ) );
518
519     /* Advanced Controls */
520     action = menu->addAction( qtr( "&Advanced Controls" ), mi,
521             SLOT( toggleAdvancedButtons() ) );
522     action->setCheckable( true );
523     if( mi->getControlsVisibilityStatus() & MainInterface::CONTROLS_ADVANCED )
524         action->setChecked( true );
525
526     action = menu->addAction( qtr( "Status Bar" ) );
527     action->setCheckable( true );
528     action->setChecked( mi->statusBar()->isVisible() );
529     CONNECT( action, triggered( bool ), mi, setStatusBarVisibility( bool) );
530 #if 0 /* For Visualisations. Not yet working */
531     adv = menu->addAction( qtr( "Visualizations selector" ), mi,
532                            SLOT( visual() ) );
533     adv->setCheckable( true );
534     if( visual_selector_enabled ) adv->setChecked( true );
535 #endif
536
537     menu->addSeparator();
538
539     InterfacesMenu( p_intf, menu );
540     menu->addSeparator();
541
542     /* Extensions */
543     ExtensionsMenu( p_intf, menu );
544
545     return menu;
546 }
547
548 /**
549  * Interface Sub-Menu, to list extras interface and skins
550  **/
551 QMenu *VLCMenuBar::InterfacesMenu( intf_thread_t *p_intf, QMenu *current )
552 {
553     QVector<vlc_object_t *> objects;
554     QVector<const char *> varnames;
555     varnames.append( "intf-add" );
556     objects.append( VLC_OBJECT(p_intf) );
557
558     return Populate( p_intf, current, varnames, objects );
559 }
560
561 /**
562  * Extensions menu: populate the current menu with extensions
563  **/
564 void VLCMenuBar::ExtensionsMenu( intf_thread_t *p_intf, QMenu *extMenu )
565 {
566     /* Get ExtensionsManager and load extensions if needed */
567     ExtensionsManager *extMgr = ExtensionsManager::getInstance( p_intf );
568
569     if( !var_InheritBool( p_intf, "qt-autoload-extensions")
570         && !extMgr->isLoaded() )
571     {
572         return;
573     }
574
575     if( !extMgr->isLoaded() && !extMgr->cannotLoad() )
576     {
577         extMgr->loadExtensions();
578     }
579
580     /* Let the ExtensionsManager build itself the menu */
581     extMenu->addSeparator();
582     extMgr->menu( extMenu );
583 }
584
585 static inline void VolumeEntries( intf_thread_t *p_intf, QMenu *current )
586 {
587     current->addSeparator();
588
589     QAction *action = current->addAction( qtr( "&Increase Volume" ),
590                 ActionsManager::getInstance( p_intf ), SLOT( AudioUp() ) );
591     action->setData( VLCMenuBar::ACTION_STATIC );
592     action = current->addAction( qtr( "&Decrease Volume" ),
593                 ActionsManager::getInstance( p_intf ), SLOT( AudioDown() ) );
594     action->setData( VLCMenuBar::ACTION_STATIC );
595     action = current->addAction( qtr( "&Mute" ),
596                 ActionsManager::getInstance( p_intf ), SLOT( toggleMuteAudio() ) );
597     action->setData( VLCMenuBar::ACTION_STATIC );
598 }
599
600 /**
601  * Main Audio Menu
602  **/
603 QMenu *VLCMenuBar::AudioMenu( intf_thread_t *p_intf, QMenu * current )
604 {
605     QVector<vlc_object_t *> objects;
606     QVector<const char *> varnames;
607     audio_output_t *p_aout;
608     input_thread_t *p_input;
609
610     if( current->isEmpty() )
611     {
612         addActionWithSubmenu( current, "audio-es", qtr( "Audio &Track" ) );
613         audioDeviceMenu = new QMenu( qtr( "Audio &Device" ) );
614         current->addMenu( audioDeviceMenu );
615         addActionWithSubmenu( current, "stereo-mode", qtr( "&Stereo Mode" ) );
616         current->addSeparator();
617
618         addActionWithSubmenu( current, "visual", qtr( "&Visualizations" ) );
619         VolumeEntries( p_intf, current );
620     }
621
622     p_input = THEMIM->getInput();
623     p_aout = THEMIM->getAout();
624     EnableStaticEntries( current, ( p_aout != NULL ) );
625     AudioAutoMenuBuilder( p_input, objects, varnames );
626     updateAudioDevice( p_intf, p_aout, audioDeviceMenu );
627     if( p_aout )
628     {
629         vlc_object_release( p_aout );
630     }
631
632     return Populate( p_intf, current, varnames, objects );
633 }
634
635 /* Subtitles */
636 QMenu *VLCMenuBar::SubtitleMenu( intf_thread_t *p_intf, QMenu *current, bool b_popup )
637 {
638     input_thread_t *p_input;
639     QVector<vlc_object_t *> objects;
640     QVector<const char *> varnames;
641
642     if( current->isEmpty() || b_popup )
643     {
644         addDPStaticEntry( current, qtr( "Add &Subtitle File..." ), "",
645                 SLOT( loadSubtitlesFile() ) );
646         addActionWithSubmenu( current, "spu-es", qtr( "Sub &Track" ) );
647         current->addSeparator();
648     }
649
650     p_input = THEMIM->getInput();
651     SubsAutoMenuBuilder( p_input, objects, varnames );
652
653     return Populate( p_intf, current, varnames, objects );
654 }
655
656 /**
657  * Main Video Menu
658  * Subtitles are part of Video.
659  **/
660 QMenu *VLCMenuBar::VideoMenu( intf_thread_t *p_intf, QMenu *current )
661 {
662     input_thread_t *p_input;
663     QVector<vlc_object_t *> objects;
664     QVector<const char *> varnames;
665
666     if( current->isEmpty() )
667     {
668         addActionWithSubmenu( current, "video-es", qtr( "Video &Track" ) );
669
670         current->addSeparator();
671         /* Surface modifiers */
672         addActionWithCheckbox( current, "fullscreen", qtr( "&Fullscreen" ) );
673         addActionWithCheckbox( current, "autoscale", qtr( "Always Fit &Window" ) );
674         addActionWithCheckbox( current, "video-on-top", qtr( "Always &on Top" ) );
675         addActionWithCheckbox( current, "video-wallpaper", qtr( "Set as Wall&paper" ) );
676
677         current->addSeparator();
678         /* Size modifiers */
679         addActionWithSubmenu( current, "zoom", qtr( "&Zoom" ) );
680         addActionWithSubmenu( current, "aspect-ratio", qtr( "&Aspect Ratio" ) );
681         addActionWithSubmenu( current, "crop", qtr( "&Crop" ) );
682
683         current->addSeparator();
684         /* Rendering modifiers */
685         addActionWithSubmenu( current, "deinterlace", qtr( "&Deinterlace" ) );
686         addActionWithSubmenu( current, "deinterlace-mode", qtr( "&Deinterlace mode" ) );
687         addActionWithSubmenu( current, "postprocess", qtr( "&Post processing" ) );
688
689         current->addSeparator();
690         /* Other actions */
691         addAction( current, "video-snapshot", qtr( "Take &Snapshot" ) );
692     }
693
694     p_input = THEMIM->getInput();
695
696     VideoAutoMenuBuilder( THEPL, p_input, objects, varnames );
697
698     return Populate( p_intf, current, varnames, objects );
699 }
700
701 /**
702  * Navigation Menu
703  * For DVD, MP4, MOV and other chapter based format
704  **/
705 QMenu *VLCMenuBar::NavigMenu( intf_thread_t *p_intf, QMenu *menu )
706 {
707     QAction *action;
708     QMenu *submenu;
709
710     addActionWithSubmenu( menu, "title", qtr( "T&itle" ) );
711     submenu = addActionWithSubmenu( menu, "chapter", qtr( "&Chapter" ) );
712     submenu->setTearOffEnabled( true );
713     addActionWithSubmenu( menu, "program", qtr( "&Program" ) );
714
715     submenu = new QMenu( qtr( I_MENU_BOOKMARK ), menu );
716     submenu->setTearOffEnabled( true );
717     addDPStaticEntry( submenu, qtr( "&Manage" ), "",
718                       SLOT( bookmarksDialog() ), "Ctrl+B" );
719     submenu->addSeparator();
720     action = menu->addMenu( submenu );
721     action->setData( "bookmark" );
722
723     menu->addSeparator();
724
725     PopupMenuControlEntries( menu, p_intf );
726
727     EnableStaticEntries( menu, ( THEMIM->getInput() != NULL ) );
728     return RebuildNavigMenu( p_intf, menu, true );
729 }
730
731 QMenu *VLCMenuBar::RebuildNavigMenu( intf_thread_t *p_intf, QMenu *menu, bool b_keep )
732 {
733     /* */
734     input_thread_t *p_object;
735     QVector<vlc_object_t *> objects;
736     QVector<const char *> varnames;
737
738     /* Get the input and hold it */
739     p_object = THEMIM->getInput();
740
741     InputAutoMenuBuilder( p_object, objects, varnames );
742
743     /* Title and so on */
744     PUSH_VAR( "prev-title" );
745     PUSH_VAR( "next-title" );
746     PUSH_VAR( "prev-chapter" );
747     PUSH_VAR( "next-chapter" );
748
749     /* */
750     EnableStaticEntries( menu, (p_object != NULL ) );
751     Populate( p_intf, menu, varnames, objects );
752
753     /* Remove playback actions to recreate them */
754     if( !b_keep )
755     {
756         QList< QAction* > actions = menu->actions();
757         for( int i = 0; i < actions.count(); i++ )
758             if( actions[i]->data().toInt() & ACTION_DELETE_ON_REBUILD )
759                 delete actions[i];
760     }
761
762     PopupMenuPlaylistEntries( menu, p_intf, p_object );
763
764     return menu;
765 }
766
767 /**
768  * Help/About Menu
769 **/
770 QMenu *VLCMenuBar::HelpMenu( QWidget *parent )
771 {
772     QMenu *menu = new QMenu( parent );
773     addDPStaticEntry( menu, qtr( "&Help" ) ,
774         ":/menu/help", SLOT( helpDialog() ), "F1" );
775 #ifdef UPDATE_CHECK
776     addDPStaticEntry( menu, qtr( "Check for &Updates..." ) , "",
777                       SLOT( updateDialog() ) );
778 #endif
779     menu->addSeparator();
780     addDPStaticEntry( menu, qtr( I_MENU_ABOUT ), ":/menu/info",
781             SLOT( aboutDialog() ), "Shift+F1", QAction::AboutRole );
782     return menu;
783 }
784
785 /*****************************************************************************
786  * Popup menus - Right Click menus                                           *
787  *****************************************************************************/
788 #define POPUP_BOILERPLATE \
789     static QMenu* menu = NULL;  \
790     delete menu; menu = NULL; \
791     if( !show ) \
792         return; \
793     QVector<vlc_object_t *> objects; \
794     QVector<const char *> varnames; \
795     input_thread_t *p_input = THEMIM->getInput();
796
797 #define CREATE_POPUP \
798     menu = new QMenu(); \
799     Populate( p_intf, menu, varnames, objects ); \
800     menu->popup( QCursor::pos() ); \
801
802 void VLCMenuBar::PopupMenuPlaylistEntries( QMenu *menu,
803                                         intf_thread_t *p_intf,
804                                         input_thread_t *p_input )
805 {
806     QAction *action;
807
808     /* Play or Pause action and icon */
809     if( !p_input || var_GetInteger( p_input, "state" ) != PLAYING_S )
810     {
811         action = menu->addAction( qtr( "&Play" ),
812                 ActionsManager::getInstance( p_intf ), SLOT( play() ) );
813 #ifndef __APPLE__ /* No icons in menus in Mac */
814         action->setIcon( QIcon( ":/menu/play" ) );
815 #endif
816     }
817     else
818     {
819         action = addMIMStaticEntry( p_intf, menu, qtr( "Pause" ),
820                 ":/menu/pause", SLOT( togglePlayPause() ) );
821     }
822     action->setData( ACTION_DELETE_ON_REBUILD );
823
824     /* Stop */
825     action = addMIMStaticEntry( p_intf, menu, qtr( "&Stop" ),
826             ":/menu/stop", SLOT( stop() ), true );
827     if( !p_input )
828         action->setEnabled( false );
829     action->setData( ACTION_DELETE_ON_REBUILD );
830
831     /* Next / Previous */
832     bool bPlaylistEmpty = THEMIM->hasEmptyPlaylist();
833     action = addMIMStaticEntry( p_intf, menu, qtr( "Pre&vious" ),
834             ":/menu/previous", SLOT( prev() ), true );
835     action->setEnabled( !bPlaylistEmpty );
836     action->setData( ACTION_NO_CLEANUP + ACTION_DELETE_ON_REBUILD );
837     CONNECT( THEMIM, playlistNotEmpty(bool), action, setEnabled(bool) );
838
839     action = addMIMStaticEntry( p_intf, menu, qtr( "Ne&xt" ),
840             ":/menu/next", SLOT( next() ), true );
841     action->setEnabled( !bPlaylistEmpty );
842     action->setData( ACTION_NO_CLEANUP + ACTION_DELETE_ON_REBUILD );
843     CONNECT( THEMIM, playlistNotEmpty(bool), action, setEnabled(bool) );
844
845     action = menu->addAction( qtr( "Record" ), THEAM, SLOT( record() ) );
846     action->setIcon( QIcon( ":/toolbar/record" ) );
847     if( !p_input )
848         action->setEnabled( false );
849     action->setData( ACTION_NO_CLEANUP + ACTION_DELETE_ON_REBUILD );
850     menu->addSeparator();
851 }
852
853 void VLCMenuBar::PopupMenuControlEntries( QMenu *menu, intf_thread_t *p_intf,
854                                         bool b_normal )
855 {
856     QAction *action;
857     QMenu *rateMenu = new QMenu( qtr( "Sp&eed" ), menu );
858     rateMenu->setTearOffEnabled( true );
859
860     if( b_normal )
861     {
862         /* Faster/Slower */
863         action = rateMenu->addAction( qtr( "&Faster" ), THEMIM->getIM(),
864                                   SLOT( faster() ) );
865 #ifndef __APPLE__ /* No icons in menus in Mac */
866         action->setIcon( QIcon( ":/toolbar/faster2") );
867 #endif
868         action->setData( ACTION_STATIC );
869     }
870
871     action = rateMenu->addAction( qtr( "Faster (fine)" ), THEMIM->getIM(),
872                               SLOT( littlefaster() ) );
873     action->setData( ACTION_STATIC );
874
875     action = rateMenu->addAction( qtr( "N&ormal Speed" ), THEMIM->getIM(),
876                               SLOT( normalRate() ) );
877     action->setData( ACTION_STATIC );
878
879     action = rateMenu->addAction( qtr( "Slower (fine)" ), THEMIM->getIM(),
880                               SLOT( littleslower() ) );
881     action->setData( ACTION_STATIC );
882
883     if( b_normal )
884     {
885         action = rateMenu->addAction( qtr( "Slo&wer" ), THEMIM->getIM(),
886                                   SLOT( slower() ) );
887 #ifndef __APPLE__ /* No icons in menus in Mac */
888         action->setIcon( QIcon( ":/toolbar/slower2") );
889 #endif
890         action->setData( ACTION_STATIC );
891     }
892
893     action = menu->addMenu( rateMenu );
894     action->setData( ACTION_STATIC );
895
896     menu->addSeparator();
897
898     if( !b_normal ) return;
899
900     action = menu->addAction( qtr( "&Jump Forward" ), THEMIM->getIM(),
901              SLOT( jumpFwd() ) );
902 #ifndef __APPLE__ /* No icons in menus in Mac */
903     action->setIcon( QIcon( ":/toolbar/skip_fw") );
904 #endif
905     action->setData( ACTION_STATIC );
906
907     action = menu->addAction( qtr( "Jump Bac&kward" ), THEMIM->getIM(),
908              SLOT( jumpBwd() ) );
909 #ifndef __APPLE__ /* No icons in menus in Mac */
910     action->setIcon( QIcon( ":/toolbar/skip_back") );
911 #endif
912     action->setData( ACTION_STATIC );
913
914     action = menu->addAction( qtr( I_MENU_GOTOTIME ), THEDP, SLOT( gotoTimeDialog() ), qtr( "Ctrl+T" ) );
915     action->setData( ACTION_ALWAYS_ENABLED );
916
917     menu->addSeparator();
918 }
919
920 void VLCMenuBar::PopupMenuStaticEntries( QMenu *menu )
921 {
922     QMenu *openmenu = new QMenu( qtr( "Open Media" ), menu );
923     addDPStaticEntry( openmenu, qtr( I_OP_OPF ),
924         ":/type/file-asym", SLOT( openFileDialog() ) );
925     addDPStaticEntry( openmenu, qtr( I_OP_OPDIR ),
926         ":/type/folder-grey", SLOT( PLOpenDir() ) );
927     addDPStaticEntry( openmenu, qtr( "Open &Disc..." ),
928         ":/type/disc", SLOT( openDiscDialog() ) );
929     addDPStaticEntry( openmenu, qtr( "Open &Network..." ),
930         ":/type/network", SLOT( openNetDialog() ) );
931     addDPStaticEntry( openmenu, qtr( "Open &Capture Device..." ),
932         ":/type/capture-card", SLOT( openCaptureDialog() ) );
933     menu->addMenu( openmenu );
934
935     menu->addSeparator();
936 #if 0
937     QMenu *helpmenu = HelpMenu( menu );
938     helpmenu->setTitle( qtr( "Help" ) );
939     menu->addMenu( helpmenu );
940 #endif
941
942     addDPStaticEntry( menu, qtr( "Quit" ), ":/menu/exit",
943                       SLOT( quit() ), "Ctrl+Q", QAction::QuitRole );
944 }
945
946 /* Video Tracks and Subtitles tracks */
947 void VLCMenuBar::VideoPopupMenu( intf_thread_t *p_intf, bool show )
948 {
949     POPUP_BOILERPLATE
950     if( p_input )
951         VideoAutoMenuBuilder( THEPL, p_input, objects, varnames );
952     CREATE_POPUP
953 }
954
955 /* Audio Tracks */
956 void VLCMenuBar::AudioPopupMenu( intf_thread_t *p_intf, bool show )
957 {
958     POPUP_BOILERPLATE
959     if( p_input )
960         AudioAutoMenuBuilder( p_input, objects, varnames );
961     CREATE_POPUP
962 }
963
964 /* Navigation stuff, and general menus ( open ), used only for skins */
965 void VLCMenuBar::MiscPopupMenu( intf_thread_t *p_intf, bool show )
966 {
967     POPUP_BOILERPLATE
968
969     menu = new QMenu();
970     if( p_input )
971     {
972         InputAutoMenuBuilder( p_input, objects, varnames );
973         menu->addSeparator();
974     }
975
976     Populate( p_intf, menu, varnames, objects );
977
978     menu->addSeparator();
979     PopupMenuPlaylistEntries( menu, p_intf, p_input );
980
981     menu->addSeparator();
982     PopupMenuControlEntries( menu, p_intf );
983
984     menu->addSeparator();
985     PopupMenuStaticEntries( menu );
986
987     menu->popup( QCursor::pos() );
988 }
989
990 /* Main Menu that sticks everything together  */
991 void VLCMenuBar::PopupMenu( intf_thread_t *p_intf, bool show )
992 {
993     POPUP_BOILERPLATE
994
995     /* */
996     menu = new QMenu();
997     QAction *action;
998     bool b_isFullscreen = false;
999     MainInterface *mi = p_intf->p_sys->p_mi;
1000
1001     PopupMenuPlaylistEntries( menu, p_intf, p_input );
1002     menu->addSeparator();
1003
1004     if( p_input )
1005     {
1006         QMenu *submenu;
1007         vout_thread_t *p_vout = THEMIM->getVout();
1008
1009         /* Add a fullscreen switch button, since it is the most used function */
1010         if( p_vout )
1011         {
1012             vlc_value_t val; var_Get( p_vout, "fullscreen", &val );
1013
1014             b_isFullscreen = !( !val.b_bool );
1015             if( b_isFullscreen )
1016             {
1017                 val.b_bool = false;
1018                 CreateAndConnect( menu, "fullscreen",
1019                         qtr( "Leave Fullscreen" ),"" , ITEM_NORMAL,
1020                         VLC_OBJECT(THEPL), val, VLC_VAR_BOOL, b_isFullscreen );
1021             }
1022             vlc_object_release( p_vout );
1023
1024             menu->addSeparator();
1025         }
1026
1027         /* Input menu */
1028         InputAutoMenuBuilder( p_input, objects, varnames );
1029
1030         /* Audio menu */
1031         submenu = new QMenu( menu );
1032         action = menu->addMenu( AudioMenu( p_intf, submenu ) );
1033         action->setText( qtr( "&Audio" ) );
1034         if( action->menu()->isEmpty() )
1035             action->setEnabled( false );
1036
1037         /* Video menu */
1038         submenu = new QMenu( menu );
1039         action = menu->addMenu( VideoMenu( p_intf, submenu ) );
1040         action->setText( qtr( "&Video" ) );
1041         if( action->menu()->isEmpty() )
1042             action->setEnabled( false );
1043
1044         /* Subtitles menu */
1045         submenu = new QMenu( menu );
1046         action = menu->addMenu( SubtitleMenu( p_intf, submenu, true ) );
1047         action->setText( qtr( "Subti&tle") );
1048         UpdateItem( p_intf, submenu, "spu-es", VLC_OBJECT(p_input), true );
1049
1050         /* Playback menu for chapters */
1051         submenu = new QMenu( menu );
1052         action = menu->addMenu( NavigMenu( p_intf, submenu ) );
1053         action->setText( qtr( "&Playback" ) );
1054         if( action->menu()->isEmpty() )
1055             action->setEnabled( false );
1056     }
1057
1058     menu->addSeparator();
1059
1060     /* Add some special entries for windowed mode: Interface Menu */
1061     if( !b_isFullscreen )
1062     {
1063         QMenu *submenu = new QMenu( qtr( "T&ools" ), menu );
1064         /*QMenu *tools =*/ ToolsMenu( p_intf, submenu );
1065         submenu->addSeparator();
1066
1067         /* In skins interface, append some items */
1068         if( !mi )
1069         {
1070             submenu->setTitle( qtr( "Interface" ) );
1071             if( p_intf->p_sys->b_isDialogProvider )
1072             {
1073                 /* list of skins available */
1074                 vlc_object_t* p_object = p_intf->p_parent;
1075
1076                 objects.clear(); varnames.clear();
1077                 objects.append( p_object );
1078                 varnames.append( "intf-skins" );
1079                 Populate( p_intf, submenu, varnames, objects );
1080
1081                 objects.clear(); varnames.clear();
1082                 objects.append( p_object );
1083                 varnames.append( "intf-skins-interactive" );
1084                 Populate( p_intf, submenu, varnames, objects );
1085
1086                 submenu->addSeparator();
1087
1088                 /* Extensions */
1089                 ExtensionsMenu( p_intf, submenu );
1090
1091             }
1092             else
1093                 msg_Warn( p_intf, "could not find parent interface" );
1094         }
1095         else
1096         {
1097             QMenu *bar = menu; // Needed for next macro
1098             BAR_DADD( ViewMenu( p_intf, NULL, mi ), qtr( "V&iew" ), 4 );
1099         }
1100
1101         menu->addMenu( submenu );
1102     }
1103
1104     /* */
1105     QMenuView *plMenu = new QMenuView( menu, 25 );
1106     plMenu->setTitle( qtr("Playlist") );
1107     PLModel *model = PLModel::getPLModel( p_intf );
1108     plMenu->setModel( model );
1109     CONNECT( plMenu, activated(const QModelIndex&),
1110              model->sigs, activateItemSlot(const QModelIndex&));
1111     menu->addMenu( plMenu );
1112
1113     /* Static entries for ending, like open */
1114     PopupMenuStaticEntries( menu );
1115
1116     menu->popup( QCursor::pos() );
1117 }
1118
1119 #undef CREATE_POPUP
1120 #undef POPUP_BOILERPLATE
1121 #undef BAR_DADD
1122
1123 /************************************************************************
1124  * Systray Menu                                                         *
1125  ************************************************************************/
1126
1127 void VLCMenuBar::updateSystrayMenu( MainInterface *mi,
1128                                   intf_thread_t *p_intf,
1129                                   bool b_force_visible )
1130 {
1131     input_thread_t *p_input = THEMIM->getInput();
1132
1133     /* Get the systray menu and clean it */
1134     QMenu *sysMenu = mi->getSysTrayMenu();
1135     sysMenu->clear();
1136
1137 #ifndef Q_OS_MAC
1138     /* Hide / Show VLC and cone */
1139     if( mi->isVisible() || b_force_visible )
1140     {
1141         sysMenu->addAction( QIcon( ":/logo/vlc16.png" ),
1142                             qtr( "&Hide VLC media player in taskbar" ), mi,
1143                             SLOT( hideUpdateSystrayMenu() ) );
1144     }
1145     else
1146     {
1147         sysMenu->addAction( QIcon( ":/logo/vlc16.png" ),
1148                             qtr( "Sho&w VLC media player" ), mi,
1149                             SLOT( showUpdateSystrayMenu() ) );
1150     }
1151     sysMenu->addSeparator();
1152 #endif
1153
1154     PopupMenuPlaylistEntries( sysMenu, p_intf, p_input );
1155     PopupMenuControlEntries( sysMenu, p_intf, false );
1156
1157     VolumeEntries( p_intf, sysMenu );
1158     sysMenu->addSeparator();
1159     addDPStaticEntry( sysMenu, qtr( "&Open Media" ),
1160             ":/type/file-wide", SLOT( openFileDialog() ) );
1161     addDPStaticEntry( sysMenu, qtr( "&Quit" ) ,
1162             ":/menu/exit", SLOT( quit() ) );
1163
1164     /* Set the menu */
1165     mi->getSysTray()->setContextMenu( sysMenu );
1166 }
1167
1168
1169 #undef PUSH_VAR
1170
1171 /*************************************************************************
1172  * Builders for automenus
1173  *************************************************************************/
1174 QMenu * VLCMenuBar::Populate( intf_thread_t *p_intf,
1175                             QMenu *current,
1176                             QVector< const char *> & varnames,
1177                             QVector<vlc_object_t *> & objects )
1178 {
1179     QMenu *menu = current;
1180     assert( menu );
1181
1182     currentGroup = NULL;
1183
1184     for( int i = 0; i < (int)objects.count() ; i++ )
1185     {
1186         if( !varnames[i] || !*varnames[i] )
1187         {
1188             menu->addSeparator();
1189             continue;
1190         }
1191
1192         UpdateItem( p_intf, menu, varnames[i], objects[i], true );
1193     }
1194     return menu;
1195 }
1196
1197 /*****************************************************************************
1198  * Private methods.
1199  *****************************************************************************/
1200
1201 static bool IsMenuEmpty( const char *psz_var,
1202                          vlc_object_t *p_object,
1203                          bool b_root = true )
1204 {
1205     vlc_value_t val, val_list;
1206     int i_type, i_result, i;
1207
1208     /* Check the type of the object variable */
1209     i_type = var_Type( p_object, psz_var );
1210
1211     /* Check if we want to display the variable */
1212     if( !( i_type & VLC_VAR_HASCHOICE ) ) return false;
1213
1214     var_Change( p_object, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
1215     if( val.i_int == 0 ) return true;
1216
1217     if( ( i_type & VLC_VAR_TYPE ) != VLC_VAR_VARIABLE )
1218     {
1219         if( val.i_int == 1 && b_root ) return true;
1220         else return false;
1221     }
1222
1223     /* Check children variables in case of VLC_VAR_VARIABLE */
1224     if( var_Change( p_object, psz_var, VLC_VAR_GETLIST, &val_list, NULL ) < 0 )
1225     {
1226         return true;
1227     }
1228
1229     for( i = 0, i_result = true; i < val_list.p_list->i_count; i++ )
1230     {
1231         if( !IsMenuEmpty( val_list.p_list->p_values[i].psz_string,
1232                     p_object, false ) )
1233         {
1234             i_result = false;
1235             break;
1236         }
1237     }
1238
1239     /* clean up everything */
1240     var_FreeList( &val_list, NULL );
1241
1242     return i_result;
1243 }
1244
1245 #define TEXT_OR_VAR qfue ( text.psz_string ? text.psz_string : psz_var )
1246
1247 void VLCMenuBar::UpdateItem( intf_thread_t *p_intf, QMenu *menu,
1248         const char *psz_var, vlc_object_t *p_object, bool b_submenu )
1249 {
1250     vlc_value_t val, text;
1251     int i_type;
1252
1253     QAction *action = FindActionWithVar( menu, psz_var );
1254     if( action )
1255         DeleteNonStaticEntries( action->menu() );
1256
1257     if( !p_object )
1258     {
1259         if( action )
1260             action->setEnabled( false );
1261         return;
1262     }
1263
1264     /* Check the type of the object variable */
1265     /* This HACK is needed so we have a radio button for audio and video tracks
1266        instread of a checkbox */
1267     if( !strcmp( psz_var, "audio-es" )
1268      || !strcmp( psz_var, "video-es" ) )
1269         i_type = VLC_VAR_INTEGER | VLC_VAR_HASCHOICE;
1270     else
1271         i_type = var_Type( p_object, psz_var );
1272
1273     switch( i_type & VLC_VAR_TYPE )
1274     {
1275         case VLC_VAR_VOID:
1276         case VLC_VAR_BOOL:
1277         case VLC_VAR_VARIABLE:
1278         case VLC_VAR_STRING:
1279         case VLC_VAR_INTEGER:
1280         case VLC_VAR_FLOAT:
1281             break;
1282         default:
1283             /* Variable doesn't exist or isn't handled */
1284             if( action )
1285                 action->setEnabled( false );
1286             return;
1287     }
1288
1289     /* Make sure we want to display the variable */
1290     if( menu->isEmpty() && IsMenuEmpty( psz_var, p_object ) )
1291     {
1292         if( action )
1293             action->setEnabled( false );
1294         return;
1295     }
1296
1297     /* Get the descriptive name of the variable */
1298     int i_ret = var_Change( p_object, psz_var, VLC_VAR_GETTEXT, &text, NULL );
1299     if( i_ret != VLC_SUCCESS )
1300     {
1301         text.psz_string = NULL;
1302     }
1303
1304     if( !action )
1305     {
1306         action = new QAction( TEXT_OR_VAR, menu );
1307         menu->addAction( action );
1308         action->setData( psz_var );
1309     }
1310
1311     /* Some specific stuff */
1312     bool forceDisabled = false;
1313     if( !strcmp( psz_var, "spu-es" ) )
1314     {
1315         vout_thread_t *p_vout = THEMIM->getVout();
1316         forceDisabled = ( p_vout == NULL );
1317         if( p_vout )
1318             vlc_object_release( p_vout );
1319     }
1320
1321     if( i_type & VLC_VAR_HASCHOICE )
1322     {
1323         /* Append choices menu */
1324         if( b_submenu )
1325         {
1326             QMenu *submenu;
1327             submenu = action->menu();
1328             if( !submenu )
1329             {
1330                 submenu = new QMenu( menu );
1331                 action->setMenu( submenu );
1332             }
1333
1334             action->setEnabled(
1335                CreateChoicesMenu( submenu, psz_var, p_object, true ) == 0 );
1336             if( forceDisabled )
1337                 action->setEnabled( false );
1338         }
1339         else
1340         {
1341             action->setEnabled(
1342                 CreateChoicesMenu( menu, psz_var, p_object, true ) == 0 );
1343         }
1344         FREENULL( text.psz_string );
1345         return;
1346     }
1347
1348     switch( i_type & VLC_VAR_TYPE )
1349     {
1350         case VLC_VAR_VOID:
1351             val.i_int = 0;  // Prevent the copy of an uninitialized value
1352             CreateAndConnect( menu, psz_var, TEXT_OR_VAR, "", ITEM_NORMAL,
1353                     p_object, val, i_type );
1354             break;
1355
1356         case VLC_VAR_BOOL:
1357             var_Get( p_object, psz_var, &val );
1358             val.b_bool = !val.b_bool;
1359             CreateAndConnect( menu, psz_var, TEXT_OR_VAR, "", ITEM_CHECK,
1360                     p_object, val, i_type, !val.b_bool );
1361             break;
1362     }
1363     FREENULL( text.psz_string );
1364 }
1365
1366 #undef TEXT_OR_VAR
1367
1368 /** HACK for the navigation submenu:
1369  * "title %2i" variables take the value 0 if not set
1370  */
1371 static bool CheckTitle( vlc_object_t *p_object, const char *psz_var )
1372 {
1373     int i_title = 0;
1374     if( sscanf( psz_var, "title %2i", &i_title ) <= 0 )
1375         return true;
1376
1377     int i_current_title = var_GetInteger( p_object, "title" );
1378     return ( i_title == i_current_title );
1379 }
1380
1381
1382 int VLCMenuBar::CreateChoicesMenu( QMenu *submenu, const char *psz_var,
1383         vlc_object_t *p_object, bool b_root )
1384 {
1385     vlc_value_t val, val_list, text_list;
1386     int i_type, i;
1387
1388     /* Check the type of the object variable */
1389     i_type = var_Type( p_object, psz_var );
1390
1391     /* Make sure we want to display the variable */
1392     if( submenu->isEmpty() && IsMenuEmpty( psz_var, p_object, b_root ) )
1393         return VLC_EGENERIC;
1394
1395     switch( i_type & VLC_VAR_TYPE )
1396     {
1397         case VLC_VAR_VOID:
1398         case VLC_VAR_BOOL:
1399         case VLC_VAR_VARIABLE:
1400         case VLC_VAR_STRING:
1401         case VLC_VAR_INTEGER:
1402         case VLC_VAR_FLOAT:
1403             break;
1404         default:
1405             /* Variable doesn't exist or isn't handled */
1406             return VLC_EGENERIC;
1407     }
1408
1409     if( var_Change( p_object, psz_var, VLC_VAR_GETLIST,
1410                     &val_list, &text_list ) < 0 )
1411     {
1412         return VLC_EGENERIC;
1413     }
1414
1415 #define CURVAL val_list.p_list->p_values[i]
1416 #define CURTEXT text_list.p_list->p_values[i].psz_string
1417 #define RADIO_OR_COMMAND  ( i_type & ( VLC_VAR_ISCOMMAND | VLC_VAR_HASCHOICE ) ) ? ITEM_RADIO : ITEM_NORMAL
1418
1419     for( i = 0; i < val_list.p_list->i_count; i++ )
1420     {
1421         vlc_value_t another_val;
1422         QString menutext;
1423         QMenu *subsubmenu = new QMenu( submenu );
1424
1425         switch( i_type & VLC_VAR_TYPE )
1426         {
1427             case VLC_VAR_VARIABLE:
1428                 CreateChoicesMenu( subsubmenu, CURVAL.psz_string, p_object, false );
1429                 subsubmenu->setTitle( qfue( CURTEXT ? CURTEXT :CURVAL.psz_string ) );
1430                 submenu->addMenu( subsubmenu );
1431                 break;
1432
1433             case VLC_VAR_STRING:
1434                 var_Get( p_object, psz_var, &val );
1435                 another_val.psz_string = strdup( CURVAL.psz_string );
1436                 menutext = qfue( CURTEXT ? CURTEXT : another_val.psz_string );
1437                 CreateAndConnect( submenu, psz_var, menutext, "", RADIO_OR_COMMAND,
1438                         p_object, another_val, i_type,
1439                         val.psz_string && !strcmp( val.psz_string, CURVAL.psz_string ) );
1440
1441                 free( val.psz_string );
1442                 break;
1443
1444             case VLC_VAR_INTEGER:
1445                 var_Get( p_object, psz_var, &val );
1446                 if( CURTEXT ) menutext = qfue( CURTEXT );
1447                 else menutext = QString::number( CURVAL.i_int );
1448                 CreateAndConnect( submenu, psz_var, menutext, "", RADIO_OR_COMMAND,
1449                         p_object, CURVAL, i_type,
1450                         ( CURVAL.i_int == val.i_int )
1451                         && CheckTitle( p_object, psz_var ) );
1452                 break;
1453
1454             case VLC_VAR_FLOAT:
1455                 var_Get( p_object, psz_var, &val );
1456                 if( CURTEXT ) menutext = qfue( CURTEXT );
1457                 else menutext.sprintf( "%.2f", CURVAL.f_float );
1458                 CreateAndConnect( submenu, psz_var, menutext, "", RADIO_OR_COMMAND,
1459                         p_object, CURVAL, i_type,
1460                         CURVAL.f_float == val.f_float );
1461                 break;
1462
1463             default:
1464                 break;
1465         }
1466     }
1467     currentGroup = NULL;
1468
1469     /* clean up everything */
1470     var_FreeList( &val_list, &text_list );
1471
1472 #undef RADIO_OR_COMMAND
1473 #undef CURVAL
1474 #undef CURTEXT
1475
1476     return submenu->isEmpty() ? VLC_EGENERIC : VLC_SUCCESS;
1477 }
1478
1479 void VLCMenuBar::CreateAndConnect( QMenu *menu, const char *psz_var,
1480         const QString& text, const QString& help,
1481         int i_item_type, vlc_object_t *p_obj,
1482         vlc_value_t val, int i_val_type,
1483         bool checked )
1484 {
1485     QAction *action = FindActionWithVar( menu, psz_var );
1486
1487     bool b_new = false;
1488     if( !action )
1489     {
1490         action = new QAction( text, menu );
1491         menu->addAction( action );
1492         b_new = true;
1493     }
1494
1495     action->setToolTip( help );
1496     action->setEnabled( p_obj != NULL );
1497
1498     if( i_item_type == ITEM_CHECK )
1499     {
1500         action->setCheckable( true );
1501     }
1502     else if( i_item_type == ITEM_RADIO )
1503     {
1504         action->setCheckable( true );
1505         if( !currentGroup )
1506             currentGroup = new QActionGroup( menu );
1507         currentGroup->addAction( action );
1508     }
1509
1510     action->setChecked( checked );
1511
1512     MenuItemData *itemData = action->findChild<MenuItemData*>( QString() );
1513     delete itemData;
1514     itemData = new MenuItemData( action, p_obj, i_val_type, val, psz_var );
1515
1516     /* remove previous signal-slot connection(s) if any */
1517     action->disconnect( );
1518
1519     CONNECT( action, triggered(), THEDP->menusMapper, map() );
1520     THEDP->menusMapper->setMapping( action, itemData );
1521
1522     if( b_new )
1523         menu->addAction( action );
1524 }
1525
1526 void VLCMenuBar::DoAction( QObject *data )
1527 {
1528     MenuItemData *itemData = qobject_cast<MenuItemData *>( data );
1529     vlc_object_t *p_object = itemData->p_obj;
1530     if( p_object == NULL ) return;
1531     const char *var = itemData->psz_var;
1532     vlc_value_t val = itemData->val;
1533
1534     if ((var_Type( p_object, var) & VLC_VAR_CLASS) == VLC_VAR_VOID)
1535         var_TriggerCallback( p_object, var );
1536     else
1537         var_Set( p_object, var, val );
1538
1539     if( !strcmp( var, "fullscreen" )
1540      || !strcmp( var, "video-on-top" )
1541      || !strcmp( var, "video-wallpaper" ) ) /* FIXME: reverse abstraction */
1542     {   /* Apply playlist variables to current existing vout too */
1543         input_thread_t *input = playlist_CurrentInput((playlist_t *)p_object);
1544         if( input != NULL )
1545         {
1546             vout_thread_t *vout = input_GetVout( input );
1547             vlc_object_release( input );
1548             if( vout != NULL )
1549             {
1550                 var_Set( vout, var, val ); /* never void class */
1551                 vlc_object_release( vout );
1552             }
1553         }
1554     }
1555 }
1556
1557 void VLCMenuBar::updateAudioDevice( intf_thread_t * p_intf, audio_output_t *p_aout, QMenu *current )
1558 {
1559     char **ids, **names;
1560     char *selected;
1561
1562     if( !p_aout || !current )
1563         return;
1564
1565     current->clear();
1566     int i_result = aout_DevicesList( p_aout, &ids, &names);
1567     selected = aout_DeviceGet( p_aout );
1568
1569     QActionGroup *actionGroup = new QActionGroup(current);
1570     QAction *action;
1571
1572     for( int i = 0; i < i_result; i++ )
1573     {
1574         action = new QAction( qfue( names[i] ), NULL );
1575         action->setData( ids[i] );
1576         action->setCheckable( true );
1577         if( (selected && !strcmp( ids[i], selected ) ) ||
1578             (selected == NULL && ids[i] && ids[i][0] == '\0' ) )
1579             action->setChecked( true );
1580         actionGroup->addAction( action );
1581         current->addAction( action );
1582         CONNECT(action, changed(), THEMIM->menusAudioMapper, map());
1583         THEMIM->menusAudioMapper->setMapping(action, ids[i]);
1584         free( ids[i] );
1585         free( names[i] );
1586     }
1587     free( ids );
1588     free( names );
1589     free( selected );
1590 }
1591
1592 void VLCMenuBar::updateRecents( intf_thread_t *p_intf )
1593 {
1594     if( recentsMenu )
1595     {
1596         QAction* action;
1597         RecentsMRL* rmrl = RecentsMRL::getInstance( p_intf );
1598         QStringList l = rmrl->recents();
1599
1600         recentsMenu->clear();
1601
1602         if( !l.count() )
1603         {
1604             recentsMenu->setEnabled( false );
1605         }
1606         else
1607         {
1608             for( int i = 0; i < l.count(); ++i )
1609             {
1610                 QString mrl = l.at( i );
1611                 char *psz = decode_URI_duplicate( qtu( mrl ) );
1612                 QString text = qfu( psz );
1613
1614                 text.replace("&", "&&");
1615 #ifdef _WIN32
1616 # define FILE_SCHEME "file:///"
1617 #else
1618 # define FILE_SCHEME "file://"
1619 #endif
1620                 if ( text.startsWith( FILE_SCHEME ) )
1621                     text.remove( 0, strlen( FILE_SCHEME ) );
1622 #undef FILE_SCHEME
1623
1624                 free( psz );
1625                 action = recentsMenu->addAction(
1626                         QString( i < 9 ? "&%1: ": "%1: " ).arg( i + 1 ) +
1627                             QApplication::fontMetrics().elidedText( text,
1628                                                           Qt::ElideLeft, 400 ),
1629                         rmrl->signalMapper, SLOT( map() ),
1630                         i < 9 ? QString( "Ctrl+%1" ).arg( i + 1 ) : "" );
1631                 rmrl->signalMapper->setMapping( action, l.at( i ) );
1632             }
1633
1634             recentsMenu->addSeparator();
1635             recentsMenu->addAction( qtr("&Clear"), rmrl, SLOT( clear() ) );
1636             addDPStaticEntry( recentsMenu, qtr("&Save To Playlist"), "", SLOT( saveRecentsToPlaylist() ), "" );
1637             recentsMenu->setEnabled( true );
1638         }
1639     }
1640 }