The design LGTM, in other words :-P
On Jul 31, 11:35 pm, "Scott Blum" <sco...@google.com> wrote:
> Hi everyone,
>
> Adding and removing a widget to/from a panel (or other parent) is a process
> that has evolved over time, as we've come to realize what the right behavior
> needs to be. Up until now, there hasn't been a formal design for doing this
> correctly. Rather, we've been converging on a set of behaviors that mostly
> work, but aren't completely consistent across the board. It's time we
> formalized exactly what needs to happen in order to correctly add or remove
> a widget. So I've proposed a "template" or order of operations for handlin
> this correctly. But first let's talk about the guiding principles behind
> the design.
>
> --------------------------------------
> Guiding Principles
>
> 1. onAttach/onDetach should occur only when both the DOM and the
> Widget structure are in a consistent, valid state. In practical terms, that
> means onAttach is the last thing to happen during an add, and onDetach is
> the first thing to happen during a remove.
> 2. Fail fast; avoid leaving things in an invalid state. In practical
> terms, error checking and other operations should happen first.
> 3. The template should be evident in any given Panel's add/remove
> method, to make it easy to maintain, enhance, and copy from.
>
> --------------------------------------
> The add()/insert() Template (also, SimpelPanel.setWidget() style methods)
>
> There are several important things that must take place in the correct
> order to properly add or insert a Widget to a Panel. Not all of these steps
> will be relevant to every Panel, but all of the steps should be
> considered.
>
> 1. *Validate:* Perform any sanity checks to ensure the Panel can
> accept a new Widget. Examples: checking for a valid index on insertion;
> checking that the Panel is not full if there is a max capacity.
> 2. *Account for Reinsertion:* Some Panels need special handling for
> the case where the Widget is already a child of this Panel. Example: when
> performing a reinsert, the index might need to be adjusted to account for
> the Widget's removal.
> 3. *Detach New Child:* Remove the Widget from its existing parent, if
> any. Most Panels will simply call Widget.removeFromParent() on the
> Widget. It's important to do this before performing any state changes to
> the Panel because some Widgets cannot be removed from their parents and will
> throw an IllegalStateException; such exceptions should be allowed to escape
> to the caller.
> 4. Remove an Existing Child (setWidget): Some Panels have a limited
> number of slots with methods whose semantics dictate that some existing
> child will be removed to make way for the new child. This should happen
> immediately after detaching the new child (which could fail) but before
> updating any state relating to inserting the new child.
> 5. *Logical Attach:* Any state variables of the Panel should be
> updated to reflect the addition of the new Widget. Example: the Widget is
> added to the Panel's WidgetCollection at the appropriate index.
> 6. *Physical Attach:* The Widget's Element must be physically attached
> to the Panel's Element, either directly or indirectly.
> 7. *Adopt:* Call adopt(Widget) to finalize the add as the very last
> step; this sets the child Widget's parent to the Panel and triggers
> onAttach().
>
> --------------------------------------
> The remove() Template
>
> There are several important things that must take place in the correct
> order to properly remove a Widget from a Panel. Not all of these steps will
> be relevant to every Panel, but all of the steps must be considered.
>
> 1. *Validate:* Make sure this Panel is actually the parent of the
> child Widget; return false if it is not.
> 2. *Orphan:* Call orphan(Widget) first while the child Widget is still
> attached; this triggers onDetach() and sets the child Widget's parent to
> null.
> 3. *Physical Detach:* Adjust the DOM to account for the removal of the
> child Widget. The Widget's Element must be physically removed from the DOM,
> either directly or indirectly.
> 4. *Logical Detach:* Update the Panel's state variables to reflect the
> widget-add-remove-SOLID-SNAKE-r1282.patch
> 79KDownload
I'm very happy the whole insert/remove situation is being thoroughly reviewed. The end result will certainly make my life easier.
Two minor notes on the patch to start with:
1. The patch is missing LocalServletRequest.java (I realize files not yet in SVN fall out pretty easily)
2. The javadoc on @domInsert for ComplexPanel#insert(Widget, Element, int, boolean) has been inverted
As far as backwards compatibility, I do have code out there that would break with this patch, but I'm quite happy to live with that if the current APIs can be improved. It would be a compile time breakage, which personally I prefer, because that is so much easier to locate and fix.
I had a quick think and i believe the parent should be responsible for calling all the on** methods on the child. The child should only be responsible for itself that is maintaining its internal state. The same concept applies to a parent ( a panel ). A child belongs to it so its the parents responsibility to maintain its internal state, which in this case is its children.
As far as backwards compatibility, I do have code out there that would break with this patch, but I'm quite happy to live with that if the current APIs can be improved. It would be a compile time breakage, which personally I prefer, because that is so much easier to locate and fix.
Compile time breaks, eth? I'm interested to hear specifically what's breaking I didnt realize I was breaking code.
Ok, this is what I was hoping it was. When I made that change, I thought that ComplexPanel.insert(3) method had been added in 1.4.10. But I checked 1.3.3 and it was in at that time.
I think the right thing to do is add back the 3 arg version that delegates to the 4 arg version, but also deprecate the 3 arg version. Thoughts?
On 8/1/07, Scott Blum <sco...@google.com > wrote:Ok, this is what I was hoping it was. When I made that change, I thought that ComplexPanel.insert(3) method had been added in 1.4.10. But I checked 1.3.3 and it was in at that time.
I think the right thing to do is add back the 3 arg version that delegates to the 4 arg version, but also deprecate the 3 arg version. Thoughts?
Agreed. I believe we have the responsibility to do everything possible to maintain the 1.3.3 API and method implementation behavior. Deprecation is the perfect way to let application developers update their code when it is convenient for them, while providing a path forward for the API.
The 3 arg method would need a bit of work though, for example, to deal with the case where the second argument is null.
What I've done in my local copy, pending Joel's approval, is to have the 3-argument version explicitly null-check container and thrown a direct NPE with a helpful message. So I definitely think we're on the same page. My intent was definitely to put assert statements in the most useful places I could think of, so if you spot more places that could benefit, definitely point them out.
Scott
On 8/1/07, Fred Sauer <fr...@allen-sauer.com> wrote:I'm perfectly happy with the NPE. And, in general, I would agree that it better to break previous hacks, than to continue to silently support something that cannot possibly be right :). I little note in the javadoc to mention that null is no longer allowed might be helpful to others out there.
I wonder though if other uses of the old 3 arg method are potentially incorrect as well. If it turns out to be reasonable to expect that a lot of existing 3 arg uses would be incorrect, then maybe a NotImplementedException is in order for the method. There be dragons....
A final recommendation for this refactoring/cleanup for 1.4 would be to really beef up all the assertions in methods that affect insertion/attachment/detachment so that the bad client code (new or existing) can get caught red handed. In the 3 arg method above I imagine a sprinkling of assertions could catch the misuse even before a NPE is thrown. That would mitigate the need for a special mention on the null parameter in the docs.