ciderpress/app/EditPropsDialog.cpp
Andy McFadden 51b5f00f5c Large set of changes to restore CiderPress build.
CiderPress and MDC now compile, and execute far enough to open
their respective "about" boxes, but I doubt they'll do much
more than that.

* Switch from MBCS to UNICODE APIs

Microsoft switched to UTF-16 (by way of UCS-2) a long time ago,
and the support for MBCS seems to be getting phased out.  So it's
time to switch to wide strings.

This is a bit awkward for CiderPress because it works with disk
and file archives with 8-bit filenames, and I want NufxLib and
DiskImgLib to continue to work on Linux (which has largely taken
the UTF-8 approach to Unicode).  The libraries will continue to
work with 8-bit filenames, with CiderPress/MDC doing the
conversion at the appropriate point.

There were a couple of places where strings from a structure
handed back by one of the libraries were used directly in the UI,
or vice-versa, which is a problem because we have nowhere to
store the result of the conversion.  These currently have fixed
place-holder "xyzzy" strings.

All UI strings are now wide.

Various format strings now use "%ls" and "%hs" to explicitly
specify wide and narrow.  This doesn't play well with gcc, so
only the Windows-specific parts use those.

* Various updates to vcxproj files

The project-file conversion had some cruft that is now largely
gone.  The build now has a common output directory for the EXEs
and libraries, avoiding the old post-build copy steps.

* Added zlib 1.2.8 and nufxlib 2.2.2 source snapshots

The old "prebuilts" directory is now gone.  The libraries are now
built as part of building the apps.

