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