/* * Copyright (c) 2011 Petter Holmström * * Licensed 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 com.github.peholmst.mvp4vaadin.navigation.incubation; import java.util.Stack; import com.github.peholmst.mvp4vaadin.navigation.ControllableView; import com.github.peholmst.mvp4vaadin.navigation.Direction; import com.github.peholmst.mvp4vaadin.navigation.ViewController; import com.github.peholmst.mvp4vaadin.navigation.ViewControllerListener; /** * TODO Document me! * * @author Petter Holmström * @deprecated Will be deleted in the 1.0 release */ @Deprecated public class NestedControllersMaster implements java.io.Serializable { private static final long serialVersionUID = 7878176235648881833L; // TODO Add logging! // Package visibility to make unit testing easier Stack<ViewController> controllerStack = new Stack<ViewController>(); ViewControllerListener listener = new ViewControllerListener() { private static final long serialVersionUID = 5278881787281496864L; @Override public void currentViewChanged(ViewController source, ControllableView oldView, ControllableView newView, Direction direction, boolean newViewIsTopMost) { // Start by making the source the active controller makeTopController(source); if (newView instanceof ControllableViewWithEmbeddedController) { // If the source's current page has an embedded controller, make // that controller // the active controller. If that controller's current page also // has an embedded controller, // recursivly add it to the stack, etc. addControllerToStack((ControllableViewWithEmbeddedController) newView); } } }; private void addControllerToStack( ControllableViewWithEmbeddedController viewWithController) { if (viewWithController.getEmbeddedController() != null) { controllerStack.push(viewWithController.getEmbeddedController()) .addListener(listener); if (viewWithController.getEmbeddedController().getCurrentView() instanceof ControllableViewWithEmbeddedController) { addControllerToStack((ControllableViewWithEmbeddedController) viewWithController .getEmbeddedController().getCurrentView()); } } } /** * * @author petter * */ protected static class TraceElement { private final ViewController controller; private final ControllableView view; /** * * @param controller */ public TraceElement(ViewController controller) { this.controller = controller; this.view = null; } /** * * @param view */ public TraceElement(ControllableView view) { this.view = view; this.controller = null; } /** * @return the controller */ public ViewController getController() { return controller; } /** * @return the view */ public ControllableView getView() { return view; } } /** * * @author Petter Holmström * */ protected interface ControllerVisitor { /** * * @param controller * @param trace * @return true to continue with the next controller, false to abort and * return from * {@link NestedControllersMaster#visitControllers(ControllerVisitor)} * immediately. */ boolean visitController(ViewController controller, Stack<TraceElement> trace); } /** * * @param visitor */ protected void visitControllers(ControllerVisitor visitor) { if (getToplevelController() != null) { doVisitController(visitor, getToplevelController(), new Stack<TraceElement>()); } } @SuppressWarnings("unchecked") private boolean doVisitController(ControllerVisitor visitor, ViewController controller, Stack<TraceElement> trace) { trace.push(new TraceElement(controller)); if (!visitor.visitController(controller, (Stack<TraceElement>) trace.clone())) { return false; } for (ControllableView openView : controller.getTrail()) { if (openView instanceof ControllableViewWithEmbeddedController) { ControllableViewWithEmbeddedController viewWithController = (ControllableViewWithEmbeddedController) openView; if (viewWithController.getEmbeddedController() != null) { trace.push(new TraceElement(openView)); if (!doVisitController(visitor, viewWithController.getEmbeddedController(), trace)) { return false; } trace.pop(); } } } trace.pop(); return true; } private void makeTopController(ViewController controller) { while (!controllerStack.isEmpty() && controllerStack.peek() != controller) { controllerStack.pop().removeListener(listener); } if (controllerStack.isEmpty()) { throw new IllegalStateException( "The controller stack is empty! This is a bug that should be reported!"); } } /** * * @param viewController */ public void setToplevelController(ViewController viewController) { // Clear the stack while (!controllerStack.isEmpty()) { controllerStack.pop().removeListener(listener); } // Add the new toplevel controller to the bottom of the stack if (viewController != null) { controllerStack.push(viewController).addListener(listener); } } /** * * @return */ public ViewController getToplevelController() { return (controllerStack.isEmpty() ? null : controllerStack .firstElement()); } /** * Gets the view controller that is currently active. * * @return the active view controller, or <code>null</code> if there are no * controllers in the stack at all. */ public ViewController getActiveViewController() { return (controllerStack.isEmpty() ? null : controllerStack.peek()); } /** * TODO Test me and document me! * * @return */ public boolean goBack() { if (controllerStack.isEmpty()) { throw new IllegalStateException("No active controller"); } for (int i = controllerStack.size() - 1; i >= 0; --i) { ViewController controller = controllerStack.get(i); if (controller.isBackwardNavigationPossible()) { return controller.goBack(); } } return false; } // TODO Implement support for forward navigation }