I added a minimal set of files for zlib, and a full set for nufxlib.
The Linux-specific nufxlib goodies are included for the benefit of
the Linux utilities, which are currently broken (don't build).

* Replace symbols used for include guards

Symbols with a leading "__" are reserved.
2014-11-16 21:01:53 -08:00

526 lines
17 KiB
C++

/*
* CiderPress
* Copyright (C) 2007 by faddenSoft, LLC. All Rights Reserved.
* See the file LICENSE for distribution terms.
*/
/*
* Support for file properties edit dialog.
*/
#include "StdAfx.h"
#include "EditPropsDialog.h"
#include "FileNameConv.h"
#include "HelpTopics.h"
using namespace DiskImgLib;
BEGIN_MESSAGE_MAP(EditPropsDialog, CDialog)
ON_BN_CLICKED(IDC_PROPS_ACCESS_W, UpdateSimpleAccess)
ON_BN_CLICKED(IDC_PROPS_HFS_MODE, UpdateHFSMode)
ON_CBN_SELCHANGE(IDC_PROPS_FILETYPE, OnTypeChange)
ON_EN_CHANGE(IDC_PROPS_AUXTYPE, OnTypeChange)
ON_EN_CHANGE(IDC_PROPS_HFS_FILETYPE, OnHFSTypeChange)
ON_EN_CHANGE(IDC_PROPS_HFS_AUXTYPE, OnHFSTypeChange)
ON_WM_HELPINFO()
ON_COMMAND(IDHELP, OnHelp)
END_MESSAGE_MAP()
/*
* Initialize fProps from the stuff in pEntry.
*/
void
EditPropsDialog::InitProps(GenericEntry* pEntry)
{
fPathName = pEntry->GetPathName();
fProps.fileType = pEntry->GetFileType();
fProps.auxType = pEntry->GetAuxType();
fProps.access = pEntry->GetAccess();
fProps.createWhen = pEntry->GetCreateWhen();
fProps.modWhen = pEntry->GetModWhen();
if (!pEntry->GetFeatureFlag(GenericEntry::kFeatureCanChangeType))
fAllowedTypes = kAllowedNone;
else if (pEntry->GetFeatureFlag(GenericEntry::kFeaturePascalTypes))
fAllowedTypes = kAllowedPascal;
else if (pEntry->GetFeatureFlag(GenericEntry::kFeatureDOSTypes))
fAllowedTypes = kAllowedDOS;
else if (pEntry->GetFeatureFlag(GenericEntry::kFeatureHFSTypes))
fAllowedTypes = kAllowedHFS; // for HFS disks and ShrinkIt archives
else
fAllowedTypes = kAllowedProDOS;
if (!pEntry->GetFeatureFlag(GenericEntry::kFeatureHasFullAccess)) {
if (pEntry->GetFeatureFlag(GenericEntry::kFeatureHasSimpleAccess))
fSimpleAccess = true;
else
fNoChangeAccess = true;
}
if (pEntry->GetFeatureFlag(GenericEntry::kFeatureHasInvisibleFlag))
fAllowInvis = true;
}
/*
* Set up the control. We need to load the drop list with the file type
* info, and configure any controls that aren't set by DoDataExchange.
*
* If this is a disk archive, we might want to make the aux type read-only,
* though this would provide a way for users to fix badly-formed archives.
*/
BOOL
EditPropsDialog::OnInitDialog(void)
{
static const int kPascalTypes[] = {
0x00 /*NON*/, 0x01 /*BAD*/, 0x02 /*PCD*/, 0x03 /*PTX*/,
0xf3 /*$F3*/, 0x05 /*PDA*/, 0xf4 /*$F4*/, 0x08 /*FOT*/,
0xf5 /*$f5*/
};
static const int kDOSTypes[] = {
0x04 /*TXT*/, 0x06 /*BIN*/, 0xf2 /*$F2*/, 0xf3 /*$F3*/,
0xf4 /*$F4*/, 0xfa /*INT*/, 0xfc /*BAS*/, 0xfe /*REL*/
};
CComboBox* pCombo;
CWnd* pWnd;
int comboIdx;
pCombo = (CComboBox*) GetDlgItem(IDC_PROPS_FILETYPE);
ASSERT(pCombo != nil);
pCombo->InitStorage(256, 256 * 8);
for (int type = 0; type < 256; type++) {
const WCHAR* str;
WCHAR buf[10];
if (fAllowedTypes == kAllowedPascal) {
/* not the most efficient way, but it'll do */
int j;
for (j = 0; j < NELEM(kPascalTypes); j++) {
if (kPascalTypes[j] == type)
break;
}
if (j == NELEM(kPascalTypes))
continue;
} else if (fAllowedTypes == kAllowedDOS) {
int j;
for (j = 0; j < NELEM(kDOSTypes); j++) {
if (kDOSTypes[j] == type)
break;
}
if (j == NELEM(kDOSTypes))
continue;
}
str = PathProposal::FileTypeString(type);
if (str[0] == '$')
wsprintf(buf, L"??? $%02X", type);
else
wsprintf(buf, L"%ls $%02X", str, type);
comboIdx = pCombo->AddString(buf);
pCombo->SetItemData(comboIdx, type);
if ((int) fProps.fileType == type)
pCombo->SetCurSel(comboIdx);
}
if (fProps.fileType >= 256) {
if (fAllowedTypes == kAllowedHFS) {
pCombo->SetCurSel(0);
} else {
// unexpected -- bogus data out of DiskFS?
comboIdx = pCombo->AddString(L"???");
pCombo->SetCurSel(comboIdx);
pCombo->SetItemData(comboIdx, 256);
}
}
CString dateStr;
pWnd = GetDlgItem(IDC_PROPS_CREATEWHEN);
ASSERT(pWnd != nil);
FormatDate(fProps.createWhen, &dateStr);
pWnd->SetWindowText(dateStr);
pWnd = GetDlgItem(IDC_PROPS_MODWHEN);
ASSERT(pWnd != nil);
FormatDate(fProps.modWhen, &dateStr);
pWnd->SetWindowText(dateStr);
//WMSG2("USING DATE '%ls' from 0x%08lx\n", dateStr, fProps.modWhen);
CEdit* pEdit = (CEdit*) GetDlgItem(IDC_PROPS_AUXTYPE);
ASSERT(pEdit != nil);
pEdit->SetLimitText(4); // max len of aux type str
pEdit = (CEdit*) GetDlgItem(IDC_PROPS_HFS_FILETYPE);
pEdit->SetLimitText(4);
pEdit = (CEdit*) GetDlgItem(IDC_PROPS_HFS_AUXTYPE);
pEdit->SetLimitText(4);
if (fReadOnly || fAllowedTypes == kAllowedNone) {
pWnd = GetDlgItem(IDC_PROPS_FILETYPE);
pWnd->EnableWindow(FALSE);
pWnd = GetDlgItem(IDC_PROPS_AUXTYPE);
pWnd->EnableWindow(FALSE);
} else if (fAllowedTypes == kAllowedPascal) {
pWnd = GetDlgItem(IDC_PROPS_AUXTYPE);
pWnd->EnableWindow(FALSE);
}
if (fReadOnly || fSimpleAccess || fNoChangeAccess) {
pWnd = GetDlgItem(IDC_PROPS_ACCESS_R);
pWnd->EnableWindow(FALSE);
pWnd = GetDlgItem(IDC_PROPS_ACCESS_B);
pWnd->EnableWindow(FALSE);
pWnd = GetDlgItem(IDC_PROPS_ACCESS_N);
pWnd->EnableWindow(FALSE);
pWnd = GetDlgItem(IDC_PROPS_ACCESS_D);
pWnd->EnableWindow(FALSE);
}
if (fReadOnly || !fAllowInvis) {
pWnd = GetDlgItem(IDC_PROPS_ACCESS_I);
pWnd->EnableWindow(FALSE);
}
if (fReadOnly || fNoChangeAccess) {
pWnd = GetDlgItem(IDC_PROPS_ACCESS_W);
pWnd->EnableWindow(FALSE);
}
if (fReadOnly) {
pWnd = GetDlgItem(IDOK);
pWnd->EnableWindow(FALSE);
CString title;
GetWindowText(/*ref*/ title);
title = title + " (read only)";
SetWindowText(title);
}
if (fAllowedTypes != kAllowedHFS) {
CButton* pButton = (CButton*) GetDlgItem(IDC_PROPS_HFS_MODE);
pButton->EnableWindow(FALSE);
}
return CDialog::OnInitDialog();
}
/*
* Convert values.
*/
void
EditPropsDialog::DoDataExchange(CDataExchange* pDX)
{
int fileTypeIdx;
BOOL accessR, accessW, accessI, accessB, accessN, accessD;
CComboBox* pCombo = (CComboBox*) GetDlgItem(IDC_PROPS_FILETYPE);
if (pDX->m_bSaveAndValidate) {
CString appName;
CButton *pButton;
bool typeChanged = false;
appName.LoadString(IDS_MB_APP_NAME);
pButton = (CButton*) GetDlgItem(IDC_PROPS_HFS_MODE);
if (pButton->GetCheck() == BST_CHECKED) {
/* HFS mode */
CString type, creator;
DDX_Text(pDX, IDC_PROPS_HFS_FILETYPE, type);
DDX_Text(pDX, IDC_PROPS_HFS_AUXTYPE, creator);
if (type.GetLength() != 4 || creator.GetLength() != 4) {
MessageBox(L"The file and creator types must be exactly"
L" 4 characters each.",
appName, MB_OK);
pDX->Fail();
return;
}
fProps.fileType = ((unsigned char) type[0]) << 24 |
((unsigned char) type[1]) << 16 |
((unsigned char) type[2]) << 8 |
((unsigned char) type[3]);
fProps.auxType = ((unsigned char) creator[0]) << 24 |
((unsigned char) creator[1]) << 16 |
((unsigned char) creator[2]) << 8 |
((unsigned char) creator[3]);
} else {
/* ProDOS mode */
if (GetAuxType() < 0) {
MessageBox(L"The AuxType field must be a valid 4-digit"
L" hexadecimal number.",
appName, MB_OK);
pDX->Fail();
return;
}
fProps.auxType = GetAuxType();
/* pull the file type out, but don't disturb >= 256 */
DDX_CBIndex(pDX, IDC_PROPS_FILETYPE, fileTypeIdx);
if (fileTypeIdx != 256) {
unsigned long oldType = fProps.fileType;
fProps.fileType = pCombo->GetItemData(fileTypeIdx);
if (fProps.fileType != oldType)
typeChanged = true;
}
}
DDX_Check(pDX, IDC_PROPS_ACCESS_R, accessR);
DDX_Check(pDX, IDC_PROPS_ACCESS_W, accessW);
DDX_Check(pDX, IDC_PROPS_ACCESS_I, accessI);
DDX_Check(pDX, IDC_PROPS_ACCESS_B, accessB);
DDX_Check(pDX, IDC_PROPS_ACCESS_N, accessN);
DDX_Check(pDX, IDC_PROPS_ACCESS_D, accessD);
fProps.access = (accessR ? GenericEntry::kAccessRead : 0) |
(accessW ? GenericEntry::kAccessWrite : 0) |
(accessI ? GenericEntry::kAccessInvisible : 0) |
(accessB ? GenericEntry::kAccessBackup : 0) |
(accessN ? GenericEntry::kAccessRename : 0) |
(accessD ? GenericEntry::kAccessDelete : 0);
if (fAllowedTypes == kAllowedDOS && typeChanged &&
(fProps.fileType == kFileTypeBIN ||
fProps.fileType == kFileTypeINT ||
fProps.fileType == kFileTypeBAS))
{
CString msg;
int result;
msg.LoadString(IDS_PROPS_DOS_TYPE_CHANGE);
result = MessageBox(msg, appName, MB_ICONQUESTION|MB_OKCANCEL);
if (result != IDOK) {
pDX->Fail();
return;
}
}
} else {
accessR = (fProps.access & GenericEntry::kAccessRead) != 0;
accessW = (fProps.access & GenericEntry::kAccessWrite) != 0;
accessI = (fProps.access & GenericEntry::kAccessInvisible) != 0;
accessB = (fProps.access & GenericEntry::kAccessBackup) != 0;
accessN = (fProps.access & GenericEntry::kAccessRename) != 0;
accessD = (fProps.access & GenericEntry::kAccessDelete) != 0;
DDX_Check(pDX, IDC_PROPS_ACCESS_R, accessR);
DDX_Check(pDX, IDC_PROPS_ACCESS_W, accessW);
DDX_Check(pDX, IDC_PROPS_ACCESS_I, accessI);
DDX_Check(pDX, IDC_PROPS_ACCESS_B, accessB);
DDX_Check(pDX, IDC_PROPS_ACCESS_N, accessN);
DDX_Check(pDX, IDC_PROPS_ACCESS_D, accessD);
if (fAllowedTypes == kAllowedHFS &&
(fProps.fileType > 0xff || fProps.auxType > 0xffff))
{
char type[5], creator[5];
type[0] = (unsigned char) (fProps.fileType >> 24);
type[1] = (unsigned char) (fProps.fileType >> 16);
type[2] = (unsigned char) (fProps.fileType >> 8);
type[3] = (unsigned char) fProps.fileType;
type[4] = '\0';
creator[0] = (unsigned char) (fProps.auxType >> 24);
creator[1] = (unsigned char) (fProps.auxType >> 16);
creator[2] = (unsigned char) (fProps.auxType >> 8);
creator[3] = (unsigned char) fProps.auxType;
creator[4] = '\0';
CString tmpStr;
tmpStr = type;
DDX_Text(pDX, IDC_PROPS_HFS_FILETYPE, tmpStr);
tmpStr = creator;
DDX_Text(pDX, IDC_PROPS_HFS_AUXTYPE, tmpStr);
tmpStr = "0000";
DDX_Text(pDX, IDC_PROPS_AUXTYPE, tmpStr);
CButton* pButton = (CButton*) GetDlgItem(IDC_PROPS_HFS_MODE);
pButton->SetCheck(BST_CHECKED);
} else {
//fileTypeIdx = fProps.fileType;
//if (fileTypeIdx > 256)
// fileTypeIdx = 256;
//DDX_CBIndex(pDX, IDC_PROPS_FILETYPE, fileTypeIdx);
/* write the aux type as a hex string */
fAuxType.Format(L"%04X", fProps.auxType);
DDX_Text(pDX, IDC_PROPS_AUXTYPE, fAuxType);
}
OnTypeChange(); // set the description field
UpdateHFSMode(); // set up fields
UpdateSimpleAccess(); // coordinate N/D with W
}
DDX_Text(pDX, IDC_PROPS_PATHNAME, fPathName);
}
/*
* This is called when the file type selection changes or something is
* typed in the aux type box.
*
* We use this notification to configure the type description field.
*
* Typing in the ProDOS aux type box causes us to nuke the HFS values.
* If we were in "HFS mode" we reset the file type to zero.
*/
void
EditPropsDialog::OnTypeChange(void)
{
static const WCHAR kUnknownFileType[] = L"Unknown file type";
CComboBox* pCombo;
CWnd* pWnd;
int fileType, fileTypeIdx;
long auxType;
const WCHAR* descr = nil;
pCombo = (CComboBox*) GetDlgItem(IDC_PROPS_FILETYPE);
ASSERT(pCombo != nil);
fileTypeIdx = pCombo->GetCurSel();
fileType = pCombo->GetItemData(fileTypeIdx);
if (fileType >= 256) {
descr = kUnknownFileType;
} else {
auxType = GetAuxType();
if (auxType < 0)
auxType = 0;
descr = PathProposal::FileTypeDescription(fileType, auxType);
if (descr == nil)
descr = kUnknownFileType;
}
pWnd = GetDlgItem(IDC_PROPS_TYPEDESCR);
ASSERT(pWnd != nil);
pWnd->SetWindowText(descr);
/* DOS aux type only applies to BIN */
if (!fReadOnly && fAllowedTypes == kAllowedDOS) {
pWnd = GetDlgItem(IDC_PROPS_AUXTYPE);
pWnd->EnableWindow(fileType == kFileTypeBIN);
}
}
/*
* Called when something is typed in one of the HFS type boxes.
*/
void
EditPropsDialog::OnHFSTypeChange(void)
{
assert(fAllowedTypes == kAllowedHFS);
}
/*
* Called initially and when switching modes.
*/
void
EditPropsDialog::UpdateHFSMode(void)
{
CButton* pButton = (CButton*) GetDlgItem(IDC_PROPS_HFS_MODE);
CComboBox* pCombo;
CWnd* pWnd;
if (pButton->GetCheck() == BST_CHECKED) {
/* switch to HFS mode */
WMSG0("Switching to HFS mode\n");
//fHFSMode = true;
pWnd = GetDlgItem(IDC_PROPS_HFS_FILETYPE);
pWnd->EnableWindow(TRUE);
pWnd = GetDlgItem(IDC_PROPS_HFS_AUXTYPE);
pWnd->EnableWindow(TRUE);
pWnd = GetDlgItem(IDC_PROPS_HFS_LABEL);
pWnd->EnableWindow(TRUE);
/* point the file type at something safe */
pCombo = (CComboBox*) GetDlgItem(IDC_PROPS_FILETYPE);
pCombo->EnableWindow(FALSE);
pWnd = GetDlgItem(IDC_PROPS_AUXTYPE);
pWnd->EnableWindow(FALSE);
pWnd = GetDlgItem(IDC_PROPS_TYPEDESCR);
ASSERT(pWnd != nil);
pWnd->SetWindowText(L"(HFS type)");
OnHFSTypeChange();
} else {
/* switch to ProDOS mode */
WMSG0("Switching to ProDOS mode\n");
//fHFSMode = false;
pCombo = (CComboBox*) GetDlgItem(IDC_PROPS_FILETYPE);
pCombo->EnableWindow(TRUE);
pWnd = GetDlgItem(IDC_PROPS_AUXTYPE);
pWnd->EnableWindow(TRUE);
pWnd = GetDlgItem(IDC_PROPS_HFS_FILETYPE);
pWnd->EnableWindow(FALSE);
pWnd = GetDlgItem(IDC_PROPS_HFS_AUXTYPE);
pWnd->EnableWindow(FALSE);
pWnd = GetDlgItem(IDC_PROPS_HFS_LABEL);
pWnd->EnableWindow(FALSE);
OnTypeChange();
}
}
/*
* For "simple" access formats, i.e. DOS 3.2/3.3, the "write" button acts
* as a "locked" flag. We want the other rename/delete flags to track this
* one.
*/
void
EditPropsDialog::UpdateSimpleAccess(void)
{
if (!fSimpleAccess)
return;
CButton* pButton;
UINT checked;
pButton = (CButton*) GetDlgItem(IDC_PROPS_ACCESS_W);
checked = pButton->GetCheck();
pButton = (CButton*) GetDlgItem(IDC_PROPS_ACCESS_N);
pButton->SetCheck(checked);
pButton = (CButton*) GetDlgItem(IDC_PROPS_ACCESS_D);
pButton->SetCheck(checked);
}
/*
* Get the aux type.
*
* Returns -1 if something was wrong with the string (e.g. empty or has
* invalid chars).
*/
long
EditPropsDialog::GetAuxType(void)
{
CWnd* pWnd = GetDlgItem(IDC_PROPS_AUXTYPE);
ASSERT(pWnd != nil);
CString aux;
pWnd->GetWindowText(aux);
const WCHAR* str = aux;
WCHAR* end;
long val;
if (str[0] == '\0') {
WMSG0(" HEY: blank aux type, returning -1\n");
return -1;
}
val = wcstoul(aux, &end, 16);
if (end != str + wcslen(str)) {
WMSG1(" HEY: found some garbage in aux type '%ls', returning -1\n",
(LPCWSTR) aux);
return -1;
}
return val;
}
/*
* Context help request (question mark button).
*/
BOOL
EditPropsDialog::OnHelpInfo(HELPINFO* lpHelpInfo)
{
WinHelp((DWORD) lpHelpInfo->iCtrlId, HELP_CONTEXTPOPUP);
return TRUE; // yes, we handled it
}
/*
* User pressed the "Help" button.
*/
void
EditPropsDialog::OnHelp(void)
{
WinHelp(HELP_TOPIC_EDIT_PROPS, HELP_CONTEXT);
}