All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.fxmisc.richtext.demo.TextArea4XML Maven / Gradle / Ivy

There is a newer version: 1.11
Show newest version

package org.fxmisc.richtext.demo;

import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import java.time.Duration;

import javafx.beans.value.ChangeListener;
import javafx.concurrent.Task;

import org.fxmisc.richtext.LineNumberFactory;
import org.fxmisc.richtext.model.StyleSpans;
import org.fxmisc.richtext.model.StyleSpansBuilder;

import com.sta.mlogger.MLogger;

/**
 * 

Name: TextArea4XML

*

Description: . *

*

Comment: ... *

*

Copyright: Copyright (c) 2018, 2019

*

Company: >StA-Soft<

* @author StA * @version 1.0 */ public class TextArea4XML extends TextAreaBase { private static final Pattern XML_TAG = Pattern.compile( // "(?(]*)(\\h*/?>))|" + "(?(]*)(\\h*/?\\??>))|" + // "(?)" // Original = falsch!!! "(?).)*-->)" // ?s = DOTALL = "." matcht auch Zeilenumbruch, somit Reduktion der Klammer-Ebenen und damit der Rekursion, sonst StackOverflow! // "(?)" // \\R scheint falsch zu sein, es muss wohl \r hei?en, dann kommt noch \n hinzu, ist aber eine Klammer-Ebene zu viel, daher StackOverflow! // "(?)" // "." funktioniert an dieser Stelle nicht // "(?)" // "." funktioniert, aber wieder eine Klammer-Ebene zu viel, StackOverflow! // "(?)(.|\\R))*-->)" // wieder eine Klammer-Ebene zu viel, StackOverflow! ); private static final Pattern ATTRIBUTES = Pattern.compile("(\\w+:?\\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 static StyleSpans> computeHighlighting(String text) { Matcher matcher = XML_TAG.matcher(text); int lastKwEnd = 0; StyleSpansBuilder> 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(); } //=========================================================================== public TextArea4XML(boolean sync) { super(); init(sync); } public TextArea4XML(boolean sync, String text) { super(text); init(sync); } public TextArea4XML(boolean sync, ChangeListener cl) { super(cl); init(sync); } //=========================================================================== private void init(boolean sync) { setParagraphGraphicFactory(LineNumberFactory.get(this)); if (sync) { initSync(); } else { initASync(); } getStylesheets().add(getClass().getResource("xml-highlighting.css").toExternalForm()); } private void initSync() { // ?bernommen aus Java/SQL: richChanges() .filter(ch -> !ch.getInserted().equals(ch.getRemoved())) // XXX .subscribe(change -> { setStyleSpans(0, computeHighlighting(getText())); }); /* // Original f?r XML: textProperty().addListener((obs, oldText, newText) -> { setStyleSpans(0, computeHighlighting(newText)); }); */ } private void initASync() { richChanges() .filter(ch -> !ch.getInserted().equals(ch.getRemoved())) // XXX .successionEnds(Duration.ofMillis(500)) .supplyTask(this::computeHighlightingAsync) .awaitLatest(richChanges()) .filterMap(t -> { if (t.isSuccess()) { return Optional.of(t.get()); } else { MLogger.err("", t.getFailure()); return Optional.empty(); } }) .subscribe(this::applyHighlighting); } private Task>> computeHighlightingAsync() { String text = getText(); Task>> task = new Task>>() { @Override protected StyleSpans> call() throws Exception { return computeHighlighting(text); } }; ExecutorHelper.getExecutor().execute(task); return task; } private void applyHighlighting(StyleSpans> highlighting) { setStyleSpans(0, highlighting); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy