package org.regenstrief.linkage.gui; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.GridLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.File; import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.DefaultCellEditor; import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.JTableHeader; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import javax.swing.table.TableModel; import org.regenstrief.linkage.analysis.ClosedFormAnalyzer; import org.regenstrief.linkage.analysis.ClosedFormDedupAnalyzer; import org.regenstrief.linkage.analysis.DataSourceAnalysis; import org.regenstrief.linkage.analysis.DataSourceFrequency; import org.regenstrief.linkage.analysis.DedupRandomSampleAnalyzer; import org.regenstrief.linkage.analysis.EMAnalyzer; import org.regenstrief.linkage.analysis.FrequencyAnalyzer; import org.regenstrief.linkage.analysis.MemoryBackedDataSourceFrequency; import org.regenstrief.linkage.analysis.PairDataSourceAnalysis; import org.regenstrief.linkage.analysis.RandomSampleAnalyzer; import org.regenstrief.linkage.io.BlockSizeFormPairs; import org.regenstrief.linkage.io.CommonPairFormPairs; import org.regenstrief.linkage.io.DataSourceReader; import org.regenstrief.linkage.io.DedupOrderedDataSourceFormPairs; import org.regenstrief.linkage.io.FormPairs; import org.regenstrief.linkage.io.OrderedDataSourceFormPairs; import org.regenstrief.linkage.io.OrderedDataSourceReader; import org.regenstrief.linkage.io.ReaderProvider; import org.regenstrief.linkage.util.DataColumn; import org.regenstrief.linkage.util.FileWritingMatcher; import org.regenstrief.linkage.util.MatchingConfig; import org.regenstrief.linkage.util.MatchingConfigRow; import org.regenstrief.linkage.util.MatchingConfigValidator; import org.regenstrief.linkage.util.RecMatchConfig; /** * @author james-egg * * */ public class SessionsPanel extends JPanel implements ActionListener, KeyListener, ListSelectionListener, ItemListener, FocusListener, TableModelListener, MouseListener{ public final String DEFAULT_NAME = "New match"; JList runs; JTextField run_name; JTable session_options; JComboBox jcb; RecMatchConfig rm_conf; MatchingConfig current_working_config; private boolean mutualInfoScore, write_xml, groupAnalysis, common_pairs_fp; private JTextField randomSampleTextField; private JLabel randomSampleSizeLabel; private JTextField thresholdTextField; private JCheckBox cbMutualInfoScore; private JCheckBox cbWriteXML; private JCheckBox write_db; private JCheckBox cbGrouping; private JCheckBox filter_pairs; private JRadioButton ucalc_closed, ucalc_rand, mcalc_lock, mcalc_uinclude; private ButtonGroup ucalc_group, mcalc_group; private JButton calculate_uvalue, calculate_mvalue; private JPopupMenu resetm, resetu; private JCheckBox common_pairs; public SessionsPanel(RecMatchConfig rmc){ //super(); rm_conf = rmc; createSessionPanel(); } public void setRecMatchConfig(RecMatchConfig rmc){ rm_conf = rmc; updateBlockingRunsList(); } private void updateBlockingRunsList() { DefaultListModel dlm = new DefaultListModel(); if(rm_conf != null){ if(rm_conf.getMatchingConfigs().size() > 0){ Iterator<MatchingConfig> it = rm_conf.getMatchingConfigs().iterator(); while(it.hasNext()){ dlm.addElement(it.next()); } runs.setSelectedIndex(0); current_working_config = rm_conf.getMatchingConfigs().get(0); displayThisMatchingConfig(current_working_config); } else { current_working_config = null; } } runs.setModel(dlm); } private void createSessionPanel(){ // split the panel into two parts, top for table, bottom for other user interaction //JPanel session_panel = new JPanel(new GridLayout(2, 1)); this.setLayout(new GridLayout(2,1)); // item for the top panel this.add(getSessionTable()); // init popup menus JMenuItem reset; resetm = new JPopupMenu(); reset = new JMenuItem("Reset m values to default"); reset.addActionListener(this); resetm.add(reset); resetu = new JPopupMenu(); reset = new JMenuItem("Reset u values to default"); reset.addActionListener(this); resetu.add(reset); // add items for the bottom panel /* ********************************* * list and move up down button area * *********************************/ JPanel list_panel = new JPanel(); list_panel.setBorder(BorderFactory.createTitledBorder("Session List")); JButton up = new JButton(); up.addActionListener(this); up.setText("Move Up"); JButton down = new JButton(); down.addActionListener(this); down.setText("Move Down"); common_pairs = new JCheckBox("Combine pairs in blocks"); common_pairs.addActionListener(this); runs = new JList(); runs.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); runs.addListSelectionListener(this); runs.setCellRenderer(new MatchingConfigCellRenderer()); updateBlockingRunsList(); JScrollPane blockingRunScrollPane = new JScrollPane(); blockingRunScrollPane.setViewportView(runs); /* **************************************** * End of list and move up down button area * ****************************************/ /* ****************************** * Session Entry Modificator Area * ******************************/ JPanel sessionListEntryPanel = new JPanel(); run_name = new JTextField(); run_name.addKeyListener(this); JButton remove = new JButton(); remove.addActionListener(this); remove.setText("Remove"); JButton rename = new JButton(); rename.addActionListener(this); rename.setText("Rename"); JButton new_run = new JButton(); new_run.addActionListener(this); new_run.setText("New"); sessionListEntryPanel.setBorder(BorderFactory.createTitledBorder("Edit Session Label")); /* ****************************** * End Session Entry Modificator Area * ******************************/ /* ****************************** * Random Sample Area * ******************************/ JPanel uvalue_panel = new JPanel(); uvalue_panel.setBorder(BorderFactory.createTitledBorder("u-Value calculation")); ucalc_closed = new JRadioButton("Closed form"); ucalc_closed.addActionListener(this); ucalc_rand = new JRadioButton("Random Sample"); ucalc_rand.addActionListener(this); ucalc_group = new ButtonGroup(); ucalc_group.add(ucalc_closed); ucalc_group.add(ucalc_rand); randomSampleSizeLabel = new JLabel(); randomSampleSizeLabel.setText("Sample Size"); randomSampleSizeLabel.setEnabled(false); randomSampleTextField = new JTextField(); randomSampleTextField.setText("100000"); randomSampleTextField.setEnabled(false); randomSampleTextField.addFocusListener(this); calculate_uvalue = new JButton("Calculate u-values"); calculate_uvalue.addActionListener(this); /* ****************************** * End Random Sample Area * ******************************/ /* ****************************** * M value calculation area * ******************************/ JPanel mvalue_panel = new JPanel(); mvalue_panel.setBorder(BorderFactory.createTitledBorder("m / u-Value calculation")); mcalc_lock = new JRadioButton("Lock existing u-values in EM calculation"); mcalc_lock.addActionListener(this); mcalc_uinclude = new JRadioButton("Calculate u-values along with m-values in EM"); mcalc_uinclude.addActionListener(this); mcalc_group = new ButtonGroup(); mcalc_group.add(mcalc_lock); mcalc_group.add(mcalc_uinclude); calculate_mvalue = new JButton("Calculate values"); calculate_mvalue.addActionListener(this); /* ****************************** * End M value calculation area * ******************************/ /* ****************** * Linkage Panel Area * ******************/ JPanel linkagePanel = new JPanel(); linkagePanel.setBorder(BorderFactory.createTitledBorder("Linkage Process")); cbMutualInfoScore = new JCheckBox("Calculate and use MI scores"); cbMutualInfoScore.addActionListener(this); cbWriteXML = new JCheckBox("Include XML When Writing Output"); cbWriteXML.addActionListener(this); cbGrouping = new JCheckBox("Perform Grouping When Writing Output"); cbGrouping.addActionListener(this); write_db = new JCheckBox("Write Results To DB File"); write_db.addActionListener(this); filter_pairs = new JCheckBox("Filter Pairs When Writing Output"); filter_pairs.addActionListener(this); JButton run_link = new JButton(); run_link.addActionListener(this); run_link.setText("Run Linkage Process"); /* ********************** * End Linkage Panel Area * **********************/ /* ******************************* * Threshold Area * *******************************/ JPanel thresholdPanel = new JPanel(); JLabel thresholdLabel = new JLabel(); thresholdTextField = new JTextField(); thresholdTextField.addFocusListener(this); /* ******************************* * End Threshold Area * *******************************/ GridBagConstraints gridBagConstraints; JPanel flowPanel = new JPanel(); JPanel mainPanelSessions = new JPanel(); JPanel listPanel = new JPanel(); list_panel.setLayout(new GridLayout(1, 0)); flowPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0)); mainPanelSessions.setLayout(new GridBagLayout()); /* * Blocking Run List Section * * Blocking run list section. This section contains list of * blocking runs and two button (up and down) to control the sequence of * the blocking run process. */ listPanel.setLayout(new GridBagLayout()); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridwidth = 2; gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.ipadx = 5; gridBagConstraints.anchor = GridBagConstraints.NORTH; gridBagConstraints.weighty = 0.7; gridBagConstraints.insets = new Insets(1, 1, 1, 1); listPanel.add(blockingRunScrollPane, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.ipadx = 15; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.insets = new Insets(5, 0, 0, 2); listPanel.add(up, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = GridBagConstraints.EAST; gridBagConstraints.insets = new Insets(5, 2, 0, 0); listPanel.add(down, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.gridwidth = 2; gridBagConstraints.anchor = GridBagConstraints.SOUTH; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.insets = new Insets(5, 0, 0, 0); listPanel.add(common_pairs, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridheight = 4; gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.anchor = GridBagConstraints.NORTH; gridBagConstraints.insets = new Insets(5, 10, 5, 10); mainPanelSessions.add(listPanel, gridBagConstraints); /* * End of Blocking Run List Section */ /* * Blocking Run Modifier Section * * This sections is used to update the blocking runs list. User * can add, remove or rename a blocking run. The text field will * display current active blocking run. */ sessionListEntryPanel.setLayout(new GridBagLayout()); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.ipadx = 10; gridBagConstraints.insets = new Insets(0, 5, 5, 5); sessionListEntryPanel.add(new_run, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridwidth = 4; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.insets = new Insets(0, 0, 5, 5); sessionListEntryPanel.add(run_name, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 1; gridBagConstraints.ipadx = 2; gridBagConstraints.insets = new Insets(0, 5, 5, 5); sessionListEntryPanel.add(rename, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 4; gridBagConstraints.gridy = 1; gridBagConstraints.ipadx = 2; gridBagConstraints.insets = new Insets(0, 5, 5, 5); sessionListEntryPanel.add(remove, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; //gridBagConstraints.gridheight = 2; gridBagConstraints.anchor = GridBagConstraints.NORTH; mainPanelSessions.add(sessionListEntryPanel, gridBagConstraints); /* * End of Blocking Run Modifier Section */ /* * Random Sampling Parameters Section * * This section is used to modify the random sampling parameter * that will be used to generate the u-values. User can specify * whether to use random sampling and the sample size */ uvalue_panel.setLayout(new GridBagLayout()); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = 5; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.weightx = 0.7; gridBagConstraints.insets = new Insets(0, 5, 5, 5); uvalue_panel.add(ucalc_closed, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.gridwidth = 5; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.weightx = 0.7; gridBagConstraints.insets = new Insets(0, 5, 5, 5); uvalue_panel.add(ucalc_rand, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.ipadx = 5; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.insets = new Insets(0, 5, 5, 5); uvalue_panel.add(randomSampleSizeLabel, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 2; gridBagConstraints.gridwidth = 4; gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.insets = new Insets(0, 5, 5, 5); uvalue_panel.add(randomSampleTextField, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.gridwidth = 5; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.weightx = 0.7; gridBagConstraints.insets = new Insets(0, 5, 5, 5); uvalue_panel.add(calculate_uvalue, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 0; gridBagConstraints.gridheight = 2; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = GridBagConstraints.WEST; mainPanelSessions.add(uvalue_panel, gridBagConstraints); /* * End of Random Sampling Parameters Section */ /* * Begin m-calculation panel section */ mvalue_panel.setLayout(new GridBagLayout()); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = 5; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.weightx = 0.7; gridBagConstraints.insets = new Insets(0, 5, 5, 5); mvalue_panel.add(mcalc_uinclude, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.gridwidth = 5; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.weightx = 0.7; gridBagConstraints.insets = new Insets(0, 5, 5, 5); mvalue_panel.add(mcalc_lock, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.gridwidth = 5; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.weightx = 0.7; gridBagConstraints.insets = new Insets(0, 5, 5, 5); mvalue_panel.add(calculate_mvalue, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 2; gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.anchor = GridBagConstraints.WEST; mainPanelSessions.add(mvalue_panel, gridBagConstraints); /* * end m-calculation panel section */ /* * Linkage Process Section * * This section is used to run the linkage process after the * record is analyzed using EM with or without random sampling */ linkagePanel.setLayout(new GridBagLayout()); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.insets = new Insets(0, 5, 0, 5); linkagePanel.add(cbMutualInfoScore, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.insets = new Insets(0, 5, 0, 5); linkagePanel.add(cbWriteXML, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.insets = new Insets(0, 5, 0, 5); linkagePanel.add(cbGrouping, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.insets = new Insets(0, 5, 0, 5); linkagePanel.add(write_db, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 4; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.insets = new Insets(0, 5, 0, 5); linkagePanel.add(filter_pairs, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 5; gridBagConstraints.insets = new Insets(0, 5, 5, 5); linkagePanel.add(run_link, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 2; // gridBagConstraints.gridheight = 4; gridBagConstraints.anchor = GridBagConstraints.NORTH; gridBagConstraints.insets = new Insets(0, 0, 0, 0); mainPanelSessions.add(linkagePanel, gridBagConstraints); /* * End of Linkage Process Section */ /* * Matching Threshold Section * * This section is used input a threshold value to determine whether a record is match * or not. #807 */ thresholdPanel.setBorder(BorderFactory.createTitledBorder("Matching Threshold")); thresholdPanel.setLayout(new GridBagLayout()); thresholdLabel.setText("Threshold Value"); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.insets = new Insets(5, 5, 5, 2); thresholdPanel.add(thresholdLabel, gridBagConstraints); thresholdTextField.setText("0"); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = 4; gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.weightx = 0.5; gridBagConstraints.weighty = 0.5; gridBagConstraints.insets = new Insets(5, 2, 5, 5); thresholdPanel.add(thresholdTextField, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; //gridBagConstraints.anchor = GridBagConstraints.NORTH; mainPanelSessions.add(thresholdPanel, gridBagConstraints); /* * End of Linkage Process Section */ flowPanel.add(mainPanelSessions); list_panel.add(flowPanel); this.add(list_panel); } private void invalidBlockingSchemeNotification(){ JOptionPane.showMessageDialog(this, "Invalid blocking scheme; cannot run process", "Invalid Configuration", JOptionPane.ERROR_MESSAGE); } private Component getSessionTable(){ SessionOptionsTableModel model = new SessionOptionsTableModel(); model.addTableModelListener(this); session_options = new JTable(model); jcb = new JComboBox(); jcb.addItem(MatchingConfig.ALGORITHMS[0]); jcb.addItem(MatchingConfig.ALGORITHMS[1]); jcb.addItem(MatchingConfig.ALGORITHMS[2]); jcb.addItem(MatchingConfig.ALGORITHMS[3]); TableColumn tc = session_options.getColumnModel().getColumn(6); tc.setCellEditor(new DefaultCellEditor(jcb)); MUValueCellRenderer muvcr = new MUValueCellRenderer(); session_options.setDefaultRenderer(Double.class, muvcr); if(rm_conf != null && rm_conf.getLinkDataSource1() != null){ String id_demographic = rm_conf.getLinkDataSource1().getUniqueID(); model.setIDName(id_demographic); } JScrollPane table_pane = new JScrollPane(session_options); table_pane.setPreferredSize(new Dimension(800, 300)); session_options.getTableHeader().addMouseListener(this); return table_pane; } public void displayThisMatchingConfig(MatchingConfig mc){ //session_options.setModel(new SessionOptionsTableModel(mc)); // only display runs data if there's actually mc in the list model if(runs.getModel().getSize() > 0) { int selectedIndex = runs.getSelectedIndex(); // this special case when a user already load they're config file // no item in the blocking runs is selected. pick the first blocking // runs if(selectedIndex == -1) { selectedIndex = 0; } // select the first element in the list or current selected index // (redundant selection process) runs.setSelectedIndex(selectedIndex); MatchingConfig m = (MatchingConfig) runs.getModel().getElementAt(selectedIndex); // update the text field to reflect currently selected element in the list run_name.setText(m.getName()); // update the random sample size and check box based on the matching // config data if(m.isUsingRandomSampling()) { randomSampleTextField.setText(String.valueOf(m.getRandomSampleSize())); ucalc_rand.setSelected(true); randomSampleSizeLabel.setEnabled(true); randomSampleTextField.setEnabled(true); } else { ucalc_closed.setSelected(true); } if(m.isLockedUValues()){ this.mcalc_lock.setSelected(true); } else { this.mcalc_uinclude.setSelected(true); } thresholdTextField.setText(String.valueOf(m.getScoreThreshold())); } current_working_config = mc; SessionOptionsTableModel model = new SessionOptionsTableModel(mc); model.addTableModelListener(this); session_options.setModel(model); TableColumn tc = session_options.getColumnModel().getColumn(6); tc.setCellEditor(new DefaultCellEditor(jcb)); if(rm_conf != null && rm_conf.getLinkDataSource1() != null){ String id_demographic = rm_conf.getLinkDataSource1().getUniqueID(); model.setIDName(id_demographic); } } private void removeSessionConfig(MatchingConfig mc){ // removes mc from the DefaultListModel for the runs JList if(runs.getModel().getSize() > 0){ int old_index = runs.getSelectedIndex(); DefaultListModel dlm = (DefaultListModel)runs.getModel(); boolean removed = dlm.removeElement(mc); if(!removed){ System.out.println("error removing matching config from JList"); return; } rm_conf.getMatchingConfigs().remove(mc); // set another item to be selected if(runs.getModel().getSize() <= old_index){ // set the new selected object as the last item if(runs.getModel().getSize() == 0){ // removed last one, clear table to clear everything and crate a blank config setGuiElements(); } runs.setSelectedIndex(runs.getModel().getSize() - 1); } else { // set the old index as what is selected runs.setSelectedIndex(old_index); } } } private void moveUpSessionConfig(int index){ // move the session config in runs at index up DefaultListModel dlm = (DefaultListModel)runs.getModel(); // if item is at beginning of list, makes no sense to move up in order if(index > 0){ Object to_move = dlm.remove(index); dlm.add(index - 1, to_move); runs.setSelectedIndex(index - 1); // swap matching config MatchingConfig configA = rm_conf.getMatchingConfigs().remove(index); MatchingConfig configB = rm_conf.getMatchingConfigs().remove(index - 1); rm_conf.getMatchingConfigs().add(index - 1, configA); rm_conf.getMatchingConfigs().add(index, configB); } } private void moveDownSessionConfig(int index){ // move the session config in runs at index down DefaultListModel dlm = (DefaultListModel)runs.getModel(); // if item is at the end of the list, then it can't move down further if(index < (dlm.getSize() - 1)){ Object to_move = dlm.remove(index); dlm.add(index + 1, to_move); runs.setSelectedIndex(index + 1); // swap matching config MatchingConfig configA = rm_conf.getMatchingConfigs().remove(index); MatchingConfig configB = rm_conf.getMatchingConfigs().remove(index + 1); rm_conf.getMatchingConfigs().add(index, configB); rm_conf.getMatchingConfigs().add(index + 1, configA); } } private void renameSessionConfig(){ // the current working session config needs to be renamed, and have it's new name displayed // in the JList runs component if(current_working_config != null && runs.getModel().getSize() > 0){ String new_name = run_name.getText(); current_working_config.setName(new_name); runs.repaint(); // update the JList runs object to display the new name //DefaultListModel dlm = (DefaultListModel)runs.getModel(); //int current_list_index = dlm.indexOf(current_working_config); //dlm.setElementAt(current_working_config, current_list_index); } } public void keyTyped(KeyEvent ke){ // used for the rename text field on the session panel // if key is enter, rename the MatchingConfig if(ke.getSource() == run_name && ke.getKeyChar() == '\n'){ renameSessionConfig(); } } public void keyReleased(KeyEvent ke){ // not currently used } public void keyPressed(KeyEvent ke){ // not currently used } public void valueChanged(ListSelectionEvent lse){ // part of ListSelectionListener used with the JList runs object if(!lse.getValueIsAdjusting()){ if(current_working_config != null){ // check to see if the current working config is the same as what is // selected in the JList runs MatchingConfig mc = (MatchingConfig)runs.getSelectedValue(); if(mc != null && mc != current_working_config){ // clicked on a new item current_working_config = mc; displayThisMatchingConfig(current_working_config); } } } } public void actionPerformed(ActionEvent ae){ if(ae.getSource() instanceof JRadioButton){ JRadioButton source = (JRadioButton)ae.getSource(); if(source.getText().equals("Closed form")){ randomSampleTextField.setEnabled(false); randomSampleSizeLabel.setEnabled(false); if(current_working_config != null) { current_working_config.setUsingRandomSampling(false); } } else if(source.getText().equals("EM")){ randomSampleTextField.setEnabled(false); randomSampleSizeLabel.setEnabled(false); if(current_working_config != null) { current_working_config.setUsingRandomSampling(false); } } else if(source.getText().equals("Random Sample")){ randomSampleTextField.setEnabled(true); randomSampleSizeLabel.setEnabled(true); randomSampleTextField.setEnabled(true); randomSampleTextField.requestFocus(); if(current_working_config != null) { current_working_config.setUsingRandomSampling(true); int sampleSize = Integer.parseInt(randomSampleTextField.getText()); current_working_config.setRandomSampleSize(sampleSize); } } else if(source.getText().equals("Calculate u-values along with m-values in EM")){ if(current_working_config != null){ current_working_config.setLockedUValues(false); } } else if(source.getText().equals("Lock existing u-values in EM calculation")){ if(current_working_config != null){ current_working_config.setLockedUValues(true); } } } if(ae.getSource() instanceof JButton){ JButton source = (JButton)ae.getSource(); System.out.println("Source: " + source.getText()); if(source.getText().equals("Move Up")){ int index = runs.getSelectedIndex(); moveUpSessionConfig(index); } else if(source.getText().equals("Move Down")){ int index = runs.getSelectedIndex(); moveDownSessionConfig(index); } else if(source.getText().equals("Rename")){ renameSessionConfig(); } else if(source.getText().equals("New")){ MatchingConfig mc = makeNewMatchingConfig(); rm_conf.getMatchingConfigs().add(mc); DefaultListModel dlm = (DefaultListModel)runs.getModel(); dlm.addElement(mc); runs.setSelectedIndex(dlm.getSize() - 1); displayThisMatchingConfig(mc); } else if(source.getText().equals("Run Linkage Process")){ runLinkageProcess(); } else if(source.getText().equals("Remove")){ Object o = runs.getSelectedValue(); if(o instanceof MatchingConfig){ MatchingConfig mc = (MatchingConfig)o; removeSessionConfig(mc); } } else if(source.getText().equals("Calculate u-values")){ // run either closed form, random sampling, or EM if(ucalc_closed.isSelected()){ calculateClosedUValues(); } else if(ucalc_rand.isSelected()){ performRandomSampling(); } } else if(source.getText().equals("Calculate values")){ if(current_working_config != null){ runEMAnalysis(); } } } else if(ae.getSource() instanceof JCheckBox){ JCheckBox source = (JCheckBox)ae.getSource(); if(source.getText().equals("Calculate and use MI scores")){ mutualInfoScore = cbMutualInfoScore.isSelected(); } else if(source.getText().equals("Include XML When Writing Output")){ write_xml = cbWriteXML.isSelected(); } else if(source.getText().equals("Perform Grouping When Writing Output")){ groupAnalysis = cbGrouping.isSelected(); } else if(source.equals(common_pairs)){ common_pairs_fp = common_pairs.isSelected(); } } else if(ae.getSource() instanceof JMenuItem){ JMenuItem jmi = (JMenuItem)ae.getSource(); if(jmi.getText().equals("Reset u values to default")){ resetUValues(); } else if(jmi.getText().equals("Reset m values to default")){ resetMValues(); } } } private void runLinkageProcess(){ if(!MatchingConfigValidator.validMatchingConfig(current_working_config)){ invalidBlockingSchemeNotification(); return; } JFileChooser out_chooser = new JFileChooser(); int ret = out_chooser.showDialog(this, "Choose output file"); File out = null; File match_file = null; if(ret == JFileChooser.APPROVE_OPTION){ out = out_chooser.getSelectedFile(); boolean db = write_db.isSelected(); boolean filter = filter_pairs.isSelected(); match_file = FileWritingMatcher.writeMatchResults(rm_conf, out, write_xml, db, groupAnalysis, true, filter); if(match_file == null){ JOptionPane.showMessageDialog(this, "Error writing match result file", "Error", JOptionPane.ERROR_MESSAGE); } else { JOptionPane.showMessageDialog(this, "Matching results written to " + match_file, "Matching Successful", JOptionPane.INFORMATION_MESSAGE); } } } private void resetUValues(){ List<MatchingConfigRow> rows = current_working_config.getMatchingConfigRows(); Iterator<MatchingConfigRow> it = rows.iterator(); while(it.hasNext()){ MatchingConfigRow mcr = it.next(); mcr.setNonAgreement(MatchingConfigRow.DEFAULT_NON_AGREEMENT); } session_options.repaint(); } private void resetMValues(){ List<MatchingConfigRow> rows = current_working_config.getMatchingConfigRows(); Iterator<MatchingConfigRow> it = rows.iterator(); while(it.hasNext()){ MatchingConfigRow mcr = it.next(); mcr.setAgreement(MatchingConfigRow.DEFAULT_AGREEMENT); } session_options.repaint(); } private void performRandomSampling() { if(!MatchingConfigValidator.validMatchingConfig(current_working_config)){ invalidBlockingSchemeNotification(); return; } MatchingConfig mc = current_working_config; // if the user not choose to use random sampling, then do nothing // if the u-values is already locked then do nothing as well if(mc.isUsingRandomSampling()) { FormPairs fp2 = getFormPairs(); if(fp2 != null){ PairDataSourceAnalysis pdsa = new PairDataSourceAnalysis(fp2); ApplyAnalyzerLoggingFrame frame = new ApplyAnalyzerLoggingFrame(mc, this); MatchingConfig mcCopy = (MatchingConfig) mc.clone(); FormPairs rsa_fp2 = getFormPairs(); RandomSampleAnalyzer rsa ; if (rm_conf.isDeduplication()) { rsa = new DedupRandomSampleAnalyzer(mcCopy, rsa_fp2); } else { rsa = new RandomSampleAnalyzer(mcCopy, rsa_fp2); } pdsa.addAnalyzer(rsa); frame.addLoggingObject(rsa); frame.configureLoggingFrame(); pdsa.analyzeData(); } } session_options.repaint(); } private void calculateClosedUValues(){ if(!MatchingConfigValidator.validMatchingConfig(current_working_config)){ invalidBlockingSchemeNotification(); return; } if(!MatchingConfigValidator.validMatchingConfig(current_working_config)){ invalidBlockingSchemeNotification(); return; } ReaderProvider rp = ReaderProvider.getInstance(); MatchingConfig mc = current_working_config; if(rm_conf.isDeduplication()){ DataSourceReader dsr = rp.getReader(rm_conf.getLinkDataSource1()); DataSourceAnalysis dsa = new DataSourceAnalysis(dsr); MatchingConfig mcCopy = (MatchingConfig)mc.clone(); ClosedFormDedupAnalyzer cfda = new ClosedFormDedupAnalyzer(rm_conf.getLinkDataSource1(), mcCopy); ApplyAnalyzerLoggingFrame frame = new ApplyAnalyzerLoggingFrame(mc, this); frame.addLoggingObject(cfda); frame.configureLoggingFrame(); dsa.addAnalyzer(cfda); dsa.analyzeData(); } else { OrderedDataSourceReader odsr1 = rp.getReader(rm_conf.getLinkDataSource1(), mc); OrderedDataSourceReader odsr2 = rp.getReader(rm_conf.getLinkDataSource2(), mc); if(odsr1 != null && odsr2 != null){ FormPairs fp2 = null; fp2 = new OrderedDataSourceFormPairs(odsr1, odsr2, mc, rm_conf.getLinkDataSource1().getTypeTable()); ApplyAnalyzerLoggingFrame frame = new ApplyAnalyzerLoggingFrame(mc, this); PairDataSourceAnalysis pdsa = new PairDataSourceAnalysis(fp2); // create u value analyzer, add to pdsa, and run analysis MatchingConfig mcCopy = (MatchingConfig) mc.clone(); ClosedFormAnalyzer cfa = new ClosedFormAnalyzer(mcCopy); frame.addLoggingObject(cfa); frame.configureLoggingFrame(); pdsa.addAnalyzer(cfa); pdsa.analyzeData(); } } } private FormPairs getFormPairs(){ FormPairs ret = null; ReaderProvider rp = ReaderProvider.getInstance(); MatchingConfig mc = current_working_config; OrderedDataSourceReader odsr1 = rp.getReader(rm_conf.getLinkDataSource1(), mc); OrderedDataSourceReader odsr2 = rp.getReader(rm_conf.getLinkDataSource2(), mc); if (rm_conf.isDeduplication()) { ret = new DedupOrderedDataSourceFormPairs(odsr1, mc, rm_conf.getLinkDataSource1().getTypeTable()); } else { ret = new OrderedDataSourceFormPairs(odsr1, odsr2, mc, rm_conf.getLinkDataSource1().getTypeTable()); } if(common_pairs_fp){ List<FormPairs> fps = new ArrayList<FormPairs>(); fps.add(ret); Iterator<MatchingConfig> it = rm_conf.getMatchingConfigs().iterator(); while(it.hasNext()){ mc = it.next(); if(mc != current_working_config){ odsr1 = rp.getReader(rm_conf.getLinkDataSource1(), mc); odsr2 = rp.getReader(rm_conf.getLinkDataSource2(), mc); if (rm_conf.isDeduplication()) { ret = new DedupOrderedDataSourceFormPairs(odsr1, mc, rm_conf.getLinkDataSource1().getTypeTable()); } else { ret = new OrderedDataSourceFormPairs(odsr1, odsr2, mc, rm_conf.getLinkDataSource1().getTypeTable()); } fps.add(ret); } } ret = new CommonPairFormPairs(fps); } return ret; } private void runEMAnalysis(){ if(!MatchingConfigValidator.validMatchingConfig(current_working_config)){ invalidBlockingSchemeNotification(); return; } MatchingConfig mc = current_working_config; FormPairs fp2 = getFormPairs(); //BlockSizeFormPairs bsfp = new BlockSizeFormPairs(mc, fp2); //bsfp.setSizeLimit(1000); //fp2 = bsfp; ApplyAnalyzerLoggingFrame frame = new ApplyAnalyzerLoggingFrame(mc, this); PairDataSourceAnalysis pdsa = new PairDataSourceAnalysis(fp2); MatchingConfig mcCopy = (MatchingConfig) mc.clone(); EMAnalyzer ema = new EMAnalyzer(mcCopy); ema.setNullAveraging(mcCopy.isNullAveragingEM()); pdsa.addAnalyzer(ema); frame.addLoggingObject(ema); frame.configureLoggingFrame(); pdsa.analyzeData(); session_options.repaint(); thresholdTextField.setText(Double.toString(mc.getScoreThreshold())); } /* * Method called to create a new MatchingConfig when the user selecs this pane for the * first time (caught in the paint method, making sure there is at least one MatchingConfig * to show in the table) or when the user clicks on the "New" button. The main behaviour * requested is to have the order of the rows in the table reflect the include ordering * of the included data columns from the Data tab */ private MatchingConfig makeNewMatchingConfig(){ Hashtable<String, DataColumn> col_names = rm_conf.getLinkDataSource1().getIncludedDataColumns(); String[] names = new String[col_names.keySet().size()]; Enumeration<String> e = col_names.keys(); while(e.hasMoreElements()){ String name = e.nextElement(); DataColumn dc = col_names.get(name); names[dc.getIncludePosition()] = name; } MatchingConfig ret = new MatchingConfig(DEFAULT_NAME, names); return ret; } /** * Method first adds a check to see what MatchingConfig to set as active * for the SessionOptionsTable to display */ public void setGuiElements(){ if(rm_conf.getMatchingConfigs().size() == 0){ DefaultListModel dlm = (DefaultListModel)runs.getModel(); dlm.clear(); // need to create an empty one to display in session options table, and add to rm_conf // but only if the two link data sources are both defined if(rm_conf.getLinkDataSource1() != null){ MatchingConfig mc = makeNewMatchingConfig(); rm_conf.getMatchingConfigs().add(mc); // add to JList, set as active dlm.addElement(mc); current_working_config = mc; } } else if(runs.getModel().getSize() == 0){ // rm_conf object has MatchingConfig objects, but they have not // been inserted into the JList yet Iterator<MatchingConfig> it = rm_conf.iterator(); DefaultListModel dlm = (DefaultListModel)runs.getModel(); while(it.hasNext()){ dlm.addElement(it.next()); } current_working_config = (MatchingConfig)dlm.get(0); } displayThisMatchingConfig(current_working_config); } public void itemStateChanged(ItemEvent e) { // update the ui based on whether the use random sample is checked or not if(e.getSource() == ucalc_rand) { if(e.getStateChange() == ItemEvent.SELECTED) { randomSampleSizeLabel.setEnabled(true); randomSampleTextField.setEnabled(true); //lock_uvalue.setEnabled(true); randomSampleTextField.requestFocus(); if(current_working_config != null) { current_working_config.setUsingRandomSampling(true); int sampleSize = Integer.parseInt(randomSampleTextField.getText()); current_working_config.setRandomSampleSize(sampleSize); } } else if(e.getStateChange() == ItemEvent.DESELECTED){ randomSampleSizeLabel.setEnabled(false); randomSampleTextField.setEnabled(false); //lock_uvalue.setEnabled(false); randomSampleTextField.select(0, 0); if(current_working_config != null) { current_working_config.setUsingRandomSampling(false); } } } } public void focusGained(FocusEvent e) { if(randomSampleTextField == e.getSource()) { randomSampleTextField.selectAll(); } else if(thresholdTextField == e.getSource()) { thresholdTextField.selectAll(); } } public void focusLost(FocusEvent e) { if(randomSampleTextField == e.getSource()) { // only allows positive digit in the text field String digit = "\\d+"; String textValue = randomSampleTextField.getText(); Pattern pattern = Pattern.compile(digit); Matcher matcher = pattern.matcher(textValue); if (matcher.matches()) { if(current_working_config != null) { int sampleSize = Integer.parseInt(textValue); current_working_config.setRandomSampleSize(sampleSize); } } else { // should be showing a message using option pane here randomSampleTextField.setText("100000"); } } else if (thresholdTextField == e.getSource()) { String thresholdPattern = "(\\d+)(.\\d*){0,1}"; String textValue = thresholdTextField.getText(); Pattern pattern = Pattern.compile(thresholdPattern); Matcher matcher = pattern.matcher(textValue); if (matcher.matches()) { if(current_working_config != null) { double threshold = Double.parseDouble(textValue); current_working_config.setScoreThreshold(threshold); } } else { thresholdTextField.setText("0"); } } } public void tableChanged(TableModelEvent e) { /*--NOTES--*/ // changes to the SessionOptionsTableModel must be propagated to this method // changes that need to be propagated are: // - adding new columns // - deleting columns int rowIndex = e.getFirstRow(); int columnIndex = e.getColumn(); TableModel model = (TableModel) e.getSource(); if(columnIndex == 3) { Boolean included = (Boolean) model.getValueAt(rowIndex, columnIndex); if(included){ model.setValueAt(0, rowIndex, 1); } } else if (columnIndex == 1) { Integer blockOrder = (Integer) model.getValueAt(rowIndex, columnIndex); if(blockOrder > 0) { model.setValueAt(new Boolean(false), rowIndex, 3); } } } public void mouseClicked(MouseEvent me){ // important to notice that 'int column' is set to table model's column index, NOT // column model's index // determine what collumn user clicked on if(me.getSource() instanceof JTableHeader){ JTableHeader jth = (JTableHeader)me.getSource(); TableColumnModel columnModel = jth.getColumnModel(); int viewColumn = columnModel.getColumnIndexAtX(me.getX()); if(me.getButton() == MouseEvent.BUTTON3){ // show popup menu for resetting values if(viewColumn == 4){ resetm.show(this, me.getX(), me.getY()); } else if(viewColumn == 5){ resetu.show(this, me.getX(), me.getY()); } } } } public void mousePressed(MouseEvent me){ } public void mouseReleased(MouseEvent me){ } public void mouseExited(MouseEvent me){ } public void mouseEntered(MouseEvent me){ } }