									 DOCUMENT/VIEW AND YOU

	Here are the basics to Doc/View, as far as I can figure them.  I suspect
they are pretty hard to figure out, as none of the aftermarket BC4 books explain
them.  They seem to be discussed only in the OWL manuals, in the online help,
and with comments in the header files and source code itself.  The source code
seems to be the place to look to figure out Doc/View, as the other material is
a little sparse at best.

To explain where a bit of information comes from, I have used the following
convention.  "1)" means copied directly from the help text, "2)" means from the
source code, and "3)" means my own explanation.

This document assumes that you are an OWL user and have compiled and run the
DOCVIEW example on the BC4 disks and have worked through the tutorial.  It was
at that point that I started pulling my hair out trying to figure out TDocument
and TDocument is there that I begin:

//==============================================================================
// TStreamableBase
//       |
//   TDocument (abstract)
//==============================================================================
TDocument:
1)
TDocument is an abstract base class that serves as an interface between the
document, its views, and the document manager (TDocManager class). TDocument
creates, destroys, and sends messages about the view. For example, if the user
changes a document, TDocument tells the view that the document has been updated.
In order to send messages to its associated views, the document maintains a list
of all the views existing for that document and communicates with the views
using ObjectWindows event-handling mechanism. Rather than using the function
SendMessage, the document accesses the view's event table. The views can update
the document's data by calling the member functions of the particular document.
Views can also request streams, which are constructed by the document.
Both documents and views have lists of properties for their applications to use.
When documents and views are created or destroyed, messages are sent to the
application, which can then query the properties to determine how to process the
document or view. It is the document manager's responsibility to determine if a
particular view is appropriate for the given document.

Because the property attribute functions are virtual, a derived class (which is
called first) might override the properties defined in a base class. Each
derived class must implement its own property attribute types of either string
or binary data. If the derived class duplicates the property names of the parent
class, it should provide the same behavior and data type as the parent.

Although documents are usually associated with files, they do not necessarily
have to be files; they can also consist of database tables, mail systems, fax or
modem transmissions, disk directories, and so on.

3) What is a parent?  All of the examples use 0 for a parent, when would I put
something else in?
The idea behind the parent is that documents can contain other documents as
objects.  For example, you can often insert a .BMP file by reference directly
into a word processor.  Because you aren't inserting the bits, you have another
file, and you might want to have a graphical tool and be drawing on the picture
in one window, and have the picture in a page of text in another.  When you
close the .BMP file you want to keep the word processing document up, but when
you close the word processing document you want the .BMP to go away.  The word
processing document would then be considered the parent of the .BMP.

What is a property?
Properties are facts about the document, like its filename and size.  A lot of
tricks are used with enums to get properties to inherit correctly.  Properties
also have the annoying problem of being any type, so you have to know what you
want before you can get it.  Properties defined in the base class TDocument are:
		DocumentClass,     // text
		TemplateName,      // text
		ViewCount,         // int
		StoragePath,       // text
		DocTitle,          // text
TFileDocument adds:
		CreateTime,        // FILETIME
		ModifyTime,        // FILETIME
		AccessTime,        // FILETIME
		StorageSize,       // unsigned long
		FileHandle,        // platform file handle (HFILE if Windows)
The example TDrawDocument for drawing lines adds:
		LineCount,
		Description,
etc.


TDocument Members (public):
	 TDocument(TDocument* parent = 0) CONSTRUCTOR
		 3) This constructor causes the document to inherit the parent's document
		 manager, if there is a parent.  Otherwise it just sets the document
		 manager member.   (I've never seen a program use more than one document
		 manager at the same time, I think that you would want to have more than
		 one for certain kinds of OLE servers, provided you could make OLE work
		 with Doc/View.)

	 virtual ~TDocument() DESTRUCTOR
		 3) This deletes all children (if there are any) and all views.

	 virtual TInStream*  InStream(int mode, const char far* strmId=0)
		 3) These three members aren't abstract, so that classes that don't use
		 TIn/OutStreams don't have to redefine it, but it does nothing in
		 TDocument.  This function expects a 'mode', this is where you tell the
		 stream if it is to be binary or text, etc.

	 virtual TOutStream* OutStream(int mode, const char far* strmId=0)
		 3) Again does nothing (just a stub).

	 virtual BOOL   Open(int mode, const char far* path=0)
		 3) also a stub, return TRUE.

	 virtual BOOL   Close();
		 2) close document, does not delete or detach
		 3) This member Close()s all children, but doesn't do anything to the
		 view itself.

	 virtual BOOL   Commit(BOOL force=FALSE);
		 1) Saves the current data to storage. When a file is closed, the document
		 manager calls either Commit or Revert. If force is TRUE, all data is
		 written to storage. TDocument's Commit checks any child documents and
		 commits their changes to storage also. Before the current data is saved,
		 all child documents must return TRUE. If all child documents return TRUE,
		 Commit flushes the views for operations that occurred since the last time
		 the view was checked. Once all data for the document is updated and
		 saved, Commit returns TRUE.
		 2) save current data, force write
		 3) Commit()s all children, then notifies all the views that a Commit is
		 taking place.  If force is FALSE, data will only be written if the doc
		 is 'dirty' (has changed since it was loaded.)
		 Interestingly, the code contains the comment:
			// should we test here for DocPath==0 , or should caller have checked?
		 Which leads us to suspect that the caller should have checked...
		 This is where you put the code in your TDocument descendent to write out
		 your changes, unless you have having the view hold the data (more on this
		 later.)

	 virtual BOOL   Revert(BOOL clear=FALSE);
		 1) Performs the reverse of Commit and cancels any changes made to the
		 document since the last commit. If clear is TRUE, data is not reloaded
		 for views. Revert also checks all child documents and cancels any changes
		 if all children return TRUE. When a file is closed, the document manager
		 calls either Commit or Revert. Returns TRUE if the operation is
		 successful.
		 2) abort changes, no reload if TRUE
		 3) Revert()s all children, doesn't do anything to itself.

	 virtual TDocument& RootDocument();
		 1) Returns the this pointer as the root document. [INCORRECT]
		 3) This member searches up the parent list to find the root of the
		 document heirarchy for this document.  (perhaps it was supposed to be
		 "of the root document.")

	 TDocManager&   GetDocManager()
		 1) Returns a pointer to the current document manager.
		 3) Not quite sure why you would want more than one document manager,
		 probably has something to do with OLE or OpenDoc.

	 void           SetDocManager(TDocManager& dm);
	 TDocument*     GetParentDoc()
		 3) These are pretty obvious

	 TDocTemplate*  GetTemplate()
		 1) Gets the template used for document creation. The template can be
		 changed during a SaveAs operation.
		 3) A template is a pair <doc, view>.  This was created by a
		 DEFINE_DOC_TEMPLATE most likely.  The only place this is used in the
		 code is to let the view know to get it's menu from the same TModule that
		 the template lives in.
	 BOOL           SetTemplate(TDocTemplate* tpl);

	 virtual BOOL   SetDocPath(const char far* path)
		 3) Filename of the document.  This can be 0 in the case of File|New.
	 const char far* GetDocPath()

	 virtual void   SetTitle(const char far* title)
	 const char far* GetTitle()
		 3) This is usually used to put the title into the views.

	 virtual BOOL   IsDirty();
		 1) Returns TRUE if the document or one of its views has changed but has
		 not been saved.
		 2) also queries doc and view hierarchy
		 3) When a document changes, it is supposed to be set to being 'dirty'
		 so that when the document is closed without saving the user can be
		 prompted if saving is to be done.
	 void           SetDirty(BOOL dirty = TRUE)

	 virtual BOOL   IsOpen()
		 1) Checks to see if the document has any streams in its stream list.
		 Returns FALSE if no streams are open; otherwise, returns TRUE.
		 3) This can be redefined to check something besides the streams list,
		 the line drawing example just checks a pointer to see if any lines
		 are around.
	 virtual BOOL   CanClose();
		 2) returns FALSE if unable to close

	 BOOL           HasFocus(HWND hwnd);

	 BOOL           NotifyViews(int event, long item=0, TView* exclude=0);
		 1) Notifies the views of the current document and the views of any child
		 documents of a change, In contrast to QueryViews, NotifyViews sends
		 notification of an event to all views and returns TRUE if any views
		 returned a TRUE result. The event, EV_OWLNOTIFY, is sent with an event
		 code, which is private to the particular document and view class, and a
		 long argument, which can be cast appropriately to the actual type passed
		 in the argument of the response function.
		 3) The event is something that begins with an EV_, like EV_NEW_VIEW.
		 The item is any 32 bit value, the views have a special mechanism to get
		 the data into the correct type, so you can pass pointers around and
		 stuff if you cast them here.  The exclude view doesn't get the
		 information, so for example (although the example doesn't do this) you
		 can have the line drawing program send the notification of a new line to
		 all the views except the one that just drew the line, that way the one
		 that submitted the line doesn't have to check for a callback and ignore
		 it.)

	 TView*         QueryViews(int event, long item=0, TView* exclude=0);
		 1) Queries the views of the current document and the views of any child
		 documents about a specified event, but stops at the first view that
		 returns TRUE,  In contrast to NotifyViews, QueryViews returns a pointer
		 to the first view that responded to an event with a TRUE result. The
		 event, EV_OWLNOTIFY, is sent with an event code (which is private to the
		 particular document and view class) and a long argument

	 virtual UINT   PostError(UINT sid, UINT choice = MB_OK)
		 3) 'sid' is supposed to be the # for some message in the resource file,
		 and 'choice' are the button flags.  This function simply calls the
		 document manager's PostDocError().  (The default document manager
		 TDocManager calls MessageBox() with the string in the resource file.  If
		 you need something else to happen, say a BWCCMessageBox(), this is where
		 subclassing the document manager comes into play.  Note that if you
		 take the MB_OK default, you automatically get MB_ICONQUESTION for some
		 reason too... it's part of TDocManager)

	 The following functions deal with properties, these are pretty mundane.
	 virtual int    PropertyCount()
	 virtual int    FindProperty(const char far* name);
		 2) return property index
	 virtual int    PropertyFlags(int index);
		 2) pfXxxxx bit array
	 virtual const char*  PropertyName(int index);
		 2) locale invariant name
		 3) If you look at the comment in the header file, you might get confused.
		 "locale invarient" means that the name of the property doesn't change
		 along with the national language stuff on 32-bit windows.
	 virtual int    GetProperty(int index, void far* dest, int textlen=0);
	 virtual BOOL   SetProperty(int index, const void far* src);
		 2) native type

	 TStream*       NextStream(const TStream* strm);
		 1) Gets the next entry in the stream. Holds 0 if none exists.
		 3) TDocuments seem to maintain a linked list of streams which they
		 disguise as a circular list.  None of the examples use these streams,
		 and neither does TFileDocument, so I have not a clue as to what they
		 were supposed to be for...

	 TView*         NextView(const TView* view);
		 1) Gets the next view in the list of views. Holds 0 if none exists.
		 3) Again, it seems to be emulating a circular list of views, so 0 will
       return the first view.  Anyway, this member lets other classes go
       through the view list in much the same way as NotifyViews does.

	 int            GetOpenMode();
		 1) Gets the mode and protection flag values for the current document.
	 void           SetOpenMode(int mode);

	 void far*     Tag;
		 1) Tag holds a pointer to the application-defined data. Typically, you
		 can use Tag to install a pointer to your own application's associated
		 data structure. Tag, which is initialized to 0 at the time a TDocument
		 is constructed, is not used otherwise by the document view classes.
		 2) application hook, not used internally
		 3) I suspect Tag is for doing tricks with TDocuments and TFileDocuments
		 when you are too lazy to subclass them.

	 List          ChildDoc;
