// XTPTaskPanelItem.cpp : implementation of the CXTPTaskPanelItem class.
//
// This file is a part of the XTREME TASKPANEL MFC class library.
// (c)1998-2012 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Common/XTPImageManager.h"
#include "Common/XTPPropExchange.h"
#include "Common/XTPDrawHelpers.h"
#include "Common/XTPMarkupRender.h"
#include "Common/XTPSystemHelpers.h"
#include "Common/XTPColorManager.h"

#include "XTPTaskPanelDefines.h"
#include "XTPTaskPanelItem.h"
#include "XTPTaskPanel.h"
#include "XTPTaskPanelItems.h"
#include "XTPTaskPanelPaintManager.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CXTPTaskPanelItem

IMPLEMENT_DYNCREATE(CXTPTaskPanelItem, CCmdTarget)

CXTPTaskPanelItem::CXTPTaskPanelItem()
{
	m_pPanel = NULL;
	m_pItems = NULL;

	m_nIconIndex = -1;
	m_nID = 0;

	m_bEnabled = TRUE;
	m_typeItem = xtpTaskItemTypeLink;

	m_bAllowDrop = TRUE;
	m_nAllowDrag = xtpTaskItemAllowDragDefault;

	m_rcText.SetRectEmpty();
	m_nTextFormat = 0;
	m_bVisible = TRUE;

	m_dwData = 0;

	m_rcIconPadding = CXTPTaskPanelPaintManager::rectDefault;

	m_pMarkupUIElement = NULL;

	EnableAutomation();

}

CXTPTaskPanelItem::~CXTPTaskPanelItem()
{
	XTPMarkupReleaseElement(m_pMarkupUIElement);
}

BOOL CXTPTaskPanelItem::IsItemHot() const
{
	return m_bEnabled && m_pPanel && m_pPanel->GetHotItem() == this;
}

BOOL CXTPTaskPanelItem::IsItemPressed() const
{
	return m_pPanel && m_pPanel->m_pItemPressed == this;
}

BOOL CXTPTaskPanelItem::IsItemDragging() const
{
	return m_pPanel && m_pPanel->m_pItemDragging == this;
}

BOOL CXTPTaskPanelItem::IsItemDragOver() const
{
	return m_pPanel && m_pPanel->m_pItemDragOver == this;
}

BOOL CXTPTaskPanelItem::IsItemFocused() const
{
	return m_pPanel && m_bEnabled && m_pPanel->GetFocusedItem() == this;
}

BOOL CXTPTaskPanelItem::IsAcceptFocus() const
{
	return (GetType() != xtpTaskItemTypeText) && m_bEnabled && m_bVisible;
}

void  CXTPTaskPanelItem::SetEnabled(BOOL bEnabled)
{
	if (m_bEnabled != bEnabled)
	{
		m_bEnabled = bEnabled;
		RedrawPanel();
	}
}
BOOL CXTPTaskPanelItem::GetEnabled() const
{
	return m_bEnabled;
}
UINT CXTPTaskPanelItem::GetID() const
{
	return m_nID;
}

XTPTaskPanelItemType CXTPTaskPanelItem::GetType() const
{
	return m_typeItem;
}

int CXTPTaskPanelItem::GetIconIndex() const
{
	return m_nIconIndex;
}



void CXTPTaskPanelItem::SetID(UINT nID)
{
	m_nID = nID;

	CString strPrompt;
	if (strPrompt.LoadString(nID))
	{
		if (strPrompt.Find('\n') != -1)
		{
			AfxExtractSubString(m_strTooltip, strPrompt, 1);
			AfxExtractSubString(m_strCaption, strPrompt, 0);
		}
		else
		{
			m_strCaption = strPrompt;
		}
	}
}

void CXTPTaskPanelItem::SetCaption(LPCTSTR lpszCaption)
{
	CString strCaption(lpszCaption);

	if (m_strCaption != strCaption)
	{
		m_strCaption = strCaption;

		XTPMarkupReleaseElement(m_pMarkupUIElement);

		CXTPTaskPanel* pTaskPanel = GetTaskPanel();
		if (pTaskPanel && pTaskPanel->GetMarkupContext())
		{
			m_pMarkupUIElement = XTPMarkupParseText(pTaskPanel->GetMarkupContext(), lpszCaption);
		}

		RepositionPanel();
	}
}


