You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by iv...@apache.org on 2010/08/18 22:43:35 UTC

svn commit: r986925 - in /wicket/trunk: wicket-examples/src/main/java/org/apache/wicket/examples/events/ wicket-examples/src/main/webapp/ wicket-examples/src/main/webapp/WEB-INF/ wicket-util/src/main/java/org/apache/wicket/util/ wicket-util/src/main/ja...

Author: ivaynberg
Date: Wed Aug 18 20:43:33 2010
New Revision: 986925

URL: http://svn.apache.org/viewvc?rev=986925&view=rev
Log:
initial inter-component event system implementation
Issue: WICKET-1312

Added:
    wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/
    wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/BasePage.html   (with props)
    wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/BasePage.java   (with props)
    wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/DecoupledAjaxUpdatePage.html   (with props)
    wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/DecoupledAjaxUpdatePage.java   (with props)
    wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/EventsApplication.java   (with props)
    wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/IndexPage.html   (with props)
    wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/IndexPage.java   (with props)
    wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/IHierarchical.java   (with props)
    wicket/trunk/wicket/src/main/java/org/apache/wicket/ComponentEvent.java   (with props)
    wicket/trunk/wicket/src/main/java/org/apache/wicket/ComponentEventSender.java   (with props)
    wicket/trunk/wicket/src/main/java/org/apache/wicket/event/
    wicket/trunk/wicket/src/main/java/org/apache/wicket/event/Broadcast.java   (with props)
    wicket/trunk/wicket/src/main/java/org/apache/wicket/event/IEvent.java   (with props)
    wicket/trunk/wicket/src/main/java/org/apache/wicket/event/IEventSink.java   (with props)
    wicket/trunk/wicket/src/main/java/org/apache/wicket/event/IEventSource.java   (with props)
    wicket/trunk/wicket/src/test/java/org/apache/wicket/ComponentEventsTest.java   (with props)
Modified:
    wicket/trunk/wicket-examples/src/main/webapp/WEB-INF/web.xml
    wicket/trunk/wicket-examples/src/main/webapp/index.html
    wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/visit/Visits.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/Application.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/Component.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/Session.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/RequestCycle.java

Added: wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/BasePage.html
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/BasePage.html?rev=986925&view=auto
==============================================================================
--- wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/BasePage.html (added)
+++ wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/BasePage.html Wed Aug 18 20:43:33 2010
@@ -0,0 +1,11 @@
+<html xmlns:wicket>
+<head>
+	<title>Wicket Examples - Events</title>
+    <link rel="stylesheet" type="text/css" href="style.css"/>
+</head>
+<body>
+    <span wicket:id="mainNavigation"></span>
+    <a href="Index.html" wicket:id="back">[go back]</a><p/>
+    <wicket:child/>
+</body>
+</html>
\ No newline at end of file

Propchange: wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/BasePage.html
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/BasePage.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/BasePage.java?rev=986925&view=auto
==============================================================================
--- wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/BasePage.java (added)
+++ wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/BasePage.java Wed Aug 18 20:43:33 2010
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.examples.events;
+
+import org.apache.wicket.examples.WicketExamplePage;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+
+
+/**
+ * Base page for events examples
+ */
+public abstract class BasePage extends WicketExamplePage
+{
+	/**
+	 * Constructor
+	 */
+	public BasePage()
+	{
+		add(new BookmarkablePageLink<Void>("back", IndexPage.class).setAutoEnable(true));
+	}
+}

Propchange: wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/BasePage.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/DecoupledAjaxUpdatePage.html
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/DecoupledAjaxUpdatePage.html?rev=986925&view=auto
==============================================================================
--- wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/DecoupledAjaxUpdatePage.html (added)
+++ wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/DecoupledAjaxUpdatePage.html Wed Aug 18 20:43:33 2010
@@ -0,0 +1,10 @@
+<wicket:extend>
+Counter Label 1: <span wicket:id="label1">1</span>
+
+
+<div wicket:id="container">Counter Label 2: <span wicket:id="label2">1</span></div>
+
+<form wicket:id="form">
+	Counter Value: <input wicket:id="counter" type="text"/> <input wicket:id="submit" type="submit" value="Update"/>
+</form>
+</wicket:extend>
\ No newline at end of file

Propchange: wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/DecoupledAjaxUpdatePage.html
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/DecoupledAjaxUpdatePage.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/DecoupledAjaxUpdatePage.java?rev=986925&view=auto
==============================================================================
--- wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/DecoupledAjaxUpdatePage.java (added)
+++ wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/DecoupledAjaxUpdatePage.java Wed Aug 18 20:43:33 2010
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.examples.events;
+
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.form.AjaxButton;
+import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.event.IEvent;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.form.TextField;
+import org.apache.wicket.model.PropertyModel;
+
+/**
+ * @author igor
+ */
+public class DecoupledAjaxUpdatePage extends BasePage
+{
+	private int counter;
+
+	/**
+	 * Construct.
+	 */
+	public DecoupledAjaxUpdatePage()
+	{
+		// add a counter label
+		add(new CounterLabel("label1"));
+
+
+		// add another counter label inside a container
+		WebMarkupContainer container = new WebMarkupContainer("container");
+		add(container);
+		container.add(new CounterLabel("label2"));
+
+		// add a form
+		Form<?> form = new Form<Void>("form");
+		add(form);
+
+		// add the textfield that will update the counter value
+		form.add(new TextField<Integer>("counter", new PropertyModel<Integer>(this, "counter"),
+			Integer.class).setRequired(true));
+
+		// add button that will broadcast counter update event
+		form.add(new AjaxButton("submit")
+		{
+
+			@Override
+			protected void onSubmit(AjaxRequestTarget target, Form<?> form)
+			{
+				send(getPage(), Broadcast.BREADTH, new CounterUpdate(target));
+			}
+
+			@Override
+			protected void onError(AjaxRequestTarget target, Form<?> form)
+			{
+			}
+
+		});
+	}
+
+	/**
+	 * An event payload that represents a counter update
+	 */
+	public class CounterUpdate
+	{
+		private final AjaxRequestTarget target;
+
+		/**
+		 * Constructor
+		 * 
+		 * @param target
+		 */
+		public CounterUpdate(AjaxRequestTarget target)
+		{
+			this.target = target;
+		}
+
+		/** @return ajax request target */
+		public AjaxRequestTarget getTarget()
+		{
+			return target;
+		}
+	}
+
+	/**
+	 * A label that renders the value of the page's counter variable. Also listens to
+	 * {@link CounterUpdate} event and updates itself.
+	 * 
+	 * @author igor
+	 */
+	public class CounterLabel extends Label
+	{
+
+		/**
+		 * Construct.
+		 * 
+		 * @param id
+		 */
+		public CounterLabel(String id)
+		{
+			super(id, new PropertyModel<Integer>(DecoupledAjaxUpdatePage.this, "counter"));
+			setOutputMarkupId(true);
+		}
+
+		/**
+		 * @see org.apache.wicket.Component#onEvent(org.apache.wicket.event.IEvent)
+		 */
+		@Override
+		public void onEvent(IEvent<?> event)
+		{
+			super.onEvent(event);
+
+			// check if this is a counter update event and if so repaint self
+			if (event.getPayload() instanceof CounterUpdate)
+			{
+				CounterUpdate update = (CounterUpdate)event.getPayload();
+				update.getTarget().addComponent(this);
+			}
+		}
+
+	}
+}

