🚩 完善文件树打开逻辑

This commit is contained in:
gewuyou 2023-10-18 15:26:19 +08:00
parent cae04fe2a0
commit 9037223584
9 changed files with 187 additions and 108 deletions

View File

@ -41,7 +41,6 @@ public abstract class AbstractBaseMenu extends AbstractMenu<Menu> {
@Override @Override
public void initMenu() { public void initMenu() {
registerMenu(); registerMenu();
logger.info("初始化菜单!");
Menu menu = getMenu(); Menu menu = getMenu();
// 菜单名称国际化 // 菜单名称国际化
UiResourceBundle.bindStringProperty(menu.textProperty(), getMenuName()); UiResourceBundle.bindStringProperty(menu.textProperty(), getMenuName());

View File

@ -18,8 +18,8 @@ import java.nio.file.Path;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.ArrayList; import java.util.List;
import java.util.Set; import java.util.*;
import static org.kordamp.ikonli.antdesignicons.AntDesignIconsFilled.*; import static org.kordamp.ikonli.antdesignicons.AntDesignIconsFilled.*;
@ -179,6 +179,42 @@ public class FileUtil {
return dirFileModel; return dirFileModel;
} }
/**
* Retrieves a DirFileModel object based on the given dirFileModels map.
*
* @param dirFileModels a map containing the dirFileModels data
* @return the DirFileModel object
*/
public static DirFileModel getDirFileModel(Map<String, Object> dirFileModels) {
if (Objects.isNull(dirFileModels) || dirFileModels.isEmpty()) {
return null;
}
DirFileModel dirFileModel = new DirFileModel(
(String) dirFileModels.get("path"),
(String) dirFileModels.get("name"), new ArrayList<>(),
new FontIcon(FOLDER),
new FontIcon(FOLDER_OPEN), (Boolean) dirFileModels.get("open"));
Optional<Object> o = Optional.ofNullable(dirFileModels.get("childFile"));
if (o.isEmpty()) {
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);
dirFileModel.getChildFile().add(childDirFileModel);
}
}
return dirFileModel;
}
/** /**
* 文件夹迁移 * 文件夹迁移
* *
@ -360,7 +396,7 @@ public class FileUtil {
processBuilder = new ProcessBuilder("open", "-a", "Terminal", folder.getAbsolutePath()); processBuilder = new ProcessBuilder("open", "-a", "Terminal", folder.getAbsolutePath());
} else { } else {
// Linux或其他系统 // Linux或其他系统
processBuilder = new ProcessBuilder("gnome-terminal", "--working-directory=", folder.getAbsolutePath()); processBuilder = new ProcessBuilder("xdg-open", folder.getAbsolutePath());
} }
return processBuilder; return processBuilder;
} }

View File

@ -4,8 +4,6 @@ import javafx.scene.control.Tab;
import javafx.scene.control.TextField; import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCode;
import javafx.stage.FileChooser; import javafx.stage.FileChooser;
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.common.constants.AppConstants; import org.jcnc.jnotepad.app.common.constants.AppConstants;
import org.jcnc.jnotepad.app.common.constants.TextConstants; import org.jcnc.jnotepad.app.common.constants.TextConstants;
import org.jcnc.jnotepad.app.common.manager.ApplicationCacheManager; import org.jcnc.jnotepad.app.common.manager.ApplicationCacheManager;
@ -28,7 +26,7 @@ import java.nio.charset.Charset;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import static org.jcnc.jnotepad.app.common.constants.TextConstants.*; import static org.jcnc.jnotepad.app.common.constants.TextConstants.NEW_FILE;
import static org.jcnc.jnotepad.app.utils.FileUtil.getFileText; import static org.jcnc.jnotepad.app.utils.FileUtil.getFileText;
import static org.jcnc.jnotepad.controller.config.UserConfigController.CONFIG_NAME; import static org.jcnc.jnotepad.controller.config.UserConfigController.CONFIG_NAME;
@ -329,73 +327,4 @@ public class TabUtil {
tab.setLastModifiedTimeOfAssociatedFile(file.lastModified()); tab.setLastModifiedTimeOfAssociatedFile(file.lastModified());
CenterTabPaneManager.getInstance().addNewTab(tab); CenterTabPaneManager.getInstance().addNewTab(tab);
} }
/**
* Updates the context menu for a given tab in the center tab pane.
*
* @param tab The tab for which the context menu is being updated.
*/
public static void initTabContextMenu(CenterTab tab) {
ContextMenuBuilder builder = new ContextMenuBuilder();
CenterTabPaneManager centerTabPaneManager = CenterTabPaneManager.getInstance();
File file = (File) tab.getUserData();
// 设置上下文菜单
tab.setContextMenu(
builder
.addMenuItem(
CLOSE,
e -> centerTabPaneManager.removeTab(tab))
.addMenuItem(
CLOSE_OTHER_TABS,
e -> centerTabPaneManager.removeOtherTabs(tab),
tab.hasOtherTabsPropertyProperty()
)
.addMenuItem(
CLOSE_ALL_TABS,
e -> centerTabPaneManager.removeAllTabs())
.addMenuItem(
CLOSE_LEFT_TABS,
e -> centerTabPaneManager.removeLeftTabs(tab),
tab.hasLeftTabsPropertyProperty()
)
.addMenuItem(
CLOSE_RIGHT_TABS,
e -> centerTabPaneManager.removeRightTabs(tab),
tab.hasRightTabsPropertyProperty()
)
.addSeparatorMenuItem(tab.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()
, tab.relevancePropertyProperty()
)
.addSeparatorMenuItem()
.addMenuItem(SAVE, e -> saveFile(tab))
.addMenuItem(SAVE_AS, e -> saveAsFile(tab), tab.relevancePropertyProperty())
.addMenuItem(RENAME, e -> rename(tab))
.addSeparatorMenuItem(tab.relevancePropertyProperty())
.addMenu(new MenuBuilder(OPEN_ON)
.addMenuItem(EXPLORER, e -> FileUtil.openExplorer(file))
.addMenuItem(TERMINAL, e -> FileUtil.openTerminal(file.getParentFile()))
.build(), tab.relevancePropertyProperty())
.addSeparatorMenuItem()
.addCheckMenuItem(FIXED_TAB,
e -> centerTabPaneManager.updateTabPinnedState(tab))
.addSeparatorMenuItem()
.addCheckMenuItem(tab.getReadOnly(),
e -> centerTabPaneManager.updateReadOnlyProperty(tab))
.build());
}
} }

View File

@ -54,6 +54,18 @@ public class CacheController {
return; return;
} }
Map<String, Cache> caches = new HashMap<>(16); Map<String, Cache> caches = new HashMap<>(16);
setCaches(namespaces, cacheFileDir, caches);
}
/**
* Sets the caches for the given namespaces.
*
* @param namespaces an array of namespace names
* @param cacheFileDir the directory where the cache files are stored
* @param caches a map of caches to be set
*/
private void setCaches(String[] namespaces, File cacheFileDir, Map<String, Cache> caches) {
for (String namespace : namespaces) { for (String namespace : namespaces) {
// 获取命名空间对应的文件夹 // 获取命名空间对应的文件夹
File namespaceDir = new File(cacheFileDir, namespace); File namespaceDir = new File(cacheFileDir, namespace);
@ -80,12 +92,16 @@ public class CacheController {
cacheMap.forEach((k, v) -> setUpCache(namespace, groupName, k, v, caches)); cacheMap.forEach((k, v) -> setUpCache(namespace, groupName, k, v, caches));
} catch (IOException e) { } catch (IOException e) {
logger.error("读取缓存文件出错!", e); logger.error("读取缓存文件出错!", e);
try {
Files.delete(cacheFileDir.toPath());
} catch (IOException ignore) {
logger.error("删除失败");
}
} }
} }
// 设置缓存 // 设置缓存
APPLICATION_CACHE_MANAGER.setCaches(caches); APPLICATION_CACHE_MANAGER.setCaches(caches);
} }
} }
/** /**

View File

@ -57,11 +57,11 @@ public class OpenDirectory implements EventHandler<ActionEvent> {
public void flushDirSidebar(File file) { public void flushDirSidebar(File file) {
// 将文件转为实体类 // 将文件转为实体类
DirFileModel dirFileModel = FileUtil.getDirFileModel(file); DirFileModel dirFileModel = FileUtil.getDirFileModel(file);
// 缓存已打开的文件夹
CACHE_MANAGER.addCache(CACHE_MANAGER.createCache(GROUP, "folderThatWasOpened", file.getAbsolutePath(), CacheExpirationTime.NEVER_EXPIRES.getValue()));
// 打开侧边栏 // 打开侧边栏
DIRECTORY_SIDEBAR_MANAGER.controlShow(true); DIRECTORY_SIDEBAR_MANAGER.controlShow(true);
// 设置文件树功能 // 设置文件树功能
DIRECTORY_SIDEBAR_MANAGER.setTreeView(dirFileModel); DIRECTORY_SIDEBAR_MANAGER.setTreeView(dirFileModel);
// 缓存已打开的文件夹
CACHE_MANAGER.addCache(CACHE_MANAGER.createCache(GROUP, "folderThatWasOpened", dirFileModel, CacheExpirationTime.NEVER_EXPIRES.getValue()));
} }
} }

View File

@ -46,7 +46,6 @@ public class Controller implements ControllerAble<List<String>> {
List<String> fileTab = (List<String>) cacheData.orElse(Collections.emptyList()); List<String> fileTab = (List<String>) cacheData.orElse(Collections.emptyList());
// 打开上次打开的标签页 // 打开上次打开的标签页
fileTab.forEach(filePath -> openFileToTab(new File(filePath))); fileTab.forEach(filePath -> openFileToTab(new File(filePath)));
if (!rawParameters.isEmpty()) { if (!rawParameters.isEmpty()) {
String filePath = rawParameters.get(0); String filePath = rawParameters.get(0);
openAssociatedFile(filePath); openAssociatedFile(filePath);

View File

@ -1,7 +1,9 @@
package org.jcnc.jnotepad.model.entity; package org.jcnc.jnotepad.model.entity;
import com.fasterxml.jackson.annotation.JsonIgnore;
import javafx.scene.Node; import javafx.scene.Node;
import java.io.File;
import java.util.List; import java.util.List;
@ -17,6 +19,7 @@ public class DirFileModel {
* 路径 * 路径
*/ */
private String path; private String path;
/** /**
* 文件名 * 文件名
*/ */
@ -25,24 +28,64 @@ public class DirFileModel {
/** /**
* 未选中时的图标 * 未选中时的图标
*/ */
@JsonIgnore
private Node iconIsNotSelected; private Node iconIsNotSelected;
/** /**
* 选中时的图标 * 选中时的图标
*/ */
@JsonIgnore
private Node iconIsSelected; private Node iconIsSelected;
/** /**
* 子文件 * 子文件
*/ */
private List<DirFileModel> childFile; private List<DirFileModel> childFile;
/**
* 是否打开
*/
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) { public DirFileModel(String path, String name, List<DirFileModel> childFile, Node iconIsNotSelected, Node iconIsSelected) {
this.path = path; this.path = path;
this.name = name; this.name = name;
this.childFile = childFile; this.childFile = childFile;
this.iconIsNotSelected = iconIsNotSelected; this.iconIsNotSelected = iconIsNotSelected;
this.iconIsSelected = iconIsSelected; this.iconIsSelected = iconIsSelected;
this.isOpen = false;
} }
public DirFileModel(String path, String name, List<DirFileModel> childFile, Node iconIsNotSelected, Node iconIsSelected, boolean isOpen) {
this.path = path;
this.name = name;
this.childFile = childFile;
this.iconIsNotSelected = iconIsNotSelected;
this.iconIsSelected = iconIsSelected;
this.isOpen = isOpen;
}
public DirFileModel() {
}
/**
* Check if the given `DirFileModel` represents a directory.
*
* @param childFile the `DirFileModel` to check
* @return `true` if the `childFile` represents a directory, `false` otherwise
*/
public static boolean isDirectoryByDirFileModel(DirFileModel childFile) {
return new File(childFile.getPath()).isDirectory();
}
public boolean isOpen() {
return isOpen;
}
public List<DirFileModel> getChildFile() { public List<DirFileModel> getChildFile() {
return childFile; return childFile;
@ -88,4 +131,9 @@ public class DirFileModel {
public void setIconIsSelected(Node iconIsSelected) { public void setIconIsSelected(Node iconIsSelected) {
this.iconIsSelected = iconIsSelected; this.iconIsSelected = iconIsSelected;
} }
public void setOpen(boolean open) {
isOpen = open;
}
} }

View File

@ -11,7 +11,7 @@ import org.jcnc.jnotepad.model.entity.DirFileModel;
import org.jcnc.jnotepad.ui.views.root.center.main.MainBorderPane; import org.jcnc.jnotepad.ui.views.root.center.main.MainBorderPane;
import org.jcnc.jnotepad.ui.views.root.center.main.center.directory.DirectorySidebarPane; import org.jcnc.jnotepad.ui.views.root.center.main.center.directory.DirectorySidebarPane;
import java.io.File; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
/** /**
@ -31,7 +31,7 @@ public class DirectorySidebarManager {
private static final MainBorderPane MAIN_BORDER_PANE = MainBorderPane.getInstance(); private static final MainBorderPane MAIN_BORDER_PANE = MainBorderPane.getInstance();
private static final DirectorySidebarPane DIRECTORY_SIDEBAR_PANE = DirectorySidebarPane.getInstance(); private static final DirectorySidebarPane DIRECTORY_SIDEBAR_PANE = DirectorySidebarPane.getInstance();
private static final double LAST_DIVIDER_POSITION = 0.3; private static final double LAST_DIVIDER_POSITION = 0.3;
private static boolean isShow = false; private boolean isShow = false;
private DirectorySidebarManager() { private DirectorySidebarManager() {
@ -49,6 +49,8 @@ public class DirectorySidebarManager {
*/ */
private static ChangeListener<Boolean> getTreeItemListener(TreeItem<DirFileModel> item) { private static ChangeListener<Boolean> getTreeItemListener(TreeItem<DirFileModel> item) {
return (observable, oldValue, newValue) -> { return (observable, oldValue, newValue) -> {
// 记录打开状态
item.getValue().setOpen(newValue);
if (Boolean.TRUE.equals(newValue)) { if (Boolean.TRUE.equals(newValue)) {
item.setGraphic(item.getValue().getIconIsSelected()); item.setGraphic(item.getValue().getIconIsSelected());
} else { } else {
@ -57,15 +59,6 @@ public class DirectorySidebarManager {
}; };
} }
/**
* Check if the given `DirFileModel` represents a directory.
*
* @param childFile the `DirFileModel` to check
* @return `true` if the `childFile` represents a directory, `false` otherwise
*/
private static boolean isDirectoryByDirFileModel(DirFileModel childFile) {
return new File(childFile.getPath()).isDirectory();
}
/** /**
* 控制文件树显示 * 控制文件树显示
@ -113,6 +106,7 @@ public class DirectorySidebarManager {
DIRECTORY_SIDEBAR_PANE.setRoot(rootItem); DIRECTORY_SIDEBAR_PANE.setRoot(rootItem);
rootItem.expandedProperty().addListener(getTreeItemListener(rootItem)); rootItem.expandedProperty().addListener(getTreeItemListener(rootItem));
rootItem.setExpanded(dirFileModel.isOpen());
expandFolder(dirFileModel, rootItem); expandFolder(dirFileModel, rootItem);
} }
@ -127,14 +121,14 @@ public class DirectorySidebarManager {
if (childFileList != null) { if (childFileList != null) {
for (DirFileModel childFile : childFileList) { for (DirFileModel childFile : childFileList) {
TreeItem<DirFileModel> childItem = new TreeItem<>(childFile, childFile.getIconIsNotSelected()); TreeItem<DirFileModel> childItem = new TreeItem<>(childFile, childFile.getIconIsNotSelected());
// 只有文件夹树才添加监听事件 // 只有文件夹树才添加监听事件与展开
if (isDirectoryByDirFileModel(childFile)) { if (DirFileModel.isDirectoryByDirFileModel(childFile)) {
childItem.setExpanded(childFile.isOpen());
childItem.expandedProperty().addListener(getTreeItemListener(childItem)); childItem.expandedProperty().addListener(getTreeItemListener(childItem));
} }
item.getChildren().add(childItem); item.getChildren().add(childItem);
expandFolder(childFile, childItem); expandFolder(childFile, childItem);
} }
} }
} }
@ -145,7 +139,7 @@ public class DirectorySidebarManager {
*/ */
public void expandTheOpenFileTree() { public void expandTheOpenFileTree() {
// 获取缓存 // 获取缓存
Object cacheData = CACHE_MANAGER.getCacheData(OpenDirectory.GROUP, "folderThatWasOpened"); LinkedHashMap<String, Object> cacheData = (LinkedHashMap<String, Object>) CACHE_MANAGER.getCacheData(OpenDirectory.GROUP, "folderThatWasOpened");
// 判空 // 判空
if (cacheData == null) { if (cacheData == null) {
return; return;
@ -153,8 +147,6 @@ public class DirectorySidebarManager {
// 打开侧边栏 // 打开侧边栏
controlShow(true); controlShow(true);
// 设置文件树功能 // 设置文件树功能
setTreeView(FileUtil.getDirFileModel(new File((String) cacheData))); setTreeView(FileUtil.getDirFileModel(cacheData));
} }
} }

View File

@ -7,9 +7,9 @@ import javafx.collections.ObservableList;
import javafx.scene.control.CheckMenuItem; import javafx.scene.control.CheckMenuItem;
import javafx.scene.control.Tab; import javafx.scene.control.Tab;
import org.fxmisc.flowless.VirtualizedScrollPane; import org.fxmisc.flowless.VirtualizedScrollPane;
import org.jcnc.jnotepad.app.utils.FileUtil; import org.jcnc.jnotepad.api.core.views.menu.builder.ContextMenuBuilder;
import org.jcnc.jnotepad.app.utils.LoggerUtil; import org.jcnc.jnotepad.api.core.views.menu.builder.MenuBuilder;
import org.jcnc.jnotepad.app.utils.TabUtil; import org.jcnc.jnotepad.app.utils.*;
import org.jcnc.jnotepad.controller.config.UserConfigController; import org.jcnc.jnotepad.controller.config.UserConfigController;
import org.jcnc.jnotepad.ui.component.module.TextCodeArea; import org.jcnc.jnotepad.ui.component.module.TextCodeArea;
import org.jcnc.jnotepad.ui.views.manager.BottomStatusBoxManager; import org.jcnc.jnotepad.ui.views.manager.BottomStatusBoxManager;
@ -22,7 +22,7 @@ import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import static org.jcnc.jnotepad.app.common.constants.TextConstants.READ_ONLY; import static org.jcnc.jnotepad.app.common.constants.TextConstants.*;
/** /**
* 封装标签页组件增加属于标签页的属性例如自动换行开关 * 封装标签页组件增加属于标签页的属性例如自动换行开关
@ -79,10 +79,10 @@ public class CenterTab extends Tab {
this.charset = charset; this.charset = charset;
this.relevanceProperty.set(relevanceProperty); this.relevanceProperty.set(relevanceProperty);
this.setUserData(file); this.setUserData(file);
// 将监听器上下文菜单集中处理 // 将监听器上下文菜单集中处理
Platform.runLater(() -> { Platform.runLater(() -> {
initTextAreaListeners(); initTextAreaListeners();
this.contextMenuMonitor(); initTabContextMenu();
initFixedStateListener(); initFixedStateListener();
}); });
} }
@ -130,13 +130,73 @@ public class CenterTab extends Tab {
} }
/** /**
* Monitors the context menu. * Updates the context menu for a given tab in the center tab pane.
*
*/ */
public void contextMenuMonitor() { private void initTabContextMenu() {
TabUtil.initTabContextMenu(this); ContextMenuBuilder builder = new ContextMenuBuilder();
CenterTabPaneManager centerTabPaneManager = CenterTabPaneManager.getInstance();
File file = (File) this.getUserData();
// 设置上下文菜单
this.setContextMenu(
builder
.addMenuItem(
CLOSE,
e -> centerTabPaneManager.removeTab(this))
.addMenuItem(
CLOSE_OTHER_TABS,
e -> centerTabPaneManager.removeOtherTabs(this),
this.hasOtherTabsPropertyProperty()
)
.addMenuItem(
CLOSE_ALL_TABS,
e -> centerTabPaneManager.removeAllTabs())
.addMenuItem(
CLOSE_LEFT_TABS,
e -> centerTabPaneManager.removeLeftTabs(this),
this.hasLeftTabsPropertyProperty()
)
.addMenuItem(
CLOSE_RIGHT_TABS,
e -> centerTabPaneManager.removeRightTabs(this),
this.hasRightTabsPropertyProperty()
)
.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()
, this.relevancePropertyProperty()
)
.addSeparatorMenuItem()
.addMenuItem(SAVE, e -> TabUtil.saveFile(this))
.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())
.addSeparatorMenuItem()
.addCheckMenuItem(FIXED_TAB,
e -> centerTabPaneManager.updateTabPinnedState(this))
.addSeparatorMenuItem()
.addCheckMenuItem(this.getReadOnly(),
e -> centerTabPaneManager.updateReadOnlyProperty(this))
.build());
} }
/** /**
* 保存选中的文件标签页 * 保存选中的文件标签页
*/ */