//Results available/unavailable does not update properly when results window is closed and opened again unless reset button is clicked //Fixed it- the server was getting the variable too far from where it was examining it. There wasn't enough time to update it??? //Reset thread connection on reset? //Sorted choices do not properly reset //Have to click reset button twice (may be fixed now) //Add functionality so it "remembers" which item is selected? Or will it automatically track that? //listbox is pass-by-value, and it should remember what's selected... improperly setting it? Or need to explicitly //change selection for data listbox when real one is clicked? //potential bug if server doesn't have any choices in list' //don't forget to flush!' //reset not working import java.awt.*; import java.awt.event.*; import java.applet.*; import javax.swing.*; import java.io.*; import java.util.*; import java.net.*; import java.text.*; import java.beans.*; public class App { //extends Applet { int threadNum; // This client's thread number (assigned by server) int port = 7000; // Port number ObjectOutputStream toServer; ObjectInputStream fromServer; // XMLEncoder toServer; // XMLDecoder fromServer; VatingSet data; //This is where we store all the data the user creates Map vatings; //List of vatings (questions) Map choices; //List of options in each vating Vating currentVating; Choice currentChoice; java.awt.List currentChoiceList; //Copy of listbox in GUI; this stores the data int maxTitle = 42; //Maximum number of characters allowable in Title Combo Box (based on wide chars like M and W) to avoid breaking GUI int maxChoice = 20; //Maximum number of characters allowable in Choice List Box (based on wide chars like M and W) to avoid breaking GUI int maxWidth = 630; //Dimensions for applet window int maxHeight = 650; //was 620/610 JPanel headerPanel; //Program title and credits JLabel headerLabel; //"Vating Booth by Chad Schultz - Voting / Rating System" JTextArea help; //Context-sensitive help information String helpMessage = "Welcome to the vating (voting/sorting/rating) booth! Please set up your vating as you wish. Click on\n" +"any object for more instructions.\n"; //Initial message displayed to user JLabel vatingLabel; //"Select vating:" JComboBox vatingCombo; //List of "vatings," each poll/vote/etc JPanel titlePanel; JLabel titleLabel; //"Description of vating:" JTextArea titleText; //displays information about poll/etc JPanel typePanel; ButtonGroup type; //Radio buttons to select whether this is a sorting, rating, or voting vating JRadioButton sortButton; JRadioButton rateButton; JRadioButton voteButton; JPanel choicesPanel; JLabel choiceLabel; //"Choices:" java.awt.List choiceListBox; //Displays listbox of candidates for votes, good/fair/poor ratings, etc. JPanel movePanel; JButton moveUp; //Only for sorting vatings: move items up in the list JButton moveDown; //Only for sorting vatings: move items down in the list JPanel detailPanel; JLabel choiceNameLabel; //"Choice name:" JTextField choiceNameField; //Shows name of the choice, the same as what appears in choiceListBox JTextArea choiceDescription; //Detailed information on individual choice JLabel yourNameLabel; //"Your name:" JTextField yourNameField; //For the name- or ID- of the person, to make sure nobody vates twice and that everyone vates JPanel buttonPanel; JButton submit; //Send votes and ratings to server MyReset reset; //Clear fields out for a new person JButton results; //View results- which may or may not be available right away, depending on server settings JFrame resultsFrame; JPanel resultsPanel; JLabel resultsLabel; //"Results for"" JComboBox resultsCombo; //displays name of vating, same as vatingCombo JTextArea resultsText; //Displays each item on a row with appropriate statistical information JFrame frame; JPanel mainPanel; public static void main(String[] args) { App me = new App(); me.go(); } public void go() { //public void init() { //Set up GUI frame = new JFrame("Vating Booth 1.0"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(maxWidth, maxHeight); //resize(maxWidth, maxHeight); mainPanel = new JPanel(); mainPanel.setPreferredSize(new Dimension(maxWidth,maxHeight)); frame.getContentPane().add(mainPanel); //headPanel contains the title, help information, and the combo box to select a vating headerPanel = new JPanel(); headerPanel.setPreferredSize(new Dimension(maxWidth,165)); mainPanel.add(headerPanel); headerLabel = new JLabel("Vating Booth 1.0"); headerLabel.setFont(new Font("SansSerif", Font.BOLD, 18)); headerPanel.add(headerLabel); help = new JTextArea(helpMessage,5,55); //We'll use this to display context-sensitive messages to user help.setEditable(false); //Hands off! JScrollPane helpScroll = new JScrollPane(help); headerPanel.add(helpScroll); vatingLabel = new JLabel("Select vating:"); headerPanel.add(vatingLabel); vatingCombo = new JComboBox(); // vatingCombo = new JComboBox(new String[] {"(empty) "}); headerPanel.add(vatingCombo); vatingCombo.addActionListener(new VatingComboListener()); //typePanel holds the radio buttons to show the type of the vating, which affects how the user gives input and how it is scored typePanel = new JPanel(); typePanel.setPreferredSize(new Dimension(maxWidth,25)); mainPanel.add(typePanel); type = new ButtonGroup(); //Logical grouping of radio buttons String sortString = new String("Sort"); sortButton = new JRadioButton(sortString); //Code for "sort" type of vating sortButton.setEnabled(false); sortButton.setActionCommand(sortString); sortButton.setSelected(true); type.add(sortButton); typePanel.add(sortButton); String rateString = new String("Rate"); rateButton = new JRadioButton(rateString); //Code for "rate" type of vating rateButton.setEnabled(false); rateButton.setActionCommand(rateString); type.add(rateButton); typePanel.add(rateButton); String voteString = new String("Vote"); voteButton = new JRadioButton(voteString); //Code for "vote" type of vating voteButton.setEnabled(false); voteButton.setActionCommand(voteString); type.add(voteButton); typePanel.add(voteButton); //Just holds title/description of vating titlePanel = new JPanel(); titlePanel.setPreferredSize(new Dimension(maxWidth, 60)); mainPanel.add(titlePanel); titleLabel = new JLabel("Description of vating:"); titlePanel.add(titleLabel); titleText = new JTextArea("",2,55); JScrollPane titleTextScroll = new JScrollPane(titleText); titlePanel.add(titleTextScroll); titleText.setEditable(false); //titlePanel.add(titleText); //Holds listbox showing choices for a vating: the options for the vater to vote, rate, or sort choicesPanel = new JPanel(); choicesPanel.setPreferredSize(new Dimension(200,290)); mainPanel.add(choicesPanel); choiceLabel = new JLabel("Choices: "); //Make it nice and wide, so it doesn't "flow" beside the listbox- put it on its own row! choicesPanel.add(choiceLabel); choiceListBox = new java.awt.List(14); //14 rows display at a time choiceListBox.addItemListener(new ChoiceListBoxListener()); choicesPanel.add(choiceListBox); //movePanel shows move up/move down buttons to reorder items in listbox movePanel = new JPanel(); choicesPanel.add(movePanel); moveUp = new JButton("Move Up"); movePanel.add(moveUp); moveUp.addActionListener(new MoveUpListener()); moveDown = new JButton("Move Down"); movePanel.add(moveDown); moveDown.addActionListener(new MoveDownListener()); //detailPanel shows name and description of an individually selected choice detailPanel = new JPanel(); detailPanel.setPreferredSize(new Dimension(390,290)); mainPanel.add(detailPanel); choiceNameLabel = new JLabel("Choice name:"); detailPanel.add(choiceNameLabel); choiceNameField = new JTextField(30); choiceNameField.setEditable(false); detailPanel.add(choiceNameField); choiceDescription = new JTextArea("",11,35); choiceDescription.setLineWrap(true); JScrollPane choiceDescriptionScroll = new JScrollPane(choiceDescription); detailPanel.add(choiceDescriptionScroll); choiceDescription.setEditable(false); detailPanel.add(choiceDescription); yourNameLabel = new JLabel ("Your name or identifier:"); detailPanel.add(yourNameLabel); yourNameField = new JTextField(30); detailPanel.add(yourNameField); //buttonPanel holds the command buttons for the main functionality of program buttonPanel = new JPanel(); buttonPanel.setPreferredSize(new Dimension(maxWidth,40)); mainPanel.add(buttonPanel); submit = new JButton("Submit Vates"); buttonPanel.add(submit); submit.addActionListener(new SubmitListener()); results = new JButton("Show Results"); buttonPanel.add(results); results.addActionListener(new ResultsListener()); reset = new MyReset("Reset Data"); buttonPanel.add(reset); reset.addActionListener(new ResetListener()); try { Socket s = new Socket("localhost", port); fromServer = new ObjectInputStream(s.getInputStream()); toServer = new ObjectOutputStream(s.getOutputStream()); threadNum = (Integer)fromServer.readObject(); System.out.println("Thread number: " + threadNum); System.out.println("Connected to server"); reset.go(); //Request data so we can vate } catch(Exception err) { System.out.println(err.getMessage()); } frame.setVisible(true); } //End of init() /* An extension of JButton to allow for specialized functionality * for the reset button, which also gets data from the server * Chad Schultz */ class MyReset extends JButton { public MyReset(String s) { super(s); //Pass information to JButton constructor } public void loadData() { //Load data into GUI // if (vatingCombo.getSelectedIndex() != vatingCombo.getItemCount() - 1) { //If is not selected if (vatingCombo.getItemCount()>0) { currentVating = (Vating) vatings.get(vatingCombo.getSelectedItem()); } else { currentVating = new Vating("",""); } //Load vating title titleText.setText(currentVating.getDescription()); //Load radio button if (currentVating.getType() == Vating.SORT) { sortButton.setSelected(true); moveUp.setEnabled(true); moveDown.setEnabled(true); } else if (currentVating.getType() == Vating.RATE) { rateButton.setSelected(true); moveUp.setEnabled(false); moveDown.setEnabled(false); } else if (currentVating.getType() == Vating.VOTE) { voteButton.setSelected(true); moveUp.setEnabled(false); moveDown.setEnabled(false); } //Load choice list choices = currentVating.getChoices(); currentChoiceList = currentVating.getChoiceList(); choiceListBox.removeAll(); for (int j=0; j < currentChoiceList.getItemCount()-1; j++) { choiceListBox.add(currentChoiceList.getItem(j)); } choiceListBox.select(0); reset.score(); //Load choice name and description /* if (choiceListBox.getSelectedIndex() == choiceListBox.getItemCount() - 1) { //If is selected choiceNameField.setText(""); choiceDescription.setText(""); } else {*/ if (choiceListBox.getItemCount()>0) { currentChoice = (Choice) choices.get(choiceListBox.getSelectedItem()); choiceNameField.setText(currentChoice.getName()); choiceDescription.setText(currentChoice.getDescription()); } // } } public void go() { //Tries to get data from server, clears window, and loads data data = new VatingSet(); vatings = data.getVatings(); currentVating = new Vating(); choices = currentVating.getChoices(); currentChoice = new Choice(); currentChoiceList = currentVating.getChoiceList(); vatingCombo.removeAllItems(); sortButton.setSelected(true); titleText.setText(""); choiceListBox.removeAll(); //choiceListBox.select(0); choiceNameField.setText(""); choiceDescription.setText(""); yourNameField.setText(""); help.setText("Data cleared."); try { toServer.writeObject("DATA"); toServer.flush(); if ((Boolean) fromServer.readObject()) { //We'll receive a boolean saying whether to expect data or not data = (VatingSet) fromServer.readObject(); //Get all vating data from file vatings = data.getVatings(); //Poll questions, etc. //Load data into GUI //Load combo box JComboBox loadedCombo = data.getVatingCombo(); //So we can access stored data vatingCombo.removeAllItems(); //Clear the combobox on the GUI before filling it for (int i=0; i < loadedCombo.getItemCount() - 1; i++) { //Why -1? We don't want the last item, vatingCombo.addItem(loadedCombo.getItemAt(i)); //Copy items from the stored data to the GUI } reset.loadData(); //Loads choice information submit.setEnabled(true); results.setEnabled(true); } else { help.setText("Cannot vate at this point in time. Try again later by clicking the reset button."); submit.setEnabled(false); results.setEnabled(false); } } catch(Exception err) { System.out.println("Error!"); System.out.println(err.getLocalizedMessage()); } } public void score() { Map cs = currentVating.getChoices(); Choice c; if (currentVating.getType() == currentVating.SORT) { for (int i=0; i < choiceListBox.getItemCount(); i++) { //Loop through all choices, setting score equal to index. Lower score = better String item = choiceListBox.getItem(i); c = (Choice) cs.get(item); c.setScore(i); // cs.remove(item); // cs.put(item,c); c = (Choice) cs.get(c.getName()); System.out.println("SORT ITEM SET:"+c.getName()+": "+c.getScore()); } } else { //RATE or VOTE Set choiceKeys = cs.keySet(); // GET THE KEY SET Iterator p = choiceKeys.iterator(); // CREATE KEY SET ITERATOR while (p.hasNext()) { //Reset all choices in list to a score of 0; only one will have a score c = (Choice) cs.get(p.next()); c.setScore(0); // cs.remove(c.getName()); // cs.put(c.getName(),c); c = (Choice) cs.get(c.getName()); System.out.println("RATE/VOTE ITEM RESET:"+c.getName()+": "+c.getScore()); } c = (Choice) cs.get(choiceListBox.getSelectedItem()); //Get the choice corresponding to the one user has selected c.setScore(1); c = (Choice) cs.get(c.getName()); System.out.println("RATE/VOTE ITEM SET:"+c.getName()+": "+c.getScore()); // cs.remove(c.getName()); // cs.put(c.getName(),c); } } } /* Implements actions for the vatingCombo when clicked. * Chad Schultz */ public class VatingComboListener implements ActionListener { public void actionPerformed(ActionEvent e) { reset.loadData(); //Load type, choice name and description help.setText("A vating (for example, a poll question) is one coherent list of choices for the user to give input on.\n" + "Click on and type a description into the box to create a new one and create the choice list."); } } /* Loads choice name and description when user clicks a choice from the list * Chad Schultz */ public class ChoiceListBoxListener implements ItemListener { public void itemStateChanged(ItemEvent e) { if (choiceListBox.getItemCount()>0) { //Only fetch data if we even have any valid choices in list currentChoice = (Choice) choices.get(choiceListBox.getSelectedItem()); choiceNameField.setText(currentChoice.getName()); choiceDescription.setText(currentChoice.getDescription()); /* Map cs = currentVating.getChoices(); Choice c; if (currentVating.getType() == currentVating.SORT) { for (int i=0; i < choiceListBox.getItemCount(); i++) { //Loop through all choices, setting score equal to index. Lower score = better String item = choiceListBox.getItem(i); c = (Choice) cs.get(item); c.setScore(i); // cs.remove(item); // cs.put(item,c); c = (Choice) cs.get(c.getName()); System.out.println("SORT ITEM SET:"+c.getName()+": "+c.getScore()); } } else { //RATE or VOTE Set choiceKeys = cs.keySet(); // GET THE KEY SET Iterator p = choiceKeys.iterator(); // CREATE KEY SET ITERATOR while (p.hasNext()) { //Reset all choices in list to a score of 0; only one will have a score c = (Choice) cs.get(p.next()); c.setScore(0); // cs.remove(c.getName()); // cs.put(c.getName(),c); c = (Choice) cs.get(c.getName()); System.out.println("RATE/VOTE ITEM RESET:"+c.getName()+": "+c.getScore()); } c = (Choice) cs.get(choiceListBox.getSelectedItem()); //Get the choice corresponding to the one user has selected c.setScore(1); c = (Choice) cs.get(c.getName()); System.out.println("RATE/VOTE ITEM SET:"+c.getName()+": "+c.getScore()); // cs.remove(c.getName()); // cs.put(c.getName(),c); }*/ reset.score(); } else { choiceNameField.setText(""); choiceDescription.setText(""); } //Context-sensitive help help.setText("Create a list of choices for your vating: for example, the candidates for an election.\n" + "Click on and enter the name and description for each one in turn."); } } /* Functionality for button that moves a choice up in the list * Chad Schultz */ public class MoveUpListener implements ActionListener { public void actionPerformed(ActionEvent e) { // if (choiceListBox.getSelectedIndex() != choiceListBox.getItemCount() - 1) { //Only move if is not selected int i = choiceListBox.getSelectedIndex(); if (i > 0) { //Don't move it up if it's at the top! String item = choiceListBox.getSelectedItem(); choiceListBox.remove(i); //Take the item out of the list and put it back one one row higher currentChoiceList.remove(i); //Duplicate all actions in our stored data i--; choiceListBox.add(item,i); currentChoiceList.add(item,i); choiceListBox.select(i); //Select the item we moved; the listbox should always have an item selected } reset.score(); // } } } /* Functionality for button that moves a choice down in the list * Chad Schultz */ public class MoveDownListener implements ActionListener { public void actionPerformed(ActionEvent e) { // if (choiceListBox.getSelectedIndex() != choiceListBox.getItemCount() - 1) { //If is not selected int i = choiceListBox.getSelectedIndex(); //if there are three items, the last one () is index 2, and the next //to last is index 1. Therefore, only move the item down when it's less then 2 less //then the number of items if (i < choiceListBox.getItemCount()-1) { String item = choiceListBox.getSelectedItem(); choiceListBox.remove(i); //take it out and put it back at the right spot currentChoiceList.remove(i); i++; choiceListBox.add(item,i); currentChoiceList.add(item,i); choiceListBox.select(i); } reset.score(); // } } } public class SubmitListener implements ActionListener { public void actionPerformed(ActionEvent e) { try { toServer.writeObject("VATE"); toServer.flush(); if ((Boolean) fromServer.readObject()) { //We'll receive a boolean saying whether to expect data or not toServer.writeObject(data); //Get all vating data from file toServer.flush(); reset.go(); } else { help.setText("Cannot vate at this point in time. Try again later by clicking the submit button."); } } catch(Exception err) { System.out.println("Error!"); System.out.println(err.getLocalizedMessage()); } } } /* Clear data when reset button is pressed. Create a new data object * to overwrite the old one, then reset all the other data objects and * GUI elements to their initial state * Chad Schultz */ public class ResetListener implements ActionListener { public void actionPerformed(ActionEvent e) { reset.go(); } } public class ResultsListener implements ActionListener { public void actionPerformed(ActionEvent e) { resultsFrame = new JFrame("Vating Results"); resultsFrame.setSize(450,450); resultsPanel = new JPanel(); resultsPanel.setPreferredSize(new Dimension(450,450)); resultsFrame.add(resultsPanel); resultsLabel = new JLabel("Results for:"); resultsPanel.add(resultsLabel); resultsCombo = new JComboBox(); resultsPanel.add(resultsCombo); resultsText = new JTextArea(23,40); resultsText.setLineWrap(true); resultsText.setEditable(false); JScrollPane resultsTextScroll = new JScrollPane(resultsText); resultsPanel.add(resultsTextScroll); resultsFrame.setVisible(true); VatingSet resultsData = new VatingSet(); Map resultsVatings = new HashMap(); //Get data from server try { toServer.writeObject("RESULTS"); toServer.flush(); Boolean b = (Boolean) fromServer.readObject(); System.out.println("Can we see results? "+b); // if ((Boolean) fromServer.readObject()) { //We'll receive a boolean saying whether to expect data or not if(b){ resultsData = (VatingSet) fromServer.readObject(); //Get all vating data from file resultsVatings = resultsData.getVatings(); //Poll questions, etc. //Load data into GUI //Load combo box JComboBox loadedCombo = resultsData.getVatingCombo(); //So we can access stored data resultsCombo.removeAllItems(); //Clear the combobox on the GUI before filling it for (int i=0; i < loadedCombo.getItemCount() - 1; i++) { //Why -1? We don't want the last item, resultsCombo.addItem(loadedCombo.getItemAt(i)); //Copy items from the stored data to the GUI } // reset.loadData(); //Loads choice information } else { resultsText.setText("Cannot view results at this point in time. Try again later."); } } catch(Exception err) { System.out.println("Error!"); System.out.println(err.getLocalizedMessage()); } } } } //End of App class /* VatingSet holds allll the data that the user creates: the set * of polling questions, etc, as well as other settings * Chad Schultz */ class VatingSet implements Serializable { //Serializable, so we can save it do disk private int vates; //Number of times people have vated private boolean vatingOpen; //Can users save vates right now? private boolean resultsOpen; //Can users view results right now? private boolean restrictVaters; //Require valid vater name Map vaters; //Map of Vater objects: who is allowed to vate Map vatings; //Map of vating objects: what people can vote/rate/sort JComboBox vCombo; public VatingSet () { vates = 0; vatingOpen = false; resultsOpen = false; restrictVaters = false; vaters = new HashMap(); vatings = new HashMap(); vCombo = new JComboBox(); } public int getVates() { return vates; } public synchronized void addVate() { //The number of votes/etc. Increment whenever a client sends us data vates = vates + 1; } public Boolean getVatingOpen() { //Can people vote/rate/sort? return vatingOpen; } public void setVatingOpen(Boolean b) { vatingOpen = b; } public Boolean getResultsOpen() { //Can people view the results? Note that people may be able to view results even after vating is closed, or may be able to vate without seeing results return resultsOpen; } public void setResultsOpen(Boolean b) { resultsOpen = b; } public Boolean getRestrictVaters() { return restrictVaters; } public void setRestrictVaters(Boolean b) { restrictVaters = b; } public Map getVaters() { return vaters; } public void setVaters(Map m) { vaters = m; } public Map getVatings() { return vatings; } public void setVatings(Map m) { vatings = m; } public JComboBox getVatingCombo() { return vCombo; } public void setVatingCombo(JComboBox c) { vCombo = c; } } /* Data for the name of a single person who is allowed to vate * Chad Schultz */ class Vater implements Serializable { private String name; private Boolean vated; public Vater(String n) { name = n; vated = false; //Have they already vated? } public String getName() { return name; } public void setName(String n) { name = n; } public Boolean getVated() { return vated; } public void setVated(Boolean b) { vated = b; } } /* Data for one poll question/etc. * Chad Schultz */ class Vating implements Serializable { private String name; private String description; public static int SORT = 0; //Codes for option button values in type public static int RATE = 1; public static int VOTE = 2; private int type; //Sort, rate, vote? private Map choices; //List of choices (such as candidates in an election) in a single vating private java.awt.List choiceList; //Storing the list object preserves much data- for example, the order of the choices. public Vating () { name = ""; description = ""; type = SORT; choices = new HashMap(); choiceList = new java.awt.List(); choiceList.add(" "); } public Vating (String n, String d) { name = n; description = d; type = SORT; choices = new HashMap(); choiceList = new java.awt.List(); choiceList.add(" "); } public String getName() { return name; } public void setName(String n) { name = n; } public String getDescription() { return description; } public void setDescription(String d) { description = d; } public int getType() { return type; } public void setType(int t) { type = t; } public Map getChoices() { return choices; } public void setChoices(Map m) { choices = m; } public java.awt.List getChoiceList() { return choiceList; } public void setChoiceList(java.awt.List l) { choiceList = l; } } /* The data for one single possible answer in one question * Chad Schultz */ class Choice implements Serializable { private String name; private String description; private int place; //Order in list private int score; public Choice () {} public Choice(String n, String d) { name = n; description = d; place = 0; score = 0; } public String getName() { return name; } public void setName(String n) { name = n; } public String getDescription() { return description; } public void setDescription(String d) { description = d; } public int getPlace() { return place; } public void setPlace(int p) { place = p; } public int getScore() { return score; } public void setScore(int s) { score = s; } }