From bc2764b123f4ec7b31fdf9e4dd6d7f193d5885ce Mon Sep 17 00:00:00 2001 From: Dmitry Isaenko Date: Wed, 22 May 2019 03:50:43 +0300 Subject: [PATCH] Titlekeys support implemented in Preferences and Setting classes --- src/main/java/konogonka/AppPreferences.java | 31 +++-- .../Controllers/NCA/NCAController.java | 5 + .../Settings/ListSelectorController.java | 113 ++++++++++++++++++ .../Settings/SettingsController.java | 62 ++++++++-- .../FXML/Settings/ListSelectorLayout.fxml | 40 +++++++ .../FXML/Settings/SettingsLayout.fxml | 2 +- 6 files changed, 235 insertions(+), 18 deletions(-) create mode 100644 src/main/java/konogonka/Settings/ListSelectorController.java create mode 100644 src/main/resources/FXML/Settings/ListSelectorLayout.fxml diff --git a/src/main/java/konogonka/AppPreferences.java b/src/main/java/konogonka/AppPreferences.java index 0820480..0eda866 100644 --- a/src/main/java/konogonka/AppPreferences.java +++ b/src/main/java/konogonka/AppPreferences.java @@ -1,6 +1,5 @@ package konogonka; -import java.util.HashMap; import java.util.prefs.Preferences; public class AppPreferences { @@ -8,8 +7,12 @@ public class AppPreferences { public static AppPreferences getInstance() { return INSTANCE; } private Preferences preferences; + private int titleKeysCount; - private AppPreferences(){ preferences = Preferences.userRoot().node("konogonka"); } + private AppPreferences(){ + preferences = Preferences.userRoot().node("konogonka"); + titleKeysCount = getTitleKeysCount(); + } public void setAll( String xciHeaderKey, @@ -98,11 +101,25 @@ public class AppPreferences { public String getSystemKey(int number){ return preferences.get("key_area_key_system_0"+number, "");} public void setSystemKey(int number, String key){ preferences.put("key_area_key_system_0"+number, key); } - public int getTitleKeysCount(){ return preferences.getInt("title_keys_count", 0);} - public void setTitleKeysCount(int number){ preferences.putInt("title_keys_count", number);} - public String[] getTitleKey(int number){ - return preferences.get(Integer.toString(number), "0 = 0").split(" = ", 2); + + public int getTitleKeysCount(){ + return preferences.getInt("title_keys_count", 0); } - public void setTitleKey(int number, String name, String value){ preferences.put(Integer.toString(number), name+" = "+value); } + // Since we don't want to store title keys that are no longer in use, we have to (try to) remove them. + // This part of code works as a charm. Don't touch. + public void setTitleKeysCount(int number){ + if (this.titleKeysCount > number){ + for (int i = number; i < this.titleKeysCount; i++) { + preferences.remove("title_key_"+i); + } + } + preferences.putInt("title_keys_count", number); + this.titleKeysCount = number; + } + + public String[] getTitleKeyPair(int number){ + return preferences.get("title_key_"+number, "0 = 0").split(" = ", 2); + } + public void setTitleKey(int number, String pair){ preferences.put("title_key_"+number, pair); } } diff --git a/src/main/java/konogonka/Controllers/NCA/NCAController.java b/src/main/java/konogonka/Controllers/NCA/NCAController.java index 4f20738..b32d981 100644 --- a/src/main/java/konogonka/Controllers/NCA/NCAController.java +++ b/src/main/java/konogonka/Controllers/NCA/NCAController.java @@ -82,6 +82,11 @@ public class NCAController implements TabController { keysMap.put("key_area_key_system_0"+i, AppPreferences.getInstance().getSystemKey(i)); // TODO: Add titlekeys } + for (int i = 0; i < AppPreferences.getInstance().getTitleKeysCount(); i++){ + String[] pair = AppPreferences.getInstance().getTitleKeyPair(i); + if ( ! pair[0].equals("0") && ! pair[1].equals("0")) + keysMap.put(pair[0], pair[1]); + } AnalyzerNCA analyzerNCA = new AnalyzerNCA(file, keysMap); analyzerNCA.setOnSucceeded(e->{ diff --git a/src/main/java/konogonka/Settings/ListSelectorController.java b/src/main/java/konogonka/Settings/ListSelectorController.java new file mode 100644 index 0000000..fd925c6 --- /dev/null +++ b/src/main/java/konogonka/Settings/ListSelectorController.java @@ -0,0 +1,113 @@ +package konogonka.Settings; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.fxml.Initializable; +import javafx.scene.control.ListView; +import javafx.scene.control.TextField; +import javafx.scene.control.TextFormatter; +import javafx.scene.input.KeyEvent; +import konogonka.ServiceWindow; + +import java.net.URL; +import java.util.Arrays; +import java.util.HashMap; +import java.util.ResourceBundle; + +public class ListSelectorController implements Initializable { + @FXML + private ListView listView; + @FXML + private TextField newRecordName, newRecordValue; + private ObservableList observableList; + + private int mandatoryValueLength; + private String predictionPattern; + + @Override + public void initialize(URL url, ResourceBundle resourceBundle) { + observableList = FXCollections.observableArrayList(); + listView.setItems(observableList); + + newRecordValue.setTextFormatter(new TextFormatter(change -> { + if (change.getControlNewText().matches("^[a-fA-F0-9]+$") || change.getControlNewText().isEmpty()) + return change; + return null; + })); + } + public void initSelector(int length, String predictionPattern){ + this.mandatoryValueLength = length; + + if (predictionPattern == null){ // If we need no validation, restrict only spaces/tabs adding + newRecordName.setTextFormatter(new TextFormatter(change -> { + if (change.getControlNewText().contains(" ") || change.getControlNewText().contains("\t")) + return null; + return change; + })); + } + else { // Otherwise use pattern as name of key + 2 dec numbers + this.predictionPattern = predictionPattern; + + newRecordName.setText(predictionPattern); + newRecordName.setTextFormatter(new TextFormatter(change -> { + if (change.getControlNewText().matches("^"+predictionPattern+"[0-9]{0,2}$")) + return change; + return null; + })); + } + } + /** + * Must be run on start + * Set list content + */ + void setList(HashMap stringPairsArray){ + if (stringPairsArray != null && ! stringPairsArray.isEmpty()) + for (String name: stringPairsArray.keySet()) + validateAndAdd(name+" = "+stringPairsArray.get(name)); + } + /** + * Return list content + * */ + String[] getList(){ + return Arrays.copyOf(observableList.toArray(), observableList.toArray().length, String[].class); + } + + @FXML + private void listKeyPressed(KeyEvent event){ + if (event.getCode().toString().equals("DELETE")) + removeRecord(); + } + + @FXML + private void removeRecord(){ observableList.remove(listView.getSelectionModel().getSelectedItem()); } + + @FXML + private void addNewRecord(){ + if (newRecordValue.getText().length() == mandatoryValueLength && ! newRecordName.getText().isEmpty()) { + if (predictionPattern == null) { + validateAndAdd(newRecordName.getText() + " = " + newRecordValue.getText()); + newRecordName.clear(); + newRecordValue.clear(); + } + else { + if (newRecordName.getText().matches("^"+predictionPattern+"[0-9]{2}$")){ + validateAndAdd(newRecordName.getText() + " = " + newRecordValue.getText()); + newRecordName.setText(predictionPattern); + newRecordValue.clear(); + } + else + ServiceWindow.getErrorNotification("Error", "Value name should be: '"+predictionPattern+"XX' where XX are two decimal numbers."); + } + } + else { + ServiceWindow.getErrorNotification("Error", "One of the fields empty or value leigh is incorrect."); + } + } + + private void validateAndAdd(String addingItem){ + if (!observableList.contains(addingItem)) { + observableList.add(addingItem); + } + } +} diff --git a/src/main/java/konogonka/Settings/SettingsController.java b/src/main/java/konogonka/Settings/SettingsController.java index 85c152b..0e5bcaf 100644 --- a/src/main/java/konogonka/Settings/SettingsController.java +++ b/src/main/java/konogonka/Settings/SettingsController.java @@ -5,7 +5,6 @@ import javafx.fxml.Initializable; import javafx.scene.control.Button; import javafx.scene.control.TextField; import javafx.scene.control.TextFormatter; -import javafx.scene.layout.VBox; import javafx.stage.FileChooser; import javafx.stage.Stage; import konogonka.AppPreferences; @@ -19,8 +18,10 @@ import java.util.ResourceBundle; public class SettingsController implements Initializable { @FXML private Button okBtn, cancelBtn, importKeysBtn, importTitleKeysBtn; + @FXML - private VBox titleKeysVbox; + ListSelectorController ListSelectorTitleKeysController; + @FXML private TextField xciHdrKeyTF, @@ -52,6 +53,17 @@ public class SettingsController implements Initializable { @Override public void initialize(URL url, ResourceBundle resourceBundle) { + ListSelectorTitleKeysController.initSelector(32, null); // 32 required + + HashMap preparedPairsMapInit = new HashMap<>(); + for (int i = 0; i < AppPreferences.getInstance().getTitleKeysCount(); i++){ + preparedPairsMapInit.put( + AppPreferences.getInstance().getTitleKeyPair(i)[0], + AppPreferences.getInstance().getTitleKeyPair(i)[1] + ); + } + ListSelectorTitleKeysController.setList(preparedPairsMapInit); + xciHdrKeyTF.setText(AppPreferences.getInstance().getXciHeaderKey()); hdrKeyTF.setText(AppPreferences.getInstance().getHeaderKey()); keyApp0TF.setText(AppPreferences.getInstance().getApplicationKey(0)); @@ -157,12 +169,37 @@ public class SettingsController implements Initializable { catch (IOException ioe){ ioe.printStackTrace(); } - /* - for (String key: fileMap.keySet()){ - System.out.print(key+ " - "); - System.out.println(fileMap.get(key)); + } + }); + + importTitleKeysBtn.setOnAction(e->{ + FileChooser fileChooser = new FileChooser(); + fileChooser.setTitle("title.keys"); + fileChooser.setInitialDirectory(new File(System.getProperty("user.home"))); + fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("title.keys", "title.keys")); + + File prodKeysFile = fileChooser.showOpenDialog(importKeysBtn.getScene().getWindow()); + + if (prodKeysFile != null && prodKeysFile.exists()) { + try { + BufferedReader br = new BufferedReader( + new FileReader(prodKeysFile) + ); + + String fileLine; + String[] keyValue; + HashMap preparedPairsMap = new HashMap<>(); + while ((fileLine = br.readLine()) != null){ + keyValue = fileLine.trim().split("\\s+?=\\s+?", 2); + if (keyValue.length == 2 && keyValue[0].length() == 32 && keyValue[1].length() == 32){ + preparedPairsMap.put(keyValue[0], keyValue[1]); + } + } + ListSelectorTitleKeysController.setList(preparedPairsMap); + } + catch (IOException ioe){ + ioe.printStackTrace(); } - //*/ } }); @@ -201,16 +238,21 @@ public class SettingsController implements Initializable { keySys6TF.getText(), keySys7TF.getText() ); + String[] titleKeysSet = ListSelectorTitleKeysController.getList(); + if (titleKeysSet != null){ + AppPreferences.getInstance().setTitleKeysCount(titleKeysSet.length); + for (int i = 0; i < titleKeysSet.length; i++) + AppPreferences.getInstance().setTitleKey(i, titleKeysSet[i]); + } thisStage.close(); }); } private void setTextValidation(TextField tf){ tf.setTextFormatter(new TextFormatter(change -> { - if (change.getControlNewText().contains(" ") | change.getControlNewText().contains("\t")) + if (change.getControlNewText().contains(" ") || change.getControlNewText().contains("\t")) return null; - else - return change; + return change; })); } } \ No newline at end of file diff --git a/src/main/resources/FXML/Settings/ListSelectorLayout.fxml b/src/main/resources/FXML/Settings/ListSelectorLayout.fxml new file mode 100644 index 0000000..a887551 --- /dev/null +++ b/src/main/resources/FXML/Settings/ListSelectorLayout.fxml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/FXML/Settings/SettingsLayout.fxml b/src/main/resources/FXML/Settings/SettingsLayout.fxml index 85f6b56..dd206f2 100644 --- a/src/main/resources/FXML/Settings/SettingsLayout.fxml +++ b/src/main/resources/FXML/Settings/SettingsLayout.fxml @@ -224,7 +224,7 @@ - +