void CXTPTaskPanelItem::OnInserted()
{
	if (m_pMarkupUIElement == 0)
	{
		CXTPTaskPanel* pTaskPanel = GetTaskPanel();
		if (pTaskPanel && pTaskPanel->GetMarkupContext())
		{
			m_pMarkupUIElement = XTPMarkupParseText(pTaskPanel->GetMarkupContext(), m_strCaption);
		}
	}
}


void CXTPTaskPanelItem::SetTooltip(LPCTSTR lpstrTooltip)
{
	m_strTooltip = lpstrTooltip;
}
void CXTPTaskPanelItem::SetType(XTPTaskPanelItemType typeItem)
{
	m_typeItem = typeItem;
	RepositionPanel();
}
void CXTPTaskPanelItem::SetIconIndex(int nIndex)
{
	if (m_nIconIndex != nIndex)
	{
		m_nIconIndex = nIndex;
		RepositionPanel();
	}
}

CXTPTaskPanelPaintManager* CXTPTaskPanelItem::GetPaintManager() const
{
	ASSERT(m_pPanel);
	return m_pPanel ? m_pPanel->GetPaintManager() : NULL;
}

void CXTPTaskPanelItem::EnsureVisible()
{
	SAFE_CALLPTR(m_pPanel, EnsureVisible(this));
}

void CXTPTaskPanelItem::SetVisible(BOOL bVisible)
{
	if (m_bVisible != bVisible)
	{
		m_bVisible = bVisible;
		RepositionPanel();
	}
}

BOOL CXTPTaskPanelItem::IsVisible() const
{
	return this != NULL && m_bVisible;
}


void CXTPTaskPanelItem::RedrawPanel(BOOL bAnimate) const
{
	if (m_pPanel && m_pPanel->GetSafeHwnd())
		m_pPanel->Redraw(GetInvalidateRect(), bAnimate);
}

void CXTPTaskPanelItem::RepositionPanel() const
{
	if (m_pPanel) m_pPanel->Reposition();
}

CXTPImageManagerIcon* CXTPTaskPanelItem::GetImage(int nWidth) const
{
	return m_pPanel->GetImageManager()->GetImage(GetIconIndex(), nWidth);
}

void CXTPTaskPanelItem::DoPropExchange(CXTPPropExchange* pPX)
{
	if (pPX->IsLoading())
		m_pPanel = (CXTPTaskPanel*)pPX->m_dwData;

	PX_String(pPX, _T("Caption"), m_strCaption, _T(""));
	PX_String(pPX, _T("Tooltip"), m_strTooltip, _T(""));
	PX_Long(pPX, _T("Id"), (long&)m_nID, 0);
	PX_Enum(pPX, _T("Type"), m_typeItem, xtpTaskItemTypeLink);
	PX_Int(pPX, _T("IconIndex"), m_nIconIndex, -1);
	PX_Bool(pPX, _T("Enabled"), m_bEnabled, TRUE);
	PX_Long(pPX, _T("AllowDrag"), m_nAllowDrag, xtpTaskItemAllowDragDefault);
	PX_Bool(pPX, _T("AllowDrop"), m_bAllowDrop, TRUE);

	if (pPX->GetSchema() > _XTP_SCHEMA_95)
	{
		PX_Bool(pPX, _T("Visible"), m_bVisible, TRUE);
		PX_Rect(pPX, _T("IconPadding"), m_rcIconPadding, CXTPTaskPanelPaintManager::rectDefault);
	}


	if (pPX->GetSchema() > _XTP_SCHEMA_100)
	{
		PX_DWord(pPX, _T("Data"), (DWORD&)m_dwData, 0);
	}

}