2) linked child document chain

TDocument Members (protected):
	 BOOL          DirtyFlag;
		 1) Indicates that unsaved changes have been made to the document.
		 Views can also independently maintain their local disk status.
		 2) document changed, might not represent views
		 3) (I am pretty sure that the comment in the source code is incorrect,
		 I think that when a document is dirty it doesn't represent the FILES.)
	 static int    UntitledIndex;
		 2) last used index for Untitled document
	 virtual void  AttachStream(TStream& strm);
		 2) called from TStream constructor
	 virtual void  DetachStream(TStream& strm);
		 2) called from TStream destructor


//==============================================================================
// TEventHandler TStreamableBase
//       |              |
//       ---------------
//              |
//            TView (abstract)
//==============================================================================
1) Derived virtually from both TEventHandler and TStreamableBase, TView is the
interface presented to a document so it can access its client views. Views then
call the document functions to request input and output streams. Views own the
streams and are responsible for attaching and deleting them. Instead of creating
an instance of TView, you create a derived class that has access to TView's
virtual functions. The derived class must have a way of knowing the associated
window (provided by GetWindow), of describing the view (provided by
GetViewName), and of displaying a range of data (GetSelection). The view must
also be able to restore the view later (SetSelection) and to display the
document title in its window (SetDocTitle).  TView uses several event handler
functions to query views, commit, and close views. For example, to query views
to find the one with the focus, you would use the vnIsWindow function, passing a
handle to the current window.

View classes can take various forms. For example, a view class can be a window
(through inheritance), can contain a window (an embedded object), can reference
a window, or can be contained within a window object. A view class might not
even have a window, as in the case of a voice mail or a format converter. Some
remote views (for example, those displayed by OLE 2.0 or DDE servers) might not
have local windows.

Public members:
	 TView(TDocument& doc) CONSTRUCTOR
		 1) Constructs a TView object of the document associated with the view.
		 Sets ViewId to NextViewId. Calls TDocument::AttachView to attach the
		 view to the associated document.
		 3) Also sets Tag and ViewMenu (publicly known as GetViewMenu()/
		 SetViewMenu().  TDocument's private AttachView() takes care of advancing
		 NextViewId.

	 virtual ~TView() DESTRUCTOR
		 1) Frees a TView object and calls DetachView to detach the view from the
		 associated document.

	 TDocument&  GetDocument() {return *Doc;}
	 unsigned    GetViewId()   {return ViewId;}
	 TMenuDescr* GetViewMenu() {return ViewMenu;}
	 void        SetViewMenu(TMenuDescr* menu);
		 1) Sets the menu descriptor for this view. This can be any existing
		 TMenuDescr object. If no descriptor exists, ViewMenu is 0.
		 3) Look at the online help for TMenuDescr on this one.  Basically, each
		 view is expected to have a piece of menu-bar, which gets merged with the
		 apps menu bar deep in the bowels of OWL.

	 BOOL        IsOK()
		 1) Returns nonzero if the view is successfully constructed.
		 2) TRUE if successfully created

	 static unsigned GetNextViewId()
		 2) next ID to assign

	 // static const char far* StaticName() {return "name of view";}
		 2) must implement, used by template manager for selection
		 3) This member doesn't actually exist, but is very important.  C++ has
		 no way of specifying an abstract static member, so Borland thoughtfully
		 commented it out in the header.  The help text for TListBox::StaticName()
		 is:
		 Overrides TView's function and returns a constant string, "ListView."
		 This information is displayed in the user interface selection box.
		 If you don't specify this, you don't get your view's name in the "Window|
		 Add View" pick menu generated by the document manager.

	 virtual const char far* GetViewName()=0;
		 2) return static name of view
		 3) This is supposed to contain EXACTLY the same thing as StaticName().
		 In fact, if you look at the code you will have a hard time finding
		 calls to StaticName(), it looks like this is to be used exclusivly, but
		 no, you MUST define both and make them the same.

	 virtual TWindow* GetWindow()
		 3) This member returns 0.  It is supposed to be subclassed in TView/
		 TWindow mix classes.

	 virtual BOOL   SetDocTitle(const char far* docname, int index)
		 1) Stores the document title.
		 3) Actually, it does no such thing.  It just calls the parent's
		 SetDocTitle(), if there is a parent.  Actually setting the window caption
		 is done by TFrameWindow.  To get your window to have a title, you have
       to override SetDocTitle() in your view class to call TWindow::SetDocTitle
       and you should call TView::SetDocTitle was well in case you will be
       dealing with child documents.  TFrameWindow::SetDocTitle appends it's
       original title to your document's name and number.

	 virtual int    PropertyCount() {return NextProperty - 1;}
	 virtual int    FindProperty(const char far* name);// return property index
	 virtual int    PropertyFlags(int index);          // pfXxxxx bit array
	 virtual const char*  PropertyName(int index);     // locale invariant name
	 virtual int    GetProperty(int index, void far* dest, int textlen=0);
	 virtual BOOL   SetProperty(int index, const void far* src) {return FALSE;}

Protected members:
	 TDocument*   Doc;
		 3) This member points to the document.  However, the type is TDocument
		 so if you plan on using this member to call your own document's
		 functions you had better downcast Doc to your own type.
	 void         NotOK()
		 1) Sets the view to an invalid state, thus causing IsOK to return 0.
		 2) to flag errors in creation
		 3) Neither TView, TDocument, or any of the document manager classes use
		 this.  This is for TView descendents to call if their Create() member
		 fails for some reason.

//==============================================================================
// TWindow  TView
//    |       |
//     -------
//        |
//   TWindowView
//==============================================================================
1) Derived from both TWindow and TView, TWindowView is a streamable base class
that can be used for deriving window-based views. TWindowView's functions
override TView's virtual function to provide their own implementation. By
deriving a window-view class from TWindow and TView, you add window
functionality to the view of your document.

3) This class simply mixes TWindow and TView.  It is a good base class to use
if you aren't making an edit window (TEditView) or a list box (TListView) and
sometimes is a good base to use even if you are.  It defines the necessary stuff
to make a view act like a window, and has a single response function,
VnIsWindow()


//==============================================================================
// Events and how to make them
//==============================================================================
Let's take a look at how the standard events are defined.  They are defined
in two pieces:  First, the argument types to the various functions are defined,
then the EV_VN_ messages are defined, like this:

NOTIFY_SIG(vnViewOpened,TView*)
NOTIFY_SIG(vnViewClosed,TView*)
NOTIFY_SIG(vnDocOpened, int)
NOTIFY_SIG(vnDocClosed, int)
NOTIFY_SIG(vnCommit, BOOL)
NOTIFY_SIG(vnRevert, BOOL)
NOTIFY_SIG(vnIsDirty, void)
NOTIFY_SIG(vnIsWindow, HWND)

#define EV_VN_VIEWOPENED VN_DEFINE(vnViewOpened,VnViewOpened,pointer)
#define EV_VN_VIEWCLOSED VN_DEFINE(vnViewClosed,VnViewClosed,pointer)
#define EV_VN_DOCOPENED  VN_DEFINE(vnDocOpened, VnDocOpened, int)
#define EV_VN_DOCCLOSED  VN_DEFINE(vnDocClosed, VnDocClosed, int)
#define EV_VN_COMMIT     VN_DEFINE(vnCommit,    VnCommit,    int)
#define EV_VN_REVERT     VN_DEFINE(vnRevert,    VnRevert,    int)
#define EV_VN_ISDIRTY    VN_DEFINE(vnIsDirty,   VnIsDirty,   void)
#define EV_VN_ISWINDOW   VN_DEFINE(vnIsWindow,  VnIsWindow,  int)

Here is a handy table of the meanings of the constants:

Constant	      Meaning
vnCommit			1) Changes are committed to the document.
					2) document is committing, flush cached changes
					3) The document is about to write changes to the file.  If the
						view is keeping changes from the document for efficiency
						reasons, it has to tell the document about them all when it
						gets this notification.
vnCustomBase	1) Base event for document notifications.
					2) base of document class specific notifications
					3) Has the value of 100.  Document classes you write are
						supposed to use vnCustomBase+x for each of their custom
						notifications.  Documents don't send events to views that are
						not their own, so you don't need to guarentee unique #s among
						documents.  Define these in your document and not your views
						so they can be shared.
vnDocOpened  	1&2) Document has been opened.
vnDocClosed  	1&2) Document has been closed.
vnIsDirty 		1&2) Is TRUE if uncommitted changes are present.
vnIsWindow 		1&2) Is TRUE if the HWND passed belongs to this view.
vnRevert			1) Document's previous data is reloaded and overwrites the
						view's current data.
					2) document has reverted, reload data from doc
vnViewOpened	1) A new view has been constructed.
vnViewClosed   2) A view is about to be destroyed.


Now, in the Borland supplied line drawing example, three additional events
were defined:  Append a line, Delete a line, and Modify a line.  Each of
these worked with an unsigned int which was the # of the line.  These events
were defined thusly:

const int vnDrawAppend = vnCustomBase+0;
const int vnDrawDelete = vnCustomBase+1;
const int vnDrawModify = vnCustomBase+2;

NOTIFY_SIG(vnDrawAppend, unsigned int)
NOTIFY_SIG(vnDrawDelete, unsigned int)
NOTIFY_SIG(vnDrawModify, unsigned int)

#define EV_VN_DRAWAPPEND  VN_DEFINE(vnDrawAppend,  VnAppend,  int)
#define EV_VN_DRAWDELETE  VN_DEFINE(vnDrawDelete,  VnDelete,  int)
#define EV_VN_DRAWMODIFY  VN_DEFINE(vnDrawModify,  VnModify,  int)

When I first started trying to make Doc/View apps, I didn't realize that I
could put any old type I wanted into NOTIFY_SIG, because I didn't understand
how it figured out what to do.  But you can, provided it fits into 32 bits.
Just follow the examples from DOCVIEW.H above.  (DOCVIEW.H has a bunch of
secret stuff in it to make this all work, it is quite hard to read...)

//==============================================================================
// TListBox  TView
//    |        |
//     --------
//        |
//    TListView
//==============================================================================
3) This class does everything that TWindow does, and LOTS more things.  We will
look only at the extra functionality.

Would you ever use TListView?  You really don't want to use it unless you are
doing something similar to what it does, scrolling over text.  For example, the
TDrawListView in the drawing example doesn't use TListView, it goes right to
TListBox and TView directly, because TListView wants to do too much.

Public members:
	 TListView(TDocument& doc, TWindow* parent = 0) CONSTRUCTOR
		 1) Creates a TListView object associated with the specified document and
		 parent window. Sets Attr.AccelTable to IDA_LISTVIEW to identify the edit
		 view. Sets Attr.Style to WS_HSCROLL | LBS_NOINTEGRALHEIGHT.
		 Sets TView::ViewMenu to the new TMenuDescr for this view.
		 3) Sets Origin, MaxWidth, and DirtyFlag to 0.
		 NOTE THAT DIRTYFLAG IS NOT THE SAME AS TDOCUMENT::DIRTYFLAG.
		 NOTE THAT THIS CONSTRUCTOR LOADS A MENU "IDM_LISTVIEW" FROM THE RESOURCE
		 FILE FOR MERGING WITH THE MENU BAR ALONG WITH ACCELERATORS.

	 BOOL Create()
		 1) Overrides TWindow::Create and calls TEditSearch::Create to create the
		 view's window. Calls GetDocPath to determine if the file is new or
		 already has data. If there is data, calls LoadData to add the data to
		 the view. If the view's window can't be created, Create throws a
		 TXInvalidWindow exception.  (INCORRECT.  Calls TListBox::Create)
		 3) NOTE THAT LOADDATA IS NOT VIRTUAL AND IS GETTING CALLED HERE.  THUS,
		 YOU GET THE LOADDATA FOR TLISTVIEW INSTEAD OF YOUR OWN LOADDATA.

	 BOOL DirtyFlag;
		 1) Is nonzero if the data in the list view has been changed; otherwise,
		 is 0.
		 3) TListView sometimes sets this to 2 to do 'tricks' with saving and
		 reloading from disk.  Don't expect the value to be TRUE or FALSE.

