menus.cpp 32.6 KB
Newer Older
zorglub's avatar
zorglub committed
1 2 3
/*****************************************************************************
 * menus.cpp : Qt menus
 *****************************************************************************
4
 * Copyright ( C ) 2006-2007 the VideoLAN team
5
 * $Id$
zorglub's avatar
zorglub committed
6
 *
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
7
 * Authors: Clément Stenac <zorglub@videolan.org>
8
 *          Jean-Baptiste Kempf <jb@videolan.org>
zorglub's avatar
zorglub committed
9 10 11 12
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
13
 * ( at your option ) any later version.
zorglub's avatar
zorglub committed
14 15 16 17 18 19 20 21 22 23 24
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

zorglub's avatar
zorglub committed
25
#include <vlc_intf_strings.h>
zorglub's avatar
zorglub committed
26

zorglub's avatar
zorglub committed
27
#include "main_interface.hpp"
zorglub's avatar
zorglub committed
28 29 30 31
#include "menus.hpp"
#include "dialogs_provider.hpp"
#include "input_manager.hpp"

32 33 34 35 36 37 38
#include <QMenu>
#include <QMenuBar>
#include <QAction>
#include <QActionGroup>
#include <QSignalMapper>
#include <QSystemTrayIcon>

zorglub's avatar
zorglub committed
39 40 41 42 43 44 45 46 47
enum
{
    ITEM_NORMAL,
    ITEM_CHECK,
    ITEM_RADIO
};

static QActionGroup *currentGroup;

48
// Add static entries to menus
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
void addDPStaticEntry( QMenu *menu,
                       const QString text,
                       char *help,
                       char *icon,
                       const char *member,
                       char *shortcut )
{
    if( !EMPTY_STR( icon ) > 0 )
    {
        if( !EMPTY_STR( shortcut ) > 0 )
            menu->addAction( QIcon( icon ), text, THEDP, member, qtr( shortcut ) );
        else
            menu->addAction( QIcon( icon ), text, THEDP, member );
    }
    else
    {
        if( !EMPTY_STR( shortcut ) > 0 )
            menu->addAction( text, THEDP, member, qtr( shortcut ) );
        else
            menu->addAction( text, THEDP, member );
    }
70
}
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87

void addMIMStaticEntry( intf_thread_t *p_intf,
               QMenu *menu,
               const QString text,
               char *help,
               char *icon,
               const char *member )
{
    if( strlen( icon ) > 0 )
    {
        QAction *action = menu->addAction( text, THEMIM, SLOT( slot ) );
        action->setIcon( QIcon( icon ) );
    }
    else
    {
        menu->addAction( text, THEMIM, SLOT( slot ) );
    }
88
}
zorglub's avatar
zorglub committed
89 90

/*****************************************************************************
91
 * Definitions of variables for the dynamic menus
zorglub's avatar
zorglub committed
92
 *****************************************************************************/
93
#define PUSH_VAR( var ) varnames.push_back( var ); \
94
    objects.push_back( p_object->i_object_id )
95 96

#define PUSH_SEPARATOR if( objects.size() != i_last_separator ) { \
97 98
    objects.push_back( 0 ); varnames.push_back( "" ); \
    i_last_separator = objects.size(); }
zorglub's avatar
zorglub committed
99 100

static int InputAutoMenuBuilder( vlc_object_t *p_object,
101 102
        vector<int> &objects,
        vector<const char *> &varnames )
zorglub's avatar
zorglub committed
103
{
104
    PUSH_VAR( "bookmark" );
zorglub's avatar
zorglub committed
105
    PUSH_VAR( "title" );
106
    PUSH_VAR( "chapter" );
zorglub's avatar
zorglub committed
107 108 109 110 111 112
    PUSH_VAR( "program" );
    PUSH_VAR( "navigation" );
    PUSH_VAR( "dvd_menus" );
    return VLC_SUCCESS;
}

zorglub's avatar
Qt4:  
zorglub committed
113
static int VideoAutoMenuBuilder( vlc_object_t *p_object,
114 115
        vector<int> &objects,
        vector<const char *> &varnames )
zorglub's avatar
zorglub committed
116 117 118 119 120 121 122 123 124 125
{
    PUSH_VAR( "fullscreen" );
    PUSH_VAR( "zoom" );
    PUSH_VAR( "deinterlace" );
    PUSH_VAR( "aspect-ratio" );
    PUSH_VAR( "crop" );
    PUSH_VAR( "video-on-top" );
    PUSH_VAR( "directx-wallpaper" );
    PUSH_VAR( "video-snapshot" );

126
    vlc_object_t *p_dec_obj = ( vlc_object_t * )vlc_object_find( p_object,
127 128
            VLC_OBJECT_DECODER,
            FIND_PARENT );
zorglub's avatar
zorglub committed
129 130
    if( p_dec_obj != NULL )
    {
131
        vlc_object_t *p_object = p_dec_obj;
zorglub's avatar
zorglub committed
132 133 134 135 136 137 138
        PUSH_VAR( "ffmpeg-pp-q" );
        vlc_object_release( p_dec_obj );
    }
    return VLC_SUCCESS;
}

