🚩 完善文件树打开逻辑

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
public void initMenu() {
registerMenu();
logger.info("初始化菜单!");
Menu menu = getMenu();
// 菜单名称国际化
UiResourceBundle.bindStringProperty(menu.textProperty(), getMenuName());

View File

@ -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<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());
} else {
// Linux或其他系统
processBuilder = new ProcessBuilder("gnome-terminal", "--working-directory=", folder.getAbsolutePath());
processBuilder = new ProcessBuilder("xdg-open", folder.getAbsolutePath());
}
return processBuilder;
}

View File

@ -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());
}
}

View File

@ -54,6 +54,18 @@ public class CacheController {
return;
}
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) {
// 获取命名空间对应的文件夹
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);
}
}
/**

View File

@ -57,11 +57,11 @@ public class OpenDirectory implements EventHandler<ActionEvent> {
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()));
}
}

View File

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

View File

@ -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<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) {
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<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() {
return childFile;
@ -88,4 +131,9 @@ public class DirFileModel {
public void setIconIsSelected(Node 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.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<Boolean> getTreeItemListener(TreeItem<DirFileModel> 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<DirFileModel> 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<String, Object> cacheData = (LinkedHashMap<String, Object>) 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));
}
}

View File

@ -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());
}
/**
* 保存选中的文件标签页
*/