//----------------------------------------------------------------------------
// ObjectComponents
// Copyright (c) 1994, 1996 by Borland International, All Rights Reserved
//
/// \file
/// Implementation of TOleView. Doc/View view derived from TOleWindow that
/// supports OLE 2 using OCF TOcView & TOcRemView
//----------------------------------------------------------------------------
#include <ocf/pch.h>
 
#include <owl/window.h>
#include <owl/gdiobjec.h>
#include <owl/scroller.h>
#include <owl/docmanag.h>
#include <owl/docview.rh>
#include <ocf/oleview.rh>
#include <ocf/oleframe.h>
#include <ocf/oleview.h>
#include <ocf/oledoc.h>
 
namespace ocf {
 
using namespace owl;
 
OWL_DIAGINFO;
 
//----------------------------------------------------------------------------
// TOleView
//
 
DEFINE_RESPONSE_TABLE1(TOleView, TOleWindow)
  EV_VN_ISWINDOW,
 
  // Container specific messages
  //
  EV_VN_INVALIDATE,
  EV_VN_DOCOPENED,
  EV_VN_DOCCLOSED,
  EV_OC_VIEWPARTINVALID,
 
  // Server specific messages
  //
  EV_OC_VIEWSAVEPART,
  EV_OC_VIEWLOADPART,
  EV_OC_VIEWINSMENUS,
  EV_OC_VIEWCLOSE,
  EV_OC_VIEWOPENDOC,
  EV_OC_VIEWATTACHWINDOW,
  EV_OC_VIEWSETLINK,
  EV_OC_VIEWBREAKLINK,
  EV_OC_VIEWGETITEMNAME,
END_RESPONSE_TABLE;
 
//
/// Constructs a TOleView object associated with the given document object (doc) and
/// parent window (parent).
//
TOleView::TOleView(TDocument& doc, TWindow* parent)
:
  TView(doc),
  TOleWindow(parent, doc.GetDocManager().GetApplication())
{
  Destroying = false;
  TOleDocument* oleDoc = TYPESAFE_DOWNCAST(&GetDocument(), TOleDocument);
  CHECK(oleDoc);
  OcDoc = oleDoc->GetOcDoc(); // Let OleWindow member point to it for accessor
}
 
//
/// Destroys the TOleView object and detaches the view from the associated document.
//
TOleView::~TOleView()
{
  Destroying = true;
  if (IsRemote())
    Destroy();  // Make sure that derived TWindow shutdown virtuals get called
  OcDoc = 0;    // We don't own it, don't let TOleWindow delete it
}
 
//
/// Override TOleWindow's version to pass info to TOleDocument & provide a
/// second chance to find the RegLink.
///
/// Creates an ObjectComponents view associated with the embedded object. Associates
/// the view with the document template specified in tpl. The isEmbedded parameter
/// is true if the view is an embedded object. The outer parameter refers to the
/// IUnknown interface with which the view will aggregate itself.
//
TOcView*
TOleView::CreateOcView(TRegLink* link, bool isRemote, IUnknown* outer)
{
  // Assume an embedded document until we find out later if we are a link
  // or a load-from-file
  //
  if (isRemote)
    GetDocument().SetEmbedded(true);
 
  return TOleWindow::CreateOcView(link ? link : GetDocument().GetTemplate(),
                                  isRemote, outer);
}
 
//
/// Overrides TView's GetViewMenu to make an on-the-fly decision about which menu to
/// use: normal, or embedded.
//
TMenuDescr*
TOleView::GetViewMenu()
{
  if (TView::GetViewMenu())
    return TView::GetViewMenu();
 
// !CQ && not a link!
  if (IsRemote() && GetModule()->FindResource(IDM_OLEVIEWEMBED, RT_MENU))
    SetViewMenu(new TMenuDescr(IDM_OLEVIEWEMBED, GetModule()));
  else
    SetViewMenu(new TMenuDescr(IDM_OLEVIEW, GetModule()));
 
  return TView::GetViewMenu();
}
 
//
/// Does a given THandle belong to this view? Yes if it is us, or a child of us
//
bool
TOleView::VnIsWindow(THandle hWnd)
{
  return hWnd == GetHandle() || IsChild(hWnd);
}
 
//
/// A view uses this function to verify whether or not it can shut down. If this is
/// a server's view window, CanClose checks to see if any open-editing is occurring
/// on any of the embedded objects in the frame window.  If so, CanClose closes this
/// open-editing session by disconnecting the embedded object from its server. Then,
/// it hides the server's frame window and returns true when appropriate.  If this
/// is a container, CanClose queries all documents and views and returns true when
/// all documents and views can be closed.
///
/// \note Unlike in-place editing, which takes place in the container's window,
/// open-editing occurs in the server's frame window.
//
bool
TOleView::CanClose()
{
  // We don't want to close the view for DLL servers
  //
  if (IsOpenEditing() && !OcApp->IsOptionSet(amExeMode)) {
    TOleFrame* olefr = TYPESAFE_DOWNCAST(GetApplication()->GetMainWindow(), TOleFrame);
    CHECK(olefr);
    olefr->ShowWindow(SW_HIDE);
    TOleWindow::OleShutDown();
    return false;
  }
 
  // Say yes if there are more than one TOleView's attached to the document
  //
  if (OtherViewExists() || GetOcRemView())
    return true;
 
  if (Doc->CanClose()) {
    if (OcDoc)
      OcDoc->Close();
    return true;
  }
  return false;
}
 
//
/// Checks whether another TOleView already exists.
//
bool
TOleView::OtherViewExists()
{
  TView* curView = GetDocument().GetViewList();
  while (curView) {
    TOleLinkView* oleLinkView = TYPESAFE_DOWNCAST(curView, TOleLinkView);
    if (!oleLinkView && curView != this)
      return true;
 
    curView = curView->GetNextView();
  }
 
  return false;
}
 
//
/// Performs a normal CleanupWindow.  Also lets the OcView object know we have closed.
//
void
TOleView::CleanupWindow()
{
  if (!OtherViewExists()) {
 
    TOleWindow::CleanupWindow();
 
    // Delete the TOleView now rather wait until ~TOleFrame if its parent
    // is TRemViewBucket
    //
    TOleFrame* mainWindow = TYPESAFE_DOWNCAST(GetApplication()->GetMainWindow(),
                                            TOleFrame);
    if (mainWindow && mainWindow->GetRemViewBucket() == Parent && !Destroying)
      GetApplication()->Condemn(this);
  }
}
 
//
/// Shuts down the associated OCF partners if possible.
//
bool
TOleView::OleShutDown()
{
  // if dll server open edit return
  if (OcApp->IsOptionSet(amExeMode) || !IsOpenEditing())
    TOleWindow::OleShutDown();
  else {
    TOleWindow::OleShutDown();
    if (OcDoc && !OtherViewExists())
      OcDoc->Close();
  }
  return true;
}
 
 
//
/// Invalidates the view region specified by p. Use this function to invalidate the
/// bounding rectangle surrounding an embedded object if the object has been
/// changed, usually as a result of in-place editing. If successful, returns true.
//
bool
TOleView::VnInvalidate(TRect& rect)
{
  InvalidateRect(rect, true);
 
  return true;
}
 
//
/// Ensures that TOleView's data members, such as DragPart, Pos, and Scale, are
/// initialized properly after a revert operation, which cancels any changes made to
/// the document since the last time the document was saved to storage.
//
bool
TOleView::VnDocOpened(int /*omode*/)
{
  DragPart = 0;
  Pos.SetNull();
  Scale.Reset();
  return true;
}
 
//
/// Sets the OcDoc data member to 0.
//
bool
TOleView::VnDocClosed(int /*omode*/)
{
  OcDoc = 0;
  return true;
}
 
//
/// Asks the server to close the view associated with this document. Tests to see if
/// the document has been changed since it was last saved. Returns true if the
/// document and its associated view are closed.
//
bool
TOleView::EvOcViewClose()
{
  TOcRemView* ocRemView = GetOcRemView();
 
  // When TOcRemView gets shut down in the Embed From File case,
  // we need to cleanup the document and view right away. Otherwise,
  // the document and view will be shut down as part of the frame shut down
  // process.
  //
  if (ocRemView && ocRemView->GetKind() == TOcRemView::LoadFromFile) {
    OcView = 0;   // OcView is going away, so don't mess with it
    OcDoc = 0;    // OleDoc will delete OcDoc, so don't mess with it
    delete &GetDocument();
  }
  else {
    TOleWindow::EvOcViewClose();
  }
 
  return true;
}
 
//
/// Asks the server to save the embedded object's data to storage. To save the
/// object, EvOcViewSavePart calls upon the TOleDocument object, which creates
/// storage as necessary for each embedded object. Saves the dimensions of the
/// server's view, which the server uses to tell the container how to redraw the
/// embedded object in the container's window.
//
bool
TOleView::EvOcViewSavePart(TOcSaveLoad & ocSave)
{
  PRECONDITION(ocSave.StorageI);
 
  TOleDocument* doc = TYPESAFE_DOWNCAST(&GetDocument(), TOleDocument);
  if (!doc)
    return false;
 
  doc->SetStorage(ocSave.StorageI, (ocSave.SameAsLoad || ocSave.Remember));
 
  bool status;
  if (ocSave.SaveSelection) {
    status = doc->CommitSelection(*this, ocSave.UserData);
  }
  else {
    // Save view remote view info such as origin and extent
    //
    TOcRemView* ocRemView = GetOcRemView();
    if (ocRemView)
      ocRemView->Save(ocSave.StorageI);
 
    status = doc->Commit(true);
  }
 
  // Restore the original storage
  //
  if (!ocSave.SameAsLoad && !ocSave.Remember)
    doc->RestoreStorage();
 
  return status;
}
 
//
/// Asks the server to load itself from storage. Loads the document and its
/// associated view.
//
bool
TOleView::EvOcViewLoadPart(TOcSaveLoad & ocLoad)
{
  PRECONDITION(ocLoad.StorageI);
 
  TOleDocument* doc = TYPESAFE_DOWNCAST(&GetDocument(), TOleDocument);
  doc->SetStorage(ocLoad.StorageI);
 
  // Load view remote view info such as origin and extent
  //
  CHECK(GetOcRemView());
  GetOcRemView()->Load(ocLoad.StorageI);
 
  bool status = GetDocument().Open(doc->GetOpenMode());
 
  if (!ocLoad.Remember)
    doc->SetStorage(0);
 
  return status;
}
 
//
/// Asks the container application to open an existing document so the document can
/// receive embedded and linked objects. (Actually, TOleView calls on the
/// TOleDocument object to read the document from storage, using the standard OLE
/// IStorage and IStream interfaces). Assigns a unique string identifier to the
/// document and returns true if successful.
//
bool
TOleView::EvOcViewOpenDoc(LPCTSTR path)
{
  TOleDocument* oleDoc = TYPESAFE_DOWNCAST(&GetDocument(), TOleDocument);
  CHECK(oleDoc && GetOcDoc());
 
  oleDoc->SetEmbedded(false); // must really be a link or load-from-file
  oleDoc->SetStorage(0);      // release the current storage
  oleDoc->SetDocPath(path);
  oleDoc->InitDoc();
  oleDoc->Open(ofRead, path);
 
  owl::tstring newName(oleDoc->GetDocPath());
  GetOcDoc()->SetName(newName);
  Invalidate();
  return true;
}
 
//
/// Inserts the server's menu into the composite menu. Determines the number of
/// groups and the number of pop-up menu items to insert within each group. The
/// shared menu (sharedMenu) is the container's menu merged with the server's menu
/// groups.
//
bool
TOleView::EvOcViewInsMenus(TOcMenuDescr & sharedMenu)
{
  // Recreate a temporary composite menu for frame and child
  //
  TMenuDescr compMenuDesc; // empty menudescr
  if (GetViewMenu()) {
    compMenuDesc.Merge(*GetViewMenu());
    compMenuDesc.Merge(TMenuDescr(0,  -1, 0, -1, 0, -1, 0));
  }
 
  TMenuDescr shMenuDescr(sharedMenu.HMenu,
                         sharedMenu.Width[0],
                         sharedMenu.Width[1],
                         sharedMenu.Width[2],
                         sharedMenu.Width[3],
                         sharedMenu.Width[4],
                         sharedMenu.Width[5]);
  shMenuDescr.Merge(compMenuDesc);
 
  for (int i = 0; i < 6; i++)
    sharedMenu.Width[i] = shMenuDescr.GetGroupCount(i);
 
  return true;
}
 
//
/// Notifies the active view of any changes made to the embedded object's data
/// (changeInfo).  Also, notifies any other views associated with this document that
/// the bounding rectangle for the document is invalid and needs to be repainted.
/// EvOcViewPartInvalid always returns true.
//
bool
TOleView::EvOcViewPartInvalid(TOcPartChangeInfo& changeInfo)
{
  if (changeInfo.IsDataChange())
    GetDocument().SetDirty(true);
 
  // Reflect the change in part in other (non-active) views
  //
  TRect rect(changeInfo.GetPart()->GetRect());
  rect.right++;
  rect.bottom++;
  TOleClientDC dc(*this);
  dc.LPtoDP((TPoint*)&rect, 2);
 
  GetDocument().NotifyViews(vnInvalidate, reinterpret_cast<TParam2>(&rect));
 
  // Notify container if this is an intermediate container
  //
  InvalidatePart((TOcInvalidate)changeInfo.GetType());
 
  return true;  // stop further processing by OCF
}
 
//
/// Attaches this view to its ObjectWindows parent window so the embedded object can
/// be either opened and edited or deactivated. To attach a view to an embedded
/// object, set the attach parameter to true. To detach the embedded object, set the
/// attach parameter to false.
//
bool
TOleView::EvOcViewAttachWindow(bool attach)
{
  TOleFrame* mainWindow = TYPESAFE_DOWNCAST(GetApplication()->GetMainWindow(),
                                            TOleFrame);
  if (!mainWindow)
    return false;  // server app is shutting down
 
  // There won't be any TOcRemView if we're reestablishing the link
  //
  if (attach) {
    if (IsOpenEditing()) {
      // Get the normal app notify handler to set up the parent for us
      // knowing that we are now open editing
      //
      if (mainWindow->GetRemViewBucket() == Parent) {
        GetDocument().GetDocManager().PostEvent(dnCreate, *this);
      }
    }
  }
  else {
    if (IsOpenEditing() && Parent != mainWindow)
      Parent->PostMessage(WM_CLOSE);
    SetParent(mainWindow->GetRemViewBucket());  // simple reparent
  }
  return true;
}
 
//
/// Finds the item name for whole document or for the selection.
//
bool
TOleView::EvOcViewGetItemName(TOcItemName& item)
{
  if (item.Selection) {
    if (DragPart) {
      item.Name = DragPart->GetName();
      return true;
    }
  }
  else {
    item.Name = _T("Content"); // item name representing the whole document
    return true;
  }
  return false;
}
 
//----------------------------------------------------------------------------
// Linking Spport
//
 
//
/// Responds to an OC_VIEWSETLINK message TOcLinkView sends when the server document
/// provides a link to a container document. EvOcViewSetLink establishes the link
/// between a TOleLinkView and a TOcLinkView. The view parameter references the view
/// with which the document or selection is associated. Returns false if
/// unsuccessful.
/// Non-Doc/View applications use TOleWIndow's implementation of the function.
//
bool
TOleView::EvOcViewSetLink(TOcLinkView& /*view*/)
{
  return false;
}
 
//
/// Responds to an OC_VIEWBREAKLINK message that TOcLinkView sends when the server
/// document that provides the link shuts down. EvOcViewBreakLink breaks the link
/// with a server document or a selection by deleting the TOleLinkView associated
/// with the TOcLinkView (view). After the link is broken, the container application
/// is left holding a static representation (that is, a metafile) of the linked
/// document. Returns false if unsuccessful.
/// Non-Doc/View applications use TOleWindow's implementation of this function.
//
bool
TOleView::EvOcViewBreakLink(TOcLinkView& view)
{
  // Find the link view with the moniker
  //
  TView* target = GetDocument().QueryViews(vnLinkView, reinterpret_cast<TParam2>(&view), this);
 
  // Delete a linked view to this document
  //
  delete target;
  return true;
}
 
IMPLEMENT_STREAMABLE2(TOleView, TOleWindow, TView);
 
#if OWL_PERSISTENT_STREAMS
 
//
//
//
void*
TOleView::Streamer::Read(ipstream& is, uint32 /*version*/) const
{
  owl::ReadBaseObject((TOleWindow*)GetObject(), is);
  owl::ReadBaseObject((TView*)GetObject(), is);
 
  GetObject()->Destroying = false;
  TOleDocument* oleDoc = TYPESAFE_DOWNCAST(&GetObject()->GetDocument(), TOleDocument);
  CHECK(oleDoc);
  GetObject()->OcDoc = oleDoc->GetOcDoc(); // Let OleWindow member point to it for accessor
  CHECK(oleDoc);
 
  return GetObject();
}
 
//
//
//
void
TOleView::Streamer::Write(opstream& os) const
{
  owl::WriteBaseObject((TOleWindow*)GetObject(), os);
  owl::WriteBaseObject((TView*)GetObject(), os);
}
 
#endif
 
//----------------------------------------------------------------------------
// TOleLinkView
//
 
DEFINE_RESPONSE_TABLE(TOleLinkView)
  EV_VN_LINKVIEW,
  EV_VN_LINKMONIKER,
END_RESPONSE_TABLE;
 
//
/// Constructs a TOleLinkView object associated with the given document object (doc)
/// and view (view).
//
TOleLinkView::TOleLinkView(TDocument& doc, TOcLinkView& view)
:
  TView(doc),
  OcLinkView(view)
{
  view.AddRef();
}
 
//
/// Destroys the TOleLinkView object and detaches the view from the associated
/// document.
//
TOleLinkView::~TOleLinkView()
{
  OcLinkView.Release();
}
 
//
/// Returns true if a TOleLinkView object is associated with the server's
/// TOcRemView, the server's remote link view object. A TOcRemView is the object
/// created by a linking and embedding server so that the server can draw its OLE
/// object in a metafile used by the container. In contrast to VnLinkMoniker, this
/// function searches for the TOleLinkView object using a reference to the view.
//
bool
TOleLinkView::VnLinkView(TOcLinkView& view)
{
  if (&OcLinkView == &view)
    return true;
 
  return false;
}
 
//
/// Returns true if a TOleLinkView object is associated with the given server's
/// TOcRemView. In contrast to VnLinkView, this function searches for the view using
/// the specified server's moniker.
/// When the document receives a request for the TOleLinkView associated with a
/// particular moniker, the document sends a vnLinkView notification message to all
/// its attached views. The handler for vnLinkMoniker in TOleLinkView simply returns
/// true if the handler finds a view associated with the moniker.
//
bool
TOleLinkView::VnLinkMoniker(TString& moniker)
{
  if ((TCHAR*)OcLinkView.GetMoniker() == (TCHAR*)moniker)
    return true;
 
  return false;
}
 
//
/// When any changes occur to the server document, UpdateLinks updates all
/// containers linked to the view of the server document. If successful, it returns
/// true.
//
bool
TOleLinkView::UpdateLinks()
{
  OcLinkView.Invalidate(invView);
  return true;
}
 
//
/// Returns the moniker for the selection in a server document associated with this
/// TOleLinkView container's view. By looking at the moniker, the application can
/// find the corresponding objects in its document.
//
/// \note Monker is the source file's path name and the object hierarchy for a linked object.
/// A moniker functions much like a map by showing where the linked object's data is
/// stored and explaining how to find the data. For example, the moniker returned
/// from a word processor for a selected range of text could be the start and end
/// offset of a text stream. The moniker returned for a spreadsheet range could be
/// something like A1:D6. Anything that a server application can use to map to its
/// data can be used as a moniker.
TString&
TOleLinkView::GetMoniker()
{
  return OcLinkView.GetMoniker();
}
 
} // OCF namespace
 
//==============================================================================
 

V522 There might be dereferencing of a potential null pointer 'oleDoc'.

V522 There might be dereferencing of a potential null pointer 'olefr'.

V522 There might be dereferencing of a potential null pointer 'doc'.

V522 There might be dereferencing of a potential null pointer 'GetOcRemView()'.

V522 There might be dereferencing of a potential null pointer 'oleDoc'.

V1027 Pointer to an object of the 'TRect' class is cast to unrelated 'TPoint' class.