HGLOBAL CXTPTaskPanelItem::CacheGlobalData()
{
	try
	{
		CSharedFile sharedFile;
		CArchive ar (&sharedFile, CArchive::store);

		CRuntimeClass* pClass = GetRuntimeClass ();
		ASSERT (pClass != NULL);

		ar.WriteClass (pClass);

		CXTPPropExchangeArchive px(ar);
		DoPropExchange(&px);

		ar.Close();

		return sharedFile.Detach();
	}
	catch (COleException* pEx)
	{
		TRACE(_T("CXTPTaskPanelItem::PrepareDrag. OLE exception: %x\r\n"),
			pEx->m_sc);
		pEx->Delete ();
	}
	catch (CArchiveException* pEx)
	{
		TRACE(_T("CXTPTaskPanelItem::PrepareDrag. Archive exception\r\n"));
		pEx->Delete ();
	}

	return NULL;
}

CXTPTaskPanelItem* CXTPTaskPanelItem::CreateFromOleData(COleDataObject* pDataObject)
{
	ASSERT (pDataObject != NULL);
	if (!pDataObject)
		return NULL;

	CFile* pFile = pDataObject->GetFileData(CXTPTaskPanel::GetClipboardFormat());
	if (!pFile)
		return NULL;

	CXTPTaskPanelItem* pItem = CreateFromOleFile(pFile);

	delete pFile;

	return pItem;

}

CXTPTaskPanelItem* CXTPTaskPanelItem::CreateFromOleFile(CFile* pFile)
{
	ASSERT (pFile != NULL);

	CXTPTaskPanelItem* pItem = NULL;

	try
	{
		CArchive ar (pFile, CArchive::load);

		CRuntimeClass* pClass = ar.ReadClass ();

		if (pClass != NULL)
		{
			pItem = (CXTPTaskPanelItem*) pClass->CreateObject();

			if (pItem != NULL)
			{
				CXTPPropExchangeArchive px(ar);
				pItem->DoPropExchange(&px);
			}
		}

		ar.Close ();
		return pItem;
	}
	catch (COleException* pEx)
	{
		TRACE(_T("CXTPTaskPanelItem::CreateFromOleData. OLE exception: %x\r\n"),
			pEx->m_sc);
		pEx->Delete ();
	}
	catch (CArchiveException* pEx)
	{
		TRACE(_T("CXTPTaskPanelItem::CreateFromOleData. Archive exception\r\n"));
		pEx->Delete ();
	}
	catch (CNotSupportedException *pEx)
	{
		TRACE(_T("CXTPTaskPanelItem::CreateFromOleData. \"Not Supported\" exception\r\n"));
		pEx->Delete ();
	}

	if (pItem != NULL)
	{
		delete pItem;
	}

	return NULL;
}

void CXTPTaskPanelItem::CopyToClipboard()
{
	if (!m_pPanel->OpenClipboard())
		return;

	if (!::EmptyClipboard())
	{
		::CloseClipboard ();
		return;
	}

	HGLOBAL hGlobal = CacheGlobalData();

	if (hGlobal)
	{
		SetClipboardData(CXTPTaskPanel::GetClipboardFormat(), hGlobal);
	}

	::CloseClipboard ();
}

CXTPTaskPanelItem* CXTPTaskPanelItem::PasteFromClipboard()
{
	COleDataObject data;

	if (!data.AttachClipboard ())
	{
		return 0;
	}

	if (!data.IsDataAvailable (CXTPTaskPanel::GetClipboardFormat()))
		return 0;

	return CXTPTaskPanelItem::CreateFromOleData(&data);
}

void CXTPTaskPanelItem::Remove()
{
	m_pItems->Remove(this);
}

int CXTPTaskPanelItem::GetIndex() const
{
	return this == NULL ? -1 : m_pItems->GetIndex(this);
}

BOOL CXTPTaskPanelItem::IsAllowDrop() const
{
	return m_bAllowDrop && ((CXTPTaskPanelItem*)GetItemGroup())->m_bAllowDrop &&
		m_pPanel && m_pPanel->m_bAllowDrop;
}
void CXTPTaskPanelItem::AllowDrop(BOOL bAllowDrop)
{
	m_bAllowDrop = bAllowDrop;
}

