/****************************************************************************
**
**  Name:  dlgobj.cpp
**
**  Description:
**     Contains definition of classes declared in DLGOBJ.H
**
**  $Log:   S:/tbird/mt2_186/cliulib/dlgobj.cpv  $
** 
**    Rev 1.0   16 Dec 1996 16:12:34   Judy
** Initial revision.
** 
**    Rev 1.4   25 Jul 1994 17:24:22   nghia
** Revised init() method to set the lpstrFile to initial directory.
** 
**    Rev 1.3   25 Jul 1994 11:28:24   nghia
** Added OFN_NOCHANGEDIR flag as the default flag for FILE dialog.
** 
**    Rev 1.2   22 Jul 1994 10:16:00   nghia
** Updated error codes.
** 
**    Rev 1.1   20 Jul 1994 10:04:30   nghia
** Return ER_USER_ABORT when users pressed CANCEL or CLOSE button.
** 
**    Rev 1.0   14 Jul 1994 10:31:28   nghia
** Initial revision.
**
**  $Header:   S:/tbird/mt2_186/cliulib/dlgobj.cpv   1.0   16 Dec 1996 16:12:34   Judy  $
**
**  Copyright (C) 1994 Microtek International.  All rights reserved.
**
*****************************************************************************/
                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/

#include <mem.h>
#include <alloc.h>
#include <cderr.h>   // Windows COMMDLG dialog error codes

#ifndef _DLGOBJ_
#include "dlgobj.h"
#endif

#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif

#ifndef _HLPENTRY_
#include "hlpentry.h"
#endif

                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/
//----------------------------------------------------------------------------
// Initialize Class Data
U16 FileDlgItem::NumObjects = 0;
FileDlgItemPtr FileDlgItem::ListOfDlgs = NULL;

                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/

extern HANDLE hInstance;  // defined in LIBMAIN.C

                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/

                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/
//----------------------------------------------------------------------------
//
// Class: FileDlgItem
//
//----------------------------------------------------------------------------
                         //--------------------------//
                         // CONSTRUCTOR & DESTRUCTOR //
                         //--------------------------//
//-----------------------------------------------------------------------------
// FileDlgItem - Ctor
//-----------------------------------------------------------------------------
FileDlgItem::FileDlgItem(HWND owner, CommFileDlgPtr dlgItem) {
   
   // store the information of the registered object.
   dlgOwner  = owner;
   dlgObject = dlgItem;
   nextItem  = NULL;
}

//-----------------------------------------------------------------------------
// FileDlgItem - Dtor
//-----------------------------------------------------------------------------
FileDlgItem::~FileDlgItem() {
   
   // clear object content - no dangling pointer
   memset(this, 0, sizeof(*this));
}

                         //--------------------------//
                         //    INITIALIZED METHODS   //
                         //--------------------------//

                         //--------------------------//
                         //    ACCESSING METHODS     //
                         //--------------------------//

                         //--------------------------//
                         //    OPERATOR METHODS      //
                         //--------------------------//

                         //--------------------------//
                         //    OPERATION METHODS     //
                         //--------------------------//

                         //--------------------------//
                         //       CLASS METHODS      //
                         //--------------------------//

//-----------------------------------------------------------------------------
// AddItem
//-----------------------------------------------------------------------------
RETCODE FileDlgItem::AddItem(CommFileDlgPtr  dlgItem) {
   FileDlgItemPtr obj;

   if (dlgItem == NULL) return ER_COMMDLG_INVALID_OBJECT;
   // allocate a new FileDlgItem to hold the input object
   if ((obj = new FileDlgItem(dlgItem->ofn.hwndOwner, dlgItem)) == NULL)
      return ER_OUT_OF_MEMORY;
   // linked into the ListOfDlgs as top item.
   obj->nextItem = ListOfDlgs;
   ListOfDlgs = obj;
   // count the number of registered object
   ++NumObjects;
   return GOOD;
}

//-----------------------------------------------------------------------------
// RemoveItem
//-----------------------------------------------------------------------------
RETCODE FileDlgItem::RemoveItem(CommFileDlgPtr dlgItem) {

   if (dlgItem == NULL) return ER_COMMDLG_INVALID_OBJECT;
   if (NumObjects == 0) return ER_COMMDLG_OBJECT_LIST_EMPTY;
   
   FileDlgItemPtr currObj, prevObj;
   // initialize traversing pointer
   currObj = prevObj = ListOfDlgs;
   for (U8 i = 0; i < NumObjects && currObj; i++) {
      if (currObj->dlgOwner == dlgItem->ofn.hwndOwner) {
         prevObj->nextItem = currObj->nextItem;
         delete currObj;  // destroy the FileDlgItem object
         --NumObjects;    // decrement the number of registered objects
         return GOOD;
      }
      // next object
      prevObj = currObj;
      currObj = currObj->nextItem;
   }
   // cannot locate the object, it must be an invalid object
   return ER_COMMDLG_INVALID_OBJECT;
}

                         //--------------------------//
                         //       LOCAL METHODS      //
                         //--------------------------//


//// End of FileDlgItem
                                   
//----------------------------------------------------------------------------
//
// Class: CommFileDlg
//
//----------------------------------------------------------------------------
                         //--------------------------//
                         // CONSTRUCTOR & DESTRUCTOR //
                         //--------------------------//
//-----------------------------------------------------------------------------
// CommFileDlg - Ctor
//-----------------------------------------------------------------------------
CommFileDlg::CommFileDlg(HWND parent, U16 helpId, U16 filterId,
                           LPSTR initDir /* = NULL */,
                           BOOLEAN usedForOpen /* = TRUE */) {
   // clear out self object
   memset(this, 0, sizeof(*this));
   
   // initialize public members
   defaultFlags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST  | OFN_ENABLEHOOK |
                  OFN_SHOWHELP | OFN_NOCHANGEDIR;

   // if FILESAVE allow user overwrite prompt
   if (!usedForOpen)
      defaultFlags |= OFN_OVERWRITEPROMPT;

   // type of FILE dialog box
   openDlg = usedForOpen;
   // save help context id
   if (!helpId)
      helpCntxtId = HE_CONTENTS;  // default to PWRVIEWS help contents
   else
      helpCntxtId = helpId;
   
   // Init private members
   if ((status = Init(parent, initDir, filterId)) == GOOD)
      // register for F1 hook to process help context of self
      // NOTES: F1 hook does not support multiple instance for FILE dialog
      status = RegisterHelpEntry(HI_FILE_DLG, (LONG)parent, helpCntxtId);   
}

//-----------------------------------------------------------------------------
// CommFileDlg - Dtor
//-----------------------------------------------------------------------------
CommFileDlg::~CommFileDlg() {
   RETCODE err;
   S16 dummy;
   
   // removed self from list - unregister object
   if ((err = FileDlgItem::RemoveItem((CommFileDlgPtr)this)) != GOOD)
      ErrDisplayFormattedError(err, FORCE_POPUP, NULL, NULL, NULL,
                               MB_OK, &dummy);
   
   // free allocated string
   if (lpDirName) free(lpDirName);
   if (lpFile) free(lpFile);
   if (lpFileTitle) free(lpFileTitle);
   if (lpFilter) free(lpFilter);
}

                         //--------------------------//
                         //    INITIALIZED METHODS   //
                         //--------------------------//
//-----------------------------------------------------------------------------
// Init
//-----------------------------------------------------------------------------
RETCODE CommFileDlg::Init(HWND parent, LPSTR initDir, U16 filterId) {
   U16  filterLen;
   CHAR delimiter;
   
   // allocate memory for private buffers
   if (((lpDirName = (LPSTR)malloc(MAX_STRING_SIZE)) == NULL) ||
       ((lpFile = (LPSTR)malloc(MAX_STRING_SIZE)) == NULL) ||
       ((lpFileTitle = (LPSTR)malloc(MAX_STRING_SIZE)) == NULL) ||
       ((lpFilter = (LPSTR)malloc(MAX_STRING_SIZE)) == NULL))
      return ER_OUT_OF_MEMORY;
   
   // get the system directory name for initial dir
   if (initDir == NULL) {
      GetSystemDirectory(lpDirName, sizeof(lpDirName));
      *lpFile = '\0';
   }
   else {  
      lstrcpy(lpDirName, initDir);
      lstrcpy(lpFile, lpDirName);
   }

   // retrieve file name filters
   if ((filterLen = LoadString(hInstance, filterId, lpFilter,
                               MAX_STRING_SIZE)) == 0) 
      return ER_COMMDLG_GET_FILTER_STR;
   // get the filter string delimiter - replace delimiter with NULL
   delimiter = lpFilter[filterLen-1];
   for (U16 i = 0; lpFilter[i] != '\0'; i++) {
      if (lpFilter[i] == delimiter)
         lpFilter[i] = '\0'; 
   }             
   // init OPENFILENAME structure
   ofn.lStructSize     = sizeof(OPENFILENAME);
   ofn.hwndOwner       = parent;
   ofn.hInstance       = hInstance;  // initialize this for HookProc
   ofn.lpstrFilter     = lpFilter;
   ofn.nFilterIndex    = 1;
   ofn.lpstrFile       = lpFile;
   ofn.nMaxFile        = MAX_STRING_SIZE;
   ofn.lpstrFileTitle  = lpFileTitle;
   ofn.nMaxFileTitle   = MAX_STRING_SIZE;
   ofn.lpstrInitialDir = lpDirName;
   ofn.Flags           = defaultFlags;
   ofn.lpfnHook        = CommDlgFileHookProc;  // hookProc 

   // add self into FileDlgItem list for session management
   return FileDlgItem::AddItem(this);
}
                         //--------------------------//
                         //    ACCESSING METHODS     //
                         //--------------------------//

                         //--------------------------//
                         //    OPERATOR METHODS      //
                         //--------------------------//

                         //--------------------------//
                         //    OPERATION METHODS     //
                         //--------------------------//
//-----------------------------------------------------------------------------
// GetFileName
//-----------------------------------------------------------------------------
RETCODE CommFileDlg::GetFileName(LPSTR lpFileName) {
  BOOL result;
  
  // invoke the API call depend upon the openDlg flag
  if (openDlg)
     result = GetOpenFileName((OPENFILENAME FAR *)&ofn);
  else
     result = GetSaveFileName((OPENFILENAME FAR *)&ofn);
  
  // if result is nonzero - copy the file name to returned buffer
  if (result) {
     lstrcpy(lpFileName, ofn.lpstrFile);
     return GOOD;
  }
  // get error from COMMDLG or the user press CANCEL or CLOSE
  return ErrorHandler();
}

                         //--------------------------//
                         //       CLASS METHODS      //
                         //--------------------------//

//-----------------------------------------------------------------------------
// GetHelpId
//-----------------------------------------------------------------------------
RETCODE CommFileDlg::GetHelpId(HWND hDlg, WORD FAR* hlpId) {
   HWND owner;
   
   if (!(owner = GetWindow(hDlg, GW_OWNER)))
      return ER_COMMDLG_CANNOT_FIND_OWNER;
   
   // search the list of active CommFileDlg objects for the id
   FileDlgItem* dlgObj = FileDlgItem::ListOfDlgs;
   for (U8 i = 0; i < FileDlgItem::NumObjects && dlgObj; i++) {
      if (dlgObj->dlgOwner == owner) {
         // get the help context id of self
         *hlpId = dlgObj->dlgObject->helpCntxtId;
         return GOOD;
      }
      dlgObj = dlgObj->nextItem;
   }
   return ER_COMMDLG_MISSING_HELP_ID;   
}

//-----------------------------------------------------------------------------
// GetObject
//-----------------------------------------------------------------------------
const CommFileDlgPtr CommFileDlg::GetObject(HWND hDlg) {
   HWND owner;

   // retrieve the parent of <hDlg> to use in searching
   if (!(owner = GetWindow(hDlg, GW_OWNER)))
      return NULL;
   
   // search the list of active CommFileDlg objects for the match
   FileDlgItem* dlgObj = FileDlgItem::ListOfDlgs;
   for (U8 i = 0; i < FileDlgItem::NumObjects && dlgObj; i++) {
      if (dlgObj->dlgOwner == owner) {
         // get the object of self
         return dlgObj->dlgObject;
      }
      dlgObj = dlgObj->nextItem;
   }
   return NULL;
}
                         //--------------------------//
                         //       LOCAL METHODS      //
                         //--------------------------//

//-----------------------------------------------------------------------------
// ErrorHandler
//
// Description: Translate COMMDLG errors to PV error codes.
//
// Parameters:
//    none
//-----------------------------------------------------------------------------
RETCODE CommFileDlg::ErrorHandler() {
   U32 commDlgErr;
   
   if ((commDlgErr = CommDlgExtendedError()) != 0L) {
      // filter out Windows COMMDLG error for FILE dialog
      if ((commDlgErr >= FNERR_FILENAMECODES) &&
          (commDlgErr <  FRERR_FINDREPLACECODES)) {
         CHAR errBuf[10] = "";
         S16 dummy;
         // display the error and mark as reported
         wsprintf(errBuf, "0x%lX",commDlgErr);
         ErrDisplayFormattedError(ER_COMMDLG_FILE_DLG, FORCE_POPUP,
                                    (LPSTR)errBuf, NULL, NULL, MB_OK, &dummy); 
         return ERR_REPORTED(ER_COMMDLG_FILE_DLG);
      }          
   }
   // users pressed CANCEL or CLOSE button
   return ER_USER_ABORT;
}
//// End of <CommFileDlg>


/********************************** E O F ***********************************/