protected members:
	 long Origin;
		 1) Holds the file position at the beginning of the display.
		 3) Ok.  Unlike the line drawing sample program, a TListView caches data
		 locally, 'cause that is what ListBox's do.  When it is time to VnCommit,
		 the list box writes all of it's data out to a stream instead of letting
		 the document take care of it.  Before it writes this data it seeks to
		 Origin.  Now, what is supposed to be happening is that the list box is
		 holding one line for each line of text in the file.  It might be possible
		 to set up Origin to point to elsewhere in the file, then a different part
		 of the file could be scrolled over, except that TListBox DOESN'T seek to
		 Origin when it reloads it's data...

	 int  MaxWidth;
		 1) Holds the maximum horizontal extent (the number of pixels by which the
		 view can be scrolled horizontally).
		 2) maximum horizontal extent
		 3) This is set to 0 by Clear() and to the length of the longest string
		 ever sent to SetExtent().  SetExtent is called whenever data in the list
		 box changes.  This lets the list box have a scroll bar big enough to
		 scroll over the longest string in the listbox.
	 void SetExtent(const char far* str)

	 BOOL LoadData(int top, int sel)
		 1) Reads the view from the stream and closes the file. Returns TRUE if
		 the view was successfully loaded.
		 Throws an xmsg exception and displays the error message "TListView
		 initial read error" if the file can't be read. Returns FALSE if the view
		 can't be loaded.
		 3) The parameters, top and sel, have to do with the TListBox members
		 SetTopIndex() and SetSelIndex(), this calls them.
		 This function interprets the file as being lines of text 100 characters
		 or shorter, and it loads each line into a line in the listbox where the
		 file can be scrolled over.

	 The following members respond to choices on the Edit menu that was loaded in
	 the constructor.

	 void CmEditUndo()
		 1) Automatically responds to a menu selection with a menu ID of
		 CM_EDITUNDO by calling TListBox::Undo.  INCORRECT
		 3) Displays "Feature not implemented" in a message box.

	 void CmEditCut();
	 void CmEditCopy();
	 void CmEditPaste();
	 void CmEditDelete();
	 void CmEditClear();
		 3) These do what they are expected, using text and the clipboard.  They
		 set the DirtyFlag if necessary.

	 void CmEditAdd();
	 void CmEditItem();
		 3) These members bring up a little dialog where the user can enter a line
		 of text.  They use a static function, so don't be expect to be able to
		 do much with the appearance of the dialog.  The dialog prompt comes from
		 the resource file.

	 UINT EvGetDlgCode(MSG far*)
		 1) Overrides TWindow's response to a WM_GETDLGCODE message (an input
		 procedure associated with a control that isn't a check box) by calling
		 DefaultProcessing.

	 BOOL VnDocClosed(int omode)
		 1) VnDocClosed indicates that the document has been closed. mode is one
		 of the ofxxxx document open constants.
		 3) This member calls LoadData() to rebuild the list box, unless it's own
		 VnCommit() decided to set the dirty flag to 2 and wrote the data itself.
		 This member is called by TFileDocument::CloseThisFile when an I/O
		 completes.
		 (Huh?  Ok, I don't quite understand it, but when the document is closed,
		 TListView wants to re-read it from disk if anyone besides itself did the
		 writing...)

	 BOOL VnCommit(BOOL force)
		 1) VnCommit commits changes made in the view to the document. If force is
		 nonzero, all data, even if it's unchanged, is saved to the document.
		 3) DirtyFlag is checked to see if the data is unchanged.

	 BOOL VnRevert(BOOL clear)
		 1) VnRevert indicates if changes made to the view should be erased, and
		 the data from the document should be restored to the view. If clear is
		 nonzero, the data is cleared instead of restored to the view.
		 3) That way VnRevert can handle both File|Revert and Edit|Clear, though
		 why those two functions are combined is unclear...

	 BOOL VnIsDirty()

	 void CmSelChange()
		 1) Automatically responds to a LBN_SELCHANGE message (which indicates
		 that the contents of the list view have changed) by calling
		 DefaultProcessing.
		 2) to prevent interpreting as unprocessed accelerator

//==============================================================================
//   TDocument
//       |
// TFileDocument
//==============================================================================
1) Derived from TDocument, TFileDocument opens and closes views and provides
stream support for views. Streams are created on top of DOS files using Windows
file services. TFileDocument has member functions that continue to process
FileNew and FileOpen messages after a view is constructed. You can add support
for specialized file types by deriving classes from TFileDocument. TFileDocument
makes this process easy by hiding the actual processs of storing file types.

public members:
	 TFileDocument(TDocument* parent = 0) CONSTRUCTORS
		 3) Initializes FHdl and InfoPresent

	~TFileDocument()
		 3) Does nothing

	 BOOL        Open(int mode, const char far* path=0)
		 1) Overrides TDocument_Open and opens the file using the specified path.
		 If the file is already open, returns 0. Calls TDocument::SetDocPath to set
		 the directory path. If omode isn't 0, sets TDocument::OpenMode to omode.
		 If the file can't be opened, returns 0.
		 3) This function set up a few things and calls OpenThisFile().  As
		 OpenThisFile() isn't virtual, if you want to be doing your own stuff
		 at opening time, YOU DON'T CALL THE OLD OPEN() TO SET THE FILE HANDLE.
		 See the line drawing program for an example of this.
		 FHdl is used to keep track of the state of the document, open or closed.

	 BOOL        Close();
		 1) Closes the document but does not delete or detach any associated
		 views. Before closing the document, Close calls TDocument's Close to make
		 sure all child documents are closed. If any children are open, Close
		 returns 0 and doesn't close the document. If all children are closed,
		 checks to see if any associated streams are open, and if so, returns 0
		 and doesn't close the document. If there are no open streams, closes the
		 file.

	 TInStream*  InStream(int mode, const char far* strmId=0)
		 1) Overrides Tdocument::InStream and provides generic input for the
		 particular storage medium. InStream returns a pointer to a TInStream.
		 mode is a combination of the ios bits defined in iostream.h. strmId is
		 not used for file documents. The view reads data from the document as a
		 stream or through stream functions.
		 3) The stream gets it's file handle from FHdl.

	 TOutStream* OutStream(int mode, const char far* strmId=0);

	 BOOL        Commit(BOOL force = FALSE)
		 1) Calls TDocument::Commit and clears TDocument's DirtyFlag data member,
		 thus indicating that there are no unsaved changes made to the document.
		 3) Commit doesn't write any data to the disk.  I think it is intended to
		 be used with views like TListView which carry all of their data in their
		 windows.  The line drawing example program doesn't even call the base
		 Commit.
	 BOOL        Revert(BOOL clear = FALSE);
		 3) Same as commit.

	 BOOL        IsOpen()
		 2) { return FHdl != HFILE_ERROR || TDocument::IsOpen(); }

	 All of the property functions are redefined:
	 int         FindProperty(const char far* name);  // return index
	 int         PropertyFlags(int index);
	 const char* PropertyName(int index);
	 int         PropertyCount() {return NextProperty - 1;}
	 int         GetProperty(int index, void far* dest, int textlen=0);
	 BOOL        SetProperty(int index, const void far* src);

	 BOOL        Open(HFILE fhdl);     // open on existing file handle
		 1) Opens a file document using an existing file handle.  Sets
		 TDocument::OpenMode to PREV_OPEN and read/write. Sets the document path
		 to 0. Sets FHd to fhdl.  Always returns nonzero.
		 3) Ok, while I have not seen this in use, I suspect that it is for OLE
		 type documents where a document is embedded in another document.  When
		 the parent document gets to a certain point in this situation it creates
		 a child document which reads bytes from its file.

Protected members
	 HFILE FHdl;  // file handle if held open at the document level
	 HFILE OpenThisFile(int omode, const char far* name, streampos* pseekpos);
		 3) You can call this if you redefine Open() and don't want to call the
		 original Open().  THIS IS NOT VIRTUAL, SO DON'T SUBCLASS IT!
	 void  CloseThisFile(HFILE fhdl, int omode);
		 3) You can call this if you redefine Close() and don't want to call the
		 original Close().  THIS IS NOT VIRTUAL, SO DON'T SUBCLASS IT!

//==============================================================================
// TEditSearch  TView
//     |          |
//      ----------
//          |
//      TEditView
//==============================================================================
3) This class does basically the same thing that TListView does, except it does
it with TEditSearches instead of TListBoxes, so you get nice Find/Next dialogs
and stuff.  Use this only if you are writing an editor or something...

//==============================================================================
// TEventHandler TStreamableBase
//       |             |
//        -------------
//              |
//         TDocManager
//==============================================================================
1) TDocManager creates a document manager object that manages the list of
current documents and registered templates, handles standard file menu commands,
and displays the user-interface for file and view selection boxes. To provide
support for documents and views, an instance of TDocManager must be created by
the application and attached to the application.

