/* * CiderPress * Copyright (C) 2007 by faddenSoft, LLC. All Rights Reserved. * See the file LICENSE for distribution terms. */ /* * Support for ConvDiskOptionsDialog. */ #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_COMMAND(IDHELP, OnHelp) 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() const int kProDOSVolNameMax = 15; // longest possible ProDOS volume name /* * Set up our modified version of the "use selection" dialog. */ BOOL ConvDiskOptionsDialog::OnInitDialog(void) { CEdit* pEdit = (CEdit*) GetDlgItem(IDC_CONVDISK_VOLNAME); ASSERT(pEdit != nil); pEdit->SetLimitText(kProDOSVolNameMax); ResetSizeControls(); pEdit = (CEdit*) GetDlgItem(IDC_CONVDISK_SPECIFY_EDIT); ASSERT(pEdit != nil); pEdit->SetLimitText(5); // enough for "65535" pEdit->EnableWindow(FALSE); return UseSelectionDialog::OnInitDialog(); } /* * Convert values. */ 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)) errMsg.LoadString(IDS_VALID_VOLNAME_PRODOS); } } if (!errMsg.IsEmpty()) { CString appName; appName.LoadString(IDS_MB_APP_NAME); MessageBox(errMsg, appName, MB_OK); pDX->Fail(); } UseSelectionDialog::DoDataExchange(pDX); } /* * When one of the radio buttons is clicked on, update the active status * and contents of the "specify size" edit box. */ void ConvDiskOptionsDialog::OnRadioChangeRange(UINT nID) { WMSG1("OnChangeRange id=%d\n", 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); } /* * Test a ProDOS filename for validity. */ bool ConvDiskOptionsDialog::IsValidVolumeName_ProDOS(const WCHAR* name) { CStringA nameA(name); return DiskImgLib::DiskFSProDOS::IsValidVolumeName(nameA); } /* * Enable all size radio buttons and reset the "size required" display. * * This should be invoked whenever the convert selection changes, and may be * called at any time. */ void ConvDiskOptionsDialog::ResetSizeControls(void) { CWnd* pWnd; CString spaceReq; WMSG0("Resetting size controls\n"); spaceReq.Format(IDS_CONVDISK_SPACEREQ, "(unknown)"); pWnd = GetDlgItem(IDC_CONVDISK_SPACEREQ); ASSERT(pWnd != nil); pWnd->SetWindowText(spaceReq); #if 0 int i; for (i = 0; i < NELEM(gDiskSizes); i++) { pWnd = GetDlgItem(gDiskSizes[i].ctrlID); ASSERT(pWnd != nil); pWnd->EnableWindow(TRUE); } #endif NewDiskSize::EnableButtons(this); } /* * Display the space requirements and disable radio button controls that are * for values that are too small. * * Pass in the number of blocks required on a 32MB ProDOS volume. */ void ConvDiskOptionsDialog::LimitSizeControls(long totalBlocks, long blocksUsed) { WMSG2("LimitSizeControls %ld %ld\n", totalBlocks, blocksUsed); WMSG1("Full volume requires %ld bitmap blocks\n", 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 != nil); 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 != nil); 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 } /* * Compute the amount of space required for the files. We use the result to * disable the controls that can't be used. * * We don't need to enable controls here, because the only way to change the * set of files is by flipping between "all" and "selected", and we can handle * that separately. */ 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; WMSG1("New volume name will be '%ls'\n", 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; } WMSG1(" Will xfer to file '%ls'\n", 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. */ 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(nil); if (result == GenericArchive::kXferOK) { DiskFS* pDiskFS; long totalBlocks, freeBlocks; int unitSize; DIError dierr; WMSG0("SUCCESS\n"); pDiskFS = ((DiskArchive*) xferOpts.fTarget)->GetDiskFS(); ASSERT(pDiskFS != nil); 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) { WMSG0("CANCEL - cancel button hit\n"); ResetSizeControls(); } else { WMSG1("FAILURE (result=%d)\n", result); ResetSizeControls(); } } // debug ((DiskArchive*) (xferOpts.fTarget))->GetDiskFS()->DumpFileList(); /* clean up */ delete xferOpts.fTarget; (void) _wunlink(nameBuf); }