File indexing completed on 2024-05-12 17:12:39
0001 /*************************************************************************** 0002 * Copyright (C) 2009 by Renaud Guezennec * 0003 * https://rolisteam.org/contact * 0004 * * 0005 * This software is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License * 0016 * along with this program; if not, write to the * 0017 * Free Software Foundation, Inc., * 0018 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 0019 ***************************************************************************/ 0020 #include <QFileDialog> 0021 #include <QInputDialog> 0022 #include <QMessageBox> 0023 #include <QMimeData> 0024 0025 #include "playerwidget.h" 0026 0027 #include "controller/audioplayercontroller.h" 0028 #include "ui_playerwidget.h" 0029 #define FACTOR_WAIT 4 0030 0031 QString getExistingFile(const QString& rootDir, const QString& pathOnGM) 0032 { 0033 QFileInfo info(pathOnGM); 0034 0035 auto list= pathOnGM.split("/"); 0036 QStringList result; 0037 for(auto& item : list) 0038 { 0039 result.prepend(item); 0040 } 0041 QString consumedPath= ""; 0042 0043 for(auto& item : result) 0044 { 0045 if(consumedPath.isEmpty()) 0046 consumedPath= item; 0047 else 0048 consumedPath= item + "/" + consumedPath; 0049 auto temp= QStringLiteral("%1/%2").arg(rootDir, consumedPath); 0050 if(QFile::exists(temp)) 0051 { 0052 return temp; 0053 } 0054 } 0055 return rootDir + "/" + info.fileName(); // error message 0056 } 0057 0058 PlayerWidget::PlayerWidget(AudioPlayerController* ctrl, QWidget* parent) 0059 : QWidget(parent), m_ctrl(ctrl), m_ui(new Ui::PlayerWidgetUI) 0060 { 0061 setAcceptDrops(true); 0062 0063 m_ui->setupUi(this); 0064 0065 if(!m_ctrl) 0066 return; 0067 0068 setupUi(); 0069 0070 m_ui->m_songList->setModel(m_ctrl->model()); 0071 0072 connect(m_ctrl, &AudioPlayerController::localIsGmChanged, this, &PlayerWidget::updateUi); 0073 updateUi(); 0074 } 0075 0076 void PlayerWidget::setupUi() 0077 { 0078 0079 m_ui->m_timeSlider->setMinimum(0); 0080 m_ui->m_volumeSlider->setRange(0, 100); 0081 // **************** CREATE ACTIONS ******************************** 0082 m_playAct= new QAction(style()->standardIcon(QStyle::SP_MediaPlay), tr("Play"), this); 0083 m_pauseAct= new QAction(style()->standardIcon(QStyle::SP_MediaPause), tr("Pause"), this); 0084 m_stopAct= new QAction(style()->standardIcon(QStyle::SP_MediaStop), tr("Stop"), this); 0085 0086 m_uniqueAct= new QAction(QIcon::fromTheme("playunique"), tr("Stop at the end"), this); 0087 m_uniqueAct->setShortcut(QKeySequence("Ctrl+U")); 0088 m_uniqueAct->setShortcutContext(Qt::WidgetWithChildrenShortcut); 0089 m_uniqueAct->setCheckable(true); 0090 0091 m_repeatAct= new QAction(QIcon::fromTheme("playloop"), tr("Play in loop"), this); 0092 m_repeatAct->setCheckable(true); 0093 m_repeatAct->setShortcut(QKeySequence("Ctrl+R")); 0094 m_repeatAct->setShortcutContext(Qt::WidgetWithChildrenShortcut); 0095 0096 m_shuffleAct= new QAction(QIcon::fromTheme("shuffle_mode"), tr("Shuffle Mode"), this); 0097 m_shuffleAct->setCheckable(true); 0098 m_shuffleAct->setShortcutContext(Qt::WidgetWithChildrenShortcut); 0099 0100 m_changeDirectoryAct= new QAction(style()->standardIcon(QStyle::SP_DirIcon), tr("Open Directory"), this); 0101 connect(m_changeDirectoryAct, &QAction::triggered, this, &PlayerWidget::changePlayerDirectory); 0102 0103 m_volumeMutedAct= new QAction(tr("Mute Volume"), this); 0104 m_volumeMutedAct->setCheckable(true); 0105 m_volumeMutedAct->setShortcut(QKeySequence("Ctrl+M")); 0106 m_volumeMutedAct->setShortcutContext(Qt::WidgetWithChildrenShortcut); 0107 m_loadTableTopAudioPlayListAct= new QAction(tr("load TableTopAudio.com playlist"), this); 0108 0109 m_openPlayList= new QAction(style()->standardIcon(QStyle::SP_DialogOpenButton), tr("Open Playlist"), this); 0110 m_openPlayList->setShortcut(QKeySequence("Ctrl+J")); 0111 m_openPlayList->setShortcutContext(Qt::WidgetWithChildrenShortcut); 0112 m_savePlayList= new QAction(style()->standardIcon(QStyle::SP_DialogSaveButton), tr("Save Playlist"), this); 0113 m_savePlayList->setShortcut(QKeySequence("Ctrl+E")); 0114 m_savePlayList->setShortcutContext(Qt::WidgetWithChildrenShortcut); 0115 m_clearList= new QAction(style()->standardIcon(QStyle::SP_DialogResetButton), tr("Clear"), this); 0116 m_clearList->setShortcut(QKeySequence("Ctrl+Del")); 0117 m_clearList->setShortcutContext(Qt::WidgetWithChildrenShortcut); 0118 0119 m_addAction= new QAction(QIcon::fromTheme("add"), tr("Add Songs"), this); 0120 m_addAction->setShortcut(QKeySequence("Ctrl+A")); 0121 m_addAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); 0122 m_addStreamAction= new QAction(tr("Open Stream"), this); 0123 0124 m_deleteAction= new QAction(QIcon::fromTheme("remove"), tr("Remove Song"), this); 0125 m_deleteAction->setShortcut(QKeySequence("Del")); 0126 m_deleteAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); 0127 0128 if(m_ctrl) 0129 m_ui->m_volumeSlider->setValue(m_ctrl->volume()); 0130 // m_audioFileFilter= m_preferences->value("AudioFileFilter", "*.wav *.mp2 *.mp3 *.ogg *.flac").toString(); 0131 0132 // **************** Add ACTIONS ******************************** 0133 0134 addAction(m_uniqueAct); 0135 addAction(m_repeatAct); 0136 addAction(m_shuffleAct); 0137 addAction(m_volumeMutedAct); 0138 addAction(m_openPlayList); 0139 addAction(m_savePlayList); 0140 addAction(m_clearList); 0141 addAction(m_deleteAction); 0142 addAction(m_addAction); 0143 addAction(m_addStreamAction); 0144 0145 // **************** TOOLTIP ACTIONS ******************************** 0146 m_addAction->setToolTip(tr("Add song to the list")); 0147 m_deleteAction->setToolTip(tr("Remove selected file")); 0148 0149 // **************** Add Action In Buttons ******************************** 0150 m_ui->m_deleteButton->setDefaultAction(m_deleteAction); 0151 m_ui->m_deleteButton->addAction(m_clearList); 0152 m_ui->m_savePlaylist->setDefaultAction(m_savePlayList); 0153 m_ui->m_addButton->setDefaultAction(m_addAction); 0154 m_ui->m_addButton->addAction(m_openPlayList); 0155 m_ui->m_addButton->addAction(m_loadTableTopAudioPlayListAct); 0156 m_ui->m_addButton->addAction(m_addStreamAction); 0157 0158 m_ui->m_volumeMutedButton->setDefaultAction(m_volumeMutedAct); 0159 m_ui->m_playButton->setDefaultAction(m_playAct); 0160 m_ui->m_pauseButton->setDefaultAction(m_pauseAct); 0161 m_ui->m_stopButton->setDefaultAction(m_stopAct); 0162 m_ui->m_uniqueMode->setDefaultAction(m_uniqueAct); 0163 m_ui->m_shuffleBtn->setDefaultAction(m_shuffleAct); 0164 m_ui->m_repeatMode->setDefaultAction(m_repeatAct); 0165 m_ui->m_changeDirectory->setDefaultAction(m_changeDirectoryAct); 0166 0167 // **************** CONNECT ******************************** 0168 connect(m_clearList, &QAction::triggered, m_ctrl, &AudioPlayerController::clear); 0169 connect(m_addAction, &QAction::triggered, this, &PlayerWidget::addFiles); 0170 connect(m_openPlayList, &QAction::triggered, this, &PlayerWidget::openPlayList); 0171 connect(m_addStreamAction, &QAction::triggered, this, &PlayerWidget::openStream); 0172 connect(m_deleteAction, &QAction::triggered, this, 0173 [this]() { m_ctrl->removeSong(m_ui->m_songList->selectionModel()->selectedIndexes()); }); 0174 connect(m_ui->m_songList, &QListView::doubleClicked, m_ctrl, [this](const QModelIndex& index) { 0175 m_ctrl->setMedia(index); 0176 m_ctrl->play(); 0177 }); 0178 0179 updateIcon(); 0180 // connect(&m_player, SIGNAL(durationChanged(qint64)), this, SLOT(setDuration(qint64))); 0181 connect(m_playAct, &QAction::triggered, this, [this]() { 0182 if(m_ctrl->state() == AudioPlayerController::PausedState) 0183 m_ctrl->play(); 0184 else 0185 { 0186 auto index= m_ui->m_songList->currentIndex(); 0187 if(!index.isValid()) 0188 return; 0189 m_ctrl->setMedia(index); 0190 m_ctrl->play(); 0191 } 0192 }); //&AudioPlayerController::play 0193 connect(m_stopAct, &QAction::triggered, m_ctrl, &AudioPlayerController::stop); 0194 connect(m_pauseAct, &QAction::triggered, m_ctrl, &AudioPlayerController::pause); 0195 0196 // time 0197 connect(m_ctrl, &AudioPlayerController::timeChanged, m_ui->m_timeSlider, 0198 [this]() { m_ui->m_timeSlider->setValue(m_ctrl->time()); }); 0199 connect(m_ui->m_timeSlider, &QSlider::sliderMoved, m_ctrl, [this](qint64 time){ 0200 0201 if(!m_ui->m_timeSlider || !m_ui->m_timeSlider->isVisible()) 0202 return; 0203 0204 m_ctrl->setTime(time); 0205 }); 0206 0207 // Volume 0208 /*connect(m_ctrl, &AudioPlayerController::volumeChanged, m_ui->m_volumeSlider, 0209 [this]() { m_ui->m_volumeSlider->setValue(m_ctrl->volume()); });*/ 0210 connect(m_ctrl, &AudioPlayerController::volumeChanged, m_ui->m_volumeSlider, &QSlider::setValue); 0211 connect(m_ui->m_volumeSlider, &QSlider::sliderMoved, m_ctrl, &AudioPlayerController::setVolume); 0212 // Mute 0213 connect(m_ctrl, &AudioPlayerController::mutedChanged, this, &PlayerWidget::updateIcon); 0214 connect(m_volumeMutedAct, &QAction::triggered, m_ctrl, &AudioPlayerController::mute); 0215 0216 // duration 0217 connect(m_ctrl, &AudioPlayerController::durationChanged, m_ui->m_timeSlider, &QSlider::setMaximum); 0218 connect(m_ctrl, &AudioPlayerController::timeChanged, m_ui->m_timerDisplay, [this](qint64 position) { 0219 auto posInSecond= position / 1000; 0220 auto min= posInSecond / 60; 0221 auto second= posInSecond - (min * 60); 0222 if(min > 0) 0223 m_ui->m_timerDisplay->setText( 0224 QString("%1min%2s").arg(min).arg(second, 2, 10, QLatin1Char('0'))); //, 3, 10, QLatin1Char('0') 0225 else 0226 m_ui->m_timerDisplay->setText(QString("%1s").arg(second, 2, 10, QLatin1Char('0'))); 0227 }); 0228 // QOverload<int>::of(&QLCDNumber::display)); 0229 connect(m_ctrl, &AudioPlayerController::visibleChanged, this, &PlayerWidget::setVisible); 0230 setVisible(m_ctrl->visible()); 0231 0232 connect(m_ctrl, &AudioPlayerController::errorChanged, this, [this]() { 0233 m_ui->m_label->setStyleSheet("color: red"); 0234 m_ui->m_label->setEchoMode(QLineEdit::Normal); 0235 m_ui->m_label->setText(m_ctrl->error()); 0236 }); 0237 connect(m_ctrl, &AudioPlayerController::textChanged, this, [this]() { 0238 m_ui->m_label->setStyleSheet("color: black"); 0239 if(!m_ctrl->localIsGm()) 0240 m_ui->m_label->setEchoMode(QLineEdit::Password); 0241 m_ui->m_label->setText(m_ctrl->text()); 0242 }); 0243 0244 connect(m_repeatAct, &QAction::triggered, this, 0245 [this](bool b) { m_ctrl->setPlayingMode(b ? AudioPlayerController::LOOP : AudioPlayerController::NEXT); }); 0246 connect(m_uniqueAct, &QAction::triggered, this, [this](bool b) { 0247 m_ctrl->setPlayingMode(b ? AudioPlayerController::UNIQUE : AudioPlayerController::NEXT); 0248 }); 0249 connect(m_shuffleAct, &QAction::triggered, this, [this](bool b) { 0250 m_ctrl->setPlayingMode(b ? AudioPlayerController::SHUFFLE : AudioPlayerController::NEXT); 0251 }); 0252 0253 connect(m_loadTableTopAudioPlayListAct, &QAction::triggered, this, &PlayerWidget::openPlayList); 0254 connect(m_savePlayList, &QAction::triggered, this, &PlayerWidget::savePlaylist); 0255 0256 connect(m_ctrl, &AudioPlayerController::stateChanged, this, [this]() { 0257 auto state= m_ctrl->state(); 0258 m_playAct->setEnabled(state == AudioPlayerController::PausedState 0259 || state == AudioPlayerController::StoppedState); 0260 0261 m_pauseAct->setEnabled(state == AudioPlayerController::PlayingState 0262 || state == AudioPlayerController::StoppedState); 0263 m_stopAct->setEnabled(state == AudioPlayerController::PlayingState); 0264 }); 0265 0266 auto updateMode= [this]() { 0267 auto m= m_ctrl->mode(); 0268 m_uniqueAct->setChecked(m == AudioPlayerController::UNIQUE); 0269 m_shuffleAct->setChecked(m == AudioPlayerController::SHUFFLE); 0270 m_repeatAct->setChecked(m == AudioPlayerController::LOOP); 0271 }; 0272 connect(m_ctrl, &AudioPlayerController::modeChanged, this, updateMode); 0273 0274 updateMode(); 0275 } 0276 0277 void PlayerWidget::addFiles() 0278 { 0279 auto fileList 0280 = QFileDialog::getOpenFileUrls(this, tr("Add song"), QUrl(), tr("Audio files (%1)").arg("*.mp3 *.flac *.webm")); 0281 if(fileList.isEmpty()) 0282 return; 0283 m_ctrl->addSong(fileList); 0284 } 0285 bool PlayerWidget::askToDeleteAll() 0286 { 0287 if(m_ctrl->model()->rowCount() == 0) 0288 return true; 0289 0290 return ( 0291 QMessageBox::Ok 0292 == QMessageBox::warning(this, tr("Attention!"), 0293 tr("You are about to load an new playlist. All previously load file will be dropped."), 0294 QMessageBox::Ok, QMessageBox::Cancel)); 0295 } 0296 void PlayerWidget::openPlayList() 0297 { 0298 if(!askToDeleteAll()) 0299 { 0300 return; 0301 } 0302 QString filename= QFileDialog::getOpenFileName(this, tr("Open Play List"), "", tr("PlayList (*.m3u)")); 0303 if(filename.isEmpty()) 0304 return; 0305 0306 m_ctrl->loadPlayList(filename); 0307 } 0308 void PlayerWidget::openStream() 0309 { 0310 bool a; 0311 QString value= QInputDialog::getText(this, tr("Open audio Stream"), tr("URL"), QLineEdit::Normal, QString(), &a); 0312 if(!a) 0313 return; 0314 0315 QUrl url(value); 0316 if(!url.isValid()) 0317 return; 0318 0319 m_ctrl->addSong({url}); 0320 } 0321 0322 void PlayerWidget::contextMenuEvent(QContextMenuEvent* ev) 0323 { 0324 ev->ignore(); 0325 } 0326 void PlayerWidget::addActionsIntoMenu(QMenu* menu) 0327 { 0328 menu->addAction(m_playAct); 0329 menu->addAction(m_pauseAct); 0330 menu->addAction(m_stopAct); 0331 menu->addSeparator(); 0332 menu->addAction(m_addAction); 0333 menu->addAction(m_addStreamAction); 0334 menu->addAction(m_openPlayList); 0335 menu->addAction(m_loadTableTopAudioPlayListAct); 0336 menu->addAction(m_savePlayList); 0337 menu->addAction(m_clearList); 0338 menu->addAction(m_deleteAction); 0339 menu->addSeparator(); 0340 } 0341 0342 void PlayerWidget::updateUi() 0343 { 0344 auto isGM= m_ctrl->localIsGm(); 0345 m_ui->m_playButton->setVisible(isGM); 0346 m_ui->m_stopButton->setVisible(isGM); 0347 m_ui->m_pauseButton->setVisible(isGM); 0348 m_ui->m_uniqueMode->setVisible(isGM); 0349 m_ui->m_repeatMode->setVisible(isGM); 0350 m_ui->m_shuffleBtn->setVisible(isGM); 0351 m_ui->m_timeSlider->setVisible(isGM); 0352 m_ui->m_addButton->setVisible(isGM); 0353 m_ui->m_deleteButton->setVisible(isGM); 0354 m_ui->m_songList->setVisible(isGM); 0355 m_ui->m_savePlaylist->setVisible(isGM); 0356 m_ui->m_changeDirectory->setVisible(!isGM); 0357 m_ui->m_timerDisplay->setVisible(isGM); 0358 m_ui->m_volumeSlider->setValue(m_ctrl->volume()); 0359 } 0360 0361 void PlayerWidget::updateIcon() 0362 { 0363 m_volumeMutedAct->setIcon( 0364 style()->standardIcon(m_ctrl->muted() ? QStyle::SP_MediaVolumeMuted : QStyle::SP_MediaVolume)); 0365 m_volumeMutedAct->setChecked(m_ctrl->muted()); 0366 } 0367 0368 void PlayerWidget::savePlaylist() 0369 { 0370 QString filename= QFileDialog::getSaveFileName(this, tr("Save Play List"), "", tr("PlayList (*.m3u)")); 0371 if(filename.isEmpty()) 0372 return; 0373 0374 m_ctrl->loadPlayList(filename); 0375 } 0376 0377 void PlayerWidget::dropEvent(QDropEvent* event) 0378 { 0379 const QMimeData* mimeData= event->mimeData(); 0380 if(mimeData->hasUrls()) 0381 { 0382 QList<QUrl> list= mimeData->urls(); 0383 for(auto& url : list) 0384 { 0385 if(url.toLocalFile().endsWith(".m3u")) // play list 0386 { 0387 m_ctrl->loadPlayList(url.toLocalFile()); 0388 } 0389 else 0390 { 0391 m_ctrl->addSong({url.toLocalFile()}); 0392 } 0393 } 0394 event->acceptProposedAction(); 0395 } 0396 }