The document manager normally handles events on behalf of the documents by using
a response table to process the standard CM_FILENEW, CM_FILEOPEN, CM_FILECLOSE,
CM_FILESAVE, CM_FILESAVEAS, and CMVIEWCREATE File menu commands. In response to
a CM_FILENEW or a CM_FILEOPEN command, the document manager creates the
appropriate document based on the user's selections. In response to the other
commands, the document manager determines which of the open documents contains
the view associated with the window that has focus. The menu commands are first
sent to the window that is in focus and then through the parent window chain to
the main window and finally to the application, which forwards the commands to
the document manager.

When you create a TDocManager or a derived class, you must specify that it has
either a multi-document (dmMDI) or single-document (dmSDI) interface. In
addition, if you want the document manager to handle the standard file commands,
you must OR these with dmMenu.

You can also enable or disable the document manager menu options by passing
dmSaveEnable or dmNoRevert in the constructor. If you want to enable the
File|Save menu option if the document is unmodified, pass the dmSaveEnable flag
in the constructor. To disable the "Revert to Saved" menu option, pass
dmNoRevert in the constructor.

When the application directly creates a new document and view, it can attach the
view to its frame window, create MDI children, float the window, or create a
splitter.  However, when the document manager creates a new document and view
from the File|Open or File|New menu selection, the application doesn't control
the process. To give the application control, the document manager sends
messages after the new document and view are successfully created. Then, the
application can use the information contained in the template to determine how
to install the new document or view object.

TDocManager and derived classes can be created to support specialized needs such
as an OLE 2.0 server.

3) The code for the document manager is pretty nasty.  It is really unclear why
Borland put all that user interface stuff into it if they intended it to be used
as the base class for OLE servers and such, instead of having an abstract doc
manager and a 'normal' one.  It shouldn't be too hard to subclass the manager to
change some small thing about it, such as using BWCC message boxes for errors
and such, but I wouldn't want to rewrite it that is for sure...

public members:
    TDocument::List DocList;      // list of attached documents
    TDocManager(int mode,TDocTemplate*& templateHead = DocTemplateStaticHead);
       1) Constructs a TDocManager object that supports either single (SDI) or
       multiple (MDI) open documents depending on the application. mode is set
       to either dmMenu, dmMDI, dmSDI, dmSaveEnable, or dmNoRevert. To install
       the standard TDocManager File menu commands, you must OR dmMDI or dmSDI
       with dmMenu. For example,
          DocManager = new TDocManager(DocMode | dmMenu);
       The document manager can then use its menu and response table to handle
       these events. If you do not specify the dmMenu parameter, you must
       provide the menu and functions to handle these commands. However, you
       can still use your application object's DocManager data member to access
       the document manager's functions.
       3) The help doesn't document the second parameter, templateHead.
       The first TDocManager created gets all of the already existing "static"
       templates, and sets templateHead to 1, so that if a second document
       manager is created it DOESN'T GET ANY TO OWN ANY TEMPLATES UNLESS THEY
       ARE IN A LIST AND THE HEAD IS EXPLICITLY PASSED IN.  All of the
       templates have their document manager set to this document manager.
    virtual ~TDocManager();
    virtual TDocument*  CreateAnyDoc(const char far* path, long flags = 0);
       1) Creates a document based on the directory path and the specified
       template. flags, one of the document view constants, determines how the
       document template is created. If path is 0 and this is not a new document
       (the flag dtNewDoc is not set), it displays a dialog box. If path is 0,
       dtNewDoc is not set, and more than one template exists, it displays a
       dialog box and a list of templates.
       3) If flags is dtNewDoc, bring up the menu of visible document types
       using SelectDocType(), otherwise brings up a file open dialog with
       SelectDocPath().  After it has figured out which template to use, returns
       the template's CreateDoc(filepath, flags).
    virtual TView*      CreateAnyView(TDocument& doc,long flags = 0);
       1) Creates a document view based on the directory path and specified
       template.  flags, one of the document view constants, determines how the
       document template is created.
       2) selects from registered templates supporting this doc
       3) Calls SelectViewType() from the templates supporting this doc, if a
       template is selected calls the template's CreateView().  The flags are
       just passed in to CreateView() which ignores them, they are supposed to
       be the dtxxxx flags.

    virtual TDocTemplate* SelectAnySave(TDocument& doc, BOOL samedoc = TRUE);
    virtual TDocTemplate* MatchTemplate(const char far* path);
    virtual TDocument*  GetCurrentDoc();  // return doc with focus, else 0
    virtual BOOL        FlushDoc(TDocument& doc); // attempt to update changes
    TDocument*          FindDocument(const char far* path); // 0 if not found
    TApplication*       GetApplication() {return Application;}
    BOOL                IsFlagSet(int flag) {return (Mode & flag) != 0;}
    void                RefTemplate(TDocTemplate&);    // add template ref
    void                UnRefTemplate(TDocTemplate&);  // drop template ref
    void                DeleteTemplate(TDocTemplate&); // remove from list
    void                AttachTemplate(TDocTemplate&); // append to list
    TDocTemplate*       GetNextTemplate(TDocTemplate* tpl)
                        {return tpl ? tpl->NextTemplate : TemplateList;}

    // primary event handlers, public to allow direct invocation from app
    //
    virtual void CmFileOpen();
       3) Just calls CreateAnyDoc(0, 0);
    virtual void CmFileNew();
       3) Just calls CreateAnyDoc(0, dtNewDoc);
    virtual void CmFileClose();
       1) Responds to a file close message. Tests to see if the document has
       been changed since it was last saved, and if not, prompts the user to
       confirm the save operation.
       3) Calls the current document's CanClose(), it the document can close
       calls Close(), if Close() returns TRUE deletes the document.
    virtual void CmFileSave();
       1) Responds to a file save message. Set doc to the current document.
       Calls IsDirty and returns IDS_NOTCHANGED if the document hasn't been
       changed since the last time it was saved.
       3) If the document doesn't have a path (created with CmFileNew()),
       calls CmFileSaveAs().  If the document has a path, does the checking
       described above and saved the document with it's Commit().
       NOTES: The "doc" referred to in the help is a local variable of
       CmFileSave() that isn't accessible or meaningful.  The IDS_NOTCHANGED
       isn't returned, as the function is void.  It is submitted to
       PostDocError(), but you should never encounter this, as the private
       command enablers keep options that will trigger errors dim on the menu.
    virtual void CmFileSaveAs();
       1) Prompts the user to enter a new name for the document.
       3) Finds the current document, calls SelectAnySave() to figure out the
       file name and template to use for saving, then call's the document's
       Commit() with TRUE to force writing.
    virtual void CmFileRevert();
       1) Reverts to the previously saved document.
       3) Call's the document's Revert() method if the document IsDirty(),
       if the document isn't it will trigger a PostDocError() message.
    virtual void CmViewCreate();
       1) Responds to a view create message by creating a document view based
       on the specified directory path.
       3) Calls CreateAnyView(*doc), to create a new view for this document.

    // overrideable document manager UI functions
    //
    virtual UINT  PostDocError(TDocument& doc, UINT sid, UINT choice = MB_OK);
       1) Displays a message box with the error message passed as a string
       resource ID in sid. By default, the message box contains either an OK
       push button or a question mark icon. If an error message can't be found,
       PostDocError displays a "Message not found" message. choice can be one
       or more of the Windows MB_Xxxx style constants. See the Windows API
       online Help for a description of the values. This function can be
       overridden.

    virtual void  PostEvent(int id, TDocument& doc); // changed doc status
       1) If the current document changes, calls ::SendMessage and
       passes a WM_OWLDOCUMENT message to indicate a change in the status of
       the document.

    virtual void  PostEvent(int id, TView& view);    // changed view status
       1) If the current view changes, calls ::SendMessage and passes a
       WM_OWLVIEW message to indicate a change in the status of the view.
       3) The ids appear to be dnxxxx message constants.

    1) TDocManager uses the dnxxxx message constants to indicate that a
    document or view has been created or closed. You can set up response
    table entries for these messages using the EV_OWLVIEW or EV_OWLDOCUMENT
    macros.

       Constant	Meaning
       dnCreate	A new document or view has been created.
       dnClose	   A document or view has been closed.

    3) An application uses recieves these dnxxxx events by putting in a
    response table something like this, from the docviewx example:
       EV_OWLVIEW(dnCreate, EvNewView),
       EV_OWLVIEW(dnClose,  EvCloseView),
    Now, EvNewView and EvCloseView are not defined in the header file for
    TApplication, the names are just placeholders, but these are the names
    generated by the AppExpert for Doc/View programs.  In a standard Doc/View
    program, the EvNewView either (mdi) creates a new mdi child and puts the
    view as the child's client or (sdi) puts the new view as the main window's
    client.  The docviewx example program uses this to modify the menu, as
    well.  EvCloseView does nothing under mdi, as mdi takes care of it,
    under sdi it should set the main window's client to 0, and can alter the
    menu, title, etc.


    // delegated methods from TApplication
    //
    void EvPreProcessMenu(HMENU hMenu);
       1) Called from MainWindow, EvPreProcessMenu loads and deletes a menu at
       the position specified by MF_POSITION or MF_POPUP.  Your application can
       call EvPreProcessMenu to process the main window's menu before it is
       displayed.
       3) Called by TApplication::PreProcessMenu(HMENU fmenu) if there is a
       document manager, using WM_OWLPREPROCMENU.  TApplication::PreProcessMenu
       is called by TFrameWindow::MergeMenu(const TMenuDescr& childMenuDescr)
       and TFrameWindow::AssignMenu(TResId menuResId).

    BOOL EvCanClose();
       1) Checks to see if all child documents can be closed before closing the
       current document. If any child returns FALSE,  returns FALSE and aborts
       the process. If all children return TRUE, EvCanClose calls
       TDocManager::FlushDoc for each document. If FlushDoc finds that the
       document is dirty, it displays a message asking the user to save the
       document, discard any changes, or cancel the operation. If the document
       is not dirty and EvCanClose returns TRUE, EvCanClose returns TRUE.
       3) Called by TApplication::CanClose(), using WM_OWLCANCLOSE.

    void EvWakeUp();
       3) This undocumented member calls ReindexFrames() for each document.
       This member is bound to the message WM_OWLWAKEUP which is send by OWL
       to the application during TDocManager::Streamer::Read(), so that
       document managers can be streamed in from disk.

