
/*
 *@@sourcefile xfobj.c:
 *      This file contains the following major XFolder parts:
 *
 *      --  XFldObject SOM stuff
 *
 *      Check the other files starting with xf* for the
 *      other XFolder classes.
 *
 *      XFldObject gives the other classes access to WPS
 *      internals that cannot be reached otherwise. It
 *      also initializes the whole XFolder environment
 *      at WPS bootup by overriding M_XFldObject::wpclsInitData.
 *
 *      This class must always be installed.
 *
 *@@somclass XFldObject xfobj_
 *@@somclass M_XFldObject xfobjM_
 */

/*
 *      Copyright (C) 1997-99 Ulrich M”ller.
 *      This file is part of the XFolder source package.
 *      XFolder 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, in version 2 as it comes in the
 *      "COPYING" file of the XFolder main distribution.
 *      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.
 */

/*
 *  This file was generated by the SOM Compiler and Emitter Framework.
 *  Generated using:
 *      SOM Emitter emitctm: 2.42
 */

#ifndef SOM_Module_xfobj_Source
#define SOM_Module_xfobj_Source
#endif
#define XFldObject_Class_Source
#define M_XFldObject_Class_Source

/*
 *  Suggested #include order:
 *  1)  os2.h
 *  2)  C library headers
 *  3)  SOM headers which work with precompiled header files
 *  4)  headers in /helpers
 *  5)  headers in /main with dlgids.h and common.h first
 *  6)  #pragma hdrstop to prevent VAC++ crashes
 *  7)  other needed SOM headers
 *  8)  for non-SOM-class files: corresponding header (e.g. classlst.h)
 */

#define INCL_DOSFILEMGR
#define INCL_DOSMODULEMGR
#define INCL_DOSPROCESS         // DosSleep, priorities, PIDs etc.
#define INCL_DOSSEMAPHORES      // needed for xthreads.h
#define INCL_DOSEXCEPTIONS
#define INCL_DOSERRORS

#define INCL_WINWINDOWMGR
#define INCL_WINPROGRAMLIST     // needed for WPProgram
#define INCL_WINFRAMEMGR        // WM_FORMATFRAME, SC_CLOSE etc.
#define INCL_WINSYS             // presparams, WinQuerySysValue()
#define INCL_WINCOUNTRY         // WinCompareStrings, WinUpper
#define INCL_WINPOINTERS

#define INCL_WINSHELLDATA       // profile funcs
#define INCL_WINTIMER
#define INCL_WINCLIPBOARD
#define INCL_WININPUT           // WinQueryFocus etc.

#define INCL_WINDIALOGS
#define INCL_WINMENUS           // needed for menus.h
#define INCL_WINENTRYFIELDS
#define INCL_WINBUTTONS
#define INCL_WINSTDBOOK         // notebooks
#define INCL_WINSTDCNR          // needed for winh.h

#include <os2.h>

// C library headers
#include <stdio.h>
#include <malloc.h>

// headers in /helpers
#include "dosh.h"               // Control Program helper routines
#include "winh.h"               // PM helper routines

#include "linklist.h"           // linked list helper routines
#include "procstat.h"           // DosQProcStat handling
#include "stringh.h"            // string helper routines
#include "undoc.h"              // some undocumented stuff
#include "wphandle.h"           // Henk Kelder's HOBJECT handling

// SOM headers which don't crash with prec. header files
#pragma hdrstop                 // VAC++ keeps crashing otherwise
#include "xfobj.ih"

// headers in /main
#include "dlgids.h"             // all the IDs that are shared with NLS
#include "common.h"             // the majestic XFolder include file

#include "classlst.h"           // SOM logic for "WPS Classes" page
#include "cnrsort.h"            // container sort comparison functions
#include "xthreads.h"           // XFolder threads; this includes threads.h

// other SOM headers
#include "xfldr.h"              // needed for XFolder SOM methods
#include "xfpgmf.ih"
#include <wpdesk.h>             // WPDesktop
#include <wpshadow.h>

#include "xwps.h"               // XFolder pseudo SOM functions

/*
 * Global variables::
 *
 */

VOID FillCnrWithObjectUsage(HWND hwndCnr, WPObject *pObject);
MRESULT EXPENTRY fnwpObjectUsage(HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2);

/*
 * XFOBJWINDATA:
 *      structure for data exchange with XFolder instance data.
 *      Created in WM_INITDLG.
 */

typedef struct _XFOBJWINDATA
{
    SOMAny          *somSelf;
    CHAR            szOldID[CCHMAXPATH];
    HWND            hwndCnr;
    CHAR            szOldObjectID[256];
    BOOL            fEscPressed;
    PRECORDCORE     preccExpanded;
} XFOBJWINDATA, *PXFOBJWINDATA;

/*
 * fnwpSettingsObjDetails:
 *      notebook dlg func for XFldObject "Details" page.
 *      Here's a trick how to interface the corresponding
 *      SOM (WPS) object from within this procedure:
 *      1)  declare a structure with all the data which is
 *          needed in this wnd proc (see XFOBJWINDATA below)
 *      2)  when inserting the notebook page, specify
 *          somSelf as the pCreateParams parameter in the
 *          PAGEINFO structure;
 *      3)  somSelf is then passed in mp2 of WM_INITDLG;
 *          with that message, we create our structure on
 *          the heap and store the address to it in the
 *          notebook's window words. We can then access
 *          our structure from later messages too.
 *      4)  Don't forget to free the structure at WM_DESTROY.
 *
 *@@changed 0.85 fixed object ID error message
 */

MRESULT EXPENTRY fnwpSettingsObjDetails(HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2)
{
    PXFOBJWINDATA   pWinData = (PXFOBJWINDATA)WinQueryWindowULong(hwndDlg, QWL_USER);
    MRESULT         mrc = FALSE;

    switch(msg)
    {
        case WM_INITDLG: {
            // we need to initialize SOM stuff to be able to
            // access instance variables later
            PSZ     pszObjectID;
            CNRINFO CnrInfo;
            pWinData = (PXFOBJWINDATA)_wpAllocMem((SOMAny*)mp2, sizeof(XFOBJWINDATA), NULL);
            WinSetWindowPtr(hwndDlg, QWL_USER, pWinData);

            // somSelf is given to us in mp2 (see pCreateParams
            // in XFldObject::xfAddObjectInternalsPage below)
            pWinData->somSelf     = (SOMAny*)mp2;
            // initialize the fields in the structure
            pszObjectID = _wpQueryObjectID(pWinData->somSelf);
            if (pszObjectID)
                strcpy(pWinData->szOldID, pszObjectID);
            else
                strcpy(pWinData->szOldID, "");

            // make Warp 4 notebook buttons and move controls
            winhAssertWarp4Notebook(hwndDlg,
                    100,         // ID threshold
                    WARP4_NOTEBOOK_OFFSET);   // move other controls offset (common.h)

            // setup container
            pWinData->hwndCnr = WinWindowFromID(hwndDlg, ID_XSDI_DTL_CNR);
            WinSendMsg(pWinData->hwndCnr, CM_QUERYCNRINFO,
                        &CnrInfo, (MPARAM)sizeof(CnrInfo));
            CnrInfo.pSortRecord = (PVOID)fnCompareName;
            CnrInfo.flWindowAttr = CV_TREE | CV_TEXT | CA_TREELINE;
            CnrInfo.cxTreeIndent = 30;
            WinSendMsg(pWinData->hwndCnr, CM_SETCNRINFO,
                    &CnrInfo,
                    (MPARAM)(CMA_PSORTRECORD | CMA_FLWINDOWATTR | CMA_CXTREEINDENT));

            WinPostMsg(hwndDlg, WM_SETTINGS2DLG, 0, 0);

            mrc = WinDefDlgProc(hwndDlg, msg, mp1, mp2);
        break; }

        case WM_SETTINGS2DLG: {
            HPOINTER hptrOld = WinQueryPointer(HWND_DESKTOP);
            WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, FALSE));
            FillCnrWithObjectUsage(pWinData->hwndCnr, pWinData->somSelf);
            WinSetPointer(HWND_DESKTOP, hptrOld);
        }   // continue, no break

        case WM_ENABLEITEMS:
        break;

        case WM_DLG2SETTINGS: {
        break; }

        /*
         * WM_TIMER:
         *      timer for tree view auto-scroll
         */

        case WM_TIMER: {
            if ( ( pWinData->preccExpanded->flRecordAttr & CRA_EXPANDED) != 0 ) {
                PRECORDCORE     preccLastChild;
                WinStopTimer(WinQueryAnchorBlock(hwndDlg),
                        hwndDlg,
                        1);
                // scroll the tree view properly
                preccLastChild = WinSendMsg(pWinData->hwndCnr,
                        CM_QUERYRECORD,
                        pWinData->preccExpanded,   // expanded PRECORDCORE from CN_EXPANDTREE
                    MPFROM2SHORT(CMA_LASTCHILD, CMA_ITEMORDER));
                if (preccLastChild) {
                    // ULONG ulrc;
                    winhCnrScrollToRecord(pWinData->hwndCnr,
                            (PRECORDCORE)preccLastChild,
                            CMA_TEXT,   // record text rectangle only
                            TRUE);      // keep parent visible
                }
            }
        }

        /*
         * WM_CONTROL:
         *
         */

        case WM_CONTROL:
        {
            if (SHORT1FROMMP(mp1) == ID_XSDI_DTL_CNR)
                switch (SHORT2FROMMP(mp1)) {

                    /*
                     * CN_EXPANDTREE:
                     *      do tree-view auto scroll
                     */

                    case CN_EXPANDTREE: {
                        PGLOBALSETTINGS pGlobalSettings = cmnQueryGlobalSettings();
                        mrc = WinDefDlgProc(hwndDlg, msg, mp1, mp2);
                        if (pGlobalSettings->TreeViewAutoScroll) {
                            pWinData->preccExpanded = (PRECORDCORE)mp2;
                            WinStartTimer(WinQueryAnchorBlock(hwndDlg),
                                    hwndDlg,
                                    1,
                                    100);
                        }
                    break; }

                    /*
                     * CN_BEGINEDIT:
                     *      when user alt-clicked on a recc
                     */

                    case CN_BEGINEDIT: {
                        pWinData->fEscPressed = TRUE;
                        mrc = (MPARAM)0;
                    break;}

                    /*
                     * CN_REALLOCPSZ:
                     *      just before the edit MLE is closed
                     */

                    case CN_REALLOCPSZ: {
                        PCNREDITDATA pced = (PCNREDITDATA)mp2;
                        PSZ pszChanging = *(pced->ppszText);
                        strcpy(pWinData->szOldObjectID, pszChanging);
                        pWinData->fEscPressed = FALSE;
                        mrc = (MPARAM)TRUE;
                    break; }

                    /*
                     * CN_ENDEDIT:
                     *      recc text changed: update our data
                     */

                    case CN_ENDEDIT: {
                        if (!pWinData->fEscPressed) {
                            PCNREDITDATA pced = (PCNREDITDATA)mp2;
                            PSZ pszNew = *(pced->ppszText);
                            BOOL fChange = FALSE;
                            // has the object ID changed?
                            if (strcmp(pWinData->szOldObjectID, pszNew) != 0)
                            {
                                // is this a valid object ID?
                                if (    (pszNew[0] != '<')
                                     || (*(pszNew + strlen(pszNew)-1) != '>')
                                   )
                                    cmnMessageBoxMsg(hwndDlg, 104, 108, MB_OK);
                                        // fixed (V0.85)
                                else
                                    // valid: confirm change
                                    if (cmnMessageBoxMsg(hwndDlg, 107, 109, MB_YESNO) == MBID_YES)
                                        fChange = TRUE;

                                if (fChange)
                                    _wpSetObjectID(pWinData->somSelf, pszNew);
                                else
                                {
                                    // change aborted: restore old recc text
                                    strcpy(((POBJECTUSAGERECORDCORE)(pced->pRecord))->szText,
                                            pWinData->szOldObjectID);
                                    WinSendMsg(pWinData->hwndCnr, CM_INVALIDATERECORD,
                                        (MPARAM)pced->pRecord,
                                        MPFROM2SHORT(1, CMA_TEXTCHANGED));
                                }
                            }
                        }
                        mrc = (MPARAM)0;
                    break; }

                    default:
                        mrc = WinDefDlgProc(hwndDlg, msg, mp1, mp2);
                    } // end switch
            else
                mrc = WinDefDlgProc(hwndDlg, msg, mp1, mp2);
        break; } // end of WM_CONTROL

        case WM_COMMAND: {
            switch (SHORT1FROMMP(mp1))
            {
                case DID_REFRESH: { // "Refresh" button
                    HPOINTER hptrOld = WinQueryPointer(HWND_DESKTOP);
                    WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, FALSE));
                    WinSendMsg(pWinData->hwndCnr,
                            CM_REMOVERECORD,
                            NULL,
                            MPFROM2SHORT(0, // remove all reccs
                                    CMA_FREE));
                    FillCnrWithObjectUsage(pWinData->hwndCnr, pWinData->somSelf);
                    WinSetPointer(HWND_DESKTOP, hptrOld);
                break; }
            }
        break; } // end of WM_COMMAND

        case WM_HELP: {
            PSZ pszHelpLibrary = cmnQueryHelpLibrary();
            // always display help for the whole page, not for single items
            if (!_wpDisplayHelp(pWinData->somSelf,
                    ID_XSH_SETTINGS_OBJINTERNALS,
                    pszHelpLibrary))
            {
                cmnMessageBoxMsg(HWND_DESKTOP, 104, 134, MB_OK);
            }
        break; }

        default:
            mrc = WinDefDlgProc(hwndDlg, msg, mp1, mp2);
    }

    return (mrc);
}