static int AudioAutoMenuBuilder( vlc_object_t *p_object,
139 140
        vector<int> &objects,
        vector<const char *> &varnames )
zorglub's avatar
zorglub committed
141 142 143 144 145 146 147 148
{
    PUSH_VAR( "audio-device" );
    PUSH_VAR( "audio-channels" );
    PUSH_VAR( "visual" );
    PUSH_VAR( "equalizer" );
    return VLC_SUCCESS;
}

149 150
/*****************************************************************************
 * All normal menus
151
 * Simple Code
152 153 154
 *****************************************************************************/

#define BAR_ADD( func, title ) { \
155
    QMenu *menu = func; menu->setTitle( title ); bar->addMenu( menu ); }
156 157

#define BAR_DADD( func, title, id ) { \
158
    QMenu *menu = func; menu->setTitle( title ); bar->addMenu( menu ); \
159
    MenuFunc *f = new MenuFunc( menu, id ); \
zorglub's avatar
zorglub committed
160
    CONNECT( menu, aboutToShow(), THEDP->menusUpdateMapper, map() ); \
161 162
    THEDP->menusUpdateMapper->setMapping( menu, f ); }

163 164 165
/**
 * Main Menu Bar Creation
 **/
166 167 168
void QVLCMenu::createMenuBar( MainInterface *mi,
                              intf_thread_t *p_intf,
                              bool visual_selector_enabled )
zorglub's avatar
Qt4:  
zorglub committed
169
{
zorglub's avatar
zorglub committed
170
    QMenuBar *bar = mi->menuBar();
171
    BAR_ADD( FileMenu(), qtr( "&Media" ) );
172
    BAR_ADD( PlaylistMenu( p_intf, mi ), qtr( "&Playlist" ) );
173 174 175
    BAR_ADD( ToolsMenu( p_intf, mi, visual_selector_enabled, true ), qtr( "&Tools" ) );
    BAR_DADD( AudioMenu( p_intf, NULL ), qtr( "&Audio" ), 2 );
    BAR_DADD( VideoMenu( p_intf, NULL ), qtr( "&Video" ), 1 );
176
    BAR_DADD( NavigMenu( p_intf, NULL ), qtr( "&Playback" ), 3 );
177

178
    BAR_ADD( HelpMenu(), qtr( "&Help" ) );
179
}
180 181
#undef BAR_ADD
#undef BAR_DADD
182 183

/**
184
 * Media ( File ) Menu
185 186
 * Opening, streaming and quit
 **/
187 188 189
QMenu *QVLCMenu::FileMenu()
{
    QMenu *menu = new QMenu();
190

191 192 193 194 195 196 197 198 199 200 201
    addDPStaticEntry( menu, qtr( "&Open File..." ), "",
        ":/pixmaps/file-asym_16px.png", SLOT( openFileDialog() ), "Ctrl+O" );
    addDPStaticEntry( menu, qtr( I_OPEN_FOLDER ), "",
        ":/pixmaps/folder-grey_16px.png", SLOT( PLAppendDir() ), "Ctrl+F" );
    addDPStaticEntry( menu, qtr( "Open &Disc..." ), "",
        ":/pixmaps/disc_16px.png", SLOT( openDiscDialog() ), "Ctrl+D" );
    addDPStaticEntry( menu, qtr( "Open &Network..." ), "",
        ":/pixmaps/network_16px.png", SLOT( openNetDialog() ), "Ctrl+N" );
    addDPStaticEntry( menu, qtr( "Open &Capture Device..." ), "",
        ":/pixmaps/capture-card_16px.png", SLOT( openCaptureDialog() ),
        "Ctrl+C" );
202
    menu->addSeparator();
203

204 205 206 207 208
    addDPStaticEntry( menu, qtr( "&Streaming..." ), "",
        ":/pixmaps/menus_stream_16px.png", SLOT( openThenStreamingDialogs() ),
        "Ctrl+S" );
    addDPStaticEntry( menu, qtr( "Conve&rt / Save..." ), "", "",
        SLOT( openThenTranscodingDialogs() ), "Ctrl+R" );
209
    menu->addSeparator();
210 211 212

    addDPStaticEntry( menu, qtr( "&Quit" ) , "",
        ":/pixmaps/menus_quit_16px.png", SLOT( quit() ), "Ctrl+Q" );
213 214 215
    return menu;
}