protected members:
    // overrideable document manager UI functions
    //
    virtual int   SelectDocPath(TDocTemplate** tpllist, int tplcount,
                     char far* path, int buflen, long flags, BOOL save=FALSE);
       1) Prompts the user to select one of the templates to use for the file
       to be opened. Returns the template index used for the selection or 0 if
       unsuccessful. For a file open operation, save is FALSE. For a file save
       operation, save is TRUE. This function can be overridden to provide a
       customized user-interface.
       3) Uses the file common dialogs directly, not the OWL versions.
    virtual int   SelectDocType(TDocTemplate** tpllist, int tplcount);
       1) SelectDocType, which can be overridden, lets the user select a
       document type from a list of document templates. Returns the template
       index used for the selection or 0 if unsuccessful.
       3) Uses a private TPickList class for this which makes a popup menu
       below the mouse cursor.
    virtual int   SelectViewType(TDocTemplate** tpllist, int tplcount);
       1) SelectViewType, which can be overridden, lets the user select a view
       name for a new view from a list of view names. Returns the template
       index used for the selection or 0 if unsuccessful.
       3) (Same as above)

3) There are private members for all of the Cmxxx members:
    virtual void CmEnableNew(TCommandEnabler& hndlr);
    virtual void CmEnableOpen(TCommandEnabler& hndlr);
    virtual void CmEnableSave(TCommandEnabler& hndlr);
    virtual void CmEnableSaveAs(TCommandEnabler& hndlr);
    virtual void CmEnableRevert(TCommandEnabler& hndlr);
    virtual void CmEnableClose(TCommandEnabler& hndlr);
    virtual void CmEnableCreate(TCommandEnabler& hndlr);
These members dim illegal menu choices.

//==============================================================================
//  TStreamableBase
//        |
//    TDocTemplate
//        |
// TDocTemplateT<D, V>
//==============================================================================
1) TDocTemplate is an abstract base class that contains document template
functionality. TDocTemplate classes create documents and views from resources
and handle document naming and browsing. The document manager maintains a list
of the current template objects. Each document type requires a separate document
template.

3) Ok, when AppExpert made your program, it set up something like this:

DEFINE_DOC_TEMPLATE_CLASS(TFileDocument, TWindowView, DocType1);
DocType1 __dvt1("All Files (*.*)", "*.*", 0, "TXT", dtAutoDelete | dtUpdateDir);

This is called a document template.

*  NOTE: This has nothing to do with C++ templates!

DEFINE_DOC_TEMPLATE has three parameters: docClass, viewClass, and tplClass.
If you are used to the container classes, this is kind of like an association,
it is saying that there is a type "DocType1".  It might be more readable like
this:

DEFINE_A_TYPE_OF_VIEW(TfooDocument, TbarWindowView, TfoobarDocViewPair);
TfoobarDocViewPair dummy("All Files (*.*)", "*.*", 0, "TXT", dtAutoDelete |
																						 dtUpdateDir);

Where 'foo' is your own special I/O routines for saving whatever kind of objects
your document holds, and 'bar' is your viewer class.  Sometimes you want more
than one viewer class, like in the line drawing example there was a graphical
viewer and a text viewer, so there were two DEFINE_DOC_TEMPLATE_CLASSes and
__dvts. You can have as many as you want.  When you select "Window|Add View" you
get a menu of the StaticName()s off all views which have the same document class
as the current view.

DEFINE_DOC_TEMPLATE_CLASS is supposed to hide from you a bunch of code that it
writes that creates a TDocTemplateT<D,V>.  While most of the Doc/View stuff
becomes clearer when you look at the code, TDocTemplateT<D,V> doesn't, so just
use the macro.

The strings in the template define what will appear in the common dialog when
a file is being opened.  The dtxxxx flags are discussed below.

TDocTemplate public members:
    virtual TDocument* CreateDoc(const char far* path, long flags = 0) = 0;
    virtual TView*     CreateView(TDocument& doc, long flags = 0) = 0;
    virtual TDocument* IsMyKindOfDoc(TDocument& doc) = 0;
    virtual TView*     IsMyKindOfView(TView& view) = 0;
    virtual const char far* GetViewName() = 0;
    BOOL               SelectSave(TDocument& doc);
    BOOL               IsVisible();     // displayable in file select dialogs
    virtual TDocTemplate* Clone(TModule* module,
                                TDocTemplate*& phead=DocTemplateStaticHead)=0;
    TDocManager*    GetDocManager() const {return DocManager;}
    void            SetDocManager(TDocManager* dm) {DocManager = dm;}
    const char far* GetFileFilter() const {return FileFilter;}
    void            SetFileFilter(const char far*);
    const char far* GetDescription() const {return Description;}
    void            SetDescription(const char far*);
    const char far* GetDirectory() const {return Directory;}
    void            SetDirectory(const char far*);
    void            SetDirectory(const char far*, int len);
    const char far* GetDefaultExt() const {return DefaultExt;}
    void            SetDefaultExt(const char far*);
    long            GetFlags() const {return Flags;}
    BOOL            IsFlagSet(long flag) {return (Flags & flag) != 0;}
    void            SetFlag(long flag)  {Flags |= flag;}
    void            ClearFlag(long flag){Flags &= ~flag;}
    BOOL            IsStatic() {return (RefCnt & 0x8000) != 0;}
    TModule*&       GetModule() {return *ModulePtr;}
    void            SetModule(TModule* module){ModuleDeref = module;
                                              ModulePtr = &ModuleDeref;}

