menus.cpp 25.9 KB
Newer Older
zorglub's avatar
zorglub committed
1 2 3
/*****************************************************************************
 * menus.cpp : Qt menus
 *****************************************************************************
4 5
 * Copyright (C) 2006 the VideoLAN team
 * $Id$
zorglub's avatar
zorglub committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * Authors: Clment Stenac <zorglub@videolan.org>
 *
 * 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
 * (at your option) any later version.
 *
 * 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.
 *****************************************************************************/

#include "menus.hpp"
#include "dialogs_provider.hpp"
26
#include "input_manager.hpp"
zorglub's avatar
zorglub committed
27
#include <QMenu>
28
#include <QMenuBar>
zorglub's avatar
zorglub committed
29 30 31 32 33 34 35 36 37 38 39 40
#include <QAction>
#include <QActionGroup>
#include <QSignalMapper>

enum
{
    ITEM_NORMAL,
    ITEM_CHECK,
    ITEM_RADIO
};

static QActionGroup *currentGroup;
zorglub's avatar
Qt4:  
zorglub committed
41
static char ** pp_sds;
zorglub's avatar
zorglub committed
42

43 44 45
// Add static entries to menus
#define DP_SADD( text, help, icon, slot ) { if( strlen(icon) > 0 ) { QAction *action = menu->addAction( text, THEDP, SLOT( slot ) ); action->setIcon(QIcon(icon));} else { menu->addAction( text, THEDP, SLOT( slot ) ); } }
#define MIM_SADD( text, help, icon, slot ) { if( strlen(icon) > 0 ) { QAction *action = menu->addAction( text, THEMIM, SLOT( slot ) ); action->setIcon(QIcon(icon));} else { menu->addAction( text, THEMIM, SLOT( slot ) ); } }
zorglub's avatar
Qt4:  
zorglub committed
46
#define PL_SADD
zorglub's avatar
zorglub committed
47 48

/*****************************************************************************
49
 * Definitions of variables for the dynamic menus
zorglub's avatar
zorglub committed
50
 *****************************************************************************/
51 52 53 54 55 56
#define PUSH_VAR( var ) varnames.push_back( var ); \
                        objects.push_back( p_object->i_object_id )

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

static int InputAutoMenuBuilder( vlc_object_t *p_object,
59 60
                                 vector<int> &objects,
                                 vector<const char *> &varnames )
zorglub's avatar
zorglub committed
61 62 63 64 65 66 67 68 69 70
{
    PUSH_VAR( "bookmark");
    PUSH_VAR( "title" );
    PUSH_VAR ("chapter" );
    PUSH_VAR( "program" );
    PUSH_VAR( "navigation" );
    PUSH_VAR( "dvd_menus" );
    return VLC_SUCCESS;
}

zorglub's avatar
Qt4:  
zorglub committed
71
static int VideoAutoMenuBuilder( vlc_object_t *p_object,
72 73
                                 vector<int> &objects,
                                 vector<const char *> &varnames )
zorglub's avatar
zorglub committed
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
{
    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" );

    vlc_object_t *p_dec_obj = (vlc_object_t *)vlc_object_find( p_object,
                                                 VLC_OBJECT_DECODER,
                                                 FIND_PARENT );
    if( p_dec_obj != NULL )
    {
        PUSH_VAR( "ffmpeg-pp-q" );
        vlc_object_release( p_dec_obj );
    }
    return VLC_SUCCESS;
}

static int AudioAutoMenuBuilder( vlc_object_t *p_object,
96 97
                                 vector<int> &objects,
                                 vector<const char *> &varnames )
zorglub's avatar
zorglub committed
98 99 100 101 102 103 104 105
{
    PUSH_VAR( "audio-device" );
    PUSH_VAR( "audio-channels" );
    PUSH_VAR( "visual" );
    PUSH_VAR( "equalizer" );
    return VLC_SUCCESS;
}

106 107 108 109 110 111 112 113 114 115 116 117 118 119
/*****************************************************************************
 * All normal menus
 *****************************************************************************/

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

