commit
32689ddbb3
11
pom.xml
11
pom.xml
@ -16,16 +16,26 @@
|
||||
<javafx.version>20.0.2</javafx.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<!-- https://mvnrepository.com/artifact/org.fxmisc.richtext/richtextfx -->
|
||||
<!--JavaFX 的富文本区域-->
|
||||
<dependency>
|
||||
<groupId>org.fxmisc.richtext</groupId>
|
||||
<artifactId>richtextfx</artifactId>
|
||||
<version>0.11.1</version>
|
||||
</dependency>
|
||||
<!--图标库主依赖-->
|
||||
<dependency>
|
||||
<groupId>org.kordamp.ikonli</groupId>
|
||||
<artifactId>ikonli-javafx</artifactId>
|
||||
<version>12.3.1</version>
|
||||
</dependency>
|
||||
<!--蚂蚁图标库-->
|
||||
<dependency>
|
||||
<groupId>org.kordamp.ikonli</groupId>
|
||||
<artifactId>ikonli-antdesignicons-pack</artifactId>
|
||||
<version>12.3.1</version>
|
||||
</dependency>
|
||||
<!--亚特兰大fx主题-->
|
||||
<dependency>
|
||||
<groupId>io.github.mkpaz</groupId>
|
||||
<artifactId>atlantafx-base</artifactId>
|
||||
@ -66,6 +76,7 @@
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.4.11</version>
|
||||
</dependency>
|
||||
<!--国际化依赖-->
|
||||
<dependency>
|
||||
<groupId>com.ibm.icu</groupId>
|
||||
<artifactId>icu4j</artifactId>
|
||||
|
||||
@ -15,6 +15,7 @@ module org.jcnc.jnotepad {
|
||||
requires org.kordamp.ikonli.core;
|
||||
requires org.kordamp.ikonli.javafx;
|
||||
requires org.kordamp.ikonli.antdesignicons;
|
||||
requires org.fxmisc.richtext;
|
||||
exports org.jcnc.jnotepad;
|
||||
exports org.jcnc.jnotepad.model.enums;
|
||||
exports org.jcnc.jnotepad.app.config;
|
||||
@ -29,6 +30,7 @@ module org.jcnc.jnotepad {
|
||||
exports org.jcnc.jnotepad.common.interfaces;
|
||||
opens org.jcnc.jnotepad.app.config;
|
||||
exports org.jcnc.jnotepad.views.root.center.main.bottom.status;
|
||||
exports org.jcnc.jnotepad.plugin.interfaces;
|
||||
exports org.jcnc.jnotepad.ui.dialog;
|
||||
exports org.jcnc.jnotepad.ui.dialog.interfaces;
|
||||
exports org.jcnc.jnotepad.model.entity;
|
||||
|
||||
@ -121,7 +121,7 @@ public class OpenFile implements EventHandler<ActionEvent> {
|
||||
String text = textBuilder.toString();
|
||||
LogUtil.getLogger(this.getClass()).info("已调用读取文件功能");
|
||||
Platform.runLater(() -> {
|
||||
textArea.getMainTextArea().setText(text);
|
||||
textArea.appendText(text);
|
||||
CenterTab tab = createNewTab(file.getName(), textArea, encoding);
|
||||
// 设置当前标签页关联本地文件
|
||||
tab.setRelevance(true);
|
||||
|
||||
@ -9,7 +9,7 @@ public class PluginInfo {
|
||||
/**
|
||||
* 插件名称
|
||||
*/
|
||||
private String pluginName;
|
||||
private String name;
|
||||
/**
|
||||
* 插件版本
|
||||
*/
|
||||
@ -19,12 +19,17 @@ public class PluginInfo {
|
||||
*/
|
||||
private boolean enabled;
|
||||
|
||||
public String getPluginName() {
|
||||
return pluginName;
|
||||
/**
|
||||
* 主类名称
|
||||
*/
|
||||
private String mainClass;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setPluginName(String pluginName) {
|
||||
this.pluginName = pluginName;
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
@ -42,4 +47,12 @@ public class PluginInfo {
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getMainClass() {
|
||||
return mainClass;
|
||||
}
|
||||
|
||||
public void setMainClass(String mainClass) {
|
||||
this.mainClass = mainClass;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,58 +0,0 @@
|
||||
package org.jcnc.jnotepad.plugin;
|
||||
|
||||
import org.jcnc.jnotepad.plugin.interfaces.Plugin;
|
||||
import org.jcnc.jnotepad.util.LogUtil;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 新按钮插件
|
||||
*
|
||||
* @author luke
|
||||
*/
|
||||
public class ButtonPlugin implements Plugin {
|
||||
|
||||
@Override
|
||||
public String getCategoryName() {
|
||||
return "新按钮插件";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "新按钮";
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化插件
|
||||
*/
|
||||
@Override
|
||||
public void initialize() {
|
||||
LogUtil.getLogger(this.getClass()).info("新按钮插件初始化了!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
// 在这里实现新按钮插件的逻辑
|
||||
LogUtil.getLogger(this.getClass()).info("新按钮插件执行了!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取插件的配置参数
|
||||
*
|
||||
* @return 插件的配置参数
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> getConfig() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置插件的配置参数
|
||||
*
|
||||
* @param config 插件的配置参数
|
||||
*/
|
||||
@Override
|
||||
public void setConfig(Map<String, Object> config) {
|
||||
|
||||
}
|
||||
}
|
||||
@ -8,7 +8,9 @@ import javafx.stage.FileChooser;
|
||||
import javafx.stage.Stage;
|
||||
import org.jcnc.jnotepad.ui.dialog.factory.impl.BasicFileChooserFactory;
|
||||
import org.jcnc.jnotepad.util.LogUtil;
|
||||
import org.jcnc.jnotepad.util.PopUpUtil;
|
||||
import org.jcnc.jnotepad.util.UiUtil;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
@ -22,6 +24,7 @@ import java.util.Map;
|
||||
* @author luke
|
||||
*/
|
||||
public class PluginDemo {
|
||||
Logger logger = LogUtil.getLogger(this.getClass());
|
||||
|
||||
/**
|
||||
* 启动插件演示界面
|
||||
@ -53,8 +56,8 @@ public class PluginDemo {
|
||||
/**
|
||||
* 创建加载插件的按钮
|
||||
*
|
||||
* @param primaryStage JavaFX的主舞台
|
||||
* @param fileChooser 文件选择器
|
||||
* @param primaryStage JavaFX的主舞台
|
||||
* @param fileChooser 文件选择器
|
||||
* @param pluginManager 插件管理器
|
||||
* @return 加载插件的按钮
|
||||
*/
|
||||
@ -65,13 +68,16 @@ public class PluginDemo {
|
||||
File selectedFile = fileChooser.showOpenDialog(primaryStage);
|
||||
if (selectedFile != null) {
|
||||
String pluginFilePath = selectedFile.getAbsolutePath();
|
||||
pluginManager.loadPlugins(pluginFilePath);
|
||||
PluginLoader.getInstance().loadPlugins(pluginFilePath);
|
||||
|
||||
// 更新插件信息显示
|
||||
displayPluginInfo(primaryStage, pluginManager);
|
||||
} else {
|
||||
PopUpUtil.infoAlert(null, null, "未找到插件!", null, null);
|
||||
logger.info("未找到插件!");
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
LogUtil.getLogger(this.getClass()).info("未加载插件!");
|
||||
} catch (Exception e) {
|
||||
logger.error("加载插件失败!", e);
|
||||
}
|
||||
});
|
||||
return loadButton;
|
||||
|
||||
98
src/main/java/org/jcnc/jnotepad/plugin/PluginLoader.java
Normal file
98
src/main/java/org/jcnc/jnotepad/plugin/PluginLoader.java
Normal file
@ -0,0 +1,98 @@
|
||||
package org.jcnc.jnotepad.plugin;
|
||||
|
||||
import org.jcnc.jnotepad.exception.AppException;
|
||||
import org.jcnc.jnotepad.model.entity.PluginInfo;
|
||||
import org.jcnc.jnotepad.plugin.interfaces.Plugin;
|
||||
import org.jcnc.jnotepad.util.JsonUtil;
|
||||
import org.jcnc.jnotepad.util.LogUtil;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
/**
|
||||
* 插件加载类
|
||||
*
|
||||
* @author gewuyou
|
||||
*/
|
||||
public class PluginLoader {
|
||||
private static final PluginLoader INSTANCE = new PluginLoader();
|
||||
Logger logger = LogUtil.getLogger(this.getClass());
|
||||
|
||||
/**
|
||||
* 从插件jar包中读取 json 文件到 PluginInfo 类
|
||||
*
|
||||
* @param pluginJar jar 包
|
||||
*/
|
||||
private static PluginInfo readPlugin(File pluginJar) throws IOException {
|
||||
InputStream is;
|
||||
StringBuilder sb;
|
||||
try (JarFile jarFile = new JarFile(pluginJar)) {
|
||||
ZipEntry zipEntry = jarFile.getEntry("META-INF/plugin.json");
|
||||
is = jarFile.getInputStream(zipEntry);
|
||||
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
|
||||
String temp;
|
||||
sb = new StringBuilder();
|
||||
while ((temp = br.readLine()) != null) {
|
||||
sb.append(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return JsonUtil.OBJECT_MAPPER.readValue(sb.toString(), PluginInfo.class);
|
||||
}
|
||||
|
||||
public static PluginLoader getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载插件
|
||||
*
|
||||
* @param pluginFilePath 插件文件的路径
|
||||
*/
|
||||
public void loadPlugins(String pluginFilePath) {
|
||||
PluginManager pluginManager = PluginManager.getInstance();
|
||||
List<Plugin> plugins = pluginManager.getPlugins();
|
||||
Map<String, List<String>> categories = pluginManager.getLoadedPluginsByCategory();
|
||||
Map<String, PluginInfo> pluginInfos = pluginManager.getPluginInfos();
|
||||
File file = new File(pluginFilePath);
|
||||
if (file.exists() && file.isFile()) {
|
||||
try {
|
||||
PluginInfo pluginInfo = readPlugin(file);
|
||||
pluginInfos.put(pluginInfo.getName(), pluginInfo);
|
||||
// 创建URLClassLoader以加载Jar文件中的类
|
||||
Class<?> pluginClass;
|
||||
try (URLClassLoader classLoader = new URLClassLoader(new URL[]{file.toURI().toURL()})) {
|
||||
pluginClass = classLoader.loadClass(pluginInfo.getMainClass());
|
||||
}
|
||||
if (pluginClass == null) {
|
||||
return;
|
||||
}
|
||||
Plugin plugin;
|
||||
plugin = (Plugin) pluginClass.getDeclaredConstructor().newInstance();
|
||||
plugins.add(plugin);
|
||||
// 添加插件到类别中
|
||||
String categoryName = plugin.getCategoryName();
|
||||
String displayName = plugin.getDisplayName();
|
||||
categories.computeIfAbsent(categoryName, k -> new ArrayList<>()).add(displayName);
|
||||
} catch (IOException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
|
||||
throw new AppException(e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
logger.error("无法找到对应的插件类!", e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
logger.error("插件类中没有找到指定方法!", e);
|
||||
}
|
||||
|
||||
} else {
|
||||
LogUtil.getLogger(this.getClass()).info("PluginInfo file not found: {}", pluginFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,14 +1,10 @@
|
||||
package org.jcnc.jnotepad.plugin;
|
||||
|
||||
import org.jcnc.jnotepad.model.entity.PluginInfo;
|
||||
import org.jcnc.jnotepad.plugin.interfaces.Plugin;
|
||||
import org.jcnc.jnotepad.util.LogUtil;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -33,6 +29,11 @@ public class PluginManager {
|
||||
* 插件类别
|
||||
*/
|
||||
private final Map<String, List<String>> categories = new HashMap<>();
|
||||
/**
|
||||
* 插件信息
|
||||
*/
|
||||
|
||||
private final Map<String, PluginInfo> pluginInfos = new HashMap<>();
|
||||
|
||||
private PluginManager() {
|
||||
|
||||
@ -42,47 +43,6 @@ public class PluginManager {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载插件
|
||||
*
|
||||
* @param pluginFilePath 插件文件的路径
|
||||
*/
|
||||
public void loadPlugins(String pluginFilePath) {
|
||||
File file = new File(pluginFilePath);
|
||||
if (file.exists() && file.isFile()) {
|
||||
// 创建URLClassLoader以加载Jar文件中的类
|
||||
Class<?> pluginClass = null;
|
||||
try (URLClassLoader classLoader = new URLClassLoader(new URL[]{file.toURI().toURL()})) {
|
||||
pluginClass = classLoader.loadClass("org.jcnc.jnotepad.plugin.ButtonPlugin");
|
||||
} catch (ClassNotFoundException e) {
|
||||
logger.error("无法找到对应的插件类!", e);
|
||||
} catch (MalformedURLException e) {
|
||||
logger.error("无法创建URL格式错误!", e);
|
||||
} catch (IOException e) {
|
||||
logger.error("IO异常!", e);
|
||||
}
|
||||
if (pluginClass == null) {
|
||||
return;
|
||||
}
|
||||
Plugin plugin = null;
|
||||
try {
|
||||
plugin = (Plugin) pluginClass.getDeclaredConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
logger.error("发生异常!", e);
|
||||
}
|
||||
if (plugin == null) {
|
||||
return;
|
||||
}
|
||||
plugins.add(plugin);
|
||||
|
||||
// 添加插件到类别中
|
||||
String categoryName = plugin.getCategoryName();
|
||||
String displayName = plugin.getDisplayName();
|
||||
categories.computeIfAbsent(categoryName, k -> new ArrayList<>()).add(displayName);
|
||||
} else {
|
||||
LogUtil.getLogger(this.getClass()).info("PluginInfo file not found: {}", pluginFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 卸载插件
|
||||
@ -122,4 +82,12 @@ public class PluginManager {
|
||||
public Map<String, List<String>> getLoadedPluginsByCategory() {
|
||||
return categories;
|
||||
}
|
||||
|
||||
public List<Plugin> getPlugins() {
|
||||
return plugins;
|
||||
}
|
||||
|
||||
public Map<String, PluginInfo> getPluginInfos() {
|
||||
return pluginInfos;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
package org.jcnc.jnotepad.ui.module;
|
||||
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import org.jcnc.jnotepad.controller.config.AppConfigController;
|
||||
import org.fxmisc.richtext.CodeArea;
|
||||
import org.fxmisc.richtext.LineNumberFactory;
|
||||
import org.jcnc.jnotepad.util.LogUtil;
|
||||
import org.jcnc.jnotepad.views.root.center.main.bottom.status.BottomStatusBox;
|
||||
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTab;
|
||||
@ -22,84 +20,36 @@ import java.io.IOException;
|
||||
*
|
||||
* @author luke
|
||||
*/
|
||||
public class LineNumberTextArea extends BorderPane {
|
||||
public class LineNumberTextArea extends CodeArea {
|
||||
|
||||
/**
|
||||
* 用于确定行号区域宽度的大小表格,每个元素表示不同的行数范围
|
||||
*/
|
||||
private static final int[] SIZE_TABLE = {9, 99, 999, 9999, 99999, 999999, 9999999,
|
||||
99999999, 999999999, Integer.MAX_VALUE};
|
||||
|
||||
/**
|
||||
* 用于记录日志的静态Logger对象
|
||||
*/
|
||||
private static final Logger logger = LogUtil.getLogger(LineNumberTextArea.class);
|
||||
|
||||
/**
|
||||
* 行号区域的最小宽度
|
||||
*/
|
||||
private static final int MIN_LINE_NUMBER_WIDTH = 30;
|
||||
|
||||
/**
|
||||
* 主文本区域的TextArea实例
|
||||
*/
|
||||
private final TextArea mainTextArea = new TextArea();
|
||||
|
||||
/**
|
||||
* 行号区域的TextArea实例
|
||||
*/
|
||||
private final TextArea lineNumberArea = new TextArea();
|
||||
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* <p>
|
||||
* 用于创建 LineNumberTextArea 对象
|
||||
*/
|
||||
public LineNumberTextArea() {
|
||||
// 设置主文本区域是否自动换行,根据应用配置决定
|
||||
mainTextArea.setWrapText(AppConfigController.getInstance().getAutoLineConfig());
|
||||
|
||||
// 设置行号区域不可编辑
|
||||
lineNumberArea.setEditable(false);
|
||||
|
||||
// 设置行号区域的首选宽度和最小宽度为最小行号宽度
|
||||
lineNumberArea.setPrefWidth(MIN_LINE_NUMBER_WIDTH);
|
||||
lineNumberArea.setMinWidth(MIN_LINE_NUMBER_WIDTH);
|
||||
|
||||
// 为行号区域和主文本区域添加CSS样式类
|
||||
lineNumberArea.getStyleClass().add("text-line-number");
|
||||
mainTextArea.getStyleClass().add("main-text-area");
|
||||
|
||||
// 设置 LineNumberTextArea 的样式,包括边框和背景颜色
|
||||
this.setStyle(
|
||||
"-fx-border-color:white;" +
|
||||
"-fx-background-color:white"
|
||||
);
|
||||
|
||||
// 初始化监听器,用于处理事件
|
||||
this.setParagraphGraphicFactory(LineNumberFactory.get(this));
|
||||
initListeners();
|
||||
// 将主文本区域设置为中央内容,将行号区域设置为左侧内容
|
||||
setCenter(mainTextArea);
|
||||
setLeft(lineNumberArea);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化监听器方法
|
||||
*/
|
||||
private void initListeners() {
|
||||
// 监听主要文本区域的滚动位置变化
|
||||
mainTextArea.scrollTopProperty().addListener((observable, oldValue, newValue) -> lineNumberArea.setScrollTop(mainTextArea.getScrollTop()));
|
||||
// 监听行号文本区域的滚动位置变化
|
||||
lineNumberArea.scrollTopProperty().addListener((observable, oldValue, newValue) -> mainTextArea.setScrollTop(lineNumberArea.getScrollTop()));
|
||||
// 监听行号文本区域的文本变化
|
||||
lineNumberArea.textProperty().addListener((observable, oldValue, newValue) -> updateLineNumberWidth());
|
||||
// 监听主要文本区域的光标位置变化
|
||||
this.mainTextArea.caretPositionProperty().addListener((caretObservable, oldPosition, newPosition) -> BottomStatusBox.getInstance().updateWordCountStatusLabel());
|
||||
// 监听主要文本区域的文本变化
|
||||
this.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||
updateLineNumberArea();
|
||||
BottomStatusBox.getInstance().updateWordCountStatusLabel();
|
||||
save();
|
||||
});
|
||||
@ -121,7 +71,7 @@ public class LineNumberTextArea extends BorderPane {
|
||||
File file = (File) tab.getUserData();
|
||||
|
||||
// 获取主文本区域中的文本内容
|
||||
String newValue = this.mainTextArea.getText();
|
||||
String newValue = this.getText();
|
||||
|
||||
// 如果文件对象为空,记录警告信息并返回,不执行保存操作
|
||||
if (file == null) {
|
||||
@ -140,90 +90,4 @@ public class LineNumberTextArea extends BorderPane {
|
||||
LogUtil.getLogger(this.getClass()).info("已忽视IO异常!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 更新行号宽度方法
|
||||
*/
|
||||
private void updateLineNumberWidth() {
|
||||
// 获取主文本区域的段落数量,即文本的行数
|
||||
int numOfLines = mainTextArea.getParagraphs().size();
|
||||
|
||||
// 初始化一个计数器,用于确定适合的行号宽度
|
||||
int count = 1;
|
||||
|
||||
// 遍历行号宽度大小的表格
|
||||
for (int i = 0; i < SIZE_TABLE.length; i++) {
|
||||
// 检查文本行数是否在当前表格项的范围内
|
||||
if (numOfLines <= SIZE_TABLE[i]) {
|
||||
// 如果是,设置计数器为当前索引+1并退出循环
|
||||
count = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 计算实际的行号区域宽度,确保不小于一个最小宽度值
|
||||
int actualWidth = Math.max(count * 10 + 11, MIN_LINE_NUMBER_WIDTH);
|
||||
|
||||
// 检查实际宽度是否与当前行号区域的宽度不同
|
||||
if (actualWidth != lineNumberArea.getWidth()) {
|
||||
// 如果不同,设置行号区域的首选宽度为实际宽度
|
||||
lineNumberArea.setPrefWidth(actualWidth);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取主要文本区域的text属性
|
||||
*
|
||||
* @return 主要文本区域的text属性
|
||||
*/
|
||||
public StringProperty textProperty() {
|
||||
return mainTextArea.textProperty();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新行号区域方法
|
||||
*/
|
||||
private void updateLineNumberArea() {
|
||||
// 获取主文本区域的垂直滚动位置
|
||||
double mainTextAreaScrollTop = mainTextArea.getScrollTop();
|
||||
|
||||
// 获取行号区域的垂直滚动位置
|
||||
double lineNumberAreaScrollTop = lineNumberArea.getScrollTop();
|
||||
|
||||
// 获取主文本区域的段落数量,即文本的行数
|
||||
int numOfLines = mainTextArea.getParagraphs().size();
|
||||
|
||||
// 用于构建行号文本的字符串构建器
|
||||
StringBuilder lineNumberText = new StringBuilder();
|
||||
|
||||
// 循环迭代,生成行号文本,
|
||||
for (int i = 1; i <= numOfLines; i++) {
|
||||
// 将行号和换行符添加到字符串中
|
||||
lineNumberText.append(i);
|
||||
if (i != numOfLines) {
|
||||
lineNumberText.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// 将生成的行号文本设置到 行号区域
|
||||
lineNumberArea.setText(lineNumberText.toString());
|
||||
|
||||
// 恢复主文本区域的垂直滚动位置
|
||||
mainTextArea.setScrollTop(mainTextAreaScrollTop);
|
||||
|
||||
// 恢复行号区域的垂直滚动位置
|
||||
lineNumberArea.setScrollTop(lineNumberAreaScrollTop);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取主要文本区域
|
||||
*
|
||||
* @return 主要文本区域
|
||||
*/
|
||||
public TextArea getMainTextArea() {
|
||||
return mainTextArea;
|
||||
}
|
||||
}
|
||||
@ -3,10 +3,10 @@ package org.jcnc.jnotepad.views.root.center.main.bottom.status;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextArea;
|
||||
import org.jcnc.jnotepad.app.i18n.UiResourceBundle;
|
||||
import org.jcnc.jnotepad.common.constants.TextConstants;
|
||||
import org.jcnc.jnotepad.ui.module.AbstractHorizontalBox;
|
||||
import org.jcnc.jnotepad.ui.module.LineNumberTextArea;
|
||||
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTab;
|
||||
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTabPane;
|
||||
|
||||
@ -94,7 +94,7 @@ public class BottomStatusBox extends AbstractHorizontalBox {
|
||||
if (instance.getSelected() == null) {
|
||||
return;
|
||||
}
|
||||
TextArea textArea = instance.getSelected().getLineNumberTextArea().getMainTextArea();
|
||||
LineNumberTextArea textArea = instance.getSelected().getLineNumberTextArea();
|
||||
int caretPosition = textArea.getCaretPosition();
|
||||
int row = getRow(caretPosition, textArea.getText());
|
||||
int column = getColumn(caretPosition, textArea.getText());
|
||||
|
||||
@ -56,7 +56,7 @@ public class CenterTab extends Tab {
|
||||
|
||||
public void setAutoLine(boolean autoLine) {
|
||||
this.autoLine = autoLine;
|
||||
lineNumberTextArea.getMainTextArea().setWrapText(autoLine);
|
||||
lineNumberTextArea.setWrapText(autoLine);
|
||||
}
|
||||
|
||||
public LineNumberTextArea getLineNumberTextArea() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user