TDocTemplate protected members:
    TDocTemplate(const char far* desc, const char far* filt,
                 const char far* dir,  const char far* ext, long flags,
                 TModule*& module, TDocTemplate*& phead);
       1) Constructs a TDocTemplate with the specified file description (desc),
       file filter pattern (filt), search path for viewing the directory (dir),
       default file extension (ext), and flags representing the view and
       creation options (flags). Sets Description to desc, FileFilter to filt,
       Directory to dir, DefaultExt to ext, and Flags to flags. Then, adds this
       template to the document manager's template list. If the document
       manager is not yet constructed, adds the template to a static list,
       which the document manager will later add to its template list.
       3) This constructor is private because it is expected that
       TDocTemplateT<D, V> will be used to construct the template.  In fact, it
       is TDocTemplateT<D, V>'s constructor that passes around the static list,
       TDocTemplate doesn't know about the static list.
   ~TDocTemplate();
    TDocument* InitDoc(TDocument* doc, const char far* path, long flags);
    TView*     InitView(TView* view);

TDocTemplateT<D, V> public members:
    TDocTemplateT(const char far* filt, const char far* desc,
                  const char far* dir, const char far* ext, long flags = 0,
                  TModule*& module = ::Module,
                  TDocTemplate*& phead = DocTemplateStaticHead);
       3) Just calls TDocTemplate's constructor.
    TDocTemplateT* Clone(TModule* module,
                         TDocTemplate*& phead = DocTemplateStaticHead);
    D* CreateDoc(const char far* path, long flags=0);
    TView* CreateView(TDocument& doc, long flags=0);
       1) CreateView creates the view specified by the document template class.
       3) The flags are the dtxxxx flags, but are ignored.  The code is:
             return (V*)InitView(new V((D&)doc));
          which basically is a type save encapsulation of calling InitView()
          with the result of calling the view's constructor.
    D* IsMyKindOfDoc(TDocument& doc);  // returns 0 if template can't support
    V* IsMyKindOfView(TView& view);    // returns 0 if template incompatible
    virtual const char far* GetViewName() {return V::StaticName();}

//==============================================================================
// Common Pitfalls with Doc/View
//==============================================================================

o Thinking the Class Expert is some kind of 'expert'

		Class Expert might know a lot about dialogs and such, but it doesn't
	know much about Doc/View and if you think it does you will make certain
	common errors:

		1. Class Expert makes you think you want to derive from TListView.  You
			probably don't.
		2. Class Expert doesn't know about multiple inheritence.  You are
			going to be using multiple inheritence if you are using something like
			a list box that isn't a TWindow.  Get used to only seeing a few
			functions for your class even when there are actually dozens.
		3. Class expert doesn't know about StaticName(), because it is not
			virtual.
		4. Class expert doesn't know about the EV_VN_ notifications.
		5. The code class expert will write for you often doesn't make any sense.
			for example, it will always put in a call to the base class's
			GetViewName().  You want to make sure you know what the call to the
			base class is doing.

o Expecting TFileDocument to ACTUALLY DO some I/O

		I/O is done by TInStream and TOutStream classes.  TFileDocument knows two
	things:  How to open and close files, and how to create those streams.  The
	actual I/O is going to be done by either a TDocument descendent or a
	TView descendent.  TFileDocument isn't going to be doing any I/O.

o Why doesn't my Open() routine get called to read in my data?

		The document manager is lazy, it doesn't open your document.  Why?  Well
	lets say you are writing the Borland C++ IDE with Doc/View.  Now, you are
	going to need the .IDE, the .EXE (for debugging and browsing) and the .APX
	(for Class Expert) when a project is opened up.  But loading in the whole
	.EXE might be a waste, so the system waits until it needs it.  If you look
	at the line drawing example it does this to show you how to do it, although
	you don't get an actual benefit out of it in this case.  (I'm not sure though
	if you wouldn't model a system like the C++ IDE with the .IDE file being a
	parent document, and the .EXE and .APX being children though...)

o Ok, I have a really nicely designed class heirarchy for the objects in my
view container, and I can write them out but not read them in.  Why?

		TInStream and TOutStream are for writing out structs, not objects.  All
	of the type information falls off your class as you write it to disk.  You
	either need to prepend a word of type information before writing and look
	up the word in a table to call the correct constructor, or you need to use
	Borland's pstream, which do that for you.  However, pstreams being what they
	are they don't mix well with regular streams.  (You don't have to worry
	about this if you are writing out all of the same kind of object together,
	like the lines in the drawing example.)

o How do I know whether I want to be holding the data in the document or the
view?

		First, do an experiment.  Bring up the DOCVIEW example, and create a new
	line document.  Set your pen to something thick, like 50, and draw some lazy
	meandering lines.  Then use Window|Add View to add two copies of the view,
	and a single copy of line list view.  Tile the windows, and then draw another
	line.  Changes go to all of the views nicely.  Then go to the line list view
	and change the color of a line.  There is an ugly redraw.

		In this case, the ugly redraw is unavoidable, because we changed the line
	and we want to see the change in all of the views.  There is no way to "un-
	draw" a line easily.  What you want to do is to make sure that you don't get
	this symptom unneccessarily.  Keeping the data in the view keeps the system
	fast, but people like to be able to work on a single document in several
	different ways at the same time.

o When I close a view, it is telling me I need to save the document when the
view is not the last open view.  Why?

		You copied the CanClose() member from the line drawing example:
			BOOL CanClose() {return TListBox::CanClose() && Doc->CanClose();}
		This bit of code asks the document if it can close when the view closes,
		even though the document is not going to close.  If your view doesn't
		hold any data, you don't want to call TDocument::CanClose() unless you
      are the _last_ view on the screen:
      BOOL CanClose()
       { return TListBox::CanClose() &&
         (Doc->NextView(this) || Doc->NextView(0) != this || Doc->CanClose()); }

o Where are those document titles coming from?  Does SetDocTitle do ANYTHING?

	  Uh, no.   SetDocTitle doesn't do anything except call the parent document,
	  and there is rarely one of those.  The only SetDocTitle() in OWL that does
	  anything interesting is the one in TFrameWindow, and that one is not in the
	  help.  What it does is takes the frame's title, the document name, and the
	  index number, and make a window caption.  If you want to set the frame's
	  title, you can do it in TMyApp::EvNewView by replacing the call to your
	  MDI child constructor with something like this:

		  TMyMDIChild* child = new TMyMDIChild(*mdiClient,
															view.GetViewName(), // caption
															view.GetWindow());

o I have made my own list view, and there is an annoying line at the bottom of
the view.

     You forgot to set the style bits of your listbox, and it is trying to
     maintain an integral height.  TListView uses the following modifications
     to the style bits:

        Attr.Style &= ~(LBS_SORT);
        Attr.Style |= (WS_HSCROLL | LBS_NOINTEGRALHEIGHT);

o I like the way the menu changes automatically in the docview example program,
but I can't seem to get my menus to do this.

     Changing the menus is your code's job, not the document manager's.  In
     your EvNewView() member you want to add the following code before the call
     to setting the icon:

        if (view.GetViewMenu())
           child->SetMenuDescr(*view.GetViewMenu());

     This of course assumes that you are setting the view menu up correctly in
     the constructor for your view.


o I need to be able to deal with errors in input and not open documents that
are corrupt.

     The standard way to not open a document is to return FALSE in ::Open().
     However, that will not work unless you have the dtAutoOpen flag set, you
     will end up with an empty view instead of the "could not open document"
     message.

     dtAutoOpen set up, you can display your own MessageBox and return TRUE if
     you want to accept the part of the file you could read, or FALSE if you
     want to fail the open.

     If you need to throw exceptions when you fail, you probably want to catch
     them and return false so that your objects get cleared up correctly.  The
     following seems to work inside open (you need a TRY, too):

       CATCH( (xmsg& x)
          {
          GetDocManager().GetApplication()->Error(x, 0, 0);
          return FALSE;
          }
       )

     Not clearing up objects can cause the document manager to refuse to try to
     load them again if you aren't using dtAutoOpen.

