Skip to content

Commit dcabf76

Browse files
authored
Merge pull request #82 from wolfposd/master
allows adding files and folders via filechooser and drag and drop #51
2 parents 128d305 + 112a0f8 commit dcabf76

File tree

5 files changed

+148
-30
lines changed

5 files changed

+148
-30
lines changed

src/main/java/nsusbloader/Controllers/GamesController.java

Lines changed: 136 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919
package nsusbloader.Controllers;
2020

21+
import javafx.application.Platform;
2122
import javafx.collections.FXCollections;
2223
import javafx.collections.ObservableList;
2324
import javafx.fxml.FXML;
@@ -40,11 +41,18 @@
4041

4142
import java.io.File;
4243
import java.net.URL;
44+
import java.util.ArrayList;
4345
import java.util.LinkedList;
4446
import java.util.List;
4547
import java.util.ResourceBundle;
48+
import java.util.function.Consumer;
49+
import java.util.function.Supplier;
4650

4751
public class GamesController implements Initializable {
52+
53+
private static final String REGEX_ONLY_NSP = ".*\\.nsp$";
54+
private static final String REGEX_ALLFILES_TINFOIL = ".*\\.(nsp$|xci$|nsz$|xcz$)";
55+
4856
@FXML
4957
private AnchorPane usbNetPane;
5058

@@ -60,7 +68,7 @@ public class GamesController implements Initializable {
6068
public NSTableViewController tableFilesListController; // Accessible from Mediator (for drag-n-drop support)
6169

6270
@FXML
63-
private Button selectNspBtn, selectSplitNspBtn, uploadStopBtn;
71+
private Button selectNspBtn, selectSplitNspBtn, selectFolderBtn, uploadStopBtn;
6472
private String previouslyOpenedPath;
6573
private Region btnUpStopImage;
6674
private ResourceBundle resourceBundle;
@@ -130,16 +138,18 @@ public void initialize(URL url, ResourceBundle resourceBundle) {
130138
switchThemeBtn.setGraphic(btnSwitchImage);
131139
this.switchThemeBtn.setOnAction(e->switchTheme());
132140

133-
134-
uploadStopBtn.setDisable(getSelectedProtocol().equals("TinFoil"));
135141
selectNspBtn.setOnAction(e-> selectFilesBtnAction());
142+
selectNspBtn.getStyleClass().add("buttonSelect");
143+
144+
selectFolderBtn.setOnAction(e-> selectFoldersBtnAction());
145+
selectFolderBtn.getStyleClass().add("buttonSelect");
146+
selectFolderBtn.setTooltip(new Tooltip(resourceBundle.getString("btn_OpenFolders_tooltip")));
136147

137148
selectSplitNspBtn.setOnAction(e-> selectSplitBtnAction());
138149
selectSplitNspBtn.getStyleClass().add("buttonSelect");
139150

140151
uploadStopBtn.setOnAction(e-> uploadBtnAction());
141-
142-
selectNspBtn.getStyleClass().add("buttonSelect");
152+
uploadStopBtn.setDisable(getSelectedProtocol().equals("TinFoil"));
143153

144154
this.btnUpStopImage = new Region();
145155
btnUpStopImage.getStyleClass().add("regionUpload");
@@ -186,32 +196,111 @@ String getNsIp(){
186196
return nsIpTextField.getText();
187197
}
188198

199+
private boolean isGoldLeaf() {
200+
return getSelectedProtocol().equals("GoldLeaf");
201+
}
202+
203+
private boolean isTinfoil() {
204+
return getSelectedProtocol().equals("TinFoil");
205+
}
206+
207+
private boolean isNSPFileFilterForGL() {
208+
return MediatorControl.getInstance().getContoller().getSettingsCtrlr().getGoldleafSettings().getNSPFileFilterForGL();
209+
}
210+
211+
private boolean isXciNszXczSupport() {
212+
return MediatorControl.getInstance().getContoller().getSettingsCtrlr().getTinfoilSettings().isXciNszXczSupport();
213+
}
214+
215+
/**
216+
* regex for selected program and selected file filter </br>
217+
* tinfoil + xcinszxcz </br>
218+
* tinfoil + nsponly </br>
219+
* goldleaf </br>
220+
* etc..
221+
*/
222+
private String getRegexForFiles() {
223+
if (isTinfoil() && isXciNszXczSupport())
224+
return REGEX_ALLFILES_TINFOIL;
225+
else
226+
return REGEX_ONLY_NSP;
227+
// currently only tinfoil supports all filetypes
228+
// everything else only supports nsp
229+
// else if (isGoldLeaf())
230+
// return REGEX_ONLY_NSP;
231+
// else
232+
}
233+
189234
/**
190235
* Functionality for selecting NSP button.
191-
* */
192-
private void selectFilesBtnAction(){
193-
List<File> filesList;
236+
*/
237+
private void selectFilesBtnAction() {
194238
FileChooser fileChooser = new FileChooser();
195239
fileChooser.setTitle(resourceBundle.getString("btn_OpenFile"));
196240

197241
fileChooser.setInitialDirectory(new File(FilesHelper.getRealFolder(previouslyOpenedPath)));
198242

199-
if (getSelectedProtocol().equals("TinFoil") && MediatorControl.getInstance().getContoller().getSettingsCtrlr().getTinfoilSettings().isXciNszXczSupport())
243+
if (isTinfoil() && isXciNszXczSupport()) {
200244
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("NSP/XCI/NSZ/XCZ", "*.nsp", "*.xci", "*.nsz", "*.xcz"));
201-
else if (getSelectedProtocol().equals("GoldLeaf") && (! MediatorControl.getInstance().getContoller().getSettingsCtrlr().getGoldleafSettings().getNSPFileFilterForGL()))
245+
} else if (isGoldLeaf() && !isNSPFileFilterForGL()) {
202246
fileChooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("Any file", "*.*"),
203-
new FileChooser.ExtensionFilter("NSP ROM", "*.nsp")
204-
);
205-
else
247+
new FileChooser.ExtensionFilter("NSP ROM", "*.nsp"));
248+
} else {
206249
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("NSP ROM", "*.nsp"));
250+
}
207251

208-
filesList = fileChooser.showOpenMultipleDialog(usbNetPane.getScene().getWindow());
252+
List<File> filesList = fileChooser.showOpenMultipleDialog(usbNetPane.getScene().getWindow());
209253
if (filesList != null && !filesList.isEmpty()) {
210254
tableFilesListController.setFiles(filesList);
211255
uploadStopBtn.setDisable(false);
212256
previouslyOpenedPath = filesList.get(0).getParent();
213257
}
214258
}
259+
260+
/**
261+
* Functionality for selecting folders button.
262+
* will scan all folders recursively for nsp-files
263+
*/
264+
private void selectFoldersBtnAction() {
265+
DirectoryChooser chooser = new DirectoryChooser();
266+
chooser.setTitle(resourceBundle.getString("btn_OpenFolders"));
267+
chooser.setInitialDirectory(new File(FilesHelper.getRealFolder(previouslyOpenedPath)));
268+
269+
File startFolder = chooser.showDialog(usbNetPane.getScene().getWindow());
270+
271+
performInBackgroundAndUpdate(() -> {
272+
final List<File> allFiles = new ArrayList<>();
273+
collectFiles(allFiles, startFolder, getRegexForFiles());
274+
return allFiles;
275+
}, (files) -> {
276+
if (!files.isEmpty()) {
277+
tableFilesListController.setFiles(files);
278+
uploadStopBtn.setDisable(false);
279+
previouslyOpenedPath = startFolder.getParent();
280+
}
281+
});
282+
}
283+
284+
/**
285+
* used to recursively walk all directories, every file will be added to the storage list
286+
* @param storage used to hold files
287+
* @param startFolder where to start
288+
* @param regex for filenames
289+
*/
290+
private void collectFiles(List<File> storage, File startFolder, final String regex) {
291+
if (startFolder.isDirectory()) {
292+
File[] files = startFolder.listFiles();
293+
if(files != null)
294+
for (File f : files) {
295+
if (f.isDirectory()) {
296+
collectFiles(storage, f, regex);
297+
} else if (f.getName().toLowerCase().matches(regex)) {
298+
storage.add(f);
299+
}
300+
}
301+
}
302+
}
303+
215304
/**
216305
* Functionality for selecting Split NSP button.
217306
* */
@@ -324,25 +413,27 @@ private void handleDragOver(DragEvent event){
324413
* Drag-n-drop support (drop consumer)
325414
* */
326415
@FXML
327-
private void handleDrop(DragEvent event){
328-
List<File> filesDropped = event.getDragboard().getFiles();
329-
SettingsController settingsController = MediatorControl.getInstance().getContoller().getSettingsCtrlr();
330-
SettingsBlockTinfoilController tinfoilSettings = settingsController.getTinfoilSettings();
331-
SettingsBlockGoldleafController goldleafController = settingsController.getGoldleafSettings();
332-
333-
if (getSelectedProtocol().equals("TinFoil") && tinfoilSettings.isXciNszXczSupport())
334-
filesDropped.removeIf(file -> ! file.getName().toLowerCase().matches("(.*\\.nsp$)|(.*\\.xci$)|(.*\\.nsz$)|(.*\\.xcz$)"));
335-
else if (getSelectedProtocol().equals("GoldLeaf") && (! goldleafController.getNSPFileFilterForGL()))
336-
filesDropped.removeIf(file -> (file.isDirectory() && ! file.getName().toLowerCase().matches(".*\\.nsp$")));
337-
else
338-
filesDropped.removeIf(file -> ! file.getName().toLowerCase().matches(".*\\.nsp$"));
416+
private void handleDrop(DragEvent event) {
417+
final String regex = getRegexForFiles();
339418

340-
if ( ! filesDropped.isEmpty() )
341-
tableFilesListController.setFiles(filesDropped);
419+
List<File> files = event.getDragboard().getFiles();
342420

343-
event.setDropCompleted(true);
344-
event.consume();
421+
performInBackgroundAndUpdate(() -> {
422+
List<File> allFiles = new ArrayList<>();
423+
if (files != null && files.size() != 0) {
424+
files.stream().filter(File::isDirectory).forEach(f -> collectFiles(allFiles, f, regex));
425+
files.stream().filter(f -> f.getName().toLowerCase().matches(regex)).forEach(allFiles::add);
426+
}
427+
return allFiles;
428+
}, allFiles -> {
429+
if (!allFiles.isEmpty())
430+
tableFilesListController.setFiles(allFiles);
431+
432+
event.setDropCompleted(true);
433+
event.consume();
434+
});
345435
}
436+
346437
/**
347438
* This thing modify UI for reusing 'Upload to NS' button and make functionality set for "Stop transmission"
348439
* Called from mediator
@@ -384,6 +475,21 @@ public void disableUploadStopBtn(boolean disable){
384475
else
385476
uploadStopBtn.setDisable(false);
386477
}
478+
479+
/**
480+
* Utility function to perform a task in the background and pass the results to a task on the javafx-ui-thread
481+
* @param background performed in background
482+
* @param update performed with results on ui-thread
483+
*/
484+
private <T> void performInBackgroundAndUpdate(Supplier<T> background, Consumer<T> update) {
485+
new Thread(() -> {
486+
final T result = background.get();
487+
Platform.runLater(() -> {
488+
update.accept(result);
489+
});
490+
}).start();
491+
}
492+
387493
/**
388494
* Get 'Recent' path
389495
*/

src/main/resources/GamesTab.fxml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@
5858
<SVGPath content="M 8,0 C 6.8954305,0 6,0.8954305 6,2 v 16 c 0,1.1 0.89,2 2,2 h 12 c 1.104569,0 2,-0.895431 2,-2 V 2 C 22,0.90484721 21.089844,0 20,0 Z m 2.1,1.2 h 7.8 C 18,1.20208 18,1.2002604 18,1.3 v 0.1 c 0,0.095833 0,0.097917 -0.1,0.1 H 10.1 C 10,1.5057292 10,1.5036458 10,1.4 V 1.3 C 10,1.20026 10,1.1981771 10.1,1.2 Z M 8,2 h 12 c 0.303385,0 0.5,0.2044271 0.5,0.5 v 12 C 20.5,14.789959 20.29836,15 20,15 H 8 C 7.7044271,15 7.5,14.803385 7.5,14.5 V 2.5 C 7.5,2.2083333 7.7122396,2 8,2 Z M 2,4 v 18 c 0,1.104569 0.8954305,2 2,2 H 20 V 22 H 4 V 4 Z m 8,12 h 8 l -4,3 z" fill="#289de8" />
5959
</graphic>
6060
</Button>
61+
<Button fx:id="selectFolderBtn" contentDisplay="TOP" mnemonicParsing="false" prefHeight="60.0" text="%btn_OpenFolders">
62+
<graphic>
63+
<SVGPath content="M 2.4003906,2 C 1.0683906,2 0,3.1125 0,4.5 v 15 c -1.7556433e-8,1.380871 1.0747547,2.500225 2.4003906,2.5 H 21.599609 C 22.925245,22.000225 24,20.880871 24,19.5 V 7 C 24,5.6125 22.919609,4.5 21.599609,4.5 H 12 L 9.5996094,2 Z" fill="#289de8" />
64+
</graphic>
65+
</Button>
6166
<Button fx:id="selectSplitNspBtn" contentDisplay="TOP" mnemonicParsing="false" prefHeight="60.0" text="%btn_OpenSplitFile">
6267
<graphic>
6368
<SVGPath content="M 2.4003906 2 C 1.0683906 2 0 3.1125 0 4.5 L 0 19.5 A 2.4 2.5 0 0 0 2.4003906 22 L 21.599609 22 A 2.4 2.5 0 0 0 24 19.5 L 24 7 C 24 5.6125 22.919609 4.5 21.599609 4.5 L 12 4.5 L 9.5996094 2 L 2.4003906 2 z M 13.193359 10.962891 C 14.113498 10.962891 14.814236 11.348741 15.296875 12.123047 C 15.779514 12.89388 16.021484 13.935113 16.021484 15.244141 C 16.021484 16.556641 15.779514 17.598741 15.296875 18.373047 C 14.814236 19.14388 14.113498 19.529297 13.193359 19.529297 C 12.276693 19.529297 11.575955 19.14388 11.089844 18.373047 C 10.607205 17.598741 10.365234 16.556641 10.365234 15.244141 C 10.365234 13.935113 10.607205 12.89388 11.089844 12.123047 C 11.575955 11.348741 12.276693 10.962891 13.193359 10.962891 z M 19.589844 10.962891 C 20.509983 10.962891 21.21072 11.348741 21.693359 12.123047 C 22.175998 12.89388 22.417969 13.935113 22.417969 15.244141 C 22.417969 16.556641 22.175998 17.598741 21.693359 18.373047 C 21.21072 19.14388 20.509983 19.529297 19.589844 19.529297 C 18.673177 19.529297 17.970486 19.14388 17.484375 18.373047 C 17.001736 17.598741 16.761719 16.556641 16.761719 15.244141 C 16.761719 13.935113 17.001736 12.89388 17.484375 12.123047 C 17.970486 11.348741 18.673177 10.962891 19.589844 10.962891 z M 13.193359 11.769531 C 12.613498 11.769531 12.173177 12.092448 11.871094 12.738281 C 11.56901 13.380642 11.417969 14.195964 11.417969 15.185547 C 11.417969 15.411241 11.423611 15.655599 11.4375 15.916016 C 11.451389 16.176432 11.511068 16.528212 11.615234 16.972656 L 14.412109 12.591797 C 14.235026 12.26888 14.042318 12.052517 13.833984 11.941406 C 13.629123 11.826823 13.415582 11.769531 13.193359 11.769531 z M 19.589844 11.769531 C 19.009983 11.769531 18.567708 12.092448 18.265625 12.738281 C 17.963542 13.380642 17.8125 14.195964 17.8125 15.185547 C 17.8125 15.411241 17.820095 15.655599 17.833984 15.916016 C 17.847873 16.176432 17.907552 16.528212 18.011719 16.972656 L 20.808594 12.591797 C 20.63151 12.26888 20.438802 12.052517 20.230469 11.941406 C 20.025608 11.826823 19.812066 11.769531 19.589844 11.769531 z M 14.761719 13.556641 L 11.984375 17.962891 C 12.133681 18.216363 12.305556 18.406684 12.5 18.535156 C 12.694444 18.660156 12.91276 18.722656 13.152344 18.722656 C 13.812066 18.722656 14.280816 18.355252 14.558594 17.619141 C 14.836372 16.879557 14.974609 16.059462 14.974609 15.160156 C 14.974609 14.604601 14.90408 14.07053 14.761719 13.556641 z M 21.15625 13.556641 L 18.380859 17.962891 C 18.530165 18.216363 18.70204 18.406684 18.896484 18.535156 C 19.090929 18.660156 19.307292 18.722656 19.546875 18.722656 C 20.206597 18.722656 20.675347 18.355252 20.953125 17.619141 C 21.230903 16.879557 21.371094 16.059462 21.371094 15.160156 C 21.371094 14.604601 21.298611 14.07053 21.15625 13.556641 z" fill="#289de8" />

src/main/resources/locale.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
btn_OpenFile=Select files
2+
btn_OpenFolders=Select folder
23
btn_Upload=Upload to NS
4+
btn_OpenFolders_tooltip=Select a folder to be scanned.\nThis folder and all of its subfolders will be scanned.\nAll matching files will be added to the list.
35
tab3_Txt_EnteredAsMsg1=You have been entered as:
46
tab3_Txt_EnteredAsMsg2=You should be root or have configured 'udev' rules for this user to avoid any issues.
57
tab3_Txt_FilesToUploadTitle=Files to upload:

src/main/resources/locale_de_DE.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
btn_OpenFile=.NSP Dateien ausw\u00E4hlen
2+
btn_OpenFolders=Ordner ausw\u00E4hlen
23
btn_Upload=Hochladen zu NS
4+
btn_OpenFolders_tooltip=W\u00E4hle einen Ordner aus.\nDieser Ordner und alle seine Unterordner werden durchsucht.\nAlle passenden Dateien werden dann zur Liste hinzugef\u00FCgt.
35
tab3_Txt_EnteredAsMsg1=Du wurdest eingelassen als:
46
tab3_Txt_EnteredAsMsg2=Du brauchst root oder konfigurierte 'udev'-Regeln um Probleme zu vermeiden.
57
tab3_Txt_FilesToUploadTitle=Dateien zum Hochladen:
@@ -42,6 +44,7 @@ tab2_Cb_AllowXciNszXcz=Erlaube XCI- NSZ- XCZ-Dateien-Verwendung f\u00FCr Tinfoil
4244
tab2_Lbl_AllowXciNszXczDesc=Von einigen Drittanbietern verwendet, welche XCI/NSZ/XCZ unterst\u00FCtzen, nutzt Tinfoil Transfer Protocol. Nicht \u00E4ndern, wenn unsicher.
4345
tab2_Lbl_Language=Sprache
4446
windowBodyRestartToApplyLang=Bitte die Applikation neustarten um die Einstellungen zu \u00FCbernehmen.
47+
btn_OpenSplitFile=Split-NSP auswählen
4548
tab2_Cb_GLshowNspOnly=Nur *.nsp in GoldLeaf zeigen.
4649
btn_Cancel=Abbrechen
4750

src/main/resources/locale_en_US.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
btn_OpenFile=Select files
2+
btn_OpenFolders=Select folder
23
btn_Upload=Upload to NS
4+
btn_OpenFolders_tooltip=Select a folder to be scanned.\nThis folder and all of its subfolders will be scanned.\nAll matching files will be added to the list.
35
tab3_Txt_EnteredAsMsg1=You have been entered as:
46
tab3_Txt_EnteredAsMsg2=You should be root or have configured 'udev' rules for this user to avoid any issues.
57
tab3_Txt_FilesToUploadTitle=Files to upload:

0 commit comments

Comments
 (0)