/* * CiderPress * Copyright (C) 2007 by faddenSoft, LLC. All Rights Reserved. * See the file LICENSE for distribution terms. */ #include "stdafx.h" #include "ConvDiskOptionsDialog.h" #include "NufxArchive.h" #include "Main.h" #include "ActionProgressDialog.h" #include "DiskArchive.h" #include "NewDiskSize.h" #include "../diskimg/DiskImgDetail.h" // need ProDOS filename validator BEGIN_MESSAGE_MAP(ConvDiskOptionsDialog, CDialog) ON_WM_HELPINFO() ON_BN_CLICKED(IDC_CONVDISK_COMPUTE, OnCompute) ON_BN_CLICKED(IDC_USE_SELECTED, ResetSizeControls) ON_BN_CLICKED(IDC_USE_ALL, ResetSizeControls) //ON_BN_CLICKED(IDC_CONVDISK_SPARSE, ResetSizeControls) ON_CONTROL_RANGE(BN_CLICKED, IDC_CONVDISK_140K, IDC_CONVDISK_SPECIFY, OnRadioChangeRange) END_MESSAGE_MAP() // TODO: get this from DiskImgLib header? const int kProDOSVolNameMax = 15; // longest possible ProDOS volume name BOOL ConvDiskOptionsDialog::OnInitDialog(void) { CEdit* pEdit = (CEdit*) GetDlgItem(IDC_CONVDISK_VOLNAME); ASSERT(pEdit != NULL); pEdit->SetLimitText(kProDOSVolNameMax); ResetSizeControls(); pEdit = (CEdit*) GetDlgItem(IDC_CONVDISK_SPECIFY_EDIT); ASSERT(pEdit != NULL); pEdit->SetLimitText(5); // enough for "65535" pEdit->EnableWindow(FALSE); return UseSelectionDialog::OnInitDialog(); } void ConvDiskOptionsDialog::DoDataExchange(CDataExchange* pDX) { UINT specifyBlocks = 280; CString errMsg; DDX_Radio(pDX, IDC_CONVDISK_140K, fDiskSizeIdx); //DDX_Check(pDX, IDC_CONVDISK_ALLOWLOWER, fAllowLower); //DDX_Check(pDX, IDC_CONVDISK_SPARSE, fSparseAlloc); DDX_Text(pDX, IDC_CONVDISK_VOLNAME, fVolName); DDX_Text(pDX, IDC_CONVDISK_SPECIFY_EDIT, specifyBlocks); ASSERT(fDiskSizeIdx >= 0 && fDiskSizeIdx < (int)NewDiskSize::GetNumSizeEntries()); if (pDX->m_bSaveAndValidate) { fNumBlocks = NewDiskSize::GetDiskSizeByIndex(fDiskSizeIdx); if (fNumBlocks == NewDiskSize::kSpecified) { fNumBlocks = specifyBlocks; // Max is really 65535, but we allow 65536 for creation of volumes // that can be copied to CFFA cards. if (specifyBlocks < 16 || specifyBlocks > 65536) errMsg = "Specify a size of at least 16 blocks and no more" " than 65536 blocks."; } if (fVolName.IsEmpty() || fVolName.GetLength() > kProDOSVolNameMax) { errMsg = "You must specify a volume name 1-15 characters long."; } else { if (!IsValidVolumeName_ProDOS(fVolName)) { CheckedLoadString(&errMsg, IDS_VALID_VOLNAME_PRODOS); } } } if (!errMsg.IsEmpty()) { CString appName; CheckedLoadString(&appName, IDS_MB_APP_NAME); MessageBox(errMsg, appName, MB_OK); pDX->Fail(); } UseSelectionDialog::DoDataExchange(pDX); } void ConvDiskOptionsDialog::OnRadioChangeRange(UINT nID) { LOGI("OnChangeRange id=%d", nID); CButton* pButton = (CButton*) GetDlgItem(IDC_CONVDISK_SPECIFY); CEdit* pEdit = (CEdit*) GetDlgItem(IDC_CONVDISK_SPECIFY_EDIT); pEdit->EnableWindow(pButton->GetCheck() == BST_CHECKED); NewDiskSize::UpdateSpecifyEdit(this); } bool ConvDiskOptionsDialog::IsValidVolumeName_ProDOS(const WCHAR* name) { CStringA nameA(name); return DiskImgLib::DiskFSProDOS::IsValidVolumeName(nameA); } void ConvDiskOptionsDialog::ResetSizeControls(void) { CWnd* pWnd; CString spaceReq; LOGI("Resetting size controls"); spaceReq.Format(IDS_CONVDISK_SPACEREQ, L"(unknown)"); pWnd = GetDlgItem(IDC_CONVDISK_SPACEREQ); ASSERT(pWnd != NULL); pWnd->SetWindowText(spaceReq); #if 0 int i; for (i = 0; i < NELEM(gDiskSizes); i++) { pWnd = GetDlgItem(gDiskSizes[i].ctrlID); ASSERT(pWnd != NULL); pWnd->EnableWindow(TRUE); } #endif NewDiskSize::EnableButtons(this); } void ConvDiskOptionsDialog::LimitSizeControls(long totalBlocks, long blocksUsed) { LOGD("LimitSizeControls %ld %ld", totalBlocks, blocksUsed); LOGD("Full volume requires %ld bitmap blocks", NewDiskSize::GetNumBitmapBlocks_ProDOS(totalBlocks)); CWnd* pWnd; long usedWithoutBitmap = blocksUsed - NewDiskSize::GetNumBitmapBlocks_ProDOS(totalBlocks); long sizeInK = usedWithoutBitmap / 2; CString sizeStr, spaceReq; sizeStr.Format(L"%dK", sizeInK); spaceReq.Format(IDS_CONVDISK_SPACEREQ, sizeStr); pWnd = GetDlgItem(IDC_CONVDISK_SPACEREQ); ASSERT(pWnd != NULL); pWnd->SetWindowText(spaceReq); NewDiskSize::EnableButtons_ProDOS(this, totalBlocks, blocksUsed); #if 0 bool first = true; for (int i = 0; i < NELEM(gDiskSizes); i++) { if (gDiskSizes[i].blocks == -1) continue; CButton* pButton; pButton = (CButton*) GetDlgItem(gDiskSizes[i].ctrlID); ASSERT(pButton != NULL); if (usedWithoutBitmap + GetNumBitmapBlocks(gDiskSizes[i].blocks) <= gDiskSizes[i].blocks) { pButton->EnableWindow(TRUE); if (first) { pButton->SetCheck(BST_CHECKED); first = false; } else { pButton->SetCheck(BST_UNCHECKED); } } else { pButton->EnableWindow(FALSE); pButton->SetCheck(BST_UNCHECKED); } } #endif } void ConvDiskOptionsDialog::OnCompute(void) { MainWindow* pMain = (MainWindow*)::AfxGetMainWnd(); const Preferences* pPreferences = GET_PREFERENCES(); if (UpdateData() == FALSE) return; /* * Create a "selection set" of data forks, resource forks, and * disk images. We don't want comment threads. We can filter all that * out later, though, so we just specify "any". */ SelectionSet selSet; int threadMask = GenericEntry::kAnyThread; if (fFilesToAction == UseSelectionDialog::kActionSelection) { selSet.CreateFromSelection(pMain->GetContentList(), threadMask); } else { selSet.CreateFromAll(pMain->GetContentList(), threadMask); } if (selSet.GetNumEntries() == 0) { /* should be impossible */ MessageBox(L"No files matched the selection criteria.", L"No match", MB_OK|MB_ICONEXCLAMATION); return; } XferFileOptions xferOpts; //xferOpts.fAllowLowerCase = // pPreferences->GetPrefBool(kPrProDOSAllowLower) != 0; //xferOpts.fUseSparseBlocks = // pPreferences->GetPrefBool(kPrProDOSUseSparse) != 0; LOGI("New volume name will be '%ls'", (LPCWSTR) fVolName); /* * Create a new disk image file. */ CString errStr; WCHAR nameBuf[MAX_PATH]; UINT unique; unique = GetTempFileName(pMain->GetPreferences()->GetPrefString(kPrTempPath), L"CPdisk", 0, nameBuf); if (unique == 0) { DWORD dwerr = ::GetLastError(); errStr.Format(L"GetTempFileName failed on '%ls' (err=0x%08lx)\n", pMain->GetPreferences()->GetPrefString(kPrTempPath), dwerr); ShowFailureMsg(this, errStr, IDS_FAILED); return; } LOGI(" Will xfer to file '%ls'", nameBuf); // annoying -- DiskArchive insists on creating it (void) _wunlink(nameBuf); DiskArchive::NewOptions options; memset(&options, 0, sizeof(options)); options.base.format = DiskImg::kFormatProDOS; options.base.sectorOrder = DiskImg::kSectorOrderProDOS; options.prodos.volName = fVolName; options.prodos.numBlocks = 65535; xferOpts.fTarget = new DiskArchive; { CWaitCursor waitc; errStr = xferOpts.fTarget->New(nameBuf, &options); } if (!errStr.IsEmpty()) { ShowFailureMsg(this, errStr, IDS_FAILED); } else { /* * Set up the progress window as a modal dialog. * * TODO: there's a weird issue where this un-modals the conversion * options dialog. While this is running, and after it finishes, * you can use menu items and perform other actions. Noted on Win7. */ GenericArchive::XferStatus result; ActionProgressDialog* pActionProgress = new ActionProgressDialog; pMain->SetActionProgressDialog(pActionProgress); pActionProgress->Create(ActionProgressDialog::kActionConvFile, this); pMain->PeekAndPump(); result = pMain->GetOpenArchive()->XferSelection(pActionProgress, &selSet, pActionProgress, &xferOpts); pActionProgress->Cleanup(this); pMain->SetActionProgressDialog(NULL); if (result == GenericArchive::kXferOK) { DiskFS* pDiskFS; long totalBlocks, freeBlocks; int unitSize; DIError dierr; LOGI("SUCCESS"); pDiskFS = ((DiskArchive*) xferOpts.fTarget)->GetDiskFS(); ASSERT(pDiskFS != NULL); dierr = pDiskFS->GetFreeSpaceCount(&totalBlocks, &freeBlocks, &unitSize); if (dierr != kDIErrNone) { errStr.Format(L"Unable to get free space count: %hs.\n", DiskImgLib::DIStrError(dierr)); ShowFailureMsg(this, errStr, IDS_FAILED); } else { ASSERT(totalBlocks >= freeBlocks); ASSERT(unitSize == DiskImgLib::kBlockSize); LimitSizeControls(totalBlocks, totalBlocks - freeBlocks); } } else if (result == GenericArchive::kXferCancelled) { LOGI("CANCEL - cancel button hit"); ResetSizeControls(); } else { LOGI("FAILURE (result=%d)", result); ResetSizeControls(); } } // debug ((DiskArchive*) (xferOpts.fTarget))->GetDiskFS()->DumpFileList(); /* clean up */ delete xferOpts.fTarget; (void) _wunlink(nameBuf); }