o My views menu items work fine, but for some reason the document manager has
disabled File|Close and Window|Add View.  (I'm deriving from TView.)

     You have to write a VnIsWindow member AND you must put a EV_VN_ISWINDOW
in the response table.  If you don't the document manager thinks that your
view isn't the active view, even when it has the focus.

o Well, I have an EV_VN_ISWINDOW, and it still isn't working.

     If your view has controls on it (for example if you are deriving from
     TView and TDialog), the example VnIsWindow will not work for you, because
     the document manager is passing around the window with the focus, and you
     have given the focus to a control.  Try this:

     BOOL TMyDialog::VnIsWindow(HWND hWnd)
     {
        return ((HWindow == hWnd) || IsChild(hWnd));
     }

o I want different icons for each kind of view.

     I haven't found a clean way to do this, although a property could probably
     take care of it.  In your EvNewView(), set the icon based upon the view
     class:

        if (TYPESAFE_DOWNCAST(&view, TAlphaView))
           child->SetIcon(this, IDI_ALPHA);
        else if (TYPESAFE_DOWNCAST(&view, TBetaView))
           child->SetIcon(this, IDI_BETA);
        else if (TYPESAFE_DOWNCAST(&view, TGammaView))
           child->SetIcon(this, IDI_GAMMA);

o I'm using a dialog box for a view, and it's getting a thick sizing frame
  about it, and the initial size is wrong.

     In your EvNewView, check for TDialog descendents:
        BOOL fIsDialog = (TYPESAFE_DOWNCAST(&view, TDialog)) ?
           TRUE : FALSE;

        myMDIChild* child = new myMDIChild(*mdiClient,
           view.GetViewName(), // caption
           view.GetWindow(),
           fIsDialog);

     (This sets the frame to shrink to the view's initial size.)

        if (fIsDialog)
           child->Attr.Style &= ~(WS_THICKFRAME|WS_MAXIMIZEBOX);

     (This makes the frame look like a modeless dialog's frame.)


//==============================================================================
// Appendex 1
// Modes:
//==============================================================================
1) This enum defines the document and open sharing modes used for constructing
streams and storing data. Any constants that have the same functionality as
those used by OLE 2.0 docfiles are indicated in the following table; for
example, STGM_TRANSACTED, STGM_CONVERT, STGM_PRIORITY, and STGM_DELETEONRELEASE.
Although files are typically used for data storage, databases or spreadsheets
can also be used. I/O streams rather than DOS use these bit values. Documents
open the object used for storage in one of the following modes:

Constant		Meaning
ofParentA		A storage object is opened using the parent's mode.
ofRead			A storage object is opened for reading.
ofWrite			A storage object is opened for writing.
ofReadWrite		A storage object is opened for reading and writing.
ofAtEnd			Seek to end-of-file when opened originally.
ofAppend			Data is appended to the end of the storage object.
ofTruncate		An already existing file is truncated.
ofNoCreate		Open fails if file doesn't exist.
ofNoReplace		Open fails if file already exists.
ofBinary			Data is stored in a binary, not text, format. Carriage returns
					are not stripped.
ofIosMask		All of the above bits are used by the ios class.

ofTransacted	Changes to the storage object are preserved until the data is
					either committed to permanent storage or discarded.
					(STGM_TRANSACTED)
ofPreserve		Backs up previous storage data using before creating a new
					storage object with the same name. (STGM_CONVERT)
ofPriority		Supports temporary, efficient reading before opening the storage.
					(STGM_PRIORITY)
ofTemporary		The storage or stream is automatically destroyed when it is
					destructed. (STGM_DELETEONRELEASE)

3) These modes use used all over the place by the TDocument descendents and the
document manager to figure out what it is supposed to be doing.  So, when you
look at a function, you have to figure out not only where it is called from and
when it is called, but what modes were passed into it.  My assumption is that
all of this extra work is so that OLE and OpenDoc servers can be run by the
current document manager...

//==============================================================================
// Appendex 2
// Template constants
//==============================================================================
1) dtxxxx constants are used by TDocument and TDocTemplate to create templates.
Several constants are equivalent to the OFN_xxxx constants defined by Windows in
commdlg.h.

Constant				Windows equivalent	Meaning
dtAutoDelete									Deletes the document when the last view
													is deleted.
													3) This has nothing to do with deleting
													the FILE the document was from.  This
													flag causes the document manager to shut
													down the TDocument descendent when the
													last view for that document is closed.
													Otherwise it hangs around until the
													app is closed.
dtAutoOpen										Opens a document upon creation.
													3) The TDocument's Open() member is
													called by the document manager after it
													creates the document in CreateAnyDoc().
                                       ***THIS IS HOW YOU AVOID HAVING TO PUT
                                       THE CALL TO ISOPEN() AND OPEN() IN YOUR
                                       PAINT() ROUTINE!************************
dtCreatePrompt		(OFN_CREATEPROMPT)	Prompts the user before creating a
													document that does not currently exist.
dtFileMustExist	(OFN_FILEMUSTEXIST)	Lets the user enter only existing file
													names in the File Name entry field. If an
													invalid file name is entered,
													causes a warning message to be displayed.
dtHidden											Hides the template from the user's
													selection.
													3) What this means is that this doc/view
													PAIR will not be available from the
													File|New or File|Open choices on the
													menu.  An example of this is the draw
													listbox which could only be created
													through Window|Add View, you couldn't
													load a .PTS file directly into one.
													You use this if you have more than one
													view for a document type, you make all
													of the non-primary views HIDDEN.
dtHideReadOnly		(OFN_HIDEREADONLY)	Hides the read-only check box.
dtNewDoc											Creates a new document with no path
													specified.
													3) This flag is passed into the document
													manager when you want to create an empty
													of the kind of document, such as with
													File|New.
dtNoAutoView									Does not automatically create the default
													view type.
													3) Not quite sure what this is to be used
													for.  It keeps the view from opening up
													when you open up the file.  I think this
													is so you can do things like emulate the
													IDE where you can open up a project and
													no windows come up if you didn't have
													any open when you last closed the
													project.
dtNoReadOnly	(OFN_NOREADONLYRETURN)	Returns the specified file as writeable.
dtNoTestCreate	(OFN_NOTESTFILECREATE)	Does not perform document-creation tests.
													The file is created after the dialog box
													is closed. If the application sets this
													flag, there is no check against write
													protection, a full disk, an open drive
													door, or network protection.  For certain
													network environments, this flag should be
													set.
dtOverwritePrompt	(OFN_OVERWRITEPROMPT)When the Save As dialog box is displayed,
													asks the user if it's OK to overwrite the
													file.
dtPathMustExist	(OFN_PATHMUSTEXIST)	Allows only valid document paths to be
													entered. If an invalid path name is
													entered, causes a warning message to be
													displayed.
dtProhibited	(OFN_ALLOWMULTISELECT)	Doesn't support these specified
					(OFN_ENABLEHOOK)			Windows options.
					(OFN_ENABLETEMPLATE)
					(OFN_ENABLETEMPLATEHANDLE)
dtReadOnly		(OFN_READONLY)				Checks the read-only check box when the
													dialog box is created.
dtSelected										Indicates the last selected template.
													3) This is for if you have more than one
													type of document or view.  When you
													define your views, you want one view to
													have this bit set.  This is the view
													that will initially come up in the
													"Type of File" part of the common dialog
													and will give you your initial default
													extension.  When you open a document,
													the document manager marks that view as
													dtSelected and clears the other one,
													this lets the common dialog have the
													same kind of default when you bring it
													up to open another document later.
dtSingleView									Provides only a single view for each
													document.
dtUpdateDir										Updates the directory with the dialog
													3) if you mark all of your templates with
													this, then when the common dialog is
													brought up for another file, it starts
													in the same directory as the last view,
													instead of the current default directory.
													(In other words, it updates the document
													manager's CURRENT directory variable, it
													doesn't write anything to an MS-DOS
													directory.)

(All of the OFN_ flags relate to common dialog stuff.  Look at the common dialog
information in your help text.)

//==============================================================================
// Appendex 3
// Property flags
//==============================================================================
pfGetText	Property is accessible in a text format.
pfGetBinary	Property is accessible as a native nontext format.
pfConstant 	Property can't be changed for the object instance.
pfSettable	Property can be set as a native format.
pfUnknown	Property is defined but unavailable for the object.
pfHidden 	Property should be hidden from the user during normal browsing.
pfUserDef 	Property has been user-defined at run time.

Should you decide to use properties, here they are...  Properties are pretty
simple.

//==============================================================================

Regarding copyright, assume that everthing marked with a 3) is public domain.
I'm hoping everything marked with a 1) or a 2) is considered fair-use of
Borland's copyrighted works...