/* ******************************************************************
 *                                                                  *
 *   here come the XFldObject instance methods                      *
 *                                                                  *
 ********************************************************************/

/*
 *@@ xfAddObjectInternalsPage:
 *           this actually adds the "Internals" pages into all object notebooks,
 *           if the Global Settings allow it
 */

SOM_Scope ULONG  SOMLINK xfobj_xfAddObjectInternalsPage(XFldObject *somSelf,
                                                            HWND hwndNotebook)
{
    PAGEINFO pi;
    PSZ pszHelpLibrary = cmnQueryHelpLibrary();

    /* XFldObjectData *somThis = XFldObjectGetData(somSelf); */
    XFldObjectMethodDebug("XFldObject","xfobj_xfAddObjectInternalsPages");

    // insert Shutdown settings page
    memset((PCH)&pi, 0, sizeof(PAGEINFO));
    pi.cb                  = sizeof(PAGEINFO);
    pi.hwndPage            = NULLHANDLE;
    pi.pfnwp               = fnwpSettingsObjDetails;
    pi.resid               = NLS_MODULE;
    pi.pCreateParams       = somSelf;
                // passed to fnwpSettingsObjDetails in mp2
    pi.dlgid               = ID_XSD_OBJECTDETAILS;
    pi.usPageStyleFlags    = BKA_STATUSTEXTON | BKA_MAJOR;   // major tab;
    pi.usPageInsertFlags   = BKA_FIRST;
    pi.usSettingsFlags     = 0; // don't enumerate in status line
    pi.pszName             = cmnQueryNLSStrings()->pszInternals;

    pi.pszHelpLibraryName  = pszHelpLibrary;
    pi.idDefaultHelpPanel  = ID_XSH_SETTINGS_OBJINTERNALS;

    return (_wpInsertSettingsPage(somSelf, hwndNotebook, &pi));
}

/*
 *@@ wpObjectReady:
 *           this instance method is called by the system when
 *           object awakening is complete and object data seems
 *           to be stable in memory;
 *           we will have this object's pointer stored
 *           in a global list (maintained by the Worker thread)
 *           so that XShutdown knows which objects are currently awake
 */

/*
 *@@ wpObjectReady:
 *           this instance method is called by the system when
 *           object awakening is complete and object data seems
 *           to be stable in memory.
 *           We will have this object's pointer stored
 *           in a global list (maintained by the Worker thread)
 *           so that XShutdown knows which objects are currently awake.
 */

SOM_Scope void  SOMLINK xfobj_wpObjectReady(XFldObject *somSelf,
                                              ULONG ulCode, WPObject* refObject)
{
    // XFldObjectData *somThis = XFldObjectGetData(somSelf);
    XFldObjectMethodDebug("XFldObject","xfobj_wpObjectReady");

    XFldObject_parent_WPObject_wpObjectReady(somSelf, ulCode,
                                             refObject);

    /* if (    (_somIsA(somSelf, _WPFolder))
         || (_somIsA(somSelf, _WPAbstract))
       ) */
    {
        xthrPostWorkerMsg(WOM_ADDAWAKEOBJECT,
                (MPARAM)somSelf,
                MPNULL);
        // _fAddedToAwakeList = TRUE;
    } /* else
        _fAddedToAwakeList = FALSE; */
}

/*
 *@@ wpUnInitData:
 *           reverse to wpInitData, this instance method is
 *           called by the system when an object is made
 *           dormant; we will have this object removed from our
 *           global list of awake objects
 */

/*
 *@@ wpUnInitData:
 *           reverse to XFldObject::wpObjectReady, this instance
 *           method is called by the system when an object is made
 *           dormant. We will have this object removed from our
 *           global list of awake objects.
 */

SOM_Scope void  SOMLINK xfobj_wpUnInitData(XFldObject *somSelf)
{
    // XFldObjectData *somThis = XFldObjectGetData(somSelf);
    XFldObjectMethodDebug("XFldObject","xfobj_wpUnInitData");

    // if (_fAddedToAwakeList)
        xthrPostWorkerMsg(WOM_REMOVEAWAKEOBJECT,
                (MPARAM)somSelf,
                MPNULL);

    XFldObject_parent_WPObject_wpUnInitData(somSelf);
}

/*
 *@@ wpFilterPopupMenu:
 *           remove default entries according to global settings
 */

/*
 *@@ wpFilterPopupMenu:
 *           remove default entries according to global settings.
 */

SOM_Scope ULONG  SOMLINK xfobj_wpFilterPopupMenu(XFldObject *somSelf,
                                                   ULONG ulFlags,
                                                   HWND hwndCnr,
                                                   BOOL fMultiSelect)
{
    ULONG ulMenuFilter = 0;
    PGLOBALSETTINGS pGlobalSettings = cmnQueryGlobalSettings();
    // XFldObjectData *somThis = XFldObjectGetData(somSelf);
    XFldObjectMethodDebug("XFldObject","xfobj_wpFilterPopupMenu");

    ulMenuFilter = XFldObject_parent_WPObject_wpFilterPopupMenu(somSelf,
                                                         ulFlags,
                                                         hwndCnr,
                                                         fMultiSelect);
    #ifdef DEBUG_MENUS
        _Pmpf(("XFldObject::wpFilterPopupMenu: ulMenuFilter & CTXT_CRANOTHER: 0x%lX %d",
                ulMenuFilter, ((ulMenuFilter) & CTXT_CRANOTHER)));
    #endif

    // now suppress default menu items according to
    // Global Settings;
    // the DefaultMenuItems field in pGlobalSettings is
    // ready-made for this function; the "Workplace Shell"
    // notebook page for removing menu items sets this field with
    // the proper CTXT_xxx flags
    return ((ulMenuFilter
            // first we add "Create another", because for
            // some reason it's always disabled if XFolder
            // is installed; I don't know why
            | CTXT_CRANOTHER )
            // then disable items, this may include CTXT_CRANOTHER
            & ~(pGlobalSettings->DefaultMenuItems)
        );
}

/*
 *@@ wpModifyPopupMenu:
 *           add my own popup menu entries
 */

/*
 *@@ wpModifyPopupMenu:
 *           add my own popup menu entries.
 */