Propchange: wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/DecoupledAjaxUpdatePage.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/EventsApplication.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/EventsApplication.java?rev=986925&view=auto
==============================================================================
--- wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/EventsApplication.java (added)
+++ wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/EventsApplication.java Wed Aug 18 20:43:33 2010
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.examples.events;
+
+import org.apache.wicket.Page;
+import org.apache.wicket.examples.WicketExampleApplication;
+
+
+/**
+ * Application class for the events example
+ * 
+ * @author igor
+ */
+public class EventsApplication extends WicketExampleApplication
+{
+	/**
+	 * @see org.apache.wicket.Application#getHomePage()
+	 */
+	@Override
+	public Class<? extends Page> getHomePage()
+	{
+		return IndexPage.class;
+	}
+
+}

Propchange: wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/EventsApplication.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/IndexPage.html
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/IndexPage.html?rev=986925&view=auto
==============================================================================
--- wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/IndexPage.html (added)
+++ wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/IndexPage.html Wed Aug 18 20:43:33 2010
@@ -0,0 +1,7 @@
+<wicket:extend>
+
+<wicket:link>
+	<a href="DecoupledAjaxUpdatePage.html">Decoupled Ajax Update</a>
+</wicket:link>
+
+</wicket:extend>
\ No newline at end of file

Propchange: wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/IndexPage.html
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/IndexPage.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/IndexPage.java?rev=986925&view=auto
==============================================================================
--- wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/IndexPage.java (added)
+++ wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/IndexPage.java Wed Aug 18 20:43:33 2010
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.examples.events;
+
+
+/**
+ * @author igor
+ */
+public class IndexPage extends BasePage
+{
+
+}

Propchange: wicket/trunk/wicket-examples/src/main/java/org/apache/wicket/examples/events/IndexPage.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: wicket/trunk/wicket-examples/src/main/webapp/WEB-INF/web.xml
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-examples/src/main/webapp/WEB-INF/web.xml?rev=986925&r1=986924&r2=986925&view=diff
==============================================================================
--- wicket/trunk/wicket-examples/src/main/webapp/WEB-INF/web.xml (original)
+++ wicket/trunk/wicket-examples/src/main/webapp/WEB-INF/web.xml Wed Aug 18 20:43:33 2010
@@ -697,6 +697,24 @@
         <dispatcher>INCLUDE</dispatcher>
 	</filter-mapping>
 
+
+	<!-- EVENTS APP -->
+	<filter>
+		<filter-name>EventsApplication</filter-name>
+		<filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
+		<init-param>
+		  <param-name>applicationClassName</param-name>
+		  <param-value>org.apache.wicket.examples.events.EventsApplication</param-value>
+		</init-param>
+	</filter>
+	<filter-mapping>
+		<filter-name>EventsApplication</filter-name>
+        <url-pattern>/events/*</url-pattern>
+	</filter-mapping>
+
+
+
+
 	<listener>
 		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 	</listener>

Modified: wicket/trunk/wicket-examples/src/main/webapp/index.html
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-examples/src/main/webapp/index.html?rev=986925&r1=986924&r2=986925&view=diff
==============================================================================
--- wicket/trunk/wicket-examples/src/main/webapp/index.html (original)
+++ wicket/trunk/wicket-examples/src/main/webapp/index.html Wed Aug 18 20:43:33 2010
@@ -59,6 +59,7 @@
 		<tr><td align="right"><a href="guice">guice</a></td><td> - Integration with the Google Guice IoC container.</td></tr>
 		<tr><td align="right"><a href="velocity">velocity</a></td><td> - Shows a Velocity panel in action.</td></tr>
 		<tr><td align="right"><a href="mappers">Wicket 1.5 Request Mappers</a></td><td> - Shows custom request mappers.</td></tr>
+		<tr><td align="right"><a href="events">Wicket 1.5 Events</a></td><td> - Shows inter-component events</td></tr>
     	</tbody>
 		</table>	
 	</div>

Added: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/IHierarchical.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/IHierarchical.java?rev=986925&view=auto
==============================================================================
--- wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/IHierarchical.java (added)
+++ wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/IHierarchical.java Wed Aug 18 20:43:33 2010
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.util;
+
+/**
+ * Represents an object that is a part of a hierarchy
+ * 
+ * @author Igor Vaynberg (ivaynberg)
+ * @param <T>
+ */
+public interface IHierarchical<T>
+{
+	/**
+	 * @return object's parent or {@code null} if this object is the root of the hierarchy
+	 */
+	T getParent();
+}

Propchange: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/IHierarchical.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/visit/Visits.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/visit/Visits.java?rev=986925&r1=986924&r2=986925&view=diff
==============================================================================
--- wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/visit/Visits.java (original)
+++ wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/visit/Visits.java Wed Aug 18 20:43:33 2010
@@ -20,8 +20,8 @@ public class Visits
 	 * 
 	 * @param <S>
 	 *            the type of object that will be visited, notice that {@code container} is not
