ciderpress/app/Preferences.cpp

623 lines
19 KiB
C++

/*
* CiderPress
* Copyright (C) 2007, 2008 by faddenSoft, LLC. All Rights Reserved.
* See the file LICENSE for distribution terms.
*/
/*
* Save and restore preferences from the config file.
*/
#include "stdafx.h"
#include "Preferences.h"
#include "NufxArchive.h"
#include "MyApp.h"
#include "../util/UtilLib.h"
static const char* kDefaultTempPath = ".";
/* registry section for columns */
static const char* kColumnSect = _T("columns");
/* registry section for file add options */
static const char* kAddSect = _T("add");
/* registry section for extraction options */
static const char* kExtractSect = _T("extract");
/* registry section for view options */
static const char* kViewSect = _T("view");
/* registry section for logical/physical volume operations */
static const char* kVolumeSect = _T("volume");
/* registry section for file-to-disk options */
//static const char* kConvDiskSect = _T("conv-disk");
/* registry section for disk-to-file options */
static const char* kConvFileSect = _T("conv-file");
/* registry section for folders */
static const char* kFolderSect = _T("folders");
/* registry section for preferences on property pages */
static const char* kPrefsSect = _T("prefs");
/* registry section for miscellaneous settings */
static const char* kMiscSect = _T("misc");
/*
* Map PrefNum to type and registry string.
*
* To make life easier, we require that the PrefNum (first entry) match the
* offset in the table. That way instead of searching for a match we can just
* index into the table.
*/
const Preferences::PrefMap Preferences::fPrefMaps[kPrefNumLastEntry] = {
/**/ { kPrefNumUnknown, kPTNone, nil, nil },
{ kPrAddIncludeSubFolders, kBool, kAddSect, _T("include-sub-folders") },
{ kPrAddStripFolderNames, kBool, kAddSect, _T("strip-folder-names") },
{ kPrAddOverwriteExisting, kBool, kAddSect, _T("overwrite-existing") },
{ kPrAddTypePreservation, kLong, kAddSect, _T("type-preservation") },
{ kPrAddConvEOL, kLong, kAddSect, _T("conv-eol") },
// { kPrExtractPath, kString, kExtractSect, _T("path") },
{ kPrExtractConvEOL, kLong, kExtractSect, _T("conv-eol") },
{ kPrExtractConvHighASCII, kBool, kExtractSect, _T("conv-high-ascii") },
{ kPrExtractIncludeData, kBool, kExtractSect, _T("include-data") },
{ kPrExtractIncludeRsrc, kBool, kExtractSect, _T("include-rsrc") },
{ kPrExtractIncludeDisk, kBool, kExtractSect, _T("include-disk") },
{ kPrExtractEnableReformat, kBool, kExtractSect, _T("enable-reformat") },
{ kPrExtractDiskTo2MG, kBool, kExtractSect, _T("disk-to-2mg") },
{ kPrExtractAddTypePreservation, kBool, kExtractSect, _T("add-type-preservation") },
{ kPrExtractAddExtension, kBool, kExtractSect, _T("add-extension") },
{ kPrExtractStripFolderNames, kBool, kExtractSect, _T("strip-folder-names") },
{ kPrExtractOverwriteExisting, kBool, kExtractSect, _T("overwrite-existing") },
// { kPrViewIncludeDataForks, kBool, kViewSect, _T("include-data-forks") },
// { kPrViewIncludeRsrcForks, kBool, kViewSect, _T("include-rsrc-forks") },
// { kPrViewIncludeDiskImages, kBool, kViewSect, _T("include-disk-images") },
// { kPrViewIncludeComments, kBool, kViewSect, _T("include-comments") },
{ kPrConvFileEmptyFolders, kBool, kConvFileSect, _T("preserve-empty-folders") },
{ kPrOpenArchiveFolder, kString, kFolderSect, _T("open-archive") },
{ kPrConvertArchiveFolder, kString, kFolderSect, _T("convert-archive") },
{ kPrAddFileFolder, kString, kFolderSect, _T("add-file") },
{ kPrExtractFileFolder, kString, kFolderSect, _T("extract-file") },
{ kPrVolumeFilter, kLong, kVolumeSect, _T("open-filter") },
//{ kPrVolumeReadOnly, kBool, kVolumeSect, _T("read-only") },
{ kPrCassetteAlgorithm, kLong, kVolumeSect, _T("cassette-algorithm") },
{ kPrOpenWAVFolder, kString, kFolderSect, _T("open-wav") },
{ kPrMimicShrinkIt, kBool, kPrefsSect, _T("mimic-shrinkit") },
{ kPrBadMacSHK, kBool, kPrefsSect, _T("bad-mac-shk") },
{ kPrReduceSHKErrorChecks, kBool, kPrefsSect, _T("reduce-shk-error-checks") },
{ kPrCoerceDOSFilenames, kBool, kPrefsSect, _T("coerce-dos-filenames") },
{ kPrSpacesToUnder, kBool, kPrefsSect, _T("spaces-to-under") },
{ kPrPasteJunkPaths, kBool, kPrefsSect, _T("paste-junk-paths") },
{ kPrBeepOnSuccess, kBool, kPrefsSect, _T("beep-on-success") },
{ kPrQueryImageFormat, kBool, kPrefsSect, _T("query-image-format") },
{ kPrOpenVolumeRO, kBool, kPrefsSect, _T("open-volume-ro") },
{ kPrOpenVolumePhys0, kBool, kPrefsSect, _T("open-volume-phys0") },
{ kPrProDOSAllowLower, kBool, kPrefsSect, _T("prodos-allow-lower") },
{ kPrProDOSUseSparse, kBool, kPrefsSect, _T("prodos-use-sparse") },
{ kPrCompressionType, kLong, kPrefsSect, _T("compression-type") },
{ kPrMaxViewFileSize, kLong, kPrefsSect, _T("max-view-file-size") },
{ kPrNoWrapText, kBool, kPrefsSect, _T("no-wrap-text") },
{ kPrHighlightHexDump, kBool, kPrefsSect, _T("highlight-hex-dump") },
{ kPrHighlightBASIC, kBool, kPrefsSect, _T("highlight-basic") },
{ kPrConvHiResBlackWhite, kBool, kPrefsSect, _T("conv-hi-res-black-white") },
{ kPrConvDHRAlgorithm, kLong, kPrefsSect, _T("dhr-algorithm") },
{ kPrRelaxGfxTypeCheck, kBool, kPrefsSect, _T("relax-gfx-type-check") },
{ kPrDisasmOneByteBrkCop, kBool, kPrefsSect, _T("disasm-onebytebrkcop") },
//{ kPrEOLConvRaw, kBool, kPrefsSect, _T("eol-conv-raw") },
{ kPrConvTextEOL_HA, kBool, kPrefsSect, _T("conv-eol-ha") },
{ kPrConvPascalText, kBool, kPrefsSect, _T("conv-pascal-text") },
{ kPrConvPascalCode, kBool, kPrefsSect, _T("conv-pascal-code") },
{ kPrConvCPMText, kBool, kPrefsSect, _T("conv-cpm-text") },
{ kPrConvApplesoft, kBool, kPrefsSect, _T("conv-applesoft") },
{ kPrConvInteger, kBool, kPrefsSect, _T("conv-integer") },
{ kPrConvBusiness, kBool, kPrefsSect, _T("conv-business") },
{ kPrConvGWP, kBool, kPrefsSect, _T("conv-gwp") },
{ kPrConvText8, kBool, kPrefsSect, _T("conv-text8") },
{ kPrConvGutenberg, kBool, kPrefsSect, _T("conv-gutenberg") },
{ kPrConvAWP, kBool, kPrefsSect, _T("conv-awp") },
{ kPrConvADB, kBool, kPrefsSect, _T("conv-adb") },
{ kPrConvASP, kBool, kPrefsSect, _T("conv-asp") },
{ kPrConvSCAssem, kBool, kPrefsSect, _T("conv-scassem") },
{ kPrConvDisasm, kBool, kPrefsSect, _T("conv-disasm") },
{ kPrConvHiRes, kBool, kPrefsSect, _T("conv-hi-res") },
{ kPrConvDHR, kBool, kPrefsSect, _T("conv-dhr") },
{ kPrConvSHR, kBool, kPrefsSect, _T("conv-shr") },
{ kPrConvPrintShop, kBool, kPrefsSect, _T("conv-print-shop") },
{ kPrConvMacPaint, kBool, kPrefsSect, _T("conv-mac-paint") },
{ kPrConvProDOSFolder, kBool, kPrefsSect, _T("conv-prodos-folder") },
{ kPrConvResources, kBool, kPrefsSect, _T("conv-resources") },
{ kPrTempPath, kString, kPrefsSect, _T("temp-path") },
{ kPrExtViewerExts, kString, kPrefsSect, _T("extviewer-exts") },
{ kPrLastOpenFilterIndex, kLong, kMiscSect, _T("open-filter-index") },
/**/ { kPrefNumLastRegistry, kPTNone, nil, nil },
{ kPrViewTextTypeFace, kString, nil, nil },
{ kPrViewTextPointSize, kLong, nil, nil },
{ kPrFileViewerWidth, kLong, nil, nil },
{ kPrFileViewerHeight, kLong, nil, nil },
{ kPrDiskImageCreateFormat, kLong, nil, nil },
};
/*
* Constructor. There should be only one Preferences object in the
* application, so this should only be run once.
*/
Preferences::Preferences(void)
{
WMSG0("Initializing Preferences\n");
ScanPrefMaps(); // sanity-check the table
memset(fValues, 0, sizeof(fValues));
SetPrefBool(kPrAddIncludeSubFolders, true);
SetPrefBool(kPrAddStripFolderNames, false);
SetPrefBool(kPrAddOverwriteExisting, false);
SetPrefLong(kPrAddTypePreservation, 1); // kPreserveTypes
SetPrefLong(kPrAddConvEOL, 1); // kConvEOLType
InitFolders(); // set default add/extract folders; overriden by reg
SetPrefLong(kPrExtractConvEOL, 0); // kConvEOLNone
SetPrefBool(kPrExtractConvHighASCII, true);
SetPrefBool(kPrExtractIncludeData, true);
SetPrefBool(kPrExtractIncludeRsrc, false);
SetPrefBool(kPrExtractIncludeDisk, true);
SetPrefBool(kPrExtractEnableReformat, false);
SetPrefBool(kPrExtractDiskTo2MG, false);
SetPrefBool(kPrExtractAddTypePreservation, true);
SetPrefBool(kPrExtractAddExtension, false);
SetPrefBool(kPrExtractStripFolderNames, false);
SetPrefBool(kPrExtractOverwriteExisting, false);
// SetPrefBool(kPrViewIncludeDataForks, true);
// SetPrefBool(kPrViewIncludeRsrcForks, false);
// SetPrefBool(kPrViewIncludeDiskImages, false);
// SetPrefBool(kPrViewIncludeComments, false);
SetPrefBool(kPrConvFileEmptyFolders, true);
// string kPrOpenArchiveFolder
// string kPrAddFileFolder
// string kPrExtractFileFolder
SetPrefLong(kPrVolumeFilter, 0);
//SetPrefBool(kPrVolumeReadOnly, true);
SetPrefLong(kPrCassetteAlgorithm, 0);
// string kPrOpenWAVFolder
SetPrefBool(kPrMimicShrinkIt, false);
SetPrefBool(kPrBadMacSHK, false);
SetPrefBool(kPrReduceSHKErrorChecks, false);
SetPrefBool(kPrCoerceDOSFilenames, false);
SetPrefBool(kPrSpacesToUnder, false);
SetPrefBool(kPrPasteJunkPaths, true);
SetPrefBool(kPrBeepOnSuccess, true);
SetPrefBool(kPrQueryImageFormat, false);
SetPrefBool(kPrOpenVolumeRO, true);
SetPrefBool(kPrOpenVolumePhys0, false);
SetPrefBool(kPrProDOSAllowLower, false);
SetPrefBool(kPrProDOSUseSparse, true);
SetPrefLong(kPrCompressionType, DefaultCompressionType());
SetPrefLong(kPrMaxViewFileSize, 1024*1024); // 1MB
SetPrefBool(kPrNoWrapText, false);
SetPrefBool(kPrHighlightHexDump, false);
SetPrefBool(kPrHighlightBASIC, false);
SetPrefBool(kPrConvHiResBlackWhite, false);
SetPrefLong(kPrConvDHRAlgorithm, 1); // latched
SetPrefBool(kPrRelaxGfxTypeCheck, true);
SetPrefBool(kPrDisasmOneByteBrkCop, false);
//SetPrefBool(kPrEOLConvRaw, true);
SetPrefBool(kPrConvTextEOL_HA, true);
SetPrefBool(kPrConvPascalText, true);
SetPrefBool(kPrConvPascalCode, true);
SetPrefBool(kPrConvCPMText, true);
SetPrefBool(kPrConvApplesoft, true);
SetPrefBool(kPrConvInteger, true);
SetPrefBool(kPrConvBusiness, true);
SetPrefBool(kPrConvGWP, true);
SetPrefBool(kPrConvText8, true);
SetPrefBool(kPrConvGutenberg, true);
SetPrefBool(kPrConvAWP, true);
SetPrefBool(kPrConvADB, true);
SetPrefBool(kPrConvASP, true);
SetPrefBool(kPrConvSCAssem, true);
SetPrefBool(kPrConvDisasm, true);
SetPrefBool(kPrConvHiRes, true);
SetPrefBool(kPrConvDHR, true);
SetPrefBool(kPrConvSHR, true);
SetPrefBool(kPrConvPrintShop, true);
SetPrefBool(kPrConvMacPaint, true);
SetPrefBool(kPrConvProDOSFolder, true);
SetPrefBool(kPrConvResources, true);
InitTempPath(); // set default for kPrTempPath
SetPrefString(kPrExtViewerExts, "gif; jpg; jpeg");
SetPrefLong(kPrLastOpenFilterIndex, 0);
SetPrefString(kPrViewTextTypeFace, "Courier New");
SetPrefLong(kPrViewTextPointSize, 10);
long width = 680; /* exact width for 80-column text */
long height = 510; /* exact height for file viewer to show IIgs graphic */
if (GetSystemMetrics(SM_CXSCREEN) < width)
width = GetSystemMetrics(SM_CXSCREEN);
if (GetSystemMetrics(SM_CYSCREEN) < height)
height = GetSystemMetrics(SM_CYSCREEN); // may overlap system bar
//width = 640; height = 480;
SetPrefLong(kPrFileViewerWidth, width);
SetPrefLong(kPrFileViewerHeight, height);
SetPrefLong(kPrDiskImageCreateFormat, -1);
}
/*
* ==========================================================================
* ColumnLayout
* ==========================================================================
*/
/*
* Restore column widths.
*/
void
ColumnLayout::LoadFromRegistry(const char* section)
{
char numBuf[8];
int i;
for (i = 0; i < kNumVisibleColumns; i++) {
sprintf(numBuf, "%d", i);
fColumnWidth[i] = gMyApp.GetProfileInt(section, numBuf,
fColumnWidth[i]);
fColumnWidth[i] = gMyApp.GetProfileInt(section, numBuf,
fColumnWidth[i]);
}
fSortColumn = gMyApp.GetProfileInt(section, _T("sort-column"), fSortColumn);
fAscending = (gMyApp.GetProfileInt(section, _T("ascending"), fAscending) != 0);
}
/*
* Store column widths.
*/
void
ColumnLayout::SaveToRegistry(const char* section)
{
char numBuf[8];
int i;
for (i = 0; i < kNumVisibleColumns; i++) {
sprintf(numBuf, "%d", i);
gMyApp.WriteProfileInt(section, numBuf, fColumnWidth[i]);
}
gMyApp.WriteProfileInt(section, _T("sort-column"), fSortColumn);
gMyApp.WriteProfileInt(section, _T("ascending"), fAscending);
}
/*
* ==========================================================================
* Preferences
* ==========================================================================
*/
/*
* Get a default value for the temp path.
*/
void
Preferences::InitTempPath(void)
{
char buf[MAX_PATH];
DWORD len;
CString tempPath;
len = ::GetTempPath(sizeof(buf), buf);
if (len == 0) {
DWORD err = ::GetLastError();
WMSG1("GetTempPath failed, err=%d\n", err);
tempPath = kDefaultTempPath;
} else if (len >= sizeof(buf)) {
/* sheesh! */
WMSG1("GetTempPath wants a %d-byte buffer\n", len);
tempPath = kDefaultTempPath;
} else {
tempPath = buf;
}
PathName path(tempPath);
WMSG1("Temp path is '%s'\n", tempPath);
path.SFNToLFN();
tempPath = path.GetPathName();
WMSG1("Temp path (long form) is '%s'\n", tempPath);
SetPrefString(kPrTempPath, tempPath);
// ::GetFullPathName(fTempPath, sizeof(buf), buf, &foo);
// ::SetCurrentDirectory(buf);
// ::GetCurrentDirectory(sizeof(buf2), buf2);
}
/*
* Set default values for the various folders.
*/
void
Preferences::InitFolders(void)
{
CString path;
if (GetMyDocuments(&path)) {
SetPrefString(kPrOpenArchiveFolder, path);
SetPrefString(kPrConvertArchiveFolder, path);
SetPrefString(kPrAddFileFolder, path);
SetPrefString(kPrExtractFileFolder, path);
SetPrefString(kPrOpenWAVFolder, path);
} else {
char buf[MAX_PATH];
::GetCurrentDirectory(sizeof(buf), buf);
SetPrefString(kPrOpenArchiveFolder, buf);
SetPrefString(kPrConvertArchiveFolder, buf);
SetPrefString(kPrAddFileFolder, buf);
SetPrefString(kPrExtractFileFolder, buf);
SetPrefString(kPrOpenWAVFolder, buf);
}
WMSG1("Default folder is '%s'\n", GetPrefString(kPrExtractFileFolder));
}
/*
* Get the path to the "My Documents" folder.
*/
bool
Preferences::GetMyDocuments(CString* pPath)
{
LPITEMIDLIST pidl = nil;
LPMALLOC lpMalloc = nil;
HRESULT hr;
bool result = false;
hr = ::SHGetMalloc(&lpMalloc);
if (FAILED(hr))
return nil;
hr = SHGetSpecialFolderLocation(nil, CSIDL_PERSONAL, &pidl);
if (FAILED(hr)) {
WMSG0("WARNING: unable to get CSIDL_PERSONAL\n");
goto bail;
}
result = (Pidl::GetPath(pidl, pPath) != FALSE);
if (!result) {
WMSG0("WARNING: unable to convert CSIDL_PERSONAL to path\n");
/* fall through with "result" */
}
bail:
lpMalloc->Free(pidl);
lpMalloc->Release();
return result;
}
/*
* Determine the type of compression to use as a default, based on what this
* version of NufxLib supports.
*
* Note this happens *before* the AppInit call, so we should restrict this to
* things that are version-safe for all of NufxLib v2.x.
*/
int
Preferences::DefaultCompressionType(void)
{
if (NufxArchive::IsCompressionSupported(kNuThreadFormatLZW2))
return kNuThreadFormatLZW2;
else
return kNuThreadFormatUncompressed;
}
/*
* Preference getters and setters.
*/
bool
Preferences::GetPrefBool(PrefNum num) const
{
if (!ValidateEntry(num, kBool))
return false;
//return (bool) (fValues[num]);
return (bool) ((long) (fValues[num]) != 0);
}
void
Preferences::SetPrefBool(PrefNum num, bool val)
{
if (!ValidateEntry(num, kBool))
return;
fValues[num] = (void*) val;
}
long
Preferences::GetPrefLong(PrefNum num) const
{
if (!ValidateEntry(num, kLong))
return -1;
return (long) fValues[num];
}
void
Preferences::SetPrefLong(PrefNum num, long val)
{
if (!ValidateEntry(num, kLong))
return;
fValues[num] = (void*) val;
}
const char*
Preferences::GetPrefString(PrefNum num) const
{
if (!ValidateEntry(num, kString))
return nil;
return (const char*) fValues[num];
}
void
Preferences::SetPrefString(PrefNum num, const char* str)
{
if (!ValidateEntry(num, kString))
return;
free(fValues[num]);
if (str == nil)
fValues[num] = nil;
else {
fValues[num] = new char[strlen(str) +1];
if (fValues[num] != nil)
strcpy((char*)fValues[num], str);
}
}
/*
* Free storage for any string entries.
*/
void
Preferences::FreeStringValues(void)
{
int i;
for (i = 0; i < kPrefNumLastEntry; i++) {
if (fPrefMaps[i].type == kString) {
delete[] fValues[i];
}
}
}
/*
* Do a quick scan of the PrefMaps to identify duplicate, misplaced, and
* missing entries.
*/
void
Preferences::ScanPrefMaps(void)
{
int i, j;
/* scan PrefNum */
for (i = 0; i < kPrefNumLastEntry; i++) {
if (fPrefMaps[i].num != i) {
WMSG2("HEY: PrefMaps[%d] has num=%d\n", i, fPrefMaps[i].num);
ASSERT(false);
break;
}
}
/* look for duplicate strings */
for (i = 0; i < kPrefNumLastEntry; i++) {
for (j = i+1; j < kPrefNumLastEntry; j++) {
if (fPrefMaps[i].registryKey == nil ||
fPrefMaps[j].registryKey == nil)
{
continue;
}
if (strcasecmp(fPrefMaps[i].registryKey,
fPrefMaps[j].registryKey) == 0 &&
strcasecmp(fPrefMaps[i].registrySection,
fPrefMaps[j].registrySection) == 0)
{
WMSG4("HEY: PrefMaps[%d] and [%d] both have '%s'/'%s'\n",
i, j, fPrefMaps[i].registrySection,
fPrefMaps[i].registryKey);
ASSERT(false);
break;
}
}
}
}
/*
* Load preferences from the registry.
*/
int
Preferences::LoadFromRegistry(void)
{
CString sval;
bool bval;
long lval;
WMSG0("Loading preferences from registry\n");
fColumnLayout.LoadFromRegistry(kColumnSect);
int i;
for (i = 0; i < kPrefNumLastRegistry; i++) {
if (fPrefMaps[i].registryKey == nil)
continue;
switch (fPrefMaps[i].type) {
case kBool:
bval = GetPrefBool(fPrefMaps[i].num);
SetPrefBool(fPrefMaps[i].num,
GetBool(fPrefMaps[i].registrySection, fPrefMaps[i].registryKey, bval));
break;
case kLong:
lval = GetPrefLong(fPrefMaps[i].num);
SetPrefLong(fPrefMaps[i].num,
GetInt(fPrefMaps[i].registrySection, fPrefMaps[i].registryKey, lval));
break;
case kString:
sval = GetPrefString(fPrefMaps[i].num);
SetPrefString(fPrefMaps[i].num,
GetString(fPrefMaps[i].registrySection, fPrefMaps[i].registryKey, sval));
break;
default:
WMSG2("Invalid type %d on num=%d\n", fPrefMaps[i].type, i);
ASSERT(false);
break;
}
}
return 0;
}
/*
* Save preferences to the registry.
*/
int
Preferences::SaveToRegistry(void)
{
WMSG0("Saving preferences to registry\n");
fColumnLayout.SaveToRegistry(kColumnSect);
int i;
for (i = 0; i < kPrefNumLastRegistry; i++) {
if (fPrefMaps[i].registryKey == nil)
continue;
switch (fPrefMaps[i].type) {
case kBool:
WriteBool(fPrefMaps[i].registrySection, fPrefMaps[i].registryKey,
GetPrefBool(fPrefMaps[i].num));
break;
case kLong:
WriteInt(fPrefMaps[i].registrySection, fPrefMaps[i].registryKey,
GetPrefLong(fPrefMaps[i].num));
break;
case kString:
WriteString(fPrefMaps[i].registrySection, fPrefMaps[i].registryKey,
GetPrefString(fPrefMaps[i].num));
break;
default:
WMSG2("Invalid type %d on num=%d\n", fPrefMaps[i].type, i);
ASSERT(false);
break;
}
}
return 0;
}