summaryrefslogtreecommitdiffstats
path: root/server/src/com/vaadin/navigator
diff options
context:
space:
mode:
authorArtur Signell <artur@vaadin.com>2012-08-13 18:34:33 +0300
committerArtur Signell <artur@vaadin.com>2012-08-13 19:18:33 +0300
commite85d933b25cc3c5cc85eb7eb4b13b950fd8e1569 (patch)
tree9ab6f13f7188cab44bbd979b1cf620f15328a03f /server/src/com/vaadin/navigator
parent14dd4d0b28c76eb994b181a4570f3adec53342e6 (diff)
downloadvaadin-framework-e85d933b25cc3c5cc85eb7eb4b13b950fd8e1569.tar.gz
vaadin-framework-e85d933b25cc3c5cc85eb7eb4b13b950fd8e1569.zip
Moved server files to a server src folder (#9299)
Diffstat (limited to 'server/src/com/vaadin/navigator')
-rw-r--r--server/src/com/vaadin/navigator/FragmentManager.java38
-rw-r--r--server/src/com/vaadin/navigator/Navigator.java656
-rw-r--r--server/src/com/vaadin/navigator/View.java36
-rw-r--r--server/src/com/vaadin/navigator/ViewChangeListener.java118
-rw-r--r--server/src/com/vaadin/navigator/ViewDisplay.java29
-rw-r--r--server/src/com/vaadin/navigator/ViewProvider.java44
6 files changed, 921 insertions, 0 deletions
diff --git a/server/src/com/vaadin/navigator/FragmentManager.java b/server/src/com/vaadin/navigator/FragmentManager.java
new file mode 100644
index 0000000000..f1fd90e569
--- /dev/null
+++ b/server/src/com/vaadin/navigator/FragmentManager.java
@@ -0,0 +1,38 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.navigator;
+
+import java.io.Serializable;
+
+/**
+ * Fragment manager that handles interaction between Navigator and URI fragments
+ * or other similar view identification and bookmarking system.
+ *
+ * Alternative implementations can be created for HTML5 pushState, for portlet
+ * URL navigation and other similar systems.
+ *
+ * This interface is mostly for internal use by {@link Navigator}.
+ *
+ * @author Vaadin Ltd
+ * @since 7.0
+ */
+public interface FragmentManager extends Serializable {
+ /**
+ * Return the current fragment (location string) including view name and any
+ * optional parameters.
+ *
+ * @return current view and parameter string, not null
+ */
+ public String getFragment();
+
+ /**
+ * Set the current fragment (location string) in the application URL or
+ * similar location, including view name and any optional parameters.
+ *
+ * @param fragment
+ * new view and parameter string, not null
+ */
+ public void setFragment(String fragment);
+} \ No newline at end of file
diff --git a/server/src/com/vaadin/navigator/Navigator.java b/server/src/com/vaadin/navigator/Navigator.java
new file mode 100644
index 0000000000..1813301fe6
--- /dev/null
+++ b/server/src/com/vaadin/navigator/Navigator.java
@@ -0,0 +1,656 @@
+package com.vaadin.navigator;
+
+/*
+ @VaadinApache2LicenseForJavaFiles@
+ */
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
+import com.vaadin.terminal.Page;
+import com.vaadin.terminal.Page.FragmentChangedEvent;
+import com.vaadin.terminal.Page.FragmentChangedListener;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.ComponentContainer;
+import com.vaadin.ui.CssLayout;
+import com.vaadin.ui.CustomComponent;
+
+/**
+ * Navigator utility that allows switching of views in a part of an application.
+ *
+ * The view switching can be based e.g. on URI fragments containing the view
+ * name and parameters to the view. There are two types of parameters for views:
+ * an optional parameter string that is included in the fragment (may be
+ * bookmarkable).
+ *
+ * Views can be explicitly registered or dynamically generated and listening to
+ * view changes is possible.
+ *
+ * Note that {@link Navigator} is not a component itself but comes with
+ * {@link SimpleViewDisplay} which is a component that displays the selected
+ * view as its contents.
+ *
+ * @author Vaadin Ltd
+ * @since 7.0
+ */
+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 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");
+ }
+
+ @Override
+ public void navigateTo(String fragmentParameters) {
+ // nothing to do
+ }
+ }
+
+ /**
+ * Fragment manager using URI fragments of a Page to track views and enable
+ * listening to view changes.
+ *
+ * This class is mostly for internal use by Navigator, and is only public
+ * and static to enable testing.
+ */
+ public static class UriFragmentManager implements FragmentManager,
+ FragmentChangedListener {
+ private final Page page;
+ private final Navigator navigator;
+
+ /**
+ * Create a new URIFragmentManager and attach it to listen to URI
+ * fragment changes of a {@link Page}.
+ *
+ * @param page
+ * page whose URI fragment to get and modify
+ * @param navigator
+ * {@link Navigator} to notify of fragment changes (using
+ * {@link Navigator#navigateTo(String)}
+ */
+ public UriFragmentManager(Page page, Navigator navigator) {
+ this.page = page;
+ this.navigator = navigator;
+
+ page.addListener(this);
+ }
+
+ @Override
+ public String getFragment() {
+ return page.getFragment();
+ }
+
+ @Override
+ public void setFragment(String fragment) {
+ page.setFragment(fragment, false);
+ }
+
+ @Override
+ public void fragmentChanged(FragmentChangedEvent event) {
+ UriFragmentManager.this.navigator.navigateTo(getFragment());
+ }
+ }
+
+ /**
+ * View display that is a component itself and replaces its contents with
+ * the view.
+ *
+ * This display only supports views that are {@link Component}s themselves.
+ * Attempting to display a view that is not a component causes an exception
+ * to be thrown.
+ *
+ * By default, the view display has full size.
+ */
+ public static class SimpleViewDisplay extends CustomComponent implements
+ ViewDisplay {
+
+ /**
+ * Create new {@link ViewDisplay} that is itself a component displaying
+ * the view.
+ */
+ public SimpleViewDisplay() {
+ setSizeFull();
+ }
+
+ @Override
+ public void showView(View view) {
+ if (view instanceof Component) {
+ setCompositionRoot((Component) view);
+ } else {
+ throw new IllegalArgumentException("View is not a component: "
+ + view);
+ }
+ }
+ }
+
+ /**
+ * View display that replaces the contents of a {@link ComponentContainer}
+ * with the active {@link View}.
+ *
+ * All components of the container are removed before adding the new view to
+ * it.
+ *
+ * This display only supports views that are {@link Component}s themselves.
+ * Attempting to display a view that is not a component causes an exception
+ * to be thrown.
+ */
+ public static class ComponentContainerViewDisplay implements ViewDisplay {
+
+ private final ComponentContainer container;
+
+ /**
+ * Create new {@link ViewDisplay} that updates a
+ * {@link ComponentContainer} to show the view.
+ */
+ public ComponentContainerViewDisplay(ComponentContainer container) {
+ this.container = container;
+ }
+
+ @Override
+ public void showView(View view) {
+ if (view instanceof Component) {
+ container.removeAllComponents();
+ container.addComponent((Component) view);
+ } else {
+ throw new IllegalArgumentException("View is not a component: "
+ + view);
+ }
+ }
+ }
+
+ /**
+ * 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 StaticViewProvider implements ViewProvider {
+ private final String viewName;
+ private final View 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;
+ }
+
+ @Override
+ public String getViewName(String viewAndParameters) {
+ if (null == viewAndParameters) {
+ return null;
+ }
+ if (viewAndParameters.startsWith(viewName)) {
+ return viewName;
+ }
+ return null;
+ }
+
+ @Override
+ public View getView(String viewName) {
+ if (this.viewName.equals(viewName)) {
+ return view;
+ }
+ return null;
+ }
+
+ /**
+ * Get the view name for this provider.
+ *
+ * @return view name for this provider
+ */
+ public String getViewName() {
+ return viewName;
+ }
+ }
+
+ /**
+ * 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 final String viewName;
+ private final Class<? extends View> viewClass;
+
+ /**
+ * 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)
+ */
+ 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;
+ }
+
+ @Override
+ public String getViewName(String viewAndParameters) {
+ if (null == viewAndParameters) {
+ return null;
+ }
+ if (viewAndParameters.equals(viewName)
+ || viewAndParameters.startsWith(viewName + "/")) {
+ return viewName;
+ }
+ return null;
+ }
+
+ @Override
+ public View getView(String viewName) {
+ if (this.viewName.equals(viewName)) {
+ try {
+ View view = viewClass.newInstance();
+ return view;
+ } catch (InstantiationException e) {
+ // TODO error handling
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ // TODO error handling
+ throw new RuntimeException(e);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get the view name for this provider.
+ *
+ * @return view name for this provider
+ */
+ public String getViewName() {
+ return viewName;
+ }
+
+ /**
+ * Get the view class for this provider.
+ *
+ * @return {@link View} class
+ */
+ public Class<? extends View> getViewClass() {
+ return viewClass;
+ }
+ }
+
+ private final FragmentManager fragmentManager;
+ private final ViewDisplay display;
+ private View currentView = null;
+ private List<ViewChangeListener> listeners = new LinkedList<ViewChangeListener>();
+ private List<ViewProvider> providers = new LinkedList<ViewProvider>();
+
+ /**
+ * Create a navigator that is tracking the active view using URI fragments
+ * of the current {@link Page} and replacing the contents of a
+ * {@link ComponentContainer} with the active view.
+ *
+ * In case the container is not on the current page, use another
+ * {@link Navigator#Navigator(Page, ViewDisplay)} with an explicitly created
+ * {@link ComponentContainerViewDisplay}.
+ *
+ * All components of the container are removed each time before adding the
+ * active {@link View}. Views must implement {@link Component} when using
+ * this constructor.
+ *
+ * <p>
+ * After all {@link View}s and {@link ViewProvider}s have been registered,
+ * the application should trigger navigation to the current fragment using
+ * e.g.
+ *
+ * <pre>
+ * navigator.navigateTo(Page.getCurrent().getFragment());
+ * </pre>
+ *
+ * @param container
+ * ComponentContainer whose contents should be replaced with the
+ * active view on view change
+ */
+ public Navigator(ComponentContainer container) {
+ display = new ComponentContainerViewDisplay(container);
+ fragmentManager = new UriFragmentManager(Page.getCurrent(), this);
+ }
+
+ /**
+ * Create a navigator that is tracking the active view using URI fragments.
+ *
+ * <p>
+ * After all {@link View}s and {@link ViewProvider}s have been registered,
+ * the application should trigger navigation to the current fragment using
+ * e.g.
+ *
+ * <pre>
+ * navigator.navigateTo(Page.getCurrent().getFragment());
+ * </pre>
+ *
+ * @param page
+ * whose URI fragments are used
+ * @param display
+ * where to display the views
+ */
+ public Navigator(Page page, ViewDisplay display) {
+ this.display = display;
+ fragmentManager = new UriFragmentManager(page, this);
+ }
+
+ /**
+ * Create a navigator.
+ *
+ * When a custom fragment manager is not needed, use the constructor
+ * {@link #Navigator(Page, ViewDisplay)} which uses a URI fragment based
+ * fragment manager.
+ *
+ * Note that navigation to the initial view must be performed explicitly by
+ * the application after creating a Navigator using this constructor.
+ *
+ * @param fragmentManager
+ * fragment manager keeping track of the active view and enabling
+ * bookmarking and direct navigation
+ * @param display
+ * where to display the views
+ */
+ public Navigator(FragmentManager fragmentManager, ViewDisplay display) {
+ this.display = display;
+ this.fragmentManager = fragmentManager;
+ }
+
+ /**
+ * Navigate to a view and initialize the view with given parameters.
+ *
+ * The view string consists of a view name optionally followed by a slash
+ * and (fragment) parameters. ViewProviders are used to find and create the
+ * correct type of view.
+ *
+ * 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 = null;
+ View viewWithLongestName = null;
+ for (ViewProvider provider : providers) {
+ String viewName = provider.getViewName(viewAndParameters);
+ if (null != viewName
+ && (longestViewName == null || viewName.length() > longestViewName
+ .length())) {
+ View view = provider.getView(viewName);
+ if (null != view) {
+ 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?
+ }
+
+ /**
+ * Internal method activating a view, setting its parameters and calling
+ * listeners.
+ *
+ * This method also verifies that the user is allowed to perform the
+ * navigation operation.
+ *
+ * @param view
+ * view to activate
+ * @param viewName
+ * (optional) name of the view or null not to set the fragment
+ * @param fragmentParameters
+ * parameters passed in the fragment for the view
+ */
+ protected void navigateTo(View view, String viewName,
+ String fragmentParameters) {
+ ViewChangeEvent event = new ViewChangeEvent(this, currentView, view,
+ viewName, fragmentParameters);
+ if (!isViewChangeAllowed(event)) {
+ return;
+ }
+
+ if (null != viewName && getFragmentManager() != null) {
+ String currentFragment = viewName;
+ if (fragmentParameters != null) {
+ currentFragment += "/" + fragmentParameters;
+ }
+ if (!currentFragment.equals(getFragmentManager().getFragment())) {
+ getFragmentManager().setFragment(currentFragment);
+ }
+ }
+
+ view.navigateTo(fragmentParameters);
+ currentView = view;
+
+ if (display != null) {
+ display.showView(view);
+ }
+
+ fireViewChange(event);
+ }
+
+ /**
+ * Check whether view change is allowed.
+ *
+ * All related listeners are called. The view change is blocked if any of
+ * them wants to block the navigation operation.
+ *
+ * The view change listeners may also e.g. open a warning or question dialog
+ * and save the parameters to re-initiate the navigation operation upon user
+ * action.
+ *
+ * @param event
+ * view change event (not null, view change not yet performed)
+ * @return true if the view change should be allowed, false to silently
+ * block the navigation operation
+ */
+ protected boolean isViewChangeAllowed(ViewChangeEvent event) {
+ for (ViewChangeListener l : listeners) {
+ if (!l.isViewChangeAllowed(event)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Return the fragment manager that is used to get, listen to and manipulate
+ * the URI fragment or other source of navigation information.
+ *
+ * @return fragment manager in use
+ */
+ protected FragmentManager getFragmentManager() {
+ return fragmentManager;
+ }
+
+ /**
+ * Returns the ViewDisplay used by the navigator. Unless another display is
+ * specified, a {@link SimpleViewDisplay} (which is a {@link Component}) is
+ * used by default.
+ *
+ * @return current ViewDisplay
+ */
+ public ViewDisplay getDisplay() {
+ return display;
+ }
+
+ /**
+ * Fire an event when the current view has changed.
+ *
+ * @param event
+ * view change event (not null)
+ */
+ protected void fireViewChange(ViewChangeEvent event) {
+ for (ViewChangeListener l : listeners) {
+ l.navigatorViewChanged(event);
+ }
+ }
+
+ /**
+ * 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
+ * the requested view name is found.
+ *
+ * @param provider
+ * provider to register
+ */
+ public void registerProvider(ViewProvider provider) {
+ providers.add(provider);
+ }
+
+ /**
+ * Unregister a view provider (factory).
+ *
+ * @param provider
+ * provider to unregister
+ */
+ public void unregisterProvider(ViewProvider provider) {
+ providers.remove(provider);
+ }
+
+ /**
+ * Listen to changes of the active view.
+ *
+ * The listener will get notified after the view has changed.
+ *
+ * @param listener
+ * Listener to invoke after view changes.
+ */
+ public void addListener(ViewChangeListener listener) {
+ listeners.add(listener);
+ }
+
+ /**
+ * Remove a view change listener.
+ *
+ * @param listener
+ * Listener to remove.
+ */
+ public void removeListener(ViewChangeListener listener) {
+ listeners.remove(listener);
+ }
+
+}
diff --git a/server/src/com/vaadin/navigator/View.java b/server/src/com/vaadin/navigator/View.java
new file mode 100644
index 0000000000..4d135b4c0b
--- /dev/null
+++ b/server/src/com/vaadin/navigator/View.java
@@ -0,0 +1,36 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.navigator;
+
+import java.io.Serializable;
+
+import com.vaadin.ui.Component;
+
+/**
+ * Interface for all views controlled by the navigator.
+ *
+ * Each view added to the navigator must implement this interface. Typically, a
+ * view is a {@link Component}.
+ *
+ * @author Vaadin Ltd
+ * @since 7.0
+ */
+public interface View extends Serializable {
+
+ /**
+ * This view is navigated to.
+ *
+ * This method is always called before the view is shown on screen. If there
+ * is any additional id to data what should be shown in the view, it is also
+ * optionally passed as parameter.
+ *
+ * TODO fragmentParameters null if no parameters or empty string?
+ *
+ * @param fragmentParameters
+ * parameters to the view or null if none given. This is the
+ * string that appears e.g. in URI after "viewname/"
+ */
+ public void navigateTo(String fragmentParameters);
+} \ No newline at end of file
diff --git a/server/src/com/vaadin/navigator/ViewChangeListener.java b/server/src/com/vaadin/navigator/ViewChangeListener.java
new file mode 100644
index 0000000000..2eb34e6fcf
--- /dev/null
+++ b/server/src/com/vaadin/navigator/ViewChangeListener.java
@@ -0,0 +1,118 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.navigator;
+
+import java.io.Serializable;
+import java.util.EventObject;
+
+/**
+ * Interface for listening to View changes before and after they occur.
+ *
+ * Implementations of this interface can also block navigation between views
+ * before it is performed.
+ *
+ * @author Vaadin Ltd
+ * @since 7.0
+ */
+public interface ViewChangeListener extends Serializable {
+
+ /**
+ * Event received by the listener for attempted and executed view changes.
+ */
+ public static class ViewChangeEvent extends EventObject {
+ private final View oldView;
+ private final View newView;
+ private final String viewName;
+ private final String fragmentParameters;
+
+ /**
+ * Create a new view change event.
+ *
+ * @param navigator
+ * Navigator that triggered the event, not null
+ */
+ public ViewChangeEvent(Navigator navigator, View oldView, View newView,
+ String viewName, String fragmentParameters) {
+ super(navigator);
+ this.oldView = oldView;
+ this.newView = newView;
+ this.viewName = viewName;
+ this.fragmentParameters = fragmentParameters;
+ }
+
+ /**
+ * Returns the navigator that triggered this event.
+ *
+ * @return Navigator (not null)
+ */
+ public Navigator getNavigator() {
+ return (Navigator) getSource();
+ }
+
+ /**
+ * Returns the view being deactivated.
+ *
+ * @return old View
+ */
+ public View getOldView() {
+ return oldView;
+ }
+
+ /**
+ * Returns the view being activated.
+ *
+ * @return new View
+ */
+ public View getNewView() {
+ return newView;
+ }
+
+ /**
+ * Returns the view name of the view being activated.
+ *
+ * @return view name of the new View
+ */
+ public String getViewName() {
+ return viewName;
+ }
+
+ /**
+ * Returns the parameters for the view being activated.
+ *
+ * @return fragment parameters (potentially bookmarkable) for the new
+ * view
+ */
+ public String getFragmentParameters() {
+ return fragmentParameters;
+ }
+ }
+
+ /**
+ * Check whether changing the view is permissible.
+ *
+ * This method may also e.g. open a "save" dialog or question about the
+ * change, which may re-initiate the navigation operation after user action.
+ *
+ * If this listener does not want to block the view change (e.g. does not
+ * know the view in question), it should return true. If any listener
+ * returns false, the view change is not allowed.
+ *
+ * @param event
+ * view change event
+ * @return true if the view change should be allowed or this listener does
+ * not care about the view change, false to block the change
+ */
+ public boolean isViewChangeAllowed(ViewChangeEvent event);
+
+ /**
+ * Invoked after the view has changed. Be careful for deadlocks if you
+ * decide to change the view again in the listener.
+ *
+ * @param event
+ * view change event
+ */
+ public void navigatorViewChanged(ViewChangeEvent event);
+
+} \ No newline at end of file
diff --git a/server/src/com/vaadin/navigator/ViewDisplay.java b/server/src/com/vaadin/navigator/ViewDisplay.java
new file mode 100644
index 0000000000..6016951394
--- /dev/null
+++ b/server/src/com/vaadin/navigator/ViewDisplay.java
@@ -0,0 +1,29 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.navigator;
+
+import java.io.Serializable;
+
+/**
+ * Interface for displaying a view in an appropriate location.
+ *
+ * The view display can be a component/layout itself or can modify a separate
+ * layout.
+ *
+ * @author Vaadin Ltd
+ * @since 7.0
+ */
+public interface ViewDisplay extends Serializable {
+ /**
+ * Remove previously shown view and show the newly selected view in its
+ * place.
+ *
+ * The parameters for the view have been set before this method is called.
+ *
+ * @param view
+ * new view to show
+ */
+ public void showView(View view);
+} \ No newline at end of file
diff --git a/server/src/com/vaadin/navigator/ViewProvider.java b/server/src/com/vaadin/navigator/ViewProvider.java
new file mode 100644
index 0000000000..4d9d22acab
--- /dev/null
+++ b/server/src/com/vaadin/navigator/ViewProvider.java
@@ -0,0 +1,44 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.navigator;
+
+import java.io.Serializable;
+
+/**
+ * A provider for view instances that can return pre-registered views or
+ * dynamically create new views.
+ *
+ * If multiple providers are used, {@link #getViewName(String)} of each is
+ * called (in registration order) until one of them returns a non-null value.
+ * The {@link #getView(String)} method of that provider is then used.
+ *
+ * @author Vaadin Ltd
+ * @since 7.0
+ */
+public interface ViewProvider extends Serializable {
+ /**
+ * Extract the view name from a combined view name and parameter string.
+ * This method should return a view name if and only if this provider
+ * handles creation of such views.
+ *
+ * @param viewAndParameters
+ * string with view name and its fragment parameters (if given),
+ * not null
+ * @return view name if the view is handled by this provider, null otherwise
+ */
+ public String getViewName(String viewAndParameters);
+
+ /**
+ * Create or return a pre-created instance of a view.
+ *
+ * The parameters for the view are set separately by the navigator when the
+ * view is activated.
+ *
+ * @param viewName
+ * name of the view, not null
+ * @return newly created view (null if none available for the view name)
+ */
+ public View getView(String viewName);
+} \ No newline at end of file