You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
501 lines
12 KiB
501 lines
12 KiB
//
|
|
// perange.cpp
|
|
//
|
|
|
|
#include "private.h"
|
|
#include "helpers.h"
|
|
#include "ic.h"
|
|
#include "range.h"
|
|
#include "rangebk.h"
|
|
#include "rprop.h"
|
|
#include "immxutil.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CRangeBackup
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// ctor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CRangeBackupProperty::CRangeBackupProperty(CRangeBackup *ppr, CProperty *pProp)
|
|
{
|
|
_ppr = ppr;
|
|
_pProp = pProp;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// dtor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CRangeBackupProperty::~CRangeBackupProperty()
|
|
{
|
|
int i;
|
|
int nCnt = _rgPropRanges.Count();
|
|
|
|
for (i = 0; i < nCnt; i++)
|
|
{
|
|
PERSISTPROPERTYRANGE *pPropRange;
|
|
pPropRange = _rgPropRanges.GetPtr(i);
|
|
|
|
Assert(pPropRange);
|
|
Assert(pPropRange->_pPropStore);
|
|
|
|
pPropRange->_pPropStore->Release();
|
|
pPropRange->_pPropStore = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Init
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CRangeBackupProperty::Init(TfEditCookie ec)
|
|
{
|
|
IEnumTfRanges *pEnum;
|
|
ITfRange *pRange;
|
|
HRESULT hr;
|
|
|
|
hr = _pProp->EnumRanges(ec, &pEnum, (ITfRangeAnchor *)_ppr->_pRange);
|
|
if (FAILED(hr) || !pEnum)
|
|
return FALSE;
|
|
|
|
while (pEnum->Next(1, &pRange, NULL) == S_OK)
|
|
{
|
|
CRange *pCRange;
|
|
pCRange = GetCRange_NA(pRange);
|
|
if (pCRange)
|
|
{
|
|
_StoreOneRange(ec, pCRange);
|
|
}
|
|
pRange->Release();
|
|
}
|
|
|
|
pEnum->Release();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// StoreOneRange
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CRangeBackupProperty::_StoreOneRange(TfEditCookie ec, CRange *pCRange)
|
|
{
|
|
PROPERTYLIST *pPropList;
|
|
ULONG achStart = 0;
|
|
ULONG achEnd = 0;
|
|
|
|
if (CompareAnchors(pCRange->_GetStart(), _ppr->_pRange->_GetStart()) < 0)
|
|
{
|
|
if (CompareAnchors(pCRange->_GetEnd(), _ppr->_pRange->_GetEnd()) > 0)
|
|
{
|
|
pPropList = _pProp->_FindPropListAndDivide(_ppr->_pRange->_GetStart(), _ppr->_pRange->_GetEnd());
|
|
|
|
achStart = _GetOffset(ec, _ppr->_pRange->_GetStart());
|
|
achEnd = _GetOffset(ec, _ppr->_pRange->_GetEnd());
|
|
}
|
|
else
|
|
{
|
|
pPropList = _pProp->_FindPropListAndDivide(_ppr->_pRange->_GetStart(), pCRange->_GetEnd());
|
|
achStart = _GetOffset(ec, _ppr->_pRange->_GetStart());
|
|
achEnd = _GetOffset(ec, pCRange->_GetEnd());
|
|
}
|
|
}
|
|
else if (CompareAnchors(pCRange->_GetEnd(), _ppr->_pRange->_GetEnd()) > 0)
|
|
{
|
|
pPropList = _pProp->_FindPropListAndDivide(pCRange->_GetStart(), _ppr->_pRange->_GetEnd());
|
|
achStart = _GetOffset(ec, pCRange->_GetStart());
|
|
achEnd = _GetOffset(ec, _ppr->_pRange->_GetEnd());
|
|
}
|
|
else
|
|
{
|
|
pPropList = _pProp->_FindPropListAndDivide(pCRange->_GetStart(), pCRange->_GetEnd());
|
|
achStart = _GetOffset(ec, pCRange->_GetStart());
|
|
achEnd = _GetOffset(ec, pCRange->_GetEnd());
|
|
}
|
|
|
|
if (pPropList)
|
|
{
|
|
if (!pPropList->_pPropStore)
|
|
_pProp->LoadData(pPropList);
|
|
|
|
if (pPropList->_pPropStore)
|
|
{
|
|
HRESULT hr;
|
|
PERSISTPROPERTYRANGE *pPropRange;
|
|
ITfPropertyStore *pPropStore = NULL;
|
|
int nCnt;
|
|
|
|
hr = pPropList->_pPropStore->Clone(&pPropStore);
|
|
if (FAILED(hr) || !pPropStore)
|
|
return FALSE;
|
|
|
|
nCnt = _rgPropRanges.Count();
|
|
|
|
if (!_rgPropRanges.Insert(nCnt, 1))
|
|
{
|
|
pPropStore->Release();
|
|
return FALSE;
|
|
}
|
|
|
|
pPropRange = _rgPropRanges.GetPtr(nCnt);
|
|
pPropRange->achStart = achStart;
|
|
pPropRange->achEnd = achEnd;
|
|
pPropRange->_pPropStore = pPropStore;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _GetOffset
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
int CRangeBackupProperty::_GetOffset(TfEditCookie ec, IAnchor *pa)
|
|
{
|
|
CRange *pCRange;
|
|
CRange *pCRangeTmp = NULL;
|
|
ULONG cch = 0;
|
|
HRESULT hr;
|
|
BOOL fEmpty;
|
|
|
|
pCRange = new CRange;
|
|
if (!pCRange)
|
|
goto Exit;
|
|
|
|
if (!pCRange->_InitWithDefaultGravity(_ppr->_pic, COPY_ANCHORS, pa, pa))
|
|
goto Exit;
|
|
|
|
pCRangeTmp = _ppr->_pRange->_Clone();
|
|
if (!pCRangeTmp)
|
|
goto Exit;
|
|
|
|
hr = pCRangeTmp->ShiftEndToRange(ec, (ITfRangeAnchor *)pCRange, TF_ANCHOR_START);
|
|
if (FAILED(hr))
|
|
goto Exit;
|
|
|
|
|
|
fEmpty = FALSE;
|
|
while ((pCRangeTmp->IsEmpty(ec, &fEmpty) == S_OK) && !fEmpty)
|
|
{
|
|
WCHAR sz[256];
|
|
ULONG cchTmp;
|
|
|
|
pCRangeTmp->GetText(ec, TF_TF_MOVESTART, sz, ARRAYSIZE(sz), &cchTmp);
|
|
cch += cchTmp;
|
|
}
|
|
|
|
Exit:
|
|
SafeRelease(pCRangeTmp);
|
|
SafeRelease(pCRange);
|
|
|
|
return cch;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Restore
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CRangeBackupProperty::Restore(TfEditCookie ec)
|
|
{
|
|
int i;
|
|
HRESULT hr;
|
|
int nCnt;
|
|
CRange *pCRange;
|
|
|
|
nCnt = _rgPropRanges.Count();
|
|
if (!nCnt)
|
|
return FALSE;
|
|
|
|
pCRange = _ppr->_pRange->_Clone();
|
|
if (!pCRange)
|
|
return FALSE;
|
|
|
|
for (i = 0; i < nCnt; i++)
|
|
{
|
|
PERSISTPROPERTYRANGE *pPropRange;
|
|
LONG cchStart, cchEnd;
|
|
pPropRange = _rgPropRanges.GetPtr(i);
|
|
|
|
Assert(pPropRange);
|
|
Assert(pPropRange->_pPropStore);
|
|
|
|
hr = pCRange->ShiftStartToRange(ec, (ITfRangeAnchor *)_ppr->_pRange,
|
|
TF_ANCHOR_START);
|
|
if (FAILED(hr))
|
|
goto Next;
|
|
|
|
hr = pCRange->Collapse(ec, TF_ANCHOR_START);
|
|
if (FAILED(hr))
|
|
goto Next;
|
|
|
|
// shift End first.
|
|
hr = pCRange->ShiftEnd(ec, pPropRange->achEnd, &cchEnd, NULL);
|
|
if (FAILED(hr))
|
|
goto Next;
|
|
|
|
hr = pCRange->ShiftStart(ec, pPropRange->achStart, &cchStart, NULL);
|
|
if (FAILED(hr))
|
|
goto Next;
|
|
|
|
_pProp->_SetStoreInternal(ec, pCRange, pPropRange->_pPropStore, TRUE);
|
|
Next:
|
|
pPropRange->_pPropStore->Release();
|
|
pPropRange->_pPropStore = NULL;
|
|
}
|
|
|
|
pCRange->Release();
|
|
_rgPropRanges.Clear();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CRangeBackup
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// ctor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CRangeBackup::CRangeBackup(CInputContext *pic)
|
|
{
|
|
_pic = pic;
|
|
Assert(!_pRange);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// dtor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CRangeBackup::~CRangeBackup()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Clear
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CRangeBackup::Clear()
|
|
{
|
|
_pic = NULL;
|
|
SafeReleaseClear(_pRange);
|
|
|
|
delete _psz;
|
|
_psz = NULL;
|
|
|
|
int nCnt = _rgProp.Count();
|
|
for (int i = 0; i < nCnt; i++)
|
|
{
|
|
CRangeBackupProperty *pprp = _rgProp.Get(i);
|
|
delete pprp;
|
|
}
|
|
_rgProp.Clear();
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Init
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CRangeBackup::Init(TfEditCookie ec, CRange *pRange)
|
|
{
|
|
ITfRange *pRangeTmp = NULL;
|
|
ULONG cch, cchCur;
|
|
BOOL fEmpty;
|
|
CProperty *pProp;
|
|
HRESULT hr;
|
|
WCHAR *pszTmp;
|
|
|
|
Assert(!_pRange);
|
|
Assert(!_psz);
|
|
|
|
_pRange = pRange->_Clone();
|
|
|
|
hr = _pRange->Clone(&pRangeTmp);
|
|
if (FAILED(hr) || !pRangeTmp)
|
|
return E_FAIL;
|
|
|
|
hr = E_FAIL;
|
|
|
|
//
|
|
// Save text.
|
|
//
|
|
fEmpty = FALSE;
|
|
cchCur = 0;
|
|
cch = 31;
|
|
while ((pRangeTmp->IsEmpty(ec, &fEmpty) == S_OK) && !fEmpty)
|
|
{
|
|
if (!_psz)
|
|
{
|
|
Assert(cchCur == 0);
|
|
_psz = (WCHAR *)cicMemAlloc((cch + 1) * sizeof(WCHAR));
|
|
}
|
|
else
|
|
{
|
|
Assert(cchCur);
|
|
pszTmp = (WCHAR *)cicMemReAlloc(_psz, (cchCur + cch + 1) * sizeof(WCHAR));
|
|
if (pszTmp != NULL)
|
|
{
|
|
_psz = pszTmp;
|
|
}
|
|
else
|
|
{
|
|
cicMemFree(_psz);
|
|
_psz = NULL;
|
|
}
|
|
}
|
|
|
|
if (_psz == NULL)
|
|
goto Exit;
|
|
|
|
pRangeTmp->GetText(ec, TF_TF_MOVESTART, _psz + cchCur, cch, &cch);
|
|
|
|
cchCur += cch;
|
|
cch *= 2;
|
|
}
|
|
|
|
if (!cchCur)
|
|
{
|
|
hr = S_FALSE;
|
|
_cch = 0;
|
|
|
|
if (_psz)
|
|
{
|
|
cicMemFree(_psz);
|
|
_psz = NULL;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
_cch = cchCur;
|
|
_psz[_cch] = L'\0';
|
|
|
|
//
|
|
// Save property.
|
|
//
|
|
pProp = _pic->_pPropList;
|
|
while (pProp)
|
|
{
|
|
CRangeBackupProperty *pPropRange;
|
|
int nCnt = _rgProp.Count();
|
|
|
|
pPropRange = new CRangeBackupProperty(this, pProp);
|
|
if (!pPropRange)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Exit;
|
|
}
|
|
|
|
if (!pPropRange->Init(ec))
|
|
{
|
|
delete pPropRange;
|
|
goto Next;
|
|
}
|
|
|
|
if (!_rgProp.Insert(nCnt, 1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
delete pPropRange;
|
|
goto Next;
|
|
}
|
|
|
|
_rgProp.Set(nCnt, pPropRange);
|
|
|
|
Next:
|
|
pProp = pProp->_pNext;
|
|
}
|
|
|
|
hr = S_OK;
|
|
Exit:
|
|
SafeRelease(pRangeTmp);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Restore
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CRangeBackup::Restore(TfEditCookie ec, ITfRange *pRange)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
int i;
|
|
int nCnt;
|
|
CRange *range;
|
|
|
|
if (!_pic->_IsValidEditCookie(ec, TF_ES_READWRITE))
|
|
{
|
|
Assert(0);
|
|
return TF_E_NOLOCK;
|
|
}
|
|
|
|
if (pRange)
|
|
{
|
|
SafeReleaseClear(_pRange);
|
|
range = GetCRange_NA(pRange);
|
|
if (range == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
if (!VerifySameContext(_pic, range))
|
|
return E_INVALIDARG;
|
|
|
|
range->_QuickCheckCrossedAnchors();
|
|
|
|
_pRange = range->_Clone();
|
|
}
|
|
|
|
Assert(_pRange);
|
|
Assert(_psz || !_cch);
|
|
|
|
if (!_pic)
|
|
return S_OK;
|
|
|
|
Assert(_pRange);
|
|
|
|
_pRange->SetText(ec, 0, _psz, _cch);
|
|
|
|
nCnt = _rgProp.Count();
|
|
for (i = 0; i < nCnt; i++)
|
|
{
|
|
CRangeBackupProperty *pPropRange = _rgProp.Get(i);
|
|
|
|
Assert(pPropRange);
|
|
pPropRange->Restore(ec);
|
|
delete pPropRange;
|
|
}
|
|
_rgProp.Clear();
|
|
|
|
hr = S_OK;
|
|
return hr;
|
|
}
|