From c4184e877467ccbf0cac862e6346c8a21fa3fb6a Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Mon, 6 Jan 2020 12:21:45 +0100 Subject: [PATCH 01/34] when applying previous mapping, also add codes not present in current file --- .../ohdsi/usagi/ReadCodeMappingsFromFile.java | 1 + .../actions/ApplyPreviousMappingAction.java | 43 ++++++++++++------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java index 88b0cf7..4ac2551 100644 --- a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java +++ b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java @@ -67,6 +67,7 @@ && new SourceCode(row).sourceName.equals(buffer.sourceCode.sourceName)) { Concept concept = Global.dbEngine.getConcept(row.getInt("conceptId")); if (concept == null) { buffer.mappingStatus = CodeMapping.MappingStatus.INVALID_TARGET; + buffer.comment = "Invalid existing target: " + row.get("conceptId"); } else { buffer.targetConcepts.add(concept); } diff --git a/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java b/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java index 26ae08e..7982c58 100644 --- a/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java @@ -46,26 +46,37 @@ public void actionPerformed(ActionEvent arg0) { FileFilter csvFilter = new FileNameExtensionFilter("CSV files", "csv"); fileChooser.setFileFilter(csvFilter); if (fileChooser.showOpenDialog(Global.frame) == JFileChooser.APPROVE_OPTION) { - int mappingsUsed = 0; + int mappingsApplied = 0; + int mappingsAdded = 0; + + // Existing code lookup + Map codeToMapping = new HashMap<>(); + for (CodeMapping codeMapping: Global.mapping) { + codeToMapping.put(codeMapping.sourceCode.sourceCode, codeMapping); + } + + // Open mapping file to be applied File file = fileChooser.getSelectedFile(); - Mapping mapping = new Mapping(); - mapping.loadFromFile(file.getAbsolutePath()); - Map codeToOldMapping = new HashMap(); - for (CodeMapping codeMapping : mapping) - if (codeMapping.mappingStatus.equals(CodeMapping.MappingStatus.APPROVED)) - codeToOldMapping.put(codeMapping.sourceCode.sourceCode, codeMapping); + Mapping mappingToBeApplied = new Mapping(); + mappingToBeApplied.loadFromFile(file.getAbsolutePath()); - for (CodeMapping newCodeMapping : Global.mapping) { - CodeMapping oldCodeMapping = codeToOldMapping.get(newCodeMapping.sourceCode.sourceCode); - if (oldCodeMapping != null) { - newCodeMapping.targetConcepts = oldCodeMapping.targetConcepts; - newCodeMapping.mappingStatus = oldCodeMapping.mappingStatus; - newCodeMapping.comment = oldCodeMapping.comment; - mappingsUsed++; + // Apply mapping. Add mappings not currently present + for (CodeMapping codeMappingToBeApplied : mappingToBeApplied) { + CodeMapping existingMapping = codeToMapping.get(codeMappingToBeApplied.sourceCode.sourceCode); + if (existingMapping != null) { + existingMapping.sourceCode.sourceName = codeMappingToBeApplied.sourceCode.sourceName; + existingMapping.targetConcepts = codeMappingToBeApplied.targetConcepts; + existingMapping.mappingStatus = codeMappingToBeApplied.mappingStatus; + existingMapping.comment = codeMappingToBeApplied.comment; + mappingsApplied++; + } else { + Global.mapping.add(codeMappingToBeApplied); + mappingsAdded++; } } - String message = "The old mapping contained " + codeToOldMapping.size() + " approved mappings of which " + mappingsUsed - + " were applied to the current mapping."; + + String message = "The old mapping contained " + mappingToBeApplied.size() + " approved mappings of which " + mappingsApplied + + " were applied to the current mapping and " + mappingsAdded + " were newly added."; Global.mappingTablePanel.updateUI(); Global.mappingDetailPanel.updateUI(); JOptionPane.showMessageDialog(Global.frame, message); From 8b49a3d2b8ba03e1d2163f4862c5b34c2b10c894 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Sat, 2 May 2020 21:15:44 +0200 Subject: [PATCH 02/34] remember last folder used to select file --- .gitignore | 92 +++++++++++++++++++ .../ohdsi/usagi/ui/actions/OpenAction.java | 1 + .../ohdsi/usagi/ui/actions/SaveAction.java | 1 + .../ohdsi/usagi/ui/actions/SaveAsAction.java | 1 + 4 files changed, 95 insertions(+) diff --git a/.gitignore b/.gitignore index 04d4786..7f8cd1a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,95 @@ /bin build/ dist/ + +### Intellij ### +# Created by https://www.gitignore.io/api/intellij +# Edit at https://www.gitignore.io/?templates=intellij +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +.idea/**/sonarlint/ + +# SonarQube Plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator/ + +# End of https://www.gitignore.io/api/intellij \ No newline at end of file diff --git a/src/org/ohdsi/usagi/ui/actions/OpenAction.java b/src/org/ohdsi/usagi/ui/actions/OpenAction.java index 574125a..9ff0e79 100644 --- a/src/org/ohdsi/usagi/ui/actions/OpenAction.java +++ b/src/org/ohdsi/usagi/ui/actions/OpenAction.java @@ -48,6 +48,7 @@ public void actionPerformed(ActionEvent arg0) { File file = fileChooser.getSelectedFile(); Global.frame.setTitle("Usagi - " + file.getName()); Global.filename = file.getAbsolutePath(); + Global.folder = file.getParentFile().getAbsolutePath(); Global.mapping.loadFromFile(Global.filename); Global.usagiSearchEngine.close(); Global.usagiSearchEngine.createDerivedIndex(Global.mapping.getSourceCodes(), Global.frame); diff --git a/src/org/ohdsi/usagi/ui/actions/SaveAction.java b/src/org/ohdsi/usagi/ui/actions/SaveAction.java index a6a1d6b..d4a99d5 100644 --- a/src/org/ohdsi/usagi/ui/actions/SaveAction.java +++ b/src/org/ohdsi/usagi/ui/actions/SaveAction.java @@ -52,6 +52,7 @@ public void actionPerformed(ActionEvent arg0) { file = new File(file.getAbsolutePath() + ".csv"); Global.frame.setTitle("Usagi - " + file.getName()); Global.filename = file.getAbsolutePath(); + Global.folder = file.getParentFile().getAbsolutePath(); } } if (Global.filename != null) { diff --git a/src/org/ohdsi/usagi/ui/actions/SaveAsAction.java b/src/org/ohdsi/usagi/ui/actions/SaveAsAction.java index 0da50ba..b26ba43 100644 --- a/src/org/ohdsi/usagi/ui/actions/SaveAsAction.java +++ b/src/org/ohdsi/usagi/ui/actions/SaveAsAction.java @@ -47,6 +47,7 @@ public void actionPerformed(ActionEvent arg0) { file = new File(file.getAbsolutePath() + ".csv"); Global.frame.setTitle("Usagi - " + file.getName()); Global.filename = file.getAbsolutePath(); + Global.folder = file.getParentFile().getAbsolutePath(); Global.frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); Global.mapping.saveToFile(Global.filename); Global.frame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); From 53d33a5182228c764b970b9286dd10b401d6f2a9 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Sat, 2 May 2020 21:26:14 +0200 Subject: [PATCH 03/34] remember folder for import and export --- .gitignore | 11 ++++++++++- Usagi.iml | 14 ++++++++++++++ .../usagi/ui/ExportSourceToConceptMapDialog.java | 1 + .../usagi/ui/actions/ExportForReviewAction.java | 1 + src/org/ohdsi/usagi/ui/actions/ImportAction.java | 1 + 5 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 Usagi.iml diff --git a/.gitignore b/.gitignore index 7f8cd1a..dd64606 100644 --- a/.gitignore +++ b/.gitignore @@ -2,12 +2,21 @@ build/ dist/ +### Usagi index files ### +derivedIndex/ +mainIndex/ +sleepyCat/ +ConceptClassIds.txt +DomainIds.txt +VocabularyIds.txt +vocabularyVersion.txt + ### Intellij ### # Created by https://www.gitignore.io/api/intellij # Edit at https://www.gitignore.io/?templates=intellij # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - +.idea/ # User-specific stuff .idea/**/workspace.xml .idea/**/tasks.xml diff --git a/Usagi.iml b/Usagi.iml new file mode 100644 index 0000000..361dee2 --- /dev/null +++ b/Usagi.iml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java b/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java index b1da340..0335a3e 100644 --- a/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java +++ b/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java @@ -105,6 +105,7 @@ private void export() { fileChooser.setDialogTitle("Export"); if (fileChooser.showSaveDialog(Global.frame) == JFileChooser.APPROVE_OPTION) { File file = fileChooser.getSelectedFile(); + Global.folder = file.getParentFile().getAbsolutePath(); if (!file.getName().toLowerCase().endsWith(".csv")) file = new File(file.getAbsolutePath() + ".csv"); diff --git a/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java b/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java index b40391c..079f307 100644 --- a/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java @@ -58,6 +58,7 @@ public void actionPerformed(ActionEvent arg0) { fileChooser.setFileFilter(csvFilter); if (fileChooser.showSaveDialog(Global.frame) == JFileChooser.APPROVE_OPTION) { File file = fileChooser.getSelectedFile(); + Global.folder = file.getParentFile().getAbsolutePath(); if (!file.getName().toLowerCase().endsWith(".csv")) file = new File(file.getAbsolutePath() + ".csv"); Global.frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); diff --git a/src/org/ohdsi/usagi/ui/actions/ImportAction.java b/src/org/ohdsi/usagi/ui/actions/ImportAction.java index 82b3836..66f32fe 100644 --- a/src/org/ohdsi/usagi/ui/actions/ImportAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ImportAction.java @@ -53,6 +53,7 @@ public void actionPerformed(ActionEvent arg0) { fileChooser.setAcceptAllFileFilterUsed(false); if (fileChooser.showOpenDialog(Global.frame) == JFileChooser.APPROVE_OPTION) { File file = fileChooser.getSelectedFile(); + Global.folder = file.getParentFile().getAbsolutePath(); new ImportDialog(file.getAbsolutePath()); } } From 26e919b7720dcbf61c99cfec7076d8733b7c02e8 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Sun, 3 May 2020 10:17:58 +0200 Subject: [PATCH 04/34] open usagi file from commandline --- src/org/ohdsi/usagi/ui/UsagiMain.java | 28 +++++++++--------- .../ohdsi/usagi/ui/actions/OpenAction.java | 29 +++++++++++-------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/UsagiMain.java b/src/org/ohdsi/usagi/ui/UsagiMain.java index b8a567f..6e231b0 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMain.java +++ b/src/org/ohdsi/usagi/ui/UsagiMain.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. @@ -28,9 +28,7 @@ import java.util.ArrayList; import java.util.List; -import javax.swing.JFrame; -import javax.swing.JPanel; -import javax.swing.JSplitPane; +import javax.swing.*; import org.ohdsi.usagi.BerkeleyDbEngine; import org.ohdsi.usagi.UsagiSearchEngine; @@ -56,22 +54,16 @@ */ public class UsagiMain implements ActionListener { - private JFrame frame; - public static void main(String[] args) { new UsagiMain(args); } public UsagiMain(String[] args) { - frame = new JFrame("Usagi"); + JFrame frame = new JFrame("Usagi"); // Initialize global variables: Global.mapping = new Mapping(); - if (args.length != 0) - Global.folder = args[0]; - else - Global.folder = new File("").getAbsolutePath(); - + Global.folder = new File("").getAbsolutePath(); Global.usagiSearchEngine = new UsagiSearchEngine(Global.folder); Global.dbEngine = new BerkeleyDbEngine(Global.folder); if (Global.usagiSearchEngine.mainIndexExists()) { @@ -139,6 +131,12 @@ public void windowClosing(WindowEvent e) { if (!Global.usagiSearchEngine.mainIndexExists()) Global.rebuildIndexAction.actionPerformed(null); + + if (args.length == 1) { + Global.folder = args[0]; + } else if (args.length > 1 && args[0].equals("--file")) { + OpenAction.open(new File(args[1])); + } } private String loadVocabularyVersion(String folder) { @@ -147,7 +145,7 @@ private String loadVocabularyVersion(String folder) { if (new File(versionFileName).exists()) { for (String line : new ReadTextFile(versionFileName)) version = line; - } + } return version; } diff --git a/src/org/ohdsi/usagi/ui/actions/OpenAction.java b/src/org/ohdsi/usagi/ui/actions/OpenAction.java index 9ff0e79..e0f1e4f 100644 --- a/src/org/ohdsi/usagi/ui/actions/OpenAction.java +++ b/src/org/ohdsi/usagi/ui/actions/OpenAction.java @@ -46,19 +46,24 @@ public void actionPerformed(ActionEvent arg0) { fileChooser.setFileFilter(csvFilter); if (fileChooser.showOpenDialog(Global.frame) == JFileChooser.APPROVE_OPTION) { File file = fileChooser.getSelectedFile(); - Global.frame.setTitle("Usagi - " + file.getName()); - Global.filename = file.getAbsolutePath(); - Global.folder = file.getParentFile().getAbsolutePath(); - Global.mapping.loadFromFile(Global.filename); - Global.usagiSearchEngine.close(); - Global.usagiSearchEngine.createDerivedIndex(Global.mapping.getSourceCodes(), Global.frame); - Global.mappingDetailPanel.doSearch(); - Global.applyPreviousMappingAction.setEnabled(true); - Global.saveAction.setEnabled(true); - Global.saveAsAction.setEnabled(true); - Global.exportAction.setEnabled(true); - Global.exportForReviewAction.setEnabled(true); + open(file); } } + public static void open(File file) { + String a = file.getName(); + Global.frame.setTitle("Usagi - " + file.getName()); + Global.filename = file.getAbsolutePath(); + Global.folder = file.getParentFile().getAbsolutePath(); + Global.mapping.loadFromFile(Global.filename); + Global.usagiSearchEngine.close(); + Global.usagiSearchEngine.createDerivedIndex(Global.mapping.getSourceCodes(), Global.frame); + Global.mappingDetailPanel.doSearch(); + Global.applyPreviousMappingAction.setEnabled(true); + Global.saveAction.setEnabled(true); + Global.saveAsAction.setEnabled(true); + Global.exportAction.setEnabled(true); + Global.exportForReviewAction.setEnabled(true); + } + } From 80401af19301fefb6aee6f18e0a0065f891c99a7 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Sun, 3 May 2020 10:23:13 +0200 Subject: [PATCH 05/34] fix writing of null columns to csv --- .../ohdsi/utilities/files/WriteCSVFile.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/org/ohdsi/utilities/files/WriteCSVFile.java b/src/org/ohdsi/utilities/files/WriteCSVFile.java index 6a7646b..f16b7d9 100644 --- a/src/org/ohdsi/utilities/files/WriteCSVFile.java +++ b/src/org/ohdsi/utilities/files/WriteCSVFile.java @@ -86,15 +86,17 @@ public String columns2line(List columns) { Iterator iterator = columns.iterator(); while (iterator.hasNext()) { String column = iterator.next(); - boolean hasQuotes = column.contains("\""); - column = column.replaceAll("\\\\", "\\\\\\\\"); - if (hasQuotes) - column = column.replaceAll("\"", "\\\\\""); - column = column.replaceAll("\r", ""); - column = column.replaceAll("\n", "\\\\n"); - if (hasQuotes || column.contains(Character.toString(delimiter))) - column = "\"" + column + "\""; - sb.append(column); + if (column != null) { + boolean hasQuotes = column.contains("\""); + column = column.replaceAll("\\\\", "\\\\\\\\"); + if (hasQuotes) + column = column.replaceAll("\"", "\\\\\""); + column = column.replaceAll("\r", ""); + column = column.replaceAll("\n", "\\\\n"); + if (hasQuotes || column.contains(Character.toString(delimiter))) + column = "\"" + column + "\""; + sb.append(column); + } if (iterator.hasNext()) sb.append(delimiter); } From 795c33a7f5309c3ec302c93fb651b4037747b789 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Sun, 3 May 2020 10:48:20 +0200 Subject: [PATCH 06/34] ask to export unapproved mappings --- src/org/ohdsi/usagi/ui/actions/Dialogs.java | 30 +++++++ .../ui/actions/ExportForReviewAction.java | 90 ++++++++++--------- 2 files changed, 78 insertions(+), 42 deletions(-) create mode 100644 src/org/ohdsi/usagi/ui/actions/Dialogs.java diff --git a/src/org/ohdsi/usagi/ui/actions/Dialogs.java b/src/org/ohdsi/usagi/ui/actions/Dialogs.java new file mode 100644 index 0000000..32fbbe9 --- /dev/null +++ b/src/org/ohdsi/usagi/ui/actions/Dialogs.java @@ -0,0 +1,30 @@ +package org.ohdsi.usagi.ui.actions; + +import org.ohdsi.usagi.ui.Global; + +import javax.swing.*; + +public class Dialogs { + public static boolean askExportUnapprovedMappings() { + int PromptResult = JOptionPane.showOptionDialog( + Global.frame, + "Do you want to export both approved and unapproved mappings?", + "Export for review", + JOptionPane.YES_NO_CANCEL_OPTION, + JOptionPane.QUESTION_MESSAGE, + null, + new String [] {"Only approved","Approved and Unapproved"}, + "Only approved" + ); + return PromptResult == JOptionPane.YES_OPTION; + } + + public static void warningNothingToExport() { + JOptionPane.showMessageDialog( + Global.frame, + "There are no approved mappings, so nothing to export", + "Nothing to export", + JOptionPane.WARNING_MESSAGE + ); + } +} diff --git a/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java b/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java index 079f307..dfa1443 100644 --- a/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java @@ -46,55 +46,61 @@ public ExportForReviewAction() { @Override public void actionPerformed(ActionEvent arg0) { + boolean exportUnapproved = Dialogs.askExportUnapprovedMappings(); + boolean hasApprovedMappings = false; - for (CodeMapping mapping : Global.mapping) + for (CodeMapping mapping : Global.mapping) { if (mapping.mappingStatus == MappingStatus.APPROVED) { hasApprovedMappings = true; break; } - if (hasApprovedMappings) { - JFileChooser fileChooser = new JFileChooser(Global.folder); - FileFilter csvFilter = new FileNameExtensionFilter("CSV files", "csv"); - fileChooser.setFileFilter(csvFilter); - if (fileChooser.showSaveDialog(Global.frame) == JFileChooser.APPROVE_OPTION) { - File file = fileChooser.getSelectedFile(); - Global.folder = file.getParentFile().getAbsolutePath(); - if (!file.getName().toLowerCase().endsWith(".csv")) - file = new File(file.getAbsolutePath() + ".csv"); - Global.frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - WriteCSVFileWithHeader out = new WriteCSVFileWithHeader(file.getAbsolutePath()); - for (CodeMapping mapping : Global.mapping) - if (mapping.mappingStatus == MappingStatus.APPROVED) { - List targetConcepts; - if (mapping.targetConcepts.size() == 0) { - targetConcepts = new ArrayList(1); - targetConcepts.add(Concept.EMPTY_CONCEPT); - } else - targetConcepts = mapping.targetConcepts; + } + + if (!exportUnapproved && !hasApprovedMappings) { + Dialogs.warningNothingToExport(); + return; + } + + JFileChooser fileChooser = new JFileChooser(Global.folder); + FileFilter csvFilter = new FileNameExtensionFilter("CSV files", "csv"); + fileChooser.setFileFilter(csvFilter); + if (fileChooser.showSaveDialog(Global.frame) == JFileChooser.APPROVE_OPTION) { + File file = fileChooser.getSelectedFile(); + Global.folder = file.getParentFile().getAbsolutePath(); + if (!file.getName().toLowerCase().endsWith(".csv")) + file = new File(file.getAbsolutePath() + ".csv"); + 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) { + List targetConcepts; + if (mapping.targetConcepts.size() == 0) { + targetConcepts = new ArrayList(1); + targetConcepts.add(Concept.EMPTY_CONCEPT); + } else + targetConcepts = mapping.targetConcepts; - for (Concept targetConcept : targetConcepts) { - Row row = mapping.sourceCode.toRow(); - row.add("matchScore", mapping.matchScore); - row.add("targetConceptId", targetConcept.conceptId); - row.add("targetConceptName", targetConcept.conceptName); - row.add("targetVocabularyId", targetConcept.vocabularyId); - row.add("targetDomainId", targetConcept.domainId); - row.add("targetStandardConcept", targetConcept.standardConcept); - row.add("targetChildCount", targetConcept.childCount); - row.add("targetParentCount", targetConcept.parentCount); - row.add("targetConceptClassId", targetConcept.conceptClassId); - row.add("targetConceptCode", targetConcept.conceptCode); - row.add("targetValidStartDate", targetConcept.validStartDate); - row.add("targetValidEndDate", targetConcept.validEndDate); - row.add("targetInvalidReason", targetConcept.invalidReason); - out.write(row); - } + for (Concept targetConcept : targetConcepts) { + Row row = mapping.sourceCode.toRow(); + row.add("matchScore", mapping.matchScore); + if (exportUnapproved) row.add("mappingStatus", mapping.mappingStatus.toString()); + row.add("targetConceptId", targetConcept.conceptId); + row.add("targetConceptName", targetConcept.conceptName); + row.add("targetVocabularyId", targetConcept.vocabularyId); + row.add("targetDomainId", targetConcept.domainId); + row.add("targetStandardConcept", targetConcept.standardConcept); + row.add("targetChildCount", targetConcept.childCount); + row.add("targetParentCount", targetConcept.parentCount); + row.add("targetConceptClassId", targetConcept.conceptClassId); + row.add("targetConceptCode", targetConcept.conceptCode); + row.add("targetValidStartDate", targetConcept.validStartDate); + row.add("targetValidEndDate", targetConcept.validEndDate); + row.add("targetInvalidReason", targetConcept.invalidReason); + out.write(row); } - out.close(); - Global.frame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - } - } else { - JOptionPane.showMessageDialog(Global.frame, "There are no approved mappings, so nothing to export", "Warning", JOptionPane.WARNING_MESSAGE); + } + out.close(); + Global.frame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } } From c154983c6afdaf154fde644c40573346f6a24892 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Sun, 3 May 2020 11:52:58 +0200 Subject: [PATCH 07/34] add os specific menu shortcut key --- src/org/ohdsi/usagi/ui/actions/Dialogs.java | 9 +++++---- .../ohdsi/usagi/ui/actions/ExportForReviewAction.java | 10 +++++----- src/org/ohdsi/usagi/ui/actions/ImportAction.java | 5 +++-- src/org/ohdsi/usagi/ui/actions/OpenAction.java | 5 +++-- src/org/ohdsi/usagi/ui/actions/SaveAction.java | 7 ++++--- 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/actions/Dialogs.java b/src/org/ohdsi/usagi/ui/actions/Dialogs.java index 32fbbe9..ffea174 100644 --- a/src/org/ohdsi/usagi/ui/actions/Dialogs.java +++ b/src/org/ohdsi/usagi/ui/actions/Dialogs.java @@ -6,17 +6,18 @@ public class Dialogs { public static boolean askExportUnapprovedMappings() { + String[] options = {"Only approved","Approved and Unapproved"}; int PromptResult = JOptionPane.showOptionDialog( Global.frame, "Do you want to export both approved and unapproved mappings?", "Export for review", - JOptionPane.YES_NO_CANCEL_OPTION, + JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, - new String [] {"Only approved","Approved and Unapproved"}, - "Only approved" + options, + options[0] ); - return PromptResult == JOptionPane.YES_OPTION; + return PromptResult == 1; } public static void warningNothingToExport() { diff --git a/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java b/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java index dfa1443..cb7c628 100644 --- a/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java @@ -15,16 +15,14 @@ ******************************************************************************/ package org.ohdsi.usagi.ui.actions; -import java.awt.Cursor; +import java.awt.*; import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; import java.io.File; import java.util.ArrayList; import java.util.List; -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.JFileChooser; -import javax.swing.JOptionPane; +import javax.swing.*; import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileNameExtensionFilter; @@ -42,6 +40,8 @@ public class ExportForReviewAction extends AbstractAction { public ExportForReviewAction() { putValue(Action.NAME, "Export for review"); putValue(Action.SHORT_DESCRIPTION, "Export mapping to a human readable format for reviewing"); + putValue(Action.MNEMONIC_KEY, KeyEvent.VK_R); + putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_R, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); } @Override diff --git a/src/org/ohdsi/usagi/ui/actions/ImportAction.java b/src/org/ohdsi/usagi/ui/actions/ImportAction.java index 66f32fe..d153d9b 100644 --- a/src/org/ohdsi/usagi/ui/actions/ImportAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ImportAction.java @@ -15,6 +15,7 @@ ******************************************************************************/ package org.ohdsi.usagi.ui.actions; +import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.io.File; @@ -36,8 +37,8 @@ public class ImportAction extends AbstractAction { public ImportAction() { putValue(Action.NAME, "Import codes"); putValue(Action.SHORT_DESCRIPTION, "Import a file containing codes"); - putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_I)); - putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_I, ActionEvent.CTRL_MASK)); + putValue(Action.MNEMONIC_KEY, KeyEvent.VK_I); + putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_I, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); } @Override diff --git a/src/org/ohdsi/usagi/ui/actions/OpenAction.java b/src/org/ohdsi/usagi/ui/actions/OpenAction.java index e0f1e4f..20fe1c5 100644 --- a/src/org/ohdsi/usagi/ui/actions/OpenAction.java +++ b/src/org/ohdsi/usagi/ui/actions/OpenAction.java @@ -15,6 +15,7 @@ ******************************************************************************/ package org.ohdsi.usagi.ui.actions; +import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.io.File; @@ -35,8 +36,8 @@ public class OpenAction extends AbstractAction { public OpenAction() { putValue(Action.NAME, "Open"); putValue(Action.SHORT_DESCRIPTION, "Open mapping file"); - putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_O)); - putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK)); + putValue(Action.MNEMONIC_KEY, KeyEvent.VK_O); + putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_O, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); } @Override diff --git a/src/org/ohdsi/usagi/ui/actions/SaveAction.java b/src/org/ohdsi/usagi/ui/actions/SaveAction.java index d4a99d5..c1bed93 100644 --- a/src/org/ohdsi/usagi/ui/actions/SaveAction.java +++ b/src/org/ohdsi/usagi/ui/actions/SaveAction.java @@ -15,8 +15,9 @@ ******************************************************************************/ package org.ohdsi.usagi.ui.actions; -import java.awt.Cursor; +import java.awt.*; import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.io.File; @@ -36,8 +37,8 @@ public class SaveAction extends AbstractAction { public SaveAction() { putValue(Action.NAME, "Save"); putValue(Action.SHORT_DESCRIPTION, "Save mapping file"); - putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_S)); - putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK)); + putValue(Action.MNEMONIC_KEY, KeyEvent.VK_S); + putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_S, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); } @Override From e202b2449bb28c730d13de61633e660e97a6aa4e Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Sun, 3 May 2020 12:03:52 +0200 Subject: [PATCH 08/34] add option to export unapproved to source_to_concept_map --- .../ui/ExportSourceToConceptMapDialog.java | 25 +++++++----------- .../ExportSourceToConceptMapAction.java | 26 ++++++++++++------- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java b/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java index 0335a3e..0e8bb19 100644 --- a/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java +++ b/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java @@ -45,6 +45,7 @@ public class ExportSourceToConceptMapDialog extends JDialog { private JTextField sourceVocabularyIdField; private static final long serialVersionUID = -6846083121849826818L; + private boolean exportUnapproved = false; public ExportSourceToConceptMapDialog() { setTitle("Export to source_to_concept_map"); @@ -56,7 +57,7 @@ public ExportSourceToConceptMapDialog() { g.gridx = 0; g.gridy = 0; - add(new JLabel("Source vocabulary id:"), g); + add(new JLabel("Source vocabulary id (max 20 alphanumerical characters):"), g); g.gridx = 1; g.gridy = 0; @@ -73,23 +74,11 @@ public ExportSourceToConceptMapDialog() { buttonPanel.add(Box.createHorizontalGlue()); JButton cancelButton = new JButton("Cancel"); cancelButton.setToolTipText("Cancel the export"); - cancelButton.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent arg0) { - setVisible(false); - } - }); + cancelButton.addActionListener(arg0 -> setVisible(false)); buttonPanel.add(cancelButton); JButton exportButton = new JButton("Export"); exportButton.setToolTipText("Select the filename and export using these settings"); - exportButton.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent arg0) { - export(); - } - }); + exportButton.addActionListener(arg0 -> export()); buttonPanel.add(exportButton); add(buttonPanel, g); @@ -98,6 +87,10 @@ public void actionPerformed(ActionEvent arg0) { setLocationRelativeTo(Global.frame); } + public void setExportUnapproved(boolean exportUnapproved) { + this.exportUnapproved = exportUnapproved; + } + private void export() { JFileChooser fileChooser = new JFileChooser(Global.folder); FileFilter csvFilter = new FileNameExtensionFilter("CSV files", "csv"); @@ -117,7 +110,7 @@ private void export() { private void writeToCsvFile(String filename) { WriteCSVFileWithHeader out = new WriteCSVFileWithHeader(filename); for (CodeMapping mapping : Global.mapping) - if (mapping.mappingStatus == MappingStatus.APPROVED) { + if (exportUnapproved || mapping.mappingStatus == MappingStatus.APPROVED) { List targetConcepts; if (mapping.targetConcepts.size() == 0) { targetConcepts = new ArrayList(1); diff --git a/src/org/ohdsi/usagi/ui/actions/ExportSourceToConceptMapAction.java b/src/org/ohdsi/usagi/ui/actions/ExportSourceToConceptMapAction.java index ad91725..f53d726 100644 --- a/src/org/ohdsi/usagi/ui/actions/ExportSourceToConceptMapAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ExportSourceToConceptMapAction.java @@ -15,12 +15,11 @@ ******************************************************************************/ package org.ohdsi.usagi.ui.actions; +import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.JOptionPane; +import javax.swing.*; import org.ohdsi.usagi.CodeMapping; import org.ohdsi.usagi.CodeMapping.MappingStatus; @@ -34,23 +33,30 @@ public class ExportSourceToConceptMapAction extends AbstractAction { public ExportSourceToConceptMapAction() { putValue(Action.NAME, "Export source_to_concept_map"); putValue(Action.SHORT_DESCRIPTION, "Export mapping to source_to_concept_map"); - putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_E)); + putValue(Action.MNEMONIC_KEY, KeyEvent.VK_E); + putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_E, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); } @Override public void actionPerformed(ActionEvent arg0) { + boolean exportUnapproved = Dialogs.askExportUnapprovedMappings(); + boolean hasApprovedMappings = false; - for (CodeMapping mapping : Global.mapping) + for (CodeMapping mapping : Global.mapping) { if (mapping.mappingStatus == MappingStatus.APPROVED) { hasApprovedMappings = true; break; } - if (hasApprovedMappings) { - ExportSourceToConceptMapDialog dialog = new ExportSourceToConceptMapDialog(); - dialog.setVisible(true); - } else { - JOptionPane.showMessageDialog(Global.frame, "There are no approved mappings, so nothing to export", "Warning", JOptionPane.WARNING_MESSAGE); } + + if (!exportUnapproved && !hasApprovedMappings) { + Dialogs.warningNothingToExport(); + return; + } + + ExportSourceToConceptMapDialog exportDialog = new ExportSourceToConceptMapDialog(); + exportDialog.setExportUnapproved(exportUnapproved); + exportDialog.setVisible(true); } } From 2a339d7e6329bddcb02c77a056c242adb8364947 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Sun, 3 May 2020 12:11:35 +0200 Subject: [PATCH 09/34] set vocabulary_id = None if target concept is 0 --- src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java | 4 ++-- .../usagi/ui/actions/{Dialogs.java => ExportDialogs.java} | 2 +- src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java | 4 ++-- .../usagi/ui/actions/ExportSourceToConceptMapAction.java | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) rename src/org/ohdsi/usagi/ui/actions/{Dialogs.java => ExportDialogs.java} (96%) diff --git a/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java b/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java index 0e8bb19..0f14318 100644 --- a/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java +++ b/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java @@ -57,7 +57,7 @@ public ExportSourceToConceptMapDialog() { g.gridx = 0; g.gridy = 0; - add(new JLabel("Source vocabulary id (max 20 alphanumerical characters):"), g); + add(new JLabel("Source vocabulary id:"), g); g.gridx = 1; g.gridy = 0; @@ -125,7 +125,7 @@ private void writeToCsvFile(String filename) { row.add("source_vocabulary_id", sourceVocabularyIdField.getText()); row.add("source_code_description", mapping.sourceCode.sourceName); row.add("target_concept_id", targetConcept.conceptId); - row.add("target_vocabulary_id", targetConcept.vocabularyId); + row.add("target_vocabulary_id", targetConcept.conceptId == 0 ? "None" : targetConcept.vocabularyId ); row.add("valid_start_date", "1970-01-01"); row.add("valid_end_date", "2099-12-31"); row.add("invalid_reason", ""); diff --git a/src/org/ohdsi/usagi/ui/actions/Dialogs.java b/src/org/ohdsi/usagi/ui/actions/ExportDialogs.java similarity index 96% rename from src/org/ohdsi/usagi/ui/actions/Dialogs.java rename to src/org/ohdsi/usagi/ui/actions/ExportDialogs.java index ffea174..4e5dcb0 100644 --- a/src/org/ohdsi/usagi/ui/actions/Dialogs.java +++ b/src/org/ohdsi/usagi/ui/actions/ExportDialogs.java @@ -4,7 +4,7 @@ import javax.swing.*; -public class Dialogs { +public class ExportDialogs { public static boolean askExportUnapprovedMappings() { String[] options = {"Only approved","Approved and Unapproved"}; int PromptResult = JOptionPane.showOptionDialog( diff --git a/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java b/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java index cb7c628..361f374 100644 --- a/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java @@ -46,7 +46,7 @@ public ExportForReviewAction() { @Override public void actionPerformed(ActionEvent arg0) { - boolean exportUnapproved = Dialogs.askExportUnapprovedMappings(); + boolean exportUnapproved = ExportDialogs.askExportUnapprovedMappings(); boolean hasApprovedMappings = false; for (CodeMapping mapping : Global.mapping) { @@ -57,7 +57,7 @@ public void actionPerformed(ActionEvent arg0) { } if (!exportUnapproved && !hasApprovedMappings) { - Dialogs.warningNothingToExport(); + ExportDialogs.warningNothingToExport(); return; } diff --git a/src/org/ohdsi/usagi/ui/actions/ExportSourceToConceptMapAction.java b/src/org/ohdsi/usagi/ui/actions/ExportSourceToConceptMapAction.java index f53d726..1074120 100644 --- a/src/org/ohdsi/usagi/ui/actions/ExportSourceToConceptMapAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ExportSourceToConceptMapAction.java @@ -39,7 +39,7 @@ public ExportSourceToConceptMapAction() { @Override public void actionPerformed(ActionEvent arg0) { - boolean exportUnapproved = Dialogs.askExportUnapprovedMappings(); + boolean exportUnapproved = ExportDialogs.askExportUnapprovedMappings(); boolean hasApprovedMappings = false; for (CodeMapping mapping : Global.mapping) { @@ -50,7 +50,7 @@ public void actionPerformed(ActionEvent arg0) { } if (!exportUnapproved && !hasApprovedMappings) { - Dialogs.warningNothingToExport(); + ExportDialogs.warningNothingToExport(); return; } From 452924bc4086fd8bb595b2e5effd78af05c5d2d0 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Mon, 6 Jan 2020 12:21:45 +0100 Subject: [PATCH 10/34] when applying previous mapping, also add codes not present in current file --- .../ohdsi/usagi/ReadCodeMappingsFromFile.java | 1 + .../actions/ApplyPreviousMappingAction.java | 43 ++++++++++++------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java index 88b0cf7..4ac2551 100644 --- a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java +++ b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java @@ -67,6 +67,7 @@ && new SourceCode(row).sourceName.equals(buffer.sourceCode.sourceName)) { Concept concept = Global.dbEngine.getConcept(row.getInt("conceptId")); if (concept == null) { buffer.mappingStatus = CodeMapping.MappingStatus.INVALID_TARGET; + buffer.comment = "Invalid existing target: " + row.get("conceptId"); } else { buffer.targetConcepts.add(concept); } diff --git a/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java b/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java index 26ae08e..7982c58 100644 --- a/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java @@ -46,26 +46,37 @@ public void actionPerformed(ActionEvent arg0) { FileFilter csvFilter = new FileNameExtensionFilter("CSV files", "csv"); fileChooser.setFileFilter(csvFilter); if (fileChooser.showOpenDialog(Global.frame) == JFileChooser.APPROVE_OPTION) { - int mappingsUsed = 0; + int mappingsApplied = 0; + int mappingsAdded = 0; + + // Existing code lookup + Map codeToMapping = new HashMap<>(); + for (CodeMapping codeMapping: Global.mapping) { + codeToMapping.put(codeMapping.sourceCode.sourceCode, codeMapping); + } + + // Open mapping file to be applied File file = fileChooser.getSelectedFile(); - Mapping mapping = new Mapping(); - mapping.loadFromFile(file.getAbsolutePath()); - Map codeToOldMapping = new HashMap(); - for (CodeMapping codeMapping : mapping) - if (codeMapping.mappingStatus.equals(CodeMapping.MappingStatus.APPROVED)) - codeToOldMapping.put(codeMapping.sourceCode.sourceCode, codeMapping); + Mapping mappingToBeApplied = new Mapping(); + mappingToBeApplied.loadFromFile(file.getAbsolutePath()); - for (CodeMapping newCodeMapping : Global.mapping) { - CodeMapping oldCodeMapping = codeToOldMapping.get(newCodeMapping.sourceCode.sourceCode); - if (oldCodeMapping != null) { - newCodeMapping.targetConcepts = oldCodeMapping.targetConcepts; - newCodeMapping.mappingStatus = oldCodeMapping.mappingStatus; - newCodeMapping.comment = oldCodeMapping.comment; - mappingsUsed++; + // Apply mapping. Add mappings not currently present + for (CodeMapping codeMappingToBeApplied : mappingToBeApplied) { + CodeMapping existingMapping = codeToMapping.get(codeMappingToBeApplied.sourceCode.sourceCode); + if (existingMapping != null) { + existingMapping.sourceCode.sourceName = codeMappingToBeApplied.sourceCode.sourceName; + existingMapping.targetConcepts = codeMappingToBeApplied.targetConcepts; + existingMapping.mappingStatus = codeMappingToBeApplied.mappingStatus; + existingMapping.comment = codeMappingToBeApplied.comment; + mappingsApplied++; + } else { + Global.mapping.add(codeMappingToBeApplied); + mappingsAdded++; } } - String message = "The old mapping contained " + codeToOldMapping.size() + " approved mappings of which " + mappingsUsed - + " were applied to the current mapping."; + + String message = "The old mapping contained " + mappingToBeApplied.size() + " approved mappings of which " + mappingsApplied + + " were applied to the current mapping and " + mappingsAdded + " were newly added."; Global.mappingTablePanel.updateUI(); Global.mappingDetailPanel.updateUI(); JOptionPane.showMessageDialog(Global.frame, message); From 222b75d80a3ef238f279598b7cbae95e0dda258d Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Sun, 3 May 2020 10:17:58 +0200 Subject: [PATCH 11/34] open usagi file from commandline --- src/org/ohdsi/usagi/ui/UsagiMain.java | 28 +++++++++--------- .../ohdsi/usagi/ui/actions/OpenAction.java | 29 +++++++++++-------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/UsagiMain.java b/src/org/ohdsi/usagi/ui/UsagiMain.java index b8a567f..6e231b0 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMain.java +++ b/src/org/ohdsi/usagi/ui/UsagiMain.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. @@ -28,9 +28,7 @@ import java.util.ArrayList; import java.util.List; -import javax.swing.JFrame; -import javax.swing.JPanel; -import javax.swing.JSplitPane; +import javax.swing.*; import org.ohdsi.usagi.BerkeleyDbEngine; import org.ohdsi.usagi.UsagiSearchEngine; @@ -56,22 +54,16 @@ */ public class UsagiMain implements ActionListener { - private JFrame frame; - public static void main(String[] args) { new UsagiMain(args); } public UsagiMain(String[] args) { - frame = new JFrame("Usagi"); + JFrame frame = new JFrame("Usagi"); // Initialize global variables: Global.mapping = new Mapping(); - if (args.length != 0) - Global.folder = args[0]; - else - Global.folder = new File("").getAbsolutePath(); - + Global.folder = new File("").getAbsolutePath(); Global.usagiSearchEngine = new UsagiSearchEngine(Global.folder); Global.dbEngine = new BerkeleyDbEngine(Global.folder); if (Global.usagiSearchEngine.mainIndexExists()) { @@ -139,6 +131,12 @@ public void windowClosing(WindowEvent e) { if (!Global.usagiSearchEngine.mainIndexExists()) Global.rebuildIndexAction.actionPerformed(null); + + if (args.length == 1) { + Global.folder = args[0]; + } else if (args.length > 1 && args[0].equals("--file")) { + OpenAction.open(new File(args[1])); + } } private String loadVocabularyVersion(String folder) { @@ -147,7 +145,7 @@ private String loadVocabularyVersion(String folder) { if (new File(versionFileName).exists()) { for (String line : new ReadTextFile(versionFileName)) version = line; - } + } return version; } diff --git a/src/org/ohdsi/usagi/ui/actions/OpenAction.java b/src/org/ohdsi/usagi/ui/actions/OpenAction.java index 9ff0e79..e0f1e4f 100644 --- a/src/org/ohdsi/usagi/ui/actions/OpenAction.java +++ b/src/org/ohdsi/usagi/ui/actions/OpenAction.java @@ -46,19 +46,24 @@ public void actionPerformed(ActionEvent arg0) { fileChooser.setFileFilter(csvFilter); if (fileChooser.showOpenDialog(Global.frame) == JFileChooser.APPROVE_OPTION) { File file = fileChooser.getSelectedFile(); - Global.frame.setTitle("Usagi - " + file.getName()); - Global.filename = file.getAbsolutePath(); - Global.folder = file.getParentFile().getAbsolutePath(); - Global.mapping.loadFromFile(Global.filename); - Global.usagiSearchEngine.close(); - Global.usagiSearchEngine.createDerivedIndex(Global.mapping.getSourceCodes(), Global.frame); - Global.mappingDetailPanel.doSearch(); - Global.applyPreviousMappingAction.setEnabled(true); - Global.saveAction.setEnabled(true); - Global.saveAsAction.setEnabled(true); - Global.exportAction.setEnabled(true); - Global.exportForReviewAction.setEnabled(true); + open(file); } } + public static void open(File file) { + String a = file.getName(); + Global.frame.setTitle("Usagi - " + file.getName()); + Global.filename = file.getAbsolutePath(); + Global.folder = file.getParentFile().getAbsolutePath(); + Global.mapping.loadFromFile(Global.filename); + Global.usagiSearchEngine.close(); + Global.usagiSearchEngine.createDerivedIndex(Global.mapping.getSourceCodes(), Global.frame); + Global.mappingDetailPanel.doSearch(); + Global.applyPreviousMappingAction.setEnabled(true); + Global.saveAction.setEnabled(true); + Global.saveAsAction.setEnabled(true); + Global.exportAction.setEnabled(true); + Global.exportForReviewAction.setEnabled(true); + } + } From 7c951ebba296674255af1be7fa823c8402cf833e Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Sun, 3 May 2020 13:48:49 +0200 Subject: [PATCH 12/34] show error if applied mapping is invalid file format --- .../ohdsi/usagi/ReadCodeMappingsFromFile.java | 24 +++++++++++++++---- .../actions/ApplyPreviousMappingAction.java | 2 +- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java index 4ac2551..48a33dd 100644 --- a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java +++ b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java @@ -22,6 +22,8 @@ import org.ohdsi.utilities.files.ReadCSVFileWithHeader; import org.ohdsi.utilities.files.Row; +import javax.swing.*; + public class ReadCodeMappingsFromFile implements Iterable { private String filename; @@ -42,17 +44,29 @@ public class RowIterator implements Iterator { public RowIterator() { iterator = new ReadCSVFileWithHeader(filename).iterator(); + if (iterator.hasNext()) { row = iterator.next(); - readNext(); - } else + try { + readNext(); + } catch (Exception e) { + JOptionPane.showMessageDialog( + Global.frame, + "Invalid File Format", + "Error", + JOptionPane.ERROR_MESSAGE + ); + return; + } + } else { buffer = null; + } } private void readNext() { - if (row == null) + if (row == null) { buffer = null; - else { + } else { buffer = new CodeMapping(new SourceCode(row)); buffer.matchScore = row.getDouble("matchScore"); buffer.mappingStatus = MappingStatus.valueOf(row.get("mappingStatus")); @@ -66,7 +80,7 @@ && 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 = CodeMapping.MappingStatus.INVALID_TARGET; + buffer.mappingStatus = MappingStatus.INVALID_TARGET; buffer.comment = "Invalid existing target: " + row.get("conceptId"); } else { buffer.targetConcepts.add(concept); diff --git a/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java b/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java index 7982c58..5fd38da 100644 --- a/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java @@ -75,7 +75,7 @@ public void actionPerformed(ActionEvent arg0) { } } - String message = "The old mapping contained " + mappingToBeApplied.size() + " approved mappings of which " + mappingsApplied + String message = "The applied mapping contained " + mappingToBeApplied.size() + " approved mappings of which " + mappingsApplied + " were applied to the current mapping and " + mappingsAdded + " were newly added."; Global.mappingTablePanel.updateUI(); Global.mappingDetailPanel.updateUI(); From 1588b85a7dba8147eab13cd480bcb4ddaa3dc7bc Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Sun, 3 May 2020 15:00:13 +0200 Subject: [PATCH 13/34] report count of illegal targets and reindex after adding new codes --- src/org/ohdsi/usagi/ui/Mapping.java | 17 ++++++++++++----- .../ui/actions/ApplyPreviousMappingAction.java | 8 ++++++-- src/org/ohdsi/usagi/ui/actions/OpenAction.java | 1 - 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/Mapping.java b/src/org/ohdsi/usagi/ui/Mapping.java index 4547f19..efa0e30 100644 --- a/src/org/ohdsi/usagi/ui/Mapping.java +++ b/src/org/ohdsi/usagi/ui/Mapping.java @@ -32,14 +32,21 @@ public class Mapping extends ArrayList { public void loadFromFile(String filename) { clear(); - boolean invalidTargets = false; + int nInvalidTargets = 0; for (CodeMapping codeMapping : new ReadCodeMappingsFromFile(filename)) { add(codeMapping); - if (codeMapping.mappingStatus == CodeMapping.MappingStatus.INVALID_TARGET) - invalidTargets = true; + if (codeMapping.mappingStatus == CodeMapping.MappingStatus.INVALID_TARGET) { + nInvalidTargets += 1; + } + } + if (nInvalidTargets > 0) { + JOptionPane.showMessageDialog( + null, + nInvalidTargets + " illegal target concepts found. The corresponding source codes are marked in red.", + "Illegal target concepts", + JOptionPane.WARNING_MESSAGE + ); } - if (invalidTargets) - JOptionPane.showMessageDialog(null, "Illegal target concepts found. The corresponding source codes are marked in red.", "Illegal target concepts", JOptionPane.WARNING_MESSAGE); fireDataChanged(DataChangeListener.RESTRUCTURE_EVENT); } diff --git a/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java b/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java index 5fd38da..c454619 100644 --- a/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java @@ -75,12 +75,16 @@ public void actionPerformed(ActionEvent arg0) { } } - String message = "The applied mapping contained " + mappingToBeApplied.size() + " approved mappings of which " + mappingsApplied + String message = "The applied mapping contained " + mappingToBeApplied.size() + " mappings of which " + mappingsApplied + " were applied to the current mapping and " + mappingsAdded + " were newly added."; Global.mappingTablePanel.updateUI(); Global.mappingDetailPanel.updateUI(); + if (mappingsAdded > 0) { + Global.usagiSearchEngine.close(); + Global.usagiSearchEngine.createDerivedIndex(Global.mapping.getSourceCodes(), Global.frame); + Global.mappingDetailPanel.doSearch(); + } JOptionPane.showMessageDialog(Global.frame, message); } } - } diff --git a/src/org/ohdsi/usagi/ui/actions/OpenAction.java b/src/org/ohdsi/usagi/ui/actions/OpenAction.java index e0f1e4f..7dbf2c8 100644 --- a/src/org/ohdsi/usagi/ui/actions/OpenAction.java +++ b/src/org/ohdsi/usagi/ui/actions/OpenAction.java @@ -51,7 +51,6 @@ public void actionPerformed(ActionEvent arg0) { } public static void open(File file) { - String a = file.getName(); Global.frame.setTitle("Usagi - " + file.getName()); Global.filename = file.getAbsolutePath(); Global.folder = file.getParentFile().getAbsolutePath(); From 3edd19abe2958634480d6bb1390ed165c5f57f98 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Sun, 3 May 2020 15:13:51 +0200 Subject: [PATCH 14/34] show warning dialog before exiting application --- src/org/ohdsi/usagi/ui/UsagiMain.java | 23 +++++-------------- .../ohdsi/usagi/ui/actions/ExitAction.java | 10 +++++--- .../ui/actions/ExportForReviewAction.java | 4 ++-- .../ExportSourceToConceptMapAction.java | 4 ++-- .../{ExportDialogs.java => UsagiDialogs.java} | 16 ++++++++++++- 5 files changed, 32 insertions(+), 25 deletions(-) rename src/org/ohdsi/usagi/ui/actions/{ExportDialogs.java => UsagiDialogs.java} (64%) diff --git a/src/org/ohdsi/usagi/ui/UsagiMain.java b/src/org/ohdsi/usagi/ui/UsagiMain.java index 6e231b0..bcb121d 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMain.java +++ b/src/org/ohdsi/usagi/ui/UsagiMain.java @@ -32,21 +32,7 @@ import org.ohdsi.usagi.BerkeleyDbEngine; import org.ohdsi.usagi.UsagiSearchEngine; -import org.ohdsi.usagi.ui.actions.AboutAction; -import org.ohdsi.usagi.ui.actions.ApplyPreviousMappingAction; -import org.ohdsi.usagi.ui.actions.ApproveAction; -import org.ohdsi.usagi.ui.actions.ApproveAllAction; -import org.ohdsi.usagi.ui.actions.ClearAllAction; -import org.ohdsi.usagi.ui.actions.ConceptInformationAction; -import org.ohdsi.usagi.ui.actions.ExitAction; -import org.ohdsi.usagi.ui.actions.ExportForReviewAction; -import org.ohdsi.usagi.ui.actions.ExportSourceToConceptMapAction; -import org.ohdsi.usagi.ui.actions.ImportAction; -import org.ohdsi.usagi.ui.actions.OpenAction; -import org.ohdsi.usagi.ui.actions.RebuildIndexAction; -import org.ohdsi.usagi.ui.actions.SaveAction; -import org.ohdsi.usagi.ui.actions.SaveAsAction; -import org.ohdsi.usagi.ui.actions.ShowStatsAction; +import org.ohdsi.usagi.ui.actions.*; import org.ohdsi.utilities.files.ReadTextFile; /** @@ -99,10 +85,13 @@ public UsagiMain(String[] args) { Global.clearAllAction.setEnabled(false); Global.conceptInfoAction.setEnabled(false); + frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { - Global.dbEngine.shutdown(); - System.exit(0); + if (UsagiDialogs.askBeforeExit()) { + Global.dbEngine.shutdown(); + System.exit(0); + } } }); frame.setLayout(new BorderLayout()); diff --git a/src/org/ohdsi/usagi/ui/actions/ExitAction.java b/src/org/ohdsi/usagi/ui/actions/ExitAction.java index 234e32f..123179a 100644 --- a/src/org/ohdsi/usagi/ui/actions/ExitAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ExitAction.java @@ -15,10 +15,11 @@ ******************************************************************************/ package org.ohdsi.usagi.ui.actions; +import org.ohdsi.usagi.ui.Global; + import java.awt.event.ActionEvent; -import javax.swing.AbstractAction; -import javax.swing.Action; +import javax.swing.*; public class ExitAction extends AbstractAction { @@ -31,7 +32,10 @@ public ExitAction() { @Override public void actionPerformed(ActionEvent arg0) { - System.exit(0); + if (UsagiDialogs.askBeforeExit()) { + Global.dbEngine.shutdown(); + System.exit(0); + } } } diff --git a/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java b/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java index 361f374..9c5fb32 100644 --- a/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java @@ -46,7 +46,7 @@ public ExportForReviewAction() { @Override public void actionPerformed(ActionEvent arg0) { - boolean exportUnapproved = ExportDialogs.askExportUnapprovedMappings(); + boolean exportUnapproved = UsagiDialogs.askExportUnapprovedMappings(); boolean hasApprovedMappings = false; for (CodeMapping mapping : Global.mapping) { @@ -57,7 +57,7 @@ public void actionPerformed(ActionEvent arg0) { } if (!exportUnapproved && !hasApprovedMappings) { - ExportDialogs.warningNothingToExport(); + UsagiDialogs.warningNothingToExport(); return; } diff --git a/src/org/ohdsi/usagi/ui/actions/ExportSourceToConceptMapAction.java b/src/org/ohdsi/usagi/ui/actions/ExportSourceToConceptMapAction.java index 1074120..174732a 100644 --- a/src/org/ohdsi/usagi/ui/actions/ExportSourceToConceptMapAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ExportSourceToConceptMapAction.java @@ -39,7 +39,7 @@ public ExportSourceToConceptMapAction() { @Override public void actionPerformed(ActionEvent arg0) { - boolean exportUnapproved = ExportDialogs.askExportUnapprovedMappings(); + boolean exportUnapproved = UsagiDialogs.askExportUnapprovedMappings(); boolean hasApprovedMappings = false; for (CodeMapping mapping : Global.mapping) { @@ -50,7 +50,7 @@ public void actionPerformed(ActionEvent arg0) { } if (!exportUnapproved && !hasApprovedMappings) { - ExportDialogs.warningNothingToExport(); + UsagiDialogs.warningNothingToExport(); return; } diff --git a/src/org/ohdsi/usagi/ui/actions/ExportDialogs.java b/src/org/ohdsi/usagi/ui/actions/UsagiDialogs.java similarity index 64% rename from src/org/ohdsi/usagi/ui/actions/ExportDialogs.java rename to src/org/ohdsi/usagi/ui/actions/UsagiDialogs.java index 4e5dcb0..4e52c20 100644 --- a/src/org/ohdsi/usagi/ui/actions/ExportDialogs.java +++ b/src/org/ohdsi/usagi/ui/actions/UsagiDialogs.java @@ -4,7 +4,7 @@ import javax.swing.*; -public class ExportDialogs { +public class UsagiDialogs { public static boolean askExportUnapprovedMappings() { String[] options = {"Only approved","Approved and Unapproved"}; int PromptResult = JOptionPane.showOptionDialog( @@ -28,4 +28,18 @@ public static void warningNothingToExport() { JOptionPane.WARNING_MESSAGE ); } + + public static boolean askBeforeExit() { + String[] objButtons = {"Yes","No"}; + int PromptResult = JOptionPane.showOptionDialog( + Global.frame, + "Do you want to exit?\nPlease make sure that any work is saved", + "Usagi", + JOptionPane.DEFAULT_OPTION, + JOptionPane.WARNING_MESSAGE, + null, objButtons, objButtons[1] + ); + return PromptResult == JOptionPane.YES_OPTION; + } + } From b3354277995794fdd7a619fb871545610f887516 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Sun, 3 May 2020 15:39:11 +0200 Subject: [PATCH 15/34] solves #70. plus some refactorings --- src/org/ohdsi/usagi/ui/RebuildIndexDialog.java | 13 ++++++------- src/org/ohdsi/usagi/ui/ShowStatsDialog.java | 8 +------- src/org/ohdsi/usagi/ui/UsagiMain.java | 10 ++++++---- src/org/ohdsi/usagi/ui/actions/AboutAction.java | 2 +- src/org/ohdsi/usagi/ui/actions/ApproveAction.java | 2 +- .../usagi/ui/actions/ConceptInformationAction.java | 2 +- .../ohdsi/usagi/ui/actions/RebuildIndexAction.java | 2 +- src/org/ohdsi/usagi/ui/actions/ShowStatsAction.java | 8 ++++---- 8 files changed, 21 insertions(+), 26 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/RebuildIndexDialog.java b/src/org/ohdsi/usagi/ui/RebuildIndexDialog.java index a33a023..dd0140b 100644 --- a/src/org/ohdsi/usagi/ui/RebuildIndexDialog.java +++ b/src/org/ohdsi/usagi/ui/RebuildIndexDialog.java @@ -58,13 +58,12 @@ public RebuildIndexDialog() { private void buildIndex() { String vocabFolder = vocabFolderField.getText(); String loincFile = loincFileField.getText(); - if (!(new File(vocabFolder + "/CONCEPT.csv").exists())) { - JOptionPane.showMessageDialog(this, "Vocabulary file CONCEPT.csv not found", "Cannot build index", JOptionPane.ERROR_MESSAGE); - return; - } - if (!(new File(vocabFolder + "/CONCEPT_SYNONYM.csv").exists())) { - JOptionPane.showMessageDialog(this, "Vocabulary file CONCEPT_SYNONYM.csv not found", "Cannot build index", JOptionPane.ERROR_MESSAGE); - return; + String[] requiredVocabularyFiles = {"/CONCEPT.csv", "/CONCEPT_SYNONYM.csv", "/VOCABULARY.csv", "/CONCEPT_RELATIONSHIP.csv"}; + for (String vocabFileName : requiredVocabularyFiles) { + if (!(new File(vocabFolder + vocabFileName).exists())) { + JOptionPane.showMessageDialog(this, "Vocabulary file " + vocabFileName + " not found", "Cannot build index", JOptionPane.ERROR_MESSAGE); + return; + } } if (loincCheckBox.isSelected() && !(new File(loincFile).exists())) { JOptionPane.showMessageDialog(this, "LOINC file loinc.csv not found", "Cannot build index", JOptionPane.ERROR_MESSAGE); diff --git a/src/org/ohdsi/usagi/ui/ShowStatsDialog.java b/src/org/ohdsi/usagi/ui/ShowStatsDialog.java index 670f5c0..efa0ea2 100644 --- a/src/org/ohdsi/usagi/ui/ShowStatsDialog.java +++ b/src/org/ohdsi/usagi/ui/ShowStatsDialog.java @@ -38,12 +38,6 @@ public class ShowStatsDialog extends JDialog { private static final long serialVersionUID = 2028328868610404663L; public ShowStatsDialog() { - String versionFileName = Global.folder + "/vocabularyVersion.txt"; - String version = "Unknown"; - if (new File(versionFileName).exists()) { - for (String line : new ReadTextFile(versionFileName)) - version = line; - } int termCount = Global.usagiSearchEngine.getTermCount(); BerkeleyDbStats berkeleyDbStats = Global.dbEngine.getStats(); NumberFormat numberFormat = NumberFormat.getNumberInstance(Locale.US); @@ -62,7 +56,7 @@ public ShowStatsDialog() { g.gridx = 1; g.gridy = 0; - add(new JLabel(version), g); + add(new JLabel(Global.vocabularyVersion), g); g.gridx = 0; g.gridy = 1; diff --git a/src/org/ohdsi/usagi/ui/UsagiMain.java b/src/org/ohdsi/usagi/ui/UsagiMain.java index bcb121d..292d26b 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMain.java +++ b/src/org/ohdsi/usagi/ui/UsagiMain.java @@ -49,7 +49,11 @@ public UsagiMain(String[] args) { // Initialize global variables: Global.mapping = new Mapping(); - Global.folder = new File("").getAbsolutePath(); + if (args.length == 1) { + Global.folder = args[0]; + } else { + Global.folder = new File("").getAbsolutePath(); + } Global.usagiSearchEngine = new UsagiSearchEngine(Global.folder); Global.dbEngine = new BerkeleyDbEngine(Global.folder); if (Global.usagiSearchEngine.mainIndexExists()) { @@ -121,9 +125,7 @@ public void windowClosing(WindowEvent e) { if (!Global.usagiSearchEngine.mainIndexExists()) Global.rebuildIndexAction.actionPerformed(null); - if (args.length == 1) { - Global.folder = args[0]; - } else if (args.length > 1 && args[0].equals("--file")) { + if (args.length > 1 && args[0].equals("--file")) { OpenAction.open(new File(args[1])); } } diff --git a/src/org/ohdsi/usagi/ui/actions/AboutAction.java b/src/org/ohdsi/usagi/ui/actions/AboutAction.java index 22d56e8..dff8fee 100644 --- a/src/org/ohdsi/usagi/ui/actions/AboutAction.java +++ b/src/org/ohdsi/usagi/ui/actions/AboutAction.java @@ -31,7 +31,7 @@ public class AboutAction extends AbstractAction { public AboutAction() { putValue(Action.NAME, "About Usagi"); putValue(Action.SHORT_DESCRIPTION, "About Usagi"); - putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_A)); + putValue(Action.MNEMONIC_KEY, KeyEvent.VK_A); } @Override diff --git a/src/org/ohdsi/usagi/ui/actions/ApproveAction.java b/src/org/ohdsi/usagi/ui/actions/ApproveAction.java index bc76ffd..cd3aa45 100644 --- a/src/org/ohdsi/usagi/ui/actions/ApproveAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ApproveAction.java @@ -31,7 +31,7 @@ public class ApproveAction extends AbstractAction { public ApproveAction() { putValue(Action.NAME, "Approve"); putValue(Action.SHORT_DESCRIPTION, "Approve the selected single mapping"); - putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_A)); + putValue(Action.MNEMONIC_KEY, KeyEvent.VK_A); putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_A, ActionEvent.ALT_MASK)); } diff --git a/src/org/ohdsi/usagi/ui/actions/ConceptInformationAction.java b/src/org/ohdsi/usagi/ui/actions/ConceptInformationAction.java index 524cfa6..a609d0b 100644 --- a/src/org/ohdsi/usagi/ui/actions/ConceptInformationAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ConceptInformationAction.java @@ -31,7 +31,7 @@ public class ConceptInformationAction extends AbstractAction { public ConceptInformationAction() { putValue(Action.NAME, "Concept information"); putValue(Action.SHORT_DESCRIPTION, "Show additional concept information"); - putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_C)); + putValue(Action.MNEMONIC_KEY, KeyEvent.VK_C); putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.ALT_MASK)); } diff --git a/src/org/ohdsi/usagi/ui/actions/RebuildIndexAction.java b/src/org/ohdsi/usagi/ui/actions/RebuildIndexAction.java index c4ae2ff..82478f4 100644 --- a/src/org/ohdsi/usagi/ui/actions/RebuildIndexAction.java +++ b/src/org/ohdsi/usagi/ui/actions/RebuildIndexAction.java @@ -30,7 +30,7 @@ public class RebuildIndexAction extends AbstractAction { public RebuildIndexAction() { putValue(Action.NAME, "Rebuild index"); putValue(Action.SHORT_DESCRIPTION, "Rebuild the index from the vocabulary data files"); - putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_R)); + putValue(Action.MNEMONIC_KEY, KeyEvent.VK_R); } @Override diff --git a/src/org/ohdsi/usagi/ui/actions/ShowStatsAction.java b/src/org/ohdsi/usagi/ui/actions/ShowStatsAction.java index 62dc5b7..b0b2cda 100644 --- a/src/org/ohdsi/usagi/ui/actions/ShowStatsAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ShowStatsAction.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. @@ -31,7 +31,7 @@ public class ShowStatsAction extends AbstractAction { public ShowStatsAction() { putValue(Action.NAME, "Show index statistics"); putValue(Action.SHORT_DESCRIPTION, "Show index stats"); - putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_S)); + putValue(Action.MNEMONIC_KEY, KeyEvent.VK_S); } @Override From 9be7e0c201f1a95e6a716cfabdd43ec975080791 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Sun, 3 May 2020 15:55:21 +0200 Subject: [PATCH 16/34] fixes #45 --- src/org/ohdsi/usagi/ui/DataChangeListener.java | 14 +++++++------- .../ui/actions/ApplyPreviousMappingAction.java | 2 ++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/DataChangeListener.java b/src/org/ohdsi/usagi/ui/DataChangeListener.java index d9f935c..d344bbb 100644 --- a/src/org/ohdsi/usagi/ui/DataChangeListener.java +++ b/src/org/ohdsi/usagi/ui/DataChangeListener.java @@ -17,19 +17,19 @@ public interface DataChangeListener { - public static DataChangeEvent APPROVE_EVENT = new DataChangeEvent(true, false); - public static DataChangeEvent SIMPLE_UPDATE_EVENT = new DataChangeEvent(false, false); - public static DataChangeEvent RESTRUCTURE_EVENT = new DataChangeEvent(false, true); + DataChangeEvent APPROVE_EVENT = new DataChangeEvent(true, false); + DataChangeEvent SIMPLE_UPDATE_EVENT = new DataChangeEvent(false, false); + DataChangeEvent RESTRUCTURE_EVENT = new DataChangeEvent(false, true); - public void dataChanged(DataChangeEvent event); + void dataChanged(DataChangeEvent event); - public static class DataChangeEvent { + class DataChangeEvent { public DataChangeEvent(boolean approved, boolean structureChange) { this.approved = approved; this.structureChange = structureChange; } - public boolean approved = false; - public boolean structureChange = false; + public boolean approved; + public boolean structureChange; } } diff --git a/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java b/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java index c454619..f9c1707 100644 --- a/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java @@ -28,6 +28,7 @@ import javax.swing.filechooser.FileNameExtensionFilter; import org.ohdsi.usagi.CodeMapping; +import org.ohdsi.usagi.ui.DataChangeListener; import org.ohdsi.usagi.ui.Global; import org.ohdsi.usagi.ui.Mapping; @@ -79,6 +80,7 @@ public void actionPerformed(ActionEvent arg0) { + " were applied to the current mapping and " + mappingsAdded + " were newly added."; Global.mappingTablePanel.updateUI(); Global.mappingDetailPanel.updateUI(); + Global.mapping.fireDataChanged(DataChangeListener.APPROVE_EVENT); // To update the footer if (mappingsAdded > 0) { Global.usagiSearchEngine.close(); Global.usagiSearchEngine.createDerivedIndex(Global.mapping.getSourceCodes(), Global.frame); From 4e1fc5ef32a84ca84421ed29c0e464d20d99bedf Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Wed, 13 May 2020 07:58:16 +0200 Subject: [PATCH 17/34] add version and display in the ui --- src/org/ohdsi/usagi/ui/AboutDialog.java | 9 +++++---- src/org/ohdsi/usagi/ui/UsagiMain.java | 4 +++- src/org/ohdsi/usagi/ui/actions/AboutAction.java | 3 ++- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/AboutDialog.java b/src/org/ohdsi/usagi/ui/AboutDialog.java index b04d6af..94dba7a 100644 --- a/src/org/ohdsi/usagi/ui/AboutDialog.java +++ b/src/org/ohdsi/usagi/ui/AboutDialog.java @@ -40,10 +40,9 @@ public class AboutDialog extends JDialog { private static final long serialVersionUID = 2028328868610404663L; - private JEditorPane text; public AboutDialog() { - setTitle("About Usagi"); + setTitle("About Usagi v" + UsagiMain.version); setLayout(new GridBagLayout()); GridBagConstraints g = new GridBagConstraints(); @@ -60,9 +59,11 @@ public AboutDialog() { g.gridx = 1; g.gridy = 0; - text = new JEditorPane( + JEditorPane text = new JEditorPane( "text/html", - "Usagi was developed by Martijn Schuemie in Observational Health Data Sciences and Informatics (OHDSI).

For help, please review the Usagi Wiki."); + "Usagi was developed by Martijn Schuemie" + + "
in Observational Health Data Sciences and Informatics (OHDSI)." + + "

For help, please review the Usagi Wiki."); text.setEditable(false); text.setOpaque(false); diff --git a/src/org/ohdsi/usagi/ui/UsagiMain.java b/src/org/ohdsi/usagi/ui/UsagiMain.java index 292d26b..1788902 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMain.java +++ b/src/org/ohdsi/usagi/ui/UsagiMain.java @@ -40,12 +40,14 @@ */ public class UsagiMain implements ActionListener { + public static String version = "1.2.9-SNAPSHOT"; + public static void main(String[] args) { new UsagiMain(args); } public UsagiMain(String[] args) { - JFrame frame = new JFrame("Usagi"); + JFrame frame = new JFrame("Usagi v" + UsagiMain.version); // Initialize global variables: Global.mapping = new Mapping(); diff --git a/src/org/ohdsi/usagi/ui/actions/AboutAction.java b/src/org/ohdsi/usagi/ui/actions/AboutAction.java index dff8fee..dd375d8 100644 --- a/src/org/ohdsi/usagi/ui/actions/AboutAction.java +++ b/src/org/ohdsi/usagi/ui/actions/AboutAction.java @@ -23,13 +23,14 @@ import org.ohdsi.usagi.ui.AboutDialog; import org.ohdsi.usagi.ui.Global; +import org.ohdsi.usagi.ui.UsagiMain; public class AboutAction extends AbstractAction { private static final long serialVersionUID = -6399524936473823131L; public AboutAction() { - putValue(Action.NAME, "About Usagi"); + putValue(Action.NAME, "About Usagi v" + UsagiMain.version); putValue(Action.SHORT_DESCRIPTION, "About Usagi"); putValue(Action.MNEMONIC_KEY, KeyEvent.VK_A); } From 85e1bf99436193ae7f1b0448d95a4f1bd2bab07f Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 15 May 2020 07:55:07 +0200 Subject: [PATCH 18/34] disable editing of cells --- src/org/ohdsi/usagi/ui/ConceptTableModel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/ohdsi/usagi/ui/ConceptTableModel.java b/src/org/ohdsi/usagi/ui/ConceptTableModel.java index 637cddd..b3442bc 100644 --- a/src/org/ohdsi/usagi/ui/ConceptTableModel.java +++ b/src/org/ohdsi/usagi/ui/ConceptTableModel.java @@ -130,7 +130,7 @@ public Class getColumnClass(int col) { } public boolean isCellEditable(int row, int col) { - return true; + return false; } public void setValueAt(Object value, int row, int col) { From 108bed664d31649d03e4c1a6212138f5c11f6106 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 15 May 2020 08:55:11 +0200 Subject: [PATCH 19/34] add link out to Athena web browser --- src/org/ohdsi/usagi/ui/Global.java | 17 +----- .../ohdsi/usagi/ui/MappingDetailPanel.java | 50 ++++++++-------- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 39 +++++++------ src/org/ohdsi/usagi/ui/UsagiMain.java | 2 + src/org/ohdsi/usagi/ui/UsagiMenubar.java | 9 +-- .../ohdsi/usagi/ui/actions/AthenaAction.java | 58 +++++++++++++++++++ .../ui/actions/ConceptInformationAction.java | 3 +- 7 files changed, 113 insertions(+), 65 deletions(-) create mode 100644 src/org/ohdsi/usagi/ui/actions/AthenaAction.java diff --git a/src/org/ohdsi/usagi/ui/Global.java b/src/org/ohdsi/usagi/ui/Global.java index 5d08a0f..1912cd2 100644 --- a/src/org/ohdsi/usagi/ui/Global.java +++ b/src/org/ohdsi/usagi/ui/Global.java @@ -19,21 +19,7 @@ import org.ohdsi.usagi.BerkeleyDbEngine; import org.ohdsi.usagi.UsagiSearchEngine; -import org.ohdsi.usagi.ui.actions.AboutAction; -import org.ohdsi.usagi.ui.actions.ApplyPreviousMappingAction; -import org.ohdsi.usagi.ui.actions.ApproveAction; -import org.ohdsi.usagi.ui.actions.ApproveAllAction; -import org.ohdsi.usagi.ui.actions.ClearAllAction; -import org.ohdsi.usagi.ui.actions.ConceptInformationAction; -import org.ohdsi.usagi.ui.actions.ExitAction; -import org.ohdsi.usagi.ui.actions.ExportForReviewAction; -import org.ohdsi.usagi.ui.actions.ExportSourceToConceptMapAction; -import org.ohdsi.usagi.ui.actions.ImportAction; -import org.ohdsi.usagi.ui.actions.OpenAction; -import org.ohdsi.usagi.ui.actions.RebuildIndexAction; -import org.ohdsi.usagi.ui.actions.SaveAction; -import org.ohdsi.usagi.ui.actions.SaveAsAction; -import org.ohdsi.usagi.ui.actions.ShowStatsAction; +import org.ohdsi.usagi.ui.actions.*; public class Global { public static JFrame frame; @@ -57,6 +43,7 @@ public class Global { public static ApproveAllAction approveAllAction; public static ClearAllAction clearAllAction; public static ConceptInformationAction conceptInfoAction; + public static AthenaAction athenaAction; public static AboutAction aboutAction; public static ExportSourceToConceptMapAction exportAction; public static ExportForReviewAction exportForReviewAction; diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 3baeadb..ddc7b6a 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -199,21 +199,20 @@ private Component createSearchResultsPanel() { searchTable.setPreferredScrollableViewportSize(new Dimension(100, 100)); searchTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); searchTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - searchTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { - public void valueChanged(ListSelectionEvent event) { - int viewRow = searchTable.getSelectedRow(); - if (viewRow == -1) { - addButton.setEnabled(false); - replaceButton.setEnabled(false); - } else { - addButton.setEnabled(true); - replaceButton.setEnabled(true); - Global.conceptInfoAction.setEnabled(true); - int modelRow = searchTable.convertRowIndexToModel(viewRow); - Global.conceptInformationDialog.setConcept(searchTableModel.getConcept(modelRow)); - } + searchTable.getSelectionModel().addListSelectionListener(event -> { + int viewRow = searchTable.getSelectedRow(); + if (viewRow == -1) { + 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)); } - }); // searchTable.hideColumn("Synonym"); searchTable.hideColumn("Valid start date"); @@ -321,19 +320,18 @@ private JPanel createTargetConceptsPanel() { targetConceptTable.setPreferredScrollableViewportSize(new Dimension(500, 45)); targetConceptTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); targetConceptTable.setRowSelectionAllowed(true); - targetConceptTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { - public void valueChanged(ListSelectionEvent event) { - int viewRow = targetConceptTable.getSelectedRow(); - if (viewRow == -1) { - removeButton.setEnabled(false); - } else { - removeButton.setEnabled(true); - Global.conceptInfoAction.setEnabled(true); - int modelRow = targetConceptTable.convertRowIndexToModel(viewRow); - Global.conceptInformationDialog.setConcept(targetConceptTableModel.getConcept(modelRow)); - } + targetConceptTable.getSelectionModel().addListSelectionListener(event -> { + int viewRow = targetConceptTable.getSelectedRow(); + if (viewRow == -1) { + removeButton.setEnabled(false); + } else { + removeButton.setEnabled(true); + int modelRow = targetConceptTable.convertRowIndexToModel(viewRow); + Global.conceptInfoAction.setEnabled(true); + Global.conceptInformationDialog.setConcept(targetConceptTableModel.getConcept(modelRow)); + Global.athenaAction.setEnabled(true); + Global.athenaAction.setConcept(targetConceptTableModel.getConcept(modelRow)); } - }); targetConceptTable.hideColumn("Valid start date"); targetConceptTable.hideColumn("Valid end date"); diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 272a4cb..5cb3ce6 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -52,26 +52,27 @@ public MappingTablePanel() { table.setPreferredScrollableViewportSize(new Dimension(1200, 200)); table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); - table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { - public void valueChanged(ListSelectionEvent event) { - if (!ignoreSelection) { - int viewRow = table.getSelectedRow(); - if (viewRow != -1) { - int modelRow = table.convertRowIndexToModel(viewRow); - for (CodeSelectedListener listener : listeners) - listener.codeSelected(tableModel.getCodeMapping(modelRow)); - Global.approveAction.setEnabled(true); - Global.approveAllAction.setEnabled(true); - Global.clearAllAction.setEnabled(true); - if (tableModel.getCodeMapping(modelRow).targetConcepts.size() > 0) { - Global.conceptInfoAction.setEnabled(true); - Global.conceptInformationDialog.setConcept(tableModel.getCodeMapping(modelRow).targetConcepts.get(0)); - } - } else { - Global.approveAllAction.setEnabled(false); - Global.approveAction.setEnabled(false); - Global.clearAllAction.setEnabled(false); + table.getSelectionModel().addListSelectionListener(event -> { + if (!ignoreSelection) { + int viewRow = table.getSelectedRow(); + if (viewRow != -1) { + int modelRow = table.convertRowIndexToModel(viewRow); + for (CodeSelectedListener listener : listeners) + listener.codeSelected(tableModel.getCodeMapping(modelRow)); + Global.approveAction.setEnabled(true); + Global.approveAllAction.setEnabled(true); + Global.clearAllAction.setEnabled(true); + if (tableModel.getCodeMapping(modelRow).targetConcepts.size() > 0) { + Concept firstConcept = tableModel.getCodeMapping(modelRow).targetConcepts.get(0); + Global.conceptInfoAction.setEnabled(true); + Global.conceptInformationDialog.setConcept(firstConcept); + Global.athenaAction.setEnabled(true); + Global.athenaAction.setConcept(firstConcept); } + } else { + Global.approveAllAction.setEnabled(false); + Global.approveAction.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 1788902..5f0e788 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMain.java +++ b/src/org/ohdsi/usagi/ui/UsagiMain.java @@ -74,6 +74,7 @@ public UsagiMain(String[] args) { Global.saveAsAction = new SaveAsAction(); Global.approveAction = new ApproveAction(); Global.conceptInfoAction = new ConceptInformationAction(); + Global.athenaAction = new AthenaAction(); Global.showStatsAction = new ShowStatsAction(); Global.aboutAction = new AboutAction(); Global.approveAllAction = new ApproveAllAction(); @@ -90,6 +91,7 @@ public UsagiMain(String[] args) { Global.clearAllAction = new ClearAllAction(); Global.clearAllAction.setEnabled(false); Global.conceptInfoAction.setEnabled(false); + Global.athenaAction.setEnabled(false); frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); frame.addWindowListener(new WindowAdapter() { diff --git a/src/org/ohdsi/usagi/ui/UsagiMenubar.java b/src/org/ohdsi/usagi/ui/UsagiMenubar.java index bc87fc7..8111b27 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMenubar.java +++ b/src/org/ohdsi/usagi/ui/UsagiMenubar.java @@ -25,7 +25,7 @@ public class UsagiMenubar extends JMenuBar { public UsagiMenubar() { JMenu fileMenu = new JMenu("File"); - fileMenu.setMnemonic(new Integer(KeyEvent.VK_F)); + fileMenu.setMnemonic(KeyEvent.VK_F); add(fileMenu); fileMenu.add(Global.openAction); @@ -38,7 +38,7 @@ public UsagiMenubar() { fileMenu.add(Global.exitAction); JMenu editMenu = new JMenu("Edit"); - editMenu.setMnemonic(new Integer(KeyEvent.VK_E)); + editMenu.setMnemonic(KeyEvent.VK_E); add(editMenu); editMenu.add(Global.approveAction); @@ -46,13 +46,14 @@ public UsagiMenubar() { editMenu.add(Global.clearAllAction); JMenu viewMenu = new JMenu("View"); - viewMenu.setMnemonic(new Integer(KeyEvent.VK_V)); + viewMenu.setMnemonic(KeyEvent.VK_V); add(viewMenu); viewMenu.add(Global.conceptInfoAction); + viewMenu.add(Global.athenaAction); JMenu helpMenu = new JMenu("Help"); - helpMenu.setMnemonic(new Integer(KeyEvent.VK_H)); + helpMenu.setMnemonic(KeyEvent.VK_H); add(helpMenu); helpMenu.add(Global.rebuildIndexAction); diff --git a/src/org/ohdsi/usagi/ui/actions/AthenaAction.java b/src/org/ohdsi/usagi/ui/actions/AthenaAction.java new file mode 100644 index 0000000..24ec7d9 --- /dev/null +++ b/src/org/ohdsi/usagi/ui/actions/AthenaAction.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * 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.Concept; +import org.ohdsi.usagi.ui.AboutDialog; +import org.ohdsi.usagi.ui.Global; +import org.ohdsi.usagi.ui.UsagiMain; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +public class AthenaAction extends AbstractAction { + + private static final long serialVersionUID = -25905854723973L; + private static final String ATHENA_URL = "https://athena.ohdsi.org/search-terms/terms/"; + private Concept selectedConcept; + + public AthenaAction() { + putValue(Action.NAME, "Athena (web)"); + putValue(Action.SHORT_DESCRIPTION, "Link out to Athena web based concept browser, showing page of currently selected OMOP concept."); + putValue(Action.MNEMONIC_KEY, KeyEvent.VK_W); + putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_W, InputEvent.ALT_MASK)); + } + + @Override + public void actionPerformed(ActionEvent arg0) { + try { + Desktop desktop = Desktop.getDesktop(); + desktop.browse(new URI(ATHENA_URL + selectedConcept.conceptId)); + } catch (URISyntaxException | IOException ex) { + + } + } + + public void setConcept(Concept concept) { + selectedConcept = concept; + } +} diff --git a/src/org/ohdsi/usagi/ui/actions/ConceptInformationAction.java b/src/org/ohdsi/usagi/ui/actions/ConceptInformationAction.java index a609d0b..cb13689 100644 --- a/src/org/ohdsi/usagi/ui/actions/ConceptInformationAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ConceptInformationAction.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; @@ -32,7 +33,7 @@ public ConceptInformationAction() { putValue(Action.NAME, "Concept information"); putValue(Action.SHORT_DESCRIPTION, "Show additional concept information"); putValue(Action.MNEMONIC_KEY, KeyEvent.VK_C); - putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.ALT_MASK)); + putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.ALT_MASK)); } @Override From f5aea9aeab993029f692f5c54378b58e59ed762a Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 15 May 2020 09:10:40 +0200 Subject: [PATCH 20/34] add google web search of source terms --- src/org/ohdsi/usagi/ui/Global.java | 1 + .../ohdsi/usagi/ui/MappingDetailPanel.java | 2 + src/org/ohdsi/usagi/ui/MappingTablePanel.java | 7 ++- src/org/ohdsi/usagi/ui/UsagiMain.java | 2 + src/org/ohdsi/usagi/ui/UsagiMenubar.java | 1 + .../usagi/ui/actions/GoogleSearchAction.java | 55 +++++++++++++++++++ 6 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 src/org/ohdsi/usagi/ui/actions/GoogleSearchAction.java diff --git a/src/org/ohdsi/usagi/ui/Global.java b/src/org/ohdsi/usagi/ui/Global.java index 1912cd2..3f810b8 100644 --- a/src/org/ohdsi/usagi/ui/Global.java +++ b/src/org/ohdsi/usagi/ui/Global.java @@ -44,6 +44,7 @@ public class Global { public static ClearAllAction clearAllAction; public static ConceptInformationAction conceptInfoAction; public static AthenaAction athenaAction; + public static GoogleSearchAction googleSearchAction; public static AboutAction aboutAction; public static ExportSourceToConceptMapAction exportAction; public static ExportForReviewAction exportForReviewAction; diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index ddc7b6a..91bfdd4 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -212,6 +212,7 @@ private Component createSearchResultsPanel() { Global.conceptInformationDialog.setConcept(searchTableModel.getConcept(modelRow)); Global.athenaAction.setEnabled(true); Global.athenaAction.setConcept(searchTableModel.getConcept(modelRow)); + Global.googleSearchAction.setEnabled(false); } }); // searchTable.hideColumn("Synonym"); @@ -331,6 +332,7 @@ private JPanel createTargetConceptsPanel() { Global.conceptInformationDialog.setConcept(targetConceptTableModel.getConcept(modelRow)); Global.athenaAction.setEnabled(true); Global.athenaAction.setConcept(targetConceptTableModel.getConcept(modelRow)); + Global.googleSearchAction.setEnabled(false); } }); targetConceptTable.hideColumn("Valid start date"); diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 5cb3ce6..c463590 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -57,8 +57,13 @@ public MappingTablePanel() { 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)); + } + + Global.googleSearchAction.setEnabled(true); + Global.googleSearchAction.setSourceTerm(tableModel.getCodeMapping(modelRow).sourceCode.sourceName); + Global.approveAction.setEnabled(true); Global.approveAllAction.setEnabled(true); Global.clearAllAction.setEnabled(true); diff --git a/src/org/ohdsi/usagi/ui/UsagiMain.java b/src/org/ohdsi/usagi/ui/UsagiMain.java index 5f0e788..e6c38e9 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMain.java +++ b/src/org/ohdsi/usagi/ui/UsagiMain.java @@ -75,6 +75,7 @@ public UsagiMain(String[] args) { Global.approveAction = new ApproveAction(); Global.conceptInfoAction = new ConceptInformationAction(); Global.athenaAction = new AthenaAction(); + Global.googleSearchAction = new GoogleSearchAction(); Global.showStatsAction = new ShowStatsAction(); Global.aboutAction = new AboutAction(); Global.approveAllAction = new ApproveAllAction(); @@ -92,6 +93,7 @@ public UsagiMain(String[] args) { Global.clearAllAction.setEnabled(false); Global.conceptInfoAction.setEnabled(false); Global.athenaAction.setEnabled(false); + Global.googleSearchAction.setEnabled(false); frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); frame.addWindowListener(new WindowAdapter() { diff --git a/src/org/ohdsi/usagi/ui/UsagiMenubar.java b/src/org/ohdsi/usagi/ui/UsagiMenubar.java index 8111b27..f2af971 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMenubar.java +++ b/src/org/ohdsi/usagi/ui/UsagiMenubar.java @@ -51,6 +51,7 @@ public UsagiMenubar() { viewMenu.add(Global.conceptInfoAction); viewMenu.add(Global.athenaAction); + viewMenu.add(Global.googleSearchAction); JMenu helpMenu = new JMenu("Help"); helpMenu.setMnemonic(KeyEvent.VK_H); diff --git a/src/org/ohdsi/usagi/ui/actions/GoogleSearchAction.java b/src/org/ohdsi/usagi/ui/actions/GoogleSearchAction.java new file mode 100644 index 0000000..bf580ae --- /dev/null +++ b/src/org/ohdsi/usagi/ui/actions/GoogleSearchAction.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * 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.Concept; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +public class GoogleSearchAction extends AbstractAction { + + private static final long serialVersionUID = -934859464521233L; + private static final String GOOGLE_Q_URL = "https://www.google.com/search?q="; + private String sourceTerm; + + public GoogleSearchAction() { + putValue(Action.NAME, "Google (web)"); + putValue(Action.SHORT_DESCRIPTION, "Search source term on Google"); + putValue(Action.MNEMONIC_KEY, KeyEvent.VK_G); + putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_G, InputEvent.ALT_MASK)); + } + + @Override + public void actionPerformed(ActionEvent arg0) { + try { + Desktop desktop = Desktop.getDesktop(); + desktop.browse(new URI(GOOGLE_Q_URL + sourceTerm)); + } catch (URISyntaxException | IOException ex) { + + } + } + + public void setSourceTerm(String sourceTerm) { + this.sourceTerm = sourceTerm; + } +} From 63f0ca4969b7a37f420353097a2068ffa1e01bd6 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 15 May 2020 10:10:45 +0200 Subject: [PATCH 21/34] remember all codes in multi and replace/add all --- .../ohdsi/usagi/ui/CodeSelectedListener.java | 4 +- .../ohdsi/usagi/ui/MappingDetailPanel.java | 18 +++++++ src/org/ohdsi/usagi/ui/MappingTablePanel.java | 47 ++++++++++++------- 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/CodeSelectedListener.java b/src/org/ohdsi/usagi/ui/CodeSelectedListener.java index 6878ca5..445d143 100644 --- a/src/org/ohdsi/usagi/ui/CodeSelectedListener.java +++ b/src/org/ohdsi/usagi/ui/CodeSelectedListener.java @@ -18,5 +18,7 @@ import org.ohdsi.usagi.CodeMapping; public interface CodeSelectedListener { - public void codeSelected(CodeMapping codeMapping); + void codeSelected(CodeMapping codeMapping); + void addCodeMultiSelected(CodeMapping codeMapping); + void clearCodeMultiSelected(); } diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 3baeadb..9665a3f 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -76,6 +76,7 @@ public class MappingDetailPanel extends JPanel implements CodeSelectedListener, private JRadioButton manualQueryButton; private JTextField manualQueryField; private CodeMapping codeMapping; + private List codeMappingFromMulti; private FilterPanel filterPanel; private Timer timer; @@ -86,6 +87,7 @@ public MappingDetailPanel() { add(createTargetConceptsPanel()); add(createSearchPanel()); add(createApprovePanel()); + codeMappingFromMulti = new ArrayList<>(); } private Component createSearchPanel() { @@ -373,6 +375,16 @@ public void codeSelected(CodeMapping codeMapping) { doSearch(); } + @Override + public void addCodeMultiSelected(CodeMapping codeMapping) { + this.codeMappingFromMulti.add(codeMapping); + } + + @Override + public void clearCodeMultiSelected() { + this.codeMappingFromMulti = new ArrayList<>(); + } + public void approve() { if (codeMapping.mappingStatus != CodeMapping.MappingStatus.APPROVED) { codeMapping.mappingStatus = CodeMapping.MappingStatus.APPROVED; @@ -398,12 +410,18 @@ private void setApproveButton() { public void addConcept(Concept concept) { codeMapping.targetConcepts.add(concept); + for (CodeMapping codeMappingMulti : codeMappingFromMulti) { + codeMappingMulti.targetConcepts.add(concept); + } targetConceptTableModel.fireTableDataChanged(); Global.mapping.fireDataChanged(DataChangeListener.SIMPLE_UPDATE_EVENT); } public void replaceConcepts(Concept concept) { codeMapping.targetConcepts.clear(); + for (CodeMapping codeMappingMulti : codeMappingFromMulti) { + codeMappingMulti.targetConcepts.clear(); + } addConcept(concept); } diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 272a4cb..76edec3 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -52,26 +52,37 @@ public MappingTablePanel() { table.setPreferredScrollableViewportSize(new Dimension(1200, 200)); table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); - table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { - public void valueChanged(ListSelectionEvent event) { - if (!ignoreSelection) { - int viewRow = table.getSelectedRow(); - if (viewRow != -1) { - int modelRow = table.convertRowIndexToModel(viewRow); - for (CodeSelectedListener listener : listeners) - listener.codeSelected(tableModel.getCodeMapping(modelRow)); - Global.approveAction.setEnabled(true); - Global.approveAllAction.setEnabled(true); - Global.clearAllAction.setEnabled(true); - if (tableModel.getCodeMapping(modelRow).targetConcepts.size() > 0) { - Global.conceptInfoAction.setEnabled(true); - Global.conceptInformationDialog.setConcept(tableModel.getCodeMapping(modelRow).targetConcepts.get(0)); + table.getSelectionModel().addListSelectionListener(event -> { + if (!ignoreSelection) { + int primaryViewRow = table.getSelectedRow(); + if (primaryViewRow != -1) { + int modelRow = table.convertRowIndexToModel(primaryViewRow); + for (CodeSelectedListener listener : listeners) + listener.codeSelected(tableModel.getCodeMapping(modelRow)); + Global.approveAction.setEnabled(true); + Global.approveAllAction.setEnabled(true); + Global.clearAllAction.setEnabled(true); + if (tableModel.getCodeMapping(modelRow).targetConcepts.size() > 0) { + Global.conceptInfoAction.setEnabled(true); + Global.conceptInformationDialog.setConcept(tableModel.getCodeMapping(modelRow).targetConcepts.get(0)); + } + + // All other selected rows + for (CodeSelectedListener listener : listeners) { + listener.clearCodeMultiSelected(); + } + for (int viewRow : table.getSelectedRows()) { + if (viewRow != -1 && viewRow != primaryViewRow) { + int modelRow = table.convertRowIndexToModel(viewRow); + for (CodeSelectedListener listener : listeners) { + listener.addCodeMultiSelected(tableModel.getCodeMapping(modelRow)); + } } - } else { - Global.approveAllAction.setEnabled(false); - Global.approveAction.setEnabled(false); - Global.clearAllAction.setEnabled(false); } + } else { + Global.approveAllAction.setEnabled(false); + Global.approveAction.setEnabled(false); + Global.clearAllAction.setEnabled(false); } } }); From 279b5452cc691fab07302a8c9bf017abd28a693d Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 15 May 2020 10:25:08 +0200 Subject: [PATCH 22/34] fix create mappings list and update model correctly --- .../ohdsi/usagi/ui/DataChangeListener.java | 11 +++++++---- .../ohdsi/usagi/ui/MappingDetailPanel.java | 19 ++++++++++++------- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 10 ++++++---- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/DataChangeListener.java b/src/org/ohdsi/usagi/ui/DataChangeListener.java index d9f935c..3f74e88 100644 --- a/src/org/ohdsi/usagi/ui/DataChangeListener.java +++ b/src/org/ohdsi/usagi/ui/DataChangeListener.java @@ -17,19 +17,22 @@ public interface DataChangeListener { - public static DataChangeEvent APPROVE_EVENT = new DataChangeEvent(true, false); - public static DataChangeEvent SIMPLE_UPDATE_EVENT = new DataChangeEvent(false, false); - public static DataChangeEvent RESTRUCTURE_EVENT = new DataChangeEvent(false, true); + public static DataChangeEvent APPROVE_EVENT = new DataChangeEvent(true, false, false); + public static DataChangeEvent SIMPLE_UPDATE_EVENT = new DataChangeEvent(false, false, false); + public static DataChangeEvent MULTI_UPDATE_EVENT = new DataChangeEvent(false, false, true); + public static DataChangeEvent RESTRUCTURE_EVENT = new DataChangeEvent(false, true, false); public void dataChanged(DataChangeEvent event); public static class DataChangeEvent { - public DataChangeEvent(boolean approved, boolean structureChange) { + public DataChangeEvent(boolean approved, boolean structureChange, boolean multiUpdate) { this.approved = approved; this.structureChange = structureChange; + this.multiUpdate = multiUpdate; } public boolean approved = false; public boolean structureChange = false; + public boolean multiUpdate = false; } } diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index 9665a3f..e05d048 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -76,7 +76,7 @@ public class MappingDetailPanel extends JPanel implements CodeSelectedListener, private JRadioButton manualQueryButton; private JTextField manualQueryField; private CodeMapping codeMapping; - private List codeMappingFromMulti; + private List codeMappingsFromMulti; private FilterPanel filterPanel; private Timer timer; @@ -87,7 +87,7 @@ public MappingDetailPanel() { add(createTargetConceptsPanel()); add(createSearchPanel()); add(createApprovePanel()); - codeMappingFromMulti = new ArrayList<>(); + codeMappingsFromMulti = new ArrayList<>(); } private Component createSearchPanel() { @@ -377,12 +377,12 @@ public void codeSelected(CodeMapping codeMapping) { @Override public void addCodeMultiSelected(CodeMapping codeMapping) { - this.codeMappingFromMulti.add(codeMapping); + this.codeMappingsFromMulti.add(codeMapping); } @Override public void clearCodeMultiSelected() { - this.codeMappingFromMulti = new ArrayList<>(); + this.codeMappingsFromMulti = new ArrayList<>(); } public void approve() { @@ -410,16 +410,21 @@ private void setApproveButton() { public void addConcept(Concept concept) { codeMapping.targetConcepts.add(concept); - for (CodeMapping codeMappingMulti : codeMappingFromMulti) { + for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { codeMappingMulti.targetConcepts.add(concept); } targetConceptTableModel.fireTableDataChanged(); - Global.mapping.fireDataChanged(DataChangeListener.SIMPLE_UPDATE_EVENT); + + if (codeMappingsFromMulti.size() > 0) { + Global.mapping.fireDataChanged(DataChangeListener.MULTI_UPDATE_EVENT); + } else { + Global.mapping.fireDataChanged(DataChangeListener.SIMPLE_UPDATE_EVENT); + } } public void replaceConcepts(Concept concept) { codeMapping.targetConcepts.clear(); - for (CodeMapping codeMappingMulti : codeMappingFromMulti) { + for (CodeMapping codeMappingMulti : codeMappingsFromMulti) { codeMappingMulti.targetConcepts.clear(); } addConcept(concept); diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 76edec3..736ee8b 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -56,15 +56,15 @@ public MappingTablePanel() { if (!ignoreSelection) { int primaryViewRow = table.getSelectedRow(); if (primaryViewRow != -1) { - int modelRow = table.convertRowIndexToModel(primaryViewRow); + int primaryModelRow = table.convertRowIndexToModel(primaryViewRow); for (CodeSelectedListener listener : listeners) - listener.codeSelected(tableModel.getCodeMapping(modelRow)); + listener.codeSelected(tableModel.getCodeMapping(primaryModelRow)); Global.approveAction.setEnabled(true); Global.approveAllAction.setEnabled(true); Global.clearAllAction.setEnabled(true); - if (tableModel.getCodeMapping(modelRow).targetConcepts.size() > 0) { + if (tableModel.getCodeMapping(primaryModelRow).targetConcepts.size() > 0) { Global.conceptInfoAction.setEnabled(true); - Global.conceptInformationDialog.setConcept(tableModel.getCodeMapping(modelRow).targetConcepts.get(0)); + Global.conceptInformationDialog.setConcept(tableModel.getCodeMapping(primaryModelRow).targetConcepts.get(0)); } // All other selected rows @@ -258,6 +258,8 @@ public void dataChanged(DataChangeEvent event) { } else if (event.structureChange) { tableModel.restructure(); table.setRowSelectionInterval(0, 0); + } else if (event.multiUpdate) { + tableModel.fireTableDataChanged(); } else { tableModel.fireTableRowsUpdated(table.getSelectedRow(), table.getSelectedRow()); } From a98c71d001896f5fd2d8e887b081087c5ab87b12 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 15 May 2020 10:43:16 +0200 Subject: [PATCH 23/34] code cleanup --- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 736ee8b..60769e1 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -24,8 +24,6 @@ import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.ListSelectionModel; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableRowSorter; @@ -36,9 +34,8 @@ public class MappingTablePanel extends JPanel implements DataChangeListener { private static final long serialVersionUID = -5862314086097240860L; private UsagiTable table; - private TableRowSorter sorter; private CodeMapTableModel tableModel; - private List listeners = new ArrayList(); + private List listeners = new ArrayList<>(); private boolean ignoreSelection = false; public MappingTablePanel() { @@ -46,9 +43,8 @@ public MappingTablePanel() { setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); tableModel = new CodeMapTableModel(); - sorter = new TableRowSorter(tableModel); table = new UsagiTable(tableModel); - table.setRowSorter(sorter); + table.setRowSorter(new TableRowSorter<>(tableModel)); table.setPreferredScrollableViewportSize(new Dimension(1200, 200)); table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); @@ -57,8 +53,10 @@ public MappingTablePanel() { int primaryViewRow = table.getSelectedRow(); if (primaryViewRow != -1) { int primaryModelRow = table.convertRowIndexToModel(primaryViewRow); - for (CodeSelectedListener listener : listeners) + for (CodeSelectedListener listener : listeners) { listener.codeSelected(tableModel.getCodeMapping(primaryModelRow)); + listener.clearCodeMultiSelected(); + } Global.approveAction.setEnabled(true); Global.approveAllAction.setEnabled(true); Global.clearAllAction.setEnabled(true); @@ -67,10 +65,7 @@ public MappingTablePanel() { Global.conceptInformationDialog.setConcept(tableModel.getCodeMapping(primaryModelRow).targetConcepts.get(0)); } - // All other selected rows - for (CodeSelectedListener listener : listeners) { - listener.clearCodeMultiSelected(); - } + // Store all other co-selected rows for (int viewRow : table.getSelectedRows()) { if (viewRow != -1 && viewRow != primaryViewRow) { int modelRow = table.convertRowIndexToModel(viewRow); @@ -91,8 +86,6 @@ public MappingTablePanel() { table.hideColumn("Valid start date"); table.hideColumn("Valid end date"); table.hideColumn("Invalid reason"); - // table.hideColumn("Domain"); - // table.hideColumn("Concept class"); JScrollPane scrollPane = new JScrollPane(table); add(scrollPane); @@ -263,6 +256,11 @@ public void dataChanged(DataChangeEvent event) { } else { tableModel.fireTableRowsUpdated(table.getSelectedRow(), table.getSelectedRow()); } + + // Multi selection is lost + for (CodeSelectedListener listener : listeners) { + listener.clearCodeMultiSelected(); + } } public void approveAll() { From 0b3a432f135a529e7ccc0be9a914b5c1ec862fc6 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 15 May 2020 10:59:38 +0200 Subject: [PATCH 24/34] add shortkey for approve all --- src/org/ohdsi/usagi/ui/actions/ApproveAllAction.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/actions/ApproveAllAction.java b/src/org/ohdsi/usagi/ui/actions/ApproveAllAction.java index 7be1aec..6c211c5 100644 --- a/src/org/ohdsi/usagi/ui/actions/ApproveAllAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ApproveAllAction.java @@ -16,9 +16,10 @@ 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; -import javax.swing.Action; +import javax.swing.*; import org.ohdsi.usagi.ui.Global; @@ -29,6 +30,7 @@ public class ApproveAllAction extends AbstractAction { public ApproveAllAction() { 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 From 561c8f7fd1b298a75c98542a330e153e5d468d2f Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 12 Jun 2020 11:45:39 +0200 Subject: [PATCH 25/34] warn if there are no mappings to export --- .../ohdsi/usagi/ui/actions/ExportForReviewAction.java | 7 ++++++- .../usagi/ui/actions/ExportSourceToConceptMapAction.java | 7 ++++++- src/org/ohdsi/usagi/ui/actions/UsagiDialogs.java | 9 +++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java b/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java index 9c5fb32..0a26db7 100644 --- a/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ExportForReviewAction.java @@ -46,6 +46,11 @@ public ExportForReviewAction() { @Override public void actionPerformed(ActionEvent arg0) { + if (Global.mapping.size() == 0) { + UsagiDialogs.warningNothingToExport(); + return; + } + boolean exportUnapproved = UsagiDialogs.askExportUnapprovedMappings(); boolean hasApprovedMappings = false; @@ -57,7 +62,7 @@ public void actionPerformed(ActionEvent arg0) { } if (!exportUnapproved && !hasApprovedMappings) { - UsagiDialogs.warningNothingToExport(); + UsagiDialogs.warningNoApprovedToExport(); return; } diff --git a/src/org/ohdsi/usagi/ui/actions/ExportSourceToConceptMapAction.java b/src/org/ohdsi/usagi/ui/actions/ExportSourceToConceptMapAction.java index 174732a..8878eb8 100644 --- a/src/org/ohdsi/usagi/ui/actions/ExportSourceToConceptMapAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ExportSourceToConceptMapAction.java @@ -39,6 +39,11 @@ public ExportSourceToConceptMapAction() { @Override public void actionPerformed(ActionEvent arg0) { + if (Global.mapping.size() == 0) { + UsagiDialogs.warningNothingToExport(); + return; + } + boolean exportUnapproved = UsagiDialogs.askExportUnapprovedMappings(); boolean hasApprovedMappings = false; @@ -50,7 +55,7 @@ public void actionPerformed(ActionEvent arg0) { } if (!exportUnapproved && !hasApprovedMappings) { - UsagiDialogs.warningNothingToExport(); + UsagiDialogs.warningNoApprovedToExport(); return; } diff --git a/src/org/ohdsi/usagi/ui/actions/UsagiDialogs.java b/src/org/ohdsi/usagi/ui/actions/UsagiDialogs.java index 4e52c20..1de882d 100644 --- a/src/org/ohdsi/usagi/ui/actions/UsagiDialogs.java +++ b/src/org/ohdsi/usagi/ui/actions/UsagiDialogs.java @@ -21,6 +21,15 @@ public static boolean askExportUnapprovedMappings() { } public static void warningNothingToExport() { + JOptionPane.showMessageDialog( + Global.frame, + "There are no mappings, so nothing to export", + "Nothing to export", + JOptionPane.WARNING_MESSAGE + ); + } + + public static void warningNoApprovedToExport() { JOptionPane.showMessageDialog( Global.frame, "There are no approved mappings, so nothing to export", From 35276dc941ed9fcd0fe2ffcaa600b0c4ec855e07 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 19 Jun 2020 19:01:02 +0200 Subject: [PATCH 26/34] bump version to v1.3.0 --- 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 e6c38e9..e465e50 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMain.java +++ b/src/org/ohdsi/usagi/ui/UsagiMain.java @@ -40,7 +40,7 @@ */ public class UsagiMain implements ActionListener { - public static String version = "1.2.9-SNAPSHOT"; + public static String version = "1.3.0"; public static void main(String[] args) { new UsagiMain(args); From 864324ed62301135be1b89ecfca54c2fec7f139f Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 19 Jun 2020 19:10:47 +0200 Subject: [PATCH 27/34] fix reading in domain, concept_class and vocabulary ids; do when opening Usagi --- src/org/ohdsi/usagi/ui/FilterPanel.java | 123 ++++++------------------ src/org/ohdsi/usagi/ui/Global.java | 5 + src/org/ohdsi/usagi/ui/UsagiMain.java | 15 +++ 3 files changed, 49 insertions(+), 94 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/FilterPanel.java b/src/org/ohdsi/usagi/ui/FilterPanel.java index 1f0481f..f8cb856 100644 --- a/src/org/ohdsi/usagi/ui/FilterPanel.java +++ b/src/org/ohdsi/usagi/ui/FilterPanel.java @@ -17,9 +17,6 @@ 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.Vector; @@ -28,21 +25,19 @@ import javax.swing.JCheckBox; import javax.swing.JPanel; -import org.ohdsi.utilities.files.ReadTextFile; - public class FilterPanel extends JPanel { - private static final long serialVersionUID = 1378433878412231259L; - private JCheckBox filterByAutoCheckBox; - private JCheckBox filterStandardCheckBox; - private JCheckBox filterByConceptClassCheckBox; - private JCheckBox filterByVocabularyCheckBox; - private JCheckBox filterByDomainCheckBox; - private JCheckBox includeSourceTermsCheckbox; - private CheckedComboBox filterConceptClassComboBox; - private CheckedComboBox filterVocabularyComboBox; - private CheckedComboBox filterDomainComboBox; - private List listeners = new ArrayList(); + private static final long serialVersionUID = 1378433878412231259L; + private JCheckBox filterByAutoCheckBox; + private JCheckBox filterStandardCheckBox; + private JCheckBox filterByConceptClassCheckBox; + private JCheckBox filterByVocabularyCheckBox; + private JCheckBox filterByDomainCheckBox; + private JCheckBox includeSourceTermsCheckbox; + private CheckedComboBox filterConceptClassComboBox; + private CheckedComboBox filterVocabularyComboBox; + private CheckedComboBox filterDomainComboBox; + private List listeners = new ArrayList<>(); public FilterPanel() { setBorder(BorderFactory.createTitledBorder("Filters")); @@ -56,14 +51,7 @@ public FilterPanel() { c.gridwidth = 2; filterByAutoCheckBox = new JCheckBox("Filter by user selected concepts / ATC code", false); filterByAutoCheckBox.setToolTipText("Limit the search to those concept IDs specified in the input file"); - filterByAutoCheckBox.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent arg0) { - notifyListeners(); - } - - }); + filterByAutoCheckBox.addActionListener(actionEvent -> notifyListeners()); add(filterByAutoCheckBox, c); c.gridx = 0; @@ -72,13 +60,7 @@ public void actionPerformed(ActionEvent arg0) { c.gridwidth = 2; filterStandardCheckBox = new JCheckBox("Filter standard concepts", false); filterStandardCheckBox.setToolTipText("Limit the search to only standard concepts"); - filterStandardCheckBox.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent arg0) { - notifyListeners(); - } - }); + filterStandardCheckBox.addActionListener(actionEvent -> notifyListeners()); filterStandardCheckBox.setSelected(true); add(filterStandardCheckBox, c); @@ -88,28 +70,17 @@ public void actionPerformed(ActionEvent arg0) { c.gridwidth = 1; filterByConceptClassCheckBox = new JCheckBox("Filter by concept class:", false); filterByConceptClassCheckBox.setToolTipText("Limit the search to concepts of this class"); - filterByConceptClassCheckBox.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent arg0) { - notifyListeners(); - - } - }); + filterByConceptClassCheckBox.addActionListener(actionEvent -> notifyListeners()); add(filterByConceptClassCheckBox, c); c.gridx = 3; c.gridy = 0; c.weightx = 1; c.gridwidth = 1; - filterConceptClassComboBox = new CheckedComboBox(loadVectorFromFile(Global.folder + "/ConceptClassIds.txt")); - filterConceptClassComboBox.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent arg0) { - if (filterByConceptClassCheckBox.isSelected()) - notifyListeners(); - } + filterConceptClassComboBox = new CheckedComboBox(Global.conceptClassIds); + filterConceptClassComboBox.addActionListener(actionEvent -> { + if (filterByConceptClassCheckBox.isSelected()) + notifyListeners(); }); add(filterConceptClassComboBox, c); @@ -119,27 +90,17 @@ public void actionPerformed(ActionEvent arg0) { c.gridwidth = 1; filterByVocabularyCheckBox = new JCheckBox("Filter by vocabulary:", false); filterByVocabularyCheckBox.setToolTipText("Limit the search to concepts of this vocabulary"); - filterByVocabularyCheckBox.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent arg0) { - notifyListeners(); - } - }); + filterByVocabularyCheckBox.addActionListener(actionEvent -> notifyListeners()); add(filterByVocabularyCheckBox, c); c.gridx = 3; c.gridy = 1; c.weightx = 1; c.gridwidth = 1; - filterVocabularyComboBox = new CheckedComboBox(loadVectorFromFile(Global.folder + "/VocabularyIds.txt")); - filterVocabularyComboBox.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent arg0) { - if (filterByVocabularyCheckBox.isSelected()) - notifyListeners(); - } + filterVocabularyComboBox = new CheckedComboBox(Global.vocabularyIds); + filterVocabularyComboBox.addActionListener(actionEvent -> { + if (filterByVocabularyCheckBox.isSelected()) + notifyListeners(); }); add(filterVocabularyComboBox, c); @@ -149,27 +110,17 @@ public void actionPerformed(ActionEvent arg0) { c.gridwidth = 1; filterByDomainCheckBox = new JCheckBox("Filter by domain:", false); filterByDomainCheckBox.setToolTipText("Limit the search to concepts of this domain"); - filterByDomainCheckBox.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent arg0) { - notifyListeners(); - } - }); + filterByDomainCheckBox.addActionListener(actionEvent -> notifyListeners()); add(filterByDomainCheckBox, c); c.gridx = 3; c.gridy = 2; c.weightx = 1; c.gridwidth = 1; - filterDomainComboBox = new CheckedComboBox(loadVectorFromFile(Global.folder + "/DomainIds.txt")); - filterDomainComboBox.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent arg0) { - if (filterByDomainCheckBox.isSelected()) - notifyListeners(); - } + filterDomainComboBox = new CheckedComboBox(Global.domainIds); + filterDomainComboBox.addActionListener(actionEvent -> { + if (filterByDomainCheckBox.isSelected()) + notifyListeners(); }); add(filterDomainComboBox, c); @@ -179,27 +130,11 @@ public void actionPerformed(ActionEvent arg0) { c.gridwidth = 2; includeSourceTermsCheckbox = new JCheckBox("Include source terms", true); includeSourceTermsCheckbox.setToolTipText("Include names of source concepts to be used to find standard concepts they map to"); - includeSourceTermsCheckbox.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent arg0) { - notifyListeners(); - } - }); + includeSourceTermsCheckbox.addActionListener(actionEvent -> notifyListeners()); add(includeSourceTermsCheckbox, c); } - private Vector loadVectorFromFile(String fileName) { - if (new File(fileName).exists()) { - Vector vector = new Vector(); - for (String line : new ReadTextFile(fileName)) - vector.add(line); - return vector; - } else - return new Vector(); - } - private void notifyListeners() { for (FilterChangeListener listener : listeners) listener.filterChanged(); diff --git a/src/org/ohdsi/usagi/ui/Global.java b/src/org/ohdsi/usagi/ui/Global.java index 3f810b8..1e63b8b 100644 --- a/src/org/ohdsi/usagi/ui/Global.java +++ b/src/org/ohdsi/usagi/ui/Global.java @@ -21,6 +21,8 @@ import org.ohdsi.usagi.UsagiSearchEngine; import org.ohdsi.usagi.ui.actions.*; +import java.util.Vector; + public class Global { public static JFrame frame; public static Mapping mapping; @@ -51,5 +53,8 @@ public class Global { public static RebuildIndexAction rebuildIndexAction; public static ExitAction exitAction; public static String vocabularyVersion; + public static Vector conceptClassIds; + public static Vector vocabularyIds; + public static Vector domainIds; public static ShowStatsAction showStatsAction; } diff --git a/src/org/ohdsi/usagi/ui/UsagiMain.java b/src/org/ohdsi/usagi/ui/UsagiMain.java index e465e50..f59ef28 100644 --- a/src/org/ohdsi/usagi/ui/UsagiMain.java +++ b/src/org/ohdsi/usagi/ui/UsagiMain.java @@ -27,6 +27,7 @@ import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.Vector; import javax.swing.*; @@ -63,6 +64,10 @@ public UsagiMain(String[] args) { Global.dbEngine.openForReading(); } Global.vocabularyVersion = loadVocabularyVersion(Global.folder); + Global.conceptClassIds = loadVectorFromFile(Global.folder + "/ConceptClassIds.txt"); + Global.vocabularyIds = loadVectorFromFile(Global.folder + "/VocabularyIds.txt"); + Global.domainIds = loadVectorFromFile(Global.folder + "/DomainIds.txt"); + Global.conceptInformationDialog = new ConceptInformationDialog(); Global.frame = frame; Global.openAction = new OpenAction(); @@ -175,4 +180,14 @@ private static Image loadIcon(String name, JFrame f) { return null; } + private Vector loadVectorFromFile(String fileName) { + if (new File(fileName).exists()) { + Vector vector = new Vector<>(); + for (String line : new ReadTextFile(fileName)) + vector.add(line); + return vector; + } else + return new Vector<>(); + } + } From c935dabb2ed27d788a53a19e0e157478b5ac8365 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Fri, 19 Jun 2020 20:07:37 +0200 Subject: [PATCH 28/34] fix vocab folder picker --- src/org/ohdsi/usagi/ui/ImportDialog.java | 2 +- src/org/ohdsi/usagi/ui/RebuildIndexDialog.java | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/ImportDialog.java b/src/org/ohdsi/usagi/ui/ImportDialog.java index e8f0d93..e78cd51 100644 --- a/src/org/ohdsi/usagi/ui/ImportDialog.java +++ b/src/org/ohdsi/usagi/ui/ImportDialog.java @@ -302,7 +302,7 @@ private void importData() { } if (filterPanel.getFilterByAuto() && conceptIdsOrAtc.getSelectedItem().toString().equals(ATC)) { boolean atcLoaded = false; - for (String line : new ReadTextFile(Global.folder + "/VocabularyIds.txt")) + for (String line : Global.vocabularyIds) if (line.equals("ATC")) { atcLoaded = true; break; diff --git a/src/org/ohdsi/usagi/ui/RebuildIndexDialog.java b/src/org/ohdsi/usagi/ui/RebuildIndexDialog.java index dd0140b..4762b56 100644 --- a/src/org/ohdsi/usagi/ui/RebuildIndexDialog.java +++ b/src/org/ohdsi/usagi/ui/RebuildIndexDialog.java @@ -172,8 +172,15 @@ private void pickVocabFolder() { JFileChooser fileChooser = new JFileChooser(new File(vocabFolderField.getText())); fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); int returnVal = fileChooser.showDialog(this, "Select folder"); - if (returnVal == JFileChooser.APPROVE_OPTION) - vocabFolderField.setText(fileChooser.getSelectedFile().getAbsolutePath()); + if (returnVal == JFileChooser.APPROVE_OPTION) { + File selectedDirectory = fileChooser.getSelectedFile(); + if (!selectedDirectory.exists()) { + // When no directory is selected when approving, FileChooser incorrectly appends the current directory to the path. + // Take the opened directory instead. + selectedDirectory = fileChooser.getCurrentDirectory(); + } + vocabFolderField.setText(selectedDirectory.getAbsolutePath()); + } } private void pickLoincFile() { From a416769dc526ee8740db3805797a438df5995295 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Wed, 24 Jun 2020 17:34:57 +0200 Subject: [PATCH 29/34] separate ui logic from io logic when reading mapping file --- .../ohdsi/usagi/ReadCodeMappingsFromFile.java | 14 +------------ src/org/ohdsi/usagi/ui/Mapping.java | 20 ++++++++++++++----- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java index 48a33dd..0092f41 100644 --- a/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java +++ b/src/org/ohdsi/usagi/ReadCodeMappingsFromFile.java @@ -22,8 +22,6 @@ import org.ohdsi.utilities.files.ReadCSVFileWithHeader; import org.ohdsi.utilities.files.Row; -import javax.swing.*; - public class ReadCodeMappingsFromFile implements Iterable { private String filename; @@ -47,17 +45,7 @@ public RowIterator() { if (iterator.hasNext()) { row = iterator.next(); - try { - readNext(); - } catch (Exception e) { - JOptionPane.showMessageDialog( - Global.frame, - "Invalid File Format", - "Error", - JOptionPane.ERROR_MESSAGE - ); - return; - } + readNext(); } else { buffer = null; } diff --git a/src/org/ohdsi/usagi/ui/Mapping.java b/src/org/ohdsi/usagi/ui/Mapping.java index efa0e30..c84bdca 100644 --- a/src/org/ohdsi/usagi/ui/Mapping.java +++ b/src/org/ohdsi/usagi/ui/Mapping.java @@ -28,17 +28,27 @@ public class Mapping extends ArrayList { private static final long serialVersionUID = -8560539820505747600L; - private List listeners = new ArrayList(); + private List listeners = new ArrayList<>(); public void loadFromFile(String filename) { clear(); int nInvalidTargets = 0; - for (CodeMapping codeMapping : new ReadCodeMappingsFromFile(filename)) { - add(codeMapping); - if (codeMapping.mappingStatus == CodeMapping.MappingStatus.INVALID_TARGET) { - nInvalidTargets += 1; + try { + for (CodeMapping codeMapping : new ReadCodeMappingsFromFile(filename)) { + add(codeMapping); + if (codeMapping.mappingStatus == CodeMapping.MappingStatus.INVALID_TARGET) { + nInvalidTargets += 1; + } } + } catch (Exception e) { + JOptionPane.showMessageDialog( + Global.frame, + "Invalid File Format: '" + e.getMessage() + "'", + "Error", + JOptionPane.ERROR_MESSAGE + ); } + if (nInvalidTargets > 0) { JOptionPane.showMessageDialog( null, From 8c2702700fadaf00161dde1b2483b83b37b32c65 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Wed, 24 Jun 2020 17:53:20 +0200 Subject: [PATCH 30/34] implement DataChangeEvent as enum --- src/org/ohdsi/usagi/ui/DataChangeEvent.java | 19 ++++++++++++++++++ .../ohdsi/usagi/ui/DataChangeListener.java | 18 ----------------- src/org/ohdsi/usagi/ui/ImportDialog.java | 5 +++-- src/org/ohdsi/usagi/ui/Mapping.java | 5 +++-- .../ohdsi/usagi/ui/MappingDetailPanel.java | 20 +++++++++---------- .../actions/ApplyPreviousMappingAction.java | 5 +++-- 6 files changed, 38 insertions(+), 34 deletions(-) create mode 100644 src/org/ohdsi/usagi/ui/DataChangeEvent.java diff --git a/src/org/ohdsi/usagi/ui/DataChangeEvent.java b/src/org/ohdsi/usagi/ui/DataChangeEvent.java new file mode 100644 index 0000000..52bb11d --- /dev/null +++ b/src/org/ohdsi/usagi/ui/DataChangeEvent.java @@ -0,0 +1,19 @@ +package org.ohdsi.usagi.ui; + +public enum DataChangeEvent { + + APPROVE_EVENT (true, false, false), + SIMPLE_UPDATE_EVENT (false, false, false), + MULTI_UPDATE_EVENT (false, false, true), + RESTRUCTURE_EVENT (false, true, false); + + public boolean approved; + public boolean structureChange; + public boolean multiUpdate; + + DataChangeEvent(boolean approved, boolean structureChange, boolean multiUpdate) { + this.approved = approved; + this.structureChange = structureChange; + this.multiUpdate = multiUpdate; + } +} diff --git a/src/org/ohdsi/usagi/ui/DataChangeListener.java b/src/org/ohdsi/usagi/ui/DataChangeListener.java index 5190fac..5a96bf5 100644 --- a/src/org/ohdsi/usagi/ui/DataChangeListener.java +++ b/src/org/ohdsi/usagi/ui/DataChangeListener.java @@ -16,23 +16,5 @@ package org.ohdsi.usagi.ui; public interface DataChangeListener { - - DataChangeEvent APPROVE_EVENT = new DataChangeEvent(true, false, false); - DataChangeEvent SIMPLE_UPDATE_EVENT = new DataChangeEvent(false, false, false); - DataChangeEvent MULTI_UPDATE_EVENT = new DataChangeEvent(false, false, true); - DataChangeEvent RESTRUCTURE_EVENT = new DataChangeEvent(false, true, false); - void dataChanged(DataChangeEvent event); - - class DataChangeEvent { - public DataChangeEvent(boolean approved, boolean structureChange, boolean multiUpdate) { - this.approved = approved; - this.structureChange = structureChange; - this.multiUpdate = multiUpdate; - } - - public boolean approved; - public boolean structureChange; - public boolean multiUpdate = false; - } } diff --git a/src/org/ohdsi/usagi/ui/ImportDialog.java b/src/org/ohdsi/usagi/ui/ImportDialog.java index e78cd51..5829223 100644 --- a/src/org/ohdsi/usagi/ui/ImportDialog.java +++ b/src/org/ohdsi/usagi/ui/ImportDialog.java @@ -56,7 +56,8 @@ import org.ohdsi.utilities.StringUtilities; import org.ohdsi.utilities.collections.Pair; import org.ohdsi.utilities.files.ReadCSVFile; -import org.ohdsi.utilities.files.ReadTextFile; + +import static org.ohdsi.usagi.ui.DataChangeEvent.*; public class ImportDialog extends JDialog { @@ -343,7 +344,7 @@ private void importData() { e.printStackTrace(); } Global.filename = null; - Global.mapping.fireDataChanged(DataChangeListener.RESTRUCTURE_EVENT); + Global.mapping.fireDataChanged(RESTRUCTURE_EVENT); setVisible(false); } catch (Exception e) { JOptionPane.showMessageDialog(Global.frame, StringUtilities.wordWrap(e.toString(), 80), "Error", JOptionPane.ERROR_MESSAGE); diff --git a/src/org/ohdsi/usagi/ui/Mapping.java b/src/org/ohdsi/usagi/ui/Mapping.java index c84bdca..d2c6305 100644 --- a/src/org/ohdsi/usagi/ui/Mapping.java +++ b/src/org/ohdsi/usagi/ui/Mapping.java @@ -24,7 +24,8 @@ import org.ohdsi.usagi.ReadCodeMappingsFromFile; import org.ohdsi.usagi.SourceCode; import org.ohdsi.usagi.WriteCodeMappingsToFile; -import org.ohdsi.usagi.ui.DataChangeListener.DataChangeEvent; + +import static org.ohdsi.usagi.ui.DataChangeEvent.*; public class Mapping extends ArrayList { private static final long serialVersionUID = -8560539820505747600L; @@ -57,7 +58,7 @@ public void loadFromFile(String filename) { JOptionPane.WARNING_MESSAGE ); } - fireDataChanged(DataChangeListener.RESTRUCTURE_EVENT); + fireDataChanged(RESTRUCTURE_EVENT); } public Mapping() { diff --git a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java index c86a968..508d46a 100644 --- a/src/org/ohdsi/usagi/ui/MappingDetailPanel.java +++ b/src/org/ohdsi/usagi/ui/MappingDetailPanel.java @@ -47,8 +47,6 @@ import javax.swing.ListSelectionModel; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableRowSorter; @@ -57,6 +55,8 @@ import org.ohdsi.usagi.Concept; 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; @@ -270,19 +270,19 @@ private Component createApprovePanel() { @Override public void removeUpdate(DocumentEvent arg0) { codeMapping.comment = commentField.getText(); - Global.mapping.fireDataChanged(DataChangeListener.SIMPLE_UPDATE_EVENT); + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); } @Override public void insertUpdate(DocumentEvent arg0) { codeMapping.comment = commentField.getText(); - Global.mapping.fireDataChanged(DataChangeListener.SIMPLE_UPDATE_EVENT); + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); } @Override public void changedUpdate(DocumentEvent arg0) { codeMapping.comment = commentField.getText(); - Global.mapping.fireDataChanged(DataChangeListener.SIMPLE_UPDATE_EVENT); + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); } }); commentField.setToolTipText("Comments about the code mapping can be written here"); @@ -388,10 +388,10 @@ public void clearCodeMultiSelected() { public void approve() { if (codeMapping.mappingStatus != CodeMapping.MappingStatus.APPROVED) { codeMapping.mappingStatus = CodeMapping.MappingStatus.APPROVED; - Global.mapping.fireDataChanged(DataChangeListener.APPROVE_EVENT); + Global.mapping.fireDataChanged(APPROVE_EVENT); } else { codeMapping.mappingStatus = CodeMapping.MappingStatus.UNCHECKED; - Global.mapping.fireDataChanged(DataChangeListener.SIMPLE_UPDATE_EVENT); + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); setApproveButton(); } } @@ -416,9 +416,9 @@ public void addConcept(Concept concept) { targetConceptTableModel.fireTableDataChanged(); if (codeMappingsFromMulti.size() > 0) { - Global.mapping.fireDataChanged(DataChangeListener.MULTI_UPDATE_EVENT); + Global.mapping.fireDataChanged(MULTI_UPDATE_EVENT); } else { - Global.mapping.fireDataChanged(DataChangeListener.SIMPLE_UPDATE_EVENT); + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); } } @@ -446,7 +446,7 @@ public int compare(Integer o1, Integer o2) { codeMapping.targetConcepts.remove(row); targetConceptTableModel.fireTableDataChanged(); - Global.mapping.fireDataChanged(DataChangeListener.SIMPLE_UPDATE_EVENT); + Global.mapping.fireDataChanged(SIMPLE_UPDATE_EVENT); } private class SearchTask extends TimerTask { diff --git a/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java b/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java index f9c1707..b2099fd 100644 --- a/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java +++ b/src/org/ohdsi/usagi/ui/actions/ApplyPreviousMappingAction.java @@ -28,10 +28,11 @@ import javax.swing.filechooser.FileNameExtensionFilter; import org.ohdsi.usagi.CodeMapping; -import org.ohdsi.usagi.ui.DataChangeListener; import org.ohdsi.usagi.ui.Global; import org.ohdsi.usagi.ui.Mapping; +import static org.ohdsi.usagi.ui.DataChangeEvent.*; + public class ApplyPreviousMappingAction extends AbstractAction { private static final long serialVersionUID = 3420357922150237898L; @@ -80,7 +81,7 @@ public void actionPerformed(ActionEvent arg0) { + " were applied to the current mapping and " + mappingsAdded + " were newly added."; Global.mappingTablePanel.updateUI(); Global.mappingDetailPanel.updateUI(); - Global.mapping.fireDataChanged(DataChangeListener.APPROVE_EVENT); // To update the footer + Global.mapping.fireDataChanged(APPROVE_EVENT); // To update the footer if (mappingsAdded > 0) { Global.usagiSearchEngine.close(); Global.usagiSearchEngine.createDerivedIndex(Global.mapping.getSourceCodes(), Global.frame); From 7031799b7e2ff70299f897df70bc3050949244f8 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Wed, 24 Jun 2020 17:54:29 +0200 Subject: [PATCH 31/34] Minor refactor of ExportSourceToConceptMapDialog Co-authored-by: Joris Borgdorff --- src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java b/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java index 0f14318..7c41b23 100644 --- a/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java +++ b/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java @@ -74,7 +74,7 @@ public ExportSourceToConceptMapDialog() { buttonPanel.add(Box.createHorizontalGlue()); JButton cancelButton = new JButton("Cancel"); cancelButton.setToolTipText("Cancel the export"); - cancelButton.addActionListener(arg0 -> setVisible(false)); + cancelButton.addActionListener(event -> setVisible(false)); buttonPanel.add(cancelButton); JButton exportButton = new JButton("Export"); exportButton.setToolTipText("Select the filename and export using these settings"); From d4c47aa46af7a8c4dd62ee53fcb95f0f3b052300 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Wed, 24 Jun 2020 17:54:50 +0200 Subject: [PATCH 32/34] Minore refactor of ExportSourceToConceptMapDialog Co-authored-by: Joris Borgdorff --- src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java b/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java index 7c41b23..4942455 100644 --- a/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java +++ b/src/org/ohdsi/usagi/ui/ExportSourceToConceptMapDialog.java @@ -78,7 +78,7 @@ public ExportSourceToConceptMapDialog() { buttonPanel.add(cancelButton); JButton exportButton = new JButton("Export"); exportButton.setToolTipText("Select the filename and export using these settings"); - exportButton.addActionListener(arg0 -> export()); + exportButton.addActionListener(event -> export()); buttonPanel.add(exportButton); add(buttonPanel, g); From 0ee63b05f56cb926de283c29c9b030dee5fdfda7 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Wed, 24 Jun 2020 18:03:25 +0200 Subject: [PATCH 33/34] update about page --- src/org/ohdsi/usagi/ui/AboutDialog.java | 25 ++++++++----------------- src/org/ohdsi/usagi/ui/Global.java | 8 ++++---- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/AboutDialog.java b/src/org/ohdsi/usagi/ui/AboutDialog.java index 94dba7a..8a5dd84 100644 --- a/src/org/ohdsi/usagi/ui/AboutDialog.java +++ b/src/org/ohdsi/usagi/ui/AboutDialog.java @@ -61,29 +61,20 @@ public AboutDialog() { JEditorPane text = new JEditorPane( "text/html", - "Usagi was developed by Martijn Schuemie" + + "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."); text.setEditable(false); text.setOpaque(false); - text.addHyperlinkListener(new HyperlinkListener() { - - public void hyperlinkUpdate(HyperlinkEvent hle) { - if (HyperlinkEvent.EventType.ACTIVATED.equals(hle.getEventType())) { - try { - // jep.setPage(hle.getURL()); - try { - Desktop desktop = Desktop.getDesktop(); - desktop.browse(new URI(hle.getURL().toString())); - } catch (URISyntaxException ex) { - - } - } catch (IOException ex) { - - } - + text.addHyperlinkListener(event -> { + if (HyperlinkEvent.EventType.ACTIVATED.equals(event.getEventType())) { + try { + Desktop desktop = Desktop.getDesktop(); + desktop.browse(new URI(event.getURL().toString())); + } catch (URISyntaxException | IOException ex) { + // url could not be opened } } }); diff --git a/src/org/ohdsi/usagi/ui/Global.java b/src/org/ohdsi/usagi/ui/Global.java index 1e63b8b..94073ce 100644 --- a/src/org/ohdsi/usagi/ui/Global.java +++ b/src/org/ohdsi/usagi/ui/Global.java @@ -21,7 +21,7 @@ import org.ohdsi.usagi.UsagiSearchEngine; import org.ohdsi.usagi.ui.actions.*; -import java.util.Vector; +import java.util.List; public class Global { public static JFrame frame; @@ -53,8 +53,8 @@ public class Global { public static RebuildIndexAction rebuildIndexAction; public static ExitAction exitAction; public static String vocabularyVersion; - public static Vector conceptClassIds; - public static Vector vocabularyIds; - public static Vector domainIds; + public static List conceptClassIds; + public static List vocabularyIds; + public static List domainIds; public static ShowStatsAction showStatsAction; } From 934aac9e3226b3b76314c400771076bb6c082ea8 Mon Sep 17 00:00:00 2001 From: Maxim Moinat Date: Wed, 24 Jun 2020 18:06:24 +0200 Subject: [PATCH 34/34] fix bugs introduced by refactorings --- src/org/ohdsi/usagi/ui/Global.java | 8 ++++---- src/org/ohdsi/usagi/ui/MappingTablePanel.java | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/org/ohdsi/usagi/ui/Global.java b/src/org/ohdsi/usagi/ui/Global.java index 94073ce..299d41b 100644 --- a/src/org/ohdsi/usagi/ui/Global.java +++ b/src/org/ohdsi/usagi/ui/Global.java @@ -21,7 +21,7 @@ import org.ohdsi.usagi.UsagiSearchEngine; import org.ohdsi.usagi.ui.actions.*; -import java.util.List; +import java.util.Vector; public class Global { public static JFrame frame; @@ -53,8 +53,8 @@ public class Global { public static RebuildIndexAction rebuildIndexAction; public static ExitAction exitAction; public static String vocabularyVersion; - public static List conceptClassIds; - public static List vocabularyIds; - public static List domainIds; + public static Vector conceptClassIds; + public static Vector vocabularyIds; + public static Vector domainIds; public static ShowStatsAction showStatsAction; } diff --git a/src/org/ohdsi/usagi/ui/MappingTablePanel.java b/src/org/ohdsi/usagi/ui/MappingTablePanel.java index 7e4374d..79230b9 100644 --- a/src/org/ohdsi/usagi/ui/MappingTablePanel.java +++ b/src/org/ohdsi/usagi/ui/MappingTablePanel.java @@ -31,6 +31,8 @@ import org.ohdsi.usagi.CodeMapping.MappingStatus; import org.ohdsi.usagi.Concept; +import static org.ohdsi.usagi.ui.DataChangeEvent.*; + public class MappingTablePanel extends JPanel implements DataChangeListener { private static final long serialVersionUID = -5862314086097240860L; private UsagiTable table;