#define BAR_DADD( func, title, id ) { \
    QMenu *menu = func; menu->setTitle( title  ); bar->addMenu( menu ); \
    MenuFunc *f = new MenuFunc( menu, id ); \
    connect( menu, SIGNAL( aboutToShow() ), \
            THEDP->menusUpdateMapper, SLOT(map()) ); \
    THEDP->menusUpdateMapper->setMapping( menu, f ); }

zorglub's avatar
Qt4:  
zorglub committed
120 121
void QVLCMenu::createMenuBar( QMenuBar *bar, intf_thread_t *p_intf )
{
zorglub's avatar
zorglub committed
122 123 124 125 126
    BAR_ADD( FileMenu(), qtr("File") );
    BAR_ADD( ToolsMenu( p_intf ), qtr("Tools") );
    BAR_DADD( VideoMenu( p_intf, NULL ), qtr("Video"), 1 );
    BAR_DADD( AudioMenu( p_intf, NULL ), qtr("Audio"), 2 );
    BAR_DADD( NavigMenu( p_intf, NULL ), qtr("Navigation"), 3 );
127

zorglub's avatar
zorglub committed
128
    //    BAR_ADD( HelpMenu(), qtr("Help" ) );
129 130
}

zorglub's avatar
Qt4:  
zorglub committed
131 132 133
void QVLCMenu::createPlMenuBar( QMenuBar *bar, intf_thread_t *p_intf )
{
    QMenu *manageMenu = new QMenu();
zorglub's avatar
zorglub committed
134
    manageMenu->setTitle( qtr("Operations") );
zorglub's avatar
zorglub committed
135 136 137 138 139 140 141 142 143 144 145 146 147 148

    QMenu *subPlaylist = new QMenu();
    subPlaylist->setTitle( qtr("Add to current playlist") );
    subPlaylist->addAction( "&File...", THEDP,
                           SLOT( simplePLAppendDialog() ) );
    subPlaylist->addAction( "&Advanced add...", THEDP,
                           SLOT( PLAppendDialog() ) );
    manageMenu->addMenu( subPlaylist );
    manageMenu->addSeparator();

    QMenu *subML = new QMenu();
    subML->setTitle( qtr("Add to Media library") );
    subML->addAction( "&File...", THEDP,
                           SLOT( simpleMLAppendDialog() ) );
zorglub's avatar
zorglub committed
149
    subML->addAction( "Directory", THEDP, SLOT( openMLDirectory() ));
zorglub's avatar
zorglub committed
150 151 152
    subML->addAction( "&Advanced add...", THEDP,
                           SLOT( MLAppendDialog() ) );
    manageMenu->addMenu( subML );
zorglub's avatar
zorglub committed
153
    manageMenu->addAction( "Open playlist file", THEDP, SLOT( openPlaylist() ));
zorglub's avatar
Qt4:  
zorglub committed
154
    manageMenu->addSeparator();
zorglub's avatar
zorglub committed
155

zorglub's avatar
zorglub committed
156
//    manageMenu->addMenu( SDMenu( p_intf ) );
zorglub's avatar
zorglub committed
157 158

    bar->addMenu( manageMenu );
zorglub's avatar
Qt4:  
zorglub committed
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
}

