shithub: aacenc

Download patch

ref: 036981aa9e8a84b794a469e134721f179e1514dd
parent: 1368f4dad39f86ee1183d8d6227eb04e9ac1dd2d
author: xfhobbes <xfhobbes>
date: Sun Mar 18 08:28:42 EST 2001

Major update: roughly consolidated filter job functionality, added shell open support and several other things, cleaned up scc files and ignore list

--- a/wingui/.cvsignore
+++ b/wingui/.cvsignore
@@ -4,5 +4,6 @@
 *.opt
 *.aac
 *.wav
+faac_wingui.clw
 Release
 Debug
\ No newline at end of file
--- a/wingui/AbstractJob.cpp
+++ b/wingui/AbstractJob.cpp
@@ -17,7 +17,11 @@
 // Construction/Destruction
 //////////////////////////////////////////////////////////////////////
 
-CAbstractJob::CAbstractJob()
+CAbstractJob::CAbstractJob():
+	m_lThisJobCountNumber(-1),
+	m_lTotalNumberOfJobs(-1),
+	m_lThisSubJobCountNumber(-1),
+	m_lTotalNumberOfSubJobs(-1)
 {
 
 }
@@ -25,4 +29,42 @@
 CAbstractJob::~CAbstractJob()
 {
 
+}
+
+void CAbstractJob::SetJobNumberInfo(long lThisJobCountNumber, long lTotalNumberOfJobs)
+{
+	m_lThisJobCountNumber=lThisJobCountNumber;
+	m_lTotalNumberOfJobs=lTotalNumberOfJobs;
+}
+
+void CAbstractJob::SetSubJobNumberInfo(long lThisSubJobCountNumber, long lTotalNumberOfSubJobs)
+{
+	m_lThisSubJobCountNumber=lThisSubJobCountNumber;
+	m_lTotalNumberOfSubJobs=lTotalNumberOfSubJobs;
+}
+
+void CAbstractJob::CopyAllJobNumberInfoFromJob(const CAbstractJob &oJob)
+{
+	m_lThisJobCountNumber=oJob.m_lThisJobCountNumber;
+	m_lTotalNumberOfJobs=oJob.m_lTotalNumberOfJobs;
+	m_lThisSubJobCountNumber=oJob.m_lThisSubJobCountNumber;
+	m_lTotalNumberOfSubJobs=oJob.m_lTotalNumberOfSubJobs;
+}
+
+CString CAbstractJob::GetJobProcessingAdditionalCaptionBarInformation() const
+{
+	CString oJobInfo;
+	if (m_lTotalNumberOfJobs>=0)
+	{
+		oJobInfo.Format(IDS_JobNofM, m_lThisJobCountNumber+1, m_lTotalNumberOfJobs);
+	}
+	if (m_lTotalNumberOfSubJobs>=0)
+	{
+		CString oSubJobInfo;
+		oSubJobInfo.Format(IDS_SubJobNofM, m_lThisSubJobCountNumber+1, m_lTotalNumberOfSubJobs);
+
+		oJobInfo+=CString(" - ")+oSubJobInfo;
+	}
+
+	return oJobInfo;
 }
--- a/wingui/AbstractJob.h
+++ b/wingui/AbstractJob.h
@@ -28,6 +28,18 @@
 	// is used during the processing of the job to give the user a
 	// feedback what exactly is done; may use up to 3 lines
 	virtual CString GetDetailedDescriptionForStatusDialog() const=0;
+
+	// job processing information; all numbers are zero based
+	void SetJobNumberInfo(long lThisJobCountNumber, long lTotalNumberOfJobs);
+	void SetSubJobNumberInfo(long lThisSubJobCountNumber, long lTotalNumberOfSubJobs);
+	void CopyAllJobNumberInfoFromJob(const CAbstractJob &oJob);
+	CString GetJobProcessingAdditionalCaptionBarInformation() const;
+
+private:
+	long m_lThisJobCountNumber;
+	long m_lTotalNumberOfJobs;
+	long m_lThisSubJobCountNumber;
+	long m_lTotalNumberOfSubJobs;
 };
 
 #endif // !defined(AFX_ABSTRACTJOB_H__DFE38E74_0E81_11D5_8402_0080C88C25BD__INCLUDED_)
