menus.cpp 37.8 KB
Newer Older
1 2 3
/*****************************************************************************
 * menus.cpp : Qt menus
 *****************************************************************************
4
 * Copyright ( C ) 2006-2007 the VideoLAN team
5
 * $Id$
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>
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.
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.
 *****************************************************************************/

25 26 27 28
/** \todo
 * - Remove static currentGroup
 */

29 30 31 32
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

33
#include <vlc_common.h>
34

35
#include <vlc_intf_strings.h>
36

37
#include "main_interface.hpp"
Clément Stenac's avatar
Clément Stenac committed
38 39 40 41
#include "menus.hpp"
#include "dialogs_provider.hpp"
#include "input_manager.hpp"

42 43 44 45 46 47 48
#include <QMenu>
#include <QMenuBar>
#include <QAction>
#include <QActionGroup>
#include <QSignalMapper>
#include <QSystemTrayIcon>

49 50 51 52 53 54 55 56 57
enum
{
    ITEM_NORMAL,
    ITEM_CHECK,
    ITEM_RADIO
};

static QActionGroup *currentGroup;

58
// Add static entries to menus
59 60
void addDPStaticEntry( QMenu *menu,
                       const QString text,
61 62
                       const char *help,
                       const char *icon,
63
                       const char *member,
64
                       const char *shortcut )
65
{
66
    QAction *action = NULL;
67 68 69
    if( !EMPTY_STR( icon ) > 0 )
    {
        if( !EMPTY_STR( shortcut ) > 0 )
70 71
            action = menu->addAction( QIcon( icon ), text, THEDP,
                                      member, qtr( shortcut ) );
72
        else
73
            action = menu->addAction( QIcon( icon ), text, THEDP, member );
74 75 76 77
    }
    else
    {
        if( !EMPTY_STR( shortcut ) > 0 )
78
            action = menu->addAction( text, THEDP, member, qtr( shortcut ) );
79
        else
80
            action = menu->addAction( text, THEDP, member );
81
    }
82
    action->setData( "_static_" );
83
}
84 85

void addMIMStaticEntry( intf_thread_t *p_intf,
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
86 87
                        QMenu *menu,
                        const QString text,
88 89
                        const char *help,
                        const char *icon,
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
90
                        const char *member )
91 92 93
{
    if( strlen( icon ) > 0 )
    {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
94
        QAction *action = menu->addAction( text, THEMIM,  member );
95 96 97 98
        action->setIcon( QIcon( icon ) );
    }
    else
    {
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
99
        menu->addAction( text, THEMIM, member );
100
    }
101
}
102

103 104 105 106 107 108
void EnableDPStaticEntries( QMenu *menu, bool enable = true )
{
    if( !menu )
        return;

    QAction *action;
109
    foreach( action, menu->actions() )
110 111 112 113 114 115
    {
        if( action->data().toString() == "_static_" )
            action->setEnabled( enable );
    }
}

116 117 118 119 120 121 122 123 124
/**
 * \return Number of static entries
 */
int DeleteNonStaticEntries( QMenu *menu )
{
    int i_ret = 0;
    QAction *action;
    if( !menu )
        return VLC_EGENERIC;
125
    foreach( action, menu->actions() )
126 127 128 129 130 131 132 133
    {
        if( action->data().toString() != "_static_" )
            delete action;
        else
            i_ret++;
    }
}

134
/*****************************************************************************
135
 * Definitions of variables for the dynamic menus
136
 *****************************************************************************/
137
#define PUSH_VAR( var ) varnames.push_back( var ); \
138 139 140 141
    objects.push_back( p_object ? p_object->i_object_id : 0 )

#define PUSH_INPUTVAR( var ) varnames.push_back( var ); \
    objects.push_back( p_input ? p_input->i_object_id : 0 );
142 143

#define PUSH_SEPARATOR if( objects.size() != i_last_separator ) { \
144
    objects.push_back( 0 ); varnames.push_back( "" ); \
145
    i_last_separator = objects.size(); }
146 147

static int InputAutoMenuBuilder( vlc_object_t *p_object,
148
        vector<int> &objects,
149
        vector<const char *> &varnames )
150
{
151
    PUSH_VAR( "bookmark" );
152
    PUSH_VAR( "title" );
153
    PUSH_VAR( "chapter" );
154 155 156 157 158 159
    PUSH_VAR( "program" );
    PUSH_VAR( "navigation" );
    PUSH_VAR( "dvd_menus" );
    return VLC_SUCCESS;
}