-	 *            declared as {@code Iterable<S>} because it may return a generalization of {@code
-	 *            S}
+	 *            declared as {@code Iterable<S>} because it may return a generalization of
+	 *            {@code S}
 	 * @param <R>
 	 *            the type of object that should be returned from the visitor, use {@link Void} if
 	 *            no return value is needed
@@ -100,8 +100,8 @@ public class Visits
 	 * 
 	 * @param <S>
 	 *            the type of object that will be visited, notice that {@code container} is not
-	 *            declared as {@code Iterable<S>} because it may return a generalization of {@code
-	 *            S}
+	 *            declared as {@code Iterable<S>} because it may return a generalization of
+	 *            {@code S}
 	 * @param <R>
 	 *            the type of object that should be returned from the visitor, use {@link Void} if
 	 *            no return value is needed
@@ -123,8 +123,8 @@ public class Visits
 	 * 
 	 * @param <S>
 	 *            the type of object that will be visited, notice that {@code container} is not
-	 *            declared as {@code Iterable<S>} because it may return a generalization of {@code
-	 *            S}
+	 *            declared as {@code Iterable<S>} because it may return a generalization of
+	 *            {@code S}
 	 * @param <R>
 	 *            the type of object that should be returned from the visitor, use {@link Void} if
 	 *            no return value is needed
@@ -147,8 +147,8 @@ public class Visits
 	 * 
 	 * @param <S>
 	 *            the type of object that will be visited, notice that {@code container} is not
-	 *            declared as {@code Iterable<S>} because it may return a generalization of {@code
-	 *            S}
+	 *            declared as {@code Iterable<S>} because it may return a generalization of
+	 *            {@code S}
 	 * @param <R>
 	 *            the type of object that should be returned from the visitor, use {@link Void} if
 	 *            no return value is needed
@@ -188,21 +188,18 @@ public class Visits
 				for (final Iterator<?> iterator = ((Iterable<?>)component).iterator(); iterator.hasNext();)
 				{
 					final Object child = iterator.next();
-					if (child instanceof Iterable<?>)
+					visitComponentsPostOrderHelper(child, visitor, filter, childTraversal);
+					if (childTraversal.isStopped())
 					{
-						visitComponentsPostOrderHelper(child, visitor, filter, childTraversal);
-						if (childTraversal.isStopped())
-						{
-							visit.stop(childTraversal.getResult());
-							return;
-						}
+						visit.stop(childTraversal.getResult());
+						return;
 					}
 				}
 			}
-			if (filter.visitObject(component))
-			{
-				visitor.component((S)component, visit);
-			}
+		}
+		if (filter.visitObject(component))
+		{
+			visitor.component((S)component, visit);
 		}
 	}
 }

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/Application.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/Application.java?rev=986925&r1=986924&r2=986925&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/Application.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/Application.java Wed Aug 18 20:43:33 2010
@@ -32,6 +32,8 @@ import java.util.Set;
 import org.apache.wicket.application.IComponentInstantiationListener;
 import org.apache.wicket.application.IComponentOnAfterRenderListener;
 import org.apache.wicket.application.IComponentOnBeforeRenderListener;
+import org.apache.wicket.event.IEvent;
+import org.apache.wicket.event.IEventSink;
 import org.apache.wicket.javascript.DefaultJavascriptCompressor;
 import org.apache.wicket.markup.MarkupParser;
 import org.apache.wicket.markup.html.EmptySrcAttributeCheckFilter;
@@ -136,7 +138,7 @@ import org.slf4j.LoggerFactory;
  * @see org.apache.wicket.protocol.http.WebApplication
  * @author Jonathan Locke
  */
-public abstract class Application implements UnboundListener
+public abstract class Application implements UnboundListener, IEventSink
 {
 	/** Configuration constant for the 2 types */
 	public static final String CONFIGURATION = "configuration";
@@ -1585,6 +1587,11 @@ public abstract class Application implem
 		return URLConnection.getFileNameMap().getContentTypeFor(fileName);
 	}
 
