bool VDUIJobControlDialog::OnMenuHit(uint32 id) {
	static const wchar_t fileFilters[]=
		L"VirtualDub job list (*.jobs)\0"			L"*.jobs\0"
		L"VirtualDub script (*.syl, *.vdscript)\0"	L"*.syl;*.vdscript\0"
		L"All files (*.*)\0"						L"*.*\0";

	try {
		switch(id) {

			case ID_FILE_LOADJOBLIST:
				{
					VDStringW filename(VDGetLoadFileName(kFileDialog_JobList, (VDGUIHandle)mhdlg, L"Load job list", fileFilters, NULL));

					if (!filename.empty())
						g_VDJobQueue.ListLoad(filename.c_str(), false);
				}
				break;

			case ID_FILE_SAVEJOBLIST:
				{
					VDStringW filename(VDGetSaveFileName(kFileDialog_JobList, (VDGUIHandle)mhdlg, L"Save job list", fileFilters, NULL));

					if (!filename.empty())
						g_VDJobQueue.Flush(filename.c_str());
				}
				break;

			case ID_FILE_USELOCALJOBQUEUE:
				if (g_VDJobQueue.IsRunInProgress())
					MessageBox(mhdlg, "Cannot switch job queues while a job is in progress.", g_szError, MB_ICONERROR | MB_OK);
				else
					g_VDJobQueue.SetJobFilePath(NULL, false, false);
				break;

			case ID_FILE_USEREMOTEJOBQUEUE:
				if (g_VDJobQueue.IsRunInProgress())
					MessageBox(mhdlg, "Cannot switch job queues while a job is in progress.", g_szError, MB_ICONERROR | MB_OK);
				else {
					const VDFileDialogOption opts[]={
						{ VDFileDialogOption::kConfirmFile, 0, NULL, 0, 0},
						{0}
					};

					int optvals[]={ false };

					VDStringW filename(VDGetSaveFileName(kFileDialog_JobList, (VDGUIHandle)mhdlg, L"Use shared job list", fileFilters, NULL, opts, optvals));

					if (!filename.empty()) {
						if (!_wcsicmp(filename.c_str(), g_VDJobQueue.GetDefaultJobFilePath())) {
							DWORD res = MessageBox(mhdlg,
								"Using the same job file that is normally used for local job queue operation is not recommended as "
								"it can cause job queue corruption.\n"
								"\n"
								"Are you sure you want to use this file for the remote queue too?",
								"VirtualDub Warning",
								MB_ICONEXCLAMATION | MB_YESNO);

							if (res != IDYES)
								break;
						}

						g_VDJobQueue.SetJobFilePath(filename.c_str(), true, true);
					}
				}
				break;

			case ID_EDIT_CLEARLIST:
				if (IDOK != MessageBox(mhdlg, "Really clear job list?", "VirtualDub job system", MB_OKCANCEL | MB_ICONEXCLAMATION))
					break;

				g_VDJobQueue.ListClear(false);
				break;

			case ID_EDIT_DELETEDONEJOBS:
				for(uint32 i=0; i<g_VDJobQueue.ListSize();) {
					VDJob *vdj = g_VDJobQueue.ListGet(i);

					if (vdj->GetState() == VDJob::kStateCompleted) {
						g_VDJobQueue.Delete(vdj, false);
						delete vdj;
					} else
						++i;
				}

				break;

			case ID_EDIT_FAILEDTOWAITING:
				g_VDJobQueue.Transform(VDJob::kStateAborted, VDJob::kStateWaiting);
				g_VDJobQueue.Transform(VDJob::kStateError, VDJob::kStateWaiting);
				break;

			case ID_EDIT_WAITINGTOPOSTPONED:
				g_VDJobQueue.Transform(VDJob::kStateWaiting, VDJob::kStatePostponed);
				break;

			case ID_EDIT_POSTPONEDTOWAITING:
				g_VDJobQueue.Transform(VDJob::kStatePostponed, VDJob::kStateWaiting);
				break;

			case ID_EDIT_DONETOWAITING:
				g_VDJobQueue.Transform(VDJob::kStateCompleted, VDJob::kStateWaiting);
				break;

			case ID_EDIT_PROCESSDIRECTORY:
				JobProcessDirectory(mhdlg);
				break;

			case ID_WHENFINISHED_DONOTHING:
				{
					VDRegistryAppKey appKey("");

					appKey.setBool(g_szRegKeyShutdownWhenFinished, false);
				}
				break;

			case ID_WHENFINISHED_SHUTDOWN:
				{
					VDRegistryAppKey appKey("");

					appKey.setBool(g_szRegKeyShutdownWhenFinished, true);
					appKey.setInt(g_szRegKeyShutdownMode, 0);
				}
				break;

			case ID_WHENFINISHED_HIBERNATE:
				{
					VDRegistryAppKey appKey("");

					appKey.setBool(g_szRegKeyShutdownWhenFinished, true);
					appKey.setInt(g_szRegKeyShutdownMode, 1);
				}
				break;
			case ID_WHENFINISHED_SLEEP:
				{
					VDRegistryAppKey appKey("");

					appKey.setBool(g_szRegKeyShutdownWhenFinished, true);
					appKey.setInt(g_szRegKeyShutdownMode, 2);
				}
				break;
		}
	} catch(const MyError& e) {
		e.post(mhdlg, "Job system error");
	}

	return true;
}
bool VDUIJobControlDialog::OnCommand(uint32 id, uint32 extcode) {
	OnMenuHit(id);
	
	if (extcode == BN_CLICKED) {
		HWND hwndItem = GetDlgItem(mhdlg, IDC_JOBS);
		int index = ListView_GetNextItem(hwndItem, -1, LVNI_ALL | LVNI_SELECTED);
		VDJob *vdj = NULL;

		if (index >= 0)
			vdj = g_VDJobQueue.ListGet(index);

		switch(id) {
		case IDOK:
			Destroy();
			return true;

		case IDC_DELETE:
			if (vdj) {
				// Do not delete jobs that are in progress!

				if (vdj->GetState() != VDJob::kStateInProgress) {
					fUpdateDisable = true;
					g_VDJobQueue.Delete(vdj, false);
					delete vdj;
					g_VDJobQueue.SetModified();
					fUpdateDisable = false;
					if (g_VDJobQueue.ListSize() > 0)
						ListView_SetItemState(hwndItem, index==g_VDJobQueue.ListSize() ? index-1 : index, LVIS_SELECTED, LVIS_SELECTED);
				}
			}

			return TRUE;

		case IDC_POSTPONE:
			if (vdj) {
				// Do not postpone jobs in progress

				int state = vdj->GetState();
				if (state != VDJob::kStateInProgress) {
					if (state == VDJob::kStatePostponed)
						vdj->SetState(VDJob::kStateWaiting);
					else
						vdj->SetState(VDJob::kStatePostponed);

					vdj->Refresh();

					g_VDJobQueue.SetModified();
				}
			}

			return TRUE;

		case IDC_MOVE_UP:
			if (!vdj || index <= 0)
				return TRUE;

			g_VDJobQueue.Swap(index-1, index);

			ListView_SetItemState(hwndItem, index  , 0, LVIS_SELECTED | LVIS_FOCUSED);
			ListView_SetItemState(hwndItem, index-1, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
			ListView_RedrawItems(hwndItem, index-1, index);

			g_VDJobQueue.SetModified();

			return TRUE;

		case IDC_MOVE_DOWN:
			if (!vdj || index >= g_VDJobQueue.ListSize()-1)
				return TRUE;

			g_VDJobQueue.Swap(index+1, index);
			
			ListView_SetItemState(hwndItem, index  , 0, LVIS_SELECTED | LVIS_FOCUSED);
			ListView_SetItemState(hwndItem, index+1, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
			ListView_RedrawItems(hwndItem, index, index+1);

			g_VDJobQueue.SetModified();

			return TRUE;

		case IDC_START:
			if (g_VDJobQueue.IsRunInProgress()) {
				g_VDJobQueue.RunAllStop();
				EnableControl(IDC_START, FALSE);
			} else
				g_VDJobQueue.RunAllStart();
			return TRUE;

		case IDC_ABORT:
			if (g_VDJobQueue.IsRunInProgress()) {
				g_VDJobQueue.RunAllStop();
				EnableControl(IDC_START, false);
				EnableControl(IDC_ABORT, false);
				if (g_dubber) g_dubber->Abort();
			}

			return TRUE;

		case IDC_RELOAD:
			if (!vdj)
				return TRUE;

			if (!vdj->IsReloadMarkerPresent())
				MessageBox(mhdlg, "This job was created with an older version of VirtualDub and cannot be reloaded.", g_szError, MB_ICONERROR|MB_OK);
			else
				vdj->Reload();

			return TRUE;

		case IDC_AUTOSTART:
			g_VDJobQueue.SetAutoRunEnabled(IsButtonChecked(IDC_AUTOSTART));
			return TRUE;
		}
	}

	return false;
}