SOM_Scope BOOL  SOMLINK xfobj_wpModifyPopupMenu(XFldObject *somSelf,
                                                  HWND hwndMenu,
                                                  HWND hwndCnr,
                                                  ULONG iPosition)
{
    HWND        hwndSettingsMenu;
    BOOL        rc;
    MENUITEM    mi;
    PGLOBALSETTINGS pGlobalSettings = cmnQueryGlobalSettings();
    PNLSSTRINGS pNLSStrings = cmnQueryNLSStrings();
    // XFldObjectData *somThis = XFldObjectGetData(somSelf);
    XFldObjectMethodDebug("XFldObject","xfobj_wpModifyPopupMenu");

    rc = (XFldObject_parent_WPObject_wpModifyPopupMenu(somSelf,
                                                         hwndMenu,
                                                         hwndCnr,
                                                         iPosition));
    if (pGlobalSettings->RemoveLockInPlaceItem) {
        // first we need a handle to the WPObject's "Lock in place"
        // submenu in the the folder's popup menu

        WinSendMsg(hwndMenu, MM_REMOVEITEM,
            MPFROM2SHORT(ID_WPM_LOCKINPLACE, FALSE),
            0);
    }

    return rc;
}

/*
 *@@ wpMenuItemSelected:
 *           process input when any menu item was selected
 */

/*
 *@@ wpMenuItemSelected:
 *           process input when any menu item was selected.
 */

SOM_Scope BOOL  SOMLINK xfobj_wpMenuItemSelected(XFldObject *somSelf,
                                                   HWND hwndFrame,
                                                   ULONG ulMenuId)
{
    PGLOBALSETTINGS     pGlobalSettings = cmnQueryGlobalSettings();
    BOOL                brc = FALSE;

    // XFldObjectData *somThis = XFldObjectGetData(somSelf);
    XFldObjectMethodDebug("XFldObject","xfobj_wpMenuItemSelected");

    switch (ulMenuId) {
        #ifdef DEBUG_CONTEXT
        case ID_XFMI_RECORDCORE: {
            int                 i;
            CHAR                szMsg[1024] = "No record core.",
                                szTitle[1024],
                                szBuf[20] = "0x00000000";
            PMINIRECORDCORE     pMRC = _wpQueryCoreRecord(somSelf);
            PCLASSFIELDINFO     pCFI, pCFI2;
            ULONG               ulCFISize = 0, ulErr;

            strcpy(szTitle, "Record core for ");
            strcat(szTitle, _wpQueryTitle(somSelf));

            strcpy(szMsg, "Size of core record (cb): ");
            UL2H(szBuf+2, pMRC->cb);
            strcat(szMsg, szBuf);

            strcat(szMsg, "\nSize of MINIRECORDCORE:   ");
            UL2H(szBuf+2, sizeof(MINIRECORDCORE));
            strcat(szMsg, szBuf);

            strcat(szMsg, "\nSize of RECORDCORE:       ");
            UL2H(szBuf+2, sizeof(RECORDCORE));
            strcat(szMsg, szBuf);

            strcat(szMsg, "\nNext record:              ");
            UL2H(szBuf+2, (ULONG)pMRC->preccNextRecord);
            strcat(szMsg, szBuf);

            strcat(szMsg, "\nIcon X pos:               ");
            UL2H(szBuf+2, pMRC->ptlIcon.x);
            strcat(szMsg, szBuf);

            strcat(szMsg, "\nIcon Y pos:               ");
            UL2H(szBuf+2, pMRC->ptlIcon.y);
            strcat(szMsg, szBuf);

            strcat(szMsg, "\n\nDetails CLASSFIELDINFO:");

            strcat(szMsg, "\nSize of structure:        ");
            _wpQueryDetailsData(somSelf, NULL, &ulCFISize);
            UL2H(szBuf+2, ulCFISize);
            strcat(szMsg, szBuf);

            pCFI = (PCLASSFIELDINFO)_wpAllocMem(somSelf, ulCFISize, &ulErr);
            pCFI2 = pCFI;
            _wpQueryDetailsData(somSelf, (PVOID)&pCFI2, &ulCFISize);

            _wpFreeMem(somSelf, (PVOID)pCFI);

            DebugBox(szTitle, szMsg);

            brc = TRUE;
        break; }

        case ID_XFMI_SHOWFOLDERDATA: {
            xthrPostWorkerMsg(WM_SHOWFOLDERDATA,
                (MPARAM)somSelf,
                MPNULL);
            brc = TRUE;
        break; }
        #endif

        default:
            brc = XFldObject_parent_WPObject_wpMenuItemSelected(somSelf,
                                                          hwndFrame,
                                                          ulMenuId);
    }

    return (brc);
}

/*
 *@@ wpAddSettingsPages:
 *           this instance method inserts all the settings
 *           pages into an object's settings notebook.
 *           We will add the object's "Internals" page here.
 */

SOM_Scope BOOL  SOMLINK xfobj_wpAddSettingsPages(XFldObject *somSelf,
                                                 HWND hwndNotebook)
{
    PGLOBALSETTINGS     pGlobalSettings = cmnQueryGlobalSettings();
    // XFldObjectData *somThis = XFldObjectGetData(somSelf);
    XFldObjectMethodDebug("XFldObject","xfobj_wpAddSettingsPages");

    if (pGlobalSettings->ShowInternals)
        _xfAddObjectInternalsPage(somSelf, hwndNotebook);

    return (XFldObject_parent_WPObject_wpAddSettingsPages(somSelf,
                                                          hwndNotebook));
}

/*
 *@@ fnwpTitleClashDlg:
 *      dlg proc for the "File exists" dialog.
 *      Most of the logic for that dialog is in the
 *      XFldObject::wpConfirmObjectTitle method actually; this
 *      function is only responsible for adjusting the dialog items'
 *      keyboard focus and such.
 */

MRESULT EXPENTRY fnwpTitleClashDlg(HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2)
{
    #define WM_DELAYEDFOCUS WM_USER+1
    MRESULT mrc = (MRESULT)0;

    switch (msg) {

        /*
         * WM_CONTROL:
         *      intercept focus messages and
         *      set focus to what we really want
         */

        case WM_CONTROL: {
            switch (SHORT2FROMMP(mp1)) // usNotifyCode
            {
                case EN_SETFOCUS: {
                // == BN_CLICKED
                    if (SHORT1FROMMP(mp1) == ID_XFDI_CLASH_RENAMENEWTXT) {
                        winhSetDlgItemChecked(hwndDlg, ID_XFDI_CLASH_RENAMENEW, TRUE);
                    } else if (SHORT1FROMMP(mp1) == ID_XFDI_CLASH_RENAMEOLDTXT) {
                        winhSetDlgItemChecked(hwndDlg, ID_XFDI_CLASH_RENAMEOLD, TRUE);
                    } else if (SHORT1FROMMP(mp1) == ID_XFDI_CLASH_RENAMENEW) {
                        WinPostMsg(hwndDlg, WM_DELAYEDFOCUS,
                            (MPARAM)ID_XFDI_CLASH_RENAMENEWTXT, MPNULL);
                    } else if (SHORT1FROMMP(mp1) == ID_XFDI_CLASH_RENAMEOLD) {
                        WinPostMsg(hwndDlg, WM_DELAYEDFOCUS,
                            (MPARAM)ID_XFDI_CLASH_RENAMEOLDTXT, MPNULL);
                    }
                }
            }
        break; }

        case WM_DELAYEDFOCUS: {
            winhSetDlgItemFocus(hwndDlg, (HWND)mp1);
        break; }

        /*
         * WM_COMMAND:
         *      intercept "OK"/"Cancel" buttons
         */

        case WM_COMMAND: {
            mrc = (MRESULT)0;
            switch ((ULONG)mp1)
            {
                case DID_OK: {
                    ULONG ulSelection = DID_CANCEL,
                          ulLastFocusID = 0;
                    CHAR szLastFocusID[20] = "";
                    if (winhIsDlgItemChecked(hwndDlg, ID_XFDI_CLASH_RENAMENEW)) {
                        ulSelection = ID_XFDI_CLASH_RENAMENEW;
                        ulLastFocusID = ID_XFDI_CLASH_RENAMENEWTXT;
                    } else if (winhIsDlgItemChecked(hwndDlg, ID_XFDI_CLASH_RENAMEOLD)) {
                        ulSelection = ID_XFDI_CLASH_RENAMEOLD;
                        ulLastFocusID = ID_XFDI_CLASH_RENAMEOLDTXT;
                    } else {
                        ulSelection = ID_XFDI_CLASH_REPLACE;
                        ulLastFocusID = ID_XFDI_CLASH_REPLACE;
                    }

                    // store focus
                    sprintf(szLastFocusID, "%d",
                            ulLastFocusID);
                    PrfWriteProfileString(HINI_USER, INIAPP_XFOLDER,
                                INIKEY_NAMECLASHFOCUS,
                                szLastFocusID);
                    // store window pos
                    winhSaveWindowPos(hwndDlg,
                                HINI_USER,
                                INIAPP_XFOLDER, INIKEY_WNDPOSNAMECLASH);
                    WinDismissDlg(hwndDlg, ulSelection);
                break; }

                case DID_CANCEL:
                    WinDismissDlg(hwndDlg, DID_CANCEL);
                break;
            }
        break; }

        case WM_HELP: {
            WPObject    *pHelpSomSelf = _wpclsQueryActiveDesktop(_WPDesktop);
            if (pHelpSomSelf) {
                PSZ pszHelpLibrary;
                BOOL fProcessed = FALSE;
                if (pszHelpLibrary = cmnQueryHelpLibrary())
                    // path found: display help panel
                    if (_wpDisplayHelp(pHelpSomSelf, ID_XFH_TITLECLASH, pszHelpLibrary))
                        fProcessed = TRUE;

                if (!fProcessed)
                    cmnMessageBoxMsg(HWND_DESKTOP, 104, 134, MB_OK);
            }
        break; }

        default:
            mrc = WinDefDlgProc(hwndDlg, msg, mp1, mp2);
    }

    return (mrc);
}

// the return codes are only #define'd in the Warp 4 Toolkit,
// so we might need to define them here:
#ifndef NAMECLASH_CANCEL
    #define NAMECLASH_CANCEL    0
#endif
#ifndef NAMECLASH_NONE
    #define NAMECLASH_NONE      1
#endif
#ifndef NAMECLASH_RENAME
    #define NAMECLASH_RENAME    2
#endif
#ifndef NAMECLASH_REPLACE
    #define NAMECLASH_REPLACE   8
#endif