QMenu *QVLCMenu::SDMenu( intf_thread_t *p_intf )
{
    QMenu *menu = new QMenu();
    menu->setTitle( qtr( "Services Discovery" ) );
    playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_intf,
                                            VLC_OBJECT_PLAYLIST,
                                            FIND_ANYWHERE );
    assert( p_playlist );
    vlc_list_t *p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE,
                                        FIND_ANYWHERE );
    int i_num = 0;
    for( int i_index = 0 ; i_index < p_list->i_count; i_index++ )
    {
        module_t * p_parser = (module_t *)p_list->p_values[i_index].p_object ;
        if( !strcmp( p_parser->psz_capability, "services_discovery" ) )
            i_num++;
    }
    if( i_num )  pp_sds = (char **)calloc( i_num, sizeof(void *) );
    for( int i_index = 0 ; i_index < p_list->i_count; i_index++ )
    {
        module_t * p_parser = (module_t *)p_list->p_values[i_index].p_object;
        if( !strcmp( p_parser->psz_capability, "services_discovery" ) )
        {
            QAction *a = menu->addAction(
                            qfu( p_parser->psz_longname ?
                                   p_parser->psz_longname :
                                   ( p_parser->psz_shortname ?
                                       p_parser->psz_shortname :
                                       p_parser->psz_object_name ) ) );
            a->setCheckable( true );
            /* hack to handle submodules properly */
            int i = -1;
            while( p_parser->pp_shortcuts[++i] != NULL );
            i--;
            if( playlist_IsServicesDiscoveryLoaded( p_playlist,
                 i>=0?p_parser->pp_shortcuts[i] : p_parser->psz_object_name ) )
            {
                a->setChecked( true );
            }
            pp_sds[i_num++] = i>=0? p_parser->pp_shortcuts[i] :
                                    p_parser->psz_object_name;
        }
    }
    vlc_list_release( p_list );
    vlc_object_release( p_playlist );
    return menu;
}

209 210 211
QMenu *QVLCMenu::FileMenu()
{
    QMenu *menu = new QMenu();
zorglub's avatar
zorglub committed
212 213
    DP_SADD( qtr("Quick &Open File...") , "", "", simpleOpenDialog() );
    DP_SADD( qtr("&Advanced Open..." ), "", "", openDialog() );
214
    menu->addSeparator();
zorglub's avatar
zorglub committed
215
    DP_SADD( qtr("Streaming..."), "", "", streamingDialog() );
216
    menu->addSeparator();
zorglub's avatar
zorglub committed
217
    DP_SADD( qtr("&Quit") , "", "", quit() );
218 219 220 221 222 223 224 225 226
    return menu;
}

QMenu *QVLCMenu::ToolsMenu( intf_thread_t *p_intf, bool with_intf )
{
    QMenu *menu = new QMenu();
    if( with_intf )
    {
        QMenu *intfmenu = InterfacesMenu( p_intf, NULL );
zorglub's avatar
zorglub committed
227
        intfmenu->setTitle( qtr("Interfaces" ) );
228 229 230 231
        menu->addMenu( intfmenu );
        /** \todo ADD EXT GUI HERE */
        menu->addSeparator();
    }
zorglub's avatar
zorglub committed
232 233 234
    DP_SADD( qtr("Messages" ), "", "", messagesDialog() );
    DP_SADD( qtr("Information") , "", "", streaminfoDialog() );
    DP_SADD( qtr("Bookmarks"), "", "", bookmarksDialog() );
235
    menu->addSeparator();
zorglub's avatar
zorglub committed
236
    DP_SADD( qtr("Preferences"), "", "", prefsDialog() );
237 238 239 240 241 242 243 244 245 246
    return menu;
}

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
247

248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
    QMenu *menu = Populate( p_intf, current, varnames, objects );
    connect( menu, SIGNAL( aboutToShow() ),
             THEDP->menusUpdateMapper, SLOT(map()) );
    THEDP->menusUpdateMapper->setMapping( menu, 4 );

    return menu;
}

QMenu *QVLCMenu::AudioMenu( intf_thread_t *p_intf, QMenu * current )
{
    vector<int> objects;
    vector<const char *> varnames;

    vlc_object_t *p_object = (vlc_object_t *)vlc_object_find( p_intf,
                                        VLC_OBJECT_INPUT, FIND_ANYWHERE );
    if( p_object != NULL )
    {
        PUSH_VAR( "audio-es" );
        vlc_object_release( p_object );
    }

    p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_AOUT,
                                                FIND_ANYWHERE );
    if( p_object )
    {
        AudioAutoMenuBuilder( p_object, objects, varnames );
        vlc_object_release( p_object );
    }
    return Populate( p_intf, current, varnames, objects );
}


