//--------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation 1993-1994 // // File: update.c // // This files contains code for the Update UI and dialog. // // History: // 08-17-93 ScottH Created. // //--------------------------------------------------------------------------- #include "brfprv.h" // common headers #include "res.h" #include "recact.h" #include // This structure contains all the important counts // that determine the specific course of action when // the user wants to update something. typedef struct { // These are 1 to 1 UINT cFiles; UINT cOrphans; UINT cSubfolders; // These are 1 to 1 UINT cUnavailable; UINT cDoSomething; UINT cConflict; UINT cTombstone; } UPDCOUNT; // This is the structure passed to the dialog at WM_INITDIALOG typedef struct { PRECLIST lprl; // Supplied reclist CBS * pcbs; UINT uFlags; // UF_ Flags HDPA hdpa; // List of RA_ITEMs UINT cDoSomething; } XUPDSTRUCT, * LPXUPDSTRUCT; typedef struct tagUPD { HWND hwnd; // dialog handle LPXUPDSTRUCT pxupd; } UPD, * PUPD; #define Upd_Prl(this) ((this)->pxupd->lprl) #define Upd_AtomBrf(this) ((this)->pxupd->pcbs->atomBrf) #define Upd_GetBrfPtr(this) Atom_GetName(Upd_AtomBrf(this)) #define Upd_GetPtr(hwnd) (PUPD)GetWindowLongPtr(hwnd, DWLP_USER) #define Upd_SetPtr(hwnd, lp) (PUPD)SetWindowLongPtr(hwnd, DWLP_USER, (LRESULT)(lp)) // These flags are used for DoUpdateMsg #define DUM_ALL 0x0001 #define DUM_SELECTION 0x0002 #define DUM_ORPHAN 0x0004 #define DUM_UPTODATE 0x0008 #define DUM_UNAVAILABLE 0x0010 #define DUM_SUBFOLDER_TWIN 0x0020 // These flags are returned by PassedSpecialCases #define PSC_SHOWDIALOG 0x0001 #define PSC_POSTMSGBOX 0x0002 //--------------------------------------------------------------------------- // Some comments //--------------------------------------------------------------------------- // There are several special cases and conditions which must be // handled. Lets break them down now. The case numbers on on the far // right, and are referenced in comments thru out this file. // // There are two user actions: Update All and Update Selection. // // Update All: // // Case What to do // ----------------- -------------- // A1. * No files in the briefcase ---> MB (messagebox) // A2. * All files are orphans ---> MB // * Some files are twins and... // * they are all available and... // A3. * they are all up-to-date ---> MB // A4. * some of them need updating ---> Update dialog // * some are unavailable and... // A5. * the available ones are up-to-date ---> MB then Update // A6. * some need updating ---> MB then Update // // // Update Selection: // // Case What to do // ----------------- -------------- // * Single selection and... // S1. * is an orphan ---> MB // * is available and... // S2. * up-to-date ---> MB // S3. * needs updating ---> Update // S4. * is unavailable ---> MB then Update // * Multi selection and... // S5. * all are orphans ---> MB // * some (non-orphans) are unavailable and... // * some need updating and... // S6. * none are orphans ---> MB then Update // S7. * some are orphans ---> MB then Update then MB // * the available ones are up-to-date and... // S8. * none are orphans ---> MB then Update // S9. * some are orphans ---> MB then Update then MB // * all (non-orphans) are available and... // * some need updating and... // S10. * none are orphans ---> Update // S11. * some are orphans ---> Update then MB // * all up-to-date and... // S12. * none are orphans ---> MB // S13. * some are orphans ---> MB //--------------------------------------------------------------------------- // Dialog code //--------------------------------------------------------------------------- /*---------------------------------------------------------- Purpose: Fill the reconciliation action listbox Returns: TRUE on success Cond: -- */ BOOL PRIVATE Upd_FillList( PUPD this) { HWND hwndCtl = GetDlgItem(this->hwnd, IDC_UPDATEACTIONS); HDPA hdpa = this->pxupd->hdpa; int cItems; int i; cItems = DPA_GetPtrCount(hdpa); for (i = 0; i < cItems; i++) { RA_ITEM * pitem = DPA_FastGetPtr(hdpa, i); RecAct_InsertItem(hwndCtl, pitem); RAI_Free(pitem); } return TRUE; } /*---------------------------------------------------------- Purpose: Sets the Update and Cancel buttons according to the bDisableUpdate parameter. Returns: -- Cond: -- */ void PRIVATE Upd_SetExitButtons( PUPD this, BOOL bDisableUpdate) { HWND hwndOK = GetDlgItem(this->hwnd, IDOK); // Disable the update button? if (bDisableUpdate) { // Yes if (GetFocus() == hwndOK) { SetFocus(GetDlgItem(this->hwnd, IDCANCEL)); } Button_Enable(hwndOK, FALSE); } else { // No Button_Enable(hwndOK, TRUE); } } /*---------------------------------------------------------- Purpose: WM_INITDIALOG Handler Returns: Cond: -- */ BOOL PRIVATE Upd_OnInitDialog( PUPD this, HWND hwndFocus, LPARAM lParam) { HWND hwnd = this->hwnd; TCHAR szFmt[MAXBUFLEN]; TCHAR sz[MAXMSGLEN]; ASSERT(lParam != 0L); this->pxupd = (LPXUPDSTRUCT)lParam; if (Upd_FillList(this)) { // Set the title caption wsprintf(sz, SzFromIDS(IDS_CAP_UpdateFmt, szFmt, ARRAYSIZE(szFmt)), PathFindFileName(Upd_GetBrfPtr(this))); SetWindowText(hwnd, sz); // Do any files need updating? if (0 == this->pxupd->cDoSomething) { // No Upd_SetExitButtons(this, TRUE); } } else { // Failed EndDialog(hwnd, -1); } return(TRUE); } /*---------------------------------------------------------- Purpose: Handle RN_ITEMCHANGED Returns: -- Cond: -- */ void PRIVATE Upd_HandleItemChange( PUPD this, NM_RECACT * lpnm) { PRECITEM lpri; ASSERT((lpnm->mask & RAIF_LPARAM) != 0); lpri = (PRECITEM)lpnm->lParam; // The action has changed, update the recnode accordingly if (lpnm->mask & RAIF_ACTION) { LPCTSTR pszDir = Upd_GetBrfPtr(this); Sync_ChangeRecItemAction(lpri, pszDir, pszDir, lpnm->uAction); switch (lpnm->uActionOld) { case RAIA_TOOUT: case RAIA_TOIN: case RAIA_MERGE: // Is this a change from "do something" to "skip"? if (RAIA_SKIP == lpnm->uAction) { // Yes ASSERT(0 < this->pxupd->cDoSomething); this->pxupd->cDoSomething--; } break; case RAIA_SKIP: case RAIA_CONFLICT: // Is this a change from "skip"/"conflict" to "do something"? if (RAIA_TOOUT == lpnm->uAction || RAIA_TOIN == lpnm->uAction || RAIA_MERGE == lpnm->uAction) { // Yes this->pxupd->cDoSomething++; } break; } Upd_SetExitButtons(this, 0 == this->pxupd->cDoSomething); } } /*---------------------------------------------------------- Purpose: WM_NOTIFY handler Returns: varies Cond: -- */ LRESULT PRIVATE Upd_OnNotify( PUPD this, int idFrom, NMHDR * lpnmhdr) { LRESULT lRet = 0; switch (lpnmhdr->code) { case RN_ITEMCHANGED: Upd_HandleItemChange(this, (NM_RECACT *)lpnmhdr); break; default: break; } return lRet; } /*---------------------------------------------------------- Purpose: Info WM_COMMAND Handler Returns: -- Cond: -- */ VOID PRIVATE Upd_OnCommand( PUPD this, int id, HWND hwndCtl, UINT uNotifyCode) { HWND hwnd = this->hwnd; switch (id) { case IDOK: case IDCANCEL: EndDialog(hwnd, id); break; } } /*---------------------------------------------------------- Purpose: WM_DESTROY handler Returns: -- Cond: -- */ void PRIVATE Upd_OnDestroy( PUPD this) { } static BOOL s_bUpdRecurse = FALSE; LRESULT INLINE Upd_DefProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { ENTEREXCLUSIVE(); { s_bUpdRecurse = TRUE; } LEAVEEXCLUSIVE(); return DefDlgProc(hDlg, msg, wParam, lParam); } /*---------------------------------------------------------- Purpose: Real Create Folder Twin dialog proc Returns: varies Cond: -- */ LRESULT Upd_DlgProc( PUPD this, UINT message, WPARAM wParam, LPARAM lParam) { const static DWORD rgHelpIDs[] = { IDC_UPDATEACTIONS, IDH_BFC_UPDATE_SCREEN, // different IDOK, IDH_BFC_UPDATE_BUTTON, 0, 0 }; switch (message) { HANDLE_MSG(this, WM_INITDIALOG, Upd_OnInitDialog); HANDLE_MSG(this, WM_COMMAND, Upd_OnCommand); HANDLE_MSG(this, WM_NOTIFY, Upd_OnNotify); HANDLE_MSG(this, WM_DESTROY, Upd_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 Upd_DefProc(this->hwnd, message, wParam, lParam); } } /*---------------------------------------------------------- Purpose: Create Folder Twin Dialog Wrapper Returns: varies Cond: -- */ INT_PTR _export CALLBACK Upd_WrapperProc( HWND hDlg, // std params UINT message, WPARAM wParam, LPARAM lParam) { PUPD this; // Cool windowsx.h dialog technique. For full explanation, see // WINDOWSX.TXT. This supports multiple-instancing of dialogs. // ENTEREXCLUSIVE(); { if (s_bUpdRecurse) { s_bUpdRecurse = FALSE; LEAVEEXCLUSIVE(); return FALSE; } } LEAVEEXCLUSIVE(); this = Upd_GetPtr(hDlg); if (this == NULL) { if (message == WM_INITDIALOG) { this = GAlloc(sizeof(*this)); if (!this) { MsgBox(hDlg, MAKEINTRESOURCE(IDS_OOM_UPDATEDIALOG), MAKEINTRESOURCE(IDS_CAP_UPDATE), NULL, MB_ERROR); EndDialog(hDlg, IDCANCEL); return Upd_DefProc(hDlg, message, wParam, lParam); } this->hwnd = hDlg; Upd_SetPtr(hDlg, this); } else { return Upd_DefProc(hDlg, message, wParam, lParam); } } if (message == WM_DESTROY) { Upd_DlgProc(this, message, wParam, lParam); GFree(this); Upd_SetPtr(hDlg, NULL); return 0; } return SetDlgMsgResult(hDlg, message, Upd_DlgProc(this, message, wParam, lParam)); } //--------------------------------------------------------------------------- // Update detection code //--------------------------------------------------------------------------- /*---------------------------------------------------------- Purpose: Checks if the briefcase is empty. This function skips the "desktop.ini" and "Briefcase Database" files. Returns: TRUE if the briefcase is empty Cond: -- */ BOOL PRIVATE IsBriefcaseEmpty( LPCTSTR pszPath) { BOOL bRet = FALSE; ASSERT(pszPath); if (pszPath) { // Enumerate thru folder TCHAR szSearch[MAXPATHLEN]; WIN32_FIND_DATA fd; HANDLE hfile; // This must be per instance, else it will cause a fixup in // shared data segment. const static LPCTSTR s_rgszIgnore[] = { TEXT("."), TEXT(".."), g_szDBName, g_szDBNameShort, c_szDesktopIni }; PathCombine(szSearch, pszPath, TEXT("*.*")); hfile = FindFirstFile(szSearch, &fd); if (INVALID_HANDLE_VALUE != hfile) { BOOL bCont = TRUE; bRet = TRUE; // Default to empty folder while (bCont) { int bIgnore = FALSE; int i; // Is this file one of the files to ignore? for (i = 0; i < ARRAYSIZE(s_rgszIgnore); i++) { if (IsSzEqual(fd.cFileName, s_rgszIgnore[i])) { // Yes bIgnore = TRUE; break; } } // Is this a valid file/folder? if (FALSE == bIgnore) { // Yes; return the briefcase is not empty bRet = FALSE; bCont = FALSE; // stop the enumeration } else { bCont = FindNextFile(hfile, &fd); } } FindClose(hfile); } } return bRet; } /*---------------------------------------------------------- Purpose: Create a DSA of RA_ITEMs Sets the cDoSomething, cUnavailable, cConflict and cTombstone fields of pupdcount. Returns: TRUE on success Cond: -- */ HDPA PRIVATE ComposeUpdateList( PCBS pcbs, PRECLIST prl, UPDCOUNT * pupdcount, HWND hwndOwner) { HRESULT hres; HDPA hdpa; ASSERT(prl); hdpa = DPA_Create(20); if (NULL != hdpa) { LPRA_ITEM pitem; PRECITEM pri; LPCTSTR pszBrf = Atom_GetName(pcbs->atomBrf); if (pszBrf) { DEBUG_CODE( Sync_DumpRecList(TR_SUCCESS, prl, TEXT("ComposeUpdateList")); ) pupdcount->cUnavailable = 0; pupdcount->cDoSomething = 0; pupdcount->cTombstone = 0; pupdcount->cConflict = 0; for (pri = prl->priFirst; pri; pri = pri->priNext) { hres = RAI_CreateFromRecItem(&pitem, pszBrf, pri); if (SUCCEEDED(hres)) { // Is this a NOP? if (RAIA_NOTHING == pitem->uAction || RAIA_ORPHAN == pitem->uAction) { // Yes; skip these guys altogether } else { pitem->mask |= RAIF_LPARAM; pitem->lParam = (LPARAM)pri; #ifndef NEW_REC // Has the file inside or outside the briefcase been deleted? if (SI_DELETED == pitem->siInside.uState || SI_DELETED == pitem->siOutside.uState) { // Yes pupdcount->cTombstone++; } else #endif // Is this a file entry? if (IsFileRecItem(pri)) { // Yes; add the item to the list. pitem->iItem = 0x7fff; DPA_InsertPtr(hdpa, DPA_APPEND, pitem); // Is this unavailable? if (RAIA_SKIP == pitem->uAction) { // Yes ASSERT(SI_UNAVAILABLE == pitem->siInside.uState || SI_UNAVAILABLE == pitem->siOutside.uState || SI_NOEXIST == pitem->siInside.uState || SI_NOEXIST == pitem->siOutside.uState); pupdcount->cUnavailable++; } else if (RAIA_CONFLICT == pitem->uAction) { pupdcount->cConflict++; } else { pupdcount->cDoSomething++; } // (prevent pitem from being freed until // the dialog fills its list in Upd_FillList) pitem = NULL; } } RAI_Free(pitem); } } } } return hdpa; } /*---------------------------------------------------------- Purpose: Displays a messagebox error specific to updating files Returns: id of button Cond: -- */ int PRIVATE DoUpdateMsg( HWND hwndOwner, LPCTSTR pszPath, UINT cFiles, UINT uFlags) // DUM_ flags { UINT ids; UINT idi; int idRet; // Is this for Update All? if (IsFlagSet(uFlags, DUM_ALL)) { // Yes idi = IDI_UPDATE_MULT; if (IsFlagSet(uFlags, DUM_ORPHAN)) { // In this case, pszPath should be the briefcase root ASSERT(pszPath); if (IsBriefcaseEmpty(pszPath)) ids = IDS_MSG_NoFiles; else ids = IDS_MSG_AllOrphans; } else if (IsFlagSet(uFlags, DUM_UPTODATE)) ids = IDS_MSG_AllUptodate; else if (IsFlagSet(uFlags, DUM_UNAVAILABLE)) ids = IDS_MSG_AllSomeUnavailable; else { ASSERT(0); // should never get here ids = (UINT)-1; } idRet = MsgBox(hwndOwner, MAKEINTRESOURCE(ids), MAKEINTRESOURCE(IDS_CAP_UPDATE), LoadIcon(g_hinst, MAKEINTRESOURCE(idi)), MB_INFO); } else { // No TCHAR sz[MAX_PATH]; ASSERT(0 != cFiles); ASSERT(pszPath); // Is this a single selection? if (1 == cFiles) { // Yes; assume it is a folder, then decrement the count // of the ids it is a file if (IsFlagSet(uFlags, DUM_ORPHAN)) ids = IDS_MSG_FolderOrphan; else if (IsFlagSet(uFlags, DUM_UPTODATE)) ids = IDS_MSG_FolderUptodate; else if (IsFlagSet(uFlags, DUM_UNAVAILABLE)) ids = IDS_MSG_FolderUnavailable; else if (IsFlagSet(uFlags, DUM_SUBFOLDER_TWIN)) ids = IDS_MSG_FolderSubfolder; else { ASSERT(0); // should never get here ids = (UINT)-1; } if (FALSE == PathIsDirectory(pszPath)) { ASSERT(IsFlagClear(uFlags, DUM_SUBFOLDER_TWIN)); ids--; // use file-oriented messages idi = IDI_UPDATE_FILE; } else { idi = IDI_UPDATE_FOLDER; } idRet = MsgBox(hwndOwner, MAKEINTRESOURCE(ids), MAKEINTRESOURCE(IDS_CAP_UPDATE), LoadIcon(g_hinst, MAKEINTRESOURCE(idi)), MB_INFO, PathGetDisplayName(pszPath, sz)); } else { // No; multi selection idi = IDI_UPDATE_MULT; if (IsFlagSet(uFlags, DUM_UPTODATE)) { if (IsFlagSet(uFlags, DUM_ORPHAN)) ids = IDS_MSG_MultiUptodateOrphan; else ids = IDS_MSG_MultiUptodate; } else if (IsFlagSet(uFlags, DUM_ORPHAN)) ids = IDS_MSG_MultiOrphans; else if (IsFlagSet(uFlags, DUM_UNAVAILABLE)) ids = IDS_MSG_MultiUnavailable; else if (IsFlagSet(uFlags, DUM_SUBFOLDER_TWIN)) ids = IDS_MSG_MultiSubfolder; else { ASSERT(0); // should never get here ids = (UINT)-1; } idRet = MsgBox(hwndOwner, MAKEINTRESOURCE(ids), MAKEINTRESOURCE(IDS_CAP_UPDATE), LoadIcon(g_hinst, MAKEINTRESOURCE(idi)), MB_INFO, cFiles); } } return idRet; } /*---------------------------------------------------------- Purpose: This function does some preliminary checks to determine whether the dialog box needs to be invoked at all. Sets the cOrphans and cSubfolders fields of pupdcount. Returns: standard result Cond: -- */ HRESULT PRIVATE PrepForUpdateAll( PCBS pcbs, PRECLIST * pprl, UPDCOUNT * pupdcount, HWND hwndProgress) { HRESULT hres = E_FAIL; TWINRESULT tr; HWND hwndOwner = GetParent(hwndProgress); BOOL bAnyTwins; pupdcount->cSubfolders = 0; // Are there any twins in the database? tr = Sync_AnyTwins(pcbs->hbrf, &bAnyTwins); if (TR_SUCCESS == tr) { if (FALSE == bAnyTwins) { // No DoUpdateMsg(hwndOwner, Atom_GetName(pcbs->atomBrf), 1, DUM_ALL | DUM_ORPHAN); hres = S_FALSE; } // Can we get a fresh reclist? else { pupdcount->cOrphans = 0; hres = Sync_CreateCompleteRecList(pcbs->hbrf, UpdBar_GetAbortEvt(hwndProgress), pprl); if (FAILED(hres)) { // No if (E_TR_ABORT != hres) { MsgBox(hwndOwner, MAKEINTRESOURCE(IDS_OOM_UPDATEDIALOG), MAKEINTRESOURCE(IDS_CAP_UPDATE), NULL, MB_ERROR); } } else { // Yes if (*pprl) { hres = S_OK; } else { hres = E_UNEXPECTED; } // (reclist is freed inFinishUpdate()) } } } return hres; } /*---------------------------------------------------------- Purpose: This function does some preliminary checks to determine whether the dialog box needs to be invoked at all. Sets the cOrphans and cSubfolders fields of pupdcount. Returns: standard result Cond: -- */ HRESULT PRIVATE PrepForUpdateSelection( PCBS pcbs, PRECLIST * pprl, LPCTSTR pszList, UINT cFiles, UPDCOUNT * pupdcount, HWND hwndProgress) { HRESULT hres; TWINRESULT tr; HTWINLIST htl; HWND hwndOwner = GetParent(hwndProgress); pupdcount->cSubfolders = 0; // Create a twin list tr = Sync_CreateTwinList(pcbs->hbrf, &htl); if (TR_SUCCESS != tr) { // Failure MsgBox(hwndOwner, MAKEINTRESOURCE(IDS_OOM_UPDATEDIALOG), MAKEINTRESOURCE(IDS_CAP_UPDATE), NULL, MB_ERROR); hres = E_OUTOFMEMORY; } else { LPCTSTR psz; UINT cOrphans = 0; UINT cSubfolders = 0; UINT i; for (i = 0, psz = pszList; i < cFiles; i++) { // Is this object really a twin? if (S_FALSE == Sync_IsTwin(pcbs->hbrf, psz, 0) ) { // No; is this a subfolder twin? if (IsSubfolderTwin(pcbs->hbrf, psz)) { // Yes cSubfolders++; } else { // No cOrphans++; } } else { // Yes; add it to the twin list Sync_AddPathToTwinList(pcbs->hbrf, htl, psz, NULL); } DataObj_NextFile(psz); // Set psz to next file in list } // Are all the selected objects orphans? if (cOrphans < cFiles) { // No; create the reclist hres = Sync_CreateRecListEx(htl, UpdBar_GetAbortEvt(hwndProgress), pprl); } else { // Yes DoUpdateMsg(hwndOwner, pszList, cFiles, DUM_SELECTION | DUM_ORPHAN); hres = S_FALSE; } pupdcount->cOrphans = cOrphans; pupdcount->cSubfolders = cSubfolders; Sync_DestroyTwinList(htl); // Don't need this anymore } return hres; } /*---------------------------------------------------------- Purpose: Checks for the special cases that are listed at the top of this file. Returns: PSC_ flags Cond: -- */ UINT PRIVATE PassedSpecialCases( HWND hwndOwner, LPCTSTR pszList, UPDCOUNT * pupdcount, UINT uFlags) // UF_ flags { UINT uRet = 0; UINT dum = 0; UINT cSomeAction = pupdcount->cDoSomething + pupdcount->cConflict; // Is this Update All? if (IsFlagSet(uFlags, UF_ALL)) { // Yes if (0 < pupdcount->cOrphans) { // Case A2 dum = DUM_ALL | DUM_ORPHAN; } else if (0 == pupdcount->cUnavailable) { if (0 == cSomeAction) { // Case A3 dum = DUM_ALL | DUM_UPTODATE; } else { // Case A4 uRet = PSC_SHOWDIALOG; } } else { // Cases A5 and A6 dum = DUM_ALL | DUM_UNAVAILABLE; uRet = PSC_SHOWDIALOG; } #ifdef DEBUG if (IsFlagSet(g_uDumpFlags, DF_UPDATECOUNT)) { TRACE_MSG(TF_ALWAYS, TEXT("Update All counts: files = %u, orphans = %u, unavailable = %u, dosomething = %u, conflict = %u, subfolders = %u"), pupdcount->cFiles, pupdcount->cOrphans, pupdcount->cUnavailable, pupdcount->cDoSomething, pupdcount->cConflict, pupdcount->cSubfolders); } #endif } else { // No; single selection? // Take caution in the comparisons below. The counts do not // have a 1-to-1 correspondence. They are split into two // groups: cFiles <---> cOrphans <---> cSubfolders // cUnavailable <---> cDoSomething // // This means comparing cFiles with cDoSomething or cUnavailable // will produce bogus results in the case when folders are // selected. // // As long as the comparisons below do not break these limits, // everything is okay. if (1 == pupdcount->cFiles) { // Yes ASSERT(2 > pupdcount->cOrphans); ASSERT(2 > pupdcount->cSubfolders); if (1 == pupdcount->cOrphans) { // Case S1 dum = DUM_SELECTION | DUM_ORPHAN; } else if (0 == pupdcount->cUnavailable) { if (0 == cSomeAction) { if (0 == pupdcount->cSubfolders) { // Case S2 dum = DUM_SELECTION | DUM_UPTODATE; } else { dum = DUM_SELECTION | DUM_SUBFOLDER_TWIN; } } else { // Case S3 uRet = PSC_SHOWDIALOG; } } else { // Case S4 dum = DUM_SELECTION | DUM_UNAVAILABLE; uRet = PSC_SHOWDIALOG; } } else { // No; this is a multi selection if (0 < pupdcount->cSubfolders) { DoUpdateMsg(hwndOwner, pszList, pupdcount->cSubfolders, DUM_SELECTION | DUM_SUBFOLDER_TWIN); goto Leave; // HACK } if (pupdcount->cFiles == pupdcount->cOrphans) { // Case S5 dum = DUM_SELECTION | DUM_ORPHAN; } else if (0 < pupdcount->cUnavailable) { if (0 < cSomeAction) { if (0 == pupdcount->cOrphans) { // Case S6 dum = DUM_SELECTION | DUM_UNAVAILABLE; uRet = PSC_SHOWDIALOG; } else { // Case S7 dum = DUM_SELECTION | DUM_UNAVAILABLE; uRet = PSC_SHOWDIALOG | PSC_POSTMSGBOX; } } else { if (0 == pupdcount->cOrphans) { // Case S8 dum = DUM_SELECTION | DUM_UNAVAILABLE; uRet = PSC_SHOWDIALOG; } else { // Case S9 dum = DUM_SELECTION | DUM_UNAVAILABLE; uRet = PSC_SHOWDIALOG | PSC_POSTMSGBOX; } } } else { if (0 < cSomeAction) { if (0 == pupdcount->cOrphans) { // Case S10 uRet = PSC_SHOWDIALOG; } else { // Case S11 uRet = PSC_SHOWDIALOG | PSC_POSTMSGBOX; } } else { if (0 == pupdcount->cOrphans) { // Case S12 dum = DUM_SELECTION | DUM_UPTODATE; } else { // Case S13 dum = DUM_SELECTION | DUM_UPTODATE | DUM_ORPHAN; } } } } Leave: ; #ifdef DEBUG if (IsFlagSet(g_uDumpFlags, DF_UPDATECOUNT)) { TRACE_MSG(TF_ALWAYS, TEXT("Update selection counts: files = %u, orphans = %u, unavailable = %u, dosomething = %u, conflict = %u, subfolders = %u"), pupdcount->cFiles, pupdcount->cOrphans, pupdcount->cUnavailable, pupdcount->cDoSomething, pupdcount->cConflict, pupdcount->cSubfolders); } #endif } if (0 != dum) { DoUpdateMsg(hwndOwner, pszList, pupdcount->cFiles, dum); } return uRet; } /*---------------------------------------------------------- Purpose: Show the update dialog and perform the reconcilation if the user chooses OK Returns: standard result Cond: -- */ HRESULT PUBLIC Upd_DoModal( HWND hwndOwner, CBS * pcbs, LPCTSTR pszList, // May be NULL if uFlags == UF_ALL UINT cFiles, UINT uFlags) { INT_PTR nRet; HRESULT hres; PRECLIST prl; UPDCOUNT updcount; HWND hwndProgress; hwndProgress = UpdBar_Show(hwndOwner, UB_CHECKING, DELAY_UPDBAR); // Get a reclist and other useful information updcount.cFiles = cFiles; if (IsFlagSet(uFlags, UF_ALL)) { hres = PrepForUpdateAll(pcbs, &prl, &updcount, hwndProgress); } else { hres = PrepForUpdateSelection(pcbs, &prl, pszList, cFiles, &updcount, hwndProgress); } UpdBar_Kill(hwndProgress); if (S_OK == GetScode(hres)) { XUPDSTRUCT xupd; xupd.lprl = prl; xupd.pcbs = pcbs; xupd.uFlags = uFlags; xupd.hdpa = ComposeUpdateList(pcbs, prl, &updcount, hwndOwner); xupd.cDoSomething = updcount.cDoSomething; if (NULL == xupd.hdpa) { hres = E_OUTOFMEMORY; MsgBox(hwndOwner, MAKEINTRESOURCE(IDS_OOM_UPDATEDIALOG), MAKEINTRESOURCE(IDS_CAP_UPDATE), NULL, MB_ERROR); } else { // Check for some of those special cases listed at top of file UINT uVal = PassedSpecialCases(hwndOwner, pszList, &updcount, uFlags); // Show the update dialog? if (IsFlagSet(uVal, PSC_SHOWDIALOG)) { // Yes nRet = DoModal(hwndOwner, Upd_WrapperProc, IDD_UPDATE, (LPARAM)&xupd); switch (nRet) { case IDOK: // Reconcile! hwndProgress = UpdBar_Show(hwndOwner, UB_UPDATING, 0); Sync_ReconcileRecList(prl, Atom_GetName(pcbs->atomBrf), hwndProgress, RF_DEFAULT); UpdBar_Kill(hwndProgress); // Show a summary messagebox? if (IsFlagSet(uVal, PSC_POSTMSGBOX)) { // Yes DoUpdateMsg(hwndOwner, pszList, updcount.cOrphans, DUM_SELECTION | DUM_ORPHAN); } // Fall thru // | | // v v case IDCANCEL: hres = NOERROR; break; case -1: MsgBox(hwndOwner, MAKEINTRESOURCE(IDS_OOM_UPDATEDIALOG), MAKEINTRESOURCE(IDS_CAP_UPDATE), NULL, MB_ERROR); hres = E_OUTOFMEMORY; break; default: ASSERT(0); break; } } DPA_Destroy(xupd.hdpa); } Sync_DestroyRecList(prl); } return hres; }