216
QMenu *QVLCMenu::PlaylistMenu( intf_thread_t *p_intf, MainInterface *mi )
zorglub's avatar
zorglub committed
217 218 219
{
    QMenu *menu = new QMenu();
    menu->addMenu( SDMenu( p_intf ) );
220 221
    menu->addAction( QIcon( ":/pixmaps/playlist_16px.png" ),
                     qtr( "Show Playlist" ), mi, SLOT( togglePlaylist() ) );
zorglub's avatar
zorglub committed
222 223
    menu->addSeparator();

224 225 226 227
    addDPStaticEntry( menu, qtr( I_PL_LOAD ), "", "", SLOT( openAPlaylist() ),
        "Ctrl+X" );
    addDPStaticEntry( menu, qtr( I_PL_SAVE ), "", "", SLOT( saveAPlaylist() ),
        "Ctrl+Y" );
zorglub's avatar
zorglub committed
228
    menu->addSeparator();
229
    menu->addAction( qtr( "Undock from interface" ), mi,
230
                     SLOT( undockPlaylist() ), qtr( "Ctrl+U" ) );
zorglub's avatar
zorglub committed
231 232 233
    return menu;
}

234 235
/**
 * Tools/View Menu
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
236
 * This is kept in the same menu for now, but could change if it gets much
237 238
 * longer.
 **/
239 240 241 242
QMenu *QVLCMenu::ToolsMenu( intf_thread_t *p_intf,
                            MainInterface *mi,
                            bool visual_selector_enabled,
                            bool with_intf )
243
{
244 245 246
    QMenu *menu = new QMenu;
    if( mi )
    {
247
        menu->addAction( QIcon( ":/pixmaps/playlist_16px.png" ),
248 249 250
                         qtr( "Playlist..." ), mi, SLOT( togglePlaylist() ),
                         qtr( "Ctrl+L" ) );
    }
251 252 253
    addDPStaticEntry( menu, qtr( I_MENU_EXT ), "",
        ":/pixmaps/menus_settings_16px.png", SLOT( extendedDialog() ),
        "Ctrl+E" );
254 255 256

    menu->addSeparator();

257 258 259
    if( with_intf )
    {
        QMenu *intfmenu = InterfacesMenu( p_intf, NULL );
260
        intfmenu->setTitle( qtr( "Add Interfaces" ) );
261 262 263
        menu->addMenu( intfmenu );
        menu->addSeparator();
    }
zorglub's avatar
zorglub committed
264 265
    if( mi )
    {
266
        /* Minimal View */
267
        QAction *action=menu->addAction( qtr( "Minimal View..." ), mi,
268 269
                SLOT( toggleMinimalView() ), qtr( "Ctrl+H" ) );
        //FIXME: remove useless thing. But keep it until the release, pls.
270
        action->setCheckable( true );
271
        if( mi->getControlsVisibilityStatus() & CONTROLS_VISIBLE )
272
            action->setChecked( true );
273

274
        /* Advanced Controls */
275 276
        action = menu->addAction( qtr( "Advanced controls" ), mi,
                SLOT( toggleAdvanced() ) );
277
        action->setCheckable( true );
278 279
        if( mi->getControlsVisibilityStatus() & CONTROLS_ADVANCED )
            action->setChecked( true );
280
#if 0 /* For Visualisations. Not yet working */
281
        adv = menu->addAction( qtr( "Visualizations selector" ),
282
                mi, SLOT( visual() ) );
283 284
        adv->setCheckable( true );
        if( visual_selector_enabled ) adv->setChecked( true );
285
#endif
zorglub's avatar
zorglub committed
286
    }
287

288 289
    menu->addSeparator();

290 291 292 293 294 295 296
    addDPStaticEntry( menu, qtr( I_MENU_MSG ), "",
        ":/pixmaps/menus_messages_16px.png", SLOT( messagesDialog() ),
        "Ctrl+M" );
    addDPStaticEntry( menu, qtr( I_MENU_INFO ) , "", "",
        SLOT( mediaInfoDialog() ), "Ctrl+I" );
    addDPStaticEntry( menu, qtr( I_MENU_CODECINFO ) , "",
        ":/pixmaps/menus_info_16px.png", SLOT( mediaCodecDialog() ), "Ctrl+J" );
297 298

#if 0 /* Not Implemented yet */
299
    addDPStaticEntry( menu, qtr( I_MENU_BOOKMARK ), "","", "bookmarksDialog()", "Ctrl+B" );
300
#endif
301 302
    addDPStaticEntry( menu, qtr( I_MENU_VLM ), "", "", SLOT( vlmDialog() ),
        "Ctrl+V" );
303

304
    menu->addSeparator();
305 306
    addDPStaticEntry( menu, qtr( "Preferences..." ), "",
        ":/pixmaps/menus_preferences_16px.png", SLOT( prefsDialog() ), "Ctrl+P" );
307 308 309
    return menu;
}

310 311 312
/**
 * Interface Sub-Menu, to list extras interface and skins
 **/