Clément Stenac's avatar
Qt4:  
Clément Stenac committed
160
static int VideoAutoMenuBuilder( vlc_object_t *p_object,
161
        input_thread_t *p_input,
162
        vector<int> &objects,
163
        vector<const char *> &varnames )
164
{
165 166
    PUSH_INPUTVAR( "video-es" );
    PUSH_INPUTVAR( "spu-es" );
167 168 169 170 171 172 173 174 175
    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" );

176
    if( p_object )
177
    {
178 179 180 181 182 183 184 185 186
        vlc_object_t *p_dec_obj = ( vlc_object_t * )vlc_object_find( p_object,
                VLC_OBJECT_DECODER,
                FIND_PARENT );
        if( p_dec_obj )
        {
            vlc_object_t *p_object = p_dec_obj;
            PUSH_VAR( "ffmpeg-pp-q" );
            vlc_object_release( p_dec_obj );
        }
187 188 189 190 191
    }
    return VLC_SUCCESS;
}

static int AudioAutoMenuBuilder( vlc_object_t *p_object,
192
        input_thread_t *p_input,
193
        vector<int> &objects,
194
        vector<const char *> &varnames )
195
{
196
    PUSH_INPUTVAR( "audio-es" );
197 198 199 200 201 202 203
    PUSH_VAR( "audio-device" );
    PUSH_VAR( "audio-channels" );
    PUSH_VAR( "visual" );
    PUSH_VAR( "equalizer" );
    return VLC_SUCCESS;
}

204 205 206
static QAction * FindActionWithVar( QMenu *menu, const char *psz_var )
{
    QAction *action;
207
    foreach( action, menu->actions() )
208 209 210 211 212 213 214 215 216 217
    {
        if( action->data().toString() == psz_var )
            return action;
    }
    return NULL;
}

static QAction * FindActionWithText( QMenu *menu, QString &text )
{
    QAction *action;
218
    foreach( action, menu->actions() )
219 220 221 222 223 224 225
    {
        if( action->text() == text )
            return action;
    }
    return NULL;
}

226 227
/*****************************************************************************
 * All normal menus
228
 * Simple Code
229 230 231
 *****************************************************************************/

#define BAR_ADD( func, title ) { \
232
    QMenu *_menu = func; _menu->setTitle( title ); bar->addMenu( _menu ); }
233 234

#define BAR_DADD( func, title, id ) { \
235 236 237 238 239 240 241 242
    QMenu *_menu = func; _menu->setTitle( title ); bar->addMenu( _menu ); \
    MenuFunc *f = new MenuFunc( _menu, id ); \
    CONNECT( _menu, aboutToShow(), THEDP->menusUpdateMapper, map() ); \
    THEDP->menusUpdateMapper->setMapping( _menu, f ); }

#define ACT_ADD( _menu, val, title ) { \
    QAction *_action = new QAction( title, _menu ); _action->setData( val ); \
    _menu->addAction( _action ); }
243

244 245 246
/**
 * Main Menu Bar Creation
 **/
247 248 249
void QVLCMenu::createMenuBar( MainInterface *mi,
                              intf_thread_t *p_intf,
                              bool visual_selector_enabled )
Clément Stenac's avatar
Qt4:  
Clément Stenac committed
250
{
251 252 253
    /* QMainWindows->menuBar()
       gives the QProcess::destroyed timeout issue on Cleanlooks style with
       setDesktopAware set to false */
254
    QMenuBar *bar = mi->menuBar();
255
    BAR_ADD( FileMenu(), qtr( "&Media" ) );
256
    BAR_ADD( PlaylistMenu( p_intf, mi ), qtr( "&Playlist" ) );
257
    BAR_ADD( ToolsMenu( p_intf, NULL, mi, visual_selector_enabled, true ),
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
258
             qtr( "&Tools" ) );
259 260
    BAR_DADD( AudioMenu( p_intf, NULL ), qtr( "&Audio" ), 1 );
    BAR_DADD( VideoMenu( p_intf, NULL ), qtr( "&Video" ), 2 );
261
    BAR_DADD( NavigMenu( p_intf, NULL ), qtr( "&Playback" ), 3 );
262
    BAR_ADD( HelpMenu( NULL ), qtr( "&Help" ) );
263
}
264 265
#undef BAR_ADD
#undef BAR_DADD
266 267