--- a/wingui/EncoderGeneralPageDialog.cpp
+++ b/wingui/EncoderGeneralPageDialog.cpp
@@ -186,7 +186,7 @@
 	CJob *poCurJob;
 	while (m_oJobsToConfigure.GetNextElemContent(oReader, poCurJob))
 	{
-		if (!poCurJob->GetJobType()==CJob::eEncoderJob)
+		if (poCurJob->GetJobType()!=CJob::eEncoderJob)
 		{
 			// must all be encoder jobs
 			ASSERT(false);
--- a/wingui/EncoderJob.cpp
+++ b/wingui/EncoderJob.cpp
@@ -43,7 +43,7 @@
 }
 
 
-CEncoderJob& CEncoderJob::operator=(const CEncoderJob &oRight)
+/*CEncoderJob& CEncoderJob::operator=(const CEncoderJob &oRight)
 {
 	m_oFiles=oRight.m_oFiles;
 	m_bSourceFileFilterIsRecursive=oRight.m_bSourceFileFilterIsRecursive;
@@ -60,7 +60,7 @@
 	m_ulBandwidth=oRight.m_ulBandwidth;
 
 	return *this;
-}
+}*/
 
 CString CEncoderJob::DescribeJobTypeShort() const
 {
@@ -134,7 +134,36 @@
 	{
 		// it's a filter encoder job
 
-		// first find out all files that actually belong to the job
+		CJobList oExpandedJobList;
+		if (!ExpandFilterJob(oExpandedJobList)) return false;
+
+		CBListReader oReader(oExpandedJobList);
+		CJob *poCurrentJob;
+		while ((poCurrentJob=oExpandedJobList.GetNextJob(oReader))!=0)
+		{
+			// make sure the target directory for the current job exists
+			CString oTargetDir(poCurrentJob->GetEncoderJob()->GetFiles().GetTargetFileDirectory());
+			if (!CRecursiveDirectoryTraverser::MakeSureDirectoryExists(oTargetDir))
+			{
+				CString oError;
+				oError.Format(IDS_ErrorCreatingNestedEncoderJob, poCurrentJob->GetEncoderJob()->GetFiles().GetCompleteSourceFilePath(), GetFiles().GetCompleteSourceFilePath());
+				AfxMessageBox("Error creating target directory", MB_OK | MB_ICONSTOP);		// XXX insert resource string and ask user what to do
+				return false;
+			}
+
+			// process the job
+			if (!poCurrentJob->GetEncoderJob()->ProcessJob())
+			{
+				CString oError;
+				oError.Format(IDS_ErrorCreatingNestedEncoderJob, poCurrentJob->GetEncoderJob()->GetFiles().GetCompleteSourceFilePath(), GetFiles().GetCompleteSourceFilePath());
+				if (AfxMessageBox(oError, MB_YESNO)!=IDYES)
+				{
+					return false;
+				}
+			}
+		}
+
+		/*// first find out all files that actually belong to the job
 		TItemList<CString> oFiles=
 			CRecursiveDirectoryTraverser::FindFiles(
 			GetFiles().GetSourceFileDirectory(),
@@ -149,11 +178,15 @@
 			return false;
 		}
 
+		long lTotalNumberOfSubJobsToProcess=oFiles.GetNumber();
+		long lCurSubJobCount=0;
+
 		CBListReader oReader(oFiles);
 		CString oCurrentFilePath;
 		while (oFiles.GetNextElemContent(oReader, oCurrentFilePath))
 		{
 			CEncoderJob oNewJob(*this);
+			oNewJob.SetSubJobNumberInfo(lCurSubJobCount++, lTotalNumberOfSubJobsToProcess);
 			if (!oNewJob.GetFiles().SetCompleteSourceFilePath(oCurrentFilePath))
 			{
 				CString oError;
@@ -169,10 +202,6 @@
 				CString oSourceFileDir;
 				{
 					oSourceFileDir=GetFiles().GetSourceFileDirectory();
-					if (oSourceFileDir[oSourceFileDir.GetLength()-1]=='\\')
-					{
-						oSourceFileDir.Delete(oSourceFileDir.GetLength()-1);
-					}
 					CString oTemp;
 					LPTSTR pDummy;
 					::GetFullPathName(oSourceFileDir,
@@ -179,6 +208,10 @@
 						MAX_PATH, oTemp.GetBuffer(MAX_PATH),
 						&pDummy);
 					oTemp.ReleaseBuffer();
+					if (oTemp[oTemp.GetLength()-1]=='\\')
+					{
+						oTemp.Delete(oTemp.GetLength()-1);
+					}
 
 					oSourceFileDir=oTemp;
 				}
@@ -227,7 +260,7 @@
 					return false;
 				}
 			}
-		}
+		}*/
 
 		return true;
 	}
@@ -349,6 +382,116 @@
 	CString oToReturn;
 	oToReturn.Format(iStringId);
 	return oToReturn;
+}
+
+bool CEncoderJob::ExpandFilterJob(CJobList &oTarget, bool bCreateDirectories) const
+{
+	if (!CFilePathCalc::IsValidFileMask(GetFiles().GetSourceFileName()))
+	{
+		ASSERT(false);		// not a filter job
+		return false;
+	}
+	else
+	{
+		// it's a filter encoder job
+
+		oTarget.DeleteAll();
+
+		// first find out all files that actually belong to the job
+		TItemList<CString> oFiles=
+			CRecursiveDirectoryTraverser::FindFiles(
+			GetFiles().GetSourceFileDirectory(),
+			GetFiles().GetSourceFileName(),
+			GetSourceFileFilterIsRecursive());
+
+		if (oFiles.GetNumber()==0)
+		{
+			CString oError;
+			oError.Format(IDS_FilterDidntFindFiles, GetFiles().GetCompleteSourceFilePath());
+			AfxMessageBox(oError);
+			return false;
+		}
+
+		long lTotalNumberOfSubJobsToProcess=oFiles.GetNumber();
+		long lCurSubJobCount=0;
+
+		CBListReader oReader(oFiles);
+		CString oCurrentFilePath;
+		while (oFiles.GetNextElemContent(oReader, oCurrentFilePath))
+		{
+			CEncoderJob oNewJob(*this);
+			oNewJob.SetSubJobNumberInfo(lCurSubJobCount++, lTotalNumberOfSubJobsToProcess);
+			if (!oNewJob.GetFiles().SetCompleteSourceFilePath(oCurrentFilePath))
+			{
+				CString oError;
+				oError.Format(IDS_ErrorCreatingNestedEncoderJob, oCurrentFilePath, GetFiles().GetCompleteSourceFilePath());
+				if (AfxMessageBox(oError, MB_YESNO)!=IDYES)
+				{
+					return false;
+				}
+			}
+			// assemble the target file name and apply it to the new job
+			{
+				// find out the long name of the source file directory
+				CString oSourceFileDir;
+				{
+					oSourceFileDir=GetFiles().GetSourceFileDirectory();
+					CString oTemp;
+					LPTSTR pDummy;
+					::GetFullPathName(oSourceFileDir,
+						MAX_PATH, oTemp.GetBuffer(MAX_PATH),
+						&pDummy);
+					oTemp.ReleaseBuffer();
+					if (oTemp[oTemp.GetLength()-1]=='\\')
+					{
+						oTemp.Delete(oTemp.GetLength()-1);
+					}
+
+					oSourceFileDir=oTemp;
+				}
+
+				// find out the suffix to append to the target directory
+				// for our particular file
+				CString oDirSuffix;
+				{
+					CString oFileDir(oCurrentFilePath);
+					CFilePathCalc::MakePath(oFileDir);
+					int iLength=oFileDir.GetLength();
+					oDirSuffix=oFileDir.Right(iLength-oSourceFileDir.GetLength());
+					oDirSuffix.Delete(0);
+				}
+
+				// determine the target directory for that particular file
+				CString oTargetDir(GetFiles().GetTargetFileDirectory());
+				CFilePathCalc::MakePath(oTargetDir, true);
+				oTargetDir+=oDirSuffix;
+				if (bCreateDirectories)
+				{
+					if (!CRecursiveDirectoryTraverser::MakeSureDirectoryExists(oTargetDir))
+					{
+						CString oError;
+						oError.Format(IDS_ErrorCreatingNestedEncoderJob, oCurrentFilePath, GetFiles().GetCompleteSourceFilePath());
+						AfxMessageBox("Error creating target directory", MB_OK | MB_ICONSTOP);		// XXX insert resource string and ask user what to do
+						return false;
+					}
+				}
+
+				CString oSourceFileName;
+				CFilePathCalc::ExtractFileName(oCurrentFilePath, oSourceFileName);
+				CString oSourceFileNameRaw;
+				CString oSourceFileExtension;
+				CFilePathCalc::SplitFileAndExtension(oSourceFileName, oSourceFileNameRaw, oSourceFileExtension);
+				oNewJob.GetFiles().SetTargetFileDirectory(oTargetDir);
+				CString oDefaultExtension;
+				oDefaultExtension.LoadString(IDS_EndTargetFileStandardExtension);
+				oNewJob.GetFiles().SetTargetFileName(oSourceFileNameRaw+"."+oDefaultExtension);
+			}
+
+			oTarget.AddJob(oNewJob);
+		}
+
+		return true;
+	}
 }
 
 CEncoderGeneralPropertyPageContents CEncoderJob::GetGeneralPageContents() const
--- a/wingui/EncoderJob.h
+++ b/wingui/EncoderJob.h
@@ -16,6 +16,8 @@
 #include "EncoderGeneralPropertyPageContents.h"
 #include "EncoderQualityPropertyPageContents.h"
 #include "EncoderId3PropertyPageContents.h"
+//#include "JobList.h"		// ring include
+class CJobList;
 
 // do not derive this class from CJob;
 // rather let CJob objects contain instances of this class
@@ -67,7 +69,8 @@
 	void SetBandwidth(unsigned long ulBandwidth)						{ m_ulBandwidth=ulBandwidth; }
 	void SetBandwidth(long lBandwidth)									{ ASSERT(lBandwidth>=0); m_ulBandwidth=lBandwidth; }
 
-	CEncoderJob& operator=(const CEncoderJob &oRight);
+	// no more up to date (also had to call base class version at least)
+	// CEncoderJob& operator=(const CEncoderJob &oRight);
 
 	// property page interaction
 	CEncoderGeneralPropertyPageContents GetGeneralPageContents() const;
@@ -92,6 +95,13 @@
 	virtual bool GetFromArchive(CArchive &oArchive);
 
 	static CString TranslateAacProfileToShortString(EAacProfile eAacProfile);
+
+	// when <this> is an encoder job with a filter as source file this method expands
+	// this job to a list of single jobs to process;
+	// returns false in case of errors but displays error messages on its own;
+	// the bCreateDirectories parameter specifies if the target directory structure
+	// is already to create (otherwise executing the job could fail)
+	bool ExpandFilterJob(CJobList &oTarget, bool bCreateDirectories=false) const;
 
 private:
 	CSourceTargetFilePair m_oFiles;
--- a/wingui/EncoderJobProcessingManager.cpp
+++ b/wingui/EncoderJobProcessingManager.cpp
@@ -49,7 +49,16 @@
 	{
 	case eInitial:
 		{
-			m_poInfoTarget->SetAvailableActions(true, false);
+			// initialize the status dialog
+			{
+				// define supported buttons
+				m_poInfoTarget->SetAvailableActions(true, false);
+
+				// set the dialog caption
+				m_poInfoTarget->SetAdditionalCaptionInfo(m_poJobToProcess->GetJobProcessingAdditionalCaptionBarInformation());
+			}
+
+			// initialize ourselves and run the job
 			m_eCurrentWorkingState=eRunning;
 			m_poInfoTarget->ReturnToCaller(DoProcessing());
 			break;
@@ -163,10 +172,6 @@
 	const CEncoderJob *poJob=m_poJobToProcess;
 	bool bInterrupted=false;
 
-	// TEMP: added to make it work, these values need to be used
-	unsigned long inputSamples, maxOutputSize;
-	//
-
 	SNDFILE *infile;
 	SF_INFO sfinfo;
 
@@ -178,8 +183,9 @@
 		unsigned int numChannels = sfinfo.channels;
 
 		// open and setup the encoder
-		faacEncHandle hEncoder = faacEncOpen(sampleRate, numChannels, &inputSamples,
-			&maxOutputSize);
+		unsigned long inputSamples;
+		unsigned long maxOutputSize;
+		faacEncHandle hEncoder = faacEncOpen(sampleRate, numChannels, &inputSamples, &maxOutputSize);
 		if (hEncoder)
 		{
 			HANDLE hOutfile;
@@ -309,6 +315,158 @@
 
 	return !bInterrupted;
 }
+
+
+// this is a version that I will try to put more the Hungarian Notation and C++ style
+/*bool CEncoderJobProcessingManager::DoProcessing()
+{
+	long lStartTimeMillis=::GetTickCount();
+	const CEncoderJob *poJob=m_poJobToProcess;
+	bool bInterrupted=false;
+
+	SNDFILE *phInfile;
+	SF_INFO sctSfInfo;
+
+	// open the input file
+	if ((phInfile=sf_open_read(poJob->GetFiles().GetCompleteSourceFilePath(), &sctSfInfo)) != NULL)
+	{
+		// determine input file parameters
+		unsigned int uiSampleRate=sctSfInfo.samplerate;
+		unsigned int uiNumChannels=sctSfInfo.channels;
+
+		// open and setup the encoder
+		unsigned long ulInputSamplesPerLoopCycle;
+		unsigned long ulMaxLoopCycleCompressionOutputSize;
+		faacEncHandle hEncoder=faacEncOpen(uiSampleRate, uiNumChannels, &ulInputSamplesPerLoopCycle, &ulMaxLoopCycleCompressionOutputSize);
+		if (hEncoder)
+		{
+			HANDLE hOutfile;
+
+			// set encoder configuration
+			faacEncConfigurationPtr pEncConfig=faacEncGetCurrentConfiguration(hEncoder);
+
+			pEncConfig->allowMidside = poJob->GetAllowMidside() ? 1 : 0;
+			pEncConfig->useTns = poJob->GetUseTns() ? 1 : 0;
+			pEncConfig->useLtp = poJob->GetUseLtp() ? 1 : 0;
+			pEncConfig->useLfe = poJob->GetUseLfe() ? 1 : 0;
+			pEncConfig->bitRate = poJob->GetBitRate();
+			pEncConfig->bandWidth = poJob->GetBandwidth();
+			pEncConfig->aacProfile = GetAacProfileConstant(poJob->GetAacProfile());
+
+			if (!faacEncSetConfiguration(hEncoder, pEncConfig))
+			{
+				faacEncClose(hEncoder);
+				sf_close(phInfile);
+
+				AfxMessageBox("faacEncSetConfiguration failed!", MB_OK | MB_ICONSTOP);
+
+				return false;
+			}
+
+			// open the output file
+			hOutfile=CreateFile(poJob->GetFiles().GetCompleteTargetFilePath(), GENERIC_WRITE, 0, NULL,
+				CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+
+			if (hOutfile != INVALID_HANDLE_VALUE)
+			{
+				UINT startTime = GetTickCount(), lastUpdated = 0;
+				DWORD totalBytesRead = 0;
+
+				unsigned int bytesInput = 0, bytesConsumed = 0;
+				DWORD numberOfBytesWritten = 0;
+				short *pcmbuf;
+				unsigned char *bitbuf;
+
+				pcmbuf = (short*)malloc(PCMBUFSIZE*numChannels*sizeof(short));
+				bitbuf = (unsigned char*)malloc(BITBUFSIZE*sizeof(unsigned char));
+
+				while (true)
+				{
+					int bytesWritten;
+					int samplesToRead = PCMBUFSIZE;
+
+					bytesInput = sf_read_short(infile, pcmbuf, numChannels*PCMBUFSIZE) * sizeof(short);
+					
+					//SendDlgItemMessage (hWnd, IDC_PROGRESS, PBM_SETPOS, (unsigned long)((float)totalBytesRead * 1024.0f / (sfinfo.samples*2*numChannels)), 0);
+					
+					totalBytesRead += bytesInput;
+
+					// call the actual encoding routine
+					bytesWritten = faacEncEncode(hEncoder,
+						pcmbuf,
+						bytesInput/2,
+						bitbuf,
+						BITBUFSIZE);
+
+					switch (m_eCurrentWorkingState)
+					{
+					case eRunning:
+						{
+							// just report our current state and process waiting window messages
+							WriteProgress(lStartTimeMillis, (sfinfo.samples*2*numChannels), totalBytesRead);
+							m_poInfoTarget->ProcessUserMessages();
+							break;
+						}
+					case ePaused:
+						{
+							// must wait
+							while (m_eCurrentWorkingState==ePaused)
+							{
+								// be idle
+								m_poInfoTarget->ProcessUserMessages();
+								Sleep(200);
+							}
+							break;
+						}
+					case eStopped:
+						{
+							// must interrupt
+							bInterrupted=true;
+							break;
+						}
+					}
+					
+					if (bInterrupted) 
+					{
+						// Stop Pressed
+						break;
+					}
+
+					if (!bytesInput && !bytesWritten)
+					{
+						// all done, bail out
+						break;
+					}
+
+					if (bytesWritten < 0)
+					{
+						AfxMessageBox("faacEncEncodeFrame failed!", MB_OK | MB_ICONSTOP);
+						bInterrupted=true;
+						break;
+					}
+
+					WriteFile(hOutfile, bitbuf, bytesWritten, &numberOfBytesWritten, NULL);
+				}
+
+				CloseHandle(hOutfile);
+				if (pcmbuf) free(pcmbuf);
+				if (bitbuf) free(bitbuf);
+			}
+
+			faacEncClose(hEncoder);
+		}
+
+		sf_close(infile);
+		MessageBeep(1);
+	}
+	else
+	{
+		AfxMessageBox("Couldn't open input file!", MB_OK | MB_ICONSTOP);
+		bInterrupted=true;
+	}
+
+	return !bInterrupted;
+}*/
 #endif
 
 void CEncoderJobProcessingManager::WriteProgress(long lOperationStartTickCount, long lMaxSteps, long lCurSteps)
@@ -352,4 +510,9 @@
 			return SSR;
 		}
 	}
+}
+
+CArchive* CEncoderJobProcessingManager::GetOutputFileArchive(const CString &oFileName)
+{
+	return 0;
 }
