/***************************************************************************
* Copyright (C) 2006 by Ilya Kotov *
* forkotov02@hotmail.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., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <QPainter>
#include <QResizeEvent>
#include <QSettings>
#include <QMenu>
#include <QAction>
#include <QSignalMapper>
#include <QHBoxLayout>
#include "dock.h"
#include "fileloader.h"
#include "playlist.h"
#include "skin.h"
#include "listwidget.h"
#include "button.h"
#include "mediafile.h"
#include "playlistmodel.h"
#include "playlisttitlebar.h"
#include "playlistslider.h"
#include "pixmapwidget.h"
#include "symboldisplay.h"
#include "playlistcontrol.h"
#include "keyboardmanager.h"
#include <qmmp/output.h>
PlayList::PlayList ( QWidget *parent )
: QWidget ( parent )
{
setWindowFlags ( Qt::Dialog | Qt::FramelessWindowHint );
m_update = FALSE;
m_resize = FALSE;
m_anchor_row = -1;
createMenus();
resize ( 275,116 );
setMinimumSize ( 275,116 );
setBaseSize ( 275,116 );
m_listWidget = new ListWidget ( this );
m_listWidget->show();
m_listWidget->setGeometry ( 12,20,243,58 );
m_plslider = new PlayListSlider ( this );
m_plslider->show();
setSizeIncrement ( 25,29 );
m_skin = Skin::getPointer();
m_buttonAdd = new Button ( this,Skin::PL_BT_ADD,Skin::PL_BT_ADD );
m_buttonAdd->move ( 11,86 );
m_buttonSub = new Button ( this,Skin::PL_BT_SUB,Skin::PL_BT_SUB );
m_buttonSub->move ( 40,86 );
m_selectButton = new Button ( this,Skin::PL_BT_SEL,Skin::PL_BT_SEL );
m_selectButton->move ( 70,86 );
m_sortButton= new Button ( this,Skin::PL_BT_SORT,Skin::PL_BT_SORT );
m_sortButton->move ( 99,86 );
m_playlistButton = new Button ( this,Skin::PL_BT_LST,Skin::PL_BT_LST );
m_pl_control = new PlaylistControl ( this );
m_pl_control->move ( 0,0 );
m_pl_control->show();
m_length_totalLength = new SymbolDisplay ( this,14 );
m_length_totalLength->setAlignment ( Qt::AlignLeft );
m_length_totalLength -> show();
m_current_time = new SymbolDisplay ( this,6 );
m_current_time->show();
m_keyboardManager = new KeyboardManager ( this );
connect ( m_listWidget, SIGNAL ( selectionChanged() ), parent, SLOT ( replay() ) );
connect ( m_plslider, SIGNAL ( sliderMoved ( int ) ), m_listWidget, SLOT ( scroll ( int ) ) );
connect ( m_listWidget, SIGNAL ( positionChanged ( int, int ) ), m_plslider,
SLOT ( setPos ( int, int ) ) );
connect ( m_skin, SIGNAL ( skinChanged() ), this, SLOT ( update() ) );
connect ( m_buttonAdd, SIGNAL ( clicked() ), SLOT ( showAddMenu() ) );
connect ( m_buttonSub, SIGNAL ( clicked() ), SLOT ( showSubMenu() ) );
connect ( m_selectButton, SIGNAL ( clicked() ), SLOT ( showSelectMenu() ) );
connect ( m_sortButton, SIGNAL ( clicked() ), SLOT ( showSortMenu() ) );
connect ( m_playlistButton, SIGNAL ( clicked() ), SLOT ( showPlaylistMenu() ) );
connect ( m_pl_control, SIGNAL ( nextClicked() ), SIGNAL ( next() ) );
connect ( m_pl_control, SIGNAL ( previousClicked() ), SIGNAL ( prev() ) );
connect ( m_pl_control, SIGNAL ( playClicked() ), SIGNAL ( play() ) );
connect ( m_pl_control, SIGNAL ( pauseClicked() ), SIGNAL ( pause() ) );
connect ( m_pl_control, SIGNAL ( stopClicked() ), SIGNAL ( stop() ) );
connect ( m_pl_control, SIGNAL ( ejectClicked() ), SIGNAL ( eject() ) );
m_titleBar = new PlayListTitleBar ( this );
m_titleBar->move ( 0,0 );
readSettings();
}
PlayList::~PlayList()
{}
void PlayList::createMenus()
{
m_addMenu = new QMenu ( this );
m_subMenu = new QMenu ( this );
m_selectMenu = new QMenu ( this );
m_sortMenu = new QMenu ( this );
m_playlistMenu = new QMenu ( this );
}
void PlayList::createActions()
{ //add menu
QAction *addFileAct = new QAction ( tr ( "&Add File" ),this );
addFileAct->setShortcut ( tr ( "F" ) );
m_addMenu->addAction ( addFileAct );
connect ( addFileAct, SIGNAL ( triggered() ), parent(), SLOT ( addFile () ) );
m_actions << addFileAct;
QAction *addDirAct = new QAction ( tr ( "&Add Directory" ),this );
addDirAct->setShortcut ( tr ( "D" ) );
m_addMenu->addAction ( addDirAct );
connect ( addDirAct, SIGNAL ( triggered() ), parent(), SLOT ( addDir () ) );
m_actions << addDirAct;
QAction *addUrlAct = new QAction ( tr ( "&Add Url" ),this );
addUrlAct->setShortcut ( tr ( "U" ) );
m_addMenu->addAction ( addUrlAct );
connect ( addUrlAct, SIGNAL ( triggered() ), parent(), SLOT ( addUrl () ) );
m_actions << addUrlAct;
//remove menu
QAction *remSelAct = new QAction ( tr ( "&Remove Selected" ),this );
remSelAct->setShortcut ( tr ( "Del" ) );
m_subMenu->addAction ( remSelAct );
connect ( remSelAct, SIGNAL ( triggered() ),
m_playListModel, SLOT ( removeSelected () ) );
this->addAction ( remSelAct );
QAction *remAllAct = new QAction ( tr ( "&Remove All" ),this );
//remAllAct->setShortcut(tr("D")); FIXME: add correct shortcat
m_subMenu->addAction ( remAllAct );
connect ( remAllAct, SIGNAL ( triggered() ), m_playListModel, SLOT ( clear () ) );
m_actions << remAllAct;
QAction *remUnselAct = new QAction ( tr ( "&Remove Unselected" ),this );
m_subMenu->addAction ( remUnselAct );
connect ( remUnselAct, SIGNAL ( triggered() ),
m_playListModel, SLOT ( removeUnselected () ) );
//listwidget menu
QAction *detailsAct = new QAction ( tr ( "&View Track Details" ),this );
detailsAct->setShortcut ( tr ( "Alt+I" ) );
m_listWidget->menu()->addAction ( detailsAct );
connect ( detailsAct, SIGNAL ( triggered() ), m_playListModel, SLOT ( showDetails () ) );
// sort menu
m_sortMenu->addAction ( detailsAct );
m_sortMenu->addSeparator();
QMenu* sort_mode_menu = new QMenu ( tr ( "Sort List" ),m_sortMenu );
QSignalMapper* signalMapper = new QSignalMapper ( this );
QAction* titleAct = sort_mode_menu->addAction ( tr ( "By Title" ) );
connect ( titleAct, SIGNAL ( triggered ( bool ) ), signalMapper, SLOT ( map() ) );
signalMapper->setMapping ( titleAct, PlayListModel::TITLE );
QAction* nameAct = sort_mode_menu->addAction ( tr ( "By Filename" ) );
connect ( nameAct, SIGNAL ( triggered ( bool ) ), signalMapper, SLOT ( map() ) );
signalMapper->setMapping ( nameAct, PlayListModel::FILENAME );
QAction* pathnameAct = sort_mode_menu->addAction ( tr ( "By Path + Filename" ) );
connect ( pathnameAct, SIGNAL ( triggered ( bool ) ), signalMapper, SLOT ( map() ) );
signalMapper->setMapping ( pathnameAct, PlayListModel::PATH_AND_FILENAME );
QAction* dateAct = sort_mode_menu->addAction ( tr ( "By Date" ) );
connect ( dateAct, SIGNAL ( triggered ( bool ) ), signalMapper, SLOT ( map() ) );
signalMapper->setMapping ( dateAct, PlayListModel::DATE );
connect ( signalMapper, SIGNAL ( mapped ( int ) ),
m_playListModel, SLOT ( sort ( int ) ) );
m_sortMenu->addMenu ( sort_mode_menu );
sort_mode_menu = new QMenu ( tr ( "Sort Selection" ),m_sortMenu );
signalMapper = new QSignalMapper ( this );
titleAct = sort_mode_menu->addAction ( tr ( "By Title" ) );
connect ( titleAct, SIGNAL ( triggered ( bool ) ), signalMapper, SLOT ( map() ) );
signalMapper->setMapping ( titleAct, PlayListModel::TITLE );
nameAct = sort_mode_menu->addAction ( tr ( "By Filename" ) );
connect ( nameAct, SIGNAL ( triggered ( bool ) ), signalMapper, SLOT ( map() ) );
signalMapper->setMapping ( nameAct, PlayListModel::FILENAME );
pathnameAct = sort_mode_menu->addAction ( tr ( "By Path + Filename" ) );
connect ( pathnameAct, SIGNAL ( triggered ( bool ) ), signalMapper, SLOT ( map() ) );
signalMapper->setMapping ( pathnameAct, PlayListModel::PATH_AND_FILENAME );
dateAct = sort_mode_menu->addAction ( tr ( "By Date" ) );
connect ( dateAct, SIGNAL ( triggered ( bool ) ), signalMapper, SLOT ( map() ) );
signalMapper->setMapping ( dateAct, PlayListModel::DATE );
connect ( signalMapper, SIGNAL ( mapped ( int ) ),
m_playListModel, SLOT ( sortSelection ( int ) ) );
m_sortMenu->addMenu ( sort_mode_menu );
m_sortMenu->addSeparator();
m_sortMenu->addAction ( tr ( "Randomize List" ),m_playListModel,SLOT ( randomizeList() ) );
m_sortMenu->addAction ( tr ( "Reverse List" ),m_playListModel,SLOT ( reverseList() ) );
m_listWidget->menu()->addSeparator();
m_listWidget->menu()->addActions ( m_subMenu->actions() );
m_actions << detailsAct;
//select menu
QAction *invSelAct = new QAction ( tr ( "Invert Selection" ),this );
m_selectMenu->addAction ( invSelAct );
connect ( invSelAct, SIGNAL ( triggered() ),
m_playListModel, SLOT ( invertSelection () ) );
m_selectMenu->addSeparator();
QAction *selNoneAct = new QAction ( tr ( "&Select None" ),this );
//selNoneAct->setShortcut(tr("Ctrl+Shift+A"));
m_selectMenu->addAction ( selNoneAct );
connect ( selNoneAct, SIGNAL ( triggered() ),
m_playListModel, SLOT ( clearSelection () ) );
this->addAction ( selNoneAct );
QAction *selAllAct = new QAction ( tr ( "&Select All" ),this );
selAllAct->setShortcut ( tr ( "Ctrl+A" ) );
m_selectMenu->addAction ( selAllAct );
connect ( selAllAct, SIGNAL ( triggered() ),
m_playListModel, SLOT ( selectAll () ) );
this->addAction ( selAllAct );
// Playlist Menu
QAction *newListAct = new QAction ( tr ( "&New List" ),this );
newListAct->setShortcut ( tr ( "Shift+N" ) );
m_actions << newListAct;
m_playlistMenu->addAction ( newListAct );
connect ( newListAct, SIGNAL ( triggered() ), this, SIGNAL ( newPlaylist() ) );
m_playlistMenu->addSeparator();
QAction *loadListAct = new QAction ( tr ( "&Load List" ),this );
loadListAct->setShortcut ( tr ( "O" ) );
m_playlistMenu->addAction ( loadListAct );
connect ( loadListAct, SIGNAL ( triggered() ), this, SIGNAL ( loadPlaylist() ) );
QAction *saveListAct = new QAction ( tr ( "&Save List" ),this );
saveListAct->setShortcut ( tr ( "Shift+S" ) );
m_playlistMenu->addAction ( saveListAct );
connect ( saveListAct, SIGNAL ( triggered() ), this, SIGNAL ( savePlaylist() ) );
this->addActions ( m_playlistMenu->actions() );
Dock::getPointer()->addActions ( m_actions );
}
void PlayList::closeEvent ( QCloseEvent* )
{
writeSettings();
}
void PlayList::paintEvent ( QPaintEvent * )
{
int m_sx = ( width()-275 ) /25;
int m_sy = ( height()-116 ) /29;
drawPixmap ( m_sx, m_sy );
}
void PlayList::drawPixmap ( int sx, int sy )
{
QPainter paint;
paint.begin ( this );
paint.drawPixmap ( 0,20,m_skin->getPlPart ( Skin::PL_LFILL ) );
for ( int i = 1; i<sy+2; i++ )
{
paint.drawPixmap ( 0,20+29*i,m_skin->getPlPart ( Skin::PL_LFILL ) );
}
paint.drawPixmap ( 0,78+29*sy,m_skin->getPlPart ( Skin::PL_LSBAR ) );
for ( int i = 0; i<sx; i++ )
{
paint.drawPixmap ( 125+i*25,78+sy*29,m_skin->getPlPart ( Skin::PL_SFILL1 ) );
}
paint.drawPixmap ( 125+sx*25,78+sy*29,m_skin->getPlPart ( Skin::PL_RSBAR ) );
paint.end();
}
void PlayList::resizeEvent ( QResizeEvent *e )
{
int sx = ( e->size().width()-275 ) /25;
int sy = ( e->size().height()-116 ) /29;
if (sx < 0 || sy < 0)
return;
m_titleBar->resize ( 275+25*sx,20 );
m_plslider->resize ( 20,58+sy*29 );
m_listWidget->resize ( 243+25*sx,58+29*sy );
m_buttonAdd->move ( 11,86+29*sy );
m_buttonSub->move ( 40,86+29*sy );
m_selectButton->move ( 70,86+29*sy );
m_sortButton->move ( 99,86+29*sy );
m_pl_control->move ( 128+sx*25,100+29*sy );
m_playlistButton->move ( 228+sx*25,86+29*sy );
m_length_totalLength -> move ( 131+sx*25,88+29*sy );
m_current_time->move ( 190+sx*25,101+29*sy );
m_plslider->move ( 255+sx*25,20 );
}
void PlayList::mousePressEvent ( QMouseEvent *e )
{
m_pos = e->pos ();
if ( ( m_pos.x() > width()-25 ) && ( m_pos.y() > height()-25 ) )
{
m_resize = TRUE;
setCursor ( Qt::SizeFDiagCursor );
}
else
m_resize = FALSE;
}
void PlayList::mouseMoveEvent ( QMouseEvent *e )
{
if ( m_resize )
{
resize ( e->x() +25, e->y() +25 );
//usleep(32000);
}
}
void PlayList::mouseReleaseEvent ( QMouseEvent * )
{
setCursor ( Qt::ArrowCursor );
/*if (m_resize)
m_listWidget->updateList();*/
m_resize = FALSE;
Dock::getPointer()->updateDock();
}
void PlayList::setModel ( PlayListModel *model )
{
m_playListModel = model;
m_listWidget->setModel (model);
m_keyboardManager->setModel (model);
m_titleBar->setModel (model);
createActions();
}
void PlayList::changeEvent ( QEvent * event )
{
if ( event->type() == QEvent::ActivationChange )
{
m_titleBar->setActive ( isActiveWindow() );
}
}
void PlayList::readSettings()
{
if ( m_update )
{
m_listWidget->readSettings();
m_titleBar->readSettings();
}
else
{
QSettings settings (QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat);
settings.beginGroup ( "PlayList" );
//position
move ( settings.value ("pos", QPoint ( 100, 332 ) ).toPoint());
settings.endGroup();
m_update = TRUE;
}
}
void PlayList::writeSettings()
{
QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat );
settings.beginGroup ( "PlayList" );
//position
settings.setValue ( "pos", this->pos() );
settings.endGroup();
}
void PlayList::showAddMenu()
{
m_addMenu->exec ( m_buttonAdd->mapToGlobal ( QPoint ( 0,0 ) ) );
}
void PlayList::showSubMenu()
{
m_subMenu->exec ( m_buttonSub->mapToGlobal ( QPoint ( 0,0 ) ) );
}
void PlayList::showSelectMenu()
{
m_selectMenu->exec ( m_selectButton->mapToGlobal ( QPoint ( 0,0 ) ) );
}
void PlayList::showSortMenu()
{
m_sortMenu->exec ( m_sortButton->mapToGlobal ( QPoint ( 0,0 ) ) );
}
QString PlayList::formatTime ( int sec )
{
int minutes = sec / 60;
int seconds = sec % 60;
QString str_minutes = QString::number ( minutes );
QString str_seconds = QString::number ( seconds );
if ( minutes < 10 ) str_minutes.prepend ( "0" );
if ( seconds < 10 ) str_seconds.prepend ( "0" );
return str_minutes + ":" + str_seconds;
}
void PlayList::setInfo (const OutputState &st,int length_current, int length_total)
{
if ( st.type() == OutputState::Info )
{
m_current_time->display ( formatTime ( st.elapsedSeconds() ) );
m_current_time->update();
QString str_length = formatTime ( length_current ) + "/" + formatTime ( length_total );
m_length_totalLength->display ( str_length );
m_length_totalLength->update();
}
}
MediaFile *PlayList::currentItem()
{
if ( m_playListModel )
return m_playListModel->currentItem();
else
return 0;
}
void PlayList::showPlaylistMenu()
{
m_playlistMenu->exec ( m_playlistButton->mapToGlobal ( QPoint ( 0,0 ) ) );
}
void PlayList::keyPressEvent ( QKeyEvent *ke )
{
if ( m_keyboardManager->handleKeyPress ( ke ) )
update();
}