Java tutorial
/* Copyright 2015 - 2016, Luc De pauw - Makercafe.be This file is part of Makerbench. Makerbench is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Makerbench is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Makerbench. If not, see <http://www.gnu.org/licenses/>. */ package be.makercafe.apps.makerbench.editors; import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.io.FileUtils; import org.fxmisc.richtext.CodeArea; import org.fxmisc.richtext.LineNumberFactory; import org.fxmisc.richtext.StyleSpans; import org.fxmisc.richtext.StyleSpansBuilder; import de.jensd.fx.glyphs.GlyphsDude; import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon; import javafx.event.ActionEvent; import javafx.geometry.Orientation; import javafx.scene.Group; import javafx.scene.control.Alert; import javafx.scene.control.Alert.AlertType; import javafx.scene.control.Button; import javafx.scene.control.ToolBar; import javafx.scene.layout.BorderPane; import javafx.scene.layout.Pane; public class XMLEditor extends Editor { private static final Pattern XML_TAG = Pattern .compile("(?<ELEMENT>(</?\\h*)(\\w+)([^<>]*)(\\h*/?>))" + "|(?<COMMENT><!--[^<>]+-->)"); private static final Pattern ATTRIBUTES = Pattern.compile("(\\w+\\h*)(=)(\\h*\"[^\"]+\")"); private static final int GROUP_OPEN_BRACKET = 2; private static final int GROUP_ELEMENT_NAME = 3; private static final int GROUP_ATTRIBUTES_SECTION = 4; private static final int GROUP_CLOSE_BRACKET = 5; private static final int GROUP_ATTRIBUTE_NAME = 1; private static final int GROUP_EQUAL_SYMBOL = 2; private static final int GROUP_ATTRIBUTE_VALUE = 3; private CodeArea caCodeArea; private ToolBar toolBar = null; public XMLEditor(String tabText, Path path) { super(tabText); this.caCodeArea = new CodeArea(""); this.caCodeArea.setEditable(true); this.caCodeArea.setParagraphGraphicFactory(LineNumberFactory.get(caCodeArea)); this.caCodeArea.setPrefSize(Double.MAX_VALUE, Double.MAX_VALUE); this.caCodeArea.getStylesheets().add(this.getClass().getResource("xml-highlighting.css").toExternalForm()); this.caCodeArea.textProperty().addListener((obs, oldText, newText) -> { this.caCodeArea.setStyleSpans(0, computeHighlighting(newText)); }); addContextMenu(this.caCodeArea); try { this.caCodeArea.replaceText(FileUtils.readFileToString(path.toFile())); } catch (IOException ex) { Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Error reading file.", ex); } BorderPane rootPane = new BorderPane(); toolBar = createToolBar(); rootPane.setTop(toolBar); rootPane.setCenter(caCodeArea); this.getTab().setContent(rootPane); } private StyleSpans<Collection<String>> computeHighlighting(String text) { Matcher matcher = XML_TAG.matcher(text); int lastKwEnd = 0; StyleSpansBuilder<Collection<String>> spansBuilder = new StyleSpansBuilder<>(); while (matcher.find()) { spansBuilder.add(Collections.emptyList(), matcher.start() - lastKwEnd); if (matcher.group("COMMENT") != null) { spansBuilder.add(Collections.singleton("comment"), matcher.end() - matcher.start()); } else { if (matcher.group("ELEMENT") != null) { String attributesText = matcher.group(GROUP_ATTRIBUTES_SECTION); spansBuilder.add(Collections.singleton("tagmark"), matcher.end(GROUP_OPEN_BRACKET) - matcher.start(GROUP_OPEN_BRACKET)); spansBuilder.add(Collections.singleton("anytag"), matcher.end(GROUP_ELEMENT_NAME) - matcher.end(GROUP_OPEN_BRACKET)); if (!attributesText.isEmpty()) { lastKwEnd = 0; Matcher amatcher = ATTRIBUTES.matcher(attributesText); while (amatcher.find()) { spansBuilder.add(Collections.emptyList(), amatcher.start() - lastKwEnd); spansBuilder.add(Collections.singleton("attribute"), amatcher.end(GROUP_ATTRIBUTE_NAME) - amatcher.start(GROUP_ATTRIBUTE_NAME)); spansBuilder.add(Collections.singleton("tagmark"), amatcher.end(GROUP_EQUAL_SYMBOL) - amatcher.end(GROUP_ATTRIBUTE_NAME)); spansBuilder.add(Collections.singleton("avalue"), amatcher.end(GROUP_ATTRIBUTE_VALUE) - amatcher.end(GROUP_EQUAL_SYMBOL)); lastKwEnd = amatcher.end(); } if (attributesText.length() > lastKwEnd) spansBuilder.add(Collections.emptyList(), attributesText.length() - lastKwEnd); } lastKwEnd = matcher.end(GROUP_ATTRIBUTES_SECTION); spansBuilder.add(Collections.singleton("tagmark"), matcher.end(GROUP_CLOSE_BRACKET) - lastKwEnd); } } lastKwEnd = matcher.end(); } spansBuilder.add(Collections.emptyList(), text.length() - lastKwEnd); return spansBuilder.create(); } private void setCode(String code) { this.caCodeArea.replaceText(code); } private String getCode() { return this.caCodeArea.getText(); } /** * Creates the toolBar for the editor. * * @return */ private ToolBar createToolBar() { ToolBar toolBar = new ToolBar(); toolBar.setOrientation(Orientation.HORIZONTAL); Button btnSave = GlyphsDude.createIconButton(MaterialDesignIcon.FLOPPY, "Save"); btnSave.setOnAction(this::handleSaveButton); toolBar.getItems().add(btnSave); return toolBar; } private void handleSaveButton(ActionEvent event) { System.out.println("Event: " + event.getSource()); @SuppressWarnings("unchecked") Map<String, String> map = (Map<String, String>) this.getTab().getUserData(); String path = map.get("path"); try { FileUtils.writeStringToFile(new File(path), caCodeArea.getText()); } catch (IOException e) { Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Unable to save file."); Alert alert = new Alert(AlertType.ERROR); alert.setTitle("Oeps an error occured"); alert.setHeaderText("Cannot save file. There went something wrong writing the file."); alert.setContentText( "Please verify that your file is not read only, is not locked by other user or program, you have enough diskspace."); alert.showAndWait(); } } public ToolBar getToolBar() { return toolBar; } public void setToolbar(ToolBar toolBar) { this.toolBar = toolBar; } }