Java tutorial
/* * #%L * GwtMaterial * %% * Copyright (C) 2015 - 2017 GwtMaterialDesign * %% * 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. * #L% */ package gwt.material.design.addins.client.stepper; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Document; import com.google.gwt.event.logical.shared.SelectionEvent; import com.google.gwt.event.logical.shared.SelectionHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.safehtml.shared.SafeHtmlUtils; import com.google.gwt.user.client.ui.Widget; import com.google.gwt.view.client.SelectionChangeEvent; import com.google.gwt.view.client.SelectionChangeEvent.Handler; import com.google.gwt.view.client.SelectionChangeEvent.HasSelectionChangedHandlers; import gwt.material.design.addins.client.MaterialAddins; import gwt.material.design.addins.client.base.constants.AddinsCssName; import gwt.material.design.addins.client.stepper.base.HasStepsHandler; import gwt.material.design.addins.client.stepper.constants.State; import gwt.material.design.addins.client.stepper.events.CompleteEvent; import gwt.material.design.addins.client.stepper.events.NextEvent; import gwt.material.design.addins.client.stepper.events.PreviousEvent; import gwt.material.design.addins.client.stepper.events.StartEvent; import gwt.material.design.client.MaterialDesignBase; import gwt.material.design.client.base.HasAxis; import gwt.material.design.client.base.HasStatusText; import gwt.material.design.client.base.MaterialWidget; import gwt.material.design.client.base.mixin.CssNameMixin; import gwt.material.design.client.constants.Axis; import gwt.material.design.client.js.Window; import gwt.material.design.client.ui.MaterialLoader; import gwt.material.design.client.ui.animate.MaterialAnimation; import gwt.material.design.client.ui.animate.Transition; import gwt.material.design.client.ui.html.Div; import gwt.material.design.client.ui.html.Span; //@formatter:off /** * Steppers convey progress through numbered steps. They may also be used for navigation. * <p> * <h3>XML Namespace Declaration</h3> * <pre> * {@code * xmlns:ma='urn:import:gwt.material.design.addins.client' * } * </pre> * <p> * <h3>UiBinder Usage:</h3> * <pre> * {@code * <ma:stepper.MaterialStepper ui:field="stepper"> * <ma:stepper.MaterialStep step="1" title="Name of Step 1"> * <m:MaterialPanel width="100%" height="300px" backgroundColor="grey lighten-2"/> * <m:MaterialButton ui:field="btnContinue1" text="Continue to Step 2" grid="l4" marginTop="12" backgroundColor="blue" textColor="white" waves="DEFAULT"/> * <m:MaterialButton ui:field="btnPrev1" text="Cancel" grid="l4" marginTop="12" type="FLAT" waves="DEFAULT"/> * </ma:stepper.MaterialStep> * <!-- Other Step components here --> * </ma:stepper.MaterialStepper> * } * </pre> * * @author kevzlou7979 * @see <a href="http://gwtmaterialdesign.github.io/gwt-material-demo/#steppers">Material Steppers</a> * @see <a href="https://material.io/guidelines/components/steppers.html">Material Design Specification</a> */ // @formatter:on public class MaterialStepper extends MaterialWidget implements HasAxis, HasStatusText, SelectionHandler<MaterialStep>, HasSelectionChangedHandlers, HasStepsHandler { static { if (MaterialAddins.isDebug()) { MaterialDesignBase.injectCss(MaterialStepperDebugClientBundle.INSTANCE.stepperDebugCss()); } else { MaterialDesignBase.injectCss(MaterialStepperClientBundle.INSTANCE.stepperCss()); } } private int currentStepIndex = 0; private int totalSteps; private boolean stepSkippingAllowed = true; private boolean detectOrientation = true; private Div divFeedback = new Div(); private Span feedbackSpan = new Span(); private HandlerRegistration orientationHandler; private CssNameMixin<MaterialStepper, Axis> axisMixin; public MaterialStepper() { super(Document.get().createDivElement(), AddinsCssName.STEPPER); divFeedback.setStyleName(AddinsCssName.FEEDBACK); divFeedback.add(feedbackSpan); } @Override protected void onLoad() { super.onLoad(); if (getChildren().size() != 0) { StartEvent.fire(MaterialStepper.this); goToStep(currentStepIndex + 1); } setDetectOrientation(detectOrientation); } public void setDetectOrientation(boolean detectOrientation) { this.detectOrientation = detectOrientation; if (orientationHandler != null) { orientationHandler.removeHandler(); orientationHandler = null; } if (detectOrientation) { orientationHandler = registerHandler( Window.addResizeHandler(resizeEvent -> detectAndApplyOrientation())); detectAndApplyOrientation(); } } protected void detectAndApplyOrientation() { if (Window.matchMedia("(orientation: portrait)")) { setAxis(Axis.VERTICAL); } else { setAxis(Axis.HORIZONTAL); } } public boolean isDetectOrientation() { return detectOrientation; } /** * Specific method to add {@link MaterialStep}s to the stepper. */ public void add(MaterialStep step) { this.add((Widget) step); step.setAxis(getAxis()); registerHandler(step.addSelectionHandler(this)); totalSteps++; } /** * Go to next step, used by linear stepper. */ public void nextStep() { if (currentStepIndex >= getWidgetCount() - 1) { CompleteEvent.fire(MaterialStepper.this, currentStepIndex + 1); } else { Widget w = getWidget(currentStepIndex); if (w instanceof MaterialStep) { MaterialStep step = (MaterialStep) w; step.setActive(false); step.setSuccessText(step.getDescription()); // next step int nextStepIndex = getWidgetIndex(step) + 1; if (nextStepIndex >= 0) { for (int i = nextStepIndex; i < getWidgetCount(); i++) { w = getWidget(i); if (!(w instanceof MaterialStep)) { continue; } MaterialStep nextStep = (MaterialStep) w; if (nextStep.isEnabled() && nextStep.isVisible()) { nextStep.setActive(true); setCurrentStepIndex(i); NextEvent.fire(MaterialStepper.this); break; } } } } } } /** * Go to previous step , used by linear stepper. */ public void prevStep() { if (currentStepIndex > 0) { Widget w = getWidget(currentStepIndex); if (w instanceof MaterialStep) { MaterialStep step = (MaterialStep) w; step.setActive(false); // prev step int prevStepIndex = getWidgetIndex(step) - 1; if (prevStepIndex >= 0) { for (int i = prevStepIndex; i >= 0; i--) { w = getWidget(i); if (!(w instanceof MaterialStep)) { continue; } MaterialStep prevStep = (MaterialStep) w; if (prevStep.isEnabled() && prevStep.isVisible()) { prevStep.setActive(true); setCurrentStepIndex(i); PreviousEvent.fire(MaterialStepper.this); break; } } } } } else { GWT.log("You have reached the minimum step."); } } /** * Go to specific step manually by setting which step index you want to go. */ public void goToStep(int step) { for (int i = 0; i < getWidgetCount(); i++) { Widget w = getWidget(i); if (w instanceof MaterialStep) { ((MaterialStep) w).setActive(false); } } Widget w = getWidget(step - 1); if (w instanceof MaterialStep) { ((MaterialStep) w).setActive(true); } setCurrentStepIndex(step - 1); } /** * Go to the specfic {@link MaterialStep}. */ public void goToStep(MaterialStep step) { for (int i = 0; i < getWidgetCount(); i++) { Widget w = getWidget(i); if (w instanceof MaterialStep) { MaterialStep materialStep = (MaterialStep) w; boolean active = materialStep.equals(step); materialStep.setActive(active); if (active) { setCurrentStepIndex(i); } } } } /** * Go to the step with the specified step id. * * @see MaterialStep#getStep() */ public void goToStepId(int id) { for (int i = 0; i < getWidgetCount(); i++) { Widget w = getWidget(i); if (w instanceof MaterialStep) { MaterialStep materialStep = (MaterialStep) w; boolean active = materialStep.getStep() == id; materialStep.setActive(active); if (active) { setCurrentStepIndex(i); } } } } /** * Reset the Stepper to initial step (first step). */ public void reset() { goToStep(1); clearStatusText(); } /** * Called internally when the index is changed. Fires a {@link SelectionChangeEvent} * when the current index changes. */ protected void setCurrentStepIndex(int currentStepIndex) { if (this.currentStepIndex != currentStepIndex) { this.currentStepIndex = currentStepIndex; SelectionChangeEvent.fire(this); } } public int getCurrentStepIndex() { return currentStepIndex; } @Override public void setAxis(Axis axis) { getAxisMixin().setCssName(axis); for (int i = 0; i < getWidgetCount(); i++) { Widget w = getWidget(i); if (w instanceof MaterialStep) { ((MaterialStep) w).setAxis(axis); } } } @Override public Axis getAxis() { return getAxisMixin().getCssName(); } /** * Gets the current step component. */ public MaterialStep getCurrentStep() { if (currentStepIndex > getWidgetCount() - 1 || currentStepIndex < 0) { return null; } Widget w = getWidget(currentStepIndex); if (w instanceof MaterialStep) { return (MaterialStep) w; } return null; } public int getTotalSteps() { return totalSteps; } public boolean isLastStep() { return getCurrentStep().getStep() == getTotalSteps(); } public boolean isFirstStep() { return getCurrentStep().getStep() == 1; } @Override public void setErrorText(String errorText) { getCurrentStep().setErrorText(errorText); } @Override public void setSuccessText(String successText) { getCurrentStep().setSuccessText(successText); } @Override public void setHelperText(String helperText) { getCurrentStep().setHelperText(helperText); } @Override public void clearStatusText() { for (int i = 0; i < getWidgetCount(); i++) { Widget w = getWidget(i); if (w instanceof MaterialStep) { ((MaterialStep) w).clearStatusText(); } } } @Override public boolean isErrorTextVisible() { return getCurrentStep().isErrorTextVisible(); } @Override public void clearErrorText() { getCurrentStep().clearErrorText(); } @Override public boolean isHelperTextVisible() { return getCurrentStep().isHelperTextVisible(); } @Override public void clearHelperText() { getCurrentStep().clearHelperText(); } @Override public boolean isSuccessTextVisible() { return getCurrentStep().isSuccessTextVisible(); } @Override public void clearSuccessText() { getCurrentStep().clearSuccessText(); } /** * Get feedback message. */ public String getFeedback() { return SafeHtmlUtils.fromString(feedbackSpan.getElement().getInnerHTML()).asString(); } /** * Show feedback message and circular loader on body container */ public void showFeedback(String feedbackText) { feedbackSpan.setText(feedbackText); new MaterialAnimation().transition(Transition.FADEINUP).duration(400).animate(feedbackSpan); MaterialLoader.loading(true, getCurrentStep().getDivBody()); add(divFeedback); } /** * Hide feedback message and circular loader on body container. */ public void hideFeedback() { divFeedback.removeFromParent(); } /** * Sets whether the user is allowed to skip steps by clicking on the step title. * The default is <code>true</code>. */ public void setStepSkippingAllowed(boolean stepSkippingAllowed) { this.stepSkippingAllowed = stepSkippingAllowed; } /** * Returns whether the user is allowed to skip steps by clicking on the step title. * The default is <code>true</code>. */ public boolean isStepSkippingAllowed() { return stepSkippingAllowed; } public Span getFeedbackSpan() { return feedbackSpan; } /** * Called when a step title is clicked. */ @Override public void onSelection(SelectionEvent<MaterialStep> event) { if (stepSkippingAllowed) { if (event.getSelectedItem().getState() == State.SUCCESS) { goToStep(event.getSelectedItem()); } } } @Override public HandlerRegistration addSelectionChangeHandler(final Handler handler) { return addHandler(handler, SelectionChangeEvent.getType()); } @Override public HandlerRegistration addStartHandler(StartEvent.StartHandler handler) { return addHandler(handler, StartEvent.TYPE); } @Override public HandlerRegistration addCompleteHandler(CompleteEvent.CompleteHandler handler) { return addHandler(handler, CompleteEvent.TYPE); } @Override public HandlerRegistration addNextHandler(NextEvent.NextHandler handler) { return addHandler(handler, NextEvent.TYPE); } @Override public HandlerRegistration addPreviousHandler(PreviousEvent.PreviousHandler handler) { return addHandler(handler, PreviousEvent.TYPE); } protected CssNameMixin<MaterialStepper, Axis> getAxisMixin() { if (axisMixin == null) { axisMixin = new CssNameMixin<>(this); } return axisMixin; } }