+	/** {@inheritDoc} */
+	public void onEvent(IEvent<?> event)
+	{
+	}
+
 	private class DefaultPageManagerProvider implements IPageManagerProvider
 	{
 

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/Component.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/Component.java?rev=986925&r1=986924&r2=986925&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/Component.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/Component.java Wed Aug 18 20:43:33 2010
@@ -30,6 +30,10 @@ import org.apache.wicket.authorization.A
 import org.apache.wicket.authorization.IAuthorizationStrategy;
 import org.apache.wicket.authorization.UnauthorizedActionException;
 import org.apache.wicket.behavior.IBehavior;
+import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.event.IEvent;
+import org.apache.wicket.event.IEventSink;
+import org.apache.wicket.event.IEventSource;
 import org.apache.wicket.feedback.FeedbackMessage;
 import org.apache.wicket.feedback.IFeedback;
 import org.apache.wicket.markup.ComponentTag;
@@ -59,6 +63,7 @@ import org.apache.wicket.request.http.We
 import org.apache.wicket.request.mapper.parameter.PageParameters;
 import org.apache.wicket.request.resource.ResourceReference;
 import org.apache.wicket.settings.IDebugSettings;
+import org.apache.wicket.util.IHierarchical;
 import org.apache.wicket.util.convert.IConverter;
 import org.apache.wicket.util.lang.Classes;
 import org.apache.wicket.util.lang.WicketObjects;
@@ -218,7 +223,10 @@ public abstract class Component
 		IClusterable,
 		IConverterLocator,
 		IRequestableComponent,
-		IHeaderContributor
+		IHeaderContributor,
+		IHierarchical<Component>,
+		IEventSink,
+		IEventSource
 {
 
 	/** True when component has been configured, had {@link #onConfigure()} called */
@@ -4490,8 +4498,21 @@ public abstract class Component
 		return isEnabledInHierarchy() && isVisibleInHierarchy();
 	}
 
+	/** {@inheritDoc} */
 	public void renderHead(IHeaderResponse response)
 	{
 		// noop
 	}
+
+	/** {@inheritDoc} */
+	public void onEvent(IEvent<?> event)
+	{
+	}
+
+	/** {@inheritDoc} */
+	public final void send(IEventSink sink, Broadcast type, Object payload)
+	{
+		new ComponentEventSender(this).send(sink, type, payload);
+	}
+
 }

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/ComponentEvent.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/ComponentEvent.java?rev=986925&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/ComponentEvent.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/ComponentEvent.java Wed Aug 18 20:43:33 2010
@@ -0,0 +1,97 @@
+package org.apache.wicket;
+
+import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.event.IEvent;
+import org.apache.wicket.event.IEventSink;
+import org.apache.wicket.event.IEventSource;
+
+/**
+ * Implementation of {@link IEvent} raised by a component
+ * 
+ * @author Igor Vaynberg (ivaynberg)
+ * @param <T>
+ *            type of payload
+ */
+final class ComponentEvent<T> implements IEvent<T>
+{
+	private final IEventSink sink;
+	private final IEventSource source;
+	private final Broadcast type;
+	private final T payload;
+
+	private boolean stop;
+	private boolean shallow;
+
+	/**
+	 * Constructor
+	 * 
+	 * @param sink
+	 *            sink
+	 * @param source
+	 *            source
+	 * @param broadcast
+	 *            broadcast
+	 * @param payload
+	 *            payload
+	 */
+	public ComponentEvent(IEventSink sink, IEventSource source, Broadcast broadcast, T payload)
+	{
+		this.sink = sink;
+		this.source = source;
+		type = broadcast;
+		this.payload = payload;
+	}
+
+	/**
+	 * @return event sink
+	 */
+	public IEventSink getSink()
+	{
+		return sink;
+	}
+
+	/** {@inheritDoc} */
+	public IEventSource getSource()
+	{
+		return source;
+	}
+
+	/** {@inheritDoc} */
+	public Broadcast getType()
+	{
+		return type;
+	}
+
+	/** {@inheritDoc} */
+	public T getPayload()
+	{
+		return payload;
+	}
+
+	/** {@inheritDoc} */
+	public void dontBroadcastDeeper()
+	{
+		shallow = true;
+	}
+
+	/** {@inheritDoc} */
+	public void stop()
+	{
+		stop = true;
+	}
+
+	boolean isStop()
+	{
+		return stop;
+	}
+
+	boolean isShallow()
+	{
+		return shallow;
+	}
+
+	void resetShallow()
+	{
+		shallow = false;
+	}
+}
\ No newline at end of file

Propchange: wicket/trunk/wicket/src/main/java/org/apache/wicket/ComponentEvent.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/ComponentEventSender.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/ComponentEventSender.java?rev=986925&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/ComponentEventSender.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/ComponentEventSender.java Wed Aug 18 20:43:33 2010
@@ -0,0 +1,282 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket;
+
+import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.event.IEventSink;
+import org.apache.wicket.event.IEventSource;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.util.lang.Checks;
+import org.apache.wicket.util.visit.IVisit;
+import org.apache.wicket.util.visit.IVisitor;
+import org.apache.wicket.util.visit.Visits;
+
+/**
+ * Implements event {@link Broadcast}ing
+ * 
+ * @author Igor Vaynberg (ivaynberg)
+ */
+final class ComponentEventSender implements IEventSource
+{
+	private final Component source;
+
+	/**
+	 * Constructor
+	 * 
+	 * @param source
+	 *            component that originated the event
+	 */
+	public ComponentEventSender(Component source)
+	{
+		this.source = source;
+	}
+
+	/** {@inheritDoc} */
+	public void send(IEventSink sink, Broadcast type, Object payload)
+	{
+		ComponentEvent event = new ComponentEvent(sink, source, type, payload);
+		Checks.argumentNotNull(type, "type");
+		switch (type)
+		{
+			case BUBBLE :
+				bubble(event);
+				break;
+			case BREADTH :
+				breadth(event);
+				break;
+			case DEPTH :
+				depth(event);
+				break;
+			case EXACT :
+				event.getSink().onEvent(event);
+				break;
+		}
+	}
+
+	/**
+	 * Breadth broadcast
+	 * 
+	 * @param event
+	 */
+	private void breadth(final ComponentEvent event)
+	{
+		IEventSink sink = event.getSink();
+
+		boolean targetsApplication = sink instanceof Application;
+		boolean targetsSession = targetsApplication || sink instanceof Session;
+		boolean targetsCycle = targetsSession || sink instanceof RequestCycle;
+		boolean targetsComponent = sink instanceof Component;
+
+		if (!targetsComponent && !targetsCycle)
+		{
+			sink.onEvent(event);
+			return;
+		}
+
+		if (targetsApplication)
+		{
+			source.getApplication().onEvent(event);
+		}
+		if (event.isStop())
+		{
+			return;
+		}
+		if (targetsSession)
+		{
+			source.getSession().onEvent(event);
+		}
+		if (event.isStop())
+		{
+			return;
+		}
+		if (targetsCycle)
+		{
+			source.getRequestCycle().onEvent(event);
+		}
+		if (event.isStop())
+		{
+			return;
+		}
+
+		Component cursor = (targetsCycle) ? cursor = source.getPage() : (Component)sink;
+
+		cursor.onEvent(event);
+
+		if (event.isStop())
+		{
+			return;
+		}
+
+		event.resetShallow(); // reset shallow flag
+
+		if (cursor instanceof MarkupContainer)
+		{
+			((MarkupContainer)cursor).visitChildren(new ComponentEventVisitor(event));
+		}
+	}
+
+	/**
+	 * Depth broadcast
+	 * 
+	 * @param event
+	 *            event
+	 */
+	private void depth(final ComponentEvent event)
+	{
+		IEventSink sink = event.getSink();
+
+		boolean targetsApplication = sink instanceof Application;
+		boolean targetsSession = targetsApplication || sink instanceof Session;
+		boolean targetsCycle = targetsSession || sink instanceof RequestCycle;
+		boolean targetsComponnet = sink instanceof Component;
+
+		if (!targetsComponnet && !targetsCycle)
+		{
+			sink.onEvent(event);
+			return;
+		}
+
+		Component cursor = (targetsCycle) ? source.getPage() : (Component)sink;
+
+		if (cursor instanceof MarkupContainer)
+		{
+			Visits.visitComponentsPostOrder(cursor, new ComponentEventVisitor(event));
+		}
+		if (event.isStop())
+		{
+			return;
+		}
+		if (targetsCycle)
+		{
+			source.getRequestCycle().onEvent(event);
+		}
+		if (event.isStop())
+		{
+			return;
+		}
+		if (targetsSession)
+		{
+			source.getSession().onEvent(event);
+		}
+		if (event.isStop())
+		{
+			return;
+		}
+		if (targetsApplication)
+		{
+			source.getApplication().onEvent(event);
+		}
+	}
+
+	/**
+	 * Bubbles the event
+	 * 
+	 * @param event
+	 *            event
+	 */
+	private void bubble(ComponentEvent event)
+	{
+		IEventSink sink = event.getSink();
+
+		boolean targetsComponent = sink instanceof Component;
+		boolean targetsCycle = targetsComponent || sink instanceof RequestCycle;
+		boolean targetsSession = targetsCycle || sink instanceof Session;
+		boolean targetsApplication = targetsSession || sink instanceof Application;
+
+		if (!targetsApplication && !targetsComponent)
+		{
+			sink.onEvent(event);
+			return;
+		}
+
+		if (targetsComponent)
+		{
+			Component cursor = (Component)sink;
+			cursor.onEvent(event);
+			if (event.isStop())
+			{
+				return;
+			}
+			cursor.visitParents(Component.class, new ComponentEventVisitor(event));
+		}
+
+		if (event.isStop())
+		{
+			return;
+		}
+		if (targetsCycle)
+		{
+			source.getRequestCycle().onEvent(event);
+		}
+		if (event.isStop())
+		{
+			return;
+		}
+		if (targetsSession)
+		{
+			source.getSession().onEvent(event);
+		}
+		if (event.isStop())
+		{
+			return;
+		}
+		if (targetsApplication)
+		{
+			source.getApplication().onEvent(event);
+		}
+	}
+
+	/**
+	 * Visitor used to broadcast events to components
+	 * 
+	 * @author igor
+	 */
+	private static class ComponentEventVisitor implements IVisitor<Component, Void>
+	{
+		private final ComponentEvent e;
+
+		/**
+		 * Constructor
+		 * 
+		 * @param event
+		 *            event to send
+		 */
+		private ComponentEventVisitor(ComponentEvent event)
+		{
+			e = event;
+		}
+
+		/** {@inheritDoc} */
+		public void component(Component object, IVisit<Void> visit)
+		{
+			object.onEvent(e);
+
+			if (e.isStop())
+			{
+				visit.stop();
+			}
+
+			if (e.isShallow())
+			{
+				visit.dontGoDeeper();
+			}
+
+			e.resetShallow(); // reset shallow bit
+		}
+	}
+
+}

