From 9037223584bdf4fb5335c4548ea1533771d51585 Mon Sep 17 00:00:00 2001 From: gewuyou <1063891901@qq.com> Date: Wed, 18 Oct 2023 15:26:19 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=A9=20=E5=AE=8C=E5=96=84=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E6=A0=91=E6=89=93=E5=BC=80=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/core/views/menu/AbstractBaseMenu.java | 1 - .../org/jcnc/jnotepad/app/utils/FileUtil.java | 42 +++++++++- .../org/jcnc/jnotepad/app/utils/TabUtil.java | 73 +---------------- .../controller/cache/CacheController.java | 18 ++++- .../event/handler/toolbar/OpenDirectory.java | 4 +- .../controller/manager/Controller.java | 1 - .../jnotepad/model/entity/DirFileModel.java | 48 +++++++++++ .../manager/DirectorySidebarManager.java | 28 +++---- .../center/main/center/tab/CenterTab.java | 80 ++++++++++++++++--- 9 files changed, 187 insertions(+), 108 deletions(-) diff --git a/src/main/java/org/jcnc/jnotepad/api/core/views/menu/AbstractBaseMenu.java b/src/main/java/org/jcnc/jnotepad/api/core/views/menu/AbstractBaseMenu.java index d70b2df..5d30707 100644 --- a/src/main/java/org/jcnc/jnotepad/api/core/views/menu/AbstractBaseMenu.java +++ b/src/main/java/org/jcnc/jnotepad/api/core/views/menu/AbstractBaseMenu.java @@ -41,7 +41,6 @@ public abstract class AbstractBaseMenu extends AbstractMenu { @Override public void initMenu() { registerMenu(); - logger.info("初始化菜单!"); Menu menu = getMenu(); // 菜单名称国际化 UiResourceBundle.bindStringProperty(menu.textProperty(), getMenuName()); diff --git a/src/main/java/org/jcnc/jnotepad/app/utils/FileUtil.java b/src/main/java/org/jcnc/jnotepad/app/utils/FileUtil.java index afd6978..d45e678 100644 --- a/src/main/java/org/jcnc/jnotepad/app/utils/FileUtil.java +++ b/src/main/java/org/jcnc/jnotepad/app/utils/FileUtil.java @@ -18,8 +18,8 @@ import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Set; +import java.util.List; +import java.util.*; import static org.kordamp.ikonli.antdesignicons.AntDesignIconsFilled.*; @@ -179,6 +179,42 @@ public class FileUtil { 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 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 o = Optional.ofNullable(dirFileModels.get("childFile")); + if (o.isEmpty()) { + return null; + } + List> childFile = (List>) o.get(); + for (Map 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()); } else { // Linux或其他系统 - processBuilder = new ProcessBuilder("gnome-terminal", "--working-directory=", folder.getAbsolutePath()); + processBuilder = new ProcessBuilder("xdg-open", folder.getAbsolutePath()); } return processBuilder; } diff --git a/src/main/java/org/jcnc/jnotepad/app/utils/TabUtil.java b/src/main/java/org/jcnc/jnotepad/app/utils/TabUtil.java index 54fc742..691825a 100644 --- a/src/main/java/org/jcnc/jnotepad/app/utils/TabUtil.java +++ b/src/main/java/org/jcnc/jnotepad/app/utils/TabUtil.java @@ -4,8 +4,6 @@ import javafx.scene.control.Tab; import javafx.scene.control.TextField; import javafx.scene.input.KeyCode; 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.TextConstants; import org.jcnc.jnotepad.app.common.manager.ApplicationCacheManager; @@ -28,7 +26,7 @@ import java.nio.charset.Charset; import java.util.Comparator; 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.controller.config.UserConfigController.CONFIG_NAME; @@ -329,73 +327,4 @@ public class TabUtil { tab.setLastModifiedTimeOfAssociatedFile(file.lastModified()); 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()); - } } diff --git a/src/main/java/org/jcnc/jnotepad/controller/cache/CacheController.java b/src/main/java/org/jcnc/jnotepad/controller/cache/CacheController.java index 6edb17b..ae8475d 100644 --- a/src/main/java/org/jcnc/jnotepad/controller/cache/CacheController.java +++ b/src/main/java/org/jcnc/jnotepad/controller/cache/CacheController.java @@ -54,6 +54,18 @@ public class CacheController { return; } Map 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 caches) { for (String namespace : namespaces) { // 获取命名空间对应的文件夹 File namespaceDir = new File(cacheFileDir, namespace); @@ -80,12 +92,16 @@ public class CacheController { cacheMap.forEach((k, v) -> setUpCache(namespace, groupName, k, v, caches)); } catch (IOException e) { logger.error("读取缓存文件出错!", e); + try { + Files.delete(cacheFileDir.toPath()); + } catch (IOException ignore) { + logger.error("删除失败"); + } } } // 设置缓存 APPLICATION_CACHE_MANAGER.setCaches(caches); } - } /** diff --git a/src/main/java/org/jcnc/jnotepad/controller/event/handler/toolbar/OpenDirectory.java b/src/main/java/org/jcnc/jnotepad/controller/event/handler/toolbar/OpenDirectory.java index 60dcce0..209d677 100644 --- a/src/main/java/org/jcnc/jnotepad/controller/event/handler/toolbar/OpenDirectory.java +++ b/src/main/java/org/jcnc/jnotepad/controller/event/handler/toolbar/OpenDirectory.java @@ -57,11 +57,11 @@ public class OpenDirectory implements EventHandler { public void flushDirSidebar(File 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.setTreeView(dirFileModel); + // 缓存已打开的文件夹 + CACHE_MANAGER.addCache(CACHE_MANAGER.createCache(GROUP, "folderThatWasOpened", dirFileModel, CacheExpirationTime.NEVER_EXPIRES.getValue())); } } diff --git a/src/main/java/org/jcnc/jnotepad/controller/manager/Controller.java b/src/main/java/org/jcnc/jnotepad/controller/manager/Controller.java index 4c79cd6..7ce6b37 100644 --- a/src/main/java/org/jcnc/jnotepad/controller/manager/Controller.java +++ b/src/main/java/org/jcnc/jnotepad/controller/manager/Controller.java @@ -46,7 +46,6 @@ public class Controller implements ControllerAble> { List fileTab = (List) cacheData.orElse(Collections.emptyList()); // 打开上次打开的标签页 fileTab.forEach(filePath -> openFileToTab(new File(filePath))); - if (!rawParameters.isEmpty()) { String filePath = rawParameters.get(0); openAssociatedFile(filePath); diff --git a/src/main/java/org/jcnc/jnotepad/model/entity/DirFileModel.java b/src/main/java/org/jcnc/jnotepad/model/entity/DirFileModel.java index 3ae2f8a..67eb026 100644 --- a/src/main/java/org/jcnc/jnotepad/model/entity/DirFileModel.java +++ b/src/main/java/org/jcnc/jnotepad/model/entity/DirFileModel.java @@ -1,7 +1,9 @@ package org.jcnc.jnotepad.model.entity; +import com.fasterxml.jackson.annotation.JsonIgnore; import javafx.scene.Node; +import java.io.File; import java.util.List; @@ -17,6 +19,7 @@ public class DirFileModel { * 路径 */ private String path; + /** * 文件名 */ @@ -25,24 +28,64 @@ public class DirFileModel { /** * 未选中时的图标 */ + @JsonIgnore private Node iconIsNotSelected; /** * 选中时的图标 */ + @JsonIgnore private Node iconIsSelected; /** * 子文件 */ private List childFile; + /** + * 是否打开 + */ + private boolean isOpen; + + public DirFileModel(String path, String name, List childFile, boolean isOpen) { + this.path = path; + this.name = name; + this.childFile = childFile; + this.isOpen = isOpen; + } + public DirFileModel(String path, String name, List childFile, Node iconIsNotSelected, Node iconIsSelected) { this.path = path; this.name = name; this.childFile = childFile; this.iconIsNotSelected = iconIsNotSelected; this.iconIsSelected = iconIsSelected; + this.isOpen = false; + } + + public DirFileModel(String path, String name, List 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 getChildFile() { return childFile; @@ -88,4 +131,9 @@ public class DirFileModel { public void setIconIsSelected(Node iconIsSelected) { this.iconIsSelected = iconIsSelected; } + + public void setOpen(boolean open) { + isOpen = open; + } + } \ No newline at end of file diff --git a/src/main/java/org/jcnc/jnotepad/ui/views/manager/DirectorySidebarManager.java b/src/main/java/org/jcnc/jnotepad/ui/views/manager/DirectorySidebarManager.java index 4e0f941..7b308a3 100644 --- a/src/main/java/org/jcnc/jnotepad/ui/views/manager/DirectorySidebarManager.java +++ b/src/main/java/org/jcnc/jnotepad/ui/views/manager/DirectorySidebarManager.java @@ -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.center.directory.DirectorySidebarPane; -import java.io.File; +import java.util.LinkedHashMap; import java.util.List; /** @@ -31,7 +31,7 @@ public class DirectorySidebarManager { private static final MainBorderPane MAIN_BORDER_PANE = MainBorderPane.getInstance(); private static final DirectorySidebarPane DIRECTORY_SIDEBAR_PANE = DirectorySidebarPane.getInstance(); private static final double LAST_DIVIDER_POSITION = 0.3; - private static boolean isShow = false; + private boolean isShow = false; private DirectorySidebarManager() { @@ -49,6 +49,8 @@ public class DirectorySidebarManager { */ private static ChangeListener getTreeItemListener(TreeItem item) { return (observable, oldValue, newValue) -> { + // 记录打开状态 + item.getValue().setOpen(newValue); if (Boolean.TRUE.equals(newValue)) { item.setGraphic(item.getValue().getIconIsSelected()); } 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); rootItem.expandedProperty().addListener(getTreeItemListener(rootItem)); + rootItem.setExpanded(dirFileModel.isOpen()); expandFolder(dirFileModel, rootItem); } @@ -127,14 +121,14 @@ public class DirectorySidebarManager { if (childFileList != null) { for (DirFileModel childFile : childFileList) { TreeItem childItem = new TreeItem<>(childFile, childFile.getIconIsNotSelected()); - // 只有文件夹树才添加监听事件 - if (isDirectoryByDirFileModel(childFile)) { + // 只有文件夹树才添加监听事件与展开 + if (DirFileModel.isDirectoryByDirFileModel(childFile)) { + childItem.setExpanded(childFile.isOpen()); childItem.expandedProperty().addListener(getTreeItemListener(childItem)); } item.getChildren().add(childItem); expandFolder(childFile, childItem); } - } } @@ -145,7 +139,7 @@ public class DirectorySidebarManager { */ public void expandTheOpenFileTree() { // 获取缓存 - Object cacheData = CACHE_MANAGER.getCacheData(OpenDirectory.GROUP, "folderThatWasOpened"); + LinkedHashMap cacheData = (LinkedHashMap) CACHE_MANAGER.getCacheData(OpenDirectory.GROUP, "folderThatWasOpened"); // 判空 if (cacheData == null) { return; @@ -153,8 +147,6 @@ public class DirectorySidebarManager { // 打开侧边栏 controlShow(true); // 设置文件树功能 - setTreeView(FileUtil.getDirFileModel(new File((String) cacheData))); + setTreeView(FileUtil.getDirFileModel(cacheData)); } - - } diff --git a/src/main/java/org/jcnc/jnotepad/ui/views/root/center/main/center/tab/CenterTab.java b/src/main/java/org/jcnc/jnotepad/ui/views/root/center/main/center/tab/CenterTab.java index d22211c..248f7ed 100644 --- a/src/main/java/org/jcnc/jnotepad/ui/views/root/center/main/center/tab/CenterTab.java +++ b/src/main/java/org/jcnc/jnotepad/ui/views/root/center/main/center/tab/CenterTab.java @@ -7,9 +7,9 @@ import javafx.collections.ObservableList; import javafx.scene.control.CheckMenuItem; import javafx.scene.control.Tab; import org.fxmisc.flowless.VirtualizedScrollPane; -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.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.controller.config.UserConfigController; import org.jcnc.jnotepad.ui.component.module.TextCodeArea; import org.jcnc.jnotepad.ui.views.manager.BottomStatusBoxManager; @@ -22,7 +22,7 @@ import java.io.FileWriter; import java.io.IOException; 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.relevanceProperty.set(relevanceProperty); this.setUserData(file); - // 将监听器于上下文菜单集中处理 + // 将监听器与上下文菜单集中处理 Platform.runLater(() -> { initTextAreaListeners(); - this.contextMenuMonitor(); + initTabContextMenu(); 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() { - TabUtil.initTabContextMenu(this); + private void initTabContextMenu() { + 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()); } - /** * 保存选中的文件标签页 */ -- Gitee