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