xwords/xwords4/wince/cesvdgms.c
ehouse c791010603 Don't let smartphone users set hintlimits checkbox, and explain
why. Fix bug calling MessageBox with main window ptr from dialog.
Include name of preexisting file when warning user who enters it while
saving/renaming.
2008-12-07 01:30:18 +00:00

509 lines
16 KiB
C

/* -*- fill-column: 77; compile-command: "make TARGET_OS=wince DEBUG=TRUE" -*- */
/*
* Copyright 2004-2008 by Eric House (xwords@eehouse.org). All rights
* reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <windowsx.h>
#include "stdafx.h"
#include <commdlg.h>
#include <wchar.h>
#ifdef _win32_wce
#include <aygshell.h>
#endif
#include "cemain.h"
#include "cesvdgms.h"
#include "ceutil.h"
#include "cedebug.h"
#include "debhacks.h"
typedef struct CeSaveGameNameState {
CeDlgHdr dlgHdr;
wchar_t* buf;
XP_U16 buflen;
XP_U16 lableTextId;
XP_Bool cancelled;
XP_Bool inited;
} CeSaveGameNameState;
static XP_Bool
ceFileExists( CEAppGlobals* globals, const wchar_t* name )
{
wchar_t buf[CE_MAX_PATH_LEN];
DWORD attributes;
XP_U16 len;
len = ceGetPath( globals, DEFAULT_DIR_PATH_L, buf, VSIZE(buf) );
swprintf( &buf[len], L"%s.xwg", name );
attributes = GetFileAttributes( buf );
return attributes != 0xFFFFFFFF;
}
static void
makeUniqueName( CEAppGlobals* globals, wchar_t* buf,
XP_U16 XP_UNUSED_DBG(bufLen) )
{
XP_U16 ii;
for ( ii = 1; ii < 100; ++ii ) {
#ifdef DEBUG
int len =
#endif
swprintf( buf, L"Untitled%d", ii );
XP_ASSERT( len < bufLen );
if ( !ceFileExists( globals, buf ) ) {
break;
}
}
/* If we fall out of the loop, the user will be asked to confirm delete
of Untitled99 or somesuch. That's ok.... */
} /* makeUniqueName */
static LRESULT CALLBACK
SaveNameDlg( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
CeSaveGameNameState* state;
XP_U16 wid;
BOOL result = FALSE;
if ( message == WM_INITDIALOG ) {
SetWindowLongPtr( hDlg, GWL_USERDATA, lParam );
state = (CeSaveGameNameState*)lParam;
state->cancelled = XP_TRUE;
state->inited = XP_FALSE;
wchar_t buf[128];
LoadString( state->dlgHdr.globals->hInst, state->lableTextId,
buf, VSIZE(buf) );
(void)SetDlgItemText( hDlg, IDC_SVGN_SELLAB, buf );
ceDlgSetup( &state->dlgHdr, hDlg, DLG_STATE_TRAPBACK );
result = TRUE;
} else {
state = (CeSaveGameNameState*)GetWindowLongPtr( hDlg, GWL_USERDATA );
if ( !!state ) {
CEAppGlobals* globals = state->dlgHdr.globals;
if ( !state->inited ) {
state->inited = XP_TRUE;
(void)SetDlgItemText( hDlg, IDC_SVGN_EDIT, state->buf );
}
if ( ceDoDlgHandle( &state->dlgHdr, message, wParam, lParam) ) {
result = TRUE;
} else {
switch (message) {
case WM_COMMAND:
wid = LOWORD(wParam);
switch( wid ) {
case IDOK: {
wchar_t buf[128];
XP_U16 len;
(void)GetDlgItemText( hDlg, IDC_SVGN_EDIT, buf,
VSIZE(buf) );
if ( ceFileExists( globals, buf ) ) {
wchar_t widebuf[128];
snwprintf( widebuf, VSIZE(widebuf),
L"File \"%s\" already exists.", buf );
result = MessageBox( hDlg, widebuf, L"Oops!", MB_OK );
(void)SetDlgItemText( hDlg, IDC_SVGN_EDIT, state->buf );
break;
}
len = ceGetPath( globals, DEFAULT_DIR_PATH_L,
state->buf, state->buflen );
swprintf( &state->buf[len], L"%s.xwg", buf );
XP_LOGW( __func__, state->buf );
/* fallthru */
state->cancelled = XP_FALSE;
}
case IDCANCEL:
EndDialog(hDlg, wid);
result = TRUE;
break;
}
}
}
}
}
return result;
} /* SaveNameDlg */
XP_Bool
ceConfirmUniqueName( CEAppGlobals* globals, XP_U16 strId, wchar_t* buf,
XP_U16 buflen )
{
CeSaveGameNameState state;
LOG_FUNC();
makeUniqueName( globals, buf, buflen );
XP_MEMSET( &state, 0, sizeof(state) );
state.dlgHdr.globals = globals;
state.buf = buf;
state.buflen = buflen;
state.lableTextId = strId;
(void)DialogBoxParam( globals->hInst, (LPCTSTR)IDD_SAVENAMEDLG,
globals->hWnd,
(DLGPROC)SaveNameDlg, (long)&state );
XP_LOGW( __func__, buf );
return !state.cancelled;
} /* ceConfirmUniqueName */
typedef struct CeSavedGamesState {
CeDlgHdr dlgHdr;
wchar_t* buf;
XP_U16 buflen;
XP_S16 sel; /* index of game name currently selected */
XP_U16 openGameIndex; /* index of game that's open */
wchar_t openNameW[128];
wchar_t newNameW[MAX_PATH];
XP_U16 nItems;
XP_U16 gameListId;
XP_Bool inited;
XP_Bool relaunch;
SavedGamesResult result;
} CeSavedGamesState;
static void
ceBasename( wchar_t* buf, const wchar_t* path )
{
const wchar_t* ptr = path + wcslen(path);
const wchar_t* dot = NULL;
for ( ; ; ) {
if ( ptr == path ) {
break;
} else if ( *ptr == L'\\' ) {
++ptr;
break;
} else if ( !dot && *ptr == L'.' ) {
dot = ptr;
}
--ptr;
}
lstrcpy( buf, ptr );
buf[dot-ptr] = 0; /* nuke extension */
} /* ceBasename */
/* Probably belongs as a utility */
static void
getComboText( CeSavedGamesState* state, wchar_t* buf, XP_U16* lenp )
{
HWND hDlg = state->dlgHdr.hDlg;
CEAppGlobals* globals = state->dlgHdr.globals;
XP_U16 id = state->gameListId;
XP_U16 sel = state->sel;
XP_U16 len;
len = SendDlgItemMessage( hDlg, id, GETLBTEXTLEN(globals), sel, 0L );
if ( len < *lenp ) {
(void)SendDlgItemMessage( hDlg, id, GETLBTEXT(globals), sel,
(LPARAM)buf );
} else {
XP_ASSERT( 0 );
}
*lenp = len;
} /* getComboText */
static void
getFullSelPath( CeSavedGamesState* state, wchar_t* buf, XP_U16 buflen )
{
XP_U16 len = ceGetPath( state->dlgHdr.globals,
DEFAULT_DIR_PATH_L, buf, buflen );
buflen -= len;
getComboText( state, &buf[len], &buflen );
lstrcat( buf, L".xwg" );
}
static void
setButtons( CeSavedGamesState* state )
{
XP_Bool curSelected = state->openGameIndex == state->sel;
XP_Bool haveItem = state->nItems > 0;
HWND hDlg = state->dlgHdr.hDlg;
ceEnOrDisable( hDlg, IDC_SVGM_OPEN, haveItem && !curSelected );
ceEnOrDisable( hDlg, IDC_SVGM_DUP, haveItem );
ceEnOrDisable( hDlg, IDC_SVGM_DEL, haveItem && !curSelected );
ceEnOrDisable( hDlg, IDC_SVGM_CHANGE, haveItem );
}
static void
initSavedGamesData( CeSavedGamesState* state )
{
HANDLE fileH;
HWND hDlg = state->dlgHdr.hDlg;
CEAppGlobals* globals = state->dlgHdr.globals;
WIN32_FIND_DATA data;
wchar_t path[CE_MAX_PATH_LEN];
XP_S16 sel;
XP_U16 ii;
XP_U16 nItems = 0;
XP_MEMSET( &data, 0, sizeof(data) );
ceGetPath( globals, DEFAULT_DIR_PATH_L, path, VSIZE(path) );
lstrcat( path, L"*.xwg" );
fileH = FindFirstFile( path, &data );
for ( ii = 0; fileH != INVALID_HANDLE_VALUE; ++ii ) {
XP_U16 len = wcslen( data.cFileName );
XP_ASSERT( data.cFileName[len-4] == L'.');
data.cFileName[len-4] = 0;
(void)SendDlgItemMessage( hDlg, state->gameListId,
ADDSTRING(globals),
0, (LPARAM)data.cFileName );
++nItems;
if ( !FindNextFile( fileH, &data ) ) {
XP_ASSERT( GetLastError() == ERROR_NO_MORE_FILES );
break;
}
}
state->nItems = nItems;
/* Now locate the open game and game we should select (which may
differ) */
sel = SendDlgItemMessage( hDlg, state->gameListId, FINDSTRINGEXACT(globals),
-1, (LPARAM)state->openNameW );
XP_ASSERT( sel >= 0 ); /* should always have this */
state->openGameIndex = sel;
sel = SendDlgItemMessage( hDlg,state->gameListId, FINDSTRINGEXACT(globals),
-1, (LPARAM)state->newNameW );
if ( sel < 0 ) {
sel = state->openGameIndex;
}
SendDlgItemMessage( hDlg, state->gameListId, SETCURSEL(globals), sel, 0 );
state->sel = sel;
setButtons( state );
} /* initSavedGamesData */
static XP_Bool
renameSelected( CeSavedGamesState* state )
{
wchar_t newPath[MAX_PATH];
XP_Bool confirmed = ceConfirmUniqueName( state->dlgHdr.globals, IDS_RENAME,
newPath, VSIZE(newPath) );
if ( confirmed ) {
/* If we're renaming the current game, we have to exit and let
calling code handle it. If we're renaming any other game, we can
do it here. */
if ( state->openGameIndex == state->sel ) {
swprintf( state->buf, L"%s", newPath );
state->result = CE_SVGAME_RENAME;
} else {
wchar_t curPath[MAX_PATH];
getFullSelPath( state, curPath, VSIZE(curPath) );
confirmed = MoveFile( curPath, newPath );
}
}
if ( confirmed ) {
ceBasename( state->newNameW, newPath );
} else {
state->newNameW[0] = 0;
}
return confirmed;
} /* renameSelected */
static XP_Bool
duplicateSelected( CeSavedGamesState* state )
{
wchar_t newPath[MAX_PATH];
XP_Bool confirmed;
confirmed = ceConfirmUniqueName( state->dlgHdr.globals, IDS_DUPENAME,
newPath, VSIZE(newPath) );
if ( confirmed ) {
wchar_t curPath[MAX_PATH];
getFullSelPath( state, curPath, VSIZE(curPath) );
confirmed = CopyFile( curPath, newPath, TRUE ); /* TRUE is what??? */
}
if ( confirmed ) {
ceBasename( state->newNameW, newPath );
} else {
state->newNameW[0] = 0;
}
return confirmed;
} /* duplicateSelected */
static XP_Bool
deleteSelected( CeSavedGamesState* state )
{
/* confirm first!!!! */
XP_Bool confirmed = queryBoxChar( state->dlgHdr.globals,
"Are you certain you want to delete the "
"selected game? This action cannot be "
"undone.");
if ( confirmed ) {
wchar_t pathW[CE_MAX_PATH_LEN];
XP_U16 len = ceGetPath( state->dlgHdr.globals,
DEFAULT_DIR_PATH_L, pathW, VSIZE(pathW) );
XP_U16 remLen = VSIZE(pathW) - len;
getComboText( state, &pathW[len], &remLen );
wcscat( pathW, L".xwg" );
confirmed = DeleteFile( pathW );
if ( confirmed ) {
state->sel = -1;
}
}
return confirmed;
} /* deleteSelected */
static XP_Bool
tryGameChanged( CeSavedGamesState* state )
{
XP_S16 sel = SendDlgItemMessage( state->dlgHdr.hDlg, state->gameListId,
GETCURSEL(state->dlgHdr.globals), 0, 0L);
XP_Bool changing = sel >= 0 && state->sel != sel;
if ( changing ) {
state->sel = sel;
setButtons( state );
}
return changing;
} /* tryGameChanged */
static LRESULT CALLBACK
SavedGamesDlg( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
CeSavedGamesState* state;
BOOL result = FALSE;
if ( message == WM_INITDIALOG ) {
SetWindowLongPtr( hDlg, GWL_USERDATA, lParam );
state = (CeSavedGamesState*)lParam;
state->inited = XP_FALSE;
state->gameListId = LB_IF_PPC(state->dlgHdr.globals,IDC_SVGM_GAMELIST);
ceDlgSetup( &state->dlgHdr, hDlg, DLG_STATE_DONEONLY );
ceDlgComboShowHide( &state->dlgHdr, IDC_SVGM_GAMELIST );
result = TRUE;
} else {
state = (CeSavedGamesState*)GetWindowLongPtr( hDlg, GWL_USERDATA );
if ( !!state ) {
if ( !state->inited ) {
state->inited = XP_TRUE;
initSavedGamesData( state );
}
if ( ceDoDlgHandle( &state->dlgHdr, message, wParam, lParam) ) {
result = TRUE;
} else if ( WM_NOTIFY == message ) {
result = tryGameChanged( state );
} else if ( message == WM_COMMAND ) {
XP_U16 wid = LOWORD(wParam);
if ( CBN_SELCHANGE == HIWORD(wParam) ) {
if (state->gameListId == wid ) {
result = tryGameChanged( state );
}
} else if ( BN_CLICKED == HIWORD(wParam) ) {
switch( wid ) {
case IDC_SVGM_DUP:
state->relaunch = duplicateSelected( state );
break;
case IDC_SVGM_CHANGE:
state->relaunch = renameSelected( state );
break;
case IDC_SVGM_DEL:
state->relaunch = deleteSelected( state );
break;
case IDC_SVGM_OPEN: {
wchar_t buf[128];
XP_U16 len = VSIZE(buf);
getComboText( state, buf, &len );
len = ceGetPath( state->dlgHdr.globals,
DEFAULT_DIR_PATH_L, state->buf,
state->buflen );
swprintf( &state->buf[len], L"%s.xwg", buf );
XP_LOGW( "returning", state->buf );
state->result = CE_SVGAME_OPEN;
}
/* fallthrough */
case IDOK: /* Done button */
EndDialog(hDlg, wid);
result = TRUE;
break;
}
if ( state->relaunch ) {
EndDialog( hDlg, wid );
result = TRUE;
}
}
}
}
}
return result;
} /* SavedGamesDlg */
SavedGamesResult
ceSavedGamesDlg( CEAppGlobals* globals, const XP_UCHAR* curPath,
wchar_t* buf, XP_U16 buflen )
{
CeSavedGamesState state;
LOG_FUNC();
XP_MEMSET( &state, 0, sizeof(state) ); /* sets cancelled */
state.dlgHdr.globals = globals;
state.buf = buf;
state.buflen = buflen;
state.sel = -1;
if ( !!curPath ) {
wchar_t widebuf[MAX_PATH];
XP_U16 len;
len = (XP_U16)XP_STRLEN( curPath );
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, curPath, len + 1,
widebuf, len + 1 );
ceBasename( state.openNameW, widebuf );
}
for ( ; ; ) {
state.relaunch = XP_FALSE;
state.result = CE_SVGAME_CANCEL;
(void)DialogBoxParam( globals->hInst, (LPCTSTR)IDD_SAVEDGAMESDLG,
globals->hWnd,
(DLGPROC)SavedGamesDlg, (long)&state );
if ( !state.relaunch || (state.result == CE_SVGAME_RENAME) ) {
break;
}
}
XP_LOGW( __func__, buf );
return state.result;
} /* ceSavedGamesDlg */