\ No newline at end of file
--- a/wingui/EncoderJobProcessingManager.h
+++ b/wingui/EncoderJobProcessingManager.h
@@ -47,6 +47,8 @@
 	void WriteProgress(long lOperationStartTickCount, long lMaxSteps, long lCurSteps);
 
 	static int GetAacProfileConstant(CEncoderJob::EAacProfile eAacProfile);
+
+	static CArchive* GetOutputFileArchive(const CString &oFileName);
 };
 
 #endif // !defined(AFX_ENCODERJOBPROCESSINGMANAGER_H__A1444E93_1546_11D5_8402_0080C88C25BD__INCLUDED_)
--- a/wingui/FloatingPropertyDialog.cpp
+++ b/wingui/FloatingPropertyDialog.cpp
@@ -6,6 +6,7 @@
 #include "stdafx.h"
 #include "faac_wingui.h"
 #include "FloatingPropertyDialog.h"
+#include "Faac_winguiDlg.h"
 
 #ifdef _DEBUG
 #define new DEBUG_NEW
@@ -52,6 +53,7 @@
 BEGIN_MESSAGE_MAP(CFloatingPropertyDialog, CDialog)
 	//{{AFX_MSG_MAP(CFloatingPropertyDialog)
 	ON_WM_SIZE()
+	ON_WM_CLOSE()
 	//}}AFX_MSG_MAP
 END_MESSAGE_MAP()
 
@@ -68,7 +70,7 @@
 	}
 }
 
-void CFloatingPropertyDialog::InvalidFloatingPropertiesDialog()
+void CFloatingPropertyDialog::InvalidateFloatingPropertiesDialog()
 {
 	if (m_poFloatingPropertyDialogSingleton!=0)
 	{
@@ -92,7 +94,7 @@
 	// TODO: Add extra initialization here
 	ShowWindow(SW_SHOW);
 	m_poPropertiesDummyDialog=new CPropertiesDummyParentDialog(true, this);
-	((CFaac_winguiApp*)AfxGetApp())->SetGlobalPropertiesDummyParentDialogSingleton(m_poPropertiesDummyDialog);
+	((CFaac_winguiApp*)AfxGetApp())->SetGlobalPropertiesDummyParentDialogSingleton(m_poPropertiesDummyDialog, this);
 	ApplyNewSize(m_oCurrentSize);
 	m_poPropertiesDummyDialog->ShowWindow(SW_SHOW);
 	
@@ -114,4 +116,13 @@
 		oDebugLabelRect.OffsetRect(-oLabelRect.Size().cx, -oLabelRect.Size().cy);
 		m_ctrlLabelDebugTag.MoveWindow(oDebugLabelRect);
 	}
-}
\ No newline at end of file
+}
+
+void CFloatingPropertyDialog::OnClose() 
+{
+	// TODO: Add your message handler code here and/or call default
+
+	((CFaac_winguiDlg*)AfxGetMainWnd())->HidePropertiesWindow(this);
+	
+	// CDialog::OnClose();
+}
--- a/wingui/FloatingPropertyDialog.h
+++ b/wingui/FloatingPropertyDialog.h
@@ -48,7 +48,7 @@
 
 	// this member properly cleans up any floating property window, if there's
 	// any
-	static void InvalidFloatingPropertiesDialog();
+	static void InvalidateFloatingPropertiesDialog();
 
 // Implementation
 protected:
@@ -57,6 +57,7 @@
 	//{{AFX_MSG(CFloatingPropertyDialog)
 	afx_msg void OnSize(UINT nType, int cx, int cy);
 	virtual BOOL OnInitDialog();
+	afx_msg void OnClose();
 	//}}AFX_MSG
 	DECLARE_MESSAGE_MAP()
 
--- a/wingui/Job.cpp
+++ b/wingui/Job.cpp
@@ -209,6 +209,7 @@
 {
 	if (m_poJob!=0)
 	{
+		m_poJob->CopyAllJobNumberInfoFromJob(*this);
 		return m_poJob->ProcessJob();
 	}
 	else
--- a/wingui/Listobj.cpp
+++ b/wingui/Listobj.cpp
@@ -213,12 +213,11 @@
 
 	pElem=CreateElem();
 
-
-	if (pLast==0) pLast=pElem;
-	pElem->pNext=pFirst;
-	if (pFirst!=0) pElem->pNext->pPrevious=pElem;
-	pElem->pPrevious=0;
-	pFirst=pElem;
+	if (pFirst==0) pFirst=pElem;
+	pElem->pPrevious=pLast;
+	if (pLast!=0) pElem->pPrevious->pNext=pElem;
+	pElem->pNext=0;
+	pLast=pElem;
 	pElem->lIndex=lIndex;
 	pElem->pParentList=this;
 
--- a/wingui/ProcessJobStatusDialog.cpp
+++ b/wingui/ProcessJobStatusDialog.cpp
@@ -54,6 +54,7 @@
 	ON_BN_CLICKED(IDC_BUTTONABORT, OnButtonAbort)
 	ON_BN_CLICKED(IDC_BUTTONPAUSE, OnButtonPause)
 	ON_BN_CLICKED(IDC_BUTTONCONTINUE, OnButtonContinue)
+	ON_BN_CLICKED(IDC_BUTTONMINIMIZEAPP, OnButtonMinimizeApp)
 	//}}AFX_MSG_MAP
 END_MESSAGE_MAP()
 
@@ -93,12 +94,32 @@
 
 void CProcessJobStatusDialog::ProcessUserMessages()
 {
+	//MSG msg;
+	//while (::PeekMessage(&msg, /**this*/0, 0, 0, PM_REMOVE)) 
+	//{ 
+	//	::TranslateMessage(&msg);
+	//	::DispatchMessage(&msg); 
+	//}
+
+	// copied from MSDN Topic "Idle Loop Processing"
 	MSG msg;
-	while (::PeekMessage(&msg, /**this*/0, 0, 0, PM_REMOVE)) 
-	{ 
-		::TranslateMessage(&msg);
-		::DispatchMessage(&msg); 
-	}
+    while ( ::PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) 
+    { 
+        if ( !AfxGetApp()->PumpMessage( ) ) 
+        { 
+			ASSERT(false);
+            //bDoingBackgroundProcessing = FALSE; 
+            ::PostQuitMessage(0); 
+            break; 
+        } 
+    } 
+    // let MFC do its idle processing
+    LONG lIdle = 0;
+    while ( AfxGetApp()->OnIdle(lIdle++ ) )
+        ;  
+    // Perform some background processing here 
+    // using another call to OnIdle
+
 }
 
 void CProcessJobStatusDialog::ReturnToCaller(bool bSuccess)
@@ -113,6 +134,32 @@
 	}
 }
 