/*
 *@@ wpConfirmObjectTitle:
 *           this instance method is called by the WPS during file
 *           operations (copy, move, rename etc.) for every single
 *           file that is being processed. This method must verify
 *           that the operation is valid WRT name clashes and display
 *           a confirmation dialog in case it is not.
 *           Apparently, this method is not overridden by subclasses,
 *           not even WPFileSystem.
 *           XFolder implements its own "Object exists" dialog here,
 *           if the Global Settings allow it.
 *           Like most interesting methods in the WPS, this thing is
 *           barely documented, so this is what I found out.
 *
 *           Parameters:
 *           -- *somSelf      in: the object being worked on
 *           -- *Folder       in: the folder being worked on
 *           -- **ppDuplicate out: if we return NAMECLASH_REPLACE,
 *                            we need to set this to the object to
 *                            be replaced
 *           -- pszTitle      out: if we return NAMECLASH_RENAME,
 *                            we need to set this to somSelf's new title
 *           -- cbTitle       in: sizeof(*pszTitle)
 *           -- menuID        in: the user's operation, which is:
 *                              0x006B    move
 *                              0x006C    copy
 *                              0x006E    rename
 *                              0x013C    create shadow
 *
 *           Returns:
 *           -- NAMECLASH_CANCEL (0):
 *                  abort processing, have the WPS do nothing ("Cancel"
 *                  button pressed in confirmation dialog); this will
 *                  just skip the current file;
 *           -- NAMECLASH_NONE (1):
 *                  continue processing, but perform no further
 *                  renaming etc.; we return this if no duplicate file
 *                  exists;
 *           -- NAMECLASH_RENAME (2):
 *                  have the WPS change the title to pszTitle, which we
 *                  need to set here; note that this does NOT change
 *                  the real name! So we do the renaming ourselves here;
 *           -- NAMECLASH_REPLACE (8):
 *                  have the WPS delete *ppDuplicate, which we need to
 *                  set here if we return this code; we need to find the
 *                  duplicate in this method then.
 */