Propchange: wicket/trunk/wicket/src/main/java/org/apache/wicket/ComponentEventSender.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/Session.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/Session.java?rev=986925&r1=986924&r2=986925&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/Session.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/Session.java Wed Aug 18 20:43:33 2010
@@ -26,6 +26,8 @@ import java.util.Map;
 
 import org.apache.wicket.application.IClassResolver;
 import org.apache.wicket.authorization.IAuthorizationStrategy;
+import org.apache.wicket.event.IEvent;
+import org.apache.wicket.event.IEventSink;
 import org.apache.wicket.feedback.FeedbackMessage;
 import org.apache.wicket.feedback.FeedbackMessages;
 import org.apache.wicket.page.IPageManager;
@@ -105,7 +107,7 @@ import org.slf4j.LoggerFactory;
  * @author Eelco Hillenius
  * @author Igor Vaynberg (ivaynberg)
  */
-public abstract class Session implements IClusterable
+public abstract class Session implements IClusterable, IEventSink
 {
 	private static final long serialVersionUID = 1L;
 
@@ -833,4 +835,9 @@ public abstract class Session implements
 	{
 		return getApplication().getPageManager();
 	}
+
+	/** {@inheritDoc} */
+	public void onEvent(IEvent<?> event)
+	{
+	}
 }

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/event/Broadcast.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/event/Broadcast.java?rev=986925&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/event/Broadcast.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/event/Broadcast.java Wed Aug 18 20:43:33 2010
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.event;
+
+import java.awt.Component;
+
+import org.apache.wicket.Application;
+import org.apache.wicket.Page;
+import org.apache.wicket.Session;
+import org.apache.wicket.request.cycle.RequestCycle;
+
+/**
+ * Defines the event broadcast type.
+ * 
+ * @author igor
+ */
+public enum Broadcast {
+	/**
+	 * Breadth first traversal. Supported sinks in order of traversal:
+	 * 
+	 * <ol>
+	 * <li>{@link Application}</li>
+	 * <li>{@link Session}</li>
+	 * <li>{@link RequestCycle}</li>
+	 * <li>{@link Page}</li>
+	 * <li>{@link Component}s</li>
+	 * </ol>
+	 * 
+	 * Any sink along the path can be specified and traversal will start with the specified sink as
+	 * root, eg:
+	 * 
+	 * <ul>
+	 * <li>If a component inside the page is specified then only the component and all its children
+	 * will receive the event</li>
+	 * <li>If Session is specified then the session, the request cycle, the page and all its
+	 * components will receive the event</li>
+	 * </ul>
+	 */
+	BREADTH,
+	/**
+	 * Depth first traversal. Supported sinks in order of traversal:
+	 * 
+	 * <ol>
+	 * <li>{@link Component}s</li>
+	 * <li>{@link Page}</li>
+	 * <li>{@link RequestCycle}</li>
+	 * <li>{@link Session}</li>
+	 * <li>{@link Application}</li>
+	 * </ol>
+	 * 
+	 * Any sink along the path can be specified and traversal will start with the specified sink as
+	 * root, eg:
+	 * 
+	 * <ul>
+	 * <li>If a component inside the page is specified then only the component and all its children
+	 * will receive the event</li>
+	 * <li>If Session is specified then the session, the request cycle, the page and all its
+	 * components will receive the event</li>
+	 * </ul>
+	 * 
+	 */
+	DEPTH,
+	/**
+	 * A bubble-up traversal. In a bubble-up traversal only the sink and its parents are notified.
+	 * 
+	 * Supported sinks in order of traversal are:
+	 * <ol>
+	 * <li>{@link Component}s</li>
+	 * <li>{@link Page}</li>
+	 * <li>{@link RequestCycle}</li>
+	 * <li>{@link Session}</li>
+	 * <li>{@link Application}</li>
+	 * </ol>
+	 * 
+	 * Any sink along the path can be specified and traversal will start at the specified sink and
+	 * work its way up to the {@link Application}, eg:
+	 * 
+	 * <ul>
+	 * <li>If a component inside the page is specified then only the component, its parents, the
+	 * request cycle, the session, and the application will be notified.
+	 * <li>If Session is specified then the session, the application will be notified</li>
+	 * </ul>
+	 */
+	BUBBLE,
+	/**
+	 * Only the specified sink receives the event
+	 */
+	EXACT;
+}

