From f3fc26c72479f62fdf04e47e41b5279655e17cc3 Mon Sep 17 00:00:00 2001 From: zhangmeng <1334717033@qq.com> Date: Sat, 7 Oct 2023 17:23:06 +0800 Subject: [PATCH] =?UTF-8?q?2023=E5=B9=B410=E6=9C=887=E6=97=A517:21:38?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tools/controller/EditListController.java | 567 ++++++++++++++++++ .../tools/controller/HomeController.java | 22 + .../tools/editors/ace/AceEditor.java | 289 +++++++++ .../tools/editors/ace/AceHelper.java | 145 +++++ .../zhangmeng/tools/editors/ace/AceMode.java | 34 ++ .../zhangmeng/tools/editors/ace/AceTheme.java | 26 + .../tools/editors/monaco/MonacoEdit.java | 200 ++++++ .../tools/editors/monaco/MonacoHelper.java | 350 +++++++++++ .../tools/editors/monaco/MonacoMode.java | 20 + .../tools/editors/monaco/MonacoThem.java | 27 + .../zhangmeng/tools/utils/ClipboardUtils.java | 35 ++ .../zhangmeng/tools/utils/ResourcesUtils.java | 30 + src/main/resources/fxml/editor-list.fxml | 122 ++++ src/main/resources/fxml/home.fxml | 7 + src/main/resources/static/editors/ace.html | 223 +------ 15 files changed, 1885 insertions(+), 212 deletions(-) create mode 100644 src/main/java/com/zhangmeng/tools/controller/EditListController.java create mode 100644 src/main/java/com/zhangmeng/tools/editors/ace/AceEditor.java create mode 100644 src/main/java/com/zhangmeng/tools/editors/ace/AceHelper.java create mode 100644 src/main/java/com/zhangmeng/tools/editors/ace/AceMode.java create mode 100644 src/main/java/com/zhangmeng/tools/editors/ace/AceTheme.java create mode 100644 src/main/java/com/zhangmeng/tools/editors/monaco/MonacoEdit.java create mode 100644 src/main/java/com/zhangmeng/tools/editors/monaco/MonacoHelper.java create mode 100644 src/main/java/com/zhangmeng/tools/editors/monaco/MonacoMode.java create mode 100644 src/main/java/com/zhangmeng/tools/editors/monaco/MonacoThem.java create mode 100644 src/main/java/com/zhangmeng/tools/utils/ClipboardUtils.java create mode 100644 src/main/resources/fxml/editor-list.fxml diff --git a/src/main/java/com/zhangmeng/tools/controller/EditListController.java b/src/main/java/com/zhangmeng/tools/controller/EditListController.java new file mode 100644 index 0000000..b91d095 --- /dev/null +++ b/src/main/java/com/zhangmeng/tools/controller/EditListController.java @@ -0,0 +1,567 @@ +package com.zhangmeng.tools.controller; + +import com.zhangmeng.tools.editors.ace.AceEditor; +import com.zhangmeng.tools.utils.ImagePath; +import com.zhangmeng.tools.utils.ResourcesUtils; +import javafx.beans.property.SimpleDoubleProperty; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.geometry.Pos; +import javafx.scene.Scene; +import javafx.scene.control.Label; +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.scene.control.SplitPane; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.HBox; +import javafx.scene.paint.Paint; +import javafx.scene.text.Font; +import javafx.scene.web.WebView; +import javafx.stage.Stage; +import javafx.util.Callback; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.util.Arrays; + +@Slf4j +public class EditListController { + + private SimpleDoubleProperty width = new SimpleDoubleProperty(0.0); + private SimpleDoubleProperty height = new SimpleDoubleProperty(0.0); + private AceEditor root; + + private AceEditor acJsEditor; + + public static final String color_cell = "#f4f4f4"; + + @FXML + private ListView listView; + + @FXML + private SplitPane splitPane; + + @FXML + public void date_query_menu_item(){ + load_small_tools(5); + } + + @FXML + public void cron_menu_item(){ + load_small_tools(6); + } + + @FXML + public void video_menu_item() { + load_player(0); + } + + @FXML + public void music_menu_item() { + load_player(1); + } + + @FXML + public void vip_parser_menu_item() { + load_player(2); + } + + @FXML + public void hex_16(){ + load_small_tools(0); + } + + @FXML + private void hex_16_menu_item(){ + load_small_tools(0); + } + + @FXML + private void unicode_menu_item(){ + load_small_tools(1); + } + + @FXML + private void jwt_menu_item(){ + load_small_tools(2); + } + + @FXML + private void color_choose_menu_item(){ + load_small_tools(3); + } + + @FXML + public void qr_code_menu_item(){ + load_small_tools(4); + } + + @FXML + public void base_62_menu_item(){ + load_codec_tools(0); + } + + @FXML + public void base_64_menu_item(){ + load_codec_tools(1); + } + + @FXML + public void base_32_menu_item(){ + load_codec_tools(2); + } + + @FXML + public void morse_coder_menu_item(){ + load_codec_tools(3); + } + + @FXML + private void sql_code_gen_menu_item(){ + load_sql_tools(0); + } + + @FXML + public void netty_client_menu_item(){ + load_network_tools(0); + } + + public void load_network_tools(int index){ + AnchorPane fx = null; + try { + fx = FXMLLoader.load(ResourcesUtils.getResource("network-tools")); + } catch (IOException e) { + e.printStackTrace(); + } + + Scene scene = new Scene(fx); + Stage stage = (Stage) splitPane.getScene().getWindow(); + stage.setScene(scene); + + ListView listView = (ListView) fx.lookup("#listView"); + listView.getSelectionModel().select(index); + } + + public void load_sql_tools(int index){ + AnchorPane fx = null; + try { + fx = FXMLLoader.load(ResourcesUtils.getResource("sql-tools")); + } catch (IOException e) { + e.printStackTrace(); + } + + Scene scene = new Scene(fx); + Stage stage = (Stage) splitPane.getScene().getWindow(); + stage.setScene(scene); + + ListView listView = (ListView) fx.lookup("#listView"); + listView.getSelectionModel().select(index); + } + + public void load_codec_tools(int index){ + AnchorPane fx = null; + try { + fx = FXMLLoader.load(ResourcesUtils.getResource("codec-tools")); + } catch (IOException e) { + e.printStackTrace(); + } + + Scene scene = new Scene(fx); + Stage stage = (Stage) splitPane.getScene().getWindow(); + stage.setScene(scene); + + ListView listView = (ListView) fx.lookup("#listView"); + listView.getSelectionModel().select(index); + } + + public void load_small_tools(int index){ + AnchorPane fx = null; + try { + fx = FXMLLoader.load(ResourcesUtils.getResource("small-tools")); + } catch (IOException e) { + e.printStackTrace(); + } + + Scene scene = new Scene(fx); + Stage stage = (Stage) splitPane.getScene().getWindow(); + stage.setScene(scene); + + ListView listView = (ListView) fx.lookup("#listView"); + listView.getSelectionModel().select(index); + } + + public void load_player(int index) { + AnchorPane fx = null; + try { + fx = FXMLLoader.load(ResourcesUtils.getResource("player")); + } catch (IOException e) { + e.printStackTrace(); + } + + Scene scene = new Scene(fx); + Stage stage = (Stage) splitPane.getScene().getWindow(); + stage.setScene(scene); + + ListView listView = (ListView) fx.lookup("#listView"); + listView.getSelectionModel().select(index); + } + + @FXML + public void initialize() { + init(); + listView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { + if (newValue != null) { + boolean flag = false; + + if (newValue.getIndex() == 0) { + if (acJsEditor != null){ + flag = true; + } + acJsEditor(flag); + } + + } + }); + } + + public static Image getImage(ResourcesUtils.EditorList player){ + return switch (player){ + case Ace_JS -> new Image(ImagePath.path(ImagePath.ImagePathType.MD5)); + }; + } + + public void init() { + ResourcesUtils.EditorList[] values = ResourcesUtils.EditorList.values(); + ObservableList list = FXCollections.observableArrayList(); + list.addAll(Arrays.asList(values)); + listView.setItems(list); + listView.setFixedCellSize(40); + listView.setCellFactory(new Callback<>() { + private int position; + @Override + public ListCell call(ListView playerListView) { + Label label = new Label(); + label.setPrefWidth(200); + ListCell listCell = new ListCell<>() { + @Override + protected void updateItem(ResourcesUtils.EditorList player, boolean b) { + super.updateItem(player, b); + if (!b) { + HBox hBox = new HBox(25); + hBox.setAlignment(Pos.CENTER); + label.setText(player.getTitle()); + label.setTextFill(Paint.valueOf("#000000")); + Image im = getImage(player); + ImageView iv = new ImageView(im); + iv.setPreserveRatio(true); + iv.setFitWidth(15); + hBox.getChildren().add(iv); + + hBox.getChildren().add(label); + this.setGraphic(hBox); + } + this.setStyle("-fx-background-color: " + color_cell); + } + }; + + listCell.hoverProperty().addListener((observableValue, aBoolean, t1) -> { + if (t1 && !label.getText().equals("")) { + position = playerListView.getItems().indexOf(label.getText()); + label.setFont(new Font(16)); + playerListView.getFocusModel().focus(position); + listCell.setStyle("-fx-background-color: #369e7d"); + } else { + label.setPrefHeight(20); + label.setFont(new Font(13)); + listCell.setStyle("-fx-background-color: " + color_cell); + } + }); + + return listCell; + } + }); + + acJsEditor(false); + } + + private void acJsEditor(boolean flag) { + //默认选择第一个 + listView.getSelectionModel().select(0); + + if (!flag){ + root = new AceEditor(); + WebView webView = root.getWebView(); + webView.prefWidthProperty().bind(root.widthProperty()); + webView.prefHeightProperty().bind(root.heightProperty()); + + acJsEditor = root; + }else { + root = acJsEditor; + } + common_method(); + } + + + private void common_method() { + splitPane.getItems().remove(1); + splitPane.getItems().add(1, root); + root.widthProperty().addListener((observable, oldValue, newValue) -> { + if (newValue != null) { + double width = splitPane.getWidth(); + EditListController.this.width.set(width); + log.info("home:--->width:{}", width); + } + }); + root.heightProperty().addListener((observable, oldValue, newValue) -> { + if (newValue != null) { + double height = splitPane.getHeight(); + EditListController.this.height.set(height); + log.info("home:--->height:{}", height); + } + }); + + this.width.addListener((observable, oldValue, newValue) -> { + EditListController.this.root.setPrefWidth(newValue.doubleValue() - listView.getWidth()); + }); + + this.height.addListener((observable, oldValue, newValue) -> { + EditListController.this.root.setPrefHeight(newValue.doubleValue() - listView.getHeight()); + }); + } + + @FXML + public void http_request_menu_item(ActionEvent event) { + load_http_tools(0); + } + + @FXML + public void http_upload_menu_item(ActionEvent event) { + load_http_tools(1); + } + + @FXML + public void http_download_menu_item(ActionEvent event) { + load_http_tools(2); + } + + public void load_http_tools(int index) { + AnchorPane fx = null; + try { + fx = FXMLLoader.load(ResourcesUtils.getResource("http-tools")); + } catch (IOException e) { + e.printStackTrace(); + } + + Scene scene = new Scene(fx); + Stage stage = (Stage) splitPane.getScene().getWindow(); + stage.setScene(scene); + + ListView listView = (ListView) fx.lookup("#listView"); + listView.getSelectionModel().select(index); + } + + @FXML + public void mail_menu_item(ActionEvent event) { + load_small_tools(7); + } + + public void http_server_menu_item(ActionEvent event) { + load_server_tools(0); + } + + public void ftp_server_menu_item(ActionEvent event) { + load_server_tools(1); + } + + public void load_server_tools(int index) { + AnchorPane fx = null; + try { + fx = FXMLLoader.load(ResourcesUtils.getResource("server-tools")); + } catch (IOException e) { + e.printStackTrace(); + } + + Scene scene = new Scene(fx); + Stage stage = (Stage) splitPane.getScene().getWindow(); + stage.setScene(scene); + + ListView listView = (ListView) fx.lookup("#listView"); + listView.getSelectionModel().select(index); + } + + public void ssh_client_menu_item(ActionEvent event) { + load_server_tools(2); + } + + public void socket_server_menu_item(ActionEvent event) { + load_server_tools(3); + } + + public void telephone_menu_item(ActionEvent event) { + load_small_tools(8); + } + + public void mybatis_plus_gen_menu_item(ActionEvent event) { + load_sql_tools(1); + } + + public void JsonView_menu_item(ActionEvent event) { + + load_small_tools(9); + } + + public void maven_jar_install_menu_item(ActionEvent event) { + load_small_tools(10); + } + + public void word_ocr_menu_item(ActionEvent event) { + load_small_tools(11); + } + + public void bar_code_menu_item(ActionEvent event) { + load_small_tools(12); + } + + public void pdf_menu_item(ActionEvent event) { + load_small_tools(13); + } + + public void json_javabean_gen_menu_item(ActionEvent event) { + load_sql_tools(2); + } + + public void music_parser_menu_item(ActionEvent event) { + load_player(3); + } + + public void batch_update_file_name_menu_item(ActionEvent event) { + load_small_tools(14); + } + + public void socket_client_aio_menu_item(ActionEvent event) { + load_server_tools(4); + } + + public void socket_server_aio_menu_item(ActionEvent event) { + load_server_tools(5); + } + + public void socket_server_nio_menu_item(ActionEvent event) { + load_server_tools(6); + } + + public void socket_client_nio_menu_item(ActionEvent event) { + load_server_tools(7); + } + + public void capter_screen_menu_item(ActionEvent event) { + load_small_tools(15); + } + + public void sql_query_gen_menu_item(ActionEvent event) { + load_sql_tools(3); + } + + public void video_transcoder_menu_item(ActionEvent event) { + load_player(4); + } + + public void json_to_struct_menu_item(ActionEvent event) { + load_go_tools(0); + } + + public void load_go_tools(int index){ + AnchorPane fx = null; + try { + fx = FXMLLoader.load(ResourcesUtils.getResource("go-tools")); + } catch (IOException e) { + e.printStackTrace(); + } + + Scene scene = new Scene(fx); + Stage stage = (Stage) splitPane.getScene().getWindow(); + stage.setScene(scene); + + ListView listView = (ListView) fx.lookup("#listView"); + listView.getSelectionModel().select(index); + } + + public void file_edit_menu_item(ActionEvent event) { + load_small_tools(16); + } + + public void web_socket_client_menu_item(ActionEvent event) { + load_server_tools(8); + } + + public void layui_form_gen_menu_item(ActionEvent actionEvent) { + load_small_tools(17); + } + + public void log_console_menu_item(ActionEvent actionEvent) { + load_small_tools(18); + } + + public void edit_plus_code_menu_item(ActionEvent actionEvent) { + load_small_tools(19); + } + + public void minio_upload_menu_item(ActionEvent actionEvent) { + load_small_tools(20); + } + + public void ace_js_menu_item(ActionEvent actionEvent) { + js_edit_list(0); + } + + public void js_edit_list(int index){ + AnchorPane fx = null; + try { + fx = FXMLLoader.load(ResourcesUtils.getResource("editor-list")); + } catch (IOException e) { + e.printStackTrace(); + } + + Scene scene = new Scene(fx); + Stage stage = (Stage) splitPane.getScene().getWindow(); + stage.setScene(scene); + + ListView listView = (ListView) fx.lookup("#listView"); + listView.getSelectionModel().select(index); + } + + public void md5_menu_item(ActionEvent actionEvent) { + + load_encrypt(0); + } + + public void spring_security_menu_item(ActionEvent actionEvent) { + load_encrypt(1); + } + + public void jks_file_menu_item(ActionEvent actionEvent) { + load_encrypt(2); + } + + public void load_encrypt(int index) { + + Stage stage = (Stage) splitPane.getScene().getWindow(); + + AnchorPane fx = null; + try { + fx = FXMLLoader.load(ResourcesUtils.getResource("home")); + } catch (IOException e) { + e.printStackTrace(); + } + Scene scene = new Scene(fx); + stage.setScene(scene); + + ListView listView = (ListView) fx.lookup("#listView"); + listView.getSelectionModel().select(index); + } +} diff --git a/src/main/java/com/zhangmeng/tools/controller/HomeController.java b/src/main/java/com/zhangmeng/tools/controller/HomeController.java index 4d10691..b9a8c65 100644 --- a/src/main/java/com/zhangmeng/tools/controller/HomeController.java +++ b/src/main/java/com/zhangmeng/tools/controller/HomeController.java @@ -616,4 +616,26 @@ public class HomeController implements Serializable { public void minio_upload_menu_item(ActionEvent actionEvent) { load_small_tools(20); } + + public void ace_js_menu_item(ActionEvent actionEvent) { + + js_edit_list(0); + } + + public void js_edit_list(int index){ + AnchorPane fx = null; + try { + fx = FXMLLoader.load(ResourcesUtils.getResource("editor-list")); + } catch (IOException e) { + e.printStackTrace(); + } + + Scene scene = new Scene(fx); + Stage stage = (Stage) splitPane.getScene().getWindow(); + stage.setScene(scene); + + ListView listView = (ListView) fx.lookup("#listView"); + listView.getSelectionModel().select(index); + } + } \ No newline at end of file diff --git a/src/main/java/com/zhangmeng/tools/editors/ace/AceEditor.java b/src/main/java/com/zhangmeng/tools/editors/ace/AceEditor.java new file mode 100644 index 0000000..d5dcd35 --- /dev/null +++ b/src/main/java/com/zhangmeng/tools/editors/ace/AceEditor.java @@ -0,0 +1,289 @@ +package com.zhangmeng.tools.editors.ace; + + +import com.zhangmeng.tools.utils.AlertUtils; +import com.zhangmeng.tools.utils.ClipboardUtils; +import javafx.beans.property.*; +import javafx.concurrent.Worker; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.StackPane; +import javafx.scene.web.WebEngine; +import javafx.scene.web.WebView; +import javafx.stage.FileChooser; +import javafx.stage.Stage; +import lombok.extern.slf4j.Slf4j; +import netscape.javascript.JSObject; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; + +/** + * @author zhangmeng + * @date 2023年10月7日09:12:41 + * @version 1.0 + * js 编辑器 ace 实现 + */ +@Slf4j +public class AceEditor extends AnchorPane { + + private final WebView webView = new WebView(); + private WebEngine engine; + private AceMode mode = AceMode.JAVA; + private JSObject window; + private JSObject editor; + private File file; + + public WebView getWebView() { + return webView; + } + + public AceEditor() { + initialize(); + } + + public AceEditor(File file) { + String file_content = null; + try { + file_content = Files.readString(file.toPath(), StandardCharsets.UTF_8); + } catch (IOException e) { + try { + file_content = Files.readString(file.toPath(), Charset.forName("GBK")); + } catch (IOException ex) { + ex.printStackTrace(); + } + } + this.file = file; + setText(file_content); + initialize(); + } + + public AceEditor(String text) { + setText(text); + initialize(); + } + + private void setText(String text) { + this.text.set(text); + } + + /** + * 设置内容 + * + * @param value + */ + private void setAceText(String value) { + editor.call("setValue", value, 1); + // 或者调用js中定义好的方法 + // JSObject editor = (JSObject) engine.executeScript("window"); + // editor.call("setEditorValue", value); + } + + private final StringProperty text = new SimpleStringProperty(""); + + public StringProperty textProperty() { + return text; + } + + public String getText() { + return text.get(); + } + + /** + * 修改主题 + */ + private void setAceTheme(AceTheme aceTheme) { + editor.call("setTheme", aceTheme.getValue()); + } + + /** + * 主题 + */ + private final ObjectProperty theme = new SimpleObjectProperty<>(AceTheme.CHROME); + + public ObjectProperty themeProperty() { + return theme; + } + + public AceTheme getTheme() { + return theme.get(); + } + + /** + * 设置模式 + */ + private void setAceMode(AceMode mode) { + window.call("setEditorMode", mode.getValue()); + } + + /** + * 编辑器是否只读 + * + * @param val + */ + private void setAceReadOnly(boolean val) { + //editor.call("setReadOnly", !val); + setAceOption("readOnly", !val); + } + + /** + * 设置ace.js配置项 + * + * @param key + * @param value + */ + private void setAceOption(String key, Object value) { + editor.call("setOption", key, value); + } + + /** + * 是否可编辑 + */ + private final BooleanProperty editable = new SimpleBooleanProperty(true); // 可编辑 + + public boolean isEditable() { + return editable.get(); + } + + /** + * 获取选定文本 + * + * @return + */ + public String selectedText() { + // 一下两个方法都可以获取到选中的文本 + // String selectedText = (String) engine.executeScript("window.getSelection().toString()"); // 有些问题 + return (String) editor.call("getSelectedText"); + } + + /** + * 删除选中的内容 + */ + private void removeSelectText() { + window.call("removeSelectRange"); // 或者:editor.call("remove", "right"); + } + + private final BooleanProperty showGutter = new SimpleBooleanProperty(true); + + public void setShowGutter(boolean showGutter) { + this.showGutter.set(showGutter); + } + + public boolean isShowGutter() { + return showGutter.get(); + } + + /** + * 监听值变化,这个由js触发调用。 + * + * @param text + */ + public void textChange(String text) { + //log.info(text); + setText(text); + } + + + /** + * 是否显示左侧内容(行号,折叠符号区域) + * + * @param val + */ + private void setAceShowGutter(boolean val) { + setAceOption("showGutter", val); + } + + public void initialize() { + getChildren().addAll(webView); + webView.setContextMenuEnabled(false); + engine = webView.getEngine(); + // 界面加载完成执行的方法 + engine.getLoadWorker().stateProperty().addListener((ov, oldState, newState) -> { + if (newState == Worker.State.SUCCEEDED) { + // + window = (JSObject) engine.executeScript("window"); + window.setMember("AceEditor", this); + editor = (JSObject) engine.executeScript("window.editor"); + setAceText(getText()); + setAceTheme(getTheme()); + setAceMode(mode); + setAceReadOnly(isEditable()); + // WebView 整合 Ace.js 后 Ctrl+C 和 Ctrl+X 有问题,重新处理下。 + webView.addEventFilter(KeyEvent.KEY_PRESSED, event -> { + if (event.isControlDown() && event.getCode() == KeyCode.C) { + event.consume(); + ClipboardUtils.setString(selectedText()); + } + if (event.isControlDown() && event.getCode() == KeyCode.X) { + event.consume(); + ClipboardUtils.setString(selectedText()); + if (isEditable()) { + removeSelectText(); // 删除选中的内容 + } + } + + if (event.isControlDown() && event.getCode() == KeyCode.S){//保存 + event.consume(); + + if (file != null){ + try { + FileWriter writer = new FileWriter(file); + writer.write(getText()); + writer.flush(); + writer.close(); + } catch (IOException ex) { + ex.printStackTrace(); + } + }else { + // + + } + + AlertUtils.alert_warning("保存成功!"); + } + + if (event.isControlDown() && event.getCode() == KeyCode.O){//保存 + event.consume(); + //打开文件 + Stage stage = new Stage(); + FileChooser dc = new FileChooser(); + dc.setTitle("文件选择"); + dc.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("文件类型", "*.java", "*.go", "*.txt", "*.json", "*.sql")); + File file = dc.showOpenDialog(stage); + String file_content = null; + try { + file_content = Files.readString(file.toPath(), StandardCharsets.UTF_8); + } catch (IOException e) { + try { + file_content = Files.readString(file.toPath(), Charset.forName("GBK")); + } catch (IOException ex) { + ex.printStackTrace(); + } + } + this.file = file; + setText(file_content); + setAceText(getText()); + } + + }); + // 主题监听 + themeProperty().addListener((observable, oldValue, newValue) -> setAceTheme(newValue)); + // 是否可编辑 + editable.addListener((observable, oldValue, newValue) -> setAceReadOnly(newValue)); + showGutter.addListener((observable, oldValue, newValue) -> setAceShowGutter(newValue)); + } + }); + engine.setJavaScriptEnabled(true); + // message print + engine.getLoadWorker().messageProperty().addListener((observable, oldValue, newValue) -> System.out.printf("engine message : %s%n", newValue)); + // exception print + engine.getLoadWorker().exceptionProperty().addListener((observable, oldValue, newValue) -> newValue.printStackTrace()); + engine.loadContent(AceHelper.getHtml(this.mode,AceTheme.XCODE_JS)); // 加载html资源 + // engine.load(""); // 同一时间多个WebView访问同一个资源时engine.executeScript();会返回undefined。 + } +} diff --git a/src/main/java/com/zhangmeng/tools/editors/ace/AceHelper.java b/src/main/java/com/zhangmeng/tools/editors/ace/AceHelper.java new file mode 100644 index 0000000..45096a5 --- /dev/null +++ b/src/main/java/com/zhangmeng/tools/editors/ace/AceHelper.java @@ -0,0 +1,145 @@ +package com.zhangmeng.tools.editors.ace; + +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +public class AceHelper { + + private static final String ace_js = "/static/editors/ace-builds/src-min/ace.js"; + private static final String ext_language_tools_js = "/static/editors/ace-builds/src-min/ext-language_tools.js"; + + public static String getHtml(AceMode aceMode,AceTheme aceTheme) { + String model_js = "/static/editors/ace-builds/src-min/" + aceMode.getName(); + + String theme_js = "/static/editors/ace-builds/src-min/" + aceTheme.getName(); + + try ( + InputStream aceJsStream = AceHelper.class.getResourceAsStream(ace_js); + InputStream ext_language_tools = AceHelper.class.getResourceAsStream(ext_language_tools_js); + InputStream modelJsStream = AceHelper.class.getResourceAsStream(model_js); + InputStream themeJsStream = AceHelper.class.getResourceAsStream(theme_js); + ) { + String html = """ + + + + + + AceDemo + + + +
+ + """; + + html += "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n"; + + html += """ + + + """; + + return html; + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/com/zhangmeng/tools/editors/ace/AceMode.java b/src/main/java/com/zhangmeng/tools/editors/ace/AceMode.java new file mode 100644 index 0000000..4520530 --- /dev/null +++ b/src/main/java/com/zhangmeng/tools/editors/ace/AceMode.java @@ -0,0 +1,34 @@ +package com.zhangmeng.tools.editors.ace; + +public enum AceMode { + + CSS("mode-css.js", "ace/mode/css"), + HTML("mode-html.js", "ace/mode/html"), + JAVA("mode-java.js", "ace/mode/java"), + JAVASCRIPT("mode-javascript.js", "ace/mode/javascript"), + JSON("mode-json.js", "ace/mode/json"), + NGINX("mode-nginx.js", "ace/mode/nginx"), + PROPERTIES("mode-properties.js", "ace/mode/properties"), + SQL("mode-sql.js", "ace/mode/sql"), + TEXT("mode-text.js", "ace/mode/text"), + XML("mode-xml.js", "ace/mode/xml"), + YAML("mode-yaml.js", "ace/mode/yaml"), + MARKDOWN("mode-markdown.js", "ace/mode/markdown"); + + AceMode(String name, String value) { + this.name = name; + this.value = value; + } + + private final String name; + + private final String value; + + public String getName() { + return name; + } + + public String getValue() { + return value; + } +} diff --git a/src/main/java/com/zhangmeng/tools/editors/ace/AceTheme.java b/src/main/java/com/zhangmeng/tools/editors/ace/AceTheme.java new file mode 100644 index 0000000..2f74e25 --- /dev/null +++ b/src/main/java/com/zhangmeng/tools/editors/ace/AceTheme.java @@ -0,0 +1,26 @@ +package com.zhangmeng.tools.editors.ace; + +public enum AceTheme { + + CHROME("theme-chrome.js", "ace/theme/chrome"), + XCODE_JS("theme-xcode.js", "ace/theme/theme-xcode"), + TOMORROW_NIGHT("theme-tomorrow_night.js", "ace/theme/tomorrow_night"); + + AceTheme(String name, String value) { + this.name = name; + this.value = value; + } + + private final String name; + + private final String value; + + public String getName() { + return name; + } + + public String getValue() { + return value; + } + +} diff --git a/src/main/java/com/zhangmeng/tools/editors/monaco/MonacoEdit.java b/src/main/java/com/zhangmeng/tools/editors/monaco/MonacoEdit.java new file mode 100644 index 0000000..dc3b020 --- /dev/null +++ b/src/main/java/com/zhangmeng/tools/editors/monaco/MonacoEdit.java @@ -0,0 +1,200 @@ +package com.zhangmeng.tools.editors.monaco; + +import com.zhangmeng.tools.editors.ace.AceHelper; +import com.zhangmeng.tools.editors.ace.AceMode; +import com.zhangmeng.tools.editors.ace.AceTheme; +import com.zhangmeng.tools.utils.AlertUtils; +import com.zhangmeng.tools.utils.ClipboardUtils; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.concurrent.Worker; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.layout.AnchorPane; +import javafx.scene.web.WebEngine; +import javafx.scene.web.WebView; +import javafx.stage.FileChooser; +import javafx.stage.Stage; +import netscape.javascript.JSObject; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; + + +/** + * @author zhangmeng + * @date 2023年10月7日16:02:39 + * @version 1.0 + */ +public class MonacoEdit extends AnchorPane { + + private final WebView webView = new WebView(); + private WebEngine engine; + private MonacoMode mode = MonacoMode.JAVA; + private JSObject window; + private JSObject editor; + private File file; + + + public WebView getWebView() { + return webView; + } + + public MonacoEdit() { + initialize(); + } + + public MonacoEdit(File file) { + String file_content = null; + try { + file_content = Files.readString(file.toPath(), StandardCharsets.UTF_8); + } catch (IOException e) { + try { + file_content = Files.readString(file.toPath(), Charset.forName("GBK")); + } catch (IOException ex) { + ex.printStackTrace(); + } + } + this.file = file; + setText(file_content); + initialize(); + } + + public MonacoEdit(String text) { + setText(text); + initialize(); + } + + private final StringProperty text = new SimpleStringProperty(""); + + public StringProperty textProperty() { + return text; + } + + public String getText() { + return text.get(); + } + + private void setText(String text) { + this.text.set(text); + } + + /** + * 设置内容 + * + * @param value + */ + private void setMonacoText(String value) { + editor.call("setValue", value, 1); + } + + /** + * 设置模式 + */ + private void setMonacoMode(MonacoMode mode) { + window.call("setEditorMode", mode.getValue()); + } + + /** + * 获取选定文本 + * + * @return + */ + public String selectedText() { + // 一下两个方法都可以获取到选中的文本 + // String selectedText = (String) engine.executeScript("window.getSelection().toString()"); // 有些问题 + return (String) editor.call("getSelectedText"); + } + + + /** + * 删除选中的内容 + */ + private void removeSelectText() { + window.call("removeSelectRange"); // 或者:editor.call("remove", "right"); + } + + public void initialize() { + getChildren().addAll(webView); + webView.setContextMenuEnabled(false); + engine = webView.getEngine(); + // 界面加载完成执行的方法 + engine.getLoadWorker().stateProperty().addListener((ov, oldState, newState) -> { + if (newState == Worker.State.SUCCEEDED) { + // + window = (JSObject) engine.executeScript("window"); + window.setMember("MonacoEdit", this); + editor = (JSObject) engine.executeScript("window.monaco.editor"); + setMonacoText(getText()); + setMonacoMode(mode); + // WebView 整合 Ace.js 后 Ctrl+C 和 Ctrl+X 有问题,重新处理下。 + webView.addEventFilter(KeyEvent.KEY_PRESSED, event -> { + if (event.isControlDown() && event.getCode() == KeyCode.C) { + event.consume(); + ClipboardUtils.setString(selectedText()); + } + if (event.isControlDown() && event.getCode() == KeyCode.X) { + event.consume(); + ClipboardUtils.setString(selectedText()); + removeSelectText(); // 删除选中的内容 + } + + if (event.isControlDown() && event.getCode() == KeyCode.S){//保存 + event.consume(); + + if (file != null){ + try { + FileWriter writer = new FileWriter(file); + writer.write(getText()); + writer.flush(); + writer.close(); + } catch (IOException ex) { + ex.printStackTrace(); + } + }else { + // + + } + + AlertUtils.alert_warning("保存成功!"); + } + + if (event.isControlDown() && event.getCode() == KeyCode.O){//保存 + event.consume(); + //打开文件 + Stage stage = new Stage(); + FileChooser dc = new FileChooser(); + dc.setTitle("文件选择"); + dc.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("文件类型", "*.java", "*.go", "*.txt", "*.json", "*.sql")); + File file = dc.showOpenDialog(stage); + String file_content = null; + try { + file_content = Files.readString(file.toPath(), StandardCharsets.UTF_8); + } catch (IOException e) { + try { + file_content = Files.readString(file.toPath(), Charset.forName("GBK")); + } catch (IOException ex) { + ex.printStackTrace(); + } + } + this.file = file; + setText(file_content); + setMonacoText(getText()); + } + + }); + } + }); + engine.setJavaScriptEnabled(true); + // message print + engine.getLoadWorker().messageProperty().addListener((observable, oldValue, newValue) -> System.out.printf("engine message : %s%n", newValue)); + // exception print + engine.getLoadWorker().exceptionProperty().addListener((observable, oldValue, newValue) -> newValue.printStackTrace()); + engine.loadContent(MonacoHelper.getHtml(this.mode, MonacoThem.VS)); // 加载html资源 + // engine.load(""); // 同一时间多个WebView访问同一个资源时engine.executeScript();会返回undefined。 + } +} diff --git a/src/main/java/com/zhangmeng/tools/editors/monaco/MonacoHelper.java b/src/main/java/com/zhangmeng/tools/editors/monaco/MonacoHelper.java new file mode 100644 index 0000000..c04a8ce --- /dev/null +++ b/src/main/java/com/zhangmeng/tools/editors/monaco/MonacoHelper.java @@ -0,0 +1,350 @@ +package com.zhangmeng.tools.editors.monaco; + +import com.zhangmeng.tools.editors.ace.AceHelper; +import com.zhangmeng.tools.editors.ace.AceMode; +import com.zhangmeng.tools.editors.ace.AceTheme; + +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +public class MonacoHelper { + + private static final String loader_js_path = "/static/editors/monaco-editor/min/vs/loader.js"; + + public static String getHtml(MonacoMode aceMode, MonacoThem aceTheme) { + + String model_js = aceMode.getName(); + String theme_js = aceTheme.getName(); + + try ( + InputStream loader_JS = AceHelper.class.getResourceAsStream(loader_js_path); + ) { + String html = """ + + + + + Monaco Editor Demo + + + """; + + html += ""; + html += """ + + + + + + + + +
+ + +
+
+ + + + + """; + + return html; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/src/main/java/com/zhangmeng/tools/editors/monaco/MonacoMode.java b/src/main/java/com/zhangmeng/tools/editors/monaco/MonacoMode.java new file mode 100644 index 0000000..e2f93e0 --- /dev/null +++ b/src/main/java/com/zhangmeng/tools/editors/monaco/MonacoMode.java @@ -0,0 +1,20 @@ +package com.zhangmeng.tools.editors.monaco; + +public enum MonacoMode { + + JAVA("java"), + JAVA_SCRIPT("javascript"); + private String name; + + MonacoMode(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/main/java/com/zhangmeng/tools/editors/monaco/MonacoThem.java b/src/main/java/com/zhangmeng/tools/editors/monaco/MonacoThem.java new file mode 100644 index 0000000..e6f6556 --- /dev/null +++ b/src/main/java/com/zhangmeng/tools/editors/monaco/MonacoThem.java @@ -0,0 +1,27 @@ +package com.zhangmeng.tools.editors.monaco; + + +/** + * vs、vs-dark、hc-black + */ + +public enum MonacoThem { + + VS("vs"), + VS_DARK("va-dark"), + HC_BLACK("hc-black"); + + private String name; + + MonacoThem(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/main/java/com/zhangmeng/tools/utils/ClipboardUtils.java b/src/main/java/com/zhangmeng/tools/utils/ClipboardUtils.java new file mode 100644 index 0000000..e915e45 --- /dev/null +++ b/src/main/java/com/zhangmeng/tools/utils/ClipboardUtils.java @@ -0,0 +1,35 @@ +package com.zhangmeng.tools.utils; + +import javafx.scene.Node; +import javafx.scene.SnapshotParameters; +import javafx.scene.input.Clipboard; +import javafx.scene.input.ClipboardContent; +import javafx.scene.paint.Color; + +/** + * 剪贴板工具 + */ +public class ClipboardUtils { + + private static final Clipboard SYSTEM_CLIPBOARD = Clipboard.getSystemClipboard(); + private static final ClipboardContent CLIPBOARD_CONTENT = new ClipboardContent(); + + public static void setString(String val) { + CLIPBOARD_CONTENT.clear(); + CLIPBOARD_CONTENT.putString(val); + SYSTEM_CLIPBOARD.setContent(CLIPBOARD_CONTENT); + } + + public static String getString() { + return SYSTEM_CLIPBOARD.getString(); + } + + public static void setSnapshotImage(Node node) { + SnapshotParameters snapshotParameters = new SnapshotParameters(); + snapshotParameters.setFill(Color.TRANSPARENT); // 透明背景 + CLIPBOARD_CONTENT.clear(); + CLIPBOARD_CONTENT.putImage(node.snapshot(snapshotParameters, null)); // 设置剪贴板内容 + SYSTEM_CLIPBOARD.setContent(CLIPBOARD_CONTENT); + } + +} diff --git a/src/main/java/com/zhangmeng/tools/utils/ResourcesUtils.java b/src/main/java/com/zhangmeng/tools/utils/ResourcesUtils.java index 9a977ec..26a512a 100644 --- a/src/main/java/com/zhangmeng/tools/utils/ResourcesUtils.java +++ b/src/main/java/com/zhangmeng/tools/utils/ResourcesUtils.java @@ -358,4 +358,34 @@ public class ResourcesUtils { private String title; private int index; } + + public enum EditorList { + + Ace_JS("ace.js 编辑器", 0), + ; + + EditorList(String title, int index) { + this.title = title; + this.index = index; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + private String title; + private int index; + } } diff --git a/src/main/resources/fxml/editor-list.fxml b/src/main/resources/fxml/editor-list.fxml new file mode 100644 index 0000000..264473d --- /dev/null +++ b/src/main/resources/fxml/editor-list.fxml @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/fxml/home.fxml b/src/main/resources/fxml/home.fxml index 36c4474..088e3d0 100644 --- a/src/main/resources/fxml/home.fxml +++ b/src/main/resources/fxml/home.fxml @@ -102,6 +102,13 @@ + + + + + + + @@ -36,218 +47,6 @@