package context.arch.intelligibility.presenters; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.JSeparator; import context.arch.discoverer.ComponentDescription; import context.arch.enactor.Enactor; import context.arch.intelligibility.Explainer; import context.arch.intelligibility.Explanation; import context.arch.intelligibility.query.AltQuery; import context.arch.intelligibility.query.Query; import context.arch.intelligibility.query.QueryListener; import context.arch.intelligibility.query.WhatIfQuery; public class QueryButton extends JButton implements ActionListener { private static final long serialVersionUID = 857616575202708153L; protected JPopupMenu popup; private int x, y; protected String context; protected String value; protected Enactor enactor; protected ComponentDescription widgetState; protected Map<String, Icon> contextIcons; public QueryButton(String label, ComponentDescription widgetState, Enactor enactor) { this(label, new HashMap<String, Icon>(), // empty icon map widgetState, enactor); } public QueryButton(String label, Map<String, Icon> contextIcons, // to map icons, if no icons, then just supply an empty map ComponentDescription widgetState, Enactor enactor) { super(label); this.contextIcons = contextIcons; this.widgetState = widgetState; this.enactor = enactor; this.context = enactor.getOutcomeName(); this.value = enactor.getOutcomeValue(); this.addActionListener(this); // listen to button press this.popup = createPopupMenu(); this.x = 0; this.y = (int)this.getPreferredSize().getHeight(); } public void setWidgetState(ComponentDescription widgetState) { this.widgetState = widgetState; this.popup = createPopupMenu(); // re-create } protected JPopupMenu createPopupMenu() { JPopupMenu popup = new JPopupMenu(); JMenu menu; /* * Preload outcome values for use in some queries */ List<String> outputValues = getOutputs(); // What attachMenuItem(Query.QUESTION_WHAT, popup, this); // Certainty attachMenuItem(Query.QUESTION_CERTAINTY, popup, this); // Inputs attachMenuItem(Query.QUESTION_INPUTS + " Values", Query.QUESTION_INPUTS, popup, this); /* ------------------------------------------------- */ popup.add(new JSeparator()); // When attachMenuItem(Query.QUESTION_WHEN, popup, this); // When Last menu = new JMenu(AltQuery.QUESTION_WHEN_LAST); popup.add(menu); for (String outputValue : outputValues) { attachMenuItem(outputValue, outputValue, AltQuery.QUESTION_WHEN_LAST, contextIcons.get(outputValue), menu, this); } // What At Time attachMenuItem(Query.QUESTION_WHAT_AT_TIME + "...", Query.QUESTION_WHAT_AT_TIME, popup, this); /* ------------------------------------------------- */ popup.add(new JSeparator()); // Why attachMenuItem(Query.QUESTION_WHY, popup, this); // Why Not menu = new JMenu(AltQuery.QUESTION_WHY_NOT); popup.add(menu); for (String outputValue : outputValues) { if (outputValue.equals(value)) { continue; } // skip if matches current value attachMenuItem(outputValue, outputValue, AltQuery.QUESTION_WHY_NOT, contextIcons.get(outputValue), menu, this); } // How To menu = new JMenu("How Does"); // AltQuery.QUESTION_HOW_TO popup.add(menu); for (String outputValue : outputValues) { attachMenuItem(outputValue, outputValue, AltQuery.QUESTION_HOW_TO, contextIcons.get(outputValue), menu, this); } // What If attachMenuItem(WhatIfQuery.QUESTION_WHAT_IF + "...", WhatIfQuery.QUESTION_WHAT_IF, popup, this); /* ------------------------------------------------- */ popup.add(new JSeparator()); // Definition attachMenuItem(Query.QUESTION_DEFINITION, popup, this); // Rationale attachMenuItem(Query.QUESTION_RATIONALE, popup, this); // Outputs attachMenuItem("Possible " + Query.QUESTION_OUTPUTS, Query.QUESTION_OUTPUTS, popup, this); return popup; } /** * To help preload outcome values for use in some queries */ protected List<String> getOutputs() { Query query = new Query(Query.QUESTION_OUTPUTS, context, System.currentTimeMillis()); Explanation explanation = enactor.getExplainer().getExplanation(query); List<String> outputValues = Explainer.outputsToLabels(explanation.getContent()); return outputValues; } public static JMenuItem attachMenuItem(String actionCommand, JComponent menu, ActionListener listener) { return attachMenuItem(actionCommand, actionCommand, actionCommand, menu, listener); } public static JMenuItem attachMenuItem(String label, String actionCommand, JComponent menu, ActionListener listener) { return attachMenuItem(label, actionCommand, actionCommand, menu, listener); } public static JMenuItem attachMenuItem(String label, String name, String actionCommand, JComponent menu, ActionListener listener) { return attachMenuItem(label, name, actionCommand, null, menu, listener); } public static JMenuItem attachMenuItem(String label, String name, String actionCommand, Icon icon, JComponent menu, ActionListener listener) { JMenuItem mi = new JMenuItem(label, icon); mi.setName(name); mi.setActionCommand(actionCommand); menu.add(mi); mi.addActionListener(listener); String tooltipText = getQuestionDefinition(actionCommand); // may be null if actionCommand is not a question mi.setToolTipText(tooltipText); return mi; } private static final Map<String, String> questionDefinitions = new HashMap<String, String>(); // <question, definition> static { questionDefinitions.put(Query.QUESTION_WHAT, "The output value of the context."); questionDefinitions.put(Query.QUESTION_CERTAINTY, "The uncertainty regarding the context value."); questionDefinitions.put(Query.QUESTION_INPUTS, "The inputs (and their values) that La\u03BAsa used to determine the context value."); questionDefinitions.put(Query.QUESTION_WHEN, "When the context was changed to the value shown."); questionDefinitions.put(AltQuery.QUESTION_WHEN_LAST, "When the context last had the value chosen."); questionDefinitions.put(Query.QUESTION_WHAT_AT_TIME, "The output value of the context at another chosen time."); questionDefinitions.put(Query.QUESTION_WHY, "The reason why La\u03BAsa inferred the context value."); questionDefinitions.put(AltQuery.QUESTION_WHY_NOT, "The reason why La\u03BAsa did not infer a particular context value."); questionDefinitions.put(AltQuery.QUESTION_HOW_TO, "A facility for you to find a way to get La\u03BAsa to achive a certain context value."); questionDefinitions.put(WhatIfQuery.QUESTION_WHAT_IF, "A facility for you to change input values to see how the context value would change."); questionDefinitions.put(Query.QUESTION_DEFINITION, "The meaning or definition of the context term."); questionDefinitions.put(Query.QUESTION_RATIONALE, "The rationale for considering this context."); questionDefinitions.put(Query.QUESTION_OUTPUTS, "The possible output values that this context can have."); } private static String getQuestionDefinition(String question) { // TODO: offload to an external file or Google Docs return questionDefinitions.get(question); } /** * To listen to when menu items are selected. * It identifies the menu item and generates the appropriate query. */ @Override public void actionPerformed(ActionEvent evt) { Object src = evt.getSource(); if (src == this) { popup.show(this, x, y); } else if (src instanceof JMenuItem) { String question = evt.getActionCommand(); // System.out.println("QueryButton question = " + question); long timestamp = System.currentTimeMillis(); /* * Process query */ Query query; if (question.equals(Query.QUESTION_WHAT)) { query = new Query(question, context, timestamp); } else if (question.equals(Query.QUESTION_WHAT_AT_TIME)) { // long time = TimePickerDialog.retrievePickedTimestamp(timestamp); // time being questioned about // System.out.println("QuestionButton QUESTION_WHAT_AT_TIME time = " + time); // // TODO // query = new Query(question, context, timestamp); } else if (question.equals(AltQuery.QUESTION_WHY_NOT) || question.equals(AltQuery.QUESTION_HOW_TO) || question.equals(AltQuery.QUESTION_WHEN_LAST)) { String altValue = ((JComponent)evt.getSource()).getName(); query = new AltQuery(question, context, altValue, timestamp); } else { // unknown query = new Query(question, context, timestamp); } notifyListeners(query); } } /* ----------------------------------------------------------- * Query Listening code * ----------------------------------------------------------- */ protected List<QueryListener> listeners = new ArrayList<QueryListener>(); public void addQueryListener(QueryListener listener) { listeners.add(listener); } protected void notifyListeners(Query query) { for (QueryListener listener : listeners) { listener.queryInvoked(query); } } }