diff --git a/compat/tablesSchema.2.0.3.xlsx b/compat/tablesSchema.2.0.3.xlsx new file mode 100644 index 0000000..7f69804 Binary files /dev/null and b/compat/tablesSchema.2.0.3.xlsx differ diff --git a/config/PredefinedResults.xlsx b/config/PredefinedResults.xlsx index e89d1a5..3876f25 100644 Binary files a/config/PredefinedResults.xlsx and b/config/PredefinedResults.xlsx differ diff --git a/config/appConfig.xml b/config/appConfig.xml index fb2a326..9f1101c 100644 --- a/config/appConfig.xml +++ b/config/appConfig.xml @@ -3,8 +3,8 @@ Application configuration EFSA TSE data reporting tool -2.0.3 -2.0.3 +2.0.4 +2.0.4 app-icon.png zoonoses_support@efsa.europa.eu diff --git a/config/tablesSchema.xlsx b/config/tablesSchema.xlsx index 7f69804..dd0da78 100644 Binary files a/config/tablesSchema.xlsx and b/config/tablesSchema.xlsx differ diff --git a/pom.xml b/pom.xml index 03573be..c2b2f05 100644 --- a/pom.xml +++ b/pom.xml @@ -41,18 +41,18 @@ org.apache.logging.log4j log4j-api - [2.17.1,) + 2.17.1 org.apache.logging.log4j log4j-core - [2.17.1,) + 2.17.1 org.junit.jupiter junit-jupiter test - [5.5.2,) + 5.5.2 org.apache.derby diff --git a/src/main/java/predefined_results/PredefinedResultList.java b/src/main/java/predefined_results/PredefinedResultList.java index 43bf5c2..007c839 100644 --- a/src/main/java/predefined_results/PredefinedResultList.java +++ b/src/main/java/predefined_results/PredefinedResultList.java @@ -9,11 +9,9 @@ import app_config.BooleanValue; public class PredefinedResultList extends ArrayList { - private static final Logger LOGGER = LogManager.getLogger(PredefinedResultList.class); - private static final long serialVersionUID = -6372192676663884532L; - + private static PredefinedResultList predefinedResultsCache; /** @@ -23,16 +21,14 @@ public class PredefinedResultList extends ArrayList { * @return */ public PredefinedResult get(String recordType, String source, boolean confirmatoryTested, String sampEventAsses) { - for (PredefinedResult prh : this) { - String thisRecordType = prh.get(PredefinedResultHeader.RECORD_TYPE); String thisSource = prh.get(PredefinedResultHeader.SOURCE); String thisSampEventAsses = prh.get(PredefinedResultHeader.SAMP_EVENT_ASSES); String thisConfTested = prh.get(PredefinedResultHeader.CONFIRMATORY_EXECUTED); boolean confCheck = (BooleanValue.isTrue(thisConfTested) && confirmatoryTested) - || (BooleanValue.isFalse(thisConfTested) && !confirmatoryTested); + || (BooleanValue.isFalse(thisConfTested) && !confirmatoryTested); if (isFieldEqual(thisRecordType, recordType) && isFieldEqual(thisSource, source) @@ -52,9 +48,8 @@ && isFieldEqual(thisSampEventAsses, sampEventAsses) * @return */ private static boolean isFieldEqual(String predefResValue, String rowValue) { - // always match an empty field in the configuration - if(predefResValue == null || predefResValue.isEmpty() || predefResValue.equals("null")) { + if (predefResValue == null || predefResValue.isEmpty() || predefResValue.equals("null")) { return true; } @@ -72,18 +67,14 @@ private static boolean isFieldEqual(String predefResValue, String rowValue) { * @throws IOException */ public static PredefinedResultList getAll() { - // if first time if (predefinedResultsCache == null) { - predefinedResultsCache = new PredefinedResultList(); //solve memory leak try (PredefinedResultsReader reader = new PredefinedResultsReader()){ reader.readFirstSheet(); - predefinedResultsCache = reader.getResults(); - } catch (IOException e) { LOGGER.error("Cannot retrieve predefined results list", e); e.printStackTrace(); diff --git a/src/main/java/providers/PredefinedResultService.java b/src/main/java/providers/PredefinedResultService.java index 95e5d86..a7331b8 100644 --- a/src/main/java/providers/PredefinedResultService.java +++ b/src/main/java/providers/PredefinedResultService.java @@ -25,11 +25,10 @@ * */ public class PredefinedResultService { - private static final Logger LOGGER = LogManager.getLogger(PredefinedResultService.class); - private ITableDaoService daoService; - private IFormulaService formulaService; + private final ITableDaoService daoService; + private final IFormulaService formulaService; public PredefinedResultService(ITableDaoService daoService, IFormulaService formulaService) { this.daoService = daoService; @@ -43,9 +42,7 @@ public PredefinedResultService(ITableDaoService daoService, IFormulaService form * @param caseReport * @throws IOException */ - public TableRowList createDefaultResults(Report report, - SummarizedInfo summInfo, CaseReport caseReport) throws IOException { - + public TableRowList createDefaultResults(Report report, SummarizedInfo summInfo, CaseReport caseReport) { TableRowList results = new TableRowList(); AnalyticalResult r = createDefaultResult(report, summInfo, caseReport, @@ -85,39 +82,34 @@ public TableRowList createDefaultResults(Report report, * @return * @throws IOException */ - public boolean isConfirmatoryTested(String type) throws IOException { - - String confirmatory = ""; - + public boolean isConfirmatoryTested(String type) { + String column; switch(type) { - case CustomStrings.SUMMARIZED_INFO_BSE_TYPE: - confirmatory = Relation.getGlobalParent(CustomStrings.PREFERENCES_SHEET, daoService) - .getCode(CustomStrings.PREFERENCES_CONFIRMATORY_BSE); - break; - case CustomStrings.SUMMARIZED_INFO_SCRAPIE_TYPE: - confirmatory = Relation.getGlobalParent(CustomStrings.PREFERENCES_SHEET, daoService) - .getCode(CustomStrings.PREFERENCES_CONFIRMATORY_SCRAPIE); - break; - case CustomStrings.SUMMARIZED_INFO_CWD_TYPE: - confirmatory = Relation.getGlobalParent(CustomStrings.PREFERENCES_SHEET, daoService) - .getCode(CustomStrings.PREFERENCES_CONFIRMATORY_CWD); - break; - default: - break; + case CustomStrings.SUMMARIZED_INFO_BSE_TYPE: + column = CustomStrings.PREFERENCES_CONFIRMATORY_BSE; + break; + case CustomStrings.SUMMARIZED_INFO_SCRAPIE_TYPE: + column = CustomStrings.PREFERENCES_CONFIRMATORY_SCRAPIE; + break; + case CustomStrings.SUMMARIZED_INFO_CWD_TYPE: + column = CustomStrings.PREFERENCES_CONFIRMATORY_CWD; + break; + case CustomStrings.SUMMARIZED_INFO_BSEOS_TYPE: + column = CustomStrings.PREFERENCES_CONFIRMATORY_BSE_OS; + break; + default: + return false; } - - return !confirmatory.isEmpty(); + return ! Relation.getGlobalParent(CustomStrings.PREFERENCES_SHEET, daoService) + .getCode(column) + .isEmpty(); } - public static String getPreferredTestType(String testType) throws IOException { - - return Relation.getGlobalParent(CustomStrings.PREFERENCES_SHEET) - .getCode(testType); + public static String getPreferredTestType(String testType) { + return Relation.getGlobalParent(CustomStrings.PREFERENCES_SHEET).getCode(testType); } - public static String getPreferredTestType(String recordType, String testType) - throws IOException { - + public static String getPreferredTestType(String recordType, String testType) { String preferredTestType = null; switch(testType) { @@ -135,6 +127,10 @@ public static String getPreferredTestType(String recordType, String testType) preferredTestType = getPreferredTestType( CustomStrings.PREFERENCES_SCREENING_CWD); break; + case CustomStrings.SUMMARIZED_INFO_BSEOS_TYPE: + preferredTestType = getPreferredTestType( + CustomStrings.PREFERENCES_SCREENING_BSE_OS); + break; default: break; } @@ -153,6 +149,10 @@ public static String getPreferredTestType(String recordType, String testType) preferredTestType = getPreferredTestType( CustomStrings.PREFERENCES_CONFIRMATORY_CWD); break; + case CustomStrings.SUMMARIZED_INFO_BSEOS_TYPE: + preferredTestType = getPreferredTestType( + CustomStrings.PREFERENCES_CONFIRMATORY_BSE_OS); + break; default: break; } @@ -171,6 +171,10 @@ public static String getPreferredTestType(String recordType, String testType) preferredTestType = getPreferredTestType( CustomStrings.PREFERENCES_DISCRIMINATORY_CWD); break; + case CustomStrings.SUMMARIZED_INFO_BSEOS_TYPE: + preferredTestType = getPreferredTestType( + CustomStrings.PREFERENCES_DISCRIMINATORY_BSE_OS); + break; default: break; } @@ -185,8 +189,7 @@ public static String getPreferredTestType(String recordType, String testType) return preferredTestType; } - public PredefinedResult getPredefinedResult(SummarizedInfo summInfo, TableRow caseReport) throws IOException { - + public PredefinedResult getPredefinedResult(SummarizedInfo summInfo, TableRow caseReport) { // put the predefined value for the param code and the result PredefinedResultList predResList = PredefinedResultList.getAll(); @@ -208,14 +211,11 @@ public PredefinedResult getPredefinedResult(SummarizedInfo summInfo, TableRow ca * @param report * @param summInfo * @param caseReport - * @param codeCol * @param testTypeCode * @throws IOException */ - private AnalyticalResult createDefaultResult(Report report, - SummarizedInfo summInfo, TableRow caseReport, - PredefinedResultHeader test, - String testTypeCode) throws IOException { + private AnalyticalResult createDefaultResult(Report report, SummarizedInfo summInfo, TableRow caseReport, + PredefinedResultHeader test, String testTypeCode) { AnalyticalResult resultRow = new AnalyticalResult(); @@ -231,7 +231,6 @@ private AnalyticalResult createDefaultResult(Report report, boolean added = addParamAndResult(resultRow, defaultResult, test); if (added) { - // code crack to save the row id for the resId field // otherwise its default value will be corrupted daoService.add(resultRow); @@ -269,10 +268,7 @@ private AnalyticalResult createDefaultResult(Report report, * @param codeCol * @return */ - public static boolean addParamAndResult(TableRow result, - PredefinedResult defValues, - PredefinedResultHeader codeCol) { - + private boolean addParamAndResult(TableRow result, PredefinedResult defValues, PredefinedResultHeader codeCol) { String code = defValues.get(codeCol); // put the test aim @@ -284,17 +280,15 @@ public static boolean addParamAndResult(TableRow result, return addParamAndResult(result, code); } - - /** * Add param and result. These values are taken from the test code * which is composed of paramBaseTerm$resultValue + * * @param result * @param testCode * @return */ public static boolean addParamAndResult(TableRow result, String testCode) { - if (testCode == null) return false; diff --git a/src/main/java/providers/TseReportService.java b/src/main/java/providers/TseReportService.java index 8c9c18d..6f91a35 100644 --- a/src/main/java/providers/TseReportService.java +++ b/src/main/java/providers/TseReportService.java @@ -2,11 +2,7 @@ import java.io.IOException; import java.text.ParseException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.Stack; +import java.util.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -26,10 +22,7 @@ import soap_interface.IGetDatasetsList; import soap_interface.ISendMessage; import table_relations.Relation; -import table_skeleton.TableCell; -import table_skeleton.TableRow; -import table_skeleton.TableRowList; -import table_skeleton.TableVersion; +import table_skeleton.*; import tse_analytical_result.AnalyticalResult; import tse_case_report.CaseReport; import tse_config.CustomStrings; @@ -41,6 +34,8 @@ import xlsx_reader.TableSchemaList; import xlsx_reader.TableHeaders.XlsxHeader; +import static tse_config.CustomStrings.RES_ID_COL; + /** * * Report service @@ -49,17 +44,18 @@ * @author shahaal * */ - public class TseReportService extends ReportService { - private static final Logger LOGGER = LogManager.getLogger(TseReportService.class); - private IFormulaService formulaService1; + public enum RowType { + SUMM, CASE, RESULT + } + + private final IFormulaService formulaService1; public TseReportService(IGetAck getAck, IGetDatasetsList getDatasetsList, ISendMessage sendMessage, IGetDataset getDataset, ITableDaoService daoService, IFormulaService formulaService) { super(getAck, getDatasetsList, sendMessage, getDataset, daoService, formulaService); - this.formulaService1 = formulaService; } @@ -72,20 +68,16 @@ public TseReportService(IGetAck getAck, IGetDatasetsList getDatasetsLi * @throws FormulaException */ public String getSampId(SummarizedInfo summInfo) throws FormulaException { - // we need all the fields to compute the context id, in order to // solve formula dependencies FormulaSolver solver = new FormulaSolver(summInfo, daoService); - ArrayList formulas = solver.solveAll(XlsxHeader.LABEL_FORMULA.getHeaderName()); - LOGGER.info("Formulas: ", Arrays.asList(formulas)); for (Formula f : formulas) { if (f.getColumn().getId().equals(CustomStrings.SAMPLE_ID_COL)) return f.getSolvedFormula(); } - return null; } @@ -97,20 +89,15 @@ public String getSampId(SummarizedInfo summInfo) throws FormulaException { * @throws ParseException */ public static boolean isRGTResult(TableRow row) throws ParseException { - FormulaDecomposer decomposer = new FormulaDecomposer(); String paramBaseTerm = decomposer.getBaseTerm(row.getCode(CustomStrings.PARAM_CODE_COL)); boolean rgtParamCode = paramBaseTerm.equals(CustomStrings.RGT_PARAM_CODE); - LOGGER.info("Αnalytical result is related to random genotyping: ", rgtParamCode); + LOGGER.info("Analytical result is related to random genotyping: {}", rgtParamCode); return rgtParamCode; } - public enum RowType { - SUMM, CASE, RESULT - } - /** * Get the type of the row * @@ -118,23 +105,13 @@ public enum RowType { * @return */ public static RowType getRowType(TableRow row) { - RowType type = null; - switch (row.getSchema().getSheetName()) { - case CustomStrings.SUMMARIZED_INFO_SHEET: - type = RowType.SUMM; - break; - case CustomStrings.CASE_INFO_SHEET: - type = RowType.CASE; - break; - case CustomStrings.RESULT_SHEET: - type = RowType.RESULT; - break; - default: - break; + case CustomStrings.SUMMARIZED_INFO_SHEET: type = RowType.SUMM; break; + case CustomStrings.CASE_INFO_SHEET: type = RowType.CASE; break; + case CustomStrings.RESULT_SHEET: type = RowType.RESULT; break; } - LOGGER.debug("Row type: ", type); + LOGGER.debug("Row type: {}", type); return type; } @@ -148,21 +125,17 @@ public static RowType getRowType(TableRow row) { * @throws FormulaException */ public static String getOrigSampIdFrom(TableRow result) throws ParseException, FormulaException { - // decompose param code TSEFormulaDecomposer decomposer = new TSEFormulaDecomposer(); - - HashMap rowValues = decomposer.decompose(CustomStrings.SAMP_INFO_COL, - result.getCode(CustomStrings.SAMP_INFO_COL)); + HashMap rowValues = decomposer.decompose(CustomStrings.SAMP_INFO_COL, result.getCode(CustomStrings.SAMP_INFO_COL)); // get the cell for origSampId TableCell cell = rowValues.get(CustomStrings.ORIG_SAMP_ID_COL); // if the cell is null (old report) then retrieve it from resId if (cell == null) { - // return the substring if dot present - String[] split = result.getCode(CustomStrings.RES_ID_COL).split("\\."); + String[] split = result.getCode(RES_ID_COL).split("\\."); // @TODO to better check, what happens if split not possible if (split.length >= 1) @@ -180,29 +153,25 @@ public static String getOrigSampIdFrom(TableRow result) throws ParseException, F * @return */ public ArrayList getAllRecords(TseReport report) { - // children schemas - TableSchema[] schemas = new TableSchema[] { TableSchemaList.getByName(CustomStrings.SUMMARIZED_INFO_SHEET), + TableSchema[] schemas = new TableSchema[] { + TableSchemaList.getByName(CustomStrings.SUMMARIZED_INFO_SHEET), TableSchemaList.getByName(CustomStrings.CASE_INFO_SHEET), - TableSchemaList.getByName(CustomStrings.RESULT_SHEET) }; + TableSchemaList.getByName(CustomStrings.RESULT_SHEET) + }; return getRecords(report, schemas); } public ArrayList getRecords(TseReport report, TableSchema[] schemas) { - ArrayList records = new ArrayList<>(); // for each child schema get the rows related to the report for (TableSchema schema : schemas) { - - ArrayList children = getDaoService().getByParentId(schema, CustomStrings.REPORT_SHEET, - report.getDatabaseId(), true, "desc"); - + ArrayList children = getDaoService().getByParentId(schema, CustomStrings.REPORT_SHEET, report.getDatabaseId(), true, "desc"); if (children != null) records.addAll(children); } - return records; } @@ -215,18 +184,16 @@ public ArrayList getRecords(TseReport report, TableSchema[] schemas) { */ public boolean hasChildren(TableRow parent, TableSchema childSchema) { return !getDaoService() - .getByParentId(childSchema, parent.getSchema().getSheetName(), parent.getDatabaseId(), false).isEmpty(); + .getByParentId(childSchema, parent.getSchema().getSheetName(), parent.getDatabaseId(), false) + .isEmpty(); } public void updateChildrenErrors(SummarizedInfo summInfo) { - - // check children errors boolean errors = false; CaseReportValidator validator = new CaseReportValidator(getDaoService()); - for (TableRow row : getDaoService().getByParentId(TableSchemaList.getByName(CustomStrings.CASE_INFO_SHEET), - summInfo.getSchema().getSheetName(), summInfo.getDatabaseId(), true)) { - + TableRowList rowsByParent = getDaoService().getByParentId(TableSchemaList.getByName(CustomStrings.CASE_INFO_SHEET), summInfo.getSchema().getSheetName(), summInfo.getDatabaseId(), true); + for (TableRow row : rowsByParent) { if (validator.getOverallWarningLevel(row) > 0) { summInfo.setChildrenError(); errors = true; @@ -237,18 +204,14 @@ public void updateChildrenErrors(SummarizedInfo summInfo) { if (!errors) { summInfo.removeChildrenError(); } - getDaoService().update(summInfo); } public void updateChildrenErrors(CaseReport caseReport) { - - // check children errors boolean error = false; ResultValidator resultValidator = new ResultValidator(); - for (TableRow r : getDaoService().getByParentId(TableSchemaList.getByName(CustomStrings.RESULT_SHEET), - caseReport.getSchema().getSheetName(), caseReport.getDatabaseId(), true)) { - + TableRowList rowsByParentId = getDaoService().getByParentId(TableSchemaList.getByName(CustomStrings.RESULT_SHEET), caseReport.getSchema().getSheetName(), caseReport.getDatabaseId(), true); + for (TableRow r : rowsByParentId) { if (resultValidator.getWarningLevel(r) > 0) { caseReport.setChildrenError(); error = true; @@ -259,142 +222,215 @@ public void updateChildrenErrors(CaseReport caseReport) { if (!error) { caseReport.removeChildrenError(); } - getDaoService().update(caseReport); } public MessageConfigBuilder getSendMessageConfiguration(TseReport report) { - Collection messageParents = new ArrayList<>(); - - // add the report data messageParents.add(report); // add the settings data try { - TableRow settings = Relation.getGlobalParent(CustomStrings.SETTINGS_SHEET, getDaoService()); - messageParents.add(settings); - } catch (IOException e) { + } catch (Exception e) { LOGGER.error("Error in setting message data", e); e.printStackTrace(); } - MessageConfigBuilder builder = new MessageConfigBuilder(formulaService1, messageParents); - - return builder; + return new MessageConfigBuilder(formulaService1, messageParents); } public MessageConfigBuilder getAcceptDwhBetaMessageConfiguration(TseReport report) { - Collection messageParents = new ArrayList<>(); - - // add the report data messageParents.add(report); // add the settings data try { - TableRow settings = Relation.getGlobalParent(CustomStrings.SETTINGS_SHEET, getDaoService()); - messageParents.add(settings); - } catch (IOException e) { + } catch (Exception e) { LOGGER.error("Error in setting Accept Dwh Beta message data", e); e.printStackTrace(); } - MessageConfigBuilder builder = new MessageConfigBuilder(formulaService1, messageParents); - - return builder; + return new MessageConfigBuilder(formulaService1, messageParents); } /** * Create a new version of the report and save it into the database. The version * is automatically increased * - * @return + * @return the amended report */ public TseReport amend(TseReport report) { - TseReport amendedReport = new TseReport(); amendedReport.copyValues(report); + amendTseReport(amendedReport, report); + TseReport tseReport = copyReportChildren(amendedReport, report, false); + LOGGER.info("Amended report : {}", report.getDatabaseId()); + return tseReport; + } + /** + * Copy a report and then generate the required fields of the new report + * + * @param source the report being copied + * @param target the report that will contain the copied data + * @return the copied report + */ + public TseReport copyReport(TseReport source, TseReport target) { + List directChildren = target.getSchema().getDirectChildren(); + for (Relation rel: directChildren) { + daoService.deleteByParentId(rel.getChildSchema(), target.getSchema().getSheetName(), target.getDatabaseId()); + } + + target.setStatus(RCLDatasetStatus.DRAFT); + target.setMessageId(""); + daoService.update(target); + + copyReportChildren(source, target, true); + LOGGER.info("Imported report {} to {}", source.getDatabaseId(), target.getDatabaseId()); + return target; + } + + /** + * Copy a report's child items (SummarizedInfo, CaseInfo and AnalyticalResults of a report). + * Does not copy the report itself. This should be handled in the caller method. + * If init is true, will also use formulas to generate the fields instead of simply copying them + * + * @param source the report being copied + * @param target the report that will contain the copied data + * @param init determines if the report's formula fields will be generated again or copied from source + * + * @return + */ + private TseReport copyReportChildren(TseReport source, TseReport target, boolean init) { Stack elements = new Stack<>(); - elements.add(amendedReport); + elements.add(source); SummarizedInfo summInfo = null; CaseReport caseReport = null; - AnalyticalResult result = null; while (!elements.isEmpty()) { - TableRow currentElement = elements.pop(); + TableSchema schema = currentElement.getSchema(); + boolean isSumm = schema.equals(TableSchemaList.getByName(CustomStrings.SUMMARIZED_INFO_SHEET)); + boolean isCase = schema.equals(TableSchemaList.getByName(CustomStrings.CASE_INFO_SHEET)); + boolean isRslt = schema.equals(TableSchemaList.getByName(CustomStrings.RESULT_SHEET)); - boolean isReport = currentElement.getSchema().equals(TableSchemaList.getByName(CustomStrings.REPORT_SHEET)); - boolean isSumm = currentElement.getSchema() - .equals(TableSchemaList.getByName(CustomStrings.SUMMARIZED_INFO_SHEET)); - boolean isCase = currentElement.getSchema() - .equals(TableSchemaList.getByName(CustomStrings.CASE_INFO_SHEET)); - boolean isResult = currentElement.getSchema().equals(TableSchemaList.getByName(CustomStrings.RESULT_SHEET)); - - TableSchema childSchema = null; - if (isReport) { - childSchema = TableSchemaList.getByName(CustomStrings.SUMMARIZED_INFO_SHEET); - } else if (isSumm) { - childSchema = TableSchemaList.getByName(CustomStrings.CASE_INFO_SHEET); - } else if (isCase) { - childSchema = TableSchemaList.getByName(CustomStrings.RESULT_SHEET); - } + // only one or none direct child exists + List directChildren = schema.getDirectChildren(); + TableSchema childSchema = directChildren.size() > 0 ? directChildren.get(0).getChildSchema() : null; // get the element children (before changing its id) Collection children = null; + if (!isRslt) { + children = getDaoService().getByParentId(childSchema, schema.getSheetName(), currentElement.getDatabaseId(), true); + } - if (!isResult) { - children = getDaoService().getByParentId(childSchema, currentElement.getSchema().getSheetName(), - currentElement.getDatabaseId(), true); + if (isSumm) { + summInfo = initSummarizedInfo(currentElement, init, target); + } else if (isCase) { + caseReport = initCaseReport(currentElement, target, summInfo); + } else if (isRslt) { + copyAnalyticalResult(currentElement, init, target, summInfo, caseReport); } - if (isReport) { - // get current version - String currentVersion = report.getVersion(); + // add the children + if (!isRslt) + elements.addAll(children); + } + return target; + } - // increase version starting from the current - String newVersion = TableVersion.createNewVersion(currentVersion); + private void amendTseReport(TseReport source, TseReport target) { + // increase version starting from the current + String newVersion = TableVersion.createNewVersion(source.getVersion()); + target.setVersion(newVersion); - amendedReport.setVersion(newVersion); + target.setStatus(RCLDatasetStatus.DRAFT); + target.setId(""); + target.setMessageId(""); + getDaoService().add(target); + } - // new version is in draft - amendedReport.setStatus(RCLDatasetStatus.DRAFT); + private SummarizedInfo initSummarizedInfo(TableRow currentElement, boolean init, TseReport target) { + return init ? copyTableRowWithFormulaUpdate(new SummarizedInfo(), currentElement, target) + : copyTableRow(new SummarizedInfo(), currentElement, target); + } - amendedReport.setId(""); - amendedReport.setMessageId(""); - getDaoService().add(amendedReport); - } else if (isSumm) { - summInfo = new SummarizedInfo(); - summInfo.copyValues(currentElement); - Relation.injectParent(amendedReport, summInfo); - getDaoService().add(summInfo); - } else if (isCase) { - caseReport = new CaseReport(); - caseReport.copyValues(currentElement); - Relation.injectParent(amendedReport, caseReport); - Relation.injectParent(summInfo, caseReport); - getDaoService().add(caseReport); - } else if (isResult) { - result = new AnalyticalResult(); - result.copyValues(currentElement); - Relation.injectParent(amendedReport, result); - Relation.injectParent(summInfo, result); - Relation.injectParent(caseReport, result); - getDaoService().add(result); - } + private CaseReport initCaseReport(TableRow currentElement, TableRow... parents) { + return copyTableRow(new CaseReport(), currentElement, parents); + } - // add the children - if (!isResult) - elements.addAll(children); + private AnalyticalResult copyAnalyticalResult(TableRow currentElement, boolean init, TableRow... parents) { + return init ? copyTableRowWithFormulaUpdate(new AnalyticalResult(), currentElement, parents) + : copyTableRow(new AnalyticalResult(), currentElement, parents); + } + + /** + * Copy values from source to target and inject new parent ids + * + * @param target the new row being added + * @param source the source row to get values + * @param parents the parent tables to inject in the target + * + * @return the target row with updated values + */ + private T copyTableRow(T target, TableRow source, TableRow... parents) { + target.copyValues(source); + + Relation.injectGlobalParent(target, CustomStrings.SETTINGS_SHEET); + Relation.injectGlobalParent(target, CustomStrings.PREFERENCES_SHEET); + for (TableRow tr : parents) { + Relation.injectParent(tr, target); + } + + getDaoService().add(target); + return target; + } + + /** + * Copies one row into another like {@link #copyTableRow(TableRow, TableRow, TableRow...)} but also initialises + * the fields that are automatically generated or are generated by formulas + * + * @param target the new row being added + * @param source the source row to get values + * @param parents the parent tables to inject in the target + * + * @return the target row with updated values + */ + private T copyTableRowWithFormulaUpdate(T target, TableRow source, TableRow... parents) { + Relation.injectGlobalParent(target, CustomStrings.SETTINGS_SHEET); + Relation.injectGlobalParent(target, CustomStrings.PREFERENCES_SHEET); + for (TableRow tr : parents) { + Relation.injectParent(tr, target); + } + target.save(); + + // Initialise the target fields with default values + target.Initialise(); + // insert the target and save also the target id + target.update(); + // Initialise the formulas with target id + target.Initialise(); + + // fill editable fields + for (TableColumn col : target.getSchema()) { + String id = col.getId(); + // resId must not be copied but generated as we do not know if it was changed manually + // type is the only none editable field that needs to be copied + if ((col.isEditable(target) && !id.equals("resId")) || id.equals("type")) { + target.put(id, source.get(id)); + } } - LOGGER.info("Amended report : ", amendedReport); - return amendedReport; + + // update the formulas + target.updateFormulas(); + // update the target with the formulas solved + target.update(); + + return target; } /** @@ -404,42 +440,30 @@ public TseReport amend(TseReport report) { * @return */ public TseReport reportFromDataset(Dataset dataset) { - TseReport report = new TseReport(); - - String senderDatasetId = dataset.getOperation().getSenderDatasetId(); - report.setId(dataset.getId()); + String senderDatasetId = dataset.getOperation().getSenderDatasetId(); String[] split = Dataset.splitSenderId(senderDatasetId); - String senderId = senderDatasetId; - String version = null; if (split != null && split.length > 1) { senderId = split[0]; - version = split[1]; - report.setVersion(version); + report.setVersion(split[1]); } else { report.setVersion(TableVersion.getFirstVersion()); } report.setSenderId(senderId); - - if (dataset.getRCLStatus() != null) - report.setStatus(dataset.getRCLStatus()); - else - report.setStatus(RCLDatasetStatus.DRAFT); + report.setStatus(dataset.getRCLStatus() != null ? dataset.getRCLStatus() : RCLDatasetStatus.DRAFT); // split FR1705... into country year and month if (senderId.length() < 6) { - LOGGER.error("Report#fromDataset Cannot parse sender dataset id, expected at least 6 characters, found " - + senderId); + LOGGER.error("Report#fromDataset Cannot parse sender dataset id, expected at least 6 characters, found {}", senderId); report.setCountry(""); report.setYear(""); report.setMonth(""); } else { - String countryCode = senderDatasetId.substring(0, 2); String year = "20" + senderDatasetId.substring(2, 4); String month = senderDatasetId.substring(4, 6); @@ -460,12 +484,7 @@ public TseReport reportFromDataset(Dataset dataset) { report.setLastValidationMessageId(dataset.getLastValidationMessageId()); // add the preferences - try { - Relation.injectGlobalParent(report, CustomStrings.PREFERENCES_SHEET, getDaoService()); - } catch (IOException e) { - LOGGER.error("Error in injecting the parent foreign key into the child row" , e); - e.printStackTrace(); - } + Relation.injectGlobalParent(report, CustomStrings.PREFERENCES_SHEET, getDaoService()); // shahaal: removed stmt since the report is not based anymore on the // exceptional country @@ -491,7 +510,6 @@ public TseReport reportFromDataset(Dataset dataset) { } public void createDefaultRGTCase(Report report, TableRow summInfo) { - TableSchema caseSchema = TableSchemaList.getByName(CustomStrings.CASE_INFO_SHEET); TableRow resultRow = new TableRow(caseSchema); @@ -505,7 +523,6 @@ public void createDefaultRGTCase(Report report, TableRow summInfo) { daoService.add(resultRow); formulaService1.Initialise(resultRow); - resultRow.put(CustomStrings.PART_COL, CustomStrings.BLOOD_CODE); daoService.update(resultRow); @@ -516,20 +533,16 @@ public void createDefaultRGTCase(Report report, TableRow summInfo) { * positive/inconclusive cases * * @param summInfo - * @param positive - * @param inconclusive * @throws IOException */ public void createDefaultCases(Report report, TableRow summInfo) throws IOException { - // check cases number int positive = summInfo.getNumLabel(CustomStrings.TOT_SAMPLE_POSITIVE_COL); int inconclusive = summInfo.getNumLabel(CustomStrings.TOT_SAMPLE_INCONCLUSIVE_COL); TableSchema resultSchema = TableSchemaList.getByName(CustomStrings.CASE_INFO_SHEET); - boolean isCervid = summInfo.getCode(CustomStrings.SUMMARIZED_INFO_TYPE) - .equals(CustomStrings.SUMMARIZED_INFO_CWD_TYPE); + boolean isCervid = summInfo.getCode(CustomStrings.SUMMARIZED_INFO_TYPE).equals(CustomStrings.SUMMARIZED_INFO_CWD_TYPE); // for cervids we need double rows int repeats = isCervid ? 2 : 1; @@ -538,7 +551,6 @@ public void createDefaultCases(Report report, TableRow summInfo) throws IOExcept for (int i = 0; i < inconclusive; ++i) { for (int j = 0; j < repeats; ++j) { - TableRow resultRow = new TableRow(resultSchema); // inject the case parent to the result @@ -574,9 +586,7 @@ public void createDefaultCases(Report report, TableRow summInfo) throws IOExcept // for each positive for (int i = 0; i < positive; ++i) { - for (int j = 0; j < repeats; ++j) { - TableRow resultRow = new TableRow(resultSchema); // inject the case parent to the result @@ -603,14 +613,9 @@ public void createDefaultCases(Report report, TableRow summInfo) throws IOExcept } } - public TableRowList createDefaultResults(Report report, SummarizedInfo summInfo, CaseReport caseInfo) - throws IOException { - + public TableRowList createDefaultResults(Report report, SummarizedInfo summInfo, CaseReport caseInfo) throws IOException { PredefinedResultService r = new PredefinedResultService(daoService, formulaService1); - TableRowList results = r.createDefaultResults(report, summInfo, caseInfo); - return results; } - } diff --git a/src/main/java/report_downloader/TseReportImporter.java b/src/main/java/report_downloader/TseReportImporter.java index 3dd9fe1..8edff74 100644 --- a/src/main/java/report_downloader/TseReportImporter.java +++ b/src/main/java/report_downloader/TseReportImporter.java @@ -1,6 +1,5 @@ package report_downloader; -import java.io.IOException; import java.text.ParseException; import java.util.ArrayList; import java.util.Collection; @@ -44,17 +43,13 @@ public class TseReportImporter extends ReportImporter { /** * Download and import a dataset, managing also all the amendments - * - * @param datasetVersions a list with all the dataset versions. This is needed - * to manage amendments. */ public TseReportImporter(TseReportService reportService, ITableDaoService daoService) { super(CustomStrings.RES_ID_COL, CustomStrings.SENDER_DATASET_ID_COL, reportService, daoService); - this.reportService = reportService; this.daoService = daoService; - this.summInfos = new ArrayList<>(); - this.cases = new HashMap<>(); + summInfos = new ArrayList<>(); + cases = new HashMap<>(); } /** @@ -76,21 +71,17 @@ private static boolean isSummarizedInfo(TableRow row) { * @throws FormulaException * @throws ParseException */ - private void importSummarizedInformation(TseReport report1, Collection datasetRows) - throws FormulaException, ParseException { - + private void importSummarizedInformation(TseReport report1, Collection datasetRows) throws FormulaException, ParseException { // first process the summarized information for (TableRow row : datasetRows) { // if we have a summarized information // import it if (isSummarizedInfo(row)) { - SummarizedInfo summInfo = new SummarizedInfo(); // if random genotyping, create the summarized information if (TseReportService.isRGTResult(row)) { - summInfo = extractSummarizedInfo(report1, row, true); // create the summarized information @@ -102,12 +93,10 @@ private void importSummarizedInformation(TseReport report1, Collection LOGGER.info("Created fake RGT summarized information"); } else { - SummarizedInfo si = extractSummarizedInfo(report1, row, false); // save it in the database daoService.add(si); - LOGGER.info("Imported summ info; sampId=" + reportService.getSampId(si)); // save it in the cache @@ -122,24 +111,18 @@ private void importSummarizedInformation(TseReport report1, Collection * Import all the cases and analytical results * * @param report1 - * @param summInfo * @param datasetRows * @throws FormulaException * @throws ParseException */ - private void importCasesAndResults(TseReport report1, Collection datasetRows) - throws FormulaException, ParseException { - + private void importCasesAndResults(TseReport report1, Collection datasetRows) throws FormulaException, ParseException { // process the cases and analytical results for (TableRow row : datasetRows) { - if (!isSummarizedInfo(row)) { - SummarizedInfo summInfo = new SummarizedInfo(); // if random genotyping, create the summarized information if (!TseReportService.isRGTResult(row)) { - row.put(CustomStrings.REPORT_ID_COL, report1.getDatabaseId()); // Report is needed for results // formulas (sampId) @@ -153,9 +136,7 @@ private void importCasesAndResults(TseReport report1, Collection datas } if (summInfo == null) { - String origSampId = TseReportService.getOrigSampIdFrom(row); - String hashes = ""; for (SummarizedInfo si : summInfos) { hashes += TseReportService.getOrigSampIdFrom(si) + "\n"; @@ -169,7 +150,6 @@ private void importCasesAndResults(TseReport report1, Collection datas + row + ". Available aggregated data are: " + summInfos + "with hashes" + hashes, 0); } - } // import the case @@ -177,7 +157,6 @@ private void importCasesAndResults(TseReport report1, Collection datas // import the result TableRow result = importResult(report1, summInfo, caseInfo, row); - LOGGER.info("Imported analytical result with database id=" + result.getDatabaseId()); } } @@ -192,22 +171,17 @@ private void importCasesAndResults(TseReport report1, Collection datas * @throws FormulaException * @throws ParseException */ - private TableRow importCase(TseReport report1, SummarizedInfo summInfo, TableRow row) - throws FormulaException, ParseException { - + private TableRow importCase(TseReport report1, SummarizedInfo summInfo, TableRow row) throws FormulaException, ParseException { // extract the case from the row TableRow currentCaseInfo = extractCase(report1, summInfo, row); // import the case info if not already imported if (currentCaseInfo.getDatabaseId() == -1) { - // import case in the db daoService.add(currentCaseInfo); String sampId = currentCaseInfo.getLabel(CustomStrings.SAMPLE_ID_COL); - - LOGGER.info( - "Imported case/sample with database id=" + currentCaseInfo.getDatabaseId() + ", sampId=" + sampId); + LOGGER.info("Imported case/sample with database id=" + currentCaseInfo.getDatabaseId() + ", sampId=" + sampId); if (sampId == null) { LOGGER.error("No sample id was found for " + currentCaseInfo); @@ -231,9 +205,7 @@ private TableRow importCase(TseReport report1, SummarizedInfo summInfo, TableRow * @return * @throws ParseException */ - private TableRow importResult(TseReport report1, SummarizedInfo summInfo, TableRow caseInfo, TableRow row) - throws ParseException { - + private TableRow importResult(TseReport report1, SummarizedInfo summInfo, TableRow caseInfo, TableRow row) throws ParseException { // then import the analytical result TableRow result = extractAnalyticalResult(report1, summInfo, caseInfo, row); LOGGER.info("Analytical Results to be imported: ", result); @@ -253,33 +225,26 @@ private TableRow importResult(TseReport report1, SummarizedInfo summInfo, TableR * @throws FormulaException * @throws ParseException */ - private SummarizedInfo extractSummarizedInfo(TseReport report1, TableRow row, boolean isRGT) - throws FormulaException, ParseException { - + private SummarizedInfo extractSummarizedInfo(TseReport report1, TableRow row, boolean isRGT) throws ParseException { // set the summarized information schema row.setSchema(TableSchemaList.getByName(CustomStrings.SUMMARIZED_INFO_SHEET)); HashMap rowValues = new HashMap<>(); - TSEFormulaDecomposer decomposer = new TSEFormulaDecomposer(); - rowValues.putAll( - decomposer.decompose(CustomStrings.SAMP_MAT_CODE_COL, row.getCode(CustomStrings.SAMP_MAT_CODE_COL))); + rowValues.putAll(decomposer.decompose(CustomStrings.SAMP_MAT_CODE_COL, row.getCode(CustomStrings.SAMP_MAT_CODE_COL))); // extract psu id for cwd - rowValues.putAll( - decomposer.decompose(CustomStrings.SAMP_UNIT_IDS_COL, row.getCode(CustomStrings.SAMP_UNIT_IDS_COL))); + rowValues.putAll(decomposer.decompose(CustomStrings.SAMP_UNIT_IDS_COL, row.getCode(CustomStrings.SAMP_UNIT_IDS_COL))); // extract prog info rowValues.putAll(decomposer.decompose(CustomStrings.PROG_INFO_COL, row.getCode(CustomStrings.PROG_INFO_COL))); // extract the allele if RGT if (isRGT) - rowValues.putAll( - decomposer.decompose(CustomStrings.PARAM_CODE_COL, row.getCode(CustomStrings.PARAM_CODE_COL))); + rowValues.putAll(decomposer.decompose(CustomStrings.PARAM_CODE_COL, row.getCode(CustomStrings.PARAM_CODE_COL))); // copy values into the summarized information SummarizedInfo summInfo = new SummarizedInfo(row); - for (String key : rowValues.keySet()) { summInfo.put(key, rowValues.get(key)); } @@ -288,26 +253,13 @@ private SummarizedInfo extractSummarizedInfo(TseReport report1, TableRow row, bo Relation.injectParent(report1, summInfo); // add pref and settings as information - try { - Relation.injectGlobalParent(summInfo, CustomStrings.PREFERENCES_SHEET, daoService); - } catch (IOException e) { - LOGGER.error("Cannot inject global parent=" + CustomStrings.PREFERENCES_SHEET, e); - e.printStackTrace(); - } - - try { - Relation.injectGlobalParent(summInfo, CustomStrings.SETTINGS_SHEET, daoService); - } catch (IOException e) { - LOGGER.error("Cannot inject global parent=" + CustomStrings.SETTINGS_SHEET, e); - e.printStackTrace(); - } + Relation.injectGlobalParent(summInfo, CustomStrings.PREFERENCES_SHEET, daoService); + Relation.injectGlobalParent(summInfo, CustomStrings.SETTINGS_SHEET, daoService); // set also the summarized information type using // the species String type = summInfo.getTypeBySpecies(); - summInfo.setType(type); - return summInfo; } @@ -321,15 +273,12 @@ private SummarizedInfo extractSummarizedInfo(TseReport report1, TableRow row, bo * @throws FormulaException * @throws ParseException */ - private TableRow extractCase(TseReport report1, SummarizedInfo summInfo, TableRow row) - throws FormulaException, ParseException { - + private TableRow extractCase(TseReport report1, SummarizedInfo summInfo, TableRow row) throws ParseException { // set schema (required for next step), we are processing a result row, // even if we are extracting the case information data! row.setSchema(TableSchemaList.getByName(CustomStrings.RESULT_SHEET)); TableCell sampId = row.get(CustomStrings.SAMPLE_ID_COL); - if (sampId == null) { LOGGER.error("Missing sampId to extract from case row: ", row); throw new ParseException("Missing sampId", -1); @@ -340,14 +289,12 @@ private TableRow extractCase(TseReport report1, SummarizedInfo summInfo, TableRo // if not already added if (cases.get(sampId.getLabel()) == null) { - // create the case info (we do not copy the data, since this row // is actually an analytical result and we just need to // extract the relevant information) caseReport = new TableRow(TableSchemaList.getByName(CustomStrings.CASE_INFO_SHEET)); HashMap rowValues = new HashMap<>(); - TSEFormulaDecomposer decomposer = new TSEFormulaDecomposer(); // get decomposed values @@ -371,9 +318,7 @@ private TableRow extractCase(TseReport report1, SummarizedInfo summInfo, TableRo // save sample id rowValues.put(CustomStrings.SAMPLE_ID_COL, sampId); - rowValues.put(CustomStrings.SAMP_AREA_COL, row.get(CustomStrings.SAMP_AREA_COL)); - rowValues.put(CustomStrings.SAMP_DAY_COL, row.get(CustomStrings.SAMP_DAY_COL)); // store all the values into the case report @@ -385,11 +330,9 @@ private TableRow extractCase(TseReport report1, SummarizedInfo summInfo, TableRo Relation.injectParent(report1, caseReport); Relation.injectParent(summInfo, caseReport); } else { - // else if already present, get it from the cache caseReport = cases.get(sampId.getLabel()); } - return caseReport; } @@ -405,16 +348,12 @@ private TableRow extractCase(TseReport report1, SummarizedInfo summInfo, TableRo */ private static TableRow extractAnalyticalResult(TseReport report, SummarizedInfo summInfo, TableRow caseInfo, TableRow row) throws ParseException { - // set the summarised information schema row.setSchema(TableSchemaList.getByName(CustomStrings.RESULT_SHEET)); // decompose param code TSEFormulaDecomposer decomposer = new TSEFormulaDecomposer(); - - HashMap rowValues = decomposer.decompose(CustomStrings.PARAM_CODE_COL, - row.getCode(CustomStrings.PARAM_CODE_COL)); - + HashMap rowValues = decomposer.decompose(CustomStrings.PARAM_CODE_COL, row.getCode(CustomStrings.PARAM_CODE_COL)); rowValues.putAll(decomposer.decompose(CustomStrings.SAMP_INFO_COL, row.getCode(CustomStrings.SAMP_INFO_COL))); // save also the test aim with base term and test result @@ -424,7 +363,6 @@ private static TableRow extractAnalyticalResult(TseReport report, SummarizedInfo row.put(CustomStrings.PARAM_CODE_BASE_TERM_COL, paramBaseTerm); String resQualValue = row.getCode(CustomStrings.RES_QUAL_VALUE_COL); - // only if we have the test result put also the test aim if (!resQualValue.isEmpty()) { String testAim = paramBaseTerm + "$" + resQualValue; @@ -449,16 +387,13 @@ private static TableRow extractAnalyticalResult(TseReport report, SummarizedInfo * Given a prog id of an analytical result, get the summarized information which * is related to it * - * @param progId + * @param resultOrigSampId * @return * @throws FormulaException */ private SummarizedInfo getSummInfoByOrigSampId(String resultOrigSampId) throws FormulaException { - for (SummarizedInfo info : summInfos) { - String sampId = reportService.getSampId(info); - if (sampId.equals(resultOrigSampId)) { return info; } @@ -469,18 +404,15 @@ private SummarizedInfo getSummInfoByOrigSampId(String resultOrigSampId) throws F @Override public TableRow importDatasetMetadata(Dataset dataset) { - // extract the information from the dataset // and insert the report into the database this.mainReport = reportService.reportFromDataset(dataset); daoService.add(mainReport); - return this.mainReport; } @Override public void importDatasetRows(List rows) throws FormulaException, ParseException { - LOGGER.info("Importing the summarized information: ", rows); // first import the summarized information diff --git a/src/main/java/tse_analytical_result/ResultDialog.java b/src/main/java/tse_analytical_result/ResultDialog.java index 72043ba..d13f393 100644 --- a/src/main/java/tse_analytical_result/ResultDialog.java +++ b/src/main/java/tse_analytical_result/ResultDialog.java @@ -14,8 +14,6 @@ import dataset.RCLDatasetStatus; import global_utils.Warnings; import i18n_messages.TSEMessages; -import predefined_results.PredefinedResult; -import predefined_results.PredefinedResultHeader; import providers.IFormulaService; import providers.ITableDaoService; import providers.PredefinedResultService; @@ -23,10 +21,8 @@ import report.Report; import session_manager.TSERestoreableWindowDao; import table_dialog.DialogBuilder; -import table_dialog.EditorListener; import table_dialog.RowValidatorLabelProvider; import table_relations.Relation; -import table_skeleton.TableColumn; import table_skeleton.TableRow; import table_skeleton.TableRowList; import tse_case_report.CaseReport; @@ -49,15 +45,14 @@ public class ResultDialog extends TableDialogWithMenu { static final Logger LOGGER = LogManager.getLogger(ResultDialog.class); - - private RestoreableWindow window; private static final String WINDOW_CODE = "AnalyticalResult"; - private TseReportService reportService; - private ITableDaoService daoService; - private Report report; - private SummarizedInfo summInfo; - private CaseReport caseInfo; + private final TseReportService reportService; + private final ITableDaoService daoService; + + private final Report report; + private final SummarizedInfo summInfo; + private final CaseReport caseInfo; public ResultDialog(Shell parent, Report report, SummarizedInfo summInfo, CaseReport caseInfo, TseReportService reportService, ITableDaoService daoService, IFormulaService formulaService) { @@ -72,7 +67,7 @@ public ResultDialog(Shell parent, Report report, SummarizedInfo summInfo, CaseRe // create the dialog super.create(); - this.window = new RestoreableWindow(getDialog(), WINDOW_CODE); + RestoreableWindow window = new RestoreableWindow(getDialog(), WINDOW_CODE); boolean restored = window.restore(TSERestoreableWindowDao.class); window.saveOnClosure(TSERestoreableWindowDao.class); @@ -80,88 +75,38 @@ public ResultDialog(Shell parent, Report report, SummarizedInfo summInfo, CaseRe if (!restored) addHeight(300); - setEditorListener(new EditorListener() { - - @Override - public void editStarted() { - } - - @Override - public void editEnded(TableRow row, TableColumn field, boolean changed) { - - // if a change is made on the row - if (changed) { - - // reset the testaim and the anmethcode if anmethtype is changed - if (field.getId().equals(CustomStrings.AN_METH_TYPE_COL)) { - row.Initialise(CustomStrings.TEST_AIM_COL); - row.Initialise(CustomStrings.AN_METH_CODE_COL); - } - - // update the baseterm and the result value if testaim changes - if (field.getId().equals(CustomStrings.TEST_AIM_COL) - || field.getId().equals(CustomStrings.AN_METH_CODE_COL)) { - - // if genotyping set base term - if (row.getCode(CustomStrings.AN_METH_CODE_COL).equals(CustomStrings.AN_METH_CODE_GENOTYPING) - && !summInfo.getCode(CustomStrings.SUMMARIZED_INFO_TYPE) - .equals(CustomStrings.SUMMARIZED_INFO_BSEOS_TYPE)) { - - try { - PredefinedResultService r = new PredefinedResultService(daoService, formulaService); - PredefinedResult predRes = r.getPredefinedResult(summInfo, caseInfo); - - row.put(CustomStrings.PARAM_CODE_BASE_TERM_COL, - predRes.get(PredefinedResultHeader.GENOTYPING_BASE_TERM)); - - } catch (IOException e) { - LOGGER.error("Cannot fill results field=" + CustomStrings.PARAM_CODE_BASE_TERM_COL - + " using the predefined results", e); - } - } else if (!row.getCode(CustomStrings.TEST_AIM_COL).isEmpty()) - PredefinedResultService.addParamAndResult(row, row.getCode(CustomStrings.TEST_AIM_COL)); - } - } - } - }); + PredefinedResultService resultService = new PredefinedResultService(daoService, formulaService); + setEditorListener(new ResultEditorListener(resultService, summInfo, caseInfo)); updateUI(); } public void askForDefault() { - - // create default if no results are present - if (!reportService.hasChildren(caseInfo, TableSchemaList.getByName(CustomStrings.RESULT_SHEET)) && isEditable() - && !this.summInfo.isBSEOS()) { - + boolean hasNoChildren = !reportService.hasChildren(caseInfo, TableSchemaList.getByName(CustomStrings.RESULT_SHEET)); + if (isEditable() && hasNoChildren) { // for RGT create directly the record if (!this.summInfo.isRGT()) { - int val = Warnings.warnUser(getDialog(), TSEMessages.get("warning.title"), - TSEMessages.get("result.confirm.default"), SWT.YES | SWT.NO | SWT.ICON_QUESTION); - - LOGGER.info("Add default results to the list? " + (val == SWT.YES)); - + int val = Warnings.warnUser( + getDialog(), + TSEMessages.get("warning.title"), + TSEMessages.get("result.confirm.default"), + SWT.YES | SWT.NO | SWT.ICON_QUESTION + ); + LOGGER.info("Add default results to the list? {}", (val == SWT.YES)); if (val == SWT.NO) return; } try { - TableRowList results = reportService.createDefaultResults(report, summInfo, caseInfo); this.setRows(results); - // warn user only if not RGT if (!this.summInfo.isRGT()) { - warnUser(TSEMessages.get("warning.title"), TSEMessages.get("result.check.default"), - SWT.ICON_WARNING); + warnUser(TSEMessages.get("warning.title"), TSEMessages.get("result.check.default"), SWT.ICON_WARNING); } - - LOGGER.info("Default results created: ", results); - + LOGGER.info("Created {} default results for case {}", results.size(), caseInfo.getDatabaseId()); } catch (IOException e) { - LOGGER.error("Cannot create predefined results for case with sampId=" - + caseInfo.getCode(CustomStrings.SAMPLE_ID_COL), e); - e.printStackTrace(); + LOGGER.error("Cannot create predefined results for caseId {} {}", caseInfo.getDatabaseId(), e); } } } @@ -170,9 +115,7 @@ public void askForDefault() { * make table non editable if needed */ private void updateUI() { - LOGGER.info("Updating GUI"); - DialogBuilder panel = getPanelBuilder(); String status = report.getLabel(AppPaths.REPORT_STATUS); RCLDatasetStatus datasetStatus = RCLDatasetStatus.fromString(status); @@ -191,12 +134,8 @@ private void updateUI() { @Override public TableRow createNewRow(TableSchema schema, Selection element) { TableRow row = new TableRow(schema); - - Relation.injectParent(report, row); - Relation.injectParent(summInfo, row); - Relation.injectParent(caseInfo, row); - - LOGGER.info("Creating a new row: ", row); + Relation.injectParents(row, report, summInfo, caseInfo); + LOGGER.info("Creating a new row for analytical results: {}", row.getDatabaseId()); return row; } @@ -217,29 +156,22 @@ public Collection loadInitialRows(TableSchema schema, TableRow parentF @Override public void processNewRow(TableRow row) { - TableRowList results = this.getRows(); - if (results.size() <= 1) return; int max = Integer.MIN_VALUE; - for (TableRow result : results) { - if (result.getDatabaseId() == row.getDatabaseId()) continue; String seq = result.getLabel(CustomStrings.AN_PORT_SEQ_COL); - - int candidateMax; - + int candidateMax = 0; try { - candidateMax = Integer.valueOf(seq); + candidateMax = Integer.parseInt(seq); } catch (NumberFormatException e) { LOGGER.error("Trying to parse new row but could not get integer value from seq ", e); e.printStackTrace(); - candidateMax = 0; } if (candidateMax > max) @@ -271,7 +203,6 @@ public Menu createMenu() { @Override public void addWidgets(DialogBuilder viewer) { - String sampleId = caseInfo.getLabel(CustomStrings.SAMPLE_ID_COL); String animalId = caseInfo.getLabel(CustomStrings.ANIMAL_ID_COL); String caseId = caseInfo.getLabel(CustomStrings.NATIONAL_CASE_ID_COL); @@ -284,15 +215,16 @@ public void addWidgets(DialogBuilder viewer) { .addComposite("labelsComp", new GridLayout(1, false), null); if (!sampleId.isEmpty()) - viewer.addLabelToComposite("sampLabel", sampleIdRow.toString(), "labelsComp"); + viewer.addLabelToComposite("sampLabel", sampleIdRow, "labelsComp"); if (!animalId.isEmpty()) - viewer.addLabelToComposite("animalLabel", animalIdRow.toString(), "labelsComp"); + viewer.addLabelToComposite("animalLabel", animalIdRow, "labelsComp"); if (!caseId.isEmpty()) - viewer.addLabelToComposite("caseIdLabel", caseIdRow.toString(), "labelsComp"); + viewer.addLabelToComposite("caseIdLabel", caseIdRow, "labelsComp"); viewer.addRowCreator(TSEMessages.get("result.add.record")) .addTable(CustomStrings.RESULT_SHEET, true, report, summInfo, caseInfo); } + } diff --git a/src/main/java/tse_analytical_result/ResultEditorListener.java b/src/main/java/tse_analytical_result/ResultEditorListener.java new file mode 100644 index 0000000..a0e879a --- /dev/null +++ b/src/main/java/tse_analytical_result/ResultEditorListener.java @@ -0,0 +1,55 @@ +package tse_analytical_result; + +import predefined_results.PredefinedResult; +import predefined_results.PredefinedResultHeader; +import providers.PredefinedResultService; +import table_dialog.EditorListener; +import table_skeleton.TableColumn; +import table_skeleton.TableRow; +import tse_case_report.CaseReport; +import tse_config.CustomStrings; +import tse_summarized_information.SummarizedInfo; + +class ResultEditorListener implements EditorListener { + + private final PredefinedResultService resultService; + + private final SummarizedInfo summInfo; + private final CaseReport caseInfo; + + public ResultEditorListener(PredefinedResultService resultService, SummarizedInfo summInfo, CaseReport caseInfo) { + this.summInfo = summInfo; + this.resultService = resultService; + this.caseInfo = caseInfo; + } + + @Override + public void editStarted() { + } + + @Override + public void editEnded(TableRow row, TableColumn field, boolean changed) { + if (changed) { + // reset the testaim and the anmethcode if anmethtype is changed + String fieldId = field.getId(); + if (fieldId.equals(CustomStrings.AN_METH_TYPE_COL)) { + row.Initialise(CustomStrings.TEST_AIM_COL); + row.Initialise(CustomStrings.AN_METH_CODE_COL); + } + + // update the baseterm and the result value if testaim changes + if (fieldId.equals(CustomStrings.TEST_AIM_COL) || fieldId.equals(CustomStrings.AN_METH_CODE_COL)) { + + // if genotyping set base term + if (row.getCode(CustomStrings.AN_METH_CODE_COL).equals(CustomStrings.AN_METH_CODE_GENOTYPING) + && !summInfo.getCode(CustomStrings.SUMMARIZED_INFO_TYPE).equals(CustomStrings.SUMMARIZED_INFO_BSEOS_TYPE)) { + + PredefinedResult predRes = resultService.getPredefinedResult(summInfo, caseInfo); + row.put(CustomStrings.PARAM_CODE_BASE_TERM_COL, predRes.get(PredefinedResultHeader.GENOTYPING_BASE_TERM)); + + } else if (!row.getCode(CustomStrings.TEST_AIM_COL).isEmpty()) + PredefinedResultService.addParamAndResult(row, row.getCode(CustomStrings.TEST_AIM_COL)); + } + } + } +} diff --git a/src/main/java/tse_case_report/CaseReportDialog.java b/src/main/java/tse_case_report/CaseReportDialog.java index dec2141..1746641 100644 --- a/src/main/java/tse_case_report/CaseReportDialog.java +++ b/src/main/java/tse_case_report/CaseReportDialog.java @@ -5,8 +5,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; @@ -40,6 +38,8 @@ import xlsx_reader.TableSchemaList; import xml_catalog_reader.Selection; +import static org.eclipse.swt.SWT.ICON_INFORMATION; + /** * Dialog which shows cases report related to a summarized information parent * @@ -48,10 +48,8 @@ * */ public class CaseReportDialog extends TableDialogWithMenu { - static final Logger LOGGER = LogManager.getLogger(CaseReportDialog.class); - private RestoreableWindow window; private static final String WINDOW_CODE = "CaseReport"; protected Report report; @@ -63,7 +61,6 @@ public class CaseReportDialog extends TableDialogWithMenu { public CaseReportDialog(Shell parent, Report report, SummarizedInfo summInfo, TseReportService reportService, ITableDaoService daoService, IFormulaService formulaService) { - super(parent, TSEMessages.get("case.title"), true, false); LOGGER.info("Opening case report dialog"); @@ -74,24 +71,20 @@ public CaseReportDialog(Shell parent, Report report, SummarizedInfo summInfo, Ts this.formulaService = formulaService; LOGGER.info("Creating dialog structure and contents"); - // create the parent structure super.create(); LOGGER.info("Saving window preferences"); - this.window = new RestoreableWindow(getDialog(), WINDOW_CODE); + RestoreableWindow window = new RestoreableWindow(getDialog(), WINDOW_CODE); boolean restored = window.restore(TSERestoreableWindowDao.class); window.saveOnClosure(TSERestoreableWindowDao.class); - // add 300 px in height if (!restored) addHeight(300); LOGGER.info("Updating UI"); - // update the ui updateUI(); LOGGER.info("Ask for default values"); - // ask for default values askForDefault(); setEditorListener(new EditorListener() { @@ -110,40 +103,30 @@ public void editEnded(TableRow row, TableColumn field, boolean changed) { } public void askForDefault() { - boolean isRGT = summInfo.isRGT(); - boolean hasExpectedCases = !isRGT // cannot compute expected cases for RGT - && getNumberOfExpectedCases(summInfo) > 0; - - boolean canAsk = isEditable() && !summInfo.isBSEOS() - && !reportService.hasChildren(summInfo, TableSchemaList.getByName(CustomStrings.CASE_INFO_SHEET)) - && (hasExpectedCases || isRGT); + boolean hasExpectedCases = getNumberOfExpectedCases(summInfo) > 0; + boolean hasChildren = reportService.hasChildren(summInfo, TableSchemaList.getByName(CustomStrings.CASE_INFO_SHEET)); + boolean canAsk = isEditable() && !hasChildren && (hasExpectedCases || isRGT); LOGGER.debug("Can ask for default = " + canAsk); // create default cases if no cases // and cases were set in the aggregated data if (canAsk) { - if (!isRGT) { LOGGER.debug("Warn user"); - - Warnings.warnUser(getDialog(), TSEMessages.get("warning.title"), TSEMessages.get("case.check.default"), - SWT.ICON_INFORMATION); - + Warnings.warnUser(getDialog(), TSEMessages.get("warning.title"), TSEMessages.get("case.check.default"), ICON_INFORMATION); LOGGER.debug("End warn user"); } - if (hasExpectedCases) { - try { + try { + if (hasExpectedCases) { reportService.createDefaultCases(report, summInfo); - } catch (IOException e) { - LOGGER.error("Cannot create default cases in summarized info with progId=" + summInfo.getProgId(), - e); - e.printStackTrace(); + } else if (isRGT) { + reportService.createDefaultRGTCase(report, summInfo); } - } else if (isRGT) { - reportService.createDefaultRGTCase(report, summInfo); + } catch (IOException e) { + LOGGER.error("Cannot create default cases in summarized info with progId={} {}", summInfo.getProgId(), e); } } } @@ -155,32 +138,20 @@ public void askForDefault() { * @return */ private static int getNumberOfExpectedCases(TableRow summInfo) { - int positive = summInfo.getNumLabel(CustomStrings.TOT_SAMPLE_POSITIVE_COL); int inconclusive = summInfo.getNumLabel(CustomStrings.TOT_SAMPLE_INCONCLUSIVE_COL); int total = positive + inconclusive; - - LOGGER.info("Number of expected cases in current row ", total); + LOGGER.info("Number of expected cases in current row {}", total); return total; } @Override public Menu createMenu() { - Menu menu = super.createMenu(); MenuItem openResults = new MenuItem(menu, SWT.PUSH); openResults.setText(TSEMessages.get("case.open.results")); openResults.setEnabled(false); - - addTableSelectionListener(new ISelectionChangedListener() { - - @Override - public void selectionChanged(SelectionChangedEvent arg0) { - openResults.setEnabled(!isTableEmpty()); - } - }); - openResults.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { @@ -188,6 +159,8 @@ public void widgetSelected(SelectionEvent arg0) { } }); + addTableSelectionListener(arg0 -> openResults.setEnabled(!isTableEmpty())); + addRemoveMenuItem(menu); // addCloneMenuItem(menu); @@ -218,14 +191,9 @@ private void updateUI() { */ @Override public TableRow createNewRow(TableSchema schema, Selection element) { - - // return the new row TableRow caseRow = new TableRow(schema); - - // add parents Relation.injectParent(report, caseRow); Relation.injectParent(summInfo, caseRow); - return caseRow; } @@ -255,7 +223,6 @@ public RowValidatorLabelProvider getValidator() { @Override public void addWidgets(DialogBuilder viewer) { - String reportMonth = report.getLabel(AppPaths.REPORT_MONTH_COL); String reportYear = report.getLabel(AppPaths.REPORT_YEAR_COL); String source = summInfo.getLabel(CustomStrings.SOURCE_COL); @@ -296,35 +263,28 @@ public void addWidgets(DialogBuilder viewer) { if (summInfo.getType().equals(CustomStrings.SUMMARIZED_INFO_CWD_TYPE)) viewer.addLabelToComposite("sexLabel", sexRow, "labelsComp"); - viewer.addRowCreator(TSEMessages.get("case.add.record")).addTable(CustomStrings.CASE_INFO_SHEET, true, report, - summInfo); + viewer.addRowCreator(TSEMessages.get("case.add.record")).addTable(CustomStrings.CASE_INFO_SHEET, true, report, summInfo); } @Override public void nextLevel() { - TableRow row = getSelection(); - if (row == null) { LOGGER.info("There are no other rows in table"); return; } Relation.emptyCache(); - CaseReport caseReport = new CaseReport(row); - if (!caseReport.areMandatoryFilled() && report.isEditable()) { warnUser(TSEMessages.get("error.title"), TSEMessages.get("case.open.results.error")); return; } LOGGER.info("Opening result dialog"); - // Initialise result passing also the // report data and the summarized information data - ResultDialog dialog = new ResultDialog(getParent(), report, summInfo, caseReport, reportService, daoService, - formulaService); + ResultDialog dialog = new ResultDialog(getParent(), report, summInfo, caseReport, reportService, daoService, formulaService); dialog.setParentFilter(caseReport); // set the case as filter (and parent) dialog.askForDefault(); dialog.open(); @@ -332,6 +292,5 @@ public void nextLevel() { // update children errors reportService.updateChildrenErrors(caseReport); replace(caseReport); - } } diff --git a/src/main/java/tse_config/CustomStrings.java b/src/main/java/tse_config/CustomStrings.java index 3dc62a0..5bd35ab 100644 --- a/src/main/java/tse_config/CustomStrings.java +++ b/src/main/java/tse_config/CustomStrings.java @@ -12,7 +12,8 @@ public class CustomStrings { public static final String CASE_ID_COL = "CasesInformationId"; public static final String SETTINGS_ID_COL = "SettingsId"; public static final String PREFERENCES_ID_COL = "PreferencesId"; - + public static final String ANALYTICAL_RESULT_ID_COL = "AnalyticalResultsId"; + // sheets names public static final String RESULT_SHEET = "AnalyticalResults"; public static final String CASE_INFO_SHEET = "CasesInformation"; @@ -27,6 +28,8 @@ public class CustomStrings { public static final String SETTINGS_ORG_CODE = "orgCode"; public static final String REPORT_COUNTRY = "country"; + public static final String REPORT_MONTH = "reportMonth"; + public static final String REPORT_YEAR = "reportYear"; public static final String CWD_EXTENDED_CONTEXT = "cwdExtCont"; public static final String PREFERENCES_COUNTRY = "country"; @@ -34,15 +37,18 @@ public class CustomStrings { public static final String PREFERENCES_SCREENING_BSE = "defScreeningBSE"; public static final String PREFERENCES_SCREENING_SCRAPIE = "defScreeningSCRAPIE"; public static final String PREFERENCES_SCREENING_CWD = "defScreeningCWD"; - + public static final String PREFERENCES_SCREENING_BSE_OS = "defScreeningBSEOS"; + public static final String PREFERENCES_CONFIRMATORY_BSE = "defConfirmatoryBSE"; public static final String PREFERENCES_CONFIRMATORY_SCRAPIE = "defConfirmatorySCRAPIE"; public static final String PREFERENCES_CONFIRMATORY_CWD = "defConfirmatoryCWD"; - + public static final String PREFERENCES_CONFIRMATORY_BSE_OS = "defConfirmatoryBSEOS"; + public static final String PREFERENCES_DISCRIMINATORY_BSE = "defDiscriminatoryBSE"; public static final String PREFERENCES_DISCRIMINATORY_SCRAPIE = "defDiscriminatorySCRAPIE"; public static final String PREFERENCES_DISCRIMINATORY_CWD = "defDiscriminatoryCWD"; - + public static final String PREFERENCES_DISCRIMINATORY_BSE_OS = "defDiscriminatoryBSEOS"; + public static final String SUMMARIZED_INFO_TYPE = "type"; public static final String SOURCE_COL = "source"; public static final String PART_COL = "part"; @@ -133,6 +139,7 @@ public class CustomStrings { public static final String TEST_AIM_COL = "testAim"; public static final String AN_METH_CODE_COL = "anMethCode"; public static final String AN_METH_CODE_GENOTYPING = "F089A"; + public static final String AN_METH_CODE_GENOTYPING_TYPE = "Genotyping"; public static final String PARAM_TYPE_COL = "paramType"; public static final String PARAM_CODE_BASE_TERM_COL = "paramCodeBaseTerm"; diff --git a/src/main/java/tse_main/MainMenu.java b/src/main/java/tse_main/MainMenu.java index 7746410..0238d5f 100644 --- a/src/main/java/tse_main/MainMenu.java +++ b/src/main/java/tse_main/MainMenu.java @@ -12,8 +12,6 @@ import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.MessageBox; @@ -43,6 +41,7 @@ import test_case.EnumPicker; import tse_config.CustomStrings; import tse_config.DebugConfig; +import tse_main.listeners.CopySelectionListener; import tse_options.PreferencesDialog; import tse_options.SettingsDialog; import tse_report.ReportCreatorDialog; @@ -60,7 +59,6 @@ * */ public class MainMenu { - static final Logger LOGGER = LogManager.getLogger(MainMenu.class); protected TseReportService reportService; @@ -82,6 +80,7 @@ public class MainMenu { protected MenuItem openReport; protected MenuItem closeReport; protected MenuItem importReport; + protected MenuItem copyReport; protected MenuItem downloadReport; protected MenuItem exportReport; protected MenuItem exitApplication; @@ -99,65 +98,56 @@ public MainMenu(MainPanel mainPanel, Shell shell, TseReportService reportService } public void create() { + main = new Menu(shell, SWT.BAR); + fileMenu = new Menu(shell, SWT.DROP_DOWN); + + file = new MenuItem(main, SWT.CASCADE); + file.setText(TSEMessages.get("file.item")); + file.setMenu(fileMenu); + + // enable report only if there is a report in the database + fileMenu.addListener(SWT.Show, arg0 -> { + TableSchema schema = TseReport.getReportSchema(); + if (schema == null) { + LOGGER.info("Schema was not found in report."); + return; + } - // create menus - this.main = new Menu(shell, SWT.BAR); - this.fileMenu = new Menu(shell, SWT.DROP_DOWN); - - this.file = new MenuItem(main, SWT.CASCADE); - this.file.setText(TSEMessages.get("file.item")); - this.file.setMenu(fileMenu); - - this.fileMenu.addListener(SWT.Show, new Listener() { - - @Override - public void handleEvent(Event arg0) { - - // enable report only if there is a report in the database - - TableSchema schema = TseReport.getReportSchema(); - - if (schema == null) { - LOGGER.info("Schema was not found in report."); - return; - } - - TableDao dao = new TableDao(); - - boolean hasReport = !dao.getAll(schema).isEmpty(); - boolean isReportOpened = mainPanel.getOpenedReport() != null; - boolean editable = isReportOpened && mainPanel.getOpenedReport().isEditable(); + TableDao dao = new TableDao(); + boolean hasReport = !dao.getAll(schema).isEmpty(); + boolean isReportOpened = mainPanel.getOpenedReport() != null; + boolean editable = isReportOpened && mainPanel.getOpenedReport().isEditable(); - newReport.setEnabled(!isReportOpened); - openReport.setEnabled(hasReport); - closeReport.setEnabled(isReportOpened); - downloadReport.setEnabled(!DebugConfig.disableFileFuncs && !isReportOpened); + newReport.setEnabled(!isReportOpened); + openReport.setEnabled(hasReport); + closeReport.setEnabled(isReportOpened); + downloadReport.setEnabled(!DebugConfig.disableFileFuncs && !isReportOpened); - // can only export valid reports - exportReport.setEnabled(isReportOpened && mainPanel.getOpenedReport().getRCLStatus().isValid()); - importReport.setEnabled(!DebugConfig.disableFileFuncs && editable); + // can only export valid reports + exportReport.setEnabled(isReportOpened && mainPanel.getOpenedReport().getRCLStatus().isValid()); + importReport.setEnabled(!DebugConfig.disableFileFuncs && editable); + copyReport.setEnabled(isReportOpened && editable); - // TODO enable import excel report if not report is currently opened - // importExcelReport.setEnabled(editable); - } + // TODO enable import excel report if not report is currently opened + // importExcelReport.setEnabled(editable); }); - this.preferences = new MenuItem(main, SWT.PUSH); - this.preferences.setText(TSEMessages.get("pref.item")); + preferences = new MenuItem(main, SWT.PUSH); + preferences.setText(TSEMessages.get("pref.item")); - this.settings = new MenuItem(main, SWT.PUSH); - this.settings.setText(TSEMessages.get("settings.item")); + settings = new MenuItem(main, SWT.PUSH); + settings.setText(TSEMessages.get("settings.item")); - this.proxyConfig = new MenuItem(main, SWT.PUSH); - this.proxyConfig.setText(TSEMessages.get("proxy.config.item")); + proxyConfig = new MenuItem(main, SWT.PUSH); + proxyConfig.setText(TSEMessages.get("proxy.config.item")); - this.proxyConfig.addSelectionListener(new SelectionAdapter() { + proxyConfig.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { ProxySettingsDialog dialog = new ProxySettingsDialog(shell, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL); try { dialog.open(); - } catch (IOException e) { + } catch (Exception e) { LOGGER.error("Cannot open proxy dialog", e); e.printStackTrace(); @@ -170,11 +160,9 @@ public void widgetSelected(SelectionEvent arg0) { }); // add buttons to the file menu - this.newReport = new MenuItem(fileMenu, SWT.PUSH); - this.newReport.setText(TSEMessages.get("new.report.item")); - - this.newReport.addSelectionListener(new SelectionListener() { - + newReport = new MenuItem(fileMenu, SWT.PUSH); + newReport.setText(TSEMessages.get("new.report.item")); + newReport.addSelectionListener(new SelectionListener() { @Override public void widgetSelected(SelectionEvent arg0) { @@ -190,36 +178,26 @@ public void widgetDefaultSelected(SelectionEvent arg0) { } }); - this.openReport = new MenuItem(fileMenu, SWT.PUSH); - this.openReport.setText(TSEMessages.get("open.report.item")); - - this.openReport.addSelectionListener(new SelectionListener() { - + openReport = new MenuItem(fileMenu, SWT.PUSH); + openReport.setText(TSEMessages.get("open.report.item")); + openReport.addSelectionListener(new SelectionListener() { @Override public void widgetSelected(SelectionEvent arg0) { - LOGGER.debug("Opening open report dialog"); - ReportListDialog dialog = new ReportListDialog(shell, TSEMessages.get("open.report.title")); dialog.setButtonText(TSEMessages.get("open.report.button")); - dialog.open(); TseReport report = dialog.getSelectedReport(); - if (report == null){ LOGGER.info("There is no report to continue"); return; } - LOGGER.info("Opening report=" + report.getSenderId()); mainPanel.setEnabled(true); - shell.setCursor(shell.getDisplay().getSystemCursor(SWT.CURSOR_WAIT)); - mainPanel.openReport(report); - shell.setCursor(shell.getDisplay().getSystemCursor(SWT.CURSOR_ARROW)); } @@ -228,16 +206,12 @@ public void widgetDefaultSelected(SelectionEvent arg0) { } }); - this.closeReport = new MenuItem(fileMenu, SWT.PUSH); - this.closeReport.setText(TSEMessages.get("close.report.item")); - - this.closeReport.addSelectionListener(new SelectionListener() { - + closeReport = new MenuItem(fileMenu, SWT.PUSH); + closeReport.setText(TSEMessages.get("close.report.item")); + closeReport.addSelectionListener(new SelectionListener() { @Override public void widgetSelected(SelectionEvent arg0) { - - LOGGER.info("Closing report=" + mainPanel.getOpenedReport().getSenderId()); - + LOGGER.info("Closing report={}", mainPanel.getOpenedReport().getSenderId()); mainPanel.closeReport(); } @@ -247,19 +221,16 @@ public void widgetDefaultSelected(SelectionEvent arg0) { }); // by default we do not have a report opened at the beginning - this.closeReport.setEnabled(false); + closeReport.setEnabled(false); // add buttons to the file menu - this.importReport = new MenuItem(fileMenu, SWT.PUSH); - this.importReport.setText(TSEMessages.get("import.report.item")); - this.importReport.setEnabled(false); - this.importReport.addSelectionListener(new SelectionListener() { - + importReport = new MenuItem(fileMenu, SWT.PUSH); + importReport.setText(TSEMessages.get("import.report.item")); + importReport.setEnabled(false); + importReport.addSelectionListener(new SelectionListener() { @Override public void widgetSelected(SelectionEvent arg0) { - LOGGER.debug("Opening import report dialog"); - ReportListDialog dialog = new ReportListDialog(shell, TSEMessages.get("import.report.title")); dialog.setButtonText(TSEMessages.get("import.report.button")); dialog.open(); @@ -275,7 +246,6 @@ public void widgetSelected(SelectionEvent arg0) { // import the report into the opened report TableRow report = dialog.getSelectedReport(); - if (report == null){ LOGGER.info("There is no report to continue"); return; @@ -283,7 +253,6 @@ public void widgetSelected(SelectionEvent arg0) { // copy the report summarized information into the opened one TableSchema childSchema = TableSchemaList.getByName(CustomStrings.SUMMARIZED_INFO_SHEET); - if (childSchema == null) { LOGGER.info("Could not find schema"); return; @@ -292,16 +261,12 @@ public void widgetSelected(SelectionEvent arg0) { LOGGER.info("Importing summarized information from report=" + report.getCode(CustomStrings.SENDER_DATASET_ID_COL) + " to report=" + mainPanel.getOpenedReport().getSenderId()); - shell.setCursor(shell.getDisplay().getSystemCursor(SWT.CURSOR_WAIT)); - TseSummarizedInfoImporter importer = new TseSummarizedInfoImporter(daoService, formulaService); - // copy the data into the selected report importer.copyByParent(childSchema, report, mainPanel.getOpenedReport()); mainPanel.refresh(); - shell.setCursor(shell.getDisplay().getSystemCursor(SWT.CURSOR_ARROW)); } @@ -310,6 +275,12 @@ public void widgetDefaultSelected(SelectionEvent arg0) { } }); + // add Copy Report button to the file menu + copyReport = new MenuItem(fileMenu, SWT.PUSH); + copyReport.setText(TSEMessages.get("copy.report.item")); + copyReport.setEnabled(false); + copyReport.addSelectionListener(new CopySelectionListener(reportService, mainPanel, shell)); + /* * TODO to be concluded the import excel function * @@ -366,14 +337,12 @@ public void widgetDefaultSelected(SelectionEvent arg0) { * } }); */ - this.downloadReport = new MenuItem(fileMenu, SWT.PUSH); - this.downloadReport.setText(TSEMessages.get("download.report.item")); - this.downloadReport.addSelectionListener(new SelectionAdapter() { + downloadReport = new MenuItem(fileMenu, SWT.PUSH); + downloadReport.setText(TSEMessages.get("download.report.item")); + downloadReport.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { - LOGGER.debug("Opening download report dialog"); - TseReportDownloader downloader = new TseReportDownloader(shell, reportService, daoService); try { downloader.download(); @@ -385,17 +354,13 @@ public void widgetSelected(SelectionEvent arg0) { } }); - this.exportReport = new MenuItem(fileMenu, SWT.PUSH); + exportReport = new MenuItem(fileMenu, SWT.PUSH); exportReport.setText(TSEMessages.get("export.report.item")); exportReport.addSelectionListener(new SelectionListener() { - @Override public void widgetSelected(SelectionEvent arg0) { - LOGGER.debug("Opening export report dialog"); - TseReport report = mainPanel.getOpenedReport(); - if (report == null) { LOGGER.info("There is no report to continue"); Warnings.warnUser(shell, TSEMessages.get("error.title"), TSEMessages.get("report.noreport.error")); @@ -406,8 +371,7 @@ public void widgetSelected(SelectionEvent arg0) { TseFileDialog fileDialog = new TseFileDialog(shell); String filename = TableVersion.mergeNameAndVersion(report.getSenderId(), report.getVersion()); File exportFile = fileDialog.saveXml(filename); - - if (exportFile == null){ + if (exportFile == null) { LOGGER.info("Could not find file to export"); return; } @@ -475,25 +439,21 @@ public void widgetDefaultSelected(SelectionEvent arg0) { } }); - this.exitApplication = new MenuItem(fileMenu, SWT.PUSH); - this.exitApplication.setText(TSEMessages.get("close.app.item")); - this.exitApplication.addSelectionListener(new SelectionAdapter() { + exitApplication = new MenuItem(fileMenu, SWT.PUSH); + exitApplication.setText(TSEMessages.get("close.app.item")); + exitApplication.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { - shell.close(); shell.dispose(); } }); // open preferences - this.preferences.addSelectionListener(new SelectionListener() { - + preferences.addSelectionListener(new SelectionListener() { @Override public void widgetSelected(SelectionEvent arg0) { - LOGGER.debug("Opening preferences dialog"); - PreferencesDialog dialog = new PreferencesDialog(shell); dialog.open(); } @@ -504,13 +464,10 @@ public void widgetDefaultSelected(SelectionEvent arg0) { }); // open settings - this.settings.addSelectionListener(new SelectionListener() { - + settings.addSelectionListener(new SelectionListener() { @Override public void widgetSelected(SelectionEvent arg0) { - LOGGER.debug("Opening settings dialog"); - SettingsDialog dialog = new SettingsDialog(shell, reportService, daoService); dialog.open(); } @@ -525,30 +482,24 @@ public void widgetDefaultSelected(SelectionEvent arg0) { } // set the menu - this.shell.setMenuBar(main); + shell.setMenuBar(main); } /** * Add some debug functionalities */ private void addDebugItems() { - MenuItem reportVersions = new MenuItem(fileMenu, SWT.PUSH); reportVersions.setText("[DEBUG] Print report versions"); reportVersions.addSelectionListener(new SelectionListener() { - @Override public void widgetSelected(SelectionEvent arg0) { - LOGGER.debug("Opening 'Print report versions' dialog"); - TseReport report = mainPanel.getOpenedReport(); - if (report == null){ LOGGER.info("There is no report to continue"); return; } - LOGGER.debug("Report versions=" + report.getAllVersions(daoService)); } @@ -560,14 +511,10 @@ public void widgetDefaultSelected(SelectionEvent arg0) { MenuItem exportReport1 = new MenuItem(fileMenu, SWT.PUSH); exportReport1.setText("[DEBUG] Export report"); exportReport1.addSelectionListener(new SelectionListener() { - @Override public void widgetSelected(SelectionEvent arg0) { - LOGGER.debug("Opening 'Export report' dialog"); - TseReport report = mainPanel.getOpenedReport(); - if (report == null) { LOGGER.info("There is no report to continue"); Warnings.warnUser(shell, TSEMessages.get("error.title"), TSEMessages.get("report.noreport.error")); @@ -578,7 +525,6 @@ public void widgetSelected(SelectionEvent arg0) { dialog.open(); OperationType opType = (OperationType) dialog.getSelection(); - if (opType == null) { LOGGER.info("Operation Type not found"); return; @@ -604,25 +550,20 @@ public void widgetDefaultSelected(SelectionEvent arg0) { MenuItem deleteReport = new MenuItem(fileMenu, SWT.PUSH); deleteReport.setText("[DEBUG] Delete report"); deleteReport.addSelectionListener(new SelectionListener() { - @Override public void widgetSelected(SelectionEvent arg0) { - ReportListDialog dialog = new ReportListDialog(shell, "Delete a report"); dialog.setButtonText("Delete"); dialog.open(); - LOGGER.debug("Opening 'Delete report' dialog"); TseReport report = dialog.getSelectedReport(); - if (report == null) { LOGGER.info("There is no report to continue"); return; } LOGGER.debug("Report " + report.getSenderId() + " deleted from disk"); - report.delete(); } @@ -634,17 +575,13 @@ public void widgetDefaultSelected(SelectionEvent arg0) { MenuItem getDc = new MenuItem(fileMenu, SWT.PUSH); getDc.setText("[DEBUG] Print current data collection"); getDc.addSelectionListener(new SelectionListener() { - @Override public void widgetSelected(SelectionEvent arg0) { - LOGGER.debug("Opening 'Print current data collection' dialog"); - TseReport report = mainPanel.getOpenedReport(); - - String dcCode = report == null ? PropertiesReader.getDataCollectionCode() + String dcCode = report == null + ? PropertiesReader.getDataCollectionCode() : PropertiesReader.getDataCollectionCode(report.getYear()); - LOGGER.debug("The tool points to the data collection=" + dcCode); } @@ -658,13 +595,10 @@ public void widgetDefaultSelected(SelectionEvent arg0) { importReport1.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { - LOGGER.debug("Opening 'Import first version .xml report' dialog"); - TseFileDialog fileDialog = new TseFileDialog(shell); File file1 = fileDialog.loadXml(); - - if (file1 == null){ + if (file1 == null) { LOGGER.info("File not found to import"); return; } @@ -672,17 +606,11 @@ public void widgetSelected(SelectionEvent arg0) { try { TseReportImporter imp = new TseReportImporter(reportService, daoService); imp.importFirstDatasetVersion(file1); - } catch (XMLStreamException | IOException | FormulaException | ParseException e) { LOGGER.error("Import report failed", e); e.printStackTrace(); } } }); - - } - - public Menu getMenu() { - return main; } } diff --git a/src/main/java/tse_main/StartUI.java b/src/main/java/tse_main/StartUI.java index 182f8c0..0bafea0 100644 --- a/src/main/java/tse_main/StartUI.java +++ b/src/main/java/tse_main/StartUI.java @@ -240,7 +240,7 @@ private Database launch() { LOGGER.error("Old version of the database found", e); e.printStackTrace(); - int val = ask(TSEMessages.get("db.need.removal")); + int val = ask(TSEMessages.get("db.need.removal", PropertiesReader.getSupportEmail())); // close application if (val == SWT.NO) diff --git a/src/main/java/tse_main/listeners/CopySelectionListener.java b/src/main/java/tse_main/listeners/CopySelectionListener.java new file mode 100644 index 0000000..d74ab24 --- /dev/null +++ b/src/main/java/tse_main/listeners/CopySelectionListener.java @@ -0,0 +1,68 @@ +package tse_main.listeners; + +import i18n_messages.TSEMessages; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.swt.widgets.Shell; +import providers.TseReportService; +import table_skeleton.TableRow; +import tse_main.MainPanel; +import tse_report.ReportListDialog; +import tse_report.TseReport; + +import static org.eclipse.swt.SWT.*; +import static tse_config.CustomStrings.SENDER_DATASET_ID_COL; + +public class CopySelectionListener implements SelectionListener { + private static final Logger LOGGER = LogManager.getLogger(CopySelectionListener.class); + + private final TseReportService reportService; + private final MainPanel mainPanel; + private final Shell shell; + + public CopySelectionListener(TseReportService reportService, MainPanel mainPanel, Shell shell) { + this.reportService = reportService; + this.mainPanel = mainPanel; + this.shell = shell; + } + + @Override + public void widgetSelected(SelectionEvent event) { + ReportListDialog dialog = new ReportListDialog(shell, TSEMessages.get("copy.report.title")); + dialog.setButtonText(TSEMessages.get("copy.report.button")); + dialog.open(); + + // show dialog that the current report will be overwritten + MessageBox mb = new MessageBox(shell, ICON_QUESTION | OK | CANCEL); + mb.setText("My info"); + mb.setMessage(TSEMessages.get("copy.report.warning")); + + // if the user press cancel then return + if (mb.open() == CANCEL) + return; + + // copy the report into the opened report + TableRow sourceReport = dialog.getSelectedReport(); + if (sourceReport == null){ + LOGGER.info("There is no report to continue"); + return; + } + + TseReport currentReport = mainPanel.getOpenedReport(); + LOGGER.info("Copying report data from reportId={} to reportId={}", sourceReport.getCode(SENDER_DATASET_ID_COL), currentReport.getSenderId()); + reportService.copyReport(new TseReport(sourceReport), currentReport); + LOGGER.info("Copied report data from reportId={} to reportId={}", sourceReport.getCode(SENDER_DATASET_ID_COL), currentReport.getSenderId()); + + shell.setCursor(shell.getDisplay().getSystemCursor(CURSOR_WAIT)); + mainPanel.refresh(); + shell.setCursor(shell.getDisplay().getSystemCursor(CURSOR_ARROW)); + } + + @Override + public void widgetDefaultSelected(SelectionEvent arg0) { + LOGGER.info("default selected {}", arg0); + } +} diff --git a/src/main/java/tse_report/ReportCreatorDialog.java b/src/main/java/tse_report/ReportCreatorDialog.java index 1a40a29..508d19e 100644 --- a/src/main/java/tse_report/ReportCreatorDialog.java +++ b/src/main/java/tse_report/ReportCreatorDialog.java @@ -1,6 +1,5 @@ package tse_report; -import java.io.IOException; import java.util.ArrayList; import java.util.Collection; @@ -39,11 +38,9 @@ * */ public class ReportCreatorDialog extends TableDialog { - private static final Logger LOGGER = LogManager.getLogger(ReportCreatorDialog.class); - private IReportService reportService; - private RestoreableWindow window; + private final IReportService reportService; private static final String WINDOW_CODE = "ReportCreator"; public ReportCreatorDialog(Shell parent, IReportService reportService) { @@ -53,8 +50,8 @@ public ReportCreatorDialog(Shell parent, IReportService reportService) { super.create(); this.reportService = reportService; - - this.window = new RestoreableWindow(getDialog(), WINDOW_CODE); + + RestoreableWindow window = new RestoreableWindow(getDialog(), WINDOW_CODE); window.restore(TSERestoreableWindowDao.class); window.saveOnClosure(TSERestoreableWindowDao.class); } @@ -72,7 +69,7 @@ public Collection loadInitialRows(TableSchema schema, TableRow parentT // add preferences to the report try { Relation.injectGlobalParent(row, CustomStrings.PREFERENCES_SHEET); - } catch (IOException e) { + } catch (Exception e) { LOGGER.error("Cannot inject global parent=" + CustomStrings.PREFERENCES_SHEET, e); e.printStackTrace(); } @@ -95,23 +92,17 @@ public Collection loadInitialRows(TableSchema schema, TableRow parentT @Override public boolean apply(TableSchema schema, Collection rows, TableRow selectedRow) { - TseReport report = (TseReport) rows.iterator().next(); - Message msg = null; - getDialog().setCursor(getDialog().getDisplay().getSystemCursor(SWT.CURSOR_WAIT)); try { RCLError error = reportService.create(report); - if (error != null) msg = getErrorMessage(error, report); - } catch (DetailedSOAPException e) { LOGGER.error("Cannot create report", e); e.printStackTrace(); - msg = Warnings.createSOAPWarning(e); } finally { @@ -119,7 +110,6 @@ public boolean apply(TableSchema schema, Collection rows, TableRow sel } boolean errorOccurred = msg != null; - if (msg == null) { msg = Warnings.create(TSEMessages.get("success.title"), TSEMessages.get("new.report.success"), @@ -127,12 +117,10 @@ public boolean apply(TableSchema schema, Collection rows, TableRow sel } msg.open(getDialog()); - return !errorOccurred; } private static Message getErrorMessage(RCLError error, TseReport report) { - IDataset oldReport = (IDataset) error.getData(); String message = null; @@ -157,14 +145,13 @@ private static Message getErrorMessage(RCLError error, TseReport report) { break; case "ERR300": fatal = true; - message = TSEMessages.get("new.report.failed", PropertiesReader.getSupportEmail()); + message = TSEMessages.get("new.report.failed", oldReport.getId(), PropertiesReader.getSupportEmail()); break; default: break; } Message msg = fatal ? Warnings.createFatal(message, report, oldReport) : Warnings.create(message); - return message != null ? msg : null; } diff --git a/src/main/java/tse_summarized_information/SummarizedInfo.java b/src/main/java/tse_summarized_information/SummarizedInfo.java index 22efb8f..4bd790b 100644 --- a/src/main/java/tse_summarized_information/SummarizedInfo.java +++ b/src/main/java/tse_summarized_information/SummarizedInfo.java @@ -93,4 +93,12 @@ public String getTypeBySpecies() { return listId; } + + public int getNegativeSamples() { + return getNumLabel(CustomStrings.TOT_SAMPLE_NEGATIVE_COL); + } + + public int getTotalTestedSamples() { + return getNumLabel(CustomStrings.TOT_SAMPLE_TESTED_COL); + } } diff --git a/src/main/java/tse_summarized_information/SummarizedInfoDialog.java b/src/main/java/tse_summarized_information/SummarizedInfoDialog.java index 4597410..e1cac28 100644 --- a/src/main/java/tse_summarized_information/SummarizedInfoDialog.java +++ b/src/main/java/tse_summarized_information/SummarizedInfoDialog.java @@ -1,14 +1,11 @@ package tse_summarized_information; import java.io.File; -import java.io.IOException; import java.util.Collection; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.poi.xssf.usermodel.XSSFWorkbook; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; @@ -17,8 +14,6 @@ import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.Shell; @@ -91,9 +86,7 @@ public class SummarizedInfoDialog extends TableDialogWithMenu { protected TseReport report; - public SummarizedInfoDialog(Shell parent, TseReportService reportService, ITableDaoService daoService, - IFormulaService formulaService) { - + public SummarizedInfoDialog(Shell parent, TseReportService reportService, ITableDaoService daoService, IFormulaService formulaService) { super(parent, "", false, false); this.reportService = reportService; @@ -115,14 +108,12 @@ public SummarizedInfoDialog(Shell parent, TseReportService reportService, ITable addHeight(300); setEditorListener(new EditorListener() { - @Override public void editStarted() { } @Override public void editEnded(TableRow row, TableColumn field, boolean changed) { - if (changed) { switch (field.getId()) { /* @@ -139,34 +130,24 @@ public void editEnded(TableRow row, TableColumn field, boolean changed) { } } }); - } @Override public Menu createMenu() { - Menu menu = super.createMenu(); MenuItem addCase = new MenuItem(menu, SWT.PUSH); addCase.setText(TSEMessages.get("si.open.cases")); addCase.setEnabled(false); - addTableSelectionListener(new ISelectionChangedListener() { - - @Override - public void selectionChanged(SelectionChangedEvent arg0) { - - // check if RGT, if this the case doesn't enable the open sample form - TableRow rowSelected = getSelection(); + addTableSelectionListener(arg0 -> { + // check if RGT, if this the case doesn't enable the open sample form + TableRow rowSelected = getSelection(); + if (rowSelected != null) { + boolean isRGT = rowSelected.getCode(CustomStrings.SUMMARIZED_INFO_TYPE) + .equals(CustomStrings.SUMMARIZED_INFO_RGT_TYPE); - // check if row has been selected - if (rowSelected != null) { - // check if row is RGT - boolean isRGT = rowSelected.getCode(CustomStrings.SUMMARIZED_INFO_TYPE) - .equals(CustomStrings.SUMMARIZED_INFO_RGT_TYPE); - - addCase.setEnabled(!isTableEmpty() && !isRGT); - } + addCase.setEnabled(!isTableEmpty() && !isRGT); } }); @@ -179,7 +160,6 @@ public void widgetSelected(SelectionEvent arg0) { addRemoveMenuItem(menu); addCloneMenuItem(menu); - return menu; } @@ -190,12 +170,10 @@ public void widgetSelected(SelectionEvent arg0) { * @return */ boolean validate(TableRow summInfo) { - if (!summInfo.areMandatoryFilled() && report.isEditable()) { warnUser(TSEMessages.get("error.title"), TSEMessages.get("si.open.cases.error")); return false; } - return true; } @@ -203,32 +181,22 @@ boolean validate(TableRow summInfo) { * Open the cases dialog of the summarized information */ void openCases(SummarizedInfo summInfo) { - Relation.emptyCache(); // create a case passing also the report information - CaseReportDialog dialog = new CaseReportDialog(getDialog(), this.report, summInfo, reportService, daoService, - formulaService); - + CaseReportDialog dialog = new CaseReportDialog(getDialog(), this.report, summInfo, reportService, daoService, formulaService); // filter the records by the clicked summarized information dialog.setParentFilter(summInfo); - dialog.open(); - // set case errors if present reportService.updateChildrenErrors(summInfo); - replace(summInfo); } @Override public void setParentFilter(TableRow parentFilter) { - this.report = new TseReport(parentFilter); - - // update ui with report data updateUI(); - super.setParentFilter(parentFilter); } @@ -257,30 +225,15 @@ public void clear() { */ @Override public TableRow createNewRow(TableSchema schema, Selection element) { - TableCell value = new TableCell(element); - /* - * monguma: removed now more RGT rows can be created // if random genotyping if - * (value.getCode().equals(CustomStrings.SUMMARIZED_INFO_RGT_TYPE)) { // check - * if already inserted for (TableRow row : this.getLoadedRows()) { if - * (row.getCode(CustomStrings.SUMMARIZED_INFO_TYPE).equals(CustomStrings. - * SUMMARIZED_INFO_RGT_TYPE)) { // cannot add two RGT! - * - * Warnings.warnUser(getDialog(), TSEMessages.get("warning.title"), - * TSEMessages.get("cannot.have.two.rgt"), SWT.ICON_WARNING); - * - * return null; } } } - */ - // create a new summarized information SummarizedInfo si = new SummarizedInfo(CustomStrings.SUMMARIZED_INFO_TYPE, value); - try { Relation.injectGlobalParent(si, CustomStrings.SETTINGS_SHEET); Relation.injectGlobalParent(si, CustomStrings.PREFERENCES_SHEET); Relation.injectParent(report, si); - } catch (IOException e) { + } catch (Exception e) { LOGGER.error("Cannot create a new summarized information", e); e.printStackTrace(); } @@ -314,11 +267,9 @@ public RowValidatorLabelProvider getValidator() { @Override public void addWidgets(DialogBuilder viewer) { - SelectionListener refreshStateListener = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { - // if no report opened, stop if (report == null) { LOGGER.info("There is no report to continue upon adding widgets"); @@ -327,48 +278,30 @@ public void widgetSelected(SelectionEvent arg0) { IndeterminateProgressDialog progressBar = new IndeterminateProgressDialog(getDialog(), SWT.APPLICATION_MODAL, TSEMessages.get("refresh.status.progress.bar.label")); - progressBar.open(); RefreshStatusThread refreshStatus = new RefreshStatusThread(report, reportService); - refreshStatus.setListener(new ThreadFinishedListener() { - @Override public void finished(Runnable thread) { - - getDialog().getDisplay().asyncExec(new Runnable() { - - @Override - public void run() { - updateUI(); - - progressBar.close(); - - Message log = refreshStatus.getLog(); - - if (log != null) - log.open(getDialog()); - } + getDialog().getDisplay().asyncExec(() -> { + updateUI(); + progressBar.close(); + Message log = refreshStatus.getLog(); + if (log != null) + log.open(getDialog()); }); } @Override public void terminated(Runnable thread, Exception e) { - - getDialog().getDisplay().asyncExec(new Runnable() { - - @Override - public void run() { - progressBar.close(); - - Message msg = (e instanceof DetailedSOAPException) - ? Warnings.createSOAPWarning((DetailedSOAPException) e) - : Warnings.createFatal(TSEMessages.get("refresh.status.error", - PropertiesReader.getSupportEmail()), report); - - msg.open(getDialog()); - } + getDialog().getDisplay().asyncExec(() -> { + progressBar.close(); + Message msg = (e instanceof DetailedSOAPException) + ? Warnings.createSOAPWarning((DetailedSOAPException) e) + : Warnings.createFatal(TSEMessages.get("refresh.status.error", + PropertiesReader.getSupportEmail()), report); + msg.open(getDialog()); }); } }); @@ -380,8 +313,6 @@ public void run() { SelectionListener editListener = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { - - // if no report opened, stop if (report == null){ LOGGER.info("There is no report to continue for editListener"); return; @@ -405,7 +336,6 @@ public void widgetSelected(SelectionEvent arg0) { SelectionListener checkListener = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { - if (report == null){ LOGGER.info("There is no report to continue for checkListener"); return; @@ -414,12 +344,10 @@ public void widgetSelected(SelectionEvent arg0) { // validate and show the errors in the browser TseReportValidator validator = new TseReportValidator(report, reportService, daoService); try { - getDialog().setCursor(getDialog().getDisplay().getSystemCursor(SWT.CURSOR_WAIT)); // validate the report Collection errors = validator.validate(); - getDialog().setCursor(getDialog().getDisplay().getSystemCursor(SWT.CURSOR_ARROW)); // if no errors update report status @@ -427,21 +355,16 @@ public void widgetSelected(SelectionEvent arg0) { report.setStatus(RCLDatasetStatus.LOCALLY_VALIDATED); report.update(); updateUI(); - warnUser(TSEMessages.get("success.title"), TSEMessages.get("check.success"), - SWT.ICON_INFORMATION); + warnUser(TSEMessages.get("success.title"), TSEMessages.get("check.success"), SWT.ICON_INFORMATION); } else { // otherwise show them to the user validator.show(errors); warnUser(TSEMessages.get("error.title"), TSEMessages.get("check.report.failed")); } - - } catch (IOException e) { + } catch (Exception e) { getDialog().setCursor(getDialog().getDisplay().getSystemCursor(SWT.CURSOR_ARROW)); - LOGGER.error("Cannot validate the report=" + report.getSenderId(), e); e.printStackTrace(); - - warnUser(TSEMessages.get("error.title"), - TSEMessages.get("check.report.error", Warnings.getStackTrace(e))); + warnUser(TSEMessages.get("error.title"), TSEMessages.get("check.report.error", PropertiesReader.getSupportEmail())); } } }; @@ -449,31 +372,23 @@ public void widgetSelected(SelectionEvent arg0) { SelectionListener sendListener = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { - if (report == null){ LOGGER.info("There is no report to continue"); return; } - boolean ok = askConfirmation(ReportAction.SEND); + boolean ok = askConfirmation(ReportAction.SEND); if (!ok) return; String dc = PropertiesReader.getDataCollectionCode(report.getYear()); int val = Warnings.warnUser(getDialog(), TSEMessages.get("warning.title"), TSEMessages.get("send.confirm.dc", dc), SWT.ICON_WARNING | SWT.YES | SWT.NO); - if (val != SWT.YES) return; ReportActions actions = new TseReportActions(getDialog(), report, reportService); - actions.send(reportService.getSendMessageConfiguration(report), new Listener() { - - @Override - public void handleEvent(Event arg01) { - updateUI(); - } - }); + actions.send(reportService.getSendMessageConfiguration(report), arg01 -> updateUI()); } }; @@ -481,9 +396,7 @@ public void handleEvent(Event arg01) { @Override public void widgetSelected(SelectionEvent arg0) { - Shell shell = getDialog(); - if (report == null) { LOGGER.info("There is no report to continue for exportListener"); Warnings.warnUser(shell, TSEMessages.get("error.title"), TSEMessages.get("report.noreport.error")); @@ -491,8 +404,7 @@ public void widgetSelected(SelectionEvent arg0) { } // get records from summarized information - Collection records = report.getRecords(daoService, - TableSchemaList.getByName(CustomStrings.SUMMARIZED_INFO_SHEET)); + Collection records = report.getRecords(daoService, TableSchemaList.getByName(CustomStrings.SUMMARIZED_INFO_SHEET)); // get headers from summarized information Collection headers = records.iterator().next().getVisibleColumns(); // initiate the summarized information exporter @@ -540,32 +452,23 @@ public void widgetSelected(SelectionEvent arg0) { SelectionListener submitListener = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { - if (report == null){ LOGGER.info("There is no report to continue for submitListener"); return; } ReportActions actions = new TseReportActions(getDialog(), report, reportService); - MessageConfigBuilder config = reportService.getSendMessageConfiguration(report); config.setOpType(OperationType.SUBMIT); // reject the report and update the ui - actions.perform(config, new Listener() { - - @Override - public void handleEvent(Event arg01) { - updateUI(); - } - }); + actions.perform(config, arg01 -> updateUI()); } }; SelectionListener displayAckListener = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { - if (report == null){ LOGGER.info("There is no report to continue for displayAckListener"); return; @@ -573,37 +476,24 @@ public void widgetSelected(SelectionEvent arg0) { IndeterminateProgressDialog progressBar = new IndeterminateProgressDialog(getDialog(), SWT.APPLICATION_MODAL, TSEMessages.get("display.ack.progress.bar.label")); - progressBar.open(); DisplayAckThread displayAck = new DisplayAckThread(report, reportService); - displayAck.setListener(new ThreadFinishedListener() { - @Override public void finished(Runnable thread) { - - getDialog().getDisplay().asyncExec(new Runnable() { - - @Override - public void run() { - updateUI(); - - progressBar.close(); - - DisplayAckResult log = displayAck.getDisplayAckResult(); - - if (log != null) { - - for (Message m : log.getMessages()) - m.open(getDialog()); - - // open the ack in the browser to see it formatted - if (log.getDownloadedAck() != null) { - - HtmlViewer viewer1 = new HtmlViewer(); - viewer1.open(log.getDownloadedAck()); - } + getDialog().getDisplay().asyncExec(() -> { + updateUI(); + progressBar.close(); + + DisplayAckResult log = displayAck.getDisplayAckResult(); + if (log != null) { + for (Message m : log.getMessages()) + m.open(getDialog()); + // open the ack in the browser to see it formatted + if (log.getDownloadedAck() != null) { + HtmlViewer viewer1 = new HtmlViewer(); + viewer1.open(log.getDownloadedAck()); } } }); @@ -611,20 +501,13 @@ public void run() { @Override public void terminated(Runnable thread, Exception e) { - getDialog().getDisplay().asyncExec(new Runnable() { - - @Override - public void run() { - - progressBar.close(); - - Message msg = (e instanceof DetailedSOAPException) - ? Warnings.createSOAPWarning((DetailedSOAPException) e) - : Warnings.createFatal(TSEMessages.get("display.ack.error", - PropertiesReader.getSupportEmail()), report); - - msg.open(getDialog()); - } + getDialog().getDisplay().asyncExec(() -> { + progressBar.close(); + Message msg = (e instanceof DetailedSOAPException) + ? Warnings.createSOAPWarning((DetailedSOAPException) e) + : Warnings.createFatal(TSEMessages.get("display.ack.error", + PropertiesReader.getSupportEmail()), report); + msg.open(getDialog()); }); } }); @@ -636,16 +519,13 @@ public void run() { SelectionListener amendListener = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent arg0) { - if (report == null){ LOGGER.info("There is no report to continue for amendListener"); return; } TseReportActions actions = new TseReportActions(getDialog(), report, reportService); - Report newVersion = actions.amend(); - if (newVersion == null){ LOGGER.info("There is no new version to continue"); return; @@ -660,7 +540,6 @@ public void widgetSelected(SelectionEvent arg0) { @Override public void widgetSelected(SelectionEvent arg0) { - EnumPicker dialog = new EnumPicker<>(getDialog(), RCLDatasetStatus.class); dialog.setDefaultValue(report.getRCLStatus()); dialog.open(); @@ -707,7 +586,6 @@ public void widgetSelected(SelectionEvent arg0) { @Override public void widgetSelected(SelectionEvent arg0) { - NumberInputDialog dialog = new NumberInputDialog(getDialog()); dialog.setDefaultValue(report.getMessageId()); Integer messageIdNumeric = dialog.open(); @@ -718,7 +596,6 @@ public void widgetSelected(SelectionEvent arg0) { } if (!dialog.wasCancelled()) { - report.setMessageId(messageId); report.update(); updateUI(); @@ -730,7 +607,6 @@ public void widgetSelected(SelectionEvent arg0) { @Override public void widgetSelected(SelectionEvent arg0) { - NumberInputDialog dialog = new NumberInputDialog(getDialog()); dialog.setDefaultValue(report.getId()); Integer dataIdNumeric = dialog.open(); @@ -813,9 +689,7 @@ public void widgetSelected(SelectionEvent arg0) { * Initialise the labels to their initial state */ private void initUI() { - DialogBuilder panel = getPanelBuilder(); - // disable refresh until a report is opened panel.setEnabled("refreshBtn", false); panel.setEnabled("validateBtn", false); @@ -879,9 +753,7 @@ private void initUI() { panel.setLabelText("reportLabel", TSEMessages.get("si.report.void")); panel.setLabelText("statusLabel", TSEMessages.get("si.dataset.status", TSEMessages.get("si.no.data"))); - panel.setLabelText("messageIdLabel", TSEMessages.get("si.message.id", TSEMessages.get("si.no.data"))); - panel.setLabelText("datasetIdLabel", TSEMessages.get("si.dataset.id", TSEMessages.get("si.no.data"))); if (DebugConfig.debug) @@ -891,11 +763,8 @@ private void initUI() { /** * Update the ui using the report information - * - * @param report */ public void updateUI() { - String reportMonth = report.getLabel(AppPaths.REPORT_MONTH_COL); String reportYear = report.getYear(); String status = report.getRCLStatus().getLabel(); @@ -915,13 +784,9 @@ public void updateUI() { } String statusRow = TSEMessages.get("si.dataset.status", checkField(status, RCLDatasetStatus.DRAFT.getLabel())); - String messageRow = TSEMessages.get("si.message.id", checkField(messageId, TSEMessages.get("si.missing.data"))); - String datasetRow = TSEMessages.get("si.dataset.id", checkField(datasetId, TSEMessages.get("si.missing.data"))); - - String senderDatasetId = TSEMessages.get("si.sender.dataset.id", - checkField(senderId, TSEMessages.get("si.missing.data"))); + String senderDatasetId = TSEMessages.get("si.sender.dataset.id", checkField(senderId, TSEMessages.get("si.missing.data"))); DialogBuilder panel = getPanelBuilder(); panel.setLabelText("reportLabel", reportRow); @@ -956,7 +821,6 @@ public void updateUI() { } protected boolean askConfirmation(ReportAction action) { - String title = TSEMessages.get("warning.title"); String message = null; switch (action) { @@ -984,7 +848,6 @@ protected boolean askConfirmation(ReportAction action) { return false; int val = Warnings.warnUser(getDialog(), title, message, SWT.ICON_WARNING | SWT.YES | SWT.NO); - return val == SWT.YES; } @@ -997,39 +860,24 @@ protected boolean askConfirmation(ReportAction action) { * @return */ private static String checkField(String field, String defaultValue) { - - String out = null; - - if (field != null && !field.isEmpty()) - out = field; - else - out = defaultValue; - - return out; + return field != null && !field.isEmpty() ? field : defaultValue; } @Override public void nextLevel() { - TableRow row = getSelection(); - if (row == null) return; - // check if row is RGT - boolean isRGT = row.getCode(CustomStrings.SUMMARIZED_INFO_TYPE).equals(CustomStrings.SUMMARIZED_INFO_RGT_TYPE); - // if the row is RGT dont open the sample case + boolean isRGT = row.getCode(CustomStrings.SUMMARIZED_INFO_TYPE).equals(CustomStrings.SUMMARIZED_INFO_RGT_TYPE); if (isRGT) return; SummarizedInfo summInfo = new SummarizedInfo(row); - - // first validate the content of the row if (!validate(summInfo) && isEditable()) return; openCases(summInfo); - } } diff --git a/src/main/java/tse_summarized_information/TseReportActions.java b/src/main/java/tse_summarized_information/TseReportActions.java index 59ba026..af618e6 100644 --- a/src/main/java/tse_summarized_information/TseReportActions.java +++ b/src/main/java/tse_summarized_information/TseReportActions.java @@ -27,9 +27,9 @@ public class TseReportActions extends ReportActions { - private TseReportService reportService; - private TseReport report; - private Shell shell; + private final TseReportService reportService; + private final TseReport report; + private final Shell shell; public TseReportActions(Shell shell, TseReport report, TseReportService reportService) { @@ -41,9 +41,6 @@ public TseReportActions(Shell shell, TseReport report, /** * Amend a report - * @param shell - * @param report - * @param listener */ public TseReport amend() { @@ -119,7 +116,7 @@ else if (e instanceof DetailedSOAPException) { } else if (e instanceof ReportException) { String title = TSEMessages.get("error.title"); - String message = TSEMessages.get("report.unsupported.action"); + String message = TSEMessages.get("report.unsupported.action", PropertiesReader.getSupportEmail()); msg = Warnings.create(title, message, SWT.ICON_ERROR); } else { @@ -169,7 +166,7 @@ else if (e instanceof AmendException) { private void unsupportedEnd() { String title = TSEMessages.get("error.title"); - String message = TSEMessages.get("report.unsupported.action"); + String message = TSEMessages.get("report.unsupported.action", PropertiesReader.getSupportEmail()); Warnings.warnUser(shell, title, message); } @@ -225,7 +222,7 @@ private Message getUnsupportedOpWarning(Dataset dataset) { message = TSEMessages.get("send.warning.processing", datasetId); break; default: - message = TSEMessages.get("send.error.acc.dcf", PropertiesReader.getSupportEmail()); + message = TSEMessages.get("send.error.acc.dcf", datasetId, PropertiesReader.getSupportEmail()); fatal = true; break; } @@ -293,7 +290,7 @@ public static boolean showSendWarning(Shell shell, ReportSendOperation operation break; default: title = TSEMessages.get("error.title"); - message = TSEMessages.get("send.error.acc.dcf", PropertiesReader.getSupportEmail()); + message = TSEMessages.get("send.error.acc.dcf", operation.getDataset().getId(), PropertiesReader.getSupportEmail()); msg = Warnings.createFatal(message, operation.getDataset()); goOn = false; break; diff --git a/src/main/java/tse_validator/DateInvalidError.java b/src/main/java/tse_validator/DateInvalidError.java new file mode 100644 index 0000000..2c4d54a --- /dev/null +++ b/src/main/java/tse_validator/DateInvalidError.java @@ -0,0 +1,44 @@ +package tse_validator; + +import java.util.Collection; +import java.util.Collections; + +import i18n_messages.TSEMessages; +import report_validator.ReportError; + +public class DateInvalidError implements ReportError { + + private final String date; + private final String invalidRow; + + public DateInvalidError(String invalidRow, int sampDay, int sampMonth, int sampYear) { + this.invalidRow = invalidRow; + this.date = String.format("%s/%s/%s", sampDay, sampMonth, sampYear); + } + + @Override + public ErrorType getTypeOfError() { + return ErrorType.ERROR; + } + + @Override + public String getErrorMessage() { + return TSEMessages.get("invalid.date"); + } + + @Override + public Collection getInvolvedRowsIdsMessage() { + return Collections.singletonList(invalidRow); + } + + @Override + public String getSuggestions() { + return TSEMessages.get("type.correct.values"); + } + + @Override + public Collection getErroneousValues() { + return Collections.singletonList(date); + } + +} diff --git a/src/main/java/tse_validator/DateValidator.java b/src/main/java/tse_validator/DateValidator.java new file mode 100644 index 0000000..95a5696 --- /dev/null +++ b/src/main/java/tse_validator/DateValidator.java @@ -0,0 +1,59 @@ +package tse_validator; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class DateValidator { + + private static final Logger LOGGER = LogManager.getLogger(DateValidator.class); + + + public boolean validate(int sampDay, int sampMonth, int sampYear) { + + boolean checkForLeapYear = checkForLeapYear(sampDay, sampMonth, sampYear); + boolean checkMonths = checkMonths(sampDay, sampMonth, sampYear); + + return checkForLeapYear && checkMonths; + } + + public boolean checkForLeapYear(int sampDay, int sampMonth, int sampYear) { + + if (sampDay == 29 && sampMonth == 2) { + + boolean isLeapYear = ((sampYear % 4 == 0) && (sampYear % 100 != 0) || (sampYear % 400 == 0)); + + if (isLeapYear) { + LOGGER.info(sampYear + " is a leap year."); + return true; + } else { + LOGGER.info(sampYear + " is not a leap year."); + return false; + } + } + return true; + } + + public boolean checkMonths(int sampDay, int sampMonth, int sampYear) { + + if (sampMonth == 4 || sampMonth == 6 || sampMonth == 9 || sampMonth == 11) { + if (sampDay <= 30) { + return true; + } else { + return false; + } + } else if (sampMonth == 2) { + if (sampDay <= 29) { + return true; + } else { + return false; + } + } else { + if (sampDay <= 31) { + return true; + } else { + return false; + } + } + } + +} diff --git a/src/main/java/tse_validator/MissingGenotypingForScrapieType.java b/src/main/java/tse_validator/MissingGenotypingForScrapieType.java new file mode 100644 index 0000000..003b840 --- /dev/null +++ b/src/main/java/tse_validator/MissingGenotypingForScrapieType.java @@ -0,0 +1,41 @@ +package tse_validator; + +import java.util.Arrays; +import java.util.Collection; + +import i18n_messages.TSEMessages; +import report_validator.ReportError; + +public class MissingGenotypingForScrapieType implements ReportError { + + private final String rowId; + + public MissingGenotypingForScrapieType(String rowId) { + this.rowId = rowId; + } + @Override + public ErrorType getTypeOfError() { + return ErrorType.ERROR; + } + + @Override + public String getErrorMessage() { + return TSEMessages.get("genotyping.mandatory.for.scrapie"); + } + + @Override + public Collection getInvolvedRowsIdsMessage() { + return Arrays.asList(rowId); + } + + @Override + public String getSuggestions() { + return TSEMessages.get("add.genotyping.scrapie"); + } + + @Override + public Collection getErroneousValues() { + return null; + } + +} diff --git a/src/main/java/tse_validator/MissingResultData.java b/src/main/java/tse_validator/MissingResultData.java new file mode 100644 index 0000000..d516e72 --- /dev/null +++ b/src/main/java/tse_validator/MissingResultData.java @@ -0,0 +1,42 @@ +package tse_validator; + +import java.util.Arrays; +import java.util.Collection; + +import i18n_messages.TSEMessages; +import report_validator.ReportError; + +public class MissingResultData implements ReportError { + + private String rowId; + + public MissingResultData(String rowId) { + this.rowId = rowId; + } + + @Override + public ErrorType getTypeOfError() { + return ErrorType.ERROR; + } + + @Override + public String getErrorMessage() { + return TSEMessages.get("analytical.results.missing", rowId); + } + + @Override + public Collection getInvolvedRowsIdsMessage() { + return Arrays.asList(rowId); + } + + @Override + public String getSuggestions() { + return TSEMessages.get("fill.analytical.results"); + } + + @Override + public Collection getErroneousValues() { + return null; + } + +} diff --git a/src/main/java/tse_validator/MissingSampleData.java b/src/main/java/tse_validator/MissingSampleData.java new file mode 100644 index 0000000..4c4d4fd --- /dev/null +++ b/src/main/java/tse_validator/MissingSampleData.java @@ -0,0 +1,42 @@ +package tse_validator; + +import java.util.Arrays; +import java.util.Collection; + +import i18n_messages.TSEMessages; +import report_validator.ReportError; + +public class MissingSampleData implements ReportError { + + private String rowId; + + public MissingSampleData( String rowId) { + this.rowId = rowId; + } + + @Override + public ErrorType getTypeOfError() { + return ErrorType.ERROR; + } + + @Override + public String getErrorMessage() { + return TSEMessages.get("sample.data.missing", rowId); + } + + @Override + public Collection getInvolvedRowsIdsMessage() { + return Arrays.asList(rowId); + } + + @Override + public String getSuggestions() { + return TSEMessages.get("fill.sample.data"); + } + + @Override + public Collection getErroneousValues() { + return null; + } + +} diff --git a/src/main/java/tse_validator/TseReportValidator.java b/src/main/java/tse_validator/TseReportValidator.java index 8c95578..269cf7b 100644 --- a/src/main/java/tse_validator/TseReportValidator.java +++ b/src/main/java/tse_validator/TseReportValidator.java @@ -1,11 +1,8 @@ package tse_validator; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; +import java.util.*; +import java.util.stream.Collectors; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -23,8 +20,11 @@ import table_skeleton.TableCell; import table_skeleton.TableColumn; import table_skeleton.TableRow; +import tse_analytical_result.AnalyticalResult; +import tse_case_report.CaseReport; import tse_config.CustomStrings; import tse_report.TseReport; +import tse_summarized_information.SummarizedInfo; import tse_validator.CaseReportValidator.Check; import tse_validator.ResultValidator.ErrorType; import tse_validator.SummarizedInfoValidator.SampleCheck; @@ -42,10 +42,15 @@ public class TseReportValidator extends ReportValidator { private static final Logger LOGGER = LogManager.getLogger(TseReportValidator.class); - private TseReport report; + private static final TableSchema REPORT_SCHEMA = TableSchemaList.getByName(CustomStrings.REPORT_SHEET); + private static final TableSchema SUMMARY_INFO_SCHEMA = TableSchemaList.getByName(CustomStrings.SUMMARIZED_INFO_SHEET); + private static final TableSchema CASE_INFO_SCHEMA = TableSchemaList.getByName(CustomStrings.CASE_INFO_SHEET); + private static final TableSchema ANALYTICAL_RESULTS_SCHEMA = TableSchemaList.getByName(CustomStrings.RESULT_SHEET); - private TseReportService reportService; - private ITableDaoService daoService; + private final TseReport report; + + private final TseReportService reportService; + private final ITableDaoService daoService; /** * Validate an entire tse report and returns the errors in a list. It is also @@ -60,18 +65,14 @@ public TseReportValidator(TseReport report, TseReportService reportService, ITab @Override public Collection validate() { - Collection errors = new ArrayList<>(); - ArrayList reportRecords = this.reportService.getAllRecords(report); - if (reportRecords.isEmpty()) { errors.add(new EmptyReportError()); } // check errors on single row (no interdependency is evaluated) for (TableRow row : reportRecords) { - try { errors.addAll(checkMandatoryFields(row)); } catch (FormulaException e) { @@ -80,7 +81,6 @@ public Collection validate() { } RowType type = TseReportService.getRowType(row); - if (type == RowType.RESULT) { errors.addAll(checkResult(row)); } else if (type == RowType.CASE) { @@ -97,7 +97,8 @@ public Collection validate() { errors.addAll(checkNationalCaseId(reportRecords)); errors.addAll(checkAnimalId(reportRecords)); errors.addAll(checkUnknownAgeClass(reportRecords)); - + errors.addAll(checkUngeneratedSampleDataAndAnalyticalResults(reportRecords)); + errors.addAll(checkDateValidity(reportRecords)); return errors; } @@ -108,17 +109,13 @@ public Collection validate() { * @return */ public Collection checkDuplicatedSampleId(Collection reportRecords) { - Collection errors = new ArrayList<>(); - HashMap cases = new HashMap<>(); for (TableRow row : reportRecords) { - if (TseReportService.getRowType(row) != RowType.CASE) continue; String currentSampId = row.getLabel(CustomStrings.SAMPLE_ID_COL); - // if there is already an element, error! duplicated value if (cases.containsKey(currentSampId)) { TableRow conflict = cases.get(currentSampId); @@ -141,17 +138,13 @@ public Collection checkDuplicatedSampleId(Collection repo * @return */ public Collection checkDuplicatedResId(Collection reportRecords) { - Collection errors = new ArrayList<>(); - HashMap results = new HashMap<>(); for (TableRow row : reportRecords) { - if (TseReportService.getRowType(row) != RowType.RESULT) continue; String currentId = row.getLabel(CustomStrings.RES_ID_COL); - // if there is already an element, error! duplicated value if (results.containsKey(currentId)) { TableRow conflict = results.get(currentId); @@ -175,23 +168,17 @@ public Collection checkDuplicatedResId(Collection reportR * @return */ public Collection checkDuplicatedSummId(ArrayList reportRecords) { - - // collection used to report duplicate errors Collection errors = new ArrayList<>(); - // the set store the values already analysed Set indexComputed = new HashSet<>(); for (int i = 0; i < reportRecords.size() - 1; i++) { - TableRow current = reportRecords.get(i); - // if the row is not summ or already computed skip if (TseReportService.getRowType(current) != RowType.SUMM || indexComputed.contains(i)) continue; for (int j = i + 1; j < reportRecords.size(); j++) { - TableRow next = reportRecords.get(j); // if the row is not summ or already computed or same as the current skip @@ -200,7 +187,6 @@ public Collection checkDuplicatedSummId(ArrayList reportR // if the records has same values under natural key if (current.sameAs(next)) { - // get their ids String rowId1 = getStackTrace(current); String rowId2 = getStackTrace(next); @@ -225,11 +211,8 @@ public Collection checkDuplicatedSummId(ArrayList reportR * @return */ public static String getRowId(TableRow row) { - String id = null; - RowType type = TseReportService.getRowType(row); - switch (type) { case SUMM: id = TSEMessages.get("si.id.label", row.getCode(CustomStrings.PROG_ID_COL)); @@ -249,40 +232,24 @@ public static String getRowId(TableRow row) { } public String getStackTrace(TableRow row) { - RowType type = TseReportService.getRowType(row); - String trace = null; - final String arrowCharacter = TSEMessages.get("table.html.arrow"); // html arrow - switch (type) { case SUMM: trace = getRowId(row); break; case CASE: - - int parentId = Integer - .valueOf(row.getCode(Relation.foreignKeyFromParent(CustomStrings.SUMMARIZED_INFO_SHEET))); - - TableRow summInfo = daoService.getById(TableSchemaList.getByName(CustomStrings.SUMMARIZED_INFO_SHEET), - parentId); - + int parentId = Integer.valueOf(row.getCode(Relation.foreignKeyFromParent(CustomStrings.SUMMARIZED_INFO_SHEET))); + TableRow summInfo = daoService.getById(TableSchemaList.getByName(CustomStrings.SUMMARIZED_INFO_SHEET), parentId); trace = getRowId(summInfo); trace = trace + arrowCharacter + getRowId(row); break; case RESULT: - - int summParentId = Integer - .valueOf(row.getCode(Relation.foreignKeyFromParent(CustomStrings.SUMMARIZED_INFO_SHEET))); - int caseParentId = Integer - .valueOf(row.getCode(Relation.foreignKeyFromParent(CustomStrings.CASE_INFO_SHEET))); - - TableRow summ = daoService.getById(TableSchemaList.getByName(CustomStrings.SUMMARIZED_INFO_SHEET), - summParentId); - TableRow caseReport = daoService.getById(TableSchemaList.getByName(CustomStrings.CASE_INFO_SHEET), - caseParentId); - + int summParentId = Integer.valueOf(row.getCode(Relation.foreignKeyFromParent(CustomStrings.SUMMARIZED_INFO_SHEET))); + int caseParentId = Integer.valueOf(row.getCode(Relation.foreignKeyFromParent(CustomStrings.CASE_INFO_SHEET))); + TableRow summ = daoService.getById(TableSchemaList.getByName(CustomStrings.SUMMARIZED_INFO_SHEET), summParentId); + TableRow caseReport = daoService.getById(TableSchemaList.getByName(CustomStrings.CASE_INFO_SHEET), caseParentId); trace = getRowId(summ); trace = trace + arrowCharacter + getRowId(caseReport); trace = trace + arrowCharacter + getRowId(row); @@ -303,18 +270,12 @@ public String getStackTrace(TableRow row) { * @throws FormulaException */ public Collection checkMandatoryFields(TableRow row) throws FormulaException { - Collection errors = new ArrayList<>(); - String rowId = getStackTrace(row); - // check mandatory fields for (TableColumn field : reportService.getMandatoryFieldNotFilled(row)) { - String label = field.getLabel(); - String fieldName = label == null || label.isEmpty() ? field.getId() : label; - errors.add(new MissingMandatoryFieldError(fieldName, rowId)); } @@ -328,13 +289,10 @@ public Collection checkMandatoryFields(TableRow row) throws Formula * @return */ public Collection checkSummarizedInfo(TableRow row) { - Collection errors = new ArrayList<>(); - SummarizedInfoValidator validator = new SummarizedInfoValidator(daoService); Collection checks = validator.isSampleCorrect(row); String rowId = getStackTrace(row); - for (SampleCheck check : checks) { switch (check) { case TOO_MANY_INCONCLUSIVES: @@ -347,7 +305,6 @@ public Collection checkSummarizedInfo(TableRow row) { errors.add(new CheckPositiveCasesError(rowId)); break; case NON_WILD_FOR_KILLED: - TableSchema schema = TableSchemaList.getByName(CustomStrings.SUMMARIZED_INFO_SHEET); String targetLabel = schema.getById(CustomStrings.TARGET_GROUP_COL).getLabel(); @@ -357,8 +314,7 @@ public Collection checkSummarizedInfo(TableRow row) { TableCell targetGroup = row.get(CustomStrings.TARGET_GROUP_COL); TableCell prod = row.get(CustomStrings.PROD_COL); - errors.add(new NonWildAndKilledError(id, targetLabel + ": " + targetGroup.getLabel(), - prodLabel + ": " + prod.getLabel())); + errors.add(new NonWildAndKilledError(id, targetLabel + ": " + targetGroup.getLabel(), prodLabel + ": " + prod.getLabel())); break; default: @@ -368,9 +324,7 @@ public Collection checkSummarizedInfo(TableRow row) { // check declared cases if (!row.getCode(CustomStrings.SUMMARIZED_INFO_TYPE).equals(CustomStrings.SUMMARIZED_INFO_RGT_TYPE)) { - // if not RGT type, then check declared cases - String total = row.getLabel(CustomStrings.TOT_SAMPLE_TESTED_COL); String unsuitable = row.getLabel(CustomStrings.TOT_SAMPLE_UNSUITABLE_COL); @@ -390,14 +344,10 @@ public Collection checkSummarizedInfo(TableRow row) { * @return */ public Collection checkCaseInfo(TableRow row) { - Collection errors = new ArrayList<>(); - CaseReportValidator validator = new CaseReportValidator(daoService); - Collection checks = new ArrayList<>(); - checks = validator.isRecordCorrect(row); - + Collection checks = validator.isRecordCorrect(row); for (Check check : checks) { switch (check) { case NO_TEST_SPECIFIED: @@ -440,23 +390,19 @@ public Collection checkCaseInfo(TableRow row) { } public Collection checkNationalCaseId(Collection reportRecords) { - String[] fieldsToCheck = { CustomStrings.ANIMAL_ID_COL }; - return checkIdField(reportRecords, CustomStrings.NATIONAL_CASE_ID_COL, TSEMessages.get("inconsistent.national.case.id"), fieldsToCheck); } public Collection checkAnimalId(Collection reportRecords) { - String[] fieldsToCheck = { CustomStrings.NATIONAL_CASE_ID_COL, CustomStrings.HERD_ID_COL, CustomStrings.STATUS_HERD_COL, CustomStrings.SAMP_HOLDING_ID_COL, CustomStrings.SAMP_DAY_COL, CustomStrings.SAMP_AREA_COL, CustomStrings.INDEX_CASE_COL, CustomStrings.BIRTH_COUNTRY_COL, CustomStrings.BIRTH_YEAR_COL, CustomStrings.BIRTH_MONTH_COL, CustomStrings.BORN_FLOCK_HERD_COL, CustomStrings.BREED_COL, CustomStrings.EVAL_COMMENT_COL }; - return checkIdField(reportRecords, CustomStrings.ANIMAL_ID_COL, TSEMessages.get("inconsistent.animal.id"), - fieldsToCheck); + return checkIdField(reportRecords, CustomStrings.ANIMAL_ID_COL, TSEMessages.get("inconsistent.animal.id"), fieldsToCheck); } /** @@ -473,26 +419,20 @@ public Collection checkIdField(Collection reportRecords, String[] fieldsToCheck) { Collection errors = new ArrayList<>(); - HashMap cases = new HashMap<>(); for (TableRow row : reportRecords) { - if (TseReportService.getRowType(row) != RowType.CASE) continue; String id = row.getLabel(idField); - if (id.isEmpty()) continue; TableRow current = cases.get(id); - // if one is already present, check if they are equal or not if (current != null) { - // add all the mismatches for (String field : fieldsToCheck) { - String currentValue = current.getCode(field); String currentValueLab = current.getLabel(field); String value = row.getCode(field); @@ -513,7 +453,6 @@ public Collection checkIdField(Collection reportRecords, } public Collection checkAgeClass(TableRow row) { - Collection errors = new ArrayList<>(); int reportId = row.getNumCode(Relation.foreignKeyFromParent(CustomStrings.REPORT_SHEET)); @@ -552,12 +491,10 @@ public Collection checkAgeClass(TableRow row) { tse_validator.AgeClassValidator.Check check2 = ageValidator.validate(); switch (check2) { case AGE_CLASS_NOT_RESPECTED: - errors.add( - new WrongAgeClassError(getStackTrace(row), ageClassLabel, ageValidator.getMonthsDifference())); + errors.add(new WrongAgeClassError(getStackTrace(row), ageClassLabel, ageValidator.getMonthsDifference())); break; case REPORT_DATE_EXCEEDED: - errors.add(new ReportDateExceededError(getStackTrace(row), reportYear, reportMonthLabel, birthYear, - birthMonthLabel)); + errors.add(new ReportDateExceededError(getStackTrace(row), reportYear, reportMonthLabel, birthYear, birthMonthLabel)); break; default: break; @@ -577,20 +514,16 @@ public Collection checkAgeClass(TableRow row) { * @return */ public Collection checkResult(TableRow row) { - Collection errors = new ArrayList<>(); - ErrorType errorType = ResultValidator.getError(row); String rowId = getStackTrace(row); switch (errorType) { case ALLELE_ERROR: - errors.add(new AlleleNotReportableError(rowId, row.getLabel(CustomStrings.ALLELE_1_COL), - row.getLabel(CustomStrings.ALLELE_2_COL))); + errors.add(new AlleleNotReportableError(rowId, row.getLabel(CustomStrings.ALLELE_1_COL), row.getLabel(CustomStrings.ALLELE_2_COL))); break; case WRONG_ALLELE_PAIR: - errors.add(new WrongAllelesPairError(rowId, row.getLabel(CustomStrings.ALLELE_1_COL), - row.getLabel(CustomStrings.ALLELE_2_COL))); + errors.add(new WrongAllelesPairError(rowId, row.getLabel(CustomStrings.ALLELE_1_COL), row.getLabel(CustomStrings.ALLELE_2_COL))); break; default: break; @@ -607,18 +540,14 @@ public Collection checkResult(TableRow row) { LOGGER.error("Error in parsing a non-numeric String", e); e.printStackTrace(); } - return errors; } public static Collection checkUnknownAgeClass(Collection rows) { - int total = 0; int unk = 0; - Collection errors = new ArrayList<>(); for (TableRow row : rows) { - // only for BSE summ info if (TseReportService.getRowType(row) == RowType.SUMM && row.getCode(CustomStrings.SUMMARIZED_INFO_TYPE).equals(CustomStrings.SUMMARIZED_INFO_BSE_TYPE)) { @@ -640,4 +569,101 @@ public static Collection checkUnknownAgeClass(Collection return errors; } -} + + public Collection checkUngeneratedSampleDataAndAnalyticalResults(ArrayList reportRecords) { + Collection errors = new ArrayList<>(); + if (reportRecords.size() == 1) { + TableRow currentRow = reportRecords.get(0); + int negSamples = currentRow.getNumLabel(CustomStrings.TOT_SAMPLE_NEGATIVE_COL); + int testedSamples = currentRow.getNumLabel(CustomStrings.TOT_SAMPLE_TESTED_COL); + String type = currentRow.getCode(CustomStrings.SUMMARIZED_INFO_TYPE); + + if (!type.equals(CustomStrings.SUMMARIZED_INFO_RGT_TYPE) && negSamples < testedSamples) { + errors.add(new MissingSampleData(getStackTrace(currentRow))); + } + } else { + List summaryInfos = reportRecords.stream().filter(r -> SUMMARY_INFO_SCHEMA == r.getSchema()).map(SummarizedInfo::new).collect(Collectors.toList()); + List caseInfos = reportRecords.stream().filter(r -> CASE_INFO_SCHEMA == r.getSchema()).map(CaseReport::new).collect(Collectors.toList()); + List analyticalResults = reportRecords.stream().filter(r -> ANALYTICAL_RESULTS_SCHEMA == r.getSchema()).map(AnalyticalResult::new).collect(Collectors.toList()); + + for (SummarizedInfo summarizedInfo: summaryInfos) { + boolean generatedSampleData = false; + + int negSamples = summarizedInfo.getNegativeSamples(); + int testedSamples = summarizedInfo.getTotalTestedSamples(); + String summarizedInfoId = summarizedInfo.getLabel(CustomStrings.SI_ID_COL); + + String type = summarizedInfo.getCode(CustomStrings.SUMMARIZED_INFO_TYPE); + boolean isScrapie = type.equals(CustomStrings.SUMMARIZED_INFO_SCRAPIE_TYPE); + boolean isGenotyping = type.equals(CustomStrings.SUMMARIZED_INFO_RGT_TYPE); + + if (negSamples < testedSamples) { + for (CaseReport caseReport: caseInfos) { + String caseReportSumInfoId = caseReport.getLabel(CustomStrings.SI_ID_COL); + // if not child report > continue + if (!caseReportSumInfoId.equals(summarizedInfoId)) { + continue; + } + generatedSampleData = true; + + boolean generatedResultData = false; + boolean hasGenotype = false; + + String caseReportId = caseReport.getLabel(CustomStrings.CASE_ID_COL); + for (AnalyticalResult analyticalResult : analyticalResults) { + String analyticalReportCaseReportId = analyticalResult.getLabel(CustomStrings.CASE_ID_COL); + // if not child report > continue + if (!analyticalReportCaseReportId.equals(caseReportId)) { + continue; + } + + generatedResultData = true; + String anMethCode = analyticalResult.getLabel(CustomStrings.AN_METH_CODE_COL); + if (isScrapie && anMethCode.equals(CustomStrings.AN_METH_CODE_GENOTYPING_TYPE)) { + hasGenotype = true; + } + } + + if (!isGenotyping && !generatedResultData) { + errors.add(new MissingResultData(getStackTrace(caseReport))); + } + + if (isScrapie && !hasGenotype) { + errors.add(new MissingGenotypingForScrapieType(getStackTrace(caseReport))); + } + } // end for 2 + + if (!generatedSampleData && !isGenotyping) { + errors.add(new MissingSampleData(getStackTrace(summarizedInfo))); + } + } + } // end for + } + + return errors; + } + + public Collection checkDateValidity(ArrayList reportRecords) { + Collection errors = new ArrayList<>(); + for (TableRow currentRow : reportRecords) { + RowType currentRowType = TseReportService.getRowType(currentRow); + if (currentRowType == RowType.CASE) { + int sampCode = currentRow.getNumCode(CustomStrings.SAMP_DAY_COL); + + TableRow report = new TseReport(currentRow.getParent(REPORT_SCHEMA)); + int sampBirthMonth = report.getNumCode(CustomStrings.REPORT_MONTH); + int sampBirthYear = report.getNumCode(CustomStrings.REPORT_YEAR); + + if (sampCode > 0 && sampBirthMonth > 0 && sampBirthYear > 0) { + DateValidator dateValidator = new DateValidator(); + boolean validDate = dateValidator.validate(sampCode, sampBirthMonth, sampBirthYear); + + if (!validDate) { + errors.add(new DateInvalidError(getStackTrace(currentRow), sampCode, sampBirthMonth, sampBirthYear)); + } + } + } + } + + return errors; + }} diff --git a/src/main/resources/tse_messages_en.properties b/src/main/resources/tse_messages_en.properties index 30df694..4f77904 100644 --- a/src/main/resources/tse_messages_en.properties +++ b/src/main/resources/tse_messages_en.properties @@ -17,9 +17,15 @@ open.report.button=Open close.report.item=Close report +copy.report.item=Copy report +copy.report.title=Copy a report +copy.report.button=Copy +copy.report.warning=This will overwrite the data already existing into the current report.\nDo you want to proceed + import.report.item=Import aggregated data import.report.title=Import a report import.report.button=Import +import.report.warning=This will overwrite the data already existing into the current report.\nDo you want to proceed? import.excel_report.button=[ALPHA] Import excel report @@ -29,8 +35,7 @@ export.report.item=Export report as XML export.report.button=Save export.report.op.title=Select the export operation export.report.op.confirm=Export -export.report.no.connection=ERR411: Connection error occurred. It was not possible to compute the export action required according to the DCF dataset status. Manual operation type must be set. -import.report.warning=This will overwrite the data already existing into the current report.\nDo you want to proceed? +export.report.no.connection=ERR411: A connection error with the DCF has occurred. It was not possible to complete the export action required according to the DCF dataset status. close.app.item=Close application @@ -54,6 +59,7 @@ proxy.config.item=Proxy configuration ### Template right click menu on records (SummInfo) delete.records=Delete records clone.records=Clone record(s) +clone.all.records=Clone all record(s) ### Summarized information table si.help.title=Aggregated Data @@ -254,6 +260,19 @@ index.case.farmed.cwd.message=The value No is not allowed for Index Case for far inconsistent.index.case.status.herd.message=The value %s1 is not allowed in Index Case when the status of the herd is %s2 not.infected.eradication=The value 'EM (eradication measures)' is not allowed as target group when the status of the herd is 'Not infected' +invalid.date = The entered date is invalid + +type.correct.values = Please type correct values + +genotyping.mandatory.for.scrapie = Genotyping is mandatory for scrapie method +add.genotyping.scrapie = Please add genotyping + +analytical.results.missing = Analytical results are missing +fill.analytical.results = Please fill the analytical results + +sample.data.missing = Sample data are missing +fill.sample.data = Please fill the sample data + wrong.an.year.message=The analysis year (%s1) cannot be minor than the sampling year (%s2) ################################################################################ #################################### POPUPs #################################### @@ -312,10 +331,10 @@ db.init.error=ERR201: %s1 db.removal.error=ERR202: The database could not be deleted. Please delete it manually in the application folder or restart the application. # s1: technical support email -new.report.failed=ERR300: An error occurred due to a conflicting dataset in DCF. Please contact %s1. +new.report.failed=ERR300: An error occurred due to a conflicting dataset (dataset_id= %s1) in DCF. Please contact %s2. # s1: technical support email -send.error.acc.dcf=ERR400: An error occurred due to a conflicting dataset in DCF. Please contact %s1. +send.error.acc.dcf=ERR400: An error occurred due to a conflicting dataset (dataset_id= %s1)in DCF. Please contact %s2. # s1: technical support email report.io.error=ERR402: Errors occurred during the export of the report. Please contact %s1. @@ -331,19 +350,20 @@ gde2.missing=ERR403: Errors occurred during the creation of the report. Please c # s1: technical support email send.message.failed=ERR404: An unexpected error has been returned from the DCF: %s1. Please contact urgently %s2. -report.unsupported.action=ERR405: The dataset cannot be sent since the operation is not supported. +report.unsupported.action=ERR405: The dataset cannot be sent since the operation is not supported. Please contact %s1. -test.connection.fail=ERR406: The test was not successful. Got TRXKO as response. # s1: technical support email -test.connection.fail2=ERR408: The test was not successful. The used operation type is not correct. Please contact %s1. +test.connection.fail2=ERR408: The test connection was not successful. Please contact %s1. # s1: technical support email -test.connection.fail3=ERR409: The test was not successful. The dataset is either badly formatted or not it was not found in the disk. Please contact %s1. +test.connection.fail3=ERR409: The test was not successful. The dataset is either badly formatted or not it was not found in the disk. You can try to download and reinstall the TSE tool again, or contact %s1. + +test.connection.fail4=The TSE tool could not establish a connection. Please check/change the 'Users settings' and the 'Proxy configuration'. If the issue persists contact %s1. -refresh.status.error=ERR503: Refresh status failed. Please contact %s1. +refresh.status.error=ERR503: Refresh status failed. You can check the status directly in DCF or contact %s1. # s1: technical support email -send.failed.no.senderId=ERR700: Something went wrong, please check if the report senderDatasetId is set. Please contact %s1. +send.failed.no.senderId=ERR700: Something is wrong with the senderDatasetId. Please contact %s1. # s1: technical support email new.report.failed.no.senderId=ERR700: Something went wrong, please check if the report senderDatasetId is set. Please contact %s1. @@ -361,7 +381,7 @@ check.report.failed=WARN001: The report contains errors. The list of errors will cannot.have.two.rgt=WARN002: An aggregated record related to random genotyping is already present. Please use that one to add samples. -db.need.removal=WARN200: The current database is out-dated and needs to be regenerated from scratch. Continue? All the data will be lost. +db.need.removal=WARN200: The current database is out-dated and needs to be regenerated from scratch. Do you want to continue? All the locally stored data will be lost. If in doubt, please contact %s1. # s1: dataset id new.report.processing=WARN300: An existing report in DCF with dataset id %s1 was found in status PROCESSING. Please wait the completion of the validation. @@ -410,8 +430,8 @@ beta_accepted_dhw.confirm=CONF908: Send DWH request. Do you want to continue? ### GENERIC ERROR MSG # s1: java error -check.report.error=ERRA00: Cannot write the list of errors in .html file. -proxy.config.file.not.found.error=ERRA01: The proxyConfig.xml file was not found. Please contact %s1. +check.report.error=Cannot write the list of errors in .html file. Please contact %s1. +proxy.config.file.not.found.error=ERRA01: The proxyConfig.xml file was not found. You can try to download and reinstall the tool again, or please contact %s1. # s1: techical support email -generic.error=XERRX: Generic runtime error. Please contact %s1. \ No newline at end of file +generic.error=XERRX: A generic error has occurred. Please contact %s1.