//----------------------------------------------------------------------------
// ObjectComponents
// Copyright (c) 1994, 1996 by Borland International, All Rights Reserved
//
/// \file
/// Implementation of TOcPart Class
//----------------------------------------------------------------------------
#include <ocf/pch.h>
#include <ocf/ocstorag.h>
#include <ocf/ocpart.h>
#include <ocf/ocdoc.h>
#include <ocf/ocapp.h>
#include <ocf/ocview.h>
#include <stdio.h>
namespace ocf {
using namespace owl;
const _TCHAR PartFormat[] = _T("OcPart.%d");
const _TCHAR PartStreamName[] = _T("\03OcPart");
//
/// Construct a new part with a given temp id
/// Must call Init method to complete initialization
//
TOcPart::TOcPart(TOcDocument& document, int id)
:
OcDocument(document), BPart(0), BPartI(0), BLPartI(0), Flags(Visible),
Storage(0)
{
AddRef(); // TUnknown defaults to 0, we need 1
if (!id)
id = OcDocument.AllocPartID();
_TCHAR name[32];
_stprintf(name, PartFormat, id);
Name = name;
// There must be a Root IStorage associated with each document
//
if (!OcDocument.GetStorage())
TXObjComp::Throw(TXObjComp::xMissingRootIStorage);
// Create a sub-storage from the parent storage in init
//
Storage = new TOcStorage(*OcDocument.GetStorage(), name, true, STGM_READWRITE);
}
//
/// Old style constructor - does init in constructor -
/// OCF messages will get passed before constructor is complete
//
TOcPart::TOcPart(TOcDocument& document, TOcInitInfo & initInfo,
TRect objPos, int id)
:
OcDocument(document), BPart(0), BPartI(0), BLPartI(0), Flags(Visible),
Storage(0)
{
// Part position and size are in logical units
//
AddRef(); // TUnknown defaults to 0, we need 1
if (!id)
id = OcDocument.AllocPartID();
_TCHAR name[32];
_stprintf(name, PartFormat, id);
Name = name;
// There must be a Root IStorage associated with each document
//
if (!OcDocument.GetStorage())
TXObjComp::Throw(TXObjComp::xMissingRootIStorage);
// Create a sub-storage from the parent storage in init
//
Storage = new TOcStorage(*OcDocument.GetStorage(), name, true, STGM_READWRITE);
Init (&initInfo, objPos);
}
//
/// Construct a part from a named stream in an oc doc's storage
//
TOcPart::TOcPart(TOcDocument& document, LPCTSTR name)
:
OcDocument(document), BPart(0), BPartI(0), BLPartI(0), Flags(Visible),
Storage(0),
Name(name)
{
AddRef(); // TUnknown defaults to 0, we need 1
// There must be an IStorage associated with each document
//
if (!OcDocument.GetStorage())
TXObjComp::Throw(TXObjComp::xMissingRootIStorage);
// Open a sub-storage from the parent storage in init
//
Storage = new TOcStorage(*OcDocument.GetStorage(), name, false, STGM_READWRITE);
// Load our data, and then add ourselves to our document's part collection if
// everthing succeeds. We'll initialize our helper objects when the parts
// become visible.
//
Load();
OcDocument.GetParts().Add(this);
}
//
//
//
TOcPart::~TOcPart()
{
// Detach this part from its document
//
Detach();
// double check if active part is "this" and, in case, delete it
if (OcDocument.GetActiveView()->GetActivePart() == this)
OcDocument.GetActiveView()->SetActivePart(NULL);
// Delete any associated storage
//
delete Storage;
}
//
/// Perform common ctor initialization
//
bool
TOcPart::Init(TOcInitInfo * initInfo, TRect objPos)
{
if (BPart)
return false; // already initialized
// Part position and size are in logical units
//
TOcSiteRect siteRect(this, objPos);
TOcView* view = OcDocument.GetActiveView();
if (view) {
view->ContainerHost->EvOcViewSetSiteRect(siteRect);
Pos = siteRect.Rect.TopLeft();
Size = siteRect.Rect.Size();
}
if (InitObj(initInfo)) {
OcDocument.GetParts().Add(this);
return true;
}
return false;
}
//
//
//
bool
TOcPart::InitObj(TOcInitInfo * initInfo)
{
// Initialize our helpers & then add ourselves to our document's part
// collection if everything succeeds
//
if (initInfo) {
// There must be an IStorage associated with each part, make sure the ctor
// got it OK
//
initInfo->Storage = Storage->GetIStorage();
// Create part helper
//
TXObjComp::Check(
OcDocument.GetOcApp().BOleComponentCreate(&BPart, GetOuter(), cidBOlePart),
TXObjComp::xInternalPartError);
// Get the interfaces we need & then release the object itself
//
if (HRSucceeded(BPart->QueryInterface(IID_IBPart, (LPVOID *)&BPartI)))
BPartI->Release();
if (HRSucceeded(BPart->QueryInterface(IID_IBLinkable, (LPVOID *)&BLPartI)))
BLPartI->Release();
HRESULT hr;
if (!BPartI || !HRSucceeded(hr = BPartI->Init(this, initInfo))) {
BPart->Release();
BPart = 0;
TXObjComp::Throw(TXObjComp::xPartInitError, hr);
}
Rename();
if (initInfo->How == ihLink) // Remember that we are a link
Flags |= Link;
// New parts become active when they are init'd above. Make sure that our
// view knows that we are active too.
//
if (initInfo->Where == iwNew) {
Flags |= Active;
TOcView* activeView = OcDocument.GetActiveView();
CHECK(activeView);
activeView->ActivatePart(this);
}
}
return true;
}
//
/// Delete this object. Actually, causes object to shutdown as much as possible
/// & then releases a reference.
//
void
TOcPart::Delete()
{
Activate(false);
Close();
Release();
}
//
/// Callback from TUnknown's implementation of QueryInterface
//
HRESULT
TOcPart::QueryObject(const IID & iid, void * * iface)
{
PRECONDITION(iface);
HRESULT hr;
// interfaces
//
HRSucceeded(hr = IBSite_QueryInterface(this, iid, iface))
// helpers
//
|| (BPart && HRSucceeded(hr = BPart->QueryInterface(iid, iface)))
;
return hr;
}
//
/// Query server for its interfaces
//
HRESULT
TOcPart::QueryServer(const IID & iid, void * * iface)
{
PRECONDITION(iface);
return BPartI->DoQueryInterface(iid, iface);
}
//
/// Disconnect servers by closing & releasing our BOle helper
//
bool
TOcPart::Close()
{
if (!BPartI)
return true;
if (BLPartI)
BLPartI->OnRename(0, 0);
if (HRSucceeded(BPartI->Close())) {
// release our BOle helper object
//
BPart->Release();
BPart = 0;
BPartI = 0;
BLPartI = 0;
// So that it won't get created again in Draw
//
Flags |= Closing;
return true;
}
return false;
}
//
/// Rename the embed site for linking
//
void
TOcPart::Rename()
{
TOcView* activeView = OcDocument.GetActiveView();
CHECK(activeView);
IBRootLinkable* bLDocumentI;
activeView->QueryInterface(IID_IBRootLinkable, (LPVOID *)&bLDocumentI);
activeView->Release();
if (BLPartI && bLDocumentI)
BLPartI->OnRename(bLDocumentI, GetName());
}
//----------------------------------------------------------------------------
// ISite Implementation--delegates site/view related queries/notifies to the
// active view of this part
//
//
/// Show/hide a site.
//
HRESULT _IFUNC
TOcPart::SiteShow(BOOL show)
{
Invalidate(invView);
// When this part is activated, the site is hidden. This is a good time to
// make sure our state is in sync.
//
if (!show) {
// Make sure the view knows about the active part
//
Flags |= Active;
TOcView* view = OcDocument.GetActiveView();
if (view) {
view->ActivatePart(this);
view->ContainerHost->EvOcViewPartActivate(*this);
}
}
return HR_NOERROR;
}
//
/// Discard undo stack for our associated [the active] view
//
HRESULT _IFUNC
TOcPart::DiscardUndo()
{
return HR_NOERROR;
}
//
/// Retrieve the site rect [relative to the active view?], and optionally the
/// view's rect too?
//
HRESULT _IFUNC
TOcPart::GetSiteRect(TRect * posRect, TRect * clipRect)
{
PRECONDITION(posRect);
if (!posRect)
return HR_INVALIDARG;
TOcView* view = OcDocument.GetActiveView();
if (!view)
return HR_FAIL;
if (posRect) {
TOcSiteRect siteRect(this, TRect(Pos, Size));
view->ContainerHost->EvOcViewGetSiteRect(siteRect);
*posRect = siteRect.Rect;
// If we don't know our site size yet, then fail this call. Let the server
// pick a size.
//
if (posRect->right-posRect->left <= 0 || posRect->bottom-posRect->top <= 0) {
posRect->right = posRect->left;
posRect->bottom = posRect->top;
return HR_FAIL;
}
}
if (clipRect)
view->GetWindowRect(clipRect);
return HR_NOERROR;
}
//
/// Set the site's rect from an in-place active part. Since user is in control
/// we generally respect both Pos & Size changes.
//
HRESULT _IFUNC
TOcPart::SetSiteRect(const TRect * newRect)
{
PRECONDITION(newRect);
if (!newRect)
return HR_INVALIDARG;
TOcView* view = OcDocument.GetActiveView();
if (!view)
return HR_FAIL;
// Give other views a chance to update
//
Invalidate(invView); // erase old image
TOcSiteRect siteRect(this, *newRect);
view->ContainerHost->EvOcViewSetSiteRect(siteRect);
Size = siteRect.Rect.Size();
Pos = siteRect.Rect.TopLeft();
// Give other views a chance to update
//
Invalidate(invView); // refresh new image position
return HR_NOERROR;
}
//
/// Set the part's site extent. This comes either after a SetPartRect, or for
/// open editing, comes alone.
//
HRESULT _IFUNC
TOcPart::SetSiteExtent(const TSize * newSize)
{
PRECONDITION(newSize);
if (!newSize)
return HR_INVALIDARG;
TOcView* view = OcDocument.GetActiveView();
if (!view)
return HR_FAIL;
// Only accept server's size if we don't have a size yet. Always say OK.
//
// if (Size.cx > 0 && Size.cy > 0)
// return HR_NOERROR;
// Give other views a chance to update
//
Invalidate(invView); // display new image
TSize ext(*newSize);
TOcSiteRect siteRect(this, TRect(Pos, ext));
if (view->ContainerHost->EvOcViewSetSiteRect(siteRect))
Size = siteRect.Rect.Size();
else
//\\// container doesn't accept server size (keep what we have)
return HR_FAIL;
// Give other views a chance to update
//
Invalidate(invView); // refresh new image position
return HR_NOERROR;
}
//
/// Get parent window for part
//
HRESULT _IFUNC
TOcPart::GetParentWindow(HWND *hWnd)
{
TOcView* activeView = OcDocument.GetActiveView();
*hWnd = activeView->GetWindow();
return 0;
}
//
/// Get zoom factor for part
//
HRESULT _IFUNC
TOcPart::GetZoom(TOcScaleInfo* zoom)
{
PRECONDITION(zoom);
if (!zoom)
return HR_INVALIDARG;
TOcView* view = OcDocument.GetActiveView();
if (!view)
return HR_FAIL;
TOcScaleFactor scaleFactor(*zoom);
if (!view->ContainerHost->EvOcViewGetScale(scaleFactor)) {
zoom->xD = zoom->xN = zoom->yD = zoom->yN = 1;
}
else
scaleFactor.GetScaleFactor(*zoom);
return HR_NOERROR;
}
//
/// Invalidate the site within the active view
//
void _IFUNC
TOcPart::Invalidate(TOcInvalidate type)
{
TOcView* view = OcDocument.GetActiveView();
TOcPartChangeInfo changeInfo(this, type);
if (view)
view->InvalidatePart(changeInfo);
}
void _IFUNC
TOcPart::OnSetFocus(BOOL set)
{
TOcView* view = OcDocument.GetActiveView();
if (view && set)
::SetFocus(view->GetWindow());
}
HRESULT _IFUNC
TOcPart::Init(IBDataProvider *, IBPart *, LPCOLESTR, BOOL)
{
return HR_FAIL; // never called
}
void _IFUNC
TOcPart::Disconnect()
{
// no need to do anything
}
//----------------------------------------------------------------------------
//
/// Save this part to storage. May be any of:
/// - Save to our storage : sameAsLoad==1
/// - Copy to a storage : sameAsLoad==0, remember==0
/// - SaveAs a new storage: sameAsLoad==0, remember==1
//
bool
TOcPart::Save(bool sameAsLoad, bool remember)
{
STATSTG statstg;
if (!HRSucceeded(Storage->Stat(&statstg, STATFLAG_NONAME)))
return false;
TOcStorage* oldStorage = 0;
// If not sameAsLoad, then we are saving to a new storage. Switch to that,
// at least for this save.
//
if (!sameAsLoad) {
oldStorage = Storage;
Storage = new TOcStorage(*OcDocument.GetStorage(), GetName(), true, STGM_READWRITE);
}
// Create/open a stream in our storage to save part information
//
TOcStream stream(*Storage, PartStreamName, true, statstg.grfMode);
// Write TOcPart data into stream, Name was written by our Doc
//
if (!HRSucceeded(stream.Write(&Pos, sizeof Pos)))
return false;
if (!HRSucceeded(stream.Write(&Size, sizeof Size)))
return false;
if (!HRSucceeded(stream.Write(&Flags, sizeof Flags)))
return false;
// Now have actual server part write itself to this storage
//
bool result = Save(Storage->GetIStorage(), sameAsLoad, remember);
// If this is a different storage, then either save it (remember) or put
// it back & clean up.
//
if (!sameAsLoad) {
if (remember) {
delete oldStorage;
}
else {
delete Storage;
Storage = oldStorage;
}
}
return result;
}
//
/// Load this part from its ocpart stream in its current storage
//
bool
TOcPart::Load()
{
// Open a stream with oc part information
//
STATSTG statstg;
if (!HRSucceeded(Storage->Stat(&statstg, STATFLAG_NONAME)))
return false;
TOcStream stream(*Storage, PartStreamName, false, statstg.grfMode);
// Read TOcPart data from stream. Server part info will be read in as needed
// after Init()
//
if (!HRSucceeded(stream.Read(&Pos, sizeof Pos)))
return false;
if (!HRSucceeded(stream.Read(&Size, sizeof Size)))
return false;
if (!HRSucceeded(stream.Read(&Flags, sizeof Flags)))
return false;
Flags &= ~(Closing | Active); // These Flags are not persistent
return true;
}
//
/// Update this part's idea of its size via the server, & then return that.
/// Use GetRect() to just get the current site rect.
//
TSize
TOcPart::GetSize() const
{
BPartI->GetPartSize(&const_cast<TSize&>(Size));
return Size;
}
//
/// Set part to the new position given in logical units
/// \note Does you update the part's location.
/// Must explicitly call UpdateRect!
//
void
TOcPart::SetPos(const TPoint& pos)
{
Pos = pos;
}
//
/// Set part to the new size given in logical units
/// \note Does you update the part's location.
/// Must explicitly call UpdateRect!
//
void
TOcPart::SetSize(const TSize& size)
{
Size = size;
}
//
/// Set part to the new rect given in logical units
//
void
TOcPart::UpdateRect()
{
// Use device units for Bolero
//
TOcView* view = OcDocument.GetActiveView();
if (!view)
return;
TOcSiteRect siteRect(this, TRect(Pos, Size));
view->ContainerHost->EvOcViewGetSiteRect(siteRect);
BPartI->SetPartPos(&siteRect.Rect);
}
//----------------------------------------------------------------------------
// IBPart pass-thrus not inlined
//
bool
TOcPart::Activate(bool activate)
{
TOcView* activeView = OcDocument.GetActiveView();
CHECK(activeView);
if (activate && activeView->GetActivePart())
if (!activeView->ActivatePart(0)) // deactivate currently active part, if any
return false;
// Makes sure that the part gets the active view as its host.
// This is important in multi-view situation.
//
SetHost(activeView);
if (!HRSucceeded(BPartI->Activate(activate)))
return false;
if (activate) {
Flags |= Active;
activeView->SetActivePart(this);
}
else {
Flags &= ~Active;
activeView->SetActivePart(0);
}
return true;
}
void
TOcPart::FinishLoading()
{
// Load embeded object on demand
//
if (!BPartI) {
TOcInitInfo initInfo(ihEmbed, iwStorage, OcDocument.GetActiveView());
InitObj(&initInfo);
}
}
//
/// Set data into the server object
//
bool
TOcPart::SetFormatData(TOcFormatInfo * fmt, HANDLE data, bool release)
{
IBPart2* bPartI2;
if (HRSucceeded(BPart->QueryInterface(IID_IBPart2, (LPVOID *)&bPartI2)))
((IBPart*)bPartI2)->Release();
else
return false;
return HRSucceeded(bPartI2->SetFormatData(fmt, data, release));
}
bool
TOcPart::Save(IStorage* storage, bool sameAsLoad, bool remember)
{
PRECONDITION(storage);
if (BPartI)
return HRSucceeded(BPartI->Save(storage, sameAsLoad, remember));
return false;
}
bool
TOcPart::Draw(HDC dc, const TRect& pos, const TRect& clip, TOcAspect aspect)
{
PRECONDITION(dc);
// Don't draw anything if we are closing down the part
//
if (Flags & Closing)
return true;
const RECTL posl = { pos.left, pos.top, pos.right, pos.bottom };
const RECTL clipl = { clip.left, clip.top, clip.right, clip.bottom };
// Load embeded object on demand
//
if (!BPartI) {
TOcInitInfo initInfo(ihEmbed, iwStorage, OcDocument.GetActiveView());
InitObj(&initInfo);
// Update the link
//
if (IsLink()) {
TOcView* view = OcDocument.GetActiveView();
if (view)
view->UpdateLinks();
}
}
return HRSucceeded(BPartI->Draw(dc, &posl, &clipl, aspect, drNone));
}
bool
TOcPart::EnumVerbs(const TOcVerb& verb)
{
if (BPartI)
return HRIsOK(BPartI->EnumVerbs(const_cast<TOcVerb*>(&verb)));
return false;
}
bool
TOcPart::DoVerb(uint whichVerb)
{
if (BPartI) {
if (HRSucceeded(BPartI->DoVerb(whichVerb))) {
TOcView* activeView = OcDocument.GetActiveView();
CHECK(activeView);
activeView->SetActivePart(this); // we may be activated now...
return true;
}
}
return false;
}
int
TOcPart::Detach()
{
return OcDocument.GetParts().Detach(this);
}
void
TOcPart::SetVisible(bool visible)
{
if (visible)
Flags |= Visible;
else
Flags &= ~Visible;
if (IsActive())
BPartI->Show(visible);
else
Invalidate(invView); // refresh new image position
}
//
/// Set the storage for this part
//
void
TOcPart::SetStorage(IStorage* storage, bool remember)
{
if (Storage && (storage == Storage->GetIStorage()))
return;
if (remember)
delete Storage;
if (storage)
Storage = new TOcStorage(storage);
else
Storage = 0;
}
//----------------------------------------------------------------------------
// CdPartCollection
//
TOcPartCollection::TOcPartCollection()
{
}
TOcPartCollection::~TOcPartCollection()
{
Clear();
}
//
/// Release parts in the collection
//
void
TOcPartCollection::Clear()
{
for (int i = Count() - 1; i >= 0; i--) {
TOcPart* part = (TOcPart*)(*this)[i];
part->Release();
}
}
//
/// walk thru Part collection & return the last one that logical point hits,
/// (first one in Z order)
//
TOcPart*
TOcPartCollection::Locate(TPoint& logicalPoint)
{
TRect hitRect(logicalPoint, TSize(1,1));
TOcPart* p = 0;
for (TOcPartCollectionIter i(*this); i; i++)
if (i.Current()->IsVisible(hitRect))
p = (TOcPart*)i.Current();
return p;
}
//
/// Select/unselect all parts
//
bool
TOcPartCollection::SelectAll(bool select)
{
for (TOcPartCollectionIter i(*this); i; i++)
i.Current()->Select(select);
return true;
}
int
TOcPartCollection::Detach(TOcPart* const& part, int del)
{
int ret = Base::Detach(Find(part));
if (ret && del)
const_cast<TOcPart*>(part)->Release();
return ret;
}
//--------------------------------- OcVerb -----------------------------------
//
TOcVerb::TOcVerb()
:
TypeName(0),
VerbName(0),
VerbIndex(0),
CanDirty(false)
{
}
} // OCF namespace
//==============================================================================
↑ V595 The 'BPartI' pointer was utilized before it was verified against nullptr. Check lines: 178, 183.
↑ V1004 The 'activeView' pointer was used unsafely after it was verified against nullptr. Check lines: 199, 200.
↑ V1004 The 'activeView' pointer was used unsafely after it was verified against nullptr. Check lines: 283, 286.
↑ V1004 The 'activeView' pointer was used unsafely after it was verified against nullptr. Check lines: 648, 650.
↑ V1004 The 'activeView' pointer was used unsafely after it was verified against nullptr. Check lines: 755, 756.
↑ V547 Expression 'posRect' is always true.
↑ V614 Potentially uninitialized variable 'hr' used. Consider checking the second actual argument of the 'Throw' function.
↑ V832 It's better to use '= default;' syntax instead of empty constructor body.
↑ V803 Decreased performance. In case 'i' is iterator it's more effective to use prefix form of increment. Replace iterator++ with ++iterator.
↑ V803 Decreased performance. In case 'i' is iterator it's more effective to use prefix form of increment. Replace iterator++ with ++iterator.
↑ V813 Decreased performance. The 'objPos' argument should probably be rendered as a constant reference.
↑ V821 Decreased performance. The 'siteRect' variable can be constructed in a lower level scope.
↑ V821 Decreased performance. The 'changeInfo' variable can be constructed in a lower level scope.