/**
268
 * Media ( File ) Menu
269 270
 * Opening, streaming and quit
 **/
271 272 273
QMenu *QVLCMenu::FileMenu()
{
    QMenu *menu = new QMenu();
274

275 276 277 278 279 280 281 282 283 284 285
    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" );
286
    menu->addSeparator();
287

288 289 290 291 292
    addDPStaticEntry( menu, qtr( "&Streaming..." ), "",
        ":/pixmaps/menus_stream_16px.png", SLOT( openThenStreamingDialogs() ),
        "Ctrl+S" );
    addDPStaticEntry( menu, qtr( "Conve&rt / Save..." ), "", "",
        SLOT( openThenTranscodingDialogs() ), "Ctrl+R" );
293
    menu->addSeparator();
294 295 296

    addDPStaticEntry( menu, qtr( "&Quit" ) , "",
        ":/pixmaps/menus_quit_16px.png", SLOT( quit() ), "Ctrl+Q" );
297 298 299
    return menu;
}

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
300
/* Playlist/MediaLibrary Control */
301
QMenu *QVLCMenu::PlaylistMenu( intf_thread_t *p_intf, MainInterface *mi )
Clément Stenac's avatar
Clément Stenac committed
302 303 304
{
    QMenu *menu = new QMenu();
    menu->addMenu( SDMenu( p_intf ) );
305 306
    menu->addAction( QIcon( ":/pixmaps/playlist_16px.png" ),
                     qtr( "Show Playlist" ), mi, SLOT( togglePlaylist() ) );
Clément Stenac's avatar
Clément Stenac committed
307 308
    menu->addSeparator();

309 310 311 312
    addDPStaticEntry( menu, qtr( I_PL_LOAD ), "", "", SLOT( openAPlaylist() ),
        "Ctrl+X" );
    addDPStaticEntry( menu, qtr( I_PL_SAVE ), "", "", SLOT( saveAPlaylist() ),
        "Ctrl+Y" );
313
    menu->addSeparator();
314
    menu->addAction( qtr( "Undock from interface" ), mi,
315
                     SLOT( undockPlaylist() ), qtr( "Ctrl+U" ) );
Clément Stenac's avatar
Clément Stenac committed
316 317 318
    return menu;
}

319 320
/**
 * Tools/View Menu
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
321
 * This is kept in the same menu for now, but could change if it gets much
322
 * longer.
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
323
 * This menu can be an interface menu but also a right click menu.
324
 **/
325
QMenu *QVLCMenu::ToolsMenu( intf_thread_t *p_intf,
326
                            QMenu *current,
327 328 329
                            MainInterface *mi,
                            bool visual_selector_enabled,
                            bool with_intf )
