diff --git a/src/main/java/nsusbloader/Controllers/FilesDropHandle.java b/src/main/java/nsusbloader/Controllers/FilesDropHandle.java new file mode 100644 index 0000000..4fb9e96 --- /dev/null +++ b/src/main/java/nsusbloader/Controllers/FilesDropHandle.java @@ -0,0 +1,120 @@ +/* + Copyright 2019-2020 Dmitry Isaenko + + This file is part of NS-USBloader. + + NS-USBloader is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + NS-USBloader is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with NS-USBloader. If not, see . +*/ +package nsusbloader.Controllers; + +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.ProgressBar; +import javafx.scene.control.ProgressIndicator; +import javafx.scene.image.Image; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Pane; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; +import javafx.stage.Stage; +import nsusbloader.AppPreferences; +import nsusbloader.MediatorControl; + +import java.io.File; +import java.util.List; +import java.util.ResourceBundle; + +public class FilesDropHandle { + + public FilesDropHandle(List files, String filesRegex, String foldersRegex){ + + // + // TODO: ADD GRAPHICS BEFORE RELEASE ! + // + + FilesDropHandleTask filesDropHandleTask = new FilesDropHandleTask(files, filesRegex, foldersRegex); + + ResourceBundle resourceBundle = MediatorControl.getInstance().getResourceBundle(); + Button cancelButton = new Button(resourceBundle.getString("btn_Cancel")); + + ProgressIndicator progressIndicator = new ProgressIndicator(); + progressIndicator.setProgress(ProgressIndicator.INDETERMINATE_PROGRESS); + + Label downloadStatusLabel = new Label(); + downloadStatusLabel.setWrapText(true); + downloadStatusLabel.textProperty().bind(filesDropHandleTask.messageProperty()); + + Pane fillerPane1 = new Pane(); + Pane fillerPane2 = new Pane(); + + VBox parentVBox = new VBox(); + parentVBox.setAlignment(Pos.TOP_CENTER); + parentVBox.setFillWidth(true); + parentVBox.setSpacing(5.0); + parentVBox.setPadding(new Insets(5.0)); + parentVBox.setFillWidth(true); + parentVBox.getChildren().addAll( + downloadStatusLabel, + fillerPane1, + progressIndicator, + fillerPane2, + cancelButton + ); // TODO:FIX + + VBox.setVgrow(fillerPane1, Priority.ALWAYS); + VBox.setVgrow(fillerPane2, Priority.ALWAYS); + + Stage stage = new Stage(); + stage.setTitle(resourceBundle.getString("windowTitleAddingFiles")); + stage.getIcons().addAll( + new Image("/res/dwnload_ico32x32.png"), //TODO: REDRAW + new Image("/res/dwnload_ico48x48.png"), + new Image("/res/dwnload_ico64x64.png"), + new Image("/res/dwnload_ico128x128.png") + ); + stage.setMinWidth(300); + stage.setMinHeight(175); + stage.setAlwaysOnTop(true); + Scene mainScene = new Scene(parentVBox, 310, 185); + + mainScene.getStylesheets().add(AppPreferences.getInstance().getTheme()); + + stage.setOnHidden(windowEvent -> filesDropHandleTask.cancel(true ) ); + + stage.setScene(mainScene); + stage.show(); + stage.toFront(); + + filesDropHandleTask.setOnSucceeded(event -> { + cancelButton.setText(resourceBundle.getString("btn_Close")); + + List allFiles = filesDropHandleTask.getValue(); + + if (! allFiles.isEmpty()) { + MediatorControl.getInstance().getGamesController().tableFilesListController.setFiles(allFiles); + } + stage.close(); + }); + + new Thread(filesDropHandleTask).start(); + + cancelButton.setOnAction(actionEvent -> { + filesDropHandleTask.cancel(true); + stage.close(); + }); + } +} diff --git a/src/main/java/nsusbloader/Controllers/FilesDropHandleTask.java b/src/main/java/nsusbloader/Controllers/FilesDropHandleTask.java new file mode 100644 index 0000000..93bc8ad --- /dev/null +++ b/src/main/java/nsusbloader/Controllers/FilesDropHandleTask.java @@ -0,0 +1,96 @@ +/* + Copyright 2019-2020 Dmitry Isaenko + + This file is part of NS-USBloader. + + NS-USBloader is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + NS-USBloader is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with NS-USBloader. If not, see . +*/ +package nsusbloader.Controllers; + +import javafx.concurrent.Task; +import nsusbloader.MediatorControl; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class FilesDropHandleTask extends Task> { + private final String filesRegex; + private final String foldersRegex; + + private final List filesDropped; + private final List allFiles; + + private String messageTemplate; + private long filesScanned = 0; + private long filesAdded = 0; + + FilesDropHandleTask(List files, + String filesRegex, + String foldersRegex) { + this.filesDropped = files; + this.filesRegex = filesRegex; + this.foldersRegex = foldersRegex; + this.allFiles = new ArrayList<>(); + this.messageTemplate = MediatorControl.getInstance().getResourceBundle().getString("windowBodyFilesScanned"); + } + + @Override + protected List call() { + if (filesDropped == null || filesDropped.size() == 0) + return allFiles; + + for (File file : filesDropped){ + if (isCancelled()) + return new ArrayList<>(); + collectFiles(file); + updateMessage(String.format(messageTemplate, filesScanned++, filesAdded)); + } + + return allFiles; + } + + private void collectFiles(File startFolder) { + if (startFolder == null) + return; + + final String startFolderNameInLowercase = startFolder.getName().toLowerCase(); + + if (startFolder.isFile()) { + if (startFolderNameInLowercase.matches(filesRegex)) { + allFiles.add(startFolder); + filesAdded++; + } + return; + } + + if (startFolderNameInLowercase.matches(foldersRegex)) { + allFiles.add(startFolder); + filesAdded++; + return; + } + + File[] files = startFolder.listFiles(); + if (files == null) + return; + + for (File file : files) { + if (isCancelled()) + return; + collectFiles(file); + updateMessage(String.format(messageTemplate, filesScanned++, filesAdded)); + } + } + +} diff --git a/src/main/java/nsusbloader/Controllers/GamesController.java b/src/main/java/nsusbloader/Controllers/GamesController.java index d204c82..3ccccd9 100644 --- a/src/main/java/nsusbloader/Controllers/GamesController.java +++ b/src/main/java/nsusbloader/Controllers/GamesController.java @@ -41,10 +41,7 @@ import nsusbloader.ServiceWindow; import java.io.File; import java.net.URL; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.ResourceBundle; +import java.util.*; import java.util.function.Consumer; import java.util.function.Supplier; @@ -294,6 +291,7 @@ public class GamesController implements Initializable { * @param filesRegex for filenames */ // TODO: Too sophisticated. Should be moved to simple class to keep things simplier + private void collectFiles(List storage, File startFolder, final String filesRegex, @@ -437,24 +435,10 @@ public class GamesController implements Initializable { * */ @FXML private void handleDrop(DragEvent event) { - final String regexForFiles = getRegexForFiles(); - final String regexForFolders = getRegexForFolders(); - List files = event.getDragboard().getFiles(); - - performInBackgroundAndUpdate(() -> { - List allFiles = new ArrayList<>(); - if (files != null && files.size() != 0) { - files.forEach(f -> collectFiles(allFiles, f, regexForFiles, regexForFolders)); - } - return allFiles; - }, allFiles -> { - if (!allFiles.isEmpty()) - tableFilesListController.setFiles(allFiles); - - event.setDropCompleted(true); - event.consume(); - }); + new FilesDropHandle(files, getRegexForFiles(), getRegexForFolders()); + event.setDropCompleted(true); + event.consume(); } /** @@ -527,7 +511,6 @@ public class GamesController implements Initializable { selectSplitNspBtn.setVisible(true); } selectNspBtn.setGraphic(btnSelectImage); - //selectFolderBtn.setTooltip(new Tooltip(resourceBundle.getString("btn_OpenFolders_tooltip"))); } /** * Get 'Recent' path diff --git a/src/main/java/nsusbloader/Controllers/NSTableViewController.java b/src/main/java/nsusbloader/Controllers/NSTableViewController.java index 5017829..267da43 100644 --- a/src/main/java/nsusbloader/Controllers/NSTableViewController.java +++ b/src/main/java/nsusbloader/Controllers/NSTableViewController.java @@ -231,7 +231,7 @@ public class NSTableViewController implements Initializable { /** * Add files when user selected them * */ - public void setFiles(List newFiles){ + public synchronized void setFiles(List newFiles){ if (!rowsObsLst.isEmpty()){ List filesAlreayInList = new ArrayList<>(); for (NSLRowModel model : rowsObsLst) diff --git a/src/main/java/nsusbloader/com/usb/TinFoil.java b/src/main/java/nsusbloader/com/usb/TinFoil.java index 9ceba47..d033f08 100644 --- a/src/main/java/nsusbloader/com/usb/TinFoil.java +++ b/src/main/java/nsusbloader/com/usb/TinFoil.java @@ -222,7 +222,6 @@ class TinFoil extends TransferModule { if ((currentOffset + chunk) >= size ) chunk = Math.toIntExact(size - currentOffset); //System.out.println("CO: "+currentOffset+"\t\tEO: "+size+"\t\tRP: "+chunk); // NOTE: DEBUG - logPrinter.updateProgress((currentOffset + chunk) / (size / 100.0) / 100.0); readBuffer = new byte[chunk]; // TODO: not perfect moment, consider refactoring. @@ -232,6 +231,7 @@ class TinFoil extends TransferModule { if (writeUsb(readBuffer)) throw new IOException("TF Failure during file transfer."); currentOffset += chunk; + logPrinter.updateProgress((double)currentOffset / (double)size); } nsSplitReader.close(); logPrinter.updateProgress(1.0); @@ -251,7 +251,6 @@ class TinFoil extends TransferModule { if ((currentOffset + chunk) >= size) chunk = Math.toIntExact(size - currentOffset); //System.out.println("CO: "+currentOffset+"\t\tEO: "+receivedRangeSize+"\t\tRP: "+chunk); // NOTE: DEBUG - logPrinter.updateProgress((currentOffset + chunk) / (size / 100.0) / 100.0); readBuffer = new byte[chunk]; @@ -261,6 +260,7 @@ class TinFoil extends TransferModule { if (writeUsb(readBuffer)) throw new IOException("TF Failure during file transfer."); currentOffset += chunk; + logPrinter.updateProgress((double)currentOffset / (double)size); } bufferedInStream.close(); logPrinter.updateProgress(1.0); diff --git a/src/main/resources/locale.properties b/src/main/resources/locale.properties index 7e9c763..b629b93 100644 --- a/src/main/resources/locale.properties +++ b/src/main/resources/locale.properties @@ -72,4 +72,6 @@ tab2_Cb_GlVersion=GoldLeaf version tab2_Cb_GLshowNspOnly=Show only *.nsp in GoldLeaf. windowBodyPleaseStopOtherProcessFirst=Please stop other active process before continuing. tab2_Cb_foldersSelectorForRoms=Select folder with ROM files instead of selecting ROMs individually. -tab2_Cb_foldersSelectorForRomsDesc=Changes 'Select files' button behaviour on 'Games' tab: instead of selecting ROM files one-by-one you can choose folder to add every supported file at once. \ No newline at end of file +tab2_Cb_foldersSelectorForRomsDesc=Changes 'Select files' button behaviour on 'Games' tab: instead of selecting ROM files one-by-one you can choose folder to add every supported file at once. +windowTitleAddingFiles=Searching for files... +windowBodyFilesScanned=Files scanned: %d\nWould be added: %d \ No newline at end of file diff --git a/src/main/resources/locale_en_US.properties b/src/main/resources/locale_en_US.properties index 7e9c763..b629b93 100644 --- a/src/main/resources/locale_en_US.properties +++ b/src/main/resources/locale_en_US.properties @@ -72,4 +72,6 @@ tab2_Cb_GlVersion=GoldLeaf version tab2_Cb_GLshowNspOnly=Show only *.nsp in GoldLeaf. windowBodyPleaseStopOtherProcessFirst=Please stop other active process before continuing. tab2_Cb_foldersSelectorForRoms=Select folder with ROM files instead of selecting ROMs individually. -tab2_Cb_foldersSelectorForRomsDesc=Changes 'Select files' button behaviour on 'Games' tab: instead of selecting ROM files one-by-one you can choose folder to add every supported file at once. \ No newline at end of file +tab2_Cb_foldersSelectorForRomsDesc=Changes 'Select files' button behaviour on 'Games' tab: instead of selecting ROM files one-by-one you can choose folder to add every supported file at once. +windowTitleAddingFiles=Searching for files... +windowBodyFilesScanned=Files scanned: %d\nWould be added: %d \ No newline at end of file diff --git a/src/main/resources/locale_ru_RU.properties b/src/main/resources/locale_ru_RU.properties index c8d6bc5..1dc4885 100644 --- a/src/main/resources/locale_ru_RU.properties +++ b/src/main/resources/locale_ru_RU.properties @@ -71,4 +71,6 @@ tab2_Cb_GlVersion=\u0412\u0435\u0440\u0441\u0438\u044F GoldLeaf windowBodyPleaseStopOtherProcessFirst=\u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0435 \u0434\u0440\u0443\u0433\u043E\u0439 \u0430\u043A\u0442\u0438\u0432\u043D\u044B\u0439 \u043F\u0440\u043E\u0446\u0435\u0441\u0441 \u043F\u0435\u0440\u0435\u0434 \u0442\u0435\u043C, \u043A\u0430\u043A \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u044C. tab2_Cb_foldersSelectorForRomsDesc=\u041C\u0435\u043D\u044F\u0435\u0442 \u043F\u043E\u0432\u0435\u0434\u0435\u043D\u0438\u0435 \u043A\u043D\u043E\u043F\u043A\u0438 "\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0444\u0430\u0439\u043B\u044B" \u043D\u0430 \u0432\u043A\u043B\u0430\u0434\u043A\u0435 '\u0418\u0433\u0440\u044B'. \u0412\u043C\u0435\u0441\u0442\u043E \u0432\u044B\u0431\u043E\u0440\u0430 ROM \u0444\u0430\u0439\u043B\u043E\u0432 \u043F\u043E \u043E\u0434\u043D\u043E\u043C\u0443 \u0432\u044B \u0443\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442\u0435 \u043F\u0430\u043F\u043A\u0443, \u043F\u043E\u0441\u043B\u0435 \u0447\u0435\u0433\u043E \u0432\u0441\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043C\u044B\u0435 \u043E\u0431\u0440\u0430\u0437\u044B \u0434\u043E\u0431\u0430\u0432\u043B\u044F\u044E\u0442\u0441\u044F. tab2_Cb_foldersSelectorForRoms=\u0412\u044B\u0431\u0438\u0440\u0430\u0442\u044C \u043F\u0430\u043F\u043A\u0443 \u0441 ROM \u0444\u0430\u0439\u043B\u0430\u043C\u0438 \u0432\u043C\u0435\u0441\u0442\u043E \u0432\u044B\u0431\u043E\u0440\u0430 \u0444\u0430\u0439\u043B\u043E\u0432 \u043F\u043E\u043E\u0434\u0438\u043D\u043E\u0447\u043A\u0435. +windowTitleAddingFiles=\u0418\u0449\u0435\u043C \u0444\u0430\u0439\u043B\u044B... +windowBodyFilesScanned=\u0424\u0430\u0439\u043B\u043E\u0432 \u043F\u0440\u043E\u0441\u043A\u0430\u043D\u0438\u0440\u043E\u0432\u0430\u043D\u043E: %d\n\u0418\u0437 \u043A\u043E\u0442\u043E\u0440\u044B\u0445 \u0431\u0443\u0434\u0435\u0442 \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u043E: %d diff --git a/src/main/resources/locale_uk_UA.properties b/src/main/resources/locale_uk_UA.properties index b5072e2..0152896 100644 --- a/src/main/resources/locale_uk_UA.properties +++ b/src/main/resources/locale_uk_UA.properties @@ -71,3 +71,5 @@ tab2_Cb_GlVersion=\u0412\u0435\u0440\u0441\u0456\u044F GoldLeaf windowBodyPleaseStopOtherProcessFirst=\u0411\u0443\u0434\u044C \u043B\u0430\u0441\u043A\u0430, \u0437\u0443\u043F\u0438\u043D\u0456\u0442\u044C \u0456\u043D\u0448\u0438\u0439 \u0430\u043A\u0442\u0438\u0432\u043D\u0438\u0439 \u043F\u0440\u043E\u0446\u0435\u0441 \u043F\u0435\u0440\u0448 \u043D\u0456\u0436 \u043F\u0440\u043E\u0434\u043E\u0432\u0436\u0438\u0442\u0438. tab2_Cb_foldersSelectorForRomsDesc=\u0417\u043C\u0456\u043D\u044E\u0454 \u043F\u043E\u0432\u0435\u0434\u0456\u043D\u043A\u0443 \u043A\u043D\u043E\u043F\u043A\u0438 \u043A\u043D\u043E\u043F\u043A\u0438 "\u0412\u0438\u0431\u0440\u0430\u0442\u0438 \u0444\u0430\u0439\u043B\u0438" \u043D\u0430 \u0432\u043A\u043B\u0430\u0434\u0446\u0456 '\u0406\u0433\u0440\u0438'. \u0417\u0430\u043C\u0456\u0441\u0442\u044C \u0432\u0438\u0431\u043E\u0440\u0443 ROM \u0444\u0430\u0439\u043B\u0456\u0432 \u043E\u0434\u0438\u043D \u0437\u0430 \u043E\u0434\u043D\u0438\u043C \u0432\u0438 \u0432\u043A\u0430\u0437\u0443\u0454\u0442\u0435 \u043F\u0430\u043F\u043A\u0443, \u043F\u0456\u0441\u043B\u044F \u0447\u043E\u0433\u043E \u0434\u043E\u0434\u0430\u044E\u0442\u044C\u0441\u044F \u0443\u0441\u0456 \u0444\u0430\u0439\u043B\u0438, \u0449\u043E \u043F\u0456\u0434\u0442\u0440\u0438\u043C\u0443\u044E\u0442\u044C\u0441\u044F. tab2_Cb_foldersSelectorForRoms=\u0412\u0438\u0431\u0438\u0440\u0430\u0442\u0438 \u043F\u0430\u043F\u043A\u0443 \u0437 ROM \u0444\u0430\u0439\u043B\u0430\u043C\u0438 \u0437\u0430\u043C\u0456\u0441\u0442\u044C \u0432\u0438\u0431\u043E\u0440\u0443 \u0444\u0430\u0439\u043B\u0456\u0432 \u043F\u043E\u043E\u0434\u0438\u043D\u0446\u0456. +windowTitleAddingFiles=\u0428\u0443\u043A\u0430\u0454\u043C\u043E \u0444\u0430\u0439\u043B\u0438... +windowBodyFilesScanned=\u0424\u0430\u0439\u043B\u0456\u0432 \u043F\u0440\u043E\u0441\u043A\u0430\u043D\u043E\u0432\u0430\u043D\u043E: %d\n\u0417 \u044F\u043A\u0438\u0445 \u0431\u0443\u0434\u0435 \u0434\u043E\u0434\u0430\u043D\u043E: %d diff --git a/src/main/resources/res/app_dark.css b/src/main/resources/res/app_dark.css index 807a88f..5ee4192 100644 --- a/src/main/resources/res/app_dark.css +++ b/src/main/resources/res/app_dark.css @@ -78,6 +78,10 @@ -fx-padding: 0.23em; } +.progress-indicator { + -fx-progress-color: #00bce4; +} + .dialog-pane { -fx-background-color: #4f4f4f; } @@ -131,7 +135,7 @@ } -// -======================== TAB PANE =========================- +/* -======================== TAB PANE =========================- */ .tab-pane .tab SVGPath{ -fx-fill: #f7fafa; } diff --git a/src/main/resources/res/app_light.css b/src/main/resources/res/app_light.css index c13c160..fde9c6a 100644 --- a/src/main/resources/res/app_light.css +++ b/src/main/resources/res/app_light.css @@ -24,7 +24,7 @@ -fx-effect: dropshadow(three-pass-box, #00caca, 2, 0, 0, 0); } .button:focused, .buttonStop:focused, .buttonUp:focused, .buttonSelect:focused, .choice-box:focused{ - -fx-background-color: #cccccc; + -fx-background-color: #fefefe; -fx-background-insets: 0 0 0 0, 0, 1, 2; -fx-border-color: #cccccc; -fx-border-radius: 3; @@ -95,6 +95,10 @@ -fx-padding: 0.23em; } +.progress-indicator { + -fx-progress-color: #00bce4; +} + .dialog-pane { -fx-background-color: #fefefe; } @@ -183,9 +187,9 @@ .tab-pane > .tab-header-area > .tab-header-background { - -fx-background-color: #ebebeb; - + -fx-background-color: linear-gradient(to right, #ebebeb 0%, #fefefe 7.5%, #fefefe 100%); } + .tab-pane > .tab-header-area > .headers-region > .tab { -fx-padding: 10; } @@ -220,7 +224,7 @@ -fx-text-fill: #2c2c2c; } .table-row-cell, .table-row-cell:filled:selected, .table-row-cell:selected{ - -fx-background-color: -fx-table-cell-border-color, #d3fffd; + -fx-background-color: -fx-table-cell-border-color, #ebfffe; -fx-background-insets: 0, 0 0 1 0; -fx-padding: 0.0em; /* 0 */ -fx-table-cell-border-color: #b0b0b0;