diff options
author | Henri Sara <hesara@vaadin.com> | 2012-06-12 14:17:41 +0300 |
---|---|---|
committer | Henri Sara <hesara@vaadin.com> | 2012-06-12 14:17:52 +0300 |
commit | fb31f69d0123af60f72db816406d3c7ee789ecd9 (patch) | |
tree | e4dc3ce59f278c85bb5bf8b1e147e2a40bdd43b1 /src | |
parent | a1a87b0ce6bf96f868f18177bebb1a226a5a2753 (diff) | |
download | vaadin-framework-fb31f69d0123af60f72db816406d3c7ee789ecd9.tar.gz vaadin-framework-fb31f69d0123af60f72db816406d3c7ee789ecd9.zip |
Navigator API changes based on review (#8859)
- Simplify the default providers and move addView()/removeView() logic
to Navigator itself.
- use longest matching view name to manage view hierarchy
- minor cleanup
Diffstat (limited to 'src')
-rw-r--r-- | src/com/vaadin/navigator/Navigator.java | 316 |
1 files changed, 172 insertions, 144 deletions
diff --git a/src/com/vaadin/navigator/Navigator.java b/src/com/vaadin/navigator/Navigator.java index 7c2cd1df55..9d9acf9ed3 100644 --- a/src/com/vaadin/navigator/Navigator.java +++ b/src/com/vaadin/navigator/Navigator.java @@ -5,7 +5,7 @@ package com.vaadin.navigator; import java.io.Serializable; -import java.util.HashMap; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -39,12 +39,15 @@ public class Navigator implements Serializable { // TODO divert navigation e.g. if no permissions? Or just show another view // but keep URL? how best to intercept - // TODO investigate relationship to TouchKit navigation support + // TODO investigate relationship with TouchKit navigation support /** * Empty view component. */ public static class EmptyView extends CssLayout implements View { + /** + * Create minimally sized empty view. + */ public EmptyView() { setWidth("0px"); setHeight("0px"); @@ -75,7 +78,7 @@ public class Navigator implements Serializable { * root whose URI fragment to get and modify * @param navigator * {@link Navigator} to notify of fragment changes (using - * {@link Navigator#navigateTo(String, Object...)} + * {@link Navigator#navigateTo(String)} */ public UriFragmentManager(Root root, Navigator navigator) { this.root = root; @@ -130,105 +133,105 @@ public class Navigator implements Serializable { } /** - * View provider which uses a map from view name to pre-created and - * registered view instances. + * View provider which supports mapping a single view name to a single + * pre-initialized view instance. + * + * For most cases, ClassBasedViewProvider should be used instead of this. */ - public static class RegisteredViewProvider implements ViewProvider { + public static class StaticViewProvider implements ViewProvider { + private final String viewName; + private final View view; - private HashMap<String, View> viewNameToView = new HashMap<String, View>(); + /** + * Create a new view provider which returns a pre-created view instance. + * + * @param viewName + * name of the view (not null) + * @param view + * view instance to return (not null), reused on every + * request + */ + public StaticViewProvider(String viewName, View view) { + this.viewName = viewName; + this.view = view; + } public String getViewName(String viewAndParameters) { if (null == viewAndParameters) { return null; } - for (String viewName : viewNameToView.keySet()) { - if (viewAndParameters.equals(viewName) - || viewAndParameters.startsWith(viewName + "/")) { - return viewName; - } + if (viewAndParameters.startsWith(viewName)) { + return viewName; } return null; } public View getView(String viewName) { - return viewNameToView.get(viewName); - } - - /** - * Register a view for a view name. - * - * Registering another view with a name that is already registered - * overwrites the old registration. - * - * @param viewName - * String that identifies a view (not null nor empty string) - * @param view - * {@link View} instance (not null) - */ - public void addView(String viewName, View view) { - - // Check parameters - if (viewName == null || view == null || viewName.length() == 0) { - throw new IllegalArgumentException( - "view and viewName must be non-null and not empty"); + if (this.viewName.equals(viewName)) { + return view; } - - viewNameToView.put(viewName, view); + return null; } /** - * Remove view from navigator. + * Get the view name for this provider. * - * @param viewName - * name of the view to remove + * @return view name for this provider */ - public void removeView(String viewName) { - viewNameToView.remove(viewName); + public String getViewName() { + return viewName; } } /** - * View provider which uses a map from view name to the class to instantiate - * for the view. - * - * Views that have been created are cached and reused when the same view - * name is requested again. + * View provider which maps a single view name to a class to instantiate for + * the view. * * Note that the view class must be accessible by the class loader used by * the provider. This may require its visibility to be public. + * + * This class is primarily for internal use by {@link Navigator}. */ public static class ClassBasedViewProvider implements ViewProvider { - private HashMap<String, Class<? extends View>> viewNameToClass = new HashMap<String, Class<? extends View>>(); - private HashMap<Class<? extends View>, String> classToViewName = new HashMap<Class<? extends View>, String>(); + private final String viewName; + private final Class<? extends View> viewClass; + /** - * Already opened (cached) views that can be reopened or reused with new - * parameters. + * Create a new view provider which creates new view instances based on + * a view class. + * + * @param viewName + * name of the views to create (not null) + * @param viewClass + * class to instantiate when a view is requested (not null) */ - private HashMap<Class<? extends View>, View> classToView = new HashMap<Class<? extends View>, View>(); + public ClassBasedViewProvider(String viewName, + Class<? extends View> viewClass) { + if (null == viewName || null == viewClass) { + throw new IllegalArgumentException( + "View name and class should not be null"); + } + this.viewName = viewName; + this.viewClass = viewClass; + } public String getViewName(String viewAndParameters) { if (null == viewAndParameters) { return null; } - for (String viewName : viewNameToClass.keySet()) { - if (viewAndParameters.equals(viewName) - || viewAndParameters.startsWith(viewName + "/")) { - return viewName; - } + if (viewAndParameters.equals(viewName) + || viewAndParameters.startsWith(viewName + "/")) { + return viewName; } return null; } public View getView(String viewName) { - Class<? extends View> newViewClass = viewNameToClass.get(viewName); - if (null == newViewClass) { - return null; - } - if (!classToView.containsKey(newViewClass)) { + if (this.viewName.equals(viewName)) { try { - View view = newViewClass.newInstance(); - classToView.put(newViewClass, view); + View view = viewClass.newInstance(); + return view; } catch (InstantiationException e) { // TODO error handling throw new RuntimeException(e); @@ -237,89 +240,25 @@ public class Navigator implements Serializable { throw new RuntimeException(e); } } - // return already cached view - final View v = classToView.get(newViewClass); - return v; - } - - /** - * Register a view class for a view name. - * - * @param viewName - * String that identifies a view (not null nor empty string) - * @param viewClass - * Component class that implements Navigator.View interface - * (not null) - */ - public void addView(String viewName, Class<? extends View> viewClass) { - - // Check parameters - if (viewName == null || viewClass == null || viewName.length() == 0) { - throw new IllegalArgumentException( - "viewClass and viewName must be non-null and not empty"); - } - - if (!View.class.isAssignableFrom(viewClass)) { - throw new IllegalArgumentException( - "viewClass must implement Navigator.View"); - } - - if (viewNameToClass.containsKey(viewName)) { - if (viewNameToClass.get(viewName) == viewClass) { - return; - } - - throw new IllegalArgumentException(viewNameToClass - .get(viewName).getName() - + " is already mapped to '" - + viewName + "'"); - } - - if (classToViewName.containsKey(viewClass)) { - throw new IllegalArgumentException( - "Each view class can only be added to Navigator with one view name"); - } - - viewNameToClass.put(viewName, viewClass); - classToViewName.put(viewClass, viewName); - } - - /** - * Remove view from navigator. - * - * @param viewName - * name of the view to remove - */ - public void removeView(String viewName) { - Class<? extends View> c = viewNameToClass.get(viewName); - if (c != null) { - viewNameToClass.remove(viewName); - classToViewName.remove(c); - classToView.remove(c); - } + return null; } /** - * Get the view name for given view implementation class. + * Get the view name for this provider. * - * @param viewClass - * Class that implements the view. - * @return view name for which the view class is registered, null if - * none + * @return view name for this provider */ - public String getViewName(Class<? extends View> viewClass) { - return classToViewName.get(viewClass); + public String getViewName() { + return viewName; } /** - * Get the view class for given view name. + * Get the view class for this provider. * - * @param viewName - * view name to get view for - * @return View that corresponds to the name + * @return {@link View} class */ - public Class<? extends View> getViewClass(String viewName) { - return viewNameToClass.get(viewName); + public Class<? extends View> getViewClass() { + return viewClass; } } @@ -380,29 +319,42 @@ public class Navigator implements Serializable { * and (fragment) parameters. ViewProviders are used to find and create the * correct type of view. * - * If the view being left indicates it wants a confirmation for the + * If multiple providers return a matching view, the view with the longest + * name is selected. This way, e.g. hierarchies of subviews can be + * registered like "admin/", "admin/users", "admin/settings" and the longest + * match is used. + * + * If the view being deactivated indicates it wants a confirmation for the * navigation operation, the user is asked for the confirmation. * + * Registered {@link ViewChangeListener}s are called upon successful view + * change. + * * @param viewAndParameters * view name and parameters */ public void navigateTo(String viewAndParameters) { + String longestViewName = ""; + View viewWithLongestName = null; for (ViewProvider provider : providers) { String viewName = provider.getViewName(viewAndParameters); - if (null != viewName) { - String parameters = null; - if (viewAndParameters.length() > viewName.length() + 1) { - parameters = viewAndParameters - .substring(viewName.length() + 1); - } + if (null != viewName + && viewName.length() > longestViewName.length()) { View view = provider.getView(viewName); if (null != view) { - navigateTo(view, viewName, parameters); - // stop after a view is found - return; + longestViewName = viewName; + viewWithLongestName = view; } } } + if (viewWithLongestName != null) { + String parameters = null; + if (viewAndParameters.length() > longestViewName.length() + 1) { + parameters = viewAndParameters.substring(longestViewName + .length() + 1); + } + navigateTo(viewWithLongestName, longestViewName, parameters); + } // TODO if no view is found, what to do? } @@ -506,6 +458,82 @@ public class Navigator implements Serializable { } /** + * Register a static, pre-initialized view instance for a view name. + * + * Registering another view with a name that is already registered + * overwrites the old registration of the same type. + * + * @param viewName + * String that identifies a view (not null nor empty string) + * @param view + * {@link View} instance (not null) + */ + public void addView(String viewName, View view) { + + // Check parameters + if (viewName == null || view == null) { + throw new IllegalArgumentException( + "view and viewName must be non-null"); + } + + removeView(viewName); + registerProvider(new StaticViewProvider(viewName, view)); + } + + /** + * Register for a view name a view class. + * + * Registering another view with a name that is already registered + * overwrites the old registration of the same type. + * + * A new view instance is created every time a view is requested. + * + * @param viewName + * String that identifies a view (not null nor empty string) + * @param viewClass + * {@link View} class to instantiate when a view is requested + * (not null) + */ + public void addView(String viewName, Class<? extends View> viewClass) { + + // Check parameters + if (viewName == null || viewClass == null) { + throw new IllegalArgumentException( + "view and viewClass must be non-null"); + } + + removeView(viewName); + registerProvider(new ClassBasedViewProvider(viewName, viewClass)); + } + + /** + * Remove view from navigator. + * + * This method only applies to views registered using + * {@link #addView(String, View)} or {@link #addView(String, Class)}. + * + * @param viewName + * name of the view to remove + */ + public void removeView(String viewName) { + Iterator<ViewProvider> it = providers.iterator(); + while (it.hasNext()) { + ViewProvider provider = it.next(); + if (provider instanceof StaticViewProvider) { + StaticViewProvider staticProvider = (StaticViewProvider) provider; + if (staticProvider.getViewName().equals(viewName)) { + it.remove(); + } + } else if (provider instanceof ClassBasedViewProvider) { + ClassBasedViewProvider classBasedProvider = (ClassBasedViewProvider) provider; + if (classBasedProvider.getViewName().equals(viewName)) { + it.remove(); + } + } + } + } + + /** * Register a view provider (factory). * * Providers are called in order of registration until one that can handle |