330
{
331
    QMenu *menu = new QMenu( current );
332 333
    if( mi )
    {
334
        menu->addAction( QIcon( ":/pixmaps/playlist_16px.png" ),
335 336 337
                         qtr( "Playlist..." ), mi, SLOT( togglePlaylist() ),
                         qtr( "Ctrl+L" ) );
    }
338 339 340
    addDPStaticEntry( menu, qtr( I_MENU_EXT ), "",
        ":/pixmaps/menus_settings_16px.png", SLOT( extendedDialog() ),
        "Ctrl+E" );
341 342 343

    menu->addSeparator();

344 345
    if( with_intf )
    {
346
        QMenu *intfmenu = InterfacesMenu( p_intf, menu );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
347
        intfmenu->setTitle( qtr( "Add Interfaces" ) );
348 349 350
        MenuFunc *f = new MenuFunc( intfmenu, 4 );
        CONNECT( intfmenu, aboutToShow(), THEDP->menusUpdateMapper, map() );
        THEDP->menusUpdateMapper->setMapping( intfmenu, f );
351 352 353
        menu->addMenu( intfmenu );
        menu->addSeparator();
    }
Clément Stenac's avatar
Clément Stenac committed
354 355
    if( mi )
    {
356
        /* Minimal View */
357
        QAction *action=menu->addAction( qtr( "Minimal View..." ), mi,
358
                SLOT( toggleMinimalView() ), qtr( "Ctrl+H" ) );
359
        action->setCheckable( true );
360
        if( mi->getControlsVisibilityStatus() & CONTROLS_VISIBLE )
361
            action->setChecked( true );
362

363 364 365 366
        /* FullScreen View */
        action = menu->addAction( qtr( "Toggle Fullscreen Interface" ), mi,
                SLOT( toggleFullScreen() ), qtr( "F11" ) );

367
        /* Advanced Controls */
368 369
        action = menu->addAction( qtr( "Advanced controls" ), mi,
                SLOT( toggleAdvanced() ) );
370
        action->setCheckable( true );
371 372
        if( mi->getControlsVisibilityStatus() & CONTROLS_ADVANCED )
            action->setChecked( true );
373
#if 0 /* For Visualisations. Not yet working */
374
        adv = menu->addAction( qtr( "Visualizations selector" ),
375
                mi, SLOT( visual() ) );
376 377
        adv->setCheckable( true );
        if( visual_selector_enabled ) adv->setChecked( true );
378
#endif
Clément Stenac's avatar
Clément Stenac committed
379
    }
380

381 382
    menu->addSeparator();

383 384 385 386 387 388 389
    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" );
390
    addDPStaticEntry( menu, qtr( I_MENU_BOOKMARK ), "","",
391
                      SLOT( bookmarksDialog() ), "Ctrl+B" );
392
#ifdef ENABLE_VLM
393
    addDPStaticEntry( menu, qtr( I_MENU_VLM ), "", "", SLOT( vlmDialog() ),
394
        "Ctrl+W" );
395
#endif
396

397
    menu->addSeparator();
398 399
    addDPStaticEntry( menu, qtr( "Preferences..." ), "",
        ":/pixmaps/menus_preferences_16px.png", SLOT( prefsDialog() ), "Ctrl+P" );
400 401 402
    return menu;
}

403 404 405
/**
 * Interface Sub-Menu, to list extras interface and skins
 **/
406 407
QMenu *QVLCMenu::InterfacesMenu( intf_thread_t *p_intf, QMenu *current )
{
408
    vector<int> objects;
409 410 411
    vector<const char *> varnames;
    /** \todo add "switch to XXX" */
    varnames.push_back( "intf-add" );
412
    objects.push_back( p_intf->i_object_id );
Clément Stenac's avatar
Qt4:  
Clément Stenac committed
413

414 415
    QMenu *submenu = new QMenu( current );
    QMenu *menu = Populate( p_intf, submenu, varnames, objects );
Clément Stenac's avatar
Clément Stenac committed
416

417 418 419
    return menu;
}

420 421 422
/**
 * Main Audio Menu
 */
423 424
QMenu *QVLCMenu::AudioMenu( intf_thread_t *p_intf, QMenu * current )
{
425
    vector<int> objects;
426
    vector<const char *> varnames;
427 428 429 430 431
    vlc_object_t *p_object;
    input_thread_t *p_input;

    if( !current )
        current = new QMenu();
432

433
    if( current->isEmpty() )
434
    {
435 436 437 438 439
        ACT_ADD( current, "audio-es", qtr( "Audio &Track" ) );
        ACT_ADD( current, "audio-device", qtr( "Audio &Device" ) );
        ACT_ADD( current, "audio-channels", qtr( "Audio &Channels" ) );
        ACT_ADD( current, "visual", qtr( "&Visualizations" ) );
        ACT_ADD( current, "equalizer", qtr( "&Equalizer" ) );
440 441
    }

442 443 444 445 446 447 448 449 450
    p_input = THEMIM->getInput();
    if( p_input )
        vlc_object_yield( p_input );
    p_object = ( vlc_object_t * ) vlc_object_find( p_intf,
                                                   VLC_OBJECT_AOUT,
                                                   FIND_ANYWHERE );

    AudioAutoMenuBuilder( p_object, p_input, objects, varnames );

451 452
    if( p_object )
        vlc_object_release( p_object );
453 454 455
    if( p_input )
        vlc_object_release( p_input );

456 457 458
    return Populate( p_intf, current, varnames, objects );
}

459 460 461 462
/**
 * Main Video Menu
 * Subtitles are part of Video.
 **/