+void CProcessJobStatusDialog::SetAdditionalCaptionInfo(const CString &oAdditionalInfo)
+{
+	if (oAdditionalInfo.GetLength()==0) return;
+
+	CString oCaption;
+	GetWindowText(oCaption);
+
+	CString oAddInfo(oAdditionalInfo);
+
+	if (oCaption.GetLength()>0)
+	{
+		// already a caption text there
+		oAddInfo=_T(" (")+oAddInfo+")";
+	}
+
+	if (oCaption.GetLength()<3 || oCaption.Right(3)!="...")
+	{
+		oCaption+=oAddInfo;
+	}
+	else
+	{
+		oCaption.Insert(oCaption.GetLength()-3, oAddInfo);
+	}
+	SetWindowText(oCaption);
+}
+
 void CALLBACK EXPORT CProcessJobStatusDialog::TimerProc(
 	   HWND hWnd,      // handle of CWnd that called SetTimer
 	   UINT nMsg,      // WM_TIMER
@@ -153,4 +200,12 @@
 {
 	// TODO: Add your control notification handler code here
 	m_poClient->Start(0);
+}
+
+void CProcessJobStatusDialog::OnButtonMinimizeApp() 
+{
+	// TODO: Add your control notification handler code here
+
+	// can't do that like this - don't yet know how to get it restored
+	// AfxGetMainWnd()->ShowWindow(SW_MINIMIZE);
 }
--- a/wingui/ProcessJobStatusDialog.h
+++ b/wingui/ProcessJobStatusDialog.h
@@ -36,6 +36,7 @@
 	virtual void SetAvailableActions(bool bStop, bool bPause);
 	virtual void ProcessUserMessages();
 	virtual void ReturnToCaller(bool bSuccess);
+	virtual void SetAdditionalCaptionInfo(const CString &oAdditionalInfo);
 
 	static CProcessJobStatusDialog *m_poDialog;
 	static void CALLBACK EXPORT TimerProc(
@@ -64,6 +65,7 @@
 	afx_msg void OnButtonAbort();
 	afx_msg void OnButtonPause();
 	afx_msg void OnButtonContinue();
+	afx_msg void OnButtonMinimizeApp();
 	//}}AFX_MSG
 	DECLARE_MESSAGE_MAP()
 
--- a/wingui/ProcessJobStatusDialog2.cpp
+++ /dev/null
@@ -1,135 +1,0 @@
-// ProcessJobStatusDialog.cpp : implementation file
-//
-
-#include "stdafx.h"
-#include "faac_wingui.h"
-#include "ProcessJobStatusDialog.h"
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-#ifndef SW_VIS_CODE
-#define SW_VIS_CODE(bVisible)		((bVisible) ? SW_SHOW : SW_HIDE)
-#endif
-
-/////////////////////////////////////////////////////////////////////////////
-// CProcessJobStatusDialog dialog
-
-
-CProcessJobStatusDialog::CProcessJobStatusDialog(CProcessingStartStopPauseInteractable *poClient, CWnd* pParent /*=NULL*/)
-	: CDialog(CProcessJobStatusDialog::IDD, pParent),
-	m_poClient(poClient)
-{
-	//{{AFX_DATA_INIT(CProcessJobStatusDialog)
-	m_oLabelBottomStatusText = _T("");
-	m_oLabelTopStatusText = _T("");
-	//}}AFX_DATA_INIT
-}
-
-CProcessJobStatusDialog::~CProcessJobStatusDialog()
-{
-}
-
-void CProcessJobStatusDialog::DoDataExchange(CDataExchange* pDX)
-{
-	CDialog::DoDataExchange(pDX);
-	//{{AFX_DATA_MAP(CProcessJobStatusDialog)
-	DDX_Control(pDX, IDC_BUTTONPAUSE, m_ctrlButtonPause);
-	DDX_Control(pDX, IDC_BUTTONCONTINUE, m_ctrlButtonContinue);
-	DDX_Control(pDX, IDC_BUTTONABORT, m_ctrlButtonAbort);
-	DDX_Control(pDX, IDC_PROGRESS1, m_ctrlProgressBar);
-	DDX_Text(pDX, IDC_LABELBOTTOMSTATUSTEXT, m_oLabelBottomStatusText);
-	DDX_Text(pDX, IDC_LABELTOPSTATUSTEXT, m_oLabelTopStatusText);
-	//}}AFX_DATA_MAP
-}
-
-
-BEGIN_MESSAGE_MAP(CProcessJobStatusDialog, CDialog)
-	//{{AFX_MSG_MAP(CProcessJobStatusDialog)
-	ON_BN_CLICKED(IDC_BUTTONABORT, OnButtonAbort)
-	ON_BN_CLICKED(IDC_BUTTONPAUSE, OnButtonPause)
-	ON_BN_CLICKED(IDC_BUTTONCONTINUE, OnButtonContinue)
-	ON_MESSAGE(4000, OnStartProcessing)
-	//}}AFX_MSG_MAP
-END_MESSAGE_MAP()
-
-/////////////////////////////////////////////////////////////////////////////
-// CProcessJobStatusDialog message handlers
-
-BOOL CProcessJobStatusDialog::OnInitDialog() 
-{
-	CDialog::OnInitDialog();
-	
-	// TODO: Add extra initialization here
-	m_ctrlProgressBar.SetRange32(0, 10000);
-
-	// install a timer to initiiate the processing
-	PostMessage(4000, 0, 0);
-	
-	return TRUE;  // return TRUE unless you set the focus to a control
-	              // EXCEPTION: OCX Property Pages should return FALSE
-}
-
-void CProcessJobStatusDialog::SetStatus(double dProgress, const CString &oTopStatusText, const CString &oBottomStatusText)
-{
-	m_ctrlProgressBar.SetPos((int)dProgress*100);
-	m_oLabelTopStatusText=oTopStatusText;
-	m_oLabelBottomStatusText=oBottomStatusText;
-	UpdateData(FALSE);
-}
-
-void CProcessJobStatusDialog::SetAvailableActions(bool bStop, bool bPause)
-{
-	m_ctrlButtonAbort.ShowWindow(SW_VIS_CODE(bStop));
-	m_ctrlButtonPause.ShowWindow(SW_VIS_CODE(bPause));
-	m_ctrlButtonContinue.ShowWindow(SW_VIS_CODE(bPause));
-}
-
-void CProcessJobStatusDialog::ProcessUserMessages()
-{
-	MSG msg;
-	while (::PeekMessage(&msg, /**this*/0, 0, 0, PM_REMOVE)) 
-	{ 
-		::TranslateMessage(&msg);
-		::DispatchMessage(&msg); 
-	}
-}
-
-void CProcessJobStatusDialog::ReturnToCaller(bool bSuccess)
-{
-	if (bSuccess)
-	{
-		CDialog::OnOK();
-	}
-	else
-	{
-		CDialog::OnCancel();
-	}
-}
-
-LRESULT CProcessJobStatusDialog::OnStartProcessing(WPARAM wParam, LPARAM lParam)
-{
-	m_poClient->Start(this);
-	return 0;
-}
-
-void CProcessJobStatusDialog::OnButtonAbort() 
-{
-	// TODO: Add your control notification handler code here
-	m_poClient->Stop();
-}
-
-void CProcessJobStatusDialog::OnButtonPause() 
-{
-	// TODO: Add your control notification handler code here
-	m_poClient->Pause();
-}
-
-void CProcessJobStatusDialog::OnButtonContinue() 
-{
-	// TODO: Add your control notification handler code here
-	m_poClient->Start(0);
-}
--- a/wingui/ProcessJobStatusDialog2.h
+++ /dev/null
@@ -1,68 +1,0 @@
-#if !defined(AFX_PROCESSJOBSTATUSDIALOG_H__A1444E8F_1546_11D5_8402_0080C88C25BD__INCLUDED_)
-#define AFX_PROCESSJOBSTATUSDIALOG_H__A1444E8F_1546_11D5_8402_0080C88C25BD__INCLUDED_
-
-#if _MSC_VER > 1000
-#pragma once
-#endif // _MSC_VER > 1000
-// ProcessJobStatusDialog.h : header file
-//
-
-#include "ProcessingStatusDialogInfoFeedbackCallbackInterface.h"
-#include "ProcessingStartStopPauseInteractable.h"
-
-/////////////////////////////////////////////////////////////////////////////
-// CProcessJobStatusDialog dialog
-
-class CProcessJobStatusDialog : public CDialog, public CProcessingStatusDialogInfoFeedbackCallbackInterface
-{
-// Construction
-public:
-	CProcessJobStatusDialog(CProcessingStartStopPauseInteractable *poClient, CWnd* pParent = NULL);   // standard constructor
-	virtual ~CProcessJobStatusDialog();
-
-// Dialog Data
-	//{{AFX_DATA(CProcessJobStatusDialog)
-	enum { IDD = IDD_PROCESSJOBSTATUSDIALOG };
-	CButton	m_ctrlButtonPause;
-	CButton	m_ctrlButtonContinue;
-	CButton	m_ctrlButtonAbort;
-	CProgressCtrl	m_ctrlProgressBar;
-	CString	m_oLabelBottomStatusText;
-	CString	m_oLabelTopStatusText;
-	//}}AFX_DATA
-
-	// implementation to interface CProcessingStatusDialogInfoFeedbackCallbackInterface
-	virtual void SetStatus(double dProgress, const CString &oTopStatusText, const CString &oBottomStatusText);
-	virtual void SetAvailableActions(bool bStop, bool bPause);
-	virtual void ProcessUserMessages();
-	virtual void ReturnToCaller(bool bSuccess);
-
-
-
-// Overrides
-	// ClassWizard generated virtual function overrides
-	//{{AFX_VIRTUAL(CProcessJobStatusDialog)
-	protected:
-	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
-	//}}AFX_VIRTUAL
-
-// Implementation
-protected:
-
-	// Generated message map functions
-	//{{AFX_MSG(CProcessJobStatusDialog)
-	virtual BOOL OnInitDialog();
-	afx_msg void OnButtonAbort();
-	afx_msg void OnButtonPause();
-	afx_msg void OnButtonContinue();
-	afx_msg LRESULT OnStartProcessing(WPARAM wParam, LPARAM lParam);
-	//}}AFX_MSG
-	DECLARE_MESSAGE_MAP()
-
-	CProcessingStartStopPauseInteractable *m_poClient;
-};
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_PROCESSJOBSTATUSDIALOG_H__A1444E8F_1546_11D5_8402_0080C88C25BD__INCLUDED_)
--- a/wingui/ProcessingStatusDialogInfoFeedbackCallbackInterface.h
+++ b/wingui/ProcessingStatusDialogInfoFeedbackCallbackInterface.h
@@ -23,6 +23,7 @@
 	virtual void SetStatus(double dProgress, const CString &oTopStatusText, const CString &oBottomStatusText)=0;
 	virtual void SetAvailableActions(bool bStop, bool bPause)=0;
 	virtual void ProcessUserMessages()=0;
+	virtual void SetAdditionalCaptionInfo(const CString &oAdditionalInfo)=0;
 
 	// the return value is the status code to return to the caller;
 	// if bSuccess then IDOK is returned, IDCANCEL otherwise
--- a/wingui/RecursiveDirectoryTraverser.cpp
+++ b/wingui/RecursiveDirectoryTraverser.cpp
@@ -27,11 +27,32 @@
 
 }
 
+int CRecursiveDirectoryTraverser::CountMatchingFiles(const CString &oFilterString)
+{
+	int iToReturn=0;
+
+	CFileFind oFileFind;
+	CString oSearchMask=oFilterString;
+	
+	if (oFileFind.FindFile(oSearchMask))
+	{		
+		iToReturn++;
+		while (oFileFind.FindNextFile())
+		{
+			iToReturn++;
+		}
+	}
+
+	oFileFind.Close();
+
+	return iToReturn;
+}
+
 TItemList<CString> CRecursiveDirectoryTraverser::FindFiles(const CString &oRootDirectory, const CString &oFileNameFilter, bool bRecursive)
 {
 	TItemList<CString> oToReturn;
 	CString oRootDir(oRootDirectory);
-	if (!CFilePathCalc::MakePath(oRootDir) || !CFilePathCalc::IsValidFileMask(oFileNameFilter))
+	if (!CFilePathCalc::MakePath(oRootDir, true) || !CFilePathCalc::IsValidFileMask(oFileNameFilter))
 	{
 		CString oError;
 		oError.Format(IDS_SearchParametersInvalid, oRootDir, oFileNameFilter);
@@ -140,27 +161,6 @@
 		}
 	}
 	return true;
-}
-
-int CRecursiveDirectoryTraverser::CountMatchingFiles(const CString &oFilterString)
-{
-	int iToReturn=0;
-
-	CFileFind oFileFind;
-	CString oSearchMask=oFilterString;
-	
-	if (oFileFind.FindFile(oSearchMask))
-	{		
-		iToReturn++;
-		while (oFileFind.FindNextFile())
-		{
-			iToReturn++;
-		}
-	}
-
-	oFileFind.Close();
-
-	return iToReturn;
 }
 
 bool CRecursiveDirectoryTraverser::CreateOneDirectory(CString &oExistingPath, CString &oCreatablePath)
--- a/wingui/RecursiveDirectoryTraverser.h
+++ b/wingui/RecursiveDirectoryTraverser.h
@@ -20,6 +20,11 @@
 	CRecursiveDirectoryTraverser();
 	virtual ~CRecursiveDirectoryTraverser();
 
+	// the filter string may be a directory name, a file, or a directory
+	// name with a file filter;
+	// returns -1 in case of errors
+	static int CountMatchingFiles(const CString &oFilterString);
+
 	// this method finds all files that are in the specified directory
 	// and match the filter; it can walk recursively through the entire
 	// subtree returning all files in the subtree that match the filter;
@@ -35,8 +40,6 @@
 	static bool MakeSureDirectoryExists(const CString &oDirectoryPath);
 
 private:
-	// returns -1 in case of errors
-	static int CountMatchingFiles(const CString &oFilterString);
 
 	// example:
 	//	before:
--- a/wingui/TItemList.h
+++ b/wingui/TItemList.h
@@ -87,6 +87,7 @@
 	bool FindContent(const LItemType &etContent, long lStartSearchAfterId, long &lId) const;
 	long GetContentCount(const LItemType &etContent) const;
 	TItemList<long> GetContentIds(const LItemType &etContent) const;
+	TItemList<long> GetAllUsedIds() const;
 
 	bool GetFirstElemContent(LItemType &etContent, long &lId) const;
 	bool GetFirstElemContent(LItemType* &etContent, long &lId) const;
@@ -474,6 +475,28 @@
 		{
 			oReturn.AddNewElem(lCurId);
 		}
