| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| // inspired by http://weitz.de/regex-coach/ |
| package swing |
| |
| import java.awt.* |
| import java.awt.event.* |
| import java.util.regex.* |
| import javax.swing.* |
| import javax.swing.text.DefaultHighlighter |
| import groovy.swing.SwingBuilder |
| |
| // define the view |
| def swing = new SwingBuilder() |
| def gui = swing.frame(title: 'The Groovy Regex Coach', location: [20, 40], size: [600, 500], defaultCloseOperation: WindowConstants.EXIT_ON_CLOSE) { |
| panel(layout: new BorderLayout()) { |
| splitPane(orientation: JSplitPane.VERTICAL_SPLIT, dividerLocation: 150) { |
| panel(layout: new BorderLayout()) { |
| label(constraints: BorderLayout.NORTH, text: 'Regular expression:') |
| scrollPane(constraints: BorderLayout.CENTER) {textPane(id: 'regexPane')} |
| label(constraints: BorderLayout.SOUTH, id: 'regexStatus', text: ' ') |
| } |
| panel(layout: new BorderLayout()) { |
| label(constraints: BorderLayout.NORTH, text: 'Target string:') |
| scrollPane(constraints: BorderLayout.CENTER) {textPane(id: 'targetPane')} |
| panel(constraints: BorderLayout.SOUTH, layout: new BorderLayout()) { |
| label(constraints: BorderLayout.NORTH, id: 'targetStatus', text: ' ') |
| panel(constraints: BorderLayout.SOUTH, layout: new FlowLayout()) { |
| button('<<-', id: 'scanLeft') |
| button('->>', id: 'scanRight') |
| } |
| } |
| } |
| } |
| } |
| } |
| def highlighter = new RegexHighlighter(swing: swing) |
| swing.regexPane.addKeyListener(highlighter) |
| swing.targetPane.addKeyListener(highlighter) |
| swing.scanLeft.addActionListener(highlighter) |
| swing.scanRight.addActionListener(highlighter) |
| gui.show() |
| |
| class RegexHighlighter extends KeyAdapter implements ActionListener { |
| def swing // reference to the view |
| int scanIndex // how many times to execute matcher.find() |
| def orange = new DefaultHighlighter.DefaultHighlightPainter(Color.ORANGE) |
| def yellow = new DefaultHighlighter.DefaultHighlightPainter(Color.YELLOW) |
| def red = new DefaultHighlighter.DefaultHighlightPainter(Color.RED) |
| |
| // react to user actions |
| |
| public void actionPerformed(ActionEvent event) { |
| if (event.actionCommand == '<<-') {scanIndex = Math.max(scanIndex - 1, 0)} |
| if (event.actionCommand == '->>') {scanIndex++} |
| doHighlights() |
| } |
| |
| public void keyReleased(KeyEvent event) { |
| scanIndex = 0 |
| doHighlights() |
| } |
| |
| private resetView() { |
| swing.regexPane.highlighter.removeAllHighlights() |
| swing.targetPane.highlighter.removeAllHighlights() |
| swing.regexStatus.text = ' ' |
| swing.targetStatus.text = ' ' |
| } |
| |
| // the main regex logic |
| |
| private doHighlights() { |
| try { |
| resetView() |
| // note: get the text from the underlying document, |
| // otherwise carriage return/line feeds different when using the JTextPane text |
| def regex = swing.regexPane.document.getText(0, swing.regexPane.document.length) |
| def target = swing.targetPane.document.getText(0, swing.targetPane.document.length) |
| |
| def matcher = (target =~ regex) |
| |
| // scan past the matches before the match we want |
| int scan = 0 |
| while (scan < scanIndex) { |
| matcher.find() |
| scan++ |
| } |
| if (matcher.find()) { |
| // highlight any captured groups |
| int i = 0 |
| while (i++ < matcher.groupCount()) { |
| swing.targetPane.highlighter.addHighlight(matcher.start(i), matcher.end(i), orange) |
| } |
| // highlight whole match |
| swing.targetPane.highlighter.addHighlight(matcher.start(), matcher.end(), yellow) |
| if (regex.length() != 0) { |
| swing.targetStatus.text = "Match #${scanIndex + 1} from ${matcher.start()} to ${matcher.end()}." |
| } |
| } else { // not found |
| scanIndex = Math.max(scan - 1, 0) |
| if (scanIndex > 0) {doHighlights()} |
| swing.targetStatus.text = "No match." |
| } |
| } catch (PatternSyntaxException e) { |
| swing.regexPane.highlighter.addHighlight(e.index, e.index + 2, red) |
| swing.regexStatus.text = e.description |
| } |
| } |
| } |