| /******************************************************************************* |
| * Copyright (c) 2006 The Pampered Chef and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * The Pampered Chef - initial API and implementation |
| ******************************************************************************/ |
| |
| package org.eclipse.jface.examples.databinding.mask.internal; |
| |
| import java.util.ArrayList; |
| |
| import org.eclipse.jface.examples.databinding.mask.EditMaskParseException; |
| |
| /** |
| * Lexical analyzer and token for an input mask. Since input masks have exactly |
| * one token type, we use the same class to be the recognizer and the token |
| * itself. |
| * |
| * @since 3.3 |
| */ |
| public class EditMaskLexerAndToken { |
| |
| /* |
| * First the literals that represent the types of characters |
| */ |
| private static ArrayList reservedWords = new ArrayList();{ |
| reservedWords.add("#"); |
| reservedWords.add("A"); |
| reservedWords.add("a"); |
| reservedWords.add("n"); |
| } |
| |
| /* |
| * ...and their corresponding regular expressions |
| */ |
| private static ArrayList inputRegexes = new ArrayList();{ |
| inputRegexes.add("^[0-9]$"); |
| inputRegexes.add("^[A-Z]$"); |
| inputRegexes.add("^[a-zA-Z]$"); |
| inputRegexes.add("^[0-9a-zA-Z]$"); |
| } |
| |
| private String charRegex = null; // A regex for matching input characters or null |
| private String literal = null; // The literal character if charRegex is null |
| private boolean readOnly; |
| private String input = null; // The user's input |
| |
| private boolean recognizeReservedWord(String inputMask, int position) { |
| String input = inputMask.substring(position, position+1); |
| for (int reservedWord = 0; reservedWord < reservedWords.size(); reservedWord++) { |
| if (input.equals(reservedWords.get(reservedWord))) { |
| charRegex = (String) inputRegexes.get(reservedWord); |
| literal = null; |
| input = null; |
| readOnly = false; |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private boolean recognizeBackslashLiteral(String inputMask, int position) throws EditMaskParseException { |
| String input = inputMask.substring(position, position+1); |
| if (input.equals("\\")) { |
| try { |
| input = inputMask.substring(position+1, position+2); |
| charRegex = null; |
| this.input = input; |
| literal = input; |
| readOnly = true; |
| return true; |
| } catch (Throwable t) { |
| throw new EditMaskParseException("Found a \\ without a character after it: " + inputMask); |
| } |
| } |
| return false; |
| } |
| |
| private boolean recognizeLiteral(String inputMask, int position) { |
| literal = inputMask.substring(position, position+1); |
| this.input = literal; |
| charRegex = null; |
| readOnly = true; |
| return true; |
| } |
| |
| /** |
| * Initializes itself based on characters in edit mask starting at position; |
| * returns number of chars consumed |
| * |
| * @param inputMask The entire edit mask |
| * @param position The position to begin parsing |
| * @return The number of characters consumed |
| * @throws EditMaskParseException If it encountered a syntax error during the parse |
| */ |
| public int initializeEditMask(String inputMask, int position) throws EditMaskParseException { |
| clear(); |
| if (recognizeReservedWord(inputMask, position)) { |
| return 1; |
| } |
| if (recognizeBackslashLiteral(inputMask, position)) { |
| return 2; |
| } |
| if (!recognizeLiteral(inputMask, position)) { |
| throw new EditMaskParseException("Should never see this error in this implementation!"); |
| } |
| readOnly = true; |
| return 1; |
| } |
| |
| /** |
| * ignores invalid input; stores valid input |
| * @param inputCharacter |
| * @return |
| */ |
| public boolean accept(String inputCharacter) { |
| if (readOnly) { |
| return false; |
| } |
| if (literal != null) { |
| return false; |
| } |
| if (!canAcceptMoreCharacters()) { |
| return false; |
| } |
| if (inputCharacter.matches(charRegex)) { |
| this.input = inputCharacter; |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * @return Returns the characters it has accepted. In the current implementation, |
| * this is exactly one character. Once quantifiers are implemented, this could |
| * be many characters. If no characters have been accepted, returns null. |
| */ |
| public String getInput() { |
| return input; |
| } |
| |
| /** |
| * Clear any accepted input |
| */ |
| public void clear() { |
| if (!isReadOnly()) |
| input = null; |
| } |
| |
| /** |
| * @return true if it's a literal; false if it's a placeholder |
| */ |
| public boolean isReadOnly() { |
| return readOnly; |
| } |
| |
| /** |
| * @return true if it is a literal or if it has accepted the minimum |
| * required number of characters |
| */ |
| public boolean isComplete() { |
| if (input != null) { |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * @return A position may be complete and yet able to accept more characters if |
| * the position includes optional characters via a quantifier of some type. |
| * Not implemented right now. |
| */ |
| public boolean canAcceptMoreCharacters() { |
| return !isComplete(); |
| } |
| |
| /** |
| * @return the minimum number of characters this RegexLexer must accept |
| * in order to be complete. Because we don't yet support quantifiers, this |
| * is currently always 1. |
| */ |
| public int getMinimumLength() { |
| return 1; |
| } |
| } |