/***************************************************************************
* Copyright (C) 2006-2018 by Ilya Kotov *
* forkotov02@ya.ru *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <QFileDialog>
#include <QDir>
#include <QAction>
#include <QMenu>
#include <QScreen>
#include <math.h>
#include <qmmp/soundcore.h>
#include <qmmp/visual.h>
#include <qmmp/metadatamanager.h>
#include <qmmpui/uihelper.h>
#include <qmmpui/general.h>
#include <qmmpui/playlistparser.h>
#include <qmmpui/playlistformat.h>
#include <qmmpui/commandlinemanager.h>
#include <qmmpui/filedialog.h>
#include <qmmpui/playlistmodel.h>
#include <qmmpui/playlistmanager.h>
#include <qmmpui/mediaplayer.h>
#include <qmmpui/configdialog.h>
#include <qmmpui/qmmpuisettings.h>
#include "hotkeyeditor.h"
#include "skinnedsettings.h"
#include "mainwindow.h"
#include "skin.h"
#include "playlist.h"
#include "dock.h"
#include "eqwidget.h"
#include "mainvisual.h"
#include "listwidget.h"
#include "visualmenu.h"
#include "windowsystem.h"
#include "actionmanager.h"
#define KEY_OFFSET 10000
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
#ifdef QMMP_WS_X11
qDebug("MainWindow: detected wm: %s", qPrintable(WindowSystem::netWindowManagerName()));
#endif
m_vis = 0;
m_update = false;
#ifdef QMMP_WS_X11
QString wm_name = WindowSystem::netWindowManagerName();
if(wm_name.contains("Marco", Qt::CaseInsensitive) ||
wm_name.contains("Metacity", Qt::CaseInsensitive) ||
wm_name.contains("Mutter", Qt::CaseInsensitive) ||
wm_name.contains("GNOME", Qt::CaseInsensitive))
{
setWindowFlags(Qt::Window | Qt::FramelessWindowHint |
Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint);
}
else
#endif
setWindowFlags(Qt::Window | Qt::FramelessWindowHint |
Qt::WindowCloseButtonHint | Qt::WindowMinMaxButtonsHint | Qt::WindowSystemMenuHint);
restoreWindowTitle();
m_titleFormatter.setPattern("%if(%p,%p - %t,%t)");
new ActionManager(this);
m_player = MediaPlayer::instance();
m_core = SoundCore::instance();
m_pl_manager = PlayListManager::instance();
m_uiHelper = UiHelper::instance();
m_ui_settings = QmmpUiSettings::instance();
//user interface
m_skin = new Skin(this);
setFixedSize(275 * m_skin->ratio(),116 * m_skin->ratio());
Dock *dock = new Dock(this);
dock->setMainWidget(this);
m_display = new MainDisplay(this);
setCentralWidget(m_display);
m_display->setFocus ();
m_playlist = new PlayList(m_pl_manager, this);
dock->addWidget(m_playlist);
m_equalizer = new EqWidget(this);
dock->addWidget(m_equalizer);
createActions();
//prepare visualization
Visual::initialize(this, m_visMenu, SLOT(updateActions()));
m_vis = MainVisual::instance();
Visual::add(m_vis);
//connections
connect (m_player,SIGNAL(playbackFinished()), SLOT(restoreWindowTitle()));
connect (m_playlist,SIGNAL(next()),SLOT(next()));
connect (m_playlist,SIGNAL(prev()),SLOT(previous()));
connect (m_playlist,SIGNAL(play()),SLOT(play()));
connect (m_playlist,SIGNAL(pause()), m_core ,SLOT(pause()));
connect (m_playlist,SIGNAL(stop()),SLOT(stop()));
connect (m_playlist,SIGNAL(eject()),SLOT(playFiles()));
connect (m_playlist,SIGNAL(loadPlaylist()),SLOT(loadPlaylist()));
connect (m_playlist,SIGNAL(savePlaylist()),SLOT(savePlaylist()));
connect(m_display,SIGNAL(shuffleToggled(bool)),m_ui_settings,SLOT(setShuffle(bool)));
connect(m_display,SIGNAL(repeatableToggled(bool)),m_ui_settings,SLOT(setRepeatableList(bool)));
connect(m_core, SIGNAL(stateChanged(Qmmp::State)), SLOT(showState(Qmmp::State)));
connect(m_core, SIGNAL(elapsedChanged(qint64)),m_playlist, SLOT(setTime(qint64)));
connect(m_core, SIGNAL(trackInfoChanged()),SLOT(showMetaData()));
connect(m_uiHelper, SIGNAL(toggleVisibilityCalled()), SLOT(toggleVisibility()));
connect(m_uiHelper, SIGNAL(showMainWindowCalled()), SLOT(showAndRaise()));
readSettings();
m_display->setEQ(m_equalizer);
m_display->setPL(m_playlist);
dock->updateDock();
m_pl_manager->currentPlayList()->doCurrentVisibleRequest();
if (m_startHidden && m_uiHelper->visibilityControl())
toggleVisibility();
}
MainWindow::~MainWindow()
{}
void MainWindow::play()
{
m_player->play();
}
void MainWindow::replay()
{
stop();
m_pl_manager->activatePlayList(m_pl_manager->selectedPlayList());
play();
}
void MainWindow::forward()
{
m_core->seek(m_core->elapsed() + KEY_OFFSET);
}
void MainWindow::backward()
{
m_core->seek(qMax(qint64(0), m_core->elapsed() - KEY_OFFSET));
}
void MainWindow::pause(void)
{
m_core->pause();
}
void MainWindow::stop()
{
m_player->stop();
}
void MainWindow::next()
{
m_player->next();
}
void MainWindow::previous()
{
m_player->previous();
}
void MainWindow::showState(Qmmp::State state)
{
switch ((int) state)
{
case Qmmp::Playing:
if (m_pl_manager->currentPlayList()->currentTrack())
m_equalizer->loadPreset(m_pl_manager->currentPlayList()->currentTrack()->path().section("/",-1));
break;
case Qmmp::Paused:
break;
case Qmmp::Stopped:
m_playlist->setTime(-1);
break;
}
}
void MainWindow::showMetaData()
{
PlayListTrack *track = m_pl_manager->currentPlayList()->currentTrack();
if (track && track->path() == m_core->trackInfo().path())
{
setWindowTitle(m_titleFormatter.format(track));
}
}
void MainWindow::closeEvent (QCloseEvent *)
{
if (!m_hideOnClose || !m_uiHelper->visibilityControl())
m_uiHelper->exit();
else
{
m_playlist->close();
m_equalizer->close();
}
}
void MainWindow::hideEvent (QHideEvent *)
{
writeSettings();
m_playlist->writeSettings();
m_equalizer->writeSettings();
}
void MainWindow::addDir()
{
m_uiHelper->addDirectory(this);
}
void MainWindow::addFile()
{
m_uiHelper->addFiles(this);
}
void MainWindow::playFiles()
{
m_uiHelper->playFiles(this);
}
void MainWindow::changeEvent (QEvent * event)
{
if (event->type() == QEvent::ActivationChange)
{
m_display->setActive(isActiveWindow());
}
}
void MainWindow::readSettings()
{
QSettings settings(Qmmp::configFile(), QSettings::IniFormat);
settings.beginGroup("Skinned");
m_titleFormatter.setPattern(settings.value("window_title_format","%if(%p,%p - %t,%t)").toString());
if (m_update)
{
if(ACTION(ActionManager::WM_ALLWAYS_ON_TOP)->isChecked())
{
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
m_playlist->setWindowFlags(m_playlist->windowFlags() | Qt::WindowStaysOnTopHint);
m_equalizer->setWindowFlags(m_equalizer->windowFlags() | Qt::WindowStaysOnTopHint);
}
else
{
setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint);
m_playlist->setWindowFlags(m_playlist->windowFlags() & ~Qt::WindowStaysOnTopHint);
m_equalizer->setWindowFlags(m_equalizer->windowFlags() & ~Qt::WindowStaysOnTopHint);
}
show();
qApp->processEvents();
m_playlist->setVisible(m_display->isPlaylistVisible());
m_equalizer->setVisible(m_display->isEqualizerVisible());
if(m_pl_manager->currentPlayList()->currentTrack())
setWindowTitle(m_titleFormatter.format(m_pl_manager->currentPlayList()->currentTrack()));
}
else
{
QScreen *screen = QGuiApplication::primaryScreen();
QRect availableGeometry = screen->availableGeometry();
QPoint pos = settings.value("mw_pos", QPoint(100, 100)).toPoint();
int r = m_skin->ratio();
foreach(QScreen *screen, QGuiApplication::screens())
{
if(screen->availableGeometry().contains(pos))
{
availableGeometry = screen->availableGeometry();
break;
}
}
pos.setX(qBound(availableGeometry.left(), pos.x(), availableGeometry.right() - r*275));
pos.setY(qBound(availableGeometry.top(), pos.y(), availableGeometry.bottom() - r*116));
move(pos); //geometry
m_startHidden = settings.value("start_hidden", false).toBool();
if(settings.value("always_on_top", false).toBool())
{
ACTION(ActionManager::WM_ALLWAYS_ON_TOP)->setChecked(true);
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
}
ACTION(ActionManager::WM_STICKY)->setChecked(settings.value("show_on_all_desktops",
false).toBool());
show();
qApp->processEvents();
//visibility
m_playlist->setVisible(settings.value("pl_visible",true).toBool());
qApp->processEvents();
m_equalizer->setVisible(settings.value("eq_visible",true).toBool());
qApp->processEvents();
// Repeat/Shuffle
m_display->setIsRepeatable(m_ui_settings->isRepeatableList());
m_display->setIsShuffle(m_ui_settings->isShuffle());
ACTION(ActionManager::REPEAT_ALL)->setChecked(m_ui_settings->isRepeatableList());
ACTION(ActionManager::SHUFFLE)->setChecked(m_ui_settings->isShuffle());
ACTION(ActionManager::REPEAT_TRACK)->setChecked(m_ui_settings->isRepeatableTrack());
ACTION(ActionManager::NO_PL_ADVANCE)->setChecked(m_ui_settings->isNoPlayListAdvance());
m_update = true;
}
#ifdef QMMP_WS_X11
WindowSystem::changeWinSticky(winId(), ACTION(ActionManager::WM_STICKY)->isChecked());
WindowSystem::setWinHint(winId(), "player", "Qmmp");
#endif
//Call setWindowOpacity only if needed
double opacity = settings.value("mw_opacity", 1.0).toDouble();
if(opacity != windowOpacity ())
setWindowOpacity(opacity);
opacity = settings.value("eq_opacity", 1.0).toDouble();
if(opacity != m_equalizer->windowOpacity ())
m_equalizer->setWindowOpacity(opacity);
opacity = settings.value("pl_opacity", 1.0).toDouble();
if(opacity != m_playlist->windowOpacity ())
m_playlist->setWindowOpacity(opacity);
m_hideOnClose = settings.value("hide_on_close", false).toBool();
settings.endGroup();
Dock::instance()->addActions(m_uiHelper->actions(UiHelper::PLAYLIST_MENU));
Dock::instance()->addActions(m_uiHelper->actions(UiHelper::TOOLS_MENU));
}
void MainWindow::writeSettings()
{
QSettings settings(Qmmp::configFile(), QSettings::IniFormat);
settings.beginGroup("Skinned");
//geometry
settings.setValue("mw_pos", this->pos());
//look & feel
settings.setValue("double_size", ACTION(ActionManager::WM_DOUBLE_SIZE)->isChecked());
settings.setValue("always_on_top", ACTION(ActionManager::WM_ALLWAYS_ON_TOP)->isChecked());
settings.setValue("show_on_all_desktops", ACTION(ActionManager::WM_STICKY)->isChecked());
settings.setValue("antialiasing", ACTION(ActionManager::WM_ANTIALIASING)->isChecked());
settings.endGroup();
}
void MainWindow::showSettings()
{
ConfigDialog *confDialog = new ConfigDialog(this);
SkinnedSettings *skinnedSettings = new SkinnedSettings(this);
confDialog->addPage(tr("Appearance"), skinnedSettings, QIcon(":/skinned/interface.png"));
confDialog->addPage(tr("Shortcuts"), new HotkeyEditor(this), QIcon(":/skinned/shortcuts.png"));
confDialog->exec();
skinnedSettings->writeSettings();
confDialog->deleteLater();
updateSettings();
ActionManager::instance()->saveActions();
}
void MainWindow::toggleVisibility()
{
if (isHidden() || isMinimized())
{
show();
raise();
activateWindow();
m_playlist->setVisible(m_display->isPlaylistVisible());
m_equalizer->setVisible(m_display->isEqualizerVisible());
#ifdef QMMP_WS_X11
if(WindowSystem::netWindowManagerName() == "Metacity")
{
m_playlist->activateWindow();
m_equalizer->activateWindow();
}
#endif
qApp->processEvents();
setFocus ();
if (isMinimized())
{
showNormal();
}
#ifdef QMMP_WS_X11
WindowSystem::changeWinSticky(winId(), ACTION(ActionManager::WM_STICKY)->isChecked());
WindowSystem::setWinHint(winId(), "player", "Qmmp");
raise();
#endif
}
else
{
if (m_playlist->isVisible())
m_playlist->hide();
if (m_equalizer->isVisible())
m_equalizer->hide();
hide();
}
qApp->processEvents();
}
void MainWindow::showAndRaise()
{
if(isHidden() || isMinimized())
toggleVisibility();
else
{
activateWindow();
raise();
}
}
void MainWindow::createActions()
{
m_mainMenu = new QMenu(this);
m_mainMenu->addAction(SET_ACTION(ActionManager::PLAY, this, SLOT(play())));
m_mainMenu->addAction(SET_ACTION(ActionManager::PAUSE, this, SLOT(pause())));
m_mainMenu->addAction(SET_ACTION(ActionManager::STOP, this, SLOT(stop())));
m_mainMenu->addAction(SET_ACTION(ActionManager::PREVIOUS, this, SLOT(previous())));
m_mainMenu->addAction(SET_ACTION(ActionManager::NEXT, this, SLOT(next())));
m_mainMenu->addAction(SET_ACTION(ActionManager::PLAY_PAUSE, this, SLOT(playPause())));
m_mainMenu->addSeparator();