blob: 2aaa8409da82611e390d996458d553148b319b1e [file] [log] [blame]
// Copyright (c) 2010 The Chromium Authors. 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
package org.eclipse.wst.jsdt.chromium.debug.ui;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.wst.jsdt.chromium.debug.ui.DialogUtils.Message;
import org.eclipse.wst.jsdt.chromium.debug.ui.DialogUtils.Optional;
import org.eclipse.wst.jsdt.chromium.debug.ui.DialogUtils.ScopeEnabler;
import org.eclipse.wst.jsdt.chromium.debug.ui.DialogUtils.Updater;
import org.eclipse.wst.jsdt.chromium.debug.ui.DialogUtils.ValueConsumer;
import org.eclipse.wst.jsdt.chromium.debug.ui.DialogUtils.ValueSource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.wizard.IWizard;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
/**
* A set of utils for creating Eclipse Wizard that is compatible with {@link Updater}.
*/
public class WizardUtils {
/**
* A simple implementation of the wizard page that stores mutable pointers
* to its next/previous pages and a pointer to page elements.
* @param <PE> type of page elements object that keeps references to all page UI controls
*/
public static class PageImpl<PE extends PageElements> extends WizardPage {
private PE pageElements = null;
private final PageElementsFactory<PE> factory;
private PageImpl<?> previousPage = null;
private PageImpl<?> nextPage = null;
private List<PageListener> listeners = new ArrayList<PageListener>(0);
public PageImpl(String pageName, PageElementsFactory<PE> factory, String title,
String description) {
super(pageName, title, null);
this.factory = factory;
setDescription(description);
}
public void createControl(Composite parent) {
pageElements = factory.create(parent);
setControl(pageElements.getMainControl());
}
public IWizardPage getPreviousPageImpl() {
return previousPage;
}
public IWizardPage getNextPageImpl() {
return nextPage;
}
@Override
public void setVisible(boolean visible) {
for (PageListener listener : listeners) {
listener.onSetVisible(visible);
}
super.setVisible(visible);
}
public void addListener(PageListener listener) {
listeners.add(listener);
}
public void removeListener(PageListener listener) {
listeners.remove(listener);
}
public PE getPageElements() {
return pageElements;
}
public void linkToNextPage(PageImpl<?> next) {
if (next != null) {
next.previousPage = this;
}
this.nextPage = next;
LogicBasedWizard wizardImpl = (LogicBasedWizard) getWizard();
wizardImpl.updateButtons();
}
public void unlinkFromNextPage(PageImpl<?> next) {
if (next != null) {
if (this.nextPage == next) {
next.previousPage = null;
this.nextPage = null;
}
}
LogicBasedWizard wizardImpl = (LogicBasedWizard) getWizard();
wizardImpl.updateButtons();
}
@Override
public String getMessage() {
LogicBasedWizard wizardImpl = (LogicBasedWizard) getWizard();
return wizardImpl.getLogicMessage().getText();
}
@Override
public int getMessageType() {
LogicBasedWizard wizardImpl = (LogicBasedWizard) getWizard();
return wizardImpl.getLogicMessage().getPriority().getMessageProviderType();
}
}
/**
* A base interface for page set object. Its sub-types should have getters to each page of
* the wizard.
*/
public interface WizardPageSet {
/**
* @return all pages that are accessible from this page set
*/
List<? extends PageImpl<?>> getAllPages();
WizardLogic createLogic(LogicBasedWizard wizardImpl);
}
/**
* A base interface for page set object. Its sub-types should have getters to page-specific
* elements.
*/
public interface PageElements {
Control getMainControl();
}
public interface PageElementsFactory<T extends PageElements> {
T create(Composite parent);
}
/**
* An accessor to a wizard logic system. Controls its basic life-cycle.
*/
public interface WizardLogic {
void updateAll();
PageImpl<?> getStartingPage();
void dispose();
}
public interface PageListener {
void onSetVisible(boolean visible);
}
/**
* A call-back that implements wizard 'finish' button action.
*/
public interface WizardFinisher {
boolean performFinish(IWizard wizard, IProgressMonitor monitor);
}
/**
* A simple implementation of Eclipse {@link IWizard} that works with {@link WizardPageSet} and
* {@link WizardLogic}. The logic is responsible for updating a {@link WizardFinisher} value
* as user input changes.
*/
public static class LogicBasedWizard extends Wizard {
private final WizardPageSet pageSet;
private WizardFinisher wizardFinisher = null;
private UpdateButtonsState updateButtonsState = UpdateButtonsState.NOT_READY;
private Message currentLogicMessage = DialogUtils.NULL_MESSAGE;
private WizardLogic logic;
private PageImpl<?> startingPage = null;
private enum UpdateButtonsState {
/**
* Do not try to update buttons.
*/
NOT_READY,
/**
* If you need to update buttons now, probably it's already available.
*/
SHOULD_BE_READY
}
public LogicBasedWizard(WizardPageSet pageSet) {
this.pageSet = pageSet;
for (PageImpl<?> page : pageSet.getAllPages()) {
addPage(page);
}
}
Message getLogicMessage() {
return currentLogicMessage;
}
@Override
public void createPageControls(Composite pageContainer) {
super.createPageControls(pageContainer);
this.logic = pageSet.createLogic(this);
this.startingPage = this.logic.getStartingPage();
logic.updateAll();
updateButtonsState = UpdateButtonsState.SHOULD_BE_READY;
}
@Override
public boolean performFinish() {
if (wizardFinisher == null) {
return false;
}
final boolean[] result = { false };
IRunnableWithProgress runnable = new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) throws InvocationTargetException,
InterruptedException {
result[0] = wizardFinisher.performFinish(LogicBasedWizard.this, monitor);
}
};
try {
getContainer().run(false, true, runnable);
return result[0];
} catch (InterruptedException e) {
return false;
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
@Override
public boolean canFinish() {
return wizardFinisher != null;
}
@Override
public IWizardPage getNextPage(IWizardPage page) {
PageImpl<?> pageImpl = (PageImpl<?>) page;
return pageImpl.getNextPageImpl();
}
@Override
public IWizardPage getPreviousPage(IWizardPage page) {
PageImpl<?> pageImpl = (PageImpl<?>) page;
return pageImpl.getPreviousPageImpl();
}
@Override
public IWizardPage getStartingPage() {
return startingPage;
}
public void setWizardFinisher(WizardFinisher wizardFinisher, Message message) {
this.wizardFinisher = wizardFinisher;
this.currentLogicMessage = message;
updateButtons();
}
void updateButtons() {
if (updateButtonsState == UpdateButtonsState.SHOULD_BE_READY) {
getContainer().updateButtons();
getContainer().updateMessage();
}
}
@Override
public void dispose() {
if (logic != null) {
logic.dispose();
}
super.dispose();
}
}
/**
* A utility class that ties {@link Updater} together with {@link LogicBasedWizard}.
* It is fed with {@link WizardFinisher} value and optional warning value.
* It controls messages and 'finish' button of the wizard.
*/
public static class WizardFinishController implements ValueConsumer {
private final ValueSource<? extends Optional<? extends WizardFinisher>> finisherValue;
private final ValueSource<? extends Optional<?>> warningValue;
private final LogicBasedWizard wizardImpl;
public WizardFinishController(
ValueSource<? extends Optional<? extends WizardFinisher>> finisherValue,
ValueSource<? extends Optional<? extends Void>> warningValue,
LogicBasedWizard wizardImpl) {
this.finisherValue = finisherValue;
this.warningValue = warningValue;
this.wizardImpl = wizardImpl;
}
public void update(Updater updater) {
WizardFinisher finisher;
Set<Message> messages = new HashSet<Message>();
if (warningValue != null) {
Optional<?> warnings = warningValue.getValue();
if (!warnings.isNormal()) {
messages.addAll(warnings.errorMessages());
}
}
if (finisherValue.getValue().isNormal()) {
finisher = finisherValue.getValue().getNormal();
} else {
finisher = null;
messages.addAll(finisherValue.getValue().errorMessages());
}
Message message = DialogUtils.chooseImportantMessage(messages);
wizardImpl.setWizardFinisher(finisher, message);
}
}
/**
* A utility class that ties {@link Updater} together with {@link LogicBasedWizard}.
* It is plugged into {@link Updater} as a {@link ScopeEnabler} and controls the
* link to next page reference accordingly.
*/
public static class NextPageEnabler implements ScopeEnabler {
private final PageImpl<?> basePage;
private final PageImpl<?> nextPage;
public NextPageEnabler(PageImpl<?> basePage, PageImpl<?> nextPage) {
this.basePage = basePage;
this.nextPage = nextPage;
}
public void setEnabled(boolean enabled, boolean recursive) {
if (enabled) {
basePage.linkToNextPage(nextPage);
} else {
basePage.unlinkFromNextPage(nextPage);
}
}
}
}