commit
8f18ba598b
@ -2,4 +2,7 @@ module org.jcnc.jnotepad {
|
||||
requires javafx.controls;
|
||||
|
||||
exports org.jcnc.jnotepad;
|
||||
exports org.jcnc.jnotepad.controller;
|
||||
exports org.jcnc.jnotepad.tool;
|
||||
exports org.jcnc.jnotepad.Interface;
|
||||
}
|
||||
@ -5,7 +5,6 @@ package org.jcnc.jnotepad;
|
||||
*/
|
||||
|
||||
public class Constants {
|
||||
|
||||
public static final double SCREEN_WIDTH = 800; //宽度
|
||||
public static final double SCREEN_LENGTH = 600; //高度
|
||||
public static final String APP_NAME = "JNotepad"; //名字
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
package org.jcnc.jnotepad.Interface;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.scene.control.TextArea;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public interface ControllerInterface {
|
||||
|
||||
TextArea openAssociatedFileAndCreateTextArea(List<String> rawParameters);
|
||||
|
||||
EventHandler<ActionEvent> getLineFeedEventHandler(TextArea textArea);
|
||||
|
||||
EventHandler<ActionEvent> getNewFileEventHandler(TextArea textArea);
|
||||
|
||||
EventHandler<ActionEvent> getOpenFileEventHandler();
|
||||
|
||||
void autoSave(TextArea textArea);
|
||||
|
||||
EventHandler<ActionEvent> getSaveFileEventHandler();
|
||||
|
||||
EventHandler<ActionEvent> getSaveAsFileEventHandler();
|
||||
|
||||
void saveAsFile();
|
||||
|
||||
void updateStatusLabel(TextArea textArea);
|
||||
|
||||
void openAssociatedFile(String filePath);
|
||||
|
||||
void getText(File file);
|
||||
|
||||
void upDateEncodingLabel(String text);
|
||||
|
||||
int getRow(int caretPosition, String text);
|
||||
|
||||
int getColumn(int caretPosition, String text);
|
||||
}
|
||||
@ -16,10 +16,15 @@ import java.util.Objects;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import static org.jcnc.jnotepad.view.View.initItem;
|
||||
import static org.jcnc.jnotepad.view.View.initTabPane;
|
||||
|
||||
public class LunchApp extends Application {
|
||||
private static final ExecutorService threadPool = Executors.newCachedThreadPool();
|
||||
public static boolean isRelevance = true;
|
||||
|
||||
Controller controller = new Controller();
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) {
|
||||
Pane root = new Pane();
|
||||
@ -42,14 +47,14 @@ public class LunchApp extends Application {
|
||||
viewManager.initScreen(scene);
|
||||
|
||||
// 初始化菜单项和标签栏
|
||||
View.initItem();
|
||||
View.initTabPane();
|
||||
initItem();
|
||||
initTabPane();
|
||||
|
||||
if (isRelevance) {
|
||||
// 使用线程池加载关联文件并创建文本区域
|
||||
List<String> rawParameters = getParameters().getRaw();
|
||||
threadPool.execute(() -> {
|
||||
TextArea textArea = Controller.openAssociatedFileAndCreateTextArea(rawParameters);
|
||||
TextArea textArea = controller.openAssociatedFileAndCreateTextArea(rawParameters);
|
||||
Platform.runLater(() -> updateUIWithNewTextArea(textArea));
|
||||
});
|
||||
}
|
||||
@ -60,7 +65,7 @@ public class LunchApp extends Application {
|
||||
tab.setContent(textArea);
|
||||
ViewManager.tabPane.getTabs().add(tab);
|
||||
ViewManager.tabPane.getSelectionModel().select(tab);
|
||||
Controller.updateStatusLabel(textArea);
|
||||
controller.updateStatusLabel(textArea);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -5,7 +5,6 @@ import javafx.scene.Scene;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import org.jcnc.jnotepad.controller.Controller;
|
||||
|
||||
/**
|
||||
* 该类管理记事本应用程序的视图组件。
|
||||
|
||||
@ -7,160 +7,74 @@ import javafx.event.EventHandler;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.stage.FileChooser;
|
||||
import org.jcnc.jnotepad.Interface.ControllerInterface;
|
||||
import org.jcnc.jnotepad.LunchApp;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jcnc.jnotepad.ViewManager.*;
|
||||
import static org.jcnc.jnotepad.controller.EncodingDetector.detectEncoding;
|
||||
import static org.jcnc.jnotepad.tool.EncodingDetector.detectEncoding;
|
||||
|
||||
/**
|
||||
* 控制器类负责处理与用户界面的交互,并实现相关事件处理逻辑。
|
||||
*/
|
||||
public class Controller {
|
||||
public class Controller implements ControllerInterface {
|
||||
|
||||
/**
|
||||
* 打开关联文件并创建一个文本编辑区。
|
||||
*
|
||||
* @param rawParameters 文件路径参数的列表
|
||||
* @return 创建的文本编辑区
|
||||
*/
|
||||
public static TextArea openAssociatedFileAndCreateTextArea(List<String> rawParameters) {
|
||||
@Override
|
||||
public TextArea openAssociatedFileAndCreateTextArea(List<String> rawParameters) {
|
||||
if (!rawParameters.isEmpty()) {
|
||||
String filePath = rawParameters.get(0);
|
||||
openAssociatedFile(filePath); //// 调用关联文件打开方法
|
||||
openAssociatedFile(filePath);
|
||||
}
|
||||
|
||||
TextArea textArea = new TextArea(); // 创建新的文本编辑区
|
||||
TextArea textArea = createNewTextArea();
|
||||
configureTextArea(textArea);
|
||||
|
||||
// 自动换行
|
||||
textArea.setWrapText(true);
|
||||
upDateEncodingLabel(textArea.getText()); // 更新文本编码信息
|
||||
updateStatusLabel(textArea);
|
||||
|
||||
// 添加文本变更监听器
|
||||
textArea.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||
// 更新状态栏信息
|
||||
updateStatusLabel(textArea);
|
||||
});
|
||||
autoSave(textArea); // 自动保存
|
||||
return textArea;
|
||||
}
|
||||
|
||||
public static class LineFeedEventHandler implements EventHandler<ActionEvent> {
|
||||
private final TextArea textArea;
|
||||
private boolean wrapText = true;
|
||||
|
||||
public LineFeedEventHandler(TextArea textArea) {
|
||||
this.textArea = textArea;
|
||||
@Override
|
||||
public EventHandler<ActionEvent> getLineFeedEventHandler(TextArea textArea) {
|
||||
return new LineFeedEventHandler(textArea);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(ActionEvent event) {
|
||||
wrapText = !wrapText; // 切换自动换行状态
|
||||
textArea.setWrapText(wrapText);
|
||||
}
|
||||
public EventHandler<ActionEvent> getNewFileEventHandler(TextArea textArea) {
|
||||
return new NewFileEventHandler();
|
||||
}
|
||||
|
||||
|
||||
// 新建文件事件处理器
|
||||
public static class NewFileEventHandler implements EventHandler<ActionEvent> {
|
||||
@Override
|
||||
public void handle(ActionEvent event) {
|
||||
TextArea textArea = new TextArea(); // 创建新的文本编辑区
|
||||
Tab tab = new Tab("新建文本 " + ++tabIndex); // 创建新的Tab页
|
||||
tab.setContent(textArea);
|
||||
tabPane.getTabs().add(tab);
|
||||
tabPane.getSelectionModel().select(tab);
|
||||
updateStatusLabel(textArea);
|
||||
// 更新编码信息
|
||||
upDateEncodingLabel(textArea.getText()); // 更新文本编码信息
|
||||
}
|
||||
public EventHandler<ActionEvent> getOpenFileEventHandler() {
|
||||
return new OpenFileEventHandler();
|
||||
}
|
||||
|
||||
// 打开文件事件处理器
|
||||
public static class OpenFileEventHandler implements EventHandler<ActionEvent> {
|
||||
@Override
|
||||
public void handle(ActionEvent event) {
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
File file = fileChooser.showOpenDialog(null);
|
||||
if (file != null) {
|
||||
Task<Void> openFileTask = new Task<>() {
|
||||
@Override
|
||||
protected Void call() {
|
||||
getText(file);
|
||||
upDateEncodingLabel(((TextArea) tabPane.getSelectionModel().getSelectedItem().getContent()).getText());
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
openFileTask.setOnSucceeded(e -> {
|
||||
// 在需要时处理成功
|
||||
});
|
||||
|
||||
openFileTask.setOnFailed(e -> {
|
||||
// 在需要时处理失败
|
||||
});
|
||||
|
||||
Thread thread = new Thread(openFileTask);
|
||||
thread.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 自动保存方法
|
||||
public static void autoSave(TextArea textArea) {
|
||||
public void autoSave(TextArea textArea) {
|
||||
textArea.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||
Tab tab = tabPane.getSelectionModel().getSelectedItem();
|
||||
if (tab != null) {
|
||||
File f = (File) tab.getUserData();
|
||||
if (f != null) {
|
||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter(f))) {
|
||||
File file = (File) tab.getUserData();
|
||||
if (file != null) {
|
||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
|
||||
writer.write(newValue);
|
||||
} catch (IOException ignored) {
|
||||
// 适当地处理异常
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 保存文件事件处理器
|
||||
public static class SaveFileEventHandler implements EventHandler<ActionEvent> {
|
||||
@Override
|
||||
public void handle(ActionEvent event) {
|
||||
Tab selectedTab = tabPane.getSelectionModel().getSelectedItem();
|
||||
if (selectedTab != null) {
|
||||
File file = (File) selectedTab.getUserData();
|
||||
if (file == null) {
|
||||
saveAsFile();
|
||||
} else {
|
||||
try {
|
||||
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8));
|
||||
TextArea textArea = (TextArea) selectedTab.getContent();
|
||||
String text = textArea.getText();
|
||||
writer.write(text);
|
||||
writer.flush();
|
||||
writer.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public EventHandler<ActionEvent> getSaveFileEventHandler() {
|
||||
return new SaveFileEventHandler();
|
||||
}
|
||||
|
||||
// 另存为文件事件处理器
|
||||
public static class SaveAsFileEventHandler implements EventHandler<ActionEvent> {
|
||||
@Override
|
||||
public void handle(ActionEvent event) {
|
||||
saveAsFile();
|
||||
}
|
||||
public EventHandler<ActionEvent> getSaveAsFileEventHandler() {
|
||||
return new SaveAsFileEventHandler();
|
||||
}
|
||||
|
||||
// 另存为文件方法
|
||||
public static void saveAsFile() {
|
||||
@Override
|
||||
public void saveAsFile() {
|
||||
Tab selectedTab = tabPane.getSelectionModel().getSelectedItem();
|
||||
if (selectedTab != null) {
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
@ -168,45 +82,32 @@ public class Controller {
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("文本文档", "*.txt"));
|
||||
File file = fileChooser.showSaveDialog(null);
|
||||
if (file != null) {
|
||||
try {
|
||||
BufferedWriter writer = new BufferedWriter(new FileWriter(file));
|
||||
TextArea textArea = (TextArea) selectedTab.getContent(); // 获取当前Tab页的文本编辑区
|
||||
autoSave(textArea);// 自动保存
|
||||
String text = textArea.getText();
|
||||
writer.write(text); // 写入文件内容
|
||||
writer.flush();
|
||||
writer.close();
|
||||
selectedTab.setText(file.getName()); // 更新Tab页标签上的文件名
|
||||
selectedTab.setUserData(file); // 将文件对象保存到Tab页的UserData中
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
saveFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新状态栏标签信息
|
||||
public static void updateStatusLabel(TextArea textArea) {
|
||||
@Override
|
||||
public void updateStatusLabel(TextArea textArea) {
|
||||
int caretPosition = textArea.getCaretPosition();
|
||||
int row = getRow(caretPosition, textArea.getText());
|
||||
int column = getColumn(caretPosition, textArea.getText());
|
||||
int length = textArea.getLength();
|
||||
statusLabel.setText("行: " + row + " \t列: " + column + " \t字数: " + length);
|
||||
System.out.println(" 正在监测字数");
|
||||
}
|
||||
|
||||
// 关联文件打开
|
||||
public static void openAssociatedFile(String filePath) {
|
||||
// 根据给定的文件路径打开关联文件
|
||||
@Override
|
||||
public void openAssociatedFile(String filePath) {
|
||||
File file = new File(filePath);
|
||||
if (file.exists() && file.isFile()) {
|
||||
LunchApp.isRelevance = false;
|
||||
getText(file);// 调用读取文件方法
|
||||
upDateEncodingLabel(((TextArea) tabPane.getSelectionModel().getSelectedItem().getContent()).getText()); // 更新文本编码信息
|
||||
openFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
public static void getText(File file) {
|
||||
TextArea textArea = new TextArea();
|
||||
@Override
|
||||
public void getText(File file) {
|
||||
TextArea textArea = createNewTextArea();
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
||||
StringBuilder textBuilder = new StringBuilder();
|
||||
String line;
|
||||
@ -218,48 +119,26 @@ public class Controller {
|
||||
Platform.runLater(() -> {
|
||||
textArea.setText(text);
|
||||
|
||||
Tab tab = new Tab(file.getName());
|
||||
tab.setContent(textArea);
|
||||
tab.setUserData(file);
|
||||
|
||||
Tab tab = createNewTab(file.getName(), textArea);
|
||||
tabPane.getTabs().add(tab);
|
||||
tabPane.getSelectionModel().select(tab);
|
||||
updateStatusLabel(textArea);
|
||||
|
||||
autoSave(textArea); // 在更新界面后调用 autoSave
|
||||
autoSave(textArea);
|
||||
});
|
||||
} catch (IOException ignored) {
|
||||
// 适当地处理异常
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// 更新文本编码标签信息
|
||||
public static void upDateEncodingLabel(String text) {
|
||||
@Override
|
||||
public void upDateEncodingLabel(String text) {
|
||||
String encoding = detectEncoding(text);
|
||||
enCodingLabel.setText("\t编码: " + encoding);
|
||||
}
|
||||
|
||||
/* // 判断编码是否有效
|
||||
public static boolean isEncodingValid(String text, Charset encoding) {
|
||||
byte[] bytes = text.getBytes(encoding);
|
||||
String decodedText = new String(bytes, encoding);
|
||||
return text.equals(decodedText);
|
||||
}*/
|
||||
|
||||
/* // 检测文本编码
|
||||
public static String detectEncoding(String text) {
|
||||
Charset[] possibleEncodings = {StandardCharsets.UTF_8, StandardCharsets.ISO_8859_1, StandardCharsets.UTF_16};
|
||||
for (Charset encoding : possibleEncodings) {
|
||||
if (isEncodingValid(text, Charset.forName(String.valueOf(encoding)))) {
|
||||
System.out.println("正在检测编码");
|
||||
return encoding.displayName();
|
||||
}
|
||||
}
|
||||
return "未知";
|
||||
}*/
|
||||
|
||||
// 获取光标所在行数
|
||||
public static int getRow(int caretPosition, String text) {
|
||||
@Override
|
||||
public int getRow(int caretPosition, String text) {
|
||||
caretPosition = Math.min(caretPosition, text.length());
|
||||
String substring = text.substring(0, caretPosition);
|
||||
int count = 0;
|
||||
@ -268,12 +147,54 @@ public class Controller {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count + 1; // Add 1 for the current line
|
||||
return count + 1;
|
||||
}
|
||||
|
||||
|
||||
// 获取光标所在列数
|
||||
public static int getColumn(int caretPosition, String text) {
|
||||
@Override
|
||||
public int getColumn(int caretPosition, String text) {
|
||||
return caretPosition - text.lastIndexOf("\n", caretPosition - 1);
|
||||
}
|
||||
|
||||
private void configureTextArea(TextArea textArea) {
|
||||
textArea.setWrapText(true);
|
||||
upDateEncodingLabel(textArea.getText());
|
||||
updateStatusLabel(textArea);
|
||||
|
||||
textArea.textProperty().addListener((observable, oldValue, newValue) -> updateStatusLabel(textArea));
|
||||
|
||||
autoSave(textArea);
|
||||
}
|
||||
|
||||
private TextArea createNewTextArea() {
|
||||
return new TextArea();
|
||||
}
|
||||
|
||||
private Tab createNewTab(String tabName, TextArea textArea) {
|
||||
Tab tab = new Tab(tabName);
|
||||
tab.setContent(textArea);
|
||||
tab.setUserData(null);
|
||||
return tab;
|
||||
}
|
||||
|
||||
private Task<Void> createOpenFileTask(File file) {
|
||||
TextArea textArea = createNewTextArea();
|
||||
return new Task<>() {
|
||||
@Override
|
||||
protected Void call() {
|
||||
getText(file);
|
||||
upDateEncodingLabel(textArea.getText());
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void openFile(File file) {
|
||||
Task<Void> openFileTask = createOpenFileTask(file);
|
||||
Thread thread = new Thread(openFileTask);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
private void saveFile() {
|
||||
new SaveFileEventHandler();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,47 +0,0 @@
|
||||
package org.jcnc.jnotepad.controller;
|
||||
|
||||
import javafx.scene.control.TextArea;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class EncodingDetector {
|
||||
|
||||
public static String detectEncoding(TextArea textArea) {
|
||||
String text = textArea.getText();
|
||||
|
||||
return detectEncoding(text);
|
||||
}
|
||||
|
||||
public static String detectEncoding(String text) {
|
||||
// 尝试常见的编码
|
||||
for (Charset charset : commonCharsets()) {
|
||||
if (isValidEncoding(text, charset)) {
|
||||
System.out.println(isValidEncoding(text, charset));
|
||||
return charset.name();
|
||||
}
|
||||
}
|
||||
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
private static Charset[] commonCharsets() {
|
||||
return new Charset[] {
|
||||
StandardCharsets.UTF_8,
|
||||
StandardCharsets.UTF_16,
|
||||
StandardCharsets.UTF_16LE,
|
||||
StandardCharsets.UTF_16BE,
|
||||
StandardCharsets.ISO_8859_1
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean isValidEncoding(String text, Charset encoding) {
|
||||
// 尝试使用指定编码解码
|
||||
byte[] bytes = text.getBytes(encoding);
|
||||
String decoded = new String(bytes, encoding);
|
||||
|
||||
|
||||
// 解码后的文本相同表示编码有效
|
||||
return text.equals(decoded);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package org.jcnc.jnotepad.controller;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.scene.control.TextArea;
|
||||
|
||||
public class LineFeedEventHandler implements EventHandler<ActionEvent> {
|
||||
private final TextArea textArea;
|
||||
|
||||
public LineFeedEventHandler(TextArea textArea) {
|
||||
this.textArea = textArea;
|
||||
}
|
||||
@Override
|
||||
public void handle(ActionEvent event) {
|
||||
String text = textArea.getText();
|
||||
textArea.setText(text + "\n");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package org.jcnc.jnotepad.controller;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TextArea;
|
||||
import org.jcnc.jnotepad.ViewManager;
|
||||
|
||||
import static org.jcnc.jnotepad.ViewManager.tabPane;
|
||||
|
||||
public class NewFileEventHandler implements EventHandler<ActionEvent> {
|
||||
@Override
|
||||
public void handle(ActionEvent event) {
|
||||
Controller controller = new Controller();
|
||||
TextArea textArea = new TextArea(); // 创建新的文本编辑区
|
||||
Tab tab = new Tab("新建文本 " + ++ViewManager.tabIndex); // 创建新的Tab页
|
||||
tab.setContent(textArea);
|
||||
tabPane.getTabs().add(tab);
|
||||
tabPane.getSelectionModel().select(tab);
|
||||
controller.updateStatusLabel(textArea);
|
||||
// 更新编码信息
|
||||
controller.upDateEncodingLabel(textArea.getText()); // 更新文本编码信息
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package org.jcnc.jnotepad.controller;
|
||||
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.stage.FileChooser;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static org.jcnc.jnotepad.ViewManager.tabPane;
|
||||
|
||||
// 打开文件事件处理器
|
||||
public class OpenFileEventHandler implements EventHandler<ActionEvent> {
|
||||
@Override
|
||||
public void handle(ActionEvent event) {
|
||||
Controller controller = new Controller();
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
File file = fileChooser.showOpenDialog(null);
|
||||
if (file != null) {
|
||||
Task<Void> openFileTask = new Task<>() {
|
||||
@Override
|
||||
protected Void call() {
|
||||
controller.getText(file);
|
||||
controller.upDateEncodingLabel(((TextArea) tabPane.getSelectionModel().getSelectedItem().getContent()).getText());
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
openFileTask.setOnSucceeded(e -> {
|
||||
// 在需要时处理成功
|
||||
});
|
||||
|
||||
openFileTask.setOnFailed(e -> {
|
||||
// 在需要时处理失败
|
||||
});
|
||||
|
||||
Thread thread = new Thread(openFileTask);
|
||||
thread.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package org.jcnc.jnotepad.controller;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.stage.FileChooser;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.jcnc.jnotepad.ViewManager.tabPane;
|
||||
|
||||
public class SaveAsFileEventHandler implements EventHandler<ActionEvent> {
|
||||
@Override
|
||||
public void handle(ActionEvent event) {
|
||||
Controller controller = new Controller();
|
||||
Tab selectedTab = tabPane.getSelectionModel().getSelectedItem();
|
||||
if (selectedTab != null) {
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.setInitialFileName("新建文本");
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("文本文档", "*.txt"));
|
||||
File file = fileChooser.showSaveDialog(null);
|
||||
if (file != null) {
|
||||
try {
|
||||
BufferedWriter writer = new BufferedWriter(new FileWriter(file));
|
||||
TextArea textArea = (TextArea) selectedTab.getContent(); // 获取当前Tab页的文本编辑区
|
||||
controller.autoSave(textArea);// 自动保存
|
||||
String text = textArea.getText();
|
||||
writer.write(text); // 写入文件内容
|
||||
writer.flush();
|
||||
writer.close();
|
||||
selectedTab.setText(file.getName()); // 更新Tab页标签上的文件名
|
||||
selectedTab.setUserData(file); // 将文件对象保存到Tab页的UserData中
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package org.jcnc.jnotepad.controller;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TextArea;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static org.jcnc.jnotepad.ViewManager.tabPane;
|
||||
|
||||
// 保存文件事件处理器
|
||||
public class SaveFileEventHandler implements EventHandler<ActionEvent> {
|
||||
@Override
|
||||
public void handle(ActionEvent event) {
|
||||
Controller controller = new Controller();
|
||||
Tab selectedTab = tabPane.getSelectionModel().getSelectedItem();
|
||||
if (selectedTab != null) {
|
||||
File file = (File) selectedTab.getUserData();
|
||||
if (file == null) {
|
||||
controller.saveAsFile();
|
||||
} else {
|
||||
try {
|
||||
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8));
|
||||
TextArea textArea = (TextArea) selectedTab.getContent();
|
||||
String text = textArea.getText();
|
||||
writer.write(text);
|
||||
writer.flush();
|
||||
writer.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
48
src/main/java/org/jcnc/jnotepad/tool/EncodingDetector.java
Normal file
48
src/main/java/org/jcnc/jnotepad/tool/EncodingDetector.java
Normal file
@ -0,0 +1,48 @@
|
||||
package org.jcnc.jnotepad.tool;
|
||||
|
||||
import javafx.scene.control.TextArea;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class EncodingDetector {
|
||||
|
||||
public static String detectEncoding(TextArea textArea) {
|
||||
String text = textArea.getText();
|
||||
|
||||
return detectEncoding(text);
|
||||
}
|
||||
|
||||
public static String detectEncoding(String text) {
|
||||
// 尝试常见的编码
|
||||
for (Charset charset : commonCharsets()) {
|
||||
if (isValidEncoding(text, charset)) {
|
||||
System.out.println(isValidEncoding(text, charset));
|
||||
return charset.name();
|
||||
}
|
||||
}
|
||||
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
private static Charset[] commonCharsets() {
|
||||
return new Charset[]{
|
||||
StandardCharsets.UTF_8,
|
||||
StandardCharsets.UTF_16,
|
||||
StandardCharsets.UTF_16LE,
|
||||
StandardCharsets.UTF_16BE,
|
||||
StandardCharsets.ISO_8859_1
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean isValidEncoding(String text, Charset encoding) {
|
||||
// 尝试使用指定编码解码
|
||||
byte[] bytes = text.getBytes(encoding);
|
||||
String decoded = new String(bytes, encoding);
|
||||
|
||||
|
||||
// 解码后的文本相同表示编码有效
|
||||
return text.equals(decoded);
|
||||
}
|
||||
|
||||
}
|
||||
@ -4,36 +4,38 @@ import javafx.scene.control.TextArea;
|
||||
import org.jcnc.jnotepad.controller.Controller;
|
||||
|
||||
import static org.jcnc.jnotepad.ViewManager.*;
|
||||
import static org.jcnc.jnotepad.controller.Controller.upDateEncodingLabel;
|
||||
import static org.jcnc.jnotepad.controller.Controller.updateStatusLabel;
|
||||
|
||||
|
||||
public class View {
|
||||
|
||||
public static void initItem() {
|
||||
// 初始化菜单项的事件处理器
|
||||
newItem.setOnAction(new Controller.NewFileEventHandler());
|
||||
openItem.setOnAction(new Controller.OpenFileEventHandler());
|
||||
saveItem.setOnAction(new Controller.SaveFileEventHandler());
|
||||
saveAsItem.setOnAction(new Controller.SaveAsFileEventHandler());
|
||||
lineFeedItem.setOnAction(new Controller.LineFeedEventHandler(new TextArea()));
|
||||
newItem.setOnAction(new Controller().getNewFileEventHandler(new TextArea()));
|
||||
openItem.setOnAction(new Controller().getOpenFileEventHandler());
|
||||
saveItem.setOnAction(new Controller().getSaveFileEventHandler());
|
||||
saveAsItem.setOnAction(new Controller().getSaveAsFileEventHandler());
|
||||
lineFeedItem.setOnAction(new Controller().getLineFeedEventHandler(new TextArea()));
|
||||
|
||||
}
|
||||
|
||||
public static void initTabPane() {
|
||||
Controller controller = new Controller();
|
||||
|
||||
tabPane.getSelectionModel().selectedItemProperty().addListener((observable, oldTab, newTab) -> {
|
||||
if (newTab != null) {
|
||||
// 获取新选定的标签页并关联的文本区域
|
||||
TextArea textArea = (TextArea) newTab.getContent();
|
||||
|
||||
// 更新状态标签
|
||||
updateStatusLabel(textArea);
|
||||
controller.updateStatusLabel(textArea);
|
||||
|
||||
// 监听文本光标位置的变化,更新状态标签
|
||||
textArea.caretPositionProperty().addListener((caretObservable, oldPosition, newPosition) -> updateStatusLabel(textArea));
|
||||
textArea.caretPositionProperty().addListener((caretObservable, oldPosition, newPosition) -> controller.updateStatusLabel(textArea));
|
||||
|
||||
// 更新编码标签
|
||||
upDateEncodingLabel(textArea.getText());
|
||||
controller.upDateEncodingLabel(textArea.getText());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user