SOM_Scope ULONG  SOMLINK xfobj_wpConfirmObjectTitle(XFldObject *somSelf,
                                                    WPFolder* Folder,
                                                    WPObject** ppDuplicate,
                                                    PSZ pszTitle,
                                                    ULONG cbTitle,
                                                    ULONG menuID)
{
    ULONG ulrc = NAMECLASH_NONE;

    PGLOBALSETTINGS pGlobalSettings = cmnQueryGlobalSettings();

    // XFldObjectData *somThis = XFldObjectGetData(somSelf);
    XFldObjectMethodDebug("XFldObject","xfobj_wpConfirmObjectTitle");

    #ifdef DEBUG_TITLECLASH
    {
        CHAR szFolder2[CCHMAXPATH];
        _Pmpf(("Entering wpConfirmObjectTitle"));
        _Pmpf(("  somSelf == 0x%lX", somSelf));
        _Pmpf(("    pszTitle: %s", pszTitle));
        _wpQueryFilename(_wpQueryFolder(somSelf), szFolder2, TRUE);
        _Pmpf(("    in folder: %s", szFolder2));
        _Pmpf(("  menuID: 0x%lX", menuID));
    }
    #endif

    // first of all, check whether the confirmation
    // dialogs have been replaced in the global settings;
    // if not, we call the default method
    if (pGlobalSettings->ReplConfirms)
    {
        // nameclashs are only a problem for file-system objects,
        // and only if we're not creating shadows
        if (    (_somIsA(somSelf, _WPFileSystem))
             && (menuID != 0x13C) // "create shadow" code
           )
        {
            WPFileSystem *pobjExisting = NULL;
            CHAR szNewRealName[CCHMAXPATH],
                 szTemp[600],
                 szFolder[CCHMAXPATH];
            BOOL fFAT;

            // check whether the target folder is valid
            if (Folder) {
                if (!_wpQueryFilename(Folder, szFolder, TRUE))
                    return (NAMECLASH_CANCEL);
            } else
                return (NAMECLASH_CANCEL);

            // before checking names, determine whether
            // the folder is on a FAT drive; we need this
            // flag for title-to-realname translations later
            fFAT = doshIsFileOnFAT(szFolder);

            // this is not trivial, since we need to take
            // in account all the FAT and HPFS file name
            // conversion.
            // 1)   get real name, unless we're renaming;
            //      we then need to check for pszTitle
            if (menuID != 0x6E)    // not "rename" code
                _wpQueryFilename(somSelf, szTemp, FALSE);
                // (V0.84) this now does work for FAT to FAT;
                // HPFS to FAT needs to be checked
            else
                strcpy(szTemp, pszTitle);
            // 2)   if the file is on FAT, make this 8+3
            doshMakeRealName(szNewRealName,   // buffer
                            szTemp,
                            '!',              // replace-with char
                            fFAT);
            // this should mimic the default WPS behavior close enough

            #ifdef DEBUG_TITLECLASH
                _Pmpf(("  Checking for existence of %s", szNewRealName));
            #endif

            // does this file exist in pFolder?
            pobjExisting = xwpsContainsFile(Folder, szNewRealName);
            if (pobjExisting)
            {
                #ifdef DEBUG_TITLECLASH
                    CHAR szFolder2[CCHMAXPATH];
                    _Pmpf(("  pObjExisting == 0x%lX", pobjExisting));
                    _Pmpf(("    Title: %s", _wpQueryTitle(pobjExisting) ));
                    _wpQueryFilename(_wpQueryFolder(pobjExisting), szFolder2, TRUE);
                    _Pmpf(("    in folder: %s", szFolder2));
                #endif

                // file exists: now we need to differentiate.
                // 1)   If we're copying, we need to always
                //      display the confirmation.
                // 2)   If we're renaming somSelf, we only
                //      display the confirmation if the
                //      existing object is != somSelf, because
                //      otherwise we have no problem.
                /* if  (   (menuID != 0x6E)    // not "rename" code
                     || (   (menuID == 0x6E)
                         && (somSelf != pobjExisting)
                        )
                    ) */
                if (    (somSelf != pobjExisting)
                     || (menuID != 0x6E)    // not "rename"
                   )
                {
                    CHAR    szProposeTitle[CCHMAXPATH],
                            szProposeRealName[CCHMAXPATH],
                            szFileCount[20],
                            szSelfFilename[CCHMAXPATH],
                            szExistingFilename[CCHMAXPATH];
                    ULONG   ulDlgReturn = 0,
                            ulLastFocusID = 0,
                            ulLastDot = 0;
                    PSZ     p, p2;
                    BOOL    fReplaceValid = TRUE,
                            fFileExists = FALSE;
                    LONG    lFileCount = -1;
                    HWND    hwndConfirm;

                    // prepare file date/time etc. for
                    // display in window
                    FILESTATUS3 fs3;
                    ULONG ulDateFormat =
                        PrfQueryProfileInt(HINI_USER, "PM_National", "iDate", 0);
                    ULONG ulTimeFormat =
                        PrfQueryProfileInt(HINI_USER, "PM_National", "iTime", 0);
                    CHAR szDateSep[10],
                         szTimeSep[10],
                         szThousand[10];
                    PrfQueryProfileString(HINI_USER, "PM_National", "sDate", "/",
                        szDateSep, sizeof(szDateSep)-1);
                    PrfQueryProfileString(HINI_USER, "PM_National", "sTime", ":",
                        szTimeSep, sizeof(szTimeSep)-1);
                    PrfQueryProfileString(HINI_USER, "PM_Default_National", "sThousand",
                            ",", szThousand, sizeof(szThousand)-1);

                    // *** load confirmation dialog
                    hwndConfirm = WinLoadDlg(HWND_DESKTOP, HWND_DESKTOP,
                                      fnwpTitleClashDlg,
                                      NLS_MODULE, ID_XFD_TITLECLASH,
                                      NULL);

                    // disable window updates for the following changes
                    WinEnableWindowUpdate(hwndConfirm, FALSE);

                    WinQueryDlgItemText(hwndConfirm, ID_XFDI_CLASH_TXT1,
                                    sizeof(szTemp)-1, szTemp);
                    strhReplace(szTemp, "%1", szNewRealName);
                    strhReplace(szTemp, "%2", szFolder);
                    WinSetDlgItemText(hwndConfirm, ID_XFDI_CLASH_TXT1,
                                    szTemp);

                    // set object information fields
                    // _wpQueryDateInfo(pobjExisting, &ffb4);
                    _wpQueryFilename(pobjExisting, szExistingFilename, TRUE);
                    DosQueryPathInfo(szExistingFilename,
                                    FIL_STANDARD,
                                    &fs3, sizeof(fs3));
                    strhFileDate(szTemp, &(fs3.fdateLastWrite), ulDateFormat, szDateSep[0]);
                    WinSetDlgItemText(hwndConfirm, ID_XFDI_CLASH_DATEOLD,
                                    szTemp);
                    strhFileTime(szTemp, &(fs3.ftimeLastWrite), ulTimeFormat, szTimeSep[0]);
                    WinSetDlgItemText(hwndConfirm, ID_XFDI_CLASH_TIMEOLD,
                                    szTemp);
                    // strhThousandsULong(szTemp, (_wpQueryFileSize(pobjExisting)+512) / 1024,
                    strhThousandsULong(szTemp, ((fs3.cbFile)+512) / 1024,
                                szThousand[0]);
                    WinSetDlgItemText(hwndConfirm, ID_XFDI_CLASH_SIZEOLD,
                                    szTemp);

                    if (pobjExisting != somSelf) {
                        // if we're not copying within the same folder,
                        // i.e. if the two objects are different,
                        // give info on ourselves too
                        // _wpQueryDateInfo(somSelf, &ffb4);
                        _wpQueryFilename(somSelf, szSelfFilename, TRUE);
                        DosQueryPathInfo(szSelfFilename,
                                        FIL_STANDARD,
                                        &fs3, sizeof(fs3));
                        strhFileDate(szTemp, &(fs3.fdateLastWrite), ulDateFormat, szDateSep[0]);
                        WinSetDlgItemText(hwndConfirm, ID_XFDI_CLASH_DATENEW,
                                        szTemp);
                        strhFileTime(szTemp, &(fs3.ftimeLastWrite), ulTimeFormat, szTimeSep[0]);
                        WinSetDlgItemText(hwndConfirm, ID_XFDI_CLASH_TIMENEW,
                                        szTemp);
                        // strhThousandsULong(szTemp, (_wpQueryFileSize(somSelf)+512) / 1024,
                        strhThousandsULong(szTemp, ((fs3.cbFile)+512) / 1024,
                                    szThousand[0]);
                        WinSetDlgItemText(hwndConfirm, ID_XFDI_CLASH_SIZENEW,
                                        szTemp);
                    } else {
                        // if we're copying within the same folder,
                        // set the "new object" fields empty
                        WinSetDlgItemText(hwndConfirm, ID_XFDI_CLASH_DATENEW, "");
                        WinSetDlgItemText(hwndConfirm, ID_XFDI_CLASH_TIMENEW, "");
                        WinSetDlgItemText(hwndConfirm, ID_XFDI_CLASH_SIZENEW, "");
                    }

                    // propose new name; we will use the title and
                    // add a ":num" before the extension and then
                    // transform that one into a real name and keep
                    // increasing "num" until no file with that
                    // real name exists (as the WPS does it too)
                    strcpy(szTemp, pszTitle);
                    // check if title contains a ':num' already
                    p2 = strchr(szTemp, ':');
                    if (p2) {
                        lFileCount = atoi(p2+1);
                        if (lFileCount) {
                            // if we have a valid number following ":", remove it
                            p = strchr(szTemp, '.');
                            if (p)
                                strcpy(p2, p);
                            else
                                *p2 = '\0';
                        }
                    }

                    // insert new number
                    p = strrchr(szTemp, '.');       // last dot == extension
                    lFileCount = 1;
                    do {
                        WPFileSystem *pExistingFile2;

                        sprintf(szFileCount, ":%d", lFileCount);
                        if (p) {
                            // has extension: insert
                            ULONG ulBeforeDot = (p - szTemp);
                            // we don't care about FAT, because
                            // we propose titles, not real names
                            // (V0.84)
                            /* if (   (fFAT)
                                && ((ulBeforeDot+strlen(szFileCount)) > 8)
                               )
                                ulBeforeDot = 8 - strlen(szFileCount); */
                            strncpy(szProposeTitle, szTemp, ulBeforeDot);
                            szProposeTitle[ulBeforeDot] = '\0';
                            strcat(szProposeTitle, szFileCount);
                            strcat(szProposeTitle, p);
                        }
                        else {
                            // has no extension: append
                            strncpy(szProposeTitle, szTemp, 255);
                            // we don't care about FAT, because
                            // we propose titles, not real names
                            // (V0.84)
                            /*     (fFAT) ? 8 : 255);
                            if (fFAT)
                                szProposeTitle[8] = '\0'; */
                            strcat(szProposeTitle, szFileCount);
                        }
                        lFileCount++;

                        if (lFileCount > 99)
                            // avoid endless loops
                            break;

                        // now go through the folder content and
                        // check whether we already have a file
                        // with the proposed title (not real name!)
                        // (V0.84)
                        fFileExists = FALSE;
                        for (   pExistingFile2 = _wpQueryContent(Folder, NULL, (ULONG)QC_FIRST);
                                (pExistingFile2);
                                pExistingFile2 = _wpQueryContent(Folder, pExistingFile2, (ULONG)QC_NEXT)
                            )
                        {
                            fFileExists = (stricmp(_wpQueryTitle(pExistingFile2),
                                                  szProposeTitle) == 0);
                            if (fFileExists)
                                break;
                        }

                        /*
                        // make real name from this title and check
                        // if that file exists; if so, try the next
                        // ":num"
                        doshMakeRealName(szProposeRealName, szProposeTitle, '!',
                            // FAT filenames?
                            fFAT);

                        // extended file exists check (V0.84); we
                        // need to compare titles, not real names
                        pExistingFile2 = xwpsContainsFile(Folder, szProposeRealName);
                        if (pExistingFile2)
                        {
                            if (lFileCount > 99)
                                // avoid endless loops
                                fFileExists = FALSE;
                            else
                                fFileExists = (stricmp(_wpQueryTitle(pExistingFile2),
                                                      szProposeTitle) == 0);
                        } else
                            fFileExists = FALSE; */

                    } while (fFileExists);

                    // OK, we've found a new filename: set dlg items
                    WinSendDlgItemMsg(hwndConfirm, ID_XFDI_CLASH_RENAMENEWTXT,
                            EM_SETTEXTLIMIT,
                            (MPARAM)(250), MPNULL);
                    WinSetDlgItemText(hwndConfirm, ID_XFDI_CLASH_RENAMENEWTXT,
                            szProposeTitle);
                    WinSendDlgItemMsg(hwndConfirm, ID_XFDI_CLASH_RENAMEOLDTXT,
                            EM_SETTEXTLIMIT,
                            (MPARAM)(250), MPNULL);
                    WinSetDlgItemText(hwndConfirm, ID_XFDI_CLASH_RENAMEOLDTXT,
                            szProposeTitle);

                    // select the first characters up to the extension
                    // in the edit field
                    p = strrchr(szProposeTitle, '.');       // last dot == extension
                    if (p)
                        ulLastDot = (p-szProposeTitle);
                    else
                        ulLastDot = 300;                    // too large == select all

                    WinSendDlgItemMsg(hwndConfirm, ID_XFDI_CLASH_RENAMENEWTXT,
                            EM_SETSEL,
                            MPFROM2SHORT(0, ulLastDot), MPNULL);
                    WinSendDlgItemMsg(hwndConfirm, ID_XFDI_CLASH_RENAMEOLDTXT,
                            EM_SETSEL,
                            MPFROM2SHORT(0, ulLastDot), MPNULL);

                    // find the selection the user has made last time;
                    // this INI key item is maintained by fnwpTitleClashDlg above
                    ulLastFocusID = PrfQueryProfileInt(HINI_USER, INIAPP_XFOLDER,
                                        INIKEY_NAMECLASHFOCUS,
                                        ID_XFDI_CLASH_RENAMENEWTXT); // default value if not set

                    // disable "Replace" and "Rename old"
                    // if we're copying within the same folder
                    // or if we're copying a folder to its parent
                    if (    (pobjExisting == somSelf)
                         || (pobjExisting == _wpQueryFolder(somSelf))
                       )
                    {
                        winhEnableDlgItem(hwndConfirm, ID_XFDI_CLASH_REPLACE, FALSE);
                        winhEnableDlgItem(hwndConfirm, ID_XFDI_CLASH_RENAMEOLD, FALSE);
                        winhEnableDlgItem(hwndConfirm, ID_XFDI_CLASH_RENAMEOLDTXT, FALSE);
                        // if the last focus is one of the disabled items,
                        // change it
                        if (   (ulLastFocusID == ID_XFDI_CLASH_REPLACE)
                            || (ulLastFocusID == ID_XFDI_CLASH_RENAMEOLDTXT)
                           )
                            ulLastFocusID = ID_XFDI_CLASH_RENAMENEWTXT;
                    }

                    // disable "Replace" for "Rename" mode; this is
                    // not allowed
                    else if (menuID == 0x006E)
                    {
                        winhEnableDlgItem(hwndConfirm, ID_XFDI_CLASH_REPLACE, FALSE);
                        // if the last focus is one of the disabled items,
                        // change it
                        if (ulLastFocusID == ID_XFDI_CLASH_REPLACE)
                            ulLastFocusID = ID_XFDI_CLASH_RENAMENEWTXT;
                    }

                    // set focus to that item
                    winhSetDlgItemFocus(hwndConfirm, ulLastFocusID);
                        // this will automatically select the corresponding
                        // radio button, see fnwpTitleClashDlg above

                    // *** go!
                    winhRestoreWindowPos(hwndConfirm,
                            HINI_USER,
                            INIAPP_XFOLDER, INIKEY_WNDPOSNAMECLASH,
                            // move only, no resize
                            SWP_MOVE | SWP_SHOW | SWP_ACTIVATE);
                    ulDlgReturn = WinProcessDlg(hwndConfirm);

                    // check return value
                    switch (ulDlgReturn) {
                        case ID_XFDI_CLASH_RENAMENEW: {
                            // rename new: copy user's entry to buffer
                            // provided by the method
                            WinQueryDlgItemText(hwndConfirm, ID_XFDI_CLASH_RENAMENEWTXT,
                                            cbTitle-1, pszTitle);
                            ulrc = NAMECLASH_RENAME;
                        break; }

                        case ID_XFDI_CLASH_RENAMEOLD: {
                            // rename old: use wpSetTitle on existing object
                            WinQueryDlgItemText(hwndConfirm, ID_XFDI_CLASH_RENAMEOLDTXT,
                                            sizeof(szTemp)-1, szTemp);
                            _wpSetTitleAndRenameFile(pobjExisting, szTemp, 0);

                            if (menuID == 0x6E)     // "rename" code
                            {
                                CHAR szNewRealName[CCHMAXPATH];
                                doshMakeRealName(szNewRealName, pszTitle, '!', TRUE);
                                _wpSetTitleAndRenameFile(somSelf, pszTitle, 0);
                            }
                            ulrc = NAMECLASH_NONE;
                        break; }

                        case ID_XFDI_CLASH_REPLACE:
                            *ppDuplicate = pobjExisting;
                            ulrc = NAMECLASH_REPLACE;
                        break;

                        case DID_CANCEL:
                            ulrc = NAMECLASH_CANCEL;
                        break;
                    }
                    WinDestroyWindow(hwndConfirm);
                } // end if  (   (menuID != 0x6E) // "rename" code
                  // || (somSelf != pobjExisting)
                  // )
            }
            else if (menuID == 0x6E)     // "rename" code
            {
                // if (!pobjExisting) and we're renaming
                CHAR szNewRealName[CCHMAXPATH];
                doshMakeRealName(szNewRealName, pszTitle, '!', TRUE);
                if (_wpSetTitleAndRenameFile(somSelf, pszTitle, 0))
                    // no error:
                    ulrc = NAMECLASH_NONE;
                else
                    ulrc = NAMECLASH_CANCEL;
            }
        } // end if (_somIsA(somSelf, _WPFileSystem))
    } // end if (pGlobalSettings->ReplConfirms)
    else {
        // global settings do not allow dialog
        // replacement: call default
        #ifdef DEBUG_TITLECLASH
            _Pmpf(("  Calling original"));
        #endif
        ulrc = XFldObject_parent_WPObject_wpConfirmObjectTitle(somSelf,
                                                            Folder,
                                                            ppDuplicate,
                                                            pszTitle,
                                                            cbTitle,
                                                            menuID);
    }

    #ifdef DEBUG_TITLECLASH
    {
        CHAR szFolder2[CCHMAXPATH];
        _Pmpf(("  Return value: %d", ulrc));
        _Pmpf(("  New somSelf == 0x%lX", somSelf));
        _Pmpf(("    New pszTitle: %s", pszTitle));
        _wpQueryFilename(_wpQueryFolder(somSelf), szFolder2, TRUE);
        _Pmpf(("    in folder: %s", szFolder2));

        if (ppDuplicate) {
            _Pmpf(("  ppDuplicate neu != NULL"));
            if (*ppDuplicate) {
                _Pmpf(("    *ppDuplicate neu == 0x%lX", *ppDuplicate));
                _Pmpf(("      Title neu: %s", _wpQueryTitle(*ppDuplicate) ));
                _wpQueryFilename(_wpQueryFolder(*ppDuplicate), szFolder2, TRUE);
                _Pmpf(("      in folder: %s", szFolder2));
            }
        }
        _Pmpf(("Done."));
    }
    #endif

    return (ulrc);
}