+	}
+
+	poThis->EndRead(hRead);
+	return oReturn;
+}
+
+template <class LItemType> TItemList<long> TItemList<LItemType>::GetAllUsedIds() const
+{
+	TItemList<long> oReturn;
+
+	// we're using non-const members though we're going
+	// to reverse all changes; therefore let's disable
+	// the const checking
+	TItemList<LItemType> *poThis=(TItemList<LItemType>*)this;
+
+	// loop through all elements and collect their ids
+	LItemType *etReadContent;		// just a dummy
+	HRead hRead=poThis->BeginRead();
+	long lCurId;
+	while (poThis->GetNextElemContent(hRead, etReadContent, &lCurId))
+	{
+		oReturn.AddNewElem(lCurId);
 	}
 
 	poThis->EndRead(hRead);
--- a/wingui/faac_wingui.clw
+++ /dev/null
@@ -1,301 +1,0 @@
-; CLW file contains information for the MFC ClassWizard
-
-[General Info]
-Version=1
-LastClass=CEncoderGeneralPageDialog
-LastTemplate=CDialog
-NewFileInclude1=#include "stdafx.h"
-NewFileInclude2=#include "faac_wingui.h"
-
-ClassCount=10
-Class1=CFaac_winguiApp
-Class2=CFaac_winguiDlg
-Class3=CAboutDlg
-
-ResourceCount=15
-Resource1=IDD_ABOUTBOX
-Resource2=IDR_MAINFRAME
-Resource3=IDD_FAAC_WINGUI_DIALOG
-Resource4=IDD_PROPERTIESDUMMYPARENTDIALOG
-Resource5=IDD_PROPERTIESTABPARENTDIALOG (English (U.S.))
-Class4=CPropertiesTabParentDialog
-Resource6=IDD_PROCESSJOBSTATUSDIALOG (English (U.S.))
-Class5=CEncoderGeneralPageDialog
-Resource7=IDD_FLOATINGPROPERTYDIALOG (English (U.S.))
-Class6=CFloatingPropertyDialog
-Resource8=IDD_ENCODERGENERALPAGEDIALOG (English (U.S.))
-Class7=CPropertiesDummyParentDialog
-Resource9=IDD_FAAC_WINGUI_DIALOG (English (U.S.))
-Class8=CEncoderId3PageDialog
-Resource10=IDD_ENCODERQUALITYPAGEDIALOG
-Class9=CEncoderQualityPageDialog
-Resource11=IDD_ENCODERID3PAGEDIALOG (English (U.S.))
-Class10=CProcessJobStatusDialog
-Resource12=IDD_ABOUTBOX (English (U.S.))
-Resource13=IDR_TOOLBARMAIN (English (U.S.))
-Resource14=IDD_ENCODERQUALITYPAGEDIALOG (German (Germany))
-Resource15=IDD_PROPERTIESDUMMYPARENTDIALOG (German (Germany))
-
-[CLS:CFaac_winguiApp]
-Type=0
-HeaderFile=faac_wingui.h
-ImplementationFile=faac_wingui.cpp
-Filter=N
-
-[CLS:CFaac_winguiDlg]
-Type=0
-HeaderFile=faac_winguiDlg.h
-ImplementationFile=faac_winguiDlg.cpp
-Filter=D
-BaseClass=CDialog
-VirtualFilter=dWC
-LastObject=IDC_BUTTONDUPLICATESELECTED
-
-[CLS:CAboutDlg]
-Type=0
-HeaderFile=faac_winguiDlg.h
-ImplementationFile=faac_winguiDlg.cpp
-Filter=D
-
-[DLG:IDD_ABOUTBOX]
-Type=1
-ControlCount=4
-Control1=IDC_STATIC,static,1342177283
-Control2=IDC_STATIC,static,1342308352
-Control3=IDC_STATIC,static,1342308352
-Control4=IDOK,button,1342373889
-Class=CAboutDlg
-
-
-[DLG:IDD_FAAC_WINGUI_DIALOG]
-Type=1
-ControlCount=3
-Control1=IDOK,button,1342242817
-Control2=IDCANCEL,button,1342242816
-Control3=IDC_STATIC,static,1342308352
-Class=CFaac_winguiDlg
-
-[DLG:IDD_FAAC_WINGUI_DIALOG (English (U.S.))]
-Type=1
-Class=CFaac_winguiDlg
-ControlCount=9
-Control1=IDOK,button,1342242817
-Control2=IDC_LISTJOBS,SysListView32,1350664201
-Control3=IDC_BUTTONADDENCODERJOB,button,1342242816
-Control4=IDC_BUTTONDELETEJOBS,button,1342242816
-Control5=IDC_BUTTONPROCESSSELECTED,button,1342242816
-Control6=IDC_CHECKREMOVEPROCESSEDJOBS,button,1342242819
-Control7=IDC_BUTTONSAVEJOBLIST,button,1342242816
-Control8=IDC_BUTTONLOADJOBLIST,button,1342242816
-Control9=IDC_BUTTONDUPLICATESELECTED,button,1342242816
-
-[DLG:IDD_ABOUTBOX (English (U.S.))]
-Type=1
-Class=CAboutDlg
-ControlCount=5
-Control1=IDC_STATIC,static,1342177283
-Control2=IDC_STATIC,static,1342308480
-Control3=IDC_STATIC,static,1342308352
-Control4=IDOK,button,1342373889
-Control5=IDC_STATIC,static,1342308352
-
-[CLS:CPropertiesTabParentDialog]
-Type=0
-HeaderFile=PropertiesTabParentDialog.h
-ImplementationFile=PropertiesTabParentDialog.cpp
-BaseClass=CDialog
-Filter=D
-VirtualFilter=dWC
-LastObject=CPropertiesTabParentDialog
-
-[DLG:IDD_PROPERTIESTABPARENTDIALOG (English (U.S.))]
-Type=1
-Class=CPropertiesTabParentDialog
-ControlCount=3
-Control1=IDC_TAB1,SysTabControl32,1342177280
-Control2=IDC_LABELNOSELECTION,static,1342308352
-Control3=IDC_LABELDEBUGTAG,static,1073872896
-
-[DLG:IDD_ENCODERGENERALPAGEDIALOG (English (U.S.))]
-Type=1
-Class=CEncoderGeneralPageDialog
-ControlCount=14
-Control1=IDC_STATIC,static,1342308352
-Control2=IDC_EDITSOURCEDIR,edit,1350631552
-Control3=IDC_BUTTONBROWSESOURCEDIR,button,1342242816
-Control4=IDC_STATIC,static,1342308352
-Control5=IDC_EDITSOURCEFILE,edit,1350631552
-Control6=IDC_BUTTONBROWSESOURCEFILE,button,1342242816
-Control7=IDC_CHECKRECURSIVE,button,1342242819
-Control8=IDC_STATIC,static,1342308352
-Control9=IDC_EDITTARGETDIR,edit,1350631552
-Control10=IDC_BUTTONBROWSETARGETDIR,button,1342242816
-Control11=IDC_STATIC,static,1342308352
-Control12=IDC_EDITTARGETFILE,edit,1350631552
-Control13=IDC_BUTTONBROWSETARGETFILE,button,1342242816
-Control14=IDC_BUTTON1,button,1073807361
-
-[CLS:CEncoderGeneralPageDialog]
-Type=0
-HeaderFile=EncoderGeneralPageDialog.h
-ImplementationFile=EncoderGeneralPageDialog.cpp
-BaseClass=CDialog
-Filter=D
-VirtualFilter=dWC
-LastObject=CEncoderGeneralPageDialog
-
-[DLG:IDD_FLOATINGPROPERTYDIALOG (English (U.S.))]
-Type=1
-Class=CFloatingPropertyDialog
-ControlCount=1
-Control1=IDC_LABELDEBUGTAG,static,1073872896
-
-[CLS:CFloatingPropertyDialog]
-Type=0
-HeaderFile=FloatingPropertyDialog.h
-ImplementationFile=FloatingPropertyDialog.cpp
-BaseClass=CDialog
-Filter=D
-LastObject=CFloatingPropertyDialog
-VirtualFilter=dWC
-
-[DLG:IDD_PROPERTIESDUMMYPARENTDIALOG]
-Type=1
-Class=CPropertiesDummyParentDialog
-ControlCount=3
-Control1=IDC_STATIC,static,1073872896
-Control2=IDC_STATIC,static,1073872896
-Control3=IDC_LABELDEBUGTAG,static,1073872896
-
-[CLS:CPropertiesDummyParentDialog]
-Type=0
-HeaderFile=PropertiesDummyParentDialog.h
-ImplementationFile=PropertiesDummyParentDialog.cpp
-BaseClass=CDialog
-Filter=D
-VirtualFilter=dWC
-
-[DLG:IDD_ENCODERID3PAGEDIALOG (English (U.S.))]
-Type=1
-Class=CEncoderId3PageDialog
-ControlCount=24
-Control1=IDC_STATIC,static,1342308352
-Control2=IDC_STATIC,static,1342308352
-Control3=IDC_STATIC,static,1342308352
-Control4=IDC_STATIC,static,1342308352
-Control5=IDC_STATIC,static,1342308352
-Control6=IDC_EDITARTIST,edit,1350631552
-Control7=IDC_EDITTRACK,edit,1350631552
-Control8=IDC_EDITTITLE,edit,1350631552
-Control9=IDC_EDITURL,edit,1350631552
-Control10=IDC_STATIC,static,1342308352
-Control11=IDC_EDITALBUM,edit,1350631552
-Control12=IDC_STATIC,static,1342308352
-Control13=IDC_EDITYEAR,edit,1350631552
-Control14=IDC_STATIC,static,1342308352
-Control15=IDC_EDITCOMPOSER,edit,1350631552
-Control16=IDC_STATIC,static,1342308352
-Control17=IDC_EDITORIGINALARTIST,edit,1350631552
-Control18=IDC_CHECKCOPYRIGHT,button,1342242819
-Control19=IDC_STATIC,static,1342308352
-Control20=IDC_EDITCOMMENT,edit,1352728580
-Control21=IDC_STATIC,static,1342308352
-Control22=IDC_EDITENCODEDBY,edit,1350631552
-Control23=IDC_COMBOGENRE,combobox,1344340227
-Control24=IDC_BUTTON1,button,1073807361
-
-[CLS:CEncoderId3PageDialog]
-Type=0
-HeaderFile=EncoderId3PageDialog.h
-ImplementationFile=EncoderId3PageDialog.cpp
-BaseClass=CDialog
-Filter=D
-LastObject=CEncoderId3PageDialog
-VirtualFilter=dWC
-
-[DLG:IDD_ENCODERQUALITYPAGEDIALOG]
-Type=1
-Class=CEncoderQualityPageDialog
-ControlCount=15
-Control1=IDC_STATIC,static,1342373888
-Control2=IDC_EDITBITRATE,edit,1350631552
-Control3=IDC_STATIC,static,1342308352
-Control4=IDC_STATIC,static,1342308352
-Control5=IDC_EDITBANDWIDTH,edit,1350631552
-Control6=IDC_STATIC,static,1342308352
-Control7=IDC_CHECKMIDSIDE,button,1342242819
-Control8=IDC_CHECKUSETNS,button,1342242819
-Control9=IDC_CHECKUSELTP,button,1342242819
-Control10=IDC_CHECKUSELFE,button,1342242819
-Control11=IDC_STATIC,button,1342177287
-Control12=IDC_RADIOAACPROFILELC,button,1342373897
-Control13=IDC_RADIOAACPROFILEMAIN,button,1342177289
-Control14=IDC_RADIOAACPROFILESSR,button,1342177289
-Control15=IDC_BUTTON1,button,1073807361
-
-[CLS:CEncoderQualityPageDialog]
-Type=0
-HeaderFile=EncoderQualityPageDialog.h
-ImplementationFile=EncoderQualityPageDialog.cpp
-BaseClass=CDialog
-Filter=D
-LastObject=CEncoderQualityPageDialog
-VirtualFilter=dWC
-
-[DLG:IDD_PROCESSJOBSTATUSDIALOG (English (U.S.))]
-Type=1
-Class=CProcessJobStatusDialog
-ControlCount=6
-Control1=IDC_LABELTOPSTATUSTEXT,static,1342308353
-Control2=IDC_LABELBOTTOMSTATUSTEXT,static,1342308353
-Control3=IDC_PROGRESS1,msctls_progress32,1350565888
-Control4=IDC_BUTTONABORT,button,1073807360
-Control5=IDC_BUTTONPAUSE,button,1073807360
-Control6=IDC_BUTTONCONTINUE,button,1208025088
-
-[CLS:CProcessJobStatusDialog]
-Type=0
-HeaderFile=ProcessJobStatusDialog.h
-ImplementationFile=ProcessJobStatusDialog.cpp
-BaseClass=CDialog
-Filter=D
-VirtualFilter=dWC
-LastObject=CProcessJobStatusDialog
-
-[TB:IDR_TOOLBARMAIN (English (U.S.))]
-Type=1
-Class=?
-Command1=ID_BUTTON32771
-Command2=ID_BUTTON32772
-Command3=ID_BUTTON32773
-Command4=ID_BUTTON32774
-CommandCount=4
-
-[DLG:IDD_PROPERTIESDUMMYPARENTDIALOG (German (Germany))]
-Type=1
-Class=?
-ControlCount=3
-Control1=IDC_STATIC,static,1073872896
-Control2=IDC_STATIC,static,1073872896
-Control3=IDC_LABELDEBUGTAG,static,1073872896
-
-[DLG:IDD_ENCODERQUALITYPAGEDIALOG (German (Germany))]
-Type=1
-Class=?
-ControlCount=15
-Control1=IDC_STATIC,static,1342373888
-Control2=IDC_EDITBITRATE,edit,1350631552
-Control3=IDC_STATIC,static,1342308352
-Control4=IDC_STATIC,static,1342308352
-Control5=IDC_EDITBANDWIDTH,edit,1350631552
-Control6=IDC_STATIC,static,1342308352
-Control7=IDC_CHECKMIDSIDE,button,1342242819
-Control8=IDC_CHECKUSETNS,button,1342242819
-Control9=IDC_CHECKUSELTP,button,1342242819
-Control10=IDC_CHECKUSELFE,button,1342242819
-Control11=IDC_STATIC,button,1342177287
-Control12=IDC_RADIOAACPROFILELC,button,1342373897
-Control13=IDC_RADIOAACPROFILEMAIN,button,1342177289
-Control14=IDC_RADIOAACPROFILESSR,button,1342177289
-Control15=IDC_BUTTON1,button,1073807361
-
--- a/wingui/faac_wingui.cpp
+++ b/wingui/faac_wingui.cpp
@@ -34,6 +34,10 @@
 	// Place all significant initialization in InitInstance
 }
 