313 314 315 316 317 318 319
QMenu *QVLCMenu::InterfacesMenu( intf_thread_t *p_intf, QMenu *current )
{
    vector<int> objects;
    vector<const char *> varnames;
    /** \todo add "switch to XXX" */
    varnames.push_back( "intf-add" );
    objects.push_back( p_intf->i_object_id );
zorglub's avatar
Qt4:  
zorglub committed
320

321
    QMenu *menu = Populate( p_intf, current, varnames, objects );
zorglub's avatar
zorglub committed
322 323 324 325

    if( !p_intf->pf_show_dialog )
    {
        menu->addSeparator();
326 327
        menu->addAction( qtr( "Switch to skins" ), THEDP, SLOT( switchToSkins() ),
                QString( "Ctrl+Z" ) );
zorglub's avatar
zorglub committed
328 329
    }

zorglub's avatar
zorglub committed
330
    CONNECT( menu, aboutToShow(), THEDP->menusUpdateMapper, map() );
331 332 333 334
    THEDP->menusUpdateMapper->setMapping( menu, 4 );
    return menu;
}

335 336 337
/**
 * Main Audio Menu
 */
338 339 340 341 342
QMenu *QVLCMenu::AudioMenu( intf_thread_t *p_intf, QMenu * current )
{
    vector<int> objects;
    vector<const char *> varnames;

343
    vlc_object_t *p_object = ( vlc_object_t * )vlc_object_find( p_intf,
344
            VLC_OBJECT_INPUT, FIND_ANYWHERE );
345 346 347 348 349 350
    if( p_object != NULL )
    {
        PUSH_VAR( "audio-es" );
        vlc_object_release( p_object );
    }

351
    p_object = ( vlc_object_t * )vlc_object_find( p_intf, VLC_OBJECT_AOUT,
352
            FIND_ANYWHERE );
353 354 355 356 357 358 359 360
    if( p_object )
    {
        AudioAutoMenuBuilder( p_object, objects, varnames );
        vlc_object_release( p_object );
    }
    return Populate( p_intf, current, varnames, objects );
}

361 362 363 364
/**
 * Main Video Menu
 * Subtitles are part of Video.
 **/
365
QMenu *QVLCMenu::VideoMenu( intf_thread_t *p_intf, QMenu *current )
zorglub's avatar
zorglub committed
366 367
{
    vlc_object_t *p_object;
368 369 370
    vector<int> objects;
    vector<const char *> varnames;

371
    p_object = ( vlc_object_t * )vlc_object_find( p_intf, VLC_OBJECT_INPUT,
372
            FIND_ANYWHERE );
zorglub's avatar
zorglub committed
373 374
    if( p_object != NULL )
    {
375 376
        PUSH_VAR( "video-es" );
        PUSH_VAR( "spu-es" );
zorglub's avatar
zorglub committed
377 378
        vlc_object_release( p_object );
    }
379

380
    p_object = ( vlc_object_t * )vlc_object_find( p_intf, VLC_OBJECT_VOUT,
381
            FIND_ANYWHERE );
382 383 384 385 386 387
    if( p_object != NULL )
    {
        VideoAutoMenuBuilder( p_object, objects, varnames );
        vlc_object_release( p_object );
    }
    return Populate( p_intf, current, varnames, objects );
zorglub's avatar
zorglub committed
388 389
}

390 391 392 393
/**
 * Navigation Menu
 * For DVD, MP4, MOV and other chapter based format
 **/
394
QMenu *QVLCMenu::NavigMenu( intf_thread_t *p_intf, QMenu *navMenu )
395 396 397 398
{
    vlc_object_t *p_object;
    vector<int> objects;
    vector<const char *> varnames;
zorglub's avatar
zorglub committed
399

400
    /* FIXME */
401
    p_object = ( vlc_object_t * )vlc_object_find( p_intf, VLC_OBJECT_INPUT,
402
            FIND_ANYWHERE );
403 404 405
    if( p_object != NULL )
    {
        InputAutoMenuBuilder( p_object, objects, varnames );
406 407
        PUSH_VAR( "prev-title" ); PUSH_VAR ( "next-title" );
        PUSH_VAR( "prev-chapter" ); PUSH_VAR( "next-chapter" );
408 409
        vlc_object_release( p_object );
    }
410
    navMenu = new QMenu();
411 412
    addDPStaticEntry( navMenu, qtr( I_MENU_GOTOTIME ), "","",
        SLOT( gotoTimeDialog() ), "Ctrl+T" );
413 414
    navMenu->addSeparator();
    return Populate( p_intf, navMenu, varnames, objects, true );
415
}
zorglub's avatar
zorglub committed
416

417
/**
418
 * Service Discovery SubMenu
419
 **/
