# Java SWT StyledText SQL-Syntax-Highligthing



## Christopher25 (11. Mai 2016)

Hallo.

Ich möchte gerne in SWT eine für die SQL-Syntax StyledText Komponente Entwerfen.
Also die Begriffe wie "SELECT", "AS", "FROM" usw. Sollen Dunkel Lila und die Kommentare mit
"/*" und "*/" sollen Dunkel Grün angezeigt werden.

Ich habe folgendes dazu im Internet gefunden:
http://www.java2s.com/Code/Java/SWT-JFace-Eclipse/Demonstratesmultilinecomments.htm

Ich habe das etwas anders umgesetzt aber mit dem selben Prinzip:

```
// Hier die Implementierung in der oberklasse, dieser Kommentar steht nicht im Quellcode
// sondern wurde nur für dieses Forum gemacht
private static final String[] KEYWORDS_START = {
       "/*", "SELECT", "FROM", "UPDATE", "DROP", "DELETE", "INSERT", "INTO", "VALUES", "AS", "CREATE", "ALTER",  "AND", "OR",
       "FROM", "WHERE", "IN", "[", "]", "{", "}", "(", ")" ,"|", "&", "LIKE", "ORDER", "BY", "DISTINCT", "UNION", "TABLE",
       "NOT", "NULL", "AUTO_INCREMENT", ";", "BETWEEN", "LEFT", "RIGHT", "INNER", "OUTER", "FULL", "JOIN", "PRIMARY KEY"
   };
   private static final String[] KEYWORDS_END = {
       "*/", "SELECT", "FROM", "UPDATE", "DROP", "DELETE", "INSERT", "INTO", "VALUES", "AS", "CREATE", "ALTER",  "AND", "OR",
       "FROM", "WHERE", "IN", "[", "]", "{", "}", "(", ")" ,"|", "&", "LIKE", "ORDER", "BY", "DISTINCT", "UNION", "TABLE",
       "NOT", "NULL", "AUTO_INCREMENT", ";", "BETWEEN", "LEFT", "RIGHT", "INNER", "OUTER", "FULL", "JOIN", "PRIMARY KEY"
   };

class StyleListener implements LineStyleListener {
        private final String[] KEY_START;
        private final String[] KEY_END;

        private Color COMMENT_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GREEN);

        private final List<int[]> commentOffsets;

        public StyleListener(String[] start, String[] end) {
            this.KEY_START = start;
            this.KEY_END = end;
            commentOffsets = new ArrayList<int[]>();
        }

        public void refreshMultilineComments(String text) {
            commentOffsets.clear();
           
            for (int index = 0; index < KEY_START.length; index++) {
                for (int pos = text.indexOf(KEY_START[index]); pos > -1; pos = text.indexOf(KEY_START[index], pos)) {
                    int[] offsets = new int[2];
                    offsets[0] = pos;

                    pos = text.indexOf(KEY_END[index], pos);

                    offsets[1] = pos == -1 ? text.length() - 1 : pos + KEY_END[index].length() - 1;
                    pos = offsets[1];

                    commentOffsets.add(offsets);
                }
            }
        }

        @Override
        public void lineGetStyle(LineStyleEvent event) {
            List<StyleRange> styles = new ArrayList<StyleRange>();

            int length = event.lineText.length();

            for (int i = 0, n = commentOffsets.size(); i < n; i++) {
                int[] offsets = (int[]) commentOffsets.get(i);
                if (offsets[0] > event.lineOffset + length) break;
                if (offsets[0] <= event.lineOffset + length && offsets[1] >= event.lineOffset) {
                    int start = Math.max(offsets[0], event.lineOffset);

                    int len = Math.min(offsets[1], event.lineOffset + length) - start + 1;

                    styles.add(new StyleRange(start, len, COMMENT_COLOR, null, SWT.BOLD | SWT.ITALIC));
                }
            }

            event.styles = (StyleRange[]) styles.toArray(new StyleRange[0]);
        }
    }
```


Leider kann die StyledText Komponente nur einen LineStyleListener haben und nicht mehrere.
Somit weiß ich z.b. nicht wie ich die kommentare von den anderen Trennen soll.
Ebenso ist es sehr unschön, dass diese Lösung es nicht trennt ob es wirklich das Keyword ist, welches farblich hinterlegt werden soll.
Also damit meine ich, dass wenn ich "SELECT column1 AS IchBinColumn1 FROM Table1" schreibe oder ob ich nur das Wort "das" schreibe, würde er mir das Wort "das" mit dem "as" auch farblich markieren, obwohl es ja nicht wirklich das ist, was er machen soll.
Ebenso finde ich, ist diese Lösung eher unperformant oder?

Wie dem auch sei. Ich suche jedenfalls einen einfach zu realisierenden und korrekt ausführenden Algorythmus.
Kann mir dabei jemand helfen?


----------



## Christopher25 (11. Mai 2016)