+CFaac_winguiApp::~CFaac_winguiApp()
+{
+}
+
 /////////////////////////////////////////////////////////////////////////////
 // The one and only CFaac_winguiApp object
 
@@ -79,7 +83,8 @@
 }
 
 void CFaac_winguiApp::SetGlobalPropertiesDummyParentDialogSingleton(
-	CPropertiesDummyParentDialog *poPropertyContainer)
+	CPropertiesDummyParentDialog *poPropertyContainer,
+	CFloatingPropertyDialog *poFloatingPropertiesDialog)
 {
 	if (m_poCurPropertiesDummyParentDialogSingletonContainer!=0)
 	{
@@ -89,6 +94,7 @@
 	}
 
 	m_poCurPropertiesDummyParentDialogSingletonContainer=poPropertyContainer;
+	m_poFloatingPropertiesDialog=poFloatingPropertiesDialog;
 }
 
 CPropertiesDummyParentDialog* CFaac_winguiApp::GetGlobalPropertiesDummyParentDialogSingleton()
@@ -96,6 +102,16 @@
 	return m_poCurPropertiesDummyParentDialogSingletonContainer;
 }
 
+bool CFaac_winguiApp::HaveFloatingProperties() const
+{
+	return m_poFloatingPropertiesDialog!=0;
+}
+
+CFloatingPropertyDialog* CFaac_winguiApp::GetFloatingPropertiesDialog() const
+{
+	return m_poFloatingPropertiesDialog;
+}
+
 void CFaac_winguiApp::PerformAppCleanup()
 {
 	if (m_poCurPropertiesDummyParentDialogSingletonContainer!=0)
@@ -103,4 +119,4 @@
 		delete m_poCurPropertiesDummyParentDialogSingletonContainer;
 		m_poCurPropertiesDummyParentDialogSingletonContainer=0;
 	}
-}
\ No newline at end of file
+}
--- a/wingui/faac_wingui.dsp
+++ b/wingui/faac_wingui.dsp
@@ -25,7 +25,7 @@
 # PROP AllowPerConfigDependencies 0
 # PROP Scc_ProjName ""
 # PROP Scc_LocalPath ""
-CPP=xicl6.exe
+CPP=cl.exe
 MTL=midl.exe
 RSC=rc.exe
 
@@ -51,9 +51,9 @@
 BSC32=bscmake.exe
 # ADD BASE BSC32 /nologo
 # ADD BSC32 /nologo
-LINK32=xilink6.exe
+LINK32=link.exe
 # ADD BASE LINK32 /nologo /subsystem:windows /machine:I386
-# ADD LINK32 libsndfile.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 /nologo /subsystem:windows /machine:I386
 
 !ELSEIF  "$(CFG)" == "faac_wingui - Win32 Debug"
 
@@ -77,9 +77,9 @@
 BSC32=bscmake.exe
 # ADD BASE BSC32 /nologo
 # ADD BSC32 /nologo
-LINK32=xilink6.exe
+LINK32=link.exe
 # ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 libsndfile.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
 
 !ENDIF 
 
--- a/wingui/faac_wingui.h
+++ b/wingui/faac_wingui.h
@@ -18,6 +18,7 @@
 #include "JobList.h"
 #include "PropertiesDummyParentDialog.h"
 #include "FaacWinguiProgramSettings.h"
+#include "FloatingPropertyDialog.h"
 
 /////////////////////////////////////////////////////////////////////////////
 // CFaac_winguiApp:
