lmi
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lmi] Child documents [Was: Adding open files to MDI "Window" menu]


From: Greg Chicares
Subject: [lmi] Child documents [Was: Adding open files to MDI "Window" menu]
Date: Thu, 20 Mar 2008 22:30:40 +0000
User-agent: Thunderbird 2.0.0.12 (Windows/20080213)

On 2008-03-14 16:58Z, Vadim Zeitlin wrote:
> On Sat, 08 Mar 2008 16:41:31 +0000 Greg Chicares <address@hidden> wrote:
> 
> GC>  + (6) "Illustration | Edit" disabled for child documents
> GC>        (corresponding accelerator Ctrl-E: likewise)
> GC>        (corresponding toolbar button: likewise)
> GC> 
> GC> The "child document" concept is described here:
> GC>   http://savannah.nongnu.org/support/?104485
> GC> and a child document can easily be created thus:
> GC>   alt-F N C
> GC>   Ctrl-R
> 
>  Unfortunately I still have no clear idea about how to implement this
> concept which doesn't really have any native equivalent.

First, let me say what this isn't. File 'include/wx/docview.h'
already contains this:
    wxDocument*       m_childDocument;
which means the document corresponding to an MDI child, the
child of an MDI parent window. That's not what this is about.

Parent-child relationships can exist between wxWindow objects.
What I seek is a similar relationship among wxDocument objects.

Second, let me say what that doesn't mean. It doesn't mean tight
coupling. As a counterexample, suppose a word-processing document
contains an embedded graphic that we might treat as a document in
its own right. Maybe the graphic can be edited separately, with
any change propagating back to its parent, perhaps affecting all
of the parent document's open views, and most likely affecting
the way the parent is stored. And deleting that graphic from the
parent document would have to destroy the subdocument, somehow.
That's the sort of tight coupling that is not intended here. I'm
consciously trying to avoid making that more difficult, in case
someone does want such tight coupling someday; but here I'm only
aiming for minimal changes to serve a much smaller purpose.

All I want is "if your parent closes, then you close" semantics,
with the loosest possible physical coupling. Here's an untested
sketch of how this might be implemented. (It changes the ABI,
which rules it out for the current wx version.)

Class wxDocument already has this member:

    wxDocument* m_documentParent;

which AFAICT is used nowhere yet. I would propose adding

    wxList<wxDocument> m_documentChildren;

and changing three member functions as follows:

wxDocument::wxDocument()
  // This is needed only for closing and deleting later.
  if(m_documentParent)
    m_documentParent->m_documentChildren->Insert(this);

wxDocument::~wxDocument()
  if(m_documentParent) {
    m_documentParent->m_documentChildren->DeleteContents(true);
    // Maybe DeleteAllViews should be called on each child?
    m_documentParent->m_documentChildren->Clear();
    }

wxDocument::Close()
  for each element 'e' of m_documentChildren
    do e->Close() /* or e->DeleteAllViews() ? */

and adding just one new function:

  wxDocument* wxDocument::GetParent() const {
    return m_documentParent;
    }

The purpose of trivial accessor wxDocument::GetParent() is
command enablement only; the only use case I intend is

    bool const should_be_enabled = NULL != doc.GetParent();
    some_menu_item.Enable(should_be_enabled);
    toolbar.EnableTool(some_tool_id, should_be_enabled);

and something like wxDocument::IsChild() would do that just as
well, but would seem gratuitously less general.

That's all there is to it, AFAICS. I'll explain exactly why I
want this, in case it's interesting. Well, I guess it's not
actually intriguing, but at least it might help you to see some
different and better way of accomplishing the goal, where I see
none myself.

In the lmi domain, we have two primary input-file types. A '.cns'
file is like a collection of '.ill' files, with some extra stuff:
the '.cns' is greater than the sum of its '.ill' parts. There
are two primary operations on these files:
 - input: mutating edit of '.ill' parts, through dialogs
 - output: const view, in MDI children
Now here's what's peculiar: you can get a consolidated view of
a '.cns' file--a so-called "composite". It looks just like an
'.ill' view; indeed, it's an instance of class IllustrationView.
But it does not correspond to any IllustrationDocument.

For '.ill' files:
  IllustrationDocument holds input data
  IllustrationView displays formatted output (not input)
  a wxBookCtrl edits input data
These three always occur together, bound as an intercommunicating
triplet. You can navigate from output back to input.

For '.cns' files:
  CensusDocument holds input data
  CensusView displays input data (not output)
  a wxBookCtrl edits '.ill' facets of input data, one at a time
and those three are always bound to each other--but:
  IllustrationView displays formatted output
and that output view is autonomous, bound to nothing; it's born
as an abandoned child that can never communicate with its parent,
but must be reaped when its parent closes. "Autonomy" here means
you cannot navigate from output back to input.

That autonomous IllustrationView of a CensusDocument doesn't need
a (mutating) binding back to the document that spawned it. Indeed
it must not have such a binding: its autonomy permits scenario
analysis. Users change the CensusDocument's input and create a
composite IllustrationView, then change the document again and
create another view that they compare to the still-open prior
view. They want those views to differ, which requires autonomy.

That autonomy means that a CensusDocument's IllustrationViews
correspond to the ephemeral state of the document at the time
each view was created. When a new scenario is tried, that state
vanishes, and the view no longer corresponds to any document on
disk or in memory. Therefore, I create these views from phony
IllustrationDocuments that contain output only, but no input.
Operations like "File | Save" must be inhibited for these views
and their corresponding, unsavable, uneditable, phony documents.
I've accomplished that through LMI_WX_CHILD_DOCUMENT, but that's
fragile [1] and doesn't quite work correctly: see the anguished
comments accompanying IllustrationView::UponUpdateFileSaveAs()
in 'illustration_view.cpp', for example, and also this:
  https://savannah.nongnu.org/support/?104430
It would seem much better to ascertain an IllustrationDocument's
phoniness by calling GetParent() instead.

Later, when users' work on a CensusDocument is done--when they've
selected the scenario they like best, and save the CensusDocument
and close its CensusView--then they want all IllustrationViews
spawned from that document to close. That's a behavior we don't
have today, which I seek to add by changing wxDocument::Close().

---------

[1] LMI_WX_CHILD_DOCUMENT is defined in 'illustration_document.hpp'
with these explanations and warnings:

/// WX !! The wx document-view implementation has no notion of 'child'
/// documents, but sometimes lmi creates a document that logically is
/// a 'child' of a parent CensusDocument: it corresponds to no actual,
/// distinct document, can't be opened or saved separately, and should
/// be closed, along with all its views, when its parent closes; and,
/// accordingly, it should never be added to any wxFileHistory. This
/// set of behaviors is implemented here by implicitly defining a new
/// document-creation flag, appropriating an unused bit in the flags
/// word. This is brittle, but then again it seems unlikely that
/// anyone will change this aspect of wx.

enum {LMI_WX_CHILD_DOCUMENT = 8};




reply via email to

[Prev in Thread] Current Thread [Next in Thread]