Merge branch 'release-v1.1.14' of https://gitee.com/jcnc-org/JNotepad into develop

# Conflicts:
#	src/main/java/org/jcnc/jnotepad/views/root/top/menubar/menu/RunTopMenu.java
This commit is contained in:
gewuyou 2023-10-07 09:47:42 +08:00
commit d9aaa17551
21 changed files with 288 additions and 90 deletions

1
.gitignore vendored
View File

@ -55,3 +55,4 @@ logs/
/jnotepadConfig.json /jnotepadConfig.json
/qodana.yaml /qodana.yaml
.mvn/ .mvn/
/main.c

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

After

Width:  |  Height:  |  Size: 81 KiB

View File

@ -47,5 +47,6 @@ module org.jcnc.jnotepad {
exports org.jcnc.jnotepad.component.module.hbox; exports org.jcnc.jnotepad.component.module.hbox;
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;
} }

View File

@ -0,0 +1,25 @@
package org.jcnc.jnotepad.common.constants;
/**
* SplitPane常量类
* *
* <p>用于记录SplitPane中子组件的索引</p>
*
* @author cccqyu
*/
public class SplitPaneItemConstants {
// rootSplitPane
// 上部
public static final int ROOT_SPLIT_PANE_TOP_SPLIT_PANE = 0;
// 底部
public static final int ROOT_SPLIT_PANE_CMDBox = 1;
// rootSplitPane中的上部面板
// 左侧
public static final int TOP_SPLIT_PANE_DIRECTORY_SIDEBAR_PANE = 0;
// 右侧
public static final int TOP_SPLIT_PANE_CENTER_TAB_PANE = 1;
}

View File

@ -12,6 +12,9 @@ public class TextConstants {
public static final String SAVE = "SAVE"; public static final String SAVE = "SAVE";
public static final String FILE = "FILE"; public static final String FILE = "FILE";
public static final String BUILD = "BUILD";
public static final String TERMINAL = "TERMINAL";
public static final String RUN = "RUN"; public static final String RUN = "RUN";
public static final String DE_BUG = "DE_BUG"; public static final String DE_BUG = "DE_BUG";
public static final String NEW = "NEW"; public static final String NEW = "NEW";

View File

@ -0,0 +1,58 @@
package org.jcnc.jnotepad.component.module.vbox;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import org.jcnc.jnotepad.component.module.vbox.components.CmdTerminalBox;
import org.jcnc.jnotepad.component.module.vbox.components.DebugBox;
import org.jcnc.jnotepad.component.module.vbox.components.RunBox;
/**
* 底部Run,Debug,Cmd面板
*
*
* @author cccqyu
*/
public class BuildPanel extends TabPane {
private static BuildPanel instance = null;
public static BuildPanel getInstance() {
if (instance == null) {
instance = new BuildPanel();
}
return instance;
}
private final CmdTerminalBox cmdTerminalBox;
private final RunBox runBox;
private final DebugBox debugBox;
private BuildPanel() {
cmdTerminalBox = new CmdTerminalBox();
runBox = new RunBox();
debugBox = new DebugBox();
Tab runTab = new Tab("运行",runBox);
runTab.setClosable(false);
Tab buildTab = new Tab("构建", debugBox);
buildTab.setClosable(false);
Tab cmdTab = new Tab("终端",cmdTerminalBox);
cmdTab.setClosable(false);
this.getTabs().addAll(runTab,buildTab,cmdTab);
}
public CmdTerminalBox getCmdTerminalBox() {
return cmdTerminalBox;
}
public RunBox getRunBox() {
return runBox;
}
public DebugBox getBuildBox() {
return debugBox;
}
}

View File

@ -1,4 +1,4 @@
package org.jcnc.jnotepad.component.module.vbox; package org.jcnc.jnotepad.component.module.vbox.components;
import javafx.animation.KeyFrame; import javafx.animation.KeyFrame;
import javafx.animation.Timeline; import javafx.animation.Timeline;

View File

@ -0,0 +1,20 @@
package org.jcnc.jnotepad.component.module.vbox.components;
import org.jcnc.jnotepad.component.module.TextCodeArea;
/**
* Debug终端界面
*
*
* @author cccqyu
*/
public class DebugBox extends TextCodeArea {
public DebugBox() {
super();
this.setEditable(false);
}
public void setText(String text) {
this.appendText(text);
}
}

View File

@ -0,0 +1,23 @@
package org.jcnc.jnotepad.component.module.vbox.components;
import org.jcnc.jnotepad.component.module.TextCodeArea;
/**
* Run终端界面
*
*
* @author cccqyu
*/
public class RunBox extends TextCodeArea {
public RunBox() {
super();
this.setEditable(false);
}
public void setText(String text) {
this.appendText(text);
}
}

View File

@ -3,15 +3,20 @@ package org.jcnc.jnotepad.controller.event.handler.toolbar;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.event.EventHandler; import javafx.event.EventHandler;
import org.jcnc.jnotepad.views.manager.BuildPanelManager;
/** /**
* @author luke * 终端处理器
*
*
* @author cccqyu
*/ */
public class RunBtn implements EventHandler<ActionEvent> { public class RunBtn implements EventHandler<ActionEvent> {
@Override private static final BuildPanelManager BUILD_PANEL_MANAGER = BuildPanelManager.getInstance();
public void handle(ActionEvent actionEvent) {
// TODO: 2023/10/6 点击按钮,打开下方侧边栏的运行输出栏
@Override
public void handle(ActionEvent event) {
BUILD_PANEL_MANAGER.controlShow();
} }
} }

View File

@ -0,0 +1,68 @@
package org.jcnc.jnotepad.views.manager;
import javafx.scene.control.SplitPane;
import org.jcnc.jnotepad.component.module.TextCodeArea;
import org.jcnc.jnotepad.views.root.center.main.MainBorderPane;
/**
* 构建底部三大菜单管理类
*
* <p>管理构建三大菜单操作</p>
*
* @author cccqyu
*/
public class BuildPanelManager {
private BuildPanelManager() {
}
/**
* 单例模式保证只有一个 BuildPanelManager 实例
*/
private static final BuildPanelManager INSTANCE = new BuildPanelManager();
public static BuildPanelManager getInstance() {
return INSTANCE;
}
private static final MainBorderPane MAIN_BORDER_PANE = MainBorderPane.getInstance();
private static boolean isShow = false;
/**
* 控制终端显示
*/
public void controlShow() {
// 获取root分割面板
SplitPane root = (SplitPane) MAIN_BORDER_PANE.getCenter();
if (isShow) {
root.setDividerPositions(1);
} else {
// 展开分割条文件树
root.setDividerPositions(0.7);
}
isShow = !isShow;
}
public void controlShow(boolean bool) {
// 获取root分割面板
SplitPane root = (SplitPane) MAIN_BORDER_PANE.getCenter();
if (!bool) {
root.setDividerPositions(1);
} else {
// 展开分割条文件树
root.setDividerPositions(0.7);
}
isShow = !isShow;
}
public void setText(TextCodeArea textCodeArea, String text) {
textCodeArea.appendText(text);
}
}

View File

@ -3,6 +3,7 @@ package org.jcnc.jnotepad.views.manager;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.scene.control.SplitPane; import javafx.scene.control.SplitPane;
import javafx.scene.control.TreeItem; import javafx.scene.control.TreeItem;
import org.jcnc.jnotepad.common.constants.SplitPaneItemConstants;
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager; import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
import org.jcnc.jnotepad.controller.event.handler.toolbar.OpenDirectory; import org.jcnc.jnotepad.controller.event.handler.toolbar.OpenDirectory;
import org.jcnc.jnotepad.model.entity.DirFileModel; import org.jcnc.jnotepad.model.entity.DirFileModel;
@ -44,26 +45,25 @@ public class DirectorySidebarManager {
private static final double LAST_DIVIDER_POSITION = 0.3; private static final double LAST_DIVIDER_POSITION = 0.3;
private static boolean isShow = false;
/** /**
* 控制文件树显示 * 控制文件树显示
*/ */
public void controlShow() { public void controlShow() {
// 获取分割面板 // 获取root分割面板
SplitPane center = (SplitPane) MAIN_BORDER_PANE.getCenter(); SplitPane root = (SplitPane) MAIN_BORDER_PANE.getCenter();
// 获取分割条位置
double dividerPosition = center.getDividerPositions()[0];
// 保留分割条位置一位小数
String formattedNumber = String.format("%.1f", dividerPosition);
double roundedNumber = Double.parseDouble(formattedNumber);
// 分割条位置不等于 代表展开 // 获取root的上部分割面板
if (Double.compare(roundedNumber, 0.0) != 0) { SplitPane topSplitPane = (SplitPane) root.getItems().get(SplitPaneItemConstants.ROOT_SPLIT_PANE_TOP_SPLIT_PANE);
// 收缩分割条 收缩文件树
center.setDividerPositions(0.0); if (isShow) {
topSplitPane.setDividerPositions(0);
} else { } else {
// 展开分割条文件树 // 展开分割条文件树
center.setDividerPositions(LAST_DIVIDER_POSITION); topSplitPane.setDividerPositions(LAST_DIVIDER_POSITION);
} }
isShow = !isShow;
} }
/** /**
@ -74,10 +74,13 @@ public class DirectorySidebarManager {
public void controlShow(boolean bool) { public void controlShow(boolean bool) {
if (bool) { if (bool) {
// 获取分割面板 // 获取分割面板
SplitPane center = (SplitPane) MAIN_BORDER_PANE.getCenter(); SplitPane root = (SplitPane) MAIN_BORDER_PANE.getCenter();
center.setDividerPositions(LAST_DIVIDER_POSITION); // 获取root的上部分割面板
} SplitPane topSplitPane = (SplitPane) root.getItems().get(SplitPaneItemConstants.ROOT_SPLIT_PANE_TOP_SPLIT_PANE);
topSplitPane.setDividerPositions(LAST_DIVIDER_POSITION);
isShow = true;
}
} }
/** /**

View File

@ -1,6 +1,9 @@
package org.jcnc.jnotepad.views.manager; package org.jcnc.jnotepad.views.manager;
import javafx.geometry.Orientation;
import javafx.scene.control.SplitPane; import javafx.scene.control.SplitPane;
import org.jcnc.jnotepad.common.constants.SplitPaneItemConstants;
import org.jcnc.jnotepad.component.module.vbox.BuildPanel;
import org.jcnc.jnotepad.views.root.center.main.MainBorderPane; import org.jcnc.jnotepad.views.root.center.main.MainBorderPane;
import org.jcnc.jnotepad.views.root.center.main.center.directory.DirectorySidebarPane; import org.jcnc.jnotepad.views.root.center.main.center.directory.DirectorySidebarPane;
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTabPane; import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTabPane;
@ -17,7 +20,8 @@ public class MainBorderPaneManager {
private static final DirectorySidebarPane DIRECTORY_SIDEBAR_PANE = DirectorySidebarPane.getInstance(); private static final DirectorySidebarPane DIRECTORY_SIDEBAR_PANE = DirectorySidebarPane.getInstance();
// 默认分割条位置 // 默认分割条位置
private static final double defaultDividerPositions = 0.3; private static final double TOP_SPLIT_PANEL_DEFAULT_DIVIDER_POSITIONS = 0.3;
private MainBorderPaneManager() { private MainBorderPaneManager() {
} }
@ -27,13 +31,30 @@ public class MainBorderPaneManager {
} }
public void initMainBorderPane() { public void initMainBorderPane() {
// 文件树和文本框的布局 // 总分割面板
SplitPane splitPane = new SplitPane(); SplitPane rootSplitPane = new SplitPane();
splitPane.getItems().add(0, DIRECTORY_SIDEBAR_PANE); // 设置上下布局
splitPane.getItems().add(1, CenterTabPane.getInstance()); rootSplitPane.setOrientation(Orientation.VERTICAL);
splitPane.setDividerPositions(defaultDividerPositions); rootSplitPane.setDividerPositions(1);
// 上部面板
// 文件树和文本框的布局
SplitPane topSplitPane = new SplitPane();
topSplitPane.getItems().add(SplitPaneItemConstants.TOP_SPLIT_PANE_DIRECTORY_SIDEBAR_PANE, DIRECTORY_SIDEBAR_PANE);
topSplitPane.getItems().add(SplitPaneItemConstants.TOP_SPLIT_PANE_CENTER_TAB_PANE, CenterTabPane.getInstance());
topSplitPane.setDividerPositions(TOP_SPLIT_PANEL_DEFAULT_DIVIDER_POSITIONS);
// 下部
// 构建三大菜单
BuildPanel buildPanel = BuildPanel.getInstance();
rootSplitPane.getItems().add(SplitPaneItemConstants.ROOT_SPLIT_PANE_TOP_SPLIT_PANE, topSplitPane);
rootSplitPane.getItems().add(SplitPaneItemConstants.ROOT_SPLIT_PANE_CMDBox, buildPanel);
// 将总分割面板设置在布局中部
MAIN_BORDER_PANE.setCenterComponent(rootSplitPane);
// 将文件树以及文本框设置在布局中部
MAIN_BORDER_PANE.setCenterComponent(splitPane);
} }
} }

View File

@ -54,10 +54,13 @@ public class SidebarToolBarManager extends AbstractManager<Node> {
.setImageViewEssentialAttribute(10D, 10D, true, 2.5D, 2.5D) .setImageViewEssentialAttribute(10D, 10D, true, 2.5D, 2.5D)
.setButtonEssentialAttribute(20D, 20D) .setButtonEssentialAttribute(20D, 20D)
.setEventHandler(new DirTreeBtn()).build()); .setEventHandler(new DirTreeBtn()).build());
// Cmd 按钮
registerNode( registerNode(
new SideBarButtonBuilder() new SideBarButtonBuilder()
.setButton(sidebarToolBar.getRunButton()) .setButton(sidebarToolBar.getRunButton())
.setImageView(new ImageView(new Image("directory.png"))) .setImageView(new ImageView(new Image("cmd.png")))
.setImageViewEssentialAttribute(10D, 10D, true, 2.5D, 2.5D) .setImageViewEssentialAttribute(10D, 10D, true, 2.5D, 2.5D)
.setButtonEssentialAttribute(20D, 20D) .setButtonEssentialAttribute(20D, 20D)
.setEventHandler(new RunBtn()).build()); .setEventHandler(new RunBtn()).build());

View File

@ -1,5 +1,6 @@
package org.jcnc.jnotepad.views.root.left.sidebar.tools; package org.jcnc.jnotepad.views.root.left.sidebar.tools;
import javafx.geometry.Insets;
import javafx.geometry.Orientation; import javafx.geometry.Orientation;
import javafx.scene.control.Button; import javafx.scene.control.Button;
@ -37,6 +38,7 @@ public class SidebarToolBar extends javafx.scene.control.ToolBar {
private SidebarToolBar() { private SidebarToolBar() {
// 垂直排列 // 垂直排列
this.setOrientation(Orientation.VERTICAL); this.setOrientation(Orientation.VERTICAL);
this.setPadding(new Insets(1,5,0,0));
this.setOnMouseClicked(event -> { this.setOnMouseClicked(event -> {
// SidebarToolBar 点击事件 // SidebarToolBar 点击事件
}); });

View File

@ -1,39 +0,0 @@
package org.jcnc.jnotepad.views.root.left.sidebar.tools;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import org.jcnc.jnotepad.component.module.base.AbstractHorizontalBox;
/**
* ToolHBox JNotepad 应用程序的工具栏水平布局类
*
* <p>该类继承自 JavaFX HBox 用于将工具栏放置在水平布局中</p>
*
* <p>工具栏水平布局中包含一个 JNotepadToolBar 的单例实例并设置其子节点水平拉伸属性以确保工具栏在水平方向上充分占用空间</p>
*
* @author luke
*/
public class ToolHorizontalBox extends AbstractHorizontalBox {
/**
* 单例模式保证只有一个 ToolHBox 实例
*/
private static final ToolHorizontalBox INSTANCE = new ToolHorizontalBox();
private ToolHorizontalBox() {
// 设置子节点水平拉伸
HBox.setHgrow(SidebarToolBar.getInstance(), Priority.ALWAYS);
// JNotepadToolBar 添加为子节点
getChildren().add(SidebarToolBar.getInstance());
getStyleClass().add("tool-horizontal-box");
}
/**
* 获取 ToolHBox 的单例实例
*
* @return ToolHBox 的单例实例
*/
public static ToolHorizontalBox getInstance() {
return INSTANCE;
}
}

View File

@ -4,9 +4,10 @@ import javafx.event.ActionEvent;
import javafx.event.EventHandler; import javafx.event.EventHandler;
import javafx.scene.control.Menu; import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem; import javafx.scene.control.MenuItem;
import javafx.scene.control.TextArea;
import org.jcnc.jnotepad.api.core.views.top.menu.AbstractTopMenu; import org.jcnc.jnotepad.api.core.views.top.menu.AbstractTopMenu;
import org.jcnc.jnotepad.component.module.vbox.BuildPanel;
import org.jcnc.jnotepad.util.LogUtil; import org.jcnc.jnotepad.util.LogUtil;
import org.jcnc.jnotepad.views.manager.BuildPanelManager;
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.CenterTab;
@ -23,7 +24,8 @@ import static org.jcnc.jnotepad.common.constants.TextConstants.RUN;
* @author gewuyou * @author gewuyou
*/ */
public class RunTopMenu extends AbstractTopMenu { public class RunTopMenu extends AbstractTopMenu {
CenterTab centerTab = CenterTabPaneManager.getInstance().getSelected(); private static final BuildPanelManager BUILD_PANEL_MANAGER = BuildPanelManager.getInstance();
private static final BuildPanel BUILD_PANEL = BuildPanel.getInstance();
private static final RunTopMenu INSTANCE = new RunTopMenu(); private static final RunTopMenu INSTANCE = new RunTopMenu();
private final Map<String, MenuItem> runMenuItems = new HashMap<>(); private final Map<String, MenuItem> runMenuItems = new HashMap<>();
@ -62,21 +64,13 @@ public class RunTopMenu extends AbstractTopMenu {
} }
EventHandler<ActionEvent> codeRun = event -> { EventHandler<ActionEvent> codeRun = event -> {
// 创建一个TextArea用于输出编译后的结果
TextArea resultTextArea = new TextArea();
resultTextArea.setPrefRowCount(10);
resultTextArea.setPrefColumnCount(40);
resultTextArea.setEditable(false); // 禁止编辑
// 获取TextCodeArea的文本内容 // 获取TextCodeArea的文本内容
CenterTab centerTab = CenterTabPaneManager.getInstance().getSelected(); CenterTab centerTab = CenterTabPaneManager.getInstance().getSelected();
String code = centerTab.getTextCodeArea().getText();
// TextCodeArea的当前文本内容 String code = centerTab.getLineNumberTextArea().getText();
System.out.println("TextCodeArea的当前文本内容" + code);
String fileName = "temp.c"; String fileName = centerTab.getText();
// 将C代码写入临时文件 // 将C代码写入临时文件
try (PrintWriter writer = new PrintWriter(new FileWriter(fileName))) { try (PrintWriter writer = new PrintWriter(new FileWriter(fileName))) {
@ -85,17 +79,18 @@ public class RunTopMenu extends AbstractTopMenu {
LogUtil.getLogger(this.getClass()).info("正在写入:{}", code); LogUtil.getLogger(this.getClass()).info("正在写入:{}", code);
} }
// 编译和运行C代码 // 编译C代码
compileAndRunCode(fileName, resultTextArea); compileAndRunCode(fileName);
}; };
/** /**
* 编译和运行C代码的方法 * 编译和运行C代码的方法
*/ */
private void compileAndRunCode(String fileName, TextArea resultTextArea) { private void compileAndRunCode(String fileName) {
try { try {
CenterTab centerTab = CenterTabPaneManager.getInstance().getSelected();
// 创建ProcessBuilder并指定GCC编译命令 // 创建ProcessBuilder并指定GCC编译命令
ProcessBuilder processBuilder = new ProcessBuilder("gcc", fileName, "-o", "temp"); ProcessBuilder processBuilder = new ProcessBuilder("gcc", fileName, "-o", centerTab.getText());
// 设置工作目录 // 设置工作目录
processBuilder.directory(null); processBuilder.directory(null);
@ -116,7 +111,7 @@ public class RunTopMenu extends AbstractTopMenu {
System.out.println("编译成功!"); System.out.println("编译成功!");
// 运行编译后的可执行文件 // 运行编译后的可执行文件
Process runProcess = new ProcessBuilder("./temp").start(); Process runProcess = new ProcessBuilder("./" + centerTab.getText()).start();
// 读取运行结果 // 读取运行结果
BufferedReader runReader = new BufferedReader(new InputStreamReader(runProcess.getInputStream())); BufferedReader runReader = new BufferedReader(new InputStreamReader(runProcess.getInputStream()));
@ -124,14 +119,14 @@ public class RunTopMenu extends AbstractTopMenu {
while ((line = runReader.readLine()) != null) { while ((line = runReader.readLine()) != null) {
result.append(line).append("\n"); result.append(line).append("\n");
} }
// 显示运行结果 // 显示运行结果
resultTextArea.setText(result.toString()); BUILD_PANEL_MANAGER.controlShow(true);
BUILD_PANEL_MANAGER.setText(BUILD_PANEL.getRunBox(), result.toString());
} else { } else {
System.out.println("编译失败,返回代码:" + compileExitCode); System.out.println("编译失败,返回代码:" + compileExitCode);
} }
} catch (IOException | InterruptedException e) { } catch (IOException | InterruptedException e) {
e.printStackTrace(); LogUtil.getLogger(this.getClass()).info("编译失败:{}", fileName);
} }
} }
@ -145,8 +140,11 @@ public class RunTopMenu extends AbstractTopMenu {
registerMenuItem(topMenuBar.getRunItem(), RUN, "runItem", codeRun); registerMenuItem(topMenuBar.getRunItem(), RUN, "runItem", codeRun);
// 调试 // 调试 test
registerMenuItem(topMenuBar.getDeBugItem(), DE_BUG, "deBugItem", null); registerMenuItem(topMenuBar.getDeBugItem(), DE_BUG, "deBugItem", event -> {
BUILD_PANEL_MANAGER.controlShow(true);
BUILD_PANEL_MANAGER.setText(BUILD_PANEL.getBuildBox(), "待开发");
});
} }

BIN
src/main/resources/cmd.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

View File

@ -10,6 +10,8 @@ CHINESE=中文
title=JNotepad title=JNotepad
OPEN=打开 OPEN=打开
OPEN_DIRECTORY=打开文件夹 OPEN_DIRECTORY=打开文件夹
BUILD=构建
TERMINAL=控制台
ABOUT=关于 ABOUT=关于
DEVELOPER=开发者 DEVELOPER=开发者
HELP=帮助 HELP=帮助

View File

@ -14,6 +14,8 @@ OPEN=Open
OPEN_DIRECTORY=Open Directory OPEN_DIRECTORY=Open Directory
HELP=Help HELP=Help
RUN=Run RUN=Run
BUILD=Build
TERMINAL=Terminal
DE_BUG=Debug DE_BUG=Debug
OPEN_CONFIGURATION_FILE=Open Configuration File OPEN_CONFIGURATION_FILE=Open Configuration File
RENAME=Rename RENAME=Rename

View File

@ -13,6 +13,8 @@ OPEN_DIRECTORY=打开文件夹
HELP=帮助 HELP=帮助
RUN=运行 RUN=运行
DE_BUG=调试 DE_BUG=调试
BUILD=构建
TERMINAL=控制台
ABOUT=关于 ABOUT=关于
DEVELOPER=开发者 DEVELOPER=开发者
OPEN_CONFIGURATION_FILE=打开配置文件 OPEN_CONFIGURATION_FILE=打开配置文件