// WsTabRepl.cpp : implementation file
//
#include "stdafx.h"
#include "DSUtils.h"
#include "resource.h"
#include "WsTabRepl.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// WsTabRepl
WsTabRepl::WsTabRepl(IApplication *pApp):
m_pApp(pApp), m_MkView(pApp), m_uTimerId(0),
m_nPrevTab(-1), m_nPrevVCTab(-1), m_nCurVCTab(-1)
{
LOG(Logger::cDebug, "WsTabRepl::WsTabRepl(){");
m_ChildrenInfo["ClassView"] = ChildInfo(0);
m_ChildrenInfo["ResourceView"] = ChildInfo(1);
m_ChildrenInfo["Data View"] = ChildInfo(2);
m_ChildrenInfo["FileView"] = ChildInfo(3);
m_ChildrenInfo["MkView"] = ChildInfo(4);
LOG(Logger::cDebug, "WsTabRepl::WsTabRepl()}");
}
WsTabRepl::~WsTabRepl()
{
LOG(Logger::cDebug, "WsTabRepl::~WsTabRepl(){");
LOG(Logger::cDebug, "WsTabRepl::~WsTabRepl()}");
}
BEGIN_MESSAGE_MAP(WsTabRepl, CTabCtrl)
//{{AFX_MSG_MAP(WsTabRepl)
ON_NOTIFY_REFLECT(TCN_SELCHANGE, OnSelchange)
ON_NOTIFY_REFLECT(TCN_SELCHANGING, OnSelchanging)
ON_WM_DESTROY()
ON_WM_TIMER()
//}}AFX_MSG_MAP
ON_MESSAGE(WsTabRepl::WM_REGISTERCHILD, OnRegisterchild)
ON_MESSAGE(WsTabRepl::WM_DEREGISTERCHILD, OnDeregisterchild)
ON_MESSAGE(WsTabRepl::WM_ADJUSTSIZE, OnAdjustSize)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// WsTabRepl message handlers
void WsTabRepl::Create(CWnd *pParent)
{
LOG(Logger::cDebug, "WsTabRepl::Create(%p){", pParent);
m_Font.CreateFont(
14, // nHeight
0, // nWidth
0, // nEscapement
0, // nOrientation
FW_NORMAL, // nWeight
FALSE, // bItalic
FALSE, // bUnderline
0, // cStrikeOut
ANSI_CHARSET, // nCharSet
OUT_DEFAULT_PRECIS, // nOutPrecision
CLIP_DEFAULT_PRECIS, // nClipPrecision
DEFAULT_QUALITY, // nQuality
DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily
"Microsoft Sans Serif"); // lpszFacename
RECT rect;
pParent->GetClientRect(&rect);
TEST_BOOL(CreateEx(WS_EX_NOPARENTNOTIFY, WC_TABCONTROL,
NULL, WS_CHILD | WS_VISIBLE | TCS_BOTTOM, rect, pParent, 0));
SetFont(&m_Font, TRUE);
if(TRUE == m_ImageList.Create(16, 16, TRUE, 5, 5))
{
HINSTANCE inst = _Module.GetModuleInstance();
DWORD Ids[] = { IDB_CLASSVIEW, IDB_RESOURCEVIEW, IDB_DATAVIEW, IDB_FILEVIEW, IDB_MKVIEW };
for(int i = 0; i < sizeof(Ids) / sizeof(Ids[0]); ++i)
{
CBitmap bm;
bm.Attach(::LoadBitmap(inst, (LPCTSTR)Ids[i]));
m_ImageList.Add(&bm, RGB(192, 192, 192));
}
SetImageList(&m_ImageList);
}
m_uTimerId = SetTimer(1, 333, NULL);
TEST_BOOL(0 != m_uTimerId);
LOG(Logger::cDebug, "WsTabRepl::Create()}");
}
void WsTabRepl::ResizeChild(CWnd *pChild, CWnd *pRef)
{
LOG(Logger::cDebug, "WsTabRepl::ResizeChild(%p, %p){", pChild, pRef);
if(NULL != pChild && NULL != pRef && pChild != pRef)
{
CRect rect;
pRef->GetWindowRect(&rect);
ScreenToClient(&rect);
LOG(Logger::cDebug, "WsTabRepl::ResizeChild(): moving child %p to (%d,%d):(%d,%d)", pChild, rect.left, rect.bottom, rect.right, rect.top);
pChild->MoveWindow(&rect);
}
LOG(Logger::cDebug, "WsTabRepl::ResizeChild()}");
}
const CPtrList* WsTabRepl::GetInternalTabList()
{
LOG(Logger::cDebug, "WsTabRepl::GetInternalTabList(){");
CWnd *pWsView = GetParent();
CPtrList *pList = reinterpret_cast<CPtrList*>(
reinterpret_cast<BYTE*>(pWsView)+0x88);
TEST_BOOL(NULL != pList);
LOG(Logger::cDebug, "WsTabRepl::GetInternalTabList()}, pList = %p", pList);
return pList;
}
int WsTabRepl::GetInternalCurSel()
{
LOG(Logger::cDebug, "WsTabRepl::GetInternalCurSel(){");
CWnd *pWsView = GetParent();
int nIndex = *reinterpret_cast<int*>(
reinterpret_cast<BYTE*>(pWsView)+0xA4);
LOG(Logger::cDebug, "WsTabRepl::GetInternalCurSel()}, nIndex = %d", nIndex);
return nIndex;
}
CWnd* WsTabRepl::GetInternalCurTabWnd()
{
LOG(Logger::cDebug, "WsTabRepl::GetInternalCurTabWnd(){");
const CPtrList *pList = GetInternalTabList();
int nIndex = GetInternalCurSel();
CWnd *pWnd = NULL;
if(-1 != nIndex)
{
TEST_BOOL(nIndex < pList->GetCount());
POSITION pos = pList->GetHeadPosition();
void *pObj = NULL;
for(int i = 0; i <= nIndex; ++ i)
pObj = pList->GetNext(pos);
pWnd = reinterpret_cast<CWnd*>(pObj);
TEST_BOOL(TRUE == IsWindow(pWnd->m_hWnd));
}
LOG(Logger::cDebug, "WsTabRepl::GetInternalCurTabWnd()}, pWnd = %p", pWnd);
return pWnd;
}
CString WsTabRepl::GetInternalCurTabId()
{
LOG(Logger::cDebug, "WsTabRepl::GetInternalCurTabId(){");
CString strTitle;
CWnd *pWnd = GetInternalCurTabWnd();
if(NULL != pWnd)
pWnd->GetWindowText(strTitle);
LOG(Logger::cDebug, "WsTabRepl::GetInternalCurTabId()}, ret = %s", static_cast<LPCTSTR>(strTitle));
return strTitle;
}
void WsTabRepl::SwitchInternalTab(int to)
{
LOG(Logger::cDebug, "WsTabRepl::SwitchInternalTab(%d){", to);
int from = GetInternalCurSel();
if(-1 != from && to != from)
{
bool bLeftToRight = from < to;
INPUT input[4];
memset(input, 0, sizeof(input));
input[0].type = input[1].type = input[2].type =
input[3].type = INPUT_KEYBOARD;
input[0].ki.wVk = input[2].ki.wVk = VK_CONTROL;
input[1].ki.wVk = input[3].ki.wVk = static_cast<WORD>(bLeftToRight ? VK_NEXT : VK_PRIOR);
input[2].ki.dwFlags = input[3].ki.dwFlags = KEYEVENTF_KEYUP;
input[0].ki.time = input[1].ki.time =
input[2].ki.time = input[3].ki.time = GetTickCount();
LOG(Logger::cInfo, "WsTabRepl::SwitchInternalTab(): switching from %d to %d", from , to);
for(int i = 0; i < abs(from - to); ++i)
{
GetParent()->SetFocus();
SendInput(4, input, sizeof(INPUT));
}
}
LOG(Logger::cDebug, "WsTabRepl::SwitchInternalTab()}");
}
void WsTabRepl::SwitchTab(int from, int to)
{
LOG(Logger::cDebug, "WsTabRepl::SwitchTab(%d, %d){", from, to);
CString sFrom = GetTabId(from);
CString sTo = GetTabId(to);
if("MkView" != sTo)
{
HideChild(&m_MkView);
SwitchInternalTab(to);
}
else
{
ResizeChild(&m_MkView, GetInternalCurTabWnd());
}
if("MkView" == sFrom || "MkView" == sTo)
DisplayChild(GetCurTabWnd());
LOG(Logger::cDebug, "WsTabRepl::SwitchTab()}");
}
CString WsTabRepl::GetTabId(int nTab)
{
TCITEM item;
memset(&item, 0, sizeof(item));
item.mask = TCIF_TEXT;
char buf[64] = {'\0'};
item.pszText = buf;
item.cchTextMax = 64;
GetItem(nTab, &item);
return buf;
}
CString WsTabRepl::GetCurTabId()
{
return GetTabId(GetCurSel());
}
CWnd* WsTabRepl::GetCurTabWnd()
{
return "MkView" == GetCurTabId() ? &m_MkView : GetInternalCurTabWnd();
}
void WsTabRepl::OnSelchange(NMHDR* pNMHDR, LRESULT* pResult)
{
LOG(Logger::cDebug, "WsTabRepl::OnSelchange(%p, %p){", pNMHDR, pResult);
SwitchTab(m_nPrevTab, GetCurSel());
*pResult = 0;
LOG(Logger::cDebug, "WsTabRepl::OnSelchange()}");
}
void WsTabRepl::OnSelchanging(NMHDR* pNMHDR, LRESULT* pResult)
{
LOG(Logger::cDebug, "WsTabRepl::OnSelchanging(%p, %p){", pNMHDR, pResult);
m_nPrevTab = GetCurSel();
*pResult = 0;
LOG(Logger::cDebug, "WsTabRepl::OnSelchanging()}");
}
int WsTabRepl::ImageFromId(const CString &id)
{
return m_ChildrenInfo[id].nImage;
}
void WsTabRepl::SyncCurTab()
{
LOG(Logger::cDebug, "WsTabRepl::SyncCurTab(){");
SetCurSel(GetInternalCurSel());
LOG(Logger::cDebug, "WsTabRepl::SyncCurTab()}");
}
void WsTabRepl::OnDestroy()
{
MK_TRY;
LOG(Logger::cDebug, "WsTabRepl::OnDestroy(){");
if(NULL != m_MkView.m_hWnd)
{
LOG(Logger::cDebug, "WsTabRepl::OnDestroy(): destroying MkView");
m_MkView.DestroyWindow();
}
m_nPrevVCTab = -1;
m_nCurVCTab = -1;
KillTimer(m_uTimerId);
m_uTimerId = 0;
CTabCtrl::OnDestroy();
LOG(Logger::cDebug, "WsTabRepl::OnDestroy()}");
MK_CATCH;
}
void WsTabRepl::RebuildTabs()
{
LOG(Logger::cDebug, "WsTabRepl::RebuildTabs(){");
DeleteAllItems();
const CPtrList *pList = GetInternalTabList();
TCITEM item;
memset(&item, 0, sizeof(item));
item.mask = TCIF_TEXT | TCIF_IMAGE;
int nItem = 0;
bool bSeenFileView = false;
for(POSITION pos = pList->GetHeadPosition(); NULL != pos; ++nItem)
{
CWnd *pTabWnd = reinterpret_cast<CWnd*>(pList->GetNext(pos));
TEST_BOOL(NULL != pTabWnd);
CString strTitle;
pTabWnd->GetWindowText(strTitle);
LOG(Logger::cInfo, "WsTabRepl::RebuildTabs(): adding %s", static_cast<LPCTSTR>(strTitle));
item.pszText = const_cast<LPTSTR>(static_cast<LPCTSTR>(strTitle));
item.iImage = ImageFromId(strTitle);
InsertItem(nItem, &item);
if(GetInternalCurSel() == nItem)
SetCurSel(nItem);
if("FileView" == strTitle)
bSeenFileView = true;
}
if(bSeenFileView && DSUtils(m_pApp).IsNormalDsw())
{
if(NULL == m_MkView.m_hWnd)
{
LOG(Logger::cInfo, "WsTabRepl::RebuildTabs(): creating MkView");
m_MkView.Create(GetParent());
m_MkView.SetWindowText("MkView");
}
LOG(Logger::cInfo, "WsTabRepl::RebuildTabs(): adding MkView as tab %d", nItem);
item.pszText = "MkView";
item.iImage = ImageFromId("MkView");
InsertItem(nItem, &item);
}
else if(!bSeenFileView && NULL != m_MkView.m_hWnd)
{
LOG(Logger::cInfo, "WsTabRepl::RebuildTabs(): destroying MkView");
m_MkView.DestroyWindow();
}
PostMessage(WM_ADJUSTSIZE);
LOG(Logger::cDebug, "WsTabRepl::RebuildTabs()}");
}
void WsTabRepl::CheckTab()
{
LOG(Logger::cDebug, "WsTabRepl::CheckTab(){");
int nCurVCTab = GetInternalCurSel();
if(m_nCurVCTab != nCurVCTab)
{
LOG(Logger::cDebug, "WsTabRepl::CheckTab(): tab index changed from %d to %d, synchronizing", m_nCurVCTab, nCurVCTab);
if(-1 == m_nCurVCTab)
m_nPrevVCTab = nCurVCTab;
else
m_nPrevVCTab = m_nCurVCTab;
m_nCurVCTab = nCurVCTab;
SyncCurTab();
}
LOG(Logger::cDebug, "WsTabRepl::CheckTab()}");
}
void WsTabRepl::OnTimer(UINT nIDEvent)
{
MK_TRY;
LOG(Logger::cDebug, "WsTabRepl::OnTimer(%d){", nIDEvent);
if(1 == nIDEvent)
{
CheckTab();
}
CTabCtrl::OnTimer(nIDEvent);
LOG(Logger::cDebug, "WsTabRepl::OnTimer()}");
MK_CATCH;
}
LRESULT WsTabRepl::OnRegisterchild(WPARAM wp, LPARAM lp)
{
MK_TRY;
LOG(Logger::cDebug, "WsTabRepl::OnRegisterchild(0x%x, 0x%x){", wp, lp);
HWND hwnd = reinterpret_cast<HWND>(wp);
TEST_BOOL(::IsWindow(hwnd));
RebuildTabs();
LOG(Logger::cDebug, "WsTabRepl::OnRegisterchild()}");
MK_CATCH;
return MK_VAR.GetErrorCode();
}
LRESULT WsTabRepl::OnDeregisterchild(WPARAM wp, LPARAM lp)
{
MK_TRY;
LOG(Logger::cDebug, "WsTabRepl::OnDeregisterchild(0x%x, 0x%x){", wp, lp);
HWND hwnd = reinterpret_cast<HWND>(wp);
TEST_BOOL(::IsWindow(hwnd));
RebuildTabs();
LOG(Logger::cDebug, "WsTabRepl::OnDeregisterchild()}");
MK_CATCH;
return 0;
}
LRESULT WsTabRepl::OnAdjustSize(WPARAM wp, LPARAM lp)
{
LOG(Logger::cDebug, "WsTabRepl::OnAdjustSize(0x%x, 0x%x){", wp, lp);
RECT rect;
GetParent()->GetClientRect(&rect);
MoveWindow(&rect, TRUE);
ResizeChild(GetCurTabWnd(), GetInternalCurTabWnd());
LOG(Logger::cDebug, "WsTabRepl::OnAdjustSize()}");
return 0;
}
void WsTabRepl::DisplayChild(CWnd *pChild)
{
LOG(Logger::cDebug, "WsTabRepl::DisplayChild(%p){", pChild);
TEST_BOOL(NULL != pChild);
const CPtrList *pList = GetInternalTabList();
for(POSITION pos = pList->GetHeadPosition(); NULL != pos; )
{
CWnd *pWnd = reinterpret_cast<CWnd*>(pList->GetNext(pos));
if(pChild != pWnd)
pWnd->SetWindowPos(&wndBottom, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE);
}
pChild->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
LOG(Logger::cDebug, "WsTabRepl::DisplayChild()}");
}
void WsTabRepl::HideChild(CWnd *pChild)
{
LOG(Logger::cDebug, "WsTabRepl::HideChild(%p){", pChild);
TEST_BOOL(NULL != pChild);
pChild->SetWindowPos(&wndBottom, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE);
LOG(Logger::cDebug, "WsTabRepl::HideChild()}");
}