!152 初步添加标签页右键菜单

Merge pull request !152 from 格物方能致知/develop
This commit is contained in:
格物方能致知 2023-10-07 17:25:15 +00:00 committed by Gitee
commit 11e1f8c607
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
19 changed files with 437 additions and 40 deletions

View File

@ -30,7 +30,6 @@ public class JnotepadApp extends Application {
// 获取当前启动位置a
String currentWorkingDirectory = System.getProperty("user.dir");
LogUtil.getLogger(this.getClass()).info("当前启动位置:{}", currentWorkingDirectory);
// 设置参数
APPLICATION_MANAGER.setApplication(this);
APPLICATION_MANAGER.setPrimaryStage(primaryStage);

View File

@ -22,9 +22,9 @@ import java.nio.file.Paths;
*/
public abstract class BaseConfigController<T> implements ConfigController<T> {
protected final String rootConfigDir = "config";
protected static final String ROOT_CONFIG_DIR = "config";
protected final String systemConfigDir = "system";
protected static final String SYSTEM_CONFIG_DIR = "system";
protected T config;
Logger logger = LogUtil.getLogger(this.getClass());

View File

@ -0,0 +1,118 @@
package org.jcnc.jnotepad.api.core.views.menu.builder;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SeparatorMenuItem;
/**
* 抽象菜单建造者类
*
* @author gewuyou
*/
public abstract class AbstractMenuBuilder<B, T> {
/**
* Get subclass builder
*
* @return builder
*/
protected abstract B getBuilder();
/**
* Retrieves the items of the menu.
*
* @return an ObservableList of MenuItems
*/
protected abstract ObservableList<MenuItem> getItems();
/**
* 添加菜单项
*
* @param label 菜单项名称
* @param eventHandler 事件
* @return 建造者
*/
public B addMenuItem(String label, EventHandler<ActionEvent> eventHandler) {
MenuItem menuItem = new MenuItem(label);
menuItem.setOnAction(eventHandler);
getItems().add(menuItem);
return getBuilder();
}
/**
* 添加菜单项
*
* @param label 菜单项名称
* @param eventHandler 事件
* @param disable 是否禁用
* @return 建造者
*/
public B addMenuItem(String label, EventHandler<ActionEvent> eventHandler, boolean disable) {
if (!disable) {
return getBuilder();
}
MenuItem menuItem = new MenuItem(label);
menuItem.setOnAction(eventHandler);
getItems().add(menuItem);
return getBuilder();
}
/**
* 添加单选菜单项
*
* @param label 菜单项名称
* @param eventHandler 事件
* @return 建造者
*/
public B addRadioMenuItem(String label, EventHandler<ActionEvent> eventHandler) {
MenuItem menuItem = new MenuItem(label);
menuItem.setOnAction(eventHandler);
getItems().add(menuItem);
return getBuilder();
}
/**
* 添加复选菜单项
*
* @param label 菜单项名称
* @param eventHandler 事件
* @return 建造者
*/
public B addCheckMenuItem(String label, EventHandler<ActionEvent> eventHandler) {
MenuItem menuItem = new MenuItem(label);
menuItem.setOnAction(eventHandler);
getItems().add(menuItem);
return getBuilder();
}
/**
* 添加菜单
*
* @param menu 菜单
* @return 建造者
*/
public B addMenu(Menu menu) {
getItems().add(menu);
return getBuilder();
}
/**
* 添加分割线
*
* @return 建造者
*/
public B addSeparatorMenuItem() {
getItems().add(new SeparatorMenuItem());
return getBuilder();
}
/**
* Build menu
*
* @return menu
*/
public abstract T build();
}

View File

@ -0,0 +1,49 @@
package org.jcnc.jnotepad.api.core.views.menu.builder;
import javafx.collections.ObservableList;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
/**
* 上下文菜单建造者类
*
* @author gewuyou
*/
public class ContextMenuBuilder extends AbstractMenuBuilder<ContextMenuBuilder, ContextMenu> {
private final ContextMenu contextMenu;
public ContextMenuBuilder() {
contextMenu = new ContextMenu();
}
/**
* Builds and returns the ContextMenu object.
*
* @return the built ContextMenu object
*/
@Override
public ContextMenu build() {
return contextMenu;
}
/**
* Get subclass builder
*
* @return builder
*/
@Override
protected ContextMenuBuilder getBuilder() {
return this;
}
/**
* Retrieves the items of the menu.
*
* @return an ObservableList of MenuItems
*/
@Override
protected ObservableList<MenuItem> getItems() {
return contextMenu.getItems();
}
}

View File

@ -0,0 +1,48 @@
package org.jcnc.jnotepad.api.core.views.menu.builder;
import javafx.collections.ObservableList;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem;
/**
* 菜单建造者类
*
* @author gewuyou
*/
public class MenuBuilder extends AbstractMenuBuilder<MenuBuilder, Menu> {
private final Menu menu;
public MenuBuilder(String label) {
menu = new Menu(label);
}
/**
* Get subclass builder
*
* @return builder
*/
@Override
protected MenuBuilder getBuilder() {
return this;
}
/**
* Retrieves the items of the menu.
*
* @return an ObservableList of MenuItems
*/
@Override
protected ObservableList<MenuItem> getItems() {
return menu.getItems();
}
/**
* Build menu
*
* @return menu
*/
@Override
public Menu build() {
return menu;
}
}

View File

@ -12,13 +12,12 @@ import javafx.scene.control.Hyperlink;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage;
import org.jcnc.jnotepad.api.core.component.stage.AbstractPaneStage;
import org.jcnc.jnotepad.util.ClipboardUtil;
import org.jcnc.jnotepad.util.LogUtil;
import org.jcnc.jnotepad.util.UiUtil;
import org.jcnc.jnotepad.views.manager.RootManager;
@ -139,12 +138,10 @@ public class HelpPaneStage extends AbstractPaneStage {
// 调用 RootManager 中的方法来显示 Notification
rootManager.addNotificationToStackPane(rootManager.getRootStackPane(), notification);
Clipboard clipboard = Clipboard.getSystemClipboard();
ClipboardContent content = new ClipboardContent();
String info = "软件名字:" + APP_NAME + "\t" + "版本:" + VERSION;
content.putString(info);
ClipboardUtil.writeTextToClipboard(info);
LogUtil.getLogger(this.getClass()).info("软件信息已经复制到剪贴板:{}", info);
clipboard.setContent(content);
// 关闭当前的 Stage
Stage currentStage = (Stage) ((Button) event.getSource()).getScene().getWindow();
currentStage.close();

View File

@ -29,7 +29,7 @@ public class AppConfigController extends BaseConfigController<AppConfig> {
private final String configDir;
public AppConfigController() {
configDir = Paths.get(System.getProperty(DEFAULT_PROPERTY), PROGRAM_FILE_DIRECTORY, systemConfigDir).toString();
configDir = Paths.get(System.getProperty(DEFAULT_PROPERTY), PROGRAM_FILE_DIRECTORY, SYSTEM_CONFIG_DIR).toString();
loadConfig();
}

View File

@ -26,7 +26,7 @@ public class PluginConfigController extends BaseConfigController<PluginConfig> {
private PluginConfigController() {
String rootPath = AppConfigController.getInstance().getConfig().getRootPath();
configDir = Paths.get(rootPath, PROGRAM_FILE_DIRECTORY, rootConfigDir).toString();
configDir = Paths.get(rootPath, PROGRAM_FILE_DIRECTORY, ROOT_CONFIG_DIR).toString();
setPluginsDir(Paths.get(rootPath, PROGRAM_FILE_DIRECTORY, "plugins").toString());
loadConfig();
}

View File

@ -32,7 +32,7 @@ public class UserConfigController extends BaseConfigController<UserConfig> {
private String configDir;
private UserConfigController() {
configDir = Paths.get(AppConfigController.getInstance().getConfig().getRootPath(), PROGRAM_FILE_DIRECTORY, rootConfigDir).toString();
configDir = Paths.get(AppConfigController.getInstance().getConfig().getRootPath(), PROGRAM_FILE_DIRECTORY, ROOT_CONFIG_DIR).toString();
loadConfig();
}

View File

@ -27,10 +27,12 @@ import java.io.File;
* @author gewuyou
*/
public class RenameFile implements EventHandler<ActionEvent> {
Logger logger = LogUtil.getLogger(this.getClass());
static Logger logger = LogUtil.getLogger(RenameFile.class);
@Override
public void handle(ActionEvent actionEvent) {
/**
* 重命名
*/
public static void rename() {
// 获取当前标签页
CenterTab centerTab = CenterTabPaneManager.getInstance().getSelected();
if (centerTab == null || centerTab.getText().isEmpty()) {
@ -52,7 +54,7 @@ public class RenameFile implements EventHandler<ActionEvent> {
*
* @param centerTab 标签页组件
*/
private void handleRenameTab(CenterTab centerTab) {
private static void handleRenameTab(CenterTab centerTab) {
TextField textField = new TextField(centerTab.getText());
textField.getStyleClass().add("tab-title-editable");
// 临时记录标签页名称
@ -116,7 +118,7 @@ public class RenameFile implements EventHandler<ActionEvent> {
* @param newTabName 要检查的新标签页名称
* @return 如果存在具有相同名称的标签页则返回 true否则返回 false
*/
private boolean isTabNameExists(String newTabName) {
private static boolean isTabNameExists(String newTabName) {
CenterTabPane tabPane = CenterTabPane.getInstance();
return tabPane.getTabs().stream()
.anyMatch(tab -> tab.getText().equals(newTabName));
@ -125,7 +127,7 @@ public class RenameFile implements EventHandler<ActionEvent> {
/**
* 显示警告弹窗提示用户更换重复的名称
*/
private void showDuplicateNameAlert(String newTabName) {
private static void showDuplicateNameAlert(String newTabName) {
PopUpUtil.errorAlert("重命名错误", "\" " + newTabName + "\" 和已有标签页名字重复", "请再次重命名", null, null);
@ -136,7 +138,7 @@ public class RenameFile implements EventHandler<ActionEvent> {
*
* @param centerTab 标签页组件
*/
private void handleRenameRelevanceFile(CenterTab centerTab) {
private static void handleRenameRelevanceFile(CenterTab centerTab) {
// 获取原始文件对象
File file = (File) centerTab.getUserData();
@ -160,4 +162,9 @@ public class RenameFile implements EventHandler<ActionEvent> {
}
}
}
@Override
public void handle(ActionEvent actionEvent) {
rename();
}
}

View File

@ -22,6 +22,6 @@ public class SaveAsFile extends SaveFile {
@Override
public void handle(ActionEvent event) {
LogUtil.getLogger(SaveAsFile.class).info("已调用另存为功能");
saveTab(this.getClass());
saveAsFile();
}
}

View File

@ -32,17 +32,9 @@ import static org.jcnc.jnotepad.controller.config.UserConfigController.CONFIG_NA
*/
public class SaveFile implements EventHandler<ActionEvent> {
private static final ApplicationCacheManager CACHE_MANAGER = ApplicationCacheManager.getInstance();
Logger logger = LogUtil.getLogger(this.getClass());
static Logger logger = LogUtil.getLogger(SaveFile.class);
/**
* 处理保存文件事件
*
* @param actionEvent 事件对象
* @apiNote 当用户选择保存文件时如果当前标签页是关联文件则自动保存
* 否则调用另存为方法
*/
@Override
public void handle(ActionEvent actionEvent) {
public static void saveFile() {
// 获取当前tab页
CenterTab selectedTab = CenterTabPaneManager.getInstance().getSelected();
if (selectedTab == null) {
@ -51,7 +43,7 @@ public class SaveFile implements EventHandler<ActionEvent> {
// 如果打开的是非关联文件则调用另存为方法
if (!selectedTab.isRelevance()) {
logger.info("当前保存文件为非关联打开文件,调用另存为方法");
saveTab(this.getClass());
saveAsFile();
} else {
logger.info("当前保存文件为关联打开文件,调用自动保存方法");
// 调用tab保存方法
@ -71,11 +63,10 @@ public class SaveFile implements EventHandler<ActionEvent> {
/**
* 保存标签页的方法
*
* @param currentClass 调用该方法的类
* @apiNote 将当前选中的标签页进行另存为弹出窗口式的保存
* @see LogUtil
*/
protected void saveTab(Class<?> currentClass) {
public static void saveAsFile() {
CenterTab selectedTab = CenterTabPaneManager.getInstance().getSelected();
if (selectedTab == null) {
return;
@ -94,7 +85,7 @@ public class SaveFile implements EventHandler<ActionEvent> {
cache.setCacheData(file.getParent());
CACHE_MANAGER.addCache(cache);
}
LogUtil.getLogger(currentClass).info("正在保存文件: {}", file.getName());
logger.info("正在保存文件: {}", file.getName());
selectedTab.save(file);
// 将保存后的文件设置为关联文件
selectedTab.setRelevance(true);
@ -102,4 +93,16 @@ public class SaveFile implements EventHandler<ActionEvent> {
selectedTab.setText(file.getName());
}
}
/**
* 处理保存文件事件
*
* @param actionEvent 事件对象
* @apiNote 当用户选择保存文件时如果当前标签页是关联文件则自动保存
* 否则调用另存为方法
*/
@Override
public void handle(ActionEvent actionEvent) {
saveFile();
}
}

View File

@ -0,0 +1,42 @@
package org.jcnc.jnotepad.util;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
/**
* 剪切板工具
*
* @author gewuyou
*/
public class ClipboardUtil {
/**
* 系统剪切板对象
*/
private static final Clipboard CLIPBOARD = Clipboard.getSystemClipboard();
private ClipboardUtil() {
}
/**
* Writes the provided text to the system clipboard.
*
* @param text the text to be written to the clipboard
*/
public static void writeTextToClipboard(String text) {
ClipboardContent content = new ClipboardContent();
content.putString(text);
CLIPBOARD.setContent(content);
}
/**
* Reads text from the clipboard.
*
* @return the text read from the clipboard
*/
public static String readTextFromClipboard() {
String text = CLIPBOARD.getString();
LogUtil.getLogger(ClipboardUtil.class).info("剪切板内容:{}", text);
return text;
}
}

View File

@ -28,7 +28,7 @@ public class BuildPanelManager {
private static final MainBorderPane MAIN_BORDER_PANE = MainBorderPane.getInstance();
private static boolean isShow = false;
private boolean isShow = false;
/**
* 控制终端显示

View File

@ -157,4 +157,82 @@ public class CenterTabPaneManager {
});
CACHE_MANAGER.addCache(CACHE_MANAGER.createCache("tabs", "centerTabs", filePaths, CacheExpirationTime.NEVER_EXPIRES.getValue()));
}
/**
* Removes the specified CenterTab from the Tabs.
*
* @param tab the CenterTab to be removed
*/
public void removeTab(CenterTab tab) {
centerTabPane.getTabs().remove(tab);
}
/**
* Removes all tabs from the center tab pane.
*/
public void removeAllTabs() {
centerTabPane.getTabs().clear();
}
/**
* 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
*/
public void removeOtherTabs(CenterTab centerTab) {
centerTabPane.getTabs().removeIf(tab -> !centerTab.equals(tab));
}
/**
* This function removes the left tabs from the given CenterTab object.
*
* @param centerTab the CenterTab object from which to remove the left tabs
*/
public void removeLeftTabs(CenterTab centerTab) {
ObservableList<Tab> tabs = centerTabPane.getTabs();
tabs.remove(0, tabs.indexOf(centerTab));
}
/**
* Removes all tabs to the right of the specified center tab.
*
* @param centerTab the center tab to remove right tabs from
*/
public void removeRightTabs(CenterTab centerTab) {
ObservableList<Tab> tabs = centerTabPane.getTabs();
tabs.remove(tabs.indexOf(centerTab), tabs.size());
}
/**
* 判断是否有其它标签页
*
* @return 是否有其它标签页
*/
public boolean hasOtherTabs() {
return centerTabPane.getTabs().size() > 1;
}
/**
* 判断是否有左侧标签页
*
* @param centerTab 标签页
* @return 是否有左侧标签页
*/
public boolean hasLeftTabs(CenterTab centerTab) {
int index = centerTabPane.getTabs().indexOf(centerTab);
return index > 0;
}
/**
* 判断是否有右侧标签页
*
* @param centerTab 标签页
* @return 是否有右侧标签页
*/
public boolean hasRightTabs(CenterTab centerTab) {
ObservableList<Tab> tabs = centerTabPane.getTabs();
int index = tabs.indexOf(centerTab);
return index != tabs.size() - 1;
}
}

View File

@ -19,7 +19,9 @@ public class MainBorderPaneManager {
private static final MainBorderPane MAIN_BORDER_PANE = MainBorderPane.getInstance();
private static final DirectorySidebarPane DIRECTORY_SIDEBAR_PANE = DirectorySidebarPane.getInstance();
// 默认分割条位置
/**
* 默认分割条位置
*/
private static final double TOP_SPLIT_PANEL_DEFAULT_DIVIDER_POSITIONS = 0.3;
private MainBorderPaneManager() {

View File

@ -27,7 +27,7 @@ public class RootManager {
/**
* 主布局
*/
private BorderPane root;
private final BorderPane root;
/**
* 私有构造函数设置场景和根布局

View File

@ -2,8 +2,13 @@ package org.jcnc.jnotepad.views.root.center.main.center.tab;
import javafx.scene.control.Tab;
import org.fxmisc.flowless.VirtualizedScrollPane;
import org.jcnc.jnotepad.api.core.views.menu.builder.ContextMenuBuilder;
import org.jcnc.jnotepad.api.core.views.menu.builder.MenuBuilder;
import org.jcnc.jnotepad.component.module.TextCodeArea;
import org.jcnc.jnotepad.controller.config.UserConfigController;
import org.jcnc.jnotepad.controller.event.handler.menuitem.RenameFile;
import org.jcnc.jnotepad.controller.event.handler.menuitem.SaveFile;
import org.jcnc.jnotepad.util.ClipboardUtil;
import org.jcnc.jnotepad.util.LogUtil;
import org.jcnc.jnotepad.views.manager.BottomStatusBoxManager;
import org.jcnc.jnotepad.views.manager.CenterTabPaneManager;
@ -17,7 +22,7 @@ import java.nio.charset.Charset;
/**
* 封装标签页组件增加属于标签页的属性例如自动换行开关
* 每个Tab关联一个LineNumberTextArea
* 每个Tab关联一个TextCodeArea
*
* @author songdragon
*/
@ -53,6 +58,7 @@ public class CenterTab extends Tab {
this.setContent(new VirtualizedScrollPane<>(textCodeArea));
setAutoLine(UserConfigController.getInstance().getAutoLineConfig());
this.charset = charset;
contextMenuMonitor();
}
public boolean isRelevance() {
@ -84,6 +90,54 @@ public class CenterTab extends Tab {
this.charset = charset;
}
public void contextMenuMonitor() {
ContextMenuBuilder builder = new ContextMenuBuilder();
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 -> {
})
.addMenuItem("终端", e -> {
})
.build())
.build());
}
/**
* 保存选中的文件标签页
*/
@ -131,6 +185,7 @@ public class CenterTab extends Tab {
saveSelectedFileTab();
});
}
/**
* 保存为指定文件
*

View File

@ -19,7 +19,7 @@ import static org.jcnc.jnotepad.common.constants.TextConstants.DE_BUG;
import static org.jcnc.jnotepad.common.constants.TextConstants.RUN;
/**
* 文件菜单
* 运行菜单
*
* @author gewuyou
*/
@ -139,7 +139,6 @@ public class RunTopMenu extends AbstractTopMenu {
// 运行
registerMenuItem(topMenuBar.getRunItem(), RUN, "runItem", codeRun);
// 调试 test
registerMenuItem(topMenuBar.getDeBugItem(), DE_BUG, "deBugItem", event -> {
BUILD_PANEL_MANAGER.controlShow(true);