Files
TeslaRel410/BORLAND/BC45/SOURCE/OWL/DOCVIEW.CPP
T
CydandClaude Fable 5 63312e07f9 source410: literal 4.10 source reconstruction + BC++ 4.52 fleet toolchain archived
- BORLAND/: Borland C++ 4.52 (chosen over 4.5 by byte-match: CODE/RP/CW32.LIB
  is identical to 4.52's install lib). BCC32/TLINK32/TLIB/MAKE run natively on
  Win11; CODE/BT/OPT.MAK is the shipped BTL4OPT.EXE's exact flag recipe
  (extender = Borland PowerPack DPMI32, not Phar Lap TNT).
- restoration/source410/: the literal 1995-form reconstruction of the missing
  BT game source (never mixed into CODE/). Round 1-3 state:
  * 6 of 10 surviving original TUs COMPILE CLEAN under the period toolchain
    (BTMSSN, BTCNSL, BTSCNRL, BTTEAM, BTL4MODE, BTL4ARND) - first builds
    since 1996.
  * BT_L4/BTL4APP.CPP pilot reconstruction: 12/12 functions, Fail() lands on
    its binary-recorded line 400 exactly.
  * BT/BTCNSL.HPP: console wire IDs recovered from the binary's ctors
    (Killed=9, Damaged=10, ScoreUpdate=13, DeathWithoutHonor=15 [T1];
    TeamScore=12 flagged [T4]).
  * MUNGA/: 8 engine-header backfills back-dated from the BT412 WinTesla tree
    (VDATA numbering decomp-verified; AUDREND's OpenAL-era virtual removed -
    the period compiler is the drift detector).
  * Tooling: backdate.py (WinTesla->1995 header transform), compile410.sh
    (per-TU verification sweep under authentic OPT.MAK flags).
  * README: corrected roadmap - MECH.HPP is the capstone grown with the mech
    TU reconstructions; BTREG.CPP green = the header-family milestone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 07:33:26 -05:00

880 lines
20 KiB
C++

//----------------------------------------------------------------------------
// ObjectWindows
// (C) Copyright 1993, 1994 by Borland International, All Rights Reserved
//
// Implements classes TDocument, TView, TWindowView
//----------------------------------------------------------------------------
#pragma hdrignore SECTION
#include <owl/owlpch.h>
#include <owl/docmanag.h>
#include <owl/appdict.h>
#include <owl/docview.rh>
#include <string.h>
DIAG_DECLARE_GROUP(OwlDocView); // General Doc/View diagnostic group
#if !defined(SECTION) || SECTION == 1
const uint MinUniqueViewId = 0x8000;
uint TView::NextViewId = MinUniqueViewId;
int TDocument::UntitledIndex = 0;
//----------------------------------------------------------------------------
// class TDocument
//
TDocument*
TDocument::List::Next(const TDocument* doc)
{
return doc ? doc->NextDoc : DocList;
}
bool
TDocument::List::Insert(TDocument* doc)
{
TDocument* pdoc;
for (pdoc = DocList; pdoc; pdoc = pdoc->NextDoc)
if (pdoc == doc)
return false;
doc->NextDoc = DocList;
DocList = doc;
return true;
}
bool
TDocument::List::Remove(TDocument* doc)
{
TDocument** ppdoc;
for (ppdoc = &DocList; *ppdoc; ppdoc = &(*ppdoc)->NextDoc) {
if (*ppdoc == doc) {
*ppdoc = doc->NextDoc;
return true;
}
}
return false;
}
void
TDocument::List::Destroy()
{
while (DocList)
delete DocList; // removes it entry from destructor
}
TDocument::TDocument(TDocument* parent)
:
ParentDoc(parent), NextDoc(0), OpenMode(0),
Title(0), Template(0), ViewList(0), Tag(0), StreamList(0),
DocPath(0), DirtyFlag(false), Embedded(false)
{
if (parent) {
DocManager = parent->DocManager;
if (parent->ParentDoc == parent) {// a dummy parent
ParentDoc = 0;
DocManager->DocList.Insert(this);
}
else
parent->ChildDoc.Insert(this);
}
else {
TApplication* app = GetApplicationObject();
if ((DocManager = app->DocManager) == 0)
THROW( TXOwl(IDS_NODOCMANAGER) ); // no doc manager to catch this one
DocManager->DocList.Insert(this);
}
}
TDocument::~TDocument()
{
if (ParentDoc == this) // a dummy doc
return;
ChildDoc.Destroy(); // destroy children first, otherwise unnecessary
Close(); // force close (not virtual at this point!)
// delete all attached views, data has already been flushed
//
SetTemplate(0); // unref tpl, prevent self autodelete when deleting views
while (ViewList)
delete ViewList; // ~View() calls DetachView, which removes it from list
// delete all streams, should only be present if abort or coding error
//
while (StreamList)
delete StreamList;
// detach from parent and doc manager
//
if (ParentDoc) {
ParentDoc->ChildDoc.Remove(this);
}
else {
DocManager->PostEvent(dnClose, *this);
DocManager->DocList.Remove(this);
}
delete [] Title;
delete [] DocPath;
}
static char* PropNames[] = {
"Document Class", // DocumentClass
"Template Name", // TemplateName
"View Count", // ViewCount
"Storage Path", // StoragePath
"Document Title", // DocTitle
};
static int PropFlags[] = {
pfGetText|pfConstant, // DocumentClass
pfGetText, // TemplateName
pfGetBinary|pfGetText, // ViewCount
pfGetText|pfSettable, // StoragePath
pfGetText|pfSettable, // DocTitle
};
const char*
TDocument::PropertyName(int index)
{
if (index <= PrevProperty)
return 0;
else if (index < NextProperty)
return PropNames[index-PrevProperty-1];
else
return 0;
}
int
TDocument::PropertyFlags(int index)
{
if (index <= PrevProperty)
return 0;
else if (index < NextProperty)
return PropFlags[index-PrevProperty-1];
else
return 0;
}
int
TDocument::FindProperty(const char far* name)
{
int i;
for (i=0; i < NextProperty-PrevProperty-1; i++)
if (strcmp(PropNames[i], name) == 0)
return i+PrevProperty+1;
return 0;
}
int
TDocument::GetProperty(int prop, void far* dest, int textlen)
{
const char far* src;
char numBuf[6];
switch (prop) {
case DocumentClass:
src = _TYPENAME(this);
break;
case TemplateName:
src = Template ? Template->GetDescription() : 0;
break;
case ViewCount: {
int cnt;
TView* view;
for (view=ViewList, cnt=0; view != 0; view=view->NextView, cnt++) ;
if (!textlen) {
*(int far*)dest = cnt;
return sizeof(int);
}
wsprintf(numBuf, "%d", cnt);
src = numBuf;
break;
}
case StoragePath:
src = DocPath;
break;
case DocTitle:
src = Title;
break;
default:
return 0;
}
if (!textlen)
return 0;
int srclen = src ? strlen(src) : 0;
if (textlen > srclen)
textlen = srclen;
if (textlen)
memcpy(dest, src, textlen);
*((char far*)dest + textlen) = 0;
return srclen;
}
bool
TDocument::SetProperty(int prop, const void far* src)
{
switch (prop) {
case DocTitle:
SetTitle((const char far*)src);
break;
case StoragePath:
return SetDocPath((const char far*)src);
default:
return false;
}
return true;
}
TDocument&
TDocument::RootDocument()
{
TDocument* pdoc = this;
while (pdoc->ParentDoc)
pdoc = pdoc->ParentDoc;
return *pdoc;
}
void
TDocument::SetDocManager(TDocManager& dm)
{
if (!ParentDoc) {
if (DocManager) // test needed for TDocManager::Streamer::Read()
DocManager->DocList.Remove(this);
dm.DocList.Insert(this);
}
DocManager = &dm;
}
bool
TDocument::SetDocPath(const char far* path)
{
// path has been set already
//
if (path && (path == DocPath))
return true;
delete DocPath;
DocPath = (path && *path) ? strnewdup(path) : 0;
char title[256];
if (!DocPath || ::GetFileTitle(DocPath, title, sizeof title) != 0) {
int len = DocManager->Application->LoadString(IDS_UNTITLED, title, sizeof title);
if (DocManager->IsFlagSet(dmMDI))
wsprintf(title+len, "%d", ++UntitledIndex);
}
SetTitle(title);
return true; // derived classes may validate path
}
void
TDocument::SetTitle(const char far* title)
{
delete Title;
Title = title ? strnewdup(title) : 0;
ReindexFrames();
}
bool
TDocument::SetTemplate(TDocTemplate* tpl)
{
if (Template)
DocManager->UnRefTemplate(*Template);
if (tpl)
DocManager->RefTemplate(*tpl);
Template = tpl;
return true;
}
void
TDocument::ReindexFrames()
{
TView* view;
int seq;
for (seq = -1, view = ViewList; view != 0; view = view->NextView) {
seq -= view->SetDocTitle(Title, seq); // decrement if title displayed
if (seq == -3) // need only check if more than one title displayed
break;
}
if (seq == -1)
return;
seq = (seq == -2 ? 0 : 1);
for (view = ViewList; view != 0; view = view->NextView) {
seq += view->SetDocTitle(Title, seq); // increment if title displayed
}
}
void
TDocument::AttachStream(TStream& strm)
{
strm.NextStream = StreamList;
StreamList = &strm;
}
void
TDocument::DetachStream(TStream& strm)
{
TStream** plist = &StreamList;
for ( ; *plist; plist = &(*plist)->NextStream) {
if (*plist == &strm) {
*plist = strm.NextStream;
return;
}
}
}
TStream*
TDocument::NextStream(const TStream* strm)
{
return strm ? strm->NextStream : StreamList;
}
TView*
TDocument::NextView(const TView* view)
{
return view ? view->NextView : ViewList;
}
void
TDocument::AttachView(TView& view)
{
TView** ppview;
for (ppview = &ViewList; *ppview; ppview = &(*ppview)->NextView)
;
*ppview = &view; // insert at end of list
view.NextView = 0;
view.Doc = this;
NotifyViews(vnViewOpened, (long)&view, &view);
}
TView*
TDocument::InitView(TView* view)
{
if (!view) // test if new TView failed
return 0;
if (!view->IsOK()) { // test if constructor failed
delete view;
return 0;
}
DocManager->PostEvent(dnCreate, *view);
if (!view->IsOK()) { // if failed in creation
delete view;
return 0;
}
ReindexFrames();
if (++TView::NextViewId < MinUniqueViewId)
TView::NextViewId = MinUniqueViewId;
return view;
}
bool
TDocument::DetachView(TView& view)
{
TView** plist = &ViewList;
for (; *plist; plist = &(*plist)->NextView) {
if (*plist == &view) {
DocManager->PostEvent(dnClose, view);
*plist = view.NextView;
NotifyViews(vnViewClosed, (long)&view, &view);
if (!ViewList) { // all views for this doc are now gone
if (Template && (Template->Flags & dtAutoDelete)) {
if (IsOpen())
Close(); // close the document streams
return view.IsOK(); // delete doc UNLESS failure in creation
}
}
else {
ReindexFrames();
}
break;
}
}
return false;
}
bool
TDocument::Commit(bool force)
{
TDocument* pdoc = 0;
while ((pdoc = ChildDoc.Next(pdoc)) != 0) {
if (!pdoc->Commit(force))
return false;
}
// should we test here for DocPath==0 , or should caller have checked?
//
return NotifyViews(vnCommit, force);
}
bool
TDocument::Revert(bool clear)
{
TDocument* pdoc = 0;
while ((pdoc = ChildDoc.Next(pdoc)) != 0) {
if (!pdoc->Revert(clear))
return false;
}
return NotifyViews(vnRevert, clear);
}
bool
TDocument::NotifyViews(int event, long item, TView* exclude)
{
bool answer = true;
TEventHandler::TEventInfo eventInfo(WM_OWLNOTIFY, event);
TDocument* pdoc = 0;
while ((pdoc = ChildDoc.Next(pdoc)) != 0)
answer = ToBool(answer && pdoc->NotifyViews(event, item, exclude));
for (TView* view = ViewList; view != 0; view = view->NextView)
if (view != exclude && view->Find(eventInfo))
answer = ToBool(answer && view->Dispatch(eventInfo, 0, item));
return answer;
}
TView*
TDocument::QueryViews(int event, long item, TView* exclude)
{
TView* view;
TDocument* pdoc = 0;
while ((pdoc = ChildDoc.Next(pdoc)) != 0)
if ((view = pdoc->QueryViews(event, item, exclude)) != 0)
return view;
TEventHandler::TEventInfo eventInfo(WM_OWLNOTIFY, event);
for (view = ViewList; view != 0; view = view->NextView)
if (view != exclude && view->Find(eventInfo)
&& view->Dispatch(eventInfo, 0, item))
return view; // return first acknowledger
return 0; // if no takers
}
bool
TDocument::IsDirty()
{
if (DirtyFlag)
return true;
TDocument* pdoc = 0;
while ((pdoc = ChildDoc.Next(pdoc)) != 0)
if (pdoc->IsDirty())
return true;
return QueryViews(vnIsDirty) != 0;
}
bool
TDocument::HasFocus(HWND hwnd)
{
TDocument* pdoc = 0;
while ((pdoc = ChildDoc.Next(pdoc)) != 0)
if (pdoc->HasFocus(hwnd))
return true;
return QueryViews(vnIsWindow, (long)hwnd) != 0;
}
bool
TDocument::CanClose()
{
TDocument* pdoc = 0;
while ((pdoc = ChildDoc.Next(pdoc)) != 0)
if (!pdoc->CanClose())
return false;
return DocManager->FlushDoc(*this); // do the UI in the doc manager
}
bool
TDocument::Close()
{
TDocument* pdoc = 0;
while ((pdoc = ChildDoc.Next(pdoc)) != 0)
if (!pdoc->Close())
return false;
return true;
}
uint
TDocument::PostError(uint sid, uint choice)
{
return DocManager->PostDocError(*this, sid, choice);
}
//----------------------------------------------------------------------------
// class TView
//
TView::TView(TDocument& doc)
:
Tag(0), ViewMenu(0)
{
ViewId = NextViewId;
doc.AttachView(*this);
}
TView::~TView()
{
delete ViewMenu;
if (Doc->DetachView(*this)) {
delete Doc;
}
}
void
TView::SetViewMenu(TMenuDescr* menu)
{
delete ViewMenu;
ViewMenu = menu;
TDocTemplate* tpl = Doc->GetTemplate();
if (tpl && ViewMenu && *ViewMenu->GetModule() == *tpl->GetModule())
ViewMenu->SetModule(tpl->GetModule());// force same module alias as template
}
static char* TView_PropertyNames[] = {
"View Class", // ViewClass
"View Name", // ViewName
};
static int TView_PropertyFlags[] = {
pfGetText|pfConstant, // ViewClass
pfGetText|pfConstant, // ViewName
};
const char*
TView::PropertyName(int index)
{
if (index <= PrevProperty)
return 0;
else if (index < NextProperty)
return TView_PropertyNames[index-PrevProperty-1];
else
return 0;
}
int
TView::PropertyFlags(int index)
{
if (index <= PrevProperty)
return 0;
else if (index < NextProperty)
return TView_PropertyFlags[index-PrevProperty-1];
else
return 0;
}
int
TView::FindProperty(const char far* name)
{
int i;
for (i=0; i < NextProperty-PrevProperty-1; i++)
if (strcmp(TView_PropertyNames[i], name) == 0)
return i+PrevProperty+1;
return 0;
}
int
TView::GetProperty(int prop, void far* dest, int textlen)
{
const char far* src;
switch (prop) {
case ViewClass:
src = _TYPENAME(this);
break;
case ViewName:
src = GetViewName();
break;
default:
return 0;
}
if (!textlen)
return 0;
int srclen = src ? strlen(src) : 0;
if (textlen > srclen)
textlen = srclen;
if (textlen)
memcpy(dest, src, textlen);
*((char far*)dest + textlen) = 0;
return srclen;
}
//----------------------------------------------------------------------------
// class TWindowView
//
DEFINE_RESPONSE_TABLE1(TWindowView, TWindow)
EV_VN_ISWINDOW,
END_RESPONSE_TABLE;
TWindowView::TWindowView(TDocument& doc, TWindow* parent)
: TView(doc), TWindow(parent, 0, doc.GetDocManager().GetApplication())
{
}
//
// Does a given HWND belong to this view? Yes if it is us, or a child of us
//
bool
TWindowView::VnIsWindow(HWND hWnd)
{
return hWnd == HWindow || IsChild(hWnd);
}
//----------------------------------------------------------------------------
// class TDateTime (eventually)
//
int _OWLFUNC FormatFileTime(FILETIME* pft, void far* dest, int textlen)
{
char buf[40];
int len;
if (!textlen) {
*(FILETIME FAR*)dest = *pft;
return sizeof(FILETIME);
}
#if defined(BI_PLAT_WIN32)
SYSTEMTIME dt;
FileTimeToSystemTime(pft, &dt);
len = wsprintf(buf,"%d/%d/%d %02d:%02d:%02d.%02d",
dt.wMonth, dt.wDay, dt.wYear,
dt.wHour, dt.wMinute, dt.wSecond, dt.wMilliseconds/10);
#else
struct time filet;
struct date filed;
if (!(FileTimeToDateTime(pft, &filed, &filet)))
return false;
len = wsprintf(buf,"%d/%d/%d %02d:%02d:%02d.%02d",
filed.da_mon,filed.da_day,filed.da_year,
filet.ti_hour,filet.ti_min,filet.ti_sec,filet.ti_hund);
#endif
if (textlen > len)
textlen = len;
memcpy(dest, buf, textlen);
*((char far*)dest + textlen) = 0;
return len;
}
#if !defined(BI_PLAT_WIN32)
//
// Win32/OLE2 compatible FILETIME support for 16-bit applications
// these functions to be incorporated into TDateTime class
//
int FormatDateTime(struct date filed, struct time filet, void far* dest, int textlen)
{
char buf[40];
if (!textlen) {
DateTimeToFileTime(&filed, &filet, (FILETIME FAR*)dest);
return sizeof(FILETIME);
}
int len = wsprintf(buf,"%d/%d/%d %02d:%02d:%02d.%02d",
filed.da_mon,filed.da_day,filed.da_year,
filet.ti_hour,filet.ti_min,filet.ti_sec,filet.ti_hund);
if (textlen > len)
textlen = len;
memcpy(dest, buf, textlen);
*((char far*)dest + textlen) = 0;
return len;
}
// Convert date and time structures to 64-bit FILETIME structure
// multiply seconds by 10^7 and adjust offset to Jan. 1, 1601
// adjustment from Jan.1, 1970 = 116,444,736,000,000,000 = 0x019DB1DED53E8000
// This code is for Win32 and OLE2 compatibility when using Win16
#include <dos.h>
void DateTimeToFileTime(struct date* dosd, struct time* dost, FILETIME FAR* pft)
{
union {
long udt;
int w[2];
} u;
u.udt = dostounix(dosd, dost);
_BL = dost->ti_hund;
_AX = u.w[0];
_CX = u.w[1];
asm mov di,200
asm mul di
asm mov bh,0
asm add bx,bx
asm add ax,bx
asm adc dl,dh
asm xchg ax,cx
asm mov bx,dx
asm mul di
asm add bx,ax
asm mov si,0
asm adc si,dx
asm les di,pft
asm mov ax,50000
asm xchg ax,cx
asm mul cx
asm add ax,0x8000
asm adc dx,0
asm mov es:[di],ax
asm xchg ax,dx
asm xchg ax,bx
asm mul cx
asm add ax,bx
asm adc dx,0
asm add ax,0xD53E
asm adc dx,0
asm mov es:[di+2],ax
asm xchg ax,dx
asm xchg ax,si
asm mul cx
asm add ax,si
asm adc dx,0
asm add ax,0xB1DE
asm adc dx,0x019D
asm mov es:[di+4],ax
asm mov es:[di+6],dx
}
//
// Convert FILETIME structure to date and time structures
//
bool FileTimeToDateTime(FILETIME FAR* pft, struct date* dosd, struct time* dost)
{
union {
long udt;
int w[2];
} u;
asm les di,pft
asm mov dx,es:[di+6]
asm mov ax,es:[di+4]
asm sub ax,0xB1DE
asm sbb dx,0x019D
asm jnc OK
return false;
OK:
asm mov cx,50000
asm div cx
asm xchg bx,ax
asm mov ax,es:[di+2]
asm sub ax,0xD53E
asm sbb dx,0
asm div cx
asm xchg si,ax
asm mov ax,es:[di]
asm sub ax,(0x8000-5000)
asm sbb dx,0
asm div cx
asm mov dx,bx
asm xchg ax,si
asm mov cx,200
asm div cx
asm xchg ax,si
asm div cx
asm shr dx,1
asm push dx
u.w[0] = _AX;
u.w[1] = _SI;
unixtodos(u.udt, dosd, dost);
asm pop ax
dost->ti_hund = _AL;
return true;
}
#endif // !defined(BI_PLAT_WIN32)
#endif
//----------------------------------------------------------------------------
#if !defined(SECTION) || SECTION == 2
IMPLEMENT_ABSTRACT_STREAMABLE(TView);
void*
TView::Streamer::Read(ipstream& is, uint32 /*version*/) const
{
TView* o = GetObject();
bool hasViewMenu = is.readByte();
if (hasViewMenu) {
o->ViewMenu = new TMenuDescr;
is >> *o->ViewMenu;
}
else
o->ViewMenu = 0;
is >> o->ViewId;
is >> o->Doc;
is >> o->NextView;
return o;
}
void
TView::Streamer::Write(opstream& os) const
{
TView* o = GetObject();
os.writeByte(int16(o->ViewMenu ? 1 : 0));
if (o->ViewMenu)
os << *o->ViewMenu;
os << o->ViewId;
os << o->Doc;
os << o->NextView;
}
IMPLEMENT_ABSTRACT_STREAMABLE(TDocument);
void*
TDocument::Streamer::Read(ipstream& is, uint32 /*version*/) const
{
TDocument* o = GetObject();
o->NextDoc = 0;
o->StreamList = 0;
o->DocManager = 0;
o->DirtyFlag = false;
is >> o->OpenMode;
o->DocPath = is.freadString();
o->Title = is.freadString();
is >> o->Template; // static templates must have been already streamed
is >> o->ParentDoc;
o->ViewList = 0; // must init, does not get set until after view streamed
is >> o->ViewList;
is >> TView::NextViewId; // static, but must get set by at least 1 document
return o;
}
void
TDocument::Streamer::Write(opstream& os) const
{
TDocument* o = GetObject();
while (!o->CanClose()) // can't permit cancel here
;
os << o->OpenMode;
os.fwriteString(o->DocPath);
os.fwriteString(o->Title);
os << o->Template; // templates already streamed, must be so if static
os << o->ParentDoc;
os << o->ViewList; // each view streams out the next
os << TView::NextViewId; // insure that this static var gets set on reload
}
IMPLEMENT_STREAMABLE2(TWindowView, TWindow, TView);
void*
TWindowView::Streamer::Read(ipstream& is, uint32 /*version*/) const
{
ReadBaseObject((TWindow*)GetObject(), is);
ReadBaseObject((TView*)GetObject(), is);
return GetObject();
}
void
TWindowView::Streamer::Write(opstream& os) const
{
WriteBaseObject((TWindow*)GetObject(), os);
WriteBaseObject((TView*)GetObject(), os);
}
#endif