/* ******************************************************************
 *                                                                  *
 *   here come the XFldObject class methods                         *
 *                                                                  *
 ********************************************************************/

BOOL fThreadsInitialized = FALSE;

/*
 *@@ wpclsInitData:
 *           we override this to initialize XFolder altogether.
 *           This is probably the first SOM method called on the
 *           system (for M_WPObject, that is), so we use this
 *           to set up some stuff, most notably, start the
 *           additional XFolder threads.
 */

/*
 *@@ wpclsInitData:
 *           we override this to initialize XFolder altogether.
 *           This is probably the first SOM method called on the
 *           system (for M_WPObject, that is), so we use this
 *           to set up some stuff, most notably, start the
 *           additional XFolder threads by calling
 *           xthrInitializeThreads (xthreads.c).
 */

SOM_Scope void  SOMLINK xfobjM_wpclsInitData(M_XFldObject *somSelf)
{
    PGLOBALSETTINGS pGlobalSettings = cmnQueryGlobalSettings();

    // M_XFldObjectData *somThis = M_XFldObjectGetData(somSelf);
    // M_XFldObjectMethodDebug("M_XFldObject","xfobjM_wpclsInitData");
    #ifdef DEBUG_SOMMETHODS
        _Pmpf(("M_XFldObject::xfobjM_wpclsInitData for class %s",
                    _somGetName(somSelf) ));
    #endif

    M_XFldObject_parent_M_WPObject_wpclsInitData(somSelf);

    // since this code is reached for every single WPS class
    // that gets initialized, we need to check if we're being
    // called for the first time
    if (!fThreadsInitialized)
    {
        fThreadsInitialized = TRUE;

        // initialize all the thread stuff (xthreads.c)
        xthrInitializeThreads();
    }

    // even if not first invocation (i.e. some class other
    // than WPObject gets initialized): notify Quick thread
    // of class initialization
    if (pGlobalSettings->ShowBootupStatus)
        xthrPostQuickMsg(QM_BOOTUPSTATUS, (MPARAM)somSelf, MPNULL);
}

/* ******************************************************************
 *                                                                  *
 *   "Object usage" dialog                                          *
 *                                                                  *
 ********************************************************************/

/*
 *@@ AddObjectUsage2Cnr:
 *      shortcut for the "object usage" functions below
 *      to add one cnr record core
 */

POBJECTUSAGERECORDCORE AddObjectUsage2Cnr(HWND hwndCnr,
    POBJECTUSAGERECORDCORE preccParent, PSZ pszTitle, ULONG flAttrs)
{
    POBJECTUSAGERECORDCORE preccNew = (POBJECTUSAGERECORDCORE)
        winhCnrAllocRecord(hwndCnr, sizeof(OBJECTUSAGERECORDCORE));

    strcpy(preccNew->szText, pszTitle);
    winhCnrInsertRecord(hwndCnr, (PRECORDCORE)preccParent, (PRECORDCORE)preccNew,
            preccNew->szText, flAttrs);
    return (preccNew);
}

#ifdef DEBUG_MEMORY

    LONG    lObjectCount,
            lTotalObjectSize,
            lFreedObjectCount,
            lHeapStatus;

    /*
     * fncbHeapWalk:
     *      callback func for _heap_walk function used for
     *      object usage (FillCnrWithObjectUsage)
     */

    int fncbHeapWalk(const void *pObject, size_t Size, int useflag, int status,
                          const char *filename, size_t line)
    {
        if (status != _HEAPOK) {
            lHeapStatus = status;
        }
        if (useflag == _USEDENTRY) {
            // object not freed
            lObjectCount++;
            lTotalObjectSize += Size;
        } else
            lFreedObjectCount++;

        return 0;
    }
#endif

/*
 *@@ FillCnrWithObjectUsage:
 *      adds all the object details into a given
 *      container window
 */

