ciderpress/app/ConvDiskOptionsDialog.cpp

305 lines
10 KiB
C++

/*
* 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);
}