@@ -28,6 +29,7 @@
 {
 public:
 	CFaac_winguiApp();
+	virtual ~CFaac_winguiApp();
 
 // Overrides
 	// ClassWizard generated virtual function overrides
@@ -43,8 +45,10 @@
 
 	// these two members are not an exact pair (getter/setter); however they
 	// work closely together
-	void SetGlobalPropertiesDummyParentDialogSingleton(CPropertiesDummyParentDialog *poPropertyContainer);
+	void SetGlobalPropertiesDummyParentDialogSingleton(CPropertiesDummyParentDialog *poPropertyContainer, CFloatingPropertyDialog *poFloatingPropertiesDialog=0);
 	CPropertiesDummyParentDialog* GetGlobalPropertiesDummyParentDialogSingleton();
+	bool HaveFloatingProperties() const;
+	CFloatingPropertyDialog* GetFloatingPropertiesDialog() const;
 
 // Implementation
 
@@ -67,6 +71,7 @@
 	// this member saves a pointer to the entry point to display
 	// properties of jobs
 	CPropertiesDummyParentDialog *m_poCurPropertiesDummyParentDialogSingletonContainer;
+	CFloatingPropertyDialog *m_poFloatingPropertiesDialog;
 
 
 	// something like the destructor of the application
--- a/wingui/faac_wingui.rc
+++ b/wingui/faac_wingui.rc
@@ -101,14 +101,14 @@
     CONTROL         "Use LTP",IDC_CHECKUSELTP,"Button",BS_AUTOCHECKBOX | 
                     WS_TABSTOP,24,72,44,10
     CONTROL         "Use LFE",IDC_CHECKUSELFE,"Button",BS_AUTOCHECKBOX | 
-                    WS_TABSTOP,24,83,43,10
+                    WS_DISABLED | WS_TABSTOP,24,83,43,10
     GROUPBOX        "AAC Profile",IDC_STATIC,133,46,47,48
     CONTROL         "LC",IDC_RADIOAACPROFILELC,"Button",BS_AUTORADIOBUTTON | 
                     WS_GROUP | WS_TABSTOP,142,58,25,10
     CONTROL         "Main",IDC_RADIOAACPROFILEMAIN,"Button",
                     BS_AUTORADIOBUTTON,142,69,31,10
-    CONTROL         "SSR",IDC_RADIOAACPROFILESSR,"Button",BS_AUTORADIOBUTTON,
-                    142,79,31,10
+    CONTROL         "SSR",IDC_RADIOAACPROFILESSR,"Button",BS_AUTORADIOBUTTON | 
+                    WS_DISABLED,142,79,31,10
     DEFPUSHBUTTON   "Enter Attractor",IDC_BUTTON1,198,112,50,14,NOT 
                     WS_VISIBLE
 END
@@ -178,13 +178,14 @@
                     IDC_STATIC,40,22,190,8
 END
 
-IDD_FAAC_WINGUI_DIALOG DIALOGEX 0, 0, 422, 199
-STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+IDD_FAAC_WINGUI_DIALOG DIALOGEX 0, 0, 422, 202
+STYLE DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | 
+    WS_SYSMENU
 EXSTYLE WS_EX_APPWINDOW
 CAPTION "winfaac"
-FONT 8, "MS Sans Serif"
+FONT 8, "MS Sans Serif", 0, 0, 0x1
 BEGIN
-    DEFPUSHBUTTON   "Bye",IDOK,365,178,50,14
+    DEFPUSHBUTTON   "Bye",IDOK,365,181,50,14
     CONTROL         "List1",IDC_LISTJOBS,"SysListView32",LVS_REPORT | 
                     LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | 
                     WS_TABSTOP,7,7,408,131
@@ -191,15 +192,20 @@
     PUSHBUTTON      "&Add Encoder Jobs...",IDC_BUTTONADDENCODERJOB,7,143,71,
                     14
     PUSHBUTTON      "&Delete Jobs",IDC_BUTTONDELETEJOBS,83,143,50,14
-    PUSHBUTTON      "&Process Selected",IDC_BUTTONPROCESSSELECTED,7,161,66,
+    PUSHBUTTON      "&Process Selected",IDC_BUTTONPROCESSSELECTED,63,161,66,
                     14
     CONTROL         "Remove Processed Jobs From List",
                     IDC_CHECKREMOVEPROCESSEDJOBS,"Button",BS_AUTOCHECKBOX | 
-                    WS_TABSTOP,7,182,125,10
+                    WS_TABSTOP,7,179,125,10
     PUSHBUTTON      "&Save Joblist...",IDC_BUTTONSAVEJOBLIST,301,143,54,14
     PUSHBUTTON      "&Load Joblist...",IDC_BUTTONLOADJOBLIST,361,143,54,14
     PUSHBUTTON      "D&uplicate Selected",IDC_BUTTONDUPLICATESELECTED,139,
                     143,69,14
+    PUSHBUTTON      "Pro&cess All",IDC_BUTTONPROCESSALL,7,161,50,14
+    PUSHBUTTON      "Open Pr&operties",IDC_BUTTONOPENPROPERTIES,356,161,59,
+                    14
+    PUSHBUTTON      "E&xpand Filter Job",IDC_BUTTONEXPANDFILTERJOB,215,143,
+                    65,14,WS_DISABLED
 END
 
 IDD_PROPERTIESTABPARENTDIALOG DIALOG DISCARDABLE  0, 0, 186, 95
@@ -283,9 +289,10 @@
 FONT 8, "MS Sans Serif"
 BEGIN
     CTEXT           "Static",IDC_LABELTOPSTATUSTEXT,7,7,340,39
-    CTEXT           "Static",IDC_LABELBOTTOMSTATUSTEXT,7,58,340,23
+    PUSHBUTTON      "_",IDC_BUTTONMINIMIZEAPP,337,91,10,11,NOT WS_VISIBLE
     CONTROL         "Progress1",IDC_PROGRESS1,"msctls_progress32",WS_BORDER,
                     23,47,307,10
+    CTEXT           "Static",IDC_LABELBOTTOMSTATUSTEXT,7,58,340,23
     PUSHBUTTON      "Abort",IDC_BUTTONABORT,152,88,50,14,NOT WS_VISIBLE
     PUSHBUTTON      "Pause",IDC_BUTTONPAUSE,207,88,50,14,NOT WS_VISIBLE
     PUSHBUTTON      "Continue",IDC_BUTTONCONTINUE,262,88,50,14,NOT 
@@ -315,7 +322,7 @@
         LEFTMARGIN, 7
         RIGHTMARGIN, 415
         TOPMARGIN, 7
-        BOTTOMMARGIN, 192
+        BOTTOMMARGIN, 195
         HORZGUIDE, 150
         HORZGUIDE, 168
     END
@@ -813,6 +820,9 @@
                             "The file filter ""%s"" didn't find any files. This might be due to an error in the filter format or because no files exist.\nThe job completes with an error."
     IDS_ErrorCreatingNestedEncoderJob 
                             "Could not process nested file ""%s"". Would you like to continue processing remaining files of encoder job ""%s""?"
+    IDS_ErrorWhileLoadingJobList "Error while loading joblist."
+    IDS_JobNofM             "%d of %d"
+    IDS_SubJobNofM          "Sub Job %d of %d"
 END
 
 #endif    // English (U.S.) resources
--- a/wingui/faac_winguiDlg.cpp
+++ b/wingui/faac_winguiDlg.cpp
@@ -69,7 +69,8 @@
 CFaac_winguiDlg::CFaac_winguiDlg(CWnd* pParent /*=NULL*/)
 	: CDialog(CFaac_winguiDlg::IDD, pParent),
 	m_iListCtrlUpdatesCounter(-1),
-	m_poCurrentStandardFile(0)
+	m_poCurrentStandardFile(0),
+	m_poHiddenPropertiesWindow(0)
 {
 	//{{AFX_DATA_INIT(CFaac_winguiDlg)
 	m_bCheckRemoveProcessedJobs = FALSE;
@@ -87,6 +88,8 @@
 {
 	CDialog::DoDataExchange(pDX);
 	//{{AFX_DATA_MAP(CFaac_winguiDlg)
+	DDX_Control(pDX, IDC_BUTTONEXPANDFILTERJOB, m_ctrlButtonExpandFilterJob);
+	DDX_Control(pDX, IDC_BUTTONOPENPROPERTIES, m_ctrlButtonOpenProperties);
 	DDX_Control(pDX, IDC_LISTJOBS, m_ctrlListJobs);
 	DDX_Check(pDX, IDC_CHECKREMOVEPROCESSEDJOBS, m_bCheckRemoveProcessedJobs);
 	//}}AFX_DATA_MAP
@@ -106,6 +109,10 @@
 	ON_BN_CLICKED(IDC_BUTTONSAVEJOBLIST, OnButtonSaveJobList)
 	ON_BN_CLICKED(IDC_BUTTONLOADJOBLIST, OnButtonLoadJobList)
 	ON_BN_CLICKED(IDC_BUTTONDUPLICATESELECTED, OnButtonDuplicateSelected)
+	ON_BN_CLICKED(IDC_BUTTONPROCESSALL, OnButtonProcessAll)
+	ON_BN_CLICKED(IDC_BUTTONOPENPROPERTIES, OnButtonOpenProperties)
+	ON_WM_SHOWWINDOW()
+	ON_BN_CLICKED(IDC_BUTTONEXPANDFILTERJOB, OnButtonExpandFilterJob)
 	//}}AFX_MSG_MAP
 END_MESSAGE_MAP()
 
@@ -152,14 +159,49 @@
 
 		// create a floating property window
 		CFloatingPropertyDialog::CreateFloatingPropertiesDummyParentDialog();
+		m_ctrlButtonOpenProperties.ShowWindow(SW_HIDE);		// property window is open
 
 		// make sure the floating window is initialized properly
 		OnJobListCtrlSelChange();
+
+
+		// load file specified on the command line (if any)
+		{
+			// Parse command line for standard shell commands, DDE, file open
+			CCommandLineInfo cmdInfo;
+			AfxGetApp()->ParseCommandLine(cmdInfo);
+			if (cmdInfo.m_nShellCommand==CCommandLineInfo::FileNew)	// prevent opening a new file on program start
+			{
+				cmdInfo.m_nShellCommand=CCommandLineInfo::FileNothing;
+			}
+			else if (cmdInfo.m_nShellCommand==CCommandLineInfo::FileOpen)
+			{
+				// must load a job list
+				LoadJobList(cmdInfo.m_strFileName);
+			}
+		}
 	}
 	
 	return TRUE;  // return TRUE  unless you set the focus to a control
 }
 
+void CFaac_winguiDlg::HidePropertiesWindow(CWnd *poPropertiesWindow)
+{
+	// must not hide two property windows at a time
+	ASSERT(m_poHiddenPropertiesWindow==0);
+
+	m_poHiddenPropertiesWindow=poPropertiesWindow;
+	m_poHiddenPropertiesWindow->ShowWindow(SW_HIDE);
+	m_ctrlButtonOpenProperties.ShowWindow(SW_SHOW);
+}
+
+void CFaac_winguiDlg::ShowPropertiesWindow()
+{
+	m_poHiddenPropertiesWindow->ShowWindow(SW_SHOW);
+	m_poHiddenPropertiesWindow=0;
+	m_ctrlButtonOpenProperties.ShowWindow(SW_HIDE);
+}
+
 void CFaac_winguiDlg::OnSysCommand(UINT nID, LPARAM lParam)
 {
 	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
@@ -412,6 +454,32 @@
 	{
 		delete poSupportedPages;
 	}
+
+	// enable/disable the expand button
+	{
+		bool bButtonEnabled=true;
+		if (m_oSelectedJobsIds.GetNumber()!=1)
+		{
+			bButtonEnabled=false;
+		}
+		else
+		{
+			long lSelectedJobId;
+			long lDummy;
+			m_oSelectedJobsIds.GetFirstElemContent(lSelectedJobId, lDummy);
+			CJob *poJob=oJobs.GetJob(lSelectedJobId);
+			if (poJob->GetEncoderJob()==0)
+			{
+				bButtonEnabled=false;
+			}
+			else if (!CFilePathCalc::IsValidFileMask(poJob->GetEncoderJob()->GetFiles().GetSourceFileName()))
+			{
+				bButtonEnabled=false;
+			}
+		}
+
+		m_ctrlButtonExpandFilterJob.EnableWindow(bButtonEnabled ? TRUE : FALSE);
+	}
 }
 
 void CFaac_winguiDlg::OnClickListJobs(NMHDR* pNMHDR, LRESULT* pResult) 
@@ -451,51 +519,10 @@
 {
 	if (!UpdateData(TRUE)) return;
 
-	CJobList *poJobList=GetGlobalJobList();
-
 	TItemList<long> oCurSelection(CWindowUtil::GetAllSelectedListCtrlItemLParams(&m_ctrlListJobs, false));
+	ProcessJobs(oCurSelection, m_bCheckRemoveProcessedJobs!=0);
 
-	TItemList<long> oItemsToRemove;
-
-	CBListReader oReader(oCurSelection);
-	long lCurIndex;
-	bool bContinue=true;
-	while (bContinue && oCurSelection.GetNextElemContent(oReader, lCurIndex))
-	{
-		// get the current job
-		CJob *poJob=poJobList->GetJob(lCurIndex);
-
-		if (!poJob->ProcessJob())
-		{
-			if (AfxMessageBox(IDS_ErrorProcessingJobSelection, MB_YESNO)!=IDYES)
-			{
-				bContinue=false;
-			}
-		}
-		else
-		{
-			// successfully processed
-			if (m_bCheckRemoveProcessedJobs)
-			{
-				int iListItem=CWindowUtil::GetListCtrlItemIdByLParam(&m_ctrlListJobs, lCurIndex);
-				ASSERT(iListItem>=0);		// must exist (logically)
-				m_ctrlListJobs.DeleteItem(iListItem);
-
-				oItemsToRemove.AddNewElem(lCurIndex);
-			}
-		}
-	}
-
-	if (oItemsToRemove.GetNumber()>0)
-	{
-		OnJobListCtrlUserAction();	// this call is very important since the property dialog must be informed about the new selection before the underlying jobs are deleted
-		poJobList->DeleteElems(oItemsToRemove);
-		ReFillInJobListCtrl(0, false);
-
-		// the selection may have changed, so make sure the property
-		// dialog is updated
-		OnJobListCtrlUserAction();
-	}
+	CJobList *poJobList=GetGlobalJobList();
 }
 
 void CFaac_winguiDlg::OnRclickListJobs(NMHDR* pNMHDR, LRESULT* pResult) 
@@ -537,13 +564,9 @@
 	if (oOpenDialog.DoModal()==IDOK)
 	{
 		// the file has been selected
-		CFileSerializableJobList oJobList(*GetGlobalJobList());
 		ReleaseStandardFile();
 		m_poCurrentStandardFile=new CString(oOpenDialog.GetPathName());
-		if (!oJobList.SaveToFile(oOpenDialog.GetPathName(), 1))
-		{
-			AfxMessageBox(IDS_ErrorWhileSavingJobList, MB_OK | MB_ICONSTOP);
-		}
+		SaveJobList(*m_poCurrentStandardFile);
 	}
 	else
 	{
@@ -588,18 +611,9 @@
 	if (oOpenDialog.DoModal()==IDOK)
 	{
 		// the file has been selected
-		CFileSerializableJobList oJobList;
 		ReleaseStandardFile();
 		m_poCurrentStandardFile=new CString(oOpenDialog.GetPathName());
-		if (!oJobList.LoadFromFile(oOpenDialog.GetPathName(), 1))
-		{
-			AfxMessageBox(IDS_ErrorWhileSavingJobList, MB_OK | MB_ICONSTOP);
-		}
-		else
-		{
-			*GetGlobalJobList()=oJobList;
-			ReFillInJobListCtrl(0, false);
-		}
+		LoadJobList(*m_poCurrentStandardFile);
 	}
 	else
 	{
@@ -649,5 +663,150 @@
 		// the selection may have changed, so make sure the property
 		// dialog is updated
 		OnJobListCtrlUserAction();
+	}
+}
+
+void CFaac_winguiDlg::OnButtonProcessAll() 
+{
+	// TODO: Add your control notification handler code here
+	if (!UpdateData(TRUE)) return;
+
+	ProcessJobs(GetGlobalJobList()->GetAllUsedIds(), m_bCheckRemoveProcessedJobs!=0);
+}
+
+void CFaac_winguiDlg::ProcessJobs(TItemList<long> oJobIds, bool bRemoveProcessJobs)
+{
+	if (oJobIds.GetNumber()==0) return;
+	CJobList *poJobList=GetGlobalJobList();
+
+	TItemList<long> oItemsToRemove;
+
+	long lTotalNumberOfJobsToProcess=oJobIds.GetNumber();
+	long lCurJobCount=0;
+
+	CBListReader oReader(oJobIds);
+	long lCurIndex;
+	bool bContinue=true;
+	while (bContinue && oJobIds.GetNextElemContent(oReader, lCurIndex))
+	{
+		// get the current job
+		CJob *poJob=poJobList->GetJob(lCurIndex);
+		poJob->SetJobNumberInfo(lCurJobCount++, lTotalNumberOfJobsToProcess);
+
+		if (!poJob->ProcessJob())
+		{
+			if (AfxMessageBox(IDS_ErrorProcessingJobSelection, MB_YESNO)!=IDYES)
+			{
+				bContinue=false;
+			}
+		}
+		else
+		{
+			// successfully processed
+			if (bRemoveProcessJobs)
+			{
+				int iListItem=CWindowUtil::GetListCtrlItemIdByLParam(&m_ctrlListJobs, lCurIndex);
+				ASSERT(iListItem>=0);		// must exist (logically)
+				m_ctrlListJobs.DeleteItem(iListItem);
+
+				oItemsToRemove.AddNewElem(lCurIndex);
+			}
+		}
+	}
+
+	if (oItemsToRemove.GetNumber()>0)
+	{
+		OnJobListCtrlUserAction();	// this call is very important since the property dialog must be informed about the new selection before the underlying jobs are deleted
+		poJobList->DeleteElems(oItemsToRemove);
+		ReFillInJobListCtrl(0, false);
+
+		// the selection may have changed, so make sure the property
+		// dialog is updated
+		OnJobListCtrlUserAction();
+	}
+}
+
+bool CFaac_winguiDlg::LoadJobList(const CString &oCompletePath)
+{
+	// the file has been selected
+	CFileSerializableJobList oJobList;
+	if (!oJobList.LoadFromFile(oCompletePath, 1))
+	{
+		AfxMessageBox(IDS_ErrorWhileLoadingJobList, MB_OK | MB_ICONSTOP);
+		return false;
+	}
+	else
+	{
+		// first make sure the property window doesn't contain anything
+		CWindowUtil::DeleteAllListCtrlItems(&m_ctrlListJobs);
+		OnJobListCtrlUserAction();
+
+		*GetGlobalJobList()=oJobList;
+		ReFillInJobListCtrl(0, false);
+		return true;
+	}
+}
+
+bool CFaac_winguiDlg::SaveJobList(const CString &oCompletePath)
+{
+	// the file has been selected
+	CFileSerializableJobList oJobList(*GetGlobalJobList());
+	if (!oJobList.SaveToFile(oCompletePath, 1))
+	{
+		AfxMessageBox(IDS_ErrorWhileSavingJobList, MB_OK | MB_ICONSTOP);
+		return false;
+	}
+	else
+	{
+		return true;
+	}
+}
+
+void CFaac_winguiDlg::OnButtonOpenProperties() 
+{
+	// TODO: Add your control notification handler code here
+	ShowPropertiesWindow();
+}
+
+void CFaac_winguiDlg::OnShowWindow(BOOL bShow, UINT nStatus) 
+{
+	CDialog::OnShowWindow(bShow, nStatus);
+	
+	// TODO: Add your message handler code here
+	
+}
+
+void CFaac_winguiDlg::OnButtonExpandFilterJob() 
+{
+	// TODO: Add your control notification handler code here
+	TItemList<long> oCurSelection(CWindowUtil::GetAllSelectedListCtrlItemLParams(&m_ctrlListJobs, false));
+
+	long lSelectedJobId;
+	long lDummy;
+	oCurSelection.GetFirstElemContent(lSelectedJobId, lDummy);
+
+	CJobList *poGlobalJobList=GetGlobalJobList();
+	CJob *poJob=poGlobalJobList->GetJob(lSelectedJobId);
+	CJobList oExpanded;
+	if (poJob->GetEncoderJob()==0)
+	{
+		ASSERT(false);
+		return;
+	}
+	else if (poJob->GetEncoderJob()->ExpandFilterJob(oExpanded, false))
+	{
+		int iListItemToDelete=CWindowUtil::GetListCtrlItemIdByLParam(&m_ctrlListJobs, lSelectedJobId);
+		if (iListItemToDelete>=0)
+		{
+			m_ctrlListJobs.DeleteItem(iListItemToDelete);
+			OnJobListCtrlUserAction();	// this call is very important since the property dialog must be informed about the new selection before the underlying jobs are deleted
+		}
+		poGlobalJobList->DeleteElem(lSelectedJobId);
+		*poGlobalJobList+=oExpanded;
+
+		CListCtrlStateSaver oListSelection;
+		oListSelection.SetToSelected(oExpanded.GetAllUsedIds());
+		ReFillInJobListCtrl(&oListSelection, false);
+		OnJobListCtrlSelChange();
 	}
 }
--- a/wingui/faac_winguiDlg.h
+++ b/wingui/faac_winguiDlg.h
@@ -26,6 +26,8 @@
 // Dialog Data
 	//{{AFX_DATA(CFaac_winguiDlg)
 	enum { IDD = IDD_FAAC_WINGUI_DIALOG };
+	CButton	m_ctrlButtonExpandFilterJob;
+	CButton	m_ctrlButtonOpenProperties;
 	CListCtrl	m_ctrlListJobs;
 	BOOL	m_bCheckRemoveProcessedJobs;
 	//}}AFX_DATA
@@ -36,9 +38,19 @@
 	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support
 	//}}AFX_VIRTUAL
 
+protected:
 	CJobList* GetGlobalJobList()								{ return &((CFaac_winguiApp*)AfxGetApp())->GetGlobalJobList(); }
 	CFaacWinguiProgramSettings* GetGlobalProgramSettings()		{ return &((CFaac_winguiApp*)AfxGetApp())->GetGlobalProgramSettings(); }
 
+public:
+
+	// a properties window that hides itself should call this member first
+	// so that the "Open Properties" button gets enabled; once this button
+	// is pressed ShowWindow is called for the window formerly specified and
+	// the button is hidden again
+	void HidePropertiesWindow(CWnd *poPropertiesWindow);
+	void ShowPropertiesWindow();
+
 // Implementation
 protected:
 	HICON m_hIcon;
@@ -58,6 +70,10 @@
 	afx_msg void OnButtonSaveJobList();
 	afx_msg void OnButtonLoadJobList();
 	afx_msg void OnButtonDuplicateSelected();
+	afx_msg void OnButtonProcessAll();
+	afx_msg void OnButtonOpenProperties();
+	afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+	afx_msg void OnButtonExpandFilterJob();
 	//}}AFX_MSG
 	DECLARE_MESSAGE_MAP()
 
@@ -89,6 +105,19 @@
 	// propose when file interaction is done
 	CString *m_poCurrentStandardFile;
 	void ReleaseStandardFile()			{ if (m_poCurrentStandardFile!=0) delete m_poCurrentStandardFile; }
+
+	// processes all jobs whose ids are in the specified list
+	void ProcessJobs(TItemList<long> oJobIds, bool bRemoveProcessJobs=false);
+
+	// file interaction; note that the load method also
+	// takes care of refilling the list control; both methods
+	// display error messages; thus their return values are
+	// only informative
+	bool LoadJobList(const CString &oCompletePath);
+	bool SaveJobList(const CString &oCompletePath);
+
+	// this member is used by the DefinePropertiesWindowToSetToEnableButton method
+	CWnd *m_poHiddenPropertiesWindow;
 };
 
 //{{AFX_INSERT_LOCATION}}