Propchange: wicket/trunk/wicket/src/main/java/org/apache/wicket/event/Broadcast.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/event/IEvent.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/event/IEvent.java?rev=986925&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/event/IEvent.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/event/IEvent.java Wed Aug 18 20:43:33 2010
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.event;
+
+/**
+ * An event
+ * 
+ * @author Igor Vaynberg (ivaynberg)
+ * @param <T>
+ *            type of event payload
+ */
+public interface IEvent<T>
+{
+	/**
+	 * Stops any further broadcast of this event
+	 */
+	void stop();
+
+	/**
+	 * Stops the broadcast of this event any deeper into the hierarchy of the current sink
+	 */
+	void dontBroadcastDeeper();
+
+	/**
+	 * @return type of broadcast that should be used to pass this event on
+	 */
+	Broadcast getType();
+
+	/**
+	 * @return the source of event
+	 */
+	IEventSource getSource();
+
+	/**
+	 * @return payload
+	 */
+	T getPayload();
+}

Propchange: wicket/trunk/wicket/src/main/java/org/apache/wicket/event/IEvent.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/event/IEventSink.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/event/IEventSink.java?rev=986925&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/event/IEventSink.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/event/IEventSink.java Wed Aug 18 20:43:33 2010
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.event;
+
+/**
+ * Objects that can receive events
+ * 
+ * @author Igor Vaynberg (ivaynberg)
+ */
+public interface IEventSink
+{
+	/**
+	 * Called when an event is sent to this sink
+	 * 
+	 * @param event
+	 */
+	void onEvent(IEvent<?> event);
+}

Propchange: wicket/trunk/wicket/src/main/java/org/apache/wicket/event/IEventSink.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/event/IEventSource.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/event/IEventSource.java?rev=986925&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/event/IEventSource.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/event/IEventSource.java Wed Aug 18 20:43:33 2010
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.event;
+
+/**
+ * Objects that can send events
+ * 
+ * @author Igor Vaynberg (ivaynberg)
+ */
+public interface IEventSource
+{
+	/**
+	 * Sends an event
+	 * 
+	 * @param sink
+	 *            object that will receive the event
+	 * @param broadcast
+	 *            if the object that receives the event needs to broadcast it to others, this is the
+	 *            type of broadcast that should be used
+	 * @param payload
+	 *            event payload
+	 */
+	void send(IEventSink sink, Broadcast broadcast, Object payload);
+}

Propchange: wicket/trunk/wicket/src/main/java/org/apache/wicket/event/IEventSource.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/RequestCycle.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/RequestCycle.java?rev=986925&r1=986924&r2=986925&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/RequestCycle.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/RequestCycle.java Wed Aug 18 20:43:33 2010
@@ -24,6 +24,8 @@ import org.apache.wicket.MetaDataKey;
 import org.apache.wicket.Page;
 import org.apache.wicket.Session;
 import org.apache.wicket.ThreadContext;
+import org.apache.wicket.event.IEvent;
+import org.apache.wicket.event.IEventSink;
 import org.apache.wicket.request.IExceptionMapper;
 import org.apache.wicket.request.IRequestCycle;
 import org.apache.wicket.request.IRequestHandler;
@@ -62,7 +64,7 @@ import org.slf4j.LoggerFactory;
  * @author Matej Knopp
  * @author igor.vaynberg
  */
-public class RequestCycle extends RequestHandlerStack implements IRequestCycle
+public class RequestCycle extends RequestHandlerStack implements IRequestCycle, IEventSink
 {
 	private static final Logger log = LoggerFactory.getLogger(RequestCycle.class);
 
@@ -578,4 +580,9 @@ public class RequestCycle extends Reques
 	{
 		return startTime;
 	}
+
+	/** {@inheritDoc} */
+	public void onEvent(IEvent<?> event)
+	{
+	}
 }

