Merge branch 'master' of https://gitee.com/gewuyou/JNotepad
This commit is contained in:
commit
60f4f90f48
@ -7,12 +7,12 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
感谢对项目的支持与关注。在提出问题之前,请确保你已查看相关开发或使用文档:
|
感谢对项目的支持与关注。在提出问题之前,请确保你已查看相关开发或使用文档:
|
||||||
- https://...
|
- https://gitee.com/jcnc-org/docs
|
||||||
- type: checkboxes
|
- type: checkboxes
|
||||||
attributes:
|
attributes:
|
||||||
label: 这个问题是否已经存在?
|
label: 这个问题是否已经存在?
|
||||||
options:
|
options:
|
||||||
- label: 我已经搜索过现有的问题 (https://gitee.com/../../issues)
|
- label: 我已经搜索过现有的问题 (https://gitee.com/organizations/jcnc-org/issues)
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
@ -48,7 +48,7 @@ body:
|
|||||||
label: 版本
|
label: 版本
|
||||||
description: 你当前正在使用我们软件的哪个版本/分支?
|
description: 你当前正在使用我们软件的哪个版本/分支?
|
||||||
options:
|
options:
|
||||||
- 1.0.2 (默认)
|
- (默认)
|
||||||
- 1.0.3 (最新)
|
- (最新)
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -37,3 +37,6 @@ build/
|
|||||||
/src/main/JNotepad.java
|
/src/main/JNotepad.java
|
||||||
/.idea/
|
/.idea/
|
||||||
/project.txt
|
/project.txt
|
||||||
|
logs/
|
||||||
|
/ch_language_pack.txt
|
||||||
|
/en_language_pack.txt
|
||||||
|
|||||||
43
libs/README.md
Normal file
43
libs/README.md
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# 解决jlink error指南
|
||||||
|
|
||||||
|
## 现象
|
||||||
|
|
||||||
|
jlink时,如果出现如下错误,参考本文档
|
||||||
|
|
||||||
|
```
|
||||||
|
"automatic module cannot be used with jlink"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 解决方法:
|
||||||
|
|
||||||
|
1. 为jar生成module-info.class
|
||||||
|
|
||||||
|
```shell
|
||||||
|
jdeps --ignore-missing-deps --module-path <jar_dir_path> --add-modules <module_name --generate-module-info <out_dir_path> <jar_path>
|
||||||
|
javac --patch-module <module_name>=<jar_path> <module-info.java>
|
||||||
|
jar uf <jar_path> -C <module_name> <module-info.class>
|
||||||
|
```
|
||||||
|
|
||||||
|
以本次icu4j为例,先将依赖的jar包copy到libs目录,然后执行:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
jdeps --ignore-missing-deps --module-path libs --add-modules com.ibm.icu --generate-module-info libs/tmpOut libs/icu4j-73.2.jar
|
||||||
|
javac --patch-module com.ibm.icu=libs/icu4j-73.2.jar libs/tmpOut/com.ibm.icu/module-info.java
|
||||||
|
jar uf libs/icu4j-73.2.jar -C libs/tmpOut/com.ibm.icu module-info.class
|
||||||
|
```
|
||||||
|
|
||||||
|
2. pom中添加依赖
|
||||||
|
|
||||||
|
```xml
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.ibm.icu</groupId>
|
||||||
|
<artifactId>icu4j</artifactId>
|
||||||
|
<version>73.2</version>
|
||||||
|
<scope>system</scope>
|
||||||
|
<systemPath>${project.basedir}/libs/icu4j-73.2.jar</systemPath>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Reference
|
||||||
|
1. [java_jlink_automatic_module_cannot_be_used_with_jlink](https://tacosteemers.com/articles/java_jlink_automatic_module_cannot_be_used_with_jlink.html)
|
||||||
BIN
libs/icu4j-73.2.jar
Normal file
BIN
libs/icu4j-73.2.jar
Normal file
Binary file not shown.
7
pom.xml
7
pom.xml
@ -55,6 +55,13 @@
|
|||||||
<artifactId>logback-classic</artifactId>
|
<artifactId>logback-classic</artifactId>
|
||||||
<version>1.4.11</version>
|
<version>1.4.11</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.ibm.icu</groupId>
|
||||||
|
<artifactId>icu4j</artifactId>
|
||||||
|
<version>73.2</version>
|
||||||
|
<scope>system</scope>
|
||||||
|
<systemPath>${project.basedir}/libs/icu4j-73.2.jar</systemPath>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@ -9,6 +9,8 @@ module org.jcnc.jnotepad {
|
|||||||
requires org.slf4j;
|
requires org.slf4j;
|
||||||
requires ch.qos.logback.core;
|
requires ch.qos.logback.core;
|
||||||
requires ch.qos.logback.classic;
|
requires ch.qos.logback.classic;
|
||||||
|
requires com.ibm.icu;
|
||||||
|
|
||||||
exports org.jcnc.jnotepad;
|
exports org.jcnc.jnotepad;
|
||||||
exports org.jcnc.jnotepad.tool;
|
exports org.jcnc.jnotepad.tool;
|
||||||
exports org.jcnc.jnotepad.Interface;
|
exports org.jcnc.jnotepad.Interface;
|
||||||
|
|||||||
@ -1,12 +0,0 @@
|
|||||||
package org.jcnc.jnotepad.Interface;
|
|
||||||
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author 许轲
|
|
||||||
*/
|
|
||||||
public interface ConfigInterface {
|
|
||||||
void showErrorAlert();
|
|
||||||
Properties readPropertiesFromFile();
|
|
||||||
void initializePropertiesFile();
|
|
||||||
}
|
|
||||||
@ -1,7 +1,5 @@
|
|||||||
package org.jcnc.jnotepad.Interface;
|
package org.jcnc.jnotepad.Interface;
|
||||||
|
|
||||||
import javafx.event.ActionEvent;
|
|
||||||
import javafx.event.EventHandler;
|
|
||||||
import org.jcnc.jnotepad.ui.LineNumberTextArea;
|
import org.jcnc.jnotepad.ui.LineNumberTextArea;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -21,43 +19,6 @@ public interface ControllerInterface {
|
|||||||
*/
|
*/
|
||||||
LineNumberTextArea openAssociatedFileAndCreateTextArea(List<String> rawParameters);
|
LineNumberTextArea openAssociatedFileAndCreateTextArea(List<String> rawParameters);
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取新建文件处理事件处理程序
|
|
||||||
*
|
|
||||||
* @param textArea 文本区域
|
|
||||||
* @return 新建文件处理事件处理程序
|
|
||||||
*/
|
|
||||||
EventHandler<ActionEvent> getNewFileEventHandler(LineNumberTextArea textArea);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取打开文件处理事件处理程序
|
|
||||||
*
|
|
||||||
* @return 打开文件处理事件处理程序
|
|
||||||
*/
|
|
||||||
EventHandler<ActionEvent> getOpenFileEventHandler();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取另存为文件处理事件处理程序
|
|
||||||
*
|
|
||||||
* @return 另存为文件处理事件处理程序
|
|
||||||
*/
|
|
||||||
EventHandler<ActionEvent> getSaveAsFileEventHandler();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自动保存
|
|
||||||
*
|
|
||||||
* @param textArea 文本区域
|
|
||||||
*/
|
|
||||||
void autoSave(LineNumberTextArea textArea);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新状态标签
|
|
||||||
*
|
|
||||||
* @param textArea 文本区域
|
|
||||||
*/
|
|
||||||
void updateStatusLabel(LineNumberTextArea textArea);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 打开关联文件
|
* 打开关联文件
|
||||||
*
|
*
|
||||||
@ -72,36 +33,6 @@ public interface ControllerInterface {
|
|||||||
*/
|
*/
|
||||||
LineNumberTextArea getText(File file);
|
LineNumberTextArea getText(File file);
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新编码标签
|
|
||||||
*
|
|
||||||
* @param text 编码标签文本
|
|
||||||
*/
|
|
||||||
void upDateEncodingLabel(String text);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取光标所在行号
|
|
||||||
*
|
|
||||||
* @param caretPosition 光标位置
|
|
||||||
* @param text 文本内容
|
|
||||||
* @return 行号
|
|
||||||
*/
|
|
||||||
int getRow(int caretPosition, String text);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取光标所在列号
|
|
||||||
*
|
|
||||||
* @param caretPosition 光标位置
|
|
||||||
* @param text 文本内容
|
|
||||||
* @return 列号
|
|
||||||
*/
|
|
||||||
int getColumn(int caretPosition, String text);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化 TabPane
|
|
||||||
*/
|
|
||||||
void initTabPane();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新UI和标签页
|
* 更新UI和标签页
|
||||||
*
|
*
|
||||||
|
|||||||
@ -53,22 +53,12 @@ public class LunchApp extends Application {
|
|||||||
double length = AppConstants.SCREEN_LENGTH;
|
double length = AppConstants.SCREEN_LENGTH;
|
||||||
String icon = AppConstants.APP_ICON;
|
String icon = AppConstants.APP_ICON;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
scene = new Scene(root, width, length);
|
scene = new Scene(root, width, length);
|
||||||
Application.setUserAgentStylesheet(new PrimerLight().getUserAgentStylesheet());
|
Application.setUserAgentStylesheet(new PrimerLight().getUserAgentStylesheet());
|
||||||
scene.getStylesheets().add(Objects.requireNonNull(getClass().getResource("/css/styles.css")).toExternalForm());
|
scene.getStylesheets().add(Objects.requireNonNull(getClass().getResource("/css/styles.css")).toExternalForm());
|
||||||
|
|
||||||
primaryStage.setTitle(title);
|
|
||||||
primaryStage.setWidth(width);
|
|
||||||
primaryStage.setHeight(length);
|
|
||||||
primaryStage.setScene(scene);
|
|
||||||
primaryStage.getIcons().add(new Image(Objects.requireNonNull(getClass().getResource(icon)).toString()));
|
|
||||||
primaryStage.show();
|
|
||||||
ViewManager viewManager = ViewManager.getInstance(scene);
|
|
||||||
viewManager.initScreen(scene);
|
|
||||||
// 初始化菜单项和标签栏
|
|
||||||
view.initTabPane();
|
|
||||||
view.initShortcutKey();
|
|
||||||
|
|
||||||
// 使用线程池加载关联文件并创建文本区域
|
// 使用线程池加载关联文件并创建文本区域
|
||||||
List<String> rawParameters = getParameters().getRaw();
|
List<String> rawParameters = getParameters().getRaw();
|
||||||
THREAD_POOL.execute(() -> {
|
THREAD_POOL.execute(() -> {
|
||||||
@ -77,6 +67,18 @@ public class LunchApp extends Application {
|
|||||||
Platform.runLater(() -> controller.updateUiWithNewTextArea(textArea));
|
Platform.runLater(() -> controller.updateUiWithNewTextArea(textArea));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
primaryStage.setTitle(title);
|
||||||
|
primaryStage.setWidth(width);
|
||||||
|
primaryStage.setHeight(length);
|
||||||
|
primaryStage.setScene(scene);
|
||||||
|
primaryStage.getIcons().add(new Image(Objects.requireNonNull(getClass().getResource(icon)).toString()));
|
||||||
|
primaryStage.show();
|
||||||
|
ViewManager viewManager = ViewManager.getInstance(scene);
|
||||||
|
viewManager.initScreen(scene);
|
||||||
|
// 初始化快捷键
|
||||||
|
view.initShortcutKey();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -29,6 +29,7 @@ public class AppConstants {
|
|||||||
/**
|
/**
|
||||||
* 配置文件名
|
* 配置文件名
|
||||||
*/
|
*/
|
||||||
public static final String PROPERTY_FILE_NAME = "project.txt";
|
public static final String CH_LANGUAGE_PACK_NAME = "ch_language_pack.txt";
|
||||||
|
|
||||||
|
public static final String EN_LANGUAGE_PACK_NAME = "en_language_pack.txt";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,32 +0,0 @@
|
|||||||
package org.jcnc.jnotepad.controller.event.handler;
|
|
||||||
|
|
||||||
import javafx.event.ActionEvent;
|
|
||||||
import javafx.event.EventHandler;
|
|
||||||
import org.jcnc.jnotepad.app.config.GlobalConfig;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 换行事件处理,针对当前选中tab进行格式化。<br/>
|
|
||||||
* 配置变更时:<br/>
|
|
||||||
* 1. 更新内存全局配置<br/>
|
|
||||||
* 2. 对当前tab生效配置。每次tab切换,根据全局配置设置进行变更<br/>
|
|
||||||
* <p>
|
|
||||||
* 用于在文本区域中插入一个换行符。
|
|
||||||
* @see GlobalConfig
|
|
||||||
*
|
|
||||||
* @deprecated 事件处理将使用item的listener实现
|
|
||||||
*
|
|
||||||
* @author 许轲
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class LineFeed implements EventHandler<ActionEvent> {
|
|
||||||
/**
|
|
||||||
* 处理事件的方法,将一个换行符插入到文本区域的末尾。
|
|
||||||
*
|
|
||||||
* @param event 触发的事件对象
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void handle(ActionEvent event) {
|
|
||||||
//
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -2,12 +2,15 @@ package org.jcnc.jnotepad.controller.event.handler;
|
|||||||
|
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.event.EventHandler;
|
import javafx.event.EventHandler;
|
||||||
import org.jcnc.jnotepad.controller.manager.Controller;
|
import org.jcnc.jnotepad.init.Config;
|
||||||
import org.jcnc.jnotepad.ui.LineNumberTextArea;
|
import org.jcnc.jnotepad.ui.LineNumberTextArea;
|
||||||
|
import org.jcnc.jnotepad.ui.status.JNotepadStatusBox;
|
||||||
import org.jcnc.jnotepad.ui.tab.JNotepadTab;
|
import org.jcnc.jnotepad.ui.tab.JNotepadTab;
|
||||||
import org.jcnc.jnotepad.ui.tab.JNotepadTabPane;
|
import org.jcnc.jnotepad.ui.tab.JNotepadTabPane;
|
||||||
import org.jcnc.jnotepad.view.manager.ViewManager;
|
import org.jcnc.jnotepad.view.manager.ViewManager;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新建文件事件的事件处理程序。
|
* 新建文件事件的事件处理程序。
|
||||||
@ -17,36 +20,30 @@ import org.jcnc.jnotepad.view.manager.ViewManager;
|
|||||||
* @author 许轲
|
* @author 许轲
|
||||||
*/
|
*/
|
||||||
public class NewFile implements EventHandler<ActionEvent> {
|
public class NewFile implements EventHandler<ActionEvent> {
|
||||||
|
|
||||||
|
Config config = new Config();
|
||||||
|
Properties properties = config.readPropertiesFromFile();
|
||||||
|
String NEW_FILE = properties.getProperty("NEW_FILE");
|
||||||
/**
|
/**
|
||||||
|
*
|
||||||
* 处理新建文件事件。
|
* 处理新建文件事件。
|
||||||
*
|
*
|
||||||
* @param event 事件对象
|
* @param event 事件对象
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void handle(ActionEvent event) {
|
public void handle(ActionEvent event) {
|
||||||
// 获取控制器
|
|
||||||
Controller controller = Controller.getInstance();
|
|
||||||
|
|
||||||
// 创建一个新的文本编辑区
|
// 创建一个新的文本编辑区
|
||||||
LineNumberTextArea textArea = new LineNumberTextArea();
|
LineNumberTextArea textArea = new LineNumberTextArea();
|
||||||
|
|
||||||
textArea.setStyle(
|
|
||||||
"-fx-border-color:white ;-fx-background-color:white;"
|
|
||||||
);
|
|
||||||
|
|
||||||
// TODO: refactor:统一TextArea新建、绑定监听器入口
|
// TODO: refactor:统一TextArea新建、绑定监听器入口
|
||||||
// 增加autoSave监听器绑定
|
|
||||||
controller.autoSave(textArea);
|
|
||||||
ViewManager viewManager = ViewManager.getInstance();
|
ViewManager viewManager = ViewManager.getInstance();
|
||||||
// 将Tab页添加到TabPane中
|
// 将Tab页添加到TabPane中
|
||||||
JNotepadTabPane.getInstance().addNewTab(new JNotepadTab("新建文本 "
|
JNotepadTabPane.getInstance().addNewTab(new JNotepadTab(NEW_FILE
|
||||||
+ viewManager.selfIncreaseAndGetTabIndex(),
|
+ viewManager.selfIncreaseAndGetTabIndex(),
|
||||||
textArea));
|
textArea));
|
||||||
|
|
||||||
// 更新状态标签
|
|
||||||
controller.updateStatusLabel(textArea);
|
|
||||||
|
|
||||||
// 更新编码信息
|
// 更新编码信息
|
||||||
controller.upDateEncodingLabel(textArea.getMainTextArea().getText());
|
JNotepadStatusBox.getInstance().updateEncodingLabel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5,8 +5,6 @@ import javafx.event.ActionEvent;
|
|||||||
import javafx.event.EventHandler;
|
import javafx.event.EventHandler;
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import org.jcnc.jnotepad.controller.manager.Controller;
|
import org.jcnc.jnotepad.controller.manager.Controller;
|
||||||
import org.jcnc.jnotepad.ui.LineNumberTextArea;
|
|
||||||
import org.jcnc.jnotepad.ui.tab.JNotepadTabPane;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
@ -15,6 +13,7 @@ import java.io.File;
|
|||||||
* 打开文件的事件处理程序。
|
* 打开文件的事件处理程序。
|
||||||
* <p>
|
* <p>
|
||||||
* 当用户选择打开文件时,将创建一个新的文本编辑区,并在Tab页中显示。
|
* 当用户选择打开文件时,将创建一个新的文本编辑区,并在Tab页中显示。
|
||||||
|
*
|
||||||
* @author 许轲
|
* @author 许轲
|
||||||
*/
|
*/
|
||||||
public class OpenFile implements EventHandler<ActionEvent> {
|
public class OpenFile implements EventHandler<ActionEvent> {
|
||||||
@ -38,8 +37,6 @@ public class OpenFile implements EventHandler<ActionEvent> {
|
|||||||
protected Void call() {
|
protected Void call() {
|
||||||
// 调用控制器的getText方法,读取文件内容
|
// 调用控制器的getText方法,读取文件内容
|
||||||
controller.getText(file);
|
controller.getText(file);
|
||||||
// 更新编码标签
|
|
||||||
controller.upDateEncodingLabel(((LineNumberTextArea) JNotepadTabPane.getInstance().getSelected().getContent()).getMainTextArea().getText());
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2,10 +2,9 @@ package org.jcnc.jnotepad.controller.event.handler;
|
|||||||
|
|
||||||
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.controller.manager.Controller;
|
|
||||||
import org.jcnc.jnotepad.tool.LogUtil;
|
import org.jcnc.jnotepad.tool.LogUtil;
|
||||||
import org.jcnc.jnotepad.ui.LineNumberTextArea;
|
import org.jcnc.jnotepad.ui.LineNumberTextArea;
|
||||||
|
import org.jcnc.jnotepad.ui.tab.JNotepadTab;
|
||||||
import org.jcnc.jnotepad.ui.tab.JNotepadTabPane;
|
import org.jcnc.jnotepad.ui.tab.JNotepadTabPane;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
@ -28,7 +27,7 @@ public class SaveFile implements EventHandler<ActionEvent> {
|
|||||||
@Override
|
@Override
|
||||||
public void handle(ActionEvent actionEvent) {
|
public void handle(ActionEvent actionEvent) {
|
||||||
// 获取当前tab页
|
// 获取当前tab页
|
||||||
Tab selectedTab = JNotepadTabPane.getInstance().getSelected();
|
JNotepadTab selectedTab = JNotepadTabPane.getInstance().getSelected();
|
||||||
if (selectedTab == null) {
|
if (selectedTab == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -40,10 +39,8 @@ public class SaveFile implements EventHandler<ActionEvent> {
|
|||||||
saveTab(this.getClass());
|
saveTab(this.getClass());
|
||||||
} else {
|
} else {
|
||||||
logger.info("当前保存文件为关联打开文件,调用自动保存方法");
|
logger.info("当前保存文件为关联打开文件,调用自动保存方法");
|
||||||
// 打开的是关联文件
|
// 调用tab保存
|
||||||
Controller controller = Controller.getInstance();
|
selectedTab.save();
|
||||||
// 自动保存
|
|
||||||
controller.autoSave(textArea);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,13 +2,8 @@ package org.jcnc.jnotepad.controller.manager;
|
|||||||
|
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.concurrent.Task;
|
import javafx.concurrent.Task;
|
||||||
import javafx.event.ActionEvent;
|
|
||||||
import javafx.event.EventHandler;
|
|
||||||
import javafx.scene.control.Tab;
|
|
||||||
import org.jcnc.jnotepad.Interface.ControllerInterface;
|
import org.jcnc.jnotepad.Interface.ControllerInterface;
|
||||||
import org.jcnc.jnotepad.controller.event.handler.NewFile;
|
import org.jcnc.jnotepad.init.Config;
|
||||||
import org.jcnc.jnotepad.controller.event.handler.OpenFile;
|
|
||||||
import org.jcnc.jnotepad.controller.event.handler.SaveAsFile;
|
|
||||||
import org.jcnc.jnotepad.tool.EncodingDetector;
|
import org.jcnc.jnotepad.tool.EncodingDetector;
|
||||||
import org.jcnc.jnotepad.tool.LogUtil;
|
import org.jcnc.jnotepad.tool.LogUtil;
|
||||||
import org.jcnc.jnotepad.ui.LineNumberTextArea;
|
import org.jcnc.jnotepad.ui.LineNumberTextArea;
|
||||||
@ -16,9 +11,13 @@ import org.jcnc.jnotepad.ui.tab.JNotepadTab;
|
|||||||
import org.jcnc.jnotepad.ui.tab.JNotepadTabPane;
|
import org.jcnc.jnotepad.ui.tab.JNotepadTabPane;
|
||||||
import org.jcnc.jnotepad.view.manager.ViewManager;
|
import org.jcnc.jnotepad.view.manager.ViewManager;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.BufferedReader;
|
||||||
import java.util.ArrayList;
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 控制器类,实现ControllerInterface接口,用于管理文本编辑器的各种操作和事件处理。
|
* 控制器类,实现ControllerInterface接口,用于管理文本编辑器的各种操作和事件处理。
|
||||||
@ -27,6 +26,11 @@ import java.util.List;
|
|||||||
* @author 许轲
|
* @author 许轲
|
||||||
*/
|
*/
|
||||||
public class Controller implements ControllerInterface {
|
public class Controller implements ControllerInterface {
|
||||||
|
|
||||||
|
Config config = new Config();
|
||||||
|
Properties properties = config.readPropertiesFromFile();
|
||||||
|
|
||||||
|
String NEW_FILE = properties.getProperty("NEW_FILE");
|
||||||
private static final Controller INSTANCE = new Controller();
|
private static final Controller INSTANCE = new Controller();
|
||||||
|
|
||||||
private Controller() {
|
private Controller() {
|
||||||
@ -57,74 +61,6 @@ public class Controller implements ControllerInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取新建文件事件处理程序。
|
|
||||||
*
|
|
||||||
* @param textArea 文本区域
|
|
||||||
* @return 新建文件事件处理程序
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public EventHandler<ActionEvent> getNewFileEventHandler(LineNumberTextArea textArea) {
|
|
||||||
return new NewFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取打开文件事件处理程序。
|
|
||||||
*
|
|
||||||
* @return 打开文件事件处理程序
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public EventHandler<ActionEvent> getOpenFileEventHandler() {
|
|
||||||
return new OpenFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自动保存文本内容。
|
|
||||||
*
|
|
||||||
* @param textArea 文本区域
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void autoSave(LineNumberTextArea textArea) {
|
|
||||||
textArea.getMainTextArea().textProperty().addListener((observable, oldValue, newValue) -> {
|
|
||||||
Tab tab = JNotepadTabPane.getInstance().getSelected();
|
|
||||||
if (tab != null) {
|
|
||||||
File file = (File) tab.getUserData();
|
|
||||||
if (file != null) {
|
|
||||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
|
|
||||||
writer.write(newValue);
|
|
||||||
LogUtil.getLogger(this.getClass()).info("正在自动保存---");
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
LogUtil.getLogger(this.getClass()).info("已忽视IO异常!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取另存为文件事件处理程序。
|
|
||||||
*
|
|
||||||
* @return 另存为文件事件处理程序
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public EventHandler<ActionEvent> getSaveAsFileEventHandler() {
|
|
||||||
return new SaveAsFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新状态标签。
|
|
||||||
*
|
|
||||||
* @param textArea 文本区域
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void updateStatusLabel(LineNumberTextArea textArea) {
|
|
||||||
int caretPosition = textArea.getMainTextArea().getCaretPosition();
|
|
||||||
int row = getRow(caretPosition, textArea.getMainTextArea().getText());
|
|
||||||
int column = getColumn(caretPosition, textArea.getMainTextArea().getText());
|
|
||||||
int length = textArea.getMainTextArea().getLength();
|
|
||||||
ViewManager.getInstance().getStatusLabel().setText("行: " + row + " \t列: " + column + " \t字数: " + length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 打开关联文件。
|
* 打开关联文件。
|
||||||
*
|
*
|
||||||
@ -148,7 +84,9 @@ public class Controller implements ControllerInterface {
|
|||||||
LineNumberTextArea textArea = createNewTextArea();
|
LineNumberTextArea textArea = createNewTextArea();
|
||||||
// 设置当前标签页关联本地文件
|
// 设置当前标签页关联本地文件
|
||||||
textArea.setRelevance(true);
|
textArea.setRelevance(true);
|
||||||
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
// 检测文件编码
|
||||||
|
Charset encoding = EncodingDetector.detectEncodingCharset(file);
|
||||||
|
try (BufferedReader reader = new BufferedReader(new FileReader(file, encoding))) {
|
||||||
StringBuilder textBuilder = new StringBuilder();
|
StringBuilder textBuilder = new StringBuilder();
|
||||||
String line;
|
String line;
|
||||||
while ((line = reader.readLine()) != null) {
|
while ((line = reader.readLine()) != null) {
|
||||||
@ -158,11 +96,9 @@ public class Controller implements ControllerInterface {
|
|||||||
|
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
textArea.getMainTextArea().setText(text);
|
textArea.getMainTextArea().setText(text);
|
||||||
JNotepadTab tab = createNewTab(file.getName(), textArea);
|
JNotepadTab tab = createNewTab(file.getName(), textArea, encoding);
|
||||||
tab.setUserData(file);
|
tab.setUserData(file);
|
||||||
JNotepadTabPane.getInstance().addNewTab(tab);
|
JNotepadTabPane.getInstance().addNewTab(tab);
|
||||||
updateStatusLabel(textArea);
|
|
||||||
autoSave(textArea);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (IOException ignored) {
|
} catch (IOException ignored) {
|
||||||
@ -171,74 +107,6 @@ public class Controller implements ControllerInterface {
|
|||||||
return textArea;
|
return textArea;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新编码标签。
|
|
||||||
*
|
|
||||||
* @param text 文本内容
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void upDateEncodingLabel(String text) {
|
|
||||||
String encoding = EncodingDetector.detectEncoding(text);
|
|
||||||
ViewManager.getInstance().getEnCodingLabel().setText("\t编码: " + encoding);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取光标所在行号。
|
|
||||||
*
|
|
||||||
* @param caretPosition 光标位置
|
|
||||||
* @param text 文本内容
|
|
||||||
* @return 光标所在行号
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int getRow(int caretPosition, String text) {
|
|
||||||
caretPosition = Math.min(caretPosition, text.length());
|
|
||||||
String substring = text.substring(0, caretPosition);
|
|
||||||
int count = 0;
|
|
||||||
for (char c : substring.toCharArray()) {
|
|
||||||
if (c == '\n') {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取光标所在列号。
|
|
||||||
*
|
|
||||||
* @param caretPosition 光标位置
|
|
||||||
* @param text 文本内容
|
|
||||||
* @return 光标所在列号
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int getColumn(int caretPosition, String text) {
|
|
||||||
return caretPosition - text.lastIndexOf("\n", caretPosition - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化标签面板。
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void initTabPane() {
|
|
||||||
JNotepadTabPane.getInstance().getSelectionModel().selectedItemProperty().addListener((observable, oldTab, newTab) -> {
|
|
||||||
LineNumberTextArea textArea;
|
|
||||||
if (newTab != null) {
|
|
||||||
// 获取新选定的标签页并关联的文本区域
|
|
||||||
textArea = (LineNumberTextArea) newTab.getContent();
|
|
||||||
} else {
|
|
||||||
// 刷新状态
|
|
||||||
textArea = openAssociatedFileAndCreateTextArea(new ArrayList<>());
|
|
||||||
}
|
|
||||||
// 更新状态标签
|
|
||||||
INSTANCE.updateStatusLabel(textArea);
|
|
||||||
|
|
||||||
// 监听文本光标位置的变化,更新状态标签
|
|
||||||
textArea.getMainTextArea().caretPositionProperty().addListener((caretObservable, oldPosition, newPosition) -> INSTANCE.updateStatusLabel(textArea));
|
|
||||||
|
|
||||||
// 更新编码标签
|
|
||||||
INSTANCE.upDateEncodingLabel(textArea.getMainTextArea().getText());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新UI和标签页
|
* 更新UI和标签页
|
||||||
*
|
*
|
||||||
@ -249,9 +117,8 @@ public class Controller implements ControllerInterface {
|
|||||||
@Override
|
@Override
|
||||||
public void updateUiWithNewTextArea(LineNumberTextArea textArea) {
|
public void updateUiWithNewTextArea(LineNumberTextArea textArea) {
|
||||||
ViewManager viewManager = ViewManager.getInstance();
|
ViewManager viewManager = ViewManager.getInstance();
|
||||||
String tabTitle = "新建文件 " + viewManager.selfIncreaseAndGetTabIndex();
|
String tabTitle = NEW_FILE + viewManager.selfIncreaseAndGetTabIndex();
|
||||||
JNotepadTabPane.getInstance().addNewTab(new JNotepadTab(tabTitle, textArea));
|
JNotepadTabPane.getInstance().addNewTab(new JNotepadTab(tabTitle, textArea));
|
||||||
updateStatusLabel(textArea);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -262,12 +129,6 @@ public class Controller implements ControllerInterface {
|
|||||||
*/
|
*/
|
||||||
private void configureTextArea(LineNumberTextArea textArea) {
|
private void configureTextArea(LineNumberTextArea textArea) {
|
||||||
textArea.getMainTextArea().setWrapText(true);
|
textArea.getMainTextArea().setWrapText(true);
|
||||||
upDateEncodingLabel(textArea.getMainTextArea().getText());
|
|
||||||
updateStatusLabel(textArea);
|
|
||||||
|
|
||||||
textArea.textProperty().addListener((observable, oldValue, newValue) -> updateStatusLabel(textArea));
|
|
||||||
|
|
||||||
autoSave(textArea);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -276,12 +137,7 @@ public class Controller implements ControllerInterface {
|
|||||||
* @return 新的文本区域
|
* @return 新的文本区域
|
||||||
*/
|
*/
|
||||||
private LineNumberTextArea createNewTextArea() {
|
private LineNumberTextArea createNewTextArea() {
|
||||||
LineNumberTextArea textArea = new LineNumberTextArea();
|
return new LineNumberTextArea();
|
||||||
textArea.setStyle(
|
|
||||||
"-fx-border-color:white;" +
|
|
||||||
"-fx-background-color:white"
|
|
||||||
);
|
|
||||||
return textArea;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -291,8 +147,8 @@ public class Controller implements ControllerInterface {
|
|||||||
* @param textArea 文本区域
|
* @param textArea 文本区域
|
||||||
* @return 新的标签页
|
* @return 新的标签页
|
||||||
*/
|
*/
|
||||||
private JNotepadTab createNewTab(String tabName, LineNumberTextArea textArea) {
|
private JNotepadTab createNewTab(String tabName, LineNumberTextArea textArea, Charset charset) {
|
||||||
return new JNotepadTab(tabName, textArea);
|
return new JNotepadTab(tabName, textArea, charset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -305,7 +161,7 @@ public class Controller implements ControllerInterface {
|
|||||||
return new Task<>() {
|
return new Task<>() {
|
||||||
@Override
|
@Override
|
||||||
protected Void call() {
|
protected Void call() {
|
||||||
upDateEncodingLabel(getText(file).getMainTextArea().getText());
|
getText(file);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,43 +1,106 @@
|
|||||||
package org.jcnc.jnotepad.init;
|
package org.jcnc.jnotepad.init;
|
||||||
|
|
||||||
import javafx.scene.control.Alert;
|
|
||||||
import org.jcnc.jnotepad.Interface.ConfigInterface;
|
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import static org.jcnc.jnotepad.constants.AppConstants.PROPERTY_FILE_NAME;
|
import static org.jcnc.jnotepad.constants.AppConstants.CH_LANGUAGE_PACK_NAME;
|
||||||
|
import static org.jcnc.jnotepad.constants.AppConstants.EN_LANGUAGE_PACK_NAME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author 许轲
|
* @author 许轲
|
||||||
|
* 该类负责配置文件的读取和初始化操作。
|
||||||
*/
|
*/
|
||||||
public class Config implements ConfigInterface {
|
public class Config {
|
||||||
|
|
||||||
|
String LANGUAGE_PACK_NAME;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从文件中读取属性配置。
|
||||||
|
*
|
||||||
|
* @return 包含从文件中读取的属性的 Properties 对象。
|
||||||
|
*/
|
||||||
public Properties readPropertiesFromFile() {
|
public Properties readPropertiesFromFile() {
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
try (InputStream inputStream = new FileInputStream(PROPERTY_FILE_NAME)) {
|
|
||||||
properties.load(inputStream);
|
//设置语言包
|
||||||
|
LANGUAGE_PACK_NAME = EN_LANGUAGE_PACK_NAME;
|
||||||
|
try (InputStream inputStream = new FileInputStream(LANGUAGE_PACK_NAME)) {
|
||||||
|
InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8); // 使用 UTF-8 编码
|
||||||
|
properties.load(reader);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
// 如果读取出错,则调用初始化方法
|
||||||
initializePropertiesFile();
|
initializePropertiesFile();
|
||||||
}
|
}
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化属性配置文件。
|
||||||
|
* 如果属性文件不存在,将创建一个新的属性文件并设置默认属性。
|
||||||
|
*/
|
||||||
public void initializePropertiesFile() {
|
public void initializePropertiesFile() {
|
||||||
Properties defaultProperties = new Properties();
|
Properties chLanguagePack = getCHLanguagePack();
|
||||||
defaultProperties.setProperty("title", "JNotepad");
|
|
||||||
|
|
||||||
try (OutputStream outputStream = new FileOutputStream(PROPERTY_FILE_NAME)) {
|
Properties enLanguagePack = getENLanguagePack();
|
||||||
defaultProperties.store(outputStream, "JNotepad Properties");
|
|
||||||
} catch (IOException e) {
|
try (OutputStream outputStream = new FileOutputStream(CH_LANGUAGE_PACK_NAME)) {
|
||||||
showErrorAlert();
|
OutputStreamWriter writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8); // 使用 UTF-8 编码
|
||||||
|
chLanguagePack.store(writer, "JNotepad ch_language_pack");
|
||||||
|
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
try (OutputStream outputStream = new FileOutputStream(EN_LANGUAGE_PACK_NAME)) {
|
||||||
|
OutputStreamWriter writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8); // 使用 UTF-8 编码
|
||||||
|
enLanguagePack.store(writer, "JNotepad en_language_pack");
|
||||||
|
|
||||||
|
} catch (IOException ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showErrorAlert() {
|
private static Properties getCHLanguagePack() {
|
||||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
Properties properties = new Properties();
|
||||||
alert.setTitle("错误");
|
|
||||||
alert.setHeaderText("文件读写错误");
|
properties.setProperty("TITLE", "JNotepad"); // 设置默认属性
|
||||||
alert.setContentText("文件读写错误");
|
properties.setProperty("NEW_FILE", "新建文件");
|
||||||
alert.showAndWait();
|
properties.setProperty("SAVA", "保存");
|
||||||
|
properties.setProperty("FILE", "文件");
|
||||||
|
properties.setProperty("NEW", "新建");
|
||||||
|
properties.setProperty("OPEN", "打开");
|
||||||
|
properties.setProperty("SAVA_AS", "另存为");
|
||||||
|
properties.setProperty("SET", "设置");
|
||||||
|
properties.setProperty("WORD_WRAP", "自动换行");
|
||||||
|
properties.setProperty("PLUGIN", "插件");
|
||||||
|
properties.setProperty("ADD_PLUGIN", "增加插件");
|
||||||
|
properties.setProperty("STATISTICS", "统计字数");
|
||||||
|
properties.setProperty("ROW", "行数");
|
||||||
|
properties.setProperty("COLUMN", "列数");
|
||||||
|
properties.setProperty("WORD_COUNT", "字数");
|
||||||
|
properties.setProperty("ENCODE", "编码");
|
||||||
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Properties getENLanguagePack() {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
|
||||||
|
properties.setProperty("TITLE", "JNotepad");
|
||||||
|
properties.setProperty("NEW_FILE", "New File");
|
||||||
|
properties.setProperty("SAVA", "Save");
|
||||||
|
properties.setProperty("FILE", "File");
|
||||||
|
properties.setProperty("NEW", "New");
|
||||||
|
properties.setProperty("OPEN", "Open");
|
||||||
|
properties.setProperty("SAVA_AS", "Save As");
|
||||||
|
properties.setProperty("SET", "Settings");
|
||||||
|
properties.setProperty("WORD_WRAP", "Word Wrap");
|
||||||
|
properties.setProperty("PLUGIN", "Plugins");
|
||||||
|
properties.setProperty("ADD_PLUGIN", "Add Plugin");
|
||||||
|
properties.setProperty("STATISTICS", "Word Count");
|
||||||
|
properties.setProperty("ROW", "Row");
|
||||||
|
properties.setProperty("COLUMN", "Column");
|
||||||
|
properties.setProperty("WORD_COUNT", "Word Count");
|
||||||
|
properties.setProperty("ENCODE", "Encoding");
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,21 @@
|
|||||||
package org.jcnc.jnotepad.tool;
|
package org.jcnc.jnotepad.tool;
|
||||||
|
|
||||||
|
|
||||||
|
import com.ibm.icu.text.CharsetDetector;
|
||||||
|
import com.ibm.icu.text.CharsetMatch;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import org.jcnc.jnotepad.ui.LineNumberTextArea;
|
import org.jcnc.jnotepad.ui.LineNumberTextArea;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编码检测工具类
|
* 编码检测工具类
|
||||||
@ -13,67 +23,46 @@ import java.nio.charset.StandardCharsets;
|
|||||||
* @author 许轲
|
* @author 许轲
|
||||||
*/
|
*/
|
||||||
public class EncodingDetector {
|
public class EncodingDetector {
|
||||||
private EncodingDetector() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
private static final Logger LOG = LoggerFactory.getLogger(EncodingDetector.class);
|
||||||
* 检测 TextArea 中的文本编码
|
public static final String UNKNOWN = "UNKNOWN";
|
||||||
*
|
|
||||||
* @param textArea 文本区域
|
private EncodingDetector() {
|
||||||
* @return 字符串表示的编码,如果检测失败则返回 "UNKNOWN"
|
|
||||||
*/
|
|
||||||
public static String detectEncoding(LineNumberTextArea textArea) {
|
|
||||||
String text = textArea.getMainTextArea().getText();
|
|
||||||
return detectEncoding(text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检测文本编码
|
* 检测文本编码
|
||||||
*
|
*
|
||||||
* @param text 要检测的文本
|
* @param file 要检测的文件
|
||||||
* @return 字符串表示的编码,如果检测失败则返回 "UNKNOWN"
|
* @return 字符串表示的编码,如果检测失败则返回 "UNKNOWN"
|
||||||
*/
|
*/
|
||||||
public static String detectEncoding(String text) {
|
public static String detectEncoding(File file) {
|
||||||
// 尝试常见的编码
|
CharsetDetector charsetDetector = new CharsetDetector();
|
||||||
for (Charset charset : commonCharsets()) {
|
try (BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(file.getPath()))) {
|
||||||
if (isValidEncoding(text, charset)) {
|
charsetDetector.setText(inputStream);
|
||||||
Platform.runLater(() -> LogUtil.getLogger(EncodingDetector.class).info("编码监测结果:{}", isValidEncoding(text, charset)));
|
CharsetMatch match = charsetDetector.detect();
|
||||||
return charset.name();
|
LOG.debug(match.getName() + " " + match.getConfidence());
|
||||||
|
if (match.getConfidence() > 50) {
|
||||||
|
return match.getName();
|
||||||
}
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error("", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return "UNKNOWN";
|
return UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取常见的字符集数组
|
* 检测文本编码
|
||||||
*
|
*
|
||||||
* @return 常见字符集数组
|
* @param file 文件
|
||||||
|
* @return Charset编码
|
||||||
*/
|
*/
|
||||||
private static Charset[] commonCharsets() {
|
public static Charset detectEncodingCharset(File file) {
|
||||||
return new Charset[]{
|
String charset = detectEncoding(file);
|
||||||
StandardCharsets.UTF_8,
|
if (charset.equals(UNKNOWN)) {
|
||||||
StandardCharsets.UTF_16,
|
return StandardCharsets.UTF_8;
|
||||||
StandardCharsets.UTF_16LE,
|
}
|
||||||
StandardCharsets.UTF_16BE,
|
return Charset.forName(charset);
|
||||||
StandardCharsets.ISO_8859_1
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查指定编码是否能够正确解码文本
|
|
||||||
*
|
|
||||||
* @param text 要检测的文本
|
|
||||||
* @param encoding 要尝试的编码
|
|
||||||
* @return 如果指定编码能够正确解码文本,则返回 true,否则返回 false
|
|
||||||
*/
|
|
||||||
private static boolean isValidEncoding(String text, Charset encoding) {
|
|
||||||
// 尝试使用指定编码解码
|
|
||||||
byte[] bytes = text.getBytes(encoding);
|
|
||||||
String decoded = new String(bytes, encoding);
|
|
||||||
|
|
||||||
// 解码后的文本相同表示编码有效
|
|
||||||
return text.equals(decoded);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -3,6 +3,7 @@ package org.jcnc.jnotepad.tool;
|
|||||||
import javafx.scene.control.Tab;
|
import javafx.scene.control.Tab;
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import org.jcnc.jnotepad.ui.LineNumberTextArea;
|
import org.jcnc.jnotepad.ui.LineNumberTextArea;
|
||||||
|
import org.jcnc.jnotepad.ui.tab.JNotepadTab;
|
||||||
import org.jcnc.jnotepad.ui.tab.JNotepadTabPane;
|
import org.jcnc.jnotepad.ui.tab.JNotepadTabPane;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
@ -49,7 +50,7 @@ public class FileUtil {
|
|||||||
* @see LogUtil
|
* @see LogUtil
|
||||||
*/
|
*/
|
||||||
public static void saveTab(Class<?> currentClass) {
|
public static void saveTab(Class<?> currentClass) {
|
||||||
Tab selectedTab = JNotepadTabPane.getInstance().getSelected();
|
JNotepadTab selectedTab = JNotepadTabPane.getInstance().getSelected();
|
||||||
if (selectedTab != null) {
|
if (selectedTab != null) {
|
||||||
// 创建一个文件窗口
|
// 创建一个文件窗口
|
||||||
FileChooser fileChooser = new FileChooser();
|
FileChooser fileChooser = new FileChooser();
|
||||||
@ -59,24 +60,13 @@ public class FileUtil {
|
|||||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("文本文档", "*.txt"));
|
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("文本文档", "*.txt"));
|
||||||
File file = fileChooser.showSaveDialog(null);
|
File file = fileChooser.showSaveDialog(null);
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
try (
|
selectedTab.save();
|
||||||
BufferedWriter writer = new BufferedWriter(new FileWriter(file))
|
// 将保存后的文件设置为已关联
|
||||||
) {
|
selectedTab.getLineNumberTextArea().setRelevance(true);
|
||||||
// 获取当前Tab页的文本编辑区
|
// 更新Tab页标签上的文件名
|
||||||
LineNumberTextArea textArea = (LineNumberTextArea) selectedTab.getContent();
|
selectedTab.setText(file.getName());
|
||||||
// 将保存后的文件设置为已关联
|
// 将文件对象保存到Tab页的UserData中
|
||||||
textArea.setRelevance(true);
|
selectedTab.setUserData(file);
|
||||||
String text = textArea.getMainTextArea().getText();
|
|
||||||
// 写入文件内容
|
|
||||||
writer.write(text);
|
|
||||||
writer.flush();
|
|
||||||
// 更新Tab页标签上的文件名
|
|
||||||
selectedTab.setText(file.getName());
|
|
||||||
// 将文件对象保存到Tab页的UserData中
|
|
||||||
selectedTab.setUserData(file);
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
LogUtil.getLogger(currentClass).info("已忽视IO异常!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,18 @@
|
|||||||
package org.jcnc.jnotepad.ui;
|
package org.jcnc.jnotepad.ui;
|
||||||
|
|
||||||
import javafx.beans.property.StringProperty;
|
import javafx.beans.property.StringProperty;
|
||||||
|
import javafx.scene.control.Tab;
|
||||||
import javafx.scene.control.TextArea;
|
import javafx.scene.control.TextArea;
|
||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.BorderPane;
|
||||||
|
import org.jcnc.jnotepad.tool.LogUtil;
|
||||||
|
import org.jcnc.jnotepad.ui.status.JNotepadStatusBox;
|
||||||
|
import org.jcnc.jnotepad.ui.tab.JNotepadTab;
|
||||||
|
import org.jcnc.jnotepad.ui.tab.JNotepadTabPane;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author 许轲
|
* @author 许轲
|
||||||
@ -28,16 +38,50 @@ public class LineNumberTextArea extends BorderPane {
|
|||||||
// 设定自定义样式
|
// 设定自定义样式
|
||||||
lineNumberArea.getStyleClass().add("text-line-number");
|
lineNumberArea.getStyleClass().add("text-line-number");
|
||||||
mainTextArea.getStyleClass().add("main-text-area");
|
mainTextArea.getStyleClass().add("main-text-area");
|
||||||
lineNumberArea.textProperty().addListener((observable, oldValue, newValue) -> updateLineNumberWidth());
|
this.setStyle(
|
||||||
mainTextArea.textProperty().addListener((observable, oldValue, newValue) -> updateLineNumberArea());
|
"-fx-border-color:white;" +
|
||||||
|
"-fx-background-color:white"
|
||||||
|
);
|
||||||
|
setCenter(mainTextArea);
|
||||||
|
setLeft(lineNumberArea);
|
||||||
|
|
||||||
|
initListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initListeners() {
|
||||||
// 当主要文本区域的垂直滚动位置发生变化时,使行号文本区域的滚动位置保持一致
|
// 当主要文本区域的垂直滚动位置发生变化时,使行号文本区域的滚动位置保持一致
|
||||||
mainTextArea.scrollTopProperty().addListener((observable, oldValue, newValue) -> lineNumberArea.setScrollTop(mainTextArea.getScrollTop()));
|
mainTextArea.scrollTopProperty().addListener((observable, oldValue, newValue) -> lineNumberArea.setScrollTop(mainTextArea.getScrollTop()));
|
||||||
|
|
||||||
// 当行号文本区域的垂直滚动位置发生变化时,使主要文本区域的滚动位置保持一致
|
// 当行号文本区域的垂直滚动位置发生变化时,使主要文本区域的滚动位置保持一致
|
||||||
lineNumberArea.scrollTopProperty().addListener((observable, oldValue, newValue) -> mainTextArea.setScrollTop(lineNumberArea.getScrollTop()));
|
lineNumberArea.scrollTopProperty().addListener((observable, oldValue, newValue) -> mainTextArea.setScrollTop(lineNumberArea.getScrollTop()));
|
||||||
setCenter(mainTextArea);
|
lineNumberArea.textProperty().addListener((observable, oldValue, newValue) -> updateLineNumberWidth());
|
||||||
setLeft(lineNumberArea);
|
|
||||||
|
this.mainTextArea.caretPositionProperty().addListener((caretObservable, oldPosition, newPosition) -> JNotepadStatusBox.getInstance().updateWordCountStatusLabel());
|
||||||
|
this.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
// 更新行号
|
||||||
|
updateLineNumberArea();
|
||||||
|
// 更新状态栏
|
||||||
|
JNotepadStatusBox.getInstance().updateWordCountStatusLabel();
|
||||||
|
// 自动保存
|
||||||
|
save();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 以原文件编码格式写回文件
|
||||||
|
*/
|
||||||
|
public void save() {
|
||||||
|
JNotepadTab tab = JNotepadTabPane.getInstance().getSelected();
|
||||||
|
File file = (File) tab.getUserData();
|
||||||
|
String newValue = this.mainTextArea.getText();
|
||||||
|
if (file != null) {
|
||||||
|
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file, tab.getCharset()))) {
|
||||||
|
writer.write(newValue);
|
||||||
|
LogUtil.getLogger(this.getClass()).info("正在自动保存---");
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
LogUtil.getLogger(this.getClass()).info("已忽视IO异常!");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRelevance() {
|
public boolean isRelevance() {
|
||||||
@ -91,5 +135,6 @@ public class LineNumberTextArea extends BorderPane {
|
|||||||
public TextArea getMainTextArea() {
|
public TextArea getMainTextArea() {
|
||||||
return mainTextArea;
|
return mainTextArea;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,11 +6,13 @@ import javafx.scene.control.MenuBar;
|
|||||||
import javafx.scene.control.MenuItem;
|
import javafx.scene.control.MenuItem;
|
||||||
import org.jcnc.jnotepad.app.config.GlobalConfig;
|
import org.jcnc.jnotepad.app.config.GlobalConfig;
|
||||||
import org.jcnc.jnotepad.controller.event.handler.*;
|
import org.jcnc.jnotepad.controller.event.handler.*;
|
||||||
|
import org.jcnc.jnotepad.init.Config;
|
||||||
import org.jcnc.jnotepad.ui.tab.JNotepadTab;
|
import org.jcnc.jnotepad.ui.tab.JNotepadTab;
|
||||||
import org.jcnc.jnotepad.ui.tab.JNotepadTabPane;
|
import org.jcnc.jnotepad.ui.tab.JNotepadTabPane;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 封装菜单栏组件。
|
* 封装菜单栏组件。
|
||||||
@ -19,6 +21,24 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public class JNotepadMenuBar extends MenuBar {
|
public class JNotepadMenuBar extends MenuBar {
|
||||||
|
|
||||||
|
Config config = new Config();
|
||||||
|
Properties properties = config.readPropertiesFromFile();
|
||||||
|
String SAVA = properties.getProperty("SAVA");
|
||||||
|
String FILE = properties.getProperty("FILE");
|
||||||
|
String NEW = properties.getProperty("NEW");
|
||||||
|
String OPEN = properties.getProperty("OPEN");
|
||||||
|
String SAVA_AS = properties.getProperty("SAVA_AS");
|
||||||
|
|
||||||
|
String SET = properties.getProperty("SET");
|
||||||
|
|
||||||
|
String WORD_WRAP = properties.getProperty("WORD_WRAP");
|
||||||
|
|
||||||
|
String PLUGIN = properties.getProperty("PLUGIN");
|
||||||
|
|
||||||
|
String ADD_PLUGIN = properties.getProperty("ADD_PLUGIN");
|
||||||
|
|
||||||
|
String STATISTICS = properties.getProperty("STATISTICS");
|
||||||
|
|
||||||
private static final JNotepadMenuBar MENU_BAR = new JNotepadMenuBar();
|
private static final JNotepadMenuBar MENU_BAR = new JNotepadMenuBar();
|
||||||
|
|
||||||
private JNotepadMenuBar() {
|
private JNotepadMenuBar() {
|
||||||
@ -90,18 +110,18 @@ public class JNotepadMenuBar extends MenuBar {
|
|||||||
*/
|
*/
|
||||||
private void initFileMenu() {
|
private void initFileMenu() {
|
||||||
// 文件菜单
|
// 文件菜单
|
||||||
fileMenu = new Menu("文件");
|
fileMenu = new Menu(FILE);
|
||||||
|
|
||||||
newItem = new MenuItem("新建");
|
newItem = new MenuItem(NEW);
|
||||||
itemMap.put("newItem", newItem);
|
itemMap.put("newItem", newItem);
|
||||||
|
|
||||||
openItem = new MenuItem("打开");
|
openItem = new MenuItem(OPEN);
|
||||||
itemMap.put("openItem", openItem);
|
itemMap.put("openItem", openItem);
|
||||||
|
|
||||||
saveItem = new MenuItem("保存");
|
saveItem = new MenuItem(SAVA);
|
||||||
itemMap.put("saveItem", saveItem);
|
itemMap.put("saveItem", saveItem);
|
||||||
|
|
||||||
saveAsItem = new MenuItem("另存为");
|
saveAsItem = new MenuItem(SAVA_AS);
|
||||||
itemMap.put("saveAsItem", saveAsItem);
|
itemMap.put("saveAsItem", saveAsItem);
|
||||||
|
|
||||||
fileMenu.getItems().addAll(newItem, openItem, saveItem, saveAsItem);
|
fileMenu.getItems().addAll(newItem, openItem, saveItem, saveAsItem);
|
||||||
@ -112,9 +132,9 @@ public class JNotepadMenuBar extends MenuBar {
|
|||||||
*/
|
*/
|
||||||
private void initSettingMenu() {
|
private void initSettingMenu() {
|
||||||
// 设置菜单
|
// 设置菜单
|
||||||
setMenu = new Menu("设置");
|
setMenu = new Menu(SET);
|
||||||
|
|
||||||
lineFeedItem = new CheckMenuItem("自动换行");
|
lineFeedItem = new CheckMenuItem(WORD_WRAP);
|
||||||
itemMap.put("lineFeedItem", lineFeedItem);
|
itemMap.put("lineFeedItem", lineFeedItem);
|
||||||
lineFeedItem.selectedProperty().set(true);
|
lineFeedItem.selectedProperty().set(true);
|
||||||
|
|
||||||
@ -126,11 +146,11 @@ public class JNotepadMenuBar extends MenuBar {
|
|||||||
*/
|
*/
|
||||||
private void initPluginMenu() {
|
private void initPluginMenu() {
|
||||||
// 插件菜单
|
// 插件菜单
|
||||||
pluginMenu = new Menu("插件");
|
pluginMenu = new Menu(PLUGIN);
|
||||||
addItem = new MenuItem("增加插件");
|
addItem = new MenuItem(ADD_PLUGIN);
|
||||||
itemMap.put("addItem", addItem);
|
itemMap.put("addItem", addItem);
|
||||||
|
|
||||||
countItem = new MenuItem("统计字数");
|
countItem = new MenuItem(STATISTICS);
|
||||||
itemMap.put("countItem", countItem);
|
itemMap.put("countItem", countItem);
|
||||||
|
|
||||||
pluginMenu.getItems().addAll(addItem, countItem);
|
pluginMenu.getItems().addAll(addItem, countItem);
|
||||||
@ -148,7 +168,6 @@ public class JNotepadMenuBar extends MenuBar {
|
|||||||
openItem.setOnAction(new OpenFile());
|
openItem.setOnAction(new OpenFile());
|
||||||
saveItem.setOnAction(new SaveFile());
|
saveItem.setOnAction(new SaveFile());
|
||||||
saveAsItem.setOnAction(new SaveAsFile());
|
saveAsItem.setOnAction(new SaveAsFile());
|
||||||
lineFeedItem.setOnAction(new LineFeed());
|
|
||||||
lineFeedItem.selectedProperty().addListener((observableValue, before, after) -> {
|
lineFeedItem.selectedProperty().addListener((observableValue, before, after) -> {
|
||||||
// 1. 更新全局配置
|
// 1. 更新全局配置
|
||||||
GlobalConfig.getConfig().setAutoLineConfig(after);
|
GlobalConfig.getConfig().setAutoLineConfig(after);
|
||||||
|
|||||||
128
src/main/java/org/jcnc/jnotepad/ui/status/JNotepadStatusBox.java
Normal file
128
src/main/java/org/jcnc/jnotepad/ui/status/JNotepadStatusBox.java
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
package org.jcnc.jnotepad.ui.status;
|
||||||
|
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.TextArea;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import org.jcnc.jnotepad.init.Config;
|
||||||
|
import org.jcnc.jnotepad.ui.tab.JNotepadTabPane;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态栏组件封装。
|
||||||
|
* 1. 文字统计
|
||||||
|
* 2. 编码
|
||||||
|
*
|
||||||
|
* @author songdragon
|
||||||
|
*/
|
||||||
|
public class JNotepadStatusBox extends HBox {
|
||||||
|
|
||||||
|
Config config = new Config();
|
||||||
|
Properties properties = config.readPropertiesFromFile();
|
||||||
|
String ROW = properties.getProperty("ROW");
|
||||||
|
|
||||||
|
String COLUMN = properties.getProperty("COLUMN");
|
||||||
|
|
||||||
|
String WORD_COUNT = properties.getProperty("WORD_COUNT");
|
||||||
|
|
||||||
|
String ENCODE = properties.getProperty("ENCODE");
|
||||||
|
|
||||||
|
private static final JNotepadStatusBox STATUS_BOX = new JNotepadStatusBox();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字数统计及光标
|
||||||
|
*/
|
||||||
|
private final Label statusLabel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示文本编码
|
||||||
|
*/
|
||||||
|
private final Label enCodingLabel;
|
||||||
|
|
||||||
|
private JNotepadStatusBox() {
|
||||||
|
// 创建状态栏
|
||||||
|
statusLabel = new Label(ROW + ":1 \t" + COLUMN + ":1 \t" + WORD_COUNT + ":0 ");
|
||||||
|
// 创建新的标签以显示编码信息
|
||||||
|
enCodingLabel = new Label();
|
||||||
|
|
||||||
|
this.getChildren().add(statusLabel);
|
||||||
|
this.getChildren().add(enCodingLabel);
|
||||||
|
this.getProperties().put("borderpane-margin", new Insets(5, 10, 5, 10));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JNotepadStatusBox getInstance() {
|
||||||
|
return STATUS_BOX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateEncodingLabel() {
|
||||||
|
updateEncodingLabel(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新编码展示
|
||||||
|
*
|
||||||
|
* @param encoding 文件编码
|
||||||
|
*/
|
||||||
|
public void updateEncodingLabel(String encoding) {
|
||||||
|
if (encoding == null) {
|
||||||
|
encoding = Charset.defaultCharset().name();
|
||||||
|
}
|
||||||
|
this.enCodingLabel.setText("\t" + ENCODE + ": " + encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新字数统计
|
||||||
|
*/
|
||||||
|
public void updateWordCountStatusLabel() {
|
||||||
|
TextArea textArea = JNotepadTabPane.getInstance().getSelected().getLineNumberTextArea().getMainTextArea();
|
||||||
|
int caretPosition = textArea.getCaretPosition();
|
||||||
|
int row = getRow(caretPosition, textArea.getText());
|
||||||
|
int column = getColumn(caretPosition, textArea.getText());
|
||||||
|
int length = textArea.getLength();
|
||||||
|
this.statusLabel.setText(ROW + ": " + row + " \t" + COLUMN + ": " + column + " \t" + WORD_COUNT + ": " + length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tab选中时,更新状态栏
|
||||||
|
* 1. 状态栏更新当前选中tab的数字统计
|
||||||
|
* 2. 状态栏更新当前选中tab的字符编码
|
||||||
|
*/
|
||||||
|
public void updateWhenTabSelected() {
|
||||||
|
updateWordCountStatusLabel();
|
||||||
|
updateEncodingLabel(JNotepadTabPane.getInstance().getSelected().getCharset().name());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取光标所在行号。
|
||||||
|
*
|
||||||
|
* @param caretPosition 光标位置
|
||||||
|
* @param text 文本内容
|
||||||
|
* @return 光标所在行号
|
||||||
|
*/
|
||||||
|
public int getRow(int caretPosition, String text) {
|
||||||
|
caretPosition = Math.min(caretPosition, text.length());
|
||||||
|
String substring = text.substring(0, caretPosition);
|
||||||
|
int count = 0;
|
||||||
|
for (char c : substring.toCharArray()) {
|
||||||
|
if (c == '\n') {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取光标所在列号。
|
||||||
|
*
|
||||||
|
* @param caretPosition 光标位置
|
||||||
|
* @param text 文本内容
|
||||||
|
* @return 光标所在列号
|
||||||
|
*/
|
||||||
|
public int getColumn(int caretPosition, String text) {
|
||||||
|
return caretPosition - text.lastIndexOf("\n", caretPosition - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -4,6 +4,8 @@ import javafx.scene.control.Tab;
|
|||||||
import org.jcnc.jnotepad.app.config.GlobalConfig;
|
import org.jcnc.jnotepad.app.config.GlobalConfig;
|
||||||
import org.jcnc.jnotepad.ui.LineNumberTextArea;
|
import org.jcnc.jnotepad.ui.LineNumberTextArea;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 封装标签页组件,增加属于标签页的属性,例如:自动换行开关。
|
* 封装标签页组件,增加属于标签页的属性,例如:自动换行开关。
|
||||||
* 每个Tab关联一个LineNumberTextArea。
|
* 每个Tab关联一个LineNumberTextArea。
|
||||||
@ -17,16 +19,22 @@ public class JNotepadTab extends Tab {
|
|||||||
*/
|
*/
|
||||||
private boolean autoLine = false;
|
private boolean autoLine = false;
|
||||||
private final LineNumberTextArea lineNumberTextArea;
|
private final LineNumberTextArea lineNumberTextArea;
|
||||||
|
private Charset charset = Charset.defaultCharset();
|
||||||
|
|
||||||
public JNotepadTab(String tabTitle) {
|
public JNotepadTab(String tabTitle) {
|
||||||
this(tabTitle, new LineNumberTextArea());
|
this(tabTitle, new LineNumberTextArea());
|
||||||
}
|
}
|
||||||
|
|
||||||
public JNotepadTab(String tabTitle, LineNumberTextArea textArea) {
|
public JNotepadTab(String tabTitle, LineNumberTextArea textArea) {
|
||||||
|
this(tabTitle, textArea, Charset.defaultCharset());
|
||||||
|
}
|
||||||
|
|
||||||
|
public JNotepadTab(String tabTitle, LineNumberTextArea textArea, Charset charset) {
|
||||||
super(tabTitle);
|
super(tabTitle);
|
||||||
lineNumberTextArea = textArea;
|
lineNumberTextArea = textArea;
|
||||||
this.setContent(lineNumberTextArea);
|
this.setContent(lineNumberTextArea);
|
||||||
setAutoLine(GlobalConfig.getConfig().getAutoLineConfig());
|
setAutoLine(GlobalConfig.getConfig().getAutoLineConfig());
|
||||||
|
this.charset = charset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAutoLine() {
|
public boolean isAutoLine() {
|
||||||
@ -41,4 +49,16 @@ public class JNotepadTab extends Tab {
|
|||||||
public LineNumberTextArea getLineNumberTextArea() {
|
public LineNumberTextArea getLineNumberTextArea() {
|
||||||
return lineNumberTextArea;
|
return lineNumberTextArea;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Charset getCharset() {
|
||||||
|
return charset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCharset(Charset charset) {
|
||||||
|
this.charset = charset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save() {
|
||||||
|
this.lineNumberTextArea.save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package org.jcnc.jnotepad.ui.tab;
|
|||||||
import javafx.scene.control.TabPane;
|
import javafx.scene.control.TabPane;
|
||||||
import org.jcnc.jnotepad.app.config.GlobalConfig;
|
import org.jcnc.jnotepad.app.config.GlobalConfig;
|
||||||
import org.jcnc.jnotepad.ui.menu.JNotepadMenuBar;
|
import org.jcnc.jnotepad.ui.menu.JNotepadMenuBar;
|
||||||
|
import org.jcnc.jnotepad.ui.status.JNotepadStatusBox;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 标签页布局组件封装。
|
* 标签页布局组件封装。
|
||||||
@ -25,8 +26,11 @@ public class JNotepadTabPane extends TabPane {
|
|||||||
this.getSelectionModel().selectedItemProperty().addListener(
|
this.getSelectionModel().selectedItemProperty().addListener(
|
||||||
(ov, from, to) -> {
|
(ov, from, to) -> {
|
||||||
if (to != null) {
|
if (to != null) {
|
||||||
|
// 更新菜单栏中与tab相关设置
|
||||||
JNotepadMenuBar.getMenuBar().updateMenuStatusBySelectedTab();
|
JNotepadMenuBar.getMenuBar().updateMenuStatusBySelectedTab();
|
||||||
}
|
}
|
||||||
|
// 更新状态标签
|
||||||
|
JNotepadStatusBox.getInstance().updateWhenTabSelected();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -65,5 +69,6 @@ public class JNotepadTabPane extends TabPane {
|
|||||||
public void fireTabSelected() {
|
public void fireTabSelected() {
|
||||||
JNotepadTab selectedTab = getSelected();
|
JNotepadTab selectedTab = getSelected();
|
||||||
selectedTab.setAutoLine(GlobalConfig.getConfig().getAutoLineConfig());
|
selectedTab.setAutoLine(GlobalConfig.getConfig().getAutoLineConfig());
|
||||||
|
JNotepadStatusBox.getInstance().updateWhenTabSelected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
package org.jcnc.jnotepad.view.init;
|
package org.jcnc.jnotepad.view.init;
|
||||||
|
|
||||||
import org.jcnc.jnotepad.controller.manager.Controller;
|
|
||||||
import org.jcnc.jnotepad.controller.manager.ShortcutKey;
|
import org.jcnc.jnotepad.controller.manager.ShortcutKey;
|
||||||
|
|
||||||
|
|
||||||
@ -9,10 +8,6 @@ import org.jcnc.jnotepad.controller.manager.ShortcutKey;
|
|||||||
*/
|
*/
|
||||||
public class View {
|
public class View {
|
||||||
|
|
||||||
public void initTabPane() {
|
|
||||||
Controller.getInstance().initTabPane();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 初始化快捷键
|
// 初始化快捷键
|
||||||
public void initShortcutKey() {
|
public void initShortcutKey() {
|
||||||
new ShortcutKey().createShortcutKeyByConfig();
|
new ShortcutKey().createShortcutKeyByConfig();
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import javafx.scene.layout.BorderPane;
|
|||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import org.jcnc.jnotepad.exception.AppException;
|
import org.jcnc.jnotepad.exception.AppException;
|
||||||
import org.jcnc.jnotepad.ui.menu.JNotepadMenuBar;
|
import org.jcnc.jnotepad.ui.menu.JNotepadMenuBar;
|
||||||
|
import org.jcnc.jnotepad.ui.status.JNotepadStatusBox;
|
||||||
import org.jcnc.jnotepad.ui.tab.JNotepadTabPane;
|
import org.jcnc.jnotepad.ui.tab.JNotepadTabPane;
|
||||||
|
|
||||||
|
|
||||||
@ -17,11 +18,6 @@ import org.jcnc.jnotepad.ui.tab.JNotepadTabPane;
|
|||||||
*/
|
*/
|
||||||
public class ViewManager {
|
public class ViewManager {
|
||||||
|
|
||||||
/**
|
|
||||||
* 显示文本编码
|
|
||||||
*/
|
|
||||||
private Label enCodingLabel; // 显示文本编码
|
|
||||||
|
|
||||||
private int tabIndex = 0;
|
private int tabIndex = 0;
|
||||||
|
|
||||||
private Boolean line = true;
|
private Boolean line = true;
|
||||||
@ -30,19 +26,13 @@ public class ViewManager {
|
|||||||
// 主界面布局
|
// 主界面布局
|
||||||
private BorderPane root; // 主布局
|
private BorderPane root; // 主布局
|
||||||
|
|
||||||
// 状态栏
|
|
||||||
private Label statusLabel;
|
|
||||||
|
|
||||||
private static ViewManager instance = null;
|
private static ViewManager instance = null;
|
||||||
|
|
||||||
|
|
||||||
public Label getEnCodingLabel() {
|
|
||||||
return enCodingLabel;
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* 自增并获取标签页索引
|
* 自增并获取标签页索引
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* @return int 标签页索引
|
* @return int 标签页索引
|
||||||
* @apiNote ++tabIndex
|
* @apiNote ++tabIndex
|
||||||
*/
|
*/
|
||||||
@ -59,10 +49,6 @@ public class ViewManager {
|
|||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Label getStatusLabel() {
|
|
||||||
return statusLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取ViewManager的实例。如果实例不存在,则创建一个新实例。
|
* 获取ViewManager的实例。如果实例不存在,则创建一个新实例。
|
||||||
@ -109,14 +95,7 @@ public class ViewManager {
|
|||||||
|
|
||||||
// 创建标签页和文本编辑区域
|
// 创建标签页和文本编辑区域
|
||||||
root.setCenter(JNotepadTabPane.getInstance());
|
root.setCenter(JNotepadTabPane.getInstance());
|
||||||
|
root.setBottom(JNotepadStatusBox.getInstance());
|
||||||
// 创建状态栏
|
|
||||||
statusLabel = new Label("行数:1 \t列数:1 \t字数:0 ");
|
|
||||||
|
|
||||||
enCodingLabel = new Label(); // 创建新的标签以显示编码信息
|
|
||||||
HBox statusBox = new HBox(statusLabel, enCodingLabel); // 使用HBox放置状态标签和编码标签
|
|
||||||
root.setBottom(statusBox);
|
|
||||||
BorderPane.setMargin(statusBox, new Insets(5, 10, 5, 10));
|
|
||||||
|
|
||||||
scene.setRoot(root);
|
scene.setRoot(root);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user