zorglub's avatar
zorglub committed
420 421 422
QMenu *QVLCMenu::SDMenu( intf_thread_t *p_intf )
{
    QMenu *menu = new QMenu();
423
    menu->setTitle( qtr( I_PL_SD ) );
424 425 426 427 428
    char **ppsz_longnames;
    char **ppsz_names = services_discovery_GetServicesNames( p_intf,
                                                             &ppsz_longnames );
    char **ppsz_name = ppsz_names, **ppsz_longname = ppsz_longnames;
    for( ; *ppsz_name; ppsz_name++, ppsz_longname++ )
zorglub's avatar
zorglub committed
429
    {
430
        QAction *a = new QAction( qfu( *ppsz_longname ), menu );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
431
        a->setCheckable( true );
432
        if( playlist_IsServicesDiscoveryLoaded( THEPL, *ppsz_name ) )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
433 434
            a->setChecked( true );
        CONNECT( a , triggered(), THEDP->SDMapper, map() );
435
        THEDP->SDMapper->setMapping( a, QString( *ppsz_name ) );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
436
        menu->addAction( a );
437

438
        if( !strcmp( *ppsz_name, "podcast" ) )
439 440 441 442 443 444
        {
            QAction *b = new QAction( qfu( "Configure podcasts..." ), menu );
            //b->setEnabled( a->isChecked() );
            menu->addAction( b );
            CONNECT( b, triggered(), THEDP, podcastConfigureDialog() );
        }
445 446
        free( *ppsz_name );
        free( *ppsz_longname );
zorglub's avatar
zorglub committed
447
    }
448 449
    free( ppsz_names );
    free( ppsz_longnames );
zorglub's avatar
zorglub committed
450 451
    return menu;
}
452 453 454
/**
 * Help/About Menu
**/
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
455 456 457
QMenu *QVLCMenu::HelpMenu()
{
    QMenu *menu = new QMenu();
458 459 460
    addDPStaticEntry( menu, qtr( "Help..." ) , "",
        ":/pixmaps/menus_help_16px.png", SLOT( helpDialog() ), "F1" );
    addDPStaticEntry( menu, qtr( "Update" ) , "", "", SLOT( updateDialog() ), "");
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
461
    menu->addSeparator();
462 463
    addDPStaticEntry( menu, qtr( I_MENU_ABOUT ), "", "", SLOT( aboutDialog() ),
        "Ctrl+F1" );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
464 465 466 467
    return menu;
}


468
/*****************************************************************************
469
 * Popup menus - Right Click menus                                           *
470
 *****************************************************************************/
zorglub's avatar
zorglub committed
471 472
#define POPUP_BOILERPLATE \
    unsigned int i_last_separator = 0; \
473 474 475 476 477 478 479 480
    vector<int> objects; \
    vector<const char *> varnames; \
    input_thread_t *p_input = THEMIM->getInput();

#define CREATE_POPUP \
    Populate( p_intf, menu, varnames, objects ); \
    p_intf->p_sys->p_popup_menu = menu; \
    menu->popup( QCursor::pos() ); \
zorglub's avatar
zorglub committed
481
    p_intf->p_sys->p_popup_menu = NULL; \
482
    i_last_separator = 0;
zorglub's avatar
zorglub committed
483

484
#define POPUP_PLAY_ENTRIES( menu )\
485
    if( p_input ) \
zorglub's avatar
zorglub committed
486
    { \
487
        vlc_value_t val; \
zorglub's avatar
zorglub committed
488
        var_Get( p_input, "state", &val ); \
489
        if( val.i_int == PLAYING_S ) \
490 491
            addMIMStaticEntry( p_intf, menu, qtr( "Pause" ), "", \
                    ":/pixmaps/pause_16px.png", SLOT( togglePlayPause() ) ); \
492
        else \
493 494
            addMIMStaticEntry( p_intf, menu, qtr( "Play" ), "", \
                    ":/pixmaps/play_16px.png", SLOT( togglePlayPause() ) ); \
zorglub's avatar
zorglub committed
495
    } \
zorglub's avatar
zorglub committed
496
    else if( THEPL->items.i_size && THEPL->i_enabled ) \
497 498
        addMIMStaticEntry( p_intf, menu, qtr( "Play" ), "", \
                ":/pixmaps/play_16px.png", SLOT( togglePlayPause() ) ); \
499
    \
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
    addMIMStaticEntry( p_intf, menu, qtr( "Stop" ), "", \
            ":/pixmaps/stop_16px.png", SLOT( stop() ) ); \
    addMIMStaticEntry( p_intf, menu, qtr( "Previous" ), "", \
            ":/pixmaps/previous_16px.png", SLOT( prev() ) ); \
    addMIMStaticEntry( p_intf, menu, qtr( "Next" ), "", \
            ":/pixmaps/next_16px.png", SLOT( next() ) );

