mirror of
https://github.com/microsoft/Microsoft-3D-Movie-Maker.git
synced 2024-11-22 02:12:33 +01:00
1637 lines
36 KiB
C++
1637 lines
36 KiB
C++
/* Copyright (c) Microsoft Corporation.
|
|
Licensed under the MIT License. */
|
|
|
|
/***************************************************************************
|
|
|
|
Handles editing a chunk consisting of a group
|
|
(GL, AL, GG, AG, GST, AST)
|
|
|
|
***************************************************************************/
|
|
#include "ched.h"
|
|
ASSERTNAME
|
|
|
|
|
|
#define kcbMaxDispGrp 16
|
|
|
|
bool _FDlgGrpbNew(PDLG pdlg, long *pidit, void *pv);
|
|
|
|
|
|
BEGIN_CMD_MAP(DCGB, DDG)
|
|
ON_CID_GEN(cidEditNatural, &DCGB::FCmdEditItem, &DCGB::FEnableDcgbCmd)
|
|
ON_CID_GEN(cidEditHex, &DCGB::FCmdEditItem, &DCGB::FEnableDcgbCmd)
|
|
ON_CID_GEN(cidInsertItem, &DCGB::FCmdAddItem, &DCGB::FEnableDcgbCmd)
|
|
ON_CID_GEN(cidAddItem, &DCGB::FCmdAddItem, pvNil)
|
|
ON_CID_GEN(cidDeleteItem, &DCGB::FCmdDeleteItem, &DCGB::FEnableDcgbCmd)
|
|
END_CMD_MAP_NIL()
|
|
|
|
|
|
RTCLASS(DOCG)
|
|
RTCLASS(DOCI)
|
|
RTCLASS(DCGB)
|
|
RTCLASS(DCGL)
|
|
RTCLASS(DCGG)
|
|
RTCLASS(DCST)
|
|
|
|
/***************************************************************************
|
|
Constructor for a group document. cls indicates which group class
|
|
the edited chunk belongs to. cls should be one of GL, AL, GG, AG,
|
|
GST, AST.
|
|
***************************************************************************/
|
|
DOCG::DOCG(PDOCB pdocb, PCFL pcfl, CTG ctg, CNO cno, long cls)
|
|
: DOCE(pdocb, pcfl, ctg, cno)
|
|
{
|
|
_pgrpb = pvNil;
|
|
_cls = cls;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Destructor for DOCG. Free the GRPB.
|
|
***************************************************************************/
|
|
DOCG::~DOCG(void)
|
|
{
|
|
ReleasePpo(&_pgrpb);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Static method to create a new document based on a group in a chunk.
|
|
Asserts that there are no other editing docs open on this chunk.
|
|
***************************************************************************/
|
|
PDOCG DOCG::PdocgNew(PDOCB pdocb, PCFL pcfl, CTG ctg, CNO cno, long cls)
|
|
{
|
|
AssertPo(pdocb, 0);
|
|
AssertPo(pcfl, 0);
|
|
|
|
Assert(pvNil == DOCE::PdoceFromChunk(pdocb, pcfl, ctg, cno),
|
|
"DOCE already exists for the chunk");
|
|
PDOCG pdocg;
|
|
|
|
if (pvNil == (pdocg = NewObj DOCG(pdocb, pcfl, ctg, cno, cls)))
|
|
return pvNil;
|
|
if (!pdocg->_FInit())
|
|
{
|
|
ReleasePpo(&pdocg);
|
|
return pvNil;
|
|
}
|
|
AssertPo(pdocg, 0);
|
|
return pdocg;
|
|
}
|
|
|
|
|
|
enum
|
|
{
|
|
kiditOkGrpbNew,
|
|
kiditCancelGrpbNew,
|
|
kiditSizeGrpbNew,
|
|
kiditLimGrpbNew
|
|
};
|
|
|
|
|
|
/***************************************************************************
|
|
Dialog proc for Adopt Chunk dialog.
|
|
***************************************************************************/
|
|
bool _FDlgGrpbNew(PDLG pdlg, long *pidit, void *pv)
|
|
{
|
|
AssertPo(pdlg, 0);
|
|
AssertVarMem(pidit);
|
|
long cb;
|
|
bool fEmpty;
|
|
|
|
switch (*pidit)
|
|
{
|
|
case kiditCancelGrpbNew:
|
|
return fTrue; //dismiss the dialog
|
|
|
|
case kiditOkGrpbNew:
|
|
if (!pdlg->FGetValues(0, kiditLimGrpbNew))
|
|
{
|
|
*pidit = ivNil;
|
|
return fTrue;
|
|
}
|
|
|
|
//check the size
|
|
if (!pdlg->FGetLwFromEdit(kiditSizeGrpbNew, &cb, &fEmpty) && !fEmpty ||
|
|
!FIn(cb, *(long *)pv, kcbMax))
|
|
{
|
|
vpappb->TGiveAlertSz(PszLit("Bad Size"), bkOk, cokStop);
|
|
pdlg->SelectDit(kiditSizeGrpbNew);
|
|
return fFalse;
|
|
}
|
|
return fTrue;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return fFalse;
|
|
}
|
|
|
|
/***************************************************************************
|
|
Read the group from the given flo.
|
|
***************************************************************************/
|
|
bool DOCG::_FRead(PBLCK pblck)
|
|
{
|
|
AssertPo(pblck, 0);
|
|
Assert(pvNil == _pgrpb, "group not nil");
|
|
|
|
if (0 == pblck->Cb(fTrue))
|
|
{
|
|
//create a new one - need to ask for a size from the user
|
|
PDLG pdlg;
|
|
long dlid, idit;
|
|
long cb, cbMin;
|
|
bool fEmpty;
|
|
|
|
//determine which dialog to use
|
|
cbMin = 0;
|
|
switch (_cls)
|
|
{
|
|
case kclsGL:
|
|
case kclsAL:
|
|
dlid = dlidGlbNew;
|
|
cbMin = 1;
|
|
break;
|
|
case kclsGG:
|
|
case kclsAG:
|
|
dlid = dlidGgbNew;
|
|
break;
|
|
case kclsGST:
|
|
case kclsAST:
|
|
dlid = dlidGstbNew;
|
|
break;
|
|
default:
|
|
BugVar("bad cls value", &_cls);
|
|
return fFalse;
|
|
}
|
|
|
|
pdlg = DLG::PdlgNew(dlid, _FDlgGrpbNew, &cbMin);
|
|
pdlg->FPutLwInEdit(kiditSizeGrpbNew, cbMin);
|
|
if (pvNil == pdlg)
|
|
goto LFail;
|
|
idit = pdlg->IditDo(kiditSizeGrpbNew);
|
|
if (idit != kiditOkGrpbNew)
|
|
goto LFail;
|
|
|
|
if (!pdlg->FGetLwFromEdit(kiditSizeGrpbNew, &cb, &fEmpty) && !fEmpty ||
|
|
!FIn(cb, cbMin, kcbMax / size(long)))
|
|
{
|
|
goto LFail;
|
|
}
|
|
|
|
switch (_cls)
|
|
{
|
|
case kclsGL:
|
|
_pgrpb = GL::PglNew(cb);
|
|
break;
|
|
case kclsAL:
|
|
_pgrpb = AL::PalNew(cb);
|
|
break;
|
|
case kclsGG:
|
|
_pgrpb = GG::PggNew(cb);
|
|
break;
|
|
case kclsAG:
|
|
_pgrpb = AG::PagNew(cb);
|
|
break;
|
|
case kclsGST:
|
|
_pgrpb = GST::PgstNew(cb * size(long));
|
|
break;
|
|
case kclsAST:
|
|
_pgrpb = AST::PastNew(cb * size(long));
|
|
break;
|
|
default:
|
|
BugVar("bad cls value", &_cls);
|
|
return fFalse;
|
|
}
|
|
LFail:
|
|
ReleasePpo(&pdlg);
|
|
_bo = kboCur;
|
|
_osk = koskCur;
|
|
_fDirty = fTrue;
|
|
}
|
|
else
|
|
{
|
|
switch (_cls)
|
|
{
|
|
case kclsGL:
|
|
_pgrpb = GL::PglRead(pblck, &_bo, &_osk);
|
|
break;
|
|
case kclsAL:
|
|
_pgrpb = AL::PalRead(pblck, &_bo, &_osk);
|
|
break;
|
|
case kclsGG:
|
|
_pgrpb = GG::PggRead(pblck, &_bo, &_osk);
|
|
break;
|
|
case kclsAG:
|
|
_pgrpb = AG::PagRead(pblck, &_bo, &_osk);
|
|
break;
|
|
case kclsGST:
|
|
_pgrpb = GST::PgstRead(pblck, &_bo, &_osk);
|
|
break;
|
|
case kclsAST:
|
|
_pgrpb = AST::PastRead(pblck, &_bo, &_osk);
|
|
break;
|
|
default:
|
|
BugVar("bad cls value", &_cls);
|
|
return fFalse;
|
|
}
|
|
}
|
|
|
|
return pvNil != _pgrpb;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Create a new DDG onto the document.
|
|
***************************************************************************/
|
|
PDDG DOCG::PddgNew(PGCB pgcb)
|
|
{
|
|
AssertThis(0);
|
|
PDDG pddg;
|
|
|
|
pddg = pvNil;
|
|
switch (_cls)
|
|
{
|
|
case kclsGL:
|
|
case kclsAL:
|
|
pddg = DCGL::PdcglNew(this, (PGLB)_pgrpb, _cls, pgcb);
|
|
break;
|
|
case kclsGG:
|
|
case kclsAG:
|
|
pddg = DCGG::PdcggNew(this, (PGGB)_pgrpb, _cls, pgcb);
|
|
break;
|
|
case kclsGST:
|
|
case kclsAST:
|
|
pddg = DCST::PdcstNew(this, (PGSTB)_pgrpb, _cls, pgcb);
|
|
break;
|
|
default:
|
|
BugVar("bad cls value", &_cls);
|
|
break;
|
|
}
|
|
return pddg;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Write the group to disk.
|
|
***************************************************************************/
|
|
bool DOCG::_FWrite(PBLCK pblck, bool fRedirect)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(pblck, 0);
|
|
return _pgrpb->FWrite(pblck, _bo, _osk);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Get the size of the group on file.
|
|
***************************************************************************/
|
|
long DOCG::_CbOnFile(void)
|
|
{
|
|
AssertThis(0);
|
|
return _pgrpb->CbOnFile();
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
/***************************************************************************
|
|
Assert the validity of an object.
|
|
***************************************************************************/
|
|
void DOCG::AssertValid(ulong grf)
|
|
{
|
|
DOCG_PAR::AssertValid(0);
|
|
AssertPo(_pgrpb, 0);
|
|
Assert(_pgrpb->FIs(_cls), "group doesn't match cls");
|
|
switch (_cls)
|
|
{
|
|
case kclsGL:
|
|
case kclsAL:
|
|
case kclsGG:
|
|
case kclsAG:
|
|
case kclsGST:
|
|
case kclsAST:
|
|
break;
|
|
default:
|
|
BugVar("bad cls value", &_cls);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Mark memory for the DOCG.
|
|
***************************************************************************/
|
|
void DOCG::MarkMem(void)
|
|
{
|
|
AssertValid(0);
|
|
DOCG_PAR::MarkMem();
|
|
MarkMemObj(_pgrpb);
|
|
}
|
|
#endif //DEBUG
|
|
|
|
|
|
/***************************************************************************
|
|
Constructor for a DCGB.
|
|
***************************************************************************/
|
|
DCGB::DCGB(PDOCB pdocb, PGRPB pgrpb, long cls, long clnItem, PGCB pgcb)
|
|
: DCLB(pdocb, pgcb)
|
|
{
|
|
AssertIn(clnItem, 1, 10);
|
|
_dypBorder = 1;
|
|
_dypLine = _dypLine + _dypBorder;
|
|
_clnItem = clnItem;
|
|
_ivCur = ivNil;
|
|
_dlnCur = 0;
|
|
_pgrpb = pgrpb;
|
|
_cls = cls;
|
|
switch (_cls)
|
|
{
|
|
default:
|
|
#ifdef DEBUG
|
|
BugVar("bad cls value", &_cls);
|
|
case kclsGL:
|
|
case kclsGG:
|
|
case kclsGST:
|
|
#endif //DEBUG
|
|
_fAllocated = fFalse;
|
|
break;
|
|
case kclsAL:
|
|
case kclsAG:
|
|
case kclsAST:
|
|
_fAllocated = fTrue;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Static method to invalidate all DCGB's on this GRPB. Also dirties the
|
|
document. Should be called by any code that edits the document.
|
|
***************************************************************************/
|
|
void DCGB::InvalAllDcgb(PDOCB pdocb, PGRPB pgrpb, long iv, long cvIns, long cvDel)
|
|
{
|
|
long ipddg;
|
|
PDDG pddg;
|
|
PDCGB pdcgb;
|
|
|
|
//mark the document dirty
|
|
pdocb->SetDirty();
|
|
|
|
//inform the DCGB's
|
|
for (ipddg = 0; pvNil != (pddg = pdocb->PddgGet(ipddg)); ipddg++)
|
|
{
|
|
if (!pddg->FIs(kclsDCGB))
|
|
continue;
|
|
pdcgb = (PDCGB)pddg;
|
|
if (pdcgb->_pgrpb == pgrpb)
|
|
pdcgb->_InvalIv(iv, cvIns, cvDel);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Invalidate the display from iv to the end of the display. If we're
|
|
the active DCGB, also redraw.
|
|
***************************************************************************/
|
|
void DCGB::_InvalIv(long iv, long cvIns, long cvDel)
|
|
{
|
|
AssertThis(0);
|
|
AssertIn(iv, 0, kcbMax);
|
|
AssertIn(cvIns, 0, kcbMax);
|
|
AssertIn(cvDel, 0, kcbMax);
|
|
RC rc;
|
|
|
|
//adjust the sel
|
|
if (_ivCur > iv)
|
|
{
|
|
if (_ivCur < iv + cvDel)
|
|
{
|
|
_ivCur = ivNil;
|
|
_dlnCur = 0;
|
|
}
|
|
else
|
|
_ivCur += cvIns - cvDel;
|
|
}
|
|
|
|
//caclculate the invalid rectangle
|
|
GetRc(&rc, cooLocal);
|
|
rc.ypTop = _YpFromIvDln(iv, 0);
|
|
if (cvIns == cvDel)
|
|
rc.ypBottom = _YpFromIvDln(iv + cvIns, 0);
|
|
|
|
if (rc.FEmpty())
|
|
return;
|
|
|
|
if (_fActive)
|
|
{
|
|
ValidRc(&rc, kginDraw);
|
|
InvalRc(&rc, kginDraw);
|
|
}
|
|
else
|
|
InvalRc(&rc);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
We're being activated or deactivated so invert the sel.
|
|
***************************************************************************/
|
|
void DCGB::_Activate(bool fActive)
|
|
{
|
|
AssertThis(0);
|
|
DDG::_Activate(fActive);
|
|
|
|
GNV gnv(this);
|
|
_DrawSel(&gnv);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Return the max for the scroll bar.
|
|
***************************************************************************/
|
|
long DCGB::_ScvMax(bool fVert)
|
|
{
|
|
AssertThis(0);
|
|
RC rc;
|
|
long ichLim;
|
|
|
|
_GetContent(&rc);
|
|
if (fVert)
|
|
{
|
|
return LwMax(0,
|
|
LwMul(_clnItem, _pgrpb->IvMac()) - rc.Dyp() / _dypLine + 1);
|
|
}
|
|
|
|
ichLim = 3 * kcbMaxDispGrp + kcbMaxDispGrp / 4 + 12;
|
|
return LwMax(0, ichLim - rc.Dxp() / _dxpChar);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Set the selection to the given line.
|
|
***************************************************************************/
|
|
void DCGB::_SetSel(long ln)
|
|
{
|
|
AssertThis(0);
|
|
long iv, dln;
|
|
|
|
if (ln < 0 || ln >= _LnLim())
|
|
{
|
|
Assert(ln == lnNil, "bad non-nil selection requested");
|
|
iv = ivNil;
|
|
dln = 0;
|
|
}
|
|
else
|
|
{
|
|
iv = ln / _clnItem;
|
|
dln = ln % _clnItem;
|
|
}
|
|
|
|
if (_ivCur == iv && _dlnCur == dln)
|
|
return;
|
|
|
|
if (_fActive)
|
|
{
|
|
GNV gnv(this);
|
|
|
|
//erase the old sel
|
|
if (_fActive)
|
|
_DrawSel(&gnv);
|
|
|
|
//set the new sel and draw it
|
|
_ivCur = iv;
|
|
_dlnCur = dln;
|
|
if (_fActive)
|
|
_DrawSel(&gnv);
|
|
}
|
|
else
|
|
{
|
|
//just set the new selection
|
|
_ivCur = iv;
|
|
_dlnCur = dln;
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Scroll the sel into view.
|
|
***************************************************************************/
|
|
void DCGB::_ShowSel(void)
|
|
{
|
|
AssertThis(0);
|
|
RC rc;
|
|
long cln, ln;
|
|
|
|
if (ivNil == _ivCur)
|
|
return;
|
|
|
|
ln = _LnFromIvDln(_ivCur, _dlnCur) - _scvVert;
|
|
if (ln < 0)
|
|
_Scroll(scaNil, scaToVal, 0, _scvVert + ln);
|
|
else
|
|
{
|
|
_GetContent(&rc);
|
|
cln = LwMax(1, rc.Dyp() / _dypLine);
|
|
if (ln >= cln)
|
|
_Scroll(scaNil, scaToVal, 0, _scvVert + ln - cln + 1);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Hilite the selection (if there is one)
|
|
***************************************************************************/
|
|
void DCGB::_DrawSel(PGNV pgnv)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(pgnv, 0);
|
|
RC rc;
|
|
|
|
if (ivNil != _ivCur)
|
|
{
|
|
pgnv->GetRcSrc(&rc);
|
|
rc.ypTop = _YpFromIvDln(_ivCur, _dlnCur);
|
|
rc.ypBottom = rc.ypTop + _dypLine - _dypBorder;
|
|
pgnv->HiliteRc(&rc, kacrWhite);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
Handle key input.
|
|
***************************************************************************/
|
|
bool DCGB::FCmdKey(PCMD_KEY pcmd)
|
|
{
|
|
AssertThis(0);
|
|
long ln, lnLim, lnNew, cln;
|
|
RC rc;
|
|
|
|
ln = _LnFromIvDln(_ivCur, _dlnCur);
|
|
lnLim = _LnLim();
|
|
switch (pcmd->vk)
|
|
{
|
|
case kvkDown:
|
|
lnNew = (0 > ln) ? 0 : (ln + 1) % lnLim;
|
|
goto LChangeSel;
|
|
|
|
case kvkUp:
|
|
lnNew = (0 > ln) ? lnLim - 1 : (ln + lnLim - 1) % lnLim;
|
|
goto LChangeSel;
|
|
|
|
case kvkPageUp:
|
|
case kvkPageDown:
|
|
_GetContent(&rc);
|
|
cln = LwMax(1, rc.Dyp() / _dypLine - 1);
|
|
if (pcmd->vk == kvkPageDown)
|
|
lnNew = LwMin(lnLim - 1, lnNil == ln ? cln : ln + cln);
|
|
else
|
|
lnNew = LwMax(0, lnNil == ln ? 0 : ln - cln);
|
|
goto LChangeSel;
|
|
|
|
case kvkHome:
|
|
lnNew = 0;
|
|
goto LChangeSel;
|
|
|
|
case kvkEnd:
|
|
lnNew = lnLim - 1;
|
|
LChangeSel:
|
|
if (lnLim == 0)
|
|
{
|
|
Assert(lnNil == ln, "no lines, but non-nil sel");
|
|
break;
|
|
}
|
|
|
|
AssertIn(lnNew, 0, lnLim);
|
|
_SetSel(lnNew);
|
|
_ShowSel();
|
|
break;
|
|
|
|
case kvkDelete:
|
|
case kvkBack:
|
|
if (ivNil != _ivCur && !_pgrpb->FFree(_ivCur))
|
|
_DeleteIv(_ivCur);
|
|
break;
|
|
|
|
default:
|
|
switch (pcmd->ch)
|
|
{
|
|
case kchReturn:
|
|
if (ivNil != _ivCur && !_pgrpb->FFree(_ivCur))
|
|
_EditIvDln(_ivCur, _dlnCur);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Handle mouse-down in a DCGB - track the mouse and select the last
|
|
item the mouse is over.
|
|
***************************************************************************/
|
|
void DCGB::MouseDown(long xp, long yp, long cact, ulong grfcust)
|
|
{
|
|
AssertThis(0);
|
|
bool fDown;
|
|
PT pt, ptT;
|
|
long ln, ivCur, dlnCur;
|
|
RC rc;
|
|
|
|
//do this before the activate to avoid flashing the selection
|
|
ivCur = _ivCur;
|
|
dlnCur = _dlnCur;
|
|
ln = _LnFromYp(yp);
|
|
if (ln >= _LnLim())
|
|
ln = lnNil;
|
|
_SetSel(ln);
|
|
|
|
if (!_fActive)
|
|
Activate(fTrue);
|
|
|
|
if (cact > 1 && ivCur == _ivCur && dlnCur == _dlnCur &&
|
|
_ivCur != ivNil && !_pgrpb->FFree(_ivCur))
|
|
{
|
|
//edit the thing
|
|
_EditIvDln(_ivCur, _dlnCur);
|
|
return;
|
|
}
|
|
|
|
Clean();
|
|
_GetContent(&rc);
|
|
for (GetPtMouse(&pt, &fDown); fDown; GetPtMouse(&pt, &fDown))
|
|
{
|
|
if (!rc.FPtIn(pt.xp, pt.yp))
|
|
{
|
|
//do autoscroll
|
|
ptT = pt;
|
|
rc.PinPt(&pt);
|
|
_Scroll(scaToVal, scaToVal,
|
|
_scvHorz + LwDivAway(ptT.xp - pt.xp, _dxpChar),
|
|
_scvVert + LwDivAway(ptT.yp - pt.yp, _dypLine));
|
|
}
|
|
if (!rc.FPtIn(pt.xp, pt.yp) || (ln = _LnFromYp(pt.yp)) >= _LnLim())
|
|
ln = lnNil;
|
|
_SetSel(ln);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Handle enabling/disabling commands.
|
|
***************************************************************************/
|
|
bool DCGB::FEnableDcgbCmd(PCMD pcmd, ulong *pgrfeds)
|
|
{
|
|
bool fT;
|
|
|
|
switch (pcmd->cid)
|
|
{
|
|
case cidEditNatural:
|
|
case cidEditHex:
|
|
case cidDeleteItem:
|
|
fT = (ivNil != _ivCur) && !_pgrpb->FFree(_ivCur);
|
|
break;
|
|
|
|
case cidInsertItem:
|
|
fT = (ivNil != _ivCur) && !_fAllocated;
|
|
break;
|
|
|
|
default:
|
|
BugVar("unhandled cid", &pcmd->cid);
|
|
fT = fFalse;
|
|
break;
|
|
}
|
|
|
|
*pgrfeds = fT ? fedsEnable : fedsDisable;
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Handles commands to edit the current line of the group.
|
|
***************************************************************************/
|
|
bool DCGB::FCmdEditItem(PCMD pcmd)
|
|
{
|
|
if (ivNil == _ivCur)
|
|
return fFalse;
|
|
|
|
_EditIvDln(_ivCur, _dlnCur);
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Edit the indicated line of the group.
|
|
***************************************************************************/
|
|
void DCGB::_EditIvDln(long iv, long dln)
|
|
{
|
|
PDOCI pdoci;
|
|
|
|
if (pvNil == (pdoci = DOCI::PdociNew(_pdocb, _pgrpb, _cls, iv, dln)))
|
|
return;
|
|
|
|
pdoci->PdmdNew();
|
|
ReleasePpo(&pdoci);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Handle cidDeleteItem.
|
|
***************************************************************************/
|
|
bool DCGB::FCmdDeleteItem(PCMD pcmd)
|
|
{
|
|
_DeleteIv(_ivCur);
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Delete the indicated item.
|
|
***************************************************************************/
|
|
void DCGB::_DeleteIv(long iv)
|
|
{
|
|
long ivMac;
|
|
|
|
if (ivNil == iv || _pgrpb->FFree(iv))
|
|
return;
|
|
|
|
//turn off the selection, delete the element and invalidate stuff
|
|
_SetSel(lnNil);
|
|
_pgrpb->Delete(iv);
|
|
ivMac = _pgrpb->IvMac();
|
|
if (iv < ivMac)
|
|
{
|
|
InvalAllDcgb(_pdocb, _pgrpb, iv, _fAllocated ? 1 : 0, 1);
|
|
_SetSel(_LnFromIvDln(iv, 0));
|
|
}
|
|
else
|
|
{
|
|
InvalAllDcgb(_pdocb, _pgrpb, ivMac, 0, iv - ivMac + 1);
|
|
if (ivMac > 0)
|
|
_SetSel(_LnFromIvDln(ivMac - 1, 0));
|
|
}
|
|
_ShowSel();
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
/***************************************************************************
|
|
Assert the validity of a DCGB.
|
|
***************************************************************************/
|
|
void DCGB::AssertValid(ulong grf)
|
|
{
|
|
//REVIEW shonk: fill out
|
|
DCGB_PAR::AssertValid(0);
|
|
AssertPo(_pgrpb, 0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Mark memory for the DCGB.
|
|
***************************************************************************/
|
|
void DCGB::MarkMem(void)
|
|
{
|
|
AssertValid(0);
|
|
DCGB_PAR::MarkMem();
|
|
MarkMemObj(_pgrpb);
|
|
}
|
|
#endif //DEBUG
|
|
|
|
|
|
/***************************************************************************
|
|
Constructor for the DCGL class. This class displays (and allows
|
|
editing of) a GL or AL.
|
|
***************************************************************************/
|
|
DCGL::DCGL(PDOCB pdocb, PGLB pglb, long cls, PGCB pgcb)
|
|
: DCGB(pdocb, pglb, cls, 1, pgcb)
|
|
{
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Static method to create a new DCGL for the GL or AL.
|
|
***************************************************************************/
|
|
PDCGL DCGL::PdcglNew(PDOCB pdocb, PGLB pglb, long cls, PGCB pgcb)
|
|
{
|
|
AssertVar(cls == kclsGL || cls == kclsAL, "bad cls", &cls);
|
|
PDCGL pdcgl;
|
|
|
|
if (pvNil == (pdcgl = NewObj DCGL(pdocb, pglb, cls, pgcb)))
|
|
return pvNil;
|
|
|
|
if (!pdcgl->_FInit())
|
|
{
|
|
ReleasePpo(&pdcgl);
|
|
return pvNil;
|
|
}
|
|
pdcgl->Activate(fTrue);
|
|
|
|
AssertPo(pdcgl, 0);
|
|
return pdcgl;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Draw the contents of the DCGL.
|
|
***************************************************************************/
|
|
void DCGL::Draw(PGNV pgnv, RC *prcClip)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(pgnv, 0);
|
|
AssertVarMem(prcClip);
|
|
PGLB pglb;
|
|
STN stn;
|
|
byte rgb[kcbMaxDispGrp];
|
|
long ivMac, iv;
|
|
long cbDisp, cbEntry;
|
|
long xp, yp, ibT;
|
|
byte bT;
|
|
|
|
pgnv->ClipRc(prcClip);
|
|
pgnv->FillRc(prcClip, kacrWhite);
|
|
pgnv->SetOnn(_onn);
|
|
|
|
pglb = (PGLB)_pgrpb;
|
|
ivMac = pglb->IvMac();
|
|
xp = _XpFromIch(0);
|
|
cbDisp = cbEntry = pglb->CbEntry();
|
|
if (cbDisp > kcbMaxDispGrp)
|
|
{
|
|
//the rest will be filled with periods to indicate that
|
|
//not everything is displayed
|
|
cbDisp = kcbMaxDispGrp - 2;
|
|
}
|
|
|
|
iv = _LnFromYp(LwMax(_dypHeader, prcClip->ypTop));
|
|
yp = _YpFromIvDln(iv, 0);
|
|
|
|
for ( ; iv < ivMac && yp < prcClip->ypBottom; iv++)
|
|
{
|
|
if (pglb->FFree(iv))
|
|
{
|
|
stn.FFormatSz(PszLit("%5d) FREE"), iv);
|
|
goto LDisplay;
|
|
}
|
|
|
|
CopyPb(pglb->QvGet(iv), rgb, cbDisp);
|
|
|
|
//first comes the item number
|
|
stn.FFormatSz(PszLit("%5d) "), iv);
|
|
|
|
//now add the bytes in hex, with a space after every four bytes
|
|
for (ibT = 0; ibT < cbDisp; ibT++)
|
|
{
|
|
bT = rgb[ibT];
|
|
if ((ibT & 0x03) == 0)
|
|
stn.FAppendCh(kchSpace);
|
|
stn.FAppendCh(vrgchHex[(bT >> 4) & 0x0F]);
|
|
stn.FAppendCh(vrgchHex[bT & 0x0F]);
|
|
}
|
|
//add the periods
|
|
if (cbDisp < cbEntry)
|
|
stn.FAppendSz(PszLit("...."));
|
|
stn.FAppendSz(PszLit(" "));
|
|
|
|
//now comes the ascii characters.
|
|
for (ibT = 0; ibT < cbDisp; ibT++)
|
|
{
|
|
bT = rgb[ibT];
|
|
if (bT < 32 || bT == 0x7F)
|
|
bT = '?';
|
|
stn.FAppendCh((achar)bT);
|
|
}
|
|
//add the periods
|
|
if (cbDisp < cbEntry)
|
|
stn.FAppendSz(PszLit(".."));
|
|
|
|
LDisplay:
|
|
pgnv->DrawStn(&stn, xp, yp);
|
|
yp += _dypLine;
|
|
}
|
|
|
|
//draw the selection
|
|
if (_fActive)
|
|
_DrawSel(pgnv);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Handle cidAddItem and cidInsertItem.
|
|
***************************************************************************/
|
|
bool DCGL::FCmdAddItem(PCMD pcmd)
|
|
{
|
|
HQ hq;
|
|
long cb;
|
|
void *pv;
|
|
long ivNew;
|
|
bool fT;
|
|
PGLB pglb;
|
|
|
|
pglb = (PGLB)_pgrpb;
|
|
cb = pglb->CbEntry();
|
|
if (!FAllocHq(&hq, cb, fmemClear, mprNormal))
|
|
return fTrue;
|
|
|
|
pv = PvLockHq(hq);
|
|
fT = fFalse;
|
|
switch (pcmd->cid)
|
|
{
|
|
case cidAddItem:
|
|
fT = pglb->FAdd(pv, &ivNew);
|
|
break;
|
|
case cidInsertItem:
|
|
if (_fAllocated)
|
|
break;
|
|
Assert(pglb->FIs(kclsGL), "bad grpb");
|
|
fT = ((PGL)pglb)->FInsert(ivNew = _ivCur, pv);
|
|
}
|
|
UnlockHq(hq);
|
|
FreePhq(&hq);
|
|
if (!fT)
|
|
return fTrue;
|
|
|
|
//turn off the selection and invalidate stuff
|
|
_SetSel(lnNil);
|
|
InvalAllDcgb(_pdocb, pglb, ivNew, 1,
|
|
(_fAllocated && ivNew == pglb->IvMac() - 1) ? 1 : 0);
|
|
_SetSel(_LnFromIvDln(ivNew, 0));
|
|
_ShowSel();
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Constructor for the DCGG class. This class displays (and allows
|
|
editing of) a GG or AG.
|
|
***************************************************************************/
|
|
DCGG::DCGG(PDOCB pdocb, PGGB pggb, long cls, PGCB pgcb)
|
|
: DCGB(pdocb, pggb, cls, pggb->CbFixed() > 0 ? 2 : 1, pgcb)
|
|
{
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Static method to create a new DCGG for the GG or AG.
|
|
***************************************************************************/
|
|
PDCGG DCGG::PdcggNew(PDOCB pdocb, PGGB pggb, long cls, PGCB pgcb)
|
|
{
|
|
AssertVar(cls == kclsGG || cls == kclsAG, "bad cls", &cls);
|
|
PDCGG pdcgg;
|
|
|
|
if (pvNil == (pdcgg = NewObj DCGG(pdocb, pggb, cls, pgcb)))
|
|
return pvNil;
|
|
|
|
if (!pdcgg->_FInit())
|
|
{
|
|
ReleasePpo(&pdcgg);
|
|
return pvNil;
|
|
}
|
|
pdcgg->Activate(fTrue);
|
|
|
|
AssertPo(pdcgg, 0);
|
|
return pdcgg;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Draw the contents of the DCGL.
|
|
***************************************************************************/
|
|
void DCGG::Draw(PGNV pgnv, RC *prcClip)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(pgnv, 0);
|
|
AssertVarMem(prcClip);
|
|
PGGB pggb;
|
|
STN stn;
|
|
byte rgb[kcbMaxDispGrp];
|
|
long ivMac, iv, dln;
|
|
long cbDisp, cbEntry;
|
|
long xp, yp, ibT;
|
|
byte bT;
|
|
RC rc;
|
|
|
|
pgnv->ClipRc(prcClip);
|
|
pgnv->GetRcSrc(&rc);
|
|
pgnv->FillRc(prcClip, kacrWhite);
|
|
pgnv->SetOnn(_onn);
|
|
|
|
pggb = (PGGB)_pgrpb;
|
|
ivMac = pggb->IvMac();
|
|
xp = _XpFromIch(0);
|
|
|
|
iv = _LnFromYp(LwMax(_dypHeader, prcClip->ypTop)) / _clnItem;
|
|
yp = _YpFromIvDln(iv, 0);
|
|
|
|
for ( ; iv < ivMac && yp < prcClip->ypBottom; iv++)
|
|
{
|
|
if (pggb->FFree(iv))
|
|
{
|
|
stn.FFormatSz(PszLit("%5d) FREE"), iv);
|
|
pgnv->DrawStn(&stn, xp, yp);
|
|
yp += _clnItem * _dypLine;
|
|
goto LDrawBorder;
|
|
}
|
|
|
|
for (dln = 0; dln < _clnItem; dln++)
|
|
{
|
|
if (dln == 0)
|
|
cbEntry = pggb->Cb(iv);
|
|
else
|
|
cbEntry = pggb->CbFixed();
|
|
if ((cbDisp = cbEntry) > kcbMaxDispGrp)
|
|
{
|
|
//the rest will be filled with periods to indicate that
|
|
//not everything is displayed
|
|
cbDisp = kcbMaxDispGrp - 2;
|
|
}
|
|
|
|
if (dln == 0)
|
|
{
|
|
CopyPb(pggb->QvGet(iv), rgb, cbDisp);
|
|
stn.FFormatSz(PszLit("%5d) "), iv);
|
|
}
|
|
else
|
|
{
|
|
CopyPb(pggb->QvFixedGet(iv), rgb, cbDisp);
|
|
stn = PszLit(" ");
|
|
}
|
|
|
|
//now add the bytes in hex, with a space after every four bytes
|
|
for (ibT = 0; ibT < cbDisp; ibT++)
|
|
{
|
|
bT = rgb[ibT];
|
|
if ((ibT & 0x03) == 0)
|
|
stn.FAppendCh(kchSpace);
|
|
stn.FAppendCh(vrgchHex[(bT >> 4) & 0x0F]);
|
|
stn.FAppendCh(vrgchHex[bT & 0x0F]);
|
|
}
|
|
//add the periods
|
|
if (cbDisp < cbEntry)
|
|
stn.FAppendSz(PszLit("...."));
|
|
else if (cbDisp < kcbMaxDispGrp)
|
|
{
|
|
for ( ; ibT < kcbMaxDispGrp; ibT++)
|
|
{
|
|
stn.FAppendRgch(PszLit(" "), (ibT & 0x03) == 0 ? 3 : 2);
|
|
}
|
|
}
|
|
stn.FAppendSz(PszLit(" "));
|
|
|
|
//now comes the ascii characters.
|
|
for (ibT = 0; ibT < cbDisp; ibT++)
|
|
{
|
|
bT = rgb[ibT];
|
|
if (bT < 32 || bT == 0x7F)
|
|
bT = '?';
|
|
stn.FAppendCh((achar)bT);
|
|
}
|
|
//add the periods
|
|
if (cbDisp < cbEntry)
|
|
stn.FAppendSz(PszLit(".."));
|
|
|
|
pgnv->DrawStn(&stn, xp, yp);
|
|
yp += _dypLine;
|
|
}
|
|
LDrawBorder:
|
|
rc.ypTop = yp - _dypBorder;
|
|
rc.ypBottom = yp;
|
|
pgnv->FillRc(&rc, kacrBlack);
|
|
}
|
|
|
|
//draw the selection
|
|
if (_fActive)
|
|
_DrawSel(pgnv);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Handle cidAddItem and cidInsertItem.
|
|
***************************************************************************/
|
|
bool DCGG::FCmdAddItem(PCMD pcmd)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pcmd);
|
|
long cb;
|
|
long ivNew;
|
|
bool fT;
|
|
PGGB pggb;
|
|
|
|
pggb = (PGGB)_pgrpb;
|
|
cb = (pggb->CbFixed() == 0);
|
|
|
|
fT = fFalse;
|
|
switch (pcmd->cid)
|
|
{
|
|
case cidAddItem:
|
|
fT = pggb->FAdd(cb, &ivNew);
|
|
break;
|
|
case cidInsertItem:
|
|
if (_fAllocated)
|
|
break;
|
|
Assert(pggb->FIs(kclsGG), "bad grpb");
|
|
fT = ((PGG)pggb)->FInsert(ivNew = _ivCur, cb);
|
|
}
|
|
if (!fT)
|
|
return fTrue;
|
|
|
|
if (cb > 0)
|
|
ClearPb(pggb->QvGet(ivNew), cb);
|
|
else
|
|
ClearPb(pggb->QvFixedGet(ivNew), pggb->CbFixed());
|
|
|
|
//turn off the selection and invalidate stuff
|
|
_SetSel(lnNil);
|
|
InvalAllDcgb(_pdocb, pggb, ivNew, 1,
|
|
(_fAllocated && ivNew == pggb->IvMac() - 1) ? 1 : 0);
|
|
_SetSel(_LnFromIvDln(ivNew, 0));
|
|
_ShowSel();
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Constructor for the DCST class. This class displays (and allows
|
|
editing of) a GST or AST.
|
|
***************************************************************************/
|
|
DCST::DCST(PDOCB pdocb, PGSTB pgstb, long cls, PGCB pgcb)
|
|
: DCGB(pdocb, pgstb, cls, pgstb->CbExtra() > 0 ? 2 : 1, pgcb)
|
|
{
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Static method to create a new DCST for the GST or AST.
|
|
***************************************************************************/
|
|
PDCST DCST::PdcstNew(PDOCB pdocb, PGSTB pgstb, long cls, PGCB pgcb)
|
|
{
|
|
AssertVar(cls == kclsGST || cls == kclsAST, "bad cls", &cls);
|
|
PDCST pdcst;
|
|
|
|
if (pvNil == (pdcst = NewObj DCST(pdocb, pgstb, cls, pgcb)))
|
|
return pvNil;
|
|
|
|
if (!pdcst->_FInit())
|
|
{
|
|
ReleasePpo(&pdcst);
|
|
return pvNil;
|
|
}
|
|
pdcst->Activate(fTrue);
|
|
|
|
AssertPo(pdcst, 0);
|
|
return pdcst;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Draw the contents of the DCGL.
|
|
***************************************************************************/
|
|
void DCST::Draw(PGNV pgnv, RC *prcClip)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(pgnv, 0);
|
|
AssertVarMem(prcClip);
|
|
PGSTB pgstb;
|
|
STN stn;
|
|
STN stnT;
|
|
byte rgb[1024];
|
|
long ivMac, iv;
|
|
long cbDisp, cbExtra;
|
|
long xp, yp, ibT;
|
|
byte bT;
|
|
RC rc;
|
|
HQ hqExtra = hqNil;
|
|
byte *pbExtra = rgb;
|
|
|
|
Assert(size(rgb) >= kcbMaxDispGrp, "rgb too small");
|
|
pgnv->ClipRc(prcClip);
|
|
pgnv->GetRcSrc(&rc);
|
|
pgnv->FillRc(prcClip, kacrWhite);
|
|
pgnv->SetOnn(_onn);
|
|
|
|
pgstb = (PGSTB)_pgrpb;
|
|
if (size(rgb) < (cbExtra = pgstb->CbExtra()))
|
|
{
|
|
if (FAllocHq(&hqExtra, cbExtra, fmemNil, mprNormal))
|
|
pbExtra = (byte *)PvLockHq(hqExtra);
|
|
else
|
|
pbExtra = pvNil;
|
|
}
|
|
|
|
if ((cbDisp = cbExtra) > kcbMaxDispGrp)
|
|
{
|
|
//the rest will be filled with periods to indicate that
|
|
//not everything is displayed
|
|
cbDisp = kcbMaxDispGrp - 2;
|
|
}
|
|
|
|
ivMac = pgstb->IvMac();
|
|
xp = _XpFromIch(0);
|
|
|
|
iv = _LnFromYp(LwMax(_dypHeader, prcClip->ypTop)) / _clnItem;
|
|
yp = _YpFromIvDln(iv, 0);
|
|
|
|
for ( ; iv < ivMac && yp < prcClip->ypBottom; iv++)
|
|
{
|
|
if (pgstb->FFree(iv))
|
|
{
|
|
stn.FFormatSz(PszLit("%5d) FREE"), iv);
|
|
pgnv->DrawStn(&stn, xp, yp);
|
|
goto LDrawBorder;
|
|
}
|
|
|
|
pgstb->GetStn(iv, &stnT);
|
|
stn.FFormatSz(PszLit("%5d) \"%s\""), iv, &stnT);
|
|
pgnv->DrawStn(&stn, xp, yp);
|
|
|
|
if (_clnItem > 1 && pvNil != pbExtra)
|
|
{
|
|
pgstb->GetExtra(iv, pbExtra);
|
|
stn = PszLit(" ");
|
|
|
|
//now add the bytes in hex, with a space after every four bytes
|
|
for (ibT = 0; ibT < cbDisp; ibT++)
|
|
{
|
|
bT = pbExtra[ibT];
|
|
if ((ibT & 0x03) == 0)
|
|
stn.FAppendCh(kchSpace);
|
|
stn.FAppendCh(vrgchHex[(bT >> 4) & 0x0F]);
|
|
stn.FAppendCh(vrgchHex[bT & 0x0F]);
|
|
}
|
|
//add the periods
|
|
if (cbDisp < cbExtra)
|
|
stn.FAppendSz(PszLit("...."));
|
|
stn.FAppendSz(PszLit(" "));
|
|
|
|
//now comes the ascii characters.
|
|
for (ibT = 0; ibT < cbDisp; ibT++)
|
|
{
|
|
bT = pbExtra[ibT];
|
|
if (bT < 32 || bT == 0x7F)
|
|
bT = '?';
|
|
stn.FAppendCh((achar)bT);
|
|
}
|
|
//add the periods
|
|
if (cbDisp < cbExtra)
|
|
stn.FAppendSz(PszLit(".."));
|
|
|
|
pgnv->DrawStn(&stn, xp, yp + _dypLine);
|
|
}
|
|
|
|
LDrawBorder:
|
|
yp += _clnItem * _dypLine;
|
|
rc.ypTop = yp - _dypBorder;
|
|
rc.ypBottom = yp;
|
|
pgnv->FillRc(&rc, kacrBlack);
|
|
}
|
|
|
|
if (hqNil != hqExtra)
|
|
{
|
|
UnlockHq(hqExtra);
|
|
FreePhq(&hqExtra);
|
|
}
|
|
|
|
//draw the selection
|
|
if (_fActive)
|
|
_DrawSel(pgnv);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Handle cidAddItem and cidInsertItem.
|
|
***************************************************************************/
|
|
bool DCST::FCmdAddItem(PCMD pcmd)
|
|
{
|
|
AssertThis(0);
|
|
AssertVarMem(pcmd);
|
|
long ivNew;
|
|
bool fT;
|
|
PGSTB pgstb;
|
|
HQ hq;
|
|
long cb;
|
|
STN stn;
|
|
|
|
stn.SetNil();
|
|
pgstb = (PGSTB)_pgrpb;
|
|
fT = fFalse;
|
|
switch (pcmd->cid)
|
|
{
|
|
case cidAddItem:
|
|
fT = pgstb->FAddStn(&stn, pvNil, &ivNew);
|
|
break;
|
|
case cidInsertItem:
|
|
if (_fAllocated)
|
|
break;
|
|
Assert(pgstb->FIs(kclsGST), "bad grpb");
|
|
fT = ((PGST)pgstb)->FInsertStn(ivNew = _ivCur, &stn, pvNil);
|
|
}
|
|
if (!fT)
|
|
return fTrue;
|
|
|
|
if ((cb = pgstb->CbExtra()) > 0 && FAllocHq(&hq, cb, fmemClear, mprNormal))
|
|
{
|
|
pgstb->PutExtra(ivNew, PvLockHq(hq));
|
|
UnlockHq(hq);
|
|
FreePhq(&hq);
|
|
}
|
|
|
|
//turn off the selection and invalidate stuff
|
|
_SetSel(lnNil);
|
|
InvalAllDcgb(_pdocb, pgstb, ivNew, 1,
|
|
(_fAllocated && ivNew == pgstb->IvMac() - 1) ? 1 : 0);
|
|
_SetSel(_LnFromIvDln(ivNew, 0));
|
|
_ShowSel();
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Constructor for DOCI. DOCI holds an item in a GRPB contained in a
|
|
chunky file. Doesn't free the GRPB when the doc goes away.
|
|
***************************************************************************/
|
|
DOCI::DOCI(PDOCB pdocb, PGRPB pgrpb, long cls, long iv, long dln)
|
|
: DOCB(pdocb)
|
|
{
|
|
AssertPo(pgrpb, 0);
|
|
AssertVar(pgrpb->FIs(cls), "wrong cls value", &cls);
|
|
AssertIn(iv, 0, pgrpb->IvMac());
|
|
_pgrpb = pgrpb;
|
|
_cls = cls;
|
|
_iv = iv;
|
|
_dln = dln;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Static member to create a new DOCI.
|
|
***************************************************************************/
|
|
PDOCI DOCI::PdociNew(PDOCB pdocb, PGRPB pgrpb, long cls, long iv, long dln)
|
|
{
|
|
AssertPo(pgrpb, 0);
|
|
AssertPo(pdocb, 0);
|
|
|
|
PDOCI pdoci;
|
|
|
|
if (pvNil == (pdoci = NewObj DOCI(pdocb, pgrpb, cls, iv, dln)))
|
|
return pvNil;
|
|
if (!pdoci->_FInit())
|
|
{
|
|
ReleasePpo(&pdoci);
|
|
return pvNil;
|
|
}
|
|
AssertPo(pdoci, 0);
|
|
return pdoci;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Reads the data (from the GRPB) and initializes the stream.
|
|
***************************************************************************/
|
|
bool DOCI::_FInit(void)
|
|
{
|
|
bool fRet;
|
|
HQ hq;
|
|
long cb;
|
|
|
|
if (hqNil == (hq = _HqRead()))
|
|
return fFalse;
|
|
|
|
if (0 < (cb = CbOfHq(hq)))
|
|
{
|
|
fRet = _bsf.FReplace(PvLockHq(hq), cb, 0, 0);
|
|
UnlockHq(hq);
|
|
}
|
|
else
|
|
fRet = fTrue;
|
|
FreePhq(&hq);
|
|
return fRet;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Create a new DDG for this doc.
|
|
***************************************************************************/
|
|
PDDG DOCI::PddgNew(PGCB pgcb)
|
|
{
|
|
return DCH::PdchNew(this, &_bsf, _fFixed, pgcb);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Get the document's name.
|
|
***************************************************************************/
|
|
void DOCI::GetName(PSTN pstn)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(pstn, 0);
|
|
STN stn;
|
|
|
|
stn.FFormatSz(PszLit(": item %d"), _iv);
|
|
_pdocbPar->GetName(pstn);
|
|
pstn->FAppendStn(&stn);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Handle saving. This is a virtual member of DOCB.
|
|
***************************************************************************/
|
|
bool DOCI::FSave(long cid)
|
|
{
|
|
AssertThis(0);
|
|
long iv;
|
|
|
|
switch (cid)
|
|
{
|
|
case cidSave:
|
|
iv = _iv;
|
|
break;
|
|
|
|
case cidSaveAs:
|
|
case cidSaveCopy:
|
|
RawRtn(); //REVIEW shonk: implement
|
|
return fFalse;
|
|
|
|
default:
|
|
return fFalse;
|
|
}
|
|
|
|
return _FSaveToItem(iv, cid != cidSaveCopy);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Save the data to an item.
|
|
***************************************************************************/
|
|
bool DOCI::_FSaveToItem(long iv, bool fRedirect)
|
|
{
|
|
if (!_FWrite(iv))
|
|
return fFalse;
|
|
|
|
//REVIEW shonk: update window names
|
|
if (fRedirect)
|
|
{
|
|
_iv = iv;
|
|
_fDirty = fFalse;
|
|
}
|
|
|
|
DCGB::InvalAllDcgb(_pdocbPar, _pgrpb, iv, 1, 1);
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Write the data to the GRPB at the given item number.
|
|
***************************************************************************/
|
|
bool DOCI::_FWrite(long iv)
|
|
{
|
|
long cb;
|
|
HQ hq;
|
|
void *pv;
|
|
bool fRet;
|
|
|
|
cb = _bsf.IbMac();
|
|
if (!FAllocHq(&hq, LwMax(1, cb), fmemNil, mprNormal))
|
|
return fFalse;
|
|
_bsf.FetchRgb(0, cb, pv = PvLockHq(hq));
|
|
fRet = fTrue;
|
|
switch (_cls)
|
|
{
|
|
case kclsGL:
|
|
case kclsAL:
|
|
Assert(cb == ((PGLB)_pgrpb)->CbEntry(), "bad cb in GL/AL");
|
|
((PGLB)_pgrpb)->Put(iv, pv);
|
|
break;
|
|
case kclsGG:
|
|
case kclsAG:
|
|
if (_dln == 0)
|
|
fRet = ((PGGB)_pgrpb)->FPut(iv, cb, pv);
|
|
else
|
|
{
|
|
Assert(cb == ((PGGB)_pgrpb)->CbFixed(), "bad cb in GG/AG");
|
|
((PGGB)_pgrpb)->PutFixed(iv, pv);
|
|
}
|
|
break;
|
|
case kclsGST:
|
|
case kclsAST:
|
|
if (_dln == 0)
|
|
{
|
|
cb = LwMin(cb, kcchMaxStz);
|
|
fRet = ((PGSTB)_pgrpb)->FPutRgch(iv, (achar *)pv, cb / size(achar));
|
|
}
|
|
else
|
|
{
|
|
Assert(cb == ((PGSTB)_pgrpb)->CbExtra(), "bad cb in GST/AST");
|
|
((PGSTB)_pgrpb)->PutExtra(iv, pv);
|
|
}
|
|
break;
|
|
default:
|
|
BugVar("bad cls value", &_cls);
|
|
fRet = fFalse;
|
|
break;
|
|
}
|
|
UnlockHq(hq);
|
|
FreePhq(&hq);
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Read the data from the GRPB and return it in an hq. Also set the
|
|
_fFixed flag (which indicates if the data is fixed length).
|
|
***************************************************************************/
|
|
HQ DOCI::_HqRead(void)
|
|
{
|
|
long cb;
|
|
HQ hq;
|
|
void *pv;
|
|
STN stn;
|
|
|
|
_fFixed = fTrue;
|
|
switch (_cls)
|
|
{
|
|
case kclsGL:
|
|
case kclsAL:
|
|
cb = ((PGLB)_pgrpb)->CbEntry();
|
|
break;
|
|
case kclsGG:
|
|
case kclsAG:
|
|
if (_dln == 0)
|
|
{
|
|
cb = ((PGGB)_pgrpb)->Cb(_iv);
|
|
_fFixed = fFalse;
|
|
}
|
|
else
|
|
cb = ((PGGB)_pgrpb)->CbFixed();
|
|
break;
|
|
case kclsGST:
|
|
case kclsAST:
|
|
if (_dln == 0)
|
|
{
|
|
((PGSTB)_pgrpb)->GetStn(_iv, &stn);
|
|
cb = stn.Cch() * size(achar);
|
|
_fFixed = fFalse;
|
|
}
|
|
else
|
|
cb = ((PGSTB)_pgrpb)->CbExtra();
|
|
break;
|
|
default:
|
|
BugVar("bad cls value", &_cls);
|
|
return hqNil;
|
|
}
|
|
|
|
if (!FAllocHq(&hq, cb, fmemNil, mprNormal))
|
|
return hqNil;
|
|
pv = PvLockHq(hq);
|
|
|
|
switch (_cls)
|
|
{
|
|
case kclsGL:
|
|
case kclsAL:
|
|
((PGLB)_pgrpb)->Get(_iv, pv);
|
|
break;
|
|
case kclsGG:
|
|
case kclsAG:
|
|
if (_dln == 0)
|
|
((PGGB)_pgrpb)->Get(_iv, pv);
|
|
else
|
|
((PGGB)_pgrpb)->GetFixed(_iv, pv);
|
|
break;
|
|
case kclsGST:
|
|
case kclsAST:
|
|
if (_dln == 0)
|
|
CopyPb(stn.Prgch(), pv, stn.Cch() * size(achar));
|
|
else
|
|
((PGSTB)_pgrpb)->GetExtra(_iv, pv);
|
|
break;
|
|
}
|
|
UnlockHq(hq);
|
|
return hq;
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
/***************************************************************************
|
|
Assert the validity of a DOCI.
|
|
***************************************************************************/
|
|
void DOCI::AssertValid(ulong grf)
|
|
{
|
|
DOCI_PAR::AssertValid(0);
|
|
AssertPo(_pgrpb, 0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Mark memory for the DOCI.
|
|
***************************************************************************/
|
|
void DOCI::MarkMem(void)
|
|
{
|
|
AssertValid(0);
|
|
DOCI_PAR::MarkMem();
|
|
MarkMemObj(_pgrpb);
|
|
}
|
|
#endif //DEBUG
|
|
|
|
|