From 0b1d334d3c4c0881f923a97629c805d65fd7e100 Mon Sep 17 00:00:00 2001 From: Laura Radaelli Date: Tue, 13 Dec 2016 10:23:51 +0200 Subject: [PATCH] start javaFX window from voting booth ToyRun --- .gitignore | 2 + .../meerkat/voting/gui/managment/Printer.java | 32 ++ .../VoteHaveBeenCastController.java | 20 +- .../voting/VotingBoothToyGraphicalRun.java | 301 +++++++++++ .../meerkat/voting/gui/ui/GraphicalFX.java | 80 +++ .../meerkat/voting/gui/ui/GraphicalUI.java | 494 ++++++++++++++++++ .../controllerFX/WelcomeSplashController.java | 39 ++ .../voting/storage/StorageManagerMockup.java | 8 +- .../graphical_fxml/welcome_splash_screen.fxml | 104 ++++ 9 files changed, 1061 insertions(+), 19 deletions(-) create mode 100644 voting-booth-gui/src/main/java/meerkat/voting/gui/managment/Printer.java create mode 100644 voting-booth/src/main/java/meerkat/voting/VotingBoothToyGraphicalRun.java create mode 100644 voting-booth/src/main/java/meerkat/voting/gui/ui/GraphicalFX.java create mode 100644 voting-booth/src/main/java/meerkat/voting/gui/ui/GraphicalUI.java create mode 100644 voting-booth/src/main/java/meerkat/voting/gui/ui/controllerFX/WelcomeSplashController.java create mode 100644 voting-booth/src/main/resources/graphical_fxml/welcome_splash_screen.fxml diff --git a/.gitignore b/.gitignore index 3a97743..e2358ac 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,5 @@ out *.db *.sql .arcconfig +/meerkat_election_params_tempfile.dat +/meerkat_booth_system_messages.dat diff --git a/voting-booth-gui/src/main/java/meerkat/voting/gui/managment/Printer.java b/voting-booth-gui/src/main/java/meerkat/voting/gui/managment/Printer.java new file mode 100644 index 0000000..10d3b0a --- /dev/null +++ b/voting-booth-gui/src/main/java/meerkat/voting/gui/managment/Printer.java @@ -0,0 +1,32 @@ +package meerkat.voting.gui.managment; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.ImageIcon; +import java.awt.image.BufferedImage; +import java.awt.Dimension; +import java.awt.Toolkit; +import javax.imageio.ImageIO; +import java.io.File; +import java.io.IOException; + +public class Printer { + + + + public static void printBallot(String filename) throws IOException { + final JFrame frame = new JFrame(); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); +// bi = ImageIO.read(ImageResourceDemo.class.getResource("../resource/avatar6.jpeg")); + BufferedImage bi = ImageIO.read(new File(filename)); + frame.add(new JLabel(new ImageIcon(bi))); + frame.pack(); + frame.setAlwaysOnTop(true); + frame.setLocationRelativeTo(null); + Dimension screenSize = new Dimension(Toolkit.getDefaultToolkit().getScreenSize()); + int wdwLeft = 500 + screenSize.width / 2; + int wdwTop = screenSize.height / 2; + frame.setLocation(wdwLeft, wdwTop); + frame.setVisible(true); + } +} \ No newline at end of file diff --git a/voting-booth-gui/src/main/java/meerkat/voting/gui/panels/vote_have_been_cast/VoteHaveBeenCastController.java b/voting-booth-gui/src/main/java/meerkat/voting/gui/panels/vote_have_been_cast/VoteHaveBeenCastController.java index ffc457e..9650068 100644 --- a/voting-booth-gui/src/main/java/meerkat/voting/gui/panels/vote_have_been_cast/VoteHaveBeenCastController.java +++ b/voting-booth-gui/src/main/java/meerkat/voting/gui/panels/vote_have_been_cast/VoteHaveBeenCastController.java @@ -3,6 +3,7 @@ package meerkat.voting.gui.panels.vote_have_been_cast; import javafx.fxml.FXML; import javafx.scene.input.MouseEvent; import meerkat.voting.gui.managment.TwoWayNode; +import meerkat.voting.gui.managment.Printer; import net.sourceforge.barbecue.Barcode; import net.sourceforge.barbecue.BarcodeException; import net.sourceforge.barbecue.BarcodeFactory; @@ -15,10 +16,7 @@ import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.ImageIcon; -import java.awt.image.BufferedImage; + /** * Created by Vladimir Eliezer Tokarev on 8/27/2016. @@ -37,7 +35,7 @@ public class VoteHaveBeenCastController extends TwoWayNode { BufferedImage image = BarcodeImageHandler.getImage(barcode); File outputfile = new File("VotersBallot.png"); ImageIO.write(image, "png", outputfile); - showBallot("VotersBallot.png"); + Printer.printBallot("VotersBallot.png"); this.logger.debug("Created the bar code with voters choises at VotersBallot.png."); } @@ -56,15 +54,5 @@ public class VoteHaveBeenCastController extends TwoWayNode { // This panel doesn't have any questions representations that why there is nothing ti show here } - private void showBallot(String filename) throws IOException { - final JFrame frame = new JFrame(); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); -// bi = ImageIO.read(ImageResourceDemo.class.getResource("../resource/avatar6.jpeg")); - BufferedImage bi = ImageIO.read(new File(filename)); - frame.add(new JLabel(new ImageIcon(bi))); - frame.pack(); - frame.setAlwaysOnTop(true); - frame.setLocationRelativeTo(null); - frame.setVisible(true); - } + } diff --git a/voting-booth/src/main/java/meerkat/voting/VotingBoothToyGraphicalRun.java b/voting-booth/src/main/java/meerkat/voting/VotingBoothToyGraphicalRun.java new file mode 100644 index 0000000..89c1cda --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/VotingBoothToyGraphicalRun.java @@ -0,0 +1,301 @@ +package meerkat.voting; + +import com.google.protobuf.ByteString; +import com.sun.corba.se.impl.orbutil.graph.Graph; +import meerkat.crypto.DigitalSignature; +import meerkat.crypto.Encryption; +import meerkat.protobuf.Voting; +import meerkat.voting.controller.VotingBoothImpl; +import meerkat.voting.encryptor.VBCryptoManager; +import meerkat.voting.encryptor.VBCryptoManagerImpl; +import meerkat.voting.gui.ui.GraphicalFX; +import javafx.application.Application; +import meerkat.voting.gui.ui.GraphicalUI; +import meerkat.voting.gui.ui.SystemConsoleUI; +import meerkat.voting.output.SystemConsoleOutputDevice; +import meerkat.voting.storage.StorageManager; +import meerkat.voting.storage.StorageManagerMockup; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.*; + +/** + * Created by Laura on 12/12/2016. + */ +public class VotingBoothToyGraphicalRun { + +// public static void main(String[] args) { +// Application.launch(GraphicalFX.class, args); +// } + + + public static void main(String[] args) { + + try { + generateSystemMessages(); + generateDemoQuestions(); + } + catch (Exception e) { + return; + } + + Random rand = new Random(); + Encryption enc = new ToyEncryption(); + DigitalSignature sig = new ToySignature("MY_SIGNER_ID"); + + StorageManager storageManager = new StorageManagerMockup(); + SystemConsoleOutputDevice outputDevice = new SystemConsoleOutputDevice(); + VBCryptoManager cryptoManager = new VBCryptoManagerImpl(rand, enc, sig); +// SystemConsoleUI ui = new SystemConsoleUI (); + GraphicalUI ui = new GraphicalUI(); + + VotingBoothImpl controller = new VotingBoothImpl(); + + try { + controller.init(outputDevice, cryptoManager, ui, storageManager); + } + catch (Exception e) { + System.err.println("init failed"); + return; + } + + + // create threads + + + Thread controllerThread = new Thread(controller); + controllerThread.setName("Meerkat VB-Controller Thread"); + Thread uiThread = new Thread(ui); + uiThread.setName("Meerkat VB-UI Thread"); + Thread outputThread = new Thread(outputDevice); + outputThread.setName("Meerkat VB-Output Thread"); + + uiThread.start(); + controllerThread.start(); + outputThread.start(); + + } + + + private static void generateDemoQuestions() throws IOException { + + Voting.ElectionParams electionParams = Voting.ElectionParams.newBuilder() + .addAllRaceQuestions(generateBallotQuestions()) + .addAllChannelChoiceQuestions(generateChannelChoiceQuestions()) + .setSelectionData(generateSelectionData()) + .build(); + + try { + FileOutputStream output = new FileOutputStream(StorageManagerMockup.electionParamFullFilename); + electionParams.writeTo(output); + output.close(); + System.out.println("Successfully wrote election parameter protobuf to a file"); + } + catch (IOException e) { + System.err.println("Could not write to the election parameter file: '" + StorageManagerMockup.electionParamFullFilename + "'."); + throw e; + } + + } + + + private static List generateChannelChoiceQuestions() { + ArrayList channelChoiceQuestions = new ArrayList(); + + String[] ans1 = {"Red", "Blue", "Green"}; + Voting.BallotQuestion ccquestion1 = generateBallotQuestion("What is your favorite color?", "Pick one answer", ans1); + channelChoiceQuestions.add(ccquestion1); + + String[] ans2 = {"Yes", "No"}; + Voting.BallotQuestion ccquestion2 = generateBallotQuestion("Are you a republican?", "Pick one answer", ans2); + channelChoiceQuestions.add(ccquestion2); + + return channelChoiceQuestions; + } + + + private static List generateBallotQuestions() { + ArrayList allBallotQuestions = new ArrayList(); + + String[] answers1 = {"answer 1", "answer 2", "answer 3", "answer 4"}; + allBallotQuestions.add(generateBallotQuestion("question 1. Asking something...", "Pick one answer", answers1)); + + String[] answers2 = {"Miranda Kerr", "Doutzen Kroes", "Moran Atias", "Roslana Rodina", "Adriana Lima"}; + allBallotQuestions.add(generateBallotQuestion("question 2: Which model do you like", "Mark as many as you want", answers2)); + + allBallotQuestions.add(generateBallotQuestion("question 3. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 4. Asking something...", "Pick one answer", answers1)); + + String[] answers5 = {"Clint Eastwood", "Ninja", "Sonic", "Tai-chi", "Diablo", "Keanu"}; + allBallotQuestions.add(generateBallotQuestion("question 5: Good name for a cat", "Pick the best one", answers5)); + + allBallotQuestions.add(generateBallotQuestion("question 6. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 7. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 8. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 9. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 10. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 11. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 12. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 13. Asking something...", "Pick one answer", answers1)); + allBallotQuestions.add(generateBallotQuestion("question 14. Asking something...", "Pick one answer", answers1)); + + return allBallotQuestions; + } + + + private static Voting.BallotQuestion generateBallotQuestion(String questionStr, String descriptionStr, String[] answers) { + Voting.UIElement question = Voting.UIElement.newBuilder() + .setType(Voting.UIElementDataType.TEXT) + .setData(stringToBytes(questionStr)) + .build(); + + Voting.UIElement description = Voting.UIElement.newBuilder() + .setType(Voting.UIElementDataType.TEXT) + .setData(stringToBytes(descriptionStr)) + .build(); + + Voting.BallotQuestion.Builder bqb = Voting.BallotQuestion.newBuilder(); + bqb.setIsMandatory(false); + bqb.setQuestion(question); + bqb.setDescription(description); + for (String answerStr : answers) { + Voting.UIElement answer = Voting.UIElement.newBuilder() + .setType(Voting.UIElementDataType.TEXT) + .setData(stringToBytes(answerStr)) + .build(); + bqb.addAnswer(answer); + } + + return bqb.build(); + } + + + private static Voting.SimpleCategoriesSelectionData generateSelectionData() { + Voting.Category sharedDefaults = Voting.Category.newBuilder() + .addQuestionIndex(0) + .addQuestionIndex(5) + .addQuestionIndex(9) + .build(); + + Voting.Category cat00 = Voting.Category.newBuilder() + .addQuestionIndex(1) + .addQuestionIndex(4) + .addQuestionIndex(6) + .addQuestionIndex(7) + .build(); + + Voting.Category cat01 = Voting.Category.newBuilder() + .addQuestionIndex(2) + .addQuestionIndex(4) + .addQuestionIndex(8) + .build(); + + Voting.Category cat02 = Voting.Category.newBuilder() + .addQuestionIndex(3) + .addQuestionIndex(8) + .build(); + + Voting.Category cat10 = Voting.Category.newBuilder() + .addQuestionIndex(10) + .addQuestionIndex(11) + .build(); + + Voting.Category cat11 = Voting.Category.newBuilder() + .addQuestionIndex(12) + .addQuestionIndex(13) + .build(); + + Voting.CategoryChooser catChooser0 = Voting.CategoryChooser.newBuilder() + .addCategory(cat00) + .addCategory(cat01) + .addCategory(cat02) + .build(); + + Voting.CategoryChooser catChooser1 = Voting.CategoryChooser.newBuilder() + .addCategory(cat10) + .addCategory(cat11) + .build(); + + return Voting.SimpleCategoriesSelectionData.newBuilder() + .setSharedDefaults(sharedDefaults) + .addCategoryChooser(catChooser0) + .addCategoryChooser(catChooser1) + .build(); + + } + + + + private static ByteString stringToBytes (String s) { + return ByteString.copyFromUtf8(s); + } + + + private static void generateSystemMessages() throws IOException{ + Map systemMessageMap = new HashMap(); + + systemMessageMap.put(StorageManager.WAIT_FOR_COMMIT_MESSAGE, Voting.UIElement.newBuilder() + .setType(Voting.UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Please wait while committing to ballot")) + .build()); + systemMessageMap.put(StorageManager.WAIT_FOR_AUDIT_MESSAGE, Voting.UIElement.newBuilder() + .setType(Voting.UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Please wait while auditing your ballot")) + .build()); + systemMessageMap.put(StorageManager.WAIT_FOR_CAST_MESSAGE, Voting.UIElement.newBuilder() + .setType(Voting.UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Please wait while finalizing your ballot for voting")) + .build()); + systemMessageMap.put(StorageManager.RESTART_VOTING_BUTTON, Voting.UIElement.newBuilder() + .setType(Voting.UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Restart voting")) + .build()); + systemMessageMap.put(StorageManager.UNRECOGNIZED_FINALIZE_RESPONSE_MESSAGE, Voting.UIElement.newBuilder() + .setType(Voting.UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Could not understand response for Cast or Audit. Force restarting.")) + .build()); + systemMessageMap.put(StorageManager.UNSUCCESSFUL_CHANNEL_CHOICE_MESSAGE, Voting.UIElement.newBuilder() + .setType(Voting.UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Choice of channel was unsuccessful. Force restarting.")) + .build()); + systemMessageMap.put(StorageManager.OUTPUT_DEVICE_FAILURE_MESSAGE, Voting.UIElement.newBuilder() + .setType(Voting.UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Ballot output device failure. Force restarting.")) + .build()); + systemMessageMap.put(StorageManager.UNSUCCESSFUL_VOTING_MESSAGE, Voting.UIElement.newBuilder() + .setType(Voting.UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Voting was unsuccessful. Force restarting.")) + .build()); + systemMessageMap.put(StorageManager.SOMETHING_WRONG_MESSAGE, Voting.UIElement.newBuilder() + .setType(Voting.UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Something was terribly wrong. Force restarting.")) + .build()); + systemMessageMap.put(StorageManager.ENCRYPTION_FAILED_MESSAGE, Voting.UIElement.newBuilder() + .setType(Voting.UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Encryption failed for some unknown reason.")) + .build()); + systemMessageMap.put(StorageManager.RETRY_BUTTON, Voting.UIElement.newBuilder() + .setType(Voting.UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Retry")) + .build()); + systemMessageMap.put(StorageManager.CANCEL_VOTE_BUTTON, Voting.UIElement.newBuilder() + .setType(Voting.UIElementDataType.TEXT) + .setData(ByteString.copyFromUtf8("Cancel Vote")) + .build()); + + Voting.BoothSystemMessages systemMessages = Voting.BoothSystemMessages.newBuilder().putAllSystemMessage(systemMessageMap).build(); + + try { + FileOutputStream output = new FileOutputStream(StorageManagerMockup.systemMessagesFilename); + systemMessages.writeTo(output); + output.close(); + System.out.println("Successfully wrote system messages protobuf to a file"); + } + catch (IOException e) { + System.err.println("Could not write to the system messages file: '" + StorageManagerMockup.systemMessagesFilename + "'."); + throw e; + } + + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/gui/ui/GraphicalFX.java b/voting-booth/src/main/java/meerkat/voting/gui/ui/GraphicalFX.java new file mode 100644 index 0000000..06a2dec --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/gui/ui/GraphicalFX.java @@ -0,0 +1,80 @@ +package meerkat.voting.gui.ui; + +/** + * Created by Laura on 12/12/2016. + */ + +import javafx.application.Application; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.layout.StackPane; +import javafx.stage.Stage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javafx.scene.Parent; +import javafx.fxml.FXMLLoader; + +import java.io.IOException; +import java.io.File; + +public class GraphicalFX extends Application { + + private static final Logger logger = LoggerFactory.getLogger(GraphicalUI.class); + private static GraphicalUI parent; + + public static void setParent(GraphicalUI ui) { + if (GraphicalFX.parent==null) { + GraphicalFX.parent = ui; + } + logger.warn("Trying to assign again the parent of GraphicalFX."); + } + + @Override + public void init() throws Exception { +// System.out.println("init() of Hello World FX"); + parent.setGraphicalFx(this); + } + +// public static void main(String[] args) { +// launch(args); +// } + + @Override + public void start(Stage primaryStage) { + primaryStage.setTitle("Hello World!"); + Button btn = new Button(); + btn.setText("Say 'Hello World'"); + btn.setOnAction(new EventHandler() { + + @Override + public void handle(ActionEvent event) { + System.out.println("Hello World!"); + System.out.println(parent.testPrint()); + } + }); + + StackPane root = new StackPane(); + root.getChildren().add(btn); + Scene scene = new Scene(root, 300, 250); + +// System.out.println("Working Directory = " + +// System.getProperty("user.dir")); +// Parent root = null; +// try { +// File dir1 = new File ("."); +// System.out.println ("Current dir : " + dir1.getCanonicalPath()); +// root = FXMLLoader.load(getClass().getClassLoader().getResource("/graphical_fxml/welcome_splash_screen.fxml")); +// } catch (IOException e) { +// e.printStackTrace(); +// System.out.println("Working Directory = " + +// System.getProperty("user.dir")); +// } +// +// Scene scene = new Scene(root, 300, 275); + + primaryStage.setScene(scene); + primaryStage.show(); + } +} diff --git a/voting-booth/src/main/java/meerkat/voting/gui/ui/GraphicalUI.java b/voting-booth/src/main/java/meerkat/voting/gui/ui/GraphicalUI.java new file mode 100644 index 0000000..36ff127 --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/gui/ui/GraphicalUI.java @@ -0,0 +1,494 @@ +package meerkat.voting.gui.ui; + +import com.google.common.util.concurrent.FutureCallback; +import javafx.application.Application; +import javafx.stage.Stage; +import meerkat.protobuf.Voting.BallotAnswer; +import meerkat.protobuf.Voting.BallotQuestion; +import meerkat.protobuf.Voting.UIElement; +import meerkat.protobuf.Voting.UIElementDataType; +import meerkat.voting.controller.callbacks.*; +import meerkat.voting.gui.ui.uicommands.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Timer; + +import static java.lang.System.in; + + +/** + * an asynchronous thread implementation of the VotingBoothUI interface + * This is a mock-up implementation using just the console as our UI device + */ +public class GraphicalUI implements VotingBoothUI, Runnable { + + private static final Logger logger = LoggerFactory.getLogger(GraphicalUI.class); + + private BufferedReader bufferedReader; + private CommandPend cmdPend; + private Date startWaitingTime; + + private volatile boolean shutDownHasBeenCalled; + + private GraphicalFX ui; + + public GraphicalUI() { + final int tickDurationInMillisec = 10; // period between view update calls + + logger.info("A graphical UI console is constructed"); + cmdPend = new CommandPend<>(); +// bufferedReader = new BufferedReader(new InputStreamReader(in)); + GraphicalFX.setParent(this); + + startWaitingTime = null; + Timer timer = new Timer(); + timer.scheduleAtFixedRate(new TickerTimerTask(cmdPend), new Date(), tickDurationInMillisec); + + shutDownHasBeenCalled = false; + } + + /** + * the run() method. Simply loops and takes the UI's pending command and handles it accordingly + */ + @Override + public void run () { + logger.info("UI starts running"); + while (! wasShutDownCalled()) { + Application.launch(GraphicalFX.class); +// try { +// UICommand command = cmdPend.take(); +// handleSingleCommand(command); +// } +// catch (InterruptedException e) { +// logger.warn ("Interrupted while reading the pending command " + e); +// } + } + } + + + @Override + public void callShutDown() { + logger.info("callShutDown command has been called"); + shutDownHasBeenCalled = true; + stopWaiting(); + cmdPend.clear(); + try { + ui.stop(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * chooses the next method to run according to the type of the given UICommand. + * Special case for the TickCommand. + * As this command is registered in the queue constantly, we simply ignore this command if the UI is not in + * a waiting state + * @param command any valid UICommand + */ + private void handleSingleCommand(UICommand command) { + if (!(command instanceof TickCommand)) { + if (startWaitingTime != null) { + stopWaiting(); + } + } + + if (command instanceof StartSessionUICommand) { + doShowWelcomeScreen((StartSessionUICommand)command); + } + else if (command instanceof ChannelChoiceUICommand) { + doAskChannelChoiceQuestions((ChannelChoiceUICommand)command); + } + else if (command instanceof RaceVotingUICommand) { + doAskVotingQuestions((RaceVotingUICommand)command); + } + else if (command instanceof CastOrAuditUICommand) { + doCastOrAudit ((CastOrAuditUICommand)command); + } + else if (command instanceof FatalErrorUICommand) { + doFatalError((FatalErrorUICommand)command); + } + else if (command instanceof WaitForFinishUICommand) { + doWaitForFinish((WaitForFinishUICommand)command); + } + else if (command instanceof TickCommand) { + doTick (); + } + else { + String errorMessage = "handleSingleCommand: unknown type of UICommand received: " + + command.getClass().getName(); + logger.error(errorMessage); + throw new RuntimeException(errorMessage); + } + } + + + /** + * start a new session by registering a StartSessionUICommand + * @param callback - a boolean future callback to return when done + */ + @Override + public void startNewVoterSession(FutureCallback callback) { + logger.debug("UI interface call to startNewVoterSession"); + cmdPend.trample(new StartSessionUICommand((NewVoterCallback)callback)); + } + + /** + * welcomes the new voter at the beginning of the session + * @param command a StartSessionUICommand with a acallback + */ + private void doShowWelcomeScreen(StartSessionUICommand command) { + logger.debug("UI entered doShowWelcomeScreen"); + System.out.println("Welcome, new voter!"); + waitForEnter(null); + ControllerCallback callback = command.getCallback(); + callback.onSuccess(null); + } + + /** + * marks that the waiting, for something else to have happened, is finished + */ + private void stopWaiting () { + System.out.println (); + startWaitingTime = null; + + } + + /** + * waits until the ENTER key is pressed in the console + * @param message a message to show the user in the console + */ + private void waitForEnter(String message) { + if (message != null) { + System.out.println(message); + } + System.out.println("\nPress ENTER to proceed.\n"); + String t = null; + while (t == null) { + try { + t = readInputLine(); + } + catch (IOException e) { + String errorMessage = "waitForEnter: threw an IOException: " + e; + logger.error(errorMessage); + System.err.println(errorMessage); + } + } + } + + /** + * call for the channel choice phase by registering a ChannelChoiceUICommand in the queue + * @param questions questions to determine the right voting channel for this voter + * @param callback that's where we store the answers to decide channel upon for the current voter + */ + @Override + public void chooseChannel(List questions, FutureCallback> callback) { + logger.debug("UI interface call to chooseChannel"); + cmdPend.trample(new ChannelChoiceUICommand(questions, (ChannelChoiceCallback)callback)); + } + + /** + * lists the channel choice questions to the voter and gathers the voter's answers + * @param command a ChannelChoiceUICommand with the data and a callback + */ + private void doAskChannelChoiceQuestions (ChannelChoiceUICommand command) { + logger.debug("UI: doAskChannelChoiceQuestions"); + System.out.println("Showing questions for choosing channel:\n"); + try { + List answers = askVoterForAnswers(command.getQuestions()); + command.getCallback().onSuccess(answers); + } + catch (VoterCancelThrowable e) { + command.getCallback().onFailure(e); + } + catch (IOException e) { + String errorMessage = "Channel choice failed due to IOException: " + e; + logger.error (errorMessage); + System.err.println(errorMessage); + command.getCallback().onFailure(e); + } + } + + /** + * call for the race voting question phase by registering a RaceVotingUICommand in the queue + * @param questions all ballot questions to present to the voter + * @param callback the responses to the questions collected by the UI, to send back to the controller. Responses are null if voter chose to cancel session + */ + @Override + public void askVoterQuestions(List questions, FutureCallback> callback) { + logger.debug("UI interface call to chooseChannel"); + cmdPend.trample(new RaceVotingUICommand(questions, (VotingCallback)callback)); + } + + /** + * lists the race voting questions to the voter and gathers the voter's answers + * @param command a RaceVotingUICommand with a callback + */ + private void doAskVotingQuestions (RaceVotingUICommand command) { + logger.debug("UI: doAskVotingQuestions"); + System.out.println("Showing questions for race voting:\n"); + try { + List answers = askVoterForAnswers(command.getQuestions()); + command.getCallback().onSuccess(answers); + } + catch (VoterCancelThrowable e) { + command.getCallback().onFailure(e); + } + catch (IOException e) { + String errorMessage = "Asking voting questions failed due to IOException: " + e; + logger.error (errorMessage); + System.err.println(errorMessage); + command.getCallback().onFailure(e); + } + } + + /** + * call for the cast-or-audit phase by registering a CastOrAuditUICommand in the queue + * @param callback the returned choice of how to finalize the ballot + */ + @Override + public void castOrAudit(FutureCallback callback) { + logger.debug("UI interface call to castOrAudit"); + cmdPend.trample(new CastOrAuditUICommand((CastOrAuditCallback)callback)); + } + + /** + * asks the voter whether to cast or audit the ballot + * @param command a simple CastOrAuditUICommand with the callback + */ + private void doCastOrAudit(CastOrAuditUICommand command) { + logger.debug("UI entered doCastOrAudit"); + System.out.println ("Finalizing your vote. Do you wish to (C)ast or (A)udit?"); + + FinalizeBallotChoice fChoice; + + try { + String s = readInputLine(); + if (s.equals("cast") || s.equals("c")) { + fChoice = FinalizeBallotChoice.CAST; + } + else if (s.equals("audit") || s.equals("a")) { + fChoice = FinalizeBallotChoice.AUDIT; + } + else { + throw new IllegalArgumentException("UI could not understand the answer for cast/audit question '" + s + "'"); + } + ControllerCallback callback = command.getCallback(); + assert (callback instanceof CastOrAuditCallback); + ((CastOrAuditCallback)callback).onSuccess(fChoice); + } + catch (IllegalArgumentException|IOException e) { + String errorMessage = "doCastOrAudit: some error with reading input from console. details: " + e; + logger.error(errorMessage); + command.getCallback().onFailure(e); + } + } + + + /** + * makes the UI (and voter) wait for something else to happen, by registering a WaitForFinishUICommand in the queue + * @param message a message to show the user on the UI device while waiting + * @param callback a success return value of the wait (cancelling returns false) + */ + @Override + public void notifyVoterToWaitForFinish(UIElement message, FutureCallback callback) { + logger.debug("UI interface call to notifyVoterToWaitForFinish"); + cmdPend.trample(new WaitForFinishUICommand(message, (WaitForFinishCallback)callback)); + } + + /** + * Tells the voter (in the console) to wait until some other process is finished + * @param command a simple WaitForFinishUICommand with the callback + */ + public void doWaitForFinish (WaitForFinishUICommand command) { + logger.debug("UI entered doWaitForFinish"); + + startWaitingTime = new Date(); + + UIElement message = command.getMessage(); + String messageString; + if (message.getType() != UIElementDataType.TEXT) { + messageString = "Default message: encountered an error. System halting"; + } else { + messageString = UIUtils.bytesToString(message.getData()); + } + System.out.println(messageString); + System.out.print ("Waiting : ."); + } + + /** + * show an error to the voter. Halts the system until a technician handles it + * @param errorMessage message to show in UI device + * @param callback returns interrupt + */ + @Override + public void showErrorMessageAndHalt(UIElement errorMessage, FutureCallback callback) { + logger.debug("UI interface call to showErrorMessageAndHalt"); + throw new UnsupportedOperationException("Not implemented becuase currently not sure if we ever use it."); + } + + /** + * show an error to the voter. let him press a (chosen) button for handling the error. + * @param errorMessage message to show in UI device + * @param buttonLabels labels for buttons to present to voter + * @param callback the number of the selected button + */ + @Override + public void showErrorMessageWithButtons(UIElement errorMessage, UIElement[] buttonLabels, FutureCallback callback) { + logger.debug("UI interface call to showErrorMessageWithButtons"); + cmdPend.trample(new FatalErrorUICommand(errorMessage, buttonLabels, (ControllerCallback)callback)); + } + + /** + * show an error to the voter. let him press a (chosen) button for handling the error. + * @param command a FatalErrorUICommand with the callback + */ + private void doFatalError (FatalErrorUICommand command) { + logger.debug("UI entered doFatalError"); + + UIElement errorMessage = command.getErrorMessage(); + String errorMessageString; + if (errorMessage.getType() != UIElementDataType.TEXT) { + errorMessageString = "Default message: encountered an error. System halting"; + } else { + errorMessageString = UIUtils.bytesToString(errorMessage.getData()); + } + + UIElement[] buttonLabels = command.getButtonLabels(); + String[] buttonLabelStrings = new String[buttonLabels.length]; + for (int i = 0; i < buttonLabels.length; ++i) { + if (buttonLabels[i].getType() != UIElementDataType.TEXT) { + buttonLabelStrings[i] = ""; + } else { + buttonLabelStrings[i] = UIUtils.bytesToString(errorMessage.getData()); + } + } + + System.out.println(errorMessageString); + for (int i = 0; i < buttonLabelStrings.length; ++i) { + System.out.println("" + i + " - " + buttonLabelStrings[i]); + } + + try { + String s = readInputLine(); + Integer chosenButton = new Integer(s); + command.getCallback().onSuccess(chosenButton); + } + catch (IOException e) { + String err = "doFatalError: some error with reading input from console. details: " + e; + logger.error(err); + command.getCallback().onFailure(e); + } + + } + + + /** + * this method is run when a TickCommand was received while in waiting state + */ + private void doTick () { + if (startWaitingTime != null) { + System.out.print ("."); // still waiting + } + } + + /** + * get an input line from the console + * @return a line from the voter + * @throws IOException + */ + private String readInputLine() throws IOException{ + String s; + try { + s = this.bufferedReader.readLine(); + if (null == s) { + throw new IOException(); + } + } catch (IOException e) { + String errorMessage = "readInputLine: some error with reading input from console. details: " + e; + logger.error(errorMessage); + throw new IOException(e); + } + return s; + } + + /** + * present the questions to the voter console sequentially. + * Voter may choose at any time to skip a question, go back or even cancel the whole session + * @param questions list of questions to present + * @return list of answers to the questions (at the same order) + * @throws VoterCancelThrowable this is thrown if a voter chose to cancel in the middle of the process + * @throws IOException + */ + private List askVoterForAnswers(List questions) throws VoterCancelThrowable, IOException { + + UIUtils.assertQuestionsAreValid (questions, logger); + + List answers = new ArrayList<>(); + int index = 0; + while (index < questions.size()) { + BallotQuestion question = questions.get(index); + System.out.println("Question number " + index); + showQuestionInConsole(question); + + System.out.println("UI screen: Enter your answer. You can also type '(b)ack' or '(c)ancel' or '(s)kip"); + String s = readInputLine(); + + if ((s.equals("cancel") || s.equals("c")) || (index == 0 && (s.equals("back") || s.equals("b")))) { + throw new VoterCancelThrowable(); + } + else if (s.equals("back") || s.equals("b")) { + --index; + answers.remove(index); + } + else if (s.equals("skip") || s.equals("s")) { + answers.add(UIUtils.translateStringAnswerToProtoBufMessageAnswer("")); + ++index; + } + else { + answers.add(UIUtils.translateStringAnswerToProtoBufMessageAnswer(s)); + ++index; + } + } + return answers; + } + + /** + * present a question in the console to the voter + * @param question a text ballot question + */ + private void showQuestionInConsole(BallotQuestion question) { + if (!UIUtils.isQuestionOnlyText(question)) { + System.err.println("debug: an element in question is not of TEXT type"); + throw new UnsupportedOperationException(); + } + + System.out.println("Question text: " + UIUtils.bytesToString(question.getQuestion().getData())); + System.out.println("Description: " + UIUtils.bytesToString(question.getDescription().getData())); + int answerIndex = 0; + for (UIElement answer : question.getAnswerList()) { + ++answerIndex; + System.out.println("Answer " + answerIndex + ": " + UIUtils.bytesToString(answer.getData())); + } + } + + private boolean wasShutDownCalled () { + return shutDownHasBeenCalled; + } + + public String testPrint() { + return "testPrint called"; + } + + public void setGraphicalFx(GraphicalFX graphicalFX) { + this.ui = graphicalFX; + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/gui/ui/controllerFX/WelcomeSplashController.java b/voting-booth/src/main/java/meerkat/voting/gui/ui/controllerFX/WelcomeSplashController.java new file mode 100644 index 0000000..b259c0e --- /dev/null +++ b/voting-booth/src/main/java/meerkat/voting/gui/ui/controllerFX/WelcomeSplashController.java @@ -0,0 +1,39 @@ +package meerkat.voting.gui.ui.controllerFX; + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.input.MouseEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Created by Vladimir Eliezer Tokarev on 8/27/2016. + * WelcomeSplashController handle the behavior of welcome splash class + */ +public class WelcomeSplashController { + + private final Logger logger = LoggerFactory.getLogger(WelcomeSplashController.class); + private final String INVALID_CONFIGURATION_ERROR_TEXT = "The given configuration is invalid please run this voting booth with different configuraiton."; + + @FXML + private Label ErrorPanel; + + @FXML + private void StartVotingProcess(MouseEvent mousePressed) { +// this.currentStage.close(); +// this.currentStage.setScene(this.next.GetCurrentScene()); +// this.next.UpdateNode(); +// this.currentStage.show(); +// this.logger.debug("Jumping to the select channel object."); + } + + /** + * Represents the given string to user in ErrorLabel + * @param message is the error string to represent to the user + */ + private void RepresentErrorToVoter(String message) { +// ErrorPanel.setText(message); +// this.currentStage.show(); + } + +} diff --git a/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java b/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java index f556e3b..cf4983e 100644 --- a/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java +++ b/voting-booth/src/main/java/meerkat/voting/storage/StorageManagerMockup.java @@ -17,8 +17,10 @@ public class StorageManagerMockup implements StorageManager { private static final Logger logger = LoggerFactory.getLogger(StorageManagerMockup.class); - public static final String electionParamFullFilename = "/home/hai/meerkat-java/meerkat_election_params_tempfile.dat"; - public static final String systemMessagesFilename = "/home/hai/meerkat-java/meerkat_booth_system_messages.dat"; +// public static final String electionParamFullFilename = "/home/hai/meerkat-java/meerkat_election_params_tempfile.dat"; +// public static final String systemMessagesFilename = "/home/hai/meerkat-java/meerkat_booth_system_messages.dat"; + public static final String electionParamFullFilename = "./meerkat_election_params_tempfile.dat"; + public static final String systemMessagesFilename = "./meerkat_booth_system_messages.dat"; private boolean adminHardwareKeyInserted; @@ -31,7 +33,7 @@ public class StorageManagerMockup implements StorageManager { @Override public boolean isAdminHardwareKeyInserted() { logger.info("Entered method isAdminHardwareKeyInserted"); - logger.warn("isAdminHardwareKeyInserted is not yet fully implemented. It does not check the file system. " + logger.warn("isAdminHardwareKe01d is not yet fully implemented. It does not check the file system. " + "Rather it just returns a private boolean member"); return adminHardwareKeyInserted; } diff --git a/voting-booth/src/main/resources/graphical_fxml/welcome_splash_screen.fxml b/voting-booth/src/main/resources/graphical_fxml/welcome_splash_screen.fxml new file mode 100644 index 0000000..aa9140e --- /dev/null +++ b/voting-booth/src/main/resources/graphical_fxml/welcome_splash_screen.fxml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + + + +
+ +
+
+ + + + +
+
+
+
+ +
+
+
+
+