|
|
//---------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation 1993-1994
//
// File: info.c
//
// This files contains dialog code for the Info property sheet
//
// History:
// 08-06-93 ScottH Transferred from twin code
//
//---------------------------------------------------------------------------
#include "brfprv.h" // common headers
#include <brfcasep.h>
#include "res.h"
#include <help.h>
//---------------------------------------------------------------------------
// INFO dialog struct
//---------------------------------------------------------------------------
// State flags for the INFO dialog
#define IS_ALLTYPES 0x0001
#define IS_INCLUDESUBS 0x0002
#define IS_DENYAPPLY 0x0004
#define IS_CHANGED 0x0008
#define IS_LAST_INCLUDESUBS 0x0010
typedef struct tagINFO { HWND hwnd; // dialog handle
PPAGEDATA ppagedata; PINFODATA pinfodata; int cselPrev; // previous count of selections
LPTSTR pszExtListPrev; // alloc: last saved settings
UINT uState; BOOL bInit; } INFO, * PINFO;
// Struct for CHANGETWINPROC callback
typedef struct tagCHANGEDATA { HBRFCASE hbrf; HFOLDERTWIN hft; HDPA hdpaTwins; int idpaTwin; HDPA hdpaFolders; int idpaStart; UINT uState; } CHANGEDATA, * PCHANGEDATA;
typedef HRESULT (CALLBACK * CHANGETWINPROC)(PNEWFOLDERTWIN, TWINRESULT, PCHANGEDATA);
// Struct for Info_AddTwins
typedef struct tagADDTWINSDATA { CHANGETWINPROC pfnCallback; HDPA hdpaSortedFolders; int idpaStart; } ADDTWINSDATA, * PADDTWINSDATA;
#define MAX_EXT_LEN 6 // Length for "*.ext"
static TCHAR const c_szAllFilesExt[] = TEXT(".*");
// Helper macros
#define Info_StandAlone(this) ((this)->pinfodata->bStandAlone)
#define Info_GetPtr(hwnd) (PINFO)GetWindowLongPtr(hwnd, DWLP_USER)
#define Info_SetPtr(hwnd, lp) (PINFO)SetWindowLongPtr(hwnd, DWLP_USER, (LRESULT)(lp))
SETbl const c_rgseInfo[4] = { // change in ibrfstg.c too
{ E_TR_OUT_OF_MEMORY, IDS_OOM_ADDFOLDER, MB_ERROR }, { E_OUTOFMEMORY, IDS_OOM_ADDFOLDER, MB_ERROR }, { E_TR_UNAVAILABLE_VOLUME, IDS_ERR_ADDFOLDER_UNAVAIL_VOL, MB_RETRYCANCEL | MB_ICONWARNING }, { E_TR_SUBTREE_CYCLE_FOUND, IDS_ERR_ADD_SUBTREECYCLE, MB_WARNING }, };
//---------------------------------------------------------------------------
// Info dialog functions
//---------------------------------------------------------------------------
/*----------------------------------------------------------
Purpose: Searches for an occurrence of the given extension in the folder twin list.
Returns: TRUE if the extension was found Cond: -- */ BOOL PRIVATE FindExtension( PFOLDERTWINLIST pftl, LPCTSTR pszExt) { PCFOLDERTWIN pcft; for (pcft = pftl->pcftFirst; pcft; pcft = pcft->pcftNext) { if (IsSzEqual(pszExt, pcft->pcszName)) { return TRUE; // Found a match!
} } return FALSE; }
/*----------------------------------------------------------
Purpose: Disable all the controls. Remove any selections. Returns: -- Cond: -- */ void PRIVATE Info_DisableAll( PINFO this) { ASSERT(!Info_StandAlone(this)); // Remove selections
//
ListBox_ResetContent(GetDlgItem(this->hwnd, IDC_LBINTYPES)); Button_SetCheck(GetDlgItem(this->hwnd, IDC_RBINALL), 0); Button_SetCheck(GetDlgItem(this->hwnd, IDC_RBINSELECTED), 0); Button_SetCheck(GetDlgItem(this->hwnd, IDC_CHININCLUDE), 0); // Disable the controls
//
Button_Enable(GetDlgItem(this->hwnd, IDC_RBINALL), FALSE); Button_Enable(GetDlgItem(this->hwnd, IDC_RBINSELECTED), FALSE); ListBox_Enable(GetDlgItem(this->hwnd, IDC_LBINTYPES), FALSE); Button_Enable(GetDlgItem(this->hwnd, IDC_CHININCLUDE), FALSE); }
/*----------------------------------------------------------
Purpose: Initialize the labels for our formatted radio buttons Returns: -- Cond: -- */ void PRIVATE Info_InitLabels( PINFO this) { HWND hwnd = this->hwnd; HWND hwndST = GetDlgItem(hwnd, IDC_CHININCLUDE); TCHAR sz[MAXMSGLEN]; TCHAR szFmt[MAXBUFLEN]; LPCTSTR pszPath = Atom_GetName(this->ppagedata->atomPath); LPTSTR pszFile; pszFile = PathFindFileName(pszPath); // Set static label
//
GetWindowText(hwndST, szFmt, ARRAYSIZE(szFmt)); wsprintf(sz, szFmt, pszFile); SetWindowText(hwndST, sz); if (Info_StandAlone(this)) { // Set title ("Create Twin of %s")
//
GetWindowText(hwnd, szFmt, ARRAYSIZE(szFmt)); wsprintf(sz, szFmt, pszFile); SetWindowText(hwnd, sz); } }
/*----------------------------------------------------------
Purpose: Queries the registry for all the legal extensions that are registered. These extensions are returned as a space-separated list in buffer.
Returns: -- Cond: Caller must GFree *ppszBuffer */ void PRIVATE GetExtensionList( LPTSTR * ppszBuffer) { HKEY hkRoot; *ppszBuffer = NULL; if (ERROR_SUCCESS == RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hkRoot)) { DWORD dwIndex; TCHAR szExt[MAX_PATH]; // Enumerate this key
for (dwIndex = 0; ERROR_SUCCESS == RegEnumKey(hkRoot, dwIndex, szExt, ARRAYSIZE(szExt)); dwIndex++) { // Did we get a node that is an extension AND
// is it a legal MS-DOS extension?
if (TEXT('.') == *szExt && 4 >= lstrlen(szExt)) { // Yes; add this extension to our list
lstrcat(szExt, TEXT(" ")); if (FALSE == GCatString(ppszBuffer, szExt)) { // Uh oh, something bad happened
break; } } } RegCloseKey(hkRoot); } }
/*----------------------------------------------------------
Purpose: Fill the file types listbox Returns: -- Cond: -- */ void PRIVATE Info_FillTypesList( PINFO this) { HWND hwndCtl = GetDlgItem(this->hwnd, IDC_LBINTYPES); LPTSTR pszExtList; GetExtensionList(&pszExtList); if (pszExtList) { int nTabWidth; TCHAR szExt[MAXBUFLEN]; LPTSTR psz; LPTSTR pszT; UINT uLen; SHFILEINFO sfi; nTabWidth = 30; ListBox_SetTabStops(hwndCtl, 1, &nTabWidth); for (psz = pszExtList; *psz; psz = CharNext(psz)) { // Skip any leading white-space
for (; TEXT(' ') == *psz; psz = CharNext(psz)) ; if (0 == *psz) { break; // End of string
} // Skip to next white-space (or null)
for (pszT = psz; TEXT(' ') < *pszT; pszT = CharNext(pszT)) { // (This will also stop at null)
} // (GetExtensionList should only get max 3 char extensions)
uLen = (UINT)(pszT - psz); ASSERT(ARRAYSIZE(szExt) > uLen); lstrcpyn(szExt, psz, uLen+1); CharUpper(szExt); SHGetFileInfo(szExt, 0, &sfi, sizeof(sfi), SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES); // Although this forces the format for international versions,
// it makes extraction much much easier.
lstrcat(szExt, TEXT("\t(")); lstrcat(szExt, sfi.szTypeName); lstrcat(szExt, TEXT(")")); ListBox_AddString(hwndCtl, szExt); psz = pszT; // To next extension
} GFree(pszExtList); } }
/*----------------------------------------------------------
Purpose: Set the selection of the dialog controls Returns: -- Cond: -- */ void PRIVATE Info_SetSelections( PINFO this) { HWND hwndLB = GetDlgItem(this->hwnd, IDC_LBINTYPES); int idBtn; int cItems = ListBox_GetCount(hwndLB); ListBox_SetSel(hwndLB, FALSE, -1); // deselect everything
// Is this the 'Add Folder' dialog?
if (Info_StandAlone(this)) { // Yes; default to *.* settings
SetFlag(this->uState, IS_ALLTYPES); SetFlag(this->uState, IS_INCLUDESUBS); } else { // No; query what the selections are
TCHAR szExt[MAXBUFLEN]; PFOLDERTWINLIST pftl; PCFOLDERTWIN pcft; int cItems; int i; BOOL bStarDotStar; LPTSTR psz; if (S_OK == PageData_Query(this->ppagedata, this->hwnd, NULL, &pftl)) { // Determine the selections in the listbox
szExt[0] = TEXT('*'); cItems = ListBox_GetCount(hwndLB); for (i = 0; i < cItems; i++) { // Extract the extension (it will be the first part of the
// string)
ListBox_GetText(hwndLB, i, &szExt[1]); for (psz = szExt; *psz && TEXT('\t') != *psz; psz = CharNext(psz)) ; ASSERT(TEXT('\t') == *psz); *psz = 0; // null terminate after the extension
// Is this extension in the folder twin list?
if (FindExtension(pftl, szExt)) { // Yes; select the entry
ListBox_SetSel(hwndLB, TRUE, i); } } ListBox_SetTopIndex(hwndLB, 0); this->cselPrev = ListBox_GetSelCount(hwndLB); // Determine the Include Subdirectories checkbox setting
//
bStarDotStar = FALSE; ClearFlag(this->uState, IS_INCLUDESUBS); for (pcft = pftl->pcftFirst; pcft; pcft = pcft->pcftNext) { if (IsFlagSet(pcft->dwFlags, FT_FL_SUBTREE)) SetFlag(this->uState, IS_INCLUDESUBS); if (IsSzEqual(pcft->pcszName, c_szAllFiles)) bStarDotStar = TRUE; } // Set the default radio button choice, and disable listbox
// if necessary. The default radio choice will be IDC_RBINALL,
// unless there are selections in the listbox AND there is no
// *.* occurrence in the folder twin list.
//
if (0 == this->cselPrev || bStarDotStar) SetFlag(this->uState, IS_ALLTYPES); else ClearFlag(this->uState, IS_ALLTYPES); } else { // An error occurred or this is an orphan. Bail early.
return; } } if (IsFlagSet(this->uState, IS_INCLUDESUBS)) SetFlag(this->uState, IS_LAST_INCLUDESUBS); else ClearFlag(this->uState, IS_LAST_INCLUDESUBS); // Set the control settings
Button_SetCheck(GetDlgItem(this->hwnd, IDC_CHININCLUDE), IsFlagSet(this->uState, IS_INCLUDESUBS)); ListBox_Enable(hwndLB, IsFlagClear(this->uState, IS_ALLTYPES)); idBtn = IsFlagSet(this->uState, IS_ALLTYPES) ? IDC_RBINALL : IDC_RBINSELECTED; CheckRadioButton(this->hwnd, IDC_RBINALL, IDC_RBINSELECTED, idBtn); // If listbox is empty, disable Selected Types radio button
if (0 == cItems) { Button_Enable(GetDlgItem(this->hwnd, IDC_RBINSELECTED), FALSE); } }
/*----------------------------------------------------------
Purpose: Get the selected extensions in the listbox and place them as a list in *ppszExtList.
.* is placed in the buffer if the Select All radio button is chosen instead. Returns: TRUE on success
Cond: The caller must GFree *ppszExtList */ BOOL PRIVATE Info_GetSelections( PINFO this, LPTSTR * ppszExtList) { BOOL bRet = FALSE; *ppszExtList = NULL; // Did user choose the All Types radio button?
if (IsFlagSet(this->uState, IS_ALLTYPES)) { // Yes; store the .* extension
bRet = GSetString(ppszExtList, c_szAllFilesExt); } else { // No; user selected a bunch of wildcards to filter
LPINT pisel; TCHAR szExt[MAXBUFLEN]; int csel; int isel; HWND hwndCtl = GetDlgItem(this->hwnd, IDC_LBINTYPES); // Allocate memory for the selection buffer
csel = ListBox_GetSelCount(hwndCtl); pisel = GAllocArray(int, csel); if (pisel) { // Get the selected extensions from the listbox
LPTSTR psz; if (0 < csel) { ListBox_GetSelItems(hwndCtl, csel, pisel); for (isel = 0; isel < csel; isel++) { // Extract the extension (it will be the first part of the string)
ListBox_GetText(hwndCtl, pisel[isel], szExt); for (psz = szExt; *psz && TEXT('\t') != *psz; psz = CharNext(psz)) ; ASSERT(TEXT('\t') == *psz); *psz = 0; if (FALSE == GCatString(ppszExtList, szExt)) { break; } } if (isel == csel) { bRet = TRUE; // Success
} else { GFree(*ppszExtList); } } GFree(pisel); } } return bRet; }
/*----------------------------------------------------------
Purpose: Create a sorted DPA version of the folder twin list
Returns: hdpa NULL on OOM Cond: -- */ HDPA PRIVATE CreateSortedFolderDPA( PFOLDERTWINLIST pftl) { HDPA hdpa; ASSERT(pftl); hdpa = DPA_Create(8); if (hdpa) { PCFOLDERTWIN pcft; for (pcft = pftl->pcftFirst; pcft; pcft = pcft->pcftNext) { // Use the dwUser field as a deletion flag
((PFOLDERTWIN)pcft)->dwUser = FALSE; if (DPA_ERR == DPA_InsertPtr(hdpa, DPA_APPEND, (LPVOID)pcft)) { DPA_Destroy(hdpa); return NULL; } } DPA_Sort(hdpa, NCompareFolders, CMP_FOLDERTWINS); } return hdpa; }
/*----------------------------------------------------------
Purpose: Process callback after adding a folder twin
Returns: standard result Cond: -- */ HRESULT CALLBACK ChangeTwinProc( PNEWFOLDERTWIN pnft, TWINRESULT tr, PCHANGEDATA pcd) { HRESULT hres = NOERROR; // Is this a duplicate twin?
if (TR_DUPLICATE_TWIN == tr) { // Yes; there's a wierd case to deal with. It's possible that the
// only thing the user did was check/uncheck the Include Subdirs
// checkbox. If this is true, then we delete the old twin and add
// a new twin (with same filespec as before) with the flags set
// differently.
PCFOLDERTWIN pcft; HDPA hdpaFolders = pcd->hdpaFolders; int cdpa = DPA_GetPtrCount(hdpaFolders); int idpa; BOOL bOldInclude; // Find the correct pcfolder. We will either tag it or
// we will delete it right now and re-add the new twin.
for (idpa = pcd->idpaStart; idpa < cdpa; idpa++) { pcft = DPA_FastGetPtr(hdpaFolders, idpa); if (IsSzEqual(pcft->pcszName, pnft->pcszName)) break; // found it!
} ASSERT(idpa < cdpa); // Tag the twin to save from impending doom...
((PFOLDERTWIN)(DWORD_PTR)pcft)->dwUser = TRUE; // Has the Include Subfolders checkbox setting changed?
bOldInclude = IsFlagSet(pcft->dwFlags, FT_FL_SUBTREE); if (bOldInclude ^ IsFlagSet(pcd->uState, IS_INCLUDESUBS)) { // Yes; delete the twin anyway and add the new one.
HFOLDERTWIN hft; DEBUG_CODE( TRACE_MSG(TF_GENERAL, TEXT("Deleting old folder twin")); ) Sync_DeleteTwin(pcft->hftOther); // Add the new folder twin to the database
tr = Sync_AddFolder(pcd->hbrf, pnft, &hft); if (TR_SUCCESS != tr) { // Adding the new twin failed
DPA_DeletePtr(pcd->hdpaTwins, pcd->idpaTwin); hres = HRESULT_FROM_TR(tr); } else { // Set the new twin handle in the pcd->hdpaTwins list
DPA_SetPtr(pcd->hdpaTwins, pcd->idpaTwin, (LPVOID)hft); DEBUG_CODE( TRACE_MSG(TF_GENERAL, TEXT("Adding new folder twin")); ) DEBUG_CODE( Sync_Dump(pnft, NEWFOLDERTWIN); ) } } else { // No; this isn't new, so don't add to list
DPA_DeletePtr(pcd->hdpaTwins, pcd->idpaTwin); } } else if (tr != TR_SUCCESS) { // Sync_AddFolder failed
DPA_DeletePtr(pcd->hdpaTwins, pcd->idpaTwin); hres = HRESULT_FROM_TR(tr); } else { // Sync_AddFolder succeeded
DPA_SetPtr(pcd->hdpaTwins, pcd->idpaTwin, (LPVOID)pcd->hft); DEBUG_CODE( TRACE_MSG(TF_GENERAL, TEXT("Adding new folder twin")); ) DEBUG_CODE( Sync_Dump(pnft, NEWFOLDERTWIN); ) } return hres; }
/*----------------------------------------------------------
Purpose: Add folder twins based on the list of extensions
Returns: standard result Cond: -- */ HRESULT PRIVATE Info_AddTwins( PINFO this, PNEWFOLDERTWIN pnft, PADDTWINSDATA patd, // May be NULL
LPTSTR pszExtList) // This function writes in this buffer
{ HRESULT hres = NOERROR; CHANGEDATA cd; HDPA hdpa; int idpa; TCHAR szWildcard[MAX_EXT_LEN]; LPTSTR psz; LPTSTR pszT; TCHAR ch; hdpa = this->pinfodata->hdpaTwins; cd.hbrf = PageData_GetHbrf(this->ppagedata); cd.hdpaTwins = hdpa; if (patd) { cd.hdpaFolders = patd->hdpaSortedFolders; cd.idpaStart = patd->idpaStart; } cd.uState = this->uState; pnft->pcszName = szWildcard; szWildcard[0] = TEXT('*'); for (psz = pszExtList; *psz; ) { TWINRESULT tr; HFOLDERTWIN hft = NULL; // Find the beginning of the next extension for the next iteration
for (pszT = CharNext(psz); *pszT && TEXT('.') != *pszT; pszT = CharNext(pszT)) ; ch = *pszT; *pszT = 0; // Temporary assignment
// Copy the extension into the name string
lstrcpy(&szWildcard[1], psz); *pszT = ch; psz = pszT; // First make sure we can add another handle to hdpaTwins
if (DPA_ERR == (idpa = DPA_InsertPtr(hdpa, DPA_APPEND, (LPVOID)hft))) { hres = ResultFromScode(E_OUTOFMEMORY); break; // Failed
} // Add the folder twin to the database
tr = Sync_AddFolder(cd.hbrf, pnft, &hft); if (patd) { cd.idpaTwin = idpa; cd.hft = hft; ASSERT(patd->pfnCallback); if ( FAILED((hres = patd->pfnCallback(pnft, tr, &cd))) ) { break; } } else if (TR_SUCCESS != tr) { // Sync_AddFolder failed
DPA_DeletePtr(hdpa, idpa); hres = HRESULT_FROM_TR(tr); break; } else { // Sync_AddFolder succeeded
DPA_SetPtr(hdpa, idpa, (LPVOID)hft); DEBUG_CODE( Sync_Dump(pnft, NEWFOLDERTWIN); ) } } return hres; }
/*----------------------------------------------------------
Purpose: Add the folder twin to the database
Returns: standard result Cond: -- */ HRESULT PRIVATE Info_CommitStandAlone( PINFO this) { HRESULT hres; NEWFOLDERTWIN nft; LPTSTR pszExtList; RETRY_BEGIN(FALSE) { ZeroInit(&nft, NEWFOLDERTWIN); nft.ulSize = sizeof(nft); nft.pcszFolder1 = Atom_GetName(this->ppagedata->atomPath); nft.pcszFolder2 = Atom_GetName(this->pinfodata->atomTo); // nft.pcszName is set in Info_AddTwins()
nft.dwAttributes = OBJECT_TWIN_ATTRIBUTES; nft.dwFlags = IsFlagSet(this->uState, IS_INCLUDESUBS) ? NFT_FL_SUBTREE : 0; // Create an extension list based on the dialog settings
if (!Info_GetSelections(this, &pszExtList)) { // Failed
hres = ResultFromScode(E_OUTOFMEMORY); } else { // Add the twins
hres = Info_AddTwins(this, &nft, NULL, pszExtList); GFree(pszExtList); } if (SUCCEEDED(hres)) { // Since the engine does not create folders if the folder is empty,
// we will create the folder now (whether it is empty or not).
// If the folder already exists, CreateDirectory will fail.
// Big deal.
CreateDirectory(nft.pcszFolder2, NULL); PathNotifyShell(nft.pcszFolder2, NSE_MKDIR, FALSE); } else { DWORD dwError = GetLastError(); int id; // Unavailable disk?
if (ERROR_INVALID_DATA == dwError || ERROR_ACCESS_DENIED == dwError) { // Yes
hres = E_TR_UNAVAILABLE_VOLUME; } id = SEMsgBox(this->hwnd, IDS_CAP_INFO, hres, c_rgseInfo, ARRAYSIZE(c_rgseInfo)); if (IDRETRY == id) { // Try the operation again
RETRY_SET(); } } } RETRY_END() return hres; }
/*----------------------------------------------------------
Purpose: Commit the user changes to the database. We delete all old hFolderTwins, and add new ones.
Returns: standard result Cond: -- */ HRESULT PRIVATE Info_CommitChange( PINFO this) { HRESULT hres; PFOLDERTWINLIST pftl; hres = PageData_Query(this->ppagedata, this->hwnd, NULL, &pftl); if (S_FALSE == hres) { // The folder has become an orphan right under our nose.
// Don't do anything.
Info_DisableAll(this); } else if (S_OK == hres) { LPCTSTR pszPath = Atom_GetName(this->ppagedata->atomPath); ADDTWINSDATA atd; DECLAREHOURGLASS; SetHourglass(); atd.pfnCallback = ChangeTwinProc; // Create a sorted DPA based on the folder twin list
atd.hdpaSortedFolders = CreateSortedFolderDPA(pftl); if (atd.hdpaSortedFolders) { // Create an extension list based on the dialog settings
LPTSTR pszExtList = NULL; if (Info_GetSelections(this, &pszExtList)) { NEWFOLDERTWIN nft; PCFOLDERTWIN pcft; PCFOLDERTWIN pcftLast; int idpa; int cdpa; // Now add new folder twins. Iterate thru atd.hdpaSortedFolders.
// For each unique folder twin in this list, we add a new twin,
// using the old lpcszFolder as the lpcszFolder2 field in our
// NEWFOLDERTWIN structure.
//
ZeroInit(&nft, NEWFOLDERTWIN); nft.ulSize = sizeof(NEWFOLDERTWIN); nft.pcszFolder1 = pszPath; // nft.pcszFolder2 is set in loop below
// nft.pcszName is set in Info_AddTwins()
nft.dwAttributes = OBJECT_TWIN_ATTRIBUTES; nft.dwFlags = IsFlagSet(this->uState, IS_INCLUDESUBS) ? NFT_FL_SUBTREE : 0; // Iterate thru existing folder twins. Act on each unique one.
cdpa = DPA_GetPtrCount(atd.hdpaSortedFolders); pcftLast = NULL; for (idpa = 0; idpa < cdpa; idpa++) { pcft = DPA_FastGetPtr(atd.hdpaSortedFolders, idpa); // Unique?
if (pcftLast && pcft->pcszOtherFolder == pcftLast->pcszOtherFolder) { // No; skip to next one
continue; } // This is a unique folder. Add it using the extensions in
// pszExtList.
atd.idpaStart = idpa; nft.pcszFolder2 = pcft->pcszOtherFolder; hres = Info_AddTwins(this, &nft, &atd, pszExtList); if (FAILED(hres)) { goto Cleanup; } pcftLast = pcft; } // Delete any old twins
for (pcft = pftl->pcftFirst; pcft; pcft = pcft->pcftNext) { // Is it okay to delete this twin?
if (pcft->hftOther && FALSE == pcft->dwUser) { // Yes
TRACE_MSG(TF_GENERAL, TEXT("Deleting folder twin with extension '%s'"), pcft->pcszName); Sync_DeleteTwin(pcft->hftOther); } } Cleanup: GFree(pszExtList); } DPA_Destroy(atd.hdpaSortedFolders); } ResetHourglass(); // Notify the shell of the change
PathNotifyShell(pszPath, NSE_UPDATEITEM, FALSE); // Throw out the last saved settings and reset
GFree(this->pszExtListPrev); Info_GetSelections(this, &this->pszExtListPrev); this->ppagedata->bRecalc = TRUE; if (FAILED(hres)) { static SETbl const c_rgseInfoChange[] = { { E_TR_OUT_OF_MEMORY, IDS_OOM_CHANGETYPES, MB_ERROR }, { E_OUTOFMEMORY, IDS_OOM_CHANGETYPES, MB_ERROR }, { E_TR_SUBTREE_CYCLE_FOUND, IDS_ERR_ADD_SUBTREECYCLE, MB_WARNING }, }; SEMsgBox(this->hwnd, IDS_CAP_INFO, hres, c_rgseInfoChange, ARRAYSIZE(c_rgseInfoChange)); } } return hres; }
/*----------------------------------------------------------
Purpose: Info WM_INITDIALOG Handler Returns: Cond: -- */ BOOL PRIVATE Info_OnInitDialog( PINFO this, HWND hwndFocus, LPARAM lParam) // LPPROPSHEETINFO
{ this->ppagedata = (PPAGEDATA)((LPPROPSHEETPAGE)lParam)->lParam; this->pinfodata = (PINFODATA)this->ppagedata->lParam; // Set the text of the controls
Info_InitLabels(this); // Fill listbox and set the control selections
Info_FillTypesList(this); if (Info_StandAlone(this)) { Info_SetSelections(this); Info_GetSelections(this, &this->pszExtListPrev); } this->bInit = TRUE; return TRUE; }
/*----------------------------------------------------------
Purpose: PSN_APPLY handler
Returns: FALSE if everything is OK TRUE to have the property sheet switch to this page to correct something. Cond: -- */ BOOL PRIVATE Info_OnApply( PINFO this) { BOOL bRet; LPTSTR pszExtList; ASSERT(!Info_StandAlone(this)); Info_GetSelections(this, &pszExtList); // Deny the apply?
if (IsFlagSet(this->uState, IS_DENYAPPLY)) { // Yes; don't let the apply go thru
MsgBox(this->hwnd, MAKEINTRESOURCE(IDS_MSG_SPECIFYTYPE), MAKEINTRESOURCE(IDS_CAP_INFO), NULL, MB_ERROR); bRet = PSNRET_INVALID; } // Have any settings changed?
else if (pszExtList && this->pszExtListPrev && // (Assume extensions are always listed in same order)
IsSzEqual(this->pszExtListPrev, pszExtList) && IsFlagSet(this->uState, IS_INCLUDESUBS) == IsFlagSet(this->uState, IS_LAST_INCLUDESUBS)) { // No
bRet = PSNRET_NOERROR; } else { // Yes; commit the changes
Info_CommitChange(this); // Sync up the current/previous state
if (IsFlagSet(this->uState, IS_INCLUDESUBS)) SetFlag(this->uState, IS_LAST_INCLUDESUBS); else ClearFlag(this->uState, IS_LAST_INCLUDESUBS); bRet = PSNRET_NOERROR; } GFree(pszExtList); ClearFlag(this->uState, IS_CHANGED); return bRet; }
/*----------------------------------------------------------
Purpose: PSN_SETACTIVE handler Returns: -- Cond: -- */ void PRIVATE Info_OnSetActive( PINFO this) { HWND hwnd = this->hwnd; // Cause the page to be painted right away
SetWindowRedraw(hwnd, TRUE); InvalidateRect(hwnd, NULL, TRUE); UpdateWindow(hwnd); if (this->bInit) { PageData_Init(this->ppagedata, GetParent(hwnd)); this->bInit = FALSE; Info_SetSelections(this); Info_GetSelections(this, &this->pszExtListPrev); } // Is this data still valid?
else if (S_FALSE == PageData_Query(this->ppagedata, this->hwnd, NULL, NULL)) { // No; the folder has become an orphan
Info_DisableAll(this); } }
/*----------------------------------------------------------
Purpose: WM_NOTIFY handler Returns: varies Cond: -- */ LRESULT PRIVATE Info_OnNotify( PINFO this, int idFrom, NMHDR * lpnmhdr) { LRESULT lRet = 0; switch (lpnmhdr->code) { case PSN_SETACTIVE: Info_OnSetActive(this); break; case PSN_APPLY: lRet = Info_OnApply(this); break; default: break; } return lRet; }
/*----------------------------------------------------------
Purpose: Determines whether to keep from leaving this sheet. For the stand-alone ('Add Folder') dialog, this function enables or disables the OK button.
Returns: -- Cond: -- */ void PRIVATE Info_DenyKill( PINFO this, BOOL bDeny) { if (Info_StandAlone(this)) { Button_Enable(GetDlgItem(this->hwnd, IDOK), !bDeny); } else { if (bDeny) SetFlag(this->uState, IS_DENYAPPLY); else ClearFlag(this->uState, IS_DENYAPPLY); } }
/*----------------------------------------------------------
Purpose: Enable the Apply button
Returns: -- Cond: -- */ void PRIVATE Info_HandleChange( PINFO this) { if (IsFlagClear(this->uState, IS_CHANGED) && !Info_StandAlone(this)) { SetFlag(this->uState, IS_CHANGED); PropSheet_Changed(GetParent(this->hwnd), this->hwnd); } }
/*----------------------------------------------------------
Purpose: Info WM_COMMAND Handler Returns: -- Cond: -- */ VOID PRIVATE Info_OnCommand( PINFO this, int id, HWND hwndCtl, UINT uNotifyCode) { HWND hwnd = this->hwnd; switch (id) { case IDC_RBINALL: Info_DenyKill(this, FALSE); // fall thru
case IDC_RBINSELECTED: // Disable/enable listbox depending on which radio button
// is marked.
//
if (IDC_RBINALL == id) SetFlag(this->uState, IS_ALLTYPES); else ClearFlag(this->uState, IS_ALLTYPES); ListBox_Enable(GetDlgItem(hwnd, IDC_LBINTYPES), IsFlagClear(this->uState, IS_ALLTYPES)); if (IDC_RBINSELECTED == id && 0 == ListBox_GetSelCount(GetDlgItem(hwnd, IDC_LBINTYPES))) { Info_DenyKill(this, TRUE); } Info_HandleChange(this); break; case IDC_LBINTYPES: if (uNotifyCode == LBN_SELCHANGE) { // Disable/enable OK button based on number of selections
// in listbox.
//
int csel = ListBox_GetSelCount(GetDlgItem(hwnd, IDC_LBINTYPES)); if (csel == 0) Info_DenyKill(this, TRUE); else if (csel != this->cselPrev && this->cselPrev == 0) Info_DenyKill(this, FALSE); this->cselPrev = csel; Info_HandleChange(this); } break; case IDC_CHININCLUDE: if (FALSE != Button_GetCheck(GetDlgItem(hwnd, IDC_CHININCLUDE))) SetFlag(this->uState, IS_INCLUDESUBS); else ClearFlag(this->uState, IS_INCLUDESUBS); Info_HandleChange(this); break; case IDOK: if (FAILED(Info_CommitStandAlone(this))) EndDialog(hwnd, -1); // Fall thru
// | |
// v v
case IDCANCEL: if (Info_StandAlone(this)) EndDialog(hwnd, id); break; } }
/*----------------------------------------------------------
Purpose: Handle WM_DESTROY Returns: -- Cond: -- */ void PRIVATE Info_OnDestroy( PINFO this) { GFree(this->pszExtListPrev); }
///////////////////////////////////////////////////// PRIVATE FUNCTIONS
static BOOL s_bInfoRecurse = FALSE;
LRESULT INLINE Info_DefProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { ENTEREXCLUSIVE(); { s_bInfoRecurse = TRUE; } LEAVEEXCLUSIVE(); return DefDlgProc(hDlg, msg, wParam, lParam); }
/*----------------------------------------------------------
Purpose: Real Create Folder Twin dialog proc Returns: varies Cond: -- */ LRESULT Info_DlgProc( PINFO this, UINT message, WPARAM wParam, LPARAM lParam) { const static DWORD rgHelpIDs[] = { IDC_RBINALL, IDH_BFC_FILTER_TYPE, IDC_RBINSELECTED, IDH_BFC_FILTER_TYPE, IDC_LBINTYPES, IDH_BFC_FILTER_TYPE, IDC_CHININCLUDE, IDH_BFC_FILTER_INCLUDE, IDC_GBIN, IDH_BFC_FILTER_TYPE, 0, 0 }; switch (message) { HANDLE_MSG(this, WM_INITDIALOG, Info_OnInitDialog); HANDLE_MSG(this, WM_COMMAND, Info_OnCommand); HANDLE_MSG(this, WM_NOTIFY, Info_OnNotify); HANDLE_MSG(this, WM_DESTROY, Info_OnDestroy); case WM_HELP: WinHelp(((LPHELPINFO)lParam)->hItemHandle, c_szWinHelpFile, HELP_WM_HELP, (DWORD_PTR)(LPVOID)rgHelpIDs); return 0; case WM_CONTEXTMENU: WinHelp((HWND)wParam, c_szWinHelpFile, HELP_CONTEXTMENU, (DWORD_PTR)(LPVOID)rgHelpIDs); return 0; default: return Info_DefProc(this->hwnd, message, wParam, lParam); } }
/*----------------------------------------------------------
Purpose: Create Folder Twin Dialog Wrapper Returns: varies Cond: -- */ INT_PTR _export CALLBACK Info_WrapperProc( HWND hDlg, // std params
UINT message, WPARAM wParam, LPARAM lParam) { PINFO this; // Cool windowsx.h dialog technique. For full explanation, see
// WINDOWSX.TXT. This supports multiple-instancing of dialogs.
//
ENTEREXCLUSIVE(); { if (s_bInfoRecurse) { s_bInfoRecurse = FALSE; LEAVEEXCLUSIVE(); return FALSE; } } LEAVEEXCLUSIVE(); this = Info_GetPtr(hDlg); if (this == NULL) { if (message == WM_INITDIALOG) { this = GAlloc(sizeof(*this)); if (!this) { MsgBox(hDlg, MAKEINTRESOURCE(IDS_OOM_INFO), MAKEINTRESOURCE(IDS_CAP_INFO), NULL, MB_ERROR); EndDialog(hDlg, IDCANCEL); return Info_DefProc(hDlg, message, wParam, lParam); } this->hwnd = hDlg; Info_SetPtr(hDlg, this); } else { return Info_DefProc(hDlg, message, wParam, lParam); } } if (message == WM_DESTROY) { Info_DlgProc(this, message, wParam, lParam); GFree(this); Info_SetPtr(hDlg, NULL); return 0; } return SetDlgMsgResult(hDlg, message, Info_DlgProc(this, message, wParam, lParam)); }
///////////////////////////////////////////////////// PUBLIC FUNCTIONS
/*----------------------------------------------------------
Purpose: Entry point to invoke dialog
Returns: standard hresult Cond: -- */ HRESULT PUBLIC Info_DoModal( HWND hwndOwner, LPCTSTR pszPathFrom, // Source path
LPCTSTR pszPathTo, // Target path
HDPA hdpaTwin, PCBS pcbs) { HRESULT hres; PROPSHEETPAGE psp; PAGEDATA pagedata; INFODATA infodata; // (Use the source path for the atomPath because the target path
// does not exist yet.)
pagedata.atomPath = Atom_Add(pszPathFrom); if (ATOM_ERR != pagedata.atomPath) { infodata.atomTo = Atom_Add(pszPathTo); if (ATOM_ERR != infodata.atomTo) { INT_PTR nRet; pagedata.pcbs = pcbs; pagedata.lParam = (LPARAM)&infodata; infodata.hdpaTwins = hdpaTwin; infodata.bStandAlone = TRUE; // Fake up a propsheetinfo struct for the dialog box
psp.lParam = (LPARAM)&pagedata; // this is all we care about
nRet = DoModal(hwndOwner, Info_WrapperProc, IDD_INFOCREATE, (LPARAM)(LPVOID)&psp); Atom_Delete(infodata.atomTo); switch (nRet) { case IDOK: hres = NOERROR; break; case IDCANCEL: hres = E_ABORT; break; default: hres = E_OUTOFMEMORY; break; } } else { hres = E_OUTOFMEMORY; } Atom_Delete(pagedata.atomPath); } else { hres = E_OUTOFMEMORY; } return hres; }
|