void QVLCMenu::PopupMenuStaticEntries( intf_thread_t *p_intf, QMenu *menu )
{
    QMenu *toolsmenu = ToolsMenu( p_intf, NULL, false, true );
    toolsmenu->setTitle( qtr( "Tools" ) );
    menu->addMenu( toolsmenu );

    QMenu *openmenu = new QMenu( qtr( "Open" ) );
    openmenu->addAction( qtr( "Open &File..." ), THEDP,
                         SLOT( openFileDialog() ) );
    openmenu->addAction( qtr( "Open &Disc..." ), THEDP,
                         SLOT( openDiscDialog() ) );
    openmenu->addAction( qtr( "Open &Network..." ), THEDP,
                         SLOT( openNetDialog() ) );
    openmenu->addAction( qtr( "Open &Capture Device..." ), THEDP,
                         SLOT( openCaptureDialog() ) );
    menu->addMenu( openmenu );

    menu->addSeparator();
    QMenu *helpmenu = HelpMenu();
    helpmenu->setTitle( qtr( "Help" ) );
    menu->addMenu( helpmenu );

    addDPStaticEntry( menu, qtr( "Quit" ), "", "", SLOT( quit() ) , "Ctrl+Q" );
}
zorglub's avatar
Qt4:  
zorglub committed
531