VOID FillCnrWithObjectUsage(HWND hwndCnr, WPObject *pObject)
{
    POBJECTUSAGERECORDCORE
                    preccRoot, preccLevel2, preccLevel3;
    CHAR            szTemp1[100], szText[300];
    PUSEITEM        pUseItem;

    CHAR            szObjectHandle[20];
    HOBJECT         hObject;
    PSZ             pszObjectID;
    ULONG           ul;

    PTHREADGLOBALS   pThreadGlobals = xthrQueryGlobals();

    // printf("Cnr: %d\n", hwndCnr);
    if (pObject) {
        sprintf(szText, "%s (Class: %s)",
                _wpQueryTitle(pObject), _somGetClassName(pObject));
        preccRoot = AddObjectUsage2Cnr(hwndCnr, NULL, szText,
                CRA_RECORDREADONLY | CRA_EXPANDED);

        // object ID
        preccLevel2 = AddObjectUsage2Cnr(hwndCnr, preccRoot, "Object ID",
                CRA_RECORDREADONLY | CRA_EXPANDED);
        pszObjectID = _wpQueryObjectID(pObject);
        if (pszObjectID)
            AddObjectUsage2Cnr(hwndCnr, preccLevel2, pszObjectID,
                    (strcmp(pszObjectID, "<WP_DESKTOP") != 0
                        ? 0 // editable!
                        : CRA_RECORDREADONLY)); // for the Desktop
        else
            AddObjectUsage2Cnr(hwndCnr, preccLevel2, "none set", 0); // editable!

        // object handle
        preccLevel2 = AddObjectUsage2Cnr(hwndCnr, preccRoot, "Object handle",
                CRA_RECORDREADONLY | CRA_EXPANDED);
        if (_somIsA(pObject, _WPFileSystem)) {
            CHAR    szPath[CCHMAXPATH];
            _wpQueryFilename(pObject, szPath,
                    TRUE);      // fully qualified
            hObject = wphQueryHandleFromPath(HINI_USER, HINI_SYSTEM,
                                szPath);
        } else if (_somIsA(pObject, _WPAbstract)) {
            hObject = _wpQueryHandle(pObject);
        }
        if ((LONG)hObject > 0)
            sprintf(szObjectHandle, "0x%lX", hObject);
        else
            sprintf(szObjectHandle, "(none queried)");
        AddObjectUsage2Cnr(hwndCnr, preccLevel2, szObjectHandle, CRA_RECORDREADONLY);

        // object style
        preccLevel2 = AddObjectUsage2Cnr(hwndCnr, preccRoot, "Object style",
                            CRA_RECORDREADONLY);
        ul = _wpQueryStyle(pObject);
        if (ul & OBJSTYLE_CUSTOMICON)
            AddObjectUsage2Cnr(hwndCnr, preccLevel2,
                        "Custom icon (destroy icon when object goes dormant)",
                        CRA_RECORDREADONLY);
        if (ul & OBJSTYLE_NOCOPY)
            AddObjectUsage2Cnr(hwndCnr, preccLevel2, "no copy",
                                CRA_RECORDREADONLY);
        if (ul & OBJSTYLE_NODELETE)
            AddObjectUsage2Cnr(hwndCnr, preccLevel2, "no delete",
                                CRA_RECORDREADONLY);
        if (ul & OBJSTYLE_NODRAG)
            AddObjectUsage2Cnr(hwndCnr, preccLevel2, "no drag",
                                CRA_RECORDREADONLY);
        if (ul & OBJSTYLE_NODROPON)
            AddObjectUsage2Cnr(hwndCnr, preccLevel2, "no drop-on",
                                CRA_RECORDREADONLY);
        if (ul & OBJSTYLE_NOLINK)
            AddObjectUsage2Cnr(hwndCnr, preccLevel2, "no link (cannot have shadows)",
                                CRA_RECORDREADONLY);
        if (ul & OBJSTYLE_NOMOVE)
            AddObjectUsage2Cnr(hwndCnr, preccLevel2, "no move",
                                CRA_RECORDREADONLY);
        if (ul & OBJSTYLE_NOPRINT)
            AddObjectUsage2Cnr(hwndCnr, preccLevel2, "no print",
                                CRA_RECORDREADONLY);
        if (ul & OBJSTYLE_NORENAME)
            AddObjectUsage2Cnr(hwndCnr, preccLevel2, "no rename",
                                CRA_RECORDREADONLY);
        if (ul & OBJSTYLE_NOSETTINGS)
            AddObjectUsage2Cnr(hwndCnr, preccLevel2, "no settings",
                                CRA_RECORDREADONLY);
        if (ul & OBJSTYLE_NOSETTINGS)
            AddObjectUsage2Cnr(hwndCnr, preccLevel2, "not visible",
                                CRA_RECORDREADONLY);
        if (ul & OBJSTYLE_TEMPLATE)
            AddObjectUsage2Cnr(hwndCnr, preccLevel2, "template",
                                CRA_RECORDREADONLY);
        /* if (ul & OBJSTYLE_LOCKEDINPLACE)
            AddObjectUsage2Cnr(hwndCnr, preccLevel2, "locked in place",
                                CRA_RECORDREADONLY); */

        // folder data
        if (_somIsA(pObject, _WPFolder)) {
            preccLevel2 = AddObjectUsage2Cnr(hwndCnr, preccRoot, "Folder flags",
                                CRA_RECORDREADONLY);
            ul = _wpQueryFldrFlags(pObject);
            if (ul & FOI_POPULATEDWITHALL)
                AddObjectUsage2Cnr(hwndCnr, preccLevel2, "Fully populated",
                                    CRA_RECORDREADONLY);
            if (ul & FOI_POPULATEDWITHFOLDERS)
                AddObjectUsage2Cnr(hwndCnr, preccLevel2, "Populated with folders",
                                    CRA_RECORDREADONLY);
            if (ul & FOI_FIRSTPOPULATE)
                AddObjectUsage2Cnr(hwndCnr, preccLevel2, "Populated with first objects",
                                    CRA_RECORDREADONLY);
            if (ul & FOI_WORKAREA)
                AddObjectUsage2Cnr(hwndCnr, preccLevel2, "Work area",
                                    CRA_RECORDREADONLY);
            if (ul & FOI_CHANGEFONT)
                AddObjectUsage2Cnr(hwndCnr, preccLevel2, "FOI_CHANGEFONT",
                                    CRA_RECORDREADONLY);
            if (ul & FOI_NOREFRESHVIEWS)
                AddObjectUsage2Cnr(hwndCnr, preccLevel2, "FOI_NOREFRESHVIEWS",
                                    CRA_RECORDREADONLY);
            if (ul & FOI_ASYNCREFRESHONOPEN)
                AddObjectUsage2Cnr(hwndCnr, preccLevel2, "FOI_ASYNCREFRESHONOPEN",
                                    CRA_RECORDREADONLY);
            if (ul & FOI_REFRESHINPROGRESS)
                AddObjectUsage2Cnr(hwndCnr, preccLevel2, "FOI_REFRESHINPROGRESS",
                                    CRA_RECORDREADONLY);
            if (ul & FOI_WAMCRINPROGRESS)
                AddObjectUsage2Cnr(hwndCnr, preccLevel2, "FOI_WAMCRINPROGRESS",
                                    CRA_RECORDREADONLY);
            if (ul & FOI_CNRBKGNDOLDFORMAT)
                AddObjectUsage2Cnr(hwndCnr, preccLevel2, "FOI_CNRBKGNDOLDFORMAT",
                                    CRA_RECORDREADONLY);
            if (ul & FOI_DELETEINPROGRESS)
                AddObjectUsage2Cnr(hwndCnr, preccLevel2, "FOI_DELETEINPROGRESS",
                                    CRA_RECORDREADONLY);

            // Desktop: add WPS data
            if (pObject == _wpclsQueryActiveDesktop(_WPDesktop)) {
                PRCPROCESS       prcp;
                PTIB             ptib;
                PPIB             ppib;
                TID              tidWorkerThread = 0,
                                 tidQuickThread = 0;

                preccLevel2 = AddObjectUsage2Cnr(hwndCnr, preccRoot, "Workplace Shell status",
                                    CRA_RECORDREADONLY);

                // we use a conditional compile flag here because
                // _heap_walk adds additional overhead to malloc()
                #ifdef DEBUG_MEMORY
                    lObjectCount = 0;
                    lTotalObjectSize = 0;
                    lFreedObjectCount = 0;
                    lHeapStatus = _HEAPOK;

                    // get heap info using the callback above
                    _heap_walk(fncbHeapWalk);

                    strths(szTemp1, lTotalObjectSize, ',');
                    sprintf(szText, "XFolder memory consumption: %s bytes\n"
                                "(%d objects used, %d objects freed)",
                                szTemp1,
                                lObjectCount,
                                lFreedObjectCount);
                    AddObjectUsage2Cnr(hwndCnr, preccLevel2, szText,
                                        CRA_RECORDREADONLY);

                    sprintf(szText, "XFolder memory heap status: %s",
                                (lHeapStatus == _HEAPOK) ? "OK"
                                : (lHeapStatus == _HEAPBADBEGIN) ? "Invalid heap (_HEAPBADBEGIN)"
                                : (lHeapStatus == _HEAPBADNODE) ? "Damaged memory node"
                                : (lHeapStatus == _HEAPEMPTY) ? "Heap not initialized"
                                : "unknown error"
                                );
                    AddObjectUsage2Cnr(hwndCnr, preccLevel2, szText,
                                        CRA_RECORDREADONLY);
                #endif

                sprintf(szText, "Currently awake WPS objects: %d",
                            pThreadGlobals->lAwakeObjectsCount);
                AddObjectUsage2Cnr(hwndCnr, preccLevel2, szText,
                                    CRA_RECORDREADONLY);

                DosGetInfoBlocks(&ptib, &ppib);
                sprintf(szText, "Workplace Shell process ID: 0x%lX", ppib->pib_ulpid);
                AddObjectUsage2Cnr(hwndCnr, preccLevel2, szText,
                                    CRA_RECORDREADONLY);

                prcQueryProcessInfo(ppib->pib_ulpid, &prcp);
                sprintf(szText, "Workplace Shell thread count: %d", prcp.usThreads);
                AddObjectUsage2Cnr(hwndCnr, preccLevel2, szText,
                                    CRA_RECORDREADONLY);

                tidWorkerThread = thrQueryID(pThreadGlobals->ptiWorkerThread);
                sprintf(szText, "XFolder Worker thread: TID 0x%lX, prty 0x%04lX",
                            tidWorkerThread,
                            prcQueryThreadPriority(ppib->pib_ulpid, tidWorkerThread));
                AddObjectUsage2Cnr(hwndCnr, preccLevel2, szText,
                                    CRA_RECORDREADONLY);

                tidQuickThread = thrQueryID(pThreadGlobals->ptiQuickThread);
                sprintf(szText, "XFolder Quick thread: TID 0x%lX, prty 0x%04lX",
                            tidQuickThread,
                            prcQueryThreadPriority(ppib->pib_ulpid, tidQuickThread));
                AddObjectUsage2Cnr(hwndCnr, preccLevel2, szText,
                                    CRA_RECORDREADONLY);

                sprintf(szText, "Last Workplace Shell startup: %02d:%02d:%02d",
                                    pThreadGlobals->StartupDateTime.hours,
                                    pThreadGlobals->StartupDateTime.minutes,
                                    pThreadGlobals->StartupDateTime.seconds);
                AddObjectUsage2Cnr(hwndCnr, preccLevel2, szText,
                                    CRA_RECORDREADONLY);

                sprintf(szText, "XFolder sound status: %s",
                                (pThreadGlobals->ulMMPM2Working == MMSTAT_UNKNOWN)
                                        ? "not initialized"
                                : (pThreadGlobals->ulMMPM2Working == MMSTAT_WORKING)
                                        ? "OK"
                                : (pThreadGlobals->ulMMPM2Working == MMSTAT_MMDIRNOTFOUND)
                                        ? "MMPM/2 directory not found"
                                : (pThreadGlobals->ulMMPM2Working == MMSTAT_SOUNDLLNOTFOUND)
                                        ? "SOUND.DLL not found"
                                : (pThreadGlobals->ulMMPM2Working == MMSTAT_SOUNDLLNOTLOADED)
                                        ? "SOUND.DLL could not be loaded"
                                : (pThreadGlobals->ulMMPM2Working == MMSTAT_SOUNDLLFUNCERROR)
                                        ? "SOUND.DLL functions could not be imported"
                                : (pThreadGlobals->ulMMPM2Working == MMSTAT_CRASHED)
                                        ? "Quick thread crashed"
                                : "unknown"
                       );
                AddObjectUsage2Cnr(hwndCnr, preccLevel2, szText,
                                    CRA_RECORDREADONLY);
            }
        } // end WPFolder
        else if (_somIsA(pObject, _XFldProgramFile))
        {
            ULONG ulAppType = _xfQueryProgType(pObject);

            preccLevel2 = AddObjectUsage2Cnr(hwndCnr, preccRoot,
                                "Program file data",
                                CRA_RECORDREADONLY);

            sprintf(szText, "DosQueryAppType return value: 0x%lX",
                        XFldProgramFileGetData(pObject)->ulDosAppType);
            AddObjectUsage2Cnr(hwndCnr, preccLevel2, szText,
                                CRA_RECORDREADONLY);

            sprintf(szText, "Using custom icon: %s",
                        (XFldProgramFileGetData(pObject)->fProgIconSet)
                            ? "yes" : "no");
            AddObjectUsage2Cnr(hwndCnr, preccLevel2, szText,
                                CRA_RECORDREADONLY);

            strcpy(szText, "Determined AppType: ");
            switch (ulAppType)
            {
                case PROG_PM:
                    strcat(szText, "PM"); break;

                case PROG_WINDOW_REAL         :
                case PROG_30_STD              :
                case PROG_WINDOW_AUTO         :
                case PROG_30_STDSEAMLESSVDM   :
                case PROG_30_STDSEAMLESSCOMMON:
                case PROG_31_STDSEAMLESSVDM   :
                case PROG_31_STDSEAMLESSCOMMON:
                case PROG_31_ENHSEAMLESSVDM   :
                case PROG_31_ENHSEAMLESSCOMMON:
                case PROG_31_ENH              :
                case PROG_31_STD              :
                    sprintf(szText+strlen(szText),
                            "Win-OS/2 (0x%lX)",
                            XFldProgramFileGetData(pObject)->ulAppType);
                    break;

                case PROG_WINDOWABLEVIO:
                    strcat(szText, "OS/2 VIO window"); break;

                case PROG_FULLSCREEN:
                    strcat(szText, "OS/2 fullscreen"); break;

                case PROG_WINDOWEDVDM:
                    strcat(szText, "DOS window"); break;

                case PROG_VDM: // == PROG_REAL
                    strcat(szText, "DOS fullscreen"); break;

                case PROG_XF_DLL:
                    strcat(szText, "Dynamic Link Library"); break;

                case PROG_XF_DRIVER:
                    strcat(szText, "Device Driver"); break;

                default:
                        sprintf(szText+strlen(szText),
                                "unknown (0x%lX)",
                                XFldProgramFileGetData(pObject)->ulAppType);
                break;
            }
            AddObjectUsage2Cnr(hwndCnr, preccLevel2, szText,
                                CRA_RECORDREADONLY);
        }

        // object usage
        preccLevel2 = AddObjectUsage2Cnr(hwndCnr, preccRoot, "Object usage",
                            CRA_RECORDREADONLY);

        preccLevel3 = NULL;
        for (pUseItem = _wpFindUseItem(pObject, USAGE_OPENVIEW, NULL);
            pUseItem;
            pUseItem = _wpFindUseItem(pObject, USAGE_OPENVIEW, pUseItem))
        {
            PVIEWITEM pViewItem = (PVIEWITEM)(pUseItem+1);
            switch (pViewItem->view) {
                case OPEN_SETTINGS: strcpy(szTemp1, "Settings"); break;
                case OPEN_CONTENTS: strcpy(szTemp1, "Icon"); break;
                case OPEN_DETAILS:  strcpy(szTemp1, "Details"); break;
                case OPEN_TREE:     strcpy(szTemp1, "Tree"); break;
                case OPEN_RUNNING:  strcpy(szTemp1, "Program running"); break;
                case OPEN_PROMPTDLG:strcpy(szTemp1, "Prompt dialog"); break;
                case OPEN_PALETTE:  strcpy(szTemp1, "Palette"); break;
                default:            sprintf(szTemp1, "unknown (0x%lX)", pViewItem->view); break;
            }
            if (pViewItem->view != OPEN_RUNNING) {
                PID pid;
                TID tid;
                WinQueryWindowProcess(pViewItem->handle, &pid, &tid);
                sprintf(szText, "%s (HWND: 0x%lX, thread ID: 0x%lX)",
                        szTemp1, pViewItem->handle, tid);
            } else {
                sprintf(szText, "%s (HWND: 0x%lX)",
                        szTemp1, pViewItem->handle);
            }
            if (!preccLevel3)
                preccLevel3 = AddObjectUsage2Cnr(hwndCnr, preccLevel2, "Currently open views",
                        CRA_RECORDREADONLY | CRA_EXPANDED);
            AddObjectUsage2Cnr(hwndCnr, preccLevel3, szText, CRA_RECORDREADONLY);
        }

        preccLevel3 = NULL;
        for (pUseItem = _wpFindUseItem(pObject, USAGE_MEMORY, NULL);
            pUseItem;
            pUseItem = _wpFindUseItem(pObject, USAGE_MEMORY, pUseItem))
        {
            PMEMORYITEM pMemoryItem = (PMEMORYITEM)(pUseItem+1);
            sprintf(szText, "Size: %d", pMemoryItem->cbBuffer);
            if (!preccLevel3)
                preccLevel3 = AddObjectUsage2Cnr(hwndCnr, preccLevel2, "Allocated memory",
                        CRA_RECORDREADONLY);
            AddObjectUsage2Cnr(hwndCnr, preccLevel3, szText, CRA_RECORDREADONLY);
        }

        preccLevel3 = NULL;
        for (pUseItem = _wpFindUseItem(pObject, USAGE_LINK, NULL);
            pUseItem;
            pUseItem = _wpFindUseItem(pObject, USAGE_LINK, pUseItem))
        {
            PLINKITEM pLinkItem = (PLINKITEM)(pUseItem+1);
            CHAR      szShadowPath[CCHMAXPATH];
            if (pLinkItem->LinkObj) {
                _wpQueryFilename(_wpQueryFolder(pLinkItem->LinkObj),
                        szShadowPath, CRA_RECORDREADONLY | CRA_EXPANDED);
                sprintf(szText, "%s in \n%s", _wpQueryTitle(pLinkItem->LinkObj),
                        szShadowPath);
            } else
                strcpy(szText, "broken");

            if (!preccLevel3)
                preccLevel3 = AddObjectUsage2Cnr(hwndCnr, preccLevel2,
                        "Awake shadows of this object",
                        CRA_RECORDREADONLY | CRA_EXPANDED);
            AddObjectUsage2Cnr(hwndCnr, preccLevel3, szText, CRA_RECORDREADONLY);
        }

        preccLevel3 = NULL;
        for (pUseItem = _wpFindUseItem(pObject, USAGE_RECORD, NULL);
            pUseItem;
            pUseItem = _wpFindUseItem(pObject, USAGE_RECORD, pUseItem))
        {
            PRECORDITEM pRecordItem = (PRECORDITEM)(pUseItem+1);
            CHAR szFolderTitle[256];
            WinQueryWindowText(WinQueryWindow(pRecordItem->hwndCnr, QW_PARENT),
                                sizeof(szFolderTitle)-1,
                                szFolderTitle);
            sprintf(szText, "Container HWND: 0x%lX\n(\"%s\")",
                        pRecordItem->hwndCnr,
                        szFolderTitle);
            if (!preccLevel3)
                preccLevel3 = AddObjectUsage2Cnr(hwndCnr, preccLevel2,
                        "Folder windows containing this object",
                        CRA_RECORDREADONLY | CRA_EXPANDED);
            AddObjectUsage2Cnr(hwndCnr, preccLevel3, szText, CRA_RECORDREADONLY);
        }

        preccLevel3 = NULL;
        for (pUseItem = _wpFindUseItem(pObject, USAGE_OPENFILE, NULL);
            pUseItem;
            pUseItem = _wpFindUseItem(pObject, USAGE_OPENFILE, pUseItem))
        {
            PVIEWFILE pViewFile = (PVIEWFILE)(pUseItem+1);
            sprintf(szText, "Open handle: 0x%lX", pViewFile->handle);
            if (!preccLevel3)
                preccLevel3 = AddObjectUsage2Cnr(hwndCnr, preccLevel2,
                        "Applications which opened this object",
                        CRA_RECORDREADONLY | CRA_EXPANDED);
            AddObjectUsage2Cnr(hwndCnr, preccLevel3, szText, CRA_RECORDREADONLY);
        }

        preccLevel3 = NULL;
        for (ul = 0; ul < 100; ul++)
            if (    (ul != USAGE_OPENVIEW)
                 && (ul != USAGE_MEMORY)
                 && (ul != USAGE_LINK)
                 && (ul != USAGE_RECORD)
                 && (ul != USAGE_OPENFILE)
               )
            {
                for (pUseItem = _wpFindUseItem(pObject, ul, NULL);
                    pUseItem;
                    pUseItem = _wpFindUseItem(pObject, ul, pUseItem))
                {
                    sprintf(szText, "Type: 0x%lX", pUseItem->type);
                    if (!preccLevel3)
                        preccLevel3 = AddObjectUsage2Cnr(hwndCnr, preccLevel2,
                                "Undocumented usage types",
                                CRA_RECORDREADONLY | CRA_EXPANDED);
                    AddObjectUsage2Cnr(hwndCnr, preccLevel3, szText, CRA_RECORDREADONLY);
                }
            }
    }
}

