diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml deleted file mode 100644 index 79ee123c2b23e069e35ed634d687e17f731cc702..0000000000000000000000000000000000000000 --- a/.idea/codeStyles/codeStyleConfig.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml deleted file mode 100644 index 106fade22c4fe3820fec6d28326ef2162989e064..0000000000000000000000000000000000000000 --- a/.idea/encodings.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/.idea/fileTemplates/code/JavaDoc Class.java b/.idea/fileTemplates/code/JavaDoc Class.java deleted file mode 100644 index 8c770c86169568f8aaec3fd46acd79eea65db516..0000000000000000000000000000000000000000 --- a/.idea/fileTemplates/code/JavaDoc Class.java +++ /dev/null @@ -1,7 +0,0 @@ -#foreach($param in $RECORD_COMPONENTS) - * @param $param -#end -#foreach($param in $TYPE_PARAMS) - * @param <$param> -#end - * @author $USER diff --git a/src/main/java/org/jcnc/jnotepad/ui/LineNumberTextArea.java b/src/main/java/org/jcnc/jnotepad/ui/LineNumberTextArea.java index acb4a036a308512d511cb156b018667cad901a71..539932c4842393d88218fb8165bc7cf3d4c4cc22 100644 --- a/src/main/java/org/jcnc/jnotepad/ui/LineNumberTextArea.java +++ b/src/main/java/org/jcnc/jnotepad/ui/LineNumberTextArea.java @@ -1,12 +1,11 @@ package org.jcnc.jnotepad.ui; import javafx.beans.property.StringProperty; +import javafx.scene.control.ScrollPane; import javafx.scene.control.TextArea; import javafx.scene.layout.BorderPane; -import org.jcnc.jnotepad.app.config.AppConfig; import org.jcnc.jnotepad.controller.config.AppConfigController; import org.jcnc.jnotepad.tool.LogUtil; -import org.jcnc.jnotepad.ui.menu.JNotepadMenuBar; import org.jcnc.jnotepad.ui.status.JNotepadStatusBox; import org.jcnc.jnotepad.ui.tab.JNotepadTab; import org.jcnc.jnotepad.ui.tab.JNotepadTabPane; @@ -15,6 +14,7 @@ import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.util.List; /** * @author 许轲 @@ -26,17 +26,27 @@ public class LineNumberTextArea extends BorderPane { private boolean isRelevance = false; private final TextArea mainTextArea; private final TextArea lineNumberArea; + private List paragraphs; // 缓存段落列表 + private String fullLineNumberText; // 缓存完整行号文本 + private boolean needToUpdateLineNumbers = false; + private static final int MIN_LINE_NUMBER_WIDTH = 30; static final int[] SIZE_TABLE = {9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, Integer.MAX_VALUE}; - private static final int MIN_LINE_NUMBER_WIDTH = 30; + private final ScrollPane scrollPane; + + private int cachedNumOfLines = 0; + public LineNumberTextArea() { + mainTextArea = new TextArea(); mainTextArea.setWrapText(AppConfigController.getInstance().getAutoLineConfig()); + scrollPane = new ScrollPane(mainTextArea); lineNumberArea = new TextArea(); lineNumberArea.setEditable(false); + lineNumberArea.setPrefWidth(MIN_LINE_NUMBER_WIDTH); lineNumberArea.setMinWidth(MIN_LINE_NUMBER_WIDTH); // 设定自定义样式 @@ -47,12 +57,36 @@ public class LineNumberTextArea extends BorderPane { "-fx-background-color:white" ); - initListeners(); + scrollPane.setFitToWidth(true); + scrollPane.viewportBoundsProperty().addListener((observable, oldValue, newValue) -> { + int firstVisibleLine = calculateFirstVisibleLine(); + int lastVisibleLine = calculateLastVisibleLine(); + loadVisibleLines(firstVisibleLine, lastVisibleLine); + + loadVisibleLineNumbers(firstVisibleLine, lastVisibleLine); + + + // 如果标记为需要更新行号,则执行更新行号的操作 + if (needToUpdateLineNumbers) { + updateLineNumberArea(); + needToUpdateLineNumbers = false; // 重置标记 + } + }); + initListeners(); + paragraphs = mainTextArea.getParagraphs(); // 缓存段落列表 + generateFullLineNumberText(); // 初始化缓存的行号文本 setCenter(mainTextArea); setLeft(lineNumberArea); + } - + private void generateFullLineNumberText() { + StringBuilder lineNumberText = new StringBuilder(); + int numOfLines = paragraphs.size(); + for (int i = 1; i <= numOfLines; i++) { + lineNumberText.append(i).append("\n"); + } + fullLineNumberText = lineNumberText.toString(); } private void initListeners() { @@ -72,6 +106,9 @@ public class LineNumberTextArea extends BorderPane { JNotepadStatusBox.getInstance().updateWordCountStatusLabel(); // 自动保存 save(); + + needToUpdateLineNumbers = true; + }); } @@ -124,10 +161,6 @@ public class LineNumberTextArea extends BorderPane { private void updateLineNumberArea() { - // 保存当前的滚动位置 - /* - 更新行号文本区域的内容,根据主要文本区域的段落数生成行号。 - */ double mainTextAreaScrollTop = mainTextArea.getScrollTop(); double lineNumberAreaScrollTop = lineNumberArea.getScrollTop(); @@ -138,14 +171,60 @@ public class LineNumberTextArea extends BorderPane { } lineNumberArea.setText(lineNumberText.toString()); - // 恢复之前的滚动位置 mainTextArea.setScrollTop(mainTextAreaScrollTop); lineNumberArea.setScrollTop(lineNumberAreaScrollTop); + + if (cachedNumOfLines != numOfLines) { + updateLineNumberWidth(); + cachedNumOfLines = numOfLines; + } + + } + + + private int calculateFirstVisibleLine() { + double scrollTop = scrollPane.getVvalue() * mainTextArea.getParagraphs().size(); + return (int) Math.floor(scrollTop); } + private int calculateLastVisibleLine() { + double scrollTop = scrollPane.getVvalue() * mainTextArea.getParagraphs().size(); + double viewportHeight = scrollPane.getViewportBounds().getHeight(); + int lastVisibleLine = (int) Math.floor(scrollTop + viewportHeight / mainTextArea.getHeight()); + return Math.min(lastVisibleLine, mainTextArea.getParagraphs().size() - 1); + } + + + // 加载可见区域的数据到 mainTextArea + private void loadVisibleLines(int firstVisibleLine, int lastVisibleLine) { + StringBuilder visibleText = new StringBuilder(); + String[] lines = mainTextArea.getText().split("\n"); + + for (int i = firstVisibleLine; i <= lastVisibleLine && i < lines.length; i++) { + visibleText.append(lines[i]); + if (i < lastVisibleLine && i < lines.length - 1) { + visibleText.append("\n"); + } + } + + mainTextArea.setText(visibleText.toString()); + } + + // 加载可见区域的行号到 lineNumberArea + private void loadVisibleLineNumbers(int firstVisibleLine, int lastVisibleLine) { + StringBuilder visibleLineNumbers = new StringBuilder(); + + String[] lineNumbers = fullLineNumberText.split("\n"); + for (int i = firstVisibleLine; i <= lastVisibleLine; i++) { + visibleLineNumbers.append(lineNumbers[i]).append("\n"); + } + + lineNumberArea.setText(visibleLineNumbers.toString()); + } + + public TextArea getMainTextArea() { return mainTextArea; } -} - +} \ No newline at end of file