Timestamper Class Extension
TimestampPropPage.cpp
// Copyright 2006 ESRI
// 
// All rights reserved under the copyright laws of the United States
// and applicable international laws, treaties, and conventions.
// 
// You may freely redistribute and use this sample code, with or
// without modification, provided you include the original copyright
// notice and use restrictions.
// 
// See the use restrictions.

// TimestampPropPage.cpp : Implementation of CTimestampPropPage
#include "stdafx.h"
#include "Timestamper.h"
#include "TimestampPropPage.h"

/////////////////////////////////////////////////////////////////////////////
// CTimestampPropPage

STDMETHODIMP CTimestampPropPage::Show(UINT nCmdShow)
{
  if (nCmdShow != SW_HIDE)
  {
    HRESULT hr;
    USES_CONVERSION;

    m_cboCre = GetDlgItem(IDC_COMBO_CRE);
    m_cboMod = GetDlgItem(IDC_COMBO_MOD);
    m_cboUsr = GetDlgItem(IDC_COMBO_USR);

    // Update the content of the property page with the current data
    // from the object class
    m_cboCre.ResetContent();
    m_cboMod.ResetContent();
    m_cboUsr.ResetContent();

    ITimestampClassExtensionPtr ipTimestampExt;
    IUnknownPtr ipExt;

    hr = m_ipObjectClass->get_Extension(&ipExt);
    if (FAILED(hr)) return hr;
    ipTimestampExt = ipExt;
    if (ipTimestampExt == 0) return E_UNEXPECTED;
  
    BOOL success;
    // Initialise Cre Combobox
    CComBSTR sCreField;
    hr = ipTimestampExt->get_CreationFieldName(&sCreField);
    if (FAILED(hr)) return hr;    
    if (sCreField.Length() > 0) 
      success = SetDlgItemText(IDC_COMBO_CRE, OLE2CT(sCreField));
    else
      success = SetDlgItemText(IDC_COMBO_CRE, TEXT("Not in use"));
    if (!success) return E_UNEXPECTED;

    // Initialise Mod Combobox
    CComBSTR sModField;
    hr = ipTimestampExt->get_ModificationFieldName(&sModField);
    if (FAILED(hr)) return hr;

    if (sModField.Length() > 0) 
      success = SetDlgItemText(IDC_COMBO_MOD, OLE2CT(sModField));
    else
      success = SetDlgItemText(IDC_COMBO_MOD, TEXT("Not in use"));
    if (!success) return E_FAIL;

    // Initialise Usr Combobox    
    CComBSTR sUsrField;
    hr = ipTimestampExt->get_UserFieldName(&sUsrField);
    if (FAILED(hr)) return hr;

    if (sUsrField.Length() > 0) 
      success = SetDlgItemText(IDC_COMBO_USR, OLE2CT(sUsrField));
    else
      success = SetDlgItemText(IDC_COMBO_USR, TEXT("Not in use"));
    if (!success) return E_UNEXPECTED;

    // Set up lists in comboboxes
    m_cboCre.AddString(TEXT("Not in use"));
    m_cboMod.AddString(TEXT("Not in use"));
    m_cboUsr.AddString(TEXT("Not in use"));

    IFieldsPtr ipFields;
    m_ipObjectClass->get_Fields(&ipFields);

    IFieldPtr ipField;
    esriFieldType eFieldType;
    long lNumFields;
    ipFields->get_FieldCount(&lNumFields);
    
    for (long i=0; i < lNumFields; i++)
    {
      hr = ipFields->get_Field(i, &ipField);
      if (FAILED(hr)) return hr;
      
      ipField->get_Type(&eFieldType);
      if (eFieldType == esriFieldTypeDate) 
      {
        CComBSTR sStrFieldName;
        ipField->get_Name(&sStrFieldName);
        m_cboCre.AddString(OLE2CT(sStrFieldName));
        m_cboMod.AddString(OLE2CT(sStrFieldName));
      }
      else if (eFieldType == esriFieldTypeString)
      {
        CComBSTR sStrFieldName;
        ipField->get_Name(&sStrFieldName);
        m_cboUsr.AddString(OLE2CT(sStrFieldName));
      }
    }
  }

  return IPropertyPageImpl<CTimestampPropPage>::Show(nCmdShow);
}


STDMETHODIMP CTimestampPropPage::Apply()
{
  HRESULT hr;

  // Make changes to extension properties to reflect what is on the form
  // First take out a schema lock, to ensure no-one else is using the
  // object class
  ISchemaLockPtr ipSchLock(m_ipObjectClass);
  hr = ipSchLock->ChangeSchemaLock(esriExclusiveSchemaLock);
  if (hr ==  FDO_E_SCHEMA_LOCK_CONFLICT)
    MessageBox(TEXT("Failed to apply the changes.\n")
               TEXT("Could not get exclusive access to the dataset"));
  else if (FAILED(hr)) 
    return hr;
  
  // Get the extension
  ITimestampClassExtensionPtr ipTimestampExt;
  IUnknownPtr ipExt;

  hr = m_ipObjectClass->get_Extension(&ipExt);
  if (FAILED(hr)) return hr;
  ipTimestampExt = ipExt;
  if (ipTimestampExt == 0) return E_FAIL;

  // Set the class extension properties according to the form
  BOOL success;
  BSTR sName = ::SysAllocStringLen(0, 100);

  success = GetDlgItemText(IDC_COMBO_CRE, sName);
  if (!success) return E_FAIL;
  if (_tcscmp(sName,TEXT("Not in use")) == 0)
    hr = ipTimestampExt->put_CreationFieldName(L"");
  else
    hr = ipTimestampExt->put_CreationFieldName(sName);
  if (FAILED(hr)) return hr;

  success = GetDlgItemText(IDC_COMBO_MOD, sName);
  if (!success) return E_FAIL;
  if (_tcscmp(sName,TEXT("Not in use")) == 0)
    hr = ipTimestampExt->put_ModificationFieldName(L"");
  else
    hr = ipTimestampExt->put_ModificationFieldName(sName);
  if (FAILED(hr)) return hr;

  success = GetDlgItemText(IDC_COMBO_USR, sName);
  if (!success) return E_FAIL;
  if (_tcscmp(sName,TEXT("Not in use")) == 0)
    hr = ipTimestampExt->put_UserFieldName(L"");
  else
    hr = ipTimestampExt->put_UserFieldName(sName);
  if (FAILED(hr)) return hr;

  ::SysFreeString(sName);

  // Update the properties in the geodatabase
  hr = ipTimestampExt->UpdateProperties();
  if (FAILED(hr)) 
  {
    IErrorInfoPtr ipError;
    CComBSTR      strError;
    GetErrorInfo(0, &ipError);
    ipError->GetDescription(&strError);
    MessageBox(OLE2T(strError), TEXT("Error"), MB_ICONEXCLAMATION);
    // Release schema lock
    ipSchLock->ChangeSchemaLock(esriSharedSchemaLock);
    return E_FAIL;
  }
  // Release schema lock
  hr = ipSchLock->ChangeSchemaLock(esriSharedSchemaLock);
  if (FAILED(hr)) return hr;
    
  // ObjectClass now reflects what is on form, so set IsDirty to false.
  SetDirty(false);

  return S_OK;
}


// IPropertyPageContext
STDMETHODIMP CTimestampPropPage::get_Priority(long *Priority)
{
  if (! Priority) return E_POINTER;

  *Priority = -1;
  return S_OK;
}

STDMETHODIMP CTimestampPropPage::Applies(VARIANT unkArray, VARIANT_BOOL *Applies)
{
  // Apply if object class has a timestamp extension

  if (Applies == NULL)
    return E_INVALIDARG;

  *Applies = VARIANT_FALSE;
  
  if (V_VT(&unkArray) != (VT_ARRAY|VT_UNKNOWN))
    return E_INVALIDARG;

  SAFEARRAY *saArray = unkArray.parray;
  HRESULT hr = ::SafeArrayLock(saArray);

  IUnknownPtr *pUnk;
  hr = ::SafeArrayAccessData(saArray,reinterpret_cast<void**> (&pUnk));
  if (FAILED(hr)) return hr;

  long lNumElements = saArray->rgsabound->cElements;
  for (long i = 0; i < lNumElements; i++)
  {
    IObjectClassPtr ipObjectClass(pUnk[i]);
    if (ipObjectClass != 0)
    {
      IUnknownPtr ipExt;
      hr = ipObjectClass->get_Extension(&ipExt);
      if (FAILED(hr)) return hr;

      if (ipExt != 0)
      {
        ITimestampClassExtensionPtr ipTimestampExt(ipExt);
        if (ipTimestampExt != 0)
        {
          m_ipObjectClass = ipObjectClass;
          *Applies = VARIANT_TRUE;
          break; //out of for loop
        }
      }
    }
  }

  hr = ::SafeArrayUnaccessData(saArray);
  if (FAILED(hr)) return hr;

  hr = ::SafeArrayUnlock(saArray);
  if (FAILED(hr)) return hr;

  return S_OK;
}

STDMETHODIMP CTimestampPropPage::CreateCompatibleObject(VARIANT kind, VARIANT *pNewObject)
{
  return S_OK;
}

STDMETHODIMP CTimestampPropPage::QueryObject(VARIANT theObject)
{
  return S_OK;
}

STDMETHODIMP CTimestampPropPage::GetHelpFile(long controlID, BSTR *HelpFile)
{
  *HelpFile = NULL;
  return S_OK;
}

STDMETHODIMP CTimestampPropPage::GetHelpId(long controlID, long *helpID)
{
  *helpID = 0;
  return S_OK;
}

STDMETHODIMP CTimestampPropPage::Cancel()
{
  return S_OK;
}


LRESULT CTimestampPropPage::OnComboChange(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
  SetDirty(true);
  return 0;
}