Skip to content

Commit 4e6e832

Browse files
Mine-diamondGlavo3gf8jv4dv
authored
feat: 文件选择器支持选择文件和文件夹 (#5806)
Co-authored-by: Glavo <zjx001202@gmail.com> Co-authored-by: 3gf8jv4dv <3gf8jv4dv@gmail.com>
1 parent d6648a8 commit 4e6e832

10 files changed

Lines changed: 62 additions & 30 deletions

File tree

HMCL/src/main/java/org/jackhuang/hmcl/ui/SVG.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ public enum SVG {
6262
EXTENSION_FILL("M8.8 21H5q-.825 0-1.4125-.5875T3 19V15.2q1.2 0 2.1-.7625T6 12.5q0-1.175-.9-1.9375T3 9.8V6q0-.825.5875-1.4125T5 4H9q0-1.05.725-1.775T11.5 1.5q1.05 0 1.775.725T14 4h4q.825 0 1.4125.5875T20 6v4q1.05 0 1.775.725T22.5 12.5q0 1.05-.725 1.775T20 15v4q0 .825-.5875 1.4125T18 21H14.2q0-1.25-.7875-2.125T11.5 18q-1.125 0-1.9125.875T8.8 21Z"),
6363
FEEDBACK("M12 15Q12.425 15 12.7125 14.7125T13 14Q13 13.575 12.7125 13.2875T12 13Q11.575 13 11.2875 13.2875T11 14Q11 14.425 11.2875 14.7125T12 15ZM11 11H13V5H11V11ZM2 22V4Q2 3.175 2.5875 2.5875T4 2H20Q20.825 2 21.4125 2.5875T22 4V16Q22 16.825 21.4125 17.4125T20 18H6L2 22ZM5.15 16H20V4H4V17.125L5.15 16ZM4 16V4 16Z"),
6464
FEEDBACK_FILL("M2 22V4q0-.825.5875-1.4125T4 2H20q.825 0 1.4125.5875T22 4V16q0 .825-.5875 1.4125T20 18H6L2 22Zm10-7q.425 0 .7125-.2875T13 14t-.2875-.7125T12 13t-.7125.2875T11 14t.2875.7125T12 15Zm-1-4h2V5H11v6Z"),
65+
FILE_OPEN("M6 22q-0.825 0-1.4125-0.5875T4 20v-16q0-0.825 0.5875-1.4125T6 2h8l6 6v6h-2v-5H13v-5H6v16h9v2H6Zm15.95 0.375L19 19.425v2.225h-2v-5.65h5.65v2h-2.25l2.95 2.95-1.4 1.425Zm-15.95-2.375v-16 16Z"),
6566
FOLDER("M4 20Q3.175 20 2.5875 19.4125T2 18V6Q2 5.175 2.5875 4.5875T4 4H10L12 6H20Q20.825 6 21.4125 6.5875T22 8V18Q22 18.825 21.4125 19.4125T20 20H4ZM4 18H20V8H11.175L9.175 6H4V18ZM4 18V6 18Z"),
6667
FOLDER_COPY("M3 21Q2.175 21 1.5875 20.4125T1 19V6H3V19H20V21H3ZM7 17Q6.175 17 5.5875 16.4125T5 15V4Q5 3.175 5.5875 2.5875T7 2H12L14 4H21Q21.825 4 22.4125 4.5875T23 6V15Q23 15.825 22.4125 16.4125T21 17H7ZM7 15H21V6H13.175L11.175 4H7V15ZM7 15V4 15Z"),
6768
FOLDER_OPEN("M4 20Q3.175 20 2.5875 19.4125T2 18V6Q2 5.175 2.5875 4.5875T4 4H10L12 6H20Q20.825 6 21.4125 6.5875T22 8H11.175L9.175 6H4V18L6.4 10H23.5L20.925 18.575Q20.725 19.225 20.1875 19.6125T19 20H4ZM6.1 18H19L20.8 12H7.9L6.1 18ZM6.1 18 7.9 12 6.1 18ZM4 8V6 8Z"),

HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FileSelector.java

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package org.jackhuang.hmcl.ui.construct;
1919

2020
import com.jfoenix.controls.JFXButton;
21+
import com.jfoenix.controls.JFXPopup;
2122
import com.jfoenix.controls.JFXTextField;
2223
import javafx.beans.property.SimpleStringProperty;
2324
import javafx.beans.property.StringProperty;
@@ -30,6 +31,7 @@
3031
import org.jackhuang.hmcl.ui.Controllers;
3132
import org.jackhuang.hmcl.ui.FXUtils;
3233
import org.jackhuang.hmcl.ui.SVG;
34+
import org.jackhuang.hmcl.util.StringUtils;
3335
import org.jackhuang.hmcl.util.io.FileUtils;
3436

3537
import java.nio.file.Path;
@@ -38,10 +40,18 @@
3840

3941
public class FileSelector extends HBox {
4042
private final StringProperty value = new SimpleStringProperty();
41-
private String chooserTitle = i18n("selector.choose_file");
42-
private boolean directory = false;
43+
private String chooserTitle = "";
44+
private SelectionMode selectionMode = SelectionMode.FILE;
4345
private final ObservableList<FileChooser.ExtensionFilter> extensionFilters = FXCollections.observableArrayList();
4446

47+
JFXButton selectButton = FXUtils.newToggleButton4(SVG.FOLDER_OPEN, 15);
48+
49+
public enum SelectionMode {
50+
FILE,
51+
DIRECTORY,
52+
FILE_OR_DIRECTORY
53+
}
54+
4555
public String getValue() {
4656
return value.get();
4757
}
@@ -63,12 +73,12 @@ public FileSelector setChooserTitle(String chooserTitle) {
6373
return this;
6474
}
6575

66-
public boolean isDirectory() {
67-
return directory;
76+
public SelectionMode getSelectionMode() {
77+
return selectionMode;
6878
}
6979

70-
public FileSelector setDirectory(boolean directory) {
71-
this.directory = directory;
80+
public FileSelector setSelectionMode(SelectionMode selectionMode) {
81+
this.selectionMode = selectionMode;
7282
return this;
7383
}
7484

@@ -80,26 +90,20 @@ public FileSelector() {
8090
JFXTextField customField = new JFXTextField();
8191
FXUtils.bindString(customField, valueProperty());
8292

83-
JFXButton selectButton = FXUtils.newToggleButton4(SVG.FOLDER_OPEN, 15);
8493
selectButton.setOnAction(e -> {
85-
if (directory) {
86-
DirectoryChooser chooser = new DirectoryChooser();
87-
chooser.setTitle(chooserTitle);
88-
Path dir = FileUtils.toPath(chooser.showDialog(Controllers.getStage()));
89-
if (dir != null) {
90-
String path = FileUtils.getAbsolutePath(dir);
91-
customField.setText(path);
92-
value.setValue(path);
93-
}
94-
} else {
95-
FileChooser chooser = new FileChooser();
96-
chooser.getExtensionFilters().addAll(getExtensionFilters());
97-
chooser.setTitle(chooserTitle);
98-
Path file = FileUtils.toPath(chooser.showOpenDialog(Controllers.getStage()));
99-
if (file != null) {
100-
String path = FileUtils.getAbsolutePath(file);
101-
customField.setText(path);
102-
value.setValue(path);
94+
switch (selectionMode) {
95+
case FILE -> openFileChooser(customField);
96+
case DIRECTORY -> openDirectoryChooser(customField);
97+
case FILE_OR_DIRECTORY -> {
98+
PopupMenu selectPopupMenu = new PopupMenu();
99+
JFXPopup selectModePopup = new JFXPopup(selectPopupMenu);
100+
101+
selectPopupMenu.getContent().addAll(
102+
new IconedMenuItem(SVG.FILE_OPEN, i18n("selector.choose_file"), () -> openFileChooser(customField), selectModePopup),
103+
new IconedMenuItem(SVG.FOLDER_OPEN, i18n("selector.choose_directory"), () -> openDirectoryChooser(customField), selectModePopup)
104+
);
105+
106+
selectModePopup.show(selectButton, JFXPopup.PopupVPosition.TOP, JFXPopup.PopupHPosition.RIGHT, -selectButton.getWidth(), 0);
103107
}
104108
}
105109
});
@@ -108,4 +112,27 @@ public FileSelector() {
108112
setSpacing(3);
109113
getChildren().addAll(customField, selectButton);
110114
}
115+
116+
private void openFileChooser(JFXTextField customField) {
117+
FileChooser chooser = new FileChooser();
118+
chooser.getExtensionFilters().addAll(getExtensionFilters());
119+
chooser.setTitle(StringUtils.isBlank(chooserTitle) ? i18n("selector.choose_file") : chooserTitle);
120+
Path file = FileUtils.toPath(chooser.showOpenDialog(Controllers.getStage()));
121+
if (file != null) {
122+
String path = FileUtils.getAbsolutePath(file);
123+
customField.setText(path);
124+
value.setValue(path);
125+
}
126+
}
127+
128+
private void openDirectoryChooser(JFXTextField customField) {
129+
DirectoryChooser chooser = new DirectoryChooser();
130+
chooser.setTitle(StringUtils.isBlank(chooserTitle) ? i18n("selector.choose_directory") : chooserTitle);
131+
Path dir = FileUtils.toPath(chooser.showDialog(Controllers.getStage()));
132+
if (dir != null) {
133+
String path = FileUtils.getAbsolutePath(dir);
134+
customField.setText(path);
135+
value.setValue(path);
136+
}
137+
}
111138
}

HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MultiFileItem.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,8 @@ public void setValue(String value) {
267267
selector.setValue(value);
268268
}
269269

270-
public FileOption<T> setDirectory(boolean directory) {
271-
selector.setDirectory(directory);
270+
public FileOption<T> setSelectionMode(FileSelector.SelectionMode selectionMode) {
271+
selector.setSelectionMode(selectionMode);
272272
return this;
273273
}
274274

HMCL/src/main/java/org/jackhuang/hmcl/ui/main/PersonalizationPage.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ public PersonalizationPage() {
135135
new MultiFileItem.FileOption<>(i18n("settings.custom"), EnumBackgroundImage.CUSTOM)
136136
.setChooserTitle(i18n("launcher.background.choose"))
137137
.addExtensionFilter(FXUtils.getImageExtensionFilter())
138+
.setSelectionMode(FileSelector.SelectionMode.FILE_OR_DIRECTORY)
138139
.bindBidirectional(config().backgroundImageProperty()),
139140
new MultiFileItem.StringOption<>(i18n("launcher.background.network"), EnumBackgroundImage.NETWORK)
140141
.setValidators(new URLValidator(true))

HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ protected int getTrailingTextIndex() {
210210
new MultiFileItem.Option<>(i18n("launcher.cache_directory.default"), EnumCommonDirectory.DEFAULT),
211211
new MultiFileItem.FileOption<>(i18n("settings.custom"), EnumCommonDirectory.CUSTOM)
212212
.setChooserTitle(i18n("launcher.cache_directory.choose"))
213-
.setDirectory(true)
213+
.setSelectionMode(FileSelector.SelectionMode.DIRECTORY)
214214
.bindBidirectional(config().commonDirectoryProperty())
215215
));
216216
fileCommonLocation.selectedDataProperty().bindBidirectional(config().commonDirTypeProperty());

HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/AdvancedVersionSettingPage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ public AdvancedVersionSettingPage(Profile profile, @Nullable String versionId, V
183183
nativesDirSublist.setHasSubtitle(true);
184184
nativesDirCustomOption = new MultiFileItem.FileOption<>(i18n("settings.advanced.natives_directory.custom"), NativesDirectoryType.CUSTOM)
185185
.setChooserTitle(i18n("settings.advanced.natives_directory.choose"))
186-
.setDirectory(true);
186+
.setSelectionMode(FileSelector.SelectionMode.DIRECTORY);
187187
nativesDirItem.loadChildren(Arrays.asList(
188188
new MultiFileItem.Option<>(i18n("settings.advanced.natives_directory.default"), NativesDirectoryType.VERSION_FOLDER),
189189
nativesDirCustomOption

HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ public VersionSettingsPage(boolean globalSetting) {
239239
gameDirItem.disableProperty().bind(modpack);
240240
gameDirCustomOption = new MultiFileItem.FileOption<>(i18n("settings.custom"), GameDirectoryType.CUSTOM)
241241
.setChooserTitle(i18n("settings.game.working_directory.choose"))
242-
.setDirectory(true);
242+
.setSelectionMode(FileSelector.SelectionMode.DIRECTORY);
243243

244244
gameDirItem.loadChildren(Arrays.asList(
245245
new MultiFileItem.Option<>(i18n("settings.advanced.game_dir.default"), GameDirectoryType.ROOT_FOLDER),

HMCL/src/main/resources/assets/lang/I18N.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1307,6 +1307,7 @@ search.page_n=%1$d / %2$s
13071307

13081308
selector.choose=Choose
13091309
selector.choose_file=Choose file
1310+
selector.choose_directory=Choose directory
13101311
selector.custom=Custom
13111312

13121313
settings=Settings

HMCL/src/main/resources/assets/lang/I18N_zh.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,7 @@ search.page_n=%d / %s
10991099

11001100
selector.choose=選取
11011101
selector.choose_file=選取檔案
1102+
selector.choose_directory=選取目錄
11021103
selector.custom=自訂
11031104

11041105
settings=設定

HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,6 +1104,7 @@ search.page_n=%d / %s
11041104

11051105
selector.choose=选择
11061106
selector.choose_file=选择文件
1107+
selector.choose_directory=选择文件夹
11071108
selector.custom=自定义
11081109

11091110
settings=设置

0 commit comments

Comments
 (0)