packagecn.com.xxx.project.controller;importjava.io.File;importjava.util.ArrayList;importjava.util.List;importorg.apache.commons.net.ftp.FTPFile;importorg.apache.commons.net.ftp.FTPFileFilter;importcn.com.xxx.project.core.DMGUIException;importcn.com.xxx.project.core.FTPFileManagerWrapper;importcn.com.xxx.project.model.GlobalConfig;importcn.com.xxx.project.model.OperationInfo;importcn.com.xxx.project.util.AlertDialogUtil;importcn.com.xxx.project.util.PathUtil;importjavafx.application.Platform;importjavafx.collections.FXCollections;importjavafx.collections.ObservableList;importjavafx.event.EventHandler;importjavafx.fxml.FXML;importjavafx.scene.control.ComboBox;importjavafx.scene.control.TextField;importjavafx.scene.input.KeyCode;importjavafx.scene.input.KeyEvent;importjavafx.stage.DirectoryChooser;importjavafx.stage.FileChooser;importjavafx.stage.FileChooser.ExtensionFilter;importjavafx.stage.Stage;interfaceItemFilter {booleanmatches(String inputStr, String optionalStr);
}public classUpload2HomeController {
@FXMLprivateTextField inputPathField;
@FXMLprivate ComboBoxremotePathComboBox;privateMain mainApp;privateStage dialogStage;private boolean okClicked = false;//下拉条目查找器
privateFTPFileManagerWrapper ftpFileMng;private final ObservableList itemList =FXCollections.observableArrayList();private boolean isFilterNotRequired = true;private final ObservableList 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) throwsDMGUIException {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 ListlistAbsDirPath(String path){
List files =ftpFileMng.list(path, ftpFilter);
List absDirPaths = new ArrayList();
path= path.endsWith("/") ? path : path + "/";for(FTPFile file: files) {
absDirPaths.add(path+file.getName());
}returnabsDirPaths;
}public void initFTPFileMng() throwsDMGUIException{
ftpFileMng= newFTPFileManagerWrapper();
ftpFileMng.setWorkPath(GlobalConfig.getInstance().getHomePath());
}private voidsetFocusedPropertyListener() {
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 voidsetKeyListener() {
remotePathComboBox.addEventHandler(KeyEvent.KEY_RELEASED,new EventHandler() {
@Overridepublic 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(finalKeyCode keyCode) {//BACK_SPACE/DELETE不做特殊处理
returnkeyCode.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 voidrefreshItems() {if(isRequiredRefresh()) {
itemList.setAll(listAbsDirPath(getDirPath(getText())));
}
}private String getDirPath(finalString path){int lastSlashCharIndex = path.lastIndexOf("/");if (lastSlashCharIndex == -1) {
lastSlashCharIndex=path.length();
}else if(lastSlashCharIndex == 0){
lastSlashCharIndex= 1;
}return path.substring(0, lastSlashCharIndex);
}/*** 待优化,考虑角度:字符在末尾增减,在中间增减,增减单字符,增减多字符*/
private booleanisRequiredRefresh(){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("/");
}returnisRequied;
}private voidrefreshFilteredItems() {
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(finalString text) {
setText(text);
moveCaret();
}private void setText(finalString text) {
remotePathComboBox.getEditor().setText(text);
}privateString getText() {returnremotePathComboBox.getEditor().getText();
}/*** FTPClient#listFiles()无法准确处理路径末尾多斜杠问题,需要强制修正*/
private voidreviseText(){
setText(PathUtil.filterExtraSlash(getText()));
}private voidresetComboBoxItemsAndDisplay() {
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 voidshow() {if (!remotePathComboBox.getItems().isEmpty() && !remotePathComboBox.isShowing()) {
remotePathComboBox.show();
}
}private voidmoveCaret() {
String test=getText();if (test != null) {
moveCaret(test.length());
}
}private void moveCaret(final intpos) {
remotePathComboBox.getEditor().positionCaret(pos);
}public void setDialogStage(finalStage dialogStage) {this.dialogStage =dialogStage;
}public void setInitInput(finalString localPath) {
inputPathField.setText(localPath);
}public booleanisOkClicked() {returnokClicked;
}public void updateInfo(finalOperationInfo updateInfo) {
updateInfo.setLocalPath(inputPathField.getText());
updateInfo.setRemotePath(
PathUtil.splicePath(GlobalConfig.getInstance().getHomePath(), getText()));
}
@FXMLprivate void handleOk() { //NOPMD
try{
checkInput();
okClicked= true;
dialogStage.close();
}catch(DMGUIException e) {
AlertDialogUtil.createLazyAlertDialog(e.getMessage(),"输入错误!");
}
}
@FXMLprivate void handleCancel() { //NOPMD
dialogStage.close();
}
@FXMLprivate void handleBrowseDir() { //NOPMD
DirectoryChooser dirChooser = newDirectoryChooser();
dirChooser.setInitialDirectory(new File("."));
File file=dirChooser.showDialog(mainApp.getPrimaryStage());if (file != null) {
inputPathField.setText(file.getPath().toString());
}
}
@FXMLprivate void handleBrowseFile() { //NOPMD//Open a directory selecting dialog
FileChooser fileChooser = newFileChooser();;
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() throwsDMGUIException{final StringBuilder errMsg = newStringBuilder();
checkInputLocalPath(errMsg);
checkInputRemotePath(errMsg);if(errMsg.length() != 0){throw newDMGUIException(errMsg.toString());
}
}private void checkInputLocalPath(finalStringBuilder errMsg){if (this.inputPathField.getText() == null
|| this.inputPathField.getText().length() == 0) {
errMsg.append("本地路径为空,请重新输入!\n");
}else{final File file = newFile(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(finalStringBuilder 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");
}
}
}