2010-11-17 19:35:50 +01:00
///////////////////////////////////////////////////////////////////////////////
// LameXP - Audio Encoder Front-End
// Copyright (C) 2004-2010 LoRd_MuldeR <MuldeR2@GMX.de>
//
// 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.
//
// http://www.gnu.org/licenses/gpl-2.0.txt
///////////////////////////////////////////////////////////////////////////////
# include "Dialog_Processing.h"
# include "Global.h"
2010-11-19 21:11:54 +01:00
# include "Model_FileList.h"
2010-11-18 00:32:46 +01:00
# include "Model_Progress.h"
2010-11-20 02:14:22 +01:00
# include "Model_Settings.h"
2010-11-18 00:32:46 +01:00
# include "Thread_Process.h"
2010-11-20 02:14:22 +01:00
# include "Encoder_MP3.h"
2010-11-22 21:45:00 +01:00
# include "Dialog_LogView.h"
2010-11-25 18:28:42 +01:00
# include "Resource.h"
2010-11-17 19:35:50 +01:00
# include <QApplication>
# include <QRect>
# include <QDesktopWidget>
# include <QMovie>
2010-11-18 00:32:46 +01:00
# include <QMessageBox>
# include <QTimer>
# include <QCloseEvent>
# include <QDesktopServices>
# include <QUrl>
2010-11-20 22:14:10 +01:00
# include <QUuid>
# include <QFileInfo>
2010-11-21 21:51:22 +01:00
# include <QDir>
2010-11-24 21:00:59 +01:00
# include <QMenu>
2010-11-20 22:14:10 +01:00
2010-11-18 00:32:46 +01:00
# include <Windows.h>
////////////////////////////////////////////////////////////
// Constructor
////////////////////////////////////////////////////////////
2010-11-17 19:35:50 +01:00
2010-11-20 19:16:04 +01:00
ProcessingDialog : : ProcessingDialog ( FileListModel * fileListModel , AudioFileModel * metaInfo , SettingsModel * settings , QWidget * parent )
2010-11-20 02:14:22 +01:00
:
2010-11-20 19:16:04 +01:00
QDialog ( parent ) ,
m_settings ( settings ) ,
m_metaInfo ( metaInfo )
2010-11-17 19:35:50 +01:00
{
//Init the dialog, from the .ui file
setupUi ( this ) ;
setWindowFlags ( windowFlags ( ) ^ Qt : : WindowContextHelpButtonHint ) ;
2010-11-18 22:37:35 +01:00
//Setup version info
2010-11-17 19:35:50 +01:00
label_versionInfo - > setText ( QString ( ) . sprintf ( " v%d.%02d %s (Build %d) " , lamexp_version_major ( ) , lamexp_version_minor ( ) , lamexp_version_release ( ) , lamexp_version_build ( ) ) ) ;
2010-11-18 00:32:46 +01:00
label_versionInfo - > installEventFilter ( this ) ;
2010-11-17 19:35:50 +01:00
2010-11-18 22:37:35 +01:00
//Register meta type
qRegisterMetaType < QUuid > ( " QUuid " ) ;
2010-11-17 19:35:50 +01:00
//Center window in screen
QRect desktopRect = QApplication : : desktop ( ) - > screenGeometry ( ) ;
QRect thisRect = this - > geometry ( ) ;
move ( ( desktopRect . width ( ) - thisRect . width ( ) ) / 2 , ( desktopRect . height ( ) - thisRect . height ( ) ) / 2 ) ;
setMinimumSize ( thisRect . width ( ) , thisRect . height ( ) ) ;
2010-11-18 00:32:46 +01:00
//Enable buttons
connect ( button_AbortProcess , SIGNAL ( clicked ( ) ) , this , SLOT ( abortEncoding ( ) ) ) ;
2010-11-17 19:35:50 +01:00
//Init progress indicator
m_progressIndicator = new QMovie ( " :/images/Working.gif " ) ;
label_headerWorking - > setMovie ( m_progressIndicator ) ;
2010-11-18 00:32:46 +01:00
progressBar - > setValue ( 0 ) ;
//Init progress model
m_progressModel = new ProgressModel ( ) ;
view_log - > setModel ( m_progressModel ) ;
view_log - > verticalHeader ( ) - > setResizeMode ( QHeaderView : : ResizeToContents ) ;
view_log - > verticalHeader ( ) - > hide ( ) ;
view_log - > horizontalHeader ( ) - > setResizeMode ( QHeaderView : : ResizeToContents ) ;
view_log - > horizontalHeader ( ) - > setResizeMode ( 0 , QHeaderView : : Stretch ) ;
2010-11-21 21:51:22 +01:00
connect ( m_progressModel , SIGNAL ( rowsInserted ( QModelIndex , int , int ) ) , this , SLOT ( progressModelChanged ( ) ) ) ;
connect ( m_progressModel , SIGNAL ( modelReset ( ) ) , this , SLOT ( progressModelChanged ( ) ) ) ;
2010-11-22 21:45:00 +01:00
connect ( view_log , SIGNAL ( doubleClicked ( QModelIndex ) ) , this , SLOT ( logViewDoubleClicked ( QModelIndex ) ) ) ;
2010-11-18 00:32:46 +01:00
2010-11-24 21:00:59 +01:00
//Create context menu
m_contextMenu = new QMenu ( ) ;
QAction * contextMenuAction = m_contextMenu - > addAction ( QIcon ( " :/icons/zoom.png " ) , " Show details for selected job " ) ;
view_log - > setContextMenuPolicy ( Qt : : CustomContextMenu ) ;
connect ( view_log , SIGNAL ( customContextMenuRequested ( QPoint ) ) , this , SLOT ( contextMenuTriggered ( QPoint ) ) ) ;
connect ( contextMenuAction , SIGNAL ( triggered ( bool ) ) , this , SLOT ( contextMenuActionTriggered ( ) ) ) ;
2010-11-19 21:11:54 +01:00
//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 ;
2010-11-20 19:16:04 +01:00
m_currentFile = 0 ;
2010-11-21 21:51:22 +01:00
m_succeededFiles = 0 ;
m_failedFiles = 0 ;
2010-11-19 21:11:54 +01:00
m_userAborted = false ;
2010-11-17 19:35:50 +01:00
}
2010-11-18 00:32:46 +01:00
////////////////////////////////////////////////////////////
// Destructor
////////////////////////////////////////////////////////////
2010-11-17 19:35:50 +01:00
ProcessingDialog : : ~ ProcessingDialog ( void )
{
2010-11-18 00:32:46 +01:00
view_log - > setModel ( NULL ) ;
2010-11-17 19:35:50 +01:00
if ( m_progressIndicator ) m_progressIndicator - > stop ( ) ;
LAMEXP_DELETE ( m_progressIndicator ) ;
2010-11-18 00:32:46 +01:00
LAMEXP_DELETE ( m_progressModel ) ;
2010-11-24 21:00:59 +01:00
LAMEXP_DELETE ( m_contextMenu ) ;
2010-11-19 21:11:54 +01:00
while ( ! m_threadList . isEmpty ( ) )
{
2010-11-20 02:14:22 +01:00
ProcessThread * thread = m_threadList . takeFirst ( ) ;
thread - > terminate ( ) ;
thread - > wait ( 15000 ) ;
delete thread ;
2010-11-19 21:11:54 +01:00
}
2010-11-18 00:32:46 +01:00
}
////////////////////////////////////////////////////////////
// EVENTS
////////////////////////////////////////////////////////////
void ProcessingDialog : : showEvent ( QShowEvent * event )
{
setCloseButtonEnabled ( false ) ;
button_closeDialog - > setEnabled ( false ) ;
button_AbortProcess - > setEnabled ( false ) ;
2010-11-25 16:56:32 +01:00
if ( ! SetPriorityClass ( GetCurrentProcess ( ) , ABOVE_NORMAL_PRIORITY_CLASS ) )
{
SetPriorityClass ( GetCurrentProcess ( ) , HIGH_PRIORITY_CLASS ) ;
}
2010-11-18 00:32:46 +01:00
QTimer : : singleShot ( 1000 , this , SLOT ( initEncoding ( ) ) ) ;
}
void ProcessingDialog : : closeEvent ( QCloseEvent * event )
{
2010-11-18 22:37:35 +01:00
if ( ! button_closeDialog - > isEnabled ( ) ) event - > ignore ( ) ;
2010-11-18 00:32:46 +01:00
}
bool ProcessingDialog : : eventFilter ( QObject * obj , QEvent * event )
{
static QColor defaultColor = QColor ( ) ;
if ( obj = = label_versionInfo )
{
if ( event - > type ( ) = = QEvent : : Enter )
{
QPalette palette = label_versionInfo - > palette ( ) ;
defaultColor = palette . color ( QPalette : : Normal , QPalette : : WindowText ) ;
palette . setColor ( QPalette : : Normal , QPalette : : WindowText , Qt : : red ) ;
label_versionInfo - > setPalette ( palette ) ;
}
else if ( event - > type ( ) = = QEvent : : Leave )
{
QPalette palette = label_versionInfo - > palette ( ) ;
palette . setColor ( QPalette : : Normal , QPalette : : WindowText , defaultColor ) ;
label_versionInfo - > setPalette ( palette ) ;
}
else if ( event - > type ( ) = = QEvent : : MouseButtonPress )
{
QUrl url ( " http://mulder.dummwiedeutsch.de/ " ) ;
QDesktopServices : : openUrl ( url ) ;
}
}
return false ;
}
////////////////////////////////////////////////////////////
// SLOTS
////////////////////////////////////////////////////////////
void ProcessingDialog : : initEncoding ( void )
{
2010-11-19 21:11:54 +01:00
m_runningThreads = 0 ;
2010-11-20 19:16:04 +01:00
m_currentFile = 0 ;
2010-11-21 21:51:22 +01:00
m_succeededFiles = 0 ;
m_failedFiles = 0 ;
2010-11-19 21:11:54 +01:00
m_userAborted = false ;
2010-11-20 22:14:10 +01:00
m_playList . clear ( ) ;
2010-11-19 21:11:54 +01:00
2010-11-18 00:32:46 +01:00
label_progress - > setText ( " Encoding files, please wait... " ) ;
m_progressIndicator - > start ( ) ;
button_closeDialog - > setEnabled ( false ) ;
button_AbortProcess - > setEnabled ( true ) ;
2010-11-19 21:11:54 +01:00
progressBar - > setRange ( 0 , m_pendingJobs . count ( ) ) ;
2010-11-24 21:00:59 +01:00
lamexp_cpu_t cpuFeatures = lamexp_detect_cpu_features ( ) ;
for ( int i = 0 ; i < min ( max ( cpuFeatures . count , 1 ) , 4 ) ; i + + )
{
startNextJob ( ) ;
}
2010-11-18 00:32:46 +01:00
}
void ProcessingDialog : : abortEncoding ( void )
{
2010-11-19 21:11:54 +01:00
m_userAborted = true ;
2010-11-18 00:32:46 +01:00
button_AbortProcess - > setEnabled ( false ) ;
2010-11-19 21:11:54 +01:00
for ( int i = 0 ; i < m_threadList . count ( ) ; i + + )
2010-11-18 00:32:46 +01:00
{
2010-11-19 21:11:54 +01:00
m_threadList . at ( i ) - > abort ( ) ;
2010-11-18 00:32:46 +01:00
}
}
void ProcessingDialog : : doneEncoding ( void )
{
2010-11-19 21:11:54 +01:00
m_runningThreads - - ;
2010-11-18 00:32:46 +01:00
progressBar - > setValue ( progressBar - > value ( ) + 1 ) ;
2010-11-20 02:14:22 +01:00
label_progress - > setText ( QString ( " Encoding: %1 files of %2 completed so far, please wait... " ) . arg ( QString : : number ( progressBar - > value ( ) ) , QString : : number ( progressBar - > maximum ( ) ) ) ) ;
2010-11-18 00:32:46 +01:00
2010-11-20 02:14:22 +01:00
int index = m_threadList . indexOf ( dynamic_cast < ProcessThread * > ( QWidget : : sender ( ) ) ) ;
if ( index > = 0 )
{
m_threadList . takeAt ( index ) - > deleteLater ( ) ;
}
2010-11-19 21:11:54 +01:00
if ( ! m_pendingJobs . isEmpty ( ) & & ! m_userAborted )
2010-11-18 00:32:46 +01:00
{
2010-11-19 21:11:54 +01:00
startNextJob ( ) ;
qDebug ( " Running jobs: %u " , m_runningThreads ) ;
2010-11-18 00:32:46 +01:00
return ;
}
2010-11-19 21:11:54 +01:00
if ( m_runningThreads > 0 )
{
qDebug ( " Running jobs: %u " , m_runningThreads ) ;
return ;
}
qDebug ( " Running jobs: %u " , m_runningThreads ) ;
2010-11-21 21:51:22 +01:00
if ( ! m_userAborted & & m_settings - > createPlaylist ( ) & & ! m_settings - > outputToSourceDir ( ) )
2010-11-20 22:14:10 +01:00
{
2010-11-21 21:51:22 +01:00
label_progress - > setText ( " Creatig the playlist file, please wait... " ) ;
2010-11-20 22:14:10 +01:00
QApplication : : processEvents ( ) ;
writePlayList ( ) ;
}
2010-11-21 21:51:22 +01:00
if ( m_userAborted )
{
2010-11-25 18:09:31 +01:00
label_progress - > setText ( QString ( " Process was aborted by the user after %1 files! " ) . arg ( QString : : number ( m_succeededFiles ) ) ) ;
2010-11-25 18:28:42 +01:00
QApplication : : processEvents ( ) ;
PlaySound ( MAKEINTRESOURCE ( IDR_WAVE_ABORTED ) , GetModuleHandle ( NULL ) , SND_RESOURCE | SND_SYNC ) ;
2010-11-21 21:51:22 +01:00
}
else
{
if ( m_failedFiles )
{
2010-11-25 18:09:31 +01:00
label_progress - > setText ( QString ( " Error: %1 of %2 files failed. Double-click failed items for detailed information! " ) . arg ( QString : : number ( m_failedFiles ) , QString : : number ( m_failedFiles + m_succeededFiles ) ) ) ;
2010-11-25 18:28:42 +01:00
QApplication : : processEvents ( ) ;
PlaySound ( MAKEINTRESOURCE ( IDR_WAVE_ERROR ) , GetModuleHandle ( NULL ) , SND_RESOURCE | SND_SYNC ) ;
2010-11-21 21:51:22 +01:00
}
else
{
label_progress - > setText ( " Alle files completed successfully. " ) ;
2010-11-25 18:28:42 +01:00
QApplication : : processEvents ( ) ;
PlaySound ( MAKEINTRESOURCE ( IDR_WAVE_SUCCESS ) , GetModuleHandle ( NULL ) , SND_RESOURCE | SND_SYNC ) ;
2010-11-21 21:51:22 +01:00
}
}
2010-11-18 00:32:46 +01:00
setCloseButtonEnabled ( true ) ;
button_closeDialog - > setEnabled ( true ) ;
button_AbortProcess - > setEnabled ( false ) ;
2010-11-25 18:09:31 +01:00
view_log - > scrollToBottom ( ) ;
2010-11-21 21:51:22 +01:00
m_progressIndicator - > stop ( ) ;
2010-11-18 00:32:46 +01:00
progressBar - > setValue ( 100 ) ;
}
2010-11-20 22:14:10 +01:00
void ProcessingDialog : : processFinished ( const QUuid & jobId , const QString & outFileName , bool success )
{
if ( success )
{
2010-11-21 21:51:22 +01:00
m_succeededFiles + + ;
2010-11-20 22:14:10 +01:00
m_playList . append ( outFileName ) ;
}
2010-11-21 21:51:22 +01:00
else
{
m_failedFiles + + ;
}
}
void ProcessingDialog : : progressModelChanged ( void )
{
view_log - > scrollToBottom ( ) ;
2010-11-20 22:14:10 +01:00
}
2010-11-22 21:45:00 +01:00
void ProcessingDialog : : logViewDoubleClicked ( const QModelIndex & index )
{
if ( m_runningThreads = = 0 )
{
const QStringList & logFile = m_progressModel - > getLogFile ( index ) ;
LogViewDialog * logView = new LogViewDialog ( this ) ;
2010-11-25 16:56:32 +01:00
logView - > setWindowTitle ( QString ( " LameXP - [%1] " ) . arg ( m_progressModel - > data ( index , Qt : : DisplayRole ) . toString ( ) ) ) ;
2010-11-22 21:45:00 +01:00
logView - > exec ( logFile ) ;
LAMEXP_DELETE ( logView ) ;
}
2010-11-24 21:00:59 +01:00
else
{
MessageBeep ( MB_ICONWARNING ) ;
}
}
void ProcessingDialog : : contextMenuTriggered ( const QPoint & pos )
{
m_contextMenu - > popup ( view_log - > mapToGlobal ( pos ) ) ;
}
void ProcessingDialog : : contextMenuActionTriggered ( void )
{
QModelIndex index = view_log - > indexAt ( view_log - > mapFromGlobal ( m_contextMenu - > pos ( ) ) ) ;
logViewDoubleClicked ( index . isValid ( ) ? index : view_log - > currentIndex ( ) ) ;
2010-11-22 21:45:00 +01:00
}
2010-11-18 00:32:46 +01:00
////////////////////////////////////////////////////////////
// Private Functions
////////////////////////////////////////////////////////////
2010-11-19 21:11:54 +01:00
void ProcessingDialog : : startNextJob ( void )
{
if ( m_pendingJobs . isEmpty ( ) )
{
return ;
}
2010-11-20 19:16:04 +01:00
m_currentFile + + ;
AudioFileModel currentFile = updateMetaInfo ( m_pendingJobs . takeFirst ( ) ) ;
2010-11-20 02:14:22 +01:00
AbstractEncoder * encoder = NULL ;
switch ( m_settings - > compressionEncoder ( ) )
{
case SettingsModel : : MP3Encoder :
{
MP3Encoder * mp3Encoder = new MP3Encoder ( ) ;
mp3Encoder - > setBitrate ( m_settings - > compressionBitrate ( ) ) ;
mp3Encoder - > setRCMode ( m_settings - > compressionRCMode ( ) ) ;
encoder = mp3Encoder ;
}
break ;
default :
throw " Unsupported encoder! " ;
}
2010-11-21 21:51:22 +01:00
ProcessThread * thread = new ProcessThread ( currentFile , ( m_settings - > outputToSourceDir ( ) ? QFileInfo ( currentFile . filePath ( ) ) . absolutePath ( ) : m_settings - > outputDir ( ) ) , encoder ) ;
2010-11-19 21:11:54 +01:00
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 ) ;
2010-11-20 22:14:10 +01:00
connect ( thread , SIGNAL ( processStateFinished ( QUuid , QString , bool ) ) , this , SLOT ( processFinished ( QUuid , QString , bool ) ) , Qt : : QueuedConnection ) ;
2010-11-22 21:45:00 +01:00
connect ( thread , SIGNAL ( processMessageLogged ( QUuid , QString ) ) , m_progressModel , SLOT ( appendToLog ( QUuid , QString ) ) , Qt : : QueuedConnection ) ;
2010-11-19 21:11:54 +01:00
m_runningThreads + + ;
thread - > start ( ) ;
}
2010-11-20 22:14:10 +01:00
void ProcessingDialog : : writePlayList ( void )
{
QString playListName = ( m_metaInfo - > fileAlbum ( ) . isEmpty ( ) ? " Playlist " : m_metaInfo - > fileAlbum ( ) ) ;
const static char * invalidChars = " \\ /:*? \" <>| " ;
for ( int i = 0 ; invalidChars [ i ] ; i + + )
{
playListName . replace ( invalidChars [ i ] , ' ' ) ;
playListName = playListName . simplified ( ) ;
}
QString playListFile = QString ( " %1/%2.m3u " ) . arg ( m_settings - > outputDir ( ) , playListName ) ;
int counter = 1 ;
while ( QFileInfo ( playListFile ) . exists ( ) )
{
playListFile = QString ( " %1/%2 (%3).m3u " ) . arg ( m_settings - > outputDir ( ) , playListName , QString : : number ( + + counter ) ) ;
}
QFile playList ( playListFile ) ;
if ( playList . open ( QIODevice : : WriteOnly ) )
{
playList . write ( " #EXTM3U \r \n " ) ;
for ( int i = 0 ; i < m_playList . count ( ) ; i + + )
{
playList . write ( QFileInfo ( m_playList . at ( i ) ) . fileName ( ) . toUtf8 ( ) . constData ( ) ) ;
playList . write ( " \r \n " ) ;
}
playList . close ( ) ;
}
2010-11-21 21:51:22 +01:00
else
{
QMessageBox : : warning ( this , " Playlist creation failed " , QString ( " The playlist file could not be created:<br><nobr>%1</nobr> " ) . arg ( playListFile ) ) ;
}
2010-11-20 22:14:10 +01:00
}
2010-11-20 19:16:04 +01:00
AudioFileModel ProcessingDialog : : updateMetaInfo ( const AudioFileModel & audioFile )
{
if ( ! m_settings - > writeMetaTags ( ) )
{
return AudioFileModel ( audioFile . filePath ( ) ) ;
}
AudioFileModel result = audioFile ;
if ( ! m_metaInfo - > fileArtist ( ) . isEmpty ( ) ) result . setFileArtist ( m_metaInfo - > fileArtist ( ) ) ;
if ( ! m_metaInfo - > fileAlbum ( ) . isEmpty ( ) ) result . setFileAlbum ( m_metaInfo - > fileAlbum ( ) ) ;
if ( ! m_metaInfo - > fileGenre ( ) . isEmpty ( ) ) result . setFileGenre ( m_metaInfo - > fileGenre ( ) ) ;
if ( m_metaInfo - > fileYear ( ) ) result . setFileYear ( m_metaInfo - > fileYear ( ) ) ;
if ( m_metaInfo - > filePosition ( ) ) result . setFileYear ( m_metaInfo - > filePosition ( ) ! = UINT_MAX ? m_metaInfo - > filePosition ( ) : m_currentFile ) ;
if ( ! m_metaInfo - > fileComment ( ) . isEmpty ( ) ) result . setFileComment ( m_metaInfo - > fileComment ( ) ) ;
return result ;
}
2010-11-18 00:32:46 +01:00
void ProcessingDialog : : setCloseButtonEnabled ( bool enabled )
{
HMENU hMenu = GetSystemMenu ( ( HWND ) winId ( ) , FALSE ) ;
EnableMenuItem ( hMenu , SC_CLOSE , MF_BYCOMMAND | ( enabled ? MF_ENABLED : MF_GRAYED ) ) ;
2010-11-17 19:35:50 +01:00
}