532
/* Video Tracks and Subtitles tracks */
533
void QVLCMenu::VideoPopupMenu( intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
534 535 536 537 538
{
    POPUP_BOILERPLATE;
    if( p_input )
    {
        vlc_object_yield( p_input );
539 540 541 542
        varnames.push_back( "video-es" );
        objects.push_back( p_input->i_object_id );
        varnames.push_back( "spu-es" );
        objects.push_back( p_input->i_object_id );
543
        vlc_object_t *p_vout = ( vlc_object_t * )vlc_object_find( p_input,
544
                VLC_OBJECT_VOUT, FIND_CHILD );
zorglub's avatar
zorglub committed
545 546
        if( p_vout )
        {
547
            VideoAutoMenuBuilder( p_vout, objects, varnames );
zorglub's avatar
zorglub committed
548 549 550 551
            vlc_object_release( p_vout );
        }
        vlc_object_release( p_input );
    }
552
    QMenu *menu = new QMenu();
553
    CREATE_POPUP;
zorglub's avatar
zorglub committed
554 555
}

556
/* Audio Tracks */
557
void QVLCMenu::AudioPopupMenu( intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
558 559 560 561 562
{
    POPUP_BOILERPLATE;
    if( p_input )
    {
        vlc_object_yield( p_input );
563 564
        varnames.push_back( "audio-es" );
        objects.push_back( p_input->i_object_id );
565
        vlc_object_t *p_aout = ( vlc_object_t * )vlc_object_find( p_input,
566
                VLC_OBJECT_AOUT, FIND_ANYWHERE );
zorglub's avatar
zorglub committed
567 568
        if( p_aout )
        {
569
            AudioAutoMenuBuilder( p_aout, objects, varnames );
zorglub's avatar
zorglub committed
570 571 572 573
            vlc_object_release( p_aout );
        }
        vlc_object_release( p_input );
    }
574
    QMenu *menu = new QMenu();
575
    CREATE_POPUP;
zorglub's avatar
zorglub committed
576 577
}

578
/* Navigation stuff, and general menus ( open ) */
579
void QVLCMenu::MiscPopupMenu( intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
580
{
581
    vlc_value_t val;
zorglub's avatar
zorglub committed
582
    POPUP_BOILERPLATE;
583

zorglub's avatar
zorglub committed
584 585 586
    if( p_input )
    {
        vlc_object_yield( p_input );
587
        varnames.push_back( "audio-es" );
588
        InputAutoMenuBuilder( VLC_OBJECT( p_input ), objects, varnames );
zorglub's avatar
zorglub committed
589 590 591
        PUSH_SEPARATOR;
    }

592 593
    QMenu *menu = new QMenu();
    Populate( p_intf, menu, varnames, objects );
594

595
    menu->addSeparator();
596 597 598
    POPUP_PLAY_ENTRIES( menu );

    menu->addSeparator();
599
    PopupMenuStaticEntries( p_intf, menu );
zorglub's avatar
zorglub committed
600

601 602
    p_intf->p_sys->p_popup_menu = menu;
    menu->popup( QCursor::pos() );
zorglub's avatar
zorglub committed
603 604 605
    p_intf->p_sys->p_popup_menu = NULL;
}

606
/* Main Menu that sticks everything together  */
damienf's avatar
damienf committed
607
void QVLCMenu::PopupMenu( intf_thread_t *p_intf, bool show )
zorglub's avatar
zorglub committed
608
{
damienf's avatar
damienf committed
609
    if( show )
zorglub's avatar
zorglub committed
610
    {
611
        // create a  popup if there is none
damienf's avatar
damienf committed
612
        if( ! p_intf->p_sys->p_popup_menu )
613
        {
614 615 616 617
            POPUP_BOILERPLATE;
            if( p_input )
            {
                vlc_object_yield( p_input );
618 619
                InputAutoMenuBuilder( VLC_OBJECT( p_input ), objects, varnames );

620
                /* Audio menu */
621 622
                PUSH_SEPARATOR;
                varnames.push_back( "audio-es" );
623
                objects.push_back( p_input->i_object_id );
624 625
                vlc_object_t *p_aout = ( vlc_object_t * )
                    vlc_object_find( p_input, VLC_OBJECT_AOUT, FIND_ANYWHERE );
626 627 628 629 630
                if( p_aout )
                {
                    AudioAutoMenuBuilder( p_aout, objects, varnames );
                    vlc_object_release( p_aout );
                }
631

632 633 634 635 636 637
                /* Video menu */
                PUSH_SEPARATOR;
                varnames.push_back( "video-es" );
                objects.push_back( p_input->i_object_id );
                varnames.push_back( "spu-es" );
                objects.push_back( p_input->i_object_id );
638 639
                vlc_object_t *p_vout = ( vlc_object_t * )
                    vlc_object_find( p_input, VLC_OBJECT_VOUT, FIND_CHILD );
640 641 642 643 644 645
                if( p_vout )
                {
                    VideoAutoMenuBuilder( p_vout, objects, varnames );
                    vlc_object_release( p_vout );
                }
            }
646

647 648 649
            QMenu *menu = new QMenu();
            Populate( p_intf, menu, varnames, objects );
            menu->addSeparator();
650 651
            POPUP_PLAY_ENTRIES( menu );
            menu->addSeparator();
652
            PopupMenuStaticEntries( p_intf, menu );
653

654 655 656
            p_intf->p_sys->p_popup_menu = menu;
        }
        p_intf->p_sys->p_popup_menu->popup( QCursor::pos() );
damienf's avatar
damienf committed
657 658
    }
    else
659
    {
660 661 662
        // destroy popup if there is one
        delete p_intf->p_sys->p_popup_menu;
        p_intf->p_sys->p_popup_menu = NULL;
zorglub's avatar
zorglub committed
663 664 665
    }
}

666 667 668 669
/************************************************************************
 * Systray Menu                                                         *
 ************************************************************************/

670 671 672
void QVLCMenu::updateSystrayMenu( MainInterface *mi,
                                  intf_thread_t *p_intf,
                                  bool b_force_visible )
673 674
{
    POPUP_BOILERPLATE;
675 676

    /* Get the systray menu and clean it */
677 678
    QMenu *sysMenu = mi->getSysTrayMenu();
    sysMenu->clear();
679 680

    /* Hide / Show VLC and cone */
681
    if( mi->isVisible() || b_force_visible )
682
    {
683
        sysMenu->addAction( QIcon( ":/vlc16.png" ),
684
                qtr( "Hide VLC media player in taskbar" ), mi,
685
                SLOT( toggleUpdateSystrayMenu() ) );
686 687 688
    }
    else
    {
689
        sysMenu->addAction( QIcon( ":/vlc16.png" ),
690
                qtr( "Show VLC media player" ), mi,
691
                SLOT( toggleUpdateSystrayMenu() ) );
692
    }
693

694 695
    sysMenu->addSeparator();
    POPUP_PLAY_ENTRIES( sysMenu );
696

697
    sysMenu->addSeparator();
698 699 700 701
    addDPStaticEntry( sysMenu, qtr( "&Open Media" ), "",
            ":/pixmaps/file-wide_16px.png", SLOT( openFileDialog() ), "" );
    addDPStaticEntry( sysMenu, qtr( "&Quit" ) , "",
        ":/pixmaps/menus_quit_16px.png", SLOT( quit() ), "" );
702

703
    /* Set the menu */
704 705 706
    mi->getSysTray()->setContextMenu( sysMenu );
}

707 708
#undef PUSH_VAR
#undef PUSH_SEPARATOR
zorglub's avatar
zorglub committed
709

710

711 712 713
/*************************************************************************
 * Builders for automenus
 *************************************************************************/
714 715 716 717 718
QMenu * QVLCMenu::Populate( intf_thread_t *p_intf,
                            QMenu *current,
                            vector< const char *> & varnames,
                            vector<int> & objects,
                            bool append )
zorglub's avatar
zorglub committed
719 720 721 722
{
    QMenu *menu = current;
    if( !menu )
        menu = new QMenu();
723
    else if( !append )
zorglub's avatar
zorglub committed
724 725 726 727 728 729 730 731
        menu->clear();

    currentGroup = NULL;

    vlc_object_t *p_object;
    vlc_bool_t b_section_empty = VLC_FALSE;
    int i;

732
#define APPEND_EMPTY { QAction *action = menu->addAction( qtr( "Empty" ) ); \
733
    action->setEnabled( false ); }
zorglub's avatar
zorglub committed
734

735
    for( i = 0; i < ( int )objects.size() ; i++ )
zorglub's avatar
zorglub committed
736
    {
737
        if( !varnames[i] || !*varnames[i] )
zorglub's avatar
zorglub committed
738 739 740 741 742 743 744 745
        {
            if( b_section_empty )
                APPEND_EMPTY;
            menu->addSeparator();
            b_section_empty = VLC_TRUE;
            continue;
        }

746
        if( objects[i] == 0 )
zorglub's avatar
zorglub committed
747 748
        {
            /// \bug What is this ?
749
            // Append( menu, varnames[i], NULL );
zorglub's avatar
zorglub committed
750 751 752 753
            b_section_empty = VLC_FALSE;
            continue;
        }

754
        p_object = ( vlc_object_t * )vlc_object_get( p_intf, objects[i] );
zorglub's avatar
zorglub committed
755 756 757
        if( p_object == NULL ) continue;

        b_section_empty = VLC_FALSE;
758
        /* Ugly specific stuff */
759
        if( strstr( varnames[i], "intf-add" ) )
760 761 762
            CreateItem( menu, varnames[i], p_object, false );
        else
            CreateItem( menu, varnames[i], p_object, true );
zorglub's avatar
zorglub committed
763 764 765 766 767 768 769
        vlc_object_release( p_object );
    }

    /* Special case for empty menus */
    if( menu->actions().size() == 0 || b_section_empty )
        APPEND_EMPTY

770
    return menu;
zorglub's avatar
zorglub committed
771
}
772
#undef APPEND_EMPTY
zorglub's avatar
zorglub committed
773 774 775 776 777

/*****************************************************************************
 * Private methods.
 *****************************************************************************/

778 779 780
static bool IsMenuEmpty( const char *psz_var,
                         vlc_object_t *p_object,
                         bool b_root = true )
zorglub's avatar
zorglub committed
781 782 783 784 785 786 787 788
{
    vlc_value_t val, val_list;
    int i_type, i_result, i;

    /* Check the type of the object variable */
    i_type = var_Type( p_object, psz_var );

    /* Check if we want to display the variable */
789
    if( !( i_type & VLC_VAR_HASCHOICE ) ) return false;
zorglub's avatar
zorglub committed
790 791

    var_Change( p_object, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
792
    if( val.i_int == 0 ) return true;
zorglub's avatar
zorglub committed
793

794
    if( ( i_type & VLC_VAR_TYPE ) != VLC_VAR_VARIABLE )
zorglub's avatar
zorglub committed
795
    {
zorglub's avatar
zorglub committed
796
        /* Very evil hack ! intf-switch can have only one value */
797 798 799
        if( !strcmp( psz_var, "intf-switch" ) ) return false;
        if( val.i_int == 1 && b_root ) return true;
        else return false;
zorglub's avatar
zorglub committed
800 801 802 803 804
    }

    /* Check children variables in case of VLC_VAR_VARIABLE */
    if( var_Change( p_object, psz_var, VLC_VAR_GETLIST, &val_list, NULL ) < 0 )
    {
805
        return true;
zorglub's avatar
zorglub committed
806 807
    }

808
    for( i = 0, i_result = true; i < val_list.p_list->i_count; i++ )
zorglub's avatar
zorglub committed
809 810
    {
        if( !IsMenuEmpty( val_list.p_list->p_values[i].psz_string,
811
                    p_object, false ) )
zorglub's avatar
zorglub committed
812
        {
813
            i_result = false;
zorglub's avatar
zorglub committed
814 815 816 817 818 819 820 821 822 823 824
            break;
        }
    }

    /* clean up everything */
    var_Change( p_object, psz_var, VLC_VAR_FREELIST, &val_list, NULL );

    return i_result;
}

void QVLCMenu::CreateItem( QMenu *menu, const char *psz_var,
825
        vlc_object_t *p_object, bool b_submenu )
zorglub's avatar
zorglub committed
826 827 828 829 830 831 832 833 834
{
    vlc_value_t val, text;
    int i_type;

    /* Check the type of the object variable */
    i_type = var_Type( p_object, psz_var );

    switch( i_type & VLC_VAR_TYPE )
    {
835 836 837 838 839 840 841 842 843 844
        case VLC_VAR_VOID:
        case VLC_VAR_BOOL:
        case VLC_VAR_VARIABLE:
        case VLC_VAR_STRING:
        case VLC_VAR_INTEGER:
        case VLC_VAR_FLOAT:
            break;
        default:
            /* Variable doesn't exist or isn't handled */
            return;
zorglub's avatar
zorglub committed
845 846 847 848 849 850 851 852 853 854 855
    }

    /* Make sure we want to display the variable */
    if( IsMenuEmpty( psz_var, p_object ) )  return;

    /* Get the descriptive name of the variable */
    var_Change( p_object, psz_var, VLC_VAR_GETTEXT, &text, NULL );

    if( i_type & VLC_VAR_HASCHOICE )
    {
        /* Append choices menu */
856 857 858
        if( b_submenu )
        {
            QMenu *submenu = new QMenu();
zorglub's avatar
Qt4:  
zorglub committed
859
            submenu->setTitle( qfu( text.psz_string ?
860
                        text.psz_string : psz_var ) );
861
            if( CreateChoicesMenu( submenu, psz_var, p_object, true ) == 0 )
862 863 864 865
                menu->addMenu( submenu );
        }
        else
            CreateChoicesMenu( menu, psz_var, p_object, true );
866
        FREENULL( text.psz_string );
zorglub's avatar
B