--- a/wingui/resource.h
+++ b/wingui/resource.h
@@ -51,6 +51,9 @@
 #define IDR_TOOLBARMAIN                 137
 #define IDS_FilterDidntFindFiles        137
 #define IDS_ErrorCreatingNestedEncoderJob 138
+#define IDS_ErrorWhileLoadingJobList    139
+#define IDS_JobNofM                     140
+#define IDS_SubJobNofM                  141
 #define IDC_LISTJOBS                    1000
 #define IDC_BUTTONADDENCODERJOB         1001
 #define IDC_TAB1                        1002
@@ -99,6 +102,10 @@
 #define IDC_BUTTONLOADJOBLIST           1050
 #define IDC_BUTTONDUPLICATESELECTED     1051
 #define IDC_CHECKRECURSIVE              1052
+#define IDC_BUTTONPROCESSALL            1053
+#define IDC_BUTTONOPENPROPERTIES        1054
+#define IDC_BUTTONMINIMIZEAPP           1055
+#define IDC_BUTTONEXPANDFILTERJOB       1056
 #define ID_BUTTON32771                  32771
 #define ID_BUTTON32772                  32772
 #define ID_BUTTON32773                  32773
@@ -110,7 +117,7 @@
 #ifndef APSTUDIO_READONLY_SYMBOLS
 #define _APS_NEXT_RESOURCE_VALUE        139
 #define _APS_NEXT_COMMAND_VALUE         32775
-#define _APS_NEXT_CONTROL_VALUE         1053
+#define _APS_NEXT_CONTROL_VALUE         1057
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif