package net.seninp.grammarviz.view; import java.awt.Dimension; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.text.SimpleDateFormat; import java.util.Observable; import java.util.Observer; import java.util.logging.Level; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JTabbedPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.ScrollPaneConstants; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.border.BevelBorder; import javax.swing.border.TitledBorder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.miginfocom.swing.MigLayout; import net.seninp.grammarviz.controller.GrammarVizController; import net.seninp.grammarviz.logic.GrammarVizChartData; import net.seninp.grammarviz.model.GrammarVizMessage; import net.seninp.grammarviz.session.UserSession; import net.seninp.jmotif.sax.NumerosityReductionStrategy; import net.seninp.util.StackTrace; /** * View component of the GrammarViz MVC GUI. * * @author psenin * */ public class GrammarVizView implements Observer, ActionListener { // the main window title private static final String APPLICATION_MOTTO = "GrammarViz 3.0: visualizing time series grammars"; // static block - we instantiate the logger private static final Logger LOGGER = LoggerFactory.getLogger(GrammarVizView.class); // relevant string constants and formatters go here // private static final String COMMA = ","; private static final String CR = "\n"; private static final String TITLE_FONT = "helvetica"; private SimpleDateFormat logDateFormat = new SimpleDateFormat("HH:mm:ss' '"); // String is the king - constants for actions // /** Select data file action key. */ protected static final String SELECT_FILE = "select_file"; /** Load data action key. */ protected static final String LOAD_DATA = "load_data"; /** Guess parameters action key. */ protected static final String GUESS_PARAMETERS = "guess_parameters"; /** Process data action key. */ protected static final String PROCESS_DATA = "process_data"; /** Reduce overlaps data action key. */ protected static final String CLUSTER_RULES = "cluster_rules"; /** Rank rules action key. */ protected static final String PRUNE_RULES = "rank_rules"; /** Find periodicity action key. */ protected static final String FIND_PERIODICITY = "find_periodicity"; /** Reduce overlaps data action key. */ protected static final String DISPLAY_CHART = "display_sequitur_chart"; /** Display density data action key. */ protected static final String DISPLAY_DENSITY_DATA = "display_density"; /** Display density data action key. */ protected static final String DISPLAY_LENGTH_HISTOGRAM = "display_length_histogram"; /** Display density data action key. */ protected static final String DISPLAY_ANOMALIES_DATA = "display_anomalies_data"; /** Save chart action key. */ protected static final String SAVE_CHART = "save_chart"; /** The guess button has two functions: "GUESS" and "STOP SAMPLING", so we need some flags */ protected static final String RESET_GUESS_BUTTON_LISTENER = "reset_guess_button_listener"; /** Chunking/Sliding switch action key. */ protected static final String USE_SLIDING_WINDOW_ACTION_KEY = "sliding_window_key"; /** The action command for Options dialog. */ private static final String OPTIONS_MENU_ITEM = "menu_item_options"; /** The action command for About dialog. */ private static final String ABOUT_MENU_ITEM = "menu_item_about"; /** Frame for the GUI. */ private static final JFrame frame = new JFrame(APPLICATION_MOTTO); /** The main menu bar. */ private static final JMenuBar menuBar = new JMenuBar(); /** Global controller handler - controller is supplier of action handlers. */ private GrammarVizController controller; // data source related variables // private JPanel dataSourcePane; private JTextField dataFilePathField; private JButton selectFileButton; private JTextField dataRowsLimitTextField; private JButton dataLoadButton; // SAX parameters related fields // private JPanel saxParametersPane; private JCheckBox useSlidingWindowCheckBox; private JLabel windowSizeLabel; private JTextField SAXwindowSizeField; private JLabel paaSizeLabel; private JTextField SAXpaaSizeField; private JTextField SAXalphabetSizeField; private JButton guessParametersButton; // the guess dialog trigger // SAX numerosity reduction dialog group // private JPanel numerosityReductionPane; private ButtonGroup numerosityButtonsGroup = new ButtonGroup(); private JRadioButton numerosityReductionOFFButton = new JRadioButton("OFF"); private JRadioButton numerosityReductionExactButton = new JRadioButton("Exact"); private JRadioButton numerosityReductionMINDISTButton = new JRadioButton("MINDIST"); // The process action pane // private JPanel discretizePane; private JButton discretizeButton; // data charting panel // private GrammarvizChartPanel dataChartPane; // sequitur rules table and other tables panel // private JTabbedPane tabbedRulesPane; private GrammarRulesPanel grammarRulesPane; private PackedRulesPanel packedRulesPane; private RulesPeriodicityPanel rulesPeriodicityPane; private GrammarVizAnomaliesPanel anomaliesPane; // rule(s) charting auxiliary panel // private GrammarvizRuleChartPanel ruleChartPane; // workflow pane - buttons // private JPanel workflowManagementPane; private JButton clusterRulesButton; // private JButton findPeriodicityButton; private JButton rankRulesButton; private JButton displayChartButton; private JButton displayRulesDensityButton; private JButton displayRulesLenHistogramButton; private JButton findAnomaliesButton; private JButton saveChartButton; private boolean isTimeSeriesLoaded = false; // logging area // private static final JTextArea logTextArea = new JTextArea(); private static final JScrollPane logTextPane = new JScrollPane(logTextArea, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); /** * Constructor. * * @param controller The controller used for the application flow control. */ public GrammarVizView(GrammarVizController controller) { this.controller = controller; this.controller.getSession().addActionListener(this); } /** * Shows the GUI. */ public void showGUI() { // Schedule a job for the event-dispatching thread: // creating and showing this application's GUI. javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); // UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); } catch (ClassNotFoundException e) { System.err.println("ClassNotFoundException: " + e.getMessage()); } catch (InstantiationException e) { System.err.println("InstantiationException: " + e.getMessage()); } catch (IllegalAccessException e) { System.err.println("IllegalAccessException: " + e.getMessage()); } catch (UnsupportedLookAndFeelException e) { System.err.println("UnsupportedLookAndFeelException: " + e.getMessage()); } catch (Exception e) { System.err.print(StackTrace.toString(e)); } configureGUI(); // do some buttons work // disableAllButtons(); selectFileButton.setEnabled(true); } }); } /** * Initialize the dialog */ private void configureGUI() { // set look and fill JFrame.setDefaultLookAndFeelDecorated(true); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // build main UI components // buildMenuBar(); buildDataSourcePane(); buildSAXParamsPane(); buildChartPane(); buildSequiturPane(); buildWorkflowPane(); buildLogPane(); // put listeners in place for the Sequitur rule panel // grammarRulesPane.addPropertyChangeListener(dataChartPane); grammarRulesPane.addPropertyChangeListener(ruleChartPane); dataChartPane.addPropertyChangeListener(GrammarVizMessage.MAIN_CHART_CLICKED_MESSAGE, grammarRulesPane); // put listeners in place for the Clustered/Packed rule panel // packedRulesPane.addPropertyChangeListener(dataChartPane); packedRulesPane.addPropertyChangeListener(ruleChartPane); dataChartPane.addPropertyChangeListener(GrammarVizMessage.MAIN_CHART_CLICKED_MESSAGE, packedRulesPane); // put listeners in place for the Periodicity rule panel // rulesPeriodicityPane.addPropertyChangeListener(dataChartPane); rulesPeriodicityPane.addPropertyChangeListener(ruleChartPane); // dataChartPane.addPropertyChangeListener(GrammarVizMessage.MAIN_CHART_CLICKED_MESSAGE, // rulesPeriodicityPane); // put listeners in place for the Anomalies rule panel // anomaliesPane.addPropertyChangeListener(dataChartPane); anomaliesPane.addPropertyChangeListener(ruleChartPane); // set the main panel layout MigLayout mainFrameLayout = new MigLayout("", "[fill,grow,center]", "[][][fill,grow 50][fill,grow 50][][]"); frame.getContentPane().setLayout(mainFrameLayout); // set the menu bar frame.setJMenuBar(menuBar); // place panels frame.getContentPane().add(dataSourcePane, "wrap"); frame.getContentPane().add(saxParametersPane, "grow, split"); frame.getContentPane().add(numerosityReductionPane, "split"); frame.getContentPane().add(discretizePane, "wrap"); frame.getContentPane().add(dataChartPane, "wrap"); frame.getContentPane().add(tabbedRulesPane, "w 70%, split"); frame.getContentPane().add(ruleChartPane, "w 30%, wrap"); frame.getContentPane().add(workflowManagementPane, "wrap"); frame.getContentPane().add(logTextPane, "h 80:100:100,wrap"); // Show frame frame.pack(); // the resize trick dataChartPane.bindToTheFrameSize(); frame.setSize(new Dimension(1020, 840)); frame.setVisible(true); } /** * Build the application menu bar. */ private void buildMenuBar() { // Build the File menu. // // JMenu fileMenu = new JMenu("File"); fileMenu.setMnemonic(KeyEvent.VK_F); fileMenu.getAccessibleContext().setAccessibleDescription("The file menu"); // Open file item JMenuItem openFileItem = new JMenuItem("Select", KeyEvent.VK_O); openFileItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK)); openFileItem.getAccessibleContext().setAccessibleDescription("Open a data file"); openFileItem.setActionCommand(SELECT_FILE); openFileItem.addActionListener(this); fileMenu.add(openFileItem); // add a separator fileMenu.addSeparator(); // an exit item JMenuItem exitItem = new JMenuItem("Exit", KeyEvent.VK_X); exitItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, ActionEvent.CTRL_MASK)); exitItem.getAccessibleContext().setAccessibleDescription("Exit from here"); exitItem.addActionListener(this); fileMenu.add(exitItem); // Build the Options menu. // // JMenu settingsMenu = new JMenu("Settings"); settingsMenu.setMnemonic(KeyEvent.VK_S); settingsMenu.getAccessibleContext().setAccessibleDescription("Settings menu"); // an exit item JMenuItem optionsItem = new JMenuItem("GrammarViz options", KeyEvent.VK_P); optionsItem.setActionCommand(OPTIONS_MENU_ITEM); optionsItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, ActionEvent.CTRL_MASK)); optionsItem.getAccessibleContext().setAccessibleDescription("Options"); optionsItem.addActionListener(this); settingsMenu.add(optionsItem); // Build the About menu. JMenu helpMenu = new JMenu("Help"); helpMenu.setMnemonic(KeyEvent.VK_F1); helpMenu.getAccessibleContext().setAccessibleDescription("Help & About"); // a help item JMenuItem helpItem = new JMenuItem("Help", KeyEvent.VK_H); helpItem.getAccessibleContext().setAccessibleDescription("Get some help here."); exitItem.addActionListener(controller); helpMenu.add(helpItem); // an about item JMenuItem aboutItem = new JMenuItem("About", KeyEvent.VK_A); aboutItem.getAccessibleContext().setAccessibleDescription("About the app."); aboutItem.setActionCommand(ABOUT_MENU_ITEM); aboutItem.addActionListener(this); helpMenu.add(aboutItem); // make sure that controller is connected with Exit item // exitItem.addActionListener(controller); menuBar.add(fileMenu); menuBar.add(settingsMenu); menuBar.add(helpMenu); } private void buildDataSourcePane() { dataSourcePane = new JPanel(); // Layout, insets: T, L, B, R. dataSourcePane.setBorder(BorderFactory.createTitledBorder( BorderFactory.createEtchedBorder(BevelBorder.LOWERED), "Data source", TitledBorder.LEFT, TitledBorder.CENTER, new Font(TITLE_FONT, Font.PLAIN, 10))); MigLayout dataSourcePaneLayout = new MigLayout("insets 0 2 2 2", "[][fill,grow 80][]10[][fill, grow 20][]", "[]"); dataSourcePane.setLayout(dataSourcePaneLayout); // file label // JLabel fileNameLabel = new JLabel("Data file: "); // field dataFilePathField = new JTextField(""); fileNameLabel.setLabelFor(dataFilePathField); // the Browse button selectFileButton = new JButton("Browse..."); selectFileButton.setMnemonic('B'); dataSourcePane.add(fileNameLabel, ""); dataSourcePane.add(dataFilePathField, ""); dataSourcePane.add(selectFileButton, ""); // add the action listener // selectFileButton.addActionListener(controller.getBrowseFilesListener()); // dataFilePathField.getDocument().addDocumentListener(controller.getDataFileNameListener()); // data rows interval section // JLabel lblCountRows = new JLabel("Row limit (0=all):"); dataRowsLimitTextField = new JTextField("0"); dataSourcePane.add(lblCountRows, ""); dataSourcePane.add(dataRowsLimitTextField, ""); // the load button // dataLoadButton = new JButton("Load data"); dataLoadButton.setMnemonic('L'); // add the action listener dataLoadButton.setActionCommand(LOAD_DATA); dataLoadButton.addActionListener(this); dataSourcePane.add(dataLoadButton, ""); } /** * Builds a parameters pane. */ private void buildSAXParamsPane() { saxParametersPane = new JPanel(); saxParametersPane.setBorder(BorderFactory.createTitledBorder( BorderFactory.createEtchedBorder(BevelBorder.LOWERED), "SAX parameteres", TitledBorder.LEFT, TitledBorder.CENTER, new Font(TITLE_FONT, Font.PLAIN, 10))); // insets: T, L, B, R. MigLayout saxPaneLayout = new MigLayout("insets 3 2 2 2", "[][]10[][fill,grow]10[][fill,grow]10[][fill,grow]10[][]", "[]"); saxParametersPane.setLayout(saxPaneLayout); // the sliding window parameter JLabel slideWindowLabel = new JLabel("Slide the window"); useSlidingWindowCheckBox = new JCheckBox(); useSlidingWindowCheckBox.setSelected(this.controller.getSession().useSlidingWindow); useSlidingWindowCheckBox.setActionCommand(USE_SLIDING_WINDOW_ACTION_KEY); useSlidingWindowCheckBox.addActionListener(this); windowSizeLabel = new JLabel("Window size:"); SAXwindowSizeField = new JTextField(String.valueOf(this.controller.getSession().saxWindow)); paaSizeLabel = new JLabel("PAA size:"); SAXpaaSizeField = new JTextField(String.valueOf(this.controller.getSession().saxPAA)); JLabel alphabetSizeLabel = new JLabel("Alphabet size:"); SAXalphabetSizeField = new JTextField(String.valueOf(this.controller.getSession().saxAlphabet)); saxParametersPane.add(slideWindowLabel); saxParametersPane.add(useSlidingWindowCheckBox); saxParametersPane.add(windowSizeLabel); saxParametersPane.add(SAXwindowSizeField); saxParametersPane.add(paaSizeLabel); saxParametersPane.add(SAXpaaSizeField); saxParametersPane.add(alphabetSizeLabel); saxParametersPane.add(SAXalphabetSizeField); guessParametersButton = new JButton("Guess"); guessParametersButton.setMnemonic('G'); guessParametersButton.setActionCommand(GUESS_PARAMETERS); guessParametersButton.addActionListener(this); saxParametersPane.add(guessParametersButton, ""); // numerosity reduction pane // numerosityReductionPane = new JPanel(); numerosityReductionPane.setBorder(BorderFactory.createTitledBorder( BorderFactory.createEtchedBorder(BevelBorder.LOWERED), "Numerosity reduction", TitledBorder.LEFT, TitledBorder.CENTER, new Font(TITLE_FONT, Font.PLAIN, 10))); // insets: T, L, B, R. MigLayout numerosityPaneLayout = new MigLayout("insets 3 2 10 2", "[]5[]5[]", "[]"); numerosityReductionPane.setLayout(numerosityPaneLayout); numerosityReductionOFFButton.setActionCommand(NumerosityReductionStrategy.NONE.toString()); numerosityButtonsGroup.add(numerosityReductionOFFButton); numerosityReductionOFFButton.addActionListener(this); numerosityReductionPane.add(numerosityReductionOFFButton); numerosityReductionExactButton.setActionCommand(NumerosityReductionStrategy.EXACT.toString()); numerosityButtonsGroup.add(numerosityReductionExactButton); numerosityReductionExactButton.addActionListener(this); numerosityReductionPane.add(numerosityReductionExactButton); numerosityReductionMINDISTButton .setActionCommand(NumerosityReductionStrategy.MINDIST.toString()); numerosityButtonsGroup.add(numerosityReductionMINDISTButton); numerosityReductionMINDISTButton.addActionListener(this); numerosityReductionPane.add(numerosityReductionMINDISTButton); this.controller.getSession().numerosityReductionStrategy = NumerosityReductionStrategy.EXACT; numerosityReductionExactButton.setSelected(true); // PROCESS button // discretizeButton = new JButton("Discretize"); discretizeButton.setMnemonic('P'); discretizeButton.setActionCommand(PROCESS_DATA); discretizeButton.addActionListener(this); discretizePane = new JPanel(); discretizePane.setBorder(BorderFactory.createTitledBorder( BorderFactory.createEtchedBorder(BevelBorder.LOWERED), "Hit to run GI", TitledBorder.LEFT, TitledBorder.CENTER, new Font(TITLE_FONT, Font.PLAIN, 10))); // insets: T, L, B, R. MigLayout processPaneLayout = new MigLayout("insets 3 2 4 2", "5[]5", "[]"); discretizePane.setLayout(processPaneLayout); discretizePane.add(discretizeButton, ""); } private void buildChartPane() { // MotifChartPanel _chart = new MotifChartPanel(null); dataChartPane = new GrammarvizChartPanel(); dataChartPane.addActionListener(this); dataChartPane.session = this.controller.getSession(); dataChartPane.setBorder(BorderFactory.createTitledBorder( BorderFactory.createEtchedBorder(BevelBorder.LOWERED), "Data display", TitledBorder.LEFT, TitledBorder.CENTER, new Font(TITLE_FONT, Font.PLAIN, 10))); MigLayout chartPaneLayout = new MigLayout("insets 0 0 0 0", "[fill,grow]", "[fill,grow]"); dataChartPane.setLayout(chartPaneLayout); // needed to be able to stop guessing... // dataChartPane.setOperationalButton(this.guessParametersButton); } /** * Builds all objects and widgets related to Sequitur tables. */ private void buildSequiturPane() { // first the tabbed pane which holds other panels // tabbedRulesPane = new JTabbedPane(); // now add the raw Sequitur rules panel // grammarRulesPane = new GrammarRulesPanel(); MigLayout sequiturPaneLayout = new MigLayout(",insets 0 0 0 0", "[fill,grow]", "[fill,grow]"); grammarRulesPane.setLayout(sequiturPaneLayout); tabbedRulesPane.addTab("Grammar rules", null, grammarRulesPane, "Shows grammar rules"); // tabbedRulesPane.addTab("Sequitur", sequiturRulesPane); // tabbedRulesPane.setIgnoreRepaint(false); // now add the prototype of reduced rules panel // packedRulesPane = new PackedRulesPanel(); MigLayout packedRulesPaneLayout = new MigLayout(",insets 0 0 0 0", "[fill,grow]", "[fill,grow]"); packedRulesPane.setLayout(packedRulesPaneLayout); tabbedRulesPane.addTab("Regularized rules", null, packedRulesPane, "Shows reduced by overlapping criterion rules subset"); // now add the rules periodicity panel // rulesPeriodicityPane = new RulesPeriodicityPanel(); MigLayout rulesPeriodicityPaneLayout = new MigLayout(",insets 0 0 0 0", "[fill,grow]", "[fill,grow]"); rulesPeriodicityPane.setLayout(rulesPeriodicityPaneLayout); tabbedRulesPane.addTab("Rules periodicity", null, rulesPeriodicityPane, "Shows rules periodicity"); // now add the anomalies panel // anomaliesPane = new GrammarVizAnomaliesPanel(); MigLayout anomaliesPaneLayout = new MigLayout(",insets 0 0 0 0", "[fill,grow]", "[fill,grow]"); anomaliesPane.setLayout(anomaliesPaneLayout); tabbedRulesPane.addTab("GrammarViz anomalies", null, anomaliesPane, "Shows anomalous subsequences"); // now format the tabbed pane // tabbedRulesPane.setBorder( BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(BevelBorder.LOWERED), "Grammar rules (search in list by clicking into list and pressing CTRL-F)", TitledBorder.LEFT, TitledBorder.CENTER, new Font(TITLE_FONT, Font.PLAIN, 10))); // MigLayout tabbedPaneLayout = new MigLayout(",insets 0 0 0 2", "[fill,grow]", // "[fill,grow]"); // tabbedRulesPane.setLayout(tabbedPaneLayout); // the rule chart panel // ruleChartPane = new GrammarvizRuleChartPanel(); ruleChartPane.setBorder(BorderFactory.createTitledBorder( BorderFactory.createEtchedBorder(BevelBorder.LOWERED), "Rule subsequences, normalized", TitledBorder.LEFT, TitledBorder.CENTER, new Font(TITLE_FONT, Font.PLAIN, 10))); MigLayout ruleChartPaneLayout = new MigLayout(",insets 0 2 0 0", "[fill,grow]", "[fill,grow]"); ruleChartPane.setLayout(ruleChartPaneLayout); ruleChartPane.setController(this.controller); } private void buildWorkflowPane() { workflowManagementPane = new JPanel(); workflowManagementPane.setBorder( BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(BevelBorder.LOWERED), "Workflow management: load > process > display", TitledBorder.LEFT, TitledBorder.CENTER, new Font(TITLE_FONT, Font.PLAIN, 10))); MigLayout workflowPaneLayout = new MigLayout(",insets 2 2 2 2", "[fill,grow]", "[fill,grow]"); workflowManagementPane.setLayout(workflowPaneLayout); rankRulesButton = new JButton("Prune rules"); rankRulesButton.setMnemonic('U'); rankRulesButton.setActionCommand(PRUNE_RULES); rankRulesButton.addActionListener(this); clusterRulesButton = new JButton("Cluster rules"); clusterRulesButton.setMnemonic('C'); clusterRulesButton.setActionCommand(CLUSTER_RULES); clusterRulesButton.addActionListener(this); displayChartButton = new JButton("Clear plot"); displayChartButton.setMnemonic('R'); displayChartButton.setActionCommand(DISPLAY_CHART); displayChartButton.addActionListener(this); displayRulesDensityButton = new JButton("Rules density"); displayRulesDensityButton.setMnemonic('D'); displayRulesDensityButton.setActionCommand(DISPLAY_DENSITY_DATA); displayRulesDensityButton.addActionListener(this); displayRulesLenHistogramButton = new JButton("Rule length histogram"); displayRulesLenHistogramButton.setMnemonic('H'); displayRulesLenHistogramButton.setActionCommand(DISPLAY_LENGTH_HISTOGRAM); displayRulesLenHistogramButton.addActionListener(this); findAnomaliesButton = new JButton("Find anomalies"); findAnomaliesButton.setMnemonic('A'); findAnomaliesButton.setActionCommand(DISPLAY_ANOMALIES_DATA); findAnomaliesButton.addActionListener(this); saveChartButton = new JButton("Save Chart"); saveChartButton.setMnemonic('S'); saveChartButton.setActionCommand(SAVE_CHART); saveChartButton.addActionListener(this); // workflowManagementPane.add(processButton); workflowManagementPane.add(displayChartButton); workflowManagementPane.add(displayRulesLenHistogramButton); workflowManagementPane.add(clusterRulesButton); workflowManagementPane.add(rankRulesButton); workflowManagementPane.add(displayRulesDensityButton); workflowManagementPane.add(findAnomaliesButton); workflowManagementPane.add(saveChartButton); } /** * Build the logging panel. */ private void buildLogPane() { // logging panel logTextArea.setFont(new Font("MonoSpaced", Font.PLAIN, 10)); logTextArea.setEditable(false); logTextArea.setCaretPosition(logTextArea.getDocument().getLength()); logTextPane.setBorder(BorderFactory.createEtchedBorder(BevelBorder.LOWERED)); logTextPane.setAutoscrolls(true); log(Level.INFO, "running GrammarViz 3.0 demo"); } /** * Shut downs the application. */ private void shutdown() { Runtime.getRuntime().exit(0); } /** * Logs message. * * @param level The logging level to use. * @param message The log message. */ protected void log(Level level, String message) { message = message.replaceAll("\n", ""); String dateStr = logDateFormat.format(System.currentTimeMillis()); if (message.startsWith("model") || message.startsWith("controller")) { logTextArea.append(dateStr + message + CR); } else { logTextArea.append(dateStr + "view: " + message + CR); } logTextArea.setCaretPosition(logTextArea.getDocument().getLength()); LOGGER.info(dateStr + message); } @Override public void update(Observable o, Object arg) { if (arg instanceof GrammarVizMessage) { final GrammarVizMessage message = (GrammarVizMessage) arg; // new log message // if (GrammarVizMessage.STATUS_MESSAGE.equalsIgnoreCase(message.getType())) { log(Level.ALL, (String) message.getPayload()); } // new FileName // else if (GrammarVizMessage.DATA_FNAME.equalsIgnoreCase(message.getType())) { Runnable doSetPath = new Runnable() { @Override public void run() { dataFilePathField.setText((String) message.getPayload()); dataFilePathField.repaint(); disableAllButtons(); selectFileButton.setEnabled(true); dataLoadButton.setEnabled(true); } }; SwingUtilities.invokeLater(doSetPath); } else if (GrammarVizMessage.TIME_SERIES_MESSAGE.equalsIgnoreCase(message.getType())) { // setting the chart first // dataChartPane.showTimeSeries((double[]) message.getPayload()); Runnable clearPanels = new Runnable() { @Override public void run() { grammarRulesPane.clearPanel(); ruleChartPane.clear(); rulesPeriodicityPane.clear(); anomaliesPane.clear(); frame.repaint(); disableAllButtons(); selectFileButton.setEnabled(true); dataLoadButton.setEnabled(true); guessParametersButton.setEnabled(true); discretizeButton.setEnabled(true); } }; SwingUtilities.invokeLater(clearPanels); this.isTimeSeriesLoaded = true; this.controller.getSession().chartData = null; } // chart object // else if (GrammarVizMessage.CHART_MESSAGE.equalsIgnoreCase(message.getType())) { this.controller.getSession().chartData = (GrammarVizChartData) message.getPayload(); // setting the chart first // dataChartPane.setSession(this.controller.getSession()); // and the rules pane second // grammarRulesPane.setChartData(this.controller.getSession()); // and the "snapshots panel" // ruleChartPane.setChartData(this.controller.getSession()); // and the rules periodicity panel // rulesPeriodicityPane.setChartData(this.controller.getSession()); // and the anomalies panel // anomaliesPane.setChartData(this.controller.getSession()); enableAllButtons(); // dataChartPane.getChart().setNotify(true); frame.revalidate(); frame.repaint(); } } } @Override public void actionPerformed(ActionEvent arg) { // get the action command code // String command = arg.getActionCommand(); // treating options // if (OPTIONS_MENU_ITEM.equalsIgnoreCase(command)) { log(Level.INFO, "options menu action performed"); GrammarvizOptionsPane parametersPanel = new GrammarvizOptionsPane( this.controller.getSession()); GrammarvizOptionsDialog parametersDialog = new GrammarvizOptionsDialog(frame, parametersPanel, this.controller.getSession()); parametersDialog.setVisible(true); } // showing up the about dialog // if (ABOUT_MENU_ITEM.equalsIgnoreCase(command)) { log(Level.INFO, "about menu action performed"); AboutGrammarVizDialog dlg = new AboutGrammarVizDialog(frame); dlg.clearAndHide(); } if (SELECT_FILE.equalsIgnoreCase(command)) { log(Level.INFO, "select file action performed"); controller.getBrowseFilesListener().actionPerformed(null); } if (LOAD_DATA.equalsIgnoreCase(command)) { log(Level.INFO, "load data action performed"); this.isTimeSeriesLoaded = false; if (this.dataFilePathField.getText().isEmpty()) { raiseValidationError("The file is not yet selected."); } else { String loadLimit = this.dataRowsLimitTextField.getText(); this.controller.getLoadFileListener().actionPerformed(new ActionEvent(this, 1, loadLimit)); } } else if (PROCESS_DATA.equalsIgnoreCase(command)) { log(Level.INFO, "process data action performed"); if (this.isTimeSeriesLoaded) { // check the values for window/paa/alphabet, etc. this.controller.getSession().saxWindow = Integer.valueOf(this.SAXwindowSizeField.getText()); this.controller.getSession().saxPAA = Integer.valueOf(this.SAXpaaSizeField.getText()); this.controller.getSession().saxAlphabet = Integer .valueOf(this.SAXalphabetSizeField.getText()); this.controller.getProcessDataListener().actionPerformed(new ActionEvent(this, 0, null)); // only // one // handler // over // there } else { raiseValidationError("The timeseries is not loaded yet."); } } else if (DISPLAY_CHART.equalsIgnoreCase(command)) { log(Level.INFO, "display chart action performed"); if (null == this.controller.getSession().chartData) { raiseValidationError("No chart data recieved yet."); } else { dataChartPane.resetChartPanel(); grammarRulesPane.resetSelection(); ruleChartPane.clear(); } } else if (DISPLAY_DENSITY_DATA.equalsIgnoreCase(command)) { log(Level.INFO, "display density plot action performed"); if (null == this.controller.getSession().chartData) { raiseValidationError("No chart data recieved yet."); } else { ruleChartPane.clear(); this.dataChartPane.actionPerformed(new ActionEvent(this, 0, DISPLAY_DENSITY_DATA)); } } else if (DISPLAY_LENGTH_HISTOGRAM.equalsIgnoreCase(command)) { log(Level.INFO, "display rule length histogram action performed"); if (null == this.controller.getSession().chartData) { raiseValidationError("No chart data recieved yet."); } else { ruleChartPane.clear(); this.dataChartPane.actionPerformed(new ActionEvent(this, 1, DISPLAY_LENGTH_HISTOGRAM)); } } else if (DISPLAY_ANOMALIES_DATA.equalsIgnoreCase(command)) { log(Level.INFO, "find/display anomalies action performed"); if (null == this.controller.getSession().chartData) { raiseValidationError("No chart data recieved yet."); } else { log(Level.INFO, "going to run anomalies search, this takes time, please wait... "); try { this.controller.getSession().chartData.addObserver(this); this.controller.getSession().chartData.findAnomalies(); this.anomaliesPane.updateAnomalies(); this.anomaliesPane.resetPanel(); this.controller.getSession().chartData.deleteObserver(this); } catch (Exception e) { String errorTrace = StackTrace.toString(e); log(Level.ALL, errorTrace); } } } else if (SAVE_CHART.equalsIgnoreCase(command)) { log(Level.INFO, "save chart action performed"); if (null == this.controller.getSession().chartData) { raiseValidationError("No chart data recieved yet."); } else { this.dataChartPane.actionPerformed(new ActionEvent(this, 2, SAVE_CHART)); } } else if (GUESS_PARAMETERS.equalsIgnoreCase(command)) { log(Level.INFO, "starting the guessing params dialog"); disableAllButtons(); this.guessParametersButton.setEnabled(true); this.guessParametersButton.removeActionListener(this); this.dataChartPane.actionPerformed(new ActionEvent(this, 2, GUESS_PARAMETERS)); enableAllButtons(); } else if (UserSession.PARAMS_CHANGED_EVENT.equalsIgnoreCase(command)) { this.SAXwindowSizeField.setText(String.valueOf(this.controller.getSession().saxWindow)); this.SAXpaaSizeField.setText(String.valueOf(this.controller.getSession().saxPAA)); this.SAXalphabetSizeField.setText(String.valueOf(this.controller.getSession().saxAlphabet)); this.saxParametersPane.revalidate(); this.saxParametersPane.repaint(); } else if (RESET_GUESS_BUTTON_LISTENER.equalsIgnoreCase(command)) { this.guessParametersButton.setText("Guess"); this.guessParametersButton.addActionListener(this); this.discretizeButton.setEnabled(true); } else if (FIND_PERIODICITY.equalsIgnoreCase(command)) { log(Level.INFO, "find periodicity action performed"); this.dataChartPane.actionPerformed(new ActionEvent(this, 3, FIND_PERIODICITY)); } else if (CLUSTER_RULES.equalsIgnoreCase(command)) { log(Level.INFO, "cluster/prune rules action performed"); if (null == this.controller.getSession().chartData) { raiseValidationError("No chart data recieved yet."); } else { // fix the parameters JTextField lengthThreshold = new JTextField("0.1"); JTextField overlapThreshold = new JTextField("0.5"); // build a parameters panel JPanel parameterPanel = new JPanel(); parameterPanel.add(new JLabel("threshold for length:")); parameterPanel.add(lengthThreshold); parameterPanel.add(Box.createHorizontalStrut(15)); // a spacer parameterPanel.add(new JLabel("threshold for overlap:")); parameterPanel.add(overlapThreshold); // wait for the user int result = JOptionPane.showConfirmDialog(null, parameterPanel, "Please Enter Parameter", JOptionPane.OK_CANCEL_OPTION); if (result == JOptionPane.OK_OPTION) { double thresholdLength = Double.parseDouble(lengthThreshold.getText()); double thresholdCommon = Double.parseDouble(overlapThreshold.getText()); dataChartPane.resetChartPanel(); packedRulesPane.resetSelection(); ruleChartPane.clear(); this.controller.getSession().chartData.performRemoveOverlapping(thresholdLength, thresholdCommon); packedRulesPane.setChartData(this.controller.getSession().chartData); } } } else if (PRUNE_RULES.equalsIgnoreCase(command)) { log(Level.INFO, "prune rules action performed"); if (null == this.controller.getSession().chartData) { raiseValidationError("No chart data recieved yet."); } else { this.controller.getSession().chartData.performRulePruning(); // setting the chart first // dataChartPane.resetChartPanel(); // and the rules pane second // grammarRulesPane.resetPanel(); // and the "snapshots panel" // ruleChartPane.clear(); // and the rules periodicity panel // rulesPeriodicityPane.resetPanel(); // and the anomalies panel // anomaliesPane.resetPanel(); // dataChartPane.getChart().setNotify(true); frame.validate(); frame.repaint(); } } else if (USE_SLIDING_WINDOW_ACTION_KEY.equalsIgnoreCase(command)) { log(Level.INFO, "sliding window toggled"); if (this.useSlidingWindowCheckBox.isSelected()) { this.controller.getSession().useSlidingWindow = true; this.windowSizeLabel.setText("Window size:"); this.windowSizeLabel.setEnabled(true); this.windowSizeLabel.setVisible(true); this.SAXwindowSizeField.setText(String.valueOf(this.controller.getSession().saxWindow)); this.SAXwindowSizeField.setEnabled(true); this.SAXwindowSizeField.setVisible(true); this.paaSizeLabel.setText("PAA size:"); } else { this.controller.getSession().useSlidingWindow = false; this.windowSizeLabel.setText(""); this.windowSizeLabel.setEnabled(false); this.windowSizeLabel.setVisible(false); this.SAXwindowSizeField.setEnabled(false); this.SAXwindowSizeField.setVisible(false); this.paaSizeLabel.setText("Segments number:"); } } else if (NumerosityReductionStrategy.NONE.toString().equalsIgnoreCase(command) || NumerosityReductionStrategy.EXACT.toString().equalsIgnoreCase(command) || NumerosityReductionStrategy.MINDIST.toString().equalsIgnoreCase(command)) { log(Level.INFO, "numerosity reduction option toggled"); this.controller.getSession().numerosityReductionStrategy = NumerosityReductionStrategy .fromString(command); } else if ("Exit".equalsIgnoreCase(command)) { log(Level.INFO, "Exit selected, shutting down, bye! "); shutdown(); } } private void raiseValidationError(String message) { JOptionPane.showMessageDialog(frame, message, "Validation error", JOptionPane.ERROR_MESSAGE); } /** * Shortcut to disable all buttons. */ private void disableAllButtons() { this.selectFileButton.setEnabled(true); this.dataLoadButton.setEnabled(false); this.guessParametersButton.setEnabled(false); this.discretizeButton.setEnabled(false); this.findAnomaliesButton.setEnabled(false); this.displayChartButton.setEnabled(false); this.clusterRulesButton.setEnabled(false); this.rankRulesButton.setEnabled(false); this.displayRulesDensityButton.setEnabled(false); this.displayRulesLenHistogramButton.setEnabled(false); this.saveChartButton.setEnabled(false); } /** * Shortcut to enable all buttons. */ private void enableAllButtons() { this.selectFileButton.setEnabled(true); this.dataLoadButton.setEnabled(true); this.guessParametersButton.setEnabled(true); this.discretizeButton.setEnabled(true); this.findAnomaliesButton.setEnabled(true); this.displayChartButton.setEnabled(true); this.clusterRulesButton.setEnabled(true); this.rankRulesButton.setEnabled(true); this.displayRulesDensityButton.setEnabled(true); this.displayRulesLenHistogramButton.setEnabled(true); this.saveChartButton.setEnabled(true); } }