Author: knopp Date: Wed Jul 25 06:03:42 2007 New Revision: 559446 URL: http://svn.apache.org/viewvc?view=rev&rev=559446 Log: WICKET-627 Can't visit components in a ListView before they're rendered.
Modified: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/Component.java incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/MarkupContainer.java incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/Page.java incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ajax/AjaxRequestTarget.java incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/list/ListView.java incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/tree/AbstractTree.java Modified: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/Component.java URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/Component.java?view=diff&rev=559446&r1=559445&r2=559446 ============================================================================== --- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/Component.java (original) +++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/Component.java Wed Jul 25 06:03:42 2007 @@ -652,6 +652,13 @@ protected static final int FLAG_RESERVED8 = 0x80000; /** + * Flag that makes we are in before-render callback phase Set after + * component.onBeforeRender is invoked (right before invoking beforeRender + * on children) + */ + static final int FLAG_PREPARED_FOR_RENDER = 0x4000000; + + /** * Meta data key for line precise error logging for the moment of addition. * Made package private for access in [EMAIL PROTECTED] MarkupContainer} and * [EMAIL PROTECTED] Page} @@ -670,6 +677,7 @@ private static final long serialVersionUID = 1L; }; + static final int FLAG_ATTACH_SUPER_CALL_VERIFIED = 0x10000000; static final int FLAG_ATTACHED = 0x20000000; @@ -839,9 +847,10 @@ */ public final void beforeRender() { - if (!getFlag(FLAG_RENDERING)) + if (!getFlag(FLAG_RENDERING) && !getFlag(FLAG_PREPARED_FOR_RENDER)) { setFlag(FLAG_BEFORE_RENDERING_SUPER_CALL_VERIFIED, false); + onBeforeRender(); getApplication().notifyComponentOnBeforeRenderListeners(this); if (!getFlag(FLAG_BEFORE_RENDERING_SUPER_CALL_VERIFIED)) @@ -851,12 +860,40 @@ getClass().getName() + " has not called super.onBeforeRender() in the override of onBeforeRender() method"); } - onBeforeRenderChildren(); - setFlag(FLAG_RENDERING, true); } } /** + * Prepares the component and it's children for rendering. On whole page + * render this method must be called on the page. On AJAX request, this + * method must be called on updated component. + */ + public void prepareForRender() + { + beforeRender(); + markRendering(); + } + + /** + * Sets the RENDERING flag on component and it's children. + */ + public final void markRendering() + { + internalMarkRendering(); + } + + boolean isPreparedForRender() + { + return getFlag(FLAG_PREPARED_FOR_RENDER); + } + + void internalMarkRendering() + { + setFlag(FLAG_PREPARED_FOR_RENDER, false); + setFlag(FLAG_RENDERING, true); + } + + /** * Redirects to any intercept page previously specified by a call to * redirectToInterceptPage. * @@ -1219,7 +1256,8 @@ // if not in the markup, generate one markupId = getId() + page.getAutoIndex(); - // make sure id is compliant with w3c requirements (starts with a letter) + // make sure id is compliant with w3c requirements (starts with a + // letter) char c = markupId.charAt(0); if (!Character.isLetter(c)) { @@ -1955,6 +1993,8 @@ */ public final void render(final MarkupStream markupStream) { + markRendering(); + setMarkupStream(markupStream); setFlag(FLAG_HAS_BEEN_RENDERED, true); @@ -2067,6 +2107,7 @@ parent.setMarkupStream(markupStream); beforeRender(); + markRendering(); // check authorization // first the component itself // (after attach as otherwise list views etc wont work) @@ -3250,6 +3291,8 @@ */ protected void onBeforeRender() { + setFlag(FLAG_PREPARED_FOR_RENDER, true); + onBeforeRenderChildren(); setFlag(FLAG_BEFORE_RENDERING_SUPER_CALL_VERIFIED, true); } Modified: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/MarkupContainer.java URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/MarkupContainer.java?view=diff&rev=559446&r1=559445&r2=559446 ============================================================================== --- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/MarkupContainer.java (original) +++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/MarkupContainer.java Wed Jul 25 06:03:42 2007 @@ -223,6 +223,7 @@ } add(component); component.beforeRender(); + component.markRendering(); if (markupStream == null) { component.render(); @@ -924,6 +925,14 @@ { page.componentAdded(component); } + + // if the PREPARED_FOR_RENDER flag is set, we have alrady called + // beforeRender on this + // component's children. So we need to initialize the newly added one + if (isPreparedForRender()) + { + component.beforeRender(); + } } /** @@ -1465,20 +1474,51 @@ super.detachChildren(); } + void internalMarkRendering() + { + super.internalMarkRendering(); + final int size = children_size(); + for (int i = 0; i < size; i++) + { + final Component child = children_get(i); + child.internalMarkRendering(); + } + } + + private Component[] copyChildren() + { + int size = children_size(); + Component result[] = new Component[size]; + for (int i = 0; i < size; ++i) + { + result[i] = children_get(i); + } + return result; + } + void onBeforeRenderChildren() { super.onBeforeRenderChildren(); + + // We need to copy the children list because the children components can + // modify the hierarchy in their onBeforeRender. + Component[] children = copyChildren(); try { // Loop through child components - final int size = children_size(); - for (int i = 0; i < size; i++) + for (int i = 0; i < children.length; i++) { // Get next child - final Component child = children_get(i); + final Component child = children[i]; // Call begin request on the child - child.beforeRender(); + // We need to check whether the child's wasn't removed from the + // component in the meanwhile (e.g. from another's child + // onBeforeRender) + if (child.getParent() == this) + { + child.beforeRender(); + } } } catch (RuntimeException ex) Modified: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/Page.java URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/Page.java?view=diff&rev=559446&r1=559445&r2=559446 ============================================================================== --- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/Page.java (original) +++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/Page.java Wed Jul 25 06:03:42 2007 @@ -366,10 +366,8 @@ } if (renderedComponents.add(component) == false) { - throw new MarkupException( - "The component " - + component - + " has the same wicket:id as another component already added at the same level"); + throw new MarkupException("The component " + component + + " has the same wicket:id as another component already added at the same level"); } if (log.isDebugEnabled()) { @@ -576,8 +574,8 @@ } else { - log.info("No version manager available to retrieve requested versionNumber " - + versionNumber); + log.info("No version manager available to retrieve requested versionNumber " + + versionNumber); return null; } } @@ -605,8 +603,8 @@ } // If we went all the way back to the original page - if (page != null && page.getCurrentVersionNumber() == 0 - && page.getAjaxVersionNumber() == 0) + if (page != null && page.getCurrentVersionNumber() == 0 && + page.getAjaxVersionNumber() == 0) { // remove version info page.versionManager = null; @@ -646,8 +644,8 @@ { levels++; } - buffer.append(StringValue.repeat(levels, " ") + component.getPageRelativePath() - + ":" + Classes.simpleName(component.getClass())); + buffer.append(StringValue.repeat(levels, " ") + component.getPageRelativePath() + + ":" + Classes.simpleName(component.getClass())); return null; } }); @@ -746,8 +744,8 @@ stateless = Boolean.FALSE; if (getStatelessHint()) { - log.warn("Page '" + this + "' is not stateless because it is not bookmarkable, " - + "but the stateless hint is set to true!"); + log.warn("Page '" + this + "' is not stateless because it is not bookmarkable, " + + "but the stateless hint is set to true!"); } } @@ -778,8 +776,8 @@ if (!stateless.booleanValue() && getStatelessHint()) { - log.warn("Page '" + this + "' is not stateless because of '" + returnArray[0] - + "' but the stateless hint is set to true!"); + log.warn("Page '" + this + "' is not stateless because of '" + returnArray[0] + + "' but the stateless hint is set to true!"); } } @@ -813,8 +811,8 @@ // Check that formClass is an instanceof Form if (!Form.class.isAssignableFrom(formClass)) { - throw new WicketRuntimeException("Form class " + formClass.getName() - + " is not a subclass of Form"); + throw new WicketRuntimeException("Form class " + formClass.getName() + + " is not a subclass of Form"); } // Visit all children which are an instance of formClass @@ -882,7 +880,7 @@ try { - beforeRender(); + prepareForRender(); } catch (RuntimeException e) { @@ -1002,8 +1000,8 @@ if (value && !isBookmarkable()) { throw new WicketRuntimeException( - "Can't set stateless hint to true on a page when the page is not bookmarkable, page: " - + this); + "Can't set stateless hint to true on a page when the page is not bookmarkable, page: " + + this); } setFlag(FLAG_STATELESS_HINT, value); } @@ -1030,14 +1028,14 @@ { if (versionManager != null) { - return "[Page class = " + getClass().getName() + ", id = " + getId() + ", version = " - + versionManager.getCurrentVersionNumber() + ", ajax = " - + versionManager.getAjaxVersionNumber() + "]"; + return "[Page class = " + getClass().getName() + ", id = " + getId() + ", version = " + + versionManager.getCurrentVersionNumber() + ", ajax = " + + versionManager.getAjaxVersionNumber() + "]"; } else { - return "[Page class = " + getClass().getName() + ", id = " + getId() + ", version = " - + 0 + "]"; + return "[Page class = " + getClass().getName() + ", id = " + getId() + ", version = " + + 0 + "]"; } } @@ -1078,8 +1076,8 @@ unrenderedComponents.increment(); // Add to explanatory string to buffer - buffer.append(Integer.toString(unrenderedComponents.getCount()) + ". " - + component + "\n"); + buffer.append(Integer.toString(unrenderedComponents.getCount()) + ". " + + component + "\n"); String metadata = (String)component .getMetaData(Component.CONSTRUCTED_AT_KEY); if (metadata != null) @@ -1120,8 +1118,8 @@ // Throw exception throw new WicketRuntimeException( - "The component(s) below failed to render. A common problem is that you have added a component in code but forgot to reference it in the markup (thus the component will never be rendered).\n\n" - + buffer.toString()); + "The component(s) below failed to render. A common problem is that you have added a component in code but forgot to reference it in the markup (thus the component will never be rendered).\n\n" + + buffer.toString()); } } @@ -1215,8 +1213,8 @@ { // Auto components do not participate in versioning since they are // added during the rendering phase (which is normally illegal). - if (component.isAuto() || (parent == null && !component.isVersioned()) - || (parent != null && !parent.isVersioned())) + if (component.isAuto() || (parent == null && !component.isVersioned()) || + (parent != null && !parent.isVersioned())) { return false; } @@ -1330,8 +1328,8 @@ // Write out an xml declaration if the markup stream and settings allow final MarkupStream markupStream = findMarkupStream(); - if ((markupStream != null) && (markupStream.getXmlDeclaration() != null) - && (application.getMarkupSettings().getStripXmlDeclarationFromOutput() == false)) + if ((markupStream != null) && (markupStream.getXmlDeclaration() != null) && + (application.getMarkupSettings().getStripXmlDeclarationFromOutput() == false)) { response.write("<?xml version='1.0' encoding='"); response.write(encoding); @@ -1403,7 +1401,7 @@ dirty(); super.onDetach(); - + } Modified: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ajax/AjaxRequestTarget.java URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ajax/AjaxRequestTarget.java?view=diff&rev=559446&r1=559445&r2=559446 ============================================================================== --- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ajax/AjaxRequestTarget.java (original) +++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/ajax/AjaxRequestTarget.java Wed Jul 25 06:03:42 2007 @@ -302,8 +302,8 @@ if (childCriteria == null) { throw new IllegalArgumentException( - "Argument `childCriteria` cannot be null. If you want to traverse all components use `" - + Component.class.getName() + ".class` as the value for this argument"); + "Argument `childCriteria` cannot be null. If you want to traverse all components use `" + + Component.class.getName() + ".class` as the value for this argument"); } @@ -334,8 +334,8 @@ if (component.getOutputMarkupId() == false) { throw new IllegalArgumentException( - "cannot update component that does not have setOutputMarkupId property set to true. Component: " - + component.toString()); + "cannot update component that does not have setOutputMarkupId property set to true. Component: " + + component.toString()); } addComponent(component, component.getMarkupId()); } @@ -366,9 +366,9 @@ else if (component instanceof AbstractRepeater) { throw new IllegalArgumentException( - "Component " - + component.getClass().getName() - + " has been added to the target. This component is a repeater and cannot be repainted via ajax directly. Instead add its parent or another markup container higher in the hierarchy."); + "Component " + + component.getClass().getName() + + " has been added to the target. This component is a repeater and cannot be repainted via ajax directly. Instead add its parent or another markup container higher in the hierarchy."); } markupIdToComponent.put(markupId, component); @@ -399,8 +399,8 @@ if (component != null && component.getOutputMarkupId() == false) { throw new IllegalArgumentException( - "cannot update component that does not have setOutputMarkupId property set to true. Component: " - + component.toString()); + "cannot update component that does not have setOutputMarkupId property set to true. Component: " + + component.toString()); } final String id = component != null ? component.getMarkupId() : null; appendJavascript("Wicket.Focus.setFocusOnId('" + id + "');"); @@ -445,9 +445,9 @@ if (obj instanceof AjaxRequestTarget) { AjaxRequestTarget that = (AjaxRequestTarget)obj; - return markupIdToComponent.equals(that.markupIdToComponent) - && prependJavascripts.equals(that.prependJavascripts) - && appendJavascripts.equals(that.appendJavascripts); + return markupIdToComponent.equals(that.markupIdToComponent) && + prependJavascripts.equals(that.prependJavascripts) && + appendJavascripts.equals(that.appendJavascripts); } return false; } @@ -668,9 +668,9 @@ */ public String toString() { - return "[AjaxRequestTarget@" + hashCode() + " markupIdToComponent [" + markupIdToComponent - + "], prependJavascript [" + prependJavascripts + "], appendJavascript [" - + appendJavascripts + "]"; + return "[AjaxRequestTarget@" + hashCode() + " markupIdToComponent [" + markupIdToComponent + + "], prependJavascript [" + prependJavascripts + "], appendJavascript [" + + appendJavascripts + "]"; } /** @@ -732,8 +732,8 @@ if (component.getRenderBodyOnly() == true) { throw new IllegalStateException( - "Ajax render cannot be called on component that has setRenderBodyOnly enabled. Component: " - + component.toString()); + "Ajax render cannot be called on component that has setRenderBodyOnly enabled. Component: " + + component.toString()); } component.setOutputMarkupId(true); @@ -754,11 +754,11 @@ page.startComponentRender(component); - component.beforeRender(); - + component.prepareForRender(); + // render any associated headers of the component respondHeaderContribution(response, component); - + component.renderComponent(); page.endComponentRender(component); Modified: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/list/ListView.java URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/list/ListView.java?view=diff&rev=559446&r1=559445&r2=559446 ============================================================================== --- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/list/ListView.java (original) +++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/list/ListView.java Wed Jul 25 06:03:42 2007 @@ -530,8 +530,6 @@ */ protected void onBeforeRender() { - super.onBeforeRender(); - if (isVisibleInHierarchy()) { // Get number of items to be displayed @@ -589,7 +587,9 @@ { removeAll(); } + } + super.onBeforeRender(); } /** @@ -665,7 +665,8 @@ { final String id = Integer.toString(firstIndex + index); index++; - return get(id); + Component c = get(id); + return c; } }; } Modified: incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/tree/AbstractTree.java URL: http://svn.apache.org/viewvc/incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/tree/AbstractTree.java?view=diff&rev=559446&r1=559445&r2=559446 ============================================================================== --- incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/tree/AbstractTree.java (original) +++ incubator/wicket/trunk/jdk-1.4/wicket/src/main/java/org/apache/wicket/markup/html/tree/AbstractTree.java Wed Jul 25 06:03:42 2007 @@ -300,7 +300,7 @@ protected void onBeforeRender() { - AbstractTree.this.onBeforeRender(); + AbstractTree.this.onBeforeRenderInternal(); super.onBeforeRender(); if (isRenderChildren()) @@ -559,13 +559,10 @@ { } - /** - * Called at the beginning of the request (not ajax request, unless we are - * rendering the entire component) - */ - public void onBeforeRender() + // This is necessary because MarkupContainer.onBeforeRender involves calling + // beforeRender on children, which results in stack overflow when called from TreeItem + private void onBeforeRenderInternal() { - super.onBeforeRender(); if (attached == false) { onBeforeAttach(); @@ -606,7 +603,16 @@ attached = true; } - + } + + /** + * Called at the beginning of the request (not ajax request, unless we are + * rendering the entire component) + */ + public void onBeforeRender() + { + onBeforeRenderInternal(); + super.onBeforeRender(); } /**