summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Dahlström <johannesd@vaadin.com>2012-09-20 14:07:14 +0300
committerJohannes Dahlström <johannesd@vaadin.com>2012-09-20 14:08:51 +0300
commit2079e8525df2b12aa8f1103755c91ec2ab1fca95 (patch)
tree59a22f56d1096f4ef96bc8a969f0bf99c0f5e829
parent6b28dc7bf41b8590fcab3d60afd5aa407f1f1401 (diff)
downloadvaadin-framework-2079e8525df2b12aa8f1103755c91ec2ab1fca95.tar.gz
vaadin-framework-2079e8525df2b12aa8f1103755c91ec2ab1fca95.zip
Add a means to handle missing views in Navigator (#9060)
-rw-r--r--server/src/com/vaadin/navigator/Navigator.java90
-rw-r--r--uitest/src/com/vaadin/tests/navigator/NavigatorTest.html55
-rw-r--r--uitest/src/com/vaadin/tests/navigator/NavigatorTest.java11
3 files changed, 145 insertions, 11 deletions
diff --git a/server/src/com/vaadin/navigator/Navigator.java b/server/src/com/vaadin/navigator/Navigator.java
index 257dfa208f..c9f6946ce5 100644
--- a/server/src/com/vaadin/navigator/Navigator.java
+++ b/server/src/com/vaadin/navigator/Navigator.java
@@ -112,7 +112,7 @@ public class Navigator implements Serializable {
public String getState() {
String fragment = page.getFragment();
if (fragment.startsWith("!")) {
- return page.getFragment().substring(1);
+ return fragment.substring(1);
} else {
return "";
}
@@ -338,6 +338,7 @@ public class Navigator implements Serializable {
private View currentView = null;
private List<ViewChangeListener> listeners = new LinkedList<ViewChangeListener>();
private List<ViewProvider> providers = new LinkedList<ViewProvider>();
+ private ViewProvider errorProvider;
/**
* Creates a navigator that is tracking the active view using URI fragments
@@ -443,6 +444,8 @@ public class Navigator implements Serializable {
*
* @param navigationState
* view name and parameters
+ *
+ * @throws IllegalArgumentException
*/
public void navigateTo(String navigationState) {
String longestViewName = null;
@@ -459,6 +462,10 @@ public class Navigator implements Serializable {
}
}
}
+ if (viewWithLongestName == null && errorProvider != null) {
+ longestViewName = errorProvider.getViewName(navigationState);
+ viewWithLongestName = errorProvider.getView(longestViewName);
+ }
if (viewWithLongestName != null) {
String parameters = "";
if (navigationState.length() > longestViewName.length() + 1) {
@@ -466,8 +473,12 @@ public class Navigator implements Serializable {
.substring(longestViewName.length() + 1);
}
navigateTo(viewWithLongestName, longestViewName, parameters);
+ } else {
+ throw new IllegalArgumentException(
+ "Trying to navigate to an unknown state '"
+ + navigationState
+ + "' and an error view provider not present");
}
- // TODO if no view is found, what to do?
}
/**
@@ -600,11 +611,11 @@ public class Navigator implements Serializable {
}
/**
- * Register a view class for a view name.
+ * Registers a view class for a view name.
* <p>
* Registering another view with a name that is already registered
* overwrites the old registration of the same type.
- *
+ * <p>
* A new view instance is created every time a view is requested.
*
* @param viewName
@@ -676,9 +687,76 @@ public class Navigator implements Serializable {
}
/**
- * Adds a listener for listening to changes of the active view.
+ * Registers a view class that is instantiated when no other view matches
+ * the navigation state. This implicitly sets an appropriate error view
+ * provider and overrides any previous
+ * {@link #setErrorProvider(ViewProvider)} call.
+ *
+ * @param viewClass
+ * The View class whose instance should be used as the error
+ * view.
+ */
+ public void setErrorView(final Class<? extends View> viewClass) {
+ setErrorProvider(new ViewProvider() {
+ @Override
+ public View getView(String viewName) {
+ try {
+ return viewClass.newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public String getViewName(String navigationState) {
+ return navigationState;
+ }
+ });
+ }
+
+ /**
+ * Registers a view that is displayed when no other view matches the
+ * navigation state. This implicitly sets an appropriate error view provider
+ * and overrides any previous {@link #setErrorProvider(ViewProvider)} call.
+ *
+ * @param view
+ * The View that should be used as the error view.
+ */
+ public void setErrorView(final View view) {
+ setErrorProvider(new ViewProvider() {
+ @Override
+ public View getView(String viewName) {
+ return view;
+ };
+
+ @Override
+ public String getViewName(String navigationState) {
+ return navigationState;
+ }
+ });
+ }
+
+ /**
+ * Registers a view provider that is queried for a view when no other view
+ * matches the navigation state. An error view provider should match any
+ * navigation state, but could return different views for different states.
+ * Its <code>getViewName(String navigationState)</code> should return
+ * <code>navigationState</code>.
+ *
+ * @param provider
+ */
+ public void setErrorProvider(ViewProvider provider) {
+ errorProvider = provider;
+ }
+
+ /**
+ * Listen to changes of the active view.
* <p>
- * The listener will get notified after the view has changed.
+ * Registered listeners are invoked in registration order before (
+ * {@link ViewChangeListener#beforeViewChange(ViewChangeEvent)
+ * beforeViewChange()}) and after (
+ * {@link ViewChangeListener#afterViewChange(ViewChangeEvent)
+ * afterViewChange()}) a view change occurs.
*
* @param listener
* Listener to invoke during a view change.
diff --git a/uitest/src/com/vaadin/tests/navigator/NavigatorTest.html b/uitest/src/com/vaadin/tests/navigator/NavigatorTest.html
index 8c4e8f657b..030b30f37a 100644
--- a/uitest/src/com/vaadin/tests/navigator/NavigatorTest.html
+++ b/uitest/src/com/vaadin/tests/navigator/NavigatorTest.html
@@ -17,6 +17,11 @@
<td></td>
</tr>
<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestsnavigatorNavigatorTest::/VVerticalLayout[0]/VOrderedLayout$Slot[4]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VLabel[0]</td>
+ <td>1. Navigated to DefaultView with params</td>
+</tr>
+<tr>
<td>click</td>
<td>vaadin=runcomvaadintestsnavigatorNavigatorTest::/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VButton[0]/domChild[0]/domChild[0]</td>
<td></td>
@@ -24,7 +29,7 @@
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestsnavigatorNavigatorTest::/VVerticalLayout[0]/VOrderedLayout$Slot[4]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VLabel[0]</td>
- <td>1. Navigated to ListView with params</td>
+ <td>2. Navigated to ListView with params</td>
</tr>
<tr>
<td>assertLocation</td>
@@ -39,7 +44,7 @@
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestsnavigatorNavigatorTest::/VVerticalLayout[0]/VOrderedLayout$Slot[4]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VLabel[0]</td>
- <td>2. Navigated to EditView with params</td>
+ <td>3. Navigated to EditView with params</td>
</tr>
<tr>
<td>assertLocation</td>
@@ -64,7 +69,7 @@
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestsnavigatorNavigatorTest::/VVerticalLayout[0]/VOrderedLayout$Slot[4]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VLabel[0]</td>
- <td>3. Navigated to ListView with params param=value</td>
+ <td>4. Navigated to ListView with params param=value</td>
</tr>
<tr>
<td>assertLocation</td>
@@ -79,7 +84,7 @@
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestsnavigatorNavigatorTest::/VVerticalLayout[0]/VOrderedLayout$Slot[4]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VLabel[0]</td>
- <td>4. Navigated to EditView with params param=value</td>
+ <td>5. Navigated to EditView with params param=value</td>
</tr>
<tr>
<td>assertLocation</td>
@@ -94,13 +99,53 @@
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestsnavigatorNavigatorTest::/VVerticalLayout[0]/VOrderedLayout$Slot[4]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VLabel[0]</td>
- <td>5. Prevent navigation to ForbiddenView</td>
+ <td>6. Prevent navigation to ForbiddenView</td>
</tr>
<tr>
<td>assertLocation</td>
<td>*#!edit/param=value</td>
<td></td>
</tr>
+<tr>
+ <td>runScript</td>
+ <td>window.location.hash='!foo'</td>
+ <td></td>
+</tr>
+<tr>
+ <td>pause</td>
+ <td>1000</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestsnavigatorNavigatorTest::/VVerticalLayout[0]/VOrderedLayout$Slot[4]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VLabel[0]</td>
+ <td>7. View 'foo' not found!</td>
+</tr>
+<tr>
+ <td>assertLocation</td>
+ <td>*#!foo</td>
+ <td></td>
+</tr>
+<tr>
+ <td>runScript</td>
+ <td>window.location.hash='foo'</td>
+ <td></td>
+</tr>
+<tr>
+ <td>pause</td>
+ <td>1000</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestsnavigatorNavigatorTest::/VVerticalLayout[0]/VOrderedLayout$Slot[4]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VLabel[0]</td>
+ <td>8. Navigated to DefaultView with params</td>
+</tr>
+<tr>
+ <td>assertLocation</td>
+ <td>*#foo</td>
+ <td></td>
+</tr>
</tbody></table>
</body>
diff --git a/uitest/src/com/vaadin/tests/navigator/NavigatorTest.java b/uitest/src/com/vaadin/tests/navigator/NavigatorTest.java
index 4986bd21e6..a3f7ce9f5b 100644
--- a/uitest/src/com/vaadin/tests/navigator/NavigatorTest.java
+++ b/uitest/src/com/vaadin/tests/navigator/NavigatorTest.java
@@ -74,6 +74,15 @@ public class NavigatorTest extends UI {
}
}
+ class ErrorView extends Label implements View {
+ @Override
+ public void enter(ViewChangeEvent event) {
+ log.log("View '" + event.getViewName() + "' not found!");
+ setValue("Tried to navigate to " + event.getViewName()
+ + " but such a view could not be found :(");
+ }
+ }
+
class NaviListener implements ViewChangeListener {
@Override
@@ -114,6 +123,8 @@ public class NavigatorTest extends UI {
navi.addViewChangeListener(new NaviListener());
+ navi.setErrorView(new ErrorView());
+
navi.navigate();
addComponent(new NaviButton("list"));