2020-09-30 16:53:55 +02:00

1189 lines
34 KiB
C++

// qryprop.cpp - Query Property Page Implementation
#include "stdafx.h"
#include "resource.h"
#include "qryprop.h"
#include "compdata.h"
#include "scopenode.h"
#include "query.h"
#include "cmndlgs.h"
#include "util.h"
#include "namemap.h"
#define SECURITY_WIN32
#include <security.h> // TranslateName
#include <windowsx.h>
#include <algorithm>
#undef SubclassWindow
int GetDateTimeString(FILETIME* pftime, LPWSTR pszBuf, int cBuf);
void LoadObjectCB(CComboBox& ComboBox, QueryObjVector& vObj);
#define CHECK_OFF INDEXTOSTATEIMAGEMASK(1)
#define CHECK_ON INDEXTOSTATEIMAGEMASK(2)
///////////////////////////////////////////////////////////////////////////////////////////
// CQueryGeneralPage
CQueryGeneralPage::CQueryGeneralPage(CQueryEditObj* pEditObj)
: m_EditObject(*pEditObj)
{
ASSERT(pEditObj != NULL);
m_EditObject.AddRef();
}
CQueryGeneralPage::~CQueryGeneralPage()
{
m_EditObject.Release();
}
LRESULT CQueryGeneralPage::OnInitDialog(UINT mMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if( !m_EditObject.m_spQueryNode ) return 0;
// display query node icon
HICON hIcon = ::LoadIcon(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDI_QUERYNODE));
Static_SetIcon(GetDlgItem(IDC_QUERYICON), hIcon);
// fill dialog fields with query node info
tstring strTempQuery;
m_EditObject.m_spQueryNode->ExpandQuery(strTempQuery);
CQueryNode* pQNode = m_EditObject.m_spQueryNode;
SetDlgItemText( IDC_NAME, m_EditObject.m_spQueryNode->GetName() );
SetDlgItemText( IDC_FILTER, strTempQuery.c_str() );
tstring strComment;
m_EditObject.m_spQueryNode->GetComment(strComment);
SetDlgItemText( IDC_COMMENTS, strComment.c_str() );
Edit_LimitText(GetDlgItem(IDC_COMMENTS), 255);
// set scope source toggle button
UINT uButton = m_EditObject.m_spQueryNode->UseLocalScope() ? IDC_LOCALSCOPE : IDC_QUERYSCOPE;
Button_SetCheck(GetDlgItem(uButton), BST_CHECKED);
tstring strScope = m_EditObject.m_spQueryNode->Scope();
tstring strDisplay;
GetScopeDisplayString(strScope, strDisplay);
SetDlgItemText( IDC_SCOPE, strDisplay.c_str() );
// if using local scope, then set the persisted scope equal to the local scope so that the
// user won't see an obsolete scope that may have been saved when creating the node.
if( m_EditObject.m_spQueryNode->UseLocalScope() )
m_EditObject.m_spQueryNode->SetScope(strScope.c_str());
// if classes known, display comma separated class names
if( m_EditObject.m_vObjInfo.size() != 0 )
{
DisplayNameMap* pNameMap = DisplayNames::GetClassMap();
ASSERT(pNameMap != NULL);
if( pNameMap != NULL )
{
QueryObjVector::iterator itQObj = m_EditObject.m_vObjInfo.begin();
tstring strClasses = pNameMap->GetAttributeDisplayName(itQObj->Name());
for( itQObj++; itQObj != m_EditObject.m_vObjInfo.end(); ++itQObj )
{
strClasses += L", ";
strClasses += pNameMap->GetAttributeDisplayName(itQObj->Name());
}
SetDlgItemText( IDC_OBJCLASS, strClasses.c_str() );
}
}
return TRUE;
}
LRESULT CQueryGeneralPage::OnScopeChange(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
if( !m_EditObject.m_spQueryNode ) return 0;
// if user changes scope selection then display the correct scope
tstring strScope;
if( Button_GetCheck(GetDlgItem(IDC_LOCALSCOPE)) == BST_CHECKED )
strScope = GetLocalDomain();
else
strScope = m_EditObject.m_spQueryNode->QueryScope();
tstring strDisplay;
GetScopeDisplayString(strScope, strDisplay);
SetDlgItemText( IDC_SCOPE, strDisplay.c_str() );
SetModified(TRUE);
return 0;
}
LRESULT CQueryGeneralPage::OnChange(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
SetModified(TRUE);
return 0;
}
//------------------------------------------------------------------------------------
// CRootGeneralPage::OnClose
//
// This method is invoked when an edit box receives an Esc char. The method converts
// the WM_CLOSE message into a command to close the property sheet. Otherwise the
// WM_CLOSE message has no effect.
//------------------------------------------------------------------------------------
LRESULT CQueryGeneralPage::OnClose( UINT mMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
// Simulate press of Cancel button
::PropSheet_PressButton(GetParent(), PSBTN_CANCEL);
return 0;
}
BOOL CQueryGeneralPage::OnSetActive()
{
m_EditObject.PageActive(m_hWnd);
return TRUE;
}
BOOL CQueryGeneralPage::OnApply()
{
if( !m_EditObject.m_spQueryNode ) return FALSE;
tstring strComment;
GetItemText(GetDlgItem(IDC_COMMENTS), strComment);
m_EditObject.m_spQueryNode->SetComment(strComment.c_str());
bool bLocal = (Button_GetCheck(GetDlgItem(IDC_LOCALSCOPE)) == BST_CHECKED);
m_EditObject.m_spQueryNode->SetLocalScope(bLocal);
return m_EditObject.ApplyChanges(m_hWnd);
}
///////////////////////////////////////////////////////////////////////////////////////////
// CQueryMenuPage
CQueryMenuPage::CQueryMenuPage(CQueryEditObj* pEditObj)
: m_EditObject(*pEditObj), m_pObjSel(NULL), m_bLoading(FALSE)
{
ASSERT(pEditObj != NULL);
m_EditObject.AddRef();
}
CQueryMenuPage::~CQueryMenuPage()
{
m_ObjectCB.Detach();
m_EditObject.Release();
}
LRESULT CQueryMenuPage::OnInitDialog( UINT mMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
HWND hwndList = GetDlgItem(IDC_MENULIST);
ASSERT( hwndList );
if( hwndList )
{
m_MenuLV.SubclassWindow(hwndList);
RECT rc;
BOOL bStat = m_MenuLV.GetClientRect(&rc);
ASSERT(bStat);
int iWidth = (rc.right - rc.left) - GetSystemMetrics(SM_CXVSCROLL);
CString strName;
strName.LoadString(IDS_MENUITEM);
int iCol = m_MenuLV.InsertColumn(0, strName, LVCFMT_LEFT, (iWidth + 1)/2, 0);
ASSERT(iCol == 0);
strName.LoadString(IDS_TYPE);
iCol = m_MenuLV.InsertColumn(1, strName, LVCFMT_LEFT, iWidth/2, 1);
ASSERT(iCol == 1);
m_MenuLV.SetExtendedListViewStyle(LVS_EX_CHECKBOXES|LVS_EX_FULLROWSELECT);
}
HWND hwndCombo = GetDlgItem(IDC_OBJECTLIST);
ASSERT(hwndCombo);
if( hwndCombo )
{
m_ObjectCB.Attach(hwndCombo);
LoadObjectCB(m_ObjectCB, m_EditObject.m_vObjInfo);
if( m_EditObject.m_vObjInfo.size() != 0 )
{
m_ObjectCB.SetCurSel(0);
m_pObjSel = reinterpret_cast<CQueryObjInfo*>(m_ObjectCB.GetItemDataPtr(0));
if( hwndList )
{
DisplayMenus();
}
}
}
return TRUE;
}
void CQueryMenuPage::DisplayMenus()
{
if( m_pObjSel == NULL )
return;
if( !m_EditObject.m_spQueryNode ) return;
m_bLoading = TRUE;
m_MenuLV.DeleteAllItems();
m_DefaultID = 0;
CRootNode* pRootNode = m_EditObject.m_spQueryNode->GetRootNode();
if( !pRootNode ) return;
CClassInfo* pClassInfo = pRootNode->FindClass(m_pObjSel->Name());
if( pClassInfo != NULL )
{
int iIndex = 0;
menuref_vector& vMenuRefs = m_pObjSel->MenuRefs();
menuref_vector::iterator itMenuRef;
menucmd_vector& vMenuCmds = pClassInfo->Menus();
menucmd_vector::iterator itMenuCmd;
// First add all root menu items that are not yet ref'd by the query node
for( itMenuCmd = vMenuCmds.begin(); itMenuCmd != vMenuCmds.end(); ++itMenuCmd )
{
if( std::find(vMenuRefs.begin(), vMenuRefs.end(), (*itMenuCmd)->ID()) != vMenuRefs.end() )
break;
// Add menu to displayed list in an enabled state
DisplayMenuItem(iIndex++, *itMenuCmd, TRUE);
}
// For each query menu reference
for( itMenuRef = vMenuRefs.begin(); itMenuRef != vMenuRefs.end(); ++itMenuRef )
{
// Find the matching root menu cmd
for( itMenuCmd = vMenuCmds.begin(); itMenuCmd != vMenuCmds.end(); ++itMenuCmd )
{
if( (*itMenuCmd)->ID() == itMenuRef->ID() )
break;
}
// if menu was deleted at the root node, then skip it
if( itMenuCmd == vMenuCmds.end() )
continue;
// Display the menu item
DisplayMenuItem(iIndex++, *(itMenuCmd++), itMenuRef->IsEnabled());
// If this is the default menu item save its ID
if( itMenuRef->IsDefault() )
{
ASSERT(m_DefaultID == 0);
m_DefaultID = itMenuRef->ID();
}
// Display any following root items that aren't in the query list
while( itMenuCmd != vMenuCmds.end() &&
std::find(vMenuRefs.begin(), vMenuRefs.end(), (*itMenuCmd)->ID()) == vMenuRefs.end() )
{
DisplayMenuItem(iIndex++, *(itMenuCmd++), TRUE);
}
}
}
// Disable buttons until selection made
EnableDlgItem( m_hWnd, IDC_MOVEUP, FALSE );
EnableDlgItem( m_hWnd, IDC_MOVEDOWN, FALSE );
EnableDlgItem( m_hWnd, IDC_DEFAULTMENU, FALSE );
// Uncheck default button until default item selected
Button_SetCheck(GetDlgItem(IDC_DEFAULTMENU), BST_UNCHECKED);
// Set Property Menu Checkbox
Button_SetCheck(GetDlgItem(IDC_PROPERTYMENU), m_pObjSel->HasPropertyMenu() ? BST_CHECKED : BST_UNCHECKED);
m_bLoading = FALSE;
}
void CQueryMenuPage::DisplayMenuItem(int iIndex, CMenuCmd* pMenuCmd, BOOL bEnabled)
{
if( !pMenuCmd ) return;
static CString strShellCmd;
static CString strADCmd;
LV_ITEM lvi;
lvi.mask = LVIF_TEXT | LVIF_PARAM;
lvi.iItem = iIndex;
lvi.iSubItem = 0;
lvi.pszText = const_cast<LPWSTR>(pMenuCmd->Name());
lvi.lParam = static_cast<LPARAM>(pMenuCmd->ID());
int iPos = m_MenuLV.InsertItem(&lvi);
ASSERT(iPos == iIndex);
lvi.iSubItem = 1;
lvi.mask = LVIF_TEXT;
switch( pMenuCmd->MenuType() )
{
case MENUTYPE_SHELL:
if( strShellCmd.IsEmpty() )
strShellCmd.LoadString(IDS_SHELLCMD);
lvi.pszText = (LPWSTR)(LPCWSTR)strShellCmd;
break;
case MENUTYPE_ACTDIR:
if( strADCmd.IsEmpty() )
strADCmd.LoadString(IDS_DISPSPEC);
lvi.pszText = (LPWSTR)(LPCWSTR)strADCmd;
break;
default:
ASSERT(FALSE);
}
m_MenuLV.SetItem(&lvi);
m_MenuLV.SetCheckState(iIndex, bEnabled);
}
LRESULT CQueryMenuPage::OnObjectSelect( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
{
int iItem = m_ObjectCB.GetCurSel();
// Double-clicking an empty combo box can call this with no selection
if( iItem >= 0 )
{
SaveMenuSet();
m_pObjSel = reinterpret_cast<CQueryObjInfo*>(m_ObjectCB.GetItemDataPtr(iItem));
DisplayMenus();
}
return 0;
}
LRESULT CQueryMenuPage::OnMoveUpDown( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
{
int iItem = m_MenuLV.GetNextItem(-1, LVNI_SELECTED);
ASSERT(iItem >= 0);
// Get the selected item data
WCHAR szName[100];
LVITEM lvi;
lvi.mask = LVIF_TEXT|LVIF_PARAM|LVIF_STATE;
lvi.stateMask = 0xFFFFFFFF;
lvi.iSubItem = 0;
lvi.iItem = iItem;
lvi.pszText = szName;
lvi.cchTextMax = sizeof(szName);
m_MenuLV.GetItem(&lvi);
WCHAR szType[100];
m_MenuLV.GetItemText(iItem, 1, szType, sizeof(szType));
// Set loading flag to avoid intermediate button enable/disables
m_bLoading = TRUE;
// Delete and insert at new position
m_MenuLV.DeleteItem(iItem);
lvi.iItem += (wID == IDC_MOVEUP) ? -1 : 1;
m_MenuLV.InsertItem(&lvi);
m_MenuLV.SetItemText(lvi.iItem, 1, szType);
// re-establish checked state (insert doesn't retain it)
if( lvi.state & CHECK_ON )
m_MenuLV.SetCheckState(lvi.iItem, TRUE);
m_bLoading = FALSE;
SetModified(TRUE);
// update button states
EnableDlgItem( m_hWnd, IDC_MOVEUP, (lvi.iItem > 0) );
EnableDlgItem( m_hWnd, IDC_MOVEDOWN, (lvi.iItem < (m_MenuLV.GetItemCount() - 1)) );
return 0;
}
LRESULT CQueryMenuPage::OnMenuChanged(int idCtrl, LPNMHDR pNMHDR, BOOL& bHandled)
{
if( !pNMHDR ) return 0;
if( !m_bLoading )
{
LPNMLISTVIEW pnmv = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
// if state has changed
if( pnmv->uChanged & LVIF_STATE )
{
// if checkbox state change
if( (pnmv->uNewState ^ pnmv->uOldState) & LVIS_STATEIMAGEMASK )
{
// if the changed item is currently selected
if( m_MenuLV.GetItemState(pnmv->iItem, LVIS_SELECTED) & LVIS_SELECTED )
{
// Change the state of all selcted items to match
BOOL bNewState = ((pnmv->uNewState & LVIS_STATEIMAGEMASK) == CHECK_ON);
m_bLoading = TRUE;
int iItem = -1;
while( (iItem = m_MenuLV.GetNextItem(iItem, LVNI_SELECTED)) >= 0 )
{
m_MenuLV.SetCheckState(iItem, bNewState);
}
m_bLoading = FALSE;
}
SetModified(TRUE);
}
if( (pnmv->uNewState ^ pnmv->uOldState) & LVIS_SELECTED )
{
int nItems = m_MenuLV.GetItemCount();
int iItem = m_MenuLV.GetNextItem(-1, LVNI_SELECTED);
int nSelected = m_MenuLV.GetSelectedCount();
BOOL bDefault = (nSelected == 1) && (m_MenuLV.GetItemData(iItem) == m_DefaultID);
Button_SetCheck(GetDlgItem(IDC_DEFAULTMENU), bDefault ? BST_CHECKED : BST_UNCHECKED);
EnableDlgItem( m_hWnd, IDC_MOVEUP, ((iItem > 0) && (nSelected == 1)) );
EnableDlgItem( m_hWnd, IDC_MOVEDOWN, ((iItem >= 0) && (iItem < (nItems - 1)) && (nSelected == 1)) );
EnableDlgItem( m_hWnd, IDC_DEFAULTMENU, (nSelected == 1) );
}
}
}
return TRUE;
}
LRESULT CQueryMenuPage::OnDefaultChanged(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
// if user checks the default then save currently selected menu ID as default
if( Button_GetCheck(GetDlgItem(IDC_DEFAULTMENU)) == BST_CHECKED )
{
// button should be disabled unless there is one menu item selected
ASSERT(m_MenuLV.GetSelectedCount() == 1);
int iItem = m_MenuLV.GetNextItem(-1, LVNI_SELECTED);
m_DefaultID = m_MenuLV.GetItemData(iItem);
}
else
{
// if user unchecks box there is no default
m_DefaultID = 0;
}
SetModified(TRUE);
return 0;
}
LRESULT CQueryMenuPage::OnPropertyMenuChanged(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
SetModified(TRUE);
return 0;
}
void CQueryMenuPage::SaveMenuSet()
{
if( m_pObjSel == NULL )
return;
m_pObjSel->m_vMenuRefs.clear();
LVITEM lvi;
lvi.mask = LVIF_PARAM | LVIF_STATE;
lvi.stateMask = LVIS_STATEIMAGEMASK;
lvi.iSubItem = 0;
int nItems = m_MenuLV.GetItemCount();
for( int iIndex = 0; iIndex < nItems; iIndex++ )
{
lvi.iItem = iIndex;
BOOL bStat = m_MenuLV.GetItem(&lvi);
ASSERT(bStat);
CMenuRef menuref;
menuref.m_menuID = static_cast<MenuID>(lvi.lParam);
menuref.SetEnable((lvi.state & LVIS_STATEIMAGEMASK) == CHECK_ON);
menuref.SetDefault(menuref.m_menuID == m_DefaultID);
m_pObjSel->m_vMenuRefs.push_back(menuref);
}
m_pObjSel->SetPropertyMenu( Button_GetCheck(GetDlgItem(IDC_PROPERTYMENU)) == BST_CHECKED );
}
BOOL CQueryMenuPage::OnSetActive()
{
m_EditObject.PageActive(m_hWnd);
return TRUE;
}
BOOL CQueryMenuPage::OnApply()
{
SaveMenuSet();
return m_EditObject.ApplyChanges(m_hWnd);
}
///////////////////////////////////////////////////////////////////////////////////////////
// CQueryViewPage
CQueryViewPage::CQueryViewPage(CQueryEditObj* pEditObj)
: m_EditObject(*pEditObj), m_bLoading(FALSE), m_pObjSel(NULL)
{
ASSERT(pEditObj != NULL);
m_EditObject.AddRef();
}
CQueryViewPage::~CQueryViewPage()
{
m_ObjectCB.Detach();
m_EditObject.Release();
}
LRESULT CQueryViewPage::OnInitDialog( UINT mMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
HWND hwndList = GetDlgItem(IDC_COLUMNLIST);
if( hwndList )
{
m_ColumnLV.SubclassWindow(hwndList);
RECT rc;
BOOL bStat = m_ColumnLV.GetClientRect(&rc);
ASSERT(bStat);
int iCol = m_ColumnLV.InsertColumn(0, NULL, LVCFMT_LEFT, (rc.right - rc.left), 0);
ASSERT(iCol == 0);
m_ColumnLV.SetExtendedListViewStyle(LVS_EX_CHECKBOXES);
}
HWND hwndCombo = GetDlgItem(IDC_OBJECTLIST);
if( hwndCombo )
{
m_ObjectCB.Attach(hwndCombo);
LoadObjectCB(m_ObjectCB, m_EditObject.m_vObjInfo);
if( m_EditObject.m_vObjInfo.size() != 0 )
{
m_ObjectCB.SetCurSel(0);
m_pObjSel = reinterpret_cast<CQueryObjInfo*>(m_ObjectCB.GetItemDataPtr(0));
if( hwndList )
{
DisplayColumns();
}
}
}
return TRUE;
}
LRESULT CQueryViewPage::OnObjectSelect( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
{
int iItem = m_ObjectCB.GetCurSel();
// Double-clicking an empty combo box can call this with no selection
if( iItem >= 0 )
{
SaveColumnSet();
m_pObjSel = reinterpret_cast<CQueryObjInfo*>(m_ObjectCB.GetItemDataPtr(iItem));
DisplayColumns();
}
return 0;
}
void CQueryViewPage::DisplayColumns()
{
if( !m_pObjSel ) return;
if( !m_EditObject.m_spQueryNode ) return;
m_bLoading = TRUE;
m_ColumnLV.DeleteAllItems();
LV_ITEM lvi;
lvi.mask = LVIF_TEXT | LVIF_PARAM;
lvi.iItem = 0;
lvi.iSubItem = 0;
CRootNode* pRootNode = m_EditObject.m_spQueryNode->GetRootNode();
if( !pRootNode ) return;
CClassInfo* pClassInfo = pRootNode->FindClass(m_pObjSel->Name());
if( pClassInfo != NULL )
{
DisplayNameMap* pNameMap = DisplayNames::GetMap(m_pObjSel->Name());
ASSERT(pNameMap != NULL);
if( pNameMap == NULL )
return;
string_vector& vDisabledCols = m_pObjSel->DisabledColumns();
string_vector::iterator itstrCol;
for( itstrCol = pClassInfo->Columns().begin(); itstrCol != pClassInfo->Columns().end(); ++itstrCol )
{
lvi.pszText = const_cast<LPWSTR>(pNameMap->GetAttributeDisplayName(itstrCol->c_str()));
lvi.lParam = reinterpret_cast<LPARAM>(itstrCol->c_str());
int iPos = m_ColumnLV.InsertItem(&lvi);
ASSERT(iPos >= 0);
//Enable all columns that aren't excluded by the query node
if( std::find(vDisabledCols.begin(), vDisabledCols.end(), *itstrCol) == vDisabledCols.end() )
m_ColumnLV.SetCheckState(iPos, TRUE);
}
}
m_bLoading = FALSE;
}
LRESULT CQueryViewPage::OnColumnChanged(int idCtrl, LPNMHDR pNMHDR, BOOL& bHandled)
{
if( !pNMHDR ) return 0;
if( !m_bLoading )
{
LPNMLISTVIEW pnmv = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
// if checked state has changed
if( (pnmv->uChanged & LVIF_STATE) &&
((pnmv->uNewState ^ pnmv->uOldState) & LVIS_STATEIMAGEMASK) )
{
// if the changed item is currently selected
if( m_ColumnLV.GetItemState(pnmv->iItem, LVIS_SELECTED) & LVIS_SELECTED )
{
// Change the state of all selcted items to match
BOOL bNewState = ((pnmv->uNewState & LVIS_STATEIMAGEMASK) == CHECK_ON);
m_bLoading = TRUE;
int iItem = -1;
while( (iItem = m_ColumnLV.GetNextItem(iItem, LVNI_SELECTED)) >= 0 )
{
m_ColumnLV.SetCheckState(iItem, bNewState);
}
m_bLoading = FALSE;
}
SetModified(TRUE);
}
}
return TRUE;
}
void CQueryViewPage::SaveColumnSet()
{
if( m_pObjSel == NULL )
return;
string_vector vstrNewCols;
int nItems = m_ColumnLV.GetItemCount();
for( int iIndex = 0; iIndex < nItems; iIndex++ )
{
// Save list of disabled columns
if( !m_ColumnLV.GetCheckState(iIndex) )
{
LVITEM lvi;
lvi.mask = LVIF_PARAM;
lvi.iItem = iIndex;
lvi.iSubItem = 0;
BOOL bStat = m_ColumnLV.GetItem(&lvi);
ASSERT(bStat);
vstrNewCols.push_back(reinterpret_cast<LPCWSTR>(lvi.lParam));
}
}
m_pObjSel->m_vstrDisabledColumns = vstrNewCols;
}
typedef struct
{
HWND hwndList;
int iCol;
}
COMPAREPARAM, *LPCOMPAREPARAM;
int CALLBACK ColumnCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
if( !lParamSort ) return 0;
LPCOMPAREPARAM pcmp = reinterpret_cast<LPCOMPAREPARAM>(lParamSort);
WCHAR sz1[MAX_PATH];
ListView_GetItemText(pcmp->hwndList, lParam1, pcmp->iCol, sz1, MAX_PATH);
WCHAR sz2[MAX_PATH];
ListView_GetItemText(pcmp->hwndList, lParam2, pcmp->iCol, sz2, MAX_PATH);
return wcscmp(sz1,sz2);
}
LRESULT CQueryViewPage::OnColumnClick(int idCtrl, LPNMHDR pNMHDR, BOOL& bHandled)
{
if( !pNMHDR ) return 0;
LPNMLISTVIEW pnmv = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
COMPAREPARAM cmp;
cmp.hwndList = pnmv->hdr.hwndFrom;
cmp.iCol = pnmv->iSubItem;
ListView_SortItemsEx(pnmv->hdr.hwndFrom, &ColumnCompare, &cmp);
return TRUE;
}
BOOL CQueryViewPage::OnSetActive()
{
DisplayColumns();
m_EditObject.PageActive(m_hWnd);
return TRUE;
}
BOOL CQueryViewPage::OnApply()
{
SaveColumnSet();
return m_EditObject.ApplyChanges(m_hWnd);
}
///////////////////////////////////////////////////////////////////////////////////////////
// CQueryNodeMenuPage
CQueryNodeMenuPage::CQueryNodeMenuPage(CQueryEditObj* pEditObj)
: m_EditObject(*pEditObj)
{
ASSERT(pEditObj != NULL);
m_EditObject.AddRef();
}
CQueryNodeMenuPage::~CQueryNodeMenuPage()
{
m_MenuLV.Detach();
m_EditObject.Release();
}
LRESULT CQueryNodeMenuPage::OnInitDialog( UINT mMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
m_MenuLV.Attach(GetDlgItem(IDC_MENULIST));
::ConfigSingleColumnListView(GetDlgItem(IDC_MENULIST));
return TRUE;
}
BOOL CQueryNodeMenuPage::OnSetActive()
{
m_EditObject.PageActive(m_hWnd);
DisplayMenus();
return TRUE;
}
void CQueryNodeMenuPage::DisplayMenus()
{
if( !m_EditObject.m_spQueryNode ) return;
HWND hwndLV = GetDlgItem(IDC_MENULIST);
ASSERT(::IsWindow(hwndLV));
ListView_DeleteAllItems(hwndLV);
// make sure menu names have been loaded
CRootNode* pRootNode = m_EditObject.m_spQueryNode->GetRootNode();
if( !pRootNode ) return;
CComponentData* pCompData = pRootNode->GetCompData();
if( !pCompData ) return;
IStringTable* pStringTable = pCompData->GetStringTable();
ASSERT(pStringTable != NULL);
if( !pStringTable ) return;
m_EditObject.LoadStrings(pStringTable);
LV_ITEM lvi;
lvi.mask = LVIF_TEXT | LVIF_PARAM;
lvi.iItem = 0;
lvi.iSubItem = 0;
menucmd_vector::iterator itMenu;
for( itMenu = m_EditObject.Menus().begin(); itMenu != m_EditObject.Menus().end(); ++itMenu )
{
lvi.pszText = const_cast<LPWSTR>((*itMenu)->Name());
lvi.lParam = (*itMenu)->ID();
int iPos = ListView_InsertItem(hwndLV, &lvi);
ASSERT(iPos >= 0);
lvi.iItem++;
}
EnableDlgItem( m_hWnd, IDC_ADDMENU, TRUE );
EnableDlgItem( m_hWnd, IDC_REMOVEMENU, FALSE );
EnableDlgItem( m_hWnd, IDC_EDITMENU, FALSE );
EnableDlgItem( m_hWnd, IDC_MOVEUP, FALSE );
EnableDlgItem( m_hWnd, IDC_MOVEDOWN, FALSE );
}
LRESULT CQueryNodeMenuPage::OnAddMenu( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
{
if( !m_EditObject.m_spQueryNode ) return 0;
CAddQNMenuDlg dlg(m_EditObject);
if( dlg.DoModal() == IDOK )
{
CMenuCmd* pMenuNew = dlg.GetMenu();
ASSERT(pMenuNew != NULL);
if( !pMenuNew ) return 0;
// Add new menu to list
HWND hwndList = GetDlgItem(IDC_MENULIST);
// Set name to add it to string table and generate the menu ID
CRootNode* pRootNode = m_EditObject.m_spQueryNode->GetRootNode();
if( !pRootNode ) return 0;
CComponentData* pCompData = pRootNode->GetCompData();
ASSERT( pCompData );
if( !pCompData ) return 0;
IStringTable* pStringTable = pCompData->GetStringTable();
ASSERT( pStringTable );
if( !pStringTable ) return 0;
// Use temp string because string fails an assignement like: strX = strX.c_str()
// (it relases the private buffer first and then assigns the string)
tstring strName = pMenuNew->Name();
pMenuNew->SetName(pStringTable, strName.c_str());
LVITEM lvi;
lvi.mask = LVIF_PARAM | LVIF_TEXT;
lvi.iSubItem = 0;
lvi.iItem = ListView_GetItemCount(hwndList);
lvi.lParam = pMenuNew->ID();
lvi.pszText = const_cast<LPWSTR>(pMenuNew->Name());
ListView_InsertItem(hwndList,&lvi);
// Add to menu vector (note that temp CMenuCmdPtr will delete pMenuNew)
m_EditObject.m_vMenus.push_back(CMenuCmdPtr(pMenuNew));
SetModified(TRUE);
}
return 0;
}
LRESULT CQueryNodeMenuPage::OnEditMenu( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
{
if( !m_EditObject.m_spQueryNode ) return 0;
HWND hwndList = GetDlgItem(IDC_MENULIST);
int iIndex = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
ASSERT(iIndex != -1);
LVITEM lvi;
lvi.mask = LVIF_PARAM;
lvi.iSubItem = 0;
lvi.iItem = iIndex;
ListView_GetItem(hwndList, &lvi);
// Locate selected menu by it's ID (lparam)
menucmd_vector& vMenus = m_EditObject.Menus();
menucmd_vector::iterator itMenu;
itMenu = std::find(vMenus.begin(), vMenus.end(), lvi.lParam);
ASSERT(itMenu != vMenus.end());
CMenuCmd* pMenu = *itMenu;
if( !pMenu ) return 0;
CAddQNMenuDlg dlg(m_EditObject, pMenu);
if( dlg.DoModal() == IDOK )
{
CMenuCmd* pMenuNew = dlg.GetMenu();
ASSERT(pMenuNew != NULL);
if( !pMenuNew ) return 0;
// Set the name again in case it was changed
CRootNode* pRootNode = m_EditObject.m_spQueryNode->GetRootNode();
if( !pRootNode ) return 0;
CComponentData* pCompData = pRootNode->GetCompData();
if( !pCompData ) return 0;
IStringTable* pStringTable = pCompData->GetStringTable();
ASSERT(pStringTable != NULL);
if( !pStringTable ) return 0;
// Use temp string because string fails an assignement like: strX = strX.c_str()
// (it relases the private buffer first and then assigns the string)
tstring strName = pMenuNew->Name();
pMenuNew->SetName(pStringTable, strName.c_str());
// locate object again because the vector may have been reallocated
menucmd_vector& vMenusNew = m_EditObject.Menus();
// locate with the old ID because it will be different if the name was changed
itMenu = std::find(vMenusNew.begin(), vMenusNew.end(), pMenu->ID());
ASSERT(itMenu != vMenusNew.end());
// Replace menu with new one
*itMenu = pMenuNew;
// Update the list
lvi.mask = LVIF_PARAM | LVIF_TEXT;
lvi.lParam = pMenuNew->ID();
lvi.pszText = const_cast<LPWSTR>(pMenuNew->Name());
ListView_SetItem(hwndList,&lvi);
SetModified(TRUE);
}
return 0;
}
LRESULT CQueryNodeMenuPage::OnRemoveMenu( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
{
HWND hwndList = GetDlgItem(IDC_MENULIST);
UINT uiMsg = (ListView_GetSelectedCount(hwndList) == 1) ? IDS_MENU_REMOVE_ONE : IDS_MENU_REMOVE;
int iRet = DisplayMessageBox(m_hWnd, IDS_MENU_REMOVE_TITLE, uiMsg, MB_YESNO|MB_ICONWARNING);
if( iRet != IDYES )
return 0;
menucmd_vector& vMenus = m_EditObject.Menus();
LVITEM lvi;
lvi.mask = LVIF_PARAM;
lvi.iSubItem = 0;
int iIndex = -1;
while( (iIndex = ListView_GetNextItem(hwndList, iIndex, LVNI_SELECTED)) >= 0 )
{
lvi.iItem = iIndex;
ListView_GetItem(hwndList, &lvi);
// Locate menu by its ID
menucmd_vector::iterator itMenu = std::find(vMenus.begin(), vMenus.end(), lvi.lParam);
ASSERT(itMenu != vMenus.end());
vMenus.erase(itMenu);
ListView_DeleteItem(hwndList, iIndex);
iIndex--;
}
EnableDlgItem( m_hWnd, IDC_REMOVEMENU, FALSE );
EnableDlgItem( m_hWnd, IDC_EDITMENU, FALSE );
EnableDlgItem( m_hWnd, IDC_MOVEUP, FALSE );
EnableDlgItem( m_hWnd, IDC_MOVEDOWN, FALSE );
SetModified(TRUE);
return 0;
}
LRESULT CQueryNodeMenuPage::OnMoveUpDown( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled )
{
HWND hwndList = GetDlgItem(IDC_MENULIST);
int iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
ASSERT(iItem >= 0);
// Determine new position for selected item
if( wID == IDC_MOVEUP )
iItem--;
else
iItem++;
// Now swap the selected item with the item at its new position
// Do it by moving the unselected item to avoid state change notifications
// because they will cause unwanted butten enables/disables.
LVITEM lvi;
lvi.mask = LVIF_PARAM;
lvi.iSubItem = 0;
lvi.iItem = iItem;
ListView_GetItem(hwndList, &lvi);
// Move the menu item in the menu vector
menucmd_vector& vMenus = m_EditObject.Menus();
menucmd_vector::iterator itMenu = std::find(vMenus.begin(), vMenus.end(), lvi.lParam);
ASSERT(itMenu != vMenus.end());
menucmd_vector::iterator itMenuOld = itMenu;
if( wID == IDC_MOVEUP )
itMenu++;
else
itMenu--;
// swap the items
std::iter_swap (itMenuOld, itMenu);
//Now delete and reinsert it in the list view
ListView_DeleteItem(hwndList, lvi.iItem);
if( wID == IDC_MOVEUP )
lvi.iItem++;
else
lvi.iItem--;
lvi.mask = LVIF_PARAM | LVIF_TEXT;
lvi.pszText = const_cast<LPWSTR>((*itMenu)->Name());
ListView_InsertItem(hwndList, &lvi);
// Update Up/Down buttons
EnableDlgItem( m_hWnd, IDC_MOVEUP, (iItem > 0) );
EnableDlgItem( m_hWnd, IDC_MOVEDOWN, (iItem < (ListView_GetItemCount(hwndList) - 1)) );
SetModified(TRUE);
return 0;
}
LRESULT CQueryNodeMenuPage::OnMenuListChanged(int idCtrl, LPNMHDR pNMHDR, BOOL& bHandled)
{
HWND hwndList = GetDlgItem(IDC_MENULIST);
int nItemSel = ListView_GetSelectedCount(hwndList);
int iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
EnableDlgItem( m_hWnd, IDC_REMOVEMENU, (nItemSel > 0) );
EnableDlgItem( m_hWnd, IDC_EDITMENU, (nItemSel == 1) );
EnableDlgItem( m_hWnd, IDC_MOVEUP, ((nItemSel == 1) && (iItem > 0)) );
EnableDlgItem( m_hWnd, IDC_MOVEDOWN, ((nItemSel == 1) && (iItem < (ListView_GetItemCount(hwndList) - 1))) );
return TRUE;
}
LRESULT CQueryNodeMenuPage::OnMenuListDblClk(int idCtrl, LPNMHDR pNMHDR, BOOL& bHandled)
{
if( ListView_GetSelectedCount(GetDlgItem(IDC_MENULIST)) )
::SendMessage(GetDlgItem(IDC_EDITMENU), BM_CLICK, (WPARAM)0, (LPARAM)0);
return 0;
}
BOOL CQueryNodeMenuPage::OnApply()
{
return m_EditObject.ApplyChanges(m_hWnd);
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// CQueryEditObj
void CQueryEditObj::PageActive(HWND hwndPage)
{
ASSERT(::IsWindow(hwndPage));
// track the highest created page number for ApplyChanges method
int iPage = PropSheet_HwndToIndex(GetParent(hwndPage), hwndPage);
if( iPage > m_iPageMax )
m_iPageMax = iPage;
}
BOOL CQueryEditObj::ApplyChanges(HWND hwndPage)
{
if( !m_spQueryNode ) return FALSE;
ASSERT(::IsWindow(hwndPage));
// Don't apply changes until called from highest activated page
if( PropSheet_HwndToIndex(GetParent(hwndPage), hwndPage) < m_iPageMax )
return TRUE;
// replace original query objects with edited copies
m_spQueryNode->Objects() = m_vObjInfo;
m_spQueryNode->Menus() = m_vMenus;
if( m_spQueryNode )
{
CRootNode* pRootNode = m_spQueryNode->GetRootNode();
if( pRootNode )
{
pRootNode->UpdateModifyTime();
}
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Helper functions
void LoadObjectCB(CComboBox& ComboBox, QueryObjVector& vObj)
{
ComboBox.ResetContent();
DisplayNameMap* pNameMap = DisplayNames::GetClassMap();
ASSERT(pNameMap != NULL);
if( pNameMap == NULL )
return;
for( QueryObjVector::iterator itObj = vObj.begin(); itObj != vObj.end(); ++itObj )
{
int iIndex = ComboBox.AddString(pNameMap->GetAttributeDisplayName(itObj->Name()));
ASSERT(iIndex >= 0);
ComboBox.SetItemDataPtr(iIndex, &(*itObj));
}
}