diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 482b8a0..52561f6 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -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; } \ No newline at end of file diff --git a/src/main/java/org/jcnc/jnotepad/Interface/ControllerInterface.java b/src/main/java/org/jcnc/jnotepad/Interface/ControllerInterface.java new file mode 100644 index 0000000..bb0da77 --- /dev/null +++ b/src/main/java/org/jcnc/jnotepad/Interface/ControllerInterface.java @@ -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 rawParameters); + + EventHandler getLineFeedEventHandler(TextArea textArea); + + EventHandler getNewFileEventHandler(TextArea textArea); + + EventHandler getOpenFileEventHandler(); + + void autoSave(TextArea textArea); + + EventHandler getSaveFileEventHandler(); + + EventHandler 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); +} diff --git a/src/main/java/org/jcnc/jnotepad/LunchApp.java b/src/main/java/org/jcnc/jnotepad/LunchApp.java index 146ef7c..3c679dc 100644 --- a/src/main/java/org/jcnc/jnotepad/LunchApp.java +++ b/src/main/java/org/jcnc/jnotepad/LunchApp.java @@ -20,8 +20,10 @@ 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) { + View view=new View(); Pane root = new Pane(); double width = Constants.SCREEN_WIDTH; @@ -42,14 +44,14 @@ public class LunchApp extends Application { viewManager.initScreen(scene); // 初始化菜单项和标签栏 - View.initItem(); + view.initItem(); View.initTabPane(); if (isRelevance) { // 使用线程池加载关联文件并创建文本区域 List rawParameters = getParameters().getRaw(); threadPool.execute(() -> { - TextArea textArea = Controller.openAssociatedFileAndCreateTextArea(rawParameters); + TextArea textArea = controller.openAssociatedFileAndCreateTextArea(rawParameters); Platform.runLater(() -> updateUIWithNewTextArea(textArea)); }); } @@ -60,7 +62,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 diff --git a/src/main/java/org/jcnc/jnotepad/controller/Controller.java b/src/main/java/org/jcnc/jnotepad/controller/Controller.java index 72430bc..cc94541 100644 --- a/src/main/java/org/jcnc/jnotepad/controller/Controller.java +++ b/src/main/java/org/jcnc/jnotepad/controller/Controller.java @@ -7,161 +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 rawParameters) { + @Override + public TextArea openAssociatedFileAndCreateTextArea(List 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 { - private final TextArea textArea; - private boolean wrapText = true; - - public LineFeedEventHandler(TextArea textArea) { - this.textArea = textArea; - } - - @Override - public void handle(ActionEvent event) { - wrapText = !wrapText; // 切换自动换行状态 - textArea.setWrapText(wrapText); - Line=!Line; - } + @Override + public EventHandler getLineFeedEventHandler(TextArea textArea) { + return new LineFeedEventHandler(textArea); } - - // 新建文件事件处理器 - public static class NewFileEventHandler implements EventHandler { - @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()); // 更新文本编码信息 - } + @Override + public EventHandler getNewFileEventHandler(TextArea textArea) { + return new NewFileEventHandler(); } - // 打开文件事件处理器 - public static class OpenFileEventHandler implements EventHandler { - @Override - public void handle(ActionEvent event) { - FileChooser fileChooser = new FileChooser(); - File file = fileChooser.showOpenDialog(null); - if (file != null) { - Task 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(); - } - } + @Override + public EventHandler getOpenFileEventHandler() { + return new OpenFileEventHandler(); } - // 自动保存方法 - public static void autoSave(TextArea textArea) { + @Override + 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 { - @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) { - } - } - } - } + @Override + public EventHandler getSaveFileEventHandler() { + return new SaveFileEventHandler(); } - // 另存为文件事件处理器 - public static class SaveAsFileEventHandler implements EventHandler { - @Override - public void handle(ActionEvent event) { - saveAsFile(); - } + @Override + public EventHandler getSaveAsFileEventHandler() { + return new SaveAsFileEventHandler(); } - // 另存为文件方法 - public static void saveAsFile() { + @Override + public void saveAsFile() { Tab selectedTab = tabPane.getSelectionModel().getSelectedItem(); if (selectedTab != null) { FileChooser fileChooser = new FileChooser(); @@ -169,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; @@ -219,29 +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 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; @@ -250,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 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 openFileTask = createOpenFileTask(file); + Thread thread = new Thread(openFileTask); + thread.start(); + } + + private void saveFile() { + new SaveFileEventHandler(); + } } diff --git a/src/main/java/org/jcnc/jnotepad/controller/LineFeedEventHandler.java b/src/main/java/org/jcnc/jnotepad/controller/LineFeedEventHandler.java new file mode 100644 index 0000000..a736e50 --- /dev/null +++ b/src/main/java/org/jcnc/jnotepad/controller/LineFeedEventHandler.java @@ -0,0 +1,19 @@ +package org.jcnc.jnotepad.controller; + +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.scene.control.TextArea; + +public class LineFeedEventHandler implements EventHandler { + 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"); + } +} diff --git a/src/main/java/org/jcnc/jnotepad/controller/NewFileEventHandler.java b/src/main/java/org/jcnc/jnotepad/controller/NewFileEventHandler.java new file mode 100644 index 0000000..83427d3 --- /dev/null +++ b/src/main/java/org/jcnc/jnotepad/controller/NewFileEventHandler.java @@ -0,0 +1,29 @@ +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 { + + + public NewFileEventHandler() { + } + + @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()); // 更新文本编码信息 + } +} \ No newline at end of file diff --git a/src/main/java/org/jcnc/jnotepad/controller/OpenFileEventHandler.java b/src/main/java/org/jcnc/jnotepad/controller/OpenFileEventHandler.java new file mode 100644 index 0000000..72d05a1 --- /dev/null +++ b/src/main/java/org/jcnc/jnotepad/controller/OpenFileEventHandler.java @@ -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 { + @Override + public void handle(ActionEvent event) { + Controller controller=new Controller(); + FileChooser fileChooser = new FileChooser(); + File file = fileChooser.showOpenDialog(null); + if (file != null) { + Task 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(); + } + } +} diff --git a/src/main/java/org/jcnc/jnotepad/controller/SaveAsFileEventHandler.java b/src/main/java/org/jcnc/jnotepad/controller/SaveAsFileEventHandler.java new file mode 100644 index 0000000..3ec0772 --- /dev/null +++ b/src/main/java/org/jcnc/jnotepad/controller/SaveAsFileEventHandler.java @@ -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 { + @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) { + } + } + } + } +} diff --git a/src/main/java/org/jcnc/jnotepad/controller/SaveFileEventHandler.java b/src/main/java/org/jcnc/jnotepad/controller/SaveFileEventHandler.java new file mode 100644 index 0000000..bc294b8 --- /dev/null +++ b/src/main/java/org/jcnc/jnotepad/controller/SaveFileEventHandler.java @@ -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 { + @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) { + } + } + } + } +} diff --git a/src/main/java/org/jcnc/jnotepad/controller/EncodingDetector.java b/src/main/java/org/jcnc/jnotepad/tool/EncodingDetector.java similarity index 96% rename from src/main/java/org/jcnc/jnotepad/controller/EncodingDetector.java rename to src/main/java/org/jcnc/jnotepad/tool/EncodingDetector.java index 83bb86c..ee56f9e 100644 --- a/src/main/java/org/jcnc/jnotepad/controller/EncodingDetector.java +++ b/src/main/java/org/jcnc/jnotepad/tool/EncodingDetector.java @@ -1,4 +1,4 @@ -package org.jcnc.jnotepad.controller; +package org.jcnc.jnotepad.tool; import javafx.scene.control.TextArea; import java.nio.charset.Charset; diff --git a/src/main/java/org/jcnc/jnotepad/view/View.java b/src/main/java/org/jcnc/jnotepad/view/View.java index 692ca01..61ebbf3 100644 --- a/src/main/java/org/jcnc/jnotepad/view/View.java +++ b/src/main/java/org/jcnc/jnotepad/view/View.java @@ -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()); } }); } + }