long CXTPTaskPanelItem::IsAllowDrag() const
{
	if (m_nAllowDrag != xtpTaskItemAllowDragDefault)
		return m_nAllowDrag;

	CXTPTaskPanelItem* pGroup = (CXTPTaskPanelItem*)GetItemGroup();
	if (pGroup && pGroup->m_nAllowDrag != xtpTaskItemAllowDragDefault)
		return pGroup->m_nAllowDrag;

	return !m_pPanel || (m_pPanel->m_nAllowDrag == xtpTaskItemAllowDragDefault) ? xtpTaskItemAllowDrag :
		m_pPanel->m_nAllowDrag;
}

void CXTPTaskPanelItem::AllowDrag(long nAllowDrag /* = xtpTaskItemAllowDragDefault */)
{
	m_nAllowDrag = nAllowDrag;
}

CFont* CXTPTaskPanelItem::GetItemFont() const
{
	return m_pPanel->GetPaintManager()->GetItemFont((CXTPTaskPanelItem*)this);
}

void CXTPTaskPanelItem::SetItemFont(LOGFONT* pLogFont)
{
	m_fntItem.DeleteObject();
	if (pLogFont) m_fntItem.CreateFontIndirect(pLogFont);
}


void CXTPTaskPanelItem::DrawCaptionText(CDC* pDC, CRect rc, UINT nFormat)
{
	if (m_pMarkupUIElement)
	{
		XTPMarkupSetDefaultFont(GetTaskPanel()->GetMarkupContext(),
			(HFONT)::GetCurrentObject(pDC->GetSafeHdc(), OBJ_FONT), pDC->GetTextColor());
		XTPMarkupRenderElement(m_pMarkupUIElement, pDC->GetSafeHdc(), rc);
	}
	else
	{
		pDC->DrawText(GetCaption(), rc, nFormat);
	}
}

CSize CXTPTaskPanelItem::GetCaptionTextSize(CDC* pDC, CRect rc, UINT nFormat)
{
	if (m_pMarkupUIElement)
	{
		XTPMarkupSetDefaultFont(GetTaskPanel()->GetMarkupContext(),
			(HFONT)::GetCurrentObject(pDC->GetSafeHdc(), OBJ_FONT), COLORREF_NULL);
		return XTPMarkupMeasureElement(m_pMarkupUIElement, rc.Width(), INT_MAX);
	}

	CRect rcText(rc.left, 0, rc.right, 0);
	CString strCaption = GetCaption();

	pDC->DrawText(strCaption.IsEmpty() ? _T(" ") : strCaption, rcText, (nFormat | DT_CALCRECT));

	return strCaption.IsEmpty() ? CSize(0, rcText.Height()) : rcText.Size();
}

void CXTPTaskPanelItem::SetTextRect(CDC* pDC, CRect rc, UINT nFormat)
{
	CSize szText = GetCaptionTextSize(pDC, rc, nFormat & (~(DT_END_ELLIPSIS | DT_VCENTER)));

	int nDelta = rc.Height() - szText.cy;
	int nOffset = nFormat & DT_VCENTER ? nDelta/2 : 0;

	rc.DeflateRect(0, nOffset, 0, nDelta - nOffset);

	m_nTextFormat = nFormat;
	m_rcText = rc;
}

CRect CXTPTaskPanelItem::GetTextRect(UINT* pFormat) const
{
	if (pFormat)
		*pFormat = m_nTextFormat;

	return m_rcText;
}

CRect CXTPTaskPanelItem::GetHitTestRect() const
{
	return CRect(0, 0, 0, 0);
}

CRect CXTPTaskPanelItem::GetInvalidateRect() const
{
	return GetHitTestRect();
}


BOOL CXTPTaskPanelItem::IsGroup() const
{
	return GetType() == xtpTaskItemTypeGroup;
}

CXTPTaskPanelGroup* CXTPTaskPanelItem::GetItemGroup() const
{
	return (CXTPTaskPanelGroup*)this;
}

CCmdTarget* CXTPTaskPanelItem::GetAccessible()
{
	return this;
}