QMenu *QVLCMenu::VideoMenu( intf_thread_t *p_intf, QMenu *current )
zorglub's avatar
zorglub committed
281 282
{
    vlc_object_t *p_object;
283 284 285 286 287
    vector<int> objects;
    vector<const char *> varnames;

    p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
                                                FIND_ANYWHERE );
zorglub's avatar
zorglub committed
288 289
    if( p_object != NULL )
    {
290 291
        PUSH_VAR( "video-es" );
        PUSH_VAR( "spu-es" );
zorglub's avatar
zorglub committed
292 293
        vlc_object_release( p_object );
    }
294 295 296 297 298 299 300 301 302

    p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_VOUT,
                                                FIND_ANYWHERE );
    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
303 304
}

305 306 307 308 309
QMenu *QVLCMenu::NavigMenu( intf_thread_t *p_intf, QMenu *current )
{
    vlc_object_t *p_object;
    vector<int> objects;
    vector<const char *> varnames;
zorglub's avatar
zorglub committed
310

311 312 313 314 315 316 317 318 319 320 321 322
    /* FIXME */
    p_object = (vlc_object_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
                                                FIND_ANYWHERE );
    if( p_object != NULL )
    {
        InputAutoMenuBuilder( p_object, objects, varnames );
        PUSH_VAR( "prev-title"); PUSH_VAR ( "next-title" );
        PUSH_VAR( "prev-chapter"); PUSH_VAR( "next-chapter" );
        vlc_object_release( p_object );
    }
    return Populate( p_intf, current, varnames, objects );
}
zorglub's avatar
zorglub committed
323 324


325 326 327
/*****************************************************************************
 * Popup menus
 *****************************************************************************/
zorglub's avatar
zorglub committed
328 329
#define POPUP_BOILERPLATE \
    unsigned int i_last_separator = 0; \
330 331 332 333 334 335 336 337 338
    vector<int> objects; \
    vector<const char *> varnames; \
    input_thread_t *p_input = THEMIM->getInput();

#define CREATE_POPUP \
    QMenu *menu = new QMenu(); \
    Populate( p_intf, menu, varnames, objects ); \
    p_intf->p_sys->p_popup_menu = menu; \
    menu->popup( QCursor::pos() ); \
zorglub's avatar
zorglub committed
339
    p_intf->p_sys->p_popup_menu = NULL; \
340
    i_last_separator = 0;
zorglub's avatar
zorglub committed
341 342

#define POPUP_STATIC_ENTRIES \
343
    vlc_value_t val; \
zorglub's avatar
zorglub committed
344 345 346
    MIM_SADD( qtr("Stop"), "", "", stop() ); \
    MIM_SADD( qtr("Previous"), "", "", prev() ); \
    MIM_SADD( qtr("Next"), "", "", next() ); \
347
    if( p_input ) \
zorglub's avatar
zorglub committed
348 349 350
    { \
        var_Get( p_input, "state", &val ); \
        if( val.i_int == PAUSE_S ) \
zorglub's avatar
zorglub committed
351
            MIM_SADD( qtr("Play"), "", "", togglePlayPause() ) \
zorglub's avatar
zorglub committed
352
        else \
zorglub's avatar
zorglub committed
353
            MIM_SADD( qtr("Pause"), "", "", togglePlayPause() ) \
zorglub's avatar
zorglub committed
354
    } \
355
    else if( THEPL->i_size && THEPL->i_enabled ) \
zorglub's avatar
zorglub committed
356
        MIM_SADD( qtr("Play"), "", "", togglePlayPause() ) \
zorglub's avatar
zorglub committed
357
    \
358
    QMenu *intfmenu = InterfacesMenu( p_intf, NULL ); \
zorglub's avatar
zorglub committed
359
    intfmenu->setTitle( qtr("Interfaces" ) ); \
360 361 362
    menu->addMenu( intfmenu ); \
    \
    QMenu *toolsmenu = ToolsMenu( p_intf, false ); \
zorglub's avatar
zorglub committed
363
    toolsmenu->setTitle( qtr("Tools" ) ); \