Aus gegebenem Anlass habe ich mich nun entschieden, die Applikation nicht weiter in SWT
zu programmieren sondern steige auf JavaFX um.
Das hat etwas mit dem RAM-Speicher Verbrauch von SWT zutun, welches eher schlecht als Recht ist.
Da aber ein Algorythmus eigentlich etwas ist, was Sprachenübergreifend funktionieren soll/te, wäre
ich euch trozdem sehr verbunden, wenn mir jemand weiterhin bei dieser Sache Unterstützung geben könntet.


----------



## lam_tr (12. Mai 2016)

Hallo Christopher25,

wenn du auf Basis von JavaFX machen willst, kann ich dir die lösung von Tom Schindl sehr gut empfehlen.

https://tomsondev.bestsolution.at/2...and-a-code-dev-environment-written-in-javafx/

Du kannst deine Regeln deklarativ beschreiben und daraus den Editor generieren, ist sehr einfach und vor allem richtig cool.

Viele Grüße
lam

P.S. Auf seine Blog Seite findest du weitere Tutorials zu dem Thema, außerdem unterstützt der Editor Autocompletion, Outline und viele Schönheiten.


----------



## dzim (12. Mai 2016)

@lam_tr - hast du das schon ausprobiert? Ich hab mir bisher nur die Videos angeschaut, aber noch keine Lust gehabt, daraus etwas selbst zu machen...


----------



## Christopher25 (12. Mai 2016)

Ich bin noch dabei die Gui in JavaFX umzuschreiben.
Bin damit schon fast soweit, dass der Stand wie von dem von SWT gleich kommt.
Jedoch merke ich gerade, dass mein Speicherproblem nicht wirklich besser geworden ist.

Die Sache ist die, dass ich eine Tabelle innerhalb eines Tabs habe.
Wenn ich den Tab schließe, werden nur wenige MB freigegeben und vieles bleibt übrig.
Ich habe bei dem Tab einen setOnClose EventHandler drangesetzt, der mir beim Schließen
alle Referenzen innerhalb der Tabelle weghauen soll, da er das anscheinend nicht beim Löschen der Gui-Komponente macht.
Hier der Code:

```
tab.setOnClosed(new EventHandler<Event>() {
                @Override
                public void handle(Event arg0) {
                    BorderPane content = (BorderPane) tab.getContent();
                    for (Node child : content.getChildren()) {
                        if (child instanceof TableView) {
                            TableView tableView = (TableView) child;
                            for (Object item : tableView.getItems()) {
                                SQLTableValue[] values = (SQLTableValue[]) item;
                                for (SQLTableValue value : values) {
                                    value.setType(null);
                                    value.setValue(null);
                                    value = null;
                                    item = null;
                                }
                                values = null;
                            }
                            tableView.setItems(null);
                            tableView = null;
                        }
                    }
                }
            });
```
Ich mach sicher einige Sachen doppelt und unnötig, aber ich will eigentlich auf Nummer sicher gehen.
Es kann nicht sein, wenn ich 10 Tabs offen hab mit Tabellen drin, diese dann Schließe, dass ich immernoch ca. 400+ MB im RAM liegen hab.
Und umso mehr Tabellen ich vorher offen hatte, umso voller wird der dann nach und nach.


----------



## lam_tr (13. Mai 2016)

Hallo dzim,

ich habe jeden Blog Eintrag von Tom Schindl verfolgt, und als er das Tutorial zum Smart Code Editor rausgebracht habe, habe ich sofort getestet.

Lief alles ganz gut und vor allem sehr schnell.

Wir dürfen hier kein JavaFX benutzen, sonst würde ich es an sehr vielen Stellen verwenden können für unsere Custom Formate. Momentan ist es halt so dass ich ein bissle am StyledText rumfrimmel, ist wirklich keine saubere Lösung.

Ich würde mal sagen, auf die schnelle über Smart Editor bräuchte man ca 30 min bis man da alles generiert hat. In 30 min hätte ich das niemals in SWT oder reines JavaFX gebacken bekommen.


```
Ich hab mir bisher nur die Videos angeschaut, aber noch keine Lust gehabt, daraus etwas selbst zu machen... ;):D
```
Es lohnt sich auf jeden Fall darein zu schauen.

Ich habe vor allem auf der letzten EclipseCon seinen Vortrag gehört und habe dann die Partitioning und die Aufteilung der Grammatik verstanden.

Viele Grüße
lam


----------



## dzim (13. Mai 2016)

@lam_tr ja die DSL für die Grammatik war mir - nur vom reinem zuschauen - nicht sofort verständlich. Ansonsten ist sein Blog lediglich einer von vielen, die ich immer wieder mal beobachte...

@Christopher25 Leider kann ich, ohne den Code des Erstellens der Tabelle zu kennen, nicht sagen, was genau das Problem ist. Es gibt Tools zum Monitoren einer JVM (VisualVM im JDK z.B.). Vielleicht kannst du damit mal schauen, ob du ein paar Hinweise bekommst.
Ansonsten kann du auch mit Scenic View (http://fxexperience.com/scenic-view/) schauen, was sich noch alles auf deinem Scene Graph befindet. Vielleicht hilft dir das.


----------



## mrBrown (13. Mai 2016)

Christopher25 hat gesagt.:


> Ich mach sicher einige Sachen doppelt und unnötig, aber ich will eigentlich auf Nummer sicher gehen.
> Es kann nicht sein, wenn ich 10 Tabs offen hab mit Tabellen drin, diese dann Schließe, dass ich immernoch ca. 400+ MB im RAM liegen hab.
> Und umso mehr Tabellen ich vorher offen hatte, umso voller wird der dann nach und nach.



Von der JVM reservierter RAM oder innerhalb der JVM reservierter Speicher?

Den RAM gibt die JVM, auch wenn intern nicht mehr belegt, nicht zwingend direkt frei, uU behält die den für die gesamte restliche Laufzeit.

Wenn innerhalb der JVM der Speicher auch belegt ist, dann werden irgendwo noch irgendwelche Referenzen liegen. Mal mit nem Profiler durchgehen, oder mit Scenic View mal gucken.

Generell ist Java aber auch nicht die Speichersparendste Sprache...


----------



## Christopher25 (14. Mai 2016)

Nun ich habe VisualVM bereits benutzt und halt gesehen, dass der Speicher meistens von meinen Objekten "SQLRow" belegt wird.
Diese sollten eigentlich garkeine Referenz mehr besitzen, deswegen habe ich oben ja auch den Code mit der Schleife beim closen eines tabs gepostet.
Nützt es etwas, die TableView nicht mit einer Liste von SQLRows zu befüllen sondern mit einer Liste von
WeakReference<SQLRow> ??


----------



## mrBrown (14. Mai 2016)

Christopher25 hat gesagt.:


> Nun ich habe VisualVM bereits benutzt und halt gesehen, dass der Speicher meistens von meinen Objekten "SQLRow" belegt wird.
> Diese sollten eigentlich garkeine Referenz mehr besitzen, deswegen habe ich oben ja auch den Code mit der Schleife beim closen eines tabs gepostet.
> Nützt es etwas, die TableView nicht mit einer Liste von SQLRows zu befüllen sondern mit einer Liste von
> WeakReference<SQLRow> ??


Vermutlich nicht, irgendwo liegt ja trotzdem noch eine Referenz rum, die das aufräumen verhindert, die in der TableView wird ja genullt.

Ist der GC überhaupt schon gelaufen?


----------



## Christopher25 (14. Mai 2016)

lam_tr hat gesagt.:


> Hallo Christopher25,
> 
> wenn du auf Basis von JavaFX machen willst, kann ich dir die lösung von Tom Schindl sehr gut empfehlen.
> 
> ...



Der benutzt irgendwas mit Python oder?


----------



## lam_tr (14. Mai 2016)

Christopher25 hat gesagt.:


> Der benutzt irgendwas mit Python oder?



Nein, ist alles Java. Er hat eine eigene Sprache zur Erleichterung der UI-Generierung gebaut.


----------



## Christopher25 (14. Mai 2016)

Naja dann versteh ich gerade nicht, was ich da machen muss.

 Ich seh in den Videos nur etwas mit SWT und Phyton


----------



## lam_tr (14. Mai 2016)

Also wenn du dieses Video meinst 



.

Diese Anwendung / Editor ist mit Hilfe von Toms Framework Code Compensator generiert worden.
An sich muss du nur noch konfigurieren mit der DSL und kannst die Anwendung erstellen lassen.

Es supported Highlighting, Autocompletion, Outline, Theming, etc.


----------



## Christopher25 (15. Mai 2016)

Und diesen Editor kann ich dann als Komponente in mein Programm einfügen?
Also ich brauche schon etwas, was ich als JavaFX.Node irgendwo innerhalb meiner Applikation
Integrieren kann^^


----------



## lam_tr (15. Mai 2016)

Guten morgen,

ich habe gerade den Code angeguckt, du sollst da org.eclipse.fx.code.editor.fx.TextEditor benutzen, was wiederum von Node erbt, passt also.

Grüße
lam


----------



## Christopher25 (16. Mai 2016)

und woher bekomme ich diesen org.eclipse.fx.code.editor.fx.TextEditor?


----------



## Christopher25 (16. Mai 2016)

Mir sind da zu viele Abhängigkeiten drin.


----------



## Christopher25 (16. Mai 2016)

Ich habe mich jetzt an dieses Beispiel gehalten und das ganze mit der CodeArea gemacht.

https://github.com/TomasMikula/Rich...g/fxmisc/richtext/demo/JavaKeywordsAsync.java


----------



## Christopher25 (17. Mai 2016)

Ich bedanke mich für eure Hilfe =)
Der Thread kann dann geschlossen werden, läuft soweit alles


----------



## dzim (17. Mai 2016)

Sieht noch nett aus - vergleichbar einfach. Der Texteditor, den @lam_tr vorgeschlagen hat, ist halt eventuell etwas mächtiger. Aber wenn du das nicht brauchst, ist dass sicher auch OK.


----------