/*
 * fnwpObjectUsage:
 *      dlg proc for "Object usage" dlg
 */

MRESULT EXPENTRY fnwpObjectUsage(HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2)
{
    MRESULT mrc;
    POBJECTUSAGEDATA poud = (POBJECTUSAGEDATA)WinQueryWindowULong(hwndDlg, QWL_USER);

    switch(msg) {
        case WM_INITDLG: {
            CNRINFO CnrInfo;
            WinSetWindowULong(hwndDlg, QWL_USER, (ULONG)mp2);
            poud = (POBJECTUSAGEDATA)mp2;

            WinSetWindowText(hwndDlg, poud->szDlgTitle);
            WinSetDlgItemText(hwndDlg, ID_XSDI_SC_INTROTEXT, poud->szIntroText);

            // setup container
            poud->hwndCnr = WinWindowFromID(hwndDlg, ID_XSDI_SC_CNR);
            WinSendMsg(poud->hwndCnr, CM_QUERYCNRINFO, &CnrInfo, (MPARAM)sizeof(CnrInfo));
            CnrInfo.pSortRecord = (PVOID)fnCompareName;
            CnrInfo.flWindowAttr = CV_TREE | CV_TEXT | CA_TREELINE;
            CnrInfo.cxTreeIndent = 30;
            WinSendMsg(poud->hwndCnr, CM_SETCNRINFO,
                    &CnrInfo,
                    (MPARAM)(CMA_PSORTRECORD | CMA_FLWINDOWATTR | CMA_CXTREEINDENT));

            if (poud->ulHelpPanel == 0)
                winhShowDlgItem(hwndDlg, DID_HELP, FALSE);

            WinPostMsg(hwndDlg, WM_FILLCNR, MPNULL, MPNULL);
            mrc = WinDefDlgProc(hwndDlg, msg, mp1, mp2);
        break; }

        case WM_FILLCNR: {
            HPOINTER hptrOld = WinQueryPointer(HWND_DESKTOP);
            WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, FALSE));
            FillCnrWithObjectUsage(poud->hwndCnr, poud->pObject);
            WinSetPointer(HWND_DESKTOP, hptrOld);
        break; }

        case WM_CONTROL: {
            mrc = WinDefDlgProc(hwndDlg, msg, mp1, mp2);
            if (SHORT1FROMMP(mp1) == ID_XSDI_SC_CNR) {
                switch (SHORT2FROMMP(mp1)) { // notify code
                    case CN_EMPHASIS: {
                        PNOTIFYRECORDEMPHASIS pnre = (PNOTIFYRECORDEMPHASIS)mp2;
                        if (pnre)
                            if (pnre->fEmphasisMask & CRA_SELECTED) {
                            }
                    break; }
                }
            }
        break; }

        case WM_DESTROY: {
            mrc = WinDefDlgProc(hwndDlg, msg, mp1, mp2);
        break; }

        default:
            mrc = WinDefDlgProc(hwndDlg, msg, mp1, mp2);
    }
    return (mrc);
}