463
QMenu *QVLCMenu::VideoMenu( intf_thread_t *p_intf, QMenu *current )
464 465
{
    vlc_object_t *p_object;
466
    input_thread_t *p_input;
467
    vector<int> objects;
468 469
    vector<const char *> varnames;

470 471 472 473
    if( !current )
        current = new QMenu();

    if( current->isEmpty() )
474
    {
475
        ACT_ADD( current, "video-es", qtr( "Video &Track" ) );
476 477 478 479 480

        QAction *action;
        QMenu *submenu = new QMenu( qtr( "&Subtitles Track" ), current );
        action = current->addMenu( submenu );
        action->setData( "spu-es" );
481 482 483
        action =  submenu->addAction( qfu( "Load File..." ), THEDP,
                                      SLOT( loadSubtitlesFile() ) );
        action->setData( "_static_" );
484

485 486 487 488 489 490
        ACT_ADD( current, "fullscreen", qtr( "&Fullscreen" ) );
        ACT_ADD( current, "zoom", qtr( "&Zoom" ) );
        ACT_ADD( current, "deinterlace", qtr( "&Deinterlace" ) );
        ACT_ADD( current, "aspect-ratio", qtr( "&Aspect Ratio" ) );
        ACT_ADD( current, "crop", qtr( "&Crop" ) );
        ACT_ADD( current, "video-on-top", qtr( "Always &On Top" ) );
491 492 493
        /* ACT_ADD( current, "directx-wallpaper", qtr( "DirectX Wallpaper" ) ); */
        ACT_ADD( current, "video-snapshot", qtr( "Snapshot" ) );
        /* ACT_ADD( current, "ffmpeg-pp-q", qtr( "Decoder" ) ); */
494
    }
495

496 497 498
    p_input = THEMIM->getInput();
    if( p_input )
        vlc_object_yield( p_input );
499
    p_object = ( vlc_object_t * )vlc_object_find( p_intf, VLC_OBJECT_VOUT,
500
            FIND_ANYWHERE );
501 502 503 504

    VideoAutoMenuBuilder( p_object, p_input, objects, varnames );

    if( p_object )
505
        vlc_object_release( p_object );
506 507 508
    if( p_input )
        vlc_object_release( p_input );

509
    return Populate( p_intf, current, varnames, objects );
510 511
}

512 513 514 515
/**
 * Navigation Menu
 * For DVD, MP4, MOV and other chapter based format
 **/
516
QMenu *QVLCMenu::NavigMenu( intf_thread_t *p_intf, QMenu *menu )
517 518
{
    vlc_object_t *p_object;
519
    vector<int> objects;
520
    vector<const char *> varnames;
521

522 523 524
    if( !menu )
    {
        menu = new QMenu();
525 526 527 528
    }

    if( menu->isEmpty() )
    {
529 530 531
        addDPStaticEntry( menu, qtr( I_MENU_GOTOTIME ), "","",
                          SLOT( gotoTimeDialog() ), "Ctrl+T" );
        menu->addSeparator();
532 533 534 535 536 537

        ACT_ADD( menu, "bookmark", qtr( "&Bookmarks" ) );
        ACT_ADD( menu, "title", qtr( "&Title" ) );
        ACT_ADD( menu, "chapter", qtr( "&Chapter" ) );
        ACT_ADD( menu, "program", qtr( "&Program" ) );
        ACT_ADD( menu, "navigation", qtr( "&Navigation" ) );
538 539
    }

540
    p_object = ( vlc_object_t * )vlc_object_find( p_intf, VLC_OBJECT_INPUT,
541
            FIND_ANYWHERE );
542 543 544 545 546
    InputAutoMenuBuilder(  p_object, objects, varnames );
    PUSH_VAR( "prev-title" );
    PUSH_VAR( "next-title" );
    PUSH_VAR( "prev-chapter" );
    PUSH_VAR( "next-chapter" );
547
    EnableDPStaticEntries( menu, ( p_object != NULL ) );
548
    if( p_object )
549
    {
550
        vlc_object_release( p_object );
551 552
    }
    return Populate( p_intf, menu, varnames, objects, true );
553
}
554

555
/**
556
 * Service Discovery SubMenu
557
 **/
