/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.api.wizard;
import com.google.inject.Inject;
import org.eclipse.che.ide.collections.ListHelper;
import javax.validation.constraints.NotNull;
import org.eclipse.che.commons.annotation.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Abstract base implementation of a {@link Wizard}.
*
* @author Andrey Plotnikov
* @author Artem Zatsarynnyi
*/
public abstract class AbstractWizard<T> implements Wizard<T> {
protected final T dataObject;
protected final Map<String, String> context;
protected List<WizardPage<T>> wizardPages;
private UpdateDelegate delegate;
private int currentPageIndex;
/**
* Creates new wizard with the specified {@code dataObject} which will be passed into every added page.
* <p/>
* So multiple pages have the same {@code dataObject}, and any change to the
* {@code dataObject} made by one page is available to the other pages.
*
* @param dataObject
* data-object for wizard
*/
@Inject
public AbstractWizard(T dataObject) {
this.dataObject = dataObject;
context = new HashMap<>();
wizardPages = new ArrayList<>();
}
public Map<String, String> getContext() {
return context;
}
/** Returns wizard's data-object. */
public T getDataObject() {
return dataObject;
}
/**
* Add page to wizard.
*
* @param page
* page to add
*/
public void addPage(@NotNull WizardPage<T> page) {
page.setUpdateDelegate(delegate);
page.setContext(context);
page.init(dataObject);
wizardPages.add(page);
}
/**
* Add page to wizard at the specified position.
*
* @param page
* page to be stored at the specified position
* @param index
* position where the page should be inserted
* @param replace
* {@code true} if the existed page should be replaced by the given one,
* {@code false} if a page should be inserted at the specified position
*/
public void addPage(@NotNull WizardPage<T> page, int index, boolean replace) {
if (index >= wizardPages.size()) {
addPage(page);
return;
}
if (replace) {
setPage(page, index);
} else {
List<WizardPage<T>> before = ListHelper.slice(wizardPages, 0, index);
WizardPage<T> currentPage = wizardPages.get(index);
List<WizardPage<T>> after = ListHelper.slice(wizardPages, index + 1, wizardPages.size());
wizardPages.clear();
wizardPages.addAll(before);
addPage(page);
wizardPages.add(currentPage);
wizardPages.addAll(after);
}
}
private void setPage(@NotNull WizardPage<T> page, int index) {
page.setUpdateDelegate(delegate);
page.setContext(context);
page.init(dataObject);
wizardPages.set(index, page);
}
@Override
public void setUpdateDelegate(@NotNull UpdateDelegate delegate) {
this.delegate = delegate;
for (WizardPage<T> page : wizardPages) {
page.setUpdateDelegate(delegate);
}
}
@Nullable
@Override
public WizardPage<T> navigateToFirst() {
resetNavigationState();
return navigateToNext();
}
/** Reset wizard's navigation state. */
private void resetNavigationState() {
currentPageIndex = -1;
}
@Nullable
@Override
public WizardPage<T> navigateToNext() {
return getNextPage();
}
/** Returns next page that may be shown. */
@Nullable
private WizardPage<T> getNextPage() {
while (++currentPageIndex < wizardPages.size()) {
WizardPage<T> page = wizardPages.get(currentPageIndex);
if (!page.canSkip()) {
return page;
}
}
return null;
}
@Nullable
@Override
public WizardPage<T> navigateToPrevious() {
while (--currentPageIndex >= 0) {
final WizardPage<T> page = wizardPages.get(currentPageIndex);
if (!page.canSkip()) {
return page;
}
}
return null;
}
@Override
public boolean hasNext() {
for (int i = currentPageIndex + 1; i < wizardPages.size(); i++) {
WizardPage<T> page = wizardPages.get(i);
if (!page.canSkip()) {
return true;
}
}
return false;
}
@Override
public boolean hasPrevious() {
for (int i = currentPageIndex - 1; i >= 0; i--) {
WizardPage<T> page = wizardPages.get(i);
if (!page.canSkip()) {
return true;
}
}
return false;
}
@Override
public boolean canComplete() {
for (WizardPage<T> page : wizardPages) {
if (!page.isCompleted()) {
return false;
}
}
return true;
}
}