/* * org.openmicroscopy.shoola.util.ui.omeeditpane.RegexTextPane * *------------------------------------------------------------------------------ * Copyright (C) 2006-2010 University of Dundee. All rights reserved. * * * This program 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 2 of the License, or * (at your option) any later version. * This program 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 this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * *------------------------------------------------------------------------------ */ package org.openmicroscopy.shoola.util.ui.omeeditpane; import java.awt.Point; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import javax.swing.JEditorPane; import javax.swing.JTextPane; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.BadLocationException; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; import javax.swing.text.StyledDocument; /** * A Text Editor with Regular expression capability. * * @author William Moore      * <a href="mailto:will@lifesci.dundee.ac.uk">will@lifesci.dundee.ac.uk</a> * @since 3.0-Beta4 */ public class RegexTextPane extends JTextPane implements DocumentListener { /** The default font family. */ public static final String FONT_FAMILY = "Arial"; /** The default font size. */ public static final int FONT_SIZE = 12; /** * Bound property indicating that a regular expression has been clicked. */ public static final String REGEX_DBL_CLICKED_PROPERTY = "regexDblClicked"; /** * Formatter for changing appearance of text according to regular * expression matching. */ private OMERegexFormatter regexFormatter; /** A simple attribute set that defines the plain text for this TextPane. */ private SimpleAttributeSet plainText; /** The document of the TextPane we're editing. */ private StyledDocument doc; /** Store the regular expressions. */ private Set<String> regexStrings; /** * Called whenever the document is edited. * Parses the regular expression. */ private void parseRegex(int caretPosition) { // apply formatting according to regex patterns regexFormatter.parseRegex(doc, true); // true: clear formatting } /** * MouseListener for handling double-clicks on URLs * @author will */ private class UrlMouseListener extends MouseAdapter { /** * Handles double-clicks, checks whether the character clicked is * within a URL (parses all text for URL regular expressions). * If so, gets the URL and opens web browser. * Display of URL is handled separately by regexFormatter. */ public void mouseClicked(MouseEvent e) { Point mouseLoc = e.getPoint(); int offset = viewToModel(mouseLoc); if (e.getClickCount() == 2) { String text = ""; try { text = doc.getText(0, doc.getLength()); Map<Position, String> matches = new HashMap<Position, String>(); String regex; Iterator<String> i = regexStrings.iterator(); Entry entry; Iterator j; Position p; String group, fullMatch; while(i.hasNext()) { regex = i.next(); WikiView.findGroups(text, regex, matches); j = matches.entrySet().iterator(); while (j.hasNext()) { entry = (Entry) j.next(); p = (Position) entry.getKey(); if (p.contains(offset, offset)) { fullMatch = doc.getText( p.getStart(), p.getEnd()-p.getStart()); group = (String) entry.getValue(); firePropertyChange(REGEX_DBL_CLICKED_PROPERTY, null, new WikiDataObject(regex, group, fullMatch)); return; } } } } catch (BadLocationException e2) {} } } } /** Installs the listeners. */ private void installListeners() { getDocument().addDocumentListener(this); //add a mouseListener for opening a URL with a double-click addMouseListener(new UrlMouseListener()); } /** * Initializes the components. * * @param fontFamily The font family to use. * @param fontSize The size of the font. */ private void initialize(String fontFamily, int fontSize) { if (fontFamily == null || fontFamily.length() == 0) fontFamily = FONT_FAMILY; if (fontSize < 4) fontSize = FONT_SIZE; doc = getStyledDocument(); regexStrings = new HashSet<String>(); //Put the initial text into the text pane. plainText = new SimpleAttributeSet(); StyleConstants.setFontFamily(plainText, fontFamily); StyleConstants.setFontSize(plainText, fontSize); // make the regexFormatter regexFormatter = new OMERegexFormatter(plainText); installListeners(); } /** Creates a default instance. */ public RegexTextPane() { initialize(getFont().getFamily(), getFont().getSize()); } /** * Creates a new instance. * * @param fontFamily The font family to use. * @param fontSize The size of the font. */ public RegexTextPane(String fontFamily, int fontSize) { initialize(fontFamily, fontSize); } /** Installs the default regular expression. */ public void installDefaultRegEx() { addRegex(OMEWikiConstants.IMAGEREGEX, AttributeSetFactory.createURLAttributeSet()); /* addRegex(OMEWikiConstants.PROJECTREGEX, AttributeSetFactory.createDefaultAttibuteSet()); addRegex(OMEWikiConstants.DATASETREGEX, AttributeSetFactory.createDefaultAttibuteSet()); */ addRegex(OMEWikiConstants.URLREGEX, AttributeSetFactory.createURLAttributeSet()); } /** * Adds a new regular expression. * * @param regex The regular expression to use. * @param styleSet The style associated to the regular expression. */ public void addRegex(String regex, SimpleAttributeSet styleSet) { if (regex == null || styleSet == null) return; if (regex.trim().length() == 0) return; regexStrings.add(regex); regexFormatter.addRegex(regex, styleSet); } /** * Overrides the {@link #setText(String)} method of {@link JEditorPane} in * order to preserve the current location of the caret position. * After delegating to the superclass {@link #setText(String)} method, the * caret position is reset. * Setting caret has no effect if this panel does not have focus, BUT * setText() is often called by editing and clicking within the editor. * * @see JEditorPane#setText(String) */ public void setText(String text) { int caret = getCaretPosition(); super.setText(text); try { setCaretPosition(caret); } catch (IllegalArgumentException ex) { setCaretPosition(0); // if there is no text, this must be 0 } } /** * Implemented as specified by the {@link DocumentListener} interface. * Causes the edited document to be parsed for regular expression matches. */ public void insertUpdate(DocumentEvent e) { parseRegex(e.getOffset()); } /** * Implemented as specified by the {@link DocumentListener} interface. * Causes the edited document to be parsed for regular expression matches. */ public void removeUpdate(DocumentEvent e) { parseRegex(e.getOffset()); } /** * Implemented as specified by the {@link DocumentListener} interface. * Null implementation, since we don't want to recognize changes in * formatting. Only want to APPLY formatting changes when the document is * edited. */ public void changedUpdate(DocumentEvent e) {} }