From ac2f228adb17257d6a52f2f3a74057a1f7d2f28e Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Thu, 1 Oct 2020 09:43:44 +0200 Subject: [PATCH 01/77] add mapping type for target concepts --- src/org/ohdsi/usagi/CodeMapping.java | 31 +++--- src/org/ohdsi/usagi/MappingTarget.java | 52 ++++++++++ .../ohdsi/usagi/ReadCodeMappingsFromFile.java | 2 +- .../ohdsi/usagi/WriteCodeMappingsToFile.java | 13 +-- .../ohdsi/usagi/dataImport/ImportData.java | 10 +- .../ui/ExportSourceToConceptMapDialog.java | 9 +- src/org/ohdsi/usagi/ui/ImportDialog.java | 3 +- .../ohdsi/usagi/ui/MappingDetailPanel.java | 10 +- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 4 +- .../usagi/ui/TargetConceptTableModel.java | 98 +++++++++++++++++++ .../ui/actions/ExportForReviewAction.java | 4 +- 11 files changed, 194 insertions(+), 42 deletions(-) create mode 100644 src/org/ohdsi/usagi/MappingTarget.java create mode 100644 src/org/ohdsi/usagi/ui/TargetConceptTableModel.java diff --git a/src/org/ohdsi/usagi/CodeMapping.java b/src/org/ohdsi/usagi/CodeMapping.java index c556d12..e7fb903 100644 --- a/src/org/ohdsi/usagi/CodeMapping.java +++ b/src/org/ohdsi/usagi/CodeMapping.java @@ -1,12 +1,12 @@ /******************************************************************************* * Copyright 2019 Observational Health Data Sciences and Informatics - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,23 +20,22 @@ /** * Data class for holding information on a single source code and its mapping - * + * * @author MSCHUEMI - * */ public class CodeMapping { - public static enum MappingStatus { - APPROVED, UNCHECKED, AUTO_MAPPED, AUTO_MAPPED_TO_1, INVALID_TARGET - }; + public enum MappingStatus { + APPROVED, UNCHECKED, AUTO_MAPPED, AUTO_MAPPED_TO_1, INVALID_TARGET + }; - public SourceCode sourceCode; - public double matchScore; - public MappingStatus mappingStatus; - public List targetConcepts = new ArrayList(1); - public String comment; + public SourceCode sourceCode; + public double matchScore; + public MappingStatus mappingStatus; + public List targetConcepts = new ArrayList<>(1); + public String comment; - public CodeMapping(SourceCode sourceCode) { - this.sourceCode = sourceCode; - } + public CodeMapping(SourceCode sourceCode) { + this.sourceCode = sourceCode; + } } diff --git a/src/org/ohdsi/usagi/MappingTarget.java b/src/org/ohdsi/usagi/MappingTarget.java new file mode 100644 index 0000000..f30af78 --- /dev/null +++ b/src/org/ohdsi/usagi/MappingTarget.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright 2020 Observational Health Data Sciences and Informatics & The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ******************************************************************************/ +package org.ohdsi.usagi; + +/** + * Class for holding information about a single (target) concept in the Vocabulary + */ +public class MappingTarget{ + public enum MappingType { + REGULAR, VALUE, UNIT // Maybe OPERATOR, TYPE, etc. + }; + public Concept concept; + public MappingType mappingType; + + public MappingTarget(Concept concept, MappingType mappingType) { + this.concept = concept; + this.mappingType = mappingType; + } + + public MappingTarget(Concept concept) { + this(concept, MappingType.REGULAR); + } + + public Concept getConcept() { + return concept; + } + + public void setConcept(Concept concept) { + this.concept = concept; + } + + public MappingType getMappingType() { + return mappingType; + } + + public void setMappingType(MappingType mappingType) { + this.mappingType = mappingType; + } +} diff --git a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java index 0092f41..c864306 100644 --- a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java +++ b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java @@ -71,7 +71,7 @@ && new SourceCode(row).sourceName.equals(buffer.sourceCode.sourceName)) { buffer.mappingStatus = MappingStatus.INVALID_TARGET; buffer.comment = "Invalid existing target: " + row.get("conceptId"); } else { - buffer.targetConcepts.add(concept); + buffer.targetConcepts.add(new MappingTarget(concept)); } } if (iterator.hasNext()) diff --git a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java index 7eb1867..5f0ae57 100644 --- a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java +++ b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java @@ -32,18 +32,19 @@ public WriteCodeMappingsToFile(String filename) { } public void write(CodeMapping codeMapping) { - List targetConcepts; + List mappingTargets; if (codeMapping.targetConcepts.size() == 0) { - targetConcepts = new ArrayList(1); - targetConcepts.add(Concept.EMPTY_CONCEPT); + mappingTargets = new ArrayList<>(1); + mappingTargets.add(new MappingTarget(Concept.createEmptyConcept())); } else - targetConcepts = codeMapping.targetConcepts; - for (Concept targetConcept : targetConcepts) { + mappingTargets = codeMapping.targetConcepts; + for (MappingTarget targetConcept : mappingTargets) { Row row = codeMapping.sourceCode.toRow(); row.add("matchScore", codeMapping.matchScore); row.add("mappingStatus", codeMapping.mappingStatus.toString()); - row.add("conceptId", targetConcept.conceptId); + row.add("conceptId", targetConcept.concept.conceptId); row.add("comment", codeMapping.comment); + row.add("mappingType", targetConcept.mappingType.toString()); out.write(row); } } diff --git a/src/org/ohdsi/usagi/dataImport/ImportData.java b/src/org/ohdsi/usagi/dataImport/ImportData.java index ea7f426..cff1e79 100644 --- a/src/org/ohdsi/usagi/dataImport/ImportData.java +++ b/src/org/ohdsi/usagi/dataImport/ImportData.java @@ -19,13 +19,9 @@ import java.util.List; import java.util.Vector; -import org.ohdsi.usagi.CodeMapping; +import org.ohdsi.usagi.*; import org.ohdsi.usagi.CodeMapping.MappingStatus; -import org.ohdsi.usagi.SourceCode; -import org.ohdsi.usagi.Concept; -import org.ohdsi.usagi.UsagiSearchEngine; import org.ohdsi.usagi.UsagiSearchEngine.ScoredConcept; -import org.ohdsi.usagi.WriteCodeMappingsToFile; import org.ohdsi.utilities.collections.Pair; import org.ohdsi.utilities.files.ReadCSVFileWithHeader; import org.ohdsi.utilities.files.Row; @@ -78,10 +74,10 @@ private void createInitialMapping(List sourceCodes, ImportSettings s List concepts = usagiSearchEngine.search(sourceCode.sourceName, true, sourceCode.sourceAutoAssignedConceptIds, settings.filterDomains, settings.filterConceptClasses, settings.filterVocabularies, settings.filterStandard, settings.includeSourceTerms); if (concepts.size() > 0) { - codeMapping.targetConcepts.add(concepts.get(0).concept); + codeMapping.targetConcepts.add(new MappingTarget(concepts.get(0).concept)); codeMapping.matchScore = concepts.get(0).matchScore; } else { - codeMapping.targetConcepts.add(Concept.EMPTY_CONCEPT); + codeMapping.targetConcepts.add(new MappingTarget(Concept.EMPTY_CONCEPT)); codeMapping.matchScore = 0; } codeMapping.mappingStatus = MappingStatus.UNCHECKED; diff --git a/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java b/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java index 4942455..82c3c48 100644 --- a/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java +++ b/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java @@ -18,11 +18,10 @@ import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import javax.swing.Box; import javax.swing.BoxLayout; @@ -38,6 +37,7 @@ import org.ohdsi.usagi.CodeMapping; import org.ohdsi.usagi.CodeMapping.MappingStatus; import org.ohdsi.usagi.Concept; +import org.ohdsi.usagi.MappingTarget; import org.ohdsi.utilities.files.Row; import org.ohdsi.utilities.files.WriteCSVFileWithHeader; @@ -115,8 +115,9 @@ private void writeToCsvFile(String filename) { if (mapping.targetConcepts.size() == 0) { targetConcepts = new ArrayList(1); targetConcepts.add(Concept.EMPTY_CONCEPT); - } else - targetConcepts = mapping.targetConcepts; + } else { + targetConcepts = mapping.targetConcepts.stream().map(MappingTarget::getConcept).collect(Collectors.toList()); + } for (Concept targetConcept : targetConcepts) { Row row = new Row(); diff --git a/src/org/ohdsi/usagi/ui/ImportDialog.java b/src/org/ohdsi/usagi/ui/ImportDialog.java index 5829223..eb77ae8 100644 --- a/src/org/ohdsi/usagi/ui/ImportDialog.java +++ b/src/org/ohdsi/usagi/ui/ImportDialog.java @@ -50,6 +50,7 @@ import org.ohdsi.usagi.CodeMapping; import org.ohdsi.usagi.CodeMapping.MappingStatus; +import org.ohdsi.usagi.MappingTarget; import org.ohdsi.usagi.SourceCode; import org.ohdsi.usagi.UsagiSearchEngine.ScoredConcept; import org.ohdsi.utilities.ReadXlsxFile; @@ -441,7 +442,7 @@ public void run() { List concepts = Global.usagiSearchEngine.search(sourceCode.sourceName, true, filterConceptIds, filterDomainsFinal, filterConceptClassesFinal, filterVocabulariesFinal, filterStandard, includeSourceConcepts); if (concepts.size() > 0) { - codeMapping.targetConcepts.add(concepts.get(0).concept); + codeMapping.targetConcepts.add(new MappingTarget(concepts.get(0).concept)); codeMapping.matchScore = concepts.get(0).matchScore; } else { codeMapping.matchScore = 0; diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 508d46a..c1b3e1c 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -31,6 +31,7 @@ import java.util.Timer; import java.util.TimerTask; import java.util.Vector; +import java.util.stream.Collectors; import javax.swing.Action; import javax.swing.BorderFactory; @@ -53,6 +54,7 @@ import org.ohdsi.usagi.CodeMapping; import org.ohdsi.usagi.CodeMapping.MappingStatus; import org.ohdsi.usagi.Concept; +import org.ohdsi.usagi.MappingTarget; import org.ohdsi.usagi.UsagiSearchEngine.ScoredConcept; import static org.ohdsi.usagi.ui.DataChangeEvent.*; @@ -63,7 +65,7 @@ public class MappingDetailPanel extends JPanel implements CodeSelectedListener, private UsagiTable sourceCodeTable; private SourceCodeTableModel sourceCodeTableModel; private UsagiTable targetConceptTable; - private ConceptTableModel targetConceptTableModel; + private TargetConceptTableModel targetConceptTableModel; private UsagiTable searchTable; private TableRowSorter sorter; private ConceptTableModel searchTableModel; @@ -318,7 +320,7 @@ private JPanel createTargetConceptsPanel() { JPanel panel = new JPanel(); panel.setBorder(BorderFactory.createTitledBorder("Target concepts")); panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); - targetConceptTableModel = new ConceptTableModel(false); + targetConceptTableModel = new TargetConceptTableModel(); targetConceptTable = new UsagiTable(targetConceptTableModel); targetConceptTable.setPreferredScrollableViewportSize(new Dimension(500, 45)); targetConceptTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); @@ -409,9 +411,9 @@ private void setApproveButton() { } public void addConcept(Concept concept) { - codeMapping.targetConcepts.add(concept); + codeMapping.targetConcepts.add(new MappingTarget(concept)); for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { - codeMappingMulti.targetConcepts.add(concept); + codeMappingMulti.targetConcepts.add(new MappingTarget(concept)); } targetConceptTableModel.fireTableDataChanged(); diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 79230b9..2ba48ef 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -67,7 +67,7 @@ public MappingTablePanel() { Global.approveAllAction.setEnabled(true); Global.clearAllAction.setEnabled(true); if (tableModel.getCodeMapping(primaryModelRow).targetConcepts.size() > 0) { - Concept firstConcept = tableModel.getCodeMapping(primaryModelRow).targetConcepts.get(0); + Concept firstConcept = tableModel.getCodeMapping(primaryModelRow).targetConcepts.get(0).concept; Global.conceptInfoAction.setEnabled(true); Global.conceptInformationDialog.setConcept(firstConcept); Global.athenaAction.setEnabled(true); @@ -159,7 +159,7 @@ public Object getValueAt(int row, int col) { } Concept targetConcept; if (codeMapping.targetConcepts.size() > 0) - targetConcept = codeMapping.targetConcepts.get(0); + targetConcept = codeMapping.targetConcepts.get(0).concept; else targetConcept = Concept.EMPTY_CONCEPT; switch (col) { diff --git a/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java b/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java new file mode 100644 index 0000000..055d399 --- /dev/null +++ b/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java @@ -0,0 +1,98 @@ +package org.ohdsi.usagi.ui; + +import org.ohdsi.usagi.Concept; +import org.ohdsi.usagi.MappingTarget; +import org.ohdsi.usagi.UsagiSearchEngine.ScoredConcept; + +import javax.swing.table.AbstractTableModel; +import java.util.ArrayList; +import java.util.List; + +class TargetConceptTableModel extends AbstractTableModel { + private static final long serialVersionUID = -4978479688021056281L; + + private final String termColumnName = "Term"; + private final String[] columnNames = {"Concept ID", "Concept name", "Domain", "Concept class", "Vocabulary", "Concept code", + "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", "Children", "Mapping Type"}; + private List targetConcepts = new ArrayList<>(); + + public TargetConceptTableModel() { + } + + public Concept getConcept(int row) { + return targetConcepts.get(row).concept; + } + + public int getColumnCount() { + return columnNames.length; + } + + public void setConcepts(List mappingTargets) { + this.targetConcepts = mappingTargets; + fireTableDataChanged(); + } + + public int getRowCount() { + return targetConcepts.size(); + } + + public String getColumnName(int col) { + return columnNames[col]; + } + + public Object getValueAt(int row, int col) { + if (row > targetConcepts.size()) { + return ""; + } + MappingTarget targetConcept = targetConcepts.get(row); + switch (col) { + case 0: + return targetConcept.concept.conceptId; + case 1: + return targetConcept.concept.conceptName; + case 2: + return targetConcept.concept.domainId; + case 3: + return targetConcept.concept.conceptClassId; + case 4: + return targetConcept.concept.vocabularyId; + case 5: + return targetConcept.concept.conceptCode; + case 6: + return targetConcept.concept.validStartDate; + case 7: + return targetConcept.concept.validEndDate; + case 8: + return targetConcept.concept.invalidReason; + case 9: + return targetConcept.concept.standardConcept; + case 10: + return targetConcept.concept.parentCount; + case 11: + return targetConcept.concept.childCount; + case 12: + return targetConcept.mappingType; + default: + return ""; + } + } + + public Class getColumnClass(int col) { + switch (col) { + case 1: + case 10: + case 11: + return Integer.class; + default: + return String.class; + } + } + + public boolean isCellEditable(int row, int col) { + return false; + } + + public void setValueAt(Object value, int row, int col) { + + } +} diff --git a/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java b/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java index 0a26db7..09ce71c 100644 --- a/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java @@ -21,6 +21,7 @@ import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import javax.swing.*; import javax.swing.filechooser.FileFilter; @@ -29,6 +30,7 @@ import org.ohdsi.usagi.CodeMapping; import org.ohdsi.usagi.CodeMapping.MappingStatus; import org.ohdsi.usagi.Concept; +import org.ohdsi.usagi.MappingTarget; import org.ohdsi.usagi.ui.Global; import org.ohdsi.utilities.files.Row; import org.ohdsi.utilities.files.WriteCSVFileWithHeader; @@ -83,7 +85,7 @@ public void actionPerformed(ActionEvent arg0) { targetConcepts = new ArrayList(1); targetConcepts.add(Concept.EMPTY_CONCEPT); } else - targetConcepts = mapping.targetConcepts; + targetConcepts = mapping.targetConcepts.stream().map(MappingTarget::getConcept).collect(Collectors.toList()); for (Concept targetConcept : targetConcepts) { Row row = mapping.sourceCode.toRow(); From 7a2f3366a43f4a53a97d9ff738c191607327f040 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Thu, 1 Oct 2020 10:21:21 +0200 Subject: [PATCH 02/77] add buttons for each mapping type --- .../ohdsi/usagi/ui/MappingDetailPanel.java | 43 +++++++++++++------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index c1b3e1c..2e9f44e 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -31,7 +31,6 @@ import java.util.Timer; import java.util.TimerTask; import java.util.Vector; -import java.util.stream.Collectors; import javax.swing.Action; import javax.swing.BorderFactory; @@ -73,7 +72,7 @@ public class MappingDetailPanel extends JPanel implements CodeSelectedListener, private JTextField commentField; private JButton removeButton; private JButton replaceButton; - private JButton addButton; + private List addButtons; private JRadioButton autoQueryButton; private JRadioButton manualQueryButton; private JTextField manualQueryField; @@ -206,10 +205,10 @@ private Component createSearchResultsPanel() { searchTable.getSelectionModel().addListSelectionListener(event -> { int viewRow = searchTable.getSelectedRow(); if (viewRow == -1) { - addButton.setEnabled(false); + addButtons.forEach(x -> x.setEnabled(false)); replaceButton.setEnabled(false); } else { - addButton.setEnabled(true); + addButtons.forEach(x -> x.setEnabled(true)); replaceButton.setEnabled(true); int modelRow = searchTable.convertRowIndexToModel(viewRow); Global.conceptInfoAction.setEnabled(true); @@ -241,18 +240,22 @@ public void actionPerformed(ActionEvent e) { }); replaceButton.setEnabled(false); buttonPanel.add(replaceButton); - addButton = new JButton("Add concept"); - addButton.setToolTipText("Add selected concept"); - addButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { + + JButton button; + addButtons = new ArrayList<>(); + for (MappingTarget.MappingType mappingType : MappingTarget.MappingType.values()) { + button = new JButton(String.format("Add %s concept", mappingType)); + button.setToolTipText(String.format("Add selected concept as %s", mappingType)); + button.addActionListener(e -> { int viewRow = searchTable.getSelectedRow(); int modelRow = searchTable.convertRowIndexToModel(viewRow); - addConcept(searchTableModel.getConcept(modelRow)); - } + addConcept(searchTableModel.getConcept(modelRow), mappingType); + }); + button.setEnabled(false); + addButtons.add(button); + buttonPanel.add(button); + } - }); - addButton.setEnabled(false); - buttonPanel.add(addButton); panel.add(buttonPanel); return panel; @@ -424,6 +427,20 @@ public void addConcept(Concept concept) { } } + public void addConcept(Concept concept, MappingTarget.MappingType mappingType) { + codeMapping.targetConcepts.add(new MappingTarget(concept, mappingType)); + for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { + codeMappingMulti.targetConcepts.add(new MappingTarget(concept, mappingType)); + } + targetConceptTableModel.fireTableDataChanged(); + + if (codeMappingsFromMulti.size() > 0) { + Global.mapping.fireDataChanged(MULTI_UPDATE_EVENT); + } else { + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + } + } + public void replaceConcepts(Concept concept) { codeMapping.targetConcepts.clear(); for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { From 8e363dac1486811c0a0ed71cbcfcaa0a030f2a5a Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Thu, 1 Oct 2020 10:27:18 +0200 Subject: [PATCH 03/77] read mappingtype from save file --- src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java index c864306..4481aee 100644 --- a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java +++ b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java @@ -67,11 +67,18 @@ private void readNext() { && new SourceCode(row).sourceName.equals(buffer.sourceCode.sourceName)) { if (row.getInt("conceptId") != 0) { Concept concept = Global.dbEngine.getConcept(row.getInt("conceptId")); + + // Older save files might not have a mappingType. + MappingTarget.MappingType mappingType = MappingTarget.MappingType.REGULAR; + if (row.getFieldNames().contains("mappingType")) { + mappingType = MappingTarget.MappingType.valueOf(row.get("mappingType")); + } + if (concept == null) { buffer.mappingStatus = MappingStatus.INVALID_TARGET; buffer.comment = "Invalid existing target: " + row.get("conceptId"); } else { - buffer.targetConcepts.add(new MappingTarget(concept)); + buffer.targetConcepts.add(new MappingTarget(concept, mappingType)); } } if (iterator.hasNext()) From b7d9b08af2896a55e2cf27a3a67ad5edc8d14129 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Thu, 1 Oct 2020 11:21:12 +0200 Subject: [PATCH 04/77] do not display regular on button --- src/org/ohdsi/usagi/MappingTarget.java | 14 +++++++------- src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java | 4 ++-- src/org/ohdsi/usagi/ui/MappingDetailPanel.java | 10 +++++++--- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/org/ohdsi/usagi/MappingTarget.java b/src/org/ohdsi/usagi/MappingTarget.java index f30af78..1b5e56a 100644 --- a/src/org/ohdsi/usagi/MappingTarget.java +++ b/src/org/ohdsi/usagi/MappingTarget.java @@ -19,19 +19,19 @@ * Class for holding information about a single (target) concept in the Vocabulary */ public class MappingTarget{ - public enum MappingType { - REGULAR, VALUE, UNIT // Maybe OPERATOR, TYPE, etc. + public enum Type { + REGULAR, VALUE, UNIT // Maybe also OPERATOR, TYPE, etc. }; public Concept concept; - public MappingType mappingType; + public Type mappingType; - public MappingTarget(Concept concept, MappingType mappingType) { + public MappingTarget(Concept concept, Type mappingType) { this.concept = concept; this.mappingType = mappingType; } public MappingTarget(Concept concept) { - this(concept, MappingType.REGULAR); + this(concept, Type.REGULAR); } public Concept getConcept() { @@ -42,11 +42,11 @@ public void setConcept(Concept concept) { this.concept = concept; } - public MappingType getMappingType() { + public Type getMappingType() { return mappingType; } - public void setMappingType(MappingType mappingType) { + public void setMappingType(Type mappingType) { this.mappingType = mappingType; } } diff --git a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java index 4481aee..8e1b68e 100644 --- a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java +++ b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java @@ -69,9 +69,9 @@ && new SourceCode(row).sourceName.equals(buffer.sourceCode.sourceName)) { Concept concept = Global.dbEngine.getConcept(row.getInt("conceptId")); // Older save files might not have a mappingType. - MappingTarget.MappingType mappingType = MappingTarget.MappingType.REGULAR; + MappingTarget.Type mappingType = MappingTarget.Type.REGULAR; if (row.getFieldNames().contains("mappingType")) { - mappingType = MappingTarget.MappingType.valueOf(row.get("mappingType")); + mappingType = MappingTarget.Type.valueOf(row.get("mappingType")); } if (concept == null) { diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 2e9f44e..a036c49 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -243,8 +243,12 @@ public void actionPerformed(ActionEvent e) { JButton button; addButtons = new ArrayList<>(); - for (MappingTarget.MappingType mappingType : MappingTarget.MappingType.values()) { - button = new JButton(String.format("Add %s concept", mappingType)); + for (MappingTarget.Type mappingType : MappingTarget.Type.values()) { + if (mappingType.equals(MappingTarget.Type.REGULAR)) { + button = new JButton("Add concept"); + } else { + button = new JButton(String.format("Add %s concept", mappingType)); + } button.setToolTipText(String.format("Add selected concept as %s", mappingType)); button.addActionListener(e -> { int viewRow = searchTable.getSelectedRow(); @@ -427,7 +431,7 @@ public void addConcept(Concept concept) { } } - public void addConcept(Concept concept, MappingTarget.MappingType mappingType) { + public void addConcept(Concept concept, MappingTarget.Type mappingType) { codeMapping.targetConcepts.add(new MappingTarget(concept, mappingType)); for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { codeMappingMulti.targetConcepts.add(new MappingTarget(concept, mappingType)); From f5569f52cf6d919f8854990e530e3cf61a9d6d55 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Thu, 1 Oct 2020 14:57:50 +0200 Subject: [PATCH 05/77] add ignored status and button to toggle --- src/org/ohdsi/usagi/CodeMapping.java | 2 +- src/org/ohdsi/usagi/ui/MappingDetailPanel.java | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/org/ohdsi/usagi/CodeMapping.java b/src/org/ohdsi/usagi/CodeMapping.java index c556d12..dc23cae 100644 --- a/src/org/ohdsi/usagi/CodeMapping.java +++ b/src/org/ohdsi/usagi/CodeMapping.java @@ -26,7 +26,7 @@ */ public class CodeMapping { public static enum MappingStatus { - APPROVED, UNCHECKED, AUTO_MAPPED, AUTO_MAPPED_TO_1, INVALID_TARGET + APPROVED, UNCHECKED, AUTO_MAPPED, AUTO_MAPPED_TO_1, INVALID_TARGET, IGNORED }; public SourceCode sourceCode; diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 508d46a..570c38e 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -68,6 +68,7 @@ public class MappingDetailPanel extends JPanel implements CodeSelectedListener, private TableRowSorter sorter; private ConceptTableModel searchTableModel; private JButton approveButton; + private JButton ignoreButton; private JTextField commentField; private JButton removeButton; private JButton replaceButton; @@ -293,6 +294,18 @@ public void changedUpdate(DocumentEvent arg0) { approveButton = new JButton(Global.approveAction); approveButton.setBackground(new Color(151, 220, 141)); panel.add(approveButton); + + ignoreButton = new JButton("Ignore"); + ignoreButton.setToolTipText("Do not map selected source variable"); + ignoreButton.addActionListener(e -> { + // TODO: toggle button text between Ignore and Unignore + // TODO: If ignored, deactivate approve button. If approved, deactivate ignore button + // TODO: Add shortcut + codeMapping.mappingStatus = MappingStatus.IGNORED; + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + }); + panel.add(ignoreButton); + return panel; } From c1727d3f662eeebd7c0d454238b1f901a64b3f73 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Thu, 1 Oct 2020 17:01:51 +0200 Subject: [PATCH 06/77] add toggling of ignore button --- src/org/ohdsi/usagi/ui/Global.java | 2 + .../ohdsi/usagi/ui/MappingDetailPanel.java | 38 ++++++++++---- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 4 ++ src/org/ohdsi/usagi/ui/UsagiMain.java | 4 ++ src/org/ohdsi/usagi/ui/UsagiMenubar.java | 2 + .../ohdsi/usagi/ui/actions/IgnoreAction.java | 49 +++++++++++++++++++ .../usagi/ui/actions/IgnoreAllAction.java | 40 +++++++++++++++ 7 files changed, 130 insertions(+), 9 deletions(-) create mode 100644 src/org/ohdsi/usagi/ui/actions/IgnoreAction.java create mode 100644 src/org/ohdsi/usagi/ui/actions/IgnoreAllAction.java diff --git a/src/org/ohdsi/usagi/ui/Global.java b/src/org/ohdsi/usagi/ui/Global.java index 299d41b..ed04649 100644 --- a/src/org/ohdsi/usagi/ui/Global.java +++ b/src/org/ohdsi/usagi/ui/Global.java @@ -43,6 +43,8 @@ public class Global { public static SaveAsAction saveAsAction; public static ApproveAction approveAction; public static ApproveAllAction approveAllAction; + public static IgnoreAction ignoreAction; + public static IgnoreAllAction ignoreAllAction; public static ClearAllAction clearAllAction; public static ConceptInformationAction conceptInfoAction; public static AthenaAction athenaAction; diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 570c38e..f12efb7 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -295,15 +295,8 @@ public void changedUpdate(DocumentEvent arg0) { approveButton.setBackground(new Color(151, 220, 141)); panel.add(approveButton); - ignoreButton = new JButton("Ignore"); - ignoreButton.setToolTipText("Do not map selected source variable"); - ignoreButton.addActionListener(e -> { - // TODO: toggle button text between Ignore and Unignore - // TODO: If ignored, deactivate approve button. If approved, deactivate ignore button - // TODO: Add shortcut - codeMapping.mappingStatus = MappingStatus.IGNORED; - Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - }); + ignoreButton = new JButton(Global.ignoreAction); + ignoreButton.setBackground(new Color(151, 220, 141)); panel.add(ignoreButton); return panel; @@ -382,6 +375,7 @@ public void actionPerformed(ActionEvent e) { public void codeSelected(CodeMapping codeMapping) { this.codeMapping = codeMapping; setApproveButton(); + setIgnoreButton(); sourceCodeTableModel.setMapping(codeMapping); targetConceptTableModel.setConcepts(codeMapping.targetConcepts); commentField.setText(codeMapping.comment); @@ -414,10 +408,36 @@ private void setApproveButton() { Global.approveAction.putValue(Action.NAME, "Unapprove"); Global.approveAction.putValue(Action.SHORT_DESCRIPTION, "Unapprove this mapping"); approveButton.setBackground(new Color(220, 151, 141)); + ignoreButton.setEnabled(false); } else { Global.approveAction.putValue(Action.NAME, "Approve"); Global.approveAction.putValue(Action.SHORT_DESCRIPTION, "Approve this mapping"); approveButton.setBackground(new Color(151, 220, 141)); + ignoreButton.setEnabled(true); + } + } + + public void ignore() { + if (codeMapping.mappingStatus != CodeMapping.MappingStatus.IGNORED) { + codeMapping.mappingStatus = MappingStatus.IGNORED; + // TODO: remove any existing mapping + Global.mapping.fireDataChanged(APPROVE_EVENT); + } else { + codeMapping.mappingStatus = CodeMapping.MappingStatus.UNCHECKED; + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + setIgnoreButton(); + } + } + + private void setIgnoreButton() { + if (codeMapping.mappingStatus == MappingStatus.IGNORED) { + Global.ignoreAction.setToIgnore(); + ignoreButton.setBackground(new Color(220, 151, 141)); + approveButton.setEnabled(false); + } else { + Global.ignoreAction.setToUnignore(); + ignoreButton.setBackground(new Color(151, 220, 141)); + approveButton.setEnabled(true); } } diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 79230b9..8090920 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -65,6 +65,8 @@ public MappingTablePanel() { Global.approveAction.setEnabled(true); Global.approveAllAction.setEnabled(true); + Global.ignoreAction.setEnabled(true); + Global.ignoreAllAction.setEnabled(true); Global.clearAllAction.setEnabled(true); if (tableModel.getCodeMapping(primaryModelRow).targetConcepts.size() > 0) { Concept firstConcept = tableModel.getCodeMapping(primaryModelRow).targetConcepts.get(0); @@ -86,6 +88,8 @@ public MappingTablePanel() { } else { Global.approveAllAction.setEnabled(false); Global.approveAction.setEnabled(false); + Global.ignoreAction.setEnabled(false); + Global.ignoreAllAction.setEnabled(false); Global.clearAllAction.setEnabled(false); } } diff --git a/src/org/ohdsi/usagi/ui/UsagiMain.java b/src/org/ohdsi/usagi/ui/UsagiMain.java index f59ef28..475be31 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMain.java +++ b/src/org/ohdsi/usagi/ui/UsagiMain.java @@ -78,12 +78,14 @@ public UsagiMain(String[] args) { Global.saveAction = new SaveAction(); Global.saveAsAction = new SaveAsAction(); Global.approveAction = new ApproveAction(); + Global.ignoreAction = new IgnoreAction(); Global.conceptInfoAction = new ConceptInformationAction(); Global.athenaAction = new AthenaAction(); Global.googleSearchAction = new GoogleSearchAction(); Global.showStatsAction = new ShowStatsAction(); Global.aboutAction = new AboutAction(); Global.approveAllAction = new ApproveAllAction(); + Global.ignoreAllAction = new IgnoreAllAction(); Global.rebuildIndexAction = new RebuildIndexAction(); Global.exitAction = new ExitAction(); @@ -94,6 +96,8 @@ public UsagiMain(String[] args) { Global.exportForReviewAction.setEnabled(false); Global.approveAction.setEnabled(false); Global.approveAllAction.setEnabled(false); + Global.ignoreAction.setEnabled(false); + Global.ignoreAllAction.setEnabled(false); Global.clearAllAction = new ClearAllAction(); Global.clearAllAction.setEnabled(false); Global.conceptInfoAction.setEnabled(false); diff --git a/src/org/ohdsi/usagi/ui/UsagiMenubar.java b/src/org/ohdsi/usagi/ui/UsagiMenubar.java index f2af971..866ae97 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMenubar.java +++ b/src/org/ohdsi/usagi/ui/UsagiMenubar.java @@ -43,6 +43,8 @@ public UsagiMenubar() { editMenu.add(Global.approveAction); editMenu.add(Global.approveAllAction); + editMenu.add(Global.ignoreAction); + editMenu.add(Global.ignoreAllAction); editMenu.add(Global.clearAllAction); JMenu viewMenu = new JMenu("View"); diff --git a/src/org/ohdsi/usagi/ui/actions/IgnoreAction.java b/src/org/ohdsi/usagi/ui/actions/IgnoreAction.java new file mode 100644 index 0000000..3431f78 --- /dev/null +++ b/src/org/ohdsi/usagi/ui/actions/IgnoreAction.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright 2020 Observational Health Data Sciences and Informatics & The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ******************************************************************************/ +package org.ohdsi.usagi.ui.actions; + +import org.ohdsi.usagi.ui.Global; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; + +public class IgnoreAction extends AbstractAction { + + private static final long serialVersionUID = 5414166576120252690L; + + public IgnoreAction() { + setToIgnore(); + putValue(Action.MNEMONIC_KEY, KeyEvent.VK_I); + putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_I, InputEvent.ALT_MASK)); + } + + @Override + public void actionPerformed(ActionEvent arg0) { + Global.mappingDetailPanel.ignore(); + } + + public void setToIgnore() { + putValue(Action.NAME, "Ignore"); + putValue(Action.SHORT_DESCRIPTION, "Set status of selected code to ignore"); + } + + public void setToUnignore() { + Global.ignoreAction.putValue(Action.NAME, "Unignore"); + Global.ignoreAction.putValue(Action.SHORT_DESCRIPTION, "Unset ignore status of selected code"); + } +} diff --git a/src/org/ohdsi/usagi/ui/actions/IgnoreAllAction.java b/src/org/ohdsi/usagi/ui/actions/IgnoreAllAction.java new file mode 100644 index 0000000..1f131e5 --- /dev/null +++ b/src/org/ohdsi/usagi/ui/actions/IgnoreAllAction.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright 2020 Observational Health Data Sciences and Informatics & The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ******************************************************************************/ +package org.ohdsi.usagi.ui.actions; + +import org.ohdsi.usagi.ui.Global; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; + +public class IgnoreAllAction extends AbstractAction { + + private static final long serialVersionUID = -2553283436556522929L; + + public IgnoreAllAction() { + putValue(Action.NAME, "Ignore selected"); + putValue(Action.SHORT_DESCRIPTION, "Set status of all selected codes to ignore"); + putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_I, InputEvent.ALT_MASK | InputEvent.SHIFT_DOWN_MASK)); + } + + @Override + public void actionPerformed(ActionEvent arg0) { + Global.mappingTablePanel.approveAll(); + } + +} From faafae8211f961658eea3feb4febe90a05c4f386 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Thu, 1 Oct 2020 17:09:00 +0200 Subject: [PATCH 07/77] refactor approve actions and add ignoreSelected --- src/org/ohdsi/usagi/ui/Global.java | 4 +- .../ohdsi/usagi/ui/MappingDetailPanel.java | 23 +++++----- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 43 +++++++++++-------- src/org/ohdsi/usagi/ui/UsagiMain.java | 8 ++-- src/org/ohdsi/usagi/ui/UsagiMenubar.java | 4 +- .../ohdsi/usagi/ui/actions/ApproveAction.java | 16 +++++-- ...Action.java => ApproveSelectedAction.java} | 6 +-- ...lAction.java => IgnoreSelectedAction.java} | 6 +-- 8 files changed, 61 insertions(+), 49 deletions(-) rename src/org/ohdsi/usagi/ui/actions/{ApproveAllAction.java => ApproveSelectedAction.java} (90%) rename src/org/ohdsi/usagi/ui/actions/{IgnoreAllAction.java => IgnoreSelectedAction.java} (91%) diff --git a/src/org/ohdsi/usagi/ui/Global.java b/src/org/ohdsi/usagi/ui/Global.java index ed04649..9b0ebe9 100644 --- a/src/org/ohdsi/usagi/ui/Global.java +++ b/src/org/ohdsi/usagi/ui/Global.java @@ -42,9 +42,9 @@ public class Global { public static SaveAction saveAction; public static SaveAsAction saveAsAction; public static ApproveAction approveAction; - public static ApproveAllAction approveAllAction; + public static ApproveSelectedAction approveSelectedAction; public static IgnoreAction ignoreAction; - public static IgnoreAllAction ignoreAllAction; + public static IgnoreSelectedAction ignoreSelectedAction; public static ClearAllAction clearAllAction; public static ConceptInformationAction conceptInfoAction; public static AthenaAction athenaAction; diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index f12efb7..2c39e3f 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -32,7 +32,6 @@ import java.util.TimerTask; import java.util.Vector; -import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; @@ -374,8 +373,8 @@ public void actionPerformed(ActionEvent e) { @Override public void codeSelected(CodeMapping codeMapping) { this.codeMapping = codeMapping; - setApproveButton(); - setIgnoreButton(); + toggleApproveButton(); + toggleIgnoreButton(); sourceCodeTableModel.setMapping(codeMapping); targetConceptTableModel.setConcepts(codeMapping.targetConcepts); commentField.setText(codeMapping.comment); @@ -399,19 +398,17 @@ public void approve() { } else { codeMapping.mappingStatus = CodeMapping.MappingStatus.UNCHECKED; Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - setApproveButton(); + toggleApproveButton(); } } - private void setApproveButton() { + private void toggleApproveButton() { if (codeMapping.mappingStatus == MappingStatus.APPROVED) { - Global.approveAction.putValue(Action.NAME, "Unapprove"); - Global.approveAction.putValue(Action.SHORT_DESCRIPTION, "Unapprove this mapping"); + Global.approveAction.setToUnapprove(); approveButton.setBackground(new Color(220, 151, 141)); ignoreButton.setEnabled(false); } else { - Global.approveAction.putValue(Action.NAME, "Approve"); - Global.approveAction.putValue(Action.SHORT_DESCRIPTION, "Approve this mapping"); + Global.approveAction.setToApprove(); approveButton.setBackground(new Color(151, 220, 141)); ignoreButton.setEnabled(true); } @@ -425,17 +422,17 @@ public void ignore() { } else { codeMapping.mappingStatus = CodeMapping.MappingStatus.UNCHECKED; Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - setIgnoreButton(); + toggleIgnoreButton(); } } - private void setIgnoreButton() { + private void toggleIgnoreButton() { if (codeMapping.mappingStatus == MappingStatus.IGNORED) { - Global.ignoreAction.setToIgnore(); + Global.ignoreAction.setToUnignore(); ignoreButton.setBackground(new Color(220, 151, 141)); approveButton.setEnabled(false); } else { - Global.ignoreAction.setToUnignore(); + Global.ignoreAction.setToIgnore(); ignoreButton.setBackground(new Color(151, 220, 141)); approveButton.setEnabled(true); } diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 8090920..c6bf64d 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -64,9 +64,9 @@ public MappingTablePanel() { Global.googleSearchAction.setSourceTerm(tableModel.getCodeMapping(primaryModelRow).sourceCode.sourceName); Global.approveAction.setEnabled(true); - Global.approveAllAction.setEnabled(true); + Global.approveSelectedAction.setEnabled(true); Global.ignoreAction.setEnabled(true); - Global.ignoreAllAction.setEnabled(true); + Global.ignoreSelectedAction.setEnabled(true); Global.clearAllAction.setEnabled(true); if (tableModel.getCodeMapping(primaryModelRow).targetConcepts.size() > 0) { Concept firstConcept = tableModel.getCodeMapping(primaryModelRow).targetConcepts.get(0); @@ -86,10 +86,10 @@ public MappingTablePanel() { } } } else { - Global.approveAllAction.setEnabled(false); + Global.approveSelectedAction.setEnabled(false); Global.approveAction.setEnabled(false); Global.ignoreAction.setEnabled(false); - Global.ignoreAllAction.setEnabled(false); + Global.ignoreSelectedAction.setEnabled(false); Global.clearAllAction.setEnabled(false); } } @@ -276,33 +276,38 @@ public void dataChanged(DataChangeEvent event) { } } - public void approveAll() { - for (int viewRow : table.getSelectedRows()) { - int modelRow = table.convertRowIndexToModel(viewRow); - tableModel.getCodeMapping(modelRow).mappingStatus = MappingStatus.APPROVED; - - } + private void fireUpdateEventAll() { Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); int viewRow = table.getSelectedRow(); if (viewRow != -1) { int modelRow = table.convertRowIndexToModel(viewRow); - for (CodeSelectedListener listener : listeners) + for (CodeSelectedListener listener : listeners) { listener.codeSelected(tableModel.getCodeMapping(modelRow)); + } } } - public void clearAll() { + private void setMappingStatusSelected(MappingStatus mappingStatus) { for (int viewRow : table.getSelectedRows()) { int modelRow = table.convertRowIndexToModel(viewRow); - tableModel.getCodeMapping(modelRow).targetConcepts.clear(); + tableModel.getCodeMapping(modelRow).mappingStatus = mappingStatus; } - Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - int viewRow = table.getSelectedRow(); - if (viewRow != -1) { + fireUpdateEventAll(); + } + + public void approveSelected() { + setMappingStatusSelected(MappingStatus.APPROVED); + } + + public void ignoreSelected() { + setMappingStatusSelected(MappingStatus.IGNORED); + } + + public void clearAll() { + for (int viewRow : table.getSelectedRows()) { int modelRow = table.convertRowIndexToModel(viewRow); - for (CodeSelectedListener listener : listeners) - listener.codeSelected(tableModel.getCodeMapping(modelRow)); + tableModel.getCodeMapping(modelRow).targetConcepts.clear(); } - + fireUpdateEventAll(); } } diff --git a/src/org/ohdsi/usagi/ui/UsagiMain.java b/src/org/ohdsi/usagi/ui/UsagiMain.java index 475be31..faa0238 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMain.java +++ b/src/org/ohdsi/usagi/ui/UsagiMain.java @@ -84,8 +84,8 @@ public UsagiMain(String[] args) { Global.googleSearchAction = new GoogleSearchAction(); Global.showStatsAction = new ShowStatsAction(); Global.aboutAction = new AboutAction(); - Global.approveAllAction = new ApproveAllAction(); - Global.ignoreAllAction = new IgnoreAllAction(); + Global.approveSelectedAction = new ApproveSelectedAction(); + Global.ignoreSelectedAction = new IgnoreSelectedAction(); Global.rebuildIndexAction = new RebuildIndexAction(); Global.exitAction = new ExitAction(); @@ -95,9 +95,9 @@ public UsagiMain(String[] args) { Global.exportAction.setEnabled(false); Global.exportForReviewAction.setEnabled(false); Global.approveAction.setEnabled(false); - Global.approveAllAction.setEnabled(false); + Global.approveSelectedAction.setEnabled(false); Global.ignoreAction.setEnabled(false); - Global.ignoreAllAction.setEnabled(false); + Global.ignoreSelectedAction.setEnabled(false); Global.clearAllAction = new ClearAllAction(); Global.clearAllAction.setEnabled(false); Global.conceptInfoAction.setEnabled(false); diff --git a/src/org/ohdsi/usagi/ui/UsagiMenubar.java b/src/org/ohdsi/usagi/ui/UsagiMenubar.java index 866ae97..bf5674c 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMenubar.java +++ b/src/org/ohdsi/usagi/ui/UsagiMenubar.java @@ -42,9 +42,9 @@ public UsagiMenubar() { add(editMenu); editMenu.add(Global.approveAction); - editMenu.add(Global.approveAllAction); + editMenu.add(Global.approveSelectedAction); editMenu.add(Global.ignoreAction); - editMenu.add(Global.ignoreAllAction); + editMenu.add(Global.ignoreSelectedAction); editMenu.add(Global.clearAllAction); JMenu viewMenu = new JMenu("View"); diff --git a/src/org/ohdsi/usagi/ui/actions/ApproveAction.java b/src/org/ohdsi/usagi/ui/actions/ApproveAction.java index cd3aa45..711d0ff 100644 --- a/src/org/ohdsi/usagi/ui/actions/ApproveAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ApproveAction.java @@ -16,6 +16,7 @@ package org.ohdsi.usagi.ui.actions; import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import javax.swing.AbstractAction; @@ -29,14 +30,23 @@ public class ApproveAction extends AbstractAction { private static final long serialVersionUID = -6399524936473823131L; public ApproveAction() { - putValue(Action.NAME, "Approve"); - putValue(Action.SHORT_DESCRIPTION, "Approve the selected single mapping"); + setToApprove(); putValue(Action.MNEMONIC_KEY, KeyEvent.VK_A); - putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_A, ActionEvent.ALT_MASK)); + putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.ALT_MASK)); } @Override public void actionPerformed(ActionEvent arg0) { Global.mappingDetailPanel.approve(); } + + public void setToApprove() { + putValue(Action.NAME, "Approve"); + putValue(Action.SHORT_DESCRIPTION, "Approve the selected single mapping"); + } + + public void setToUnapprove() { + Global.approveAction.putValue(Action.NAME, "Unapprove"); + Global.approveAction.putValue(Action.SHORT_DESCRIPTION, "Unapprove this mapping"); + } } diff --git a/src/org/ohdsi/usagi/ui/actions/ApproveAllAction.java b/src/org/ohdsi/usagi/ui/actions/ApproveSelectedAction.java similarity index 90% rename from src/org/ohdsi/usagi/ui/actions/ApproveAllAction.java rename to src/org/ohdsi/usagi/ui/actions/ApproveSelectedAction.java index 6c211c5..2215f64 100644 --- a/src/org/ohdsi/usagi/ui/actions/ApproveAllAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ApproveSelectedAction.java @@ -23,11 +23,11 @@ import org.ohdsi.usagi.ui.Global; -public class ApproveAllAction extends AbstractAction { +public class ApproveSelectedAction extends AbstractAction { private static final long serialVersionUID = 3420357922150237898L; - public ApproveAllAction() { + public ApproveSelectedAction() { putValue(Action.NAME, "Approve selected"); putValue(Action.SHORT_DESCRIPTION, "Approve all selected mappings"); putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.ALT_MASK | InputEvent.SHIFT_DOWN_MASK)); @@ -35,7 +35,7 @@ public ApproveAllAction() { @Override public void actionPerformed(ActionEvent arg0) { - Global.mappingTablePanel.approveAll(); + Global.mappingTablePanel.approveSelected(); } } diff --git a/src/org/ohdsi/usagi/ui/actions/IgnoreAllAction.java b/src/org/ohdsi/usagi/ui/actions/IgnoreSelectedAction.java similarity index 91% rename from src/org/ohdsi/usagi/ui/actions/IgnoreAllAction.java rename to src/org/ohdsi/usagi/ui/actions/IgnoreSelectedAction.java index 1f131e5..4f46ed9 100644 --- a/src/org/ohdsi/usagi/ui/actions/IgnoreAllAction.java +++ b/src/org/ohdsi/usagi/ui/actions/IgnoreSelectedAction.java @@ -22,11 +22,11 @@ import java.awt.event.InputEvent; import java.awt.event.KeyEvent; -public class IgnoreAllAction extends AbstractAction { +public class IgnoreSelectedAction extends AbstractAction { private static final long serialVersionUID = -2553283436556522929L; - public IgnoreAllAction() { + public IgnoreSelectedAction() { putValue(Action.NAME, "Ignore selected"); putValue(Action.SHORT_DESCRIPTION, "Set status of all selected codes to ignore"); putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_I, InputEvent.ALT_MASK | InputEvent.SHIFT_DOWN_MASK)); @@ -34,7 +34,7 @@ public IgnoreAllAction() { @Override public void actionPerformed(ActionEvent arg0) { - Global.mappingTablePanel.approveAll(); + Global.mappingTablePanel.ignoreSelected(); } } From b879adb983ae3dbdcc1eaf0bb8f2a9d04efae2b6 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Thu, 1 Oct 2020 17:16:59 +0200 Subject: [PATCH 08/77] refactor clear all to clear selected --- src/org/ohdsi/usagi/ui/Global.java | 6 +++--- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 6 +++--- src/org/ohdsi/usagi/ui/UsagiMain.java | 4 ++-- src/org/ohdsi/usagi/ui/UsagiMenubar.java | 2 +- .../{ClearAllAction.java => ClearSelectedAction.java} | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) rename src/org/ohdsi/usagi/ui/actions/{ClearAllAction.java => ClearSelectedAction.java} (90%) diff --git a/src/org/ohdsi/usagi/ui/Global.java b/src/org/ohdsi/usagi/ui/Global.java index 9b0ebe9..a9c6adb 100644 --- a/src/org/ohdsi/usagi/ui/Global.java +++ b/src/org/ohdsi/usagi/ui/Global.java @@ -42,10 +42,10 @@ public class Global { public static SaveAction saveAction; public static SaveAsAction saveAsAction; public static ApproveAction approveAction; - public static ApproveSelectedAction approveSelectedAction; + public static ApproveSelectedAction approveSelectedAction; public static IgnoreAction ignoreAction; - public static IgnoreSelectedAction ignoreSelectedAction; - public static ClearAllAction clearAllAction; + public static IgnoreSelectedAction ignoreSelectedAction; + public static ClearSelectedAction clearSelectedAction; public static ConceptInformationAction conceptInfoAction; public static AthenaAction athenaAction; public static GoogleSearchAction googleSearchAction; diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index c6bf64d..18bd0c8 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -67,7 +67,7 @@ public MappingTablePanel() { Global.approveSelectedAction.setEnabled(true); Global.ignoreAction.setEnabled(true); Global.ignoreSelectedAction.setEnabled(true); - Global.clearAllAction.setEnabled(true); + Global.clearSelectedAction.setEnabled(true); if (tableModel.getCodeMapping(primaryModelRow).targetConcepts.size() > 0) { Concept firstConcept = tableModel.getCodeMapping(primaryModelRow).targetConcepts.get(0); Global.conceptInfoAction.setEnabled(true); @@ -90,7 +90,7 @@ public MappingTablePanel() { Global.approveAction.setEnabled(false); Global.ignoreAction.setEnabled(false); Global.ignoreSelectedAction.setEnabled(false); - Global.clearAllAction.setEnabled(false); + Global.clearSelectedAction.setEnabled(false); } } }); @@ -303,7 +303,7 @@ public void ignoreSelected() { setMappingStatusSelected(MappingStatus.IGNORED); } - public void clearAll() { + public void clearSelected() { for (int viewRow : table.getSelectedRows()) { int modelRow = table.convertRowIndexToModel(viewRow); tableModel.getCodeMapping(modelRow).targetConcepts.clear(); diff --git a/src/org/ohdsi/usagi/ui/UsagiMain.java b/src/org/ohdsi/usagi/ui/UsagiMain.java index faa0238..d36746a 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMain.java +++ b/src/org/ohdsi/usagi/ui/UsagiMain.java @@ -98,8 +98,8 @@ public UsagiMain(String[] args) { Global.approveSelectedAction.setEnabled(false); Global.ignoreAction.setEnabled(false); Global.ignoreSelectedAction.setEnabled(false); - Global.clearAllAction = new ClearAllAction(); - Global.clearAllAction.setEnabled(false); + Global.clearSelectedAction = new ClearSelectedAction(); + Global.clearSelectedAction.setEnabled(false); Global.conceptInfoAction.setEnabled(false); Global.athenaAction.setEnabled(false); Global.googleSearchAction.setEnabled(false); diff --git a/src/org/ohdsi/usagi/ui/UsagiMenubar.java b/src/org/ohdsi/usagi/ui/UsagiMenubar.java index bf5674c..b646ce5 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMenubar.java +++ b/src/org/ohdsi/usagi/ui/UsagiMenubar.java @@ -45,7 +45,7 @@ public UsagiMenubar() { editMenu.add(Global.approveSelectedAction); editMenu.add(Global.ignoreAction); editMenu.add(Global.ignoreSelectedAction); - editMenu.add(Global.clearAllAction); + editMenu.add(Global.clearSelectedAction); JMenu viewMenu = new JMenu("View"); viewMenu.setMnemonic(KeyEvent.VK_V); diff --git a/src/org/ohdsi/usagi/ui/actions/ClearAllAction.java b/src/org/ohdsi/usagi/ui/actions/ClearSelectedAction.java similarity index 90% rename from src/org/ohdsi/usagi/ui/actions/ClearAllAction.java rename to src/org/ohdsi/usagi/ui/actions/ClearSelectedAction.java index 7e3c225..d081280 100644 --- a/src/org/ohdsi/usagi/ui/actions/ClearAllAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ClearSelectedAction.java @@ -22,18 +22,18 @@ import org.ohdsi.usagi.ui.Global; -public class ClearAllAction extends AbstractAction { +public class ClearSelectedAction extends AbstractAction { private static final long serialVersionUID = 3420357922150237898L; - public ClearAllAction() { + public ClearSelectedAction() { putValue(Action.NAME, "Clear selected"); putValue(Action.SHORT_DESCRIPTION, "Clear all selected mappings (set target to 0)"); } @Override public void actionPerformed(ActionEvent arg0) { - Global.mappingTablePanel.clearAll(); + Global.mappingTablePanel.clearSelected(); } } From 407304a5c0c76208da67638168d72eebf527c14d Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Thu, 1 Oct 2020 17:25:08 +0200 Subject: [PATCH 09/77] clear existing mappings if status set to ignored --- .../ohdsi/usagi/ui/MappingDetailPanel.java | 3 ++- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 23 ++++++++++--------- .../ohdsi/usagi/ui/actions/IgnoreAction.java | 2 +- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 2c39e3f..d4540ac 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -417,7 +417,8 @@ private void toggleApproveButton() { public void ignore() { if (codeMapping.mappingStatus != CodeMapping.MappingStatus.IGNORED) { codeMapping.mappingStatus = MappingStatus.IGNORED; - // TODO: remove any existing mapping + Global.mappingTablePanel.clearSelected(); + // TODO: grey out ignored rows Global.mapping.fireDataChanged(APPROVE_EVENT); } else { codeMapping.mappingStatus = CodeMapping.MappingStatus.UNCHECKED; diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 18bd0c8..b051024 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -276,8 +276,8 @@ public void dataChanged(DataChangeEvent event) { } } - private void fireUpdateEventAll() { - Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + private void fireUpdateEventAll(DataChangeEvent event) { + Global.mapping.fireDataChanged(event); int viewRow = table.getSelectedRow(); if (viewRow != -1) { int modelRow = table.convertRowIndexToModel(viewRow); @@ -287,20 +287,21 @@ private void fireUpdateEventAll() { } } - private void setMappingStatusSelected(MappingStatus mappingStatus) { + public void approveSelected() { for (int viewRow : table.getSelectedRows()) { int modelRow = table.convertRowIndexToModel(viewRow); - tableModel.getCodeMapping(modelRow).mappingStatus = mappingStatus; + tableModel.getCodeMapping(modelRow).mappingStatus = MappingStatus.APPROVED; } - fireUpdateEventAll(); - } - - public void approveSelected() { - setMappingStatusSelected(MappingStatus.APPROVED); + fireUpdateEventAll(APPROVE_EVENT); } public void ignoreSelected() { - setMappingStatusSelected(MappingStatus.IGNORED); + for (int viewRow : table.getSelectedRows()) { + int modelRow = table.convertRowIndexToModel(viewRow); + tableModel.getCodeMapping(modelRow).mappingStatus = MappingStatus.IGNORED; + Global.mappingTablePanel.clearSelected(); + } + fireUpdateEventAll(APPROVE_EVENT); } public void clearSelected() { @@ -308,6 +309,6 @@ public void clearSelected() { int modelRow = table.convertRowIndexToModel(viewRow); tableModel.getCodeMapping(modelRow).targetConcepts.clear(); } - fireUpdateEventAll(); + fireUpdateEventAll(SIMPLE_UPDATE_EVENT); } } diff --git a/src/org/ohdsi/usagi/ui/actions/IgnoreAction.java b/src/org/ohdsi/usagi/ui/actions/IgnoreAction.java index 3431f78..40e4547 100644 --- a/src/org/ohdsi/usagi/ui/actions/IgnoreAction.java +++ b/src/org/ohdsi/usagi/ui/actions/IgnoreAction.java @@ -39,7 +39,7 @@ public void actionPerformed(ActionEvent arg0) { public void setToIgnore() { putValue(Action.NAME, "Ignore"); - putValue(Action.SHORT_DESCRIPTION, "Set status of selected code to ignore"); + putValue(Action.SHORT_DESCRIPTION, "Remove mapping and set status of selected code to ignore"); } public void setToUnignore() { From 66ecd58da33ad3397eaa0179c3ae84edd299136c Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Thu, 1 Oct 2020 17:36:15 +0200 Subject: [PATCH 10/77] set rendering of ignored rows grey text on white --- src/org/ohdsi/usagi/ui/UsagiCellRenderer.java | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/UsagiCellRenderer.java b/src/org/ohdsi/usagi/ui/UsagiCellRenderer.java index a477f1b..122a0be 100644 --- a/src/org/ohdsi/usagi/ui/UsagiCellRenderer.java +++ b/src/org/ohdsi/usagi/ui/UsagiCellRenderer.java @@ -26,14 +26,15 @@ public class UsagiCellRenderer extends DefaultTableCellRenderer { - public static int MAX_TOOLTIP_WIDTH_IN_CHARS = 150; - private static final long serialVersionUID = -4732586716304918837L; - private static Color oddColor = new Color(0.95f, 0.95f, 1f); - private static Color checkedColor = new Color(0.75f, 1f, 0.75f); - private static Color checkedOddColor = new Color(0.85f, 1f, 0.85f); - private static Color errorColor = new Color(1f, 0.75f, 0.75f); - private static Color errorOddColor = new Color(1f, 0.85f, 0.85f); - private static DecimalFormat doubleFormatter = new DecimalFormat("###,###,###,##0.00"); + public static int MAX_TOOLTIP_WIDTH_IN_CHARS = 150; + private static final long serialVersionUID = -4732586716304918837L; + private static final Color evenColor = Color.white; + private static final Color oddColor = new Color(0.95f, 0.95f, 1.00f); + private static final Color checkedColor = new Color(0.75f, 1.00f, 0.75f); + private static final Color checkedOddColor = new Color(0.85f, 1.00f, 0.85f); + private static final Color errorColor = new Color(1.00f, 0.75f, 0.75f); + private static final Color errorOddColor = new Color(1.00f, 0.85f, 0.85f); + private static final DecimalFormat doubleFormatter = new DecimalFormat("###,###,###,##0.00"); @Override public void setValue(Object aValue) { @@ -72,11 +73,14 @@ else if (value == MappingStatus.UNCHECKED) value = "Unchecked"; else if (value == MappingStatus.INVALID_TARGET) value = "Invalid target"; + else if (value == MappingStatus.IGNORED) + value = "Ignored"; } Component component = super.getTableCellRendererComponent(aTable, value, isSelected, hasFocus, row, column); if (!isSelected) { int modelRow = aTable.convertRowIndexToModel(row); + component.setForeground(Color.black); if (aTable.getModel().getValueAt(modelRow, 0) == MappingStatus.APPROVED) { if (row % 2 == 1) component.setBackground(checkedColor); @@ -87,11 +91,15 @@ else if (value == MappingStatus.INVALID_TARGET) component.setBackground(errorColor); else component.setBackground(errorOddColor); + } else if (aTable.getModel().getValueAt(modelRow, 0) == MappingStatus.IGNORED) { + component.setBackground(Color.white); + component.setForeground(Color.gray); } else { if (row % 2 == 1) { component.setBackground(oddColor); - } else - component.setBackground(Color.white); + } else { + component.setBackground(evenColor); + } } } return component; From 85453967488e6ea0e76d38f0e2bec4b255250cf8 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Thu, 1 Oct 2020 18:26:18 +0200 Subject: [PATCH 11/77] prevent approving of ignored and ignoring of approved mappings --- src/org/ohdsi/usagi/ui/MappingDetailPanel.java | 6 +++--- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 10 +++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index d4540ac..04f36b7 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -203,7 +203,8 @@ private Component createSearchResultsPanel() { searchTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); searchTable.getSelectionModel().addListSelectionListener(event -> { int viewRow = searchTable.getSelectedRow(); - if (viewRow == -1) { + // Don't enable the buttons if no row selected or status is either approved or ignored + if (viewRow == -1 || codeMapping.mappingStatus == MappingStatus.APPROVED || codeMapping.mappingStatus == MappingStatus.IGNORED) { addButton.setEnabled(false); replaceButton.setEnabled(false); } else { @@ -330,7 +331,7 @@ private JPanel createTargetConceptsPanel() { targetConceptTable.setRowSelectionAllowed(true); targetConceptTable.getSelectionModel().addListSelectionListener(event -> { int viewRow = targetConceptTable.getSelectedRow(); - if (viewRow == -1) { + if (viewRow == -1 || codeMapping.mappingStatus == MappingStatus.APPROVED) { removeButton.setEnabled(false); } else { removeButton.setEnabled(true); @@ -418,7 +419,6 @@ public void ignore() { if (codeMapping.mappingStatus != CodeMapping.MappingStatus.IGNORED) { codeMapping.mappingStatus = MappingStatus.IGNORED; Global.mappingTablePanel.clearSelected(); - // TODO: grey out ignored rows Global.mapping.fireDataChanged(APPROVE_EVENT); } else { codeMapping.mappingStatus = CodeMapping.MappingStatus.UNCHECKED; diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index b051024..fd507de 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -290,7 +290,9 @@ private void fireUpdateEventAll(DataChangeEvent event) { public void approveSelected() { for (int viewRow : table.getSelectedRows()) { int modelRow = table.convertRowIndexToModel(viewRow); - tableModel.getCodeMapping(modelRow).mappingStatus = MappingStatus.APPROVED; + if (tableModel.getCodeMapping(modelRow).mappingStatus != MappingStatus.IGNORED) { + tableModel.getCodeMapping(modelRow).mappingStatus = MappingStatus.APPROVED; + } } fireUpdateEventAll(APPROVE_EVENT); } @@ -298,8 +300,10 @@ public void approveSelected() { public void ignoreSelected() { for (int viewRow : table.getSelectedRows()) { int modelRow = table.convertRowIndexToModel(viewRow); - tableModel.getCodeMapping(modelRow).mappingStatus = MappingStatus.IGNORED; - Global.mappingTablePanel.clearSelected(); + if (tableModel.getCodeMapping(modelRow).mappingStatus != MappingStatus.APPROVED) { + tableModel.getCodeMapping(modelRow).mappingStatus = MappingStatus.IGNORED; + Global.mappingTablePanel.clearSelected(); + } } fireUpdateEventAll(APPROVE_EVENT); } From 9cc065591f5405556f4d1ee678a840a0e82b6a68 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Thu, 1 Oct 2020 18:50:35 +0200 Subject: [PATCH 12/77] render background of ignored rows as normal --- src/org/ohdsi/usagi/ui/UsagiCellRenderer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/UsagiCellRenderer.java b/src/org/ohdsi/usagi/ui/UsagiCellRenderer.java index 122a0be..1fb30e8 100644 --- a/src/org/ohdsi/usagi/ui/UsagiCellRenderer.java +++ b/src/org/ohdsi/usagi/ui/UsagiCellRenderer.java @@ -91,9 +91,6 @@ else if (value == MappingStatus.IGNORED) component.setBackground(errorColor); else component.setBackground(errorOddColor); - } else if (aTable.getModel().getValueAt(modelRow, 0) == MappingStatus.IGNORED) { - component.setBackground(Color.white); - component.setForeground(Color.gray); } else { if (row % 2 == 1) { component.setBackground(oddColor); @@ -101,6 +98,9 @@ else if (value == MappingStatus.IGNORED) component.setBackground(evenColor); } } + if (aTable.getModel().getValueAt(modelRow, 0) == MappingStatus.IGNORED) { + component.setForeground(Color.gray); + } } return component; } From 8f89c9843ec01bf6ca1b72b6e55abb9be00fe174 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 2 Oct 2020 08:07:19 +0200 Subject: [PATCH 13/77] add author and time details to mappings --- src/org/ohdsi/usagi/CodeMapping.java | 39 +++++++++++- src/org/ohdsi/usagi/MappingTarget.java | 10 +++ src/org/ohdsi/usagi/ui/AuthorDialog.java | 63 +++++++++++++++++++ src/org/ohdsi/usagi/ui/Global.java | 2 + .../ohdsi/usagi/ui/MappingDetailPanel.java | 12 ++-- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 10 ++- .../usagi/ui/TargetConceptTableModel.java | 7 ++- src/org/ohdsi/usagi/ui/UsagiMain.java | 6 ++ 8 files changed, 140 insertions(+), 9 deletions(-) create mode 100644 src/org/ohdsi/usagi/ui/AuthorDialog.java diff --git a/src/org/ohdsi/usagi/CodeMapping.java b/src/org/ohdsi/usagi/CodeMapping.java index e609a5b..e65337a 100644 --- a/src/org/ohdsi/usagi/CodeMapping.java +++ b/src/org/ohdsi/usagi/CodeMapping.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright 2019 Observational Health Data Sciences and Informatics + * Copyright 2020 Observational Health Data Sciences and Informatics & The Hyve * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,9 +33,46 @@ public enum MappingStatus { public MappingStatus mappingStatus; public List targetConcepts = new ArrayList<>(1); public String comment; + // TODO: write these to Usagi save file + public String createdBy; + public long createdOn; + public String approvedBy; + public long approvedOn; + public String ignoredBy; + public long ignoredOn; + public CodeMapping(SourceCode sourceCode) { this.sourceCode = sourceCode; + this.createdOn = System.currentTimeMillis(); + } + + public CodeMapping(SourceCode sourceCode, String createdBy) { + this(sourceCode); + this.createdBy = createdBy; + } + + public void approve(String approvedBy) { + this.mappingStatus = MappingStatus.APPROVED; + this.approvedOn = System.currentTimeMillis(); + this.approvedBy = approvedBy; } + public void unapprove() { + this.mappingStatus = MappingStatus.UNCHECKED; + this.approvedOn = 0; + this.approvedBy = ""; + } + + public void ignore(String ignoredBy) { + this.mappingStatus = MappingStatus.IGNORED; + this.ignoredOn = System.currentTimeMillis(); + this.ignoredBy = ignoredBy; + } + + public void unignore() { + this.mappingStatus = MappingStatus.UNCHECKED; + this.ignoredOn = 0; + this.ignoredBy = ""; + } } diff --git a/src/org/ohdsi/usagi/MappingTarget.java b/src/org/ohdsi/usagi/MappingTarget.java index 1b5e56a..adfb23a 100644 --- a/src/org/ohdsi/usagi/MappingTarget.java +++ b/src/org/ohdsi/usagi/MappingTarget.java @@ -22,18 +22,28 @@ public class MappingTarget{ public enum Type { REGULAR, VALUE, UNIT // Maybe also OPERATOR, TYPE, etc. }; + public Concept concept; public Type mappingType; + // TODO: write these to Usagi save file + public String createdBy; + public long createdOn; public MappingTarget(Concept concept, Type mappingType) { this.concept = concept; this.mappingType = mappingType; + this.createdOn = System.currentTimeMillis(); } public MappingTarget(Concept concept) { this(concept, Type.REGULAR); } + public MappingTarget(Concept concept, Type mappingType, String createdBy) { + this(concept, mappingType); + this.createdBy = createdBy; + } + public Concept getConcept() { return concept; } diff --git a/src/org/ohdsi/usagi/ui/AuthorDialog.java b/src/org/ohdsi/usagi/ui/AuthorDialog.java new file mode 100644 index 0000000..cf2b194 --- /dev/null +++ b/src/org/ohdsi/usagi/ui/AuthorDialog.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright 2020 Observational Health Data Sciences and Informatics & The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ******************************************************************************/ +package org.ohdsi.usagi.ui; + +import javax.swing.*; +import java.awt.*; + +public class AuthorDialog extends JDialog { + + private static final long serialVersionUID = 8239922540117895957L; + + public AuthorDialog() { + setTitle("Author"); + setLayout(new GridBagLayout()); + GridBagConstraints g = new GridBagConstraints(); + g.fill = GridBagConstraints.BOTH; + g.ipadx = 5; + g.ipady = 5; + + g.gridx = 0; + g.gridy = 0; + add(new JLabel("Author:"), g); + + g.gridx = 1; + g.gridy = 0; + JTextFieldLimit authorField = new JTextFieldLimit(20); + authorField.setToolTipText("Please enter your name"); + authorField.setPreferredSize(new Dimension(100, 10)); + add(authorField, g); + + g.gridx = 0; + g.gridy = 2; + g.gridwidth = 2; + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS)); + buttonPanel.add(Box.createHorizontalGlue()); + JButton saveButton = new JButton("Save"); + saveButton.setToolTipText("Save your name"); + saveButton.addActionListener(event -> { + Global.author = authorField.getText(); + setVisible(false); + }); + buttonPanel.add(saveButton); + add(buttonPanel, g); + + pack(); + setModal(true); + setLocationRelativeTo(Global.frame); + } +} diff --git a/src/org/ohdsi/usagi/ui/Global.java b/src/org/ohdsi/usagi/ui/Global.java index a9c6adb..c4a82a0 100644 --- a/src/org/ohdsi/usagi/ui/Global.java +++ b/src/org/ohdsi/usagi/ui/Global.java @@ -59,4 +59,6 @@ public class Global { public static Vector vocabularyIds; public static Vector domainIds; public static ShowStatsAction showStatsAction; + + public static String author; } diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index ba2d516..0c9d8cc 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -403,10 +403,10 @@ public void clearCodeMultiSelected() { public void approve() { if (codeMapping.mappingStatus != CodeMapping.MappingStatus.APPROVED) { - codeMapping.mappingStatus = CodeMapping.MappingStatus.APPROVED; + codeMapping.approve(Global.author); Global.mapping.fireDataChanged(APPROVE_EVENT); } else { - codeMapping.mappingStatus = CodeMapping.MappingStatus.UNCHECKED; + codeMapping.unapprove(); Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); toggleApproveButton(); } @@ -426,11 +426,11 @@ private void toggleApproveButton() { public void ignore() { if (codeMapping.mappingStatus != CodeMapping.MappingStatus.IGNORED) { - codeMapping.mappingStatus = MappingStatus.IGNORED; + codeMapping.ignore(Global.author); Global.mappingTablePanel.clearSelected(); Global.mapping.fireDataChanged(APPROVE_EVENT); } else { - codeMapping.mappingStatus = CodeMapping.MappingStatus.UNCHECKED; + codeMapping.unignore(); Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); toggleIgnoreButton(); } @@ -463,9 +463,9 @@ public void addConcept(Concept concept) { } public void addConcept(Concept concept, MappingTarget.Type mappingType) { - codeMapping.targetConcepts.add(new MappingTarget(concept, mappingType)); + codeMapping.targetConcepts.add(new MappingTarget(concept, mappingType, Global.author)); for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { - codeMappingMulti.targetConcepts.add(new MappingTarget(concept, mappingType)); + codeMappingMulti.targetConcepts.add(new MappingTarget(concept, mappingType, Global.author)); } targetConceptTableModel.fireTableDataChanged(); diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index be2acce..bb329c4 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -111,7 +111,7 @@ class CodeMapTableModel extends AbstractTableModel { private String[] defaultColumnNames = { "Status", "Source code", "Source term", "Frequency", "Match score", "Concept ID", "Concept name", "Domain", "Concept class", "Vocabulary", "Concept code", "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", - "Children", "Comment" }; + "Children", "Comment", "Created by", "Created on", "Approved by", "Approved on" }; private String[] columnNames = defaultColumnNames; private int addInfoColCount = 0; private int ADD_INFO_START_COL = 4; @@ -203,6 +203,14 @@ public Object getValueAt(int row, int col) { return targetConcept.childCount; case 17: return codeMapping.comment; + case 18: + return codeMapping.createdBy; + case 19: + return codeMapping.createdOn; + case 20: + return codeMapping.approvedBy; + case 21: + return codeMapping.approvedOn; default: return ""; } diff --git a/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java b/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java index 055d399..cc42588 100644 --- a/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java +++ b/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java @@ -13,7 +13,8 @@ class TargetConceptTableModel extends AbstractTableModel { private final String termColumnName = "Term"; private final String[] columnNames = {"Concept ID", "Concept name", "Domain", "Concept class", "Vocabulary", "Concept code", - "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", "Children", "Mapping Type"}; + "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", "Children", "Mapping Type", + "Created by", "Created on"}; private List targetConcepts = new ArrayList<>(); public TargetConceptTableModel() { @@ -72,6 +73,10 @@ public Object getValueAt(int row, int col) { return targetConcept.concept.childCount; case 12: return targetConcept.mappingType; + case 13: + return targetConcept.createdBy; + case 14: + return targetConcept.createdOn; default: return ""; } diff --git a/src/org/ohdsi/usagi/ui/UsagiMain.java b/src/org/ohdsi/usagi/ui/UsagiMain.java index d36746a..8b2a22a 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMain.java +++ b/src/org/ohdsi/usagi/ui/UsagiMain.java @@ -63,6 +63,7 @@ public UsagiMain(String[] args) { Global.usagiSearchEngine.openIndexForSearching(false); Global.dbEngine.openForReading(); } + Global.vocabularyVersion = loadVocabularyVersion(Global.folder); Global.conceptClassIds = loadVectorFromFile(Global.folder + "/ConceptClassIds.txt"); Global.vocabularyIds = loadVectorFromFile(Global.folder + "/VocabularyIds.txt"); @@ -143,6 +144,11 @@ public void windowClosing(WindowEvent e) { if (args.length > 1 && args[0].equals("--file")) { OpenAction.open(new File(args[1])); } + + // TODO: save author to file and load if available + AuthorDialog authorDialog = new AuthorDialog(); + authorDialog.setVisible(true); + } private String loadVocabularyVersion(String folder) { From 026a720b9e06c4fd2ba92a251b75ad2a719267a2 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 2 Oct 2020 08:15:44 +0200 Subject: [PATCH 14/77] simplify approve/ignore author and date --- src/org/ohdsi/usagi/CodeMapping.java | 41 ++++++------------- .../ohdsi/usagi/ui/MappingDetailPanel.java | 4 +- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 10 ++--- 3 files changed, 18 insertions(+), 37 deletions(-) diff --git a/src/org/ohdsi/usagi/CodeMapping.java b/src/org/ohdsi/usagi/CodeMapping.java index e65337a..5081b55 100644 --- a/src/org/ohdsi/usagi/CodeMapping.java +++ b/src/org/ohdsi/usagi/CodeMapping.java @@ -34,45 +34,30 @@ public enum MappingStatus { public List targetConcepts = new ArrayList<>(1); public String comment; // TODO: write these to Usagi save file - public String createdBy; - public long createdOn; - public String approvedBy; - public long approvedOn; - public String ignoredBy; - public long ignoredOn; - + public String statusSetBy; + public long statusSetOn; public CodeMapping(SourceCode sourceCode) { this.sourceCode = sourceCode; - this.createdOn = System.currentTimeMillis(); - } - - public CodeMapping(SourceCode sourceCode, String createdBy) { - this(sourceCode); - this.createdBy = createdBy; } - public void approve(String approvedBy) { - this.mappingStatus = MappingStatus.APPROVED; - this.approvedOn = System.currentTimeMillis(); - this.approvedBy = approvedBy; + public void setStatus(MappingStatus mappingStatus, String author) { + this.mappingStatus = mappingStatus; + this.statusSetOn = System.currentTimeMillis(); + this.statusSetBy = author; } - public void unapprove() { + public void setUnchecked() { this.mappingStatus = MappingStatus.UNCHECKED; - this.approvedOn = 0; - this.approvedBy = ""; + this.statusSetOn = 0; + this.statusSetBy = ""; } - public void ignore(String ignoredBy) { - this.mappingStatus = MappingStatus.IGNORED; - this.ignoredOn = System.currentTimeMillis(); - this.ignoredBy = ignoredBy; + public void approve(String approvedBy) { + setStatus(MappingStatus.APPROVED, approvedBy); } - public void unignore() { - this.mappingStatus = MappingStatus.UNCHECKED; - this.ignoredOn = 0; - this.ignoredBy = ""; + public void ignore(String ignoredBy) { + setStatus(MappingStatus.IGNORED, ignoredBy); } } diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 0c9d8cc..541565e 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -406,7 +406,7 @@ public void approve() { codeMapping.approve(Global.author); Global.mapping.fireDataChanged(APPROVE_EVENT); } else { - codeMapping.unapprove(); + codeMapping.setUnchecked(); Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); toggleApproveButton(); } @@ -430,7 +430,7 @@ public void ignore() { Global.mappingTablePanel.clearSelected(); Global.mapping.fireDataChanged(APPROVE_EVENT); } else { - codeMapping.unignore(); + codeMapping.setUnchecked(); Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); toggleIgnoreButton(); } diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index bb329c4..c0c26e3 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -111,7 +111,7 @@ class CodeMapTableModel extends AbstractTableModel { private String[] defaultColumnNames = { "Status", "Source code", "Source term", "Frequency", "Match score", "Concept ID", "Concept name", "Domain", "Concept class", "Vocabulary", "Concept code", "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", - "Children", "Comment", "Created by", "Created on", "Approved by", "Approved on" }; + "Children", "Comment", "Approved/Ignored by", "Approved/Ignored on" }; private String[] columnNames = defaultColumnNames; private int addInfoColCount = 0; private int ADD_INFO_START_COL = 4; @@ -204,13 +204,9 @@ public Object getValueAt(int row, int col) { case 17: return codeMapping.comment; case 18: - return codeMapping.createdBy; + return codeMapping.statusSetBy; case 19: - return codeMapping.createdOn; - case 20: - return codeMapping.approvedBy; - case 21: - return codeMapping.approvedOn; + return codeMapping.statusSetOn; default: return ""; } From 3dc5be4c4d2a90462acdf1c5b5ee23f784863c8c Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 2 Oct 2020 08:21:18 +0200 Subject: [PATCH 15/77] assign concept added by as upon import --- src/org/ohdsi/usagi/MappingTarget.java | 4 ++++ src/org/ohdsi/usagi/dataImport/ImportData.java | 4 ++-- src/org/ohdsi/usagi/ui/ImportDialog.java | 2 +- src/org/ohdsi/usagi/ui/MappingDetailPanel.java | 4 ++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/org/ohdsi/usagi/MappingTarget.java b/src/org/ohdsi/usagi/MappingTarget.java index adfb23a..35546bc 100644 --- a/src/org/ohdsi/usagi/MappingTarget.java +++ b/src/org/ohdsi/usagi/MappingTarget.java @@ -39,6 +39,10 @@ public MappingTarget(Concept concept) { this(concept, Type.REGULAR); } + public MappingTarget(Concept concept, String createdBy) { + this(concept, Type.REGULAR, createdBy); + } + public MappingTarget(Concept concept, Type mappingType, String createdBy) { this(concept, mappingType); this.createdBy = createdBy; diff --git a/src/org/ohdsi/usagi/dataImport/ImportData.java b/src/org/ohdsi/usagi/dataImport/ImportData.java index cff1e79..ab37ad4 100644 --- a/src/org/ohdsi/usagi/dataImport/ImportData.java +++ b/src/org/ohdsi/usagi/dataImport/ImportData.java @@ -74,10 +74,10 @@ private void createInitialMapping(List sourceCodes, ImportSettings s List concepts = usagiSearchEngine.search(sourceCode.sourceName, true, sourceCode.sourceAutoAssignedConceptIds, settings.filterDomains, settings.filterConceptClasses, settings.filterVocabularies, settings.filterStandard, settings.includeSourceTerms); if (concepts.size() > 0) { - codeMapping.targetConcepts.add(new MappingTarget(concepts.get(0).concept)); + codeMapping.targetConcepts.add(new MappingTarget(concepts.get(0).concept, "")); codeMapping.matchScore = concepts.get(0).matchScore; } else { - codeMapping.targetConcepts.add(new MappingTarget(Concept.EMPTY_CONCEPT)); + codeMapping.targetConcepts.add(new MappingTarget(Concept.EMPTY_CONCEPT, "")); codeMapping.matchScore = 0; } codeMapping.mappingStatus = MappingStatus.UNCHECKED; diff --git a/src/org/ohdsi/usagi/ui/ImportDialog.java b/src/org/ohdsi/usagi/ui/ImportDialog.java index eb77ae8..b218bac 100644 --- a/src/org/ohdsi/usagi/ui/ImportDialog.java +++ b/src/org/ohdsi/usagi/ui/ImportDialog.java @@ -442,7 +442,7 @@ public void run() { List concepts = Global.usagiSearchEngine.search(sourceCode.sourceName, true, filterConceptIds, filterDomainsFinal, filterConceptClassesFinal, filterVocabulariesFinal, filterStandard, includeSourceConcepts); if (concepts.size() > 0) { - codeMapping.targetConcepts.add(new MappingTarget(concepts.get(0).concept)); + codeMapping.targetConcepts.add(new MappingTarget(concepts.get(0).concept, "")); codeMapping.matchScore = concepts.get(0).matchScore; } else { codeMapping.matchScore = 0; diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 541565e..88b0238 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -449,9 +449,9 @@ private void toggleIgnoreButton() { } public void addConcept(Concept concept) { - codeMapping.targetConcepts.add(new MappingTarget(concept)); + codeMapping.targetConcepts.add(new MappingTarget(concept, Global.author)); for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { - codeMappingMulti.targetConcepts.add(new MappingTarget(concept)); + codeMappingMulti.targetConcepts.add(new MappingTarget(concept, Global.author)); } targetConceptTableModel.fireTableDataChanged(); From 682e13d04ebeabd94fe2477def8bfbc7007e1b54 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 2 Oct 2020 09:06:06 +0200 Subject: [PATCH 16/77] save and load provenance fields --- src/org/ohdsi/usagi/CodeMapping.java | 1 - src/org/ohdsi/usagi/MappingTarget.java | 5 +- .../ohdsi/usagi/ReadCodeMappingsFromFile.java | 180 +++++++++--------- .../ohdsi/usagi/WriteCodeMappingsToFile.java | 6 +- src/org/ohdsi/utilities/files/Row.java | 34 +++- 5 files changed, 128 insertions(+), 98 deletions(-) diff --git a/src/org/ohdsi/usagi/CodeMapping.java b/src/org/ohdsi/usagi/CodeMapping.java index 5081b55..7d22ae1 100644 --- a/src/org/ohdsi/usagi/CodeMapping.java +++ b/src/org/ohdsi/usagi/CodeMapping.java @@ -33,7 +33,6 @@ public enum MappingStatus { public MappingStatus mappingStatus; public List targetConcepts = new ArrayList<>(1); public String comment; - // TODO: write these to Usagi save file public String statusSetBy; public long statusSetOn; diff --git a/src/org/ohdsi/usagi/MappingTarget.java b/src/org/ohdsi/usagi/MappingTarget.java index 35546bc..b378d7c 100644 --- a/src/org/ohdsi/usagi/MappingTarget.java +++ b/src/org/ohdsi/usagi/MappingTarget.java @@ -25,7 +25,6 @@ public enum Type { public Concept concept; public Type mappingType; - // TODO: write these to Usagi save file public String createdBy; public long createdOn; @@ -47,6 +46,10 @@ public MappingTarget(Concept concept, Type mappingType, String createdBy) { this(concept, mappingType); this.createdBy = createdBy; } + public MappingTarget(Concept concept, Type mappingType, String createdBy, long createdOn) { + this(concept, mappingType, createdBy); + this.createdOn = createdOn; + } public Concept getConcept() { return concept; diff --git a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java index 8e1b68e..b9f3a35 100644 --- a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java +++ b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java @@ -1,12 +1,12 @@ /******************************************************************************* * Copyright 2019 Observational Health Data Sciences and Informatics - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -23,89 +23,95 @@ import org.ohdsi.utilities.files.Row; public class ReadCodeMappingsFromFile implements Iterable { - private String filename; - - public ReadCodeMappingsFromFile(String filename) { - this.filename = filename; - } - - @Override - public Iterator iterator() { - return new RowIterator(); - } - - public class RowIterator implements Iterator { - - private Iterator iterator; - private CodeMapping buffer; - private Row row; - - public RowIterator() { - iterator = new ReadCSVFileWithHeader(filename).iterator(); - - if (iterator.hasNext()) { - row = iterator.next(); - readNext(); - } else { - buffer = null; - } - } - - private void readNext() { - if (row == null) { - buffer = null; - } else { - buffer = new CodeMapping(new SourceCode(row)); - buffer.matchScore = row.getDouble("matchScore"); - buffer.mappingStatus = MappingStatus.valueOf(row.get("mappingStatus")); - try { - buffer.comment = row.get("comment"); - } catch (Exception e) { - buffer.comment = ""; - } - while (row != null && new SourceCode(row).sourceCode.equals(buffer.sourceCode.sourceCode) - && new SourceCode(row).sourceName.equals(buffer.sourceCode.sourceName)) { - if (row.getInt("conceptId") != 0) { - Concept concept = Global.dbEngine.getConcept(row.getInt("conceptId")); - - // Older save files might not have a mappingType. - MappingTarget.Type mappingType = MappingTarget.Type.REGULAR; - if (row.getFieldNames().contains("mappingType")) { - mappingType = MappingTarget.Type.valueOf(row.get("mappingType")); - } - - if (concept == null) { - buffer.mappingStatus = MappingStatus.INVALID_TARGET; - buffer.comment = "Invalid existing target: " + row.get("conceptId"); - } else { - buffer.targetConcepts.add(new MappingTarget(concept, mappingType)); - } - } - if (iterator.hasNext()) - row = iterator.next(); - else - row = null; - } - } - } - - @Override - public boolean hasNext() { - return buffer != null; - } - - @Override - public CodeMapping next() { - CodeMapping next = buffer; - readNext(); - return next; - } - - @Override - public void remove() { - throw new RuntimeException("Remove not supported"); - } - - } + private String filename; + + public ReadCodeMappingsFromFile(String filename) { + this.filename = filename; + } + + @Override + public Iterator iterator() { + return new RowIterator(); + } + + public class RowIterator implements Iterator { + + private Iterator iterator; + private CodeMapping buffer; + private Row row; + + public RowIterator() { + iterator = new ReadCSVFileWithHeader(filename).iterator(); + + if (iterator.hasNext()) { + row = iterator.next(); + readNext(); + } else { + buffer = null; + } + } + + private void readNext() { + if (row == null) { + buffer = null; + } else { + buffer = new CodeMapping(new SourceCode(row)); + buffer.matchScore = row.getDouble("matchScore"); + buffer.mappingStatus = MappingStatus.valueOf(row.get("mappingStatus")); + + // Status provenance fields might not be available in older Usagi files + buffer.statusSetBy = row.get("statusSetBy", ""); + buffer.statusSetOn = row.getLong("statusSetOn", "0"); + + try { + buffer.comment = row.get("comment"); + } catch (Exception e) { + buffer.comment = ""; + } + while (row != null && new SourceCode(row).sourceCode.equals(buffer.sourceCode.sourceCode) + && new SourceCode(row).sourceName.equals(buffer.sourceCode.sourceName)) { + if (row.getInt("conceptId") != 0) { + Concept concept = Global.dbEngine.getConcept(row.getInt("conceptId")); + + if (concept == null) { + buffer.mappingStatus = MappingStatus.INVALID_TARGET; + buffer.comment = "Invalid existing target: " + row.get("conceptId"); + } else { + // Type and provenance might not be available in older Usagi files + MappingTarget mappingTarget = new MappingTarget( + concept, + MappingTarget.Type.valueOf(row.get("mappingType", "REGULAR")), + row.get("createdBy", ""), + row.getLong("createdOn", "0") + ); + buffer.targetConcepts.add(mappingTarget); + } + } + if (iterator.hasNext()) + row = iterator.next(); + else + row = null; + } + } + } + + @Override + public boolean hasNext() { + return buffer != null; + } + + @Override + public CodeMapping next() { + CodeMapping next = buffer; + readNext(); + return next; + } + + @Override + public void remove() { + throw new RuntimeException("Remove not supported"); + } + + } } diff --git a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java index 5f0ae57..6f7d597 100644 --- a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java +++ b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java @@ -43,8 +43,12 @@ public void write(CodeMapping codeMapping) { row.add("matchScore", codeMapping.matchScore); row.add("mappingStatus", codeMapping.mappingStatus.toString()); row.add("conceptId", targetConcept.concept.conceptId); - row.add("comment", codeMapping.comment); row.add("mappingType", targetConcept.mappingType.toString()); + row.add("statusSetBy", codeMapping.statusSetBy); + row.add("statusSetOn", codeMapping.statusSetOn); + row.add("createdBy", targetConcept.createdBy); + row.add("createdOn", targetConcept.createdOn); + row.add("comment", codeMapping.comment); out.write(row); } } diff --git a/src/org/ohdsi/utilities/files/Row.java b/src/org/ohdsi/utilities/files/Row.java index 94323f9..2788566 100644 --- a/src/org/ohdsi/utilities/files/Row.java +++ b/src/org/ohdsi/utilities/files/Row.java @@ -42,18 +42,25 @@ public Row(Row row) { } public String get(String fieldName) { + return get(fieldName, null); + } + + public String get(String fieldName, String defaultValue) { int index; - try { - index = fieldName2ColumnIndex.get(fieldName); - } catch (NullPointerException e) { - throw new RuntimeException("Field \"" + fieldName + "\" not found"); + if (!fieldName2ColumnIndex.containsKey(fieldName)) { + if (defaultValue == null) { + throw new RuntimeException("Field \"" + fieldName + "\" not found"); + } else { + return defaultValue; + } } + index = fieldName2ColumnIndex.get(fieldName); if (cells.size() <= index) return ""; else return cells.get(index); } - + public List getFieldNames() { List names = new ArrayList(fieldName2ColumnIndex.size()); for (int i = 0; i < fieldName2ColumnIndex.size(); i++) @@ -64,15 +71,26 @@ public List getFieldNames() { } public int getInt(String fieldName) { - return Integer.parseInt(get(fieldName).trim()); + return Integer.parseInt(get(fieldName, null).trim()); + } + + public int getInt(String fieldName, String defaultValue) { + return Integer.parseInt(get(fieldName, defaultValue).trim()); } public long getLong(String fieldName) { - return Long.parseLong(get(fieldName)); + return Long.parseLong(get(fieldName, null)); + } + public long getLong(String fieldName, String defaultValue) { + return Long.parseLong(get(fieldName, defaultValue)); } public double getDouble(String fieldName) { - return Double.parseDouble(get(fieldName)); + return Double.parseDouble(get(fieldName, null)); + } + + public double getDouble(String fieldName, String defaultValue) { + return Double.parseDouble(get(fieldName, defaultValue)); } public void add(String fieldName, String value) { From fc3aee538f72ae01e57388f0bbd9fd61d6a7fce1 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 2 Oct 2020 12:09:52 +0200 Subject: [PATCH 17/77] format provenance --- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 9 +++++---- src/org/ohdsi/usagi/ui/TargetConceptTableModel.java | 8 ++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index c0c26e3..c2fc1c7 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -17,6 +17,7 @@ import java.awt.Dimension; import java.awt.Rectangle; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; @@ -111,7 +112,7 @@ class CodeMapTableModel extends AbstractTableModel { private String[] defaultColumnNames = { "Status", "Source code", "Source term", "Frequency", "Match score", "Concept ID", "Concept name", "Domain", "Concept class", "Vocabulary", "Concept code", "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", - "Children", "Comment", "Approved/Ignored by", "Approved/Ignored on" }; + "Children", "Comment", "Status Provenance"}; private String[] columnNames = defaultColumnNames; private int addInfoColCount = 0; private int ADD_INFO_START_COL = 4; @@ -204,9 +205,9 @@ public Object getValueAt(int row, int col) { case 17: return codeMapping.comment; case 18: - return codeMapping.statusSetBy; - case 19: - return codeMapping.statusSetOn; + if (codeMapping.statusSetOn != 0L) { + return String.format("%s (%tF)", codeMapping.statusSetBy, codeMapping.statusSetOn); + } default: return ""; } diff --git a/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java b/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java index cc42588..d5e877e 100644 --- a/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java +++ b/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java @@ -14,7 +14,7 @@ class TargetConceptTableModel extends AbstractTableModel { private final String termColumnName = "Term"; private final String[] columnNames = {"Concept ID", "Concept name", "Domain", "Concept class", "Vocabulary", "Concept code", "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", "Children", "Mapping Type", - "Created by", "Created on"}; + "Creation Provenance"}; private List targetConcepts = new ArrayList<>(); public TargetConceptTableModel() { @@ -74,9 +74,9 @@ public Object getValueAt(int row, int col) { case 12: return targetConcept.mappingType; case 13: - return targetConcept.createdBy; - case 14: - return targetConcept.createdOn; + if (targetConcept.createdOn != 0L) { + return String.format("%s (%tF)", targetConcept.createdBy, targetConcept.createdOn); + } default: return ""; } From 9ca258f59387c938f45300835589a28253f5b532 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 2 Oct 2020 12:12:49 +0200 Subject: [PATCH 18/77] change order of fields in usagi save file --- src/org/ohdsi/usagi/WriteCodeMappingsToFile.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java index 6f7d597..d4a28d2 100644 --- a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java +++ b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java @@ -42,13 +42,13 @@ public void write(CodeMapping codeMapping) { Row row = codeMapping.sourceCode.toRow(); row.add("matchScore", codeMapping.matchScore); row.add("mappingStatus", codeMapping.mappingStatus.toString()); - row.add("conceptId", targetConcept.concept.conceptId); - row.add("mappingType", targetConcept.mappingType.toString()); row.add("statusSetBy", codeMapping.statusSetBy); row.add("statusSetOn", codeMapping.statusSetOn); + row.add("conceptId", targetConcept.concept.conceptId); + row.add("mappingType", targetConcept.mappingType.toString()); + row.add("comment", codeMapping.comment); row.add("createdBy", targetConcept.createdBy); row.add("createdOn", targetConcept.createdOn); - row.add("comment", codeMapping.comment); out.write(row); } } From cd1a3e5c1a2ed4a0f5bb7e74da0a6ae0a6827e06 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Mon, 5 Oct 2020 12:45:43 +0200 Subject: [PATCH 19/77] refactor ImportDialog --- src/org/ohdsi/usagi/ui/ImportDialog.java | 88 +++++++++--------------- 1 file changed, 34 insertions(+), 54 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/ImportDialog.java b/src/org/ohdsi/usagi/ui/ImportDialog.java index eb77ae8..ad25e73 100644 --- a/src/org/ohdsi/usagi/ui/ImportDialog.java +++ b/src/org/ohdsi/usagi/ui/ImportDialog.java @@ -15,12 +15,7 @@ ******************************************************************************/ package org.ohdsi.usagi.ui; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; +import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; @@ -191,64 +186,49 @@ private Component createColumnMappingPanel() { columnMappingPanel = new JPanel(); columnMappingPanel.setLayout(new GridBagLayout()); - GridBagConstraints c = new GridBagConstraints(); - c.fill = GridBagConstraints.BOTH; - - c.gridx = 0; - c.gridy = 0; - c.anchor = GridBagConstraints.WEST; - c.weightx = 1; - columnMappingPanel.add(new JLabel("Source code column"), c); - c.gridx = 1; - c.gridy = 0; - c.anchor = GridBagConstraints.EAST; - c.weightx = 0.1; + GridBagConstraints cLabel = new GridBagConstraints(); + cLabel.fill = GridBagConstraints.BOTH; + cLabel.gridx = 0; + cLabel.gridy = 1; + cLabel.anchor = GridBagConstraints.WEST; + cLabel.weightx = 1; + + GridBagConstraints cBox = new GridBagConstraints(); + cBox.fill = GridBagConstraints.BOTH; + cBox.gridx = 1; + cBox.gridy = 1; + cBox.anchor = GridBagConstraints.EAST; + cBox.weightx = 0.1; + + columnMappingPanel.add(new JLabel("Source code column"), cLabel); sourceCodeColumn = new JComboBox(comboBoxOptions); sourceCodeColumn.setToolTipText("The column containing the source code"); - columnMappingPanel.add(sourceCodeColumn, c); + columnMappingPanel.add(sourceCodeColumn, cBox); - c.gridx = 0; - c.gridy = 1; - c.anchor = GridBagConstraints.WEST; - c.weightx = 1; - columnMappingPanel.add(new JLabel("Source name column"), c); - c.gridx = 1; - c.gridy = 1; - c.anchor = GridBagConstraints.EAST; - c.weightx = 0.1; - sourceNameColumn = new JComboBox(comboBoxOptions); + cLabel.gridy++; + cBox.gridy++; + columnMappingPanel.add(new JLabel("Source name column"), cLabel); + sourceNameColumn = new JComboBox<>(comboBoxOptions); sourceNameColumn.setToolTipText("The column containing the name or description of the source code, which will be used for matching"); - columnMappingPanel.add(sourceNameColumn, c); + columnMappingPanel.add(sourceNameColumn, cBox); - c.gridx = 0; - c.gridy = 2; - c.anchor = GridBagConstraints.WEST; - c.weightx = 1; - columnMappingPanel.add(new JLabel("Source frequency column"), c); - c.gridx = 1; - c.gridy = 2; - c.anchor = GridBagConstraints.EAST; - c.weightx = 0.1; - sourceFrequencyColumn = new JComboBox(comboBoxOptions); + cLabel.gridy++; + cBox.gridy++; + columnMappingPanel.add(new JLabel("Source frequency column"), cLabel); + sourceFrequencyColumn = new JComboBox<>(comboBoxOptions); sourceFrequencyColumn.setToolTipText("The column containing the frequency of the code in the source database"); - columnMappingPanel.add(sourceFrequencyColumn, c); + columnMappingPanel.add(sourceFrequencyColumn, cBox); - c.gridx = 0; - c.gridy = 3; - c.anchor = GridBagConstraints.WEST; - c.weightx = 1; - conceptIdsOrAtc = new JComboBox(new String[] { CONCEPT_IDS, ATC }); - columnMappingPanel.add(conceptIdsOrAtc, c); - c.gridx = 1; - c.gridy = 3; - c.anchor = GridBagConstraints.EAST; - c.weightx = 0.1; - autoConceptIdColumn = new JComboBox(comboBoxOptions); + cLabel.gridy++; + cBox.gridy++; + conceptIdsOrAtc = new JComboBox<>(new String[] { CONCEPT_IDS, ATC }); + columnMappingPanel.add(conceptIdsOrAtc, cLabel); + autoConceptIdColumn = new JComboBox<>(comboBoxOptions); autoConceptIdColumn.setToolTipText("The column containing a (semicolon-delimited) list of concept IDs to which the search will be restricted"); - columnMappingPanel.add(autoConceptIdColumn, c); + columnMappingPanel.add(autoConceptIdColumn, cBox); - gridY = 4; + gridY = cLabel.gridy + 1; addExtraColumnMapping(); columnMappingScrollPane = new JScrollPane(columnMappingPanel); From bef371cc8a1c1ec39909f88b4e25347d1143428b Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Mon, 5 Oct 2020 12:51:33 +0200 Subject: [PATCH 20/77] read value code, value name and unit on import --- src/org/ohdsi/usagi/SourceCode.java | 11 +++++++- src/org/ohdsi/usagi/ui/ImportDialog.java | 33 ++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/org/ohdsi/usagi/SourceCode.java b/src/org/ohdsi/usagi/SourceCode.java index 3da47fc..19dca65 100644 --- a/src/org/ohdsi/usagi/SourceCode.java +++ b/src/org/ohdsi/usagi/SourceCode.java @@ -32,16 +32,22 @@ public class SourceCode { public String sourceCode; public String sourceName; + public String sourceValueCode; + public String sourceValueName; + public String sourceUnitName; public int sourceFrequency; public Set sourceAutoAssignedConceptIds = new HashSet(); public List> sourceAdditionalInfo = new ArrayList>(); - private static String ADDITIONAL_INFO_PREFIX = "ADD_INFO:"; + private final static String ADDITIONAL_INFO_PREFIX = "ADD_INFO:"; public Row toRow() { Row row = new Row(); row.add("sourceCode", sourceCode); row.add("sourceName", sourceName); + row.add("sourceValueCode", sourceValueCode); + row.add("sourceValueName", sourceValueName); + row.add("sourceUnitName", sourceUnitName); row.add("sourceFrequency", sourceFrequency); row.add("sourceAutoAssignedConceptIds", StringUtilities.join(sourceAutoAssignedConceptIds, ";")); for (Pair pair : sourceAdditionalInfo) { @@ -56,6 +62,9 @@ public SourceCode() { public SourceCode(Row row) { sourceCode = row.get("sourceCode"); sourceName = row.get("sourceName"); + sourceValueCode = row.get("sourceValueCode"); + sourceValueName = row.get("sourceValueName"); + sourceUnitName = row.get("sourceUnitName"); sourceFrequency = row.getInt("sourceFrequency"); sourceAutoAssignedConceptIds = parse(row.get("sourceAutoAssignedConceptIds")); for (String field : row.getFieldNames()) diff --git a/src/org/ohdsi/usagi/ui/ImportDialog.java b/src/org/ohdsi/usagi/ui/ImportDialog.java index ad25e73..83edc23 100644 --- a/src/org/ohdsi/usagi/ui/ImportDialog.java +++ b/src/org/ohdsi/usagi/ui/ImportDialog.java @@ -70,6 +70,9 @@ public class ImportDialog extends JDialog { private JComboBox sourceCodeColumn; private JComboBox sourceNameColumn; private JComboBox sourceFrequencyColumn; + private JComboBox sourceValueCodeColumn; + private JComboBox sourceValueNameColumn; + private JComboBox sourceUnitNameColumn; private JComboBox autoConceptIdColumn; private List> additionalInfoColumns = new ArrayList>(); private int gridY; @@ -220,6 +223,27 @@ private Component createColumnMappingPanel() { sourceFrequencyColumn.setToolTipText("The column containing the frequency of the code in the source database"); columnMappingPanel.add(sourceFrequencyColumn, cBox); + cLabel.gridy++; + cBox.gridy++; + columnMappingPanel.add(new JLabel("Value code column"), cLabel); + sourceValueCodeColumn = new JComboBox<>(comboBoxOptions); + sourceValueCodeColumn.setToolTipText("The column containing the value code"); + columnMappingPanel.add(sourceValueCodeColumn, cBox); + + cLabel.gridy++; + cBox.gridy++; + columnMappingPanel.add(new JLabel("Value name column "), cLabel); + sourceValueNameColumn = new JComboBox<>(comboBoxOptions); + sourceValueNameColumn.setToolTipText("The column containing the value name"); + columnMappingPanel.add(sourceValueNameColumn, cBox); + + cLabel.gridy++; + cBox.gridy++; + columnMappingPanel.add(new JLabel("Unit name column"), cLabel); + sourceUnitNameColumn = new JComboBox<>(comboBoxOptions); + sourceUnitNameColumn.setToolTipText("The column containing the name of the unit"); + columnMappingPanel.add(sourceUnitNameColumn, cBox); + cLabel.gridy++; cBox.gridy++; conceptIdsOrAtc = new JComboBox<>(new String[] { CONCEPT_IDS, ATC }); @@ -336,6 +360,9 @@ private List createSourceCodes() { int sourceCodeIndex = columnNames.indexOf(sourceCodeColumn.getSelectedItem().toString()); int sourceNameIndex = columnNames.indexOf(sourceNameColumn.getSelectedItem().toString()); int sourceFrequencyIndex = columnNames.indexOf(sourceFrequencyColumn.getSelectedItem().toString()); + int sourceValueCodeIndex = columnNames.indexOf(sourceValueCodeColumn.getSelectedItem().toString()); + int sourceValueNameIndex = columnNames.indexOf(sourceValueNameColumn.getSelectedItem().toString()); + int sourceUnitNameIndex = columnNames.indexOf(sourceUnitNameColumn.getSelectedItem().toString()); int sourceAutoIndex = columnNames.indexOf(autoConceptIdColumn.getSelectedItem().toString()); List additionalInfoIndexes = new ArrayList(); for (JComboBox additionalInfoColumn : additionalInfoColumns) { @@ -357,6 +384,12 @@ private List createSourceCodes() { sourceCode.sourceFrequency = Integer.parseInt(row.get(sourceFrequencyIndex)); else sourceCode.sourceFrequency = -1; + if (sourceValueCodeIndex != -1) + sourceCode.sourceValueCode = row.get(sourceValueCodeIndex); + if (sourceValueNameIndex != -1) + sourceCode.sourceValueName = row.get(sourceValueNameIndex); + if (sourceUnitNameIndex != -1) + sourceCode.sourceUnitName = row.get(sourceUnitNameIndex); if (sourceAutoIndex != -1) if (conceptIdsOrAtc.getSelectedItem().toString().equals(CONCEPT_IDS)) { for (String conceptId : row.get(sourceAutoIndex).split(";")) From cc2f99cae754b172a2924da9359c3061b92746c7 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Mon, 5 Oct 2020 13:01:30 +0200 Subject: [PATCH 21/77] display new source code attributes --- .../ohdsi/usagi/ui/MappingDetailPanel.java | 10 ++++- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 40 +++++++++++-------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index ba2d516..86fe88c 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -548,11 +548,11 @@ public void doSearch() { class SourceCodeTableModel extends AbstractTableModel { private static final long serialVersionUID = 169286268154988911L; - private String[] defaultColumnNames = { "Source code", "Source term", "Frequency" }; + private String[] defaultColumnNames = { "Source code", "Source term", "Frequency", "Value", "Value term", "Unit term" }; private String[] columnNames = defaultColumnNames; private CodeMapping codeMapping; private int addInfoColCount = 0; - private int ADD_INFO_START_COL = 3; + private int ADD_INFO_START_COL = 6; public int getColumnCount() { return columnNames.length; @@ -594,6 +594,12 @@ public Object getValueAt(int row, int col) { return codeMapping.sourceCode.sourceName; case 2: return codeMapping.sourceCode.sourceFrequency; + case 3: + return codeMapping.sourceCode.sourceValueCode; + case 4: + return codeMapping.sourceCode.sourceValueName; + case 5: + return codeMapping.sourceCode.sourceUnitName; default: return ""; } diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index be2acce..9680914 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -109,12 +109,12 @@ public MappingTablePanel() { class CodeMapTableModel extends AbstractTableModel { private static final long serialVersionUID = 169286268154988911L; - private String[] defaultColumnNames = { "Status", "Source code", "Source term", "Frequency", "Match score", "Concept ID", "Concept name", - "Domain", "Concept class", "Vocabulary", "Concept code", "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", - "Children", "Comment" }; + private String[] defaultColumnNames = { "Status", "Source code", "Source term", "Frequency", "Value", "Value term", "Unit term", + "Match score", "Concept ID", "Concept name", "Domain", "Concept class", "Vocabulary", "Concept code", + "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", "Children", "Comment" }; private String[] columnNames = defaultColumnNames; private int addInfoColCount = 0; - private int ADD_INFO_START_COL = 4; + private int ADD_INFO_START_COL = 7; public int getColumnCount() { return columnNames.length; @@ -176,32 +176,38 @@ public Object getValueAt(int row, int col) { case 3: return codeMapping.sourceCode.sourceFrequency == -1 ? "" : codeMapping.sourceCode.sourceFrequency; case 4: - return codeMapping.matchScore; + return codeMapping.sourceCode.sourceValueCode; case 5: - return targetConcept.conceptId; + return codeMapping.sourceCode.sourceValueName; case 6: - return targetConcept.conceptName; + return codeMapping.sourceCode.sourceUnitName; case 7: - return targetConcept.domainId; + return codeMapping.matchScore; case 8: - return targetConcept.conceptClassId; + return targetConcept.conceptId; case 9: - return targetConcept.vocabularyId; + return targetConcept.conceptName; case 10: - return targetConcept.conceptCode; + return targetConcept.domainId; case 11: - return targetConcept.validStartDate; + return targetConcept.conceptClassId; case 12: - return targetConcept.validEndDate; + return targetConcept.vocabularyId; case 13: - return targetConcept.invalidReason; + return targetConcept.conceptCode; case 14: - return targetConcept.standardConcept; + return targetConcept.validStartDate; case 15: - return targetConcept.parentCount; + return targetConcept.validEndDate; case 16: - return targetConcept.childCount; + return targetConcept.invalidReason; case 17: + return targetConcept.standardConcept; + case 18: + return targetConcept.parentCount; + case 19: + return targetConcept.childCount; + case 20: return codeMapping.comment; default: return ""; From c89b8ddc1759658d92c45a8e2a623759137997a5 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Mon, 5 Oct 2020 13:03:24 +0200 Subject: [PATCH 22/77] frequency at the end in source code panel --- src/org/ohdsi/usagi/ui/MappingDetailPanel.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 86fe88c..076616f 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -548,7 +548,7 @@ public void doSearch() { class SourceCodeTableModel extends AbstractTableModel { private static final long serialVersionUID = 169286268154988911L; - private String[] defaultColumnNames = { "Source code", "Source term", "Frequency", "Value", "Value term", "Unit term" }; + private String[] defaultColumnNames = { "Source code", "Source term", "Value", "Value term", "Unit term", "Frequency" }; private String[] columnNames = defaultColumnNames; private CodeMapping codeMapping; private int addInfoColCount = 0; @@ -593,13 +593,13 @@ public Object getValueAt(int row, int col) { case 1: return codeMapping.sourceCode.sourceName; case 2: - return codeMapping.sourceCode.sourceFrequency; - case 3: return codeMapping.sourceCode.sourceValueCode; - case 4: + case 3: return codeMapping.sourceCode.sourceValueName; - case 5: + case 4: return codeMapping.sourceCode.sourceUnitName; + case 5: + return codeMapping.sourceCode.sourceFrequency; default: return ""; } From b05afe85ef4c63d042257f8718336ff6b403bb9b Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Mon, 5 Oct 2020 13:10:26 +0200 Subject: [PATCH 23/77] allow auto querying by value or unit name --- .../ohdsi/usagi/ui/MappingDetailPanel.java | 37 +++++++++++++------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 076616f..cfbab30 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -73,7 +73,9 @@ public class MappingDetailPanel extends JPanel implements CodeSelectedListener, private JButton removeButton; private JButton replaceButton; private List addButtons; - private JRadioButton autoQueryButton; + private JRadioButton autoQueryCodeButton; + private JRadioButton autoQueryValueButton; + private JRadioButton autoQueryUnitButton; private JRadioButton manualQueryButton; private JTextField manualQueryField; private CodeMapping codeMapping; @@ -133,15 +135,17 @@ private Component createQueryPanel() { c.weightx = 0.1; c.gridwidth = 2; - autoQueryButton = new JRadioButton("Use source term as query", true); - autoQueryButton.addActionListener(new ActionListener() { + autoQueryCodeButton = new JRadioButton("Use source term as query", true); + autoQueryCodeButton.addActionListener(arg0 -> doSearch()); + panel.add(autoQueryCodeButton, c); - @Override - public void actionPerformed(ActionEvent arg0) { - doSearch(); - } - }); - panel.add(autoQueryButton, c); + autoQueryValueButton = new JRadioButton("Value as query", true); + autoQueryValueButton.addActionListener(arg0 -> doSearch()); + panel.add(autoQueryValueButton, c); + + autoQueryUnitButton = new JRadioButton("Unit as query", true); + autoQueryUnitButton.addActionListener(arg0 -> doSearch()); + panel.add(autoQueryUnitButton, c); c.gridx = 0; c.gridy = 1; @@ -158,7 +162,7 @@ public void actionPerformed(ActionEvent arg0) { panel.add(manualQueryButton, c); ButtonGroup buttonGroup = new ButtonGroup(); - buttonGroup.add(autoQueryButton); + buttonGroup.add(autoQueryCodeButton); buttonGroup.add(manualQueryButton); c.gridx = 1; @@ -521,9 +525,18 @@ public void run() { Vector filterDomains = null; if (filterPanel.getFilterByDomains()) filterDomains = filterPanel.getDomain(); - String query = manualQueryField.getText(); - if (autoQueryButton.isSelected()) + + String query; + if (autoQueryCodeButton.isSelected()) { query = codeMapping.sourceCode.sourceName; + } else if (autoQueryValueButton.isSelected()) { + query = codeMapping.sourceCode.sourceValueName; + } else if (autoQueryUnitButton.isSelected()) { + query = codeMapping.sourceCode.sourceUnitName; + } else { + query = manualQueryField.getText(); + } + boolean includeSourceConcepts = filterPanel.getIncludeSourceTerms(); if (Global.usagiSearchEngine.isOpenForSearching()) { From 92916a19a46474a3ecaa35090e71444374cdfb9b Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Mon, 5 Oct 2020 13:11:54 +0200 Subject: [PATCH 24/77] make value and unit fields optional in Usagi save file --- src/org/ohdsi/usagi/SourceCode.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/org/ohdsi/usagi/SourceCode.java b/src/org/ohdsi/usagi/SourceCode.java index 19dca65..3fd0efc 100644 --- a/src/org/ohdsi/usagi/SourceCode.java +++ b/src/org/ohdsi/usagi/SourceCode.java @@ -62,9 +62,12 @@ public SourceCode() { public SourceCode(Row row) { sourceCode = row.get("sourceCode"); sourceName = row.get("sourceName"); - sourceValueCode = row.get("sourceValueCode"); - sourceValueName = row.get("sourceValueName"); - sourceUnitName = row.get("sourceUnitName"); + if (row.getFieldNames().contains("sourceValueCode")) { + // Assume that if source value code exists, then other new fields as well + sourceValueCode = row.get("sourceValueCode"); + sourceValueName = row.get("sourceValueName"); + sourceUnitName = row.get("sourceUnitName"); + } sourceFrequency = row.getInt("sourceFrequency"); sourceAutoAssignedConceptIds = parse(row.get("sourceAutoAssignedConceptIds")); for (String field : row.getFieldNames()) From 396db8e62dc10059f4988a74d76717c8d08a6db7 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Mon, 5 Oct 2020 13:29:42 +0200 Subject: [PATCH 25/77] display term, value, unit toggle properly --- .../ohdsi/usagi/ui/MappingDetailPanel.java | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index cfbab30..34c3d7f 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -130,21 +130,23 @@ private Component createQueryPanel() { GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.WEST; - c.gridx = 0; + c.gridx = GridBagConstraints.RELATIVE; c.gridy = 0; c.weightx = 0.1; c.gridwidth = 2; - autoQueryCodeButton = new JRadioButton("Use source term as query", true); - autoQueryCodeButton.addActionListener(arg0 -> doSearch()); + panel.add(new JLabel("Use:"), c); + + autoQueryCodeButton = new JRadioButton("Term", true); + autoQueryCodeButton.addActionListener(x -> doSearch()); panel.add(autoQueryCodeButton, c); - autoQueryValueButton = new JRadioButton("Value as query", true); - autoQueryValueButton.addActionListener(arg0 -> doSearch()); + autoQueryValueButton = new JRadioButton("Value", false); + autoQueryValueButton.addActionListener(x -> doSearch()); panel.add(autoQueryValueButton, c); - autoQueryUnitButton = new JRadioButton("Unit as query", true); - autoQueryUnitButton.addActionListener(arg0 -> doSearch()); + autoQueryUnitButton = new JRadioButton("Unit", false); + autoQueryUnitButton.addActionListener(x -> doSearch()); panel.add(autoQueryUnitButton, c); c.gridx = 0; @@ -152,23 +154,19 @@ private Component createQueryPanel() { c.weightx = 0.1; c.gridwidth = 1; manualQueryButton = new JRadioButton("Query:", false); - manualQueryButton.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent arg0) { - doSearch(); - } - }); + manualQueryButton.addActionListener(x -> doSearch()); panel.add(manualQueryButton, c); ButtonGroup buttonGroup = new ButtonGroup(); buttonGroup.add(autoQueryCodeButton); + buttonGroup.add(autoQueryValueButton); + buttonGroup.add(autoQueryUnitButton); buttonGroup.add(manualQueryButton); c.gridx = 1; c.gridy = 1; c.weightx = 1; - c.gridwidth = 1; + c.gridwidth = GridBagConstraints.REMAINDER; manualQueryField = new JTextField(""); // manualQueryField.setPreferredSize(new Dimension(200, 5)); manualQueryField.getDocument().addDocumentListener(new DocumentListener() { From 9ce9245f46ed925ecf45c0841a9989ff7ca7f3f1 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Mon, 5 Oct 2020 13:47:57 +0200 Subject: [PATCH 26/77] flag button --- src/org/ohdsi/usagi/CodeMapping.java | 2 +- src/org/ohdsi/usagi/ui/Global.java | 1 + .../ohdsi/usagi/ui/MappingDetailPanel.java | 34 +++++++++++-- src/org/ohdsi/usagi/ui/UsagiMain.java | 2 + .../ohdsi/usagi/ui/actions/FlagAction.java | 49 +++++++++++++++++++ 5 files changed, 83 insertions(+), 5 deletions(-) create mode 100644 src/org/ohdsi/usagi/ui/actions/FlagAction.java diff --git a/src/org/ohdsi/usagi/CodeMapping.java b/src/org/ohdsi/usagi/CodeMapping.java index e609a5b..0f4c084 100644 --- a/src/org/ohdsi/usagi/CodeMapping.java +++ b/src/org/ohdsi/usagi/CodeMapping.java @@ -25,7 +25,7 @@ */ public class CodeMapping { public enum MappingStatus { - APPROVED, UNCHECKED, AUTO_MAPPED, AUTO_MAPPED_TO_1, INVALID_TARGET, IGNORED + APPROVED, UNCHECKED, AUTO_MAPPED, AUTO_MAPPED_TO_1, INVALID_TARGET, IGNORED, FLAGGED }; public SourceCode sourceCode; diff --git a/src/org/ohdsi/usagi/ui/Global.java b/src/org/ohdsi/usagi/ui/Global.java index a9c6adb..1df3950 100644 --- a/src/org/ohdsi/usagi/ui/Global.java +++ b/src/org/ohdsi/usagi/ui/Global.java @@ -45,6 +45,7 @@ public class Global { public static ApproveSelectedAction approveSelectedAction; public static IgnoreAction ignoreAction; public static IgnoreSelectedAction ignoreSelectedAction; + public static FlagAction flagAction; public static ClearSelectedAction clearSelectedAction; public static ConceptInformationAction conceptInfoAction; public static AthenaAction athenaAction; diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index ba2d516..2f5e900 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -69,6 +69,7 @@ public class MappingDetailPanel extends JPanel implements CodeSelectedListener, private ConceptTableModel searchTableModel; private JButton approveButton; private JButton ignoreButton; + private JButton flagButton; private JTextField commentField; private JButton removeButton; private JButton replaceButton; @@ -269,6 +270,15 @@ public void actionPerformed(ActionEvent e) { private Component createApprovePanel() { JPanel panel = new JPanel(); panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); + + ignoreButton = new JButton(Global.ignoreAction); + ignoreButton.setBackground(new Color(151, 220, 141)); + panel.add(ignoreButton); + + flagButton = new JButton(Global.flagAction); + flagButton.setBackground(new Color(151, 220, 141)); + panel.add(flagButton); + panel.add(new JLabel("Comment:")); panel.add(Box.createHorizontalStrut(5)); @@ -304,10 +314,6 @@ public void changedUpdate(DocumentEvent arg0) { approveButton.setBackground(new Color(151, 220, 141)); panel.add(approveButton); - ignoreButton = new JButton(Global.ignoreAction); - ignoreButton.setBackground(new Color(151, 220, 141)); - panel.add(ignoreButton); - return panel; } @@ -385,6 +391,7 @@ public void codeSelected(CodeMapping codeMapping) { this.codeMapping = codeMapping; toggleApproveButton(); toggleIgnoreButton(); + toggleFlagButton(); sourceCodeTableModel.setMapping(codeMapping); targetConceptTableModel.setConcepts(codeMapping.targetConcepts); commentField.setText(codeMapping.comment); @@ -448,6 +455,25 @@ private void toggleIgnoreButton() { } } + public void flag() { + if (codeMapping.mappingStatus != CodeMapping.MappingStatus.FLAGGED) { + codeMapping.mappingStatus = MappingStatus.FLAGGED; + Global.mapping.fireDataChanged(APPROVE_EVENT); + } else { + codeMapping.mappingStatus = CodeMapping.MappingStatus.UNCHECKED; + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + toggleFlagButton(); + } + } + + private void toggleFlagButton() { + if (codeMapping.mappingStatus == MappingStatus.FLAGGED) { + Global.flagAction.setToUnflag(); + } else { + Global.flagAction.setToFlag(); + } + } + public void addConcept(Concept concept) { codeMapping.targetConcepts.add(new MappingTarget(concept)); for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { diff --git a/src/org/ohdsi/usagi/ui/UsagiMain.java b/src/org/ohdsi/usagi/ui/UsagiMain.java index d36746a..0bdddf5 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMain.java +++ b/src/org/ohdsi/usagi/ui/UsagiMain.java @@ -79,6 +79,7 @@ public UsagiMain(String[] args) { Global.saveAsAction = new SaveAsAction(); Global.approveAction = new ApproveAction(); Global.ignoreAction = new IgnoreAction(); + Global.flagAction = new FlagAction(); Global.conceptInfoAction = new ConceptInformationAction(); Global.athenaAction = new AthenaAction(); Global.googleSearchAction = new GoogleSearchAction(); @@ -97,6 +98,7 @@ public UsagiMain(String[] args) { Global.approveAction.setEnabled(false); Global.approveSelectedAction.setEnabled(false); Global.ignoreAction.setEnabled(false); + Global.flagAction.setEnabled(false); Global.ignoreSelectedAction.setEnabled(false); Global.clearSelectedAction = new ClearSelectedAction(); Global.clearSelectedAction.setEnabled(false); diff --git a/src/org/ohdsi/usagi/ui/actions/FlagAction.java b/src/org/ohdsi/usagi/ui/actions/FlagAction.java new file mode 100644 index 0000000..02dccb6 --- /dev/null +++ b/src/org/ohdsi/usagi/ui/actions/FlagAction.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright 2020 Observational Health Data Sciences and Informatics & The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ******************************************************************************/ +package org.ohdsi.usagi.ui.actions; + +import org.ohdsi.usagi.ui.Global; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; + +public class FlagAction extends AbstractAction { + + private static final long serialVersionUID = -395107404415936659L; + + public FlagAction() { + setToFlag(); + putValue(Action.MNEMONIC_KEY, KeyEvent.VK_F); + putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.ALT_MASK)); + } + + @Override + public void actionPerformed(ActionEvent arg0) { + Global.mappingDetailPanel.flag(); + } + + public void setToFlag() { + putValue(Action.NAME, "Flag"); + putValue(Action.SHORT_DESCRIPTION, "Flag this source code for further review"); + } + + public void setToUnflag() { + Global.ignoreAction.putValue(Action.NAME, "Unflag"); + Global.ignoreAction.putValue(Action.SHORT_DESCRIPTION, "Unflag this code"); + } +} From 649a29865f2b17f6404e649e8386215609077700 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Mon, 5 Oct 2020 15:43:54 +0200 Subject: [PATCH 27/77] toggle flag button upon ignore and approve --- .../ohdsi/usagi/ui/MappingDetailPanel.java | 64 +++++++++---------- .../ohdsi/usagi/ui/actions/FlagAction.java | 4 +- 2 files changed, 31 insertions(+), 37 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 2f5e900..4bb296c 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -389,9 +389,7 @@ public void actionPerformed(ActionEvent e) { @Override public void codeSelected(CodeMapping codeMapping) { this.codeMapping = codeMapping; - toggleApproveButton(); - toggleIgnoreButton(); - toggleFlagButton(); + toggleStatusButtons(); sourceCodeTableModel.setMapping(codeMapping); targetConceptTableModel.setConcepts(codeMapping.targetConcepts); commentField.setText(codeMapping.comment); @@ -415,19 +413,7 @@ public void approve() { } else { codeMapping.mappingStatus = CodeMapping.MappingStatus.UNCHECKED; Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - toggleApproveButton(); - } - } - - private void toggleApproveButton() { - if (codeMapping.mappingStatus == MappingStatus.APPROVED) { - Global.approveAction.setToUnapprove(); - approveButton.setBackground(new Color(220, 151, 141)); - ignoreButton.setEnabled(false); - } else { - Global.approveAction.setToApprove(); - approveButton.setBackground(new Color(151, 220, 141)); - ignoreButton.setEnabled(true); + toggleStatusButtons(); } } @@ -439,19 +425,7 @@ public void ignore() { } else { codeMapping.mappingStatus = CodeMapping.MappingStatus.UNCHECKED; Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - toggleIgnoreButton(); - } - } - - private void toggleIgnoreButton() { - if (codeMapping.mappingStatus == MappingStatus.IGNORED) { - Global.ignoreAction.setToUnignore(); - ignoreButton.setBackground(new Color(220, 151, 141)); - approveButton.setEnabled(false); - } else { - Global.ignoreAction.setToIgnore(); - ignoreButton.setBackground(new Color(151, 220, 141)); - approveButton.setEnabled(true); + toggleStatusButtons(); } } @@ -462,15 +436,35 @@ public void flag() { } else { codeMapping.mappingStatus = CodeMapping.MappingStatus.UNCHECKED; Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - toggleFlagButton(); + toggleStatusButtons(); } } - private void toggleFlagButton() { - if (codeMapping.mappingStatus == MappingStatus.FLAGGED) { - Global.flagAction.setToUnflag(); - } else { - Global.flagAction.setToFlag(); + private void toggleStatusButtons() { + Global.approveAction.setToApprove(); + Global.ignoreAction.setToIgnore(); + Global.flagAction.setToFlag(); + flagButton.setEnabled(false); + approveButton.setEnabled(false); + ignoreButton.setEnabled(false); + + switch(codeMapping.mappingStatus) { + case APPROVED: + Global.approveAction.setToUnapprove(); + approveButton.setEnabled(true); + break; + case IGNORED: + Global.ignoreAction.setToUnignore(); + ignoreButton.setEnabled(true); + break; + case FLAGGED: + Global.flagAction.setToUnflag(); + flagButton.setEnabled(true); + break; + default: + flagButton.setEnabled(true); + approveButton.setEnabled(true); + ignoreButton.setEnabled(true); } } diff --git a/src/org/ohdsi/usagi/ui/actions/FlagAction.java b/src/org/ohdsi/usagi/ui/actions/FlagAction.java index 02dccb6..b8bcca9 100644 --- a/src/org/ohdsi/usagi/ui/actions/FlagAction.java +++ b/src/org/ohdsi/usagi/ui/actions/FlagAction.java @@ -43,7 +43,7 @@ public void setToFlag() { } public void setToUnflag() { - Global.ignoreAction.putValue(Action.NAME, "Unflag"); - Global.ignoreAction.putValue(Action.SHORT_DESCRIPTION, "Unflag this code"); + putValue(Action.NAME, "Unflag"); + putValue(Action.SHORT_DESCRIPTION, "Unflag this code"); } } From 2dbd56c90c9a2c2ec20f8a6d90a1ff960dffcba9 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Mon, 5 Oct 2020 16:22:11 +0200 Subject: [PATCH 28/77] render flagged cells with red text --- .gitignore | 2 ++ src/org/ohdsi/usagi/ui/UsagiCellRenderer.java | 3 +++ 2 files changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index dd64606..8e09288 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,8 @@ DomainIds.txt VocabularyIds.txt vocabularyVersion.txt +local_files/ + ### Intellij ### # Created by https://www.gitignore.io/api/intellij # Edit at https://www.gitignore.io/?templates=intellij diff --git a/src/org/ohdsi/usagi/ui/UsagiCellRenderer.java b/src/org/ohdsi/usagi/ui/UsagiCellRenderer.java index 1fb30e8..173f3d3 100644 --- a/src/org/ohdsi/usagi/ui/UsagiCellRenderer.java +++ b/src/org/ohdsi/usagi/ui/UsagiCellRenderer.java @@ -101,6 +101,9 @@ else if (value == MappingStatus.IGNORED) if (aTable.getModel().getValueAt(modelRow, 0) == MappingStatus.IGNORED) { component.setForeground(Color.gray); } + if (aTable.getModel().getValueAt(modelRow, 0) == MappingStatus.FLAGGED) { + component.setForeground(Color.red); + } } return component; } From 5d3d7e92cd70cd3f178929c34e9e5307d3f9054a Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Mon, 5 Oct 2020 21:31:19 +0200 Subject: [PATCH 29/77] add comboBox to change mapping target type --- .../ohdsi/usagi/ui/MappingDetailPanel.java | 59 ++++++++++--------- .../usagi/ui/TargetConceptTableModel.java | 6 +- 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index ba2d516..1bbe756 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -32,18 +32,7 @@ import java.util.TimerTask; import java.util.Vector; -import javax.swing.BorderFactory; -import javax.swing.Box; -import javax.swing.BoxLayout; -import javax.swing.ButtonGroup; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JRadioButton; -import javax.swing.JScrollPane; -import javax.swing.JTable; -import javax.swing.JTextField; -import javax.swing.ListSelectionModel; +import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.table.AbstractTableModel; @@ -71,6 +60,7 @@ public class MappingDetailPanel extends JPanel implements CodeSelectedListener, private JButton ignoreButton; private JTextField commentField; private JButton removeButton; + private JComboBox typesChooser; private JButton replaceButton; private List addButtons; private JRadioButton autoQueryButton; @@ -342,13 +332,17 @@ private JPanel createTargetConceptsPanel() { int viewRow = targetConceptTable.getSelectedRow(); if (viewRow == -1 || codeMapping.mappingStatus == MappingStatus.APPROVED) { removeButton.setEnabled(false); + typesChooser.setEnabled(false); } else { removeButton.setEnabled(true); + typesChooser.setEnabled(true); int modelRow = targetConceptTable.convertRowIndexToModel(viewRow); + MappingTarget mappingTarget = targetConceptTableModel.getMappingTarget(modelRow); + typesChooser.setSelectedItem(mappingTarget.getMappingType()); Global.conceptInfoAction.setEnabled(true); - Global.conceptInformationDialog.setConcept(targetConceptTableModel.getConcept(modelRow)); + Global.conceptInformationDialog.setConcept(mappingTarget.concept); Global.athenaAction.setEnabled(true); - Global.athenaAction.setConcept(targetConceptTableModel.getConcept(modelRow)); + Global.athenaAction.setConcept(mappingTarget.concept); Global.googleSearchAction.setEnabled(false); } }); @@ -366,14 +360,19 @@ private JPanel createTargetConceptsPanel() { buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS)); buttonPanel.add(Box.createHorizontalGlue()); + typesChooser = new JComboBox<>(MappingTarget.Type.values()); + typesChooser.setToolTipText("Set type of the mapping"); + typesChooser.addActionListener(e -> { + if (((JComboBox)e.getSource()).hasFocus()) + changeTargetType(); + }); + typesChooser.setMaximumSize(typesChooser.getPreferredSize()); + typesChooser.setEnabled(false); + buttonPanel.add(typesChooser); + removeButton = new JButton("Remove concept"); removeButton.setToolTipText("Add selected concept"); - removeButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - remove(); - } - - }); + removeButton.addActionListener(e -> remove()); removeButton.setEnabled(false); buttonPanel.add(removeButton); panel.add(buttonPanel); @@ -485,17 +484,11 @@ public void replaceConcepts(Concept concept) { } private void remove() { - List rows = new ArrayList(); + List rows = new ArrayList<>(); for (int row : targetConceptTable.getSelectedRows()) rows.add(targetConceptTable.convertRowIndexToModel(row)); - Collections.sort(rows, new Comparator() { - - @Override - public int compare(Integer o1, Integer o2) { - return o2.compareTo(o1); - } - }); + rows.sort(Comparator.reverseOrder()); for (int row : rows) codeMapping.targetConcepts.remove(row); @@ -503,6 +496,16 @@ public int compare(Integer o1, Integer o2) { Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); } + private void changeTargetType() { + for (int row : targetConceptTable.getSelectedRows()) { + MappingTarget mappingTarget = codeMapping.targetConcepts.get(row); + mappingTarget.setMappingType((MappingTarget.Type) typesChooser.getSelectedItem()); + } + + targetConceptTableModel.fireTableDataChanged(); + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + } + private class SearchTask extends TimerTask { @Override diff --git a/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java b/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java index 055d399..c253d02 100644 --- a/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java +++ b/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java @@ -19,8 +19,12 @@ class TargetConceptTableModel extends AbstractTableModel { public TargetConceptTableModel() { } + public MappingTarget getMappingTarget(int row) { + return targetConcepts.get(row); + } + public Concept getConcept(int row) { - return targetConcepts.get(row).concept; + return getMappingTarget(row).concept; } public int getColumnCount() { From 87a2b1710361440ccc8d640e730c4b8991d6e50b Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Mon, 5 Oct 2020 21:32:43 +0200 Subject: [PATCH 30/77] rename mapping type regular to event --- src/org/ohdsi/usagi/MappingTarget.java | 4 ++-- src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java | 2 +- src/org/ohdsi/usagi/ui/MappingDetailPanel.java | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/org/ohdsi/usagi/MappingTarget.java b/src/org/ohdsi/usagi/MappingTarget.java index 1b5e56a..4823eb6 100644 --- a/src/org/ohdsi/usagi/MappingTarget.java +++ b/src/org/ohdsi/usagi/MappingTarget.java @@ -20,7 +20,7 @@ */ public class MappingTarget{ public enum Type { - REGULAR, VALUE, UNIT // Maybe also OPERATOR, TYPE, etc. + EVENT, VALUE, UNIT // Maybe also OPERATOR, TYPE, etc. }; public Concept concept; public Type mappingType; @@ -31,7 +31,7 @@ public MappingTarget(Concept concept, Type mappingType) { } public MappingTarget(Concept concept) { - this(concept, Type.REGULAR); + this(concept, Type.EVENT); } public Concept getConcept() { diff --git a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java index 8e1b68e..fb56c09 100644 --- a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java +++ b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java @@ -69,7 +69,7 @@ && new SourceCode(row).sourceName.equals(buffer.sourceCode.sourceName)) { Concept concept = Global.dbEngine.getConcept(row.getInt("conceptId")); // Older save files might not have a mappingType. - MappingTarget.Type mappingType = MappingTarget.Type.REGULAR; + MappingTarget.Type mappingType = MappingTarget.Type.EVENT; if (row.getFieldNames().contains("mappingType")) { mappingType = MappingTarget.Type.valueOf(row.get("mappingType")); } diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 1bbe756..da99f06 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -24,7 +24,6 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Set; @@ -235,7 +234,7 @@ public void actionPerformed(ActionEvent e) { JButton button; addButtons = new ArrayList<>(); for (MappingTarget.Type mappingType : MappingTarget.Type.values()) { - if (mappingType.equals(MappingTarget.Type.REGULAR)) { + if (mappingType.equals(MappingTarget.Type.EVENT)) { button = new JButton("Add concept"); } else { button = new JButton(String.format("Add %s concept", mappingType)); From 943800e6f1e23495ef9fb3c52508d1c448f042b3 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Tue, 6 Oct 2020 08:41:59 +0200 Subject: [PATCH 31/77] fix old regular type --- src/org/ohdsi/usagi/MappingTarget.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/ohdsi/usagi/MappingTarget.java b/src/org/ohdsi/usagi/MappingTarget.java index e894f3d..9aa0840 100644 --- a/src/org/ohdsi/usagi/MappingTarget.java +++ b/src/org/ohdsi/usagi/MappingTarget.java @@ -39,7 +39,7 @@ public MappingTarget(Concept concept) { } public MappingTarget(Concept concept, String createdBy) { - this(concept, Type.REGULAR, createdBy); + this(concept, Type.EVENT, createdBy); } public MappingTarget(Concept concept, Type mappingType, String createdBy) { From ebc1ea686bc8e1b75c4856e75b95abfa4528b7dc Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Tue, 6 Oct 2020 10:07:53 +0200 Subject: [PATCH 32/77] bump version --- src/org/ohdsi/usagi/ui/UsagiMain.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/ohdsi/usagi/ui/UsagiMain.java b/src/org/ohdsi/usagi/ui/UsagiMain.java index e60d50b..a605c3e 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMain.java +++ b/src/org/ohdsi/usagi/ui/UsagiMain.java @@ -41,7 +41,7 @@ */ public class UsagiMain implements ActionListener { - public static String version = "1.3.0"; + public static String version = "1.4.0-SNAPSHOT"; public static void main(String[] args) { new UsagiMain(args); From f16a84dab340bdb997c51c031554dd4248d591b7 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Mon, 26 Oct 2020 12:25:07 +0100 Subject: [PATCH 33/77] fix opening of file with value codes - sourcecode/value is unique --- src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java index 135fc81..c72611f 100644 --- a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java +++ b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java @@ -63,8 +63,10 @@ private void readNext() { } catch (Exception e) { buffer.comment = ""; } - while (row != null && new SourceCode(row).sourceCode.equals(buffer.sourceCode.sourceCode) - && new SourceCode(row).sourceName.equals(buffer.sourceCode.sourceName)) { + while (row != null + && new SourceCode(row).sourceCode.equals(buffer.sourceCode.sourceCode) + && new SourceCode(row).sourceName.equals(buffer.sourceCode.sourceName) // MM: is this needed? + && new SourceCode(row).sourceValueCode.equals(buffer.sourceCode.sourceValueCode)) { if (row.getInt("conceptId") != 0) { Concept concept = Global.dbEngine.getConcept(row.getInt("conceptId")); From 75e362dec4718ec49c8d48824dd4c5de7f48cc9e Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Thu, 22 Oct 2020 16:21:37 +0200 Subject: [PATCH 34/77] fix issue with loading provenance --- src/org/ohdsi/usagi/MappingTarget.java | 8 +++-- .../ohdsi/usagi/ReadCodeMappingsFromFile.java | 29 +++++++++++-------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/org/ohdsi/usagi/MappingTarget.java b/src/org/ohdsi/usagi/MappingTarget.java index 9aa0840..ed1763f 100644 --- a/src/org/ohdsi/usagi/MappingTarget.java +++ b/src/org/ohdsi/usagi/MappingTarget.java @@ -43,11 +43,15 @@ public MappingTarget(Concept concept, String createdBy) { } public MappingTarget(Concept concept, Type mappingType, String createdBy) { - this(concept, mappingType); + this.concept = concept; + this.mappingType = mappingType; this.createdBy = createdBy; } + public MappingTarget(Concept concept, Type mappingType, String createdBy, long createdOn) { - this(concept, mappingType, createdBy); + this.concept = concept; + this.mappingType = mappingType; + this.createdBy = createdBy; this.createdOn = createdOn; } diff --git a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java index c72611f..cb08af2 100644 --- a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java +++ b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java @@ -23,7 +23,7 @@ import org.ohdsi.utilities.files.Row; public class ReadCodeMappingsFromFile implements Iterable { - private String filename; + private final String filename; public ReadCodeMappingsFromFile(String filename) { this.filename = filename; @@ -36,9 +36,9 @@ public Iterator iterator() { public class RowIterator implements Iterator { - private Iterator iterator; - private CodeMapping buffer; - private Row row; + private Iterator iterator; + private CodeMapping buffer; + private Row row; public RowIterator() { iterator = new ReadCSVFileWithHeader(filename).iterator(); @@ -58,6 +58,11 @@ private void readNext() { buffer = new CodeMapping(new SourceCode(row)); buffer.matchScore = row.getDouble("matchScore"); buffer.mappingStatus = MappingStatus.valueOf(row.get("mappingStatus")); + + // Status provenance fields might not be available in older Usagi files + buffer.statusSetBy = row.get("statusSetBy", ""); + buffer.statusSetOn = row.getLong("statusSetOn", "0"); + try { buffer.comment = row.get("comment"); } catch (Exception e) { @@ -70,17 +75,18 @@ && new SourceCode(row).sourceValueCode.equals(buffer.sourceCode.sourceValueCode) if (row.getInt("conceptId") != 0) { Concept concept = Global.dbEngine.getConcept(row.getInt("conceptId")); - // Older save files might not have a mappingType. - MappingTarget.Type mappingType = MappingTarget.Type.EVENT; - if (row.getFieldNames().contains("mappingType")) { - mappingType = MappingTarget.Type.valueOf(row.get("mappingType")); - } - if (concept == null) { buffer.mappingStatus = MappingStatus.INVALID_TARGET; buffer.comment = "Invalid existing target: " + row.get("conceptId"); } else { - buffer.targetConcepts.add(new MappingTarget(concept, mappingType)); + // Type and provenance might not be available in older Usagi files + MappingTarget mappingTarget = new MappingTarget( + concept, + MappingTarget.Type.valueOf(row.get("mappingType", "EVENT")), + row.get("createdBy", ""), + row.getLong("createdOn", "0") + ); + buffer.targetConcepts.add(mappingTarget); } } if (iterator.hasNext()) @@ -107,6 +113,5 @@ public CodeMapping next() { public void remove() { throw new RuntimeException("Remove not supported"); } - } } From 437e231d77ad9e4ef37db19c532e3fd3551866b2 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Thu, 22 Oct 2020 19:32:14 +0200 Subject: [PATCH 35/77] save empty target without creation date --- src/org/ohdsi/usagi/MappingTarget.java | 14 ++++++-------- src/org/ohdsi/usagi/WriteCodeMappingsToFile.java | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/org/ohdsi/usagi/MappingTarget.java b/src/org/ohdsi/usagi/MappingTarget.java index ed1763f..4e08e7c 100644 --- a/src/org/ohdsi/usagi/MappingTarget.java +++ b/src/org/ohdsi/usagi/MappingTarget.java @@ -28,14 +28,11 @@ public enum Type { public String createdBy; public long createdOn; - public MappingTarget(Concept concept, Type mappingType) { - this.concept = concept; - this.mappingType = mappingType; - this.createdOn = System.currentTimeMillis(); - } - - public MappingTarget(Concept concept) { - this(concept, Type.EVENT); + public MappingTarget() { + this.concept = Concept.createEmptyConcept(); + this.mappingType = Type.EVENT; + this.createdBy = ""; + this.createdOn = 0; } public MappingTarget(Concept concept, String createdBy) { @@ -46,6 +43,7 @@ public MappingTarget(Concept concept, Type mappingType, String createdBy) { this.concept = concept; this.mappingType = mappingType; this.createdBy = createdBy; + this.createdOn = System.currentTimeMillis(); } public MappingTarget(Concept concept, Type mappingType, String createdBy, long createdOn) { diff --git a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java index d4a28d2..92a5735 100644 --- a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java +++ b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java @@ -35,7 +35,7 @@ public void write(CodeMapping codeMapping) { List mappingTargets; if (codeMapping.targetConcepts.size() == 0) { mappingTargets = new ArrayList<>(1); - mappingTargets.add(new MappingTarget(Concept.createEmptyConcept())); + mappingTargets.add(new MappingTarget()); } else mappingTargets = codeMapping.targetConcepts; for (MappingTarget targetConcept : mappingTargets) { From 29e55f146bd89b4d84496c6b1605ad89c65860c7 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Mon, 26 Oct 2020 10:31:00 +0100 Subject: [PATCH 36/77] escape quote in csv with two quotes --- src/org/ohdsi/utilities/files/ReadCSVFile.java | 1 + src/org/ohdsi/utilities/files/WriteCSVFile.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/org/ohdsi/utilities/files/ReadCSVFile.java b/src/org/ohdsi/utilities/files/ReadCSVFile.java index f60713b..f768db0 100644 --- a/src/org/ohdsi/utilities/files/ReadCSVFile.java +++ b/src/org/ohdsi/utilities/files/ReadCSVFile.java @@ -146,6 +146,7 @@ private List line2columns(String line) { String column = columns.get(i); if (column.startsWith("\"") && column.endsWith("\"") && column.length() > 1) column = column.substring(1, column.length() - 1); + column = column.replace("\"\"", "\""); column = column.replace("\\\"", "\""); column = column.replaceAll("\\\\\\\\", "\\\\"); columns.set(i, column); diff --git a/src/org/ohdsi/utilities/files/WriteCSVFile.java b/src/org/ohdsi/utilities/files/WriteCSVFile.java index f16b7d9..b1c5150 100644 --- a/src/org/ohdsi/utilities/files/WriteCSVFile.java +++ b/src/org/ohdsi/utilities/files/WriteCSVFile.java @@ -90,7 +90,7 @@ public String columns2line(List columns) { boolean hasQuotes = column.contains("\""); column = column.replaceAll("\\\\", "\\\\\\\\"); if (hasQuotes) - column = column.replaceAll("\"", "\\\\\""); + column = column.replaceAll("\"", "\"\""); column = column.replaceAll("\r", ""); column = column.replaceAll("\n", "\\\\n"); if (hasQuotes || column.contains(Character.toString(delimiter))) From 389e7c00588f49a1d4dbb883d54ad297ca509b70 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Sun, 24 Jan 2021 18:52:38 +0100 Subject: [PATCH 37/77] bump snapshot version --- src/org/ohdsi/usagi/ui/UsagiMain.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/ohdsi/usagi/ui/UsagiMain.java b/src/org/ohdsi/usagi/ui/UsagiMain.java index f59ef28..9d23bb3 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMain.java +++ b/src/org/ohdsi/usagi/ui/UsagiMain.java @@ -41,7 +41,7 @@ */ public class UsagiMain implements ActionListener { - public static String version = "1.3.0"; + public static String version = "1.4.0-Snapshot"; public static void main(String[] args) { new UsagiMain(args); From 1895a1bf033da2d5f20d80fdf24a7f1f749216ad Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Sun, 24 Jan 2021 21:43:33 +0100 Subject: [PATCH 38/77] Hide mapping type ui elements --- src/org/ohdsi/usagi/ui/ImportDialog.java | 41 ++++++++++--------- .../ohdsi/usagi/ui/MappingDetailPanel.java | 18 +++++--- 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/ImportDialog.java b/src/org/ohdsi/usagi/ui/ImportDialog.java index 7414cf8..fede2da 100644 --- a/src/org/ohdsi/usagi/ui/ImportDialog.java +++ b/src/org/ohdsi/usagi/ui/ImportDialog.java @@ -223,26 +223,27 @@ private Component createColumnMappingPanel() { sourceFrequencyColumn.setToolTipText("The column containing the frequency of the code in the source database"); columnMappingPanel.add(sourceFrequencyColumn, cBox); - cLabel.gridy++; - cBox.gridy++; - columnMappingPanel.add(new JLabel("Value code column"), cLabel); - sourceValueCodeColumn = new JComboBox<>(comboBoxOptions); - sourceValueCodeColumn.setToolTipText("The column containing the value code"); - columnMappingPanel.add(sourceValueCodeColumn, cBox); - - cLabel.gridy++; - cBox.gridy++; - columnMappingPanel.add(new JLabel("Value name column "), cLabel); - sourceValueNameColumn = new JComboBox<>(comboBoxOptions); - sourceValueNameColumn.setToolTipText("The column containing the value name"); - columnMappingPanel.add(sourceValueNameColumn, cBox); - - cLabel.gridy++; - cBox.gridy++; - columnMappingPanel.add(new JLabel("Unit name column"), cLabel); - sourceUnitNameColumn = new JComboBox<>(comboBoxOptions); - sourceUnitNameColumn.setToolTipText("The column containing the name of the unit"); - columnMappingPanel.add(sourceUnitNameColumn, cBox); +// Hide mapping type +// cLabel.gridy++; +// cBox.gridy++; +// columnMappingPanel.add(new JLabel("Value code column"), cLabel); +// sourceValueCodeColumn = new JComboBox<>(comboBoxOptions); +// sourceValueCodeColumn.setToolTipText("The column containing the value code"); +// columnMappingPanel.add(sourceValueCodeColumn, cBox); +// +// cLabel.gridy++; +// cBox.gridy++; +// columnMappingPanel.add(new JLabel("Value name column "), cLabel); +// sourceValueNameColumn = new JComboBox<>(comboBoxOptions); +// sourceValueNameColumn.setToolTipText("The column containing the value name"); +// columnMappingPanel.add(sourceValueNameColumn, cBox); +// +// cLabel.gridy++; +// cBox.gridy++; +// columnMappingPanel.add(new JLabel("Unit name column"), cLabel); +// sourceUnitNameColumn = new JComboBox<>(comboBoxOptions); +// sourceUnitNameColumn.setToolTipText("The column containing the name of the unit"); +// columnMappingPanel.add(sourceUnitNameColumn, cBox); cLabel.gridy++; cBox.gridy++; diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index cfb3d25..f61fb23 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -125,19 +125,21 @@ private Component createQueryPanel() { c.weightx = 0.1; c.gridwidth = 2; - panel.add(new JLabel("Use:"), c); +// panel.add(new JLabel("Use:"), c); - autoQueryCodeButton = new JRadioButton("Term", true); + autoQueryCodeButton = new JRadioButton("Use source term", true); autoQueryCodeButton.addActionListener(x -> doSearch()); panel.add(autoQueryCodeButton, c); autoQueryValueButton = new JRadioButton("Value", false); autoQueryValueButton.addActionListener(x -> doSearch()); - panel.add(autoQueryValueButton, c); +// Hide other types +// panel.add(autoQueryValueButton, c); autoQueryUnitButton = new JRadioButton("Unit", false); autoQueryUnitButton.addActionListener(x -> doSearch()); - panel.add(autoQueryUnitButton, c); +// Hide other types +// panel.add(autoQueryUnitButton, c); c.gridx = 0; c.gridy = 1; @@ -240,7 +242,9 @@ public void actionPerformed(ActionEvent e) { if (mappingType.equals(MappingTarget.Type.EVENT)) { button = new JButton("Add concept"); } else { - button = new JButton(String.format("Add %s concept", mappingType)); +// Hide other (value, unit) mapping types +// button = new JButton(String.format("Add %s concept", mappingType)); + continue; } button.setToolTipText(String.format("Add selected concept as %s", mappingType)); button.addActionListener(e -> { @@ -353,6 +357,7 @@ private JPanel createTargetConceptsPanel() { Global.googleSearchAction.setEnabled(false); } }); + targetConceptTable.hideColumn("Mapping Type"); // Hide mapping types targetConceptTable.hideColumn("Valid start date"); targetConceptTable.hideColumn("Valid end date"); targetConceptTable.hideColumn("Invalid reason"); @@ -375,7 +380,8 @@ private JPanel createTargetConceptsPanel() { }); typesChooser.setMaximumSize(typesChooser.getPreferredSize()); typesChooser.setEnabled(false); - buttonPanel.add(typesChooser); +// Hide type chooser, only event type +// buttonPanel.add(typesChooser); removeButton = new JButton("Remove concept"); removeButton.setToolTipText("Add selected concept"); From e8f34f632feba4b83357234e5a535462a1267521 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Sun, 7 Feb 2021 20:57:56 +0100 Subject: [PATCH 39/77] model for review status and unfunctional review buttons --- src/org/ohdsi/usagi/CodeMapping.java | 12 ++++++ src/org/ohdsi/usagi/ui/Global.java | 1 + .../ohdsi/usagi/ui/MappingDetailPanel.java | 17 +++++++++ .../ohdsi/usagi/ui/actions/ReviewAction.java | 38 +++++++++++++++++++ 4 files changed, 68 insertions(+) create mode 100644 src/org/ohdsi/usagi/ui/actions/ReviewAction.java diff --git a/src/org/ohdsi/usagi/CodeMapping.java b/src/org/ohdsi/usagi/CodeMapping.java index f89edd2..4add73c 100644 --- a/src/org/ohdsi/usagi/CodeMapping.java +++ b/src/org/ohdsi/usagi/CodeMapping.java @@ -27,14 +27,20 @@ public class CodeMapping { public enum MappingStatus { APPROVED, UNCHECKED, AUTO_MAPPED, AUTO_MAPPED_TO_1, INVALID_TARGET, IGNORED, FLAGGED }; + public enum ReviewStatus { + IDENTICAL, MAPPED_UP, MAPPED_DOWN, UNREVIEWED + }; public SourceCode sourceCode; public double matchScore; public MappingStatus mappingStatus; + public ReviewStatus reviewStatus; public List targetConcepts = new ArrayList<>(1); public String comment; public String statusSetBy; public long statusSetOn; + public String reviewedBy; + public long reviewedOn; public CodeMapping(SourceCode sourceCode) { this.sourceCode = sourceCode; @@ -59,4 +65,10 @@ public void approve(String approvedBy) { public void ignore(String ignoredBy) { setStatus(MappingStatus.IGNORED, ignoredBy); } + + public void setReviewStatus(ReviewStatus reviewStatus, String author) { + this.reviewStatus = reviewStatus; + this.reviewedOn = System.currentTimeMillis(); + this.reviewedBy = author; + } } diff --git a/src/org/ohdsi/usagi/ui/Global.java b/src/org/ohdsi/usagi/ui/Global.java index 96a7620..8a27543 100644 --- a/src/org/ohdsi/usagi/ui/Global.java +++ b/src/org/ohdsi/usagi/ui/Global.java @@ -46,6 +46,7 @@ public class Global { public static IgnoreAction ignoreAction; public static IgnoreSelectedAction ignoreSelectedAction; public static FlagAction flagAction; + public static ReviewAction reviewAction; public static ClearSelectedAction clearSelectedAction; public static ConceptInformationAction conceptInfoAction; public static AthenaAction athenaAction; diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index f61fb23..81506a9 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -58,6 +58,9 @@ public class MappingDetailPanel extends JPanel implements CodeSelectedListener, private JButton approveButton; private JButton ignoreButton; private JButton flagButton; + private JButton reviewIdenticalButton; + private JButton mapUpButton; + private JButton mapDownButton; private JTextField commentField; private JButton removeButton; private JComboBox typesChooser; @@ -274,6 +277,20 @@ private Component createApprovePanel() { flagButton.setBackground(new Color(151, 220, 141)); panel.add(flagButton); + panel.add(new JLabel("Review:")); + + reviewIdenticalButton = new JButton("Identical"); + reviewIdenticalButton.setBackground(new Color(151, 220, 141)); + panel.add(reviewIdenticalButton); + + mapUpButton = new JButton("Mapped Up"); + mapUpButton.setBackground(new Color(151, 220, 141)); + panel.add(mapUpButton); + + mapDownButton = new JButton("Mapped Down"); + mapDownButton.setBackground(new Color(151, 220, 141)); + panel.add(mapDownButton); + panel.add(new JLabel("Comment:")); panel.add(Box.createHorizontalStrut(5)); diff --git a/src/org/ohdsi/usagi/ui/actions/ReviewAction.java b/src/org/ohdsi/usagi/ui/actions/ReviewAction.java new file mode 100644 index 0000000..d71587a --- /dev/null +++ b/src/org/ohdsi/usagi/ui/actions/ReviewAction.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright 2020 Observational Health Data Sciences and Informatics & The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ******************************************************************************/ +package org.ohdsi.usagi.ui.actions; + +import org.ohdsi.usagi.ui.Global; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; + +public class ReviewAction extends AbstractAction { + + private static final long serialVersionUID = 2081755360857938731L; + + public ReviewAction() { + // TBD + } + + @Override + public void actionPerformed(ActionEvent arg0) { + // TBD + } + +} From 542f819847ab164f095d034b9583aab25d064a89 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Sun, 7 Feb 2021 20:59:50 +0100 Subject: [PATCH 40/77] hide ignore button and move flag button --- src/org/ohdsi/usagi/ui/MappingDetailPanel.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 81506a9..2412648 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -269,14 +269,6 @@ private Component createApprovePanel() { JPanel panel = new JPanel(); panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); - ignoreButton = new JButton(Global.ignoreAction); - ignoreButton.setBackground(new Color(151, 220, 141)); - panel.add(ignoreButton); - - flagButton = new JButton(Global.flagAction); - flagButton.setBackground(new Color(151, 220, 141)); - panel.add(flagButton); - panel.add(new JLabel("Review:")); reviewIdenticalButton = new JButton("Identical"); @@ -322,6 +314,14 @@ public void changedUpdate(DocumentEvent arg0) { panel.add(Box.createHorizontalStrut(5)); + ignoreButton = new JButton(Global.ignoreAction); + ignoreButton.setBackground(new Color(151, 220, 141)); +// panel.add(ignoreButton); + + flagButton = new JButton(Global.flagAction); + flagButton.setBackground(new Color(151, 220, 141)); + panel.add(flagButton); + approveButton = new JButton(Global.approveAction); approveButton.setBackground(new Color(151, 220, 141)); panel.add(approveButton); From b5e765d0ce5a92ab455fbeb37d3f9ea212dad60b Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Mon, 8 Feb 2021 09:54:36 +0100 Subject: [PATCH 41/77] fix. do not require the sourceValueCode column --- src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java index cb08af2..410b424 100644 --- a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java +++ b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java @@ -71,7 +71,8 @@ private void readNext() { while (row != null && new SourceCode(row).sourceCode.equals(buffer.sourceCode.sourceCode) && new SourceCode(row).sourceName.equals(buffer.sourceCode.sourceName) // MM: is this needed? - && new SourceCode(row).sourceValueCode.equals(buffer.sourceCode.sourceValueCode)) { + && (new SourceCode(row).sourceValueCode != null + && new SourceCode(row).sourceValueCode.equals(buffer.sourceCode.sourceValueCode))) { if (row.getInt("conceptId") != 0) { Concept concept = Global.dbEngine.getConcept(row.getInt("conceptId")); From ebb97d09353ea8ebc9604bf1e5a616e7a56c2f01 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Tue, 9 Feb 2021 11:41:33 +0100 Subject: [PATCH 42/77] hide value and unit columns --- src/org/ohdsi/usagi/ui/MappingDetailPanel.java | 9 +++++---- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 3 +++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 2412648..92bf472 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -344,6 +344,11 @@ private JPanel createSourceCodePanel() { pane.setMinimumSize(new Dimension(500, 40)); pane.setPreferredSize(new Dimension(500, 40)); panel.add(pane); + + sourceCodeTable.hideColumn("Value"); + sourceCodeTable.hideColumn("Value term"); + sourceCodeTable.hideColumn("Unit term"); + return panel; } @@ -668,10 +673,6 @@ public Class getColumnClass(int col) { return String.class; } else { switch (col) { - case 0: - return String.class; - case 1: - return String.class; case 2: return Integer.class; default: diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 875eebf..6622c74 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -100,6 +100,9 @@ public MappingTablePanel() { table.hideColumn("Valid start date"); table.hideColumn("Valid end date"); table.hideColumn("Invalid reason"); + table.hideColumn("Value"); + table.hideColumn("Value term"); + table.hideColumn("Unit term"); JScrollPane scrollPane = new JScrollPane(table); add(scrollPane); From 883069be7ed290ad9bb62f05d5d5f3e8d0266eda Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Tue, 9 Feb 2021 12:05:55 +0100 Subject: [PATCH 43/77] fix reading of sourceValueCode if not given --- src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java index 410b424..46d9f37 100644 --- a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java +++ b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java @@ -71,8 +71,8 @@ private void readNext() { while (row != null && new SourceCode(row).sourceCode.equals(buffer.sourceCode.sourceCode) && new SourceCode(row).sourceName.equals(buffer.sourceCode.sourceName) // MM: is this needed? - && (new SourceCode(row).sourceValueCode != null - && new SourceCode(row).sourceValueCode.equals(buffer.sourceCode.sourceValueCode))) { + && (new SourceCode(row).sourceValueCode == null + || new SourceCode(row).sourceValueCode.equals(buffer.sourceCode.sourceValueCode))) { if (row.getInt("conceptId") != 0) { Concept concept = Global.dbEngine.getConcept(row.getInt("conceptId")); From c894107d82675e40f6dc49458b02a336fc6fedf7 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Tue, 9 Feb 2021 12:18:35 +0100 Subject: [PATCH 44/77] functional review button --- src/org/ohdsi/usagi/CodeMapping.java | 2 +- .../ohdsi/usagi/ui/MappingDetailPanel.java | 31 +++++++++++++------ src/org/ohdsi/usagi/ui/MappingTablePanel.java | 6 ++-- src/org/ohdsi/usagi/ui/UsagiMain.java | 1 + .../ohdsi/usagi/ui/actions/ReviewAction.java | 5 +-- 5 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/org/ohdsi/usagi/CodeMapping.java b/src/org/ohdsi/usagi/CodeMapping.java index 4add73c..99b0ad8 100644 --- a/src/org/ohdsi/usagi/CodeMapping.java +++ b/src/org/ohdsi/usagi/CodeMapping.java @@ -28,7 +28,7 @@ public enum MappingStatus { APPROVED, UNCHECKED, AUTO_MAPPED, AUTO_MAPPED_TO_1, INVALID_TARGET, IGNORED, FLAGGED }; public enum ReviewStatus { - IDENTICAL, MAPPED_UP, MAPPED_DOWN, UNREVIEWED + IDENTICAL, UP, DOWN }; public SourceCode sourceCode; diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 92bf472..3002cca 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -58,6 +58,7 @@ public class MappingDetailPanel extends JPanel implements CodeSelectedListener, private JButton approveButton; private JButton ignoreButton; private JButton flagButton; + private JComboBox reviewOptionChooser; private JButton reviewIdenticalButton; private JButton mapUpButton; private JButton mapDownButton; @@ -271,17 +272,23 @@ private Component createApprovePanel() { panel.add(new JLabel("Review:")); - reviewIdenticalButton = new JButton("Identical"); + reviewOptionChooser = new JComboBox<>(CodeMapping.ReviewStatus.values()); + reviewOptionChooser.setToolTipText("Choose review type"); + reviewOptionChooser.setMaximumSize(reviewOptionChooser.getPreferredSize()); + reviewOptionChooser.setEnabled(true); + panel.add(reviewOptionChooser); + + reviewIdenticalButton = new JButton(Global.reviewAction); reviewIdenticalButton.setBackground(new Color(151, 220, 141)); panel.add(reviewIdenticalButton); - - mapUpButton = new JButton("Mapped Up"); - mapUpButton.setBackground(new Color(151, 220, 141)); - panel.add(mapUpButton); - - mapDownButton = new JButton("Mapped Down"); - mapDownButton.setBackground(new Color(151, 220, 141)); - panel.add(mapDownButton); +// +// mapUpButton = new JButton("Mapped Up"); +// mapUpButton.setBackground(new Color(151, 220, 141)); +// panel.add(mapUpButton); +// +// mapDownButton = new JButton("Mapped Down"); +// mapDownButton.setBackground(new Color(151, 220, 141)); +// panel.add(mapDownButton); panel.add(new JLabel("Comment:")); @@ -496,6 +503,12 @@ private void toggleStatusButtons() { } } + public void review() { + CodeMapping.ReviewStatus reviewStatusToApply = (CodeMapping.ReviewStatus) reviewOptionChooser.getSelectedItem(); + codeMapping.setReviewStatus(reviewStatusToApply, Global.author); + Global.mapping.fireDataChanged(APPROVE_EVENT); + } + public void addConcept(Concept concept) { codeMapping.targetConcepts.add(new MappingTarget(concept, Global.author)); for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 6622c74..5b35130 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -115,7 +115,7 @@ class CodeMapTableModel extends AbstractTableModel { private String[] defaultColumnNames = { "Status", "Source code", "Source term", "Frequency", "Value", "Value term", "Unit term", "Match score", "Concept ID", "Concept name", "Domain", "Concept class", "Vocabulary", "Concept code", - "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", "Children", "Comment", "Status Provenance" }; + "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", "Children", "Review", "Comment", "Status Provenance" }; private String[] columnNames = defaultColumnNames; private int addInfoColCount = 0; private int ADD_INFO_START_COL = 7; @@ -212,8 +212,10 @@ public Object getValueAt(int row, int col) { case 19: return targetConcept.childCount; case 20: - return codeMapping.comment; + return codeMapping.reviewStatus; case 21: + return codeMapping.comment; + case 22: if (codeMapping.statusSetOn != 0L) { return String.format("%s (%tF)", codeMapping.statusSetBy, codeMapping.statusSetOn); } diff --git a/src/org/ohdsi/usagi/ui/UsagiMain.java b/src/org/ohdsi/usagi/ui/UsagiMain.java index a605c3e..5bfbf3b 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMain.java +++ b/src/org/ohdsi/usagi/ui/UsagiMain.java @@ -81,6 +81,7 @@ public UsagiMain(String[] args) { Global.approveAction = new ApproveAction(); Global.ignoreAction = new IgnoreAction(); Global.flagAction = new FlagAction(); + Global.reviewAction = new ReviewAction(); Global.conceptInfoAction = new ConceptInformationAction(); Global.athenaAction = new AthenaAction(); Global.googleSearchAction = new GoogleSearchAction(); diff --git a/src/org/ohdsi/usagi/ui/actions/ReviewAction.java b/src/org/ohdsi/usagi/ui/actions/ReviewAction.java index d71587a..967877c 100644 --- a/src/org/ohdsi/usagi/ui/actions/ReviewAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ReviewAction.java @@ -27,12 +27,13 @@ public class ReviewAction extends AbstractAction { private static final long serialVersionUID = 2081755360857938731L; public ReviewAction() { - // TBD + putValue(Action.NAME, "Review"); + putValue(Action.SHORT_DESCRIPTION, "Add a review of the mapping"); } @Override public void actionPerformed(ActionEvent arg0) { - // TBD + Global.mappingDetailPanel.review(); } } From d8a9a250caa6d82960e967475c16de680f4c17c8 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Tue, 9 Feb 2021 12:36:02 +0100 Subject: [PATCH 45/77] read and write review status --- src/org/ohdsi/usagi/CodeMapping.java | 2 +- src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java | 6 +++++- src/org/ohdsi/usagi/WriteCodeMappingsToFile.java | 6 +++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/org/ohdsi/usagi/CodeMapping.java b/src/org/ohdsi/usagi/CodeMapping.java index 99b0ad8..4995500 100644 --- a/src/org/ohdsi/usagi/CodeMapping.java +++ b/src/org/ohdsi/usagi/CodeMapping.java @@ -28,7 +28,7 @@ public enum MappingStatus { APPROVED, UNCHECKED, AUTO_MAPPED, AUTO_MAPPED_TO_1, INVALID_TARGET, IGNORED, FLAGGED }; public enum ReviewStatus { - IDENTICAL, UP, DOWN + IDENTICAL, UP, DOWN, UNREVIEWED }; public SourceCode sourceCode; diff --git a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java index 46d9f37..5de764b 100644 --- a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java +++ b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java @@ -18,6 +18,7 @@ import java.util.Iterator; import org.ohdsi.usagi.CodeMapping.MappingStatus; +import org.ohdsi.usagi.CodeMapping.ReviewStatus; import org.ohdsi.usagi.ui.Global; import org.ohdsi.utilities.files.ReadCSVFileWithHeader; import org.ohdsi.utilities.files.Row; @@ -59,9 +60,12 @@ private void readNext() { buffer.matchScore = row.getDouble("matchScore"); buffer.mappingStatus = MappingStatus.valueOf(row.get("mappingStatus")); - // Status provenance fields might not be available in older Usagi files + // Status provenance and review need a default as these fields might not be available in older Usagi files buffer.statusSetBy = row.get("statusSetBy", ""); buffer.statusSetOn = row.getLong("statusSetOn", "0"); + buffer.reviewStatus = ReviewStatus.valueOf(row.get("reviewStatus", "UNREVIEWED")); + buffer.reviewedBy = row.get("reviewedBy", ""); + buffer.reviewedOn = row.getLong("reviewedOn", "0"); try { buffer.comment = row.get("comment"); diff --git a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java index 92a5735..fb8d709 100644 --- a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java +++ b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java @@ -36,8 +36,9 @@ public void write(CodeMapping codeMapping) { if (codeMapping.targetConcepts.size() == 0) { mappingTargets = new ArrayList<>(1); mappingTargets.add(new MappingTarget()); - } else + } else { mappingTargets = codeMapping.targetConcepts; + } for (MappingTarget targetConcept : mappingTargets) { Row row = codeMapping.sourceCode.toRow(); row.add("matchScore", codeMapping.matchScore); @@ -49,6 +50,9 @@ public void write(CodeMapping codeMapping) { row.add("comment", codeMapping.comment); row.add("createdBy", targetConcept.createdBy); row.add("createdOn", targetConcept.createdOn); + row.add("reviewStatus", codeMapping.reviewStatus.toString()); + row.add("reviewedBy", codeMapping.reviewedBy); + row.add("reviewedOn", codeMapping.reviewedOn); out.write(row); } } From 7eb9ccc8c80ff83c3bca8cc294b736ba522a3c11 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Tue, 9 Feb 2021 20:39:52 +0100 Subject: [PATCH 46/77] add functionality to randomly assign reviewers --- src/org/ohdsi/usagi/CodeMapping.java | 3 +- .../ohdsi/usagi/ReadCodeMappingsFromFile.java | 1 + .../ohdsi/usagi/WriteCodeMappingsToFile.java | 1 + src/org/ohdsi/usagi/ui/Global.java | 1 + src/org/ohdsi/usagi/ui/MappingTablePanel.java | 25 ++++++++++-- src/org/ohdsi/usagi/ui/UsagiMain.java | 1 + src/org/ohdsi/usagi/ui/UsagiMenubar.java | 1 + .../ui/actions/ReviewerAssignmentAction.java | 39 +++++++++++++++++++ 8 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 src/org/ohdsi/usagi/ui/actions/ReviewerAssignmentAction.java diff --git a/src/org/ohdsi/usagi/CodeMapping.java b/src/org/ohdsi/usagi/CodeMapping.java index 4995500..cb677ab 100644 --- a/src/org/ohdsi/usagi/CodeMapping.java +++ b/src/org/ohdsi/usagi/CodeMapping.java @@ -28,7 +28,7 @@ public enum MappingStatus { APPROVED, UNCHECKED, AUTO_MAPPED, AUTO_MAPPED_TO_1, INVALID_TARGET, IGNORED, FLAGGED }; public enum ReviewStatus { - IDENTICAL, UP, DOWN, UNREVIEWED + IDENTICAL, UP, DOWN, WRONG, UNREVIEWED }; public SourceCode sourceCode; @@ -41,6 +41,7 @@ public enum ReviewStatus { public long statusSetOn; public String reviewedBy; public long reviewedOn; + public String assignedReviewer; public CodeMapping(SourceCode sourceCode) { this.sourceCode = sourceCode; diff --git a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java index 5de764b..3334217 100644 --- a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java +++ b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java @@ -66,6 +66,7 @@ private void readNext() { buffer.reviewStatus = ReviewStatus.valueOf(row.get("reviewStatus", "UNREVIEWED")); buffer.reviewedBy = row.get("reviewedBy", ""); buffer.reviewedOn = row.getLong("reviewedOn", "0"); + buffer.assignedReviewer = row.get("assignedReviewer", ""); try { buffer.comment = row.get("comment"); diff --git a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java index fb8d709..b0a321e 100644 --- a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java +++ b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java @@ -53,6 +53,7 @@ public void write(CodeMapping codeMapping) { row.add("reviewStatus", codeMapping.reviewStatus.toString()); row.add("reviewedBy", codeMapping.reviewedBy); row.add("reviewedOn", codeMapping.reviewedOn); + row.add("assignedReviewer", codeMapping.assignedReviewer); out.write(row); } } diff --git a/src/org/ohdsi/usagi/ui/Global.java b/src/org/ohdsi/usagi/ui/Global.java index 8a27543..1e2d1da 100644 --- a/src/org/ohdsi/usagi/ui/Global.java +++ b/src/org/ohdsi/usagi/ui/Global.java @@ -47,6 +47,7 @@ public class Global { public static IgnoreSelectedAction ignoreSelectedAction; public static FlagAction flagAction; public static ReviewAction reviewAction; + public static ReviewerAssignmentAction reviewerAssignmentAction; public static ClearSelectedAction clearSelectedAction; public static ConceptInformationAction conceptInfoAction; public static AthenaAction athenaAction; diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 5b35130..19f95fb 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -20,6 +20,7 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; +import java.util.Random; import javax.swing.BoxLayout; import javax.swing.JPanel; @@ -115,7 +116,7 @@ class CodeMapTableModel extends AbstractTableModel { private String[] defaultColumnNames = { "Status", "Source code", "Source term", "Frequency", "Value", "Value term", "Unit term", "Match score", "Concept ID", "Concept name", "Domain", "Concept class", "Vocabulary", "Concept code", - "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", "Children", "Review", "Comment", "Status Provenance" }; + "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", "Children", "Assigned To", "Review", "Comment", "Status Provenance" }; private String[] columnNames = defaultColumnNames; private int addInfoColCount = 0; private int ADD_INFO_START_COL = 7; @@ -212,10 +213,16 @@ public Object getValueAt(int row, int col) { case 19: return targetConcept.childCount; case 20: - return codeMapping.reviewStatus; + return codeMapping.assignedReviewer; case 21: - return codeMapping.comment; + if (codeMapping.reviewStatus != CodeMapping.ReviewStatus.UNREVIEWED) { + return codeMapping.reviewStatus; + } else { + return null; + } case 22: + return codeMapping.comment; + case 23: if (codeMapping.statusSetOn != 0L) { return String.format("%s (%tF)", codeMapping.statusSetBy, codeMapping.statusSetOn); } @@ -323,7 +330,6 @@ public void ignoreSelected() { } fireUpdateEventAll(APPROVE_EVENT); } - public void clearSelected() { for (int viewRow : table.getSelectedRows()) { int modelRow = table.convertRowIndexToModel(viewRow); @@ -331,4 +337,15 @@ public void clearSelected() { } fireUpdateEventAll(SIMPLE_UPDATE_EVENT); } + + public void assignReviewers() { + String[] REVIEWERS = {"A", "B", "C", "D"}; + Random rgen = new Random(); + for (CodeMapping codeMapping : Global.mapping) { + int random = rgen.nextInt(REVIEWERS.length); + String reviewer = REVIEWERS[random]; + codeMapping.assignedReviewer = reviewer; + } + fireUpdateEventAll(APPROVE_EVENT); + } } diff --git a/src/org/ohdsi/usagi/ui/UsagiMain.java b/src/org/ohdsi/usagi/ui/UsagiMain.java index 5bfbf3b..337170d 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMain.java +++ b/src/org/ohdsi/usagi/ui/UsagiMain.java @@ -82,6 +82,7 @@ public UsagiMain(String[] args) { Global.ignoreAction = new IgnoreAction(); Global.flagAction = new FlagAction(); Global.reviewAction = new ReviewAction(); + Global.reviewerAssignmentAction = new ReviewerAssignmentAction(); Global.conceptInfoAction = new ConceptInformationAction(); Global.athenaAction = new AthenaAction(); Global.googleSearchAction = new GoogleSearchAction(); diff --git a/src/org/ohdsi/usagi/ui/UsagiMenubar.java b/src/org/ohdsi/usagi/ui/UsagiMenubar.java index b646ce5..3a59c2d 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMenubar.java +++ b/src/org/ohdsi/usagi/ui/UsagiMenubar.java @@ -46,6 +46,7 @@ public UsagiMenubar() { editMenu.add(Global.ignoreAction); editMenu.add(Global.ignoreSelectedAction); editMenu.add(Global.clearSelectedAction); + editMenu.add(Global.reviewerAssignmentAction); JMenu viewMenu = new JMenu("View"); viewMenu.setMnemonic(KeyEvent.VK_V); diff --git a/src/org/ohdsi/usagi/ui/actions/ReviewerAssignmentAction.java b/src/org/ohdsi/usagi/ui/actions/ReviewerAssignmentAction.java new file mode 100644 index 0000000..ecfeaa6 --- /dev/null +++ b/src/org/ohdsi/usagi/ui/actions/ReviewerAssignmentAction.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright 2019 Observational Health Data Sciences and Informatics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ******************************************************************************/ +package org.ohdsi.usagi.ui.actions; + +import org.ohdsi.usagi.ui.Global; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; + +public class ReviewerAssignmentAction extends AbstractAction { + + private static final long serialVersionUID = -6399524936473823131L; + + public ReviewerAssignmentAction() { + putValue(Action.NAME, "Assign Reviewers"); + putValue(Action.SHORT_DESCRIPTION, "Assign reviewer to the mappings"); + } + + @Override + public void actionPerformed(ActionEvent arg0) { + Global.mappingTablePanel.assignReviewers(); + } + +} From 70995c5378b7c26ec2246dda00c2da5bd46790a0 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Tue, 9 Feb 2021 21:17:01 +0100 Subject: [PATCH 47/77] add % reviewed in status bar --- src/org/ohdsi/usagi/ui/UsagiStatusBar.java | 36 ++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/UsagiStatusBar.java b/src/org/ohdsi/usagi/ui/UsagiStatusBar.java index 69a619e..708a669 100644 --- a/src/org/ohdsi/usagi/ui/UsagiStatusBar.java +++ b/src/org/ohdsi/usagi/ui/UsagiStatusBar.java @@ -32,6 +32,7 @@ public class UsagiStatusBar extends JPanel implements DataChangeListener { private static final long serialVersionUID = 4406343348570974587L; private JLabel countLabel; private JLabel percentLabel; + private JLabel reviewPercentLabel; private JLabel searchLabel; private DecimalFormat percentFormatter = new DecimalFormat("##0.0"); @@ -39,25 +40,42 @@ public UsagiStatusBar() { super(); setBorder(BorderFactory.createEmptyBorder()); setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); + JLabel description = new JLabel("Approved / total:"); description.setForeground(Color.gray); add(description); add(Box.createHorizontalStrut(5)); + countLabel = new JLabel("0/0"); countLabel.setForeground(Color.black); add(countLabel); + add(Box.createHorizontalStrut(15)); + percentLabel = new JLabel("0%"); percentLabel.setForeground(Color.black); add(percentLabel); description = new JLabel(" of total frequency"); description.setForeground(Color.gray); add(description); + add(Box.createHorizontalGlue()); + searchLabel = new JLabel("Searching..."); searchLabel.setVisible(false); add(searchLabel); + add(Box.createHorizontalGlue()); + + reviewPercentLabel = new JLabel("0%"); + reviewPercentLabel.setForeground(Color.black); + add(reviewPercentLabel); + description = new JLabel(" codes reviewed"); + description.setForeground(Color.gray); + add(description); + + add(Box.createHorizontalStrut(15)); + JLabel versionLabel = new JLabel("Vocabulary version: " + Global.vocabularyVersion); add(versionLabel); Global.mapping.addListener(this); @@ -71,6 +89,7 @@ private void update() { int approved = 0; long totalFreq = 0; long approvedFreq = 0; + long reviewedCount = 0; for (CodeMapping codeMapping : Global.mapping) { if (codeMapping.mappingStatus == MappingStatus.APPROVED) { approved++; @@ -79,10 +98,20 @@ private void update() { else approvedFreq += codeMapping.sourceCode.sourceFrequency; } - if (codeMapping.sourceCode.sourceFrequency == -1) + if (codeMapping.sourceCode.sourceFrequency == -1) { totalFreq++; - else + } else { totalFreq += codeMapping.sourceCode.sourceFrequency; + } + + switch (codeMapping.reviewStatus) { + case UP: + case DOWN: + case IDENTICAL: + reviewedCount++; + default: + break; + } } countLabel.setText(approved + " / " + Global.mapping.size()); countLabel.setToolTipText(approved + " of the " + Global.mapping.size() + " source codes now has an approved mapping"); @@ -90,6 +119,9 @@ private void update() { percentLabel.setText(percent); percentLabel.setToolTipText(percent + " of all entries in the source data now has an approved mapping"); + String percentReviewed = percentFormatter.format(100 * reviewedCount / (double) Global.mapping.size()) + "%"; + reviewPercentLabel.setText(percentReviewed); + reviewPercentLabel.setToolTipText(percentReviewed + " of all codes in the source data now has a reviewed mapping"); } @Override From 0a2ac22839e00e7d8ccd0d9815073ab5f666f80f Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 12 Feb 2021 11:20:48 +0100 Subject: [PATCH 48/77] equivalence instead of review status --- src/org/ohdsi/usagi/CodeMapping.java | 22 +++++----- .../ohdsi/usagi/ReadCodeMappingsFromFile.java | 6 +-- .../ohdsi/usagi/WriteCodeMappingsToFile.java | 4 +- src/org/ohdsi/usagi/ui/AboutDialog.java | 12 +++++- src/org/ohdsi/usagi/ui/Global.java | 1 - .../ohdsi/usagi/ui/MappingDetailPanel.java | 40 +++++-------------- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 7 ++-- src/org/ohdsi/usagi/ui/UsagiMain.java | 1 - src/org/ohdsi/usagi/ui/UsagiStatusBar.java | 23 ----------- .../ohdsi/usagi/ui/actions/ReviewAction.java | 39 ------------------ 10 files changed, 36 insertions(+), 119 deletions(-) delete mode 100644 src/org/ohdsi/usagi/ui/actions/ReviewAction.java diff --git a/src/org/ohdsi/usagi/CodeMapping.java b/src/org/ohdsi/usagi/CodeMapping.java index cb677ab..5577c19 100644 --- a/src/org/ohdsi/usagi/CodeMapping.java +++ b/src/org/ohdsi/usagi/CodeMapping.java @@ -27,20 +27,19 @@ public class CodeMapping { public enum MappingStatus { APPROVED, UNCHECKED, AUTO_MAPPED, AUTO_MAPPED_TO_1, INVALID_TARGET, IGNORED, FLAGGED }; - public enum ReviewStatus { - IDENTICAL, UP, DOWN, WRONG, UNREVIEWED + + public enum Equivalence { + EQUAL, EQUIVALENT, WIDER, NARROWER, INEXACT, UNMATCHED, UNREVIEWED }; public SourceCode sourceCode; public double matchScore; public MappingStatus mappingStatus; - public ReviewStatus reviewStatus; + public Equivalence equivalence; public List targetConcepts = new ArrayList<>(1); public String comment; public String statusSetBy; public long statusSetOn; - public String reviewedBy; - public long reviewedOn; public String assignedReviewer; public CodeMapping(SourceCode sourceCode) { @@ -59,17 +58,16 @@ public void setUnchecked() { this.statusSetBy = ""; } - public void approve(String approvedBy) { + public void approve(String approvedBy, Equivalence equivalence) { setStatus(MappingStatus.APPROVED, approvedBy); + this.equivalence = equivalence; } - public void ignore(String ignoredBy) { - setStatus(MappingStatus.IGNORED, ignoredBy); + public void approve(String approvedBy) { + approve(approvedBy, Equivalence.EQUAL); } - public void setReviewStatus(ReviewStatus reviewStatus, String author) { - this.reviewStatus = reviewStatus; - this.reviewedOn = System.currentTimeMillis(); - this.reviewedBy = author; + public void ignore(String ignoredBy) { + setStatus(MappingStatus.IGNORED, ignoredBy); } } diff --git a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java index 3334217..2799ae8 100644 --- a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java +++ b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java @@ -18,7 +18,7 @@ import java.util.Iterator; import org.ohdsi.usagi.CodeMapping.MappingStatus; -import org.ohdsi.usagi.CodeMapping.ReviewStatus; +import org.ohdsi.usagi.CodeMapping.Equivalence; import org.ohdsi.usagi.ui.Global; import org.ohdsi.utilities.files.ReadCSVFileWithHeader; import org.ohdsi.utilities.files.Row; @@ -63,9 +63,7 @@ private void readNext() { // Status provenance and review need a default as these fields might not be available in older Usagi files buffer.statusSetBy = row.get("statusSetBy", ""); buffer.statusSetOn = row.getLong("statusSetOn", "0"); - buffer.reviewStatus = ReviewStatus.valueOf(row.get("reviewStatus", "UNREVIEWED")); - buffer.reviewedBy = row.get("reviewedBy", ""); - buffer.reviewedOn = row.getLong("reviewedOn", "0"); + buffer.equivalence = Equivalence.valueOf(row.get("equivalence", "UNREVIEWED")); buffer.assignedReviewer = row.get("assignedReviewer", ""); try { diff --git a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java index b0a321e..cd9adca 100644 --- a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java +++ b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java @@ -50,9 +50,7 @@ public void write(CodeMapping codeMapping) { row.add("comment", codeMapping.comment); row.add("createdBy", targetConcept.createdBy); row.add("createdOn", targetConcept.createdOn); - row.add("reviewStatus", codeMapping.reviewStatus.toString()); - row.add("reviewedBy", codeMapping.reviewedBy); - row.add("reviewedOn", codeMapping.reviewedOn); + row.add("equivalence", codeMapping.equivalence.toString()); row.add("assignedReviewer", codeMapping.assignedReviewer); out.write(row); } diff --git a/src/org/ohdsi/usagi/ui/AboutDialog.java b/src/org/ohdsi/usagi/ui/AboutDialog.java index 8a5dd84..575c2d9 100644 --- a/src/org/ohdsi/usagi/ui/AboutDialog.java +++ b/src/org/ohdsi/usagi/ui/AboutDialog.java @@ -63,7 +63,17 @@ public AboutDialog() { "text/html", "Usagi is maintained by The Hyve (www.thehyve.nl), and originally developed by Martijn Schuemie" + "
in Observational Health Data Sciences and Informatics (OHDSI)." + - "

For help, please review the Usagi Wiki."); + "

For help, please review the Usagi Wiki." + + "

Equivalence definitions based on HL7 concept-map-quivalence:" + + "
    " + + "
  • Equal = The concepts are exactly the same (i.e. intentionally identical).
  • " + + "
  • Equivalent = The concepts mean the same thing (i.e. extensionally identical).
  • " + + "
  • Wider = The target contains more information than to the source.
  • " + + "
  • Narrower = The target contains less information than the source.
  • " + + "
  • Inexact = The target overlaps with the source, but both source and target cover additional meaning.
  • " + + "
  • Unmatched = There is no match for this concept in the target code system.
  • " + + "
" + ); text.setEditable(false); text.setOpaque(false); diff --git a/src/org/ohdsi/usagi/ui/Global.java b/src/org/ohdsi/usagi/ui/Global.java index 1e2d1da..4100acf 100644 --- a/src/org/ohdsi/usagi/ui/Global.java +++ b/src/org/ohdsi/usagi/ui/Global.java @@ -46,7 +46,6 @@ public class Global { public static IgnoreAction ignoreAction; public static IgnoreSelectedAction ignoreSelectedAction; public static FlagAction flagAction; - public static ReviewAction reviewAction; public static ReviewerAssignmentAction reviewerAssignmentAction; public static ClearSelectedAction clearSelectedAction; public static ConceptInformationAction conceptInfoAction; diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 3002cca..8571a5b 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -58,10 +58,7 @@ public class MappingDetailPanel extends JPanel implements CodeSelectedListener, private JButton approveButton; private JButton ignoreButton; private JButton flagButton; - private JComboBox reviewOptionChooser; - private JButton reviewIdenticalButton; - private JButton mapUpButton; - private JButton mapDownButton; + private JComboBox equivalenceOptionChooser; private JTextField commentField; private JButton removeButton; private JComboBox typesChooser; @@ -270,26 +267,6 @@ private Component createApprovePanel() { JPanel panel = new JPanel(); panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); - panel.add(new JLabel("Review:")); - - reviewOptionChooser = new JComboBox<>(CodeMapping.ReviewStatus.values()); - reviewOptionChooser.setToolTipText("Choose review type"); - reviewOptionChooser.setMaximumSize(reviewOptionChooser.getPreferredSize()); - reviewOptionChooser.setEnabled(true); - panel.add(reviewOptionChooser); - - reviewIdenticalButton = new JButton(Global.reviewAction); - reviewIdenticalButton.setBackground(new Color(151, 220, 141)); - panel.add(reviewIdenticalButton); -// -// mapUpButton = new JButton("Mapped Up"); -// mapUpButton.setBackground(new Color(151, 220, 141)); -// panel.add(mapUpButton); -// -// mapDownButton = new JButton("Mapped Down"); -// mapDownButton.setBackground(new Color(151, 220, 141)); -// panel.add(mapDownButton); - panel.add(new JLabel("Comment:")); panel.add(Box.createHorizontalStrut(5)); @@ -329,6 +306,12 @@ public void changedUpdate(DocumentEvent arg0) { flagButton.setBackground(new Color(151, 220, 141)); panel.add(flagButton); + equivalenceOptionChooser = new JComboBox<>(CodeMapping.Equivalence.values()); + equivalenceOptionChooser.setToolTipText("Choose mapping equivalence"); + equivalenceOptionChooser.setMaximumSize(equivalenceOptionChooser.getPreferredSize()); + equivalenceOptionChooser.setEnabled(true); + panel.add(equivalenceOptionChooser); + approveButton = new JButton(Global.approveAction); approveButton.setBackground(new Color(151, 220, 141)); panel.add(approveButton); @@ -443,7 +426,8 @@ public void clearCodeMultiSelected() { public void approve() { if (codeMapping.mappingStatus != CodeMapping.MappingStatus.APPROVED) { - codeMapping.approve(Global.author); + CodeMapping.Equivalence equivalenceToApply = (CodeMapping.Equivalence) equivalenceOptionChooser.getSelectedItem(); + codeMapping.approve(Global.author, equivalenceToApply); Global.mapping.fireDataChanged(APPROVE_EVENT); } else { codeMapping.setUnchecked(); @@ -503,12 +487,6 @@ private void toggleStatusButtons() { } } - public void review() { - CodeMapping.ReviewStatus reviewStatusToApply = (CodeMapping.ReviewStatus) reviewOptionChooser.getSelectedItem(); - codeMapping.setReviewStatus(reviewStatusToApply, Global.author); - Global.mapping.fireDataChanged(APPROVE_EVENT); - } - public void addConcept(Concept concept) { codeMapping.targetConcepts.add(new MappingTarget(concept, Global.author)); for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 19f95fb..0c6e594 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -17,7 +17,6 @@ import java.awt.Dimension; import java.awt.Rectangle; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import java.util.Random; @@ -116,7 +115,7 @@ class CodeMapTableModel extends AbstractTableModel { private String[] defaultColumnNames = { "Status", "Source code", "Source term", "Frequency", "Value", "Value term", "Unit term", "Match score", "Concept ID", "Concept name", "Domain", "Concept class", "Vocabulary", "Concept code", - "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", "Children", "Assigned To", "Review", "Comment", "Status Provenance" }; + "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", "Children", "Assigned To", "Equivalence", "Comment", "Status Provenance" }; private String[] columnNames = defaultColumnNames; private int addInfoColCount = 0; private int ADD_INFO_START_COL = 7; @@ -215,8 +214,8 @@ public Object getValueAt(int row, int col) { case 20: return codeMapping.assignedReviewer; case 21: - if (codeMapping.reviewStatus != CodeMapping.ReviewStatus.UNREVIEWED) { - return codeMapping.reviewStatus; + if (codeMapping.equivalence != CodeMapping.Equivalence.UNREVIEWED) { + return codeMapping.equivalence; } else { return null; } diff --git a/src/org/ohdsi/usagi/ui/UsagiMain.java b/src/org/ohdsi/usagi/ui/UsagiMain.java index 337170d..6e70a17 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMain.java +++ b/src/org/ohdsi/usagi/ui/UsagiMain.java @@ -81,7 +81,6 @@ public UsagiMain(String[] args) { Global.approveAction = new ApproveAction(); Global.ignoreAction = new IgnoreAction(); Global.flagAction = new FlagAction(); - Global.reviewAction = new ReviewAction(); Global.reviewerAssignmentAction = new ReviewerAssignmentAction(); Global.conceptInfoAction = new ConceptInformationAction(); Global.athenaAction = new AthenaAction(); diff --git a/src/org/ohdsi/usagi/ui/UsagiStatusBar.java b/src/org/ohdsi/usagi/ui/UsagiStatusBar.java index 708a669..64e8dec 100644 --- a/src/org/ohdsi/usagi/ui/UsagiStatusBar.java +++ b/src/org/ohdsi/usagi/ui/UsagiStatusBar.java @@ -67,15 +67,6 @@ public UsagiStatusBar() { add(Box.createHorizontalGlue()); - reviewPercentLabel = new JLabel("0%"); - reviewPercentLabel.setForeground(Color.black); - add(reviewPercentLabel); - description = new JLabel(" codes reviewed"); - description.setForeground(Color.gray); - add(description); - - add(Box.createHorizontalStrut(15)); - JLabel versionLabel = new JLabel("Vocabulary version: " + Global.vocabularyVersion); add(versionLabel); Global.mapping.addListener(this); @@ -89,7 +80,6 @@ private void update() { int approved = 0; long totalFreq = 0; long approvedFreq = 0; - long reviewedCount = 0; for (CodeMapping codeMapping : Global.mapping) { if (codeMapping.mappingStatus == MappingStatus.APPROVED) { approved++; @@ -103,25 +93,12 @@ private void update() { } else { totalFreq += codeMapping.sourceCode.sourceFrequency; } - - switch (codeMapping.reviewStatus) { - case UP: - case DOWN: - case IDENTICAL: - reviewedCount++; - default: - break; - } } countLabel.setText(approved + " / " + Global.mapping.size()); countLabel.setToolTipText(approved + " of the " + Global.mapping.size() + " source codes now has an approved mapping"); String percent = percentFormatter.format(100 * approvedFreq / (double) totalFreq) + "%"; percentLabel.setText(percent); percentLabel.setToolTipText(percent + " of all entries in the source data now has an approved mapping"); - - String percentReviewed = percentFormatter.format(100 * reviewedCount / (double) Global.mapping.size()) + "%"; - reviewPercentLabel.setText(percentReviewed); - reviewPercentLabel.setToolTipText(percentReviewed + " of all codes in the source data now has a reviewed mapping"); } @Override diff --git a/src/org/ohdsi/usagi/ui/actions/ReviewAction.java b/src/org/ohdsi/usagi/ui/actions/ReviewAction.java deleted file mode 100644 index 967877c..0000000 --- a/src/org/ohdsi/usagi/ui/actions/ReviewAction.java +++ /dev/null @@ -1,39 +0,0 @@ -/******************************************************************************* - * Copyright 2020 Observational Health Data Sciences and Informatics & The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ******************************************************************************/ -package org.ohdsi.usagi.ui.actions; - -import org.ohdsi.usagi.ui.Global; - -import javax.swing.*; -import java.awt.event.ActionEvent; -import java.awt.event.InputEvent; -import java.awt.event.KeyEvent; - -public class ReviewAction extends AbstractAction { - - private static final long serialVersionUID = 2081755360857938731L; - - public ReviewAction() { - putValue(Action.NAME, "Review"); - putValue(Action.SHORT_DESCRIPTION, "Add a review of the mapping"); - } - - @Override - public void actionPerformed(ActionEvent arg0) { - Global.mappingDetailPanel.review(); - } - -} From ea10d8e60628d026725dd5b446aba18f7b4b129d Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 12 Feb 2021 11:38:00 +0100 Subject: [PATCH 49/77] disable equivalence chooser when approved or flagged --- src/org/ohdsi/usagi/ui/MappingDetailPanel.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 8571a5b..3f1f78c 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -58,7 +58,7 @@ public class MappingDetailPanel extends JPanel implements CodeSelectedListener, private JButton approveButton; private JButton ignoreButton; private JButton flagButton; - private JComboBox equivalenceOptionChooser; + private JComboBox equivalenceOptionChooser; private JTextField commentField; private JButton removeButton; private JComboBox typesChooser; @@ -309,7 +309,6 @@ public void changedUpdate(DocumentEvent arg0) { equivalenceOptionChooser = new JComboBox<>(CodeMapping.Equivalence.values()); equivalenceOptionChooser.setToolTipText("Choose mapping equivalence"); equivalenceOptionChooser.setMaximumSize(equivalenceOptionChooser.getPreferredSize()); - equivalenceOptionChooser.setEnabled(true); panel.add(equivalenceOptionChooser); approveButton = new JButton(Global.approveAction); @@ -392,7 +391,7 @@ private JPanel createTargetConceptsPanel() { }); typesChooser.setMaximumSize(typesChooser.getPreferredSize()); typesChooser.setEnabled(false); -// Hide type chooser, only event type +// Hide type chooser for this version, only allow event type // buttonPanel.add(typesChooser); removeButton = new JButton("Remove concept"); @@ -466,6 +465,7 @@ private void toggleStatusButtons() { flagButton.setEnabled(false); approveButton.setEnabled(false); ignoreButton.setEnabled(false); + equivalenceOptionChooser.setEnabled(false); switch(codeMapping.mappingStatus) { case APPROVED: @@ -480,10 +480,11 @@ private void toggleStatusButtons() { Global.flagAction.setToUnflag(); flagButton.setEnabled(true); break; - default: + default: // unchecked, invalid or auto-mapped flagButton.setEnabled(true); approveButton.setEnabled(true); ignoreButton.setEnabled(true); + equivalenceOptionChooser.setEnabled(true); } } From 17b0cbf71e5e9b3abb1a2513fa53e747a80e29c6 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 12 Feb 2021 12:06:43 +0100 Subject: [PATCH 50/77] update save format: round score to 2 decimals, add concept name and remove redundant columns --- src/org/ohdsi/usagi/SourceCode.java | 6 +++--- src/org/ohdsi/usagi/WriteCodeMappingsToFile.java | 12 +++++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/org/ohdsi/usagi/SourceCode.java b/src/org/ohdsi/usagi/SourceCode.java index 3fd0efc..4ea892c 100644 --- a/src/org/ohdsi/usagi/SourceCode.java +++ b/src/org/ohdsi/usagi/SourceCode.java @@ -45,9 +45,9 @@ public Row toRow() { Row row = new Row(); row.add("sourceCode", sourceCode); row.add("sourceName", sourceName); - row.add("sourceValueCode", sourceValueCode); - row.add("sourceValueName", sourceValueName); - row.add("sourceUnitName", sourceUnitName); +// row.add("sourceValueCode", sourceValueCode); +// row.add("sourceValueName", sourceValueName); +// row.add("sourceUnitName", sourceUnitName); row.add("sourceFrequency", sourceFrequency); row.add("sourceAutoAssignedConceptIds", StringUtilities.join(sourceAutoAssignedConceptIds, ";")); for (Pair pair : sourceAdditionalInfo) { diff --git a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java index cd9adca..7b9b634 100644 --- a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java +++ b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java @@ -15,8 +15,12 @@ ******************************************************************************/ package org.ohdsi.usagi; +import java.math.RoundingMode; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import org.ohdsi.utilities.files.Row; import org.ohdsi.utilities.files.WriteCSVFileWithHeader; @@ -26,6 +30,7 @@ */ public class WriteCodeMappingsToFile { private WriteCSVFileWithHeader out; + private DecimalFormat scoreFormat = new DecimalFormat("####0.00", new DecimalFormatSymbols(Locale.US)); public WriteCodeMappingsToFile(String filename) { out = new WriteCSVFileWithHeader(filename); @@ -41,16 +46,17 @@ public void write(CodeMapping codeMapping) { } for (MappingTarget targetConcept : mappingTargets) { Row row = codeMapping.sourceCode.toRow(); - row.add("matchScore", codeMapping.matchScore); + row.add("matchScore", scoreFormat.format(codeMapping.matchScore)); row.add("mappingStatus", codeMapping.mappingStatus.toString()); + row.add("equivalence", codeMapping.equivalence.toString()); row.add("statusSetBy", codeMapping.statusSetBy); row.add("statusSetOn", codeMapping.statusSetOn); row.add("conceptId", targetConcept.concept.conceptId); - row.add("mappingType", targetConcept.mappingType.toString()); + row.add("conceptName", targetConcept.concept.conceptName); // Never read in. +// row.add("mappingType", targetConcept.mappingType.toString()); row.add("comment", codeMapping.comment); row.add("createdBy", targetConcept.createdBy); row.add("createdOn", targetConcept.createdOn); - row.add("equivalence", codeMapping.equivalence.toString()); row.add("assignedReviewer", codeMapping.assignedReviewer); out.write(row); } From b89579a2eef6d51dc700f98fcde0eeb8ae14f1f8 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Tue, 16 Feb 2021 22:08:48 +0100 Subject: [PATCH 51/77] dialog to assign reviewers by name --- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 11 ++-- .../usagi/ui/ReviewerAssignmentDialog.java | 66 +++++++++++++++++++ .../ui/actions/ReviewerAssignmentAction.java | 6 +- 3 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 src/org/ohdsi/usagi/ui/ReviewerAssignmentDialog.java diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 0c6e594..a6bf625 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -337,13 +337,12 @@ public void clearSelected() { fireUpdateEventAll(SIMPLE_UPDATE_EVENT); } - public void assignReviewers() { - String[] REVIEWERS = {"A", "B", "C", "D"}; - Random rgen = new Random(); + public void assignReviewers(String[] reviewers) { + // Randomly assign code mappings to given reviewers + Random randomGenerator = new Random(); for (CodeMapping codeMapping : Global.mapping) { - int random = rgen.nextInt(REVIEWERS.length); - String reviewer = REVIEWERS[random]; - codeMapping.assignedReviewer = reviewer; + int random = randomGenerator.nextInt(reviewers.length); + codeMapping.assignedReviewer = reviewers[random].trim(); } fireUpdateEventAll(APPROVE_EVENT); } diff --git a/src/org/ohdsi/usagi/ui/ReviewerAssignmentDialog.java b/src/org/ohdsi/usagi/ui/ReviewerAssignmentDialog.java new file mode 100644 index 0000000..edf33c2 --- /dev/null +++ b/src/org/ohdsi/usagi/ui/ReviewerAssignmentDialog.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright 2020 Observational Health Data Sciences and Informatics & The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ******************************************************************************/ +package org.ohdsi.usagi.ui; + +import javax.swing.*; +import java.awt.*; + +public class ReviewerAssignmentDialog extends JDialog { + + private static final long serialVersionUID = 4349740743952812807L; + + public ReviewerAssignmentDialog() { + setTitle("Reviewer"); + setLayout(new GridBagLayout()); + GridBagConstraints g = new GridBagConstraints(); + g.fill = GridBagConstraints.BOTH; + g.ipadx = 10; + g.ipady = 10; + + g.gridx = 0; + g.gridy = 0; + add(new JLabel("Reviewers:"), g); + + g.gridx = 1; + g.gridy = 0; + JTextFieldLimit reviewersField = new JTextFieldLimit(20); + reviewersField.setToolTipText("Please enter the reviewers as comma separated list"); + reviewersField.setPreferredSize(new Dimension(300, 10)); + reviewersField.setText("A,B,C,D"); + add(reviewersField, g); + + g.gridx = 0; + g.gridy = 2; + g.gridwidth = 2; + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS)); + buttonPanel.add(Box.createHorizontalGlue()); + JButton saveButton = new JButton("Assign"); + saveButton.setToolTipText("Assign reviewers"); + saveButton.addActionListener(event -> { + Global.mappingTablePanel.assignReviewers( + reviewersField.getText().split(",") + ); + setVisible(false); + }); + buttonPanel.add(saveButton); + add(buttonPanel, g); + + pack(); + setModal(true); + setLocationRelativeTo(Global.frame); + } +} diff --git a/src/org/ohdsi/usagi/ui/actions/ReviewerAssignmentAction.java b/src/org/ohdsi/usagi/ui/actions/ReviewerAssignmentAction.java index ecfeaa6..b313001 100644 --- a/src/org/ohdsi/usagi/ui/actions/ReviewerAssignmentAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ReviewerAssignmentAction.java @@ -16,6 +16,8 @@ package org.ohdsi.usagi.ui.actions; import org.ohdsi.usagi.ui.Global; +import org.ohdsi.usagi.ui.ReviewerAssignmentDialog; +import org.ohdsi.usagi.ui.ShowStatsDialog; import javax.swing.*; import java.awt.event.ActionEvent; @@ -33,7 +35,9 @@ public ReviewerAssignmentAction() { @Override public void actionPerformed(ActionEvent arg0) { - Global.mappingTablePanel.assignReviewers(); + ReviewerAssignmentDialog dialog = new ReviewerAssignmentDialog(); + dialog.setLocationRelativeTo(Global.frame); + dialog.setVisible(true); } } From 662333ac722711aebcbb22bed50915c7dd7b4f9f Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Wed, 17 Feb 2021 09:21:39 +0100 Subject: [PATCH 52/77] assign each reviewer same number of code mappings, randomly --- src/org/ohdsi/usagi/ui/AuthorDialog.java | 2 +- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 20 +++++++++++++++++-- .../usagi/ui/ReviewerAssignmentDialog.java | 8 +++++--- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/AuthorDialog.java b/src/org/ohdsi/usagi/ui/AuthorDialog.java index cf2b194..6b83d35 100644 --- a/src/org/ohdsi/usagi/ui/AuthorDialog.java +++ b/src/org/ohdsi/usagi/ui/AuthorDialog.java @@ -36,7 +36,7 @@ public AuthorDialog() { g.gridx = 1; g.gridy = 0; - JTextFieldLimit authorField = new JTextFieldLimit(20); + JTextField authorField = new JTextField(20); authorField.setToolTipText("Please enter your name"); authorField.setPreferredSize(new Dimension(100, 10)); add(authorField, g); diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index a6bf625..0d7977a 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -18,6 +18,7 @@ import java.awt.Dimension; import java.awt.Rectangle; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Random; @@ -337,12 +338,27 @@ public void clearSelected() { fireUpdateEventAll(SIMPLE_UPDATE_EVENT); } - public void assignReviewers(String[] reviewers) { + public void assignReviewersRandomly(String[] reviewers) { // Randomly assign code mappings to given reviewers Random randomGenerator = new Random(); for (CodeMapping codeMapping : Global.mapping) { int random = randomGenerator.nextInt(reviewers.length); - codeMapping.assignedReviewer = reviewers[random].trim(); + codeMapping.assignedReviewer = reviewers[random]; + } + fireUpdateEventAll(APPROVE_EVENT); + } + + public void assignReviewersEqually(String[] reviewers) { + // Shuffle the code mapping array, then assign reviewers one by one, + // dividing the code mappings equally between reviewers. + // If the number of code mappings is not a multiple of the number of reviewers, + // then the first, second, etc. reviewer get one mapping more assigned. + int nReviewers = reviewers.length; + Mapping shuffledCodeMapping = (Mapping) Global.mapping.clone(); + Collections.shuffle(shuffledCodeMapping); + for (int i = 0; i < shuffledCodeMapping.size(); i++) { + CodeMapping codeMapping = shuffledCodeMapping.get(i); + codeMapping.assignedReviewer = reviewers[i % nReviewers]; } fireUpdateEventAll(APPROVE_EVENT); } diff --git a/src/org/ohdsi/usagi/ui/ReviewerAssignmentDialog.java b/src/org/ohdsi/usagi/ui/ReviewerAssignmentDialog.java index edf33c2..f0e3dfe 100644 --- a/src/org/ohdsi/usagi/ui/ReviewerAssignmentDialog.java +++ b/src/org/ohdsi/usagi/ui/ReviewerAssignmentDialog.java @@ -17,6 +17,7 @@ import javax.swing.*; import java.awt.*; +import java.util.Arrays; public class ReviewerAssignmentDialog extends JDialog { @@ -36,7 +37,7 @@ public ReviewerAssignmentDialog() { g.gridx = 1; g.gridy = 0; - JTextFieldLimit reviewersField = new JTextFieldLimit(20); + JTextField reviewersField = new JTextField(); reviewersField.setToolTipText("Please enter the reviewers as comma separated list"); reviewersField.setPreferredSize(new Dimension(300, 10)); reviewersField.setText("A,B,C,D"); @@ -51,8 +52,9 @@ public ReviewerAssignmentDialog() { JButton saveButton = new JButton("Assign"); saveButton.setToolTipText("Assign reviewers"); saveButton.addActionListener(event -> { - Global.mappingTablePanel.assignReviewers( - reviewersField.getText().split(",") + String[] reviewers = Arrays.stream(reviewersField.getText().split(",")).map(String::trim).toArray(String[]::new); + Global.mappingTablePanel.assignReviewersEqually( + reviewers ); setVisible(false); }); From d4050d58b87de9aff5e2a0d545c2ea055085ffd2 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Wed, 17 Feb 2021 11:06:36 +0100 Subject: [PATCH 53/77] make reviewer cell editable --- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 0d7977a..e3ea652 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -119,7 +119,7 @@ class CodeMapTableModel extends AbstractTableModel { "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", "Children", "Assigned To", "Equivalence", "Comment", "Status Provenance" }; private String[] columnNames = defaultColumnNames; private int addInfoColCount = 0; - private int ADD_INFO_START_COL = 7; + private final int ADD_INFO_START_COL = 7; public int getColumnCount() { return columnNames.length; @@ -163,9 +163,7 @@ public Object getValueAt(int row, int col) { if (col >= ADD_INFO_START_COL && col < ADD_INFO_START_COL + addInfoColCount) { return codeMapping.sourceCode.sourceAdditionalInfo.get(col - ADD_INFO_START_COL).getItem2(); } else { - if (col >= ADD_INFO_START_COL) { - col = col - addInfoColCount; - } + col = resolveColumnIndex(col); Concept targetConcept; if (codeMapping.targetConcepts.size() > 0) targetConcept = codeMapping.targetConcepts.get(0).concept; @@ -236,9 +234,7 @@ public Class getColumnClass(int col) { if (col >= ADD_INFO_START_COL && col < ADD_INFO_START_COL + addInfoColCount) { return String.class; } else { - if (col >= ADD_INFO_START_COL) { - col = col - addInfoColCount; - } + col = resolveColumnIndex(col); switch (col) { case 0: return MappingStatus.class; @@ -261,11 +257,26 @@ public Class getColumnClass(int col) { } public boolean isCellEditable(int row, int col) { + col = resolveColumnIndex(col); + if (col == 20) { + return true; + } return false; } public void setValueAt(Object value, int row, int col) { + col = resolveColumnIndex(col); + if (col == 20) { + CodeMapping codeMapping = Global.mapping.get(row); + codeMapping.assignedReviewer = (String) value; + } + } + private int resolveColumnIndex(int col) { + if (col >= ADD_INFO_START_COL) { + return col - addInfoColCount; + } + return col; } } From 128b1cafab355be2fefc6b3980fb5113130facec Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Wed, 17 Feb 2021 12:14:17 +0100 Subject: [PATCH 54/77] fix import of source codes with default UNREVIEWED status --- .../ohdsi/usagi/dataImport/ImportData.java | 1 + src/org/ohdsi/usagi/ui/ImportDialog.java | 21 ++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/org/ohdsi/usagi/dataImport/ImportData.java b/src/org/ohdsi/usagi/dataImport/ImportData.java index ab37ad4..70f96c7 100644 --- a/src/org/ohdsi/usagi/dataImport/ImportData.java +++ b/src/org/ohdsi/usagi/dataImport/ImportData.java @@ -86,6 +86,7 @@ private void createInitialMapping(List sourceCodes, ImportSettings s } else if (sourceCode.sourceAutoAssignedConceptIds.size() > 1 && concepts.size() > 0) { codeMapping.mappingStatus = MappingStatus.AUTO_MAPPED; } + codeMapping.equivalence = CodeMapping.Equivalence.UNREVIEWED; out.write(codeMapping); } out.close(); diff --git a/src/org/ohdsi/usagi/ui/ImportDialog.java b/src/org/ohdsi/usagi/ui/ImportDialog.java index fede2da..5717102 100644 --- a/src/org/ohdsi/usagi/ui/ImportDialog.java +++ b/src/org/ohdsi/usagi/ui/ImportDialog.java @@ -361,11 +361,11 @@ private List createSourceCodes() { int sourceCodeIndex = columnNames.indexOf(sourceCodeColumn.getSelectedItem().toString()); int sourceNameIndex = columnNames.indexOf(sourceNameColumn.getSelectedItem().toString()); int sourceFrequencyIndex = columnNames.indexOf(sourceFrequencyColumn.getSelectedItem().toString()); - int sourceValueCodeIndex = columnNames.indexOf(sourceValueCodeColumn.getSelectedItem().toString()); - int sourceValueNameIndex = columnNames.indexOf(sourceValueNameColumn.getSelectedItem().toString()); - int sourceUnitNameIndex = columnNames.indexOf(sourceUnitNameColumn.getSelectedItem().toString()); +// int sourceValueCodeIndex = columnNames.indexOf(sourceValueCodeColumn.getSelectedItem().toString()); +// int sourceValueNameIndex = columnNames.indexOf(sourceValueNameColumn.getSelectedItem().toString()); +// int sourceUnitNameIndex = columnNames.indexOf(sourceUnitNameColumn.getSelectedItem().toString()); int sourceAutoIndex = columnNames.indexOf(autoConceptIdColumn.getSelectedItem().toString()); - List additionalInfoIndexes = new ArrayList(); + List additionalInfoIndexes = new ArrayList<>(); for (JComboBox additionalInfoColumn : additionalInfoColumns) { int index = columnNames.indexOf(additionalInfoColumn.getSelectedItem().toString()); if (index != -1) @@ -385,12 +385,12 @@ private List createSourceCodes() { sourceCode.sourceFrequency = Integer.parseInt(row.get(sourceFrequencyIndex)); else sourceCode.sourceFrequency = -1; - if (sourceValueCodeIndex != -1) - sourceCode.sourceValueCode = row.get(sourceValueCodeIndex); - if (sourceValueNameIndex != -1) - sourceCode.sourceValueName = row.get(sourceValueNameIndex); - if (sourceUnitNameIndex != -1) - sourceCode.sourceUnitName = row.get(sourceUnitNameIndex); +// if (sourceValueCodeIndex != -1) +// sourceCode.sourceValueCode = row.get(sourceValueCodeIndex); +// if (sourceValueNameIndex != -1) +// sourceCode.sourceValueName = row.get(sourceValueNameIndex); +// if (sourceUnitNameIndex != -1) +// sourceCode.sourceUnitName = row.get(sourceUnitNameIndex); if (sourceAutoIndex != -1) if (conceptIdsOrAtc.getSelectedItem().toString().equals(CONCEPT_IDS)) { for (String conceptId : row.get(sourceAutoIndex).split(";")) @@ -468,6 +468,7 @@ public void run() { } else if (sourceCode.sourceAutoAssignedConceptIds.size() > 1 && concepts.size() > 0) { codeMapping.mappingStatus = MappingStatus.AUTO_MAPPED; } + codeMapping.equivalence = CodeMapping.Equivalence.UNREVIEWED; synchronized (globalMappingList) { globalMappingList.add(codeMapping); progressBar.setValue(Math.round(100 * globalMappingList.size() / sourceCodes.size())); From 2561f319e9366c252ed01f39000f5c86f1536cde Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Wed, 17 Feb 2021 12:24:17 +0100 Subject: [PATCH 55/77] remove legacy code for ignore status --- src/org/ohdsi/usagi/CodeMapping.java | 7 +-- src/org/ohdsi/usagi/ui/Global.java | 2 - .../ohdsi/usagi/ui/MappingDetailPanel.java | 28 +---------- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 18 +------ src/org/ohdsi/usagi/ui/UsagiCellRenderer.java | 5 -- src/org/ohdsi/usagi/ui/UsagiMain.java | 4 -- src/org/ohdsi/usagi/ui/UsagiMenubar.java | 2 - .../ohdsi/usagi/ui/actions/IgnoreAction.java | 49 ------------------- .../ui/actions/IgnoreSelectedAction.java | 40 --------------- 9 files changed, 5 insertions(+), 150 deletions(-) delete mode 100644 src/org/ohdsi/usagi/ui/actions/IgnoreAction.java delete mode 100644 src/org/ohdsi/usagi/ui/actions/IgnoreSelectedAction.java diff --git a/src/org/ohdsi/usagi/CodeMapping.java b/src/org/ohdsi/usagi/CodeMapping.java index 5577c19..d1017cc 100644 --- a/src/org/ohdsi/usagi/CodeMapping.java +++ b/src/org/ohdsi/usagi/CodeMapping.java @@ -25,7 +25,8 @@ */ public class CodeMapping { public enum MappingStatus { - APPROVED, UNCHECKED, AUTO_MAPPED, AUTO_MAPPED_TO_1, INVALID_TARGET, IGNORED, FLAGGED + // Includes IGNORED for backwards compatibility + APPROVED, UNCHECKED, AUTO_MAPPED, AUTO_MAPPED_TO_1, INVALID_TARGET, FLAGGED, IGNORED }; public enum Equivalence { @@ -66,8 +67,4 @@ public void approve(String approvedBy, Equivalence equivalence) { public void approve(String approvedBy) { approve(approvedBy, Equivalence.EQUAL); } - - public void ignore(String ignoredBy) { - setStatus(MappingStatus.IGNORED, ignoredBy); - } } diff --git a/src/org/ohdsi/usagi/ui/Global.java b/src/org/ohdsi/usagi/ui/Global.java index 4100acf..280302b 100644 --- a/src/org/ohdsi/usagi/ui/Global.java +++ b/src/org/ohdsi/usagi/ui/Global.java @@ -43,8 +43,6 @@ public class Global { public static SaveAsAction saveAsAction; public static ApproveAction approveAction; public static ApproveSelectedAction approveSelectedAction; - public static IgnoreAction ignoreAction; - public static IgnoreSelectedAction ignoreSelectedAction; public static FlagAction flagAction; public static ReviewerAssignmentAction reviewerAssignmentAction; public static ClearSelectedAction clearSelectedAction; diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 3f1f78c..2b8e4b6 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -56,7 +56,6 @@ public class MappingDetailPanel extends JPanel implements CodeSelectedListener, private TableRowSorter sorter; private ConceptTableModel searchTableModel; private JButton approveButton; - private JButton ignoreButton; private JButton flagButton; private JComboBox equivalenceOptionChooser; private JTextField commentField; @@ -199,8 +198,8 @@ private Component createSearchResultsPanel() { searchTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); searchTable.getSelectionModel().addListSelectionListener(event -> { int viewRow = searchTable.getSelectedRow(); - // Don't enable the buttons if no row selected or status is either approved or ignored - if (viewRow == -1 || codeMapping.mappingStatus == MappingStatus.APPROVED || codeMapping.mappingStatus == MappingStatus.IGNORED) { + // Don't enable the buttons if no row selected or status is approved + if (viewRow == -1 || codeMapping.mappingStatus == MappingStatus.APPROVED) { addButtons.forEach(x -> x.setEnabled(false)); replaceButton.setEnabled(false); } else { @@ -298,10 +297,6 @@ public void changedUpdate(DocumentEvent arg0) { panel.add(Box.createHorizontalStrut(5)); - ignoreButton = new JButton(Global.ignoreAction); - ignoreButton.setBackground(new Color(151, 220, 141)); -// panel.add(ignoreButton); - flagButton = new JButton(Global.flagAction); flagButton.setBackground(new Color(151, 220, 141)); panel.add(flagButton); @@ -435,18 +430,6 @@ public void approve() { } } - public void ignore() { - if (codeMapping.mappingStatus != CodeMapping.MappingStatus.IGNORED) { - codeMapping.ignore(Global.author); - Global.mappingTablePanel.clearSelected(); - Global.mapping.fireDataChanged(APPROVE_EVENT); - } else { - codeMapping.setUnchecked(); - Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - toggleStatusButtons(); - } - } - public void flag() { if (codeMapping.mappingStatus != CodeMapping.MappingStatus.FLAGGED) { codeMapping.mappingStatus = MappingStatus.FLAGGED; @@ -460,11 +443,9 @@ public void flag() { private void toggleStatusButtons() { Global.approveAction.setToApprove(); - Global.ignoreAction.setToIgnore(); Global.flagAction.setToFlag(); flagButton.setEnabled(false); approveButton.setEnabled(false); - ignoreButton.setEnabled(false); equivalenceOptionChooser.setEnabled(false); switch(codeMapping.mappingStatus) { @@ -472,10 +453,6 @@ private void toggleStatusButtons() { Global.approveAction.setToUnapprove(); approveButton.setEnabled(true); break; - case IGNORED: - Global.ignoreAction.setToUnignore(); - ignoreButton.setEnabled(true); - break; case FLAGGED: Global.flagAction.setToUnflag(); flagButton.setEnabled(true); @@ -483,7 +460,6 @@ private void toggleStatusButtons() { default: // unchecked, invalid or auto-mapped flagButton.setEnabled(true); approveButton.setEnabled(true); - ignoreButton.setEnabled(true); equivalenceOptionChooser.setEnabled(true); } } diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index e3ea652..cfd3f9b 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -67,8 +67,6 @@ public MappingTablePanel() { Global.approveAction.setEnabled(true); Global.approveSelectedAction.setEnabled(true); - Global.ignoreAction.setEnabled(true); - Global.ignoreSelectedAction.setEnabled(true); Global.clearSelectedAction.setEnabled(true); if (tableModel.getCodeMapping(primaryModelRow).targetConcepts.size() > 0) { Concept firstConcept = tableModel.getCodeMapping(primaryModelRow).targetConcepts.get(0).concept; @@ -90,8 +88,6 @@ public MappingTablePanel() { } else { Global.approveSelectedAction.setEnabled(false); Global.approveAction.setEnabled(false); - Global.ignoreAction.setEnabled(false); - Global.ignoreSelectedAction.setEnabled(false); Global.clearSelectedAction.setEnabled(false); } } @@ -324,23 +320,11 @@ private void fireUpdateEventAll(DataChangeEvent event) { public void approveSelected() { for (int viewRow : table.getSelectedRows()) { int modelRow = table.convertRowIndexToModel(viewRow); - if (tableModel.getCodeMapping(modelRow).mappingStatus != MappingStatus.IGNORED) { - tableModel.getCodeMapping(modelRow).mappingStatus = MappingStatus.APPROVED; - } + tableModel.getCodeMapping(modelRow).mappingStatus = MappingStatus.APPROVED; } fireUpdateEventAll(APPROVE_EVENT); } - public void ignoreSelected() { - for (int viewRow : table.getSelectedRows()) { - int modelRow = table.convertRowIndexToModel(viewRow); - if (tableModel.getCodeMapping(modelRow).mappingStatus != MappingStatus.APPROVED) { - tableModel.getCodeMapping(modelRow).mappingStatus = MappingStatus.IGNORED; - Global.mappingTablePanel.clearSelected(); - } - } - fireUpdateEventAll(APPROVE_EVENT); - } public void clearSelected() { for (int viewRow : table.getSelectedRows()) { int modelRow = table.convertRowIndexToModel(viewRow); diff --git a/src/org/ohdsi/usagi/ui/UsagiCellRenderer.java b/src/org/ohdsi/usagi/ui/UsagiCellRenderer.java index 173f3d3..a6d4d69 100644 --- a/src/org/ohdsi/usagi/ui/UsagiCellRenderer.java +++ b/src/org/ohdsi/usagi/ui/UsagiCellRenderer.java @@ -73,8 +73,6 @@ else if (value == MappingStatus.UNCHECKED) value = "Unchecked"; else if (value == MappingStatus.INVALID_TARGET) value = "Invalid target"; - else if (value == MappingStatus.IGNORED) - value = "Ignored"; } Component component = super.getTableCellRendererComponent(aTable, value, isSelected, hasFocus, row, column); @@ -98,9 +96,6 @@ else if (value == MappingStatus.IGNORED) component.setBackground(evenColor); } } - if (aTable.getModel().getValueAt(modelRow, 0) == MappingStatus.IGNORED) { - component.setForeground(Color.gray); - } if (aTable.getModel().getValueAt(modelRow, 0) == MappingStatus.FLAGGED) { component.setForeground(Color.red); } diff --git a/src/org/ohdsi/usagi/ui/UsagiMain.java b/src/org/ohdsi/usagi/ui/UsagiMain.java index 6e70a17..6beb4ab 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMain.java +++ b/src/org/ohdsi/usagi/ui/UsagiMain.java @@ -79,7 +79,6 @@ public UsagiMain(String[] args) { Global.saveAction = new SaveAction(); Global.saveAsAction = new SaveAsAction(); Global.approveAction = new ApproveAction(); - Global.ignoreAction = new IgnoreAction(); Global.flagAction = new FlagAction(); Global.reviewerAssignmentAction = new ReviewerAssignmentAction(); Global.conceptInfoAction = new ConceptInformationAction(); @@ -88,7 +87,6 @@ public UsagiMain(String[] args) { Global.showStatsAction = new ShowStatsAction(); Global.aboutAction = new AboutAction(); Global.approveSelectedAction = new ApproveSelectedAction(); - Global.ignoreSelectedAction = new IgnoreSelectedAction(); Global.rebuildIndexAction = new RebuildIndexAction(); Global.exitAction = new ExitAction(); @@ -99,9 +97,7 @@ public UsagiMain(String[] args) { Global.exportForReviewAction.setEnabled(false); Global.approveAction.setEnabled(false); Global.approveSelectedAction.setEnabled(false); - Global.ignoreAction.setEnabled(false); Global.flagAction.setEnabled(false); - Global.ignoreSelectedAction.setEnabled(false); Global.clearSelectedAction = new ClearSelectedAction(); Global.clearSelectedAction.setEnabled(false); Global.conceptInfoAction.setEnabled(false); diff --git a/src/org/ohdsi/usagi/ui/UsagiMenubar.java b/src/org/ohdsi/usagi/ui/UsagiMenubar.java index 3a59c2d..67c680f 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMenubar.java +++ b/src/org/ohdsi/usagi/ui/UsagiMenubar.java @@ -43,8 +43,6 @@ public UsagiMenubar() { editMenu.add(Global.approveAction); editMenu.add(Global.approveSelectedAction); - editMenu.add(Global.ignoreAction); - editMenu.add(Global.ignoreSelectedAction); editMenu.add(Global.clearSelectedAction); editMenu.add(Global.reviewerAssignmentAction); diff --git a/src/org/ohdsi/usagi/ui/actions/IgnoreAction.java b/src/org/ohdsi/usagi/ui/actions/IgnoreAction.java deleted file mode 100644 index 40e4547..0000000 --- a/src/org/ohdsi/usagi/ui/actions/IgnoreAction.java +++ /dev/null @@ -1,49 +0,0 @@ -/******************************************************************************* - * Copyright 2020 Observational Health Data Sciences and Informatics & The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ******************************************************************************/ -package org.ohdsi.usagi.ui.actions; - -import org.ohdsi.usagi.ui.Global; - -import javax.swing.*; -import java.awt.event.ActionEvent; -import java.awt.event.InputEvent; -import java.awt.event.KeyEvent; - -public class IgnoreAction extends AbstractAction { - - private static final long serialVersionUID = 5414166576120252690L; - - public IgnoreAction() { - setToIgnore(); - putValue(Action.MNEMONIC_KEY, KeyEvent.VK_I); - putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_I, InputEvent.ALT_MASK)); - } - - @Override - public void actionPerformed(ActionEvent arg0) { - Global.mappingDetailPanel.ignore(); - } - - public void setToIgnore() { - putValue(Action.NAME, "Ignore"); - putValue(Action.SHORT_DESCRIPTION, "Remove mapping and set status of selected code to ignore"); - } - - public void setToUnignore() { - Global.ignoreAction.putValue(Action.NAME, "Unignore"); - Global.ignoreAction.putValue(Action.SHORT_DESCRIPTION, "Unset ignore status of selected code"); - } -} diff --git a/src/org/ohdsi/usagi/ui/actions/IgnoreSelectedAction.java b/src/org/ohdsi/usagi/ui/actions/IgnoreSelectedAction.java deleted file mode 100644 index 4f46ed9..0000000 --- a/src/org/ohdsi/usagi/ui/actions/IgnoreSelectedAction.java +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - * Copyright 2020 Observational Health Data Sciences and Informatics & The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ******************************************************************************/ -package org.ohdsi.usagi.ui.actions; - -import org.ohdsi.usagi.ui.Global; - -import javax.swing.*; -import java.awt.event.ActionEvent; -import java.awt.event.InputEvent; -import java.awt.event.KeyEvent; - -public class IgnoreSelectedAction extends AbstractAction { - - private static final long serialVersionUID = -2553283436556522929L; - - public IgnoreSelectedAction() { - putValue(Action.NAME, "Ignore selected"); - putValue(Action.SHORT_DESCRIPTION, "Set status of all selected codes to ignore"); - putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_I, InputEvent.ALT_MASK | InputEvent.SHIFT_DOWN_MASK)); - } - - @Override - public void actionPerformed(ActionEvent arg0) { - Global.mappingTablePanel.ignoreSelected(); - } - -} From cee6c3cbd509e5231c6bca3b8d311a51c3bb142c Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Wed, 17 Feb 2021 13:32:40 +0100 Subject: [PATCH 56/77] remove legacy target types --- src/org/ohdsi/usagi/MappingTarget.java | 25 +---- .../ohdsi/usagi/ReadCodeMappingsFromFile.java | 7 +- src/org/ohdsi/usagi/SourceCode.java | 12 -- .../ohdsi/usagi/WriteCodeMappingsToFile.java | 1 - src/org/ohdsi/usagi/ui/ImportDialog.java | 34 ------ .../ohdsi/usagi/ui/MappingDetailPanel.java | 106 +++--------------- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 45 +++----- .../usagi/ui/TargetConceptTableModel.java | 2 - 8 files changed, 36 insertions(+), 196 deletions(-) diff --git a/src/org/ohdsi/usagi/MappingTarget.java b/src/org/ohdsi/usagi/MappingTarget.java index 4e08e7c..f8ae9b2 100644 --- a/src/org/ohdsi/usagi/MappingTarget.java +++ b/src/org/ohdsi/usagi/MappingTarget.java @@ -19,36 +19,23 @@ * Class for holding information about a single (target) concept in the Vocabulary */ public class MappingTarget{ - public enum Type { - EVENT, VALUE, UNIT // Maybe also OPERATOR, TYPE, etc. - }; public Concept concept; - public Type mappingType; public String createdBy; public long createdOn; public MappingTarget() { this.concept = Concept.createEmptyConcept(); - this.mappingType = Type.EVENT; this.createdBy = ""; this.createdOn = 0; } public MappingTarget(Concept concept, String createdBy) { - this(concept, Type.EVENT, createdBy); + this(concept, createdBy, System.currentTimeMillis()); } - public MappingTarget(Concept concept, Type mappingType, String createdBy) { + public MappingTarget(Concept concept, String createdBy, long createdOn) { this.concept = concept; - this.mappingType = mappingType; - this.createdBy = createdBy; - this.createdOn = System.currentTimeMillis(); - } - - public MappingTarget(Concept concept, Type mappingType, String createdBy, long createdOn) { - this.concept = concept; - this.mappingType = mappingType; this.createdBy = createdBy; this.createdOn = createdOn; } @@ -60,12 +47,4 @@ public Concept getConcept() { public void setConcept(Concept concept) { this.concept = concept; } - - public Type getMappingType() { - return mappingType; - } - - public void setMappingType(Type mappingType) { - this.mappingType = mappingType; - } } diff --git a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java index 2799ae8..2f901a4 100644 --- a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java +++ b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java @@ -73,9 +73,7 @@ private void readNext() { } while (row != null && new SourceCode(row).sourceCode.equals(buffer.sourceCode.sourceCode) - && new SourceCode(row).sourceName.equals(buffer.sourceCode.sourceName) // MM: is this needed? - && (new SourceCode(row).sourceValueCode == null - || new SourceCode(row).sourceValueCode.equals(buffer.sourceCode.sourceValueCode))) { + && new SourceCode(row).sourceName.equals(buffer.sourceCode.sourceName)) { if (row.getInt("conceptId") != 0) { Concept concept = Global.dbEngine.getConcept(row.getInt("conceptId")); @@ -83,10 +81,9 @@ && new SourceCode(row).sourceName.equals(buffer.sourceCode.sourceName) // MM: is buffer.mappingStatus = MappingStatus.INVALID_TARGET; buffer.comment = "Invalid existing target: " + row.get("conceptId"); } else { - // Type and provenance might not be available in older Usagi files + // Provenance might not be available in older Usagi files MappingTarget mappingTarget = new MappingTarget( concept, - MappingTarget.Type.valueOf(row.get("mappingType", "EVENT")), row.get("createdBy", ""), row.getLong("createdOn", "0") ); diff --git a/src/org/ohdsi/usagi/SourceCode.java b/src/org/ohdsi/usagi/SourceCode.java index 4ea892c..92ba068 100644 --- a/src/org/ohdsi/usagi/SourceCode.java +++ b/src/org/ohdsi/usagi/SourceCode.java @@ -32,9 +32,6 @@ public class SourceCode { public String sourceCode; public String sourceName; - public String sourceValueCode; - public String sourceValueName; - public String sourceUnitName; public int sourceFrequency; public Set sourceAutoAssignedConceptIds = new HashSet(); public List> sourceAdditionalInfo = new ArrayList>(); @@ -45,9 +42,6 @@ public Row toRow() { Row row = new Row(); row.add("sourceCode", sourceCode); row.add("sourceName", sourceName); -// row.add("sourceValueCode", sourceValueCode); -// row.add("sourceValueName", sourceValueName); -// row.add("sourceUnitName", sourceUnitName); row.add("sourceFrequency", sourceFrequency); row.add("sourceAutoAssignedConceptIds", StringUtilities.join(sourceAutoAssignedConceptIds, ";")); for (Pair pair : sourceAdditionalInfo) { @@ -62,12 +56,6 @@ public SourceCode() { public SourceCode(Row row) { sourceCode = row.get("sourceCode"); sourceName = row.get("sourceName"); - if (row.getFieldNames().contains("sourceValueCode")) { - // Assume that if source value code exists, then other new fields as well - sourceValueCode = row.get("sourceValueCode"); - sourceValueName = row.get("sourceValueName"); - sourceUnitName = row.get("sourceUnitName"); - } sourceFrequency = row.getInt("sourceFrequency"); sourceAutoAssignedConceptIds = parse(row.get("sourceAutoAssignedConceptIds")); for (String field : row.getFieldNames()) diff --git a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java index 7b9b634..a8f3617 100644 --- a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java +++ b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java @@ -53,7 +53,6 @@ public void write(CodeMapping codeMapping) { row.add("statusSetOn", codeMapping.statusSetOn); row.add("conceptId", targetConcept.concept.conceptId); row.add("conceptName", targetConcept.concept.conceptName); // Never read in. -// row.add("mappingType", targetConcept.mappingType.toString()); row.add("comment", codeMapping.comment); row.add("createdBy", targetConcept.createdBy); row.add("createdOn", targetConcept.createdOn); diff --git a/src/org/ohdsi/usagi/ui/ImportDialog.java b/src/org/ohdsi/usagi/ui/ImportDialog.java index 5717102..cfccf76 100644 --- a/src/org/ohdsi/usagi/ui/ImportDialog.java +++ b/src/org/ohdsi/usagi/ui/ImportDialog.java @@ -70,9 +70,6 @@ public class ImportDialog extends JDialog { private JComboBox sourceCodeColumn; private JComboBox sourceNameColumn; private JComboBox sourceFrequencyColumn; - private JComboBox sourceValueCodeColumn; - private JComboBox sourceValueNameColumn; - private JComboBox sourceUnitNameColumn; private JComboBox autoConceptIdColumn; private List> additionalInfoColumns = new ArrayList>(); private int gridY; @@ -223,28 +220,6 @@ private Component createColumnMappingPanel() { sourceFrequencyColumn.setToolTipText("The column containing the frequency of the code in the source database"); columnMappingPanel.add(sourceFrequencyColumn, cBox); -// Hide mapping type -// cLabel.gridy++; -// cBox.gridy++; -// columnMappingPanel.add(new JLabel("Value code column"), cLabel); -// sourceValueCodeColumn = new JComboBox<>(comboBoxOptions); -// sourceValueCodeColumn.setToolTipText("The column containing the value code"); -// columnMappingPanel.add(sourceValueCodeColumn, cBox); -// -// cLabel.gridy++; -// cBox.gridy++; -// columnMappingPanel.add(new JLabel("Value name column "), cLabel); -// sourceValueNameColumn = new JComboBox<>(comboBoxOptions); -// sourceValueNameColumn.setToolTipText("The column containing the value name"); -// columnMappingPanel.add(sourceValueNameColumn, cBox); -// -// cLabel.gridy++; -// cBox.gridy++; -// columnMappingPanel.add(new JLabel("Unit name column"), cLabel); -// sourceUnitNameColumn = new JComboBox<>(comboBoxOptions); -// sourceUnitNameColumn.setToolTipText("The column containing the name of the unit"); -// columnMappingPanel.add(sourceUnitNameColumn, cBox); - cLabel.gridy++; cBox.gridy++; conceptIdsOrAtc = new JComboBox<>(new String[] { CONCEPT_IDS, ATC }); @@ -361,9 +336,6 @@ private List createSourceCodes() { int sourceCodeIndex = columnNames.indexOf(sourceCodeColumn.getSelectedItem().toString()); int sourceNameIndex = columnNames.indexOf(sourceNameColumn.getSelectedItem().toString()); int sourceFrequencyIndex = columnNames.indexOf(sourceFrequencyColumn.getSelectedItem().toString()); -// int sourceValueCodeIndex = columnNames.indexOf(sourceValueCodeColumn.getSelectedItem().toString()); -// int sourceValueNameIndex = columnNames.indexOf(sourceValueNameColumn.getSelectedItem().toString()); -// int sourceUnitNameIndex = columnNames.indexOf(sourceUnitNameColumn.getSelectedItem().toString()); int sourceAutoIndex = columnNames.indexOf(autoConceptIdColumn.getSelectedItem().toString()); List additionalInfoIndexes = new ArrayList<>(); for (JComboBox additionalInfoColumn : additionalInfoColumns) { @@ -385,12 +357,6 @@ private List createSourceCodes() { sourceCode.sourceFrequency = Integer.parseInt(row.get(sourceFrequencyIndex)); else sourceCode.sourceFrequency = -1; -// if (sourceValueCodeIndex != -1) -// sourceCode.sourceValueCode = row.get(sourceValueCodeIndex); -// if (sourceValueNameIndex != -1) -// sourceCode.sourceValueName = row.get(sourceValueNameIndex); -// if (sourceUnitNameIndex != -1) -// sourceCode.sourceUnitName = row.get(sourceUnitNameIndex); if (sourceAutoIndex != -1) if (conceptIdsOrAtc.getSelectedItem().toString().equals(CONCEPT_IDS)) { for (String conceptId : row.get(sourceAutoIndex).split(";")) diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 2b8e4b6..1d63b6b 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -60,12 +60,9 @@ public class MappingDetailPanel extends JPanel implements CodeSelectedListener, private JComboBox equivalenceOptionChooser; private JTextField commentField; private JButton removeButton; - private JComboBox typesChooser; private JButton replaceButton; - private List addButtons; + private JButton addButton; private JRadioButton autoQueryCodeButton; - private JRadioButton autoQueryValueButton; - private JRadioButton autoQueryUnitButton; private JRadioButton manualQueryButton; private JTextField manualQueryField; private CodeMapping codeMapping; @@ -125,22 +122,10 @@ private Component createQueryPanel() { c.weightx = 0.1; c.gridwidth = 2; -// panel.add(new JLabel("Use:"), c); - autoQueryCodeButton = new JRadioButton("Use source term", true); autoQueryCodeButton.addActionListener(x -> doSearch()); panel.add(autoQueryCodeButton, c); - autoQueryValueButton = new JRadioButton("Value", false); - autoQueryValueButton.addActionListener(x -> doSearch()); -// Hide other types -// panel.add(autoQueryValueButton, c); - - autoQueryUnitButton = new JRadioButton("Unit", false); - autoQueryUnitButton.addActionListener(x -> doSearch()); -// Hide other types -// panel.add(autoQueryUnitButton, c); - c.gridx = 0; c.gridy = 1; c.weightx = 0.1; @@ -151,8 +136,6 @@ private Component createQueryPanel() { ButtonGroup buttonGroup = new ButtonGroup(); buttonGroup.add(autoQueryCodeButton); - buttonGroup.add(autoQueryValueButton); - buttonGroup.add(autoQueryUnitButton); buttonGroup.add(manualQueryButton); c.gridx = 1; @@ -200,10 +183,10 @@ private Component createSearchResultsPanel() { int viewRow = searchTable.getSelectedRow(); // Don't enable the buttons if no row selected or status is approved if (viewRow == -1 || codeMapping.mappingStatus == MappingStatus.APPROVED) { - addButtons.forEach(x -> x.setEnabled(false)); + addButton.setEnabled(false); replaceButton.setEnabled(false); } else { - addButtons.forEach(x -> x.setEnabled(true)); + addButton.setEnabled(true); replaceButton.setEnabled(true); int modelRow = searchTable.convertRowIndexToModel(viewRow); Global.conceptInfoAction.setEnabled(true); @@ -236,26 +219,17 @@ public void actionPerformed(ActionEvent e) { replaceButton.setEnabled(false); buttonPanel.add(replaceButton); - JButton button; - addButtons = new ArrayList<>(); - for (MappingTarget.Type mappingType : MappingTarget.Type.values()) { - if (mappingType.equals(MappingTarget.Type.EVENT)) { - button = new JButton("Add concept"); - } else { -// Hide other (value, unit) mapping types -// button = new JButton(String.format("Add %s concept", mappingType)); - continue; - } - button.setToolTipText(String.format("Add selected concept as %s", mappingType)); - button.addActionListener(e -> { + addButton = new JButton("Add concept"); + addButton.setToolTipText("Add selected concept"); + addButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { int viewRow = searchTable.getSelectedRow(); int modelRow = searchTable.convertRowIndexToModel(viewRow); - addConcept(searchTableModel.getConcept(modelRow), mappingType); - }); - button.setEnabled(false); - addButtons.add(button); - buttonPanel.add(button); - } + addConcept(searchTableModel.getConcept(modelRow)); + } + }); + addButton.setEnabled(false); + buttonPanel.add(addButton); panel.add(buttonPanel); @@ -329,10 +303,6 @@ private JPanel createSourceCodePanel() { pane.setPreferredSize(new Dimension(500, 40)); panel.add(pane); - sourceCodeTable.hideColumn("Value"); - sourceCodeTable.hideColumn("Value term"); - sourceCodeTable.hideColumn("Unit term"); - return panel; } @@ -349,13 +319,10 @@ private JPanel createTargetConceptsPanel() { int viewRow = targetConceptTable.getSelectedRow(); if (viewRow == -1 || codeMapping.mappingStatus == MappingStatus.APPROVED) { removeButton.setEnabled(false); - typesChooser.setEnabled(false); } else { removeButton.setEnabled(true); - typesChooser.setEnabled(true); int modelRow = targetConceptTable.convertRowIndexToModel(viewRow); MappingTarget mappingTarget = targetConceptTableModel.getMappingTarget(modelRow); - typesChooser.setSelectedItem(mappingTarget.getMappingType()); Global.conceptInfoAction.setEnabled(true); Global.conceptInformationDialog.setConcept(mappingTarget.concept); Global.athenaAction.setEnabled(true); @@ -378,17 +345,6 @@ private JPanel createTargetConceptsPanel() { buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS)); buttonPanel.add(Box.createHorizontalGlue()); - typesChooser = new JComboBox<>(MappingTarget.Type.values()); - typesChooser.setToolTipText("Set type of the mapping"); - typesChooser.addActionListener(e -> { - if (((JComboBox)e.getSource()).hasFocus()) - changeTargetType(); - }); - typesChooser.setMaximumSize(typesChooser.getPreferredSize()); - typesChooser.setEnabled(false); -// Hide type chooser for this version, only allow event type -// buttonPanel.add(typesChooser); - removeButton = new JButton("Remove concept"); removeButton.setToolTipText("Add selected concept"); removeButton.addActionListener(e -> remove()); @@ -478,20 +434,6 @@ public void addConcept(Concept concept) { } } - public void addConcept(Concept concept, MappingTarget.Type mappingType) { - codeMapping.targetConcepts.add(new MappingTarget(concept, mappingType, Global.author)); - for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { - codeMappingMulti.targetConcepts.add(new MappingTarget(concept, mappingType, Global.author)); - } - targetConceptTableModel.fireTableDataChanged(); - - if (codeMappingsFromMulti.size() > 0) { - Global.mapping.fireDataChanged(MULTI_UPDATE_EVENT); - } else { - Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - } - } - public void replaceConcepts(Concept concept) { codeMapping.targetConcepts.clear(); for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { @@ -513,16 +455,6 @@ private void remove() { Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); } - private void changeTargetType() { - for (int row : targetConceptTable.getSelectedRows()) { - MappingTarget mappingTarget = codeMapping.targetConcepts.get(row); - mappingTarget.setMappingType((MappingTarget.Type) typesChooser.getSelectedItem()); - } - - targetConceptTableModel.fireTableDataChanged(); - Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - } - private class SearchTask extends TimerTask { @Override @@ -545,10 +477,6 @@ public void run() { String query; if (autoQueryCodeButton.isSelected()) { query = codeMapping.sourceCode.sourceName; - } else if (autoQueryValueButton.isSelected()) { - query = codeMapping.sourceCode.sourceValueName; - } else if (autoQueryUnitButton.isSelected()) { - query = codeMapping.sourceCode.sourceUnitName; } else { query = manualQueryField.getText(); } @@ -577,11 +505,11 @@ public void doSearch() { class SourceCodeTableModel extends AbstractTableModel { private static final long serialVersionUID = 169286268154988911L; - private String[] defaultColumnNames = { "Source code", "Source term", "Value", "Value term", "Unit term", "Frequency" }; + private String[] defaultColumnNames = { "Source code", "Source term", "Frequency" }; private String[] columnNames = defaultColumnNames; private CodeMapping codeMapping; private int addInfoColCount = 0; - private int ADD_INFO_START_COL = 6; + private int ADD_INFO_START_COL = 3; public int getColumnCount() { return columnNames.length; @@ -622,12 +550,6 @@ public Object getValueAt(int row, int col) { case 1: return codeMapping.sourceCode.sourceName; case 2: - return codeMapping.sourceCode.sourceValueCode; - case 3: - return codeMapping.sourceCode.sourceValueName; - case 4: - return codeMapping.sourceCode.sourceUnitName; - case 5: return codeMapping.sourceCode.sourceFrequency; default: return ""; diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index cfd3f9b..9cad690 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -97,9 +97,6 @@ public MappingTablePanel() { table.hideColumn("Valid start date"); table.hideColumn("Valid end date"); table.hideColumn("Invalid reason"); - table.hideColumn("Value"); - table.hideColumn("Value term"); - table.hideColumn("Unit term"); JScrollPane scrollPane = new JScrollPane(table); add(scrollPane); @@ -110,7 +107,7 @@ public MappingTablePanel() { class CodeMapTableModel extends AbstractTableModel { private static final long serialVersionUID = 169286268154988911L; - private String[] defaultColumnNames = { "Status", "Source code", "Source term", "Frequency", "Value", "Value term", "Unit term", + private String[] defaultColumnNames = { "Status", "Source code", "Source term", "Frequency", "Match score", "Concept ID", "Concept name", "Domain", "Concept class", "Vocabulary", "Concept code", "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", "Children", "Assigned To", "Equivalence", "Comment", "Status Provenance" }; private String[] columnNames = defaultColumnNames; @@ -175,48 +172,42 @@ public Object getValueAt(int row, int col) { case 3: return codeMapping.sourceCode.sourceFrequency == -1 ? "" : codeMapping.sourceCode.sourceFrequency; case 4: - return codeMapping.sourceCode.sourceValueCode; - case 5: - return codeMapping.sourceCode.sourceValueName; - case 6: - return codeMapping.sourceCode.sourceUnitName; - case 7: return codeMapping.matchScore; - case 8: + case 5: return targetConcept.conceptId; - case 9: + case 6: return targetConcept.conceptName; - case 10: + case 7: return targetConcept.domainId; - case 11: + case 8: return targetConcept.conceptClassId; - case 12: + case 9: return targetConcept.vocabularyId; - case 13: + case 10: return targetConcept.conceptCode; - case 14: + case 11: return targetConcept.validStartDate; - case 15: + case 12: return targetConcept.validEndDate; - case 16: + case 13: return targetConcept.invalidReason; - case 17: + case 14: return targetConcept.standardConcept; - case 18: + case 15: return targetConcept.parentCount; - case 19: + case 16: return targetConcept.childCount; - case 20: + case 17: return codeMapping.assignedReviewer; - case 21: + case 18: if (codeMapping.equivalence != CodeMapping.Equivalence.UNREVIEWED) { return codeMapping.equivalence; } else { return null; } - case 22: + case 19: return codeMapping.comment; - case 23: + case 20: if (codeMapping.statusSetOn != 0L) { return String.format("%s (%tF)", codeMapping.statusSetBy, codeMapping.statusSetOn); } @@ -262,7 +253,7 @@ public boolean isCellEditable(int row, int col) { public void setValueAt(Object value, int row, int col) { col = resolveColumnIndex(col); - if (col == 20) { + if (col == 17) { CodeMapping codeMapping = Global.mapping.get(row); codeMapping.assignedReviewer = (String) value; } diff --git a/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java b/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java index 4cee4ae..88a0e96 100644 --- a/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java +++ b/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java @@ -76,8 +76,6 @@ public Object getValueAt(int row, int col) { case 11: return targetConcept.concept.childCount; case 12: - return targetConcept.mappingType; - case 13: if (targetConcept.createdOn != 0L) { return String.format("%s (%tF)", targetConcept.createdBy, targetConcept.createdOn); } From aef9ae8666eaaf15351996d37c7a9c439344c0fc Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Wed, 17 Feb 2021 13:44:03 +0100 Subject: [PATCH 57/77] refactorings --- .../ohdsi/usagi/ui/MappingDetailPanel.java | 1176 ++++++++--------- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 6 +- src/org/ohdsi/usagi/ui/UsagiMain.java | 2 - 3 files changed, 591 insertions(+), 593 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 1d63b6b..802e786 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -1,588 +1,588 @@ -/******************************************************************************* - * Copyright 2019 Observational Health Data Sciences and Informatics - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ******************************************************************************/ -package org.ohdsi.usagi.ui; - -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Set; -import java.util.Timer; -import java.util.TimerTask; -import java.util.Vector; - -import javax.swing.*; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; -import javax.swing.table.AbstractTableModel; -import javax.swing.table.TableRowSorter; - -import org.ohdsi.usagi.CodeMapping; -import org.ohdsi.usagi.CodeMapping.MappingStatus; -import org.ohdsi.usagi.Concept; -import org.ohdsi.usagi.MappingTarget; -import org.ohdsi.usagi.UsagiSearchEngine.ScoredConcept; - -import static org.ohdsi.usagi.ui.DataChangeEvent.*; - -public class MappingDetailPanel extends JPanel implements CodeSelectedListener, FilterChangeListener { - - private static final long serialVersionUID = 2127318722005512776L; - private UsagiTable sourceCodeTable; - private SourceCodeTableModel sourceCodeTableModel; - private UsagiTable targetConceptTable; - private TargetConceptTableModel targetConceptTableModel; - private UsagiTable searchTable; - private TableRowSorter sorter; - private ConceptTableModel searchTableModel; - private JButton approveButton; - private JButton flagButton; - private JComboBox equivalenceOptionChooser; - private JTextField commentField; - private JButton removeButton; - private JButton replaceButton; - private JButton addButton; - private JRadioButton autoQueryCodeButton; - private JRadioButton manualQueryButton; - private JTextField manualQueryField; - private CodeMapping codeMapping; - private List codeMappingsFromMulti; - private FilterPanel filterPanel; - private Timer timer; - - public MappingDetailPanel() { - super(); - setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - add(createSourceCodePanel()); - add(createTargetConceptsPanel()); - add(createSearchPanel()); - add(createApprovePanel()); - codeMappingsFromMulti = new ArrayList<>(); - } - - private Component createSearchPanel() { - JPanel panel = new JPanel(); - panel.setBorder(BorderFactory.createTitledBorder("Search")); - panel.setLayout(new GridBagLayout()); - GridBagConstraints c = new GridBagConstraints(); - c.fill = GridBagConstraints.BOTH; - - c.gridx = 0; - c.gridy = 0; - c.weightx = 1; - c.weighty = 0.1; - panel.add(createQueryPanel(), c); - - c.gridx = 1; - c.gridy = 0; - c.weightx = 0.1; - c.weighty = 0.1; - filterPanel = new FilterPanel(); - filterPanel.addListener(this); - panel.add(filterPanel, c); - - c.gridx = 0; - c.gridy = 1; - c.weightx = 1; - c.weighty = 1; - c.gridwidth = 2; - panel.add(createSearchResultsPanel(), c); - return panel; - } - - private Component createQueryPanel() { - JPanel panel = new JPanel(); - panel.setBorder(BorderFactory.createTitledBorder("Query")); - panel.setLayout(new GridBagLayout()); - GridBagConstraints c = new GridBagConstraints(); - c.fill = GridBagConstraints.BOTH; - c.anchor = GridBagConstraints.WEST; - c.gridx = GridBagConstraints.RELATIVE; - c.gridy = 0; - c.weightx = 0.1; - c.gridwidth = 2; - - autoQueryCodeButton = new JRadioButton("Use source term", true); - autoQueryCodeButton.addActionListener(x -> doSearch()); - panel.add(autoQueryCodeButton, c); - - c.gridx = 0; - c.gridy = 1; - c.weightx = 0.1; - c.gridwidth = 1; - manualQueryButton = new JRadioButton("Query:", false); - manualQueryButton.addActionListener(x -> doSearch()); - panel.add(manualQueryButton, c); - - ButtonGroup buttonGroup = new ButtonGroup(); - buttonGroup.add(autoQueryCodeButton); - buttonGroup.add(manualQueryButton); - - c.gridx = 1; - c.gridy = 1; - c.weightx = 1; - c.gridwidth = GridBagConstraints.REMAINDER; - manualQueryField = new JTextField(""); - // manualQueryField.setPreferredSize(new Dimension(200, 5)); - manualQueryField.getDocument().addDocumentListener(new DocumentListener() { - - @Override - public void removeUpdate(DocumentEvent arg0) { - manualQueryButton.setSelected(true); - doSearch(); - } - - @Override - public void insertUpdate(DocumentEvent arg0) { - manualQueryButton.setSelected(true); - doSearch(); - } - - @Override - public void changedUpdate(DocumentEvent arg0) { - manualQueryButton.setSelected(true); - doSearch(); - } - }); - panel.add(manualQueryField, c); - return panel; - } - - private Component createSearchResultsPanel() { - JPanel panel = new JPanel(); - panel.setBorder(BorderFactory.createTitledBorder("Results")); - panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); - searchTableModel = new ConceptTableModel(true); - searchTable = new UsagiTable(searchTableModel); - sorter = new TableRowSorter(searchTableModel); - searchTable.setRowSorter(sorter); - searchTable.setPreferredScrollableViewportSize(new Dimension(100, 100)); - searchTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); - searchTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - searchTable.getSelectionModel().addListSelectionListener(event -> { - int viewRow = searchTable.getSelectedRow(); - // Don't enable the buttons if no row selected or status is approved - if (viewRow == -1 || codeMapping.mappingStatus == MappingStatus.APPROVED) { - addButton.setEnabled(false); - replaceButton.setEnabled(false); - } else { - addButton.setEnabled(true); - replaceButton.setEnabled(true); - int modelRow = searchTable.convertRowIndexToModel(viewRow); - Global.conceptInfoAction.setEnabled(true); - Global.conceptInformationDialog.setConcept(searchTableModel.getConcept(modelRow)); - Global.athenaAction.setEnabled(true); - Global.athenaAction.setConcept(searchTableModel.getConcept(modelRow)); - Global.googleSearchAction.setEnabled(false); - } - }); - // searchTable.hideColumn("Synonym"); - searchTable.hideColumn("Valid start date"); - searchTable.hideColumn("Valid end date"); - searchTable.hideColumn("Invalid reason"); - panel.add(new JScrollPane(searchTable)); - - JPanel buttonPanel = new JPanel(); - buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS)); - buttonPanel.add(Box.createHorizontalGlue()); - - replaceButton = new JButton("Replace concept"); - replaceButton.setToolTipText("Replace selected concept"); - replaceButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - int viewRow = searchTable.getSelectedRow(); - int modelRow = searchTable.convertRowIndexToModel(viewRow); - replaceConcepts(searchTableModel.getConcept(modelRow)); - } - - }); - replaceButton.setEnabled(false); - buttonPanel.add(replaceButton); - - addButton = new JButton("Add concept"); - addButton.setToolTipText("Add selected concept"); - addButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - int viewRow = searchTable.getSelectedRow(); - int modelRow = searchTable.convertRowIndexToModel(viewRow); - addConcept(searchTableModel.getConcept(modelRow)); - } - }); - addButton.setEnabled(false); - buttonPanel.add(addButton); - - panel.add(buttonPanel); - - return panel; - } - - private Component createApprovePanel() { - JPanel panel = new JPanel(); - panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); - - panel.add(new JLabel("Comment:")); - - panel.add(Box.createHorizontalStrut(5)); - - commentField = new JTextField(); - commentField.setMaximumSize(new Dimension(Integer.MAX_VALUE, commentField.getPreferredSize().height)); - commentField.getDocument().addDocumentListener(new DocumentListener() { - - @Override - public void removeUpdate(DocumentEvent arg0) { - codeMapping.comment = commentField.getText(); - Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - } - - @Override - public void insertUpdate(DocumentEvent arg0) { - codeMapping.comment = commentField.getText(); - Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - } - - @Override - public void changedUpdate(DocumentEvent arg0) { - codeMapping.comment = commentField.getText(); - Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - } - }); - commentField.setToolTipText("Comments about the code mapping can be written here"); - panel.add(commentField); - - panel.add(Box.createHorizontalStrut(5)); - - flagButton = new JButton(Global.flagAction); - flagButton.setBackground(new Color(151, 220, 141)); - panel.add(flagButton); - - equivalenceOptionChooser = new JComboBox<>(CodeMapping.Equivalence.values()); - equivalenceOptionChooser.setToolTipText("Choose mapping equivalence"); - equivalenceOptionChooser.setMaximumSize(equivalenceOptionChooser.getPreferredSize()); - panel.add(equivalenceOptionChooser); - - approveButton = new JButton(Global.approveAction); - approveButton.setBackground(new Color(151, 220, 141)); - panel.add(approveButton); - - return panel; - } - - private JPanel createSourceCodePanel() { - JPanel panel = new JPanel(); - panel.setBorder(BorderFactory.createTitledBorder("Source code")); - panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); - sourceCodeTableModel = new SourceCodeTableModel(); - sourceCodeTable = new UsagiTable(sourceCodeTableModel); - sourceCodeTable.setPreferredScrollableViewportSize(new Dimension(500, 35)); - sourceCodeTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); - sourceCodeTable.setRowSelectionAllowed(false); - sourceCodeTable.setCellSelectionEnabled(false); - JScrollPane pane = new JScrollPane(sourceCodeTable); - pane.setBorder(BorderFactory.createEmptyBorder()); - pane.setMinimumSize(new Dimension(500, 40)); - pane.setPreferredSize(new Dimension(500, 40)); - panel.add(pane); - - return panel; - } - - private JPanel createTargetConceptsPanel() { - JPanel panel = new JPanel(); - panel.setBorder(BorderFactory.createTitledBorder("Target concepts")); - panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); - targetConceptTableModel = new TargetConceptTableModel(); - targetConceptTable = new UsagiTable(targetConceptTableModel); - targetConceptTable.setPreferredScrollableViewportSize(new Dimension(500, 45)); - targetConceptTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); - targetConceptTable.setRowSelectionAllowed(true); - targetConceptTable.getSelectionModel().addListSelectionListener(event -> { - int viewRow = targetConceptTable.getSelectedRow(); - if (viewRow == -1 || codeMapping.mappingStatus == MappingStatus.APPROVED) { - removeButton.setEnabled(false); - } else { - removeButton.setEnabled(true); - int modelRow = targetConceptTable.convertRowIndexToModel(viewRow); - MappingTarget mappingTarget = targetConceptTableModel.getMappingTarget(modelRow); - Global.conceptInfoAction.setEnabled(true); - Global.conceptInformationDialog.setConcept(mappingTarget.concept); - Global.athenaAction.setEnabled(true); - Global.athenaAction.setConcept(mappingTarget.concept); - Global.googleSearchAction.setEnabled(false); - } - }); - targetConceptTable.hideColumn("Mapping Type"); // Hide mapping types - targetConceptTable.hideColumn("Valid start date"); - targetConceptTable.hideColumn("Valid end date"); - targetConceptTable.hideColumn("Invalid reason"); - - JScrollPane pane = new JScrollPane(targetConceptTable); - pane.setBorder(BorderFactory.createEmptyBorder()); - pane.setMinimumSize(new Dimension(500, 50)); - pane.setPreferredSize(new Dimension(500, 50)); - panel.add(pane); - - JPanel buttonPanel = new JPanel(); - buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS)); - buttonPanel.add(Box.createHorizontalGlue()); - - removeButton = new JButton("Remove concept"); - removeButton.setToolTipText("Add selected concept"); - removeButton.addActionListener(e -> remove()); - removeButton.setEnabled(false); - buttonPanel.add(removeButton); - panel.add(buttonPanel); - return panel; - } - - @Override - public void codeSelected(CodeMapping codeMapping) { - this.codeMapping = codeMapping; - toggleStatusButtons(); - sourceCodeTableModel.setMapping(codeMapping); - targetConceptTableModel.setConcepts(codeMapping.targetConcepts); - commentField.setText(codeMapping.comment); - doSearch(); - } - - @Override - public void addCodeMultiSelected(CodeMapping codeMapping) { - this.codeMappingsFromMulti.add(codeMapping); - } - - @Override - public void clearCodeMultiSelected() { - this.codeMappingsFromMulti = new ArrayList<>(); - } - - public void approve() { - if (codeMapping.mappingStatus != CodeMapping.MappingStatus.APPROVED) { - CodeMapping.Equivalence equivalenceToApply = (CodeMapping.Equivalence) equivalenceOptionChooser.getSelectedItem(); - codeMapping.approve(Global.author, equivalenceToApply); - Global.mapping.fireDataChanged(APPROVE_EVENT); - } else { - codeMapping.setUnchecked(); - Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - toggleStatusButtons(); - } - } - - public void flag() { - if (codeMapping.mappingStatus != CodeMapping.MappingStatus.FLAGGED) { - codeMapping.mappingStatus = MappingStatus.FLAGGED; - Global.mapping.fireDataChanged(APPROVE_EVENT); - } else { - codeMapping.mappingStatus = CodeMapping.MappingStatus.UNCHECKED; - Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - toggleStatusButtons(); - } - } - - private void toggleStatusButtons() { - Global.approveAction.setToApprove(); - Global.flagAction.setToFlag(); - flagButton.setEnabled(false); - approveButton.setEnabled(false); - equivalenceOptionChooser.setEnabled(false); - - switch(codeMapping.mappingStatus) { - case APPROVED: - Global.approveAction.setToUnapprove(); - approveButton.setEnabled(true); - break; - case FLAGGED: - Global.flagAction.setToUnflag(); - flagButton.setEnabled(true); - break; - default: // unchecked, invalid or auto-mapped - flagButton.setEnabled(true); - approveButton.setEnabled(true); - equivalenceOptionChooser.setEnabled(true); - } - } - - public void addConcept(Concept concept) { - codeMapping.targetConcepts.add(new MappingTarget(concept, Global.author)); - for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { - codeMappingMulti.targetConcepts.add(new MappingTarget(concept, Global.author)); - } - targetConceptTableModel.fireTableDataChanged(); - - if (codeMappingsFromMulti.size() > 0) { - Global.mapping.fireDataChanged(MULTI_UPDATE_EVENT); - } else { - Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - } - } - - public void replaceConcepts(Concept concept) { - codeMapping.targetConcepts.clear(); - for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { - codeMappingMulti.targetConcepts.clear(); - } - addConcept(concept); - } - - private void remove() { - List rows = new ArrayList<>(); - for (int row : targetConceptTable.getSelectedRows()) - rows.add(targetConceptTable.convertRowIndexToModel(row)); - - rows.sort(Comparator.reverseOrder()); - for (int row : rows) - codeMapping.targetConcepts.remove(row); - - targetConceptTableModel.fireTableDataChanged(); - Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - } - - private class SearchTask extends TimerTask { - - @Override - public void run() { - Set filterConceptIds = null; - if (filterPanel.getFilterByAuto()) - filterConceptIds = codeMapping.sourceCode.sourceAutoAssignedConceptIds; - - boolean filterStandard = filterPanel.getFilterStandard(); - Vector filterConceptClasses = null; - if (filterPanel.getFilterByConceptClasses()) - filterConceptClasses = filterPanel.getConceptClass(); - Vector filterVocabularies = null; - if (filterPanel.getFilterByVocabularies()) - filterVocabularies = filterPanel.getVocabulary(); - Vector filterDomains = null; - if (filterPanel.getFilterByDomains()) - filterDomains = filterPanel.getDomain(); - - String query; - if (autoQueryCodeButton.isSelected()) { - query = codeMapping.sourceCode.sourceName; - } else { - query = manualQueryField.getText(); - } - - boolean includeSourceConcepts = filterPanel.getIncludeSourceTerms(); - - if (Global.usagiSearchEngine.isOpenForSearching()) { - List searchResults = Global.usagiSearchEngine.search(query, true, filterConceptIds, filterDomains, filterConceptClasses, - filterVocabularies, filterStandard, includeSourceConcepts); - - searchTableModel.setScoredConcepts(searchResults); - searchTable.scrollRectToVisible(new Rectangle(searchTable.getCellRect(0, 0, true))); - } - Global.statusBar.setSearching(false); - } - } - - public void doSearch() { - Global.statusBar.setSearching(true); - if (timer != null) - timer.cancel(); - timer = new Timer(); - timer.schedule(new SearchTask(), 500); - } - - class SourceCodeTableModel extends AbstractTableModel { - private static final long serialVersionUID = 169286268154988911L; - - private String[] defaultColumnNames = { "Source code", "Source term", "Frequency" }; - private String[] columnNames = defaultColumnNames; - private CodeMapping codeMapping; - private int addInfoColCount = 0; - private int ADD_INFO_START_COL = 3; - - public int getColumnCount() { - return columnNames.length; - } - - public void setMapping(CodeMapping codeMapping) { - this.codeMapping = codeMapping; - - columnNames = defaultColumnNames; - addInfoColCount = codeMapping.sourceCode.sourceAdditionalInfo.size(); - columnNames = new String[defaultColumnNames.length + addInfoColCount]; - for (int i = 0; i < ADD_INFO_START_COL; i++) - columnNames[i] = defaultColumnNames[i]; - - for (int i = 0; i < addInfoColCount; i++) - columnNames[i + ADD_INFO_START_COL] = codeMapping.sourceCode.sourceAdditionalInfo.get(i).getItem1(); - - fireTableStructureChanged(); - } - - public int getRowCount() { - return 1; - } - - public String getColumnName(int col) { - return columnNames[col]; - } - - public Object getValueAt(int row, int col) { - if (codeMapping == null) - return ""; - if (col >= ADD_INFO_START_COL) { - return codeMapping.sourceCode.sourceAdditionalInfo.get(col - ADD_INFO_START_COL).getItem2(); - } else { - switch (col) { - case 0: - return codeMapping.sourceCode.sourceCode; - case 1: - return codeMapping.sourceCode.sourceName; - case 2: - return codeMapping.sourceCode.sourceFrequency; - default: - return ""; - } - } - - } - - public Class getColumnClass(int col) { - if (col >= ADD_INFO_START_COL) { - return String.class; - } else { - switch (col) { - case 2: - return Integer.class; - default: - return String.class; - } - } - } - - public boolean isCellEditable(int row, int col) { - return true; - } - - public void setValueAt(Object value, int row, int col) { - - } - } - - @Override - public void filterChanged() { - doSearch(); - } - -} +/******************************************************************************* + * Copyright 2019 Observational Health Data Sciences and Informatics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ******************************************************************************/ +package org.ohdsi.usagi.ui; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; +import java.util.Vector; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableRowSorter; + +import org.ohdsi.usagi.CodeMapping; +import org.ohdsi.usagi.CodeMapping.MappingStatus; +import org.ohdsi.usagi.Concept; +import org.ohdsi.usagi.MappingTarget; +import org.ohdsi.usagi.UsagiSearchEngine.ScoredConcept; + +import static org.ohdsi.usagi.ui.DataChangeEvent.*; + +public class MappingDetailPanel extends JPanel implements CodeSelectedListener, FilterChangeListener { + + private static final long serialVersionUID = 2127318722005512776L; + private UsagiTable sourceCodeTable; + private SourceCodeTableModel sourceCodeTableModel; + private UsagiTable targetConceptTable; + private TargetConceptTableModel targetConceptTableModel; + private UsagiTable searchTable; + private TableRowSorter sorter; + private ConceptTableModel searchTableModel; + private JButton approveButton; + private JButton flagButton; + private JComboBox equivalenceOptionChooser; + private JTextField commentField; + private JButton removeButton; + private JButton replaceButton; + private JButton addButton; + private JRadioButton autoQueryCodeButton; + private JRadioButton manualQueryButton; + private JTextField manualQueryField; + private CodeMapping codeMapping; + private List codeMappingsFromMulti; + private FilterPanel filterPanel; + private Timer timer; + + public MappingDetailPanel() { + super(); + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + add(createSourceCodePanel()); + add(createTargetConceptsPanel()); + add(createSearchPanel()); + add(createApprovePanel()); + codeMappingsFromMulti = new ArrayList<>(); + } + + private Component createSearchPanel() { + JPanel panel = new JPanel(); + panel.setBorder(BorderFactory.createTitledBorder("Search")); + panel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.BOTH; + + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.weighty = 0.1; + panel.add(createQueryPanel(), c); + + c.gridx = 1; + c.gridy = 0; + c.weightx = 0.1; + c.weighty = 0.1; + filterPanel = new FilterPanel(); + filterPanel.addListener(this); + panel.add(filterPanel, c); + + c.gridx = 0; + c.gridy = 1; + c.weightx = 1; + c.weighty = 1; + c.gridwidth = 2; + panel.add(createSearchResultsPanel(), c); + return panel; + } + + private Component createQueryPanel() { + JPanel panel = new JPanel(); + panel.setBorder(BorderFactory.createTitledBorder("Query")); + panel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.WEST; + c.gridx = GridBagConstraints.RELATIVE; + c.gridy = 0; + c.weightx = 0.1; + c.gridwidth = 2; + + autoQueryCodeButton = new JRadioButton("Use source term", true); + autoQueryCodeButton.addActionListener(x -> doSearch()); + panel.add(autoQueryCodeButton, c); + + c.gridx = 0; + c.gridy = 1; + c.weightx = 0.1; + c.gridwidth = 1; + manualQueryButton = new JRadioButton("Query:", false); + manualQueryButton.addActionListener(x -> doSearch()); + panel.add(manualQueryButton, c); + + ButtonGroup buttonGroup = new ButtonGroup(); + buttonGroup.add(autoQueryCodeButton); + buttonGroup.add(manualQueryButton); + + c.gridx = 1; + c.gridy = 1; + c.weightx = 1; + c.gridwidth = GridBagConstraints.REMAINDER; + manualQueryField = new JTextField(""); + // manualQueryField.setPreferredSize(new Dimension(200, 5)); + manualQueryField.getDocument().addDocumentListener(new DocumentListener() { + + @Override + public void removeUpdate(DocumentEvent arg0) { + manualQueryButton.setSelected(true); + doSearch(); + } + + @Override + public void insertUpdate(DocumentEvent arg0) { + manualQueryButton.setSelected(true); + doSearch(); + } + + @Override + public void changedUpdate(DocumentEvent arg0) { + manualQueryButton.setSelected(true); + doSearch(); + } + }); + panel.add(manualQueryField, c); + return panel; + } + + private Component createSearchResultsPanel() { + JPanel panel = new JPanel(); + panel.setBorder(BorderFactory.createTitledBorder("Results")); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + searchTableModel = new ConceptTableModel(true); + searchTable = new UsagiTable(searchTableModel); + sorter = new TableRowSorter(searchTableModel); + searchTable.setRowSorter(sorter); + searchTable.setPreferredScrollableViewportSize(new Dimension(100, 100)); + searchTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); + searchTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + searchTable.getSelectionModel().addListSelectionListener(event -> { + int viewRow = searchTable.getSelectedRow(); + // Don't enable the buttons if no row selected or status is approved + if (viewRow == -1 || codeMapping.mappingStatus == MappingStatus.APPROVED) { + addButton.setEnabled(false); + replaceButton.setEnabled(false); + } else { + addButton.setEnabled(true); + replaceButton.setEnabled(true); + int modelRow = searchTable.convertRowIndexToModel(viewRow); + Global.conceptInfoAction.setEnabled(true); + Global.conceptInformationDialog.setConcept(searchTableModel.getConcept(modelRow)); + Global.athenaAction.setEnabled(true); + Global.athenaAction.setConcept(searchTableModel.getConcept(modelRow)); + Global.googleSearchAction.setEnabled(false); + } + }); + // searchTable.hideColumn("Synonym"); + searchTable.hideColumn("Valid start date"); + searchTable.hideColumn("Valid end date"); + searchTable.hideColumn("Invalid reason"); + panel.add(new JScrollPane(searchTable)); + + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS)); + buttonPanel.add(Box.createHorizontalGlue()); + + replaceButton = new JButton("Replace concept"); + replaceButton.setToolTipText("Replace selected concept"); + replaceButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + int viewRow = searchTable.getSelectedRow(); + int modelRow = searchTable.convertRowIndexToModel(viewRow); + replaceConcepts(searchTableModel.getConcept(modelRow)); + } + + }); + replaceButton.setEnabled(false); + buttonPanel.add(replaceButton); + + addButton = new JButton("Add concept"); + addButton.setToolTipText("Add selected concept"); + addButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + int viewRow = searchTable.getSelectedRow(); + int modelRow = searchTable.convertRowIndexToModel(viewRow); + addConcept(searchTableModel.getConcept(modelRow)); + } + }); + addButton.setEnabled(false); + buttonPanel.add(addButton); + + panel.add(buttonPanel); + + return panel; + } + + private Component createApprovePanel() { + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); + + panel.add(new JLabel("Comment:")); + + panel.add(Box.createHorizontalStrut(5)); + + commentField = new JTextField(); + commentField.setMaximumSize(new Dimension(Integer.MAX_VALUE, commentField.getPreferredSize().height)); + commentField.getDocument().addDocumentListener(new DocumentListener() { + + @Override + public void removeUpdate(DocumentEvent arg0) { + codeMapping.comment = commentField.getText(); + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + } + + @Override + public void insertUpdate(DocumentEvent arg0) { + codeMapping.comment = commentField.getText(); + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + } + + @Override + public void changedUpdate(DocumentEvent arg0) { + codeMapping.comment = commentField.getText(); + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + } + }); + commentField.setToolTipText("Comments about the code mapping can be written here"); + panel.add(commentField); + + panel.add(Box.createHorizontalStrut(5)); + + flagButton = new JButton(Global.flagAction); + flagButton.setBackground(new Color(151, 220, 141)); + panel.add(flagButton); + + equivalenceOptionChooser = new JComboBox<>(CodeMapping.Equivalence.values()); + equivalenceOptionChooser.setToolTipText("Choose mapping equivalence"); + equivalenceOptionChooser.setMaximumSize(equivalenceOptionChooser.getPreferredSize()); + panel.add(equivalenceOptionChooser); + + approveButton = new JButton(Global.approveAction); + approveButton.setBackground(new Color(151, 220, 141)); + panel.add(approveButton); + + return panel; + } + + private JPanel createSourceCodePanel() { + JPanel panel = new JPanel(); + panel.setBorder(BorderFactory.createTitledBorder("Source code")); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + sourceCodeTableModel = new SourceCodeTableModel(); + sourceCodeTable = new UsagiTable(sourceCodeTableModel); + sourceCodeTable.setPreferredScrollableViewportSize(new Dimension(500, 35)); + sourceCodeTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); + sourceCodeTable.setRowSelectionAllowed(false); + sourceCodeTable.setCellSelectionEnabled(false); + JScrollPane pane = new JScrollPane(sourceCodeTable); + pane.setBorder(BorderFactory.createEmptyBorder()); + pane.setMinimumSize(new Dimension(500, 40)); + pane.setPreferredSize(new Dimension(500, 40)); + panel.add(pane); + + return panel; + } + + private JPanel createTargetConceptsPanel() { + JPanel panel = new JPanel(); + panel.setBorder(BorderFactory.createTitledBorder("Target concepts")); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + targetConceptTableModel = new TargetConceptTableModel(); + targetConceptTable = new UsagiTable(targetConceptTableModel); + targetConceptTable.setPreferredScrollableViewportSize(new Dimension(500, 45)); + targetConceptTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); + targetConceptTable.setRowSelectionAllowed(true); + targetConceptTable.getSelectionModel().addListSelectionListener(event -> { + int viewRow = targetConceptTable.getSelectedRow(); + if (viewRow == -1 || codeMapping.mappingStatus == MappingStatus.APPROVED) { + removeButton.setEnabled(false); + } else { + removeButton.setEnabled(true); + int modelRow = targetConceptTable.convertRowIndexToModel(viewRow); + MappingTarget mappingTarget = targetConceptTableModel.getMappingTarget(modelRow); + Global.conceptInfoAction.setEnabled(true); + Global.conceptInformationDialog.setConcept(mappingTarget.concept); + Global.athenaAction.setEnabled(true); + Global.athenaAction.setConcept(mappingTarget.concept); + Global.googleSearchAction.setEnabled(false); + } + }); + targetConceptTable.hideColumn("Mapping Type"); // Hide mapping types + targetConceptTable.hideColumn("Valid start date"); + targetConceptTable.hideColumn("Valid end date"); + targetConceptTable.hideColumn("Invalid reason"); + + JScrollPane pane = new JScrollPane(targetConceptTable); + pane.setBorder(BorderFactory.createEmptyBorder()); + pane.setMinimumSize(new Dimension(500, 50)); + pane.setPreferredSize(new Dimension(500, 50)); + panel.add(pane); + + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS)); + buttonPanel.add(Box.createHorizontalGlue()); + + removeButton = new JButton("Remove concept"); + removeButton.setToolTipText("Add selected concept"); + removeButton.addActionListener(e -> remove()); + removeButton.setEnabled(false); + buttonPanel.add(removeButton); + panel.add(buttonPanel); + return panel; + } + + @Override + public void codeSelected(CodeMapping codeMapping) { + this.codeMapping = codeMapping; + toggleStatusButtons(); + sourceCodeTableModel.setMapping(codeMapping); + targetConceptTableModel.setConcepts(codeMapping.targetConcepts); + commentField.setText(codeMapping.comment); + doSearch(); + } + + @Override + public void addCodeMultiSelected(CodeMapping codeMapping) { + this.codeMappingsFromMulti.add(codeMapping); + } + + @Override + public void clearCodeMultiSelected() { + this.codeMappingsFromMulti = new ArrayList<>(); + } + + public void approve() { + if (codeMapping.mappingStatus != CodeMapping.MappingStatus.APPROVED) { + CodeMapping.Equivalence equivalenceToApply = (CodeMapping.Equivalence) equivalenceOptionChooser.getSelectedItem(); + codeMapping.approve(Global.author, equivalenceToApply); + Global.mapping.fireDataChanged(APPROVE_EVENT); + } else { + codeMapping.setUnchecked(); + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + toggleStatusButtons(); + } + } + + public void flag() { + if (codeMapping.mappingStatus != CodeMapping.MappingStatus.FLAGGED) { + codeMapping.mappingStatus = MappingStatus.FLAGGED; + Global.mapping.fireDataChanged(APPROVE_EVENT); + } else { + codeMapping.mappingStatus = CodeMapping.MappingStatus.UNCHECKED; + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + toggleStatusButtons(); + } + } + + private void toggleStatusButtons() { + Global.approveAction.setToApprove(); + Global.flagAction.setToFlag(); + flagButton.setEnabled(false); + approveButton.setEnabled(false); + equivalenceOptionChooser.setEnabled(false); + + switch(codeMapping.mappingStatus) { + case APPROVED: + Global.approveAction.setToUnapprove(); + approveButton.setEnabled(true); + break; + case FLAGGED: + Global.flagAction.setToUnflag(); + flagButton.setEnabled(true); + break; + default: // unchecked, invalid or auto-mapped + flagButton.setEnabled(true); + approveButton.setEnabled(true); + equivalenceOptionChooser.setEnabled(true); + } + } + + public void addConcept(Concept concept) { + codeMapping.targetConcepts.add(new MappingTarget(concept, Global.author)); + for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { + codeMappingMulti.targetConcepts.add(new MappingTarget(concept, Global.author)); + } + targetConceptTableModel.fireTableDataChanged(); + + if (codeMappingsFromMulti.size() > 0) { + Global.mapping.fireDataChanged(MULTI_UPDATE_EVENT); + } else { + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + } + } + + public void replaceConcepts(Concept concept) { + codeMapping.targetConcepts.clear(); + for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { + codeMappingMulti.targetConcepts.clear(); + } + addConcept(concept); + } + + private void remove() { + List rows = new ArrayList<>(); + for (int row : targetConceptTable.getSelectedRows()) + rows.add(targetConceptTable.convertRowIndexToModel(row)); + + rows.sort(Comparator.reverseOrder()); + for (int row : rows) + codeMapping.targetConcepts.remove(row); + + targetConceptTableModel.fireTableDataChanged(); + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + } + + private class SearchTask extends TimerTask { + + @Override + public void run() { + Set filterConceptIds = null; + if (filterPanel.getFilterByAuto()) + filterConceptIds = codeMapping.sourceCode.sourceAutoAssignedConceptIds; + + boolean filterStandard = filterPanel.getFilterStandard(); + Vector filterConceptClasses = null; + if (filterPanel.getFilterByConceptClasses()) + filterConceptClasses = filterPanel.getConceptClass(); + Vector filterVocabularies = null; + if (filterPanel.getFilterByVocabularies()) + filterVocabularies = filterPanel.getVocabulary(); + Vector filterDomains = null; + if (filterPanel.getFilterByDomains()) + filterDomains = filterPanel.getDomain(); + + String query; + if (autoQueryCodeButton.isSelected()) { + query = codeMapping.sourceCode.sourceName; + } else { + query = manualQueryField.getText(); + } + + boolean includeSourceConcepts = filterPanel.getIncludeSourceTerms(); + + if (Global.usagiSearchEngine.isOpenForSearching()) { + List searchResults = Global.usagiSearchEngine.search(query, true, filterConceptIds, filterDomains, filterConceptClasses, + filterVocabularies, filterStandard, includeSourceConcepts); + + searchTableModel.setScoredConcepts(searchResults); + searchTable.scrollRectToVisible(new Rectangle(searchTable.getCellRect(0, 0, true))); + } + Global.statusBar.setSearching(false); + } + } + + public void doSearch() { + Global.statusBar.setSearching(true); + if (timer != null) + timer.cancel(); + timer = new Timer(); + timer.schedule(new SearchTask(), 500); + } + + class SourceCodeTableModel extends AbstractTableModel { + private static final long serialVersionUID = 169286268154988911L; + + private String[] defaultColumnNames = { "Source code", "Source term", "Frequency" }; + private String[] columnNames = defaultColumnNames; + private CodeMapping codeMapping; + private int addInfoColCount = 0; + private int ADD_INFO_START_COL = 3; + + public int getColumnCount() { + return columnNames.length; + } + + public void setMapping(CodeMapping codeMapping) { + this.codeMapping = codeMapping; + + columnNames = defaultColumnNames; + addInfoColCount = codeMapping.sourceCode.sourceAdditionalInfo.size(); + columnNames = new String[defaultColumnNames.length + addInfoColCount]; + for (int i = 0; i < ADD_INFO_START_COL; i++) + columnNames[i] = defaultColumnNames[i]; + + for (int i = 0; i < addInfoColCount; i++) + columnNames[i + ADD_INFO_START_COL] = codeMapping.sourceCode.sourceAdditionalInfo.get(i).getItem1(); + + fireTableStructureChanged(); + } + + public int getRowCount() { + return 1; + } + + public String getColumnName(int col) { + return columnNames[col]; + } + + public Object getValueAt(int row, int col) { + if (codeMapping == null) + return ""; + if (col >= ADD_INFO_START_COL) { + return codeMapping.sourceCode.sourceAdditionalInfo.get(col - ADD_INFO_START_COL).getItem2(); + } else { + switch (col) { + case 0: + return codeMapping.sourceCode.sourceCode; + case 1: + return codeMapping.sourceCode.sourceName; + case 2: + return codeMapping.sourceCode.sourceFrequency; + default: + return ""; + } + } + + } + + public Class getColumnClass(int col) { + if (col >= ADD_INFO_START_COL) { + return String.class; + } else { + switch (col) { + case 2: + return Integer.class; + default: + return String.class; + } + } + } + + public boolean isCellEditable(int row, int col) { + return true; + } + + public void setValueAt(Object value, int row, int col) { + + } + } + + @Override + public void filterChanged() { + doSearch(); + } + +} diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 9cad690..b860c4e 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -107,9 +107,9 @@ public MappingTablePanel() { class CodeMapTableModel extends AbstractTableModel { private static final long serialVersionUID = 169286268154988911L; - private String[] defaultColumnNames = { "Status", "Source code", "Source term", "Frequency", - "Match score", "Concept ID", "Concept name", "Domain", "Concept class", "Vocabulary", "Concept code", - "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", "Children", "Assigned To", "Equivalence", "Comment", "Status Provenance" }; + private String[] defaultColumnNames = { "Status", "Source code", "Source term", "Frequency", "Match score", "Concept ID", "Concept name", + "Domain", "Concept class", "Vocabulary", "Concept code", "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", + "Children", "Assigned To", "Equivalence", "Comment", "Status Provenance" }; private String[] columnNames = defaultColumnNames; private int addInfoColCount = 0; private final int ADD_INFO_START_COL = 7; diff --git a/src/org/ohdsi/usagi/ui/UsagiMain.java b/src/org/ohdsi/usagi/ui/UsagiMain.java index 6beb4ab..b710df9 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMain.java +++ b/src/org/ohdsi/usagi/ui/UsagiMain.java @@ -144,10 +144,8 @@ public void windowClosing(WindowEvent e) { OpenAction.open(new File(args[1])); } - // TODO: save author to file and load if available AuthorDialog authorDialog = new AuthorDialog(); authorDialog.setVisible(true); - } private String loadVocabularyVersion(String folder) { From 465c862a8bb9dc5da086f03cf210cdd2a1aebe5a Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Wed, 17 Feb 2021 13:48:41 +0100 Subject: [PATCH 58/77] remove redundant mapping type reference --- src/org/ohdsi/usagi/ui/MappingDetailPanel.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 802e786..fde4c07 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -330,7 +330,6 @@ private JPanel createTargetConceptsPanel() { Global.googleSearchAction.setEnabled(false); } }); - targetConceptTable.hideColumn("Mapping Type"); // Hide mapping types targetConceptTable.hideColumn("Valid start date"); targetConceptTable.hideColumn("Valid end date"); targetConceptTable.hideColumn("Invalid reason"); From 4468adee4c782b2ed116252e219b0c26e55b54e2 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Wed, 17 Feb 2021 17:17:15 +0100 Subject: [PATCH 59/77] upon opening mapping, if cell empty, assign default value if given --- src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java | 6 +----- src/org/ohdsi/usagi/ui/Mapping.java | 1 + src/org/ohdsi/utilities/files/Row.java | 12 +++++++++--- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java index 2f901a4..f3cfe09 100644 --- a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java +++ b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java @@ -65,12 +65,8 @@ private void readNext() { buffer.statusSetOn = row.getLong("statusSetOn", "0"); buffer.equivalence = Equivalence.valueOf(row.get("equivalence", "UNREVIEWED")); buffer.assignedReviewer = row.get("assignedReviewer", ""); + buffer.comment = row.get("comment", ""); - try { - buffer.comment = row.get("comment"); - } catch (Exception e) { - buffer.comment = ""; - } while (row != null && new SourceCode(row).sourceCode.equals(buffer.sourceCode.sourceCode) && new SourceCode(row).sourceName.equals(buffer.sourceCode.sourceName)) { diff --git a/src/org/ohdsi/usagi/ui/Mapping.java b/src/org/ohdsi/usagi/ui/Mapping.java index d2c6305..7358ded 100644 --- a/src/org/ohdsi/usagi/ui/Mapping.java +++ b/src/org/ohdsi/usagi/ui/Mapping.java @@ -42,6 +42,7 @@ public void loadFromFile(String filename) { } } } catch (Exception e) { + e.printStackTrace(); JOptionPane.showMessageDialog( Global.frame, "Invalid File Format: '" + e.getMessage() + "'", diff --git a/src/org/ohdsi/utilities/files/Row.java b/src/org/ohdsi/utilities/files/Row.java index 2788566..323eab2 100644 --- a/src/org/ohdsi/utilities/files/Row.java +++ b/src/org/ohdsi/utilities/files/Row.java @@ -54,11 +54,17 @@ public String get(String fieldName, String defaultValue) { return defaultValue; } } + index = fieldName2ColumnIndex.get(fieldName); - if (cells.size() <= index) + if (cells.size() <= index) { return ""; - else - return cells.get(index); + } + + String value = cells.get(index); + if (value.isEmpty() && defaultValue != null) { + return defaultValue; + } + return value; } public List getFieldNames() { From 0a1cac057b4028761e88506acb5d0b938b2a7cc5 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Wed, 17 Feb 2021 18:11:24 +0100 Subject: [PATCH 60/77] refactor target concept removal --- .../ohdsi/usagi/ui/MappingDetailPanel.java | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index fde4c07..73b6079 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -23,13 +23,8 @@ import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.Timer; -import java.util.TimerTask; -import java.util.Vector; import javax.swing.*; import javax.swing.event.DocumentEvent; @@ -345,7 +340,7 @@ private JPanel createTargetConceptsPanel() { buttonPanel.add(Box.createHorizontalGlue()); removeButton = new JButton("Remove concept"); - removeButton.setToolTipText("Add selected concept"); + removeButton.setToolTipText("Remove selected concept"); removeButton.addActionListener(e -> remove()); removeButton.setEnabled(false); buttonPanel.add(removeButton); @@ -442,13 +437,10 @@ public void replaceConcepts(Concept concept) { } private void remove() { - List rows = new ArrayList<>(); - for (int row : targetConceptTable.getSelectedRows()) - rows.add(targetConceptTable.convertRowIndexToModel(row)); - - rows.sort(Comparator.reverseOrder()); - for (int row : rows) - codeMapping.targetConcepts.remove(row); + Arrays.stream(targetConceptTable.getSelectedRows()) + .map(r -> targetConceptTable.convertRowIndexToModel(r)) + .boxed().sorted(Comparator.reverseOrder()).mapToInt(Integer::intValue) // sorting for array integrity, remove last first. + .forEach(r -> codeMapping.targetConcepts.remove(r)); targetConceptTableModel.fireTableDataChanged(); Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); From 32b41801745d0e0d055b3fe86ca1dd3c22f0d4a1 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Wed, 17 Feb 2021 18:27:51 +0100 Subject: [PATCH 61/77] fix editable assigned reviewer column --- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index b860c4e..09fb911 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -113,6 +113,7 @@ class CodeMapTableModel extends AbstractTableModel { private String[] columnNames = defaultColumnNames; private int addInfoColCount = 0; private final int ADD_INFO_START_COL = 7; + private static final int ASSIGNED_REVIEWER_COL = 17; // special meaning, as public int getColumnCount() { return columnNames.length; @@ -197,7 +198,7 @@ public Object getValueAt(int row, int col) { return targetConcept.parentCount; case 16: return targetConcept.childCount; - case 17: + case ASSIGNED_REVIEWER_COL: return codeMapping.assignedReviewer; case 18: if (codeMapping.equivalence != CodeMapping.Equivalence.UNREVIEWED) { @@ -245,7 +246,7 @@ public Class getColumnClass(int col) { public boolean isCellEditable(int row, int col) { col = resolveColumnIndex(col); - if (col == 20) { + if (col == ASSIGNED_REVIEWER_COL) { return true; } return false; @@ -253,7 +254,7 @@ public boolean isCellEditable(int row, int col) { public void setValueAt(Object value, int row, int col) { col = resolveColumnIndex(col); - if (col == 17) { + if (col == ASSIGNED_REVIEWER_COL) { CodeMapping codeMapping = Global.mapping.get(row); codeMapping.assignedReviewer = (String) value; } From 961b2d8517a666be1486ced06211d59eba397004 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Wed, 17 Feb 2021 18:28:34 +0100 Subject: [PATCH 62/77] Use ThreadLocalRandom instead of Random Co-authored-by: Joris Borgdorff --- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 09fb911..7e11d5d 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -327,7 +327,7 @@ public void clearSelected() { public void assignReviewersRandomly(String[] reviewers) { // Randomly assign code mappings to given reviewers - Random randomGenerator = new Random(); + Random randomGenerator = ThreadLocalRandom.current(); for (CodeMapping codeMapping : Global.mapping) { int random = randomGenerator.nextInt(reviewers.length); codeMapping.assignedReviewer = reviewers[random]; From 6aa5b0ef9f86281068f344a119ce257cae508036 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Wed, 17 Feb 2021 18:39:09 +0100 Subject: [PATCH 63/77] refactor reviewer assignemnt --- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 16 ++++++++++------ .../ohdsi/usagi/ui/ReviewerAssignmentDialog.java | 4 +++- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 7e11d5d..1aae63a 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -20,7 +20,9 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.Collectors; +import java.util.stream.IntStream; import javax.swing.BoxLayout; import javax.swing.JPanel; @@ -327,7 +329,7 @@ public void clearSelected() { public void assignReviewersRandomly(String[] reviewers) { // Randomly assign code mappings to given reviewers - Random randomGenerator = ThreadLocalRandom.current(); + ThreadLocalRandom randomGenerator = ThreadLocalRandom.current(); for (CodeMapping codeMapping : Global.mapping) { int random = randomGenerator.nextInt(reviewers.length); codeMapping.assignedReviewer = reviewers[random]; @@ -341,10 +343,12 @@ public void assignReviewersEqually(String[] reviewers) { // If the number of code mappings is not a multiple of the number of reviewers, // then the first, second, etc. reviewer get one mapping more assigned. int nReviewers = reviewers.length; - Mapping shuffledCodeMapping = (Mapping) Global.mapping.clone(); - Collections.shuffle(shuffledCodeMapping); - for (int i = 0; i < shuffledCodeMapping.size(); i++) { - CodeMapping codeMapping = shuffledCodeMapping.get(i); + List codeMappingIndex = IntStream.range(0, Global.mapping.size()) + .boxed().collect(Collectors.toList()); + + Collections.shuffle(codeMappingIndex); + for (int i = 0; i < codeMappingIndex.size(); i++) { + CodeMapping codeMapping = Global.mapping.get(codeMappingIndex.get(i)); codeMapping.assignedReviewer = reviewers[i % nReviewers]; } fireUpdateEventAll(APPROVE_EVENT); diff --git a/src/org/ohdsi/usagi/ui/ReviewerAssignmentDialog.java b/src/org/ohdsi/usagi/ui/ReviewerAssignmentDialog.java index f0e3dfe..409a30a 100644 --- a/src/org/ohdsi/usagi/ui/ReviewerAssignmentDialog.java +++ b/src/org/ohdsi/usagi/ui/ReviewerAssignmentDialog.java @@ -52,7 +52,9 @@ public ReviewerAssignmentDialog() { JButton saveButton = new JButton("Assign"); saveButton.setToolTipText("Assign reviewers"); saveButton.addActionListener(event -> { - String[] reviewers = Arrays.stream(reviewersField.getText().split(",")).map(String::trim).toArray(String[]::new); + String[] reviewers = Arrays.stream(reviewersField.getText().split(",")) + .map(String::trim) + .toArray(String[]::new); Global.mappingTablePanel.assignReviewersEqually( reviewers ); From abe3d87f98fd58e6787fc7c99e1b30043a1d534d Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Wed, 17 Feb 2021 18:43:15 +0100 Subject: [PATCH 64/77] refactorings --- src/org/ohdsi/usagi/MappingTarget.java | 10 ++++++---- src/org/ohdsi/usagi/WriteCodeMappingsToFile.java | 3 +-- src/org/ohdsi/usagi/ui/TargetConceptTableModel.java | 5 ++--- .../ohdsi/usagi/ui/actions/ExportForReviewAction.java | 4 +++- src/org/ohdsi/utilities/files/Row.java | 6 +++--- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/org/ohdsi/usagi/MappingTarget.java b/src/org/ohdsi/usagi/MappingTarget.java index f8ae9b2..3d5a770 100644 --- a/src/org/ohdsi/usagi/MappingTarget.java +++ b/src/org/ohdsi/usagi/MappingTarget.java @@ -22,22 +22,22 @@ public class MappingTarget{ public Concept concept; public String createdBy; - public long createdOn; + public long createdTime; public MappingTarget() { this.concept = Concept.createEmptyConcept(); this.createdBy = ""; - this.createdOn = 0; + this.createdTime = 0; } public MappingTarget(Concept concept, String createdBy) { this(concept, createdBy, System.currentTimeMillis()); } - public MappingTarget(Concept concept, String createdBy, long createdOn) { + public MappingTarget(Concept concept, String createdBy, long createdTime) { this.concept = concept; this.createdBy = createdBy; - this.createdOn = createdOn; + this.createdTime = createdTime; } public Concept getConcept() { @@ -47,4 +47,6 @@ public Concept getConcept() { public void setConcept(Concept concept) { this.concept = concept; } + + } diff --git a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java index a8f3617..7c54422 100644 --- a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java +++ b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java @@ -15,7 +15,6 @@ ******************************************************************************/ package org.ohdsi.usagi; -import java.math.RoundingMode; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.ArrayList; @@ -55,7 +54,7 @@ public void write(CodeMapping codeMapping) { row.add("conceptName", targetConcept.concept.conceptName); // Never read in. row.add("comment", codeMapping.comment); row.add("createdBy", targetConcept.createdBy); - row.add("createdOn", targetConcept.createdOn); + row.add("createdOn", targetConcept.createdTime); row.add("assignedReviewer", codeMapping.assignedReviewer); out.write(row); } diff --git a/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java b/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java index 88a0e96..6943518 100644 --- a/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java +++ b/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java @@ -2,7 +2,6 @@ import org.ohdsi.usagi.Concept; import org.ohdsi.usagi.MappingTarget; -import org.ohdsi.usagi.UsagiSearchEngine.ScoredConcept; import javax.swing.table.AbstractTableModel; import java.util.ArrayList; @@ -76,8 +75,8 @@ public Object getValueAt(int row, int col) { case 11: return targetConcept.concept.childCount; case 12: - if (targetConcept.createdOn != 0L) { - return String.format("%s (%tF)", targetConcept.createdBy, targetConcept.createdOn); + if (targetConcept.createdTime != 0L) { + return String.format("%s (%tF)", targetConcept.createdBy, targetConcept.createdTime); } default: return ""; diff --git a/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java b/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java index 09ce71c..1586729 100644 --- a/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java @@ -85,7 +85,9 @@ public void actionPerformed(ActionEvent arg0) { targetConcepts = new ArrayList(1); targetConcepts.add(Concept.EMPTY_CONCEPT); } else - targetConcepts = mapping.targetConcepts.stream().map(MappingTarget::getConcept).collect(Collectors.toList()); + targetConcepts = mapping.targetConcepts.stream() + .map(MappingTarget::getConcept) + .collect(Collectors.toList()); for (Concept targetConcept : targetConcepts) { Row row = mapping.sourceCode.toRow(); diff --git a/src/org/ohdsi/utilities/files/Row.java b/src/org/ohdsi/utilities/files/Row.java index 323eab2..5cd29d6 100644 --- a/src/org/ohdsi/utilities/files/Row.java +++ b/src/org/ohdsi/utilities/files/Row.java @@ -48,10 +48,10 @@ public String get(String fieldName) { public String get(String fieldName, String defaultValue) { int index; if (!fieldName2ColumnIndex.containsKey(fieldName)) { - if (defaultValue == null) { - throw new RuntimeException("Field \"" + fieldName + "\" not found"); - } else { + if (defaultValue != null) { return defaultValue; + } else { + throw new RuntimeException("Field \"" + fieldName + "\" not found"); } } From d3dbdebefed50582bf1a7e24d9077d8df1a81a1c Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Wed, 17 Feb 2021 18:46:05 +0100 Subject: [PATCH 65/77] refactor mappingtarget class --- src/org/ohdsi/usagi/MappingTarget.java | 14 ++++---- .../ohdsi/usagi/WriteCodeMappingsToFile.java | 8 ++--- .../usagi/ui/TargetConceptTableModel.java | 34 +++++++++---------- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/org/ohdsi/usagi/MappingTarget.java b/src/org/ohdsi/usagi/MappingTarget.java index 3d5a770..a8e3ab6 100644 --- a/src/org/ohdsi/usagi/MappingTarget.java +++ b/src/org/ohdsi/usagi/MappingTarget.java @@ -20,9 +20,9 @@ */ public class MappingTarget{ - public Concept concept; - public String createdBy; - public long createdTime; + private final Concept concept; + private final String createdBy; + private final long createdTime; public MappingTarget() { this.concept = Concept.createEmptyConcept(); @@ -44,9 +44,11 @@ public Concept getConcept() { return concept; } - public void setConcept(Concept concept) { - this.concept = concept; + public String getCreatedBy() { + return createdBy; } - + public long getCreatedTime() { + return createdTime; + } } diff --git a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java index 7c54422..9c4c493 100644 --- a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java +++ b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java @@ -50,11 +50,11 @@ public void write(CodeMapping codeMapping) { row.add("equivalence", codeMapping.equivalence.toString()); row.add("statusSetBy", codeMapping.statusSetBy); row.add("statusSetOn", codeMapping.statusSetOn); - row.add("conceptId", targetConcept.concept.conceptId); - row.add("conceptName", targetConcept.concept.conceptName); // Never read in. + row.add("conceptId", targetConcept.getConcept().conceptId); + row.add("conceptName", targetConcept.getConcept().conceptName); // Never read in. row.add("comment", codeMapping.comment); - row.add("createdBy", targetConcept.createdBy); - row.add("createdOn", targetConcept.createdTime); + row.add("createdBy", targetConcept.getCreatedBy()); + row.add("createdOn", targetConcept.getCreatedTime()); row.add("assignedReviewer", codeMapping.assignedReviewer); out.write(row); } diff --git a/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java b/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java index 6943518..c531434 100644 --- a/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java +++ b/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java @@ -10,7 +10,6 @@ class TargetConceptTableModel extends AbstractTableModel { private static final long serialVersionUID = -4978479688021056281L; - private final String termColumnName = "Term"; private final String[] columnNames = {"Concept ID", "Concept name", "Domain", "Concept class", "Vocabulary", "Concept code", "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", "Children", "Mapping Type", "Creation Provenance"}; @@ -24,7 +23,7 @@ public MappingTarget getMappingTarget(int row) { } public Concept getConcept(int row) { - return getMappingTarget(row).concept; + return getMappingTarget(row).getConcept(); } public int getColumnCount() { @@ -48,35 +47,36 @@ public Object getValueAt(int row, int col) { if (row > targetConcepts.size()) { return ""; } - MappingTarget targetConcept = targetConcepts.get(row); + MappingTarget mappingTarget = targetConcepts.get(row); + Concept targetConcept = mappingTarget.getConcept(); switch (col) { case 0: - return targetConcept.concept.conceptId; + return targetConcept.conceptId; case 1: - return targetConcept.concept.conceptName; + return targetConcept.conceptName; case 2: - return targetConcept.concept.domainId; + return targetConcept.domainId; case 3: - return targetConcept.concept.conceptClassId; + return targetConcept.conceptClassId; case 4: - return targetConcept.concept.vocabularyId; + return targetConcept.vocabularyId; case 5: - return targetConcept.concept.conceptCode; + return targetConcept.conceptCode; case 6: - return targetConcept.concept.validStartDate; + return targetConcept.validStartDate; case 7: - return targetConcept.concept.validEndDate; + return targetConcept.validEndDate; case 8: - return targetConcept.concept.invalidReason; + return targetConcept.invalidReason; case 9: - return targetConcept.concept.standardConcept; + return targetConcept.standardConcept; case 10: - return targetConcept.concept.parentCount; + return targetConcept.parentCount; case 11: - return targetConcept.concept.childCount; + return targetConcept.childCount; case 12: - if (targetConcept.createdTime != 0L) { - return String.format("%s (%tF)", targetConcept.createdBy, targetConcept.createdTime); + if (mappingTarget.getCreatedTime() != 0L) { + return String.format("%s (%tF)", mappingTarget.getCreatedBy(), mappingTarget.getCreatedTime()); } default: return ""; From 97267affefca5f5ed0fc4d35b1d872a721806a7f Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Wed, 17 Feb 2021 18:59:02 +0100 Subject: [PATCH 66/77] refactor codemapping class to have private members --- src/org/ohdsi/usagi/CodeMapping.java | 106 +++++++++++++++--- .../ohdsi/usagi/ReadCodeMappingsFromFile.java | 24 ++-- .../ohdsi/usagi/WriteCodeMappingsToFile.java | 20 ++-- .../ohdsi/usagi/dataImport/ImportData.java | 16 +-- .../ui/ExportSourceToConceptMapDialog.java | 10 +- src/org/ohdsi/usagi/ui/ImportDialog.java | 16 +-- src/org/ohdsi/usagi/ui/Mapping.java | 4 +- .../ohdsi/usagi/ui/MappingDetailPanel.java | 54 ++++----- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 48 ++++---- src/org/ohdsi/usagi/ui/UsagiStatusBar.java | 10 +- .../actions/ApplyPreviousMappingAction.java | 12 +- .../ui/actions/ExportForReviewAction.java | 14 +-- .../ExportSourceToConceptMapAction.java | 2 +- 13 files changed, 204 insertions(+), 132 deletions(-) diff --git a/src/org/ohdsi/usagi/CodeMapping.java b/src/org/ohdsi/usagi/CodeMapping.java index d1017cc..511858c 100644 --- a/src/org/ohdsi/usagi/CodeMapping.java +++ b/src/org/ohdsi/usagi/CodeMapping.java @@ -33,38 +33,110 @@ public enum Equivalence { EQUAL, EQUIVALENT, WIDER, NARROWER, INEXACT, UNMATCHED, UNREVIEWED }; - public SourceCode sourceCode; - public double matchScore; - public MappingStatus mappingStatus; - public Equivalence equivalence; - public List targetConcepts = new ArrayList<>(1); - public String comment; - public String statusSetBy; - public long statusSetOn; - public String assignedReviewer; + private SourceCode sourceCode; + private double matchScore; + private MappingStatus mappingStatus; + private Equivalence equivalence; + private List targetConcepts = new ArrayList<>(1); + private String comment; + private String statusSetBy; + private long statusSetOn; + private String assignedReviewer; public CodeMapping(SourceCode sourceCode) { - this.sourceCode = sourceCode; + this.setSourceCode(sourceCode); } public void setStatus(MappingStatus mappingStatus, String author) { - this.mappingStatus = mappingStatus; - this.statusSetOn = System.currentTimeMillis(); - this.statusSetBy = author; + this.setMappingStatus(mappingStatus); + this.setStatusSetOn(System.currentTimeMillis()); + this.setStatusSetBy(author); } public void setUnchecked() { - this.mappingStatus = MappingStatus.UNCHECKED; - this.statusSetOn = 0; - this.statusSetBy = ""; + this.setMappingStatus(MappingStatus.UNCHECKED); + this.setStatusSetOn(0); + this.setStatusSetBy(""); } public void approve(String approvedBy, Equivalence equivalence) { setStatus(MappingStatus.APPROVED, approvedBy); - this.equivalence = equivalence; + this.setEquivalence(equivalence); } public void approve(String approvedBy) { approve(approvedBy, Equivalence.EQUAL); } + + public SourceCode getSourceCode() { + return sourceCode; + } + + public void setSourceCode(SourceCode sourceCode) { + this.sourceCode = sourceCode; + } + + public double getMatchScore() { + return matchScore; + } + + public void setMatchScore(double matchScore) { + this.matchScore = matchScore; + } + + public MappingStatus getMappingStatus() { + return mappingStatus; + } + + public void setMappingStatus(MappingStatus mappingStatus) { + this.mappingStatus = mappingStatus; + } + + public Equivalence getEquivalence() { + return equivalence; + } + + public void setEquivalence(Equivalence equivalence) { + this.equivalence = equivalence; + } + + public List getTargetConcepts() { + return targetConcepts; + } + + public void setTargetConcepts(List targetConcepts) { + this.targetConcepts = targetConcepts; + } + + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } + + public String getStatusSetBy() { + return statusSetBy; + } + + public void setStatusSetBy(String statusSetBy) { + this.statusSetBy = statusSetBy; + } + + public long getStatusSetOn() { + return statusSetOn; + } + + public void setStatusSetOn(long statusSetOn) { + this.statusSetOn = statusSetOn; + } + + public String getAssignedReviewer() { + return assignedReviewer; + } + + public void setAssignedReviewer(String assignedReviewer) { + this.assignedReviewer = assignedReviewer; + } } diff --git a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java index f3cfe09..1462a11 100644 --- a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java +++ b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java @@ -57,25 +57,25 @@ private void readNext() { buffer = null; } else { buffer = new CodeMapping(new SourceCode(row)); - buffer.matchScore = row.getDouble("matchScore"); - buffer.mappingStatus = MappingStatus.valueOf(row.get("mappingStatus")); + buffer.setMatchScore(row.getDouble("matchScore")); + buffer.setMappingStatus(MappingStatus.valueOf(row.get("mappingStatus"))); // Status provenance and review need a default as these fields might not be available in older Usagi files - buffer.statusSetBy = row.get("statusSetBy", ""); - buffer.statusSetOn = row.getLong("statusSetOn", "0"); - buffer.equivalence = Equivalence.valueOf(row.get("equivalence", "UNREVIEWED")); - buffer.assignedReviewer = row.get("assignedReviewer", ""); - buffer.comment = row.get("comment", ""); + buffer.setStatusSetBy(row.get("statusSetBy", "")); + buffer.setStatusSetOn(row.getLong("statusSetOn", "0")); + buffer.setEquivalence(Equivalence.valueOf(row.get("equivalence", "UNREVIEWED"))); + buffer.setAssignedReviewer(row.get("assignedReviewer", "")); + buffer.setComment(row.get("comment", "")); while (row != null - && new SourceCode(row).sourceCode.equals(buffer.sourceCode.sourceCode) - && new SourceCode(row).sourceName.equals(buffer.sourceCode.sourceName)) { + && new SourceCode(row).sourceCode.equals(buffer.getSourceCode().sourceCode) + && new SourceCode(row).sourceName.equals(buffer.getSourceCode().sourceName)) { if (row.getInt("conceptId") != 0) { Concept concept = Global.dbEngine.getConcept(row.getInt("conceptId")); if (concept == null) { - buffer.mappingStatus = MappingStatus.INVALID_TARGET; - buffer.comment = "Invalid existing target: " + row.get("conceptId"); + buffer.setMappingStatus(MappingStatus.INVALID_TARGET); + buffer.setComment("Invalid existing target: " + row.get("conceptId")); } else { // Provenance might not be available in older Usagi files MappingTarget mappingTarget = new MappingTarget( @@ -83,7 +83,7 @@ && new SourceCode(row).sourceName.equals(buffer.sourceCode.sourceName)) { row.get("createdBy", ""), row.getLong("createdOn", "0") ); - buffer.targetConcepts.add(mappingTarget); + buffer.getTargetConcepts().add(mappingTarget); } } if (iterator.hasNext()) diff --git a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java index 9c4c493..7a370a1 100644 --- a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java +++ b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java @@ -37,25 +37,25 @@ public WriteCodeMappingsToFile(String filename) { public void write(CodeMapping codeMapping) { List mappingTargets; - if (codeMapping.targetConcepts.size() == 0) { + if (codeMapping.getTargetConcepts().size() == 0) { mappingTargets = new ArrayList<>(1); mappingTargets.add(new MappingTarget()); } else { - mappingTargets = codeMapping.targetConcepts; + mappingTargets = codeMapping.getTargetConcepts(); } for (MappingTarget targetConcept : mappingTargets) { - Row row = codeMapping.sourceCode.toRow(); - row.add("matchScore", scoreFormat.format(codeMapping.matchScore)); - row.add("mappingStatus", codeMapping.mappingStatus.toString()); - row.add("equivalence", codeMapping.equivalence.toString()); - row.add("statusSetBy", codeMapping.statusSetBy); - row.add("statusSetOn", codeMapping.statusSetOn); + Row row = codeMapping.getSourceCode().toRow(); + row.add("matchScore", scoreFormat.format(codeMapping.getMatchScore())); + row.add("mappingStatus", codeMapping.getMappingStatus().toString()); + row.add("equivalence", codeMapping.getEquivalence().toString()); + row.add("statusSetBy", codeMapping.getStatusSetBy()); + row.add("statusSetOn", codeMapping.getStatusSetOn()); row.add("conceptId", targetConcept.getConcept().conceptId); row.add("conceptName", targetConcept.getConcept().conceptName); // Never read in. - row.add("comment", codeMapping.comment); + row.add("comment", codeMapping.getComment()); row.add("createdBy", targetConcept.getCreatedBy()); row.add("createdOn", targetConcept.getCreatedTime()); - row.add("assignedReviewer", codeMapping.assignedReviewer); + row.add("assignedReviewer", codeMapping.getAssignedReviewer()); out.write(row); } } diff --git a/src/org/ohdsi/usagi/dataImport/ImportData.java b/src/org/ohdsi/usagi/dataImport/ImportData.java index 70f96c7..2d0e43c 100644 --- a/src/org/ohdsi/usagi/dataImport/ImportData.java +++ b/src/org/ohdsi/usagi/dataImport/ImportData.java @@ -74,19 +74,19 @@ private void createInitialMapping(List sourceCodes, ImportSettings s List concepts = usagiSearchEngine.search(sourceCode.sourceName, true, sourceCode.sourceAutoAssignedConceptIds, settings.filterDomains, settings.filterConceptClasses, settings.filterVocabularies, settings.filterStandard, settings.includeSourceTerms); if (concepts.size() > 0) { - codeMapping.targetConcepts.add(new MappingTarget(concepts.get(0).concept, "")); - codeMapping.matchScore = concepts.get(0).matchScore; + codeMapping.getTargetConcepts().add(new MappingTarget(concepts.get(0).concept, "")); + codeMapping.setMatchScore(concepts.get(0).matchScore); } else { - codeMapping.targetConcepts.add(new MappingTarget(Concept.EMPTY_CONCEPT, "")); - codeMapping.matchScore = 0; + codeMapping.getTargetConcepts().add(new MappingTarget(Concept.EMPTY_CONCEPT, "")); + codeMapping.setMatchScore(0); } - codeMapping.mappingStatus = MappingStatus.UNCHECKED; + codeMapping.setMappingStatus(MappingStatus.UNCHECKED); if (sourceCode.sourceAutoAssignedConceptIds.size() == 1 && concepts.size() > 0) { - codeMapping.mappingStatus = MappingStatus.AUTO_MAPPED_TO_1; + codeMapping.setMappingStatus(MappingStatus.AUTO_MAPPED_TO_1); } else if (sourceCode.sourceAutoAssignedConceptIds.size() > 1 && concepts.size() > 0) { - codeMapping.mappingStatus = MappingStatus.AUTO_MAPPED; + codeMapping.setMappingStatus(MappingStatus.AUTO_MAPPED); } - codeMapping.equivalence = CodeMapping.Equivalence.UNREVIEWED; + codeMapping.setEquivalence(CodeMapping.Equivalence.UNREVIEWED); out.write(codeMapping); } out.close(); diff --git a/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java b/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java index 82c3c48..2dcc2e0 100644 --- a/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java +++ b/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java @@ -110,21 +110,21 @@ private void export() { private void writeToCsvFile(String filename) { WriteCSVFileWithHeader out = new WriteCSVFileWithHeader(filename); for (CodeMapping mapping : Global.mapping) - if (exportUnapproved || mapping.mappingStatus == MappingStatus.APPROVED) { + if (exportUnapproved || mapping.getMappingStatus() == MappingStatus.APPROVED) { List targetConcepts; - if (mapping.targetConcepts.size() == 0) { + if (mapping.getTargetConcepts().size() == 0) { targetConcepts = new ArrayList(1); targetConcepts.add(Concept.EMPTY_CONCEPT); } else { - targetConcepts = mapping.targetConcepts.stream().map(MappingTarget::getConcept).collect(Collectors.toList()); + targetConcepts = mapping.getTargetConcepts().stream().map(MappingTarget::getConcept).collect(Collectors.toList()); } for (Concept targetConcept : targetConcepts) { Row row = new Row(); - row.add("source_code", mapping.sourceCode.sourceCode); + row.add("source_code", mapping.getSourceCode().sourceCode); row.add("source_concept_id", "0"); row.add("source_vocabulary_id", sourceVocabularyIdField.getText()); - row.add("source_code_description", mapping.sourceCode.sourceName); + row.add("source_code_description", mapping.getSourceCode().sourceName); row.add("target_concept_id", targetConcept.conceptId); row.add("target_vocabulary_id", targetConcept.conceptId == 0 ? "None" : targetConcept.vocabularyId ); row.add("valid_start_date", "1970-01-01"); diff --git a/src/org/ohdsi/usagi/ui/ImportDialog.java b/src/org/ohdsi/usagi/ui/ImportDialog.java index cfccf76..054dc81 100644 --- a/src/org/ohdsi/usagi/ui/ImportDialog.java +++ b/src/org/ohdsi/usagi/ui/ImportDialog.java @@ -422,19 +422,19 @@ public void run() { List concepts = Global.usagiSearchEngine.search(sourceCode.sourceName, true, filterConceptIds, filterDomainsFinal, filterConceptClassesFinal, filterVocabulariesFinal, filterStandard, includeSourceConcepts); if (concepts.size() > 0) { - codeMapping.targetConcepts.add(new MappingTarget(concepts.get(0).concept, "")); - codeMapping.matchScore = concepts.get(0).matchScore; + codeMapping.getTargetConcepts().add(new MappingTarget(concepts.get(0).concept, "")); + codeMapping.setMatchScore(concepts.get(0).matchScore); } else { - codeMapping.matchScore = 0; + codeMapping.setMatchScore(0); } - codeMapping.comment = ""; - codeMapping.mappingStatus = MappingStatus.UNCHECKED; + codeMapping.setComment(""); + codeMapping.setMappingStatus(MappingStatus.UNCHECKED); if (sourceCode.sourceAutoAssignedConceptIds.size() == 1 && concepts.size() > 0) { - codeMapping.mappingStatus = MappingStatus.AUTO_MAPPED_TO_1; + codeMapping.setMappingStatus(MappingStatus.AUTO_MAPPED_TO_1); } else if (sourceCode.sourceAutoAssignedConceptIds.size() > 1 && concepts.size() > 0) { - codeMapping.mappingStatus = MappingStatus.AUTO_MAPPED; + codeMapping.setMappingStatus(MappingStatus.AUTO_MAPPED); } - codeMapping.equivalence = CodeMapping.Equivalence.UNREVIEWED; + codeMapping.setEquivalence(CodeMapping.Equivalence.UNREVIEWED); synchronized (globalMappingList) { globalMappingList.add(codeMapping); progressBar.setValue(Math.round(100 * globalMappingList.size() / sourceCodes.size())); diff --git a/src/org/ohdsi/usagi/ui/Mapping.java b/src/org/ohdsi/usagi/ui/Mapping.java index 7358ded..d760ce0 100644 --- a/src/org/ohdsi/usagi/ui/Mapping.java +++ b/src/org/ohdsi/usagi/ui/Mapping.java @@ -37,7 +37,7 @@ public void loadFromFile(String filename) { try { for (CodeMapping codeMapping : new ReadCodeMappingsFromFile(filename)) { add(codeMapping); - if (codeMapping.mappingStatus == CodeMapping.MappingStatus.INVALID_TARGET) { + if (codeMapping.getMappingStatus() == CodeMapping.MappingStatus.INVALID_TARGET) { nInvalidTargets += 1; } } @@ -85,7 +85,7 @@ public void saveToFile(String filename) { public List getSourceCodes() { List sourceCodes = new ArrayList(size()); for (CodeMapping codeMapping : this) - sourceCodes.add(codeMapping.sourceCode); + sourceCodes.add(codeMapping.getSourceCode()); return sourceCodes; } } diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 73b6079..4f6a1c0 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -177,7 +177,7 @@ private Component createSearchResultsPanel() { searchTable.getSelectionModel().addListSelectionListener(event -> { int viewRow = searchTable.getSelectedRow(); // Don't enable the buttons if no row selected or status is approved - if (viewRow == -1 || codeMapping.mappingStatus == MappingStatus.APPROVED) { + if (viewRow == -1 || codeMapping.getMappingStatus() == MappingStatus.APPROVED) { addButton.setEnabled(false); replaceButton.setEnabled(false); } else { @@ -245,19 +245,19 @@ private Component createApprovePanel() { @Override public void removeUpdate(DocumentEvent arg0) { - codeMapping.comment = commentField.getText(); + codeMapping.setComment(commentField.getText()); Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); } @Override public void insertUpdate(DocumentEvent arg0) { - codeMapping.comment = commentField.getText(); + codeMapping.setComment(commentField.getText()); Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); } @Override public void changedUpdate(DocumentEvent arg0) { - codeMapping.comment = commentField.getText(); + codeMapping.setComment(commentField.getText()); Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); } }); @@ -312,16 +312,16 @@ private JPanel createTargetConceptsPanel() { targetConceptTable.setRowSelectionAllowed(true); targetConceptTable.getSelectionModel().addListSelectionListener(event -> { int viewRow = targetConceptTable.getSelectedRow(); - if (viewRow == -1 || codeMapping.mappingStatus == MappingStatus.APPROVED) { + if (viewRow == -1 || codeMapping.getMappingStatus() == MappingStatus.APPROVED) { removeButton.setEnabled(false); } else { removeButton.setEnabled(true); int modelRow = targetConceptTable.convertRowIndexToModel(viewRow); MappingTarget mappingTarget = targetConceptTableModel.getMappingTarget(modelRow); Global.conceptInfoAction.setEnabled(true); - Global.conceptInformationDialog.setConcept(mappingTarget.concept); + Global.conceptInformationDialog.setConcept(mappingTarget.getConcept()); Global.athenaAction.setEnabled(true); - Global.athenaAction.setConcept(mappingTarget.concept); + Global.athenaAction.setConcept(mappingTarget.getConcept()); Global.googleSearchAction.setEnabled(false); } }); @@ -353,8 +353,8 @@ public void codeSelected(CodeMapping codeMapping) { this.codeMapping = codeMapping; toggleStatusButtons(); sourceCodeTableModel.setMapping(codeMapping); - targetConceptTableModel.setConcepts(codeMapping.targetConcepts); - commentField.setText(codeMapping.comment); + targetConceptTableModel.setConcepts(codeMapping.getTargetConcepts()); + commentField.setText(codeMapping.getComment()); doSearch(); } @@ -369,7 +369,7 @@ public void clearCodeMultiSelected() { } public void approve() { - if (codeMapping.mappingStatus != CodeMapping.MappingStatus.APPROVED) { + if (codeMapping.getMappingStatus() != CodeMapping.MappingStatus.APPROVED) { CodeMapping.Equivalence equivalenceToApply = (CodeMapping.Equivalence) equivalenceOptionChooser.getSelectedItem(); codeMapping.approve(Global.author, equivalenceToApply); Global.mapping.fireDataChanged(APPROVE_EVENT); @@ -381,11 +381,11 @@ public void approve() { } public void flag() { - if (codeMapping.mappingStatus != CodeMapping.MappingStatus.FLAGGED) { - codeMapping.mappingStatus = MappingStatus.FLAGGED; + if (codeMapping.getMappingStatus() != CodeMapping.MappingStatus.FLAGGED) { + codeMapping.setMappingStatus(MappingStatus.FLAGGED); Global.mapping.fireDataChanged(APPROVE_EVENT); } else { - codeMapping.mappingStatus = CodeMapping.MappingStatus.UNCHECKED; + codeMapping.setMappingStatus(MappingStatus.UNCHECKED); Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); toggleStatusButtons(); } @@ -398,7 +398,7 @@ private void toggleStatusButtons() { approveButton.setEnabled(false); equivalenceOptionChooser.setEnabled(false); - switch(codeMapping.mappingStatus) { + switch(codeMapping.getMappingStatus()) { case APPROVED: Global.approveAction.setToUnapprove(); approveButton.setEnabled(true); @@ -415,9 +415,9 @@ private void toggleStatusButtons() { } public void addConcept(Concept concept) { - codeMapping.targetConcepts.add(new MappingTarget(concept, Global.author)); + codeMapping.getTargetConcepts().add(new MappingTarget(concept, Global.author)); for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { - codeMappingMulti.targetConcepts.add(new MappingTarget(concept, Global.author)); + codeMappingMulti.getTargetConcepts().add(new MappingTarget(concept, Global.author)); } targetConceptTableModel.fireTableDataChanged(); @@ -429,9 +429,9 @@ public void addConcept(Concept concept) { } public void replaceConcepts(Concept concept) { - codeMapping.targetConcepts.clear(); + codeMapping.getTargetConcepts().clear(); for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { - codeMappingMulti.targetConcepts.clear(); + codeMappingMulti.getTargetConcepts().clear(); } addConcept(concept); } @@ -440,7 +440,7 @@ private void remove() { Arrays.stream(targetConceptTable.getSelectedRows()) .map(r -> targetConceptTable.convertRowIndexToModel(r)) .boxed().sorted(Comparator.reverseOrder()).mapToInt(Integer::intValue) // sorting for array integrity, remove last first. - .forEach(r -> codeMapping.targetConcepts.remove(r)); + .forEach(r -> codeMapping.getTargetConcepts().remove(r)); targetConceptTableModel.fireTableDataChanged(); Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); @@ -452,7 +452,7 @@ private class SearchTask extends TimerTask { public void run() { Set filterConceptIds = null; if (filterPanel.getFilterByAuto()) - filterConceptIds = codeMapping.sourceCode.sourceAutoAssignedConceptIds; + filterConceptIds = codeMapping.getSourceCode().sourceAutoAssignedConceptIds; boolean filterStandard = filterPanel.getFilterStandard(); Vector filterConceptClasses = null; @@ -467,7 +467,7 @@ public void run() { String query; if (autoQueryCodeButton.isSelected()) { - query = codeMapping.sourceCode.sourceName; + query = codeMapping.getSourceCode().sourceName; } else { query = manualQueryField.getText(); } @@ -510,13 +510,13 @@ public void setMapping(CodeMapping codeMapping) { this.codeMapping = codeMapping; columnNames = defaultColumnNames; - addInfoColCount = codeMapping.sourceCode.sourceAdditionalInfo.size(); + addInfoColCount = codeMapping.getSourceCode().sourceAdditionalInfo.size(); columnNames = new String[defaultColumnNames.length + addInfoColCount]; for (int i = 0; i < ADD_INFO_START_COL; i++) columnNames[i] = defaultColumnNames[i]; for (int i = 0; i < addInfoColCount; i++) - columnNames[i + ADD_INFO_START_COL] = codeMapping.sourceCode.sourceAdditionalInfo.get(i).getItem1(); + columnNames[i + ADD_INFO_START_COL] = codeMapping.getSourceCode().sourceAdditionalInfo.get(i).getItem1(); fireTableStructureChanged(); } @@ -533,15 +533,15 @@ public Object getValueAt(int row, int col) { if (codeMapping == null) return ""; if (col >= ADD_INFO_START_COL) { - return codeMapping.sourceCode.sourceAdditionalInfo.get(col - ADD_INFO_START_COL).getItem2(); + return codeMapping.getSourceCode().sourceAdditionalInfo.get(col - ADD_INFO_START_COL).getItem2(); } else { switch (col) { case 0: - return codeMapping.sourceCode.sourceCode; + return codeMapping.getSourceCode().sourceCode; case 1: - return codeMapping.sourceCode.sourceName; + return codeMapping.getSourceCode().sourceName; case 2: - return codeMapping.sourceCode.sourceFrequency; + return codeMapping.getSourceCode().sourceFrequency; default: return ""; } diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 1aae63a..46e02c2 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -65,13 +65,13 @@ public MappingTablePanel() { } Global.googleSearchAction.setEnabled(true); - Global.googleSearchAction.setSourceTerm(tableModel.getCodeMapping(primaryModelRow).sourceCode.sourceName); + Global.googleSearchAction.setSourceTerm(tableModel.getCodeMapping(primaryModelRow).getSourceCode().sourceName); Global.approveAction.setEnabled(true); Global.approveSelectedAction.setEnabled(true); Global.clearSelectedAction.setEnabled(true); - if (tableModel.getCodeMapping(primaryModelRow).targetConcepts.size() > 0) { - Concept firstConcept = tableModel.getCodeMapping(primaryModelRow).targetConcepts.get(0).concept; + if (tableModel.getCodeMapping(primaryModelRow).getTargetConcepts().size() > 0) { + Concept firstConcept = tableModel.getCodeMapping(primaryModelRow).getTargetConcepts().get(0).getConcept(); Global.conceptInfoAction.setEnabled(true); Global.conceptInformationDialog.setConcept(firstConcept); Global.athenaAction.setEnabled(true); @@ -130,13 +130,13 @@ public void restructure() { addInfoColCount = 0; if (Global.mapping.size() != 0) { CodeMapping codeMapping = Global.mapping.get(0); - addInfoColCount = codeMapping.sourceCode.sourceAdditionalInfo.size(); + addInfoColCount = codeMapping.getSourceCode().sourceAdditionalInfo.size(); columnNames = new String[defaultColumnNames.length + addInfoColCount]; for (int i = 0; i < ADD_INFO_START_COL; i++) columnNames[i] = defaultColumnNames[i]; for (int i = 0; i < addInfoColCount; i++) - columnNames[i + ADD_INFO_START_COL] = codeMapping.sourceCode.sourceAdditionalInfo.get(i).getItem1(); + columnNames[i + ADD_INFO_START_COL] = codeMapping.getSourceCode().sourceAdditionalInfo.get(i).getItem1(); for (int i = ADD_INFO_START_COL; i < defaultColumnNames.length; i++) columnNames[i + addInfoColCount] = defaultColumnNames[i]; @@ -157,25 +157,25 @@ public Object getValueAt(int row, int col) { CodeMapping codeMapping = Global.mapping.get(row); if (col >= ADD_INFO_START_COL && col < ADD_INFO_START_COL + addInfoColCount) { - return codeMapping.sourceCode.sourceAdditionalInfo.get(col - ADD_INFO_START_COL).getItem2(); + return codeMapping.getSourceCode().sourceAdditionalInfo.get(col - ADD_INFO_START_COL).getItem2(); } else { col = resolveColumnIndex(col); Concept targetConcept; - if (codeMapping.targetConcepts.size() > 0) - targetConcept = codeMapping.targetConcepts.get(0).concept; + if (codeMapping.getTargetConcepts().size() > 0) + targetConcept = codeMapping.getTargetConcepts().get(0).getConcept(); else targetConcept = Concept.EMPTY_CONCEPT; switch (col) { case 0: - return codeMapping.mappingStatus; + return codeMapping.getMappingStatus(); case 1: - return codeMapping.sourceCode.sourceCode; + return codeMapping.getSourceCode().sourceCode; case 2: - return codeMapping.sourceCode.sourceName; + return codeMapping.getSourceCode().sourceName; case 3: - return codeMapping.sourceCode.sourceFrequency == -1 ? "" : codeMapping.sourceCode.sourceFrequency; + return codeMapping.getSourceCode().sourceFrequency == -1 ? "" : codeMapping.getSourceCode().sourceFrequency; case 4: - return codeMapping.matchScore; + return codeMapping.getMatchScore(); case 5: return targetConcept.conceptId; case 6: @@ -201,18 +201,18 @@ public Object getValueAt(int row, int col) { case 16: return targetConcept.childCount; case ASSIGNED_REVIEWER_COL: - return codeMapping.assignedReviewer; + return codeMapping.getAssignedReviewer(); case 18: - if (codeMapping.equivalence != CodeMapping.Equivalence.UNREVIEWED) { - return codeMapping.equivalence; + if (codeMapping.getEquivalence() != CodeMapping.Equivalence.UNREVIEWED) { + return codeMapping.getEquivalence(); } else { return null; } case 19: - return codeMapping.comment; + return codeMapping.getComment(); case 20: - if (codeMapping.statusSetOn != 0L) { - return String.format("%s (%tF)", codeMapping.statusSetBy, codeMapping.statusSetOn); + if (codeMapping.getStatusSetOn() != 0L) { + return String.format("%s (%tF)", codeMapping.getStatusSetBy(), codeMapping.getStatusSetOn()); } default: return ""; @@ -258,7 +258,7 @@ public void setValueAt(Object value, int row, int col) { col = resolveColumnIndex(col); if (col == ASSIGNED_REVIEWER_COL) { CodeMapping codeMapping = Global.mapping.get(row); - codeMapping.assignedReviewer = (String) value; + codeMapping.setAssignedReviewer((String) value); } } @@ -314,7 +314,7 @@ private void fireUpdateEventAll(DataChangeEvent event) { public void approveSelected() { for (int viewRow : table.getSelectedRows()) { int modelRow = table.convertRowIndexToModel(viewRow); - tableModel.getCodeMapping(modelRow).mappingStatus = MappingStatus.APPROVED; + tableModel.getCodeMapping(modelRow).setMappingStatus(MappingStatus.APPROVED); } fireUpdateEventAll(APPROVE_EVENT); } @@ -322,7 +322,7 @@ public void approveSelected() { public void clearSelected() { for (int viewRow : table.getSelectedRows()) { int modelRow = table.convertRowIndexToModel(viewRow); - tableModel.getCodeMapping(modelRow).targetConcepts.clear(); + tableModel.getCodeMapping(modelRow).getTargetConcepts().clear(); } fireUpdateEventAll(SIMPLE_UPDATE_EVENT); } @@ -332,7 +332,7 @@ public void assignReviewersRandomly(String[] reviewers) { ThreadLocalRandom randomGenerator = ThreadLocalRandom.current(); for (CodeMapping codeMapping : Global.mapping) { int random = randomGenerator.nextInt(reviewers.length); - codeMapping.assignedReviewer = reviewers[random]; + codeMapping.setAssignedReviewer(reviewers[random]); } fireUpdateEventAll(APPROVE_EVENT); } @@ -349,7 +349,7 @@ public void assignReviewersEqually(String[] reviewers) { Collections.shuffle(codeMappingIndex); for (int i = 0; i < codeMappingIndex.size(); i++) { CodeMapping codeMapping = Global.mapping.get(codeMappingIndex.get(i)); - codeMapping.assignedReviewer = reviewers[i % nReviewers]; + codeMapping.setAssignedReviewer(reviewers[i % nReviewers]); } fireUpdateEventAll(APPROVE_EVENT); } diff --git a/src/org/ohdsi/usagi/ui/UsagiStatusBar.java b/src/org/ohdsi/usagi/ui/UsagiStatusBar.java index 64e8dec..6d0ec04 100644 --- a/src/org/ohdsi/usagi/ui/UsagiStatusBar.java +++ b/src/org/ohdsi/usagi/ui/UsagiStatusBar.java @@ -81,17 +81,17 @@ private void update() { long totalFreq = 0; long approvedFreq = 0; for (CodeMapping codeMapping : Global.mapping) { - if (codeMapping.mappingStatus == MappingStatus.APPROVED) { + if (codeMapping.getMappingStatus() == MappingStatus.APPROVED) { approved++; - if (codeMapping.sourceCode.sourceFrequency == -1) + if (codeMapping.getSourceCode().sourceFrequency == -1) approvedFreq++; else - approvedFreq += codeMapping.sourceCode.sourceFrequency; + approvedFreq += codeMapping.getSourceCode().sourceFrequency; } - if (codeMapping.sourceCode.sourceFrequency == -1) { + if (codeMapping.getSourceCode().sourceFrequency == -1) { totalFreq++; } else { - totalFreq += codeMapping.sourceCode.sourceFrequency; + totalFreq += codeMapping.getSourceCode().sourceFrequency; } } countLabel.setText(approved + " / " + Global.mapping.size()); diff --git a/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java b/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java index b2099fd..9c72b83 100644 --- a/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java @@ -54,7 +54,7 @@ public void actionPerformed(ActionEvent arg0) { // Existing code lookup Map codeToMapping = new HashMap<>(); for (CodeMapping codeMapping: Global.mapping) { - codeToMapping.put(codeMapping.sourceCode.sourceCode, codeMapping); + codeToMapping.put(codeMapping.getSourceCode().sourceCode, codeMapping); } // Open mapping file to be applied @@ -64,12 +64,12 @@ public void actionPerformed(ActionEvent arg0) { // Apply mapping. Add mappings not currently present for (CodeMapping codeMappingToBeApplied : mappingToBeApplied) { - CodeMapping existingMapping = codeToMapping.get(codeMappingToBeApplied.sourceCode.sourceCode); + CodeMapping existingMapping = codeToMapping.get(codeMappingToBeApplied.getSourceCode().sourceCode); if (existingMapping != null) { - existingMapping.sourceCode.sourceName = codeMappingToBeApplied.sourceCode.sourceName; - existingMapping.targetConcepts = codeMappingToBeApplied.targetConcepts; - existingMapping.mappingStatus = codeMappingToBeApplied.mappingStatus; - existingMapping.comment = codeMappingToBeApplied.comment; + existingMapping.getSourceCode().sourceName = codeMappingToBeApplied.getSourceCode().sourceName; + existingMapping.setTargetConcepts(codeMappingToBeApplied.getTargetConcepts()); + existingMapping.setMappingStatus(codeMappingToBeApplied.getMappingStatus()); + existingMapping.setComment(codeMappingToBeApplied.getComment()); mappingsApplied++; } else { Global.mapping.add(codeMappingToBeApplied); diff --git a/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java b/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java index 1586729..65b6329 100644 --- a/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java @@ -57,7 +57,7 @@ public void actionPerformed(ActionEvent arg0) { boolean hasApprovedMappings = false; for (CodeMapping mapping : Global.mapping) { - if (mapping.mappingStatus == MappingStatus.APPROVED) { + if (mapping.getMappingStatus() == MappingStatus.APPROVED) { hasApprovedMappings = true; break; } @@ -79,20 +79,20 @@ public void actionPerformed(ActionEvent arg0) { Global.frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); WriteCSVFileWithHeader out = new WriteCSVFileWithHeader(file.getAbsolutePath()); for (CodeMapping mapping : Global.mapping) - if (exportUnapproved || mapping.mappingStatus == MappingStatus.APPROVED) { + if (exportUnapproved || mapping.getMappingStatus() == MappingStatus.APPROVED) { List targetConcepts; - if (mapping.targetConcepts.size() == 0) { + if (mapping.getTargetConcepts().size() == 0) { targetConcepts = new ArrayList(1); targetConcepts.add(Concept.EMPTY_CONCEPT); } else - targetConcepts = mapping.targetConcepts.stream() + targetConcepts = mapping.getTargetConcepts().stream() .map(MappingTarget::getConcept) .collect(Collectors.toList()); for (Concept targetConcept : targetConcepts) { - Row row = mapping.sourceCode.toRow(); - row.add("matchScore", mapping.matchScore); - if (exportUnapproved) row.add("mappingStatus", mapping.mappingStatus.toString()); + Row row = mapping.getSourceCode().toRow(); + row.add("matchScore", mapping.getMatchScore()); + if (exportUnapproved) row.add("mappingStatus", mapping.getMappingStatus().toString()); row.add("targetConceptId", targetConcept.conceptId); row.add("targetConceptName", targetConcept.conceptName); row.add("targetVocabularyId", targetConcept.vocabularyId); diff --git a/src/org/ohdsi/usagi/ui/actions/ExportSourceToConceptMapAction.java b/src/org/ohdsi/usagi/ui/actions/ExportSourceToConceptMapAction.java index 8878eb8..5a9f6ee 100644 --- a/src/org/ohdsi/usagi/ui/actions/ExportSourceToConceptMapAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ExportSourceToConceptMapAction.java @@ -48,7 +48,7 @@ public void actionPerformed(ActionEvent arg0) { boolean hasApprovedMappings = false; for (CodeMapping mapping : Global.mapping) { - if (mapping.mappingStatus == MappingStatus.APPROVED) { + if (mapping.getMappingStatus() == MappingStatus.APPROVED) { hasApprovedMappings = true; break; } From 5e08ddf24bfeeda485cad9a63890dadd272b4ae2 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Thu, 18 Feb 2021 12:15:31 +0100 Subject: [PATCH 67/77] remove mapping type from mapping detail panel --- src/org/ohdsi/usagi/ui/TargetConceptTableModel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java b/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java index c531434..8d3acd9 100644 --- a/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java +++ b/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java @@ -11,7 +11,7 @@ class TargetConceptTableModel extends AbstractTableModel { private static final long serialVersionUID = -4978479688021056281L; private final String[] columnNames = {"Concept ID", "Concept name", "Domain", "Concept class", "Vocabulary", "Concept code", - "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", "Children", "Mapping Type", + "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", "Children", "Creation Provenance"}; private List targetConcepts = new ArrayList<>(); From 7d71b4f309646c243552898f802222c7c39a63f1 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 19 Feb 2021 21:53:31 +0100 Subject: [PATCH 68/77] mapping type for value and unit --- src/org/ohdsi/usagi/MappingTarget.java | 25 +- .../ohdsi/usagi/ReadCodeMappingsFromFile.java | 7 +- .../ohdsi/usagi/WriteCodeMappingsToFile.java | 1 + .../ohdsi/usagi/ui/MappingDetailPanel.java | 1203 +++++++++-------- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 2 +- .../usagi/ui/TargetConceptTableModel.java | 6 +- 6 files changed, 659 insertions(+), 585 deletions(-) diff --git a/src/org/ohdsi/usagi/MappingTarget.java b/src/org/ohdsi/usagi/MappingTarget.java index a8e3ab6..1038d4c 100644 --- a/src/org/ohdsi/usagi/MappingTarget.java +++ b/src/org/ohdsi/usagi/MappingTarget.java @@ -19,23 +19,36 @@ * Class for holding information about a single (target) concept in the Vocabulary */ public class MappingTarget{ + public enum Type { + MAPS_TO, MAPS_TO_VALUE, MAPS_TO_UNIT + }; private final Concept concept; private final String createdBy; private final long createdTime; + private Type mappingType; public MappingTarget() { this.concept = Concept.createEmptyConcept(); + this.mappingType = Type.MAPS_TO; this.createdBy = ""; this.createdTime = 0; } public MappingTarget(Concept concept, String createdBy) { - this(concept, createdBy, System.currentTimeMillis()); + this(concept, Type.MAPS_TO, createdBy); } - public MappingTarget(Concept concept, String createdBy, long createdTime) { + public MappingTarget(Concept concept, Type mappingType, String createdBy) { this.concept = concept; + this.mappingType = mappingType; + this.createdBy = createdBy; + this.createdTime = System.currentTimeMillis(); + } + + public MappingTarget(Concept concept, Type mappingType, String createdBy, long createdTime) { + this.concept = concept; + this.mappingType = mappingType; this.createdBy = createdBy; this.createdTime = createdTime; } @@ -51,4 +64,12 @@ public String getCreatedBy() { public long getCreatedTime() { return createdTime; } + + public Type getMappingType() { + return mappingType; + } + + public void setMappingType(Type mappingType) { + this.mappingType = mappingType; + } } diff --git a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java index 1462a11..f514fdd 100644 --- a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java +++ b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java @@ -77,9 +77,14 @@ && new SourceCode(row).sourceName.equals(buffer.getSourceCode().sourceName)) { buffer.setMappingStatus(MappingStatus.INVALID_TARGET); buffer.setComment("Invalid existing target: " + row.get("conceptId")); } else { - // Provenance might not be available in older Usagi files + // Type and provenance might not be available in older Usagi files MappingTarget mappingTarget = new MappingTarget( concept, + MappingTarget.Type.valueOf(row.get("mappingType", "MAPS_TO") + .replace("EVENT", "MAPS_TO") + .replace("VALUE", "MAPS_TO_VALUE") + .replace("UNIT", "MAPS_TO_UNIT") + ), row.get("createdBy", ""), row.getLong("createdOn", "0") ); diff --git a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java index 7a370a1..2e62d92 100644 --- a/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java +++ b/src/org/ohdsi/usagi/WriteCodeMappingsToFile.java @@ -52,6 +52,7 @@ public void write(CodeMapping codeMapping) { row.add("statusSetOn", codeMapping.getStatusSetOn()); row.add("conceptId", targetConcept.getConcept().conceptId); row.add("conceptName", targetConcept.getConcept().conceptName); // Never read in. + row.add("mappingType", targetConcept.getMappingType().toString()); row.add("comment", codeMapping.getComment()); row.add("createdBy", targetConcept.getCreatedBy()); row.add("createdOn", targetConcept.getCreatedTime()); diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 4f6a1c0..360910f 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -1,579 +1,624 @@ -/******************************************************************************* - * Copyright 2019 Observational Health Data Sciences and Informatics - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ******************************************************************************/ -package org.ohdsi.usagi.ui; - -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.*; -import java.util.Timer; - -import javax.swing.*; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; -import javax.swing.table.AbstractTableModel; -import javax.swing.table.TableRowSorter; - -import org.ohdsi.usagi.CodeMapping; -import org.ohdsi.usagi.CodeMapping.MappingStatus; -import org.ohdsi.usagi.Concept; -import org.ohdsi.usagi.MappingTarget; -import org.ohdsi.usagi.UsagiSearchEngine.ScoredConcept; - -import static org.ohdsi.usagi.ui.DataChangeEvent.*; - -public class MappingDetailPanel extends JPanel implements CodeSelectedListener, FilterChangeListener { - - private static final long serialVersionUID = 2127318722005512776L; - private UsagiTable sourceCodeTable; - private SourceCodeTableModel sourceCodeTableModel; - private UsagiTable targetConceptTable; - private TargetConceptTableModel targetConceptTableModel; - private UsagiTable searchTable; - private TableRowSorter sorter; - private ConceptTableModel searchTableModel; - private JButton approveButton; - private JButton flagButton; - private JComboBox equivalenceOptionChooser; - private JTextField commentField; - private JButton removeButton; - private JButton replaceButton; - private JButton addButton; - private JRadioButton autoQueryCodeButton; - private JRadioButton manualQueryButton; - private JTextField manualQueryField; - private CodeMapping codeMapping; - private List codeMappingsFromMulti; - private FilterPanel filterPanel; - private Timer timer; - - public MappingDetailPanel() { - super(); - setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - add(createSourceCodePanel()); - add(createTargetConceptsPanel()); - add(createSearchPanel()); - add(createApprovePanel()); - codeMappingsFromMulti = new ArrayList<>(); - } - - private Component createSearchPanel() { - JPanel panel = new JPanel(); - panel.setBorder(BorderFactory.createTitledBorder("Search")); - panel.setLayout(new GridBagLayout()); - GridBagConstraints c = new GridBagConstraints(); - c.fill = GridBagConstraints.BOTH; - - c.gridx = 0; - c.gridy = 0; - c.weightx = 1; - c.weighty = 0.1; - panel.add(createQueryPanel(), c); - - c.gridx = 1; - c.gridy = 0; - c.weightx = 0.1; - c.weighty = 0.1; - filterPanel = new FilterPanel(); - filterPanel.addListener(this); - panel.add(filterPanel, c); - - c.gridx = 0; - c.gridy = 1; - c.weightx = 1; - c.weighty = 1; - c.gridwidth = 2; - panel.add(createSearchResultsPanel(), c); - return panel; - } - - private Component createQueryPanel() { - JPanel panel = new JPanel(); - panel.setBorder(BorderFactory.createTitledBorder("Query")); - panel.setLayout(new GridBagLayout()); - GridBagConstraints c = new GridBagConstraints(); - c.fill = GridBagConstraints.BOTH; - c.anchor = GridBagConstraints.WEST; - c.gridx = GridBagConstraints.RELATIVE; - c.gridy = 0; - c.weightx = 0.1; - c.gridwidth = 2; - - autoQueryCodeButton = new JRadioButton("Use source term", true); - autoQueryCodeButton.addActionListener(x -> doSearch()); - panel.add(autoQueryCodeButton, c); - - c.gridx = 0; - c.gridy = 1; - c.weightx = 0.1; - c.gridwidth = 1; - manualQueryButton = new JRadioButton("Query:", false); - manualQueryButton.addActionListener(x -> doSearch()); - panel.add(manualQueryButton, c); - - ButtonGroup buttonGroup = new ButtonGroup(); - buttonGroup.add(autoQueryCodeButton); - buttonGroup.add(manualQueryButton); - - c.gridx = 1; - c.gridy = 1; - c.weightx = 1; - c.gridwidth = GridBagConstraints.REMAINDER; - manualQueryField = new JTextField(""); - // manualQueryField.setPreferredSize(new Dimension(200, 5)); - manualQueryField.getDocument().addDocumentListener(new DocumentListener() { - - @Override - public void removeUpdate(DocumentEvent arg0) { - manualQueryButton.setSelected(true); - doSearch(); - } - - @Override - public void insertUpdate(DocumentEvent arg0) { - manualQueryButton.setSelected(true); - doSearch(); - } - - @Override - public void changedUpdate(DocumentEvent arg0) { - manualQueryButton.setSelected(true); - doSearch(); - } - }); - panel.add(manualQueryField, c); - return panel; - } - - private Component createSearchResultsPanel() { - JPanel panel = new JPanel(); - panel.setBorder(BorderFactory.createTitledBorder("Results")); - panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); - searchTableModel = new ConceptTableModel(true); - searchTable = new UsagiTable(searchTableModel); - sorter = new TableRowSorter(searchTableModel); - searchTable.setRowSorter(sorter); - searchTable.setPreferredScrollableViewportSize(new Dimension(100, 100)); - searchTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); - searchTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - searchTable.getSelectionModel().addListSelectionListener(event -> { - int viewRow = searchTable.getSelectedRow(); - // Don't enable the buttons if no row selected or status is approved - if (viewRow == -1 || codeMapping.getMappingStatus() == MappingStatus.APPROVED) { - addButton.setEnabled(false); - replaceButton.setEnabled(false); - } else { - addButton.setEnabled(true); - replaceButton.setEnabled(true); - int modelRow = searchTable.convertRowIndexToModel(viewRow); - Global.conceptInfoAction.setEnabled(true); - Global.conceptInformationDialog.setConcept(searchTableModel.getConcept(modelRow)); - Global.athenaAction.setEnabled(true); - Global.athenaAction.setConcept(searchTableModel.getConcept(modelRow)); - Global.googleSearchAction.setEnabled(false); - } - }); - // searchTable.hideColumn("Synonym"); - searchTable.hideColumn("Valid start date"); - searchTable.hideColumn("Valid end date"); - searchTable.hideColumn("Invalid reason"); - panel.add(new JScrollPane(searchTable)); - - JPanel buttonPanel = new JPanel(); - buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS)); - buttonPanel.add(Box.createHorizontalGlue()); - - replaceButton = new JButton("Replace concept"); - replaceButton.setToolTipText("Replace selected concept"); - replaceButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - int viewRow = searchTable.getSelectedRow(); - int modelRow = searchTable.convertRowIndexToModel(viewRow); - replaceConcepts(searchTableModel.getConcept(modelRow)); - } - - }); - replaceButton.setEnabled(false); - buttonPanel.add(replaceButton); - - addButton = new JButton("Add concept"); - addButton.setToolTipText("Add selected concept"); - addButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - int viewRow = searchTable.getSelectedRow(); - int modelRow = searchTable.convertRowIndexToModel(viewRow); - addConcept(searchTableModel.getConcept(modelRow)); - } - }); - addButton.setEnabled(false); - buttonPanel.add(addButton); - - panel.add(buttonPanel); - - return panel; - } - - private Component createApprovePanel() { - JPanel panel = new JPanel(); - panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); - - panel.add(new JLabel("Comment:")); - - panel.add(Box.createHorizontalStrut(5)); - - commentField = new JTextField(); - commentField.setMaximumSize(new Dimension(Integer.MAX_VALUE, commentField.getPreferredSize().height)); - commentField.getDocument().addDocumentListener(new DocumentListener() { - - @Override - public void removeUpdate(DocumentEvent arg0) { - codeMapping.setComment(commentField.getText()); - Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - } - - @Override - public void insertUpdate(DocumentEvent arg0) { - codeMapping.setComment(commentField.getText()); - Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - } - - @Override - public void changedUpdate(DocumentEvent arg0) { - codeMapping.setComment(commentField.getText()); - Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - } - }); - commentField.setToolTipText("Comments about the code mapping can be written here"); - panel.add(commentField); - - panel.add(Box.createHorizontalStrut(5)); - - flagButton = new JButton(Global.flagAction); - flagButton.setBackground(new Color(151, 220, 141)); - panel.add(flagButton); - - equivalenceOptionChooser = new JComboBox<>(CodeMapping.Equivalence.values()); - equivalenceOptionChooser.setToolTipText("Choose mapping equivalence"); - equivalenceOptionChooser.setMaximumSize(equivalenceOptionChooser.getPreferredSize()); - panel.add(equivalenceOptionChooser); - - approveButton = new JButton(Global.approveAction); - approveButton.setBackground(new Color(151, 220, 141)); - panel.add(approveButton); - - return panel; - } - - private JPanel createSourceCodePanel() { - JPanel panel = new JPanel(); - panel.setBorder(BorderFactory.createTitledBorder("Source code")); - panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); - sourceCodeTableModel = new SourceCodeTableModel(); - sourceCodeTable = new UsagiTable(sourceCodeTableModel); - sourceCodeTable.setPreferredScrollableViewportSize(new Dimension(500, 35)); - sourceCodeTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); - sourceCodeTable.setRowSelectionAllowed(false); - sourceCodeTable.setCellSelectionEnabled(false); - JScrollPane pane = new JScrollPane(sourceCodeTable); - pane.setBorder(BorderFactory.createEmptyBorder()); - pane.setMinimumSize(new Dimension(500, 40)); - pane.setPreferredSize(new Dimension(500, 40)); - panel.add(pane); - - return panel; - } - - private JPanel createTargetConceptsPanel() { - JPanel panel = new JPanel(); - panel.setBorder(BorderFactory.createTitledBorder("Target concepts")); - panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); - targetConceptTableModel = new TargetConceptTableModel(); - targetConceptTable = new UsagiTable(targetConceptTableModel); - targetConceptTable.setPreferredScrollableViewportSize(new Dimension(500, 45)); - targetConceptTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); - targetConceptTable.setRowSelectionAllowed(true); - targetConceptTable.getSelectionModel().addListSelectionListener(event -> { - int viewRow = targetConceptTable.getSelectedRow(); - if (viewRow == -1 || codeMapping.getMappingStatus() == MappingStatus.APPROVED) { - removeButton.setEnabled(false); - } else { - removeButton.setEnabled(true); - int modelRow = targetConceptTable.convertRowIndexToModel(viewRow); - MappingTarget mappingTarget = targetConceptTableModel.getMappingTarget(modelRow); - Global.conceptInfoAction.setEnabled(true); - Global.conceptInformationDialog.setConcept(mappingTarget.getConcept()); - Global.athenaAction.setEnabled(true); - Global.athenaAction.setConcept(mappingTarget.getConcept()); - Global.googleSearchAction.setEnabled(false); - } - }); - targetConceptTable.hideColumn("Valid start date"); - targetConceptTable.hideColumn("Valid end date"); - targetConceptTable.hideColumn("Invalid reason"); - - JScrollPane pane = new JScrollPane(targetConceptTable); - pane.setBorder(BorderFactory.createEmptyBorder()); - pane.setMinimumSize(new Dimension(500, 50)); - pane.setPreferredSize(new Dimension(500, 50)); - panel.add(pane); - - JPanel buttonPanel = new JPanel(); - buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS)); - buttonPanel.add(Box.createHorizontalGlue()); - - removeButton = new JButton("Remove concept"); - removeButton.setToolTipText("Remove selected concept"); - removeButton.addActionListener(e -> remove()); - removeButton.setEnabled(false); - buttonPanel.add(removeButton); - panel.add(buttonPanel); - return panel; - } - - @Override - public void codeSelected(CodeMapping codeMapping) { - this.codeMapping = codeMapping; - toggleStatusButtons(); - sourceCodeTableModel.setMapping(codeMapping); - targetConceptTableModel.setConcepts(codeMapping.getTargetConcepts()); - commentField.setText(codeMapping.getComment()); - doSearch(); - } - - @Override - public void addCodeMultiSelected(CodeMapping codeMapping) { - this.codeMappingsFromMulti.add(codeMapping); - } - - @Override - public void clearCodeMultiSelected() { - this.codeMappingsFromMulti = new ArrayList<>(); - } - - public void approve() { - if (codeMapping.getMappingStatus() != CodeMapping.MappingStatus.APPROVED) { - CodeMapping.Equivalence equivalenceToApply = (CodeMapping.Equivalence) equivalenceOptionChooser.getSelectedItem(); - codeMapping.approve(Global.author, equivalenceToApply); - Global.mapping.fireDataChanged(APPROVE_EVENT); - } else { - codeMapping.setUnchecked(); - Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - toggleStatusButtons(); - } - } - - public void flag() { - if (codeMapping.getMappingStatus() != CodeMapping.MappingStatus.FLAGGED) { - codeMapping.setMappingStatus(MappingStatus.FLAGGED); - Global.mapping.fireDataChanged(APPROVE_EVENT); - } else { - codeMapping.setMappingStatus(MappingStatus.UNCHECKED); - Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - toggleStatusButtons(); - } - } - - private void toggleStatusButtons() { - Global.approveAction.setToApprove(); - Global.flagAction.setToFlag(); - flagButton.setEnabled(false); - approveButton.setEnabled(false); - equivalenceOptionChooser.setEnabled(false); - - switch(codeMapping.getMappingStatus()) { - case APPROVED: - Global.approveAction.setToUnapprove(); - approveButton.setEnabled(true); - break; - case FLAGGED: - Global.flagAction.setToUnflag(); - flagButton.setEnabled(true); - break; - default: // unchecked, invalid or auto-mapped - flagButton.setEnabled(true); - approveButton.setEnabled(true); - equivalenceOptionChooser.setEnabled(true); - } - } - - public void addConcept(Concept concept) { - codeMapping.getTargetConcepts().add(new MappingTarget(concept, Global.author)); - for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { - codeMappingMulti.getTargetConcepts().add(new MappingTarget(concept, Global.author)); - } - targetConceptTableModel.fireTableDataChanged(); - - if (codeMappingsFromMulti.size() > 0) { - Global.mapping.fireDataChanged(MULTI_UPDATE_EVENT); - } else { - Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - } - } - - public void replaceConcepts(Concept concept) { - codeMapping.getTargetConcepts().clear(); - for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { - codeMappingMulti.getTargetConcepts().clear(); - } - addConcept(concept); - } - - private void remove() { - Arrays.stream(targetConceptTable.getSelectedRows()) - .map(r -> targetConceptTable.convertRowIndexToModel(r)) - .boxed().sorted(Comparator.reverseOrder()).mapToInt(Integer::intValue) // sorting for array integrity, remove last first. - .forEach(r -> codeMapping.getTargetConcepts().remove(r)); - - targetConceptTableModel.fireTableDataChanged(); - Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - } - - private class SearchTask extends TimerTask { - - @Override - public void run() { - Set filterConceptIds = null; - if (filterPanel.getFilterByAuto()) - filterConceptIds = codeMapping.getSourceCode().sourceAutoAssignedConceptIds; - - boolean filterStandard = filterPanel.getFilterStandard(); - Vector filterConceptClasses = null; - if (filterPanel.getFilterByConceptClasses()) - filterConceptClasses = filterPanel.getConceptClass(); - Vector filterVocabularies = null; - if (filterPanel.getFilterByVocabularies()) - filterVocabularies = filterPanel.getVocabulary(); - Vector filterDomains = null; - if (filterPanel.getFilterByDomains()) - filterDomains = filterPanel.getDomain(); - - String query; - if (autoQueryCodeButton.isSelected()) { - query = codeMapping.getSourceCode().sourceName; - } else { - query = manualQueryField.getText(); - } - - boolean includeSourceConcepts = filterPanel.getIncludeSourceTerms(); - - if (Global.usagiSearchEngine.isOpenForSearching()) { - List searchResults = Global.usagiSearchEngine.search(query, true, filterConceptIds, filterDomains, filterConceptClasses, - filterVocabularies, filterStandard, includeSourceConcepts); - - searchTableModel.setScoredConcepts(searchResults); - searchTable.scrollRectToVisible(new Rectangle(searchTable.getCellRect(0, 0, true))); - } - Global.statusBar.setSearching(false); - } - } - - public void doSearch() { - Global.statusBar.setSearching(true); - if (timer != null) - timer.cancel(); - timer = new Timer(); - timer.schedule(new SearchTask(), 500); - } - - class SourceCodeTableModel extends AbstractTableModel { - private static final long serialVersionUID = 169286268154988911L; - - private String[] defaultColumnNames = { "Source code", "Source term", "Frequency" }; - private String[] columnNames = defaultColumnNames; - private CodeMapping codeMapping; - private int addInfoColCount = 0; - private int ADD_INFO_START_COL = 3; - - public int getColumnCount() { - return columnNames.length; - } - - public void setMapping(CodeMapping codeMapping) { - this.codeMapping = codeMapping; - - columnNames = defaultColumnNames; - addInfoColCount = codeMapping.getSourceCode().sourceAdditionalInfo.size(); - columnNames = new String[defaultColumnNames.length + addInfoColCount]; - for (int i = 0; i < ADD_INFO_START_COL; i++) - columnNames[i] = defaultColumnNames[i]; - - for (int i = 0; i < addInfoColCount; i++) - columnNames[i + ADD_INFO_START_COL] = codeMapping.getSourceCode().sourceAdditionalInfo.get(i).getItem1(); - - fireTableStructureChanged(); - } - - public int getRowCount() { - return 1; - } - - public String getColumnName(int col) { - return columnNames[col]; - } - - public Object getValueAt(int row, int col) { - if (codeMapping == null) - return ""; - if (col >= ADD_INFO_START_COL) { - return codeMapping.getSourceCode().sourceAdditionalInfo.get(col - ADD_INFO_START_COL).getItem2(); - } else { - switch (col) { - case 0: - return codeMapping.getSourceCode().sourceCode; - case 1: - return codeMapping.getSourceCode().sourceName; - case 2: - return codeMapping.getSourceCode().sourceFrequency; - default: - return ""; - } - } - - } - - public Class getColumnClass(int col) { - if (col >= ADD_INFO_START_COL) { - return String.class; - } else { - switch (col) { - case 2: - return Integer.class; - default: - return String.class; - } - } - } - - public boolean isCellEditable(int row, int col) { - return true; - } - - public void setValueAt(Object value, int row, int col) { - - } - } - - @Override - public void filterChanged() { - doSearch(); - } - -} +/******************************************************************************* + * Copyright 2019 Observational Health Data Sciences and Informatics + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ******************************************************************************/ +package org.ohdsi.usagi.ui; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.*; +import java.util.Timer; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableRowSorter; + +import org.ohdsi.usagi.CodeMapping; +import org.ohdsi.usagi.CodeMapping.MappingStatus; +import org.ohdsi.usagi.Concept; +import org.ohdsi.usagi.MappingTarget; +import org.ohdsi.usagi.UsagiSearchEngine.ScoredConcept; + +import static org.ohdsi.usagi.ui.DataChangeEvent.*; + +public class MappingDetailPanel extends JPanel implements CodeSelectedListener, FilterChangeListener { + + private static final long serialVersionUID = 2127318722005512776L; + private UsagiTable sourceCodeTable; + private SourceCodeTableModel sourceCodeTableModel; + private UsagiTable targetConceptTable; + private TargetConceptTableModel targetConceptTableModel; + private UsagiTable searchTable; + private TableRowSorter sorter; + private ConceptTableModel searchTableModel; + private JButton approveButton; + private JButton flagButton; + private JComboBox equivalenceOptionChooser; + private JTextField commentField; + private JButton removeButton; + private JComboBox typesChooser; + private JButton replaceButton; + private List addButtons; + private JRadioButton autoQueryCodeButton; + private JRadioButton manualQueryButton; + private JTextField manualQueryField; + private CodeMapping codeMapping; + private List codeMappingsFromMulti; + private FilterPanel filterPanel; + private Timer timer; + + public MappingDetailPanel() { + super(); + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + add(createSourceCodePanel()); + add(createTargetConceptsPanel()); + add(createSearchPanel()); + add(createApprovePanel()); + codeMappingsFromMulti = new ArrayList<>(); + } + + private Component createSearchPanel() { + JPanel panel = new JPanel(); + panel.setBorder(BorderFactory.createTitledBorder("Search")); + panel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.BOTH; + + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.weighty = 0.1; + panel.add(createQueryPanel(), c); + + c.gridx = 1; + c.gridy = 0; + c.weightx = 0.1; + c.weighty = 0.1; + filterPanel = new FilterPanel(); + filterPanel.addListener(this); + panel.add(filterPanel, c); + + c.gridx = 0; + c.gridy = 1; + c.weightx = 1; + c.weighty = 1; + c.gridwidth = 2; + panel.add(createSearchResultsPanel(), c); + return panel; + } + + private Component createQueryPanel() { + JPanel panel = new JPanel(); + panel.setBorder(BorderFactory.createTitledBorder("Query")); + panel.setLayout(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.WEST; + c.gridx = GridBagConstraints.RELATIVE; + c.gridy = 0; + c.weightx = 0.1; + c.gridwidth = 2; + + autoQueryCodeButton = new JRadioButton("Use source term", true); + autoQueryCodeButton.addActionListener(x -> doSearch()); + panel.add(autoQueryCodeButton, c); + + c.gridx = 0; + c.gridy = 1; + c.weightx = 0.1; + c.gridwidth = 1; + manualQueryButton = new JRadioButton("Query:", false); + manualQueryButton.addActionListener(x -> doSearch()); + panel.add(manualQueryButton, c); + + ButtonGroup buttonGroup = new ButtonGroup(); + buttonGroup.add(autoQueryCodeButton); + buttonGroup.add(manualQueryButton); + + c.gridx = 1; + c.gridy = 1; + c.weightx = 1; + c.gridwidth = GridBagConstraints.REMAINDER; + manualQueryField = new JTextField(""); + // manualQueryField.setPreferredSize(new Dimension(200, 5)); + manualQueryField.getDocument().addDocumentListener(new DocumentListener() { + + @Override + public void removeUpdate(DocumentEvent arg0) { + manualQueryButton.setSelected(true); + doSearch(); + } + + @Override + public void insertUpdate(DocumentEvent arg0) { + manualQueryButton.setSelected(true); + doSearch(); + } + + @Override + public void changedUpdate(DocumentEvent arg0) { + manualQueryButton.setSelected(true); + doSearch(); + } + }); + panel.add(manualQueryField, c); + return panel; + } + + private Component createSearchResultsPanel() { + JPanel panel = new JPanel(); + panel.setBorder(BorderFactory.createTitledBorder("Results")); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + searchTableModel = new ConceptTableModel(true); + searchTable = new UsagiTable(searchTableModel); + sorter = new TableRowSorter(searchTableModel); + searchTable.setRowSorter(sorter); + searchTable.setPreferredScrollableViewportSize(new Dimension(100, 100)); + searchTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); + searchTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + searchTable.getSelectionModel().addListSelectionListener(event -> { + int viewRow = searchTable.getSelectedRow(); + // Don't enable the buttons if no row selected or status is approved + if (viewRow == -1 || codeMapping.getMappingStatus() == MappingStatus.APPROVED) { + addButtons.forEach(x -> x.setEnabled(false)); + replaceButton.setEnabled(false); + } else { + addButtons.forEach(x -> x.setEnabled(true)); + replaceButton.setEnabled(true); + int modelRow = searchTable.convertRowIndexToModel(viewRow); + Global.conceptInfoAction.setEnabled(true); + Global.conceptInformationDialog.setConcept(searchTableModel.getConcept(modelRow)); + Global.athenaAction.setEnabled(true); + Global.athenaAction.setConcept(searchTableModel.getConcept(modelRow)); + Global.googleSearchAction.setEnabled(false); + } + }); + // searchTable.hideColumn("Synonym"); + searchTable.hideColumn("Valid start date"); + searchTable.hideColumn("Valid end date"); + searchTable.hideColumn("Invalid reason"); + panel.add(new JScrollPane(searchTable)); + + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS)); + buttonPanel.add(Box.createHorizontalGlue()); + + replaceButton = new JButton("Replace concept"); + replaceButton.setToolTipText("Replace selected concept"); + replaceButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + int viewRow = searchTable.getSelectedRow(); + int modelRow = searchTable.convertRowIndexToModel(viewRow); + replaceConcepts(searchTableModel.getConcept(modelRow)); + } + + }); + replaceButton.setEnabled(false); + buttonPanel.add(replaceButton); + + JButton button; + addButtons = new ArrayList<>(); + for (MappingTarget.Type mappingType : MappingTarget.Type.values()) { + if (mappingType.equals(MappingTarget.Type.MAPS_TO)) { + button = new JButton("Add concept"); + } else { + button = new JButton(String.format("Add %s concept", mappingType)); + } + button.setToolTipText(String.format("Add selected concept as %s", mappingType)); + button.addActionListener(e -> { + int viewRow = searchTable.getSelectedRow(); + int modelRow = searchTable.convertRowIndexToModel(viewRow); + addConcept(searchTableModel.getConcept(modelRow), mappingType); + }); + button.setEnabled(false); + addButtons.add(button); + buttonPanel.add(button); + } + + panel.add(buttonPanel); + + return panel; + } + + private Component createApprovePanel() { + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); + + panel.add(new JLabel("Comment:")); + + panel.add(Box.createHorizontalStrut(5)); + + commentField = new JTextField(); + commentField.setMaximumSize(new Dimension(Integer.MAX_VALUE, commentField.getPreferredSize().height)); + commentField.getDocument().addDocumentListener(new DocumentListener() { + + @Override + public void removeUpdate(DocumentEvent arg0) { + codeMapping.setComment(commentField.getText()); + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + } + + @Override + public void insertUpdate(DocumentEvent arg0) { + codeMapping.setComment(commentField.getText()); + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + } + + @Override + public void changedUpdate(DocumentEvent arg0) { + codeMapping.setComment(commentField.getText()); + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + } + }); + commentField.setToolTipText("Comments about the code mapping can be written here"); + panel.add(commentField); + + panel.add(Box.createHorizontalStrut(5)); + + flagButton = new JButton(Global.flagAction); + flagButton.setBackground(new Color(151, 220, 141)); + panel.add(flagButton); + + equivalenceOptionChooser = new JComboBox<>(CodeMapping.Equivalence.values()); + equivalenceOptionChooser.setToolTipText("Choose mapping equivalence"); + equivalenceOptionChooser.setMaximumSize(equivalenceOptionChooser.getPreferredSize()); + panel.add(equivalenceOptionChooser); + + approveButton = new JButton(Global.approveAction); + approveButton.setBackground(new Color(151, 220, 141)); + panel.add(approveButton); + + return panel; + } + + private JPanel createSourceCodePanel() { + JPanel panel = new JPanel(); + panel.setBorder(BorderFactory.createTitledBorder("Source code")); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + sourceCodeTableModel = new SourceCodeTableModel(); + sourceCodeTable = new UsagiTable(sourceCodeTableModel); + sourceCodeTable.setPreferredScrollableViewportSize(new Dimension(500, 35)); + sourceCodeTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); + sourceCodeTable.setRowSelectionAllowed(false); + sourceCodeTable.setCellSelectionEnabled(false); + JScrollPane pane = new JScrollPane(sourceCodeTable); + pane.setBorder(BorderFactory.createEmptyBorder()); + pane.setMinimumSize(new Dimension(500, 40)); + pane.setPreferredSize(new Dimension(500, 40)); + panel.add(pane); + + return panel; + } + + private JPanel createTargetConceptsPanel() { + JPanel panel = new JPanel(); + panel.setBorder(BorderFactory.createTitledBorder("Target concepts")); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + targetConceptTableModel = new TargetConceptTableModel(); + targetConceptTable = new UsagiTable(targetConceptTableModel); + targetConceptTable.setPreferredScrollableViewportSize(new Dimension(500, 45)); + targetConceptTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); + targetConceptTable.setRowSelectionAllowed(true); + targetConceptTable.getSelectionModel().addListSelectionListener(event -> { + int viewRow = targetConceptTable.getSelectedRow(); + if (viewRow == -1 || codeMapping.getMappingStatus() == MappingStatus.APPROVED) { + removeButton.setEnabled(false); + typesChooser.setEnabled(false); + } else { + removeButton.setEnabled(true); + typesChooser.setEnabled(true); + int modelRow = targetConceptTable.convertRowIndexToModel(viewRow); + MappingTarget mappingTarget = targetConceptTableModel.getMappingTarget(modelRow); + typesChooser.setSelectedItem(mappingTarget.getMappingType()); + Global.conceptInfoAction.setEnabled(true); + Global.conceptInformationDialog.setConcept(mappingTarget.getConcept()); + Global.athenaAction.setEnabled(true); + Global.athenaAction.setConcept(mappingTarget.getConcept()); + Global.googleSearchAction.setEnabled(false); + } + }); + targetConceptTable.hideColumn("Valid start date"); + targetConceptTable.hideColumn("Valid end date"); + targetConceptTable.hideColumn("Invalid reason"); + + JScrollPane pane = new JScrollPane(targetConceptTable); + pane.setBorder(BorderFactory.createEmptyBorder()); + pane.setMinimumSize(new Dimension(500, 50)); + pane.setPreferredSize(new Dimension(500, 50)); + panel.add(pane); + + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS)); + buttonPanel.add(Box.createHorizontalGlue()); + + typesChooser = new JComboBox<>(MappingTarget.Type.values()); + typesChooser.setToolTipText("Set type of the mapping"); + typesChooser.addActionListener(e -> { + if (((JComboBox)e.getSource()).hasFocus()) + changeTargetType(); + }); + typesChooser.setMaximumSize(typesChooser.getPreferredSize()); + typesChooser.setEnabled(false); + buttonPanel.add(typesChooser); + + removeButton = new JButton("Remove concept"); + removeButton.setToolTipText("Remove selected concept"); + removeButton.addActionListener(e -> remove()); + removeButton.setEnabled(false); + buttonPanel.add(removeButton); + panel.add(buttonPanel); + return panel; + } + + @Override + public void codeSelected(CodeMapping codeMapping) { + this.codeMapping = codeMapping; + toggleStatusButtons(); + sourceCodeTableModel.setMapping(codeMapping); + targetConceptTableModel.setConcepts(codeMapping.getTargetConcepts()); + commentField.setText(codeMapping.getComment()); + doSearch(); + } + + @Override + public void addCodeMultiSelected(CodeMapping codeMapping) { + this.codeMappingsFromMulti.add(codeMapping); + } + + @Override + public void clearCodeMultiSelected() { + this.codeMappingsFromMulti = new ArrayList<>(); + } + + public void approve() { + if (codeMapping.getMappingStatus() != CodeMapping.MappingStatus.APPROVED) { + CodeMapping.Equivalence equivalenceToApply = (CodeMapping.Equivalence) equivalenceOptionChooser.getSelectedItem(); + codeMapping.approve(Global.author, equivalenceToApply); + Global.mapping.fireDataChanged(APPROVE_EVENT); + } else { + codeMapping.setUnchecked(); + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + toggleStatusButtons(); + } + } + + public void flag() { + if (codeMapping.getMappingStatus() != CodeMapping.MappingStatus.FLAGGED) { + codeMapping.setMappingStatus(MappingStatus.FLAGGED); + Global.mapping.fireDataChanged(APPROVE_EVENT); + } else { + codeMapping.setMappingStatus(MappingStatus.UNCHECKED); + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + toggleStatusButtons(); + } + } + + private void toggleStatusButtons() { + Global.approveAction.setToApprove(); + Global.flagAction.setToFlag(); + flagButton.setEnabled(false); + approveButton.setEnabled(false); + equivalenceOptionChooser.setEnabled(false); + + switch(codeMapping.getMappingStatus()) { + case APPROVED: + Global.approveAction.setToUnapprove(); + approveButton.setEnabled(true); + break; + case FLAGGED: + Global.flagAction.setToUnflag(); + flagButton.setEnabled(true); + break; + default: // unchecked, invalid or auto-mapped + flagButton.setEnabled(true); + approveButton.setEnabled(true); + equivalenceOptionChooser.setEnabled(true); + } + } + + public void addConcept(Concept concept) { + codeMapping.getTargetConcepts().add(new MappingTarget(concept, Global.author)); + for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { + codeMappingMulti.getTargetConcepts().add(new MappingTarget(concept, Global.author)); + } + targetConceptTableModel.fireTableDataChanged(); + + if (codeMappingsFromMulti.size() > 0) { + Global.mapping.fireDataChanged(MULTI_UPDATE_EVENT); + } else { + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + } + } + + public void addConcept(Concept concept, MappingTarget.Type mappingType) { + codeMapping.getTargetConcepts().add(new MappingTarget(concept, mappingType, Global.author)); + for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { + codeMappingMulti.getTargetConcepts().add(new MappingTarget(concept, mappingType, Global.author)); + } + targetConceptTableModel.fireTableDataChanged(); + + if (codeMappingsFromMulti.size() > 0) { + Global.mapping.fireDataChanged(MULTI_UPDATE_EVENT); + } else { + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + } + } + + public void replaceConcepts(Concept concept) { + codeMapping.getTargetConcepts().clear(); + for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { + codeMappingMulti.getTargetConcepts().clear(); + } + addConcept(concept); + } + + private void remove() { + Arrays.stream(targetConceptTable.getSelectedRows()) + .map(r -> targetConceptTable.convertRowIndexToModel(r)) + .boxed().sorted(Comparator.reverseOrder()).mapToInt(Integer::intValue) // sorting for array integrity, remove last first. + .forEach(r -> codeMapping.getTargetConcepts().remove(r)); + + targetConceptTableModel.fireTableDataChanged(); + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + } + + private void changeTargetType() { + for (int row : targetConceptTable.getSelectedRows()) { + MappingTarget mappingTarget = codeMapping.getTargetConcepts().get(row); + mappingTarget.setMappingType((MappingTarget.Type) typesChooser.getSelectedItem()); + } + + targetConceptTableModel.fireTableDataChanged(); + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + } + + private class SearchTask extends TimerTask { + + @Override + public void run() { + Set filterConceptIds = null; + if (filterPanel.getFilterByAuto()) + filterConceptIds = codeMapping.getSourceCode().sourceAutoAssignedConceptIds; + + boolean filterStandard = filterPanel.getFilterStandard(); + Vector filterConceptClasses = null; + if (filterPanel.getFilterByConceptClasses()) + filterConceptClasses = filterPanel.getConceptClass(); + Vector filterVocabularies = null; + if (filterPanel.getFilterByVocabularies()) + filterVocabularies = filterPanel.getVocabulary(); + Vector filterDomains = null; + if (filterPanel.getFilterByDomains()) + filterDomains = filterPanel.getDomain(); + + String query; + if (autoQueryCodeButton.isSelected()) { + query = codeMapping.getSourceCode().sourceName; + } else { + query = manualQueryField.getText(); + } + + boolean includeSourceConcepts = filterPanel.getIncludeSourceTerms(); + + if (Global.usagiSearchEngine.isOpenForSearching()) { + List searchResults = Global.usagiSearchEngine.search(query, true, filterConceptIds, filterDomains, filterConceptClasses, + filterVocabularies, filterStandard, includeSourceConcepts); + + searchTableModel.setScoredConcepts(searchResults); + searchTable.scrollRectToVisible(new Rectangle(searchTable.getCellRect(0, 0, true))); + } + Global.statusBar.setSearching(false); + } + } + + public void doSearch() { + Global.statusBar.setSearching(true); + if (timer != null) + timer.cancel(); + timer = new Timer(); + timer.schedule(new SearchTask(), 500); + } + + class SourceCodeTableModel extends AbstractTableModel { + private static final long serialVersionUID = 169286268154988911L; + + private String[] defaultColumnNames = { "Source code", "Source term", "Frequency" }; + private String[] columnNames = defaultColumnNames; + private CodeMapping codeMapping; + private int addInfoColCount = 0; + private int ADD_INFO_START_COL = 3; + + public int getColumnCount() { + return columnNames.length; + } + + public void setMapping(CodeMapping codeMapping) { + this.codeMapping = codeMapping; + + columnNames = defaultColumnNames; + addInfoColCount = codeMapping.getSourceCode().sourceAdditionalInfo.size(); + columnNames = new String[defaultColumnNames.length + addInfoColCount]; + for (int i = 0; i < ADD_INFO_START_COL; i++) + columnNames[i] = defaultColumnNames[i]; + + for (int i = 0; i < addInfoColCount; i++) + columnNames[i + ADD_INFO_START_COL] = codeMapping.getSourceCode().sourceAdditionalInfo.get(i).getItem1(); + + fireTableStructureChanged(); + } + + public int getRowCount() { + return 1; + } + + public String getColumnName(int col) { + return columnNames[col]; + } + + public Object getValueAt(int row, int col) { + if (codeMapping == null) + return ""; + if (col >= ADD_INFO_START_COL) { + return codeMapping.getSourceCode().sourceAdditionalInfo.get(col - ADD_INFO_START_COL).getItem2(); + } else { + switch (col) { + case 0: + return codeMapping.getSourceCode().sourceCode; + case 1: + return codeMapping.getSourceCode().sourceName; + case 2: + return codeMapping.getSourceCode().sourceFrequency; + default: + return ""; + } + } + + } + + public Class getColumnClass(int col) { + if (col >= ADD_INFO_START_COL) { + return String.class; + } else { + switch (col) { + case 2: + return Integer.class; + default: + return String.class; + } + } + } + + public boolean isCellEditable(int row, int col) { + return true; + } + + public void setValueAt(Object value, int row, int col) { + + } + } + + @Override + public void filterChanged() { + doSearch(); + } + +} diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 46e02c2..7df9830 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -114,7 +114,7 @@ class CodeMapTableModel extends AbstractTableModel { "Children", "Assigned To", "Equivalence", "Comment", "Status Provenance" }; private String[] columnNames = defaultColumnNames; private int addInfoColCount = 0; - private final int ADD_INFO_START_COL = 7; + private final int ADD_INFO_START_COL = 4; private static final int ASSIGNED_REVIEWER_COL = 17; // special meaning, as public int getColumnCount() { diff --git a/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java b/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java index 8d3acd9..edbd5c4 100644 --- a/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java +++ b/src/org/ohdsi/usagi/ui/TargetConceptTableModel.java @@ -11,7 +11,7 @@ class TargetConceptTableModel extends AbstractTableModel { private static final long serialVersionUID = -4978479688021056281L; private final String[] columnNames = {"Concept ID", "Concept name", "Domain", "Concept class", "Vocabulary", "Concept code", - "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", "Children", + "Valid start date", "Valid end date", "Invalid reason", "Standard concept", "Parents", "Children", "Mapping Type", "Creation Provenance"}; private List targetConcepts = new ArrayList<>(); @@ -75,6 +75,8 @@ public Object getValueAt(int row, int col) { case 11: return targetConcept.childCount; case 12: + return mappingTarget.getMappingType(); + case 13: if (mappingTarget.getCreatedTime() != 0L) { return String.format("%s (%tF)", mappingTarget.getCreatedBy(), mappingTarget.getCreatedTime()); } @@ -85,7 +87,7 @@ public Object getValueAt(int row, int col) { public Class getColumnClass(int col) { switch (col) { - case 1: + case 0: case 10: case 11: return Integer.class; From fcbb9769267e257bb708898b44faa3aaecfa4a7b Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 19 Feb 2021 22:22:35 +0100 Subject: [PATCH 69/77] set equivalence upon flagging --- src/org/ohdsi/usagi/CodeMapping.java | 29 ++++++++++--------- src/org/ohdsi/usagi/MappingTarget.java | 2 +- .../ohdsi/usagi/ui/MappingDetailPanel.java | 7 +++-- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/org/ohdsi/usagi/CodeMapping.java b/src/org/ohdsi/usagi/CodeMapping.java index 511858c..6338cc0 100644 --- a/src/org/ohdsi/usagi/CodeMapping.java +++ b/src/org/ohdsi/usagi/CodeMapping.java @@ -15,6 +15,8 @@ ******************************************************************************/ package org.ohdsi.usagi; +import org.ohdsi.usagi.ui.Global; + import java.util.ArrayList; import java.util.List; @@ -27,11 +29,11 @@ public class CodeMapping { public enum MappingStatus { // Includes IGNORED for backwards compatibility APPROVED, UNCHECKED, AUTO_MAPPED, AUTO_MAPPED_TO_1, INVALID_TARGET, FLAGGED, IGNORED - }; + } public enum Equivalence { EQUAL, EQUIVALENT, WIDER, NARROWER, INEXACT, UNMATCHED, UNREVIEWED - }; + } private SourceCode sourceCode; private double matchScore; @@ -47,10 +49,20 @@ public CodeMapping(SourceCode sourceCode) { this.setSourceCode(sourceCode); } - public void setStatus(MappingStatus mappingStatus, String author) { + public void approve(Equivalence equivalence) { + setStatus(MappingStatus.APPROVED); + this.setEquivalence(equivalence); + } + + public void flag(Equivalence equivalence) { + setStatus(MappingStatus.FLAGGED); + this.setEquivalence(equivalence); + } + + public void setStatus(MappingStatus mappingStatus) { this.setMappingStatus(mappingStatus); this.setStatusSetOn(System.currentTimeMillis()); - this.setStatusSetBy(author); + this.setStatusSetBy(Global.author); } public void setUnchecked() { @@ -59,15 +71,6 @@ public void setUnchecked() { this.setStatusSetBy(""); } - public void approve(String approvedBy, Equivalence equivalence) { - setStatus(MappingStatus.APPROVED, approvedBy); - this.setEquivalence(equivalence); - } - - public void approve(String approvedBy) { - approve(approvedBy, Equivalence.EQUAL); - } - public SourceCode getSourceCode() { return sourceCode; } diff --git a/src/org/ohdsi/usagi/MappingTarget.java b/src/org/ohdsi/usagi/MappingTarget.java index 1038d4c..5341dc6 100644 --- a/src/org/ohdsi/usagi/MappingTarget.java +++ b/src/org/ohdsi/usagi/MappingTarget.java @@ -21,7 +21,7 @@ public class MappingTarget{ public enum Type { MAPS_TO, MAPS_TO_VALUE, MAPS_TO_UNIT - }; + } private final Concept concept; private final String createdBy; diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 360910f..980c4ff 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -392,7 +392,7 @@ public void clearCodeMultiSelected() { public void approve() { if (codeMapping.getMappingStatus() != CodeMapping.MappingStatus.APPROVED) { CodeMapping.Equivalence equivalenceToApply = (CodeMapping.Equivalence) equivalenceOptionChooser.getSelectedItem(); - codeMapping.approve(Global.author, equivalenceToApply); + codeMapping.approve(equivalenceToApply); Global.mapping.fireDataChanged(APPROVE_EVENT); } else { codeMapping.setUnchecked(); @@ -403,10 +403,11 @@ public void approve() { public void flag() { if (codeMapping.getMappingStatus() != CodeMapping.MappingStatus.FLAGGED) { - codeMapping.setMappingStatus(MappingStatus.FLAGGED); + CodeMapping.Equivalence equivalenceToApply = (CodeMapping.Equivalence) equivalenceOptionChooser.getSelectedItem(); + codeMapping.flag(equivalenceToApply); Global.mapping.fireDataChanged(APPROVE_EVENT); } else { - codeMapping.setMappingStatus(MappingStatus.UNCHECKED); + codeMapping.setUnchecked(); Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); toggleStatusButtons(); } From ada5c3d81727f2d34d3345c6204d2dc11ea9a5d0 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 19 Feb 2021 22:24:24 +0100 Subject: [PATCH 70/77] set equivalence to unreviewed upon unapproving --- src/org/ohdsi/usagi/CodeMapping.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/org/ohdsi/usagi/CodeMapping.java b/src/org/ohdsi/usagi/CodeMapping.java index 6338cc0..e7c8f77 100644 --- a/src/org/ohdsi/usagi/CodeMapping.java +++ b/src/org/ohdsi/usagi/CodeMapping.java @@ -67,6 +67,7 @@ public void setStatus(MappingStatus mappingStatus) { public void setUnchecked() { this.setMappingStatus(MappingStatus.UNCHECKED); + this.setEquivalence(Equivalence.UNREVIEWED); this.setStatusSetOn(0); this.setStatusSetBy(""); } From ad4c8923199573417f7739f5a2edef7867d26ff3 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 19 Feb 2021 22:26:42 +0100 Subject: [PATCH 71/77] rename add buttons --- src/org/ohdsi/usagi/ui/MappingDetailPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 980c4ff..7e644ee 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -221,7 +221,7 @@ public void actionPerformed(ActionEvent e) { if (mappingType.equals(MappingTarget.Type.MAPS_TO)) { button = new JButton("Add concept"); } else { - button = new JButton(String.format("Add %s concept", mappingType)); + button = new JButton(String.format("Add %s", mappingType)); } button.setToolTipText(String.format("Add selected concept as %s", mappingType)); button.addActionListener(e -> { From 3b21991c9eeb469cc79ea07dba18607aefa62aaf Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 19 Feb 2021 22:44:17 +0100 Subject: [PATCH 72/77] assign reviewers only to selected codes --- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 7df9830..737b3ed 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -31,6 +31,7 @@ import javax.swing.table.AbstractTableModel; import javax.swing.table.TableRowSorter; +import org.apache.xmlbeans.impl.xb.ltgfmt.Code; import org.ohdsi.usagi.CodeMapping; import org.ohdsi.usagi.CodeMapping.MappingStatus; import org.ohdsi.usagi.Concept; @@ -343,12 +344,25 @@ public void assignReviewersEqually(String[] reviewers) { // If the number of code mappings is not a multiple of the number of reviewers, // then the first, second, etc. reviewer get one mapping more assigned. int nReviewers = reviewers.length; - List codeMappingIndex = IntStream.range(0, Global.mapping.size()) + + List codesToAssign = new ArrayList<>(); + if (table.getSelectedRows().length == 1) { + // If only one row selected, assign all rows to the given reviewers + codesToAssign = Global.mapping; + } else { + // If a multi selection is made, only assign the select rows. + for (int viewRow : table.getSelectedRows()) { + int modelRow = table.convertRowIndexToModel(viewRow); + codesToAssign.add(tableModel.getCodeMapping(modelRow)); + } + } + + List codeMappingIndex = IntStream.range(0, codesToAssign.size()) .boxed().collect(Collectors.toList()); Collections.shuffle(codeMappingIndex); for (int i = 0; i < codeMappingIndex.size(); i++) { - CodeMapping codeMapping = Global.mapping.get(codeMappingIndex.get(i)); + CodeMapping codeMapping = codesToAssign.get(codeMappingIndex.get(i)); codeMapping.setAssignedReviewer(reviewers[i % nReviewers]); } fireUpdateEventAll(APPROVE_EVENT); From 69218ed420145f0cde78df5b7732574bf8a8a6fd Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Thu, 11 Mar 2021 17:51:26 +0100 Subject: [PATCH 73/77] approve selected with equivalence status --- src/org/ohdsi/usagi/ui/MappingDetailPanel.java | 9 +++++++++ src/org/ohdsi/usagi/ui/MappingTablePanel.java | 8 -------- .../ohdsi/usagi/ui/actions/ApproveSelectedAction.java | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 7e644ee..6a25589 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -401,6 +401,15 @@ public void approve() { } } + public void approveSelected() { + CodeMapping.Equivalence equivalenceToApply = (CodeMapping.Equivalence) equivalenceOptionChooser.getSelectedItem(); + codeMapping.approve(equivalenceToApply); + for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { + codeMappingMulti.approve(equivalenceToApply); + } + Global.mapping.fireDataChanged(APPROVE_EVENT); + } + public void flag() { if (codeMapping.getMappingStatus() != CodeMapping.MappingStatus.FLAGGED) { CodeMapping.Equivalence equivalenceToApply = (CodeMapping.Equivalence) equivalenceOptionChooser.getSelectedItem(); diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 737b3ed..671d1af 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -312,14 +312,6 @@ private void fireUpdateEventAll(DataChangeEvent event) { } } - public void approveSelected() { - for (int viewRow : table.getSelectedRows()) { - int modelRow = table.convertRowIndexToModel(viewRow); - tableModel.getCodeMapping(modelRow).setMappingStatus(MappingStatus.APPROVED); - } - fireUpdateEventAll(APPROVE_EVENT); - } - public void clearSelected() { for (int viewRow : table.getSelectedRows()) { int modelRow = table.convertRowIndexToModel(viewRow); diff --git a/src/org/ohdsi/usagi/ui/actions/ApproveSelectedAction.java b/src/org/ohdsi/usagi/ui/actions/ApproveSelectedAction.java index 2215f64..b8799c0 100644 --- a/src/org/ohdsi/usagi/ui/actions/ApproveSelectedAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ApproveSelectedAction.java @@ -35,7 +35,7 @@ public ApproveSelectedAction() { @Override public void actionPerformed(ActionEvent arg0) { - Global.mappingTablePanel.approveSelected(); + Global.mappingDetailPanel.approveSelected(); } } From 846052d99cfdbfd2690c51ddaaea4bbc879ab727 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Thu, 11 Mar 2021 18:05:04 +0100 Subject: [PATCH 74/77] always apply approve and flag actions on all selected codes --- src/org/ohdsi/usagi/ui/Global.java | 1 - .../ohdsi/usagi/ui/MappingDetailPanel.java | 49 ++++++++++++------- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 2 - src/org/ohdsi/usagi/ui/UsagiMain.java | 2 - src/org/ohdsi/usagi/ui/UsagiMenubar.java | 1 - .../ohdsi/usagi/ui/actions/ApproveAction.java | 2 +- .../ui/actions/ApproveSelectedAction.java | 41 ---------------- .../ohdsi/usagi/ui/actions/FlagAction.java | 2 +- 8 files changed, 32 insertions(+), 68 deletions(-) delete mode 100644 src/org/ohdsi/usagi/ui/actions/ApproveSelectedAction.java diff --git a/src/org/ohdsi/usagi/ui/Global.java b/src/org/ohdsi/usagi/ui/Global.java index 280302b..be488b8 100644 --- a/src/org/ohdsi/usagi/ui/Global.java +++ b/src/org/ohdsi/usagi/ui/Global.java @@ -42,7 +42,6 @@ public class Global { public static SaveAction saveAction; public static SaveAsAction saveAsAction; public static ApproveAction approveAction; - public static ApproveSelectedAction approveSelectedAction; public static FlagAction flagAction; public static ReviewerAssignmentAction reviewerAssignmentAction; public static ClearSelectedAction clearSelectedAction; diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 6a25589..548bd83 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -389,37 +389,48 @@ public void clearCodeMultiSelected() { this.codeMappingsFromMulti = new ArrayList<>(); } - public void approve() { - if (codeMapping.getMappingStatus() != CodeMapping.MappingStatus.APPROVED) { - CodeMapping.Equivalence equivalenceToApply = (CodeMapping.Equivalence) equivalenceOptionChooser.getSelectedItem(); - codeMapping.approve(equivalenceToApply); - Global.mapping.fireDataChanged(APPROVE_EVENT); + public void approveOrUnapprove() { + if (codeMapping.getMappingStatus() == MappingStatus.APPROVED) { + uncheckSelected(); + toggleStatusButtons(); } else { - codeMapping.setUnchecked(); - Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + approveSelected(); + } + } + + public void flagOrUnflag() { + if (codeMapping.getMappingStatus() == MappingStatus.FLAGGED) { + uncheckSelected(); toggleStatusButtons(); + } else { + flagSelected(); } } public void approveSelected() { - CodeMapping.Equivalence equivalenceToApply = (CodeMapping.Equivalence) equivalenceOptionChooser.getSelectedItem(); - codeMapping.approve(equivalenceToApply); - for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { + CodeMapping.Equivalence equivalenceToApply = (CodeMapping.Equivalence) equivalenceOptionChooser.getSelectedItem(); + codeMapping.approve(equivalenceToApply); + for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { codeMappingMulti.approve(equivalenceToApply); } Global.mapping.fireDataChanged(APPROVE_EVENT); } - public void flag() { - if (codeMapping.getMappingStatus() != CodeMapping.MappingStatus.FLAGGED) { - CodeMapping.Equivalence equivalenceToApply = (CodeMapping.Equivalence) equivalenceOptionChooser.getSelectedItem(); - codeMapping.flag(equivalenceToApply); - Global.mapping.fireDataChanged(APPROVE_EVENT); - } else { - codeMapping.setUnchecked(); - Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); - toggleStatusButtons(); + public void flagSelected() { + CodeMapping.Equivalence equivalenceToApply = (CodeMapping.Equivalence) equivalenceOptionChooser.getSelectedItem(); + codeMapping.flag(equivalenceToApply); + for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { + codeMappingMulti.flag(equivalenceToApply); + } + Global.mapping.fireDataChanged(APPROVE_EVENT); + } + + public void uncheckSelected() { + codeMapping.setUnchecked(); + for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { + codeMappingMulti.setUnchecked(); } + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); } private void toggleStatusButtons() { diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 671d1af..9e7ab8c 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -69,7 +69,6 @@ public MappingTablePanel() { Global.googleSearchAction.setSourceTerm(tableModel.getCodeMapping(primaryModelRow).getSourceCode().sourceName); Global.approveAction.setEnabled(true); - Global.approveSelectedAction.setEnabled(true); Global.clearSelectedAction.setEnabled(true); if (tableModel.getCodeMapping(primaryModelRow).getTargetConcepts().size() > 0) { Concept firstConcept = tableModel.getCodeMapping(primaryModelRow).getTargetConcepts().get(0).getConcept(); @@ -89,7 +88,6 @@ public MappingTablePanel() { } } } else { - Global.approveSelectedAction.setEnabled(false); Global.approveAction.setEnabled(false); Global.clearSelectedAction.setEnabled(false); } diff --git a/src/org/ohdsi/usagi/ui/UsagiMain.java b/src/org/ohdsi/usagi/ui/UsagiMain.java index b710df9..c72a19a 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMain.java +++ b/src/org/ohdsi/usagi/ui/UsagiMain.java @@ -86,7 +86,6 @@ public UsagiMain(String[] args) { Global.googleSearchAction = new GoogleSearchAction(); Global.showStatsAction = new ShowStatsAction(); Global.aboutAction = new AboutAction(); - Global.approveSelectedAction = new ApproveSelectedAction(); Global.rebuildIndexAction = new RebuildIndexAction(); Global.exitAction = new ExitAction(); @@ -96,7 +95,6 @@ public UsagiMain(String[] args) { Global.exportAction.setEnabled(false); Global.exportForReviewAction.setEnabled(false); Global.approveAction.setEnabled(false); - Global.approveSelectedAction.setEnabled(false); Global.flagAction.setEnabled(false); Global.clearSelectedAction = new ClearSelectedAction(); Global.clearSelectedAction.setEnabled(false); diff --git a/src/org/ohdsi/usagi/ui/UsagiMenubar.java b/src/org/ohdsi/usagi/ui/UsagiMenubar.java index 67c680f..f36ce04 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMenubar.java +++ b/src/org/ohdsi/usagi/ui/UsagiMenubar.java @@ -42,7 +42,6 @@ public UsagiMenubar() { add(editMenu); editMenu.add(Global.approveAction); - editMenu.add(Global.approveSelectedAction); editMenu.add(Global.clearSelectedAction); editMenu.add(Global.reviewerAssignmentAction); diff --git a/src/org/ohdsi/usagi/ui/actions/ApproveAction.java b/src/org/ohdsi/usagi/ui/actions/ApproveAction.java index 711d0ff..5dd0e46 100644 --- a/src/org/ohdsi/usagi/ui/actions/ApproveAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ApproveAction.java @@ -37,7 +37,7 @@ public ApproveAction() { @Override public void actionPerformed(ActionEvent arg0) { - Global.mappingDetailPanel.approve(); + Global.mappingDetailPanel.approveOrUnapprove(); } public void setToApprove() { diff --git a/src/org/ohdsi/usagi/ui/actions/ApproveSelectedAction.java b/src/org/ohdsi/usagi/ui/actions/ApproveSelectedAction.java deleted file mode 100644 index b8799c0..0000000 --- a/src/org/ohdsi/usagi/ui/actions/ApproveSelectedAction.java +++ /dev/null @@ -1,41 +0,0 @@ -/******************************************************************************* - * Copyright 2019 Observational Health Data Sciences and Informatics - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ******************************************************************************/ -package org.ohdsi.usagi.ui.actions; - -import java.awt.event.ActionEvent; -import java.awt.event.InputEvent; -import java.awt.event.KeyEvent; - -import javax.swing.*; - -import org.ohdsi.usagi.ui.Global; - -public class ApproveSelectedAction extends AbstractAction { - - private static final long serialVersionUID = 3420357922150237898L; - - public ApproveSelectedAction() { - putValue(Action.NAME, "Approve selected"); - putValue(Action.SHORT_DESCRIPTION, "Approve all selected mappings"); - putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.ALT_MASK | InputEvent.SHIFT_DOWN_MASK)); - } - - @Override - public void actionPerformed(ActionEvent arg0) { - Global.mappingDetailPanel.approveSelected(); - } - -} diff --git a/src/org/ohdsi/usagi/ui/actions/FlagAction.java b/src/org/ohdsi/usagi/ui/actions/FlagAction.java index b8bcca9..fbfda41 100644 --- a/src/org/ohdsi/usagi/ui/actions/FlagAction.java +++ b/src/org/ohdsi/usagi/ui/actions/FlagAction.java @@ -34,7 +34,7 @@ public FlagAction() { @Override public void actionPerformed(ActionEvent arg0) { - Global.mappingDetailPanel.flag(); + Global.mappingDetailPanel.flagOrUnflag(); } public void setToFlag() { From 60ff72f85e18f855d8d18d3a5ef9c79c95db1983 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Thu, 11 Mar 2021 18:22:31 +0100 Subject: [PATCH 75/77] trigger multi update event when changing status of multi selection --- .../ohdsi/usagi/ui/MappingDetailPanel.java | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 548bd83..c42b06f 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -413,7 +413,11 @@ public void approveSelected() { for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { codeMappingMulti.approve(equivalenceToApply); } - Global.mapping.fireDataChanged(APPROVE_EVENT); + if (codeMappingsFromMulti.isEmpty()) { + Global.mapping.fireDataChanged(APPROVE_EVENT); + } else { + Global.mapping.fireDataChanged(MULTI_UPDATE_EVENT); + } } public void flagSelected() { @@ -422,7 +426,11 @@ public void flagSelected() { for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { codeMappingMulti.flag(equivalenceToApply); } - Global.mapping.fireDataChanged(APPROVE_EVENT); + if (codeMappingsFromMulti.isEmpty()) { + Global.mapping.fireDataChanged(APPROVE_EVENT); + } else { + Global.mapping.fireDataChanged(MULTI_UPDATE_EVENT); + } } public void uncheckSelected() { @@ -430,7 +438,11 @@ public void uncheckSelected() { for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { codeMappingMulti.setUnchecked(); } - Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + if (codeMappingsFromMulti.isEmpty()) { + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + } else { + Global.mapping.fireDataChanged(MULTI_UPDATE_EVENT); + } } private void toggleStatusButtons() { @@ -463,10 +475,10 @@ public void addConcept(Concept concept) { } targetConceptTableModel.fireTableDataChanged(); - if (codeMappingsFromMulti.size() > 0) { - Global.mapping.fireDataChanged(MULTI_UPDATE_EVENT); - } else { + if (codeMappingsFromMulti.isEmpty()) { Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + } else { + Global.mapping.fireDataChanged(MULTI_UPDATE_EVENT); } } @@ -477,10 +489,10 @@ public void addConcept(Concept concept, MappingTarget.Type mappingType) { } targetConceptTableModel.fireTableDataChanged(); - if (codeMappingsFromMulti.size() > 0) { - Global.mapping.fireDataChanged(MULTI_UPDATE_EVENT); - } else { + if (codeMappingsFromMulti.isEmpty()) { Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); + } else { + Global.mapping.fireDataChanged(MULTI_UPDATE_EVENT); } } From 7291f1c5b49f5d83af5bea250d4a66c83685d562 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Thu, 11 Mar 2021 18:34:09 +0100 Subject: [PATCH 76/77] clear selected also unapproves code mapping --- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 9e7ab8c..d69c331 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -314,8 +314,9 @@ public void clearSelected() { for (int viewRow : table.getSelectedRows()) { int modelRow = table.convertRowIndexToModel(viewRow); tableModel.getCodeMapping(modelRow).getTargetConcepts().clear(); + tableModel.getCodeMapping(modelRow).setUnchecked(); } - fireUpdateEventAll(SIMPLE_UPDATE_EVENT); + fireUpdateEventAll(MULTI_UPDATE_EVENT); } public void assignReviewersRandomly(String[] reviewers) { From 2246472fa3f583a4f612cada94aa7abe0cc0ec0a Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Thu, 11 Mar 2021 18:35:59 +0100 Subject: [PATCH 77/77] bump version --- src/org/ohdsi/usagi/ui/UsagiMain.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/ohdsi/usagi/ui/UsagiMain.java b/src/org/ohdsi/usagi/ui/UsagiMain.java index c72a19a..7f4f94d 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMain.java +++ b/src/org/ohdsi/usagi/ui/UsagiMain.java @@ -41,7 +41,7 @@ */ public class UsagiMain implements ActionListener { - public static String version = "1.4.0-SNAPSHOT"; + public static String version = "1.4.1"; public static void main(String[] args) { new UsagiMain(args);