📄 additemdlg.cpp
字号:
// AddItemDlg.cpp : 实现文件
//
#include "stdafx.h"
#include "SuperOPC.h"
#include "AddItemDlg.h"
#include ".\additemdlg.h"
// Registry sections;
static LPCTSTR lpszRegSection = _T("Add Items");
static LPCTSTR lpszAutoValidate = _T("Auto Validate");
static LPCTSTR lpszBrowseFlat = _T("Browse Flat");
// Default add item list size:
#define DEF_ITEM_LIST_SIZE 16
// Branch dummy item data:
#define NULL_ITEM_NAME _T("_QCNULL_DUMMY")
#define NULL_ITEM_DATA 0xFFFFFFFF
// Image list indices:
#define ILI_BRANCH 8
#define ILI_SELBRANCH 9
#define ILI_LEAF 3
// Access rights filter combo box indices:
#define CB_ACCESS_ANY 0
#define CB_ACCESS_READONLY 1
#define CB_ACCESS_WRITEONLY 2
#define CB_ACCESS_READWRITE 4
// CAddItemDlg 对话框
IMPLEMENT_DYNAMIC(CAddItemDlg, CDialog)
CAddItemDlg::CAddItemDlg(CHotOpcGroup *pGroup, IOPCBrowseServerAddressSpace *pIBrowse, CWnd* pParent /*=NULL*/)
: CDialog(CAddItemDlg::IDD, pParent)
, m_strItemID(_T(""))
{
ASSERT (pGroup != NULL);
m_pGroup = pGroup;
m_pIBrowse = pIBrowse;
m_vtDataType = VT_EMPTY;
m_nListIndex = 0;
m_nSelIndex = 0;
m_bModified = false;
m_pIItemMgt = NULL;
// Load registry settings. These are settings we may want to use each time
// we add some items:
m_bAutoValidate = FALSE;
m_bBrowseFlat = FALSE;
// Allocate memory for add item list:
try
{
m_cItemList.SetSize (DEF_ITEM_LIST_SIZE, DEF_ITEM_LIST_SIZE);
}
catch (...)
{
ASSERT (FALSE);
}
}
CAddItemDlg::~CAddItemDlg()
{
}
void CAddItemDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
// Transfer data type combo box index to vartype:
CComboBox *pCombo = (CComboBox *)GetDlgItem (IDC_DATATYPE);
CListCtrl *pList = (CListCtrl *)GetDlgItem(IDC_LEAFLIST);
pList->ModifyStyle(NULL, LVS_REPORT | LVS_SORTASCENDING ,0);
pList->SetExtendedStyle(LVS_EX_FULLROWSELECT);
// If save and validate, transfer data type combo box index to
// vartype member variable:
if (pDX->m_bSaveAndValidate)
{
CString strType;
pCombo->GetLBText (pCombo->GetCurSel (), strType);
m_vtDataType = VartypeFromString (strType);
}
// else use current member variable value to make combo box selection:
else
{
CString strType;
// Convert data type to combo box entry string:
switch (m_vtDataType & ~VT_ARRAY)
{
case VT_BOOL: strType = _T("Boolean"); break;
case VT_UI1: strType = _T("Byte"); break;
case VT_I1: strType = _T("Char"); break;
case VT_UI2: strType = _T("Word"); break;
case VT_I2: strType = _T("Short"); break;
case VT_UI4: strType = _T("DWord"); break;
case VT_I4: strType = _T("Long"); break;
case VT_R4: strType = _T("Float"); break;
case VT_R8: strType = _T("Double"); break;
case VT_BSTR: strType = _T("String"); break;
default: strType = _T("Native"); break;
}
// Update array flag data:
if ((m_vtDataType & VT_ARRAY) != 0)
strType += _T(" Array");
// Select combo box entry:
pCombo->SelectString (-1, strType);
}
DDX_Text(pDX, IDC_ACCESSPATH, m_strAccessPath);
DDX_Text(pDX, IDC_ITEMID, m_strItemID);
}
BEGIN_MESSAGE_MAP(CAddItemDlg, CDialog)
ON_NOTIFY(TVN_ITEMEXPANDING, IDC_BRANCHLIST, OnTvnItemexpandingBranchlist)
ON_NOTIFY(TVN_SELCHANGED, IDC_BRANCHLIST, OnTvnSelchangedBranchlist)
ON_CBN_SELCHANGE(IDC_DATATYPE, OnCbnSelchangeDatatype)
ON_EN_CHANGE(IDC_ACCESSPATH, OnEnChangeAccesspath)
ON_EN_CHANGE(IDC_ITEMID, OnEnChangeItemid)
ON_WM_SHOWWINDOW()
ON_NOTIFY(NM_DBLCLK, IDC_LEAFLIST, OnNMDblclkLeaflist)
END_MESSAGE_MAP()
// CAddItemDlg 消息处理程序
BOOL CAddItemDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Limit the access path to 255 chars:
((CEdit *)GetDlgItem (IDC_ACCESSPATH))->LimitText (255);
// Allow 10 levels of 32 character names plus a tag name of 31 characters:
((CEdit *)GetDlgItem (IDC_ITEMID))->LimitText (10*32 + 31);
// Get our group's item management interface pointer for the group:
m_pIItemMgt = m_pGroup->GetIItemMgt ();
// Intialize our item browser:
InitializeBrowser ();
// Intialize control status:
UpdateStatus ();
return TRUE; // return TRUE unless you set the focus to a control
// 异常: OCX 属性页应返回 FALSE
}
// **************************************************************************
// AutoIncrementID ()
//
// Description:
// Create a new item ID by incrementing current ID.
//
// Parameters:
// bool bDotBitAddress Set to true if item has "dot bit number"
// address format.
//
// Returns:
// void
// **************************************************************************
void CAddItemDlg::AutoIncrementID (bool bDotBitAddress)
{
static TCHAR szBuffer [MAX_PATH];
static TCHAR *pch = NULL;
// If the item ID is defined, we will modify it by incrementing:
if (!m_strItemID.IsEmpty ())
{
// Make a local copy of the current item ID:
lstrcpyn (szBuffer, m_strItemID, sizeof (szBuffer) / sizeof (TCHAR));
// Ensure it is null terminated:
szBuffer [MAX_PATH - 1] = '\0';
// Get a pointer to the last character of the string (search for
// NULL terminator, then back up a character):
pch = _tcschr (szBuffer, _T('\0'));
pch--;
// If it is a digit we can simply increment this address:
if (_istdigit (*pch))
{
int nNumber;
// Scan backwards from last character until we encounter
// a non-digit:
while (_istdigit (*pch) && pch != szBuffer)
pch--;
// Obtain the number we are peeling off (go to next character
// which will be the first digit, then convert text to right
// to an integer):
pch++;
nNumber = _ttol (pch);
// Increment the number:
nNumber++;
// If we are dealing with a "dot bit number" address,
// make sure we do not increment bit number beyond 15.
// Increment bit numbers to 15, then increment offset
// and make bit number 0.
// If bDotBitAddress is set, then character to the left
// of current pointer should be the "dot".
if (bDotBitAddress && *(pch - 1) == _T('.'))
{
// Assume dot specifier is a bit and increment 0 - 15.
// If nNumber is greater than 15, determine offset, and
// increment that instead of the bit number:
if (nNumber > 15)
{
// Roll offset ahead:
pch = _tcsrchr (szBuffer, _T('.'));
pch--;
// Peel back looking for the first non-digit:
while (_istdigit (*pch) && pch != szBuffer)
pch--;
// Go to next character and convert to integer. This will
// be the offset since _ttol will not use any characters to
// the right of the dot. Increment the result by one. This
// will be our new offset.
pch++;
nNumber = _ttol (pch) + 1;
// Replace old offset and bit number with incremented
// offset and bit number "00".
_stprintf (pch, _T("%d.00"), nNumber);
}
// Otherwise just replace the bit number with incremeted
// bit number:
else
_stprintf (pch, _T("%02d"), nNumber);
}
// If not a dot bit number address, make sure we do not lose
// any leading zeros (as in modbus addresses):
else
{
// We should currently be pointing at first character of
// trailing digit portion of address. Check to see if
// this is a zero.
if (*pch == _T('0'))
{
// We found a leading zero.
TCHAR *pZeros = pch;
int cnDigits = 0;
// Scan forwared until we find a non-zero character.
// Count each zero along the way:
while (*pZeros++ != _T('\0'))
cnDigits++;
// Replace the trailing digits of the adress with
// the new incremented number, keeping the same
// number of leading zeros:
_stprintf (pch, _T("%0*d"), cnDigits, nNumber);
}
// Else if no leading zeros, just replace the trailing
// digits with the new incremented number:
else
_stprintf (pch, _T("%d"), nNumber);
}
}
// else if last character is not a digit, append a good starting offset:
else
*(pch + 1) = '0';
// Update item ID:
m_strItemID = szBuffer;
// Update controls:
UpdateData (false);
// Set modifed flag:
m_bModified = true;
}
}
// **************************************************************************
// UpdateStatus ()
//
// Description:
// Update status of dialog controls based on current item selected.
//
// Parameters:
// none
//
// Returns:
// void
// **************************************************************************
void CAddItemDlg::UpdateStatus ()
{
// Determine the focus so that if we disable the focused control
// we can move it.
HWND hWnd = ::GetFocus ();
// Enable the next button if the selected item has an item ID defined:
// Update the browse controls:
m_pBranchList->EnableWindow (m_pIBrowse != NULL);
m_pLeafList->EnableWindow (m_pIBrowse != NULL);
// Set the focus to the first control if the previous control with the
// focus just lost it:
if (hWnd && !::IsWindowEnabled (hWnd))
GetDlgItem (IDC_ITEMID)->SetFocus ();
}
// **************************************************************************
// InitializeBrowser ()
//
// Description:
// Initialize things related to the browser.
//
// Parameters:
// none
//
// Returns:
// void
// **************************************************************************
void CAddItemDlg::InitializeBrowser ()
{
// Get pointers to our browse controls for easy access:
m_pBranchList = (CTreeCtrl *) GetDlgItem (IDC_BRANCHLIST);
ASSERT (m_pBranchList != NULL);
m_pLeafList = (CListCtrl *) GetDlgItem (IDC_LEAFLIST);
ASSERT (m_pLeafList != NULL);
// Insert a column for our leaf item list control:
CRect rc;
m_pLeafList->GetClientRect (&rc);
m_pLeafList->InsertColumn (0, _T(""), LVCFMT_LEFT, rc.Width ());
// Intialize browse controls if browsing is supported, otherwise
// just disable the controls:
if (m_pIBrowse != NULL)
{
// Create a wait cursor object. This will cause the wait cursor,
// usually an hourglass, to be displayed. When this object goes
// out of scope, its destructor will restore the previous cursor
// type.
CWaitCursor wc;
HRESULT hr;
// Query the server name space:
hr = m_pIBrowse->QueryOrganization (&m_cOpcNameSpace);
if (SUCCEEDED (hr))
{
// Browse root level:
switch (m_cOpcNameSpace)
{
case OPC_NS_HIERARCHIAL:
case OPC_NS_FLAT:
BrowseRootLevel ();
break;
// Did the foundation add a new type?
default:
ASSERT (FALSE);
break;
}
}
// We will assume a hierarchial search if the server fails this request:
// (This allows us to work with any server that uses the ICONICS toolkit.)
else
{
TRACE (_T("OTC: Attempting agressive browsing since the server failed on QueryOrganization ()\r\n"));
m_cOpcNameSpace = OPC_NS_HIERARCHIAL;
BrowseRootLevel ();
}
}
}
// **************************************************************************
// BrowseRootLevel ()
//
// Description:
// Reset the browser to the root object.
//
// Parameters:
// none
//
// Returns:
// void
// **************************************************************************
void CAddItemDlg::BrowseRootLevel ()
{
HRESULT hr = E_FAIL;
HTREEITEM hItem = NULL;
try
{
// If hierarchial namespace:
if (m_cOpcNameSpace == OPC_NS_HIERARCHIAL)
{
// Re-initialize server's browse position to the root:
do
{
// Use the OPC_BROWSE_UP rather than the OPC_BROWSE_TO which
// is only supported in OOPC version 2.0. We will have to
// browse up to root one level at a time. Function will
// fail when we are at root.
hr = m_pIBrowse->ChangeBrowsePosition (OPC_BROWSE_UP, L"\0");
} while (SUCCEEDED (hr));
// Insert our root level item:
hItem = m_pBranchList->InsertItem ((m_pGroup->GetParentServer ())->GetServerName(),
ILI_BRANCH, ILI_SELBRANCH, TVI_ROOT);
// Set the item data and add a dummy child branch:
m_pBranchList->SetItemData (hItem, DWORD (-1));
AddDummyBranch (hItem);
}
// Else flat namespace:
else
{
ASSERT (m_cOpcNameSpace == OPC_NS_FLAT);
// Insert our root level item (there is no need to add any dummy
// branches since a flat space will only have one level of leaves)
hItem = m_pBranchList->InsertItem ((m_pGroup->GetParentServer ())->GetServerName (),
ILI_BRANCH, ILI_SELBRANCH, TVI_ROOT);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -