/*
* Cantata
*
* Copyright (c) 2011-2014 Craig Drummond
*
*/
/*
* Copyright (c) 2008 Sander Knopper (sander AT knopper DOT tk) and
* Roeland Douma (roeland AT rullzer DOT com)
*
* This file is part of QtMPC.
*
* QtMPC 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.
*
* QtMPC 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 QtMPC. If not, see .
*/
#include "mainwindow.h"
#include "support/localize.h"
#include "plurals.h"
#include "support/thread.h"
#include "trayitem.h"
#include "support/messagebox.h"
#include "support/inputdialog.h"
#include "models/playlistsmodel.h"
#include "covers.h"
#include "coverdialog.h"
#include "currentcover.h"
#include "preferencesdialog.h"
#include "mpd/mpdconnection.h"
#include "mpd/mpdstats.h"
#include "mpd/mpdstatus.h"
#include "mpd/mpdparseutils.h"
#include "settings.h"
#include "support/utils.h"
#include "support/touchproxystyle.h"
#include "models/musiclibrarymodel.h"
#include "models/musiclibraryitemartist.h"
#include "models/musiclibraryitemalbum.h"
#include "librarypage.h"
#include "albumspage.h"
#include "folderpage.h"
#ifdef ENABLE_STREAMS
#include "streams/streamspage.h"
#include "streams/streamdialog.h"
#endif
#include "searchpage.h"
#include "support/gtkstyle.h"
#ifdef ENABLE_DEVICES_SUPPORT
#include "devices/filejob.h"
#include "devices/devicespage.h"
#include "models/devicesmodel.h"
#include "devices/actiondialog.h"
#include "devices/syncdialog.h"
#if defined CDDB_FOUND || defined MUSICBRAINZ5_FOUND
#include "devices/audiocddevice.h"
#endif
#endif
#ifdef ENABLE_ONLINE_SERVICES
#include "online/onlineservicespage.h"
#include "models/onlineservicesmodel.h"
#endif
#include "http/httpserver.h"
#ifdef TAGLIB_FOUND
#include "tags/trackorganiser.h"
#include "tags/tageditor.h"
#include "tags/tags.h"
#ifdef ENABLE_REPLAYGAIN_SUPPORT
#include "replaygain/rgdialog.h"
#endif
#endif
#include "models/streamsmodel.h"
#include "playlistspage.h"
#include "support/fancytabwidget.h"
#ifdef QT_QTDBUS_FOUND
#include "dbus/mpris.h"
#include "cantataadaptor.h"
#include "dbus/powermanagement.h"
#endif
#if !defined Q_OS_WIN && !defined Q_OS_MAC
#include "devices/mountpoints.h"
#endif
#ifdef ENABLE_DYNAMIC
#include "dynamic/dynamicpage.h"
#include "dynamic/dynamic.h"
#endif
#include "support/messagewidget.h"
#include "widgets/groupedview.h"
#include "widgets/actionitemdelegate.h"
#include "widgets/icons.h"
#include "widgets/volumeslider.h"
#include "support/action.h"
#include "support/actioncollection.h"
#include "stdactions.h"
#ifdef ENABLE_HTTP_STREAM_PLAYBACK
#include "mpd/httpstream.h"
#endif
#ifdef Q_OS_WIN
static void raiseWindow(QWidget *w);
#endif
#include
#include
#include
#include
#if defined Q_OS_MAC && QT_VERSION >= 0x050000
// QMacNativeToolBar requres Qt Mac Extras to be installed on Qt 5.0 and 5.1.
#include
#endif
#if QT_VERSION >= 0x050000
#include
#endif
#include
#include
#ifdef ENABLE_KDE_SUPPORT
#include
#include
#include
#include
#include
#include
#include
#else
#include
#include "mediakeys.h"
#endif
#include
static int nextKey(int &key)
{
int k=key;
if (Qt::Key_0==key) {
key=Qt::Key_A;
} else if (Qt::Key_Colon==++key) {
key=Qt::Key_0;
}
return k;
}
MainWindow::MainWindow(QWidget *parent)
: MAIN_WINDOW_BASE_CLASS(parent)
, prevPage(-1)
, lastState(MPDState_Inactive)
, lastSongId(-1)
, autoScrollPlayQueue(true)
, showMenuAction(0)
#ifdef ENABLE_HTTP_STREAM_PLAYBACK
, httpStream(new HttpStream(this))
#endif
, currentPage(0)
#ifdef QT_QTDBUS_FOUND
, mpris(0)
#endif
, statusTimer(0)
, playQueueSearchTimer(0)
#if !defined Q_OS_WIN && !defined Q_OS_MAC
, mpdAccessibilityTimer(0)
#endif
, contextTimer(0)
, contextSwitchTime(0)
, connectedState(CS_Init)
, stopAfterCurrent(false)
, volumeFade(0)
, origVolume(0)
, lastVolume(0)
, stopState(StopState_None)
{
QPoint p=pos();
ActionCollection::setMainWidget(this);
trayItem=new TrayItem(this);
#ifdef ENABLE_KDE_SUPPORT
bool menuIcons=true;
#else
bool menuIcons=!QCoreApplication::testAttribute(Qt::AA_DontShowIconsInMenus);
#endif
#ifdef QT_QTDBUS_FOUND
new CantataAdaptor(this);
QDBusConnection::sessionBus().registerObject("/cantata", this);
#endif
setMinimumHeight(256);
QWidget *widget = new QWidget(this);
setupUi(widget);
setCentralWidget(widget);
messageWidget->hide();
// Need to set these values here, as used in library/device loading...
MPDParseUtils::setGroupSingle(Settings::self()->groupSingle());
Song::setUseComposer(Settings::self()->useComposer());
#ifdef Q_OS_WIN
GtkStyle::applyTheme(this); // Despite its name, it *might* also apply touch style to spinboxes...
#else
#if defined Q_OS_MAC && QT_VERSION>=0x050000
QMacNativeToolBar *topToolBar = new QMacNativeToolBar(this);
topToolBar->showInWindowForWidget(this);
#else // defined Q_OS_MAC && QT_VERSION>=0x050000
setUnifiedTitleAndToolBarOnMac(true);
QToolBar *topToolBar = addToolBar("ToolBar");
#endif // defined Q_OS_MAC && QT_VERSION>=0x050000
toolbar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
topToolBar->setObjectName("MainToolBar");
topToolBar->addWidget(toolbar);
topToolBar->setMovable(false);
topToolBar->setContextMenuPolicy(Qt::PreventContextMenu);
topToolBar->ensurePolished();
GtkStyle::applyTheme(topToolBar); // Despite its name, it *might* also apply touch style to spinboxes...
toolbar=topToolBar;
#endif // Q_OS_WIN
toolbar->ensurePolished();
toolbar->adjustSize();
coverWidget->setSize(toolbar->height());
Icons::self()->initToolbarIcons(toolbar->palette().color(QPalette::Foreground));
Icons::self()->initSidebarIcons();
#ifdef ENABLE_KDE_SUPPORT
prefAction=static_cast(KStandardAction::preferences(this, SLOT(showPreferencesDialog()), ActionCollection::get()));
quitAction=static_cast(KStandardAction::quit(this, SLOT(quit()), ActionCollection::get()));
shortcutsAction=static_cast(KStandardAction::keyBindings(this, SLOT(configureShortcuts()), ActionCollection::get()));
StdActions::self()->prevTrackAction->setGlobalShortcut(KShortcut(Qt::Key_MediaPrevious));
StdActions::self()->nextTrackAction->setGlobalShortcut(KShortcut(Qt::Key_MediaNext));
StdActions::self()->playPauseTrackAction->setGlobalShortcut(KShortcut(Qt::Key_MediaPlay));
StdActions::self()->stopPlaybackAction->setGlobalShortcut(KShortcut(Qt::Key_MediaStop));
StdActions::self()->stopAfterCurrentTrackAction->setGlobalShortcut(KShortcut());
#else
setWindowIcon(Icons::self()->appIcon);
prefAction=ActionCollection::get()->createAction("configure", Utils::KDE==Utils::currentDe() ? i18n("Configure Cantata...") : i18n("Preferences"),
menuIcons ? Icons::self()->configureIcon : Icon());
connect(prefAction, SIGNAL(triggered(bool)),this, SLOT(showPreferencesDialog()));
quitAction = ActionCollection::get()->createAction("quit", i18n("Quit"), menuIcons ? "application-exit" : "");
connect(quitAction, SIGNAL(triggered(bool)), this, SLOT(quit()));
quitAction->setShortcut(QKeySequence::Quit);
Action *aboutAction=ActionCollection::get()->createAction("about", i18nc("Qt-only", "About Cantata..."), menuIcons ? Icons::self()->appIcon : Icon());
connect(aboutAction, SIGNAL(triggered(bool)),this, SLOT(showAboutDialog()));
#ifdef Q_OS_MAC
prefAction->setMenuRole(QAction::PreferencesRole);
quitAction->setMenuRole(QAction::QuitRole);
aboutAction->setMenuRole(QAction::AboutRole);
#endif
#endif // ENABLE_KDE_SUPPORT
restoreAction = ActionCollection::get()->createAction("showwindow", i18n("Show Window"));
connect(restoreAction, SIGNAL(triggered(bool)), this, SLOT(restoreWindow()));
serverInfoAction=ActionCollection::get()->createAction("mpdinfo", i18n("Server information..."), menuIcons ? "network-server" : "");
connect(serverInfoAction, SIGNAL(triggered(bool)),this, SLOT(showServerInfo()));
serverInfoAction->setEnabled(Settings::self()->firstRun());
refreshDbAction = ActionCollection::get()->createAction("refresh", i18n("Refresh Database"), menuIcons ? "view-refresh" : "");
doDbRefreshAction = new Action(refreshDbAction->icon(), i18n("Refresh"), this);
refreshDbAction->setEnabled(false);
connectAction = ActionCollection::get()->createAction("connect", i18n("Connect"), Icons::self()->connectIcon);
connectionsAction = ActionCollection::get()->createAction("connections", i18n("Collection"), menuIcons ? "network-server" : "");
outputsAction = ActionCollection::get()->createAction("outputs", i18n("Outputs"), menuIcons ? Icons::self()->speakerIcon : Icon());
stopAfterTrackAction = ActionCollection::get()->createAction("stopaftertrack", i18n("Stop After Track"), Icons::self()->toolbarStopIcon);
addPlayQueueToStoredPlaylistAction = ActionCollection::get()->createAction("addpqtostoredplaylist", i18n("Add To Stored Playlist"), Icons::self()->playlistIcon);
cropPlayQueueAction = ActionCollection::get()->createAction("cropplaylist", i18n("Crop"));
addStreamToPlayQueueAction = ActionCollection::get()->createAction("addstreamtoplayqueue", i18n("Add Stream URL"), menuIcons ? Icons::self()->addRadioStreamIcon : Icon());
promptClearPlayQueueAction = ActionCollection::get()->createAction("clearplaylist", i18n("Clear"), Icons::self()->clearListIcon);
centerPlayQueueAction = ActionCollection::get()->createAction("centerplaylist", i18n("Center On Current Track"), isRightToLeft() ? "go-previous" : "go-next");
expandInterfaceAction = ActionCollection::get()->createAction("expandinterface", i18n("Expanded Interface"), menuIcons ? "view-media-playlist" : "");
expandInterfaceAction->setCheckable(true);
songInfoAction = ActionCollection::get()->createAction("showsonginfo", i18n("Show Current Song Information"), Icons::self()->infoIcon);
songInfoAction->setShortcut(Qt::Key_F12);
songInfoAction->setCheckable(true);
fullScreenAction = ActionCollection::get()->createAction("fullScreen", i18n("Full Screen"), menuIcons ? "view-fullscreen" : "");
fullScreenAction->setShortcut(Qt::Key_F11);
randomPlayQueueAction = ActionCollection::get()->createAction("randomplaylist", i18n("Random"), Icons::self()->shuffleIcon);
repeatPlayQueueAction = ActionCollection::get()->createAction("repeatplaylist", i18n("Repeat"), Icons::self()->repeatIcon);
singlePlayQueueAction = ActionCollection::get()->createAction("singleplaylist", i18n("Single"), Icons::self()->singleIcon, i18n("When 'Single' is activated, playback is stopped after current song, or song is repeated if 'Repeat' is enabled."));
consumePlayQueueAction = ActionCollection::get()->createAction("consumeplaylist", i18n("Consume"), Icons::self()->consumeIcon, i18n("When consume is activated, a song is removed from the play queue after it has been played."));
setPriorityAction = ActionCollection::get()->createAction("setprio", i18n("Set Priority"), Icon("favorites"));
#ifdef ENABLE_HTTP_STREAM_PLAYBACK
streamPlayAction = ActionCollection::get()->createAction("streamplay", i18n("Play Stream"));
streamPlayAction->setCheckable(true);
streamPlayAction->setChecked(false);
streamPlayAction->setVisible(false);
#endif
locateTrackAction = ActionCollection::get()->createAction("locatetrack", i18n("Locate In Library"), "edit-find");
#ifdef TAGLIB_FOUND
editPlayQueueTagsAction = ActionCollection::get()->createAction("editpqtags", i18n("Edit Song Tags"), "document-edit");
#endif
addAction(expandAllAction = ActionCollection::get()->createAction("expandall", i18n("Expand All")));
expandAllAction->setShortcut(Qt::ControlModifier+Qt::Key_Plus);
addAction(collapseAllAction = ActionCollection::get()->createAction("collapseall", i18n("Collapse All")));
collapseAllAction->setShortcut(Qt::ControlModifier+Qt::Key_Minus);
clearPlayQueueAction = ActionCollection::get()->createAction("confimclearplaylist", i18n("Remove All Songs"), Icons::self()->clearListIcon);
clearPlayQueueAction->setShortcut(Qt::AltModifier+Qt::Key_Return);
cancelAction = ActionCollection::get()->createAction("cancel", i18n("Cancel"), Icons::self()->cancelIcon);
cancelAction->setShortcut(Qt::AltModifier+Qt::Key_Escape);
connect(cancelAction, SIGNAL(triggered(bool)), messageWidget, SLOT(animatedHide()));
connect(clearPlayQueueAction, SIGNAL(triggered(bool)), messageWidget, SLOT(animatedHide()));
connect(clearPlayQueueAction, SIGNAL(triggered(bool)), this, SLOT(clearPlayQueue()));
clearNewStateAction = ActionCollection::get()->createAction("clearnewstate", i18n("Clear 'New' State Of Artists and Albums"));
connect(clearNewStateAction, SIGNAL(triggered(bool)), MusicLibraryModel::self(), SLOT(clearNewState()));
connect(clearNewStateAction, SIGNAL(triggered(bool)), AlbumsModel::self(), SLOT(clearNewState()));
connect(MusicLibraryModel::self(), SIGNAL(haveNewItems(bool)), clearNewStateAction, SLOT(setEnabled(bool)));
clearNewStateAction->setEnabled(false);
StdActions::self()->playPauseTrackAction->setEnabled(false);
StdActions::self()->nextTrackAction->setEnabled(false);
updateNextTrack(-1);
StdActions::self()->prevTrackAction->setEnabled(false);
enableStopActions(false);
volumeSlider->initActions();
connectionsAction->setMenu(new QMenu(this));
connectionsGroup=new QActionGroup(connectionsAction->menu());
outputsAction->setMenu(new QMenu(this));
outputsAction->setVisible(false);
addPlayQueueToStoredPlaylistAction->setMenu(PlaylistsModel::self()->menu());
playPauseTrackButton->setDefaultAction(StdActions::self()->playPauseTrackAction);
stopTrackButton->setDefaultAction(StdActions::self()->stopPlaybackAction);
nextTrackButton->setDefaultAction(StdActions::self()->nextTrackAction);
prevTrackButton->setDefaultAction(StdActions::self()->prevTrackAction);
QMenu *stopMenu=new QMenu(this);
stopMenu->addAction(StdActions::self()->stopPlaybackAction);
stopMenu->addAction(StdActions::self()->stopAfterCurrentTrackAction);
stopTrackButton->setMenu(stopMenu);
stopTrackButton->setPopupMode(QToolButton::DelayedPopup);
promptClearPlayQueueAction->setEnabled(false);
centerPlayQueueAction->setEnabled(false);
StdActions::self()->savePlayQueueAction->setEnabled(false);
addStreamToPlayQueueAction->setEnabled(false);
clearPlayQueueButton->setDefaultAction(promptClearPlayQueueAction);
savePlayQueueButton->setDefaultAction(StdActions::self()->savePlayQueueAction);
centerPlayQueueButton->setDefaultAction(centerPlayQueueAction);
randomButton->setDefaultAction(randomPlayQueueAction);
repeatButton->setDefaultAction(repeatPlayQueueAction);
singleButton->setDefaultAction(singlePlayQueueAction);
consumeButton->setDefaultAction(consumePlayQueueAction);
QStringList hiddenPages=Settings::self()->hiddenPages();
playQueuePage=new PlayQueuePage(this);
contextPage=new ContextPage(this);
QBoxLayout *layout=new QBoxLayout(QBoxLayout::TopToBottom, playQueuePage);
layout->setContentsMargins(0, 0, 0, 0);
bool playQueueInSidebar=!hiddenPages.contains(playQueuePage->metaObject()->className());
if (playQueueInSidebar && (Settings::self()->firstRun() || Settings::self()->version()metaObject()->className());
if (contextInSidebar && (Settings::self()->firstRun() || Settings::self()->version()setContentsMargins(0, 0, 0, 0);
// Build sidebar...
#define TAB_ACTION(A) A->icon(), A->text(), A->text()
int sidebarPageShortcutKey=Qt::Key_1;
addAction(showPlayQueueAction = ActionCollection::get()->createAction("showplayqueue", i18n("Play Queue"), Icons::self()->playqueueIcon));
showPlayQueueAction->setShortcut(Qt::ControlModifier+Qt::ShiftModifier+Qt::Key_Q);
tabWidget->addTab(playQueuePage, TAB_ACTION(showPlayQueueAction), playQueueInSidebar);
connect(showPlayQueueAction, SIGNAL(triggered(bool)), this, SLOT(showPlayQueue()));
libraryPage = new LibraryPage(this);
addAction(libraryTabAction = ActionCollection::get()->createAction("showlibrarytab", i18n("Artists"), Icons::self()->artistsIcon));
libraryTabAction->setShortcut(Qt::ControlModifier+Qt::ShiftModifier+nextKey(sidebarPageShortcutKey));
tabWidget->addTab(libraryPage, TAB_ACTION(libraryTabAction), !hiddenPages.contains(libraryPage->metaObject()->className()));
connect(libraryTabAction, SIGNAL(triggered(bool)), this, SLOT(showLibraryTab()));
albumsPage = new AlbumsPage(this);
addAction(albumsTabAction = ActionCollection::get()->createAction("showalbumstab", i18n("Albums"), Icons::self()->albumsIcon));
albumsTabAction->setShortcut(Qt::ControlModifier+Qt::ShiftModifier+nextKey(sidebarPageShortcutKey));
tabWidget->addTab(albumsPage, TAB_ACTION(albumsTabAction), !hiddenPages.contains(albumsPage->metaObject()->className()));
connect(albumsTabAction, SIGNAL(triggered(bool)), this, SLOT(showAlbumsTab()));
AlbumsModel::self()->setEnabled(!hiddenPages.contains(albumsPage->metaObject()->className()));
folderPage = new FolderPage(this);
addAction(foldersTabAction = ActionCollection::get()->createAction("showfolderstab", i18n("Folders"), Icons::self()->foldersIcon));
foldersTabAction->setShortcut(Qt::ControlModifier+Qt::ShiftModifier+nextKey(sidebarPageShortcutKey));
tabWidget->addTab(folderPage, TAB_ACTION(foldersTabAction), !hiddenPages.contains(folderPage->metaObject()->className()));
connect(foldersTabAction, SIGNAL(triggered(bool)), this, SLOT(showFoldersTab()));
folderPage->setEnabled(!hiddenPages.contains(folderPage->metaObject()->className()));
playlistsPage = new PlaylistsPage(this);
addAction(playlistsTabAction = ActionCollection::get()->createAction("showplayliststab", i18n("Playlists"), Icons::self()->playlistsIcon));
playlistsTabAction->setShortcut(Qt::ControlModifier+Qt::ShiftModifier+nextKey(sidebarPageShortcutKey));
tabWidget->addTab(playlistsPage, TAB_ACTION(playlistsTabAction), !hiddenPages.contains(playlistsPage->metaObject()->className()));
connect(playlistsTabAction, SIGNAL(triggered(bool)), this, SLOT(showPlaylistsTab()));
setPlaylistsEnabled(!hiddenPages.contains(playlistsPage->metaObject()->className()));
#ifdef ENABLE_DYNAMIC
dynamicPage = new DynamicPage(this);
addAction(dynamicTabAction = ActionCollection::get()->createAction("showdynamictab", i18n("Dynamic"), Icons::self()->dynamicIcon));
dynamicTabAction->setShortcut(Qt::ControlModifier+Qt::ShiftModifier+nextKey(sidebarPageShortcutKey));
tabWidget->addTab(dynamicPage, TAB_ACTION(dynamicTabAction), !hiddenPages.contains(dynamicPage->metaObject()->className()));
connect(dynamicTabAction, SIGNAL(triggered(bool)), this, SLOT(showDynamicTab()));
connect(Dynamic::self(), SIGNAL(error(const QString &)), SLOT(showError(const QString &)));
connect(Dynamic::self(), SIGNAL(running(bool)), dynamicLabel, SLOT(setVisible(bool)));
connect(Dynamic::self(), SIGNAL(running(bool)), this, SLOT(controlDynamicButton()));
stopDynamicButton->setDefaultAction(Dynamic::self()->stopAct());
#endif
#ifdef ENABLE_STREAMS
streamsPage = new StreamsPage(this);
addAction(streamsTabAction = ActionCollection::get()->createAction("showstreamstab", i18n("Streams"), Icons::self()->streamsIcon));
streamsTabAction->setShortcut(Qt::ControlModifier+Qt::ShiftModifier+nextKey(sidebarPageShortcutKey));
tabWidget->addTab(streamsPage, TAB_ACTION(streamsTabAction), !hiddenPages.contains(streamsPage->metaObject()->className()));
connect(streamsTabAction, SIGNAL(triggered(bool)), this, SLOT(showStreamsTab()));
connect(streamsPage, SIGNAL(add(const QStringList &, bool, quint8)), &playQueueModel, SLOT(addItems(const QStringList &, bool, quint8)));
connect(streamsPage, SIGNAL(error(QString)), this, SLOT(showError(QString)));
connect(streamsPage, SIGNAL(showPreferencesPage(QString)), this, SLOT(showPreferencesDialog(QString)));
#endif
#ifdef ENABLE_ONLINE_SERVICES
onlinePage = new OnlineServicesPage(this);
addAction(onlineTabAction = ActionCollection::get()->createAction("showonlinetab", i18n("Online"), Icons::self()->onlineIcon));
onlineTabAction->setShortcut(Qt::ControlModifier+Qt::ShiftModifier+nextKey(sidebarPageShortcutKey));
tabWidget->addTab(onlinePage, TAB_ACTION(onlineTabAction), !hiddenPages.contains(onlinePage->metaObject()->className()));
onlinePage->setEnabled(!hiddenPages.contains(onlinePage->metaObject()->className()));
connect(onlineTabAction, SIGNAL(triggered(bool)), this, SLOT(showOnlineTab()));
connect(onlinePage, SIGNAL(showPreferencesPage(QString)), this, SLOT(showPreferencesDialog(QString)));
connect(onlinePage, SIGNAL(addToDevice(const QString &, const QString &, const QList &)), SLOT(copyToDevice(const QString &, const QString &, const QList &)));
connect(OnlineServicesModel::self(), SIGNAL(error(const QString &)), this, SLOT(showError(const QString &)));
#endif
#ifdef ENABLE_DEVICES_SUPPORT
devicesPage = new DevicesPage(this);
addAction(devicesTabAction = ActionCollection::get()->createAction("showdevicestab", i18n("Devices"), Icons::self()->devicesIcon));
devicesTabAction->setShortcut(Qt::ControlModifier+Qt::ShiftModifier+nextKey(sidebarPageShortcutKey));
tabWidget->addTab(devicesPage, TAB_ACTION(devicesTabAction), !hiddenPages.contains(devicesPage->metaObject()->className()));
DevicesModel::self()->setEnabled(!hiddenPages.contains(devicesPage->metaObject()->className()));
connect(devicesTabAction, SIGNAL(triggered(bool)), this, SLOT(showDevicesTab()));
#endif
searchPage = new SearchPage(this);
addAction(searchTabAction = ActionCollection::get()->createAction("showsearchtab", i18n("Search"), Icons::self()->searchTabIcon));
searchTabAction->setShortcut(Qt::ControlModifier+Qt::ShiftModifier+nextKey(sidebarPageShortcutKey));
connect(searchTabAction, SIGNAL(triggered(bool)), this, SLOT(showSearchTab()));
connect(searchPage, SIGNAL(locate(QList)), this, SLOT(locateTracks(QList)));
tabWidget->addTab(searchPage, TAB_ACTION(searchTabAction), !hiddenPages.contains(searchPage->metaObject()->className()));
tabWidget->addTab(contextPage, Icons::self()->infoSidebarIcon, i18n("Info"), songInfoAction->text(),
!hiddenPages.contains(contextPage->metaObject()->className()));
tabWidget->setStyle(Settings::self()->sidebar());
if (playQueueInSidebar) {
tabToggled(PAGE_PLAYQUEUE);
} else {
tabWidget->setCurrentIndex(PAGE_LIBRARY);
}
if (contextInSidebar) {
tabToggled(PAGE_CONTEXT);
} else {
tabWidget->toggleTab(PAGE_CONTEXT, false);
}
initSizes();
expandInterfaceAction->setChecked(Settings::self()->showPlaylist());
fullScreenAction->setEnabled(expandInterfaceAction->isChecked());
if (fullScreenAction->isEnabled()) {
fullScreenAction->setChecked(Settings::self()->showFullScreen());
}
randomPlayQueueAction->setCheckable(true);
repeatPlayQueueAction->setCheckable(true);
singlePlayQueueAction->setCheckable(true);
consumePlayQueueAction->setCheckable(true);
songInfoButton->setDefaultAction(songInfoAction);
fullScreenLabel->setVisible(false);
connect(fullScreenLabel, SIGNAL(leftClickedUrl()), fullScreenAction, SIGNAL(triggered()));
if (Configuration(playQueuePage->metaObject()->className()).get(ItemView::constSearchActiveKey, false)) {
playQueueSearchWidget->activate();
} else {
playQueueSearchWidget->setVisible(false);
}
QList playbackBtns=QList() << prevTrackButton << stopTrackButton << playPauseTrackButton << nextTrackButton;
QList controlBtns=QList() << menuButton << songInfoButton;
int playbackIconSize=28;
int playPauseIconSize=32;
int controlIconSize=22;
int controlButtonSize=32;
if (repeatButton->iconSize().height()>=32) {
controlIconSize=playbackIconSize=48;
controlButtonSize=54;
playPauseIconSize=64;
} else if (repeatButton->iconSize().height()>=22) {
controlIconSize=playbackIconSize=32;
controlButtonSize=36;
playPauseIconSize=48;
} else if (QLatin1String("oxygen")!=Icon::currentTheme().toLower() || (GtkStyle::isActive() && GtkStyle::useSymbolicIcons())) {
// Oxygen does not have 24x24 icons, and media players seem to use scaled 28x28 icons...
// But, if the theme does have media icons at 24x24 use these - as they will be sharper...
playbackIconSize=24==Icons::self()->toolbarPlayIcon.actualSize(QSize(24, 24)).width() ? 24 : 28;
}
#ifdef USE_SYSTEM_MENU_ICON
if (GtkStyle::isActive() && GtkStyle::useSymbolicIcons()) {
controlIconSize=22==controlIconSize ? 16 : 32==controlIconSize ? 22 : 32;
}
#endif
stopTrackButton->setHideMenuIndicator(true);
int playbackButtonSize=28==playbackIconSize ? 34 : controlButtonSize;
int controlButtonWidth=Utils::touchFriendly() ? controlButtonSize*TouchProxyStyle::constScaleFactor : controlButtonSize;
int playbackButtonWidth=Utils::touchFriendly() ? playbackButtonSize*TouchProxyStyle::constScaleFactor : playbackButtonSize;
foreach (QToolButton *b, controlBtns) {
b->setAutoRaise(true);
b->setToolButtonStyle(Qt::ToolButtonIconOnly);
#ifdef USE_SYSTEM_MENU_ICON
if (b==menuButton && !GtkStyle::isActive()) {
b->setFixedHeight(controlButtonSize);
} else
#endif
b->setFixedSize(QSize(controlButtonWidth, controlButtonSize));
b->setIconSize(QSize(controlIconSize, controlIconSize));
}
foreach (QToolButton *b, playbackBtns) {
b->setAutoRaise(true);
b->setToolButtonStyle(Qt::ToolButtonIconOnly);
b->setFixedSize(QSize(playbackButtonWidth, playbackButtonSize));
b->setIconSize(QSize(playbackIconSize, playbackIconSize));
}
playPauseTrackButton->setIconSize(QSize(playPauseIconSize, playPauseIconSize));
playPauseTrackButton->setFixedSize(QSize((playPauseIconSize+6)*(Utils::touchFriendly() ? TouchProxyStyle::constScaleFactor : 1.0), playPauseIconSize+6));
if (fullScreenAction->isEnabled()) {
fullScreenAction->setChecked(Settings::self()->showFullScreen());
}
randomPlayQueueAction->setChecked(false);
repeatPlayQueueAction->setChecked(false);
singlePlayQueueAction->setChecked(false);
consumePlayQueueAction->setChecked(false);
MusicLibraryItemAlbum::setCoverSize((MusicLibraryItemAlbum::CoverSize)Settings::self()->libraryCoverSize());
MusicLibraryItemAlbum::setSortByDate(Settings::self()->libraryYear());
AlbumsModel::setCoverSize((MusicLibraryItemAlbum::CoverSize)Settings::self()->albumsCoverSize());
expandedSize=Settings::self()->mainWindowSize();
collapsedSize=Settings::self()->mainWindowCollapsedSize();
#ifdef ENABLE_KDE_SUPPORT
setupGUI(KXmlGuiWindow::Keys);
#endif
if (Settings::self()->firstRun()) {
int width=playPauseTrackButton->width()*25;
resize(playPauseTrackButton->width()*25, playPauseTrackButton->height()*18);
splitter->setSizes(QList() << width*0.4 << width*0.6);
} else {
QSize sz=Settings::self()->mainWindowSize();
if (!sz.isEmpty() && sz.width()>0) {
resize(sz);
}
if (expandInterfaceAction->isChecked()) {
if (!expandedSize.isEmpty() && expandedSize.width()>0) {
resize(expandedSize);
expandOrCollapse(false);
}
} else {
if (!collapsedSize.isEmpty() && collapsedSize.width()>0) {
resize(collapsedSize);
expandOrCollapse(false);
}
}
if (!playQueueInSidebar) {
QByteArray state=Settings::self()->splitterState();
if (!state.isEmpty()) {
splitter->restoreState(Settings::self()->splitterState());
}
}
if (fullScreenAction->isChecked()) {
fullScreen();
}
}
int menuCfg=Settings::self()->menu();
#ifndef Q_OS_MAC
if (Utils::Unity!=Utils::currentDe() && menuCfg&Settings::MC_Bar && menuCfg&Settings::MC_Button) {
#ifdef ENABLE_KDE_SUPPORT
showMenuAction=KStandardAction::showMenubar(this, SLOT(toggleMenubar()), ActionCollection::get());
#else
showMenuAction=ActionCollection::get()->createAction("showmenubar", i18n("Show Menubar"));
showMenuAction->setShortcut(Qt::ControlModifier+Qt::Key_M);
showMenuAction->setCheckable(true);
connect(showMenuAction, SIGNAL(toggled(bool)), this, SLOT(toggleMenubar()));
#endif
}
#endif
if (menuCfg&Settings::MC_Button) {
QMenu *mainMenu=new QMenu(this);
mainMenu->addAction(expandInterfaceAction);
// mainMenu->addAction(songInfoAction);
mainMenu->addAction(fullScreenAction);
mainMenu->addAction(connectionsAction);
mainMenu->addAction(outputsAction);
#ifdef ENABLE_HTTP_STREAM_PLAYBACK
mainMenu->addAction(streamPlayAction);
#endif
if (showMenuAction) {
mainMenu->addAction(showMenuAction);
}
#ifdef ENABLE_KDE_SUPPORT
mainMenu->addAction(prefAction);
mainMenu->addAction(refreshDbAction);
mainMenu->addAction(shortcutsAction);
mainMenu->addSeparator();
mainMenu->addAction(StdActions::self()->searchAction);
mainMenu->addSeparator();
mainMenu->addAction(serverInfoAction);
mainMenu->addMenu(helpMenu());
#else
mainMenu->addAction(prefAction);
mainMenu->addAction(refreshDbAction);
mainMenu->addAction(clearNewStateAction);
mainMenu->addSeparator();
mainMenu->addAction(StdActions::self()->searchAction);
mainMenu->addSeparator();
mainMenu->addAction(serverInfoAction);
mainMenu->addAction(aboutAction);
#endif
mainMenu->addSeparator();
mainMenu->addAction(quitAction);
menuButton->setIcon(Icons::self()->toolbarMenuIcon);
menuButton->setAlignedMenu(mainMenu);
} else {
menuButton->deleteLater();
menuButton=0;
}
if (menuCfg&Settings::MC_Bar) {
QMenu *menu=new QMenu(i18n("&Music"), this);
addMenuAction(menu, refreshDbAction);
menu->addSeparator();
addMenuAction(menu, connectionsAction);
addMenuAction(menu, outputsAction);
#ifdef ENABLE_HTTP_STREAM_PLAYBACK
addMenuAction(menu, streamPlayAction);
#endif
menu->addSeparator();
addMenuAction(menu, quitAction);
menuBar()->addMenu(menu);
menu=new QMenu(i18n("&Edit"), this);
addMenuAction(menu, playQueueModel.undoAct());
addMenuAction(menu, playQueueModel.redoAct());
menu->addSeparator();
addMenuAction(menu, clearNewStateAction);
menu->addSeparator();
addMenuAction(menu, StdActions::self()->searchAction);
#ifndef ENABLE_KDE_SUPPORT
if (Utils::KDE!=Utils::currentDe()) {
menu->addSeparator();
addMenuAction(menu, prefAction);
}
#endif
menuBar()->addMenu(menu);
#ifndef ENABLE_KDE_SUPPORT
if (Utils::KDE!=Utils::currentDe()) {
menu=new QMenu(i18n("&View"), this);
if (showMenuAction) {
addMenuAction(menu, showMenuAction);
menu->addSeparator();
}
// addMenuAction(menu, songInfoAction);
// menu->addSeparator();
addMenuAction(menu, expandInterfaceAction);
addMenuAction(menu, fullScreenAction);
menuBar()->addMenu(menu);
}
#endif
menu=new QMenu(i18n("&Queue"), this);
// addMenuAction(menu, promptClearPlayQueueAction);
// addMenuAction(menu, StdActions::self()->savePlayQueueAction);
// menu->addSeparator();
addMenuAction(menu, addStreamToPlayQueueAction);
menu->addSeparator();
addMenuAction(menu, playQueueModel.shuffleAct());
addMenuAction(menu, playQueueModel.sortAct());
menuBar()->addMenu(menu);
#ifndef ENABLE_KDE_SUPPORT
if (Utils::KDE==Utils::currentDe())
#endif
{
menu=new QMenu(i18n("&Settings"), this);
if (showMenuAction) {
addMenuAction(menu, showMenuAction);
}
addMenuAction(menu, expandInterfaceAction);
addMenuAction(menu, fullScreenAction);
addMenuAction(menu, songInfoAction);
menu->addSeparator();
#ifdef ENABLE_KDE_SUPPORT
addMenuAction(menu, shortcutsAction);
#endif
addMenuAction(menu, prefAction);
menuBar()->addMenu(menu);
}
menu=new QMenu(i18n("&Help"), this);
addMenuAction(menu, serverInfoAction);
#ifdef ENABLE_KDE_SUPPORT
menu->addSeparator();
foreach (QAction *act, helpMenu()->actions()) {
addMenuAction(menu, act);
}
#else
addMenuAction(menu, aboutAction);
#endif
menuBar()->addMenu(menu);
GtkStyle::registerWidget(menuBar());
}
if (showMenuAction) {
showMenuAction->setChecked(Settings::self()->showMenubar());
toggleMenubar();
}
dynamicLabel->setVisible(false);
stopDynamicButton->setVisible(false);
StdActions::self()->addWithPriorityAction->setVisible(false);
setPriorityAction->setVisible(false);
setPriorityAction->setMenu(StdActions::self()->addWithPriorityAction->menu());
playQueueProxyModel.setSourceModel(&playQueueModel);
playQueue->setModel(&playQueueProxyModel);
playQueue->addAction(playQueue->removeFromAct());
playQueue->addAction(promptClearPlayQueueAction);
playQueue->addAction(StdActions::self()->savePlayQueueAction);
playQueue->addAction(addStreamToPlayQueueAction);
playQueue->addAction(addPlayQueueToStoredPlaylistAction);
playQueue->addAction(cropPlayQueueAction);
playQueue->addAction(playQueueModel.shuffleAct());
playQueue->addAction(playQueueModel.sortAct());
playQueue->addAction(playQueueModel.undoAct());
playQueue->addAction(playQueueModel.redoAct());
Action *sep=new Action(this);
sep->setSeparator(true);
playQueue->addAction(sep);
playQueue->addAction(stopAfterTrackAction);
playQueue->addAction(setPriorityAction);
playQueue->addAction(locateTrackAction);
#ifdef TAGLIB_FOUND
playQueue->addAction(editPlayQueueTagsAction);
#endif
playQueue->addAction(playQueueModel.removeDuplicatesAct());
playQueue->readConfig();
playlistsPage->setStartClosed(Settings::self()->playListsStartClosed());
#ifdef ENABLE_DEVICES_SUPPORT
connect(DevicesModel::self(), SIGNAL(addToDevice(const QString &)), this, SLOT(addToDevice(const QString &)));
connect(DevicesModel::self(), SIGNAL(error(const QString &)), this, SLOT(showError(const QString &)));
connect(libraryPage, SIGNAL(addToDevice(const QString &, const QString &, const QList &)), SLOT(copyToDevice(const QString &, const QString &, const QList &)));
connect(albumsPage, SIGNAL(addToDevice(const QString &, const QString &, const QList &)), SLOT(copyToDevice(const QString &, const QString &, const QList &)));
connect(folderPage, SIGNAL(addToDevice(const QString &, const QString &, const QList &)), SLOT(copyToDevice(const QString &, const QString &, const QList &)));
connect(playlistsPage, SIGNAL(addToDevice(const QString &, const QString &, const QList &)), SLOT(copyToDevice(const QString &, const QString &, const QList &)));
connect(devicesPage, SIGNAL(addToDevice(const QString &, const QString &, const QList &)), SLOT(copyToDevice(const QString &, const QString &, const QList &)));
connect(searchPage, SIGNAL(addToDevice(const QString &, const QString &, const QList &)), SLOT(copyToDevice(const QString &, const QString &, const QList &)));
connect(StdActions::self()->deleteSongsAction, SIGNAL(triggered(bool)), SLOT(deleteSongs()));
connect(devicesPage, SIGNAL(deleteSongs(const QString &, const QList &)), SLOT(deleteSongs(const QString &, const QList &)));
connect(libraryPage, SIGNAL(deleteSongs(const QString &, const QList &)), SLOT(deleteSongs(const QString &, const QList &)));
connect(albumsPage, SIGNAL(deleteSongs(const QString &, const QList &)), SLOT(deleteSongs(const QString &, const QList &)));
connect(folderPage, SIGNAL(deleteSongs(const QString &, const QList &)), SLOT(deleteSongs(const QString &, const QList &)));
#endif
connect(StdActions::self()->addPrioHighestAction, SIGNAL(triggered(bool)), this, SLOT(addWithPriority()));
connect(StdActions::self()->addPrioHighAction, SIGNAL(triggered(bool)), this, SLOT(addWithPriority()));
connect(StdActions::self()->addPrioMediumAction, SIGNAL(triggered(bool)), this, SLOT(addWithPriority()));
connect(StdActions::self()->addPrioLowAction, SIGNAL(triggered(bool)), this, SLOT(addWithPriority()));
connect(StdActions::self()->addPrioDefaultAction, SIGNAL(triggered(bool)), this, SLOT(addWithPriority()));
connect(StdActions::self()->addPrioCustomAction, SIGNAL(triggered(bool)), this, SLOT(addWithPriority()));
connect(MPDConnection::self(), SIGNAL(outputsUpdated(const QList
"),
i18n("Server Information"));
}
void MainWindow::enableStopActions(bool enable)
{
StdActions::self()->stopAfterCurrentTrackAction->setEnabled(enable);
StdActions::self()->stopPlaybackAction->setEnabled(enable);
}
void MainWindow::stopPlayback()
{
if (!fadeWhenStop() || MPDState_Paused==MPDStatus::self()->state() || 0==volume) {
emit stop();
}
enableStopActions(false);
StdActions::self()->nextTrackAction->setEnabled(false);
StdActions::self()->prevTrackAction->setEnabled(false);
startVolumeFade();
}
void MainWindow::stopAfterCurrentTrack()
{
playQueueModel.clearStopAfterTrack();
emit stop(true);
}
void MainWindow::stopAfterTrack()
{
QModelIndexList selected=playQueue->selectedIndexes(false); // Dont need sorted selection here...
if (1==selected.count()) {
QModelIndex idx=playQueueProxyModel.mapToSource(selected.first());
playQueueModel.setStopAfterTrack(playQueueModel.getIdByRow(idx.row()));
}
}
void MainWindow::startVolumeFade()
{
if (!fadeWhenStop()) {
return;
}
stopState=StopState_Stopping;
volumeSlider->setFadingStop(true);
if (!volumeFade) {
volumeFade = new QPropertyAnimation(this, "volume");
volumeFade->setDuration(Settings::self()->stopFadeDuration());
}
origVolume=lastVolume=volumeSlider->value();
volumeFade->setStartValue(origVolume);
volumeFade->setEndValue(-1);
volumeFade->start();
}
void MainWindow::stopVolumeFade()
{
if (StopState_None!=stopState) {
stopState=StopState_None;
volumeFade->stop();
setMpdVolume(-1);
}
}
void MainWindow::setMpdVolume(int v)
{
if (-1==v) {
volumeSlider->setFadingStop(false);
emit setVolume(volumeSlider->value());
if (StopState_Stopping==stopState) {
emit stop();
}
stopState=StopState_None;
} else if (lastVolume!=v) {
emit setVolume(v);
lastVolume=v;
}
}
void MainWindow::playPauseTrack()
{
switch (MPDStatus::self()->state()) {
case MPDState_Playing:
emit pause(true);
break;
case MPDState_Paused:
stopVolumeFade();
emit pause(false);
break;
default:
if (playQueueModel.rowCount()>0) {
stopVolumeFade();
if (-1!=playQueueModel.currentSong() && -1!=playQueueModel.currentSongRow()) {
emit startPlayingSongId(playQueueModel.currentSong());
} else {
emit play();
}
}
}
}
void MainWindow::setPosition()
{
emit setSeekId(MPDStatus::self()->songId(), nowPlaying->value());
}
void MainWindow::searchPlayQueue()
{
if (playQueueSearchWidget->text().isEmpty()) {
if (playQueueSearchTimer) {
playQueueSearchTimer->stop();
}
realSearchPlayQueue();
} else {
if (!playQueueSearchTimer) {
playQueueSearchTimer=new QTimer(this);
playQueueSearchTimer->setSingleShot(true);
connect(playQueueSearchTimer, SIGNAL(timeout()), SLOT(realSearchPlayQueue()));
}
playQueueSearchTimer->start(250);
}
}
void MainWindow::realSearchPlayQueue()
{
if (playQueueSearchTimer) {
playQueueSearchTimer->stop();
}
QString filter=playQueueSearchWidget->text().trimmed();
if (filter.length()<2) {
filter=QString();
}
if (filter!=playQueueProxyModel.filterText()) {
playQueue->setFilterActive(!filter.isEmpty());
playQueue->clearSelection();
playQueueProxyModel.update(filter);
QModelIndex idx=playQueueProxyModel.mapFromSource(playQueueModel.index(playQueueModel.currentSongRow(), 0));
playQueue->updateRows(idx.row(), current.key, autoScrollPlayQueue && playQueueProxyModel.isEmpty() && MPDState_Playing==MPDStatus::self()->state());
scrollPlayQueue();
}
}
void MainWindow::playQueueSearchActivated(bool a)
{
if (!a && playQueue->isVisible()) {
playQueue->setFocus();
}
}
void MainWindow::updatePlayQueue(const QList &songs)
{
StdActions::self()->playPauseTrackAction->setEnabled(!songs.isEmpty());
StdActions::self()->nextTrackAction->setEnabled(StdActions::self()->stopPlaybackAction->isEnabled() && songs.count()>1);
StdActions::self()->prevTrackAction->setEnabled(StdActions::self()->stopPlaybackAction->isEnabled() && songs.count()>1);
StdActions::self()->savePlayQueueAction->setEnabled(!songs.isEmpty());
promptClearPlayQueueAction->setEnabled(!songs.isEmpty());
centerPlayQueueAction->setEnabled(songs.count()>1);
int topRow=-1;
QModelIndex topIndex=playQueueModel.lastCommandWasUnodOrRedo() ? playQueue->indexAt(QPoint(0, 0)) : QModelIndex();
if (topIndex.isValid()) {
topRow=playQueueProxyModel.mapToSource(topIndex).row();
}
bool wasEmpty=0==playQueueModel.rowCount();
playQueueModel.update(songs);
QModelIndex idx=playQueueProxyModel.mapFromSource(playQueueModel.index(playQueueModel.currentSongRow(), 0));
bool scroll=autoScrollPlayQueue && playQueueProxyModel.isEmpty() && wasEmpty && MPDState_Playing==MPDStatus::self()->state();
playQueue->updateRows(idx.row(), current.key, scroll);
if (!scroll && topRow>0 && topRowscrollTo(playQueueProxyModel.mapFromSource(playQueueModel.index(topRow, 0)), QAbstractItemView::PositionAtTop);
}
if (songs.isEmpty()) {
updateCurrentSong(Song());
} else if (current.isStandardStream()) {
// Check to see if it has been updated...
Song pqSong=playQueueModel.getSongByRow(playQueueModel.currentSongRow());
if (pqSong.artist!=current.artist || pqSong.album!=current.album || pqSong.title!=current.title || pqSong.year!=current.year || pqSong.name()!=current.name() ) {
updateCurrentSong(pqSong);
}
}
playQueueItemsSelected(playQueue->haveSelectedItems());
}
void MainWindow::updateWindowTitle()
{
bool multipleConnections=connectionsAction->isVisible();
QString connection=MPDConnection::self()->getDetails().getName();
setWindowTitle(multipleConnections ? i18n("Cantata (%1)", connection) : "Cantata");
}
void MainWindow::updateCurrentSong(const Song &song)
{
if (fadeWhenStop() && StopState_None!=stopState) {
if (StopState_Stopping==stopState) {
emit stop();
}
}
current=song;
if (current.isCdda()) {
emit getStatus();
if (current.isUnknown()) {
Song pqSong=playQueueModel.getSongById(current.id);
if (!pqSong.isEmpty()) {
current=pqSong;
}
}
}
if (current.isCantataStream()) {
Song mod=HttpServer::self()->decodeUrl(current.file);
if (!mod.title.isEmpty()) {
current=mod;
current.id=song.id;
}
}
CurrentCover::self()->update(current);
#ifdef QT_QTDBUS_FOUND
mpris->updateCurrentSong(current);
#endif
if (current.time<5 && MPDStatus::self()->songId()==current.id && MPDStatus::self()->timeTotal()>5) {
current.time=MPDStatus::self()->timeTotal();
}
nowPlaying->setEnabled(-1!=current.id && !current.isCdda() && (!currentIsStream() || current.time>5));
nowPlaying->update(current);
bool isPlaying=MPDState_Playing==MPDStatus::self()->state();
playQueueModel.updateCurrentSong(current.id);
QModelIndex idx=playQueueProxyModel.mapFromSource(playQueueModel.index(playQueueModel.currentSongRow(), 0));
playQueue->updateRows(idx.row(), current.key, autoScrollPlayQueue && playQueueProxyModel.isEmpty() && isPlaying);
scrollPlayQueue();
context->update(current);
trayItem->songChanged(song, isPlaying);
}
void MainWindow::scrollPlayQueue()
{
if (autoScrollPlayQueue && MPDState_Playing==MPDStatus::self()->state() && !playQueue->isGrouped()) {
qint32 row=playQueueModel.currentSongRow();
if (row>=0) {
playQueue->scrollTo(playQueueProxyModel.mapFromSource(playQueueModel.index(row, 0)), QAbstractItemView::PositionAtCenter);
}
}
}
void MainWindow::updateStats()
{
// Check if remote db is more recent than local one
if (!MusicLibraryModel::self()->lastUpdate().isValid() || MPDStats::self()->dbUpdate() > MusicLibraryModel::self()->lastUpdate()) {
if (!MusicLibraryModel::self()->lastUpdate().isValid()) {
libraryPage->clear();
//albumsPage->clear();
folderPage->clear();
playlistsPage->clear();
}
albumsPage->goTop();
libraryPage->refresh();
folderPage->refresh();
}
}
void MainWindow::updateStatus()
{
updateStatus(MPDStatus::self());
}
void MainWindow::updateStatus(MPDStatus * const status)
{
if (!status->error().isEmpty()) {
showError(i18n("MPD reported the following error: %1", status->error()));
}
if (MPDState_Stopped==status->state() || MPDState_Inactive==status->state()) {
nowPlaying->clearTimes();
playQueueModel.clearStopAfterTrack();
if (statusTimer) {
statusTimer->stop();
statusTimer->setProperty("count", 0);
}
} else {
nowPlaying->setRange(0, 0==status->timeTotal() && 0!=current.time && (current.isCdda() || current.isCantataStream())
? current.time : status->timeTotal());
nowPlaying->setValue(status->timeElapsed());
if (0==status->timeTotal() && 0==status->timeElapsed()) {
if (!statusTimer) {
statusTimer=new QTimer(this);
statusTimer->setSingleShot(true);
connect(statusTimer, SIGNAL(timeout()), SIGNAL(getStatus()));
}
QVariant id=statusTimer->property("id");
if (!id.isValid() || id.toInt()!=current.id) {
statusTimer->setProperty("id", current.id);
statusTimer->setProperty("count", 0);
statusTimer->start(250);
} else if (statusTimer->property("count").toInt()<12) {
statusTimer->setProperty("count", statusTimer->property("count").toInt()+1);
statusTimer->start(250);
}
} else if (!nowPlaying->isEnabled()) {
nowPlaying->setEnabled(-1!=current.id && !current.isCdda() && (!currentIsStream() || status->timeTotal()>5));
}
}
randomPlayQueueAction->setChecked(status->random());
repeatPlayQueueAction->setChecked(status->repeat());
singlePlayQueueAction->setChecked(status->single());
consumePlayQueueAction->setChecked(status->consume());
updateNextTrack(status->nextSongId());
if (status->timeElapsed()<172800 && (!currentIsStream() || (status->timeTotal()>0 && status->timeElapsed()<=status->timeTotal()))) {
if (status->state() == MPDState_Stopped || status->state() == MPDState_Inactive) {
nowPlaying->setRange(0, 0);
} else {
nowPlaying->setValue(status->timeElapsed());
}
}
playQueueModel.setState(status->state());
switch (status->state()) {
case MPDState_Playing:
StdActions::self()->playPauseTrackAction->setIcon(Icons::self()->toolbarPauseIcon);
StdActions::self()->playPauseTrackAction->setEnabled(0!=status->playlistLength());
if (StopState_Stopping!=stopState) {
enableStopActions(true);
StdActions::self()->nextTrackAction->setEnabled(status->playlistLength()>1);
StdActions::self()->prevTrackAction->setEnabled(status->playlistLength()>1);
}
nowPlaying->startTimer();
break;
case MPDState_Inactive:
case MPDState_Stopped:
StdActions::self()->playPauseTrackAction->setIcon(Icons::self()->toolbarPlayIcon);
StdActions::self()->playPauseTrackAction->setEnabled(0!=status->playlistLength());
enableStopActions(false);
StdActions::self()->nextTrackAction->setEnabled(false);
StdActions::self()->prevTrackAction->setEnabled(false);
if (!StdActions::self()->playPauseTrackAction->isEnabled()) {
current=Song();
nowPlaying->update(current);
CurrentCover::self()->update(current);
}
current.id=0;
trayItem->setToolTip("cantata", i18n("Cantata"), QLatin1String("")+i18n("Playback stopped")+QLatin1String(""));
nowPlaying->stopTimer();
break;
case MPDState_Paused:
StdActions::self()->playPauseTrackAction->setIcon(Icons::self()->toolbarPlayIcon);
StdActions::self()->playPauseTrackAction->setEnabled(0!=status->playlistLength());
enableStopActions(0!=status->playlistLength());
StdActions::self()->nextTrackAction->setEnabled(status->playlistLength()>1);
StdActions::self()->prevTrackAction->setEnabled(status->playlistLength()>1);
nowPlaying->stopTimer();
default:
break;
}
// Check if song has changed or we're playing again after being stopped, and update song info if needed
if (MPDState_Inactive!=status->state() &&
(MPDState_Inactive==lastState || (MPDState_Stopped==lastState && MPDState_Playing==status->state()) || lastSongId != status->songId())) {
emit currentSong();
}
if (status->state()!=lastState && (MPDState_Playing==status->state() || MPDState_Stopped==status->state())) {
startContextTimer();
}
// Update status info
lastState = status->state();
lastSongId = status->songId();
}
void MainWindow::playQueueItemActivated(const QModelIndex &index)
{
emit startPlayingSongId(playQueueModel.getIdByRow(playQueueProxyModel.mapToSource(index).row()));
}
void MainWindow::promptClearPlayQueue()
{
if (Settings::self()->playQueueConfirmClear()) {
if (QDialogButtonBox::GnomeLayout==style()->styleHint(QStyle::SH_DialogButtonLayout)) {
messageWidget->setActions(QList() << cancelAction << clearPlayQueueAction);
} else {
messageWidget->setActions(QList() << clearPlayQueueAction << cancelAction);
}
messageWidget->setWarning(i18n("Remove all songs from play queue?"), false);
expand();
} else {
clearPlayQueue();
}
}
void MainWindow::clearPlayQueue()
{
if (dynamicLabel->isVisible()) {
#ifdef ENABLE_DYNAMIC
Dynamic::self()->stop(true);
#endif
} else {
playQueueModel.removeAll();
}
}
void MainWindow::centerPlayQueue()
{
QModelIndex idx=playQueueProxyModel.mapFromSource(playQueueModel.index(playQueueModel.currentSongRow(), 0));
if (idx.isValid()) {
if (playQueue->isGrouped()) {
playQueue->updateRows(idx.row(), current.key, true, true);
} else {
playQueue->scrollTo(idx, QAbstractItemView::PositionAtCenter);
}
}
}
void MainWindow::addToPlayQueue(bool replace, quint8 priority, bool randomAlbums)
{
playQueueSearchWidget->clear();
if (currentPage) {
currentPage->addSelectionToPlaylist(QString(), replace, priority, randomAlbums);
}
}
void MainWindow::addWithPriority()
{
QAction *act=qobject_cast(sender());
if (!act || !MPDConnection::self()->canUsePriority() || !StdActions::self()->addWithPriorityAction->isVisible()) {
return;
}
int prio=act->data().toInt();
bool isPlayQueue=playQueue->hasFocus();
QModelIndexList pqItems;
if (isPlayQueue) {
pqItems=playQueue->selectedIndexes();
if (pqItems.isEmpty()) {
return;
}
}
if (-1==prio) {
bool ok=false;
prio=InputDialog::getInteger(i18n("Priority"), i18n("Enter priority (0..255):"), 150, 0, 255, 5, 10, &ok, this);
if (!ok) {
return;
}
}
if (prio>=0 && prio<=255) {
if (isPlayQueue) {
QList ids;
foreach (const QModelIndex &idx, pqItems) {
ids.append(playQueueModel.getIdByRow(playQueueProxyModel.mapToSource(idx).row()));
}
emit setPriority(ids, prio);
} else {
addToPlayQueue(false, prio);
}
}
}
void MainWindow::addToNewStoredPlaylist()
{
bool pq=playQueue->hasFocus();
for(;;) {
QString name = InputDialog::getText(i18n("Playlist Name"), i18n("Enter a name for the playlist:"), QString(), 0, this);
if (name==StreamsModel::constPlayListName) {
MessageBox::error(this, i18n("%1 is used to store favorite streams, please choose another name.", name));
continue;
}
if (PlaylistsModel::self()->exists(name)) {
switch(MessageBox::warningYesNoCancel(this, i18n("A playlist named %1 already exists!
Add to that playlist?", name),
i18n("Existing Playlist"))) {
case MessageBox::Cancel: return;
case MessageBox::Yes: break;
case MessageBox::No:
default: continue;
}
}
if (!name.isEmpty()) {
addToExistingStoredPlaylist(name, pq);
}
break;
}
}
void MainWindow::addToExistingStoredPlaylist(const QString &name, bool pq)
{
if (pq) {
QModelIndexList items = playQueue->selectedIndexes();
QStringList files;
if (items.isEmpty()) {
files = playQueueModel.filenames();
} else {
foreach (const QModelIndex &idx, items) {
Song s = playQueueModel.getSongByRow(playQueueProxyModel.mapToSource(idx).row());
if (!s.file.isEmpty()) {
files.append(s.file);
}
}
}
if (!files.isEmpty()) {
emit addSongsToPlaylist(name, files);
}
} else if (currentPage) {
currentPage->addSelectionToPlaylist(name);
}
}
void MainWindow::addStreamToPlayQueue()
{
#ifdef ENABLE_STREAMS
StreamDialog dlg(this, true);
if (QDialog::Accepted==dlg.exec()) {
QString url=dlg.url();
if (dlg.save()) {
StreamsModel::self()->addToFavourites(url, dlg.name());
}
playQueueModel.addItems(QStringList() << StreamsModel::modifyUrl(url), false, 0);
}
#else
QString url = InputDialog::getText(i18n("Stream URL"), i18n("Enter URL of stream:"), QString(), 0, this).trimmed();
if (!url.isEmpty()) {
if (!MPDConnection::self()->urlHandlers().contains(QUrl(url).scheme())) {
MessageBox::error(this, i18n("Invalid, or unsupported, URL!"));
} else {
playQueueModel.addItems(QStringList() << StreamsModel::modifyUrl(url), false, 0);
}
}
#endif
}
void MainWindow::removeItems()
{
if (currentPage) {
currentPage->removeItems();
}
}
void MainWindow::checkMpdAccessibility()
{
#ifdef Q_OS_LINUX
if (!mpdAccessibilityTimer) {
mpdAccessibilityTimer=new QTimer(this);
connect(mpdAccessibilityTimer, SIGNAL(timeout()), SLOT(checkMpdDir()));
}
mpdAccessibilityTimer->start(500);
#endif
}
void MainWindow::updatePlayQueueStats(int songs, quint32 time)
{
if (0==songs) {
playQueueStatsLabel->setText(QString());
} else if (0==time) {
playQueueStatsLabel->setText(Plurals::tracks(songs));
} else {
playQueueStatsLabel->setText(Plurals::tracksWithDuration(songs, Utils::formatDuration(time)));
}
}
void MainWindow::showSongInfo()
{
if (songInfoAction->isCheckable()) {
stack->setCurrentWidget(songInfoAction->isChecked() ? (QWidget *)context : (QWidget *)splitter);
} else {
showTab(PAGE_CONTEXT);
}
}
void MainWindow::fullScreen()
{
if (expandInterfaceAction->isChecked()) {
fullScreenLabel->setVisible(!isFullScreen());
expandInterfaceAction->setEnabled(isFullScreen());
if (isFullScreen()) {
showNormal();
} else {
showFullScreen();
}
} else {
fullScreenAction->setChecked(false);
}
}
void MainWindow::sidebarModeChanged()
{
if (expandInterfaceAction->isChecked()) {
setMinimumHeight(calcMinHeight());
}
}
void MainWindow::currentTabChanged(int index)
{
prevPage=index;
controlDynamicButton();
switch(index) {
case PAGE_LIBRARY: currentPage=libraryPage; break;
case PAGE_ALBUMS: currentPage=albumsPage; break;
case PAGE_FOLDERS: folderPage->load(); currentPage=folderPage; break;
case PAGE_PLAYLISTS: currentPage=playlistsPage; break;
#ifdef ENABLE_DYNAMIC
case PAGE_DYNAMIC: currentPage=dynamicPage; break;
#endif
#ifdef ENABLE_STREAMS
case PAGE_STREAMS: currentPage=streamsPage; break;
#endif
#ifdef ENABLE_ONLINE_SERVICES
case PAGE_ONLINE: currentPage=onlinePage; break;
#endif
#ifdef ENABLE_DEVICES_SUPPORT
case PAGE_DEVICES: currentPage=devicesPage; break;
#endif
case PAGE_SEARCH: currentPage=searchPage; break;
default: currentPage=0; break;
}
if (currentPage) {
currentPage->controlActions();
}
}
void MainWindow::tabToggled(int index)
{
switch (index) {
case PAGE_PLAYQUEUE:
if (tabWidget->isEnabled(index)) {
splitter->setAutohidable(0, Settings::self()->splitterAutoHide() && !tabWidget->isEnabled(PAGE_PLAYQUEUE));
playQueueWidget->setParent(playQueuePage);
playQueuePage->layout()->addWidget(playQueueWidget);
playQueueWidget->setVisible(true);
} else {
playQueuePage->layout()->removeWidget(playQueueWidget);
playQueueWidget->setParent(splitter);
playQueueWidget->setVisible(true);
splitter->setAutohidable(0, Settings::self()->splitterAutoHide() && !tabWidget->isEnabled(PAGE_PLAYQUEUE));
}
playQueue->updatePalette();
break;
case PAGE_CONTEXT:
if (tabWidget->isEnabled(index) && songInfoAction->isCheckable()) {
context->setParent(contextPage);
contextPage->layout()->addWidget(context);
context->setVisible(true);
songInfoButton->setVisible(false);
songInfoAction->setCheckable(false);
} else if (!songInfoAction->isCheckable()) {
contextPage->layout()->removeWidget(context);
stack->addWidget(context);
songInfoButton->setVisible(true);
songInfoAction->setCheckable(true);
}
break;
case PAGE_LIBRARY:
locateTrackAction->setVisible(tabWidget->isEnabled(index));
break;
case PAGE_ALBUMS:
AlbumsModel::self()->setEnabled(!AlbumsModel::self()->isEnabled());
break;
case PAGE_FOLDERS:
folderPage->setEnabled(!folderPage->isEnabled());
break;
case PAGE_PLAYLISTS:
setPlaylistsEnabled(tabWidget->isEnabled(index));
break;
#ifdef ENABLE_STREAMS
case PAGE_STREAMS:
break;
#endif
#ifdef ENABLE_ONLINE_SERVICES
case PAGE_ONLINE:
OnlineServicesModel::self()->setEnabled(!OnlineServicesModel::self()->isEnabled());
break;
#endif
#ifdef ENABLE_DEVICES_SUPPORT
case PAGE_DEVICES:
DevicesModel::self()->setEnabled(!DevicesModel::self()->isEnabled());
StdActions::self()->copyToDeviceAction->setVisible(DevicesModel::self()->isEnabled());
break;
#endif
default:
break;
}
sidebarModeChanged();
}
void MainWindow::toggleSplitterAutoHide()
{
bool ah=Settings::self()->splitterAutoHide();
if (splitter->isAutoHideEnabled()!=ah) {
splitter->setAutoHideEnabled(ah);
splitter->setAutohidable(0, ah);
}
}
void MainWindow::toggleMonoIcons()
{
if (Settings::self()->monoSidebarIcons()!=Icons::self()->monoSidebarIcons()) {
Icons::self()->initSidebarIcons();
showPlayQueueAction->setIcon(Icons::self()->playqueueIcon);
tabWidget->setIcon(PAGE_PLAYQUEUE, showPlayQueueAction->icon());
libraryTabAction->setIcon(Icons::self()->artistsIcon);
tabWidget->setIcon(PAGE_LIBRARY, libraryTabAction->icon());
albumsTabAction->setIcon(Icons::self()->albumsIcon);
tabWidget->setIcon(PAGE_ALBUMS, albumsTabAction->icon());
foldersTabAction->setIcon(Icons::self()->foldersIcon);
tabWidget->setIcon(PAGE_FOLDERS, foldersTabAction->icon());
playlistsTabAction->setIcon(Icons::self()->playlistsIcon);
tabWidget->setIcon(PAGE_PLAYLISTS, playlistsTabAction->icon());
#ifdef ENABLE_DYNAMIC
dynamicTabAction->setIcon(Icons::self()->dynamicIcon);
tabWidget->setIcon(PAGE_DYNAMIC, dynamicTabAction->icon());
#endif
#ifdef ENABLE_STREAMS
streamsTabAction->setIcon(Icons::self()->streamsIcon);
tabWidget->setIcon(PAGE_STREAMS, streamsTabAction->icon());
#endif
#ifdef ENABLE_ONLINE_SERVICES
onlineTabAction->setIcon(Icons::self()->onlineIcon);
tabWidget->setIcon(PAGE_ONLINE, onlineTabAction->icon());
#endif
tabWidget->setIcon(PAGE_CONTEXT, Icons::self()->infoSidebarIcon);
#ifdef ENABLE_DEVICES_SUPPORT
devicesTabAction->setIcon(Icons::self()->devicesIcon);
tabWidget->setIcon(PAGE_DEVICES, devicesTabAction->icon());
#endif
searchTabAction->setIcon(Icons::self()->searchTabIcon);
tabWidget->setIcon(PAGE_SEARCH, searchTabAction->icon());
tabWidget->recreate();
}
}
void MainWindow::locateTracks(const QList &songs)
{
if (!songs.isEmpty() && tabWidget->isEnabled(PAGE_LIBRARY)) {
showLibraryTab();
libraryPage->showSongs(songs);
}
}
void MainWindow::locateTrack()
{
locateTracks(playQueue->selectedSongs());
}
void MainWindow::locateArtist(const QString &artist)
{
if (songInfoAction->isCheckable()) {
songInfoAction->setChecked(false);
showSongInfo();
}
showLibraryTab();
libraryPage->showArtist(artist);
}
void MainWindow::locateAlbum(const QString &artist, const QString &album)
{
if (songInfoAction->isCheckable()) {
songInfoAction->setChecked(false);
showSongInfo();
}
showLibraryTab();
libraryPage->showAlbum(artist, album);
}
void MainWindow::dynamicStatus(const QString &message)
{
#ifdef ENABLE_DYNAMIC
Dynamic::self()->helperMessage(message);
#else
Q_UNUSED(message)
#endif
}
void MainWindow::showSearch()
{
if (playQueue->hasFocus()) {
playQueueSearchWidget->activate();
} else if (context->isVisible()) {
context->search();
} else if (currentPage && splitter->sizes().at(0)>0) {
currentPage->focusSearch();
} else if (playQueuePage->isVisible() || playQueue->isVisible()) {
playQueueSearchWidget->activate();
}
}
void MainWindow::expandAll()
{
QWidget *f=QApplication::focusWidget();
if (f && qobject_cast(f) && !qobject_cast(f)) {
static_cast(f)->expandAll(QModelIndex(), true);
}
}
void MainWindow::collapseAll()
{
QWidget *f=QApplication::focusWidget();
if (f && qobject_cast(f) && !qobject_cast(f)) {
static_cast(f)->collapseAll();
}
}
void MainWindow::editTags()
{
#ifdef TAGLIB_FOUND
QList songs;
if (currentPage==folderPage) {
songs=folderPage->selectedSongs(FolderPage::ES_FillEmpty);
} else if (currentPage) {
songs=currentPage->selectedSongs();
}
editTags(songs, false);
#endif
}
void MainWindow::editPlayQueueTags()
{
#ifdef TAGLIB_FOUND
editTags(playQueue->selectedSongs(), true);
#endif
}
#ifdef TAGLIB_FOUND
void MainWindow::editTags(const QList &songs, bool isPlayQueue)
{
if (songs.isEmpty() && isPlayQueue) {
MessageBox::error(this, i18n("Can only edit tags of songs within MPD's music collection."));
}
if (songs.isEmpty() || TagEditor::instanceCount() || !canShowDialog()) {
return;
}
QSet artists, albumArtists, composers, albums, genres;
QString udi;
#ifdef ENABLE_DEVICES_SUPPORT
if (!isPlayQueue && currentPage==devicesPage) {
DevicesModel::self()->getDetails(artists, albumArtists, composers, albums, genres);
udi=devicesPage->activeFsDeviceUdi();
if (udi.isEmpty()) {
return;
}
} else
#else
Q_UNUSED(isPlayQueue)
#endif
MusicLibraryModel::self()->getDetails(artists, albumArtists, composers, albums, genres);
TagEditor *dlg=new TagEditor(this, songs, artists, albumArtists, composers, albums, genres, udi);
dlg->show();
}
#endif
void MainWindow::organiseFiles()
{
#ifdef TAGLIB_FOUND
if (TrackOrganiser::instanceCount() || !canShowDialog()) {
return;
}
QList songs;
if (currentPage) {
songs=currentPage->selectedSongs();
}
if (!songs.isEmpty()) {
QString udi;
#ifdef ENABLE_DEVICES_SUPPORT
if (currentPage==devicesPage) {
udi=devicesPage->activeFsDeviceUdi();
if (udi.isEmpty()) {
return;
}
}
#endif
TrackOrganiser *dlg=new TrackOrganiser(this);
dlg->show(songs, udi);
}
#endif
}
void MainWindow::addToDevice(const QString &udi)
{
#ifdef ENABLE_DEVICES_SUPPORT
if (currentPage) {
currentPage->addSelectionToDevice(udi);
}
#else
Q_UNUSED(udi)
#endif
}
void MainWindow::deleteSongs()
{
#ifdef ENABLE_DEVICES_SUPPORT
if (!StdActions::self()->deleteSongsAction->isVisible()) {
return;
}
if (currentPage) {
currentPage->deleteSongs();
}
#endif
}
void MainWindow::copyToDevice(const QString &from, const QString &to, const QList &songs)
{
#ifdef ENABLE_DEVICES_SUPPORT
if (songs.isEmpty() || ActionDialog::instanceCount() || !canShowDialog()) {
return;
}
ActionDialog *dlg=new ActionDialog(this);
dlg->copy(from, to, songs);
#else
Q_UNUSED(from) Q_UNUSED(to) Q_UNUSED(songs)
#endif
}
void MainWindow::deleteSongs(const QString &from, const QList &songs)
{
#ifdef ENABLE_DEVICES_SUPPORT
if (songs.isEmpty() || ActionDialog::instanceCount() || !canShowDialog()) {
return;
}
ActionDialog *dlg=new ActionDialog(this);
dlg->remove(from, songs);
#else
Q_UNUSED(from) Q_UNUSED(songs)
#endif
}
void MainWindow::replayGain()
{
#ifdef ENABLE_REPLAYGAIN_SUPPORT
if (RgDialog::instanceCount() || !canShowDialog()) {
return;
}
QList songs;
if (currentPage==folderPage) {
songs=folderPage->selectedSongs(FolderPage::ES_GuessTags);
} else if (currentPage) {
songs=currentPage->selectedSongs();
}
if (!songs.isEmpty()) {
QString udi;
#ifdef ENABLE_DEVICES_SUPPORT
if (currentPage==devicesPage) {
udi=devicesPage->activeFsDeviceUdi();
if (udi.isEmpty()) {
return;
}
}
#endif
RgDialog *dlg=new RgDialog(this);
dlg->show(songs, udi);
}
#endif
}
void MainWindow::setCover()
{
if (CoverDialog::instanceCount() || !canShowDialog()) {
return;
}
Song song;
if (currentPage) {
song=currentPage->coverRequest();
}
if (!song.isEmpty()) {
CoverDialog *dlg=new CoverDialog(this);
dlg->show(song);
}
}
void MainWindow::updateNextTrack(int nextTrackId)
{
if (-1!=nextTrackId && MPDState_Stopped==MPDStatus::self()->state()) {
nextTrackId=-1; // nextSongId is not accurate if we are stopped.
}
QString tt=StdActions::self()->nextTrackAction->property("tooltip").toString();
if (-1==nextTrackId && tt.isEmpty()) {
StdActions::self()->nextTrackAction->setProperty("tooltip", StdActions::self()->nextTrackAction->toolTip());
} else if (-1==nextTrackId) {
StdActions::self()->nextTrackAction->setToolTip(tt);
StdActions::self()->nextTrackAction->setProperty("trackid", nextTrackId);
} else if (nextTrackId!=StdActions::self()->nextTrackAction->property("trackid").toInt()) {
Song s=playQueueModel.getSongByRow(playQueueModel.getRowById(nextTrackId));
if (!s.artist.isEmpty() && !s.title.isEmpty()) {
tt+=QLatin1String("
")+s.artistSong()+QLatin1String("");
} else {
nextTrackId=-1;
}
StdActions::self()->nextTrackAction->setToolTip(tt);
StdActions::self()->nextTrackAction->setProperty("trackid", nextTrackId);
}
}
void MainWindow::updateActionToolTips()
{
ActionCollection::get()->updateToolTips();
tabWidget->setToolTip(PAGE_PLAYQUEUE, showPlayQueueAction->toolTip());
tabWidget->setToolTip(PAGE_LIBRARY, libraryTabAction->toolTip());
tabWidget->setToolTip(PAGE_ALBUMS, albumsTabAction->toolTip());
tabWidget->setToolTip(PAGE_FOLDERS, foldersTabAction->toolTip());
tabWidget->setToolTip(PAGE_PLAYLISTS, playlistsTabAction->toolTip());
#ifdef ENABLE_DYNAMIC
tabWidget->setToolTip(PAGE_DYNAMIC, dynamicTabAction->toolTip());
#endif
#ifdef ENABLE_STREAMS
tabWidget->setToolTip(PAGE_STREAMS, streamsTabAction->toolTip());
#endif
#ifdef ENABLE_ONLINE_SERVICES
tabWidget->setToolTip(PAGE_ONLINE, onlineTabAction->toolTip());
#endif
#ifdef ENABLE_DEVICES_SUPPORT
tabWidget->setToolTip(PAGE_DEVICES, devicesTabAction->toolTip());
#endif
tabWidget->setToolTip(PAGE_SEARCH, searchTabAction->toolTip());
tabWidget->setToolTip(PAGE_CONTEXT, songInfoAction->toolTip());
}
void MainWindow::setPlaylistsEnabled(bool e)
{
PlaylistsModel::self()->setEnabled(e);
controlPlaylistActions();
}
void MainWindow::controlPlaylistActions()
{
bool enable=!MPDConnection::self()->isMopdidy() && PlaylistsModel::self()->isEnabled();
StdActions::self()->addToStoredPlaylistAction->setVisible(enable);
StdActions::self()->savePlayQueueAction->setVisible(enable);
savePlayQueueButton->setVisible(enable);
addPlayQueueToStoredPlaylistAction->setVisible(enable);
}
void MainWindow::startContextTimer()
{
if (!contextSwitchTime || current.isStandardStream()) {
return;
}
if (!contextTimer) {
contextTimer=new QTimer(this);
contextTimer->setSingleShot(true);
connect(contextTimer, SIGNAL(timeout()), this, SLOT(toggleContext()));
}
contextTimer->start(contextSwitchTime);
}
int MainWindow::calcMinHeight()
{
if (tabWidget->style()&FancyTabWidget::Side && tabWidget->style()&FancyTabWidget::Large) {
return toolbar->height()+(tabWidget->visibleCount()*tabWidget->tabSize().height());
} else {
return Utils::scaleForDpi(256);
}
}
int MainWindow::calcCollapsedSize()
{
if (showMenuAction && menuButton && showMenuAction->isChecked()) {
return toolbar->height()+menuBar()->height();
}
return toolbar->height();
}
void MainWindow::setCollapsedSize()
{
if (!expandInterfaceAction->isChecked()) {
int w=width();
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
adjustSize();
collapsedSize=QSize(w, calcCollapsedSize());
resize(collapsedSize);
setFixedHeight(collapsedSize.height());
}
}
void MainWindow::expandOrCollapse(bool saveCurrentSize)
{
if (!expandInterfaceAction->isChecked() && (isFullScreen() || isMaximized() || messageWidget->isVisible())) {
expandInterfaceAction->setChecked(true);
return;
}
static bool lastMax=false;
bool showing=expandInterfaceAction->isChecked();
QPoint p(isVisible() ? pos() : QPoint());
if (!showing) {
setMinimumHeight(0);
lastMax=isMaximized();
if (saveCurrentSize) {
expandedSize=size();
}
} else {
if (saveCurrentSize) {
collapsedSize=size();
}
setMinimumHeight(calcMinHeight());
setMaximumHeight(QWIDGETSIZE_MAX);
}
int prevWidth=size().width();
stack->setVisible(showing);
if (!showing) {
setWindowState(windowState()&~Qt::WindowMaximized);
}
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
adjustSize();
if (showing) {
bool adjustWidth=size().width()!=expandedSize.width();
bool adjustHeight=size().height()!=expandedSize.height();
if (adjustWidth || adjustHeight) {
resize(adjustWidth ? expandedSize.width() : size().width(), adjustHeight ? expandedSize.height() : size().height());
}
if (lastMax) {
showMaximized();
}
} else {
// Width also sometimes expands, so make sure this is no larger than it was before...
collapsedSize=QSize(collapsedSize.isValid() ? collapsedSize.width() : (size().width()>prevWidth ? prevWidth : size().width()), calcCollapsedSize());
resize(collapsedSize);
setFixedHeight(size().height());
}
if (!p.isNull()) {
move(p);
}
fullScreenAction->setEnabled(showing);
songInfoButton->setVisible(songInfoAction->isCheckable() && showing);
songInfoAction->setEnabled(showing);
}
void MainWindow::toggleContext()
{
if ( songInfoButton->isVisible()) {
if ( (MPDState_Playing==MPDStatus::self()->state() && !songInfoAction->isChecked()) ||
(MPDState_Stopped==MPDStatus::self()->state() && songInfoAction->isChecked()) ) {
songInfoAction->trigger();
}
} else if (MPDState_Playing==MPDStatus::self()->state() && PAGE_CONTEXT!=tabWidget->currentIndex()) {
int pp=prevPage;
showTab(PAGE_CONTEXT);
prevPage=pp;
} else if (MPDState_Stopped==MPDStatus::self()->state() && PAGE_CONTEXT==tabWidget->currentIndex() && -1!=prevPage) {
showTab(prevPage);
}
}
void MainWindow::toggleMenubar()
{
if (showMenuAction && menuButton) {
menuButton->setVisible(!showMenuAction->isChecked());
menuBar()->setVisible(showMenuAction->isChecked());
setCollapsedSize();
}
}
#if !defined Q_OS_WIN && !defined Q_OS_MAC && QT_VERSION < 0x050000
#include
#include
#endif
void MainWindow::hideWindow()
{
lastPos=pos();
hide();
}
void MainWindow::restoreWindow()
{
bool wasHidden=isHidden();
#ifdef Q_OS_WIN // FIXME - need on mac?
raiseWindow(this);
#endif
raise();
showNormal();
activateWindow();
#if !defined Q_OS_WIN && !defined Q_OS_MAC
// This section seems to be required for compiz, so that MPRIS.Raise actually shows the window, and not just highlight launcher.
#if QT_VERSION < 0x050000
static const Atom constNetActive=XInternAtom(QX11Info::display(), "_NET_ACTIVE_WINDOW", False);
QX11Info info;
XEvent xev;
xev.xclient.type = ClientMessage;
xev.xclient.serial = 0;
xev.xclient.send_event = True;
xev.xclient.message_type = constNetActive;
xev.xclient.display = QX11Info::display();
xev.xclient.window = effectiveWinId();
xev.xclient.format = 32;
xev.xclient.data.l[0] = 2;
xev.xclient.data.l[1] = xev.xclient.data.l[2] = xev.xclient.data.l[3] = xev.xclient.data.l[4] = 0;
XSendEvent(QX11Info::display(), QX11Info::appRootWindow(info.screen()), False, SubstructureRedirectMask|SubstructureNotifyMask, &xev);
#else // QT_VERSION < 0x050000
QString wmctrl=Utils::findExe(QLatin1String("wmctrl"));
if (!wmctrl.isEmpty()) {
if (wasHidden) {
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
}
QProcess::execute(wmctrl, QStringList() << QLatin1String("-i") << QLatin1String("-a") << QString::number(effectiveWinId()));
}
#endif // QT_VERSION < 0x050000
#endif // !defined Q_OS_WIN && !defined Q_OS_MAC
if (wasHidden && !lastPos.isNull()) {
move(lastPos);
}
#ifdef ENABLE_KDE_SUPPORT
KWindowSystem::forceActiveWindow(effectiveWinId());
#endif
}
#ifdef Q_OS_WIN
// This is down here, because windows.h includes ALL windows stuff - and we get conflicts with MessageBox :-(
#include
static void raiseWindow(QWidget *w)
{
::SetWindowPos(reinterpret_cast(w->effectiveWinId()), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
::SetWindowPos(reinterpret_cast(w->effectiveWinId()), HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
}
#endif