Implement multi-theaded processing in progress dialog.

This commit is contained in:
LoRd_MuldeR 2010-11-19 21:11:54 +01:00
parent 98dc212d68
commit 28a926b820
10 changed files with 185 additions and 110 deletions

View File

@ -1344,24 +1344,10 @@
<include location="../res/Images.qrc"/>
<include location="../res/Icons.qrc"/>
<include location="../res/Images.qrc"/>
<include location="../res/Icons.qrc"/>
<include location="../res/Images.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonQuit</sender>
<signal>clicked()</signal>
<receiver>MainWindow</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>483</x>
<y>422</y>
</hint>
<hint type="destinationlabel">
<x>276</x>
<y>222</y>
</hint>
</hints>
</connection>
<connection>
<sender>actionAbout</sender>
<signal>triggered()</signal>

View File

@ -25,7 +25,7 @@
#define VER_LAMEXP_MAJOR 4
#define VER_LAMEXP_MINOR_HI 0
#define VER_LAMEXP_MINOR_LO 0
#define VER_LAMEXP_BUILD 41
#define VER_LAMEXP_BUILD 44
#define VER_LAMEXP_SUFFIX TechPreview
/*

View File

@ -31,6 +31,7 @@
#include "Thread_MessageHandler.h"
#include "Model_MetaInfo.h"
#include "Model_Settings.h"
#include "Model_FileList.h"
#include "Encoder_MP3.h"
//Qt includes
@ -79,8 +80,13 @@ private:
// Constructor
////////////////////////////////////////////////////////////
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
MainWindow::MainWindow(FileListModel *fileListModel, AudioFileModel *metaInfo, SettingsModel *settingsModel, QWidget *parent)
:
QMainWindow(parent),
m_fileListModel(fileListModel),
m_metaData(metaInfo),
m_settings(settingsModel),
m_accepted(false)
{
//Init the dialog, from the .ui file
setupUi(this);
@ -95,20 +101,16 @@ MainWindow::MainWindow(QWidget *parent)
setWindowTitle(windowTitle().append(" [DEMO VERSION]"));
}
//Load configuration
m_settings = new SettingsModel();
m_settings->validate();
//Enabled main buttons
connect(buttonAbout, SIGNAL(clicked()), this, SLOT(aboutButtonClicked()));
connect(buttonStart, SIGNAL(clicked()), this, SLOT(encodeButtonClicked()));
connect(buttonQuit, SIGNAL(clicked()), this, SLOT(closeButtonClicked()));
//Setup tab widget
tabWidget->setCurrentIndex(0);
connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabPageChanged(int)));
//Setup "Source" tab
m_fileListModel = new FileListModel();
sourceFileView->setModel(m_fileListModel);
sourceFileView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
sourceFileView->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
@ -139,7 +141,6 @@ MainWindow::MainWindow(QWidget *parent)
connect(buttonGotoMusic, SIGNAL(clicked()), this, SLOT(gotoMusicFolderButtonClicked()));
//Setup "Meta Data" tab
m_metaData = new AudioFileModel();
m_metaInfoModel = new MetaInfoModel(m_metaData, 6);
m_metaInfoModel->clearData();
metaDataView->setModel(m_metaInfoModel);
@ -261,15 +262,12 @@ MainWindow::~MainWindow(void)
//Free memory
LAMEXP_DELETE(m_tabActionGroup);
LAMEXP_DELETE(m_styleActionGroup);
LAMEXP_DELETE(m_fileListModel);
LAMEXP_DELETE(m_banner);
LAMEXP_DELETE(m_fileSystemModel);
LAMEXP_DELETE(m_messageHandler);
LAMEXP_DELETE(m_delayedFileList);
LAMEXP_DELETE(m_delayedFileTimer);
LAMEXP_DELETE(m_metaData);
LAMEXP_DELETE(m_metaInfoModel);
LAMEXP_DELETE(m_settings);
LAMEXP_DELETE(m_encoderButtonGroup);
}
@ -313,6 +311,7 @@ void MainWindow::addFiles(const QStringList &files)
void MainWindow::showEvent(QShowEvent *event)
{
QTimer::singleShot(0, this, SLOT(windowShown()));
m_accepted = false;
}
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
@ -357,6 +356,15 @@ void MainWindow::dropEvent(QDropEvent *event)
addFiles(droppedFiles);
}
void MainWindow::closeEvent(QCloseEvent *event)
{
if(m_banner->isVisible() || m_delayedFileTimer->isActive())
{
MessageBeep(MB_ICONEXCLAMATION);
event->ignore();
}
}
////////////////////////////////////////////////////////////
// Slots
////////////////////////////////////////////////////////////
@ -458,36 +466,48 @@ void MainWindow::encodeButtonClicked(void)
return;
}
m_banner->show("Encoding files, please wait...");
QApplication::processEvents();
m_accepted = true;
close();
MP3Encoder *mp3Encoder = new MP3Encoder();
connect(mp3Encoder, SIGNAL(statusUpdated(QString)), m_banner, SLOT(setText(QString)));
//m_banner->show("Encoding files, please wait...");
//QApplication::processEvents();
for(int i = 0; i < m_fileListModel->rowCount(); i++)
{
AudioFileModel file = m_fileListModel->getFile(m_fileListModel->index(i,0));
QString outFolder = m_fileSystemModel->filePath(this->outputFolderView->currentIndex());
//MP3Encoder *mp3Encoder = new MP3Encoder();
//connect(mp3Encoder, SIGNAL(statusUpdated(QString)), m_banner, SLOT(setText(QString)));
QString baseName = QFileInfo(file.filePath()).fileName();
int pos = baseName.lastIndexOf(".");
if(pos >= 1) baseName = baseName.left(pos);
//for(int i = 0; i < m_fileListModel->rowCount(); i++)
//{
// AudioFileModel file = m_fileListModel->getFile(m_fileListModel->index(i,0));
// QString outFolder = m_fileSystemModel->filePath(this->outputFolderView->currentIndex());
//
// QString baseName = QFileInfo(file.filePath()).fileName();
// int pos = baseName.lastIndexOf(".");
// if(pos >= 1) baseName = baseName.left(pos);
int n = 1;
QString outFileName = QString(outFolder).append("/").append(baseName).append(".mp3");
// int n = 1;
// QString outFileName = QString(outFolder).append("/").append(baseName).append(".mp3");
//
// while(QFileInfo(outFileName).exists())
// {
// outFileName = QString(outFolder).append("/").append(baseName).append(" (").append(QString::number(++n)).append(").mp3");
// }
//
// mp3Encoder->encode(file, outFileName);
//}
while(QFileInfo(outFileName).exists())
{
outFileName = QString(outFolder).append("/").append(baseName).append(" (").append(QString::number(++n)).append(").mp3");
//LAMEXP_DELETE(mp3Encoder);
//m_banner->close();
//
//QMessageBox::information(this, "Done", "Encoding process completed.");
}
mp3Encoder->encode(file, outFileName);
}
LAMEXP_DELETE(mp3Encoder);
m_banner->close();
QMessageBox::information(this, "Done", "Encoding process completed.");
/*
* Close button
*/
void MainWindow::closeButtonClicked(void)
{
ABORT_IF_BUSY;
close();
}
/*

View File

@ -23,7 +23,7 @@
#include "../tmp/UIC_MainWindow.h"
#include "Model_FileList.h"
//#include "Model_FileList.h"
//Class declarations
class QFileSystemModel;
@ -33,19 +33,23 @@ class AudioFileModel;
class MetaInfoModel;
class SettingsModel;
class QButtonGroup;
class FileListModel;
class MainWindow: public QMainWindow, private Ui::MainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
MainWindow(FileListModel *fileListModel, AudioFileModel *metaInfo, SettingsModel *settingsModel, QWidget *parent = 0);
~MainWindow(void);
bool isAccepted() { return m_accepted; }
private slots:
void windowShown(void);
void aboutButtonClicked(void);
void encodeButtonClicked(void);
void closeButtonClicked(void);
void addFilesButtonClicked(void);
void clearFilesButtonClicked(void);
void removeFileButtonClicked(void);
@ -76,10 +80,12 @@ protected:
void showEvent(QShowEvent *event);
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
void closeEvent(QCloseEvent *event);
private:
void addFiles(const QStringList &files);
bool m_accepted;
FileListModel *m_fileListModel;
QFileSystemModel *m_fileSystemModel;
QActionGroup *m_tabActionGroup;

View File

@ -22,6 +22,7 @@
#include "Dialog_Processing.h"
#include "Global.h"
#include "Model_FileList.h"
#include "Model_Progress.h"
#include "Thread_Process.h"
@ -40,7 +41,7 @@
// Constructor
////////////////////////////////////////////////////////////
ProcessingDialog::ProcessingDialog(void)
ProcessingDialog::ProcessingDialog(FileListModel *fileListModel)
{
//Init the dialog, from the .ui file
setupUi(this);
@ -65,7 +66,6 @@ ProcessingDialog::ProcessingDialog(void)
//Init progress indicator
m_progressIndicator = new QMovie(":/images/Working.gif");
label_headerWorking->setMovie(m_progressIndicator);
progressBar->setRange(0, 4);
progressBar->setValue(0);
//Init progress model
@ -76,8 +76,18 @@ ProcessingDialog::ProcessingDialog(void)
view_log->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
view_log->horizontalHeader()->setResizeMode(0, QHeaderView::Stretch);
//Init member vars
for(int i = 0; i < 4; i++) m_thread[i] = NULL;
//Enque jobs
if(fileListModel)
{
for(int i = 0; i < fileListModel->rowCount(); i++)
{
m_pendingJobs.append(fileListModel->getFile(fileListModel->index(i,0)));
}
}
//Init other vars
m_runningThreads = 0;
m_userAborted = false;
}
////////////////////////////////////////////////////////////
@ -90,6 +100,11 @@ ProcessingDialog::~ProcessingDialog(void)
if(m_progressIndicator) m_progressIndicator->stop();
LAMEXP_DELETE(m_progressIndicator);
LAMEXP_DELETE(m_progressModel);
while(!m_threadList.isEmpty())
{
delete m_threadList.takeFirst();
}
}
////////////////////////////////////////////////////////////
@ -145,63 +160,60 @@ bool ProcessingDialog::eventFilter(QObject *obj, QEvent *event)
void ProcessingDialog::initEncoding(void)
{
m_runningThreads = 0;
m_userAborted = false;
label_progress->setText("Encoding files, please wait...");
m_progressIndicator->start();
m_pendingJobs = 4;
for(int i = 0; i < 4; i++)
{
m_thread[i] = new ProcessThread();
connect(m_thread[i], SIGNAL(finished()), this, SLOT(doneEncoding()), Qt::QueuedConnection);
connect(m_thread[i], SIGNAL(processStateInitialized(QUuid,QString,QString,int)), m_progressModel, SLOT(addJob(QUuid,QString,QString,int)), Qt::QueuedConnection);
connect(m_thread[i], SIGNAL(processStateChanged(QUuid,QString,int)), m_progressModel, SLOT(updateJob(QUuid,QString,int)), Qt::QueuedConnection);
m_thread[i]->start();
}
button_closeDialog->setEnabled(false);
button_AbortProcess->setEnabled(true);
progressBar->setRange(0, m_pendingJobs.count());
startNextJob();
startNextJob();
}
void ProcessingDialog::abortEncoding(void)
{
m_userAborted = true;
button_AbortProcess->setEnabled(false);
for(int i = 0; i < 4; i++)
for(int i = 0; i < m_threadList.count(); i++)
{
if(m_thread[i])
{
m_thread[i]->abort();
}
m_threadList.at(i)->abort();
}
}
void ProcessingDialog::doneEncoding(void)
{
progressBar->setValue(progressBar->value() + 1);
m_runningThreads--;
if(--m_pendingJobs > 0)
progressBar->setValue(progressBar->value() + 1);
label_progress->setText(QString("%1 files out of %2 completed, please wait...").arg(QString::number(progressBar->value()), QString::number(progressBar->maximum())));
if(!m_pendingJobs.isEmpty() && !m_userAborted)
{
startNextJob();
qDebug("Running jobs: %u", m_runningThreads);
return;
}
label_progress->setText("Completed.");
if(m_runningThreads > 0)
{
qDebug("Running jobs: %u", m_runningThreads);
return;
}
qDebug("Running jobs: %u", m_runningThreads);
label_progress->setText(m_userAborted ? "Process aborted by user." : "Alle files completed.");
m_progressIndicator->stop();
setCloseButtonEnabled(true);
button_closeDialog->setEnabled(true);
button_AbortProcess->setEnabled(false);
for(int i = 0; i < 4; i++)
{
if(m_thread[i])
{
m_thread[i]->terminate();
m_thread[i]->wait();
LAMEXP_DELETE(m_thread[i]);
}
}
progressBar->setValue(100);
}
@ -209,6 +221,22 @@ void ProcessingDialog::doneEncoding(void)
// Private Functions
////////////////////////////////////////////////////////////
void ProcessingDialog::startNextJob(void)
{
if(m_pendingJobs.isEmpty())
{
return;
}
ProcessThread *thread = new ProcessThread(m_pendingJobs.takeFirst());
m_threadList.append(thread);
connect(thread, SIGNAL(finished()), this, SLOT(doneEncoding()), Qt::QueuedConnection);
connect(thread, SIGNAL(processStateInitialized(QUuid,QString,QString,int)), m_progressModel, SLOT(addJob(QUuid,QString,QString,int)), Qt::QueuedConnection);
connect(thread, SIGNAL(processStateChanged(QUuid,QString,int)), m_progressModel, SLOT(updateJob(QUuid,QString,int)), Qt::QueuedConnection);
m_runningThreads++;
thread->start();
}
void ProcessingDialog::setCloseButtonEnabled(bool enabled)
{
HMENU hMenu = GetSystemMenu((HWND) winId(), FALSE);

View File

@ -26,13 +26,15 @@
class QMovie;
class ProgressModel;
class ProcessThread;
class FileListModel;
class AudioFileModel;
class ProcessingDialog : public QDialog, private Ui::ProcessingDialog
{
Q_OBJECT
public:
ProcessingDialog(void);
ProcessingDialog(FileListModel *fileListModel = NULL);
~ProcessingDialog(void);
private slots:
@ -47,9 +49,12 @@ protected:
private:
void setCloseButtonEnabled(bool enabled);
void ProcessingDialog::startNextJob(void);
int m_pendingJobs;
QList<AudioFileModel> m_pendingJobs;
QList<ProcessThread*> m_threadList;
QMovie *m_progressIndicator;
ProgressModel *m_progressModel;
ProcessThread *m_thread[4];
unsigned int m_runningThreads;
bool m_userAborted;
};

View File

@ -27,6 +27,8 @@
#include "Thread_Initialization.h"
#include "Thread_MessageProducer.h"
#include "Model_Settings.h"
#include "Model_FileList.h"
#include "Model_AudioFile.h"
//Qt includes
#include <QApplication>
@ -41,6 +43,7 @@
int lamexp_main(int argc, char* argv[])
{
int iResult = -1;
bool bAccepted = true;
//Init console
lamexp_init_console(argc, argv);
@ -112,21 +115,39 @@ int lamexp_main(int argc, char* argv[])
}
}
//Create models
FileListModel *fileListModel = new FileListModel();
AudioFileModel *metaInfo = new AudioFileModel();
SettingsModel *settingsModel = new SettingsModel();
settingsModel->validate();
//Show splash screen
InitializationThread *poInitializationThread = new InitializationThread();
SplashScreen::showSplash(poInitializationThread);
LAMEXP_DELETE(poInitializationThread);
//Show main window
MainWindow *poMainWindow = new MainWindow();
while(bAccepted)
{
MainWindow *poMainWindow = new MainWindow(fileListModel, metaInfo, settingsModel);
poMainWindow->show();
iResult = QApplication::instance()->exec();
bAccepted = poMainWindow->isAccepted();
LAMEXP_DELETE(poMainWindow);
//Show processing dialog
ProcessingDialog *processingDialog = new ProcessingDialog();
if(bAccepted && fileListModel->rowCount() > 0)
{
ProcessingDialog *processingDialog = new ProcessingDialog(fileListModel);
processingDialog->exec();
LAMEXP_DELETE(processingDialog);
}
}
//Free models
LAMEXP_DELETE(fileListModel);
LAMEXP_DELETE(metaInfo);
LAMEXP_DELETE(settingsModel);
//Final clean-up
qDebug("Shutting down, please wait...\n");

View File

@ -213,10 +213,10 @@ void InitializationThread::initNeroAac(void)
if(versionTokens.count() == 4)
{
neroVersion = 0;
neroVersion += versionTokens.at(3).toInt();
neroVersion += versionTokens.at(2).toInt() * 10;
neroVersion += versionTokens.at(1).toInt() * 100;
neroVersion += versionTokens.at(0).toInt() * 1000;
neroVersion += min(9, max(0, versionTokens.at(3).toInt()));
neroVersion += min(9, max(0, versionTokens.at(2).toInt())) * 10;
neroVersion += min(9, max(0, versionTokens.at(1).toInt())) * 100;
neroVersion += min(9, max(0, versionTokens.at(0).toInt())) * 1000;
}
}
}

View File

@ -22,9 +22,12 @@
#include "Thread_Process.h"
#include "Global.h"
#include "Model_AudioFile.h"
#include "Model_Progress.h"
#include <QUuid.h>
#include <QUuid>
#include <QFileInfo>
#include <limits.h>
#include <time.h>
@ -32,8 +35,11 @@
// Constructor
////////////////////////////////////////////////////////////
ProcessThread::ProcessThread(void)
: m_jobId(QUuid::createUuid()), m_aborted(false)
ProcessThread::ProcessThread(AudioFileModel audioFile)
:
m_audioFile(audioFile),
m_jobId(QUuid::createUuid()),
m_aborted(false)
{
}
@ -46,12 +52,11 @@ void ProcessThread::run()
m_aborted = false;
qDebug("Process thread %s has started.", m_jobId.toString().toLatin1().constData());
emit processStateInitialized(m_jobId, "Slime - Der Tod Ist Ein Meister Aus Deutschland.mp3", "Starting...", ProgressModel::JobRunning);
emit processStateInitialized(m_jobId, QFileInfo(m_audioFile.filePath()).fileName(), "Starting...", ProgressModel::JobRunning);
QUuid uuid = QUuid::createUuid();
qsrand(uuid.data1 * uuid.data2 * uuid.data3 * uuid.data4[0] * uuid.data4[1] * uuid.data4[2] * uuid.data4[3] * uuid.data4[4] * uuid.data4[5] * uuid.data4[6] * uuid.data4[7]);
unsigned long delay = 250 + (qrand() % 500);
unsigned long delay = 100 + (qrand() % 150);
for(int i = 1; i <= 100; i++)
{

View File

@ -24,15 +24,18 @@
#include <QThread>
#include <QUuid>
#include "Model_AudioFile.h"
class ProcessThread: public QThread
{
Q_OBJECT
public:
ProcessThread(void);
ProcessThread(AudioFileModel audioFile);
~ProcessThread(void);
void run();
void abort() { m_aborted = true; }
QUuid getId() { return m_jobId; }
signals:
void processStateInitialized(const QUuid &jobId, const QString &jobName, const QString &jobInitialStatus, int jobInitialState);
@ -40,5 +43,6 @@ signals:
private:
const QUuid m_jobId;
AudioFileModel m_audioFile;
volatile bool m_aborted;
};