SECComDoc: Communication Document
Figure 142 shows the SECComDoc hierarchy. As the hierarchy suggests, to add ComDoc capabilities to your document, you only need to change its derivation from CDocument to SECComDoc.
Figure 142 – Hierarchy of SECComDoc and your derived document
SECComDoc builds upon the basic CDocument by adding several new functions and overloading other functions. SECComDoc holds and maintains a linked list of pointers to child documents and, when functioning as a child itself, maintains a pointer to its parent. Figure 143 shows the document linking variables.
Figure 143 – SECComDoc's document linking member variables
The m_DocLinkList member keeps a list of all other documents that are attached to it. The only real limits to the number of documents that may be managed are memory and disk space.
The life cycle and functions of a communication document are described in the remainder of this section.
Stages in the Life of an SECComDoc
This section describes the linking system and its various phases of operation. Figure 144 shows a new ComDoc. In phase 1 of a ComDoc's lifetime, it behaves like a simple CDocument class.
Figure 144 – A New ComDoc
Figure 145 shows phase two of a ComDoc's lifetime. CMyComDoc has invoked two child documents and has added pointers to them to the linked list. The list of children may be augmented at any time. Furthermore, child documents may be deleted without effecting the data links to the other documents. Child documents have their own document-linking lists and can also invoke and link their own children. Data is passed by direct function calls to child documents and from child documents to the parent.
Figure 145 – A parent document with links to child documents
The sample application, MultiGrph, uses this ComDoc system to link Objective Grid documents to Objective Chart documents. In this example, the user may invoke one or more linked charts from the grid. Then, any changes made to the grid data are also reflected in all of the charts that are linked to the parent grid document. Furthermore, thanks to a link from child to parent, any data items dragged by the user on a chart also update the grid cells in the parent document, which updates all the other charts.
Figure 146 shows the final phase of the ComDoc's life—when the parent document is destroyed. The links are automatically broken, leaving autonomous and independent child documents.
Figure 146 – The parent document is destroyed
Communication Between ComDocs
Because m_DocLinkList and m_Parent keep pointers to documents, it is possible to call functions within the document, but the derived documents may potentially be of unknown types. Therefore, unless you use RTTI or add huge amounts of code for verifying the document type by its RUNTIME_CLASS information, the only universally available functions are the virtual functions in CDocument or SECComDoc.
SECComDoc's document link architecture is a true MFC solution. Messages are passed directly to the document via a function call. The function call system has been made simple, flexible, and easily expanded so that it can be adapted to any document. Once the child document has been created and linked (see SECDocManager later in this document), a single function call to an SECComDoc virtual function is all that is required to transfer information between documents.
SECComDoc uses a single function that utilizes integer codes for various commands. The function prototype is:
BOOL SECComDoc::ProcessDocumentCommand\
(UINT nOpCode,UINT nSubCode,DWORD dwData)
The nOpCode parameter specifies the basic type of operation to perform. Your document can handle the four built-in op-codes that it inherits from SECComDoc. These four op-codes are:
*SEC_NOOP— Does nothing at this time, but is reserved by Stingray.
*SEC_CLIPBOARD_TEXT— Signifies that a document may find text data on the clipboard with which to initialize itself.
*SEC_GMEM_INIT— Signifies that initialization data is in a shared global memory block, the handle of which is supplied in the dwData parameter.
*SEC_DOC_UPDATE— Indicates that some change has taken place. The values of the sub-code and dwData parameters can be used to indicate what has changed and what the document should do about it.
NOTE >> You can add your own op-codes by claiming any value above SEC_USER_COMMAND. You may also override the virtual function SECComDoc::ProcessUserCommand() to handle your own codes. SECComDoc::ProcessUserCommand processes inputs from the user and distributes your accompanying tasks to the system.
Each of these commands, except SEC_NOOP, calls dead-ended virtual functions within SECComDoc. To make them perform a useful function, you must override them in your descendant document.
The interpretation of the nSubCode parameter is completely open for your own purposes.
The interpretation of the dwData parameter is only fixed when sent with the SEC_GEM_INIT command. In this case, dwData should always be an HGLOBAL for a valid memory block cast to a DWORD. All other interpretations are open-ended.
Apart from the code that manages the links, there is one significant addition to the standard CDocument functions. The prototype for this is shown below.
BOOL SECComDoc::OnOpenDocument(
UINT nOpCode, UINT nSubCode, DWORD dwData)
As you can see, this allows a document to be opened and provided immediately with some initialization data. The syntax is compatible with the parameters discussed in the previous section. In fact, this routine calls OnNewDocument() and then calls ProcessDocumentCommand() with the given parameters.
Once the document has invoked and linked to the child documents (there may be more than one), the parent can inform all children of changes by using the UpdateLinkedDocuments() command. This function iterates all documents in the list and performs an update on each of them.
When used as a child document, the SECComDoc class may inform the parent of changes in its own data by using the UpdateParentDocument() command. This function sets a flag that signifies that incoming updates from the parent should be ignored temporarily. It then performs a document update on the parent. The semaphore keeps the two documents from becoming locked in an endless cycle of mutual updates.
Objective Chart provides an SECComDoc-derived document class, named CGraphDoc. CGraphDoc implements the several sub-functions of ProcessDocumentCommand() to perform common functions related to chart data.
CGraphDoc::GmemInit() can initialize the chart in two ways. A pointer to a character string containing the name of a text template file can be passed in the nSubCode parameter. Alternatively, an HGLOBAL of a memory block containing tab-delimited data can be passed in the dwData parameter.
CGraphDoc::SecDocUpdate() defines specific sub-codes for the SEC_DOC_UPDATE command for the following chart related actions:
Table 23 – Sub-Codes for SEC_DOC_UPDATE 
Changes values in the data array.
Updates the annotation of a data object or a group header.
Sets/resets the highlight flag in the style of a data object.
Alters the data scope of a display component.
These definitions should not be thought of as absolute rules. You are free to invent your own sub-codes. Just remember that if you use CGraphDoc, you must use codes that act in harmony with, or do not collide with, those already chosen.
When used with a CGraphDoc document, the Objective Chart view classes, SRGraphView and SRGScrollView, call pDoc->UpdateParentDocument() when data objects are dragged by the mouse. This allows data values to be updated in the parent document and all linked documents.