From 9f9d4aac73fb962063786b1d0111ba89a0c069b8 Mon Sep 17 00:00:00 2001 From: Auriga2 <64826928+Auriga2@users.noreply.github.com> Date: Fri, 17 Dec 2021 13:15:32 +1030 Subject: [PATCH] Fix importer inconsistencies and bug fixes (#1602) * Fix the importer inconsistencies and satus message * Fix the database importer status message and add Changelog entry * Fix the row filter style when files are added later * Convert to a ternary statement * Remove redundant parameter and brief refactor to fix sonar issues. --- CHANGELOG.md | 8 + .../plugins/importexport/RunPane.java | 18 +- .../delimited/ImportDelimitedPlugin.java | 35 ++- .../importexport/jdbc/ImportJDBCPlugin.java | 29 ++- .../importexport/jdbc/JDBCSourcePane.java | 209 +++++++++++------- 5 files changed, 183 insertions(+), 116 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e00cba101..85317d6441 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Constellation Changes +## Changes in December 2021 + +- Changed the return type of `processVertices` and `processTransactions` methods + in `ImportJDBCPlugin` and `ImportDelimitedPlugin` classes to return the number + of imported rows. Added a new parameter `totalRows` in `displaySummaryAlert` + method of `ImportJDBCPlugin` class. These allow a more meaningful + summary status message after importing. + ## Changes in November 2021 - Added `netbeans.exception.report.min.level=900` and diff --git a/CoreImportExportPlugins/src/au/gov/asd/tac/constellation/plugins/importexport/RunPane.java b/CoreImportExportPlugins/src/au/gov/asd/tac/constellation/plugins/importexport/RunPane.java index 4e3a02b332..242e8c30e6 100644 --- a/CoreImportExportPlugins/src/au/gov/asd/tac/constellation/plugins/importexport/RunPane.java +++ b/CoreImportExportPlugins/src/au/gov/asd/tac/constellation/plugins/importexport/RunPane.java @@ -180,13 +180,7 @@ public RunPane(final ImportController importController, final String displayText filterField.setFocusTraversable(false); filterField.setMinHeight(USE_PREF_SIZE); filterField.setStyle(FILTER_STYLE); - filterField.textProperty().addListener((observable, oldValue, newValue) -> { - if (setFilter(newValue)) { - filterField.setStyle(FILTER_STYLE); - } else { - filterField.setStyle(FILTER_STYLE_ALERT); - } - }); + filterField.textProperty().addListener((observable, oldValue, newValue) -> setFilterStyle(newValue)); filterField.setPromptText("Currently unavailable. The filter will be ready to use shortly"); FILTER_LOAD.thenRun(() -> filterField.setPromptText("Start typing to search, e.g. first_name==\"NICK\"")); @@ -305,6 +299,10 @@ public RunPane(final ImportController importController, final String displayText }); } + private void setFilterStyle(final String value) { + filterField.setStyle(setFilter(value) ? FILTER_STYLE : FILTER_STYLE_ALERT); + } + /** * Update name associated with this pane. This value is used in ImportDefinition construction to identify the * source of the ImportDefinition - ultimately being used when performing import to support an import status dialog. @@ -457,7 +455,7 @@ public void setSampleData(final String[] columnLabels, final ObservableList tableRow.setIncluded(true)); @@ -571,7 +569,7 @@ void update(final ImportDefinition impdef) { script = ""; } filterField.setText(script); - setFilter(script); + setFilterStyle(script); updateColumns(impdef, sourceVertexAttributeList, AttributeType.SOURCE_VERTEX); updateColumns(impdef, destinationVertexAttributeList, AttributeType.DESTINATION_VERTEX); diff --git a/CoreImportExportPlugins/src/au/gov/asd/tac/constellation/plugins/importexport/delimited/ImportDelimitedPlugin.java b/CoreImportExportPlugins/src/au/gov/asd/tac/constellation/plugins/importexport/delimited/ImportDelimitedPlugin.java index 4b47938f1c..25030a4142 100644 --- a/CoreImportExportPlugins/src/au/gov/asd/tac/constellation/plugins/importexport/delimited/ImportDelimitedPlugin.java +++ b/CoreImportExportPlugins/src/au/gov/asd/tac/constellation/plugins/importexport/delimited/ImportDelimitedPlugin.java @@ -211,13 +211,13 @@ protected void edit(final GraphWriteMethods graph, final PluginInteraction inter final boolean initialiseWithSchema = parameters.getParameters().get(SCHEMA_PARAMETER_ID).getBooleanValue(); final PluginParameters parserParameters = (PluginParameters) parameters.getParameters().get(PARSER_PARAMETER_IDS_PARAMETER_ID).getObjectValue(); final boolean filesIncludeHeaders = parameters.getParameters().get(FILES_INCLUDE_HEADERS_PARAMETER_ID).getBooleanValue(); - final List newVertices = new ArrayList<>(); boolean positionalAtrributesExist = false; final List validFiles = new ArrayList<>(); final List emptyFiles = new ArrayList<>(); final List invalidFiles = new ArrayList<>(); final List emptyRunConfigs = new ArrayList<>(); - int importRows = 0; + int totalRows = 0; + int totalImportedRows = 0; int dataSize = 0; // Loop through import definitions looking for those that don't have either a source or destination vertex (as @@ -232,13 +232,13 @@ protected void edit(final GraphWriteMethods graph, final PluginInteraction inter for (final File file : files) { interaction.setProgress(0, 0, "Reading File: " + file.getName(), true); List data = null; + int importedRowsPerFile = 0; try { data = parser.parse(new InputSource(file), parserParameters); dataSize = filesIncludeHeaders ? data.size() - 1 : data.size(); - importRows = importRows + Integer.max(0, dataSize); + totalRows = totalRows + Integer.max(0, dataSize); - LOGGER.log(Level.INFO, "Imported {0} rows of data from file {1}. {2} total rows imported", new Object[]{dataSize, file.getPath(), importRows}); if (dataSize > 0) { if (validFiles.isEmpty()) { validFiles.add(file.getName().concat(" (").concat(Integer.toString(dataSize)).concat(" rows)")); @@ -264,14 +264,14 @@ protected void edit(final GraphWriteMethods graph, final PluginInteraction inter // No source vertex definitions are set, the only option left is destination vertexes being mapped. // Process destination vertexes if defintions are defined, otherwise there is nothing to do. if (!definition.getDefinitions(AttributeType.DESTINATION_VERTEX).isEmpty()) { - processVertices(definition, graph, data, AttributeType.DESTINATION_VERTEX, initialiseWithSchema, interaction, file.getName(), newVertices); + importedRowsPerFile += processVertices(definition, graph, data, AttributeType.DESTINATION_VERTEX, initialiseWithSchema, interaction, file.getName()); } } else if (definition.getDefinitions(AttributeType.DESTINATION_VERTEX).isEmpty()) { // Source defintions exist, but no destination definitions exist. Process the source definitions. - processVertices(definition, graph, data, AttributeType.SOURCE_VERTEX, initialiseWithSchema, interaction, file.getName(), newVertices); + importedRowsPerFile += processVertices(definition, graph, data, AttributeType.SOURCE_VERTEX, initialiseWithSchema, interaction, file.getName()); } else { // Both source and destination defintions exist, process them. - processTransactions(definition, graph, data, initialiseWithSchema, interaction, file.getName()); + importedRowsPerFile += processTransactions(definition, graph, data, initialiseWithSchema, interaction, file.getName()); } // Determine if a positional attribute has been defined, if so update the overall flag @@ -279,9 +279,11 @@ protected void edit(final GraphWriteMethods graph, final PluginInteraction inter positionalAtrributesExist = (positionalAtrributesExist || isPositional); } } + totalImportedRows += importedRowsPerFile; + LOGGER.log(Level.INFO, "Imported {0} rows of data from file {1} containing {2} total rows", new Object[]{importedRowsPerFile, file.getPath(), dataSize}); } - displaySummaryAlert(graph.getVertexCount() + graph.getTransactionCount(), importRows, validFiles, emptyFiles, invalidFiles, emptyRunConfigs); + displaySummaryAlert(graph.getVertexCount() + graph.getTransactionCount(), totalImportedRows, validFiles, emptyFiles, invalidFiles, emptyRunConfigs); ConstellationLoggerHelper.importPropertyBuilder( this, @@ -300,7 +302,8 @@ protected void edit(final GraphWriteMethods graph, final PluginInteraction inter graph.validateKey(GraphElementType.TRANSACTION, true); // unfortunately need to arrange with pendants and uncollide because grid arranger works based on selection - final VertexListInclusionGraph vlGraph = new VertexListInclusionGraph(graph, AbstractInclusionGraph.Connections.NONE, newVertices); + final VertexListInclusionGraph vlGraph = new VertexListInclusionGraph(graph, AbstractInclusionGraph.Connections.NONE, new ArrayList<>()); + PluginExecutor.startWith(ArrangementPluginRegistry.GRID_COMPOSITE) .followedBy(ArrangementPluginRegistry.PENDANTS) .followedBy(ArrangementPluginRegistry.UNCOLLIDE) @@ -322,12 +325,14 @@ private static boolean attributeDefintionIsPositional(List attribute.getAttribute().getName()).anyMatch(name -> (VisualConcept.VertexAttribute.X.getName().equals(name) || VisualConcept.VertexAttribute.Y.getName().equals(name) || VisualConcept.VertexAttribute.Z.getName().equals(name))); } - private static void processVertices(ImportDefinition definition, GraphWriteMethods graph, List data, AttributeType attributeType, boolean initialiseWithSchema, PluginInteraction interaction, String source, final List newVertices) throws InterruptedException { + private static int processVertices(ImportDefinition definition, GraphWriteMethods graph, List data, AttributeType attributeType, + boolean initialiseWithSchema, PluginInteraction interaction, String source) throws InterruptedException { final List attributeDefinitions = definition.getDefinitions(attributeType); addAttributes(graph, GraphElementType.VERTEX, attributeDefinitions); int currentRow = 0; + int importedRows = 0; final int totalRows = data.size() - definition.getFirstRow(); final RowFilter filter = definition.getRowFilter(); @@ -337,8 +342,9 @@ private static void processVertices(ImportDefinition definition, GraphWriteMetho final String[] row = data.get(i); if (filter == null || filter.passesFilter(i - 1, row)) { + // Count the number of processed rows to notify in the status message + ++importedRows; final int vertexId = graph.addVertex(); - newVertices.add(vertexId); for (final ImportAttributeDefinition attributeDefinition : attributeDefinitions) { attributeDefinition.setValue(graph, vertexId, row, (i - 1)); @@ -349,9 +355,10 @@ private static void processVertices(ImportDefinition definition, GraphWriteMetho } } } + return importedRows; } - private static void processTransactions(ImportDefinition definition, GraphWriteMethods graph, List data, boolean initialiseWithSchema, PluginInteraction interaction, String source) throws InterruptedException { + private static int processTransactions(ImportDefinition definition, GraphWriteMethods graph, List data, boolean initialiseWithSchema, PluginInteraction interaction, String source) throws InterruptedException { final List sourceVertexDefinitions = definition.getDefinitions(AttributeType.SOURCE_VERTEX); final List destinationVertexDefinitions = definition.getDefinitions(AttributeType.DESTINATION_VERTEX); final List transactionDefinitions = definition.getDefinitions(AttributeType.TRANSACTION); @@ -369,6 +376,7 @@ private static void processTransactions(ImportDefinition definition, GraphWriteM addAttributes(graph, GraphElementType.TRANSACTION, transactionDefinitions); int currentRow = 0; + int importedRows = 0; final int totalRows = data.size() - definition.getFirstRow(); final RowFilter filter = definition.getRowFilter(); @@ -379,6 +387,8 @@ private static void processTransactions(ImportDefinition definition, GraphWriteM final String[] row = data.get(i); if (filter == null || filter.passesFilter(i - 1, row)) { + // Count the number of processed rows to notify in the status message + ++importedRows; final int sourceVertexId = graph.addVertex(); for (final ImportAttributeDefinition attributeDefinition : sourceVertexDefinitions) { attributeDefinition.setValue(graph, sourceVertexId, row, (i - 1)); @@ -407,6 +417,7 @@ private static void processTransactions(ImportDefinition definition, GraphWriteM } } } + return importedRows; } /** diff --git a/CoreImportExportPlugins/src/au/gov/asd/tac/constellation/plugins/importexport/jdbc/ImportJDBCPlugin.java b/CoreImportExportPlugins/src/au/gov/asd/tac/constellation/plugins/importexport/jdbc/ImportJDBCPlugin.java index 5055837f0f..13adda8218 100644 --- a/CoreImportExportPlugins/src/au/gov/asd/tac/constellation/plugins/importexport/jdbc/ImportJDBCPlugin.java +++ b/CoreImportExportPlugins/src/au/gov/asd/tac/constellation/plugins/importexport/jdbc/ImportJDBCPlugin.java @@ -119,8 +119,8 @@ protected void edit(final GraphWriteMethods graph, final PluginInteraction inter final String query = parameters.getParameters().get(QUERY_PARAMETER_ID).getStringValue(); final List definitions = (List) parameters.getParameters().get(DEFINITIONS_PARAMETER_ID).getObjectValue(); final Boolean initialiseWithSchema = parameters.getParameters().get(SCHEMA_PARAMETER_ID).getBooleanValue(); - final List newVertices = new ArrayList<>(); boolean positionalAtrributesExist = false; + int totalImportedRows = 0; final String username = parameters.getParameters().get(USERNAME_PARAMETER_ID).getStringValue(); final String password = parameters.getParameters().get(PASSWORD_PARAMETER_ID).getStringValue(); @@ -148,19 +148,19 @@ protected void edit(final GraphWriteMethods graph, final PluginInteraction inter for (final ImportDefinition definition : definitions) { if (definition.getDefinitions(AttributeType.SOURCE_VERTEX).isEmpty()) { if (!definition.getDefinitions(AttributeType.DESTINATION_VERTEX).isEmpty()) { - processVertices(definition, graph, data, AttributeType.DESTINATION_VERTEX, initialiseWithSchema, interaction, newVertices); + totalImportedRows += processVertices(definition, graph, data, AttributeType.DESTINATION_VERTEX, initialiseWithSchema, interaction); } } else if (definition.getDefinitions(AttributeType.DESTINATION_VERTEX).isEmpty()) { - processVertices(definition, graph, data, AttributeType.SOURCE_VERTEX, initialiseWithSchema, interaction, newVertices); + totalImportedRows += processVertices(definition, graph, data, AttributeType.SOURCE_VERTEX, initialiseWithSchema, interaction); } else { - processTransactions(definition, graph, data, initialiseWithSchema, interaction); + totalImportedRows += processTransactions(definition, graph, data, initialiseWithSchema, interaction); } // Determine if a positional attribute has been defined, if so update the overall flag final boolean isPositional = attributeDefintionIsPositional(definition.getDefinitions(AttributeType.SOURCE_VERTEX), definition.getDefinitions(AttributeType.DESTINATION_VERTEX)); positionalAtrributesExist = (positionalAtrributesExist || isPositional); } - displaySummaryAlert(data.size(), connection.getConnectionName()); + displaySummaryAlert(totalImportedRows, data.size(), connection.getConnectionName()); // If at least one positional attribute has been received for either the src or destination vertex we will assume that the user is trying to import positions and won't auto arrange // the graph. This does mean some nodes could sit on top of each other if multiple nodes have the same coordinates. @@ -171,7 +171,7 @@ protected void edit(final GraphWriteMethods graph, final PluginInteraction inter graph.validateKey(GraphElementType.TRANSACTION, true); // unfortunately need to arrange with pendants and uncollide because grid arranger works based on selection - final VertexListInclusionGraph vlGraph = new VertexListInclusionGraph(graph, AbstractInclusionGraph.Connections.NONE, newVertices); + final VertexListInclusionGraph vlGraph = new VertexListInclusionGraph(graph, AbstractInclusionGraph.Connections.NONE, new ArrayList<>()); PluginExecutor.startWith(ArrangementPluginRegistry.GRID_COMPOSITE) .followedBy(ArrangementPluginRegistry.PENDANTS) .followedBy(ArrangementPluginRegistry.UNCOLLIDE) @@ -190,12 +190,13 @@ private static boolean attributeDefintionIsPositional(final List attribute.getAttribute().getName()).anyMatch(name -> (VisualConcept.VertexAttribute.X.getName().equals(name) || VisualConcept.VertexAttribute.Y.getName().equals(name) || VisualConcept.VertexAttribute.Z.getName().equals(name))); } - private static void processVertices(final ImportDefinition definition, final GraphWriteMethods graph, final List data, final AttributeType attributeType, final boolean initialiseWithSchema, final PluginInteraction interaction, final List newVertices) throws InterruptedException { + private static int processVertices(final ImportDefinition definition, final GraphWriteMethods graph, final List data, final AttributeType attributeType, final boolean initialiseWithSchema, final PluginInteraction interaction) throws InterruptedException { final List attributeDefinitions = definition.getDefinitions(attributeType); addAttributes(graph, GraphElementType.VERTEX, attributeDefinitions); int currentRow = 0; + int importedRows = 0; final int totalRows = data.size() - definition.getFirstRow(); final RowFilter filter = definition.getRowFilter(); @@ -205,8 +206,9 @@ private static void processVertices(final ImportDefinition definition, final Gra final String[] row = data.get(i); if (filter == null || filter.passesFilter(i, row)) { + // Count the number of processed rows to notify in the status message + ++importedRows; final int vertexId = graph.addVertex(); - newVertices.add(vertexId); for (final ImportAttributeDefinition attributeDefinition : attributeDefinitions) { attributeDefinition.setValue(graph, vertexId, row, (i - 1)); @@ -217,9 +219,10 @@ private static void processVertices(final ImportDefinition definition, final Gra } } } + return importedRows; } - private static void processTransactions(final ImportDefinition definition, final GraphWriteMethods graph, final List data, final boolean initialiseWithSchema, final PluginInteraction interaction) throws InterruptedException { + private static int processTransactions(final ImportDefinition definition, final GraphWriteMethods graph, final List data, final boolean initialiseWithSchema, final PluginInteraction interaction) throws InterruptedException { final List sourceVertexDefinitions = definition.getDefinitions(AttributeType.SOURCE_VERTEX); final List destinationVertexDefinitions = definition.getDefinitions(AttributeType.DESTINATION_VERTEX); final List transactionDefinitions = definition.getDefinitions(AttributeType.TRANSACTION); @@ -237,6 +240,7 @@ private static void processTransactions(final ImportDefinition definition, final addAttributes(graph, GraphElementType.TRANSACTION, transactionDefinitions); int currentRow = 0; + int importedRows = 0; final int totalRows = data.size() - definition.getFirstRow(); final RowFilter filter = definition.getRowFilter(); @@ -247,6 +251,8 @@ private static void processTransactions(final ImportDefinition definition, final final String[] row = data.get(i); if (filter == null || filter.passesFilter(i, row)) { + // Count the number of processed rows to notify in the status message + ++importedRows; final int sourceVertexId = graph.addVertex(); for (final ImportAttributeDefinition attributeDefinition : sourceVertexDefinitions) { attributeDefinition.setValue(graph, sourceVertexId, row, (i - 1)); @@ -275,6 +281,7 @@ private static void processTransactions(final ImportDefinition definition, final } } } + return importedRows; } /** @@ -311,7 +318,7 @@ private static void addAttributes(final GraphWriteMethods graph, final GraphElem * @param importedRows is the number of rows of data imported * @param connectionName the name of the connection */ - private void displaySummaryAlert(final int importedRows, final String connectionName) { + private void displaySummaryAlert(final int importedRows, final int totalRows, final String connectionName) { Platform.runLater(() -> { final StringBuilder sbHeader = new StringBuilder(); final StringBuilder sbMessage = new StringBuilder(); @@ -319,7 +326,7 @@ private void displaySummaryAlert(final int importedRows, final String connection if (importedRows > 0) { // At least 1 row was successfully imported. List all successful file imports, as well as any files that there were // issues for. If there were any files with issues use a warning dialog. - sbHeader.append(String.format("Imported %d rows of data from connection: %s", importedRows, connectionName)); + sbHeader.append(String.format("Imported %d out of %d rows of data from connection: %s", importedRows, totalRows, connectionName)); } else { // No rows were imported list all files that resulted in failures. diff --git a/CoreImportExportPlugins/src/au/gov/asd/tac/constellation/plugins/importexport/jdbc/JDBCSourcePane.java b/CoreImportExportPlugins/src/au/gov/asd/tac/constellation/plugins/importexport/jdbc/JDBCSourcePane.java index fa247ceafe..52903e9515 100644 --- a/CoreImportExportPlugins/src/au/gov/asd/tac/constellation/plugins/importexport/jdbc/JDBCSourcePane.java +++ b/CoreImportExportPlugins/src/au/gov/asd/tac/constellation/plugins/importexport/jdbc/JDBCSourcePane.java @@ -80,6 +80,7 @@ public class JDBCSourcePane extends SourcePane { private static final String PROMPT_TEXT_COLOUR = "-fx-prompt-text-fill: grey"; private static final String ADD_CONNECTION = "Add Connection"; private static final String MODIFY_CONNECTION = "Modify Connection"; + private static final String ADD_DRIVER = "Add Driver"; private final ComboBox dbConnectionComboBox; @@ -234,88 +235,7 @@ public JDBCSourcePane(final JDBCImportController importController) { }; final Button addDriverButton = new Button("Add"); - addDriverButton.setOnAction((final ActionEvent t1) -> { - final Stage d = new Stage(); - final BorderPane r = new BorderPane(); - final EasyGridPane gp = new EasyGridPane(); - gp.getColumnConstraints().addAll(column0Constraints, column1Constraints, column2Constraints); - gp.setPadding(GRIDPANE_PADDING); - gp.setHgap(GAP); - gp.setVgap(GAP); - final Label jarLabel = new Label("Driver"); - gp.add(jarLabel, 0, 0, 1, 1); - final TextField j = new TextField(); - gp.add(j, 1, 0, 1, 1); - final Label nameLabel = new Label("Name"); - gp.add(nameLabel, 0, 1, 1, 1); - final ComboBox driverName = new ComboBox(); - gp.add(driverName, 1, 1, 1, 1); - final Button chooser = new Button(" ... "); - chooser.setOnAction((final ActionEvent t2) -> { - final FileChooser cho = new FileChooser(); - cho.getExtensionFilters().add(new ExtensionFilter(FileExtensionConstants.JAR, "*.jar")); - - final File f = cho.showOpenDialog(d); - if (f != null) { - try { - j.setText(f.getCanonicalPath()); - driverName.getItems().clear(); - driverName.getItems().addAll(JDBCDriver.getDrivers(f)); - driverName.getSelectionModel().selectFirst(); - } catch (final IOException ex) { - LOGGER.log(Level.WARNING, ex.getMessage(), ex); - } - } - }); - gp.add(chooser, 2, 0, 1, 1); - final Button add = new Button("Add"); - add.setOnAction((final ActionEvent t2) -> { - if (driverName.getSelectionModel().getSelectedItem() != null) { - if (driverManager.isDriverUsed((String) driverName.getSelectionModel().getSelectedItem())) { - final Optional res = NotifyDisplayer.displayConfirmationAlert(TITLE_JDBC_IMPORT, - "Add Driver", "This Driver already exists.\n Do you want to overwrite?"); - if (!res.isPresent() || res.get() == ButtonType.NO) { - return; - } - } - driverManager.addDriver((String) driverName.getSelectionModel().getSelectedItem(), new File(j.getText())); - driverTable.getItems().clear(); - driverTable.getItems().addAll(driverManager.getDrivers()); - driver.getItems().clear(); - driver.getItems().addAll(driverManager.getDrivers()); - d.close(); - } - }); - gp.add(add, 0, 2, 1, 1); - final Button buttonCancel = new Button(ACTION_CANCEL); - buttonCancel.setOnAction((final ActionEvent event) -> { - event.consume(); - final Stage stage = (Stage) buttonCancel.getScene().getWindow(); - stage.close(); - }); - gp.add(buttonCancel, 2, 2, 1, 1); - - final ScrollPane sp = new ScrollPane(gp); - sp.setFitToWidth(true); - sp.setPrefHeight(SCROLLPANE_PREF_HEIGHT); - sp.setPrefWidth(SCROLLPANE_PREF_WIDTH); - sp.setHbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED); - sp.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED); - r.setCenter(sp); - - final Scene scene2 = new Scene(r); - scene2.setFill(Color.WHITESMOKE); - scene2.getStylesheets().add(JavafxStyleManager.getMainStyleSheet()); - d.setScene(scene2); - d.setTitle("Add Driver"); - d.centerOnScreen(); - d.initOwner(dialog); - d.initModality(Modality.APPLICATION_MODAL); - d.setAlwaysOnTop(true); - d.setWidth(LARGE_SCROLLPANE_PREF_WIDTH); - d.setHeight(ADD_DRIVER_PANE_HEIGHT); - d.showAndWait(); - }); + addDriverButton.setOnAction((final ActionEvent t1) -> openAddDriverDialog(driverManager, driverTable, driver, dialog)); driversTabGridPane.add(addDriverButton, 0, 1, 1, 1); final Button removeBtn1 = new Button("Remove"); @@ -397,6 +317,111 @@ public JDBCSourcePane(final JDBCImportController importController) { passwordLabel, password, queryLabel, query, destinationLabel, graphComboBox, queryButton); } + private void openAddDriverDialog(final JDBCDriverManager driverManager, final TableView driverTable, final ComboBox driver, final Stage dialog) { + final Stage d = new Stage(); + final BorderPane r = new BorderPane(); + final EasyGridPane gp = new EasyGridPane(); + gp.getColumnConstraints().addAll(column0Constraints, column1Constraints, column2Constraints); + gp.setPadding(GRIDPANE_PADDING); + gp.setHgap(GAP); + gp.setVgap(GAP); + final Label jarLabel = new Label("Driver"); + gp.add(jarLabel, 0, 0, 1, 1); + final TextField driverFilePath = new TextField(); + driverFilePath.setPromptText("Select or enter the JDBC driver JAR file"); + driverFilePath.setStyle(PROMPT_TEXT_COLOUR); + driverFilePath.setFocusTraversable(false); + gp.add(driverFilePath, 1, 0, 1, 1); + + final Label nameLabel = new Label("Name"); + gp.add(nameLabel, 0, 1, 1, 1); + final ComboBox driverName = new ComboBox(); + gp.add(driverName, 1, 1, 1, 1); + final Button chooser = new Button(" ... "); + chooser.setOnAction((final ActionEvent t2) -> { + final FileChooser cho = new FileChooser(); + cho.getExtensionFilters().add(new ExtensionFilter(FileExtensionConstants.JAR, "*.jar")); + + final File f = cho.showOpenDialog(d); + + if (f != null) { + try { + driverFilePath.setText(f.getCanonicalPath()); + setDriver(f, driverName); + } catch (final IOException ex) { + LOGGER.log(Level.WARNING, ex.getMessage(), ex); + } + } + }); + // Allow manual editing on the driver path + driverFilePath.textProperty().addListener((observable, oldValue, newValue) -> { + if (!StringUtils.isBlank(driverFilePath.getText())) { + final File f = new File(newValue); + if (f != null) { + setDriver(f, driverName); + } + } + }); + gp.add(chooser, 2, 0, 1, 1); + final Button add = new Button("Add"); + add.setOnAction((final ActionEvent t2) -> { + if (!validateDriverParams(driverFilePath, driverName)) { + return; + } + + if (driverName.getSelectionModel().getSelectedItem() != null) { + if (driverManager.isDriverUsed((String) driverName.getSelectionModel().getSelectedItem())) { + final Optional res = NotifyDisplayer.displayConfirmationAlert(TITLE_JDBC_IMPORT, + ADD_DRIVER, "This Driver already exists.\n Do you want to overwrite?"); + if (!res.isPresent() || res.get() == ButtonType.NO) { + return; + } + } + driverManager.addDriver((String) driverName.getSelectionModel().getSelectedItem(), new File(driverFilePath.getText())); + driverTable.getItems().clear(); + driverTable.getItems().addAll(driverManager.getDrivers()); + driver.getItems().clear(); + driver.getItems().addAll(driverManager.getDrivers()); + d.close(); + } + }); + gp.add(add, 0, 2, 1, 1); + final Button buttonCancel = new Button(ACTION_CANCEL); + buttonCancel.setOnAction((final ActionEvent event) -> { + event.consume(); + final Stage stage = (Stage) buttonCancel.getScene().getWindow(); + stage.close(); + }); + gp.add(buttonCancel, 2, 2, 1, 1); + + final ScrollPane sp = new ScrollPane(gp); + sp.setFitToWidth(true); + sp.setPrefHeight(SCROLLPANE_PREF_HEIGHT); + sp.setPrefWidth(SCROLLPANE_PREF_WIDTH); + sp.setHbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED); + sp.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED); + r.setCenter(sp); + + final Scene scene2 = new Scene(r); + scene2.setFill(Color.WHITESMOKE); + scene2.getStylesheets().add(JavafxStyleManager.getMainStyleSheet()); + d.setScene(scene2); + d.setTitle(ADD_DRIVER); + d.centerOnScreen(); + d.initOwner(dialog); + d.initModality(Modality.APPLICATION_MODAL); + d.setAlwaysOnTop(true); + d.setWidth(LARGE_SCROLLPANE_PREF_WIDTH); + d.setHeight(ADD_DRIVER_PANE_HEIGHT); + d.showAndWait(); + } + + private void setDriver(final File f, final ComboBox driverName) { + driverName.getItems().clear(); + driverName.getItems().addAll(JDBCDriver.getDrivers(f)); + driverName.getSelectionModel().selectFirst(); + } + /** * The import controller has been modified: update the GUI to match. * @@ -407,7 +432,25 @@ public void update(final ImportController importController) { graphComboBox.getSelectionModel().select(((JDBCImportController) importController).getDestination()); } - + + private boolean validateDriverParams(final TextField driverFilePath, final ComboBox driverName) { + final StringJoiner missingParamsMsgs = new StringJoiner(System.lineSeparator() + System.lineSeparator()); + + if (StringUtils.isBlank(driverFilePath.getText())) { + missingParamsMsgs.add("Driver - please select or enter the JDBC driver JAR file before continuing."); + } else if (driverName.getValue() == null) { + missingParamsMsgs.add("Driver Name - please select or enter a valid JDBC driver JAR file to populate the driver name."); + } + if (missingParamsMsgs.length() > 0) { + NotifyDisplayer.displayAlert(ADD_DRIVER, + "Missing driver parameters", + missingParamsMsgs.toString(), + AlertType.ERROR); + return false; + } + return true; + } + private boolean validateConnectionParams(final TextField cn, final TextField connectionStringF, final ComboBox driversComboBox) { final StringJoiner missingParamsMsgs = new StringJoiner(System.lineSeparator() + System.lineSeparator());