364
    menu->addMenu( toolsmenu ); \
zorglub's avatar
Qt4:  
zorglub committed
365

366
void QVLCMenu::VideoPopupMenu( intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
367 368 369 370 371
{
    POPUP_BOILERPLATE;
    if( p_input )
    {
        vlc_object_yield( p_input );
372 373 374 375
        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 );
zorglub's avatar
zorglub committed
376 377 378 379
        vlc_object_t *p_vout = (vlc_object_t *)vlc_object_find( p_input,
                                                VLC_OBJECT_VOUT, FIND_CHILD );
        if( p_vout )
        {
380
            VideoAutoMenuBuilder( p_vout, objects, varnames );
zorglub's avatar
zorglub committed
381 382 383 384
            vlc_object_release( p_vout );
        }
        vlc_object_release( p_input );
    }
385
    CREATE_POPUP;
zorglub's avatar
zorglub committed
386 387
}

388
void QVLCMenu::AudioPopupMenu( intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
389 390 391 392 393
{
    POPUP_BOILERPLATE;
    if( p_input )
    {
        vlc_object_yield( p_input );
394 395
        varnames.push_back( "audio-es" );
        objects.push_back( p_input->i_object_id );
zorglub's avatar
zorglub committed
396 397 398 399
        vlc_object_t *p_aout = (vlc_object_t *)vlc_object_find( p_input,
                                             VLC_OBJECT_AOUT, FIND_ANYWHERE );
        if( p_aout )
        {
400
            AudioAutoMenuBuilder( p_aout, objects, varnames );
zorglub's avatar
zorglub committed
401 402 403 404
            vlc_object_release( p_aout );
        }
        vlc_object_release( p_input );
    }
405
    CREATE_POPUP;
zorglub's avatar
zorglub committed
406 407 408
}

/* Navigation stuff, and general */
409
void QVLCMenu::MiscPopupMenu( intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
410 411 412 413 414
{
    POPUP_BOILERPLATE;
    if( p_input )
    {
        vlc_object_yield( p_input );
415 416
        varnames.push_back( "audio-es" );
        InputAutoMenuBuilder( VLC_OBJECT(p_input), objects, varnames );
zorglub's avatar
zorglub committed
417 418 419
        PUSH_SEPARATOR;
    }

420 421 422
    QMenu *menu = new QMenu();
    Populate( p_intf, menu, varnames, objects );
    menu->addSeparator();
zorglub's avatar
zorglub committed
423 424
    POPUP_STATIC_ENTRIES;

425 426
    p_intf->p_sys->p_popup_menu = menu;
    menu->popup( QCursor::pos() );
zorglub's avatar
zorglub committed
427 428 429
    p_intf->p_sys->p_popup_menu = NULL;
}

430
void QVLCMenu::PopupMenu( intf_thread_t *p_intf )
zorglub's avatar
zorglub committed
431 432 433 434 435
{
    POPUP_BOILERPLATE;
    if( p_input )
    {
        vlc_object_yield( p_input );
436
        InputAutoMenuBuilder( VLC_OBJECT(p_input), objects, varnames );
zorglub's avatar
zorglub committed
437 438 439

        /* Video menu */
        PUSH_SEPARATOR;
440 441 442 443
        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 );
zorglub's avatar
zorglub committed
444 445 446 447
        vlc_object_t *p_vout = (vlc_object_t *)vlc_object_find( p_input,
                                                VLC_OBJECT_VOUT, FIND_CHILD );
        if( p_vout )
        {
448
            VideoAutoMenuBuilder( p_vout, objects, varnames );
zorglub's avatar
zorglub committed
449 450 451 452
            vlc_object_release( p_vout );
        }
        /* Audio menu */
        PUSH_SEPARATOR
453 454
        varnames.push_back( "audio-es" );
        objects.push_back( p_input->i_object_id );
zorglub's avatar
zorglub committed
455 456 457 458
        vlc_object_t *p_aout = (vlc_object_t *)vlc_object_find( p_input,
                                             VLC_OBJECT_AOUT, FIND_ANYWHERE );
        if( p_aout )
        {
459
            AudioAutoMenuBuilder( p_aout, objects, varnames );
zorglub's avatar
zorglub committed
460 461 462 463
            vlc_object_release( p_aout );
        }
    }

464 465 466
    QMenu *menu = new QMenu();
    Populate( p_intf, menu, varnames, objects );
    menu->addSeparator();
zorglub's avatar
zorglub committed
467 468
    POPUP_STATIC_ENTRIES;

469 470
    p_intf->p_sys->p_popup_menu = menu;
    menu->popup( QCursor::pos() );
zorglub's avatar
zorglub committed
471 472 473
    p_intf->p_sys->p_popup_menu = NULL;
}

474 475
#undef PUSH_VAR
#undef PUSH_SEPARATOR
zorglub's avatar
zorglub committed
476

477 478 479
/*************************************************************************
 * Builders for automenus
 *************************************************************************/
zorglub's avatar
zorglub committed
480
QMenu * QVLCMenu::Populate( intf_thread_t *p_intf, QMenu *current,
481 482
                            vector< const char *> & varnames,
                            vector<int> & objects, bool append )
zorglub's avatar
zorglub committed
483 484 485 486
{
    QMenu *menu = current;
    if( !menu )
        menu = new QMenu();
487
    else if( !append )
zorglub's avatar
zorglub committed
488 489 490 491 492 493 494 495
        menu->clear();

    currentGroup = NULL;

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

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

499
    for( i = 0; i < (int)objects.size() ; i++ )
zorglub's avatar
zorglub committed
500
    {
501
        if( !varnames[i] || !*varnames[i] )
zorglub's avatar
zorglub committed
502 503 504 505 506 507 508 509
        {
            if( b_section_empty )
                APPEND_EMPTY;
            menu->addSeparator();
            b_section_empty = VLC_TRUE;
            continue;
        }

510
        if( objects[i] == 0  )
zorglub's avatar
zorglub committed
511 512
        {
            /// \bug What is this ?
513
            // Append( menu, varnames[i], NULL );
zorglub's avatar
zorglub committed
514 515 516 517 518
            b_section_empty = VLC_FALSE;
            continue;
        }

        p_object = (vlc_object_t *)vlc_object_get( p_intf,
519
                                                   objects[i] );
zorglub's avatar
zorglub committed
520 521 522
        if( p_object == NULL ) continue;

        b_section_empty = VLC_FALSE;
523 524 525 526 527
        /* Ugly specific stuff */
        if( strstr(varnames[i], "intf-add" ) )
            CreateItem( menu, varnames[i], p_object, false );
        else
            CreateItem( menu, varnames[i], p_object, true );
zorglub's avatar
zorglub committed
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
        vlc_object_release( p_object );
    }

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

    return menu;
}

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

static bool IsMenuEmpty( const char *psz_var, vlc_object_t *p_object,
                         bool b_root = TRUE )
{
    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 */
    if( !(i_type & VLC_VAR_HASCHOICE) ) return FALSE;

    var_Change( p_object, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
    if( val.i_int == 0 ) return TRUE;

    if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE )
    {
zorglub's avatar
zorglub committed
559
        /* Very evil hack ! intf-switch can have only one value */
zorglub's avatar
zorglub committed
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
        if( !strcmp( psz_var, "intf-switch" ) ) return FALSE;
        if( val.i_int == 1 && b_root ) return TRUE;
        else return FALSE;
    }

    /* Check children variables in case of VLC_VAR_VARIABLE */
    if( var_Change( p_object, psz_var, VLC_VAR_GETLIST, &val_list, NULL ) < 0 )
    {
        return TRUE;
    }

    for( i = 0, i_result = TRUE; i < val_list.p_list->i_count; i++ )
    {
        if( !IsMenuEmpty( val_list.p_list->p_values[i].psz_string,
                          p_object, FALSE ) )
        {
            i_result = FALSE;
            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,
588
                           vlc_object_t *p_object, bool b_submenu )
zorglub's avatar
zorglub committed
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618
{
    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 )
    {
    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;
    }

    /* 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 */
619 620 621
        if( b_submenu )
        {
            QMenu *submenu = new QMenu();
zorglub's avatar
Qt4:  
zorglub committed
622
            submenu->setTitle( qfu( text.psz_string ?
zorglub's avatar
zorglub committed
623
                                    text.psz_string : psz_var ) );
624 625 626 627 628
            if( CreateChoicesMenu( submenu, psz_var, p_object, true ) == 0)
                menu->addMenu( submenu );
        }
        else
            CreateChoicesMenu( menu, psz_var, p_object, true );
629
        FREENULL( text.psz_string );
zorglub's avatar
zorglub committed
630 631 632
        return;
    }

633
#define TEXT_OR_VAR qfu ( text.psz_string ? text.psz_string : psz_var )
zorglub's avatar
zorglub committed
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648

    switch( i_type & VLC_VAR_TYPE )
    {
    case VLC_VAR_VOID:
        var_Get( p_object, psz_var, &val );
        CreateAndConnect( menu, psz_var, TEXT_OR_VAR, "", ITEM_NORMAL,
                          p_object->i_object_id, val, i_type );
        break;

    case VLC_VAR_BOOL:
        var_Get( p_object, psz_var, &val );
        CreateAndConnect( menu, psz_var, TEXT_OR_VAR, "", ITEM_CHECK,
                          p_object->i_object_id, val, i_type, val.b_bool );
        break;
    }
649
    FREENULL( text.psz_string );
zorglub's avatar
zorglub committed
650 651 652
}


zorglub's avatar
zorglub committed
653
int QVLCMenu::CreateChoicesMenu( QMenu *submenu, const char *psz_var,
654
                                 vlc_object_t *p_object, bool b_root )
zorglub's avatar
zorglub committed
655 656 657 658 659 660 661 662
{
    vlc_value_t val, val_list, text_list;
    int i_type, i;

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

    /* Make sure we want to display the variable */
663
    if( IsMenuEmpty( psz_var, p_object, b_root ) ) return VLC_EGENERIC;
zorglub's avatar
zorglub committed
664 665 666 667 668 669 670 671 672 673 674 675

    switch( i_type & VLC_VAR_TYPE )
    {
    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 */
676
        return VLC_EGENERIC;
zorglub's avatar
zorglub committed
677 678 679 680 681
    }

    if( var_Change( p_object, psz_var, VLC_VAR_GETLIST,
                    &val_list, &text_list ) < 0 )
    {
682
        return VLC_EGENERIC;
zorglub's avatar
zorglub committed
683 684
    }
#define NORMAL_OR_RADIO i_type & VLC_VAR_ISCOMMAND ? ITEM_NORMAL: ITEM_RADIO
zorglub's avatar
Qt4:  
zorglub committed
685
#define NOTCOMMAND !(i_type & VLC_VAR_ISCOMMAND)
zorglub's avatar
zorglub committed
686 687 688 689 690 691 692
#define CURVAL val_list.p_list->p_values[i]
#define CURTEXT text_list.p_list->p_values[i].psz_string

    for( i = 0; i < val_list.p_list->i_count; i++ )
    {
        vlc_value_t another_val;
        QString menutext;
693
        QMenu *subsubmenu = new QMenu();
zorglub's avatar
zorglub committed
694 695 696 697

        switch( i_type & VLC_VAR_TYPE )
        {
        case VLC_VAR_VARIABLE:
698
            CreateChoicesMenu( subsubmenu, CURVAL.psz_string, p_object, false );
699
            subsubmenu->setTitle( qfu( CURTEXT ? CURTEXT :CURVAL.psz_string ) );
zorglub's avatar
zorglub committed
700 701 702 703 704 705
            submenu->addMenu( subsubmenu );
            break;

        case VLC_VAR_STRING:
          var_Get( p_object, psz_var, &val );
          another_val.psz_string = strdup( CURVAL.psz_string );
706
          menutext = qfu( CURTEXT ? CURTEXT : another_val.psz_string );
zorglub's avatar
zorglub committed
707
          CreateAndConnect( submenu, psz_var, menutext, "", NORMAL_OR_RADIO,
zorglub's avatar
Qt4:  
zorglub committed
708
                            p_object->i_object_id, another_val, i_type,
zorglub's avatar
zorglub committed
709 710 711 712 713 714 715 716
                            NOTCOMMAND && val.psz_string &&
                            !strcmp( val.psz_string, CURVAL.psz_string ) );

          if( val.psz_string ) free( val.psz_string );
          break;

        case VLC_VAR_INTEGER:
          var_Get( p_object, psz_var, &val );
717
          if( CURTEXT ) menutext = qfu( CURTEXT );
zorglub's avatar
zorglub committed
718 719 720 721 722 723 724 725
          else menutext.sprintf( "%d", CURVAL.i_int);
          CreateAndConnect( submenu, psz_var, menutext, "", NORMAL_OR_RADIO,
                            p_object->i_object_id, CURVAL, i_type,
                            NOTCOMMAND && CURVAL.i_int == val.i_int );
          break;

        case VLC_VAR_FLOAT:
          var_Get( p_object, psz_var, &val );
726
          if( CURTEXT ) menutext = qfu( CURTEXT );
zorglub's avatar
zorglub committed
727 728 729 730 731 732 733 734 735 736
          else menutext.sprintf( "%.2f", CURVAL.f_float );
          CreateAndConnect( submenu, psz_var, menutext, "", NORMAL_OR_RADIO,
                            p_object->i_object_id, CURVAL, i_type,
                            NOTCOMMAND && CURVAL.f_float == val.f_float );
          break;

        default:
          break;
        }
    }
zorglub's avatar
zorglub committed
737
    currentGroup = NULL;
zorglub's avatar
zorglub committed
738 739 740 741 742 743 744 745

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

#undef NORMAL_OR_RADIO
#undef NOTCOMMAND
#undef CURVAL
#undef CURTEXT
746
    return VLC_SUCCESS;
zorglub's avatar
zorglub committed
747 748 749 750
}

void QVLCMenu::CreateAndConnect( QMenu *menu, const char *psz_var,
                                 QString text, QString help,
zorglub's avatar
Qt4:  
zorglub committed
751
                                 int i_item_type, int i_object_id,
zorglub's avatar
zorglub committed
752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770
                                 vlc_value_t val, int i_val_type,
                                 bool checked )
{
    QAction *action = new QAction( text, menu );
    action->setText( text );
    action->setToolTip( help );

    if( i_item_type == ITEM_CHECK )
    {
        action->setCheckable( true );
    }
    else if( i_item_type == ITEM_RADIO )
    {
        action->setCheckable( true );
        if( !currentGroup )
            currentGroup = new QActionGroup(menu);
        currentGroup->addAction( action );
    }

zorglub's avatar
zorglub committed
771 772 773 774
    if( checked )
    {
        action->setChecked( true );
    }
zorglub's avatar
zorglub committed
775 776
    MenuItemData *itemData = new MenuItemData( i_object_id, i_val_type,
                                               val, psz_var );
zorglub's avatar
zorglub committed
777
    connect( action, SIGNAL(triggered()), THEDP->menusMapper, SLOT(map()) );
zorglub's avatar
zorglub committed
778 779 780 781 782 783 784 785 786 787 788 789 790 791
    THEDP->menusMapper->setMapping( action, itemData );
    menu->addAction( action );
}

void QVLCMenu::DoAction( intf_thread_t *p_intf, QObject *data )
{
    MenuItemData *itemData = qobject_cast<MenuItemData *>(data);
    vlc_object_t *p_object = (vlc_object_t *)vlc_object_get( p_intf,
                                           itemData->i_object_id );
    if( p_object == NULL ) return;

    var_Set( p_object, itemData->psz_var, itemData->val );
    vlc_object_release( p_object );
}