🐛 修复文件树由于缓存问题导致新增的文件无法被显示 🚩初步添加文件树菜单

This commit is contained in:
gewuyou 2023-10-24 18:50:25 +08:00
parent 9037223584
commit 2c3416fde5
13 changed files with 279 additions and 74 deletions

View File

@ -76,6 +76,23 @@ public abstract class AbstractMenuBuilder<B, T> {
return getBuilder();
}
/**
* 添加菜单项
*
* @param label 菜单项名称
* @param eventHandler 事件
* @param visible 是否可见
* @return 建造者
*/
public B addMenuItem(String label, EventHandler<ActionEvent> eventHandler, boolean visible) {
MenuItem menuItem = new MenuItem(label);
menuItem.setOnAction(eventHandler);
menuItem.setVisible(visible);
menuItems.put(label, menuItem);
getItems().add(menuItem);
return getBuilder();
}
/**
* 添加单选菜单项
*
@ -141,6 +158,20 @@ public abstract class AbstractMenuBuilder<B, T> {
return getBuilder();
}
/**
* 添加菜单
*
* @param menu 菜单
* @param visible 是否隐藏
* @return 建造者
*/
public B addMenu(Menu menu, boolean visible) {
menu.setVisible(visible);
menuItems.put(menu.getText(), menu);
getItems().add(menu);
return getBuilder();
}
/**
* 添加分割线
@ -166,6 +197,19 @@ public abstract class AbstractMenuBuilder<B, T> {
return getBuilder();
}
/**
* 添加分割线
*
* @param visible 是否可见
* @return 建造者
*/
public B addSeparatorMenuItem(boolean visible) {
SeparatorMenuItem separatorMenuItem = new SeparatorMenuItem();
separatorMenuItem.setVisible(visible);
getItems().add(separatorMenuItem);
return getBuilder();
}
/**
* Build menu
*

View File

@ -23,6 +23,10 @@ public class TextConstants {
* 文件文本常量
*/
public static final String FILE = "FILE";
/**
* 文件夹
*/
public static final String FOLDER = "FOLDER";
/**
* 构建文本常量
@ -139,6 +143,16 @@ public class TextConstants {
*/
public static final String NEW_FILE = "NEW_FILE";
/**
* 新建文件夹
*/
public static final String NEW_DIRECTORY = "NEW_DIRECTORY";
/**
* 删除
*/
public static final String DELETE = "DELETE";
/**
* 行文本常量
*/

View File

@ -37,6 +37,8 @@ public class FileUtil {
private static final String MAC = "mac";
private static final String PATH = "path";
static {
try {
MESSAGE_DIGEST_SHA_256 = MessageDigest.getInstance("SHA-256");
@ -189,9 +191,10 @@ public class FileUtil {
if (Objects.isNull(dirFileModels) || dirFileModels.isEmpty()) {
return null;
}
File rootDir = new File((String) dirFileModels.get(PATH));
DirFileModel dirFileModel = new DirFileModel(
(String) dirFileModels.get("path"),
(String) dirFileModels.get("name"), new ArrayList<>(),
rootDir.getAbsolutePath(),
rootDir.getName(), new ArrayList<>(),
new FontIcon(FOLDER),
new FontIcon(FOLDER_OPEN), (Boolean) dirFileModels.get("open"));
Optional<Object> o = Optional.ofNullable(dirFileModels.get("childFile"));
@ -199,16 +202,29 @@ public class FileUtil {
return null;
}
List<Map<String, Object>> childFile = (List<Map<String, Object>>) o.get();
for (Map<String, Object> map : childFile) {
Object obj = map.get("childFile");
if (obj == null) {
dirFileModel.getChildFile().add(new DirFileModel(
(String) map.get("path"), (String) map.get("name"), null,
getIconCorrespondingToFileName((String) map.get("name")),
null));
} else {
DirFileModel childDirFileModel = getDirFileModel(map);
File[] files = rootDir.listFiles();
if (files == null) {
return null;
}
for (File f : files) {
if (f.isDirectory()) {
Optional<Map<String, Object>> first = childFile
.stream()
.filter(map -> map.get(PATH).equals(f.getAbsolutePath())).findFirst();
DirFileModel childDirFileModel;
if (first.isPresent()) {
childDirFileModel = getDirFileModel(first.get());
} else {
childDirFileModel = getDirFileModel(f);
}
dirFileModel.getChildFile().add(childDirFileModel);
} else {
// 在此监测文件后缀设置对应的图标
dirFileModel.getChildFile().add(new DirFileModel(
f.getAbsolutePath(), f.getName(), null,
getIconCorrespondingToFileName(f.getName()),
null));
}
}
return dirFileModel;
@ -365,17 +381,18 @@ public class FileUtil {
* @param folder the folder in which to open the terminal
*/
public static void openTerminal(File folder) {
if (folder.exists() && folder.isDirectory()) {
String os = System.getProperty("os.name").toLowerCase();
ProcessBuilder processBuilder = getProcessBuilder(folder, os);
try {
processBuilder.start();
} catch (IOException e) {
PopUpUtil.errorAlert("打开失败", "打开于终端失败", "错误原因" + e.getMessage(), null, null);
}
} else {
logger.info("文件夹不存在或者不是文件夹");
if (!folder.exists()) {
return;
}
if (folder.isFile()) {
folder = folder.getParentFile();
}
String os = System.getProperty("os.name").toLowerCase();
ProcessBuilder processBuilder = getProcessBuilder(folder, os);
try {
processBuilder.start();
} catch (IOException e) {
PopUpUtil.errorAlert("打开失败", "打开于终端失败", "错误原因:" + e.getMessage(), null, null);
}
}
@ -400,5 +417,18 @@ public class FileUtil {
}
return processBuilder;
}
/**
* Creates a file at the specified path.
*
* @param path The path to the file to be created.
*/
public static void createFile(Path path) {
try {
Files.createFile(path);
} catch (IOException e) {
logger.error("创建文件失败", e);
}
}
}

View File

@ -128,19 +128,18 @@ public class TabUtil {
* @param tab 标签页组件
*/
private static void handleRenameTab(CenterTab tab) {
TextField textField = new TextField(tab.getText());
textField.getStyleClass().add("tab-title-editable");
// 临时记录标签页名称
String tempName = tab.getText();
TextField textField = new TextField(tempName);
textField.getStyleClass().add("tab-title-editable");
// 清空标签页名称
tab.setText("");
// 监听 Enter 完成编辑
textField.setOnKeyPressed(event -> {
if (event.getCode() == KeyCode.ENTER) {
String newTabName = textField.getText();
// 检查是否存在相同名称的标签页
if (isTabNameExists(newTabName)) {
if (tabNameExists(newTabName)) {
// 显示弹窗并提示用户更换名称
showDuplicateNameAlert(newTabName);
@ -162,7 +161,7 @@ public class TabUtil {
textField.focusedProperty().addListener((observable, oldValue, newValue) -> {
String newTabName = textField.getText();
// 检查是否存在相同名称的标签页
if (isTabNameExists(newTabName)) {
if (tabNameExists(newTabName)) {
// 恢复原始名称
tab.setText(tempName);
@ -191,7 +190,7 @@ public class TabUtil {
* @param newTabName 要检查的新标签页名称
* @return 如果存在具有相同名称的标签页则返回 true否则返回 false
*/
private static boolean isTabNameExists(String newTabName) {
private static boolean tabNameExists(String newTabName) {
CenterTabPane tabPane = CenterTabPane.getInstance();
return tabPane.getTabs().stream()
.anyMatch(tab -> tab.getText().equals(newTabName));
@ -245,6 +244,22 @@ public class TabUtil {
public static void addNewFileTab() {
// 创建一个新的文本编辑区
TextCodeArea textArea = new TextCodeArea();
// 创建标签页
CenterTab centerTab = new CenterTab(
generateDefaultName(),
textArea);
// 将Tab页添加到TabPane中
CenterTabPaneManager.getInstance().addNewTab(centerTab);
// 更新编码信息
BottomStatusBoxManager.getInstance().updateEncodingLabel();
}
/**
* Generate the default name for a new tab.
*
* @return The default name for a new tab.
*/
private static String generateDefaultName() {
// 设定初始索引
int index = 1;
StringBuilder tabTitle = new StringBuilder();
@ -275,14 +290,7 @@ public class TabUtil {
break;
}
}
// 创建标签页
CenterTab centerTab = new CenterTab(
tabTitle.toString(),
textArea);
// 将Tab页添加到TabPane中
CenterTabPaneManager.getInstance().addNewTab(centerTab);
// 更新编码信息
BottomStatusBoxManager.getInstance().updateEncodingLabel();
return tabTitle.toString();
}
/**

View File

@ -51,9 +51,13 @@ public class OpenDirectory implements EventHandler<ActionEvent> {
CACHE_MANAGER.addCache(cache);
}
flushDirSidebar(file);
}
/**
* Flushes the directory sidebar with the given file.
*
* @param file the file to be converted into an entity class
*/
public void flushDirSidebar(File file) {
// 将文件转为实体类
DirFileModel dirFileModel = FileUtil.getDirFileModel(file);

View File

@ -23,6 +23,7 @@ public class DirFileModel {
/**
* 文件名
*/
@JsonIgnore
private String name;
/**
@ -45,13 +46,6 @@ public class DirFileModel {
*/
private boolean isOpen;
public DirFileModel(String path, String name, List<DirFileModel> childFile, boolean isOpen) {
this.path = path;
this.name = name;
this.childFile = childFile;
this.isOpen = isOpen;
}
public DirFileModel(String path, String name, List<DirFileModel> childFile, Node iconIsNotSelected, Node iconIsSelected) {
this.path = path;
this.name = name;

View File

@ -103,13 +103,13 @@ public class DirectorySidebarManager {
*/
public void setTreeView(DirFileModel dirFileModel) {
TreeItem<DirFileModel> rootItem = new TreeItem<>(dirFileModel, dirFileModel.getIconIsNotSelected());
DIRECTORY_SIDEBAR_PANE.setRoot(rootItem);
rootItem.expandedProperty().addListener(getTreeItemListener(rootItem));
rootItem.setExpanded(dirFileModel.isOpen());
expandFolder(dirFileModel, rootItem);
}
/**
* 递归展开 dirFileModel
*

View File

@ -0,0 +1,74 @@
package org.jcnc.jnotepad.ui.views.manager;
import javafx.scene.control.Menu;
import org.jcnc.jnotepad.api.core.views.menu.builder.MenuBuilder;
import org.jcnc.jnotepad.app.utils.ClipboardUtil;
import org.jcnc.jnotepad.app.utils.FileUtil;
import org.jcnc.jnotepad.app.utils.NotificationUtil;
import java.io.File;
import static org.jcnc.jnotepad.app.common.constants.TextConstants.*;
/**
* 菜单管理类
*
* @author gewuyou
*/
public class MenuManager {
private MenuManager() {
}
/**
* Generates a copy menu for the given file.
*
* @param file the file to generate the copy menu for
* @return the generated copy menu
*/
public static Menu getCopyMenu(File file) {
return new MenuBuilder(COPY)
.addMenuItem(FILE_NAME, e -> {
ClipboardUtil.writeTextToClipboard(file.getName());
NotificationUtil.infoNotification("已复制文件名!");
})
.addMenuItem(FILE_PATH, e -> {
ClipboardUtil.writeTextToClipboard(file.getAbsolutePath());
NotificationUtil.infoNotification("已复制文件路径!");
})
.addMenuItem(FOLDER_PATH, e -> {
ClipboardUtil.writeTextToClipboard(file.getParent());
NotificationUtil.infoNotification("已复制所在文件夹!");
})
.build();
}
/**
* Retrieves the open menu for a given file.
*
* @param file the file for which to retrieve the open menu
* @return the open menu for the given file
*/
public static Menu getOpenMenu(File file) {
return new MenuBuilder(OPEN_ON)
.addMenuItem(EXPLORER, e -> FileUtil.openExplorer(file))
.addMenuItem(TERMINAL, e -> FileUtil.openTerminal(file))
.build();
}
/**
* Returns a new Menu.
*
* @return a new Menu object
*/
public static Menu getNewMenu() {
return new MenuBuilder(NEW)
.addMenuItem(FILE, e -> {
})
.addMenuItem(FOLDER, e -> {
})
.build();
}
}

View File

@ -1,12 +1,19 @@
package org.jcnc.jnotepad.ui.views.root.center.main.center.directory;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import org.jcnc.jnotepad.api.core.views.menu.builder.ContextMenuBuilder;
import org.jcnc.jnotepad.model.entity.DirFileModel;
import org.jcnc.jnotepad.ui.views.manager.DirectorySidebarManager;
import org.jcnc.jnotepad.ui.views.manager.MenuManager;
import java.io.File;
import java.util.Objects;
import static org.jcnc.jnotepad.app.common.constants.TextConstants.OPEN;
import static org.jcnc.jnotepad.app.utils.TabUtil.openFileToTab;
@ -23,23 +30,64 @@ public class DirectorySidebarPane extends TreeView<DirFileModel> {
private static final int CLICK_COUNT = 2;
private DirectorySidebarPane() {
this.setOnMouseClicked(mouseEvent -> {
if (mouseEvent.getClickCount() == CLICK_COUNT) {
TreeItem<DirFileModel> item = DirectorySidebarPane.this.getSelectionModel().getSelectedItem();
if (Objects.isNull(item)) {
return;
}
File file = new File(item.getValue().getPath());
private final DirectorySidebarManager directorySidebarManager = DirectorySidebarManager.getInstance();
private ContextMenu contextMenu;
private DirectorySidebarPane() {
initMouseClickEvent();
}
/**
* Initializes the mouse click event for the Java function.
*/
private void initMouseClickEvent() {
this.setOnMouseClicked(mouseEvent -> {
TreeItem<DirFileModel> item = DirectorySidebarPane.this.getSelectionModel().getSelectedItem();
if (Objects.isNull(item)) {
return;
}
if (mouseEvent.getClickCount() == CLICK_COUNT) {
File file = new File(item.getValue().getPath());
if (!file.isFile()) {
return;
}
openFileToTab(file);
}
if (!Objects.isNull(contextMenu)) {
contextMenu.hide();
}
if (mouseEvent.getButton() == MouseButton.SECONDARY) {
updateContextMenu(mouseEvent, item);
}
});
}
private void updateContextMenu(MouseEvent mouseEvent, TreeItem<DirFileModel> item) {
createContextMenu(item);
contextMenu.show(this, mouseEvent.getScreenX(), mouseEvent.getScreenY());
}
private void createContextMenu(TreeItem<DirFileModel> item) {
ContextMenuBuilder builder = new ContextMenuBuilder();
boolean isFile = !DirFileModel.isDirectoryByDirFileModel(item.getValue());
File file = new File(item.getValue().getPath());
contextMenu = builder
.addMenuItem(OPEN, e -> openFileToTab(file), isFile)
.addSeparatorMenuItem(isFile)
.addMenu(MenuManager.getNewMenu(), !isFile)
// .addSeparatorMenuItem()
// .addMenuItem(RENAME, e -> directorySidebarManager.rename(file))
// .addMenuItem(DELETE, e -> directorySidebarManager.delete(file))
// .addSeparatorMenuItem(isFile)
.addMenu(MenuManager.getCopyMenu(file), isFile)
.addSeparatorMenuItem(isFile)
.addMenu(MenuManager.getOpenMenu(file))
.build();
}
public static DirectorySidebarPane getInstance() {
return INSTANCE;
}

View File

@ -8,12 +8,14 @@ import javafx.scene.control.CheckMenuItem;
import javafx.scene.control.Tab;
import org.fxmisc.flowless.VirtualizedScrollPane;
import org.jcnc.jnotepad.api.core.views.menu.builder.ContextMenuBuilder;
import org.jcnc.jnotepad.api.core.views.menu.builder.MenuBuilder;
import org.jcnc.jnotepad.app.utils.*;
import org.jcnc.jnotepad.app.utils.FileUtil;
import org.jcnc.jnotepad.app.utils.LoggerUtil;
import org.jcnc.jnotepad.app.utils.TabUtil;
import org.jcnc.jnotepad.controller.config.UserConfigController;
import org.jcnc.jnotepad.ui.component.module.TextCodeArea;
import org.jcnc.jnotepad.ui.views.manager.BottomStatusBoxManager;
import org.jcnc.jnotepad.ui.views.manager.CenterTabPaneManager;
import org.jcnc.jnotepad.ui.views.manager.MenuManager;
import org.slf4j.Logger;
import java.io.BufferedWriter;
@ -163,20 +165,7 @@ public class CenterTab extends Tab {
)
.addSeparatorMenuItem(this.relevancePropertyProperty())
.addMenu(
new MenuBuilder(COPY)
.addMenuItem(FILE_NAME, e -> {
ClipboardUtil.writeTextToClipboard(file.getName());
NotificationUtil.infoNotification("已复制文件名!");
})
.addMenuItem(FILE_PATH, e -> {
ClipboardUtil.writeTextToClipboard(file.getAbsolutePath());
NotificationUtil.infoNotification("已复制文件路径!");
})
.addMenuItem(FOLDER_PATH, e -> {
ClipboardUtil.writeTextToClipboard(file.getParent());
NotificationUtil.infoNotification("已复制所在文件夹!");
})
.build()
MenuManager.getCopyMenu(file)
, this.relevancePropertyProperty()
)
.addSeparatorMenuItem()
@ -184,10 +173,7 @@ public class CenterTab extends Tab {
.addMenuItem(SAVE_AS, e -> TabUtil.saveAsFile(this), this.relevancePropertyProperty())
.addMenuItem(RENAME, e -> TabUtil.rename(this))
.addSeparatorMenuItem(this.relevancePropertyProperty())
.addMenu(new MenuBuilder(OPEN_ON)
.addMenuItem(EXPLORER, e -> FileUtil.openExplorer(file))
.addMenuItem(TERMINAL, e -> FileUtil.openTerminal(file.getParentFile()))
.build(), this.relevancePropertyProperty())
.addMenu(MenuManager.getOpenMenu(file), this.relevancePropertyProperty())
.addSeparatorMenuItem()
.addCheckMenuItem(FIXED_TAB,
e -> centerTabPaneManager.updateTabPinnedState(this))
@ -197,6 +183,7 @@ public class CenterTab extends Tab {
.build());
}
/**
* 保存选中的文件标签页
*/

View File

@ -41,5 +41,5 @@ CLOSE_OTHER_TABS=关闭其他标签页
FIXED_TAB=固定标签页
READ_ONLY=只读
OPEN_ON=打开于
FOLDER=文件夹

View File

@ -41,3 +41,4 @@ CLOSE_OTHER_TABS=Close Other Tabs
FIXED_TAB=Fixed Tab
READ_ONLY=Read Only
OPEN_ON=Open On
FOLDER=Folder

View File

@ -41,3 +41,4 @@ CLOSE_OTHER_TABS=关闭其他标签页
FIXED_TAB=固定标签页
READ_ONLY=只读
OPEN_ON=打开于
FOLDER=文件夹