HRESULT CXTPTaskPanelItem::GetAccessibleParent(IDispatch* FAR* ppdispParent)
{
	SAFE_MANAGE_STATE(m_pModuleState);

	*ppdispParent = NULL;

	return GetTaskPanel()->InternalQueryInterface(&IID_IAccessible, (void**)ppdispParent);
}

HRESULT CXTPTaskPanelItem::GetAccessibleName(VARIANT varChild, BSTR* pszName)
{
	if (GetChildIndex(&varChild) != CHILDID_SELF)
		return E_INVALIDARG;

	CString strCaption = GetCaption();

	*pszName = strCaption.AllocSysString();
	return S_OK;
}

HRESULT CXTPTaskPanelItem::GetAccessibleDescription(VARIANT varChild, BSTR* pszDescription)
{
	if (GetChildIndex(&varChild) != CHILDID_SELF)
		return E_INVALIDARG;

	*pszDescription = GetTooltip().AllocSysString();
	return S_OK;
}

HRESULT CXTPTaskPanelItem::GetAccessibleRole(VARIANT varChild, VARIANT* pvarRole)
{
	pvarRole->vt = VT_EMPTY;

	if (GetChildIndex(&varChild) == CHILDID_SELF)
	{
		pvarRole->vt = VT_I4;
		pvarRole->lVal = ROLE_SYSTEM_LISTITEM;
		return S_OK;
	}

	return E_INVALIDARG;
}

HRESULT CXTPTaskPanelItem::GetAccessibleState(VARIANT varChild, VARIANT* pvarState)
{
	if (GetChildIndex(&varChild) != CHILDID_SELF)
		return E_INVALIDARG;

	pvarState->vt = VT_I4;
	pvarState->lVal = STATE_SYSTEM_FOCUSABLE |
		(IsItemFocused() ? STATE_SYSTEM_FOCUSED : 0);

	if (!IsVisible())
		pvarState->lVal |= STATE_SYSTEM_INVISIBLE;

	if (!GetEnabled())
		pvarState->lVal |= STATE_SYSTEM_UNAVAILABLE;

	return S_OK;
}


HRESULT CXTPTaskPanelItem::AccessibleLocation(long* pxLeft, long* pyTop, long* pcxWidth, long* pcyHeight, VARIANT varChild)
{
	*pxLeft = *pyTop = *pcxWidth = *pcyHeight = 0;

	if (GetChildIndex(&varChild) != CHILDID_SELF)
		return E_INVALIDARG;

	if (!GetTaskPanel()->GetSafeHwnd())
		return S_OK;

	CRect rcItem = GetHitTestRect();
	GetTaskPanel()->ClientToScreen(&rcItem);

	*pxLeft = rcItem.left;
	*pyTop = rcItem.top;
	*pcxWidth = rcItem.Width();
	*pcyHeight = rcItem.Height();

	return S_OK;
}

HRESULT CXTPTaskPanelItem::AccessibleHitTest(long xLeft, long yTop, VARIANT* pvarID)
{
	if (pvarID == NULL)
		return E_INVALIDARG;

	pvarID->vt = VT_EMPTY;

	if (!GetTaskPanel()->GetSafeHwnd())
		return S_FALSE;

	if (!CXTPWindowRect(GetTaskPanel()).PtInRect(CPoint(xLeft, yTop)))
		return S_FALSE;

	pvarID->vt = VT_I4;
	pvarID->lVal = 0;

	CPoint pt(xLeft, yTop);
	GetTaskPanel()->ScreenToClient(&pt);

	if (!GetHitTestRect().PtInRect(pt))
		return S_FALSE;

	return S_OK;
}

HRESULT CXTPTaskPanelItem::AccessibleSelect(long flagsSelect, VARIANT varChild)
{
	if (GetChildIndex(&varChild) != CHILDID_SELF)
		return E_INVALIDARG;

	if (flagsSelect == SELFLAG_TAKEFOCUS)
	{
		GetTaskPanel()->SetFocusedItem(this);
	}

	return S_OK;
}



BEGIN_INTERFACE_MAP(CXTPTaskPanelItem, CCmdTarget)
	INTERFACE_PART(CXTPTaskPanelItem, IID_IAccessible, ExternalAccessible)
END_INTERFACE_MAP()