/****************************************************************************
* Copyright (C) 2012 ecsec GmbH.
* All rights reserved.
* Contact: ecsec GmbH (info@ecsec.de)
*
* This file is part of the Open eCard App.
*
* GNU General Public License Usage
* This file may be used under the terms of the GNU General Public
* License version 3.0 as published by the Free Software Foundation
* and appearing in the file LICENSE.GPL included in the packaging of
* this file. Please review the following information to ensure the
* GNU General Public License version 3.0 requirements will be met:
* http://www.gnu.org/copyleft/gpl.html.
*
* Other Usage
* Alternatively, this file may be used in accordance with the terms
* and conditions contained in a signed written agreement between
* you and ecsec GmbH.
*
***************************************************************************/
package org.openecard.gui.swing;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
import org.openecard.gui.ResultStatus;
import org.openecard.gui.StepResult;
import org.openecard.gui.UserConsentNavigator;
import org.openecard.gui.definition.Step;
import org.openecard.gui.swing.common.GUIConstants;
import org.openecard.gui.swing.common.NavigationEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Implementation of the UserConsentNavigator interface for the Swing GUI.
* This class receives button clicks and orchestrates the update of the steps and progress indication components.
*
* @author Tobias Wich <tobias.wich@ecsec.de>
* @author Moritz Horsch <horsch@cdc.informatik.tu-darmstadt.de>
*/
public class SwingNavigator implements UserConsentNavigator, ActionListener {
public static final Logger logger = LoggerFactory.getLogger(SwingNavigator.class);
private final DialogWrapper dialogWrapper;
private final Container stepContainer;
private final ArrayList<StepFrame> stepFrames;
private final NavigationBar navBar;
private final StepBar stepBar;
private final String dialogType;
private int stepPointer;
private Future action;
public SwingNavigator(DialogWrapper dialogWrapper, String dialogType, List<Step> steps, Container stepContainer,
NavigationBar navPanel, StepBar stepBar) {
this.stepPointer = -1;
this.dialogWrapper = dialogWrapper;
this.stepContainer = stepContainer;
this.dialogType = dialogType;
this.stepFrames = createStepFrames(steps, dialogType);
this.navBar = navPanel;
this.stepBar = stepBar;
this.dialogWrapper.show();
}
@Override
public boolean hasNext() {
return stepPointer < (stepFrames.size() - 1);
}
@Override
public StepResult current() {
stepBar.disableLoaderImage();
selectIdx(stepPointer);
StepFrame frame = stepFrames.get(stepPointer);
// click next button without giving the user the possibility to interfere
clickIfInstantReturn(frame);
return frame.getStepResult();
}
@Override
public StepResult next() {
stepBar.disableLoaderImage();
if (hasNext()) {
selectIdx(stepPointer + 1);
StepFrame frame = stepFrames.get(stepPointer);
// click next button without giving the user the possibility to interfere
clickIfInstantReturn(frame);
return frame.getStepResult();
}
return new SwingStepResult(null, ResultStatus.CANCEL);
}
@Override
public StepResult previous() {
stepBar.disableLoaderImage();
if (stepPointer > 0) {
selectIdx(stepPointer - 1);
StepFrame frame = stepFrames.get(stepPointer);
// click next button without giving the user the possibility to interfere
clickIfInstantReturn(frame);
return frame.getStepResult();
}
return new SwingStepResult(null, ResultStatus.CANCEL);
}
@Override
public StepResult replaceCurrent(Step step) {
stepBar.disableLoaderImage();
stepFrames.remove(stepPointer);
StepFrame sf = new StepFrame(step, dialogType);
stepFrames.add(stepPointer, sf);
selectIdx(stepPointer);
// click next button without giving the user the possibility to interfere
clickIfInstantReturn(sf);
return sf.getStepResult();
}
@Override
public StepResult replaceNext(Step step) {
stepBar.disableLoaderImage();
stepPointer = stepPointer + 1;
if (stepPointer < stepFrames.size()) {
stepFrames.remove(stepPointer);
}
StepFrame sf = new StepFrame(step, dialogType);
stepFrames.add(stepPointer, sf);
selectIdx(stepPointer);
// click next button without giving the user the possibility to interfere
clickIfInstantReturn(sf);
return sf.getStepResult();
}
@Override
public StepResult replacePrevious(Step step) {
stepBar.disableLoaderImage();
if (stepPointer > 0) {
stepPointer = stepPointer - 1;
stepFrames.remove(stepPointer);
}
StepFrame sf = new StepFrame(step, dialogType);
stepFrames.add(stepPointer, sf);
selectIdx(stepPointer);
// click next button without giving the user the possibility to interfere
clickIfInstantReturn(sf);
return sf.getStepResult();
}
@Override
public void setRunningAction(Future action) {
this.action = action;
}
@Override
public void close() {
dialogWrapper.hide();
}
private ArrayList<StepFrame> createStepFrames(List<Step> steps, String dialogType) {
ArrayList<StepFrame> frames = new ArrayList<StepFrame>(steps.size());
for (int i = 0; i < steps.size(); i++) {
if (i == 0) {
steps.get(0).setReversible(false);
}
Step s = steps.get(i);
StepFrame sf = new StepFrame(s, dialogType);
frames.add(sf);
}
return frames;
}
private void selectIdx(int idx) {
// Content replacement
StepFrame nextStep = stepFrames.get(idx);
stepBar.selectIdx(idx);
navBar.selectIdx(idx);
Container nextPanel = nextStep.getPanel();
nextStep.resetResult();
stepContainer.removeAll();
stepContainer.add(nextPanel);
stepContainer.validate();
stepContainer.repaint();
stepPointer = idx;
nextStep.updateFrame();
nextStep.unlockControls();
navBar.unlockControls();
}
private void clickIfInstantReturn(StepFrame frame) {
if (frame.isInstantReturn()) {
String command = GUIConstants.BUTTON_NEXT;
final ActionEvent e = new ActionEvent(frame.getStep(), ActionEvent.ACTION_PERFORMED, command);
// create async invocation of the action
new Thread("Instant-Return-Thread") {
@Override
public void run() {
actionPerformed(e);
}
}.start();
}
}
@Override
public void actionPerformed(ActionEvent e) {
logger.debug("Received event: {}", e.getActionCommand());
NavigationEvent event = NavigationEvent.fromEvent(e);
if (event == null) {
logger.error("Unknown event received: {}", e.getActionCommand());
return;
}
// in case the user wants to proceed check if all components are valid
StepFrame curStep = stepFrames.get(stepPointer);
if (event == NavigationEvent.NEXT && ! curStep.validateComponents()) {
logger.debug("Validation of components failed.");
return;
}
// in case there is a running action, kill it and bail out
if (action != null && ! action.isDone()) {
logger.debug("Canceling execution of the currently running StepAction.");
action.cancel(true);
return;
}
// lock controls and update current step result
stepBar.enableLoaderImage();
navBar.lockControls();
curStep.lockControls();
curStep.updateResult(event);
}
}