commit
ac015b4679
2
pom.xml
2
pom.xml
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>org.jcnc</groupId>
|
<groupId>org.jcnc</groupId>
|
||||||
<artifactId>JNotepad</artifactId>
|
<artifactId>JNotepad</artifactId>
|
||||||
<version>1.1.4-beta</version>
|
<version>1.0.14-alpha</version>
|
||||||
<name>JNotepad</name>
|
<name>JNotepad</name>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
|||||||
@ -48,5 +48,6 @@ module org.jcnc.jnotepad {
|
|||||||
exports org.jcnc.jnotepad.component.stage.topmenu.help;
|
exports org.jcnc.jnotepad.component.stage.topmenu.help;
|
||||||
exports org.jcnc.jnotepad.component.stage.topmenu.plugin;
|
exports org.jcnc.jnotepad.component.stage.topmenu.plugin;
|
||||||
exports org.jcnc.jnotepad.component.module.vbox.components;
|
exports org.jcnc.jnotepad.component.module.vbox.components;
|
||||||
|
exports org.jcnc.jnotepad.views.root.center.main.center.tab;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -3,9 +3,7 @@ package org.jcnc.jnotepad.api.core.views.menu.builder;
|
|||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.event.EventHandler;
|
import javafx.event.EventHandler;
|
||||||
import javafx.scene.control.Menu;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.control.MenuItem;
|
|
||||||
import javafx.scene.control.SeparatorMenuItem;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 抽象菜单建造者类
|
* 抽象菜单建造者类
|
||||||
@ -60,14 +58,14 @@ public abstract class AbstractMenuBuilder<B, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加单选菜单项
|
* 添加单选菜单项 todo 待完善
|
||||||
*
|
*
|
||||||
* @param label 菜单项名称
|
* @param label 菜单项名称
|
||||||
* @param eventHandler 事件
|
* @param eventHandler 事件
|
||||||
* @return 建造者
|
* @return 建造者
|
||||||
*/
|
*/
|
||||||
public B addRadioMenuItem(String label, EventHandler<ActionEvent> eventHandler) {
|
public B addRadioMenuItem(String label, EventHandler<ActionEvent> eventHandler) {
|
||||||
MenuItem menuItem = new MenuItem(label);
|
RadioMenuItem menuItem = new RadioMenuItem(label);
|
||||||
menuItem.setOnAction(eventHandler);
|
menuItem.setOnAction(eventHandler);
|
||||||
getItems().add(menuItem);
|
getItems().add(menuItem);
|
||||||
return getBuilder();
|
return getBuilder();
|
||||||
@ -81,7 +79,7 @@ public abstract class AbstractMenuBuilder<B, T> {
|
|||||||
* @return 建造者
|
* @return 建造者
|
||||||
*/
|
*/
|
||||||
public B addCheckMenuItem(String label, EventHandler<ActionEvent> eventHandler) {
|
public B addCheckMenuItem(String label, EventHandler<ActionEvent> eventHandler) {
|
||||||
MenuItem menuItem = new MenuItem(label);
|
CheckMenuItem menuItem = new CheckMenuItem(label);
|
||||||
menuItem.setOnAction(eventHandler);
|
menuItem.setOnAction(eventHandler);
|
||||||
getItems().add(menuItem);
|
getItems().add(menuItem);
|
||||||
return getBuilder();
|
return getBuilder();
|
||||||
@ -98,6 +96,21 @@ public abstract class AbstractMenuBuilder<B, T> {
|
|||||||
return getBuilder();
|
return getBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加菜单
|
||||||
|
*
|
||||||
|
* @param menu 菜单
|
||||||
|
* @param disable 是否禁用
|
||||||
|
* @return 建造者
|
||||||
|
*/
|
||||||
|
public B addMenu(Menu menu, boolean disable) {
|
||||||
|
if (!disable) {
|
||||||
|
return getBuilder();
|
||||||
|
}
|
||||||
|
getItems().add(menu);
|
||||||
|
return getBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加分割线
|
* 添加分割线
|
||||||
*
|
*
|
||||||
|
|||||||
@ -13,7 +13,7 @@ public class AppConstants {
|
|||||||
/**
|
/**
|
||||||
* 版本号
|
* 版本号
|
||||||
*/
|
*/
|
||||||
public static final String VERSION = "1.0.14";
|
public static final String VERSION = "1.0.14-alpha";
|
||||||
/**
|
/**
|
||||||
* 作者
|
* 作者
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
package org.jcnc.jnotepad.component.stage.topmenu.help;
|
package org.jcnc.jnotepad.component.stage.topmenu.help;
|
||||||
|
|
||||||
import atlantafx.base.controls.Notification;
|
|
||||||
import atlantafx.base.theme.Styles;
|
import atlantafx.base.theme.Styles;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.event.EventHandler;
|
import javafx.event.EventHandler;
|
||||||
@ -19,8 +18,8 @@ import javafx.stage.Stage;
|
|||||||
import org.jcnc.jnotepad.api.core.component.stage.AbstractPaneStage;
|
import org.jcnc.jnotepad.api.core.component.stage.AbstractPaneStage;
|
||||||
import org.jcnc.jnotepad.util.ClipboardUtil;
|
import org.jcnc.jnotepad.util.ClipboardUtil;
|
||||||
import org.jcnc.jnotepad.util.LogUtil;
|
import org.jcnc.jnotepad.util.LogUtil;
|
||||||
|
import org.jcnc.jnotepad.util.NotificationUtil;
|
||||||
import org.jcnc.jnotepad.util.UiUtil;
|
import org.jcnc.jnotepad.util.UiUtil;
|
||||||
import org.jcnc.jnotepad.views.manager.RootManager;
|
|
||||||
|
|
||||||
import static org.jcnc.jnotepad.common.constants.AppConstants.*;
|
import static org.jcnc.jnotepad.common.constants.AppConstants.*;
|
||||||
|
|
||||||
@ -128,16 +127,7 @@ public class HelpPaneStage extends AbstractPaneStage {
|
|||||||
bottomBox.setAlignment(Pos.BOTTOM_RIGHT);
|
bottomBox.setAlignment(Pos.BOTTOM_RIGHT);
|
||||||
|
|
||||||
Button leftBtn = getButton(" 复制并关闭 ", event -> {
|
Button leftBtn = getButton(" 复制并关闭 ", event -> {
|
||||||
// 获取 RootManager 的实例
|
NotificationUtil.infoNotification("软件信息已经复制到剪贴板!");
|
||||||
RootManager rootManager = RootManager.getInstance();
|
|
||||||
|
|
||||||
// 创建一个新的 Notification
|
|
||||||
Notification notification = new Notification();
|
|
||||||
notification.setMessage("已成功复制软件信息!");
|
|
||||||
|
|
||||||
// 调用 RootManager 中的方法来显示 Notification
|
|
||||||
rootManager.addNotificationToStackPane(rootManager.getRootStackPane(), notification);
|
|
||||||
|
|
||||||
String info = "软件名字:" + APP_NAME + "\t" + "版本:" + VERSION;
|
String info = "软件名字:" + APP_NAME + "\t" + "版本:" + VERSION;
|
||||||
ClipboardUtil.writeTextToClipboard(info);
|
ClipboardUtil.writeTextToClipboard(info);
|
||||||
LogUtil.getLogger(this.getClass()).info("软件信息已经复制到剪贴板:{}", info);
|
LogUtil.getLogger(this.getClass()).info("软件信息已经复制到剪贴板:{}", info);
|
||||||
|
|||||||
@ -2,18 +2,8 @@ package org.jcnc.jnotepad.controller.event.handler.menuitem;
|
|||||||
|
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.event.EventHandler;
|
import javafx.event.EventHandler;
|
||||||
import javafx.scene.control.Tab;
|
|
||||||
import org.jcnc.jnotepad.app.i18n.UiResourceBundle;
|
|
||||||
import org.jcnc.jnotepad.common.constants.AppConstants;
|
|
||||||
import org.jcnc.jnotepad.common.constants.TextConstants;
|
|
||||||
import org.jcnc.jnotepad.component.module.TextCodeArea;
|
|
||||||
import org.jcnc.jnotepad.views.manager.BottomStatusBoxManager;
|
|
||||||
import org.jcnc.jnotepad.views.manager.CenterTabPaneManager;
|
|
||||||
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTab;
|
|
||||||
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTabPane;
|
|
||||||
|
|
||||||
import java.util.Comparator;
|
import static org.jcnc.jnotepad.util.TabUtil.addNewFileTab;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新建文件事件的事件处理程序。
|
* 新建文件事件的事件处理程序。
|
||||||
@ -32,46 +22,4 @@ public class NewFile implements EventHandler<ActionEvent> {
|
|||||||
public void handle(ActionEvent event) {
|
public void handle(ActionEvent event) {
|
||||||
addNewFileTab();
|
addNewFileTab();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加新的文件标签页。
|
|
||||||
*/
|
|
||||||
public void addNewFileTab() {
|
|
||||||
// 创建一个新的文本编辑区
|
|
||||||
TextCodeArea textArea = new TextCodeArea();
|
|
||||||
// TODO: refactor:统一TextArea新建、绑定监听器入口
|
|
||||||
// 设定初始索引
|
|
||||||
int index = 1;
|
|
||||||
StringBuilder tabTitle = new StringBuilder();
|
|
||||||
// 获取当前默认创建标签页集合
|
|
||||||
List<Tab> tabs = CenterTabPane.getInstance()
|
|
||||||
.getTabs()
|
|
||||||
.stream()
|
|
||||||
// 排除不属于默认创建的标签页
|
|
||||||
.filter(tab -> AppConstants.TABNAME_PATTERN.matcher(tab.getText()).matches())
|
|
||||||
// 对默认创建的标签页进行排序
|
|
||||||
.sorted(Comparator.comparing(Tab::getText))
|
|
||||||
// 转为List集合
|
|
||||||
.toList();
|
|
||||||
// 构建初始标签页名称
|
|
||||||
tabTitle.append(UiResourceBundle.getContent(TextConstants.NEW_FILE)).append(index);
|
|
||||||
for (Tab tab : tabs) {
|
|
||||||
if (tab.getText().contentEquals(tabTitle)) {
|
|
||||||
tabTitle.setLength(0);
|
|
||||||
tabTitle.append(UiResourceBundle.getContent(TextConstants.NEW_FILE)).append(++index);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 创建标签页
|
|
||||||
CenterTab centerTab = new CenterTab(
|
|
||||||
tabTitle.toString(),
|
|
||||||
textArea);
|
|
||||||
// 设置当前标签页与本地文件无关联
|
|
||||||
centerTab.setRelevance(false);
|
|
||||||
// 将Tab页添加到TabPane中
|
|
||||||
CenterTabPaneManager.getInstance().addNewTab(centerTab);
|
|
||||||
// 更新编码信息
|
|
||||||
BottomStatusBoxManager.getInstance().updateEncodingLabel();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,8 @@ import org.jcnc.jnotepad.util.LogUtil;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
|
import static org.jcnc.jnotepad.util.TabUtil.openFileToTab;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 打开配置文件事件处理程序。
|
* 打开配置文件事件处理程序。
|
||||||
*
|
*
|
||||||
@ -26,6 +28,6 @@ public class OpenConfig extends OpenFile {
|
|||||||
File file = UserConfigController.getInstance().getConfigPath().toFile();
|
File file = UserConfigController.getInstance().getConfigPath().toFile();
|
||||||
LogUtil.getLogger(this.getClass()).info("已调用打开配置文件功能, {}", file);
|
LogUtil.getLogger(this.getClass()).info("已调用打开配置文件功能, {}", file);
|
||||||
// 创建打开文件的任务并启动线程执行任务
|
// 创建打开文件的任务并启动线程执行任务
|
||||||
openFile(file);
|
openFileToTab(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,26 +2,18 @@ package org.jcnc.jnotepad.controller.event.handler.menuitem;
|
|||||||
|
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.event.EventHandler;
|
import javafx.event.EventHandler;
|
||||||
import javafx.scene.control.Tab;
|
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import org.jcnc.jnotepad.app.i18n.UiResourceBundle;
|
import org.jcnc.jnotepad.app.i18n.UiResourceBundle;
|
||||||
import org.jcnc.jnotepad.common.constants.TextConstants;
|
import org.jcnc.jnotepad.common.constants.TextConstants;
|
||||||
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
|
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
|
||||||
import org.jcnc.jnotepad.component.module.TextCodeArea;
|
|
||||||
import org.jcnc.jnotepad.component.stage.dialog.factory.impl.BasicFileChooserFactory;
|
import org.jcnc.jnotepad.component.stage.dialog.factory.impl.BasicFileChooserFactory;
|
||||||
import org.jcnc.jnotepad.model.entity.Cache;
|
import org.jcnc.jnotepad.model.entity.Cache;
|
||||||
import org.jcnc.jnotepad.model.enums.CacheExpirationTime;
|
import org.jcnc.jnotepad.model.enums.CacheExpirationTime;
|
||||||
import org.jcnc.jnotepad.util.EncodingDetector;
|
|
||||||
import org.jcnc.jnotepad.util.LogUtil;
|
|
||||||
import org.jcnc.jnotepad.util.UiUtil;
|
import org.jcnc.jnotepad.util.UiUtil;
|
||||||
import org.jcnc.jnotepad.views.manager.CenterTabPaneManager;
|
|
||||||
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTab;
|
|
||||||
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTabPane;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
|
|
||||||
import static org.jcnc.jnotepad.util.FileUtil.getFileText;
|
import static org.jcnc.jnotepad.util.TabUtil.openFileToTab;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,73 +52,6 @@ public class OpenFile implements EventHandler<ActionEvent> {
|
|||||||
cache.setCacheData(file.getParent());
|
cache.setCacheData(file.getParent());
|
||||||
CACHE_MANAGER.addCache(cache);
|
CACHE_MANAGER.addCache(cache);
|
||||||
}
|
}
|
||||||
openFile(file);
|
openFileToTab(file);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 打开文件。
|
|
||||||
*
|
|
||||||
* @param file 文件对象
|
|
||||||
*/
|
|
||||||
public static void openFile(File file) {
|
|
||||||
// 获取标签页集合
|
|
||||||
CenterTabPane centerTabPane = CenterTabPane.getInstance();
|
|
||||||
// 遍历标签页,查找匹配的标签页
|
|
||||||
for (Tab tab : centerTabPane.getTabs()) {
|
|
||||||
// 获取绑定的文件
|
|
||||||
File tabFile = (File) tab.getUserData();
|
|
||||||
if (tabFile == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (file.getPath().equals((tabFile).getPath())) {
|
|
||||||
// 找到匹配的标签页,设置为选中状态并跳转
|
|
||||||
centerTabPane.getSelectionModel().select(tab);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getText(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 读取文本文件的内容。
|
|
||||||
*
|
|
||||||
* @param file 文件对象
|
|
||||||
*/
|
|
||||||
public static void getText(File file) {
|
|
||||||
TextCodeArea textCodeArea = createNewTextArea();
|
|
||||||
// 检测文件编码
|
|
||||||
Charset encoding = EncodingDetector.detectEncodingCharset(file);
|
|
||||||
String fileText = getFileText(file, encoding);
|
|
||||||
LogUtil.getLogger(OpenFile.class).info("已调用读取文件功能");
|
|
||||||
textCodeArea.appendText(fileText);
|
|
||||||
CenterTab tab = createNewTab(file.getName(), textCodeArea, encoding);
|
|
||||||
// 设置当前标签页关联本地文件
|
|
||||||
tab.setRelevance(true);
|
|
||||||
// 设置标签页关联文件
|
|
||||||
tab.setUserData(file);
|
|
||||||
// 设置关联文件最后的修改时间
|
|
||||||
tab.setLastModifiedTimeOfAssociatedFile(file.lastModified());
|
|
||||||
CenterTabPaneManager.getInstance().addNewTab(tab);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建新的文本区域。
|
|
||||||
*
|
|
||||||
* @return 新的文本区域
|
|
||||||
*/
|
|
||||||
private static TextCodeArea createNewTextArea() {
|
|
||||||
return new TextCodeArea();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建新的标签页。
|
|
||||||
*
|
|
||||||
* @param tabName 标签名
|
|
||||||
* @param textCodeArea 文本区域
|
|
||||||
* @return 新的标签页
|
|
||||||
*/
|
|
||||||
private static CenterTab createNewTab(String tabName, TextCodeArea textCodeArea, Charset charset) {
|
|
||||||
return new CenterTab(tabName, textCodeArea, charset);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,21 +2,9 @@ package org.jcnc.jnotepad.controller.event.handler.menuitem;
|
|||||||
|
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.event.EventHandler;
|
import javafx.event.EventHandler;
|
||||||
import javafx.scene.control.TextField;
|
|
||||||
import javafx.scene.input.KeyCode;
|
|
||||||
import javafx.stage.FileChooser;
|
|
||||||
import org.jcnc.jnotepad.app.i18n.UiResourceBundle;
|
|
||||||
import org.jcnc.jnotepad.common.constants.TextConstants;
|
|
||||||
import org.jcnc.jnotepad.component.stage.dialog.factory.impl.BasicFileChooserFactory;
|
|
||||||
import org.jcnc.jnotepad.util.LogUtil;
|
|
||||||
import org.jcnc.jnotepad.util.PopUpUtil;
|
|
||||||
import org.jcnc.jnotepad.util.UiUtil;
|
|
||||||
import org.jcnc.jnotepad.views.manager.CenterTabPaneManager;
|
import org.jcnc.jnotepad.views.manager.CenterTabPaneManager;
|
||||||
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTab;
|
|
||||||
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTabPane;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
|
|
||||||
import java.io.File;
|
import static org.jcnc.jnotepad.util.TabUtil.rename;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 重命名文件事件处理器。
|
* 重命名文件事件处理器。
|
||||||
@ -27,144 +15,8 @@ import java.io.File;
|
|||||||
* @author gewuyou
|
* @author gewuyou
|
||||||
*/
|
*/
|
||||||
public class RenameFile implements EventHandler<ActionEvent> {
|
public class RenameFile implements EventHandler<ActionEvent> {
|
||||||
static Logger logger = LogUtil.getLogger(RenameFile.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重命名
|
|
||||||
*/
|
|
||||||
public static void rename() {
|
|
||||||
// 获取当前标签页
|
|
||||||
CenterTab centerTab = CenterTabPaneManager.getInstance().getSelected();
|
|
||||||
if (centerTab == null || centerTab.getText().isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 判断当前是否为关联文件
|
|
||||||
if (centerTab.isRelevance()) {
|
|
||||||
// 重命名关联文件
|
|
||||||
handleRenameRelevanceFile(centerTab);
|
|
||||||
}
|
|
||||||
// 如果当前不是关联文件则重命名标签页
|
|
||||||
else {
|
|
||||||
handleRenameTab(centerTab);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重命名标签页。
|
|
||||||
*
|
|
||||||
* @param centerTab 标签页组件
|
|
||||||
*/
|
|
||||||
private static void handleRenameTab(CenterTab centerTab) {
|
|
||||||
TextField textField = new TextField(centerTab.getText());
|
|
||||||
textField.getStyleClass().add("tab-title-editable");
|
|
||||||
// 临时记录标签页名称
|
|
||||||
String tempName = centerTab.getText();
|
|
||||||
// 清空标签页名称
|
|
||||||
centerTab.setText("");
|
|
||||||
|
|
||||||
// 监听 Enter 键,完成编辑
|
|
||||||
textField.setOnKeyPressed(event -> {
|
|
||||||
if (event.getCode() == KeyCode.ENTER) {
|
|
||||||
String newTabName = textField.getText();
|
|
||||||
// 检查是否存在相同名称的标签页
|
|
||||||
if (isTabNameExists(newTabName)) {
|
|
||||||
|
|
||||||
// 显示弹窗并提示用户更换名称
|
|
||||||
showDuplicateNameAlert(newTabName);
|
|
||||||
|
|
||||||
// 恢复原始名称
|
|
||||||
centerTab.setText(tempName);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
centerTab.setText(newTabName);
|
|
||||||
// 可选:移除 TextField 的图形
|
|
||||||
centerTab.setGraphic(null);
|
|
||||||
// 可选:恢复标签页的关闭按钮
|
|
||||||
centerTab.setClosable(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 监听失去焦点事件,完成编辑
|
|
||||||
textField.focusedProperty().addListener((observable, oldValue, newValue) -> {
|
|
||||||
String newTabName = textField.getText();
|
|
||||||
// 检查是否存在相同名称的标签页
|
|
||||||
if (isTabNameExists(newTabName)) {
|
|
||||||
// 恢复原始名称
|
|
||||||
centerTab.setText(tempName);
|
|
||||||
|
|
||||||
}
|
|
||||||
if (Boolean.FALSE.equals(newValue)) {
|
|
||||||
centerTab.setText(newTabName);
|
|
||||||
// 可选:移除 TextField 的图形
|
|
||||||
centerTab.setGraphic(null);
|
|
||||||
// 可选:恢复标签页的关闭按钮
|
|
||||||
centerTab.setClosable(true);
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
centerTab.setClosable(false);
|
|
||||||
// 设置 TextField 作为标签页的图形
|
|
||||||
centerTab.setGraphic(textField);
|
|
||||||
// 默认获取焦点并选中所有文字
|
|
||||||
textField.requestFocus();
|
|
||||||
textField.selectAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断是否存在具有相同名称的标签页。
|
|
||||||
*
|
|
||||||
* @param newTabName 要检查的新标签页名称
|
|
||||||
* @return 如果存在具有相同名称的标签页,则返回 true;否则返回 false
|
|
||||||
*/
|
|
||||||
private static boolean isTabNameExists(String newTabName) {
|
|
||||||
CenterTabPane tabPane = CenterTabPane.getInstance();
|
|
||||||
return tabPane.getTabs().stream()
|
|
||||||
.anyMatch(tab -> tab.getText().equals(newTabName));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 显示警告弹窗,提示用户更换重复的名称。
|
|
||||||
*/
|
|
||||||
private static void showDuplicateNameAlert(String newTabName) {
|
|
||||||
|
|
||||||
PopUpUtil.errorAlert("重命名错误", "\" " + newTabName + "\" 和已有标签页名字重复", "请再次重命名", null, null);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重命名关联文件。
|
|
||||||
*
|
|
||||||
* @param centerTab 标签页组件
|
|
||||||
*/
|
|
||||||
private static void handleRenameRelevanceFile(CenterTab centerTab) {
|
|
||||||
// 获取原始文件对象
|
|
||||||
File file = (File) centerTab.getUserData();
|
|
||||||
|
|
||||||
// 获取应用窗口并绑定
|
|
||||||
File newFile = BasicFileChooserFactory.getInstance()
|
|
||||||
.createFileChooser(
|
|
||||||
UiResourceBundle.getContent(TextConstants.RENAME),
|
|
||||||
centerTab.getText(),
|
|
||||||
new File(file.getParent()),
|
|
||||||
new FileChooser.ExtensionFilter("All types", "*.*"))
|
|
||||||
.showSaveDialog(UiUtil.getAppWindow());
|
|
||||||
if (newFile != null) {
|
|
||||||
boolean rename = file.renameTo(newFile);
|
|
||||||
// 设置文件数据
|
|
||||||
centerTab.setUserData(newFile);
|
|
||||||
if (rename) {
|
|
||||||
centerTab.setText(newFile.getName());
|
|
||||||
logger.info("文件重命名成功");
|
|
||||||
} else {
|
|
||||||
logger.debug("文件重命名失败");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(ActionEvent actionEvent) {
|
public void handle(ActionEvent actionEvent) {
|
||||||
rename();
|
rename(CenterTabPaneManager.getInstance().getSelected());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,9 @@ package org.jcnc.jnotepad.controller.event.handler.menuitem;
|
|||||||
|
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import org.jcnc.jnotepad.util.LogUtil;
|
import org.jcnc.jnotepad.util.LogUtil;
|
||||||
|
import org.jcnc.jnotepad.views.manager.CenterTabPaneManager;
|
||||||
|
|
||||||
|
import static org.jcnc.jnotepad.util.TabUtil.saveAsFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存文件事件处理器。
|
* 保存文件事件处理器。
|
||||||
@ -22,6 +25,6 @@ public class SaveAsFile extends SaveFile {
|
|||||||
@Override
|
@Override
|
||||||
public void handle(ActionEvent event) {
|
public void handle(ActionEvent event) {
|
||||||
LogUtil.getLogger(SaveAsFile.class).info("已调用另存为功能");
|
LogUtil.getLogger(SaveAsFile.class).info("已调用另存为功能");
|
||||||
saveAsFile();
|
saveAsFile(CenterTabPaneManager.getInstance().getSelected());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,25 +2,9 @@ package org.jcnc.jnotepad.controller.event.handler.menuitem;
|
|||||||
|
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.event.EventHandler;
|
import javafx.event.EventHandler;
|
||||||
import javafx.stage.FileChooser;
|
|
||||||
import org.jcnc.jnotepad.app.i18n.UiResourceBundle;
|
|
||||||
import org.jcnc.jnotepad.common.constants.TextConstants;
|
|
||||||
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
|
|
||||||
import org.jcnc.jnotepad.component.stage.dialog.factory.impl.BasicFileChooserFactory;
|
|
||||||
import org.jcnc.jnotepad.controller.config.UserConfigController;
|
|
||||||
import org.jcnc.jnotepad.controller.i18n.LocalizationController;
|
|
||||||
import org.jcnc.jnotepad.model.entity.Cache;
|
|
||||||
import org.jcnc.jnotepad.model.enums.CacheExpirationTime;
|
|
||||||
import org.jcnc.jnotepad.util.LogUtil;
|
|
||||||
import org.jcnc.jnotepad.util.UiUtil;
|
|
||||||
import org.jcnc.jnotepad.views.manager.CenterTabPaneManager;
|
import org.jcnc.jnotepad.views.manager.CenterTabPaneManager;
|
||||||
import org.jcnc.jnotepad.views.manager.TopMenuBarManager;
|
|
||||||
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTab;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
|
|
||||||
import java.io.File;
|
import static org.jcnc.jnotepad.util.TabUtil.saveFile;
|
||||||
|
|
||||||
import static org.jcnc.jnotepad.controller.config.UserConfigController.CONFIG_NAME;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存文件事件处理程序。
|
* 保存文件事件处理程序。
|
||||||
@ -31,68 +15,6 @@ import static org.jcnc.jnotepad.controller.config.UserConfigController.CONFIG_NA
|
|||||||
* @author gewuyou
|
* @author gewuyou
|
||||||
*/
|
*/
|
||||||
public class SaveFile implements EventHandler<ActionEvent> {
|
public class SaveFile implements EventHandler<ActionEvent> {
|
||||||
private static final ApplicationCacheManager CACHE_MANAGER = ApplicationCacheManager.getInstance();
|
|
||||||
static Logger logger = LogUtil.getLogger(SaveFile.class);
|
|
||||||
|
|
||||||
public static void saveFile() {
|
|
||||||
// 获取当前tab页
|
|
||||||
CenterTab selectedTab = CenterTabPaneManager.getInstance().getSelected();
|
|
||||||
if (selectedTab == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 如果打开的是非关联文件,则调用另存为方法
|
|
||||||
if (!selectedTab.isRelevance()) {
|
|
||||||
logger.info("当前保存文件为非关联打开文件,调用另存为方法");
|
|
||||||
saveAsFile();
|
|
||||||
} else {
|
|
||||||
logger.info("当前保存文件为关联打开文件,调用自动保存方法");
|
|
||||||
// 调用tab保存方法
|
|
||||||
selectedTab.saveSelectedFileTab();
|
|
||||||
// 如果该文件是配置文件,则刷新快捷键
|
|
||||||
if (CONFIG_NAME.equals(selectedTab.getText())) {
|
|
||||||
// 重新加载语言包和快捷键
|
|
||||||
UserConfigController.getInstance().loadConfig();
|
|
||||||
TopMenuBarManager.getInstance().initShortcutKeys();
|
|
||||||
LocalizationController.initLocal();
|
|
||||||
logger.info("已刷新语言包!");
|
|
||||||
logger.info("已刷新快捷键!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 保存标签页的方法。
|
|
||||||
*
|
|
||||||
* @apiNote 将当前选中的标签页进行另存为弹出窗口式的保存。
|
|
||||||
* @see LogUtil
|
|
||||||
*/
|
|
||||||
public static void saveAsFile() {
|
|
||||||
CenterTab selectedTab = CenterTabPaneManager.getInstance().getSelected();
|
|
||||||
if (selectedTab == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Cache cache = CACHE_MANAGER.getCache("folder", "saveFile");
|
|
||||||
File file = BasicFileChooserFactory.getInstance().createFileChooser(
|
|
||||||
UiResourceBundle.getContent(TextConstants.SAVE_AS),
|
|
||||||
selectedTab.getText(),
|
|
||||||
cache == null ? null : new File((String) cache.getCacheData()),
|
|
||||||
new FileChooser.ExtensionFilter("All types", "*.*"))
|
|
||||||
.showSaveDialog(UiUtil.getAppWindow());
|
|
||||||
if (file != null) {
|
|
||||||
if (cache == null) {
|
|
||||||
CACHE_MANAGER.addCache(CACHE_MANAGER.createCache("folder", "saveFile", file.getParent(), CacheExpirationTime.NEVER_EXPIRES.getValue()));
|
|
||||||
} else {
|
|
||||||
cache.setCacheData(file.getParent());
|
|
||||||
CACHE_MANAGER.addCache(cache);
|
|
||||||
}
|
|
||||||
logger.info("正在保存文件: {}", file.getName());
|
|
||||||
selectedTab.save(file);
|
|
||||||
// 将保存后的文件设置为关联文件
|
|
||||||
selectedTab.setRelevance(true);
|
|
||||||
// 更新标签页上的文件名
|
|
||||||
selectedTab.setText(file.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理保存文件事件。
|
* 处理保存文件事件。
|
||||||
@ -103,6 +25,7 @@ public class SaveFile implements EventHandler<ActionEvent> {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void handle(ActionEvent actionEvent) {
|
public void handle(ActionEvent actionEvent) {
|
||||||
saveFile();
|
// 保存当前选中的标签页
|
||||||
|
saveFile(CenterTabPaneManager.getInstance().getSelected());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,14 +2,15 @@ package org.jcnc.jnotepad.controller.manager;
|
|||||||
|
|
||||||
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
|
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
|
||||||
import org.jcnc.jnotepad.component.module.interfaces.ControllerAble;
|
import org.jcnc.jnotepad.component.module.interfaces.ControllerAble;
|
||||||
import org.jcnc.jnotepad.controller.event.handler.menuitem.NewFile;
|
|
||||||
import org.jcnc.jnotepad.controller.event.handler.menuitem.OpenFile;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static org.jcnc.jnotepad.util.TabUtil.addNewFileTab;
|
||||||
|
import static org.jcnc.jnotepad.util.TabUtil.openFileToTab;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 控制器类,实现 ControllerAble 接口,用于管理文本编辑器的各种操作和事件处理。
|
* 控制器类,实现 ControllerAble 接口,用于管理文本编辑器的各种操作和事件处理。
|
||||||
*
|
*
|
||||||
@ -44,7 +45,7 @@ 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 -> OpenFile.openFile(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);
|
||||||
@ -52,7 +53,7 @@ public class Controller implements ControllerAble<List<String>> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (fileTab.isEmpty()) {
|
if (fileTab.isEmpty()) {
|
||||||
new NewFile().addNewFileTab();
|
addNewFileTab();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +66,7 @@ public class Controller implements ControllerAble<List<String>> {
|
|||||||
public void openAssociatedFile(String filePath) {
|
public void openAssociatedFile(String filePath) {
|
||||||
File file = new File(filePath);
|
File file = new File(filePath);
|
||||||
if (file.exists() && file.isFile()) {
|
if (file.exists() && file.isFile()) {
|
||||||
OpenFile.openFile(file);
|
openFileToTab(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import org.jcnc.jnotepad.controller.exception.AppException;
|
|||||||
import org.jcnc.jnotepad.model.entity.DirFileModel;
|
import org.jcnc.jnotepad.model.entity.DirFileModel;
|
||||||
import org.kordamp.ikonli.javafx.FontIcon;
|
import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.FileChannel;
|
import java.nio.channels.FileChannel;
|
||||||
@ -267,5 +268,24 @@ public class FileUtil {
|
|||||||
throw new AppException(e);
|
throw new AppException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the file explorer to the specified file or its parent directory.
|
||||||
|
*
|
||||||
|
* @param file the file or directory to open in the file explorer
|
||||||
|
*/
|
||||||
|
public static void openExplorer(File file) {
|
||||||
|
try { // 判断传入的是文件还是文件夹
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
Desktop.getDesktop().open(file);
|
||||||
|
}
|
||||||
|
// 如果是文件则打开所在文件夹
|
||||||
|
else {
|
||||||
|
Desktop.getDesktop().open(file.getParentFile());
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new AppException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
102
src/main/java/org/jcnc/jnotepad/util/NotificationUtil.java
Normal file
102
src/main/java/org/jcnc/jnotepad/util/NotificationUtil.java
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package org.jcnc.jnotepad.util;
|
||||||
|
|
||||||
|
import atlantafx.base.controls.Notification;
|
||||||
|
import atlantafx.base.theme.Styles;
|
||||||
|
import javafx.scene.layout.StackPane;
|
||||||
|
import org.jcnc.jnotepad.views.manager.RootManager;
|
||||||
|
import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知实用程序
|
||||||
|
*
|
||||||
|
* @author gewuyou
|
||||||
|
*/
|
||||||
|
public class NotificationUtil {
|
||||||
|
private static final RootManager ROOT_MANAGER = RootManager.getInstance();
|
||||||
|
private static final StackPane ROOT_STACK_PANE = ROOT_MANAGER.getRootStackPane();
|
||||||
|
|
||||||
|
private NotificationUtil() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a custom notification with the given message and icon, applying the specified styles.
|
||||||
|
*
|
||||||
|
* @param message the message to display in the notification
|
||||||
|
* @param icon the icon to display in the notification
|
||||||
|
* @param styles additional styles to apply to the notification
|
||||||
|
*/
|
||||||
|
public static void customNotification(String message, FontIcon icon, String... styles) {
|
||||||
|
Notification notification = new Notification(message, icon);
|
||||||
|
Collections.addAll(notification.getStyleClass(), styles);
|
||||||
|
RootManager.addNotificationToStackPane(ROOT_STACK_PANE, notification, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a success notification with the given message.
|
||||||
|
*
|
||||||
|
* @param message the message to be displayed in the notification
|
||||||
|
*/
|
||||||
|
public static void successNotification(String message) {
|
||||||
|
Notification notification = new Notification(message, UiUtil.getSuccessIcon());
|
||||||
|
setStyleClass(notification, Styles.SUCCESS);
|
||||||
|
RootManager.addNotificationToStackPane(ROOT_STACK_PANE, notification, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an info notification with the given message.
|
||||||
|
*
|
||||||
|
* @param message the message to display in the notification
|
||||||
|
*/
|
||||||
|
public static void infoNotification(String message) {
|
||||||
|
Notification notification = new Notification(message, UiUtil.getInfoIcon());
|
||||||
|
setStyleClass(notification, Styles.ACCENT);
|
||||||
|
RootManager.addNotificationToStackPane(ROOT_STACK_PANE, notification, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an error notification with the given message and displays it on the root stack pane.
|
||||||
|
*
|
||||||
|
* @param message the error message to be displayed
|
||||||
|
*/
|
||||||
|
public static void errorNotification(String message) {
|
||||||
|
Notification notification = new Notification(message, UiUtil.getErrorIcon());
|
||||||
|
setStyleClass(notification, Styles.DANGER);
|
||||||
|
RootManager.addNotificationToStackPane(ROOT_STACK_PANE, notification, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a warning notification with the given message and displays it on the root stack pane.
|
||||||
|
*
|
||||||
|
* @param message the warning message to be displayed
|
||||||
|
*/
|
||||||
|
public static void warningNotification(String message) {
|
||||||
|
Notification notification = new Notification(message, UiUtil.getWarningIcon());
|
||||||
|
setStyleClass(notification, Styles.WARNING);
|
||||||
|
RootManager.addNotificationToStackPane(ROOT_STACK_PANE, notification, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a question notification with the given message and displays it on the root stack pane.
|
||||||
|
*
|
||||||
|
* @param message the question message to be displayed
|
||||||
|
*/
|
||||||
|
public static void questionNotification(String message) {
|
||||||
|
Notification notification = new Notification(message, UiUtil.getQuestionIcon());
|
||||||
|
setStyleClass(notification, Styles.ACCENT);
|
||||||
|
RootManager.addNotificationToStackPane(ROOT_STACK_PANE, notification, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the style class of the given notification.
|
||||||
|
*
|
||||||
|
* @param notification The notification object to set the style class for.
|
||||||
|
* @param styleClass The style class to add to the notification.
|
||||||
|
*/
|
||||||
|
private static void setStyleClass(Notification notification, String styleClass) {
|
||||||
|
notification.getStyleClass().add(Styles.ELEVATED_1);
|
||||||
|
notification.getStyleClass().add(styleClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
386
src/main/java/org/jcnc/jnotepad/util/TabUtil.java
Normal file
386
src/main/java/org/jcnc/jnotepad/util/TabUtil.java
Normal file
@ -0,0 +1,386 @@
|
|||||||
|
package org.jcnc.jnotepad.util;
|
||||||
|
|
||||||
|
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.i18n.UiResourceBundle;
|
||||||
|
import org.jcnc.jnotepad.common.constants.AppConstants;
|
||||||
|
import org.jcnc.jnotepad.common.constants.TextConstants;
|
||||||
|
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
|
||||||
|
import org.jcnc.jnotepad.component.module.TextCodeArea;
|
||||||
|
import org.jcnc.jnotepad.component.stage.dialog.factory.impl.BasicFileChooserFactory;
|
||||||
|
import org.jcnc.jnotepad.controller.config.UserConfigController;
|
||||||
|
import org.jcnc.jnotepad.controller.event.handler.menuitem.OpenFile;
|
||||||
|
import org.jcnc.jnotepad.controller.i18n.LocalizationController;
|
||||||
|
import org.jcnc.jnotepad.model.entity.Cache;
|
||||||
|
import org.jcnc.jnotepad.model.enums.CacheExpirationTime;
|
||||||
|
import org.jcnc.jnotepad.views.manager.BottomStatusBoxManager;
|
||||||
|
import org.jcnc.jnotepad.views.manager.CenterTabPaneManager;
|
||||||
|
import org.jcnc.jnotepad.views.manager.TopMenuBarManager;
|
||||||
|
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTab;
|
||||||
|
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTabPane;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.jcnc.jnotepad.controller.config.UserConfigController.CONFIG_NAME;
|
||||||
|
import static org.jcnc.jnotepad.util.FileUtil.getFileText;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标签页工具
|
||||||
|
*
|
||||||
|
* @author gewuyou
|
||||||
|
*/
|
||||||
|
public class TabUtil {
|
||||||
|
private static final ApplicationCacheManager CACHE_MANAGER = ApplicationCacheManager.getInstance();
|
||||||
|
static Logger logger = LogUtil.getLogger(TabUtil.class);
|
||||||
|
private TabUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存文件标签页
|
||||||
|
*/
|
||||||
|
public static void saveFile(CenterTab tab) {
|
||||||
|
if (tab == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 如果打开的是非关联文件,则调用另存为方法
|
||||||
|
if (!tab.isRelevance()) {
|
||||||
|
logger.info("当前保存文件为非关联打开文件,调用另存为方法");
|
||||||
|
saveAsFile(tab);
|
||||||
|
} else {
|
||||||
|
logger.info("当前保存文件为关联打开文件,调用自动保存方法");
|
||||||
|
// 调用tab保存方法
|
||||||
|
tab.saveSelectedFileTab();
|
||||||
|
// 如果该文件是配置文件,则刷新快捷键
|
||||||
|
if (CONFIG_NAME.equals(tab.getText())) {
|
||||||
|
// 重新加载语言包和快捷键
|
||||||
|
UserConfigController.getInstance().loadConfig();
|
||||||
|
TopMenuBarManager.getInstance().initShortcutKeys();
|
||||||
|
LocalizationController.initLocal();
|
||||||
|
logger.info("已刷新语言包!");
|
||||||
|
logger.info("已刷新快捷键!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 另存为
|
||||||
|
*
|
||||||
|
* @apiNote 将当前选中的标签页进行另存为弹出窗口式的保存。
|
||||||
|
* @see LogUtil
|
||||||
|
*/
|
||||||
|
public static void saveAsFile(CenterTab tab) {
|
||||||
|
if (tab == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Cache cache = CACHE_MANAGER.getCache("folder", "saveFile");
|
||||||
|
File file = BasicFileChooserFactory.getInstance().createFileChooser(
|
||||||
|
UiResourceBundle.getContent(TextConstants.SAVE_AS),
|
||||||
|
tab.getText(),
|
||||||
|
cache == null ? null : new File((String) cache.getCacheData()),
|
||||||
|
new FileChooser.ExtensionFilter("All types", "*.*"))
|
||||||
|
.showSaveDialog(UiUtil.getAppWindow());
|
||||||
|
if (file != null) {
|
||||||
|
if (cache == null) {
|
||||||
|
CACHE_MANAGER.addCache(CACHE_MANAGER.createCache("folder", "saveFile", file.getParent(), CacheExpirationTime.NEVER_EXPIRES.getValue()));
|
||||||
|
} else {
|
||||||
|
cache.setCacheData(file.getParent());
|
||||||
|
CACHE_MANAGER.addCache(cache);
|
||||||
|
}
|
||||||
|
logger.info("正在保存文件: {}", file.getName());
|
||||||
|
tab.save(file);
|
||||||
|
// 将保存后的文件设置为关联文件
|
||||||
|
tab.setRelevance(true);
|
||||||
|
// 更新标签页上的文件名
|
||||||
|
tab.setText(file.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重命名
|
||||||
|
*/
|
||||||
|
public static void rename(CenterTab tab) {
|
||||||
|
if (tab == null || tab.getText().isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 判断当前是否为关联文件
|
||||||
|
if (tab.isRelevance()) {
|
||||||
|
// 重命名关联文件
|
||||||
|
handleRenameRelevanceFile(tab);
|
||||||
|
}
|
||||||
|
// 如果当前不是关联文件则重命名标签页
|
||||||
|
else {
|
||||||
|
handleRenameTab(tab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重命名标签页。
|
||||||
|
*
|
||||||
|
* @param tab 标签页组件
|
||||||
|
*/
|
||||||
|
private static void handleRenameTab(CenterTab tab) {
|
||||||
|
TextField textField = new TextField(tab.getText());
|
||||||
|
textField.getStyleClass().add("tab-title-editable");
|
||||||
|
// 临时记录标签页名称
|
||||||
|
String tempName = tab.getText();
|
||||||
|
// 清空标签页名称
|
||||||
|
tab.setText("");
|
||||||
|
|
||||||
|
// 监听 Enter 键,完成编辑
|
||||||
|
textField.setOnKeyPressed(event -> {
|
||||||
|
if (event.getCode() == KeyCode.ENTER) {
|
||||||
|
String newTabName = textField.getText();
|
||||||
|
// 检查是否存在相同名称的标签页
|
||||||
|
if (isTabNameExists(newTabName)) {
|
||||||
|
|
||||||
|
// 显示弹窗并提示用户更换名称
|
||||||
|
showDuplicateNameAlert(newTabName);
|
||||||
|
|
||||||
|
// 恢复原始名称
|
||||||
|
tab.setText(tempName);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
tab.setText(newTabName);
|
||||||
|
// 可选:移除 TextField 的图形
|
||||||
|
tab.setGraphic(null);
|
||||||
|
// 可选:恢复标签页的关闭按钮
|
||||||
|
tab.setClosable(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听失去焦点事件,完成编辑
|
||||||
|
textField.focusedProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
String newTabName = textField.getText();
|
||||||
|
// 检查是否存在相同名称的标签页
|
||||||
|
if (isTabNameExists(newTabName)) {
|
||||||
|
// 恢复原始名称
|
||||||
|
tab.setText(tempName);
|
||||||
|
|
||||||
|
}
|
||||||
|
if (Boolean.FALSE.equals(newValue)) {
|
||||||
|
tab.setText(newTabName);
|
||||||
|
// 可选:移除 TextField 的图形
|
||||||
|
tab.setGraphic(null);
|
||||||
|
// 可选:恢复标签页的关闭按钮
|
||||||
|
tab.setClosable(true);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tab.setClosable(false);
|
||||||
|
// 设置 TextField 作为标签页的图形
|
||||||
|
tab.setGraphic(textField);
|
||||||
|
// 默认获取焦点并选中所有文字
|
||||||
|
textField.requestFocus();
|
||||||
|
textField.selectAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否存在具有相同名称的标签页。
|
||||||
|
*
|
||||||
|
* @param newTabName 要检查的新标签页名称
|
||||||
|
* @return 如果存在具有相同名称的标签页,则返回 true;否则返回 false
|
||||||
|
*/
|
||||||
|
private static boolean isTabNameExists(String newTabName) {
|
||||||
|
CenterTabPane tabPane = CenterTabPane.getInstance();
|
||||||
|
return tabPane.getTabs().stream()
|
||||||
|
.anyMatch(tab -> tab.getText().equals(newTabName));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示警告弹窗,提示用户更换重复的名称。
|
||||||
|
*/
|
||||||
|
private static void showDuplicateNameAlert(String newTabName) {
|
||||||
|
|
||||||
|
PopUpUtil.errorAlert("重命名错误", "\" " + newTabName + "\" 和已有标签页名字重复", "请再次重命名", null, null);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重命名关联文件。
|
||||||
|
*
|
||||||
|
* @param tab 标签页组件
|
||||||
|
*/
|
||||||
|
private static void handleRenameRelevanceFile(CenterTab tab) {
|
||||||
|
// 获取原始文件对象
|
||||||
|
File file = (File) tab.getUserData();
|
||||||
|
|
||||||
|
// 获取应用窗口并绑定
|
||||||
|
File newFile = BasicFileChooserFactory.getInstance()
|
||||||
|
.createFileChooser(
|
||||||
|
UiResourceBundle.getContent(TextConstants.RENAME),
|
||||||
|
tab.getText(),
|
||||||
|
new File(file.getParent()),
|
||||||
|
new FileChooser.ExtensionFilter("All types", "*.*"))
|
||||||
|
.showSaveDialog(UiUtil.getAppWindow());
|
||||||
|
if (newFile != null) {
|
||||||
|
boolean rename = file.renameTo(newFile);
|
||||||
|
// 设置文件数据
|
||||||
|
tab.setUserData(newFile);
|
||||||
|
if (rename) {
|
||||||
|
tab.setText(newFile.getName());
|
||||||
|
logger.info("文件重命名成功");
|
||||||
|
} else {
|
||||||
|
logger.debug("文件重命名失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加新的文件标签页。
|
||||||
|
*/
|
||||||
|
public static void addNewFileTab() {
|
||||||
|
// 创建一个新的文本编辑区
|
||||||
|
TextCodeArea textArea = new TextCodeArea();
|
||||||
|
// 设定初始索引
|
||||||
|
int index = 1;
|
||||||
|
StringBuilder tabTitle = new StringBuilder();
|
||||||
|
// 获取当前默认创建标签页集合
|
||||||
|
List<Tab> tabs = CenterTabPane.getInstance()
|
||||||
|
.getTabs()
|
||||||
|
.stream()
|
||||||
|
// 排除不属于默认创建的标签页
|
||||||
|
.filter(tab -> AppConstants.TABNAME_PATTERN.matcher(tab.getText()).matches())
|
||||||
|
// 对默认创建的标签页进行排序
|
||||||
|
.sorted(Comparator.comparing(Tab::getText))
|
||||||
|
// 转为List集合
|
||||||
|
.toList();
|
||||||
|
// 构建初始标签页名称
|
||||||
|
tabTitle.append(UiResourceBundle.getContent(TextConstants.NEW_FILE)).append(index);
|
||||||
|
for (Tab tab : tabs) {
|
||||||
|
if (tab.getText().contentEquals(tabTitle)) {
|
||||||
|
tabTitle.setLength(0);
|
||||||
|
tabTitle.append(UiResourceBundle.getContent(TextConstants.NEW_FILE)).append(++index);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 创建标签页
|
||||||
|
CenterTab centerTab = new CenterTab(
|
||||||
|
tabTitle.toString(),
|
||||||
|
textArea);
|
||||||
|
// 设置当前标签页与本地文件无关联
|
||||||
|
centerTab.setRelevance(false);
|
||||||
|
// 将Tab页添加到TabPane中
|
||||||
|
CenterTabPaneManager.getInstance().addNewTab(centerTab);
|
||||||
|
// 更新编码信息
|
||||||
|
BottomStatusBoxManager.getInstance().updateEncodingLabel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开文件到选项卡
|
||||||
|
*
|
||||||
|
* @param file 文件对象
|
||||||
|
*/
|
||||||
|
public static void openFileToTab(File file) {
|
||||||
|
// 获取标签页集合
|
||||||
|
CenterTabPane centerTabPane = CenterTabPane.getInstance();
|
||||||
|
// 遍历标签页,查找匹配的标签页
|
||||||
|
for (Tab tab : centerTabPane.getTabs()) {
|
||||||
|
// 获取绑定的文件
|
||||||
|
File tabFile = (File) tab.getUserData();
|
||||||
|
if (tabFile == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (file.getPath().equals((tabFile).getPath())) {
|
||||||
|
// 找到匹配的标签页,设置为选中状态并跳转
|
||||||
|
centerTabPane.getSelectionModel().select(tab);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getText(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取文本文件的内容。
|
||||||
|
*
|
||||||
|
* @param file 文件对象
|
||||||
|
*/
|
||||||
|
public static void getText(File file) {
|
||||||
|
TextCodeArea textCodeArea = new TextCodeArea();
|
||||||
|
// 检测文件编码
|
||||||
|
Charset encoding = EncodingDetector.detectEncodingCharset(file);
|
||||||
|
String fileText = getFileText(file, encoding);
|
||||||
|
LogUtil.getLogger(OpenFile.class).info("已调用读取文件功能");
|
||||||
|
textCodeArea.appendText(fileText);
|
||||||
|
CenterTab tab = new CenterTab(file.getName(), textCodeArea, encoding);
|
||||||
|
// 设置当前标签页关联本地文件
|
||||||
|
tab.setRelevance(true);
|
||||||
|
// 设置标签页关联文件
|
||||||
|
tab.setUserData(file);
|
||||||
|
// 设置关联文件最后的修改时间
|
||||||
|
tab.setLastModifiedTimeOfAssociatedFile(file.lastModified());
|
||||||
|
CenterTabPaneManager.getInstance().addNewTab(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updateTabContextMenu(CenterTab tab) {
|
||||||
|
ContextMenuBuilder builder = new ContextMenuBuilder();
|
||||||
|
CenterTabPaneManager centerTabPaneManager = CenterTabPaneManager.getInstance();
|
||||||
|
File file = (File) tab.getUserData();
|
||||||
|
//todo 设置上下文菜单
|
||||||
|
tab.setContextMenu(
|
||||||
|
builder
|
||||||
|
.addMenuItem("关闭", e -> centerTabPaneManager.removeTab(tab))
|
||||||
|
.addMenuItem(
|
||||||
|
"关闭其它标签页",
|
||||||
|
e -> centerTabPaneManager.removeOtherTabs(tab),
|
||||||
|
centerTabPaneManager.hasOtherTabs()
|
||||||
|
)
|
||||||
|
.addMenuItem("关闭所有标签页", e -> centerTabPaneManager.removeAllTabs())
|
||||||
|
.addMenuItem(
|
||||||
|
"关闭左侧标签页",
|
||||||
|
e -> centerTabPaneManager.removeLeftTabs(tab),
|
||||||
|
centerTabPaneManager.hasLeftTabs(tab)
|
||||||
|
)
|
||||||
|
.addMenuItem(
|
||||||
|
"关闭右侧标签页",
|
||||||
|
e -> centerTabPaneManager.removeRightTabs(tab),
|
||||||
|
centerTabPaneManager.hasRightTabs(tab)
|
||||||
|
)
|
||||||
|
.addSeparatorMenuItem()
|
||||||
|
.addMenu(
|
||||||
|
new MenuBuilder("复制")
|
||||||
|
.addMenuItem("文件名", e -> {
|
||||||
|
ClipboardUtil.writeTextToClipboard(tab.getText());
|
||||||
|
NotificationUtil.infoNotification("已复制文件名!");
|
||||||
|
}, tab.isRelevance())
|
||||||
|
.addMenuItem("标签页名", e -> {
|
||||||
|
ClipboardUtil.writeTextToClipboard(tab.getText());
|
||||||
|
NotificationUtil.infoNotification("已复制标签页名!");
|
||||||
|
}, !tab.isRelevance())
|
||||||
|
.addMenuItem("文件路径", e -> {
|
||||||
|
ClipboardUtil.writeTextToClipboard(file.getAbsolutePath());
|
||||||
|
NotificationUtil.infoNotification("已复制文件路径!");
|
||||||
|
}, tab.isRelevance())
|
||||||
|
.addMenuItem("所在文件夹", e -> {
|
||||||
|
ClipboardUtil.writeTextToClipboard(file.getParent());
|
||||||
|
NotificationUtil.infoNotification("已复制所在文件夹!");
|
||||||
|
}, tab.isRelevance())
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.addSeparatorMenuItem()
|
||||||
|
.addMenuItem("保存", e -> saveFile(tab))
|
||||||
|
.addMenuItem("另存为", e -> saveAsFile(tab), tab.isRelevance())
|
||||||
|
.addMenuItem("重命名", e -> rename(tab))
|
||||||
|
.addSeparatorMenuItem()
|
||||||
|
.addMenu(new MenuBuilder("打开于")
|
||||||
|
.addMenuItem("资源管理器", e -> FileUtil.openExplorer(file))
|
||||||
|
.addMenuItem("终端", e -> {
|
||||||
|
//todo @luke 请你在此设置打开文件所在文件夹路径于终端
|
||||||
|
})
|
||||||
|
.build(), tab.isRelevance())
|
||||||
|
.addSeparatorMenuItem()
|
||||||
|
.addMenuItem("固定标签页", e -> centerTabPaneManager.updateTabPinnedState(tab), !tab.isFixed())
|
||||||
|
.addMenuItem("取消固定", e -> centerTabPaneManager.updateTabPinnedState(tab), tab.isFixed())
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
package org.jcnc.jnotepad.views.manager;
|
package org.jcnc.jnotepad.views.manager;
|
||||||
|
|
||||||
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.scene.control.Tab;
|
import javafx.scene.control.Tab;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
@ -9,12 +10,14 @@ import org.jcnc.jnotepad.controller.config.UserConfigController;
|
|||||||
import org.jcnc.jnotepad.model.enums.CacheExpirationTime;
|
import org.jcnc.jnotepad.model.enums.CacheExpirationTime;
|
||||||
import org.jcnc.jnotepad.util.FileUtil;
|
import org.jcnc.jnotepad.util.FileUtil;
|
||||||
import org.jcnc.jnotepad.util.PopUpUtil;
|
import org.jcnc.jnotepad.util.PopUpUtil;
|
||||||
|
import org.jcnc.jnotepad.util.TabUtil;
|
||||||
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTab;
|
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTab;
|
||||||
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTabPane;
|
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTabPane;
|
||||||
import org.jcnc.jnotepad.views.root.top.menubar.TopMenuBar;
|
import org.jcnc.jnotepad.views.root.top.menubar.TopMenuBar;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -177,10 +180,10 @@ public class CenterTabPaneManager {
|
|||||||
/**
|
/**
|
||||||
* Removes all tabs from the center tab pane that are not equal to the specified center tab.
|
* Removes all tabs from the center tab pane that are not equal to the specified center tab.
|
||||||
*
|
*
|
||||||
* @param centerTab the center tab to compare against
|
* @param currTab the current tab
|
||||||
*/
|
*/
|
||||||
public void removeOtherTabs(CenterTab centerTab) {
|
public void removeOtherTabs(CenterTab currTab) {
|
||||||
centerTabPane.getTabs().removeIf(tab -> !centerTab.equals(tab));
|
centerTabPane.getTabs().removeIf(tab -> (!currTab.equals(tab) || !((CenterTab) tab).isFixed()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -190,7 +193,16 @@ public class CenterTabPaneManager {
|
|||||||
*/
|
*/
|
||||||
public void removeLeftTabs(CenterTab centerTab) {
|
public void removeLeftTabs(CenterTab centerTab) {
|
||||||
ObservableList<Tab> tabs = centerTabPane.getTabs();
|
ObservableList<Tab> tabs = centerTabPane.getTabs();
|
||||||
tabs.remove(0, tabs.indexOf(centerTab));
|
Iterator<Tab> iterator = tabs.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
CenterTab tab = (CenterTab) iterator.next();
|
||||||
|
if (tab.equals(centerTab)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!tab.isFixed()) {
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -200,7 +212,18 @@ public class CenterTabPaneManager {
|
|||||||
*/
|
*/
|
||||||
public void removeRightTabs(CenterTab centerTab) {
|
public void removeRightTabs(CenterTab centerTab) {
|
||||||
ObservableList<Tab> tabs = centerTabPane.getTabs();
|
ObservableList<Tab> tabs = centerTabPane.getTabs();
|
||||||
tabs.remove(tabs.indexOf(centerTab), tabs.size());
|
Iterator<Tab> iterator = tabs.iterator();
|
||||||
|
boolean flag = false;
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
CenterTab tab = (CenterTab) iterator.next();
|
||||||
|
if (tab.equals(centerTab)) {
|
||||||
|
flag = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (flag && !tab.isFixed()) {
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -235,4 +258,26 @@ public class CenterTabPaneManager {
|
|||||||
int index = tabs.indexOf(centerTab);
|
int index = tabs.indexOf(centerTab);
|
||||||
return index != tabs.size() - 1;
|
return index != tabs.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a listener for the tabs in the center tab pane.
|
||||||
|
*
|
||||||
|
* @param tab the tab to set the listener for
|
||||||
|
*/
|
||||||
|
public void setTabsListener(CenterTab tab) {
|
||||||
|
centerTabPane.getTabs().addListener((ListChangeListener<Tab>) c -> tab.contextMenuMonitor());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the pinned state of the given center tab.
|
||||||
|
*
|
||||||
|
* @param tab the center tab to update
|
||||||
|
*/
|
||||||
|
public void updateTabPinnedState(CenterTab tab) {
|
||||||
|
tab.setFixed(!tab.isFixed());
|
||||||
|
TabUtil.updateTabContextMenu(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
package org.jcnc.jnotepad.views.manager;
|
package org.jcnc.jnotepad.views.manager;
|
||||||
|
|
||||||
import atlantafx.base.controls.Notification;
|
import atlantafx.base.controls.Notification;
|
||||||
import atlantafx.base.theme.Styles;
|
|
||||||
import atlantafx.base.util.Animations;
|
import atlantafx.base.util.Animations;
|
||||||
|
import javafx.animation.KeyFrame;
|
||||||
|
import javafx.animation.Timeline;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
@ -89,8 +90,33 @@ public class RootManager {
|
|||||||
* @param stackPane 要添加提示框的 StackPane。
|
* @param stackPane 要添加提示框的 StackPane。
|
||||||
* @param msg 要显示的提示框。
|
* @param msg 要显示的提示框。
|
||||||
*/
|
*/
|
||||||
public void addNotificationToStackPane(StackPane stackPane, Notification msg) {
|
public static void addNotificationToStackPane(StackPane stackPane, Notification msg, int closeDelaySeconds) {
|
||||||
msg.getStyleClass().addAll(Styles.ACCENT, Styles.ELEVATED_1);
|
addNotificationToStackPane(stackPane, msg);
|
||||||
|
automaticallyCloseNotification(stackPane, msg, closeDelaySeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a notification to the given StackPane.
|
||||||
|
*
|
||||||
|
* @param stackPane the StackPane to add the notification to
|
||||||
|
* @param msg the notification message
|
||||||
|
* @param autoClose true if the notification should automatically close, false otherwise
|
||||||
|
*/
|
||||||
|
public static void addNotificationToStackPane(StackPane stackPane, Notification msg, boolean autoClose) {
|
||||||
|
addNotificationToStackPane(stackPane, msg);
|
||||||
|
if (autoClose) {
|
||||||
|
automaticallyCloseNotification(stackPane, msg, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a notification message to a StackPane.
|
||||||
|
*
|
||||||
|
* @param stackPane the StackPane to add the notification to
|
||||||
|
* @param msg the notification message to be added
|
||||||
|
*/
|
||||||
|
private static void addNotificationToStackPane(StackPane stackPane, Notification msg) {
|
||||||
msg.setPrefHeight(Region.USE_PREF_SIZE);
|
msg.setPrefHeight(Region.USE_PREF_SIZE);
|
||||||
msg.setMaxHeight(Region.USE_PREF_SIZE);
|
msg.setMaxHeight(Region.USE_PREF_SIZE);
|
||||||
StackPane.setAlignment(msg, Pos.BOTTOM_RIGHT);
|
StackPane.setAlignment(msg, Pos.BOTTOM_RIGHT);
|
||||||
@ -109,6 +135,26 @@ public class RootManager {
|
|||||||
in.playFromStart();
|
in.playFromStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatically closes the notification after a specified delay.
|
||||||
|
*
|
||||||
|
* @param stackPane the StackPane containing the notification
|
||||||
|
* @param msg the notification to be closed
|
||||||
|
* @param closeDelaySeconds the delay time in seconds before closing the notification
|
||||||
|
*/
|
||||||
|
private static void automaticallyCloseNotification(StackPane stackPane, Notification msg, int closeDelaySeconds) {
|
||||||
|
// 自动关闭提示框
|
||||||
|
// 设置关闭延迟时间(单位:秒)
|
||||||
|
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(closeDelaySeconds), event -> {
|
||||||
|
// 关闭提示框
|
||||||
|
var out = Animations.slideOutUp(msg, Duration.millis(450));
|
||||||
|
out.setOnFinished(f -> stackPane.getChildren().remove(msg));
|
||||||
|
out.playFromStart();
|
||||||
|
}));
|
||||||
|
timeline.setCycleCount(1);
|
||||||
|
timeline.play();
|
||||||
|
}
|
||||||
|
|
||||||
public StackPane getRootStackPane() {
|
public StackPane getRootStackPane() {
|
||||||
return rootStackPane;
|
return rootStackPane;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,12 +2,13 @@ package org.jcnc.jnotepad.views.root.center.main.center.directory;
|
|||||||
|
|
||||||
import javafx.scene.control.TreeItem;
|
import javafx.scene.control.TreeItem;
|
||||||
import javafx.scene.control.TreeView;
|
import javafx.scene.control.TreeView;
|
||||||
import org.jcnc.jnotepad.controller.event.handler.menuitem.OpenFile;
|
|
||||||
import org.jcnc.jnotepad.model.entity.DirFileModel;
|
import org.jcnc.jnotepad.model.entity.DirFileModel;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static org.jcnc.jnotepad.util.TabUtil.openFileToTab;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 目录树ui
|
* 目录树ui
|
||||||
@ -34,7 +35,7 @@ public class DirectorySidebarPane extends TreeView<DirFileModel> {
|
|||||||
if (!file.isFile()) {
|
if (!file.isFile()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
OpenFile.openFile(file);
|
openFileToTab(file);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,16 +6,15 @@ import org.jcnc.jnotepad.api.core.views.menu.builder.ContextMenuBuilder;
|
|||||||
import org.jcnc.jnotepad.api.core.views.menu.builder.MenuBuilder;
|
import org.jcnc.jnotepad.api.core.views.menu.builder.MenuBuilder;
|
||||||
import org.jcnc.jnotepad.component.module.TextCodeArea;
|
import org.jcnc.jnotepad.component.module.TextCodeArea;
|
||||||
import org.jcnc.jnotepad.controller.config.UserConfigController;
|
import org.jcnc.jnotepad.controller.config.UserConfigController;
|
||||||
import org.jcnc.jnotepad.controller.event.handler.menuitem.OpenFile;
|
|
||||||
import org.jcnc.jnotepad.controller.event.handler.menuitem.RenameFile;
|
import org.jcnc.jnotepad.controller.event.handler.menuitem.RenameFile;
|
||||||
import org.jcnc.jnotepad.controller.event.handler.menuitem.SaveFile;
|
import org.jcnc.jnotepad.controller.event.handler.menuitem.SaveFile;
|
||||||
import org.jcnc.jnotepad.util.ClipboardUtil;
|
import org.jcnc.jnotepad.util.ClipboardUtil;
|
||||||
import org.jcnc.jnotepad.util.LogUtil;
|
import org.jcnc.jnotepad.util.LogUtil;
|
||||||
|
import org.jcnc.jnotepad.util.TabUtil;
|
||||||
import org.jcnc.jnotepad.views.manager.BottomStatusBoxManager;
|
import org.jcnc.jnotepad.views.manager.BottomStatusBoxManager;
|
||||||
import org.jcnc.jnotepad.views.manager.CenterTabPaneManager;
|
import org.jcnc.jnotepad.views.manager.CenterTabPaneManager;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
@ -39,6 +38,11 @@ public class CenterTab extends Tab {
|
|||||||
* 是否与本地文件关联
|
* 是否与本地文件关联
|
||||||
*/
|
*/
|
||||||
private boolean isRelevance = false;
|
private boolean isRelevance = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否固定
|
||||||
|
*/
|
||||||
|
private boolean isFixed = false;
|
||||||
/**
|
/**
|
||||||
* 关联文件上次修改时间
|
* 关联文件上次修改时间
|
||||||
*/
|
*/
|
||||||
@ -60,7 +64,8 @@ public class CenterTab extends Tab {
|
|||||||
this.setContent(new VirtualizedScrollPane<>(textCodeArea));
|
this.setContent(new VirtualizedScrollPane<>(textCodeArea));
|
||||||
setAutoLine(UserConfigController.getInstance().getAutoLineConfig());
|
setAutoLine(UserConfigController.getInstance().getAutoLineConfig());
|
||||||
this.charset = charset;
|
this.charset = charset;
|
||||||
contextMenuMonitor();
|
// 绑定标签页监听
|
||||||
|
CenterTabPaneManager.getInstance().setTabsListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRelevance() {
|
public boolean isRelevance() {
|
||||||
@ -92,59 +97,13 @@ public class CenterTab extends Tab {
|
|||||||
this.charset = charset;
|
this.charset = charset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Monitors the context menu.
|
||||||
|
*/
|
||||||
public void contextMenuMonitor() {
|
public void contextMenuMonitor() {
|
||||||
ContextMenuBuilder builder = new ContextMenuBuilder();
|
TabUtil.updateTabContextMenu(this);
|
||||||
CenterTabPaneManager centerTabPaneManager = CenterTabPaneManager.getInstance();
|
|
||||||
File file = (File) this.getUserData();
|
|
||||||
//todo 设置上下文菜单
|
|
||||||
this.setContextMenu(
|
|
||||||
builder
|
|
||||||
.addMenuItem("关闭", e -> centerTabPaneManager.removeTab(this))
|
|
||||||
.addMenuItem(
|
|
||||||
"关闭其它标签页",
|
|
||||||
e -> centerTabPaneManager.removeOtherTabs(this),
|
|
||||||
centerTabPaneManager.hasOtherTabs()
|
|
||||||
)
|
|
||||||
.addMenuItem("关闭所有标签页", e -> centerTabPaneManager.removeAllTabs())
|
|
||||||
.addMenuItem(
|
|
||||||
"关闭左侧标签页",
|
|
||||||
e -> centerTabPaneManager.removeLeftTabs(this),
|
|
||||||
centerTabPaneManager.hasLeftTabs(this)
|
|
||||||
)
|
|
||||||
.addMenuItem(
|
|
||||||
"关闭右侧标签页",
|
|
||||||
e -> centerTabPaneManager.removeRightTabs(this),
|
|
||||||
centerTabPaneManager.hasRightTabs(this)
|
|
||||||
)
|
|
||||||
.addSeparatorMenuItem()
|
|
||||||
.addMenu(
|
|
||||||
new MenuBuilder("复制")
|
|
||||||
.addMenuItem("文件名", e -> ClipboardUtil.writeTextToClipboard(this.getText()))
|
|
||||||
.addMenuItem("文件路径", e -> ClipboardUtil.writeTextToClipboard(file.getAbsolutePath()))
|
|
||||||
.addMenuItem("所在文件夹", e -> ClipboardUtil.writeTextToClipboard(file.getParent()))
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.addSeparatorMenuItem()
|
|
||||||
.addMenuItem("保存", e -> SaveFile.saveFile())
|
|
||||||
.addMenuItem("另存为", e -> SaveFile.saveAsFile(), isRelevance)
|
|
||||||
.addMenuItem("重命名", e -> RenameFile.rename())
|
|
||||||
.addSeparatorMenuItem()
|
|
||||||
.addMenu(new MenuBuilder("打开于")
|
|
||||||
.addMenuItem("资源管理器", e -> {
|
|
||||||
try {
|
|
||||||
LogUtil.getLogger(OpenFile.class).info("已调用资源管理器");
|
|
||||||
File file1 = (File) this.getUserData();
|
|
||||||
Desktop.getDesktop().open(file1.getParentFile());
|
|
||||||
} catch (IOException exception) {
|
|
||||||
logger.error("加载资源管理器失败!");
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.addMenuItem("终端", e -> {
|
|
||||||
|
|
||||||
})
|
|
||||||
.build())
|
|
||||||
.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存选中的文件标签页
|
* 保存选中的文件标签页
|
||||||
@ -214,4 +173,12 @@ public class CenterTab extends Tab {
|
|||||||
public void setLastModifiedTimeOfAssociatedFile(Long lastModifiedTimeOfAssociatedFile) {
|
public void setLastModifiedTimeOfAssociatedFile(Long lastModifiedTimeOfAssociatedFile) {
|
||||||
this.lastModifiedTimeOfAssociatedFile = lastModifiedTimeOfAssociatedFile;
|
this.lastModifiedTimeOfAssociatedFile = lastModifiedTimeOfAssociatedFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isFixed() {
|
||||||
|
return isFixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFixed(boolean fixed) {
|
||||||
|
isFixed = fixed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user