Added: wicket/trunk/wicket/src/test/java/org/apache/wicket/ComponentEventsTest.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/test/java/org/apache/wicket/ComponentEventsTest.java?rev=986925&view=auto
==============================================================================
--- wicket/trunk/wicket/src/test/java/org/apache/wicket/ComponentEventsTest.java (added)
+++ wicket/trunk/wicket/src/test/java/org/apache/wicket/ComponentEventsTest.java Wed Aug 18 20:43:33 2010
@@ -0,0 +1,575 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.event.IEvent;
+import org.apache.wicket.markup.html.WebComponent;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.mock.MockApplication;
+import org.apache.wicket.protocol.http.WebSession;
+import org.apache.wicket.request.Request;
+import org.apache.wicket.request.Response;
+import org.apache.wicket.request.cycle.RequestCycle;
+import org.apache.wicket.request.cycle.RequestCycleContext;
+import org.apache.wicket.util.tester.WicketTester;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+
+/**
+ * Tests component events
+ * 
+ * @author igor
+ */
+public class ComponentEventsTest
+{
+
+	private WicketTester tester;
+	private TestPage page;
+	private TestContainer c1;
+	private TestContainer c12;
+	private TestContainer c13;
+	private TestContainer c134;
+	private TestComponent c135;
+	private TestComponent c6;
+	private TestApplication application;
+	private TestSession session;
+	private TestRequestCycle cycle;
+	private Testable[] all;
+
+	private Object stop;
+
+	/** */
+	@Before
+	public void setup()
+	{
+		tester = new WicketTester(new TestApplication());
+
+		application = (TestApplication)tester.getApplication();
+
+		session = (TestSession)tester.getSession();
+		cycle = (TestRequestCycle)tester.getRequestCycle();
+
+		page = new TestPage();
+		c1 = new TestContainer("c1");
+		c12 = new TestContainer("c12");
+		c13 = new TestContainer("c13");
+		c134 = new TestContainer("c134");
+		c135 = new TestComponent("c135");
+		c6 = new TestComponent("c6");
+
+		page.add(c1);
+		c1.add(c12);
+		c1.add(c13);
+		c13.add(c134);
+		c13.add(c135);
+		page.add(c6);
+
+		all = new Testable[] { page, c1, c12, c13, c134, c135, c6, application, session, cycle };
+
+		stop = null;
+	}
+
+	/** */
+	@After
+	public void destroy()
+	{
+		tester.destroy();
+	}
+
+	/** */
+	@Test
+	public void testBreadth_Application()
+	{
+		page.send(tester.getApplication(), Broadcast.BREADTH, new Payload());
+		assertPath(application, session, cycle, page, c1, c12, c13, c134, c135, c6);
+	}
+
+	/** */
+	@Test
+	public void testBreadth_Session()
+	{
+		page.send(tester.getSession(), Broadcast.BREADTH, new Payload());
+		assertPath(session, cycle, page, c1, c12, c13, c134, c135, c6);
+	}
+
+	/** */
+	@Test
+	public void testBreadth_Cycle()
+	{
+		page.send(tester.getRequestCycle(), Broadcast.BREADTH, new Payload());
+		assertPath(cycle, page, c1, c12, c13, c134, c135, c6);
+	}
+
+	/** */
+	@Test
+	public void testBreadth_Page()
+	{
+		page.send(page, Broadcast.BREADTH, new Payload());
+		assertPath(page, c1, c12, c13, c134, c135, c6);
+	}
+
+	/** */
+	@Test
+	public void testBreadth_Component()
+	{
+		page.send(c13, Broadcast.BREADTH, new Payload());
+		assertPath(c13, c134, c135);
+	}
+
+	/** */
+	@Test
+	public void testBreadth_Application_Stop()
+	{
+		stop = application;
+		page.send(application, Broadcast.BREADTH, new Payload());
+		assertPath(application);
+	}
+
+	/** */
+	@Test
+	public void testBreadth_Session_Stop()
+	{
+		stop = session;
+		page.send(application, Broadcast.BREADTH, new Payload());
+		assertPath(application, session);
+	}
+
+	/** */
+	@Test
+	public void testBreadth_Cycle_Stop()
+	{
+		stop = cycle;
+		page.send(application, Broadcast.BREADTH, new Payload());
+		assertPath(application, session, cycle);
+	}
+
+	/** */
+	@Test
+	public void testBreadth_Page_Stop()
+	{
+		stop = page;
+		page.send(application, Broadcast.BREADTH, new Payload());
+		assertPath(application, session, cycle, page);
+	}
+
+	/** */
+	@Test
+	public void testBreadth_Component_Stop()
+	{
+		stop = c13;
+		page.send(application, Broadcast.BREADTH, new Payload());
+		assertPath(application, session, cycle, page, c1, c12, c13);
+	}
+
+
+	/** */
+	@Test
+	public void testDepth_Application()
+	{
+		page.send(application, Broadcast.DEPTH, new Payload());
+		assertPath(c12, c134, c135, c13, c1, c6, page, cycle, session, application);
+	}
+
+	/** */
+	@Test
+	public void testDepth_Session()
+	{
+		page.send(session, Broadcast.DEPTH, new Payload());
+		assertPath(c12, c134, c135, c13, c1, c6, page, cycle, session);
+	}
+
+	/** */
+	@Test
+	public void testDepth_Cycle()
+	{
+		page.send(cycle, Broadcast.DEPTH, new Payload());
+		assertPath(c12, c134, c135, c13, c1, c6, page, cycle);
+	}
+
+	/** */
+	@Test
+	public void testDepth_Page()
+	{
+		page.send(page, Broadcast.DEPTH, new Payload());
+		assertPath(c12, c134, c135, c13, c1, c6, page);
+	}
+
+	/** */
+	@Test
+	public void testDepth_Component()
+	{
+		page.send(c1, Broadcast.DEPTH, new Payload());
+		assertPath(c12, c134, c135, c13, c1);
+	}
+
+	/** */
+	@Test
+	public void testDepth_Session_Stop()
+	{
+		stop = session;
+		page.send(application, Broadcast.DEPTH, new Payload());
+		assertPath(c12, c134, c135, c13, c1, c6, page, cycle, session);
+	}
+
+	/** */
+	@Test
+	public void testDepth_Cycle_Stop()
+	{
+		stop = cycle;
+		page.send(application, Broadcast.DEPTH, new Payload());
+		assertPath(c12, c134, c135, c13, c1, c6, page, cycle);
+	}
+
+	/** */
+	@Test
+	public void testDepth_Page_Stop()
+	{
+		stop = page;
+		page.send(application, Broadcast.DEPTH, new Payload());
+		assertPath(c12, c134, c135, c13, c1, c6, page);
+	}
+
+	/** */
+	@Test
+	public void testDepth_Component_Stop()
+	{
+		stop = c1;
+		page.send(application, Broadcast.DEPTH, new Payload());
+		assertPath(c12, c134, c135, c13, c1);
+	}
+
+
+	/**
+	 * 
+	 */
+	@Test
+	public void testBubble_Component()
+	{
+		c6.send(c135, Broadcast.BUBBLE, new Payload());
+		assertPath(c135, c13, c1, page, cycle, session, application);
+	}
+
+	/** */
+	@Test
+	public void testBubble_Page()
+	{
+		c6.send(page, Broadcast.BUBBLE, new Payload());
+		assertPath(page, cycle, session, application);
+	}
+
+	/** */
+	@Test
+	public void testBubble_Cycle()
+	{
+		c6.send(cycle, Broadcast.BUBBLE, new Payload());
+		assertPath(cycle, session, application);
+	}
+
+	/** */
+	@Test
+	public void testBubble_Session()
+	{
+		c6.send(session, Broadcast.BUBBLE, new Payload());
+		assertPath(session, application);
+	}
+
+
+	/** */
+	@Test
+	public void testBubble_Application()
+	{
+		c6.send(application, Broadcast.BUBBLE, new Payload());
+		assertPath(application);
+	}
+
+	/** */
+	@Test
+	public void testBubble_Component_Stop()
+	{
+		stop = c1;
+		c6.send(c135, Broadcast.BUBBLE, new Payload());
+		assertPath(c135, c13, c1);
+	}
+
+	/** */
+	@Test
+	public void testBubble_Component_Page()
+	{
+		stop = page;
+		c6.send(c135, Broadcast.BUBBLE, new Payload());
+		assertPath(c135, c13, c1, page);
+	}
+
+	/** */
+	@Test
+	public void testBubble_Cycle_Stop()
+	{
+		stop = cycle;
+		c6.send(c135, Broadcast.BUBBLE, new Payload());
+		assertPath(c135, c13, c1, page, cycle);
+	}
+
+	/** */
+	@Test
+	public void testBubble_Session_Stop()
+	{
+		stop = session;
+		c6.send(c135, Broadcast.BUBBLE, new Payload());
+		assertPath(c135, c13, c1, page, cycle, session);
+	}
+
+
+	private void assertPath(Testable... testables)
+	{
+		List<Testable> remaining = new ArrayList<Testable>(Arrays.asList(all));
+
+		for (int i = 0; i < testables.length; i++)
+		{
+			Assert.assertEquals("checking path element " + i, i, testables[i].getSequence());
+			remaining.remove(testables[i]);
+		}
+
+		for (Testable testable : remaining)
+		{
+			String name = testable.getClass().getSimpleName();
+			if (testable instanceof Component && !(testable instanceof Page))
+			{
+				name += "#" + ((Component)testable).getId();
+			}
+			Assert.assertEquals(name + " should not have been visited, but was.", -1,
+				testable.getSequence());
+		}
+	}
+
+	private static interface Testable
+	{
+		int getSequence();
+	}
+
+
+	private class TestApplication extends MockApplication implements Testable
+	{
+		int sequence = -1;
+
+		@Override
+		public void onEvent(IEvent<?> event)
+		{
+			super.onEvent(event);
+			Payload payload = (Payload)event.getPayload();
+			sequence = payload.next();
+			if (stop == this)
+			{
+				event.stop();
+			}
+		}
+
+		@Override
+		public Session newSession(Request request, Response response)
+		{
+			return new TestSession(request);
+		}
+
+		@Override
+		protected void init()
+		{
+			super.init();
+			setRequestCycleProvider(new IRequestCycleProvider()
+			{
+				public RequestCycle get(RequestCycleContext context)
+				{
+					return new TestRequestCycle(context);
+				}
+			});
+		}
+
+		public int getSequence()
+		{
+			return sequence;
+		}
+	}
+
+	private class TestSession extends WebSession implements Testable
+	{
+		private static final long serialVersionUID = 1L;
+
+		int sequence = -1;
+
+		public TestSession(Request request)
+		{
+			super(request);
+		}
+
+
+		public int getSequence()
+		{
+			return sequence;
+		}
+
+		@Override
+		public void onEvent(IEvent<?> event)
+		{
+			super.onEvent(event);
+			Payload payload = (Payload)event.getPayload();
+			sequence = payload.next();
+			if (stop == this)
+			{
+				event.stop();
+			}
+		}
+	}
+
+	private class TestRequestCycle extends RequestCycle implements Testable
+	{
+		int sequence = -1;
+
+		public TestRequestCycle(RequestCycleContext context)
+		{
+			super(context);
+		}
+
+
+		public int getSequence()
+		{
+			return sequence;
+		}
+
+		@Override
+		public void onEvent(IEvent<?> event)
+		{
+			super.onEvent(event);
+			Payload payload = (Payload)event.getPayload();
+			sequence = payload.next();
+			if (stop == this)
+			{
+				event.stop();
+			}
+		}
+	}
+
+
+	private class TestPage extends WebPage implements Testable
+	{
+		int sequence = -1;
+
+		public TestPage()
+		{
+		}
+
+
+		public int getSequence()
+		{
+			return sequence;
+		}
+
+		@Override
+		public void onEvent(IEvent<?> event)
+		{
+			super.onEvent(event);
+			Payload payload = (Payload)event.getPayload();
+			sequence = payload.next();
+			// System.out.println(getId());
+			if (stop == this)
+			{
+				event.stop();
+			}
+		}
+
+	}
+
+
+	private class TestContainer extends WebMarkupContainer implements Testable
+	{
+		private static final long serialVersionUID = 1L;
+
+		int sequence = -1;
+
+		public TestContainer(String id)
+		{
+			super(id);
+		}
+
+		@Override
+		public void onEvent(IEvent<?> event)
+		{
+			super.onEvent(event);
+			Payload payload = (Payload)event.getPayload();
+			sequence = payload.next();
+			// System.out.println(getId());
+			if (stop == this)
+			{
+				event.stop();
+			}
+		}
+
+
+		public int getSequence()
+		{
+			return sequence;
+		}
+	}
+
+	private class TestComponent extends WebComponent implements Testable
+	{
+		private static final long serialVersionUID = 1L;
+
+		int sequence = -1;
+
+		public TestComponent(String id)
+		{
+			super(id);
+		}
+
+		@Override
+		public void onEvent(IEvent<?> event)
+		{
+			super.onEvent(event);
+			Payload payload = (Payload)event.getPayload();
+			sequence = payload.next();
+			// System.out.println(getId());
+			if (stop == this)
+			{
+				event.stop();
+			}
+		}
+
+
+		public int getSequence()
+		{
+			return sequence;
+		}
+	}
+
+	private static class Payload
+	{
+		private int counter;
+
+		public int next()
+		{
+			return counter++;
+		}
+	}
+
+}

Propchange: wicket/trunk/wicket/src/test/java/org/apache/wicket/ComponentEventsTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain