#ifndef __IAGCRangesImpl_h__
#define __IAGCRangesImpl_h__
#include <AGC.h>
#include <..\TCLib\RangeSet.h>
#include <..\TCLib\ObjectLock.h>
#define COM_INTERFACE_ENTRIES_IAGCRangesImpl() \
COM_INTERFACE_ENTRY(IAGCRangesPrivate) \
COM_INTERFACE_ENTRY(IDispatch) \
COM_INTERFACE_ENTRY(ISupportErrorInfo) \
COM_INTERFACE_ENTRY(IPersistStreamInit) \
COM_INTERFACE_ENTRY(IPersistPropertyBag) \
COM_INTERFACE_ENTRY2(IPersistStream, IPersistStreamInit) \
COM_INTERFACE_ENTRY2(IPersist, IPersistStreamInit) \
COM_INTERFACE_ENTRY_AUTOAGGREGATE(IID_IMarshal, m_punkMBV.p, \
CLSID_TCMarshalByValue)
template <class T, class RT, class ITF, class RTITF, const GUID* plibid>
class ATL_NO_VTABLE IAGCRangesImpl :
public IDispatchImpl<ITF, &__uuidof(ITF), plibid>,
public IAGCRangesPrivate,
public ISupportErrorInfo,
public IPersistStreamInit,
public IPersistPropertyBag
{
public:
typedef TCObjectLock<T> XLock;
typedef range<RT> XRange;
typedef rangeset<XRange> XRangeSet;
typedef VSNET_TNFIX XRangeSet::iterator XRangeIt;
typedef VSNET_TNFIX XRangeSet::reverse_iterator XRangeRevIt;
typedef IDispatchImpl<ITF, &__uuidof(ITF), plibid> IAGCRangesImplBase;
public:
IAGCRangesImpl()
{
ZSucceeded(T::CreateRange(RT(), RT(), &m_spRange));
m_spRange.QueryInterface(&m_spPrivate);
assert(NULL != m_spPrivate);
m_spRange.QueryInterface(&m_spPersist);
if (NULL == m_spPersist)
{
ZSucceeded(m_spRange->QueryInterface(IID_IPersistStreamInit,
(void**)&m_spPersist));
}
}
public:
static HRESULT CreateRange(const RT& value1, const RT& value2,
RTITF** ppRange);
public:
STDMETHODIMP get_Count(long* pnCount)
{
XLock lock(static_cast<T*>(this));
CLEAROUT(pnCount, static_cast<long>(m_ranges.size()));
return S_OK;
}
STDMETHODIMP get__NewEnum(IUnknown** ppunkEnum)
{
typedef CComObject<CComEnum<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT,
_Copy<VARIANT> > > CEnum;
CEnum* pEnum = new CEnum;
assert(NULL != pEnum);
IUnknownPtr spEnum(pEnum);
XLock lock(static_cast<T*>(this));
long cTotal = m_ranges.size();
std::vector<CComVariant> vecTemp(cTotal);
long i = 0;
RT value1, value2;
for (XRangeIt it = m_ranges.begin(); it != m_ranges.end(); ++it)
{
value1 = it->lower();
value2 = it->upper();
CComPtr<RTITF> spRange;
RETURN_FAILED(T::CreateRange(value1, value2, &spRange));
vecTemp[i++] = (IDispatch*)spRange;
}
#if _MSC_VER >= 1310
RETURN_FAILED(pEnum->Init(&(*vecTemp.begin()), &(*vecTemp.end()), NULL, AtlFlagCopy));
#else
RETURN_FAILED(pEnum->Init(vecTemp.begin(), vecTemp.end(), NULL, AtlFlagCopy));
#endif
RETURN_FAILED(spEnum->QueryInterface(IID_IEnumVARIANT, (void**)ppunkEnum));
return S_OK;
}
STDMETHODIMP get_Item(VARIANT* pvIndex, RTITF** ppRange)
{
CLEAROUT(ppRange, (RTITF*)NULL);
CComVariant varIndex;
RETURN_FAILED(VariantChangeType(&varIndex, pvIndex, 0, VT_I4));
long nIndex = V_I4(&varIndex);
XLock lock(static_cast<T*>(this));
if (0 > nIndex || nIndex >= m_ranges.size())
return E_INVALIDARG;
RT value1, value2;
if (nIndex < (m_ranges.size() / 2))
{
XRangeIt it;
for (it = m_ranges.begin(); nIndex; ++it)
--nIndex;
value1 = it->lower();
value2 = it->upper();
}
else
{
XRangeRevIt it;
for (it = m_ranges.rbegin(); nIndex; ++it)
--nIndex;
value1 = it->lower();
value2 = it->upper();
}
lock.Unlock();
return T::CreateRange(value1, value2, ppRange);
}
STDMETHODIMP put_DisplayString(BSTR bstr)
{
RETURN_FAILED(InitNew());
UINT cch = BSTRLen(bstr);
if (!cch)
return S_OK;
ITCStringsPtr spStrings;
RETURN_FAILED(spStrings.CreateInstance("TCObj.Strings"));
RETURN_FAILED(spStrings->AddDelimited(CComBSTR(L";"), bstr));
long cItems;
RETURN_FAILED(spStrings->get_Count(&cItems));
for (CComVariant v(0L); V_I4(&v) < cItems; ++V_I4(&v))
{
CComBSTR bstrItem;
RETURN_FAILED(spStrings->get_Item(&v, &bstrItem));
RETURN_FAILED(m_spRange->put_DisplayString(bstrItem));
XRangeSet::key_type range;
RETURN_FAILED(m_spPrivate->CopyRangeTo(&range));
m_ranges.insert(range);
}
return S_OK;
}
STDMETHODIMP get_DisplayString(BSTR* pbstr)
{
ITCStringsPtr spStrings;
RETURN_FAILED(spStrings.CreateInstance("TCObj.Strings"));
XLock lock(static_cast<T*>(this));
for (XRangeIt it = m_ranges.begin(); it != m_ranges.end(); ++it)
{
RETURN_FAILED(m_spPrivate->InitFromRange(&(*it)));
CComBSTR bstrItem;
RETURN_FAILED(m_spRange->get_DisplayString(&bstrItem));
if (bstrItem.Length())
spStrings->Add(bstrItem);
}
return spStrings->get_DelimitedItems(CComBSTR(L";"), pbstr);
}
STDMETHODIMP AddByValues(RT value1, RT value2)
{
XLock lock(static_cast<T*>(this));
m_ranges.insert(value1, value2);
return S_OK;
}
STDMETHODIMP Add(RTITF* pRange)
{
RT value1, value2;
RETURN_FAILED(pRange->get_Lower(&value1));
RETURN_FAILED(pRange->get_Upper(&value2));
return AddByValues(value1, value2);
}
STDMETHODIMP RemoveByValues(RT value1, RT value2)
{
XLock lock(static_cast<T*>(this));
m_ranges.erase(value1, value2);
return S_OK;
}
STDMETHODIMP Remove(RTITF* pRange)
{
RT value1, value2;
RETURN_FAILED(pRange->get_Lower(&value1));
RETURN_FAILED(pRange->get_Upper(&value2));
return RemoveByValues(value1, value2);
}
STDMETHODIMP RemoveAll()
{
XLock lock(static_cast<T*>(this));
m_ranges.clear();
return S_OK;
}
STDMETHODIMP get_IntersectsWithValue(RT value,
VARIANT_BOOL* pbIntersects)
{
XLock lock(static_cast<T*>(this));
bool bIntr = m_ranges.find(make_range(value, value)) != m_ranges.end();
CLEAROUT(pbIntersects, VARBOOL(bIntr));
return S_OK;
}
STDMETHODIMP get_IntersectsWithRangeValues(RT value1, RT value2,
VARIANT_BOOL* pbIntersects)
{
XLock lock(static_cast<T*>(this));
bool bIntr = m_ranges.find(make_range(value1, value2)) != m_ranges.end();
CLEAROUT(pbIntersects, VARBOOL(bIntr));
return S_OK;
}
STDMETHODIMP get_IntersectsWithRange(RTITF* pRange,
VARIANT_BOOL* pbIntersects)
{
RT value1, value2;
RETURN_FAILED(pRange->get_Lower(&value1));
RETURN_FAILED(pRange->get_Upper(&value2));
return get_IntersectsWithRangeValues(value1, value2, pbIntersects);
}
public:
STDMETHODIMP InitFromRanges(const void* pvRanges)
{
const XRangeSet* pRanges = reinterpret_cast<const XRangeSet*>(pvRanges);
XLock lock(static_cast<T*>(this));
if (pRanges)
m_ranges = *pRanges;
else
m_ranges.clear();
return S_OK;
}
STDMETHODIMP CopyRangesTo(void* pvRanges)
{
XRangeSet* pRanges = reinterpret_cast<XRangeSet*>(pvRanges);
XLock lock(static_cast<T*>(this));
*pRanges = m_ranges;
return S_OK;
}
public:
STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid)
{
static const IID* arr[] =
{
&__uuidof(ITF),
};
for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
if (InlineIsEqualGUID(*arr[i],riid))
return S_OK;
}
return S_FALSE;
}
public:
STDMETHODIMP GetClassID(CLSID* pClassID)
{
__try
{
*pClassID = T::GetObjectCLSID();
}
__except(1)
{
return E_POINTER;
}
return S_OK;
}
public:
STDMETHODIMP IsDirty()
{
return S_OK;
}
STDMETHODIMP Load(LPSTREAM pStm)
{
DWORD cItems;
RETURN_FAILED(pStm->Read(&cItems, sizeof(cItems), NULL));
XLock lock(static_cast<T*>(this));
m_ranges.clear();
assert(NULL != m_spPrivate);
assert(NULL != m_spPersist);
for (DWORD i = 0; i < cItems; ++i)
{
RETURN_FAILED(m_spPersist->Load(pStm));
XRangeSet::key_type range;
RETURN_FAILED(m_spPrivate->CopyRangeTo(&range));
m_ranges.insert(range);
}
return S_OK;
}
STDMETHODIMP Save(LPSTREAM pStm, BOOL fClearDirty)
{
UNUSED_ALWAYS(fClearDirty);
XLock lock(static_cast<T*>(this));
DWORD cItems = m_ranges.size();
RETURN_FAILED(pStm->Write(&cItems, sizeof(cItems), NULL));
assert(NULL != m_spPrivate);
assert(NULL != m_spPersist);
for (XRangeIt it = m_ranges.begin(); it != m_ranges.end(); ++it)
{
RETURN_FAILED(m_spPrivate->InitFromRange(&(*it)));
RETURN_FAILED(m_spPersist->Save(pStm, fClearDirty));
}
return S_OK;
}
STDMETHODIMP GetSizeMax(ULARGE_INTEGER* pCbSize)
{
XLock lock(static_cast<T*>(this));
ULARGE_INTEGER uli;
assert(NULL != m_spPersist);
RETURN_FAILED(m_spPersist->GetSizeMax(&uli));
pCbSize->HighPart = 0;
pCbSize->LowPart = sizeof(DWORD) + m_ranges.size() * uli.LowPart;
return S_OK;
}
STDMETHODIMP InitNew()
{
XLock lock(static_cast<T*>(this));
m_ranges.clear();
return S_OK;
}
public:
STDMETHODIMP Load(IPropertyBag* pPropBag, IErrorLog* pErrorLog)
{
CComVariant var(BSTR(NULL));
RETURN_FAILED(pPropBag->Read(L"Value", &var, pErrorLog));
return put_DisplayString(V_BSTR(&var));
}
STDMETHODIMP Save(IPropertyBag* pPropBag, BOOL fClearDirty,
BOOL fSaveAllProperties)
{
UNUSED_ALWAYS(fClearDirty);
UNUSED_ALWAYS(fSaveAllProperties);
CComBSTR bstr;
RETURN_FAILED(get_DisplayString(&bstr));
return pPropBag->Write(L"Value", &CComVariant(bstr));
}
protected:
XRangeSet m_ranges;
CComPtr<RTITF> m_spRange;
IAGCRangePrivatePtr m_spPrivate;
IPersistStreamPtr m_spPersist;
public:
CComPtr<IUnknown> m_punkMBV;
};
#endif