👔 完善标签页右键菜单的图标支持

This commit is contained in:
gewuyou 2023-10-09 18:50:35 +08:00
parent 249333b961
commit 6fee8fe4ee
8 changed files with 150 additions and 48 deletions

View File

@ -0,0 +1,46 @@
package org.jcnc.jnotepad.api.core.views.manager.builder;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Button;
import org.kordamp.ikonli.javafx.FontIcon;
import java.util.Optional;
/**
* 下方状态栏按钮建造者
*
* @author gewuyou
*/
public class BottomStatusBoxButtonBuilder {
private Button button;
private FontIcon fontIcon;
private EventHandler<ActionEvent> eventHandler;
public BottomStatusBoxButtonBuilder() {
}
public BottomStatusBoxButtonBuilder(Button button) {
this.button = button;
}
public BottomStatusBoxButtonBuilder setFontIcon(FontIcon fontIcon) {
this.fontIcon = fontIcon;
return this;
}
public BottomStatusBoxButtonBuilder setEventHandler(EventHandler<ActionEvent> eventHandler) {
this.eventHandler = eventHandler;
return this;
}
public Button build() {
Optional<Button> container = Optional.ofNullable(button);
button = container.orElseGet(Button::new);
button.setGraphic(fontIcon);
button.setOnAction(eventHandler);
return button;
}
}

View File

@ -58,7 +58,7 @@ public abstract class AbstractMenuBuilder<B, T> {
} }
/** /**
* 添加单选菜单项 todo 待完善 * 添加单选菜单项
* *
* @param label 菜单项名称 * @param label 菜单项名称
* @param eventHandler 事件 * @param eventHandler 事件

View File

@ -160,7 +160,6 @@ public class SetStage {
securityItem.getChildren().add(securityItem2); securityItem.getChildren().add(securityItem2);
root.getChildren().add(generalItem); root.getChildren().add(generalItem);
root.getChildren().add(appearanceItem); root.getChildren().add(appearanceItem);
root.getChildren().add(securityItem); root.getChildren().add(securityItem);
@ -203,7 +202,6 @@ public class SetStage {
} }
/** /**
* 创建常规设置项1的布局 * 创建常规设置项1的布局
* *
@ -225,12 +223,11 @@ public class SetStage {
var fileChooseBtn = new Button(); var fileChooseBtn = new Button();
fileChooseBtn.setText("选择文件夹"); fileChooseBtn.setText("选择文件夹");
fileChooseBtn.getStyleClass().addAll(Styles.SMALL); fileChooseBtn.getStyleClass().addAll(Styles.SMALL);
BasicDirectoryChooserFactory directoryChooserFactory = BasicDirectoryChooserFactory.getInstance();
fileChooseBtn.setOnAction(event -> { fileChooseBtn.setOnAction(event -> {
// 获取打开目录缓存 // 获取打开目录缓存
Cache cache = cacheManager.getCache(OpenDirectory.GROUP, "openDirectory"); Cache cache = cacheManager.getCache(OpenDirectory.GROUP, "openDirectory");
File file = directoryChooserFactory.createDirectoryChooser( File file = BasicDirectoryChooserFactory.getInstance().createDirectoryChooser(
UiResourceBundle.getContent(TextConstants.OPEN), UiResourceBundle.getContent(TextConstants.OPEN),
cache == null ? null : new File((String) cache.getCacheData())) cache == null ? null : new File((String) cache.getCacheData()))
.showDialog(UiUtil.getAppWindow()); .showDialog(UiUtil.getAppWindow());

View File

@ -1,6 +1,5 @@
package org.jcnc.jnotepad.util; package org.jcnc.jnotepad.util;
import javafx.scene.control.CheckMenuItem;
import javafx.scene.control.Tab; import javafx.scene.control.Tab;
import javafx.scene.control.TextField; import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCode;
@ -40,7 +39,7 @@ import static org.jcnc.jnotepad.util.FileUtil.getFileText;
*/ */
public class TabUtil { public class TabUtil {
private static final ApplicationCacheManager CACHE_MANAGER = ApplicationCacheManager.getInstance(); private static final ApplicationCacheManager CACHE_MANAGER = ApplicationCacheManager.getInstance();
static Logger logger = LogUtil.getLogger(TabUtil.class); private static final Logger logger = LogUtil.getLogger(TabUtil.class);
private TabUtil() { private TabUtil() {
} }
@ -91,7 +90,9 @@ public class TabUtil {
.showSaveDialog(UiUtil.getAppWindow()); .showSaveDialog(UiUtil.getAppWindow());
if (file != null) { if (file != null) {
if (cache == null) { if (cache == null) {
CACHE_MANAGER.addCache(CACHE_MANAGER.createCache("folder", "saveFile", file.getParent(), CacheExpirationTime.NEVER_EXPIRES.getValue())); CACHE_MANAGER.addCache(
CACHE_MANAGER.createCache("folder", "saveFile", file.getParent(),
CacheExpirationTime.NEVER_EXPIRES.getValue()));
} else { } else {
cache.setCacheData(file.getParent()); cache.setCacheData(file.getParent());
CACHE_MANAGER.addCache(cache); CACHE_MANAGER.addCache(cache);
@ -202,9 +203,12 @@ public class TabUtil {
* 显示警告弹窗提示用户更换重复的名称 * 显示警告弹窗提示用户更换重复的名称
*/ */
private static void showDuplicateNameAlert(String newTabName) { private static void showDuplicateNameAlert(String newTabName) {
PopUpUtil.errorAlert(
PopUpUtil.errorAlert("重命名错误", "\" " + newTabName + "\" 和已有标签页名字重复", "请再次重命名", null, null); "重命名错误",
"\" " + newTabName + "\" 和已有标签页名字重复",
"请再次重命名",
null,
null);
} }
/** /**
@ -336,13 +340,17 @@ public class TabUtil {
//todo 设置上下文菜单 //todo 设置上下文菜单
tab.setContextMenu( tab.setContextMenu(
builder builder
.addMenuItem("关闭", e -> centerTabPaneManager.removeTab(tab)) .addMenuItem(
"关闭",
e -> centerTabPaneManager.removeTab(tab))
.addMenuItem( .addMenuItem(
"关闭其它标签页", "关闭其它标签页",
e -> centerTabPaneManager.removeOtherTabs(tab), e -> centerTabPaneManager.removeOtherTabs(tab),
centerTabPaneManager.hasOtherTabs() centerTabPaneManager.hasOtherTabs()
) )
.addMenuItem("关闭所有标签页", e -> centerTabPaneManager.removeAllTabs()) .addMenuItem(
"关闭所有标签页",
e -> centerTabPaneManager.removeAllTabs())
.addMenuItem( .addMenuItem(
"关闭左侧标签页", "关闭左侧标签页",
e -> centerTabPaneManager.removeLeftTabs(tab), e -> centerTabPaneManager.removeLeftTabs(tab),
@ -386,9 +394,19 @@ public class TabUtil {
}) })
.build(), tab.isRelevance()) .build(), tab.isRelevance())
.addSeparatorMenuItem() .addSeparatorMenuItem()
.addCheckMenuItem("固定标签页", e -> centerTabPaneManager.updateTabPinnedState(tab, (CheckMenuItem) e.getSource())) .addMenuItem("固定标签页",
e -> centerTabPaneManager.updateTabPinnedState(tab),
!tab.isFixed())
.addMenuItem("取消固定",
e -> centerTabPaneManager.updateTabPinnedState(tab),
tab.isFixed())
.addSeparatorMenuItem() .addSeparatorMenuItem()
.addCheckMenuItem("只读", e -> centerTabPaneManager.updateReadOnlyProperty(tab, (CheckMenuItem) e.getSource())) .addMenuItem("只读",
e -> centerTabPaneManager.updateReadOnlyProperty(tab),
tab.getTextCodeArea().isEditable())
.addMenuItem("取消只读",
e -> centerTabPaneManager.updateReadOnlyProperty(tab),
!tab.getTextCodeArea().isEditable())
.build()); .build());
} }
} }

View File

@ -1,18 +1,27 @@
package org.jcnc.jnotepad.views.manager; package org.jcnc.jnotepad.views.manager;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.collections.ObservableList;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.geometry.Pos; import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import org.jcnc.jnotepad.api.core.views.manager.builder.BottomStatusBoxButtonBuilder;
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.component.module.TextCodeArea; import org.jcnc.jnotepad.component.module.TextCodeArea;
import org.jcnc.jnotepad.views.root.bottom.status.BottomStatusBox; import org.jcnc.jnotepad.views.root.bottom.status.BottomStatusBox;
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTab; import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTab;
import org.kordamp.ikonli.javafx.FontIcon;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import static org.kordamp.ikonli.antdesignicons.AntDesignIconsFilled.LOCK;
import static org.kordamp.ikonli.antdesignicons.AntDesignIconsFilled.UNLOCK;
/** /**
* 状态栏组件管理类 * 状态栏组件管理类
* *
@ -58,10 +67,9 @@ public class BottomStatusBoxManager {
*/ */
public void registerBottomStatusBox() { public void registerBottomStatusBox() {
Label statusLabel = BOTTOM_STATUS_BOX.getStatusLabel(); Label statusLabel = BOTTOM_STATUS_BOX.getStatusLabel();
registerChildrenByLabel(statusLabel); registerChildren(statusLabel);
statusLabel.setText(getStatusBarFormattedText(0, 0, 1)); statusLabel.setText(getStatusBarFormattedText(0, 0, 1));
registerChildren(BOTTOM_STATUS_BOX.getEncodingLabel());
registerChildrenByLabel(BOTTOM_STATUS_BOX.getEncodingLabel());
} }
/** /**
@ -73,13 +81,14 @@ public class BottomStatusBoxManager {
this.style = style; this.style = style;
} }
/** /**
* 注册状态栏标签组件 * Registers the given node as a child of the current node.
* *
* @param label 标签组件 * @param node the node to be registered as a child
*/ */
public void registerChildrenByLabel(Label label) { public void registerChildren(Node node) {
BOTTOM_STATUS_BOX.getChildren().add(label); BOTTOM_STATUS_BOX.getChildren().add(node);
} }
public void updateEncodingLabel() { public void updateEncodingLabel() {
@ -195,4 +204,35 @@ public class BottomStatusBoxManager {
String encodingLabelFormat = "%s : %s"; String encodingLabelFormat = "%s : %s";
return String.format(encodingLabelFormat, UiResourceBundle.getContent(TextConstants.ENCODE), encoding); return String.format(encodingLabelFormat, UiResourceBundle.getContent(TextConstants.ENCODE), encoding);
} }
public void updateReadOnlyProperty(CenterTab tab, ObservableList<Tab> tabs) {
ObservableList<Node> children = BOTTOM_STATUS_BOX.getChildren();
Button readOnlyButton = BOTTOM_STATUS_BOX.getReadOnlyButton();
BottomStatusBoxButtonBuilder builder = new BottomStatusBoxButtonBuilder(readOnlyButton);
if (tab.getTextCodeArea().isEditable()) {
FontIcon icon = FontIcon.of(LOCK);
if (children.contains(readOnlyButton)) {
readOnlyButton.setGraphic(icon);
} else {
registerChildren(builder
.setFontIcon(icon)
.setEventHandler(e -> CenterTabPaneManager.getInstance().updateReadOnlyProperty(tab))
.build());
}
} else {
FontIcon icon = FontIcon.of(UNLOCK);
if (children.contains(readOnlyButton)) {
readOnlyButton.setGraphic(icon);
} else {
registerChildren(builder
.setFontIcon(icon)
.setEventHandler(e -> CenterTabPaneManager.getInstance().updateReadOnlyProperty(tab))
.build());
}
}
if (tabs.isEmpty()) {
children.remove(readOnlyButton);
}
}
} }

View File

@ -2,7 +2,6 @@ package org.jcnc.jnotepad.views.manager;
import javafx.collections.ListChangeListener; import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.scene.control.CheckMenuItem;
import javafx.scene.control.Tab; import javafx.scene.control.Tab;
import javafx.stage.Stage; import javafx.stage.Stage;
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager; import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
@ -14,15 +13,12 @@ import org.jcnc.jnotepad.util.PopUpUtil;
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 org.kordamp.ikonli.javafx.FontIcon;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import static org.kordamp.ikonli.antdesignicons.AntDesignIconsFilled.PUSHPIN;
/** /**
* 中心标签页窗格管理类 * 中心标签页窗格管理类
* *
@ -276,7 +272,7 @@ public class CenterTabPaneManager {
* <blockquote><pre> * <blockquote><pre>
* public boolean hasRightTabs(CenterTab centerTab) { * public boolean hasRightTabs(CenterTab centerTab) {
* ObservableList<Tab> tabs = centerTabPane.getTabs(); * ObservableList<Tab> tabs = centerTabPane.getTabs();
* for (int i = tabs.indexOf(centerTab); i < tabs.size(); i++) { * for (int i = tabs.indexOf(centerTab)+1; i < tabs.size(); i++) {
* CenterTab tab = (CenterTab) tabs.get(i); * CenterTab tab = (CenterTab) tabs.get(i);
* if (!tab.isFixed()) { * if (!tab.isFixed()) {
* return true; * return true;
@ -298,7 +294,11 @@ public class CenterTabPaneManager {
* @param tab the tab to set the listener for * @param tab the tab to set the listener for
*/ */
public void setTabsListener(CenterTab tab) { public void setTabsListener(CenterTab tab) {
centerTabPane.getTabs().addListener((ListChangeListener<Tab>) c -> tab.contextMenuMonitor()); ObservableList<Tab> tabs = centerTabPane.getTabs();
tabs.addListener((ListChangeListener<Tab>) c -> {
tab.contextMenuMonitor();
BottomStatusBoxManager.getInstance().updateReadOnlyProperty(tab, centerTabPane.getTabs());
});
} }
/** /**
@ -306,27 +306,20 @@ public class CenterTabPaneManager {
* *
* @param tab the center tab to update * @param tab the center tab to update
*/ */
public void updateTabPinnedState(CenterTab tab, CheckMenuItem checkMenuItem) { public void updateTabPinnedState(CenterTab tab) {
tab.setFixed(!tab.isFixed()); tab.setFixed(!tab.isFixed());
if (tab.isFixed()) { tab.setClosable(!tab.isFixed());
FontIcon icon = FontIcon.of(PUSHPIN);
icon.setRotate(-45);
tab.setGraphic(icon);
} else {
tab.setGraphic(new FontIcon());
}
checkMenuItem.setSelected(tab.isFixed());
} }
/** /**
* Updates the read-only property of a given tab and its associated check menu item. * Updates the read-only property of a given tab and its associated check menu item.
* *
* @param tab the center tab to update * @param tab the center tab to update
* @param checkMenuItem the check menu item associated with the tab
*/ */
public void updateReadOnlyProperty(CenterTab tab, CheckMenuItem checkMenuItem) { public void updateReadOnlyProperty(CenterTab tab) {
TextCodeArea textCodeArea = tab.getTextCodeArea(); TextCodeArea textCodeArea = tab.getTextCodeArea();
textCodeArea.setEditable(!textCodeArea.isEditable()); textCodeArea.setEditable(!textCodeArea.isEditable());
checkMenuItem.setSelected(!textCodeArea.isEditable()); tab.contextMenuMonitor();
BottomStatusBoxManager.getInstance().updateReadOnlyProperty(tab, centerTabPane.getTabs());
} }
} }

View File

@ -1,5 +1,6 @@
package org.jcnc.jnotepad.views.root.bottom.status; package org.jcnc.jnotepad.views.root.bottom.status;
import javafx.scene.control.Button;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import org.jcnc.jnotepad.component.module.base.AbstractHorizontalBox; import org.jcnc.jnotepad.component.module.base.AbstractHorizontalBox;
@ -23,6 +24,11 @@ public class BottomStatusBox extends AbstractHorizontalBox {
*/ */
private final Label encodingLabel = new Label(); private final Label encodingLabel = new Label();
/**
* 只读按钮
*/
private final Button readOnlyButton = new Button();
private BottomStatusBox() { private BottomStatusBox() {
} }
@ -39,4 +45,8 @@ public class BottomStatusBox extends AbstractHorizontalBox {
public Label getEncodingLabel() { public Label getEncodingLabel() {
return encodingLabel; return encodingLabel;
} }
public Button getReadOnlyButton() {
return readOnlyButton;
}
} }

View File

@ -1,14 +1,11 @@
package org.jcnc.jnotepad.views.root.center.main.center.tab; package org.jcnc.jnotepad.views.root.center.main.center.tab;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.control.Tab; import javafx.scene.control.Tab;
import org.fxmisc.flowless.VirtualizedScrollPane; 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.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.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.util.LogUtil;
import org.jcnc.jnotepad.util.TabUtil; import org.jcnc.jnotepad.util.TabUtil;
import org.jcnc.jnotepad.views.manager.BottomStatusBoxManager; import org.jcnc.jnotepad.views.manager.BottomStatusBoxManager;
@ -42,7 +39,7 @@ public class CenterTab extends Tab {
/** /**
* 是否固定 * 是否固定
*/ */
private boolean isFixed = false; private final BooleanProperty isFixed = new SimpleBooleanProperty(false);
/** /**
* 关联文件上次修改时间 * 关联文件上次修改时间
*/ */
@ -66,6 +63,7 @@ public class CenterTab extends Tab {
this.charset = charset; this.charset = charset;
// 绑定标签页监听 // 绑定标签页监听
CenterTabPaneManager.getInstance().setTabsListener(this); CenterTabPaneManager.getInstance().setTabsListener(this);
isFixed.addListener((observable, oldValue, newValue) -> this.contextMenuMonitor());
} }
public boolean isRelevance() { public boolean isRelevance() {
@ -175,10 +173,10 @@ public class CenterTab extends Tab {
} }
public boolean isFixed() { public boolean isFixed() {
return isFixed; return isFixed.get();
} }
public void setFixed(boolean fixed) { public void setFixed(boolean fixed) {
isFixed = fixed; isFixed.set(fixed);
} }
} }