commit
79dc83b2c1
@ -21,7 +21,7 @@ module org.jcnc.jnotepad {
|
|||||||
requires javafx.web;
|
requires javafx.web;
|
||||||
|
|
||||||
exports org.jcnc.jnotepad;
|
exports org.jcnc.jnotepad;
|
||||||
exports org.jcnc.jnotepad.cache.enums;
|
exports org.jcnc.jnotepad.model.enums;
|
||||||
exports org.jcnc.jnotepad.app.config;
|
exports org.jcnc.jnotepad.app.config;
|
||||||
exports org.jcnc.jnotepad.app.i18n;
|
exports org.jcnc.jnotepad.app.i18n;
|
||||||
exports org.jcnc.jnotepad.common.constants;
|
exports org.jcnc.jnotepad.common.constants;
|
||||||
@ -36,7 +36,7 @@ module org.jcnc.jnotepad {
|
|||||||
exports org.jcnc.jnotepad.views.root.bottom.function;
|
exports org.jcnc.jnotepad.views.root.bottom.function;
|
||||||
|
|
||||||
exports org.jcnc.jnotepad.component.module;
|
exports org.jcnc.jnotepad.component.module;
|
||||||
exports org.jcnc.jnotepad.cache.entity;
|
exports org.jcnc.jnotepad.model.entity;
|
||||||
exports org.jcnc.jnotepad.views.root.bottom;
|
exports org.jcnc.jnotepad.views.root.bottom;
|
||||||
exports org.jcnc.jnotepad.views.root.bottom.status;
|
exports org.jcnc.jnotepad.views.root.bottom.status;
|
||||||
exports org.jcnc.jnotepad.api.core.views.sidebar.bottom;
|
exports org.jcnc.jnotepad.api.core.views.sidebar.bottom;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
package org.jcnc.jnotepad.api.core.ui.stage;
|
package org.jcnc.jnotepad.api.core.component.stage;
|
||||||
|
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package org.jcnc.jnotepad.api.core.manager;
|
package org.jcnc.jnotepad.api.core.manager;
|
||||||
|
|
||||||
import org.jcnc.jnotepad.cache.entity.Cache;
|
import org.jcnc.jnotepad.model.entity.Cache;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|||||||
@ -18,8 +18,8 @@ public class SideBarButtonBuilder {
|
|||||||
private EventHandler<ActionEvent> eventHandler;
|
private EventHandler<ActionEvent> eventHandler;
|
||||||
|
|
||||||
public Button build() {
|
public Button build() {
|
||||||
Optional<Button> container = Optional.of(new Button());
|
Optional<Button> container = Optional.ofNullable(button);
|
||||||
button = container.get();
|
button = container.orElseGet(Button::new);
|
||||||
button.setGraphic(imageView);
|
button.setGraphic(imageView);
|
||||||
button.setOnAction(eventHandler);
|
button.setOnAction(eventHandler);
|
||||||
return button;
|
return button;
|
||||||
@ -31,9 +31,9 @@ public class SideBarButtonBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SideBarButtonBuilder setButtonEssentialAttribute(Double relativelyPrefWidth, Double relativelyPrefHeight) {
|
public SideBarButtonBuilder setButtonEssentialAttribute(Double relativelyPrefWidth, Double relativelyPrefHeight) {
|
||||||
Optional<Double> container = Optional.of(relativelyPrefHeight);
|
Optional<Double> container = Optional.ofNullable(relativelyPrefHeight);
|
||||||
button.setPrefWidth(imageView.getFitWidth() + container.orElse(20D));
|
button.setPrefWidth(imageView.getFitWidth() + container.orElse(20D));
|
||||||
container = Optional.of(relativelyPrefWidth);
|
container = Optional.ofNullable(relativelyPrefWidth);
|
||||||
button.setPrefHeight(imageView.getFitHeight() + container.orElse(20D));
|
button.setPrefHeight(imageView.getFitHeight() + container.orElse(20D));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -49,14 +49,14 @@ public class SideBarButtonBuilder {
|
|||||||
* @return 建造者对象
|
* @return 建造者对象
|
||||||
*/
|
*/
|
||||||
public SideBarButtonBuilder setImageViewEssentialAttribute(Double fitWidth, Double fitHeight, boolean preserveRatio, Double scaleX, Double scaleY) {
|
public SideBarButtonBuilder setImageViewEssentialAttribute(Double fitWidth, Double fitHeight, boolean preserveRatio, Double scaleX, Double scaleY) {
|
||||||
Optional<Double> container = Optional.of(fitWidth);
|
Optional<Double> container = Optional.ofNullable(fitWidth);
|
||||||
imageView.setFitWidth(container.orElse(10D));
|
imageView.setFitWidth(container.orElse(10D));
|
||||||
container = Optional.of(fitHeight);
|
container = Optional.ofNullable(fitHeight);
|
||||||
imageView.setFitHeight(container.orElse(10D));
|
imageView.setFitHeight(container.orElse(10D));
|
||||||
imageView.setPreserveRatio(preserveRatio);
|
imageView.setPreserveRatio(preserveRatio);
|
||||||
container = Optional.of(scaleX);
|
container = Optional.ofNullable(scaleX);
|
||||||
imageView.setScaleX(container.orElse(2.5));
|
imageView.setScaleX(container.orElse(2.5));
|
||||||
container = Optional.of(scaleY);
|
container = Optional.ofNullable(scaleY);
|
||||||
imageView.setScaleY(container.orElse(2.5));
|
imageView.setScaleY(container.orElse(2.5));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
package org.jcnc.jnotepad.app.config;
|
package org.jcnc.jnotepad.app.config;
|
||||||
|
|
||||||
import org.jcnc.jnotepad.cache.entity.PluginDescriptor;
|
import org.jcnc.jnotepad.model.entity.PluginDescriptor;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package org.jcnc.jnotepad.app.config;
|
package org.jcnc.jnotepad.app.config;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import org.jcnc.jnotepad.cache.entity.ShortcutKey;
|
import org.jcnc.jnotepad.model.entity.ShortcutKey;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,6 @@ import org.jcnc.jnotepad.common.manager.ThreadPoolManager;
|
|||||||
import org.jcnc.jnotepad.controller.ResourceController;
|
import org.jcnc.jnotepad.controller.ResourceController;
|
||||||
import org.jcnc.jnotepad.controller.cache.CacheController;
|
import org.jcnc.jnotepad.controller.cache.CacheController;
|
||||||
import org.jcnc.jnotepad.controller.config.PluginConfigController;
|
import org.jcnc.jnotepad.controller.config.PluginConfigController;
|
||||||
import org.jcnc.jnotepad.controller.config.UserConfigController;
|
|
||||||
import org.jcnc.jnotepad.controller.manager.Controller;
|
import org.jcnc.jnotepad.controller.manager.Controller;
|
||||||
import org.jcnc.jnotepad.plugin.manager.PluginManager;
|
import org.jcnc.jnotepad.plugin.manager.PluginManager;
|
||||||
import org.jcnc.jnotepad.util.LogUtil;
|
import org.jcnc.jnotepad.util.LogUtil;
|
||||||
@ -140,8 +139,7 @@ public class ApplicationManager {
|
|||||||
// 刷新插件配置文件
|
// 刷新插件配置文件
|
||||||
pluginConfigController.getConfig().setPlugins(PluginManager.getInstance().getPluginDescriptors());
|
pluginConfigController.getConfig().setPlugins(PluginManager.getInstance().getPluginDescriptors());
|
||||||
pluginConfigController.writeConfig();
|
pluginConfigController.writeConfig();
|
||||||
// 保存配置文件
|
|
||||||
UserConfigController.getInstance().writeConfig();
|
|
||||||
// 销毁插件可能申请的资源
|
// 销毁插件可能申请的资源
|
||||||
PluginManager.getInstance().destroyPlugins();
|
PluginManager.getInstance().destroyPlugins();
|
||||||
// 保存已打开的文件标签页
|
// 保存已打开的文件标签页
|
||||||
|
|||||||
@ -1,226 +0,0 @@
|
|||||||
package org.jcnc.jnotepad.component.module;
|
|
||||||
|
|
||||||
import javafx.application.Platform;
|
|
||||||
import javafx.geometry.Insets;
|
|
||||||
import javafx.scene.control.ContextMenu;
|
|
||||||
import javafx.scene.control.MenuItem;
|
|
||||||
import javafx.scene.input.KeyCode;
|
|
||||||
import javafx.scene.input.KeyEvent;
|
|
||||||
import org.fxmisc.richtext.GenericStyledArea;
|
|
||||||
import org.fxmisc.richtext.LineNumberFactory;
|
|
||||||
import org.fxmisc.richtext.model.Paragraph;
|
|
||||||
import org.fxmisc.richtext.model.StyleSpans;
|
|
||||||
import org.fxmisc.richtext.model.StyleSpansBuilder;
|
|
||||||
import org.reactfx.Subscription;
|
|
||||||
import org.reactfx.collection.ListModification;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 行号文本区域
|
|
||||||
*
|
|
||||||
* <p>这个类继承自JavaFX的BorderPane类,用于显示带有行号的文本区域。它包括主要文本区域和行号文本区域。</p>
|
|
||||||
*
|
|
||||||
* @author luke
|
|
||||||
*/
|
|
||||||
public class CodeArea extends org.fxmisc.richtext.CodeArea {
|
|
||||||
|
|
||||||
private static final String[] KEYWORDS = new String[]{
|
|
||||||
"abstract", "assert", "boolean", "break", "byte",
|
|
||||||
"case", "catch", "char", "class", "const",
|
|
||||||
"continue", "default", "do", "double", "else",
|
|
||||||
"enum", "extends", "final", "finally", "float",
|
|
||||||
"for", "goto", "if", "implements", "import",
|
|
||||||
"instanceof", "int", "interface", "long", "native",
|
|
||||||
"new", "package", "private", "protected", "public",
|
|
||||||
"return", "short", "static", "strictfp", "super",
|
|
||||||
"switch", "synchronized", "this", "throw", "throws",
|
|
||||||
"transient", "try", "void", "volatile", "while"
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 定义用于匹配关键字、括号、分号、字符串和注释的正则表达式模式
|
|
||||||
*/
|
|
||||||
private static final String KEYWORD_PATTERN = "\\b(" + String.join("|", KEYWORDS) + ")\\b";
|
|
||||||
private static final String PAREN_PATTERN = "\\(|\\)";
|
|
||||||
private static final String BRACE_PATTERN = "\\{|\\}";
|
|
||||||
private static final String BRACKET_PATTERN = "\\[|\\]";
|
|
||||||
private static final String SEMICOLON_PATTERN = "\\;";
|
|
||||||
private static final String STRING_PATTERN = "\"([^\"\\\\]|\\\\.)*\"";
|
|
||||||
private static final String COMMENT_PATTERN =
|
|
||||||
// 用于整体文本处理(文本块)
|
|
||||||
"//[^\n]*" + "|" + "/\\*(.|\\R)*?\\*/"
|
|
||||||
// 用于可见段落处理(逐行)
|
|
||||||
+ "|" + "/\\*[^\\v]*" + "|" + "^\\h*\\*([^\\v]*|/)";
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用正则表达式将关键字、括号、分号、字符串和注释的模式组合成一个复合模式
|
|
||||||
*/
|
|
||||||
private static final Pattern PATTERN = Pattern.compile(
|
|
||||||
"(?<KEYWORD>" + KEYWORD_PATTERN + ")"
|
|
||||||
+ "|(?<PAREN>" + PAREN_PATTERN + ")"
|
|
||||||
+ "|(?<BRACE>" + BRACE_PATTERN + ")"
|
|
||||||
+ "|(?<BRACKET>" + BRACKET_PATTERN + ")"
|
|
||||||
+ "|(?<SEMICOLON>" + SEMICOLON_PATTERN + ")"
|
|
||||||
+ "|(?<STRING>" + STRING_PATTERN + ")"
|
|
||||||
+ "|(?<COMMENT>" + COMMENT_PATTERN + ")"
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构造函数
|
|
||||||
* <p>
|
|
||||||
* 用于创建 LineNumberTextArea 对象
|
|
||||||
*/
|
|
||||||
public CodeArea() {
|
|
||||||
// 上、右、下、左
|
|
||||||
this.setPadding(new Insets(8, 0, 0, 0));
|
|
||||||
|
|
||||||
// 在区域左侧添加行号
|
|
||||||
this.setParagraphGraphicFactory(LineNumberFactory.get(this));
|
|
||||||
this.setContextMenu(new DefaultContextMenu());
|
|
||||||
|
|
||||||
/*
|
|
||||||
重新计算所有文本的语法高亮,用户停止编辑区域后的500毫秒内
|
|
||||||
*/
|
|
||||||
Subscription cleanupWhenNoLongerNeedIt = this
|
|
||||||
.multiPlainChanges()
|
|
||||||
.successionEnds(Duration.ofMillis(500))
|
|
||||||
.subscribe(ignore -> this.setStyleSpans(0, computeHighlighting(this.getText())));
|
|
||||||
|
|
||||||
this.getVisibleParagraphs().addModificationObserver
|
|
||||||
(
|
|
||||||
new CodeArea.VisibleParagraphStyler<>(this, this::computeHighlighting)
|
|
||||||
);
|
|
||||||
|
|
||||||
// 自动缩进:在按下回车键时插入上一行的缩进
|
|
||||||
final Pattern whiteSpace = Pattern.compile("^\\s+");
|
|
||||||
this.addEventHandler(KeyEvent.KEY_PRESSED, kE ->
|
|
||||||
{
|
|
||||||
if (kE.getCode() == KeyCode.ENTER) {
|
|
||||||
int caretPosition = this.getCaretPosition();
|
|
||||||
int currentParagraph = this.getCurrentParagraph();
|
|
||||||
Matcher m0 = whiteSpace.matcher(this.getParagraph(currentParagraph - 1).getSegments().get(0));
|
|
||||||
if (m0.find()) {
|
|
||||||
Platform.runLater(() -> this.insertText(caretPosition, m0.group()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.getStylesheets().add(Objects.requireNonNull(getClass().getResource("/css/java_code_styles.css")).toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private StyleSpans<Collection<String>> computeHighlighting(String text) {
|
|
||||||
Matcher matcher = PATTERN.matcher(text);
|
|
||||||
int lastKwEnd = 0;
|
|
||||||
StyleSpansBuilder<Collection<String>> spansBuilder
|
|
||||||
= new StyleSpansBuilder<>();
|
|
||||||
while (matcher.find()) {
|
|
||||||
String styleClass = getStyleClass(matcher);
|
|
||||||
spansBuilder.add(Collections.emptyList(), matcher.start() - lastKwEnd);
|
|
||||||
spansBuilder.add(Collections.singleton(styleClass), matcher.end() - matcher.start());
|
|
||||||
lastKwEnd = matcher.end();
|
|
||||||
}
|
|
||||||
spansBuilder.add(Collections.emptyList(), text.length() - lastKwEnd);
|
|
||||||
return spansBuilder.create();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getStyleClass(Matcher matcher) {
|
|
||||||
String styleClass =
|
|
||||||
matcher.group("KEYWORD") != null ? "keyword" :
|
|
||||||
matcher.group("PAREN") != null ? "paren" :
|
|
||||||
matcher.group("BRACE") != null ? "brace" :
|
|
||||||
matcher.group("BRACKET") != null ? "bracket" :
|
|
||||||
matcher.group("SEMICOLON") != null ? "semicolon" :
|
|
||||||
matcher.group("STRING") != null ? "string" :
|
|
||||||
matcher.group("COMMENT") != null ? "comment" :
|
|
||||||
null; /* 永远不会发生 */
|
|
||||||
assert styleClass != null;
|
|
||||||
return styleClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
static class VisibleParagraphStyler<PS, SEG, S> implements Consumer<ListModification<? extends Paragraph<PS, SEG, S>>> {
|
|
||||||
private final GenericStyledArea<PS, SEG, S> area;
|
|
||||||
private final Function<String, StyleSpans<S>> computeStyles;
|
|
||||||
private int prevParagraph, prevTextLength;
|
|
||||||
|
|
||||||
public VisibleParagraphStyler(GenericStyledArea<PS, SEG, S> area, Function<String, StyleSpans<S>> computeStyles) {
|
|
||||||
this.computeStyles = computeStyles;
|
|
||||||
this.area = area;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void accept(ListModification<? extends Paragraph<PS, SEG, S>> lm) {
|
|
||||||
if (lm.getAddedSize() > 0) {
|
|
||||||
Platform.runLater(() -> {
|
|
||||||
int paragraph = Math.min(area.firstVisibleParToAllParIndex() + lm.getFrom(), area.getParagraphs().size() - 1);
|
|
||||||
String text = area.getText(paragraph, 0, paragraph, area.getParagraphLength(paragraph));
|
|
||||||
|
|
||||||
if (paragraph != prevParagraph || text.length() != prevTextLength) {
|
|
||||||
if (paragraph < area.getParagraphs().size() - 1) {
|
|
||||||
int startPos = area.getAbsolutePosition(paragraph, 0);
|
|
||||||
area.setStyleSpans(startPos, computeStyles.apply(text));
|
|
||||||
}
|
|
||||||
prevTextLength = text.length();
|
|
||||||
prevParagraph = paragraph;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class DefaultContextMenu extends ContextMenu {
|
|
||||||
private final MenuItem fold;
|
|
||||||
private final MenuItem unfold;
|
|
||||||
private final MenuItem print;
|
|
||||||
|
|
||||||
public DefaultContextMenu() {
|
|
||||||
fold = new MenuItem("折叠所选文本");
|
|
||||||
fold.setOnAction(aE -> {
|
|
||||||
hide();
|
|
||||||
fold();
|
|
||||||
});
|
|
||||||
|
|
||||||
unfold = new MenuItem("从光标处展开");
|
|
||||||
unfold.setOnAction(aE -> {
|
|
||||||
hide();
|
|
||||||
unfold();
|
|
||||||
});
|
|
||||||
|
|
||||||
print = new MenuItem("打印");
|
|
||||||
print.setOnAction(aE -> {
|
|
||||||
hide();
|
|
||||||
print();
|
|
||||||
});
|
|
||||||
|
|
||||||
getItems().addAll(fold, unfold, print);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 折叠多行所选文本,仅显示第一行并隐藏其余部分。
|
|
||||||
*/
|
|
||||||
private void fold() {
|
|
||||||
((org.fxmisc.richtext.CodeArea) getOwnerNode()).foldSelectedParagraphs();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 展开当前行/段落(如果有折叠)。
|
|
||||||
*/
|
|
||||||
private void unfold() {
|
|
||||||
org.fxmisc.richtext.CodeArea area = (org.fxmisc.richtext.CodeArea) getOwnerNode();
|
|
||||||
area.unfoldParagraphs(area.getCurrentParagraph());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void print() {
|
|
||||||
System.out.println(((org.fxmisc.richtext.CodeArea) getOwnerNode()).getText());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,146 @@
|
|||||||
|
package org.jcnc.jnotepad.component.module;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.scene.input.KeyCode;
|
||||||
|
import javafx.scene.input.KeyEvent;
|
||||||
|
import org.fxmisc.richtext.CodeArea;
|
||||||
|
import org.fxmisc.richtext.LineNumberFactory;
|
||||||
|
import org.fxmisc.richtext.model.StyleSpans;
|
||||||
|
import org.fxmisc.richtext.model.StyleSpansBuilder;
|
||||||
|
import org.jcnc.jnotepad.model.entity.DefaultContextMenu;
|
||||||
|
import org.jcnc.jnotepad.model.entity.VisibleParagraphStyler;
|
||||||
|
import org.reactfx.Subscription;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本代码域
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author luke
|
||||||
|
*/
|
||||||
|
public class TextCodeArea extends CodeArea {
|
||||||
|
|
||||||
|
private static final String[] KEYWORDS = new String[]{
|
||||||
|
"abstract", "assert", "boolean", "break", "byte",
|
||||||
|
"case", "catch", "char", "class", "const",
|
||||||
|
"continue", "default", "do", "double", "else",
|
||||||
|
"enum", "extends", "final", "finally", "float",
|
||||||
|
"for", "goto", "if", "implements", "import",
|
||||||
|
"instanceof", "int", "interface", "long", "native",
|
||||||
|
"new", "package", "private", "protected", "public",
|
||||||
|
"return", "short", "static", "strictfp", "super",
|
||||||
|
"switch", "synchronized", "this", "throw", "throws",
|
||||||
|
"transient", "try", "void", "volatile", "while"
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定义用于匹配关键字、括号、分号、字符串和注释的正则表达式模式
|
||||||
|
*/
|
||||||
|
private static final String KEYWORD_PATTERN = "\\b(" + String.join("|", KEYWORDS) + ")\\b";
|
||||||
|
private static final String PAREN_PATTERN = "[()]";
|
||||||
|
private static final String BRACE_PATTERN = "[{}]";
|
||||||
|
private static final String BRACKET_PATTERN = "[\\[\\]]";
|
||||||
|
private static final String SEMICOLON_PATTERN = ";";
|
||||||
|
private static final String STRING_PATTERN = "\"([^\"\\\\]|\\\\.)*\"";
|
||||||
|
private static final String COMMENT_PATTERN =
|
||||||
|
// 用于整体文本处理(文本块)
|
||||||
|
"//[^\n]*" + "|" + "/\\*(.|\\R)*?\\*/"
|
||||||
|
// 用于可见段落处理(逐行)
|
||||||
|
+ "|" + "/\\*\\V*" + "|" + "^\\h*\\*(\\V*|/)";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用正则表达式将关键字、括号、分号、字符串和注释的模式组合成一个复合模式
|
||||||
|
*/
|
||||||
|
private static final Pattern PATTERN = Pattern.compile(
|
||||||
|
"(?<KEYWORD>" + KEYWORD_PATTERN + ")"
|
||||||
|
+ "|(?<PAREN>" + PAREN_PATTERN + ")"
|
||||||
|
+ "|(?<BRACE>" + BRACE_PATTERN + ")"
|
||||||
|
+ "|(?<BRACKET>" + BRACKET_PATTERN + ")"
|
||||||
|
+ "|(?<SEMICOLON>" + SEMICOLON_PATTERN + ")"
|
||||||
|
+ "|(?<STRING>" + STRING_PATTERN + ")"
|
||||||
|
+ "|(?<COMMENT>" + COMMENT_PATTERN + ")"
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数
|
||||||
|
* <p>
|
||||||
|
* 用于创建 TextCodeArea 对象
|
||||||
|
*/
|
||||||
|
public TextCodeArea() {
|
||||||
|
// 上、右、下、左
|
||||||
|
this.setPadding(new Insets(8, 0, 0, 0));
|
||||||
|
|
||||||
|
// 在区域左侧添加行号
|
||||||
|
this.setParagraphGraphicFactory(LineNumberFactory.get(this));
|
||||||
|
this.setContextMenu(new DefaultContextMenu());
|
||||||
|
|
||||||
|
/*
|
||||||
|
重新计算所有文本的语法高亮,用户停止编辑区域后的500毫秒内
|
||||||
|
fixme 这个代码没有作用
|
||||||
|
*/
|
||||||
|
Subscription cleanupWhenNoLongerNeedIt = this
|
||||||
|
.multiPlainChanges()
|
||||||
|
.successionEnds(Duration.ofMillis(500))
|
||||||
|
.subscribe(ignore -> this.setStyleSpans(0, computeHighlighting(this.getText())));
|
||||||
|
|
||||||
|
this.getVisibleParagraphs().addModificationObserver
|
||||||
|
(
|
||||||
|
new VisibleParagraphStyler<>(this, this::computeHighlighting)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 自动缩进:在按下回车键时插入上一行的缩进
|
||||||
|
final Pattern whiteSpace = Pattern.compile("^\\s+");
|
||||||
|
this.addEventHandler(KeyEvent.KEY_PRESSED, kE ->
|
||||||
|
{
|
||||||
|
if (kE.getCode() == KeyCode.ENTER) {
|
||||||
|
int caretPosition = this.getCaretPosition();
|
||||||
|
int currentParagraph = this.getCurrentParagraph();
|
||||||
|
Matcher m0 = whiteSpace.matcher(this.getParagraph(currentParagraph - 1).getSegments().get(0));
|
||||||
|
if (m0.find()) {
|
||||||
|
Platform.runLater(() -> this.insertText(caretPosition, m0.group()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.getStylesheets().add(Objects.requireNonNull(getClass().getResource("/css/java_code_styles.css")).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private StyleSpans<Collection<String>> computeHighlighting(String text) {
|
||||||
|
Matcher matcher = PATTERN.matcher(text);
|
||||||
|
int lastKwEnd = 0;
|
||||||
|
StyleSpansBuilder<Collection<String>> spansBuilder
|
||||||
|
= new StyleSpansBuilder<>();
|
||||||
|
while (matcher.find()) {
|
||||||
|
String styleClass = getStyleClass(matcher);
|
||||||
|
spansBuilder.add(Collections.emptyList(), matcher.start() - lastKwEnd);
|
||||||
|
spansBuilder.add(Collections.singleton(styleClass), matcher.end() - matcher.start());
|
||||||
|
lastKwEnd = matcher.end();
|
||||||
|
}
|
||||||
|
spansBuilder.add(Collections.emptyList(), text.length() - lastKwEnd);
|
||||||
|
return spansBuilder.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getStyleClass(Matcher matcher) {
|
||||||
|
Map<String, String> patternToStyleClass = new HashMap<>(16);
|
||||||
|
patternToStyleClass.put("keyword", matcher.group("KEYWORD"));
|
||||||
|
patternToStyleClass.put("paren", matcher.group("PAREN"));
|
||||||
|
patternToStyleClass.put("brace", matcher.group("BRACE"));
|
||||||
|
patternToStyleClass.put("bracket", matcher.group("BRACKET"));
|
||||||
|
patternToStyleClass.put("semicolon", matcher.group("SEMICOLON"));
|
||||||
|
patternToStyleClass.put("string", matcher.group("STRING"));
|
||||||
|
patternToStyleClass.put("comment", matcher.group("COMMENT"));
|
||||||
|
for (Map.Entry<String, String> entry : patternToStyleClass.entrySet()) {
|
||||||
|
if (entry.getValue() != null) {
|
||||||
|
return entry.getKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 永不发生
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,8 +5,8 @@ import javafx.geometry.Pos;
|
|||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.stage.Modality;
|
import javafx.stage.Modality;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.jcnc.jnotepad.cache.enums.DialogType;
|
|
||||||
import org.jcnc.jnotepad.component.stage.dialog.interfaces.DialogButtonAction;
|
import org.jcnc.jnotepad.component.stage.dialog.interfaces.DialogButtonAction;
|
||||||
|
import org.jcnc.jnotepad.model.enums.DialogType;
|
||||||
import org.jcnc.jnotepad.util.UiUtil;
|
import org.jcnc.jnotepad.util.UiUtil;
|
||||||
import org.kordamp.ikonli.javafx.FontIcon;
|
import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import javafx.scene.input.ClipboardContent;
|
|||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.jcnc.jnotepad.api.core.ui.stage.AbstractPaneStage;
|
import org.jcnc.jnotepad.api.core.component.stage.AbstractPaneStage;
|
||||||
import org.jcnc.jnotepad.util.LogUtil;
|
import org.jcnc.jnotepad.util.LogUtil;
|
||||||
import org.jcnc.jnotepad.util.UiUtil;
|
import org.jcnc.jnotepad.util.UiUtil;
|
||||||
import org.jcnc.jnotepad.views.manager.RootManager;
|
import org.jcnc.jnotepad.views.manager.RootManager;
|
||||||
|
|||||||
@ -16,9 +16,22 @@ import javafx.scene.text.Font;
|
|||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
import javafx.stage.Modality;
|
import javafx.stage.Modality;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
import org.jcnc.jnotepad.app.config.AppConfig;
|
||||||
|
import org.jcnc.jnotepad.app.i18n.UiResourceBundle;
|
||||||
|
import org.jcnc.jnotepad.app.manager.ApplicationManager;
|
||||||
|
import org.jcnc.jnotepad.common.constants.TextConstants;
|
||||||
|
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
|
||||||
|
import org.jcnc.jnotepad.component.stage.dialog.factory.impl.BasicDirectoryChooserFactory;
|
||||||
|
import org.jcnc.jnotepad.controller.config.AppConfigController;
|
||||||
|
import org.jcnc.jnotepad.controller.event.handler.menuitem.OpenDirectory;
|
||||||
|
import org.jcnc.jnotepad.model.entity.Cache;
|
||||||
|
import org.jcnc.jnotepad.model.enums.CacheExpirationTime;
|
||||||
import org.jcnc.jnotepad.plugin.PluginManagerInterface;
|
import org.jcnc.jnotepad.plugin.PluginManagerInterface;
|
||||||
|
import org.jcnc.jnotepad.util.PopUpUtil;
|
||||||
import org.jcnc.jnotepad.util.UiUtil;
|
import org.jcnc.jnotepad.util.UiUtil;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
import static org.jcnc.jnotepad.common.constants.AppConstants.SCREEN_LENGTH;
|
import static org.jcnc.jnotepad.common.constants.AppConstants.SCREEN_LENGTH;
|
||||||
import static org.jcnc.jnotepad.common.constants.AppConstants.SCREEN_WIDTH;
|
import static org.jcnc.jnotepad.common.constants.AppConstants.SCREEN_WIDTH;
|
||||||
|
|
||||||
@ -42,6 +55,8 @@ public class SetStage extends Stage {
|
|||||||
private static SetStage instance;
|
private static SetStage instance;
|
||||||
private StackPane contentDisplay;
|
private StackPane contentDisplay;
|
||||||
|
|
||||||
|
private final ApplicationCacheManager cacheManager = ApplicationCacheManager.getInstance();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 私有构造方法以实现单例模式。
|
* 私有构造方法以实现单例模式。
|
||||||
*/
|
*/
|
||||||
@ -202,8 +217,6 @@ public class SetStage extends Stage {
|
|||||||
DeveloperDebugStage debugPage = new DeveloperDebugStage();
|
DeveloperDebugStage debugPage = new DeveloperDebugStage();
|
||||||
debugPage.start(new Stage());
|
debugPage.start(new Stage());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
generalLayout.getChildren().addAll(devBox);
|
generalLayout.getChildren().addAll(devBox);
|
||||||
|
|
||||||
return generalLayout;
|
return generalLayout;
|
||||||
@ -220,19 +233,46 @@ public class SetStage extends Stage {
|
|||||||
|
|
||||||
var hBox = new HBox(5);
|
var hBox = new HBox(5);
|
||||||
|
|
||||||
var fileChooseText =new Text("路径选择: ");
|
var fileChooseText = new Text("文件根路径: ");
|
||||||
fileChooseText.setFont(new Font(18));
|
fileChooseText.setFont(new Font(18));
|
||||||
|
AppConfig config = AppConfigController.getInstance().getConfig();
|
||||||
var fileChoose =new CustomTextField("");
|
var fileChoose = new CustomTextField(config.getRootPath());
|
||||||
fileChoose.getStyleClass().add(Styles.SMALL);
|
fileChoose.getStyleClass().add(Styles.SMALL);
|
||||||
fileChoose.setPrefWidth(420);
|
fileChoose.setPrefWidth(420);
|
||||||
|
|
||||||
var fileChooseBtn = new Button();
|
var fileChooseBtn = new Button();
|
||||||
fileChooseBtn.setText("选择文件夹");
|
fileChooseBtn.setText("选择文件夹");
|
||||||
fileChooseBtn.getStyleClass().addAll(Styles.SMALL);
|
fileChooseBtn.getStyleClass().addAll(Styles.SMALL);
|
||||||
|
BasicDirectoryChooserFactory directoryChooserFactory = BasicDirectoryChooserFactory.getInstance();
|
||||||
fileChooseBtn.setOnAction(event -> {
|
fileChooseBtn.setOnAction(event -> {
|
||||||
// TODO: 2023/10/4 选择文件
|
// 获取打开目录缓存
|
||||||
|
Cache cache = cacheManager.getCache(OpenDirectory.GROUP, "openDirectory");
|
||||||
|
|
||||||
|
File file = directoryChooserFactory.createDirectoryChooser(
|
||||||
|
UiResourceBundle.getContent(TextConstants.OPEN),
|
||||||
|
cache == null ? null : new File((String) cache.getCacheData()))
|
||||||
|
.showDialog(UiUtil.getAppWindow());
|
||||||
|
if (file == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (file.equals(new File(config.getRootPath()))) {
|
||||||
|
PopUpUtil.errorAlert("错误", "路径不能和默认路径相同", "请重新选择路径", null, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 设置缓存
|
||||||
|
if (cache == null) {
|
||||||
|
cacheManager.addCache(cacheManager.createCache(OpenDirectory.GROUP, "openDirectory", file.getAbsolutePath(), CacheExpirationTime.NEVER_EXPIRES.getValue()));
|
||||||
|
} else {
|
||||||
|
cache.setCacheData(file.getParent());
|
||||||
|
cacheManager.addCache(cache);
|
||||||
|
}
|
||||||
|
config.setRootPath(file.getAbsolutePath());
|
||||||
|
PopUpUtil.questionAlert("更改", "设置程序文件根路径", "设置成功,请重启程序以应用路径更改!", appDialog -> {
|
||||||
|
appDialog.close();
|
||||||
|
ApplicationManager.getInstance().restart();
|
||||||
|
}, null, "重启", "以后再说");
|
||||||
|
Stage stage = (Stage) fileChooseBtn.getScene().getWindow();
|
||||||
|
stage.close();
|
||||||
});
|
});
|
||||||
hBox.getChildren().addAll(fileChooseText, fileChoose, fileChooseBtn);
|
hBox.getChildren().addAll(fileChooseText, fileChoose, fileChooseBtn);
|
||||||
|
|
||||||
|
|||||||
@ -25,9 +25,9 @@ import javafx.scene.web.WebView;
|
|||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.commonmark.parser.Parser;
|
import org.commonmark.parser.Parser;
|
||||||
import org.commonmark.renderer.html.HtmlRenderer;
|
import org.commonmark.renderer.html.HtmlRenderer;
|
||||||
import org.jcnc.jnotepad.api.core.ui.stage.AbstractPaneStage;
|
import org.jcnc.jnotepad.api.core.component.stage.AbstractPaneStage;
|
||||||
import org.jcnc.jnotepad.cache.entity.PluginDescriptor;
|
|
||||||
import org.jcnc.jnotepad.component.stage.setting.CustomSetButton;
|
import org.jcnc.jnotepad.component.stage.setting.CustomSetButton;
|
||||||
|
import org.jcnc.jnotepad.model.entity.PluginDescriptor;
|
||||||
import org.jcnc.jnotepad.plugin.manager.PluginManager;
|
import org.jcnc.jnotepad.plugin.manager.PluginManager;
|
||||||
import org.jcnc.jnotepad.util.LogUtil;
|
import org.jcnc.jnotepad.util.LogUtil;
|
||||||
import org.jcnc.jnotepad.util.PopUpUtil;
|
import org.jcnc.jnotepad.util.PopUpUtil;
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
package org.jcnc.jnotepad.controller.cache;
|
package org.jcnc.jnotepad.controller.cache;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
import org.jcnc.jnotepad.cache.entity.Cache;
|
|
||||||
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
|
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
|
||||||
import org.jcnc.jnotepad.controller.config.AppConfigController;
|
import org.jcnc.jnotepad.controller.config.AppConfigController;
|
||||||
|
import org.jcnc.jnotepad.model.entity.Cache;
|
||||||
import org.jcnc.jnotepad.util.JsonUtil;
|
import org.jcnc.jnotepad.util.JsonUtil;
|
||||||
import org.jcnc.jnotepad.util.LogUtil;
|
import org.jcnc.jnotepad.util.LogUtil;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|||||||
@ -2,7 +2,7 @@ package org.jcnc.jnotepad.controller.config;
|
|||||||
|
|
||||||
import org.jcnc.jnotepad.api.core.controller.config.BaseConfigController;
|
import org.jcnc.jnotepad.api.core.controller.config.BaseConfigController;
|
||||||
import org.jcnc.jnotepad.app.config.UserConfig;
|
import org.jcnc.jnotepad.app.config.UserConfig;
|
||||||
import org.jcnc.jnotepad.cache.entity.ShortcutKey;
|
import org.jcnc.jnotepad.model.entity.ShortcutKey;
|
||||||
|
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import javafx.scene.control.Tab;
|
|||||||
import org.jcnc.jnotepad.app.i18n.UiResourceBundle;
|
import org.jcnc.jnotepad.app.i18n.UiResourceBundle;
|
||||||
import org.jcnc.jnotepad.common.constants.AppConstants;
|
import org.jcnc.jnotepad.common.constants.AppConstants;
|
||||||
import org.jcnc.jnotepad.common.constants.TextConstants;
|
import org.jcnc.jnotepad.common.constants.TextConstants;
|
||||||
import org.jcnc.jnotepad.component.module.CodeArea;
|
import org.jcnc.jnotepad.component.module.TextCodeArea;
|
||||||
import org.jcnc.jnotepad.views.manager.BottomStatusBoxManager;
|
import org.jcnc.jnotepad.views.manager.BottomStatusBoxManager;
|
||||||
import org.jcnc.jnotepad.views.manager.CenterTabPaneManager;
|
import org.jcnc.jnotepad.views.manager.CenterTabPaneManager;
|
||||||
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTab;
|
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTab;
|
||||||
@ -38,7 +38,7 @@ public class NewFile implements EventHandler<ActionEvent> {
|
|||||||
*/
|
*/
|
||||||
public void addNewFileTab() {
|
public void addNewFileTab() {
|
||||||
// 创建一个新的文本编辑区
|
// 创建一个新的文本编辑区
|
||||||
CodeArea textArea = new CodeArea();
|
TextCodeArea textArea = new TextCodeArea();
|
||||||
// TODO: refactor:统一TextArea新建、绑定监听器入口
|
// TODO: refactor:统一TextArea新建、绑定监听器入口
|
||||||
// 设定初始索引
|
// 设定初始索引
|
||||||
int index = 1;
|
int index = 1;
|
||||||
|
|||||||
@ -4,12 +4,12 @@ package org.jcnc.jnotepad.controller.event.handler.menuitem;
|
|||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.event.EventHandler;
|
import javafx.event.EventHandler;
|
||||||
import org.jcnc.jnotepad.app.i18n.UiResourceBundle;
|
import org.jcnc.jnotepad.app.i18n.UiResourceBundle;
|
||||||
import org.jcnc.jnotepad.cache.entity.Cache;
|
|
||||||
import org.jcnc.jnotepad.cache.entity.DirFileModel;
|
|
||||||
import org.jcnc.jnotepad.cache.enums.CacheExpirationTime;
|
|
||||||
import org.jcnc.jnotepad.common.constants.TextConstants;
|
import org.jcnc.jnotepad.common.constants.TextConstants;
|
||||||
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
|
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
|
||||||
import org.jcnc.jnotepad.component.stage.dialog.factory.impl.BasicDirectoryChooserFactory;
|
import org.jcnc.jnotepad.component.stage.dialog.factory.impl.BasicDirectoryChooserFactory;
|
||||||
|
import org.jcnc.jnotepad.model.entity.Cache;
|
||||||
|
import org.jcnc.jnotepad.model.entity.DirFileModel;
|
||||||
|
import org.jcnc.jnotepad.model.enums.CacheExpirationTime;
|
||||||
import org.jcnc.jnotepad.util.FileUtil;
|
import org.jcnc.jnotepad.util.FileUtil;
|
||||||
import org.jcnc.jnotepad.util.UiUtil;
|
import org.jcnc.jnotepad.util.UiUtil;
|
||||||
import org.jcnc.jnotepad.views.manager.DirectorySidebarManager;
|
import org.jcnc.jnotepad.views.manager.DirectorySidebarManager;
|
||||||
|
|||||||
@ -5,12 +5,12 @@ import javafx.event.EventHandler;
|
|||||||
import javafx.scene.control.Tab;
|
import javafx.scene.control.Tab;
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import org.jcnc.jnotepad.app.i18n.UiResourceBundle;
|
import org.jcnc.jnotepad.app.i18n.UiResourceBundle;
|
||||||
import org.jcnc.jnotepad.cache.entity.Cache;
|
|
||||||
import org.jcnc.jnotepad.cache.enums.CacheExpirationTime;
|
|
||||||
import org.jcnc.jnotepad.common.constants.TextConstants;
|
import org.jcnc.jnotepad.common.constants.TextConstants;
|
||||||
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
|
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
|
||||||
import org.jcnc.jnotepad.component.module.CodeArea;
|
import org.jcnc.jnotepad.component.module.TextCodeArea;
|
||||||
import org.jcnc.jnotepad.component.stage.dialog.factory.impl.BasicFileChooserFactory;
|
import org.jcnc.jnotepad.component.stage.dialog.factory.impl.BasicFileChooserFactory;
|
||||||
|
import org.jcnc.jnotepad.model.entity.Cache;
|
||||||
|
import org.jcnc.jnotepad.model.enums.CacheExpirationTime;
|
||||||
import org.jcnc.jnotepad.util.EncodingDetector;
|
import org.jcnc.jnotepad.util.EncodingDetector;
|
||||||
import org.jcnc.jnotepad.util.LogUtil;
|
import org.jcnc.jnotepad.util.LogUtil;
|
||||||
import org.jcnc.jnotepad.util.UiUtil;
|
import org.jcnc.jnotepad.util.UiUtil;
|
||||||
@ -70,9 +70,9 @@ public class OpenFile implements EventHandler<ActionEvent> {
|
|||||||
*/
|
*/
|
||||||
public static void openFile(File file) {
|
public static void openFile(File file) {
|
||||||
// 获取标签页集合
|
// 获取标签页集合
|
||||||
CenterTabPane jnotepadTabPane = CenterTabPane.getInstance();
|
CenterTabPane centerTabPane = CenterTabPane.getInstance();
|
||||||
// 遍历标签页,查找匹配的标签页
|
// 遍历标签页,查找匹配的标签页
|
||||||
for (Tab tab : jnotepadTabPane.getTabs()) {
|
for (Tab tab : centerTabPane.getTabs()) {
|
||||||
// 获取绑定的文件
|
// 获取绑定的文件
|
||||||
File tabFile = (File) tab.getUserData();
|
File tabFile = (File) tab.getUserData();
|
||||||
if (tabFile == null) {
|
if (tabFile == null) {
|
||||||
@ -80,7 +80,7 @@ public class OpenFile implements EventHandler<ActionEvent> {
|
|||||||
}
|
}
|
||||||
if (file.getPath().equals((tabFile).getPath())) {
|
if (file.getPath().equals((tabFile).getPath())) {
|
||||||
// 找到匹配的标签页,设置为选中状态并跳转
|
// 找到匹配的标签页,设置为选中状态并跳转
|
||||||
jnotepadTabPane.getSelectionModel().select(tab);
|
centerTabPane.getSelectionModel().select(tab);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -93,13 +93,13 @@ public class OpenFile implements EventHandler<ActionEvent> {
|
|||||||
* @param file 文件对象
|
* @param file 文件对象
|
||||||
*/
|
*/
|
||||||
public static void getText(File file) {
|
public static void getText(File file) {
|
||||||
CodeArea textArea = createNewTextArea();
|
TextCodeArea textCodeArea = createNewTextArea();
|
||||||
// 检测文件编码
|
// 检测文件编码
|
||||||
Charset encoding = EncodingDetector.detectEncodingCharset(file);
|
Charset encoding = EncodingDetector.detectEncodingCharset(file);
|
||||||
String fileText = getFileText(file, encoding);
|
String fileText = getFileText(file, encoding);
|
||||||
LogUtil.getLogger(OpenFile.class).info("已调用读取文件功能");
|
LogUtil.getLogger(OpenFile.class).info("已调用读取文件功能");
|
||||||
textArea.appendText(fileText);
|
textCodeArea.appendText(fileText);
|
||||||
CenterTab tab = createNewTab(file.getName(), textArea, encoding);
|
CenterTab tab = createNewTab(file.getName(), textCodeArea, encoding);
|
||||||
// 设置当前标签页关联本地文件
|
// 设置当前标签页关联本地文件
|
||||||
tab.setRelevance(true);
|
tab.setRelevance(true);
|
||||||
// 设置标签页关联文件
|
// 设置标签页关联文件
|
||||||
@ -115,18 +115,18 @@ public class OpenFile implements EventHandler<ActionEvent> {
|
|||||||
*
|
*
|
||||||
* @return 新的文本区域
|
* @return 新的文本区域
|
||||||
*/
|
*/
|
||||||
private static CodeArea createNewTextArea() {
|
private static TextCodeArea createNewTextArea() {
|
||||||
return new CodeArea();
|
return new TextCodeArea();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建新的标签页。
|
* 创建新的标签页。
|
||||||
*
|
*
|
||||||
* @param tabName 标签名
|
* @param tabName 标签名
|
||||||
* @param textArea 文本区域
|
* @param textCodeArea 文本区域
|
||||||
* @return 新的标签页
|
* @return 新的标签页
|
||||||
*/
|
*/
|
||||||
private static CenterTab createNewTab(String tabName, CodeArea textArea, Charset charset) {
|
private static CenterTab createNewTab(String tabName, TextCodeArea textCodeArea, Charset charset) {
|
||||||
return new CenterTab(tabName, textArea, charset);
|
return new CenterTab(tabName, textCodeArea, charset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,13 +4,13 @@ import javafx.event.ActionEvent;
|
|||||||
import javafx.event.EventHandler;
|
import javafx.event.EventHandler;
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import org.jcnc.jnotepad.app.i18n.UiResourceBundle;
|
import org.jcnc.jnotepad.app.i18n.UiResourceBundle;
|
||||||
import org.jcnc.jnotepad.cache.entity.Cache;
|
|
||||||
import org.jcnc.jnotepad.cache.enums.CacheExpirationTime;
|
|
||||||
import org.jcnc.jnotepad.common.constants.TextConstants;
|
import org.jcnc.jnotepad.common.constants.TextConstants;
|
||||||
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
|
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
|
||||||
import org.jcnc.jnotepad.component.stage.dialog.factory.impl.BasicFileChooserFactory;
|
import org.jcnc.jnotepad.component.stage.dialog.factory.impl.BasicFileChooserFactory;
|
||||||
import org.jcnc.jnotepad.controller.config.UserConfigController;
|
import org.jcnc.jnotepad.controller.config.UserConfigController;
|
||||||
import org.jcnc.jnotepad.controller.i18n.LocalizationController;
|
import org.jcnc.jnotepad.controller.i18n.LocalizationController;
|
||||||
|
import org.jcnc.jnotepad.model.entity.Cache;
|
||||||
|
import org.jcnc.jnotepad.model.enums.CacheExpirationTime;
|
||||||
import org.jcnc.jnotepad.util.LogUtil;
|
import org.jcnc.jnotepad.util.LogUtil;
|
||||||
import org.jcnc.jnotepad.util.UiUtil;
|
import org.jcnc.jnotepad.util.UiUtil;
|
||||||
import org.jcnc.jnotepad.views.manager.CenterTabPaneManager;
|
import org.jcnc.jnotepad.views.manager.CenterTabPaneManager;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
package org.jcnc.jnotepad.cache.entity;
|
package org.jcnc.jnotepad.model.entity;
|
||||||
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
package org.jcnc.jnotepad.model.entity;
|
||||||
|
|
||||||
|
import javafx.scene.control.ContextMenu;
|
||||||
|
import javafx.scene.control.MenuItem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认上下文菜单
|
||||||
|
*
|
||||||
|
* @author gewuyou
|
||||||
|
*/
|
||||||
|
public class DefaultContextMenu extends ContextMenu {
|
||||||
|
private final MenuItem fold;
|
||||||
|
private final MenuItem unfold;
|
||||||
|
private final MenuItem print;
|
||||||
|
|
||||||
|
public DefaultContextMenu() {
|
||||||
|
fold = new MenuItem("折叠所选文本");
|
||||||
|
fold.setOnAction(aE -> {
|
||||||
|
hide();
|
||||||
|
fold();
|
||||||
|
});
|
||||||
|
|
||||||
|
unfold = new MenuItem("从光标处展开");
|
||||||
|
unfold.setOnAction(aE -> {
|
||||||
|
hide();
|
||||||
|
unfold();
|
||||||
|
});
|
||||||
|
|
||||||
|
print = new MenuItem("打印");
|
||||||
|
print.setOnAction(aE -> {
|
||||||
|
hide();
|
||||||
|
print();
|
||||||
|
});
|
||||||
|
|
||||||
|
getItems().addAll(fold, unfold, print);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 折叠多行所选文本,仅显示第一行并隐藏其余部分。
|
||||||
|
*/
|
||||||
|
private void fold() {
|
||||||
|
((org.fxmisc.richtext.CodeArea) getOwnerNode()).foldSelectedParagraphs();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 展开当前行/段落(如果有折叠)。
|
||||||
|
*/
|
||||||
|
private void unfold() {
|
||||||
|
org.fxmisc.richtext.CodeArea area = (org.fxmisc.richtext.CodeArea) getOwnerNode();
|
||||||
|
area.unfoldParagraphs(area.getCurrentParagraph());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void print() {
|
||||||
|
System.out.println(((org.fxmisc.richtext.CodeArea) getOwnerNode()).getText());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package org.jcnc.jnotepad.cache.entity;
|
package org.jcnc.jnotepad.model.entity;
|
||||||
|
|
||||||
import org.kordamp.ikonli.javafx.FontIcon;
|
import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package org.jcnc.jnotepad.cache.entity;
|
package org.jcnc.jnotepad.model.entity;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import org.jcnc.jnotepad.plugin.interfaces.Plugin;
|
import org.jcnc.jnotepad.plugin.interfaces.Plugin;
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package org.jcnc.jnotepad.cache.entity;
|
package org.jcnc.jnotepad.model.entity;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
package org.jcnc.jnotepad.model.entity;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import org.fxmisc.richtext.GenericStyledArea;
|
||||||
|
import org.fxmisc.richtext.model.Paragraph;
|
||||||
|
import org.fxmisc.richtext.model.StyleSpans;
|
||||||
|
import org.reactfx.collection.ListModification;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 可见段落样式器
|
||||||
|
*
|
||||||
|
* @author gewuyou
|
||||||
|
*/
|
||||||
|
public class VisibleParagraphStyler<PS, SEG, S> implements Consumer<ListModification<? extends Paragraph<PS, SEG, S>>> {
|
||||||
|
private final GenericStyledArea<PS, SEG, S> area;
|
||||||
|
private final Function<String, StyleSpans<S>> computeStyles;
|
||||||
|
private int prevParagraph;
|
||||||
|
private int prevTextLength;
|
||||||
|
|
||||||
|
public VisibleParagraphStyler(GenericStyledArea<PS, SEG, S> area, Function<String, StyleSpans<S>> computeStyles) {
|
||||||
|
this.computeStyles = computeStyles;
|
||||||
|
this.area = area;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void accept(ListModification<? extends Paragraph<PS, SEG, S>> lm) {
|
||||||
|
if (lm.getAddedSize() > 0) {
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
int paragraph = Math.min(area.firstVisibleParToAllParIndex() + lm.getFrom(), area.getParagraphs().size() - 1);
|
||||||
|
String text = area.getText(paragraph, 0, paragraph, area.getParagraphLength(paragraph));
|
||||||
|
|
||||||
|
if (paragraph != prevParagraph || text.length() != prevTextLength) {
|
||||||
|
if (paragraph < area.getParagraphs().size() - 1) {
|
||||||
|
int startPos = area.getAbsolutePosition(paragraph, 0);
|
||||||
|
area.setStyleSpans(startPos, computeStyles.apply(text));
|
||||||
|
}
|
||||||
|
prevTextLength = text.length();
|
||||||
|
prevParagraph = paragraph;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package org.jcnc.jnotepad.cache.enums;
|
package org.jcnc.jnotepad.model.enums;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 缓存过期时间枚举
|
* 缓存过期时间枚举
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package org.jcnc.jnotepad.cache.enums;
|
package org.jcnc.jnotepad.model.enums;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对话框类型
|
* 对话框类型
|
||||||
@ -1,9 +1,9 @@
|
|||||||
package org.jcnc.jnotepad.plugin;
|
package org.jcnc.jnotepad.plugin;
|
||||||
|
|
||||||
import org.jcnc.jnotepad.cache.entity.PluginDescriptor;
|
|
||||||
import org.jcnc.jnotepad.common.manager.ThreadPoolManager;
|
import org.jcnc.jnotepad.common.manager.ThreadPoolManager;
|
||||||
import org.jcnc.jnotepad.controller.config.PluginConfigController;
|
import org.jcnc.jnotepad.controller.config.PluginConfigController;
|
||||||
import org.jcnc.jnotepad.controller.exception.AppException;
|
import org.jcnc.jnotepad.controller.exception.AppException;
|
||||||
|
import org.jcnc.jnotepad.model.entity.PluginDescriptor;
|
||||||
import org.jcnc.jnotepad.plugin.interfaces.Plugin;
|
import org.jcnc.jnotepad.plugin.interfaces.Plugin;
|
||||||
import org.jcnc.jnotepad.plugin.manager.PluginManager;
|
import org.jcnc.jnotepad.plugin.manager.PluginManager;
|
||||||
import org.jcnc.jnotepad.util.JsonUtil;
|
import org.jcnc.jnotepad.util.JsonUtil;
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
package org.jcnc.jnotepad.plugin.manager;
|
package org.jcnc.jnotepad.plugin.manager;
|
||||||
|
|
||||||
import org.jcnc.jnotepad.app.manager.ApplicationManager;
|
import org.jcnc.jnotepad.app.manager.ApplicationManager;
|
||||||
import org.jcnc.jnotepad.cache.entity.PluginDescriptor;
|
|
||||||
import org.jcnc.jnotepad.common.manager.ThreadPoolManager;
|
import org.jcnc.jnotepad.common.manager.ThreadPoolManager;
|
||||||
import org.jcnc.jnotepad.controller.config.PluginConfigController;
|
import org.jcnc.jnotepad.controller.config.PluginConfigController;
|
||||||
|
import org.jcnc.jnotepad.model.entity.PluginDescriptor;
|
||||||
import org.jcnc.jnotepad.util.LogUtil;
|
import org.jcnc.jnotepad.util.LogUtil;
|
||||||
import org.jcnc.jnotepad.util.PopUpUtil;
|
import org.jcnc.jnotepad.util.PopUpUtil;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|||||||
@ -1,15 +1,17 @@
|
|||||||
package org.jcnc.jnotepad.util;
|
package org.jcnc.jnotepad.util;
|
||||||
|
|
||||||
import org.jcnc.jnotepad.cache.entity.DirFileModel;
|
|
||||||
import org.jcnc.jnotepad.controller.event.handler.menuitem.OpenFile;
|
import org.jcnc.jnotepad.controller.event.handler.menuitem.OpenFile;
|
||||||
import org.jcnc.jnotepad.controller.exception.AppException;
|
import org.jcnc.jnotepad.controller.exception.AppException;
|
||||||
|
import org.jcnc.jnotepad.model.entity.DirFileModel;
|
||||||
import org.kordamp.ikonli.javafx.FontIcon;
|
import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.FileChannel;
|
import java.nio.channels.FileChannel;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -157,7 +159,42 @@ public class FileUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dirFileModel;
|
return dirFileModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件夹迁移
|
||||||
|
*
|
||||||
|
* @param sourceFolder 源文件夹
|
||||||
|
* @param targetFolder 目标文件夹
|
||||||
|
* @since 2023/10/5 12:18
|
||||||
|
*/
|
||||||
|
|
||||||
|
private static void migrateFolder(File sourceFolder, File targetFolder) {
|
||||||
|
// 创建目标文件夹
|
||||||
|
targetFolder.mkdirs();
|
||||||
|
|
||||||
|
// 获取源文件夹中的所有文件和文件夹
|
||||||
|
File[] files = sourceFolder.listFiles();
|
||||||
|
|
||||||
|
if (files != null) {
|
||||||
|
// 遍历源文件夹中的每个文件和文件夹
|
||||||
|
for (File file : files) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
// 如果是文件夹,递归调用自身进行迁移
|
||||||
|
migrateFolder(file, new File(targetFolder, file.getName()));
|
||||||
|
} else {
|
||||||
|
// 如果是文件,将文件复制到目标文件夹中
|
||||||
|
Path sourceFilePath = file.toPath();
|
||||||
|
Path targetFilePath = new File(targetFolder, file.getName()).toPath();
|
||||||
|
try {
|
||||||
|
Files.copy(sourceFilePath, targetFilePath, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new AppException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
package org.jcnc.jnotepad.util;
|
package org.jcnc.jnotepad.util;
|
||||||
|
|
||||||
import org.jcnc.jnotepad.cache.enums.DialogType;
|
|
||||||
import org.jcnc.jnotepad.component.stage.dialog.AppDialogBuilder;
|
import org.jcnc.jnotepad.component.stage.dialog.AppDialogBuilder;
|
||||||
import org.jcnc.jnotepad.component.stage.dialog.interfaces.DialogButtonAction;
|
import org.jcnc.jnotepad.component.stage.dialog.interfaces.DialogButtonAction;
|
||||||
|
import org.jcnc.jnotepad.model.enums.DialogType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 弹窗工具类
|
* 弹窗工具类
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import javafx.scene.control.Label;
|
|||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import org.jcnc.jnotepad.app.i18n.UiResourceBundle;
|
import org.jcnc.jnotepad.app.i18n.UiResourceBundle;
|
||||||
import org.jcnc.jnotepad.common.constants.TextConstants;
|
import org.jcnc.jnotepad.common.constants.TextConstants;
|
||||||
import org.jcnc.jnotepad.component.module.CodeArea;
|
import org.jcnc.jnotepad.component.module.TextCodeArea;
|
||||||
import org.jcnc.jnotepad.views.root.bottom.status.BottomStatusBox;
|
import org.jcnc.jnotepad.views.root.bottom.status.BottomStatusBox;
|
||||||
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTab;
|
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTab;
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ public class BottomStatusBoxManager {
|
|||||||
if (instance.getSelected() == null) {
|
if (instance.getSelected() == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CodeArea textArea = instance.getSelected().getLineNumberTextArea();
|
TextCodeArea textArea = instance.getSelected().getLineNumberTextArea();
|
||||||
int caretPosition = textArea.getCaretPosition();
|
int caretPosition = textArea.getCaretPosition();
|
||||||
int row = getRow(caretPosition, textArea.getText());
|
int row = getRow(caretPosition, textArea.getText());
|
||||||
int column = getColumn(caretPosition, textArea.getText());
|
int column = getColumn(caretPosition, textArea.getText());
|
||||||
@ -128,7 +128,7 @@ public class BottomStatusBoxManager {
|
|||||||
updateEncodingLabel(centerTab.getCharset().name());
|
updateEncodingLabel(centerTab.getCharset().name());
|
||||||
|
|
||||||
// 添加光标位置变化监听器
|
// 添加光标位置变化监听器
|
||||||
CodeArea textArea = centerTab.getLineNumberTextArea();
|
TextCodeArea textArea = centerTab.getLineNumberTextArea();
|
||||||
textArea.caretPositionProperty().addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> updateRowColumnLabel(textArea.getCaretPosition(), textArea.getText()));
|
textArea.caretPositionProperty().addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> updateRowColumnLabel(textArea.getCaretPosition(), textArea.getText()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,10 +3,10 @@ package org.jcnc.jnotepad.views.manager;
|
|||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.scene.control.Tab;
|
import javafx.scene.control.Tab;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.jcnc.jnotepad.cache.enums.CacheExpirationTime;
|
|
||||||
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
|
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
|
||||||
import org.jcnc.jnotepad.component.module.CodeArea;
|
import org.jcnc.jnotepad.component.module.TextCodeArea;
|
||||||
import org.jcnc.jnotepad.controller.config.UserConfigController;
|
import org.jcnc.jnotepad.controller.config.UserConfigController;
|
||||||
|
import org.jcnc.jnotepad.model.enums.CacheExpirationTime;
|
||||||
import org.jcnc.jnotepad.util.FileUtil;
|
import org.jcnc.jnotepad.util.FileUtil;
|
||||||
import org.jcnc.jnotepad.util.PopUpUtil;
|
import org.jcnc.jnotepad.util.PopUpUtil;
|
||||||
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTab;
|
import org.jcnc.jnotepad.views.root.center.main.center.tab.CenterTab;
|
||||||
@ -79,7 +79,7 @@ public class CenterTabPaneManager {
|
|||||||
}
|
}
|
||||||
if (tab.isRelevance()) {
|
if (tab.isRelevance()) {
|
||||||
// 获取当前文本域对象
|
// 获取当前文本域对象
|
||||||
CodeArea codeArea = tab.getLineNumberTextArea();
|
TextCodeArea textCodeArea = tab.getLineNumberTextArea();
|
||||||
// 获取当前标签页对应文件上次修改时间
|
// 获取当前标签页对应文件上次修改时间
|
||||||
Long lastModifiedTime = tab.getLastModifiedTimeOfAssociatedFile();
|
Long lastModifiedTime = tab.getLastModifiedTimeOfAssociatedFile();
|
||||||
// 获取对应文件上次修改时间
|
// 获取对应文件上次修改时间
|
||||||
@ -95,8 +95,8 @@ public class CenterTabPaneManager {
|
|||||||
PopUpUtil.questionAlert(
|
PopUpUtil.questionAlert(
|
||||||
"重新加载", file.getAbsolutePath(), "此文件已被外部修改,是否重新加载该文件?",
|
"重新加载", file.getAbsolutePath(), "此文件已被外部修改,是否重新加载该文件?",
|
||||||
appDialog -> {
|
appDialog -> {
|
||||||
codeArea.clear();
|
textCodeArea.clear();
|
||||||
codeArea.appendText(fileText);
|
textCodeArea.appendText(fileText);
|
||||||
appDialog.close();
|
appDialog.close();
|
||||||
}, Stage::close, "是", "否");
|
}, Stage::close, "是", "否");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,9 +3,9 @@ package org.jcnc.jnotepad.views.manager;
|
|||||||
import javafx.beans.value.ChangeListener;
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.scene.control.SplitPane;
|
import javafx.scene.control.SplitPane;
|
||||||
import javafx.scene.control.TreeItem;
|
import javafx.scene.control.TreeItem;
|
||||||
import org.jcnc.jnotepad.cache.entity.DirFileModel;
|
|
||||||
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
|
import org.jcnc.jnotepad.common.manager.ApplicationCacheManager;
|
||||||
import org.jcnc.jnotepad.controller.event.handler.menuitem.OpenDirectory;
|
import org.jcnc.jnotepad.controller.event.handler.menuitem.OpenDirectory;
|
||||||
|
import org.jcnc.jnotepad.model.entity.DirFileModel;
|
||||||
import org.jcnc.jnotepad.util.FileUtil;
|
import org.jcnc.jnotepad.util.FileUtil;
|
||||||
import org.jcnc.jnotepad.views.root.center.main.MainBorderPane;
|
import org.jcnc.jnotepad.views.root.center.main.MainBorderPane;
|
||||||
import org.jcnc.jnotepad.views.root.center.main.center.directory.DirectorySidebarPane;
|
import org.jcnc.jnotepad.views.root.center.main.center.directory.DirectorySidebarPane;
|
||||||
|
|||||||
@ -6,8 +6,8 @@ import javafx.scene.control.Menu;
|
|||||||
import javafx.scene.control.MenuItem;
|
import javafx.scene.control.MenuItem;
|
||||||
import javafx.scene.input.KeyCombination;
|
import javafx.scene.input.KeyCombination;
|
||||||
import org.jcnc.jnotepad.api.core.views.manager.AbstractManager;
|
import org.jcnc.jnotepad.api.core.views.manager.AbstractManager;
|
||||||
import org.jcnc.jnotepad.cache.entity.ShortcutKey;
|
|
||||||
import org.jcnc.jnotepad.controller.config.UserConfigController;
|
import org.jcnc.jnotepad.controller.config.UserConfigController;
|
||||||
|
import org.jcnc.jnotepad.model.entity.ShortcutKey;
|
||||||
import org.jcnc.jnotepad.util.LogUtil;
|
import org.jcnc.jnotepad.util.LogUtil;
|
||||||
import org.jcnc.jnotepad.views.root.top.menubar.TopMenuBar;
|
import org.jcnc.jnotepad.views.root.top.menubar.TopMenuBar;
|
||||||
import org.jcnc.jnotepad.views.root.top.menubar.menu.*;
|
import org.jcnc.jnotepad.views.root.top.menubar.menu.*;
|
||||||
|
|||||||
@ -2,8 +2,8 @@ package org.jcnc.jnotepad.views.root.center.main.center.directory;
|
|||||||
|
|
||||||
import javafx.scene.control.TreeItem;
|
import javafx.scene.control.TreeItem;
|
||||||
import javafx.scene.control.TreeView;
|
import javafx.scene.control.TreeView;
|
||||||
import org.jcnc.jnotepad.cache.entity.DirFileModel;
|
|
||||||
import org.jcnc.jnotepad.controller.event.handler.menuitem.OpenFile;
|
import org.jcnc.jnotepad.controller.event.handler.menuitem.OpenFile;
|
||||||
|
import org.jcnc.jnotepad.model.entity.DirFileModel;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|||||||
@ -2,7 +2,7 @@ package org.jcnc.jnotepad.views.root.center.main.center.tab;
|
|||||||
|
|
||||||
import javafx.scene.control.Tab;
|
import javafx.scene.control.Tab;
|
||||||
import org.fxmisc.flowless.VirtualizedScrollPane;
|
import org.fxmisc.flowless.VirtualizedScrollPane;
|
||||||
import org.jcnc.jnotepad.component.module.CodeArea;
|
import org.jcnc.jnotepad.component.module.TextCodeArea;
|
||||||
import org.jcnc.jnotepad.controller.config.UserConfigController;
|
import org.jcnc.jnotepad.controller.config.UserConfigController;
|
||||||
import org.jcnc.jnotepad.util.LogUtil;
|
import org.jcnc.jnotepad.util.LogUtil;
|
||||||
import org.jcnc.jnotepad.views.manager.BottomStatusBoxManager;
|
import org.jcnc.jnotepad.views.manager.BottomStatusBoxManager;
|
||||||
@ -23,7 +23,7 @@ import java.nio.charset.Charset;
|
|||||||
*/
|
*/
|
||||||
public class CenterTab extends Tab {
|
public class CenterTab extends Tab {
|
||||||
Logger logger = LogUtil.getLogger(this.getClass());
|
Logger logger = LogUtil.getLogger(this.getClass());
|
||||||
private final CodeArea codeArea;
|
private final TextCodeArea textCodeArea;
|
||||||
/**
|
/**
|
||||||
* 默认关闭自动换行
|
* 默认关闭自动换行
|
||||||
*/
|
*/
|
||||||
@ -39,18 +39,18 @@ public class CenterTab extends Tab {
|
|||||||
private Charset charset = Charset.defaultCharset();
|
private Charset charset = Charset.defaultCharset();
|
||||||
|
|
||||||
public CenterTab(String tabTitle) {
|
public CenterTab(String tabTitle) {
|
||||||
this(tabTitle, new CodeArea());
|
this(tabTitle, new TextCodeArea());
|
||||||
}
|
}
|
||||||
|
|
||||||
public CenterTab(String tabTitle, CodeArea textArea) {
|
public CenterTab(String tabTitle, TextCodeArea textArea) {
|
||||||
this(tabTitle, textArea, Charset.defaultCharset());
|
this(tabTitle, textArea, Charset.defaultCharset());
|
||||||
}
|
}
|
||||||
|
|
||||||
public CenterTab(String tabTitle, CodeArea textArea, Charset charset) {
|
public CenterTab(String tabTitle, TextCodeArea textArea, Charset charset) {
|
||||||
super(tabTitle);
|
super(tabTitle);
|
||||||
codeArea = textArea;
|
textCodeArea = textArea;
|
||||||
initTextAreaListeners();
|
initTextAreaListeners();
|
||||||
this.setContent(new VirtualizedScrollPane<>(codeArea));
|
this.setContent(new VirtualizedScrollPane<>(textCodeArea));
|
||||||
setAutoLine(UserConfigController.getInstance().getAutoLineConfig());
|
setAutoLine(UserConfigController.getInstance().getAutoLineConfig());
|
||||||
this.charset = charset;
|
this.charset = charset;
|
||||||
}
|
}
|
||||||
@ -69,11 +69,11 @@ public class CenterTab extends Tab {
|
|||||||
|
|
||||||
public void setAutoLine(boolean autoLine) {
|
public void setAutoLine(boolean autoLine) {
|
||||||
this.autoLine = autoLine;
|
this.autoLine = autoLine;
|
||||||
codeArea.setWrapText(autoLine);
|
textCodeArea.setWrapText(autoLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CodeArea getLineNumberTextArea() {
|
public TextCodeArea getLineNumberTextArea() {
|
||||||
return codeArea;
|
return textCodeArea;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Charset getCharset() {
|
public Charset getCharset() {
|
||||||
@ -126,7 +126,7 @@ public class CenterTab extends Tab {
|
|||||||
*/
|
*/
|
||||||
private void initTextAreaListeners() {
|
private void initTextAreaListeners() {
|
||||||
// 监听主要文本区域的文本变化
|
// 监听主要文本区域的文本变化
|
||||||
codeArea.textProperty().addListener((observable, oldValue, newValue) -> {
|
textCodeArea.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
BottomStatusBoxManager.getInstance().updateWordCountStatusLabel();
|
BottomStatusBoxManager.getInstance().updateWordCountStatusLabel();
|
||||||
saveSelectedFileTab();
|
saveSelectedFileTab();
|
||||||
});
|
});
|
||||||
|
|||||||
11
tool/jpackage.sh
Normal file
11
tool/jpackage.sh
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#请在jlink之后通过文件管理器打开tool双击这个脚本,而不是直接使用Idea执行
|
||||||
|
cd ..
|
||||||
|
jpackage \
|
||||||
|
--name JNotepad \
|
||||||
|
--type app-image \
|
||||||
|
-m org.jcnc.jnotepad/org.jcnc.jnotepad.LunchApp \
|
||||||
|
--runtime-image ./target/JNotepad/ \
|
||||||
|
--icon src/main/resources/img/icon.ico \
|
||||||
|
--app-version 1.1.13 \
|
||||||
|
--vendor "JCNC"
|
||||||
Loading…
x
Reference in New Issue
Block a user