Clément Stenac's avatar
Clément Stenac committed
558 559 560
QMenu *QVLCMenu::SDMenu( intf_thread_t *p_intf )
{
    QMenu *menu = new QMenu();
561
    menu->setTitle( qtr( I_PL_SD ) );
562 563 564
    char **ppsz_longnames;
    char **ppsz_names = services_discovery_GetServicesNames( p_intf,
                                                             &ppsz_longnames );
565 566 567
    if( !ppsz_names )
        return menu;

568 569
    char **ppsz_name = ppsz_names, **ppsz_longname = ppsz_longnames;
    for( ; *ppsz_name; ppsz_name++, ppsz_longname++ )
Clément Stenac's avatar
Clément Stenac committed
570
    {
571
        QAction *a = new QAction( qfu( *ppsz_longname ), menu );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
572
        a->setCheckable( true );
573
        if( playlist_IsServicesDiscoveryLoaded( THEPL, *ppsz_name ) )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
574 575
            a->setChecked( true );
        CONNECT( a , triggered(), THEDP->SDMapper, map() );
576
        THEDP->SDMapper->setMapping( a, QString( *ppsz_name ) );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
577
        menu->addAction( a );
578

579
        if( !strcmp( *ppsz_name, "podcast" ) )
580 581 582 583 584 585
        {
            QAction *b = new QAction( qfu( "Configure podcasts..." ), menu );
            //b->setEnabled( a->isChecked() );
            menu->addAction( b );
            CONNECT( b, triggered(), THEDP, podcastConfigureDialog() );
        }
586 587
        free( *ppsz_name );
        free( *ppsz_longname );
Clément Stenac's avatar
Clément Stenac committed
588
    }
589 590
    free( ppsz_names );
    free( ppsz_longnames );
Clément Stenac's avatar
Clément Stenac committed
591 592
    return menu;
}
593 594 595
/**
 * Help/About Menu
**/
596
QMenu *QVLCMenu::HelpMenu( QMenu *current )
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
597
{
598
    QMenu *menu = new QMenu( current );
599 600
    addDPStaticEntry( menu, qtr( "Help..." ) , "",
        ":/pixmaps/menus_help_16px.png", SLOT( helpDialog() ), "F1" );
601
#ifdef UPDATE_CHECK
602
    addDPStaticEntry( menu, qtr( "Check for updates..." ) , "", "", SLOT( updateDialog() ), "");
603
#endif
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
604
    menu->addSeparator();
605 606
    addDPStaticEntry( menu, qtr( I_MENU_ABOUT ), "", "", SLOT( aboutDialog() ),
        "Ctrl+F1" );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
607 608 609
    return menu;
}

610
#undef ACT_ADD
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
611

612
/*****************************************************************************
613
 * Popup menus - Right Click menus                                           *
614
 *****************************************************************************/
615 616
#define POPUP_BOILERPLATE \
    unsigned int i_last_separator = 0; \
617
    vector<int> objects; \
618 619 620 621 622 623 624
    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() ); \
625
    p_intf->p_sys->p_popup_menu = NULL; \
626
    i_last_separator = 0;
627

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642
void QVLCMenu::PopupMenuControlEntries( QMenu *menu,
                                        intf_thread_t *p_intf,
                                        input_thread_t *p_input )
{
    if( p_input )
    {
        vlc_value_t val;
        var_Get( p_input, "state", &val );
        if( val.i_int == PLAYING_S )
            addMIMStaticEntry( p_intf, menu, qtr( "Pause" ), "",
                    ":/pixmaps/pause_16px.png", SLOT( togglePlayPause() ) );
        else
            addMIMStaticEntry( p_intf, menu, qtr( "Play" ), "",
                    ":/pixmaps/play_16px.png", SLOT( togglePlayPause() ) );
    }
643
    else if( THEPL->items.i_size )
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
644 645 646 647 648 649 650 651
        addMIMStaticEntry( p_intf, menu, qtr( "Play" ), "",
                ":/pixmaps/play_16px.png", SLOT( togglePlayPause() ) );

    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" ), "",
652
            ":/pixmaps/next_16px.png", SLOT( next() ) );
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
653
    }
654 655 656

void QVLCMenu::PopupMenuStaticEntries( intf_thread_t *p_intf, QMenu *menu )
{
Jean-Philippe Andre's avatar
Jean-Philippe Andre committed
657
#if 0
658
    QMenu *toolsmenu = ToolsMenu( p_intf, menu, false, true );
659 660
    toolsmenu->setTitle( qtr( "Tools" ) );
    menu->addMenu( toolsmenu );
Jean-Philippe Andre's avatar
Jean-Philippe Andre committed
661
#endif
662

663
    QMenu *openmenu = new QMenu( qtr( "Open" ), menu );
664 665 666 667 668 669 670 671 672 673 674
    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();
Jean-Philippe Andre's avatar
Jean-Philippe Andre committed
675
#if 0
676
    QMenu *helpmenu = HelpMenu( menu );
677 678
    helpmenu->setTitle( qtr( "Help" ) );
    menu->addMenu( helpmenu );
Jean-Philippe Andre's avatar
Jean-Philippe Andre committed
679
#endif
680 681 682

    addDPStaticEntry( menu, qtr( "Quit" ), "", "", SLOT( quit() ) , "Ctrl+Q" );
}
Clément Stenac's avatar
Qt4:  
Clément Stenac committed
683

684
/* Video Tracks and Subtitles tracks */
685
void QVLCMenu::VideoPopupMenu( intf_thread_t *p_intf )
686 687 688 689 690
{
    POPUP_BOILERPLATE;
    if( p_input )
    {
        vlc_object_yield( p_input );
691
        vlc_object_t *p_vout = ( vlc_object_t * )vlc_object_find( p_input,
692
                VLC_OBJECT_VOUT, FIND_CHILD );
693 694
        if( p_vout )
        {
695
            VideoAutoMenuBuilder( p_vout, p_input, objects, varnames );
696 697 698 699
            vlc_object_release( p_vout );
        }
        vlc_object_release( p_input );
    }
700
    QMenu *menu = new QMenu();
701
    CREATE_POPUP;
702 703
}

704
/* Audio Tracks */
705
void QVLCMenu::AudioPopupMenu( intf_thread_t *p_intf )
706 707 708 709 710
{
    POPUP_BOILERPLATE;
    if( p_input )
    {
        vlc_object_yield( p_input );
711
        vlc_object_t *p_aout = ( vlc_object_t * )vlc_object_find( p_input,
712
                VLC_OBJECT_AOUT, FIND_ANYWHERE );
713
        AudioAutoMenuBuilder( p_aout, p_input, objects, varnames );
714 715 716 717
        if( p_aout )
            vlc_object_release( p_aout );
        vlc_object_release( p_input );
    }
718
    QMenu *menu = new QMenu();
719
    CREATE_POPUP;
720 721
}

722
/* Navigation stuff, and general menus ( open ) */
723
void QVLCMenu::MiscPopupMenu( intf_thread_t *p_intf )
724
{
725
    vlc_value_t val;
726
    POPUP_BOILERPLATE;
727

728 729 730
    if( p_input )
    {
        vlc_object_yield( p_input );
731
        varnames.push_back( "audio-es" );
732
        InputAutoMenuBuilder( VLC_OBJECT( p_input ), objects, varnames );
733 734 735
        PUSH_SEPARATOR;
    }

736 737
    QMenu *menu = new QMenu();
    Populate( p_intf, menu, varnames, objects );
738

739
    menu->addSeparator();
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
740
    PopupMenuControlEntries( menu, p_intf, p_input );
741 742

    menu->addSeparator();
743
    PopupMenuStaticEntries( p_intf, menu );
744

745 746
    p_intf->p_sys->p_popup_menu = menu;
    menu->popup( QCursor::pos() );
747 748 749
    p_intf->p_sys->p_popup_menu = NULL;
}

750
/* Main Menu that sticks everything together  */
Damien Fouilleul's avatar
Damien Fouilleul committed
751
void QVLCMenu::PopupMenu( intf_thread_t *p_intf, bool show )
752
{
Damien Fouilleul's avatar
Damien Fouilleul committed
753
    if( show )
754
    {
Jean-Philippe Andre's avatar
Jean-Philippe Andre committed
755 756 757 758 759 760 761 762 763 764 765 766 767 768
        /* Delete and recreate a popup if there is one */
        if( p_intf->p_sys->p_popup_menu )
            delete p_intf->p_sys->p_popup_menu;

        QMenu *menu = new QMenu();
        QMenu *submenu;
        QAction *action;

        POPUP_BOILERPLATE;

        PopupMenuControlEntries( menu, p_intf, p_input );
        menu->addSeparator();

        if( p_input )
769
        {
Jean-Philippe Andre's avatar
Jean-Philippe Andre committed
770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799
            vlc_object_yield( p_input );
            InputAutoMenuBuilder( VLC_OBJECT( p_input ), objects, varnames );

            /* Audio menu */
            vlc_object_t *p_aout = ( vlc_object_t * )
                vlc_object_find( p_input, VLC_OBJECT_AOUT, FIND_ANYWHERE );
            AudioAutoMenuBuilder( p_aout, p_input, objects, varnames );
            if( p_aout )
                vlc_object_release( p_aout );
            submenu = Populate( p_intf, NULL, varnames, objects );
            varnames.clear(); objects.clear();
            action = menu->addMenu( submenu );
            action->setText( qtr( "Audio" ) );
            if( submenu->isEmpty() )
                action->setEnabled( false );

            /* Video menu */
            vlc_object_t *p_vout = ( vlc_object_t * )
                vlc_object_find( p_input, VLC_OBJECT_VOUT, FIND_CHILD );
            VideoAutoMenuBuilder( p_vout, p_input, objects, varnames );
            if( p_vout )
                vlc_object_release( p_vout );
            submenu = Populate( p_intf, NULL, varnames, objects );
            varnames.clear(); objects.clear();
            action = menu->addMenu( submenu );
            action->setText( qtr( "Video" ) );
            if( submenu->isEmpty() )
                action->setEnabled( false );

            vlc_object_release( p_input );
800
        }
Jean-Philippe Andre's avatar
Jean-Philippe Andre committed
801 802 803 804 805

        menu->addSeparator();
        PopupMenuStaticEntries( p_intf, menu );

        p_intf->p_sys->p_popup_menu = menu;
806
        p_intf->p_sys->p_popup_menu->popup( QCursor::pos() );
Damien Fouilleul's avatar
Damien Fouilleul committed
807 808
    }
    else
809
    {
810 811 812
        // destroy popup if there is one
        delete p_intf->p_sys->p_popup_menu;
        p_intf->p_sys->p_popup_menu = NULL;
813 814 815
    }
}

816 817 818 819
/************************************************************************
 * Systray Menu                                                         *
 ************************************************************************/

820 821 822
void QVLCMenu::updateSystrayMenu( MainInterface *mi,
                                  intf_thread_t *p_intf,
                                  bool b_force_visible )
823 824
{
    POPUP_BOILERPLATE;
825 826

    /* Get the systray menu and clean it */
827 828
    QMenu *sysMenu = mi->getSysTrayMenu();
    sysMenu->clear();
829 830

    /* Hide / Show VLC and cone */
831
    if( mi->isVisible() || b_force_visible )
832
    {
833
        sysMenu->addAction( QIcon( ":/vlc16.png" ),
834
                qtr( "Hide VLC media player in taskbar" ), mi,
835
                SLOT( toggleUpdateSystrayMenu() ) );
836 837 838
    }
    else
    {
839
        sysMenu->addAction( QIcon( ":/vlc16.png" ),
840
                qtr( "Show VLC media player" ), mi,
841
                SLOT( toggleUpdateSystrayMenu() ) );
842
    }
843

844
    sysMenu->addSeparator();
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
845
    PopupMenuControlEntries( sysMenu, p_intf, p_input );
846

847
    sysMenu->addSeparator();
848 849 850 851
    addDPStaticEntry( sysMenu, qtr( "&Open Media" ), "",
            ":/pixmaps/file-wide_16px.png", SLOT( openFileDialog() ), "" );
    addDPStaticEntry( sysMenu, qtr( "&Quit" ) , "",
        ":/pixmaps/menus_quit_16px.png", SLOT( quit() ), "" );
852

853
    /* Set the menu */
854 855 856
    mi->getSysTray()->setContextMenu( sysMenu );
}

857 858
#undef PUSH_VAR
#undef PUSH_SEPARATOR
859

860 861 862
/*************************************************************************
 * Builders for automenus
 *************************************************************************/
863 864 865
QMenu * QVLCMenu::Populate( intf_thread_t *p_intf,
                            QMenu *current,
                            vector< const char *> & varnames,
866
                            vector<int> & objects,
867
                            bool append )
868 869 870 871
{
    QMenu *menu = current;
    if( !menu )
        menu = new QMenu();
872

873
    /* Disable all non static entries */
874
    QAction *p_action;
875
    foreach( p_action, menu->actions() )
876
    {
877 878
        if( p_action->data().toString() != "_static_" )
            p_action->setEnabled( false );
879
    }
880 881 882 883 884 885

    currentGroup = NULL;

    vlc_object_t *p_object;
    int i;

886
    for( i = 0; i < ( int )objects.size() ; i++ )
887
    {
888
        if( !varnames[i] || !*varnames[i] )