public boolean showUpload2HomeDialog(final OperationInfo initDataInfo) { boolean result = false; try { // Load the fxml file and create a new stage for the popup dialog. FXMLLoader loader = new FXMLLoader(); loader.setLocation(Main.class.getClassLoader().getResource("fxml/UploadHomeView.fxml")); AnchorPane updateDatasetDialogView = (AnchorPane) loader.load(); // update the dialog Stage. Stage dialogStage = new Stage(); dialogStage.setTitle("Upload To Home"); dialogStage.initModality(Modality.WINDOW_MODAL); dialogStage.initOwner(primaryStage); AlertDialogUtil.modifyDialogPosition(dialogStage, primaryStage); Scene scene = new Scene(updateDatasetDialogView); dialogStage.setScene(scene); Upload2HomeController controller = loader.getController(); controller.setDialogStage(dialogStage); controller.setInitInput(initDataInfo.getLocalPath()); controller.setMainApp(this); // Show the dialog and wait until the user closes it dialogStage.showAndWait(); // update updateDataInfo to get datasetName and localPath controller.updateInfo(initDataInfo); result = controller.isOkClicked(); } catch (IOException | DMGUIException e) { logger.error(e.getLocalizedMessage(), e); } return result; }
package cn.com.xxx.project.controller; import java.io.File; import java.util.ArrayList; import java.util.List; import org.apache.commons.net.ftp.FTPFile; import org.apache.commons.net.ftp.FTPFileFilter; import cn.com.xxx.project.core.DMGUIException; import cn.com.xxx.project.core.FTPFileManagerWrapper; import cn.com.xxx.project.model.GlobalConfig; import cn.com.xxx.project.model.OperationInfo; import cn.com.xxx.project.util.AlertDialogUtil; import cn.com.xxx.project.util.PathUtil; import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.scene.control.ComboBox; import javafx.scene.control.TextField; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; import javafx.stage.DirectoryChooser; import javafx.stage.FileChooser; import javafx.stage.FileChooser.ExtensionFilter; import javafx.stage.Stage; interface ItemFilter { boolean matches(String inputStr, String optionalStr); } public class Upload2HomeController { @FXML private TextField inputPathField; @FXML private ComboBox<String> remotePathComboBox; private Main mainApp; private Stage dialogStage; private boolean okClicked = false; //下拉条目查找器 private FTPFileManagerWrapper ftpFileMng; private final ObservableList<String> itemList = FXCollections.observableArrayList(); private boolean isFilterNotRequired = true; private final ObservableList<String> filteredItemList = FXCollections.observableArrayList(); private final FTPFileFilter ftpFilter = file -> file.isDirectory() && ! file.getName().startsWith("."); private final ItemFilter filter = (inputStr, optionalStr) -> optionalStr.startsWith(inputStr); private String tempRemotePath = null; private String oldRemotePath = null; private static final int MAX_VISIBLE_ROW_COUNT = 5; /** * 属性初始化 */ public void setMainApp(final Main mainApp) throws DMGUIException { this.mainApp = mainApp; initFTPFileMng(); mainApp.getRemoteDatasetsController().selectHomeTab(); Platform.runLater(()->{ String remotePath = mainApp.getRemoteDatasetController().getRemotePath(); remotePathComboBox.setItems(itemList); remotePathComboBox.setVisibleRowCount(MAX_VISIBLE_ROW_COUNT); itemList.addAll(listAbsDirPath(remotePath)); setText(remotePath); oldRemotePath = remotePath; setFocusedPropertyListener(); setKeyListener(); }); } private List<String> listAbsDirPath(String path){ List<FTPFile> files = ftpFileMng.list(path, ftpFilter); List<String> absDirPaths = new ArrayList<String>(); path = path.endsWith("/") ? path : path + "/"; for (FTPFile file: files) { absDirPaths.add(path + file.getName()); } return absDirPaths; } public void initFTPFileMng() throws DMGUIException{ ftpFileMng = new FTPFileManagerWrapper(); ftpFileMng.setWorkPath(GlobalConfig.getInstance().getHomePath()); } private void setFocusedPropertyListener() { remotePathComboBox.getEditor().focusedProperty().addListener( (observable, oldValue, newValue) -> { if (observable.getValue()){ remotePathComboBox.show(); String test = getText(); if (test != null){ Platform.runLater(()->{remotePathComboBox.getEditor().positionCaret(test.length());}); } } } ); } private void setKeyListener() { remotePathComboBox.addEventHandler(KeyEvent.KEY_RELEASED, new EventHandler<KeyEvent>() { @Override public void handle(KeyEvent event) {//NOPMD if (event.getCode() == KeyCode.UP || event.getCode() == KeyCode.DOWN) { show(); moveCaret(); return; } if (isIgnoredKey(event.getCode())) { return; } reviseText(); refreshItems(); refreshFilteredItems(); resetComboBoxItemsAndDisplay(); oldRemotePath = getText(); } }); } private boolean isIgnoredKey(final KeyCode keyCode) { // BACK_SPACE/DELETE不做特殊处理 return keyCode.equals(KeyCode.SHIFT) || keyCode.equals(KeyCode.CONTROL) || keyCode.equals(KeyCode.LEFT) || keyCode.equals(KeyCode.RIGHT) || keyCode.equals(KeyCode.HOME) || keyCode.equals(KeyCode.END) || keyCode.equals(KeyCode.TAB) || keyCode.equals(KeyCode.ENTER); } private void refreshItems() { if (isRequiredRefresh()) { itemList.setAll(listAbsDirPath(getDirPath(getText()))); } } private String getDirPath(final String path){ int lastSlashCharIndex = path.lastIndexOf("/"); if (lastSlashCharIndex == -1) { lastSlashCharIndex = path.length(); }else if(lastSlashCharIndex == 0){ lastSlashCharIndex = 1; } return path.substring(0, lastSlashCharIndex); } /** * 待优化,考虑角度:字符在末尾增减,在中间增减,增减单字符,增减多字符 */ private boolean isRequiredRefresh(){ boolean isRequied = false; final int changedPathLen = getText().length() - oldRemotePath.length(); if (changedPathLen>0) { isRequied = getText().endsWith("/") && filteredItemList.size() > 0;//条件:斜杠前面的路径有效 // && filteredItemList.size() == 1 // && filteredItemList.get(0).equals(oldRemotePath); isFilterNotRequired = isRequied; }else if (changedPathLen < 0){ isRequied = oldRemotePath.endsWith("/"); } return isRequied; } private void refreshFilteredItems() { tempRemotePath = getText(); if (isFilterNotRequired){ filteredItemList.setAll(itemList); isFilterNotRequired = false; }else{ filteredItemList.clear();//路径文本也会被刷掉 for (String aData : itemList) { if (aData != null && tempRemotePath != null && filter.matches(tempRemotePath, aData)) { filteredItemList.add(aData); } } } } private void setTextAndMoveCaret(final String text) { setText(text); moveCaret(); } private void setText(final String text) { remotePathComboBox.getEditor().setText(text); } private String getText() { return remotePathComboBox.getEditor().getText(); } /** * FTPClient#listFiles()无法准确处理路径末尾多斜杠问题,需要强制修正 */ private void reviseText(){ setText(PathUtil.filterExtraSlash(getText())); } private void resetComboBoxItemsAndDisplay() { remotePathComboBox.setItems(filteredItemList); remotePathComboBox.getSelectionModel().clearSelection(); remotePathComboBox.setVisibleRowCount(filteredItemList.size() < MAX_VISIBLE_ROW_COUNT ? filteredItemList.size() : MAX_VISIBLE_ROW_COUNT); // 调用了总开关,重置显示下拉布局;可以优化,只重置具体的下拉布局属性。 remotePathComboBox.hide(); remotePathComboBox.show(); setTextAndMoveCaret(tempRemotePath); } private void show() { if (!remotePathComboBox.getItems().isEmpty() && !remotePathComboBox.isShowing()) { remotePathComboBox.show(); } } private void moveCaret() { String test = getText(); if (test != null) { moveCaret(test.length()); } } private void moveCaret(final int pos) { remotePathComboBox.getEditor().positionCaret(pos); } public void setDialogStage(final Stage dialogStage) { this.dialogStage = dialogStage; } public void setInitInput(final String localPath) { inputPathField.setText(localPath); } public boolean isOkClicked() { return okClicked; } public void updateInfo(final OperationInfo updateInfo) { updateInfo.setLocalPath(inputPathField.getText()); updateInfo.setRemotePath( PathUtil.splicePath(GlobalConfig.getInstance().getHomePath(), getText())); } @FXML private void handleOk() { //NOPMD try { checkInput(); okClicked = true; dialogStage.close(); } catch (DMGUIException e) { AlertDialogUtil.createLazyAlertDialog(e.getMessage(), "输入错误!"); } } @FXML private void handleCancel() { //NOPMD dialogStage.close(); } @FXML private void handleBrowseDir() { //NOPMD DirectoryChooser dirChooser = new DirectoryChooser(); dirChooser.setInitialDirectory(new File(".")); File file = dirChooser.showDialog(mainApp.getPrimaryStage()); if (file != null) { inputPathField.setText(file.getPath().toString()); } } @FXML private void handleBrowseFile() { //NOPMD // Open a directory selecting dialog FileChooser fileChooser = new FileChooser();; fileChooser.setInitialDirectory(new File(".")); fileChooser.getExtensionFilters().addAll( new ExtensionFilter("All Files", "*.*"), new ExtensionFilter("Text Files", "*.txt"), new ExtensionFilter("CSV Files", "*.csv"), new ExtensionFilter("Image Files", "*.png", "*.jpg", "*.gif"), new ExtensionFilter("Audio Files", "*.wav", "*.mp3", "*.aac"), new ExtensionFilter("XML files", "*.xml")); File file = fileChooser.showOpenDialog(mainApp.getPrimaryStage()); if (file != null) { inputPathField.setText(file.getPath().toString()); } } private void checkInput() throws DMGUIException{ final StringBuilder errMsg = new StringBuilder(); checkInputLocalPath(errMsg); checkInputRemotePath(errMsg); if(errMsg.length() != 0){ throw new DMGUIException(errMsg.toString()); } } private void checkInputLocalPath(final StringBuilder errMsg){ if (this.inputPathField.getText() == null || this.inputPathField.getText().length() == 0) { errMsg.append("本地路径为空,请重新输入!\n"); } else { final File file = new File(inputPathField.getText()); if (!file.exists()) { // NOPMD errMsg.append("本地路径不存在,请重新输入!\n"); } } if(errMsg.length() == 0){ this.inputPathField.setStyle("-fx-border-color: null"); }else{ this.inputPathField.setStyle("-fx-border-color: red"); } } private void checkInputRemotePath(final StringBuilder errMsg){ String inputRemotePath = getText(); boolean isExist = ftpFileMng.isDirExist(inputRemotePath); if (isExist){ remotePathComboBox.setStyle("-fx-border-color: null"); }else{ errMsg.append("远端路径不存在,请重新输入!\n"); remotePathComboBox.setStyle("-fx-border-color: red"); } } }
public static List<String> filterExtraSubPath(final String[] fileNameArr){ List<String> newFileNameList = new ArrayList<>(); for(String fileName: fileNameArr){ if( ! fileName.equals(".") && ! fileName.equals("")){ newFileNameList.add(fileName); } } return newFileNameList; } public static String filterExtraSlash(final String path){ if (null == path){ return null;//NOPMD } String[] fileNameArr = path.split("/"); List<String> subPathList = filterExtraSubPath(fileNameArr); return "/" + String.join("/", subPathList) + (path.endsWith("/") && !path.equals("/")?"/":""); }
pathutil.java