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

org.assertj.swing.keystroke.KeyStrokeMappingsParser Maven / Gradle / Ivy

There is a newer version: 3.17.1
Show newest version
/**
 * Licensed 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.
 *
 * Copyright 2012-2015 the original author or authors.
 */
package org.assertj.swing.keystroke;

import static java.lang.Thread.currentThread;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.util.Closeables.closeQuietly;
import static org.assertj.core.util.Lists.newArrayList;
import static org.assertj.core.util.Preconditions.checkNotNull;
import static org.assertj.core.util.Preconditions.checkNotNullOrEmpty;
import static org.assertj.core.util.Strings.concat;
import static org.assertj.core.util.Strings.quote;
import static org.assertj.swing.keystroke.KeyStrokeMapping.mapping;
import static org.assertj.swing.keystroke.KeyStrokeMappingProvider.NO_MASK;
import static org.assertj.swing.util.Maps.newHashMap;
import static org.fest.reflect.core.Reflection.field;

import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Map;

import javax.annotation.Nonnull;

import org.assertj.core.util.VisibleForTesting;
import org.assertj.swing.exception.ParsingException;
import org.fest.reflect.exception.ReflectionError;

/**
 * 

* Creates {@link KeyStrokeMapping}s by parsing a text file. *

* *

* Mappings for the following characters: *

*
    *
  • Backspace
  • *
  • Delete
  • *
  • Enter
  • *
  • Escape
  • *
  • Tab
  • *
*

* will be automatically added and should not be included to the file to parse. *

* *

* The following is an example of a mapping file: *

* *
 * a, A, NO_MASK
 * A, A, SHIFT_MASK
 * COMMA, COMMA, NO_MASK
 * 
* *

* Each line represents a character-keystroke mapping where each value is separated by a comma. *

* *

* The first value represents the character to map. For example 'a' or 'A'. Since each field is separated by a comma, to * map the ',' character we need to specify the text "COMMA." *

* *

* The second value represents the key code, which should be the name of a key code from {@link KeyEvent} without the * prefix "VK_". For example, if the key code is {@link KeyEvent#VK_COMMA} we just need to specify "COMMA". *

* *

* The third value represents any modifiers to use, which should be the name of a modifier from a {@code InputEvent}. * For example, if the modifier to use is {@code InputEvent.SHIFT_MASK} we need to specify "SHIFT_MASK". If no modifiers * are necessary, we just specify "NO_MASK". *

* * @author Olivier DOREMIEUX * @author Alex Ruiz */ public class KeyStrokeMappingsParser { private static final Map SPECIAL_MAPPINGS = newHashMap(); static { SPECIAL_MAPPINGS.put("COMMA", ','); } /** *

* Creates a {@link KeyStrokeMappingProvider} containing all the character-keystroke mappings specified in the file * with the given name. *

* *

* Note: This attempts to read the file using {@link ClassLoader#getResourceAsStream(String)}. *

* * @param fileName the name of the file to parse. * @return the created {@code KeyStrokeMappingProvider}. * @throws NullPointerException if the given name is {@code null}. * @throws IllegalArgumentException if the given name is empty. * @throws ParsingException if any error occurs during parsing. * @see #parse(File) */ public @Nonnull KeyStrokeMappingProvider parse(@Nonnull String fileName) { checkNotNullOrEmpty(fileName); try { return parse(fileAsStream(fileName)); } catch (IOException e) { throw new ParsingException(concat("An I/O error ocurred while parsing file ", fileName), e); } } private @Nonnull InputStream fileAsStream(String file) { InputStream stream = currentThread().getContextClassLoader().getResourceAsStream(file); if (stream == null) { throw new ParsingException(String.format("Unable to open file %s", file)); } return stream; } /** * Creates a {@link KeyStrokeMappingProvider} containing all the character-keystroke mappings specified in the given * file. * * @param file the file to parse. * @return the created {@code KeyStrokeMappingProvider}. * @throws NullPointerException if the given file is {@code null}. * @throws AssertionError if the given file does not represent an existing file. * @throws ParsingException if any error occurs during parsing. */ public @Nonnull KeyStrokeMappingProvider parse(@Nonnull File file) { assertThat(file).isFile(); try { return parse(fileAsStream(file)); } catch (IOException e) { throw new ParsingException(concat("An I/O error ocurred while parsing file ", file), e); } } private @Nonnull InputStream fileAsStream(@Nonnull File file) { try { return new FileInputStream(file); } catch (FileNotFoundException e) { String msg = String.format("The file %s was not found", file.getPath()); throw new ParsingException(msg, e); } } private @Nonnull KeyStrokeMappingProvider parse(@Nonnull InputStream input) throws IOException { List mappings = newArrayList(); BufferedReader reader = new BufferedReader(new InputStreamReader(input)); try { String line = reader.readLine(); while (line != null) { mappings.add(mappingFrom(line)); line = reader.readLine(); } return new ParsedKeyStrokeMappingProvider(mappings); } finally { closeQuietly(reader); } } @VisibleForTesting @Nonnull KeyStrokeMapping mappingFrom(@Nonnull String line) { String[] parts = line.trim().split(","); if (parts.length != 3) { String msg = String.format("Line '%s' does not conform with pattern '{char}, {keycode}, {modifiers}'", line); throw new ParsingException(msg); } char character = characterFrom(parts[0].trim()); int keyCode = keyCodeFrom(parts[1].trim()); int modifiers = modifiersFrom(parts[2].trim()); return mapping(character, keyCode, modifiers); } private static char characterFrom(@Nonnull String s) { if (SPECIAL_MAPPINGS.containsKey(s)) { return SPECIAL_MAPPINGS.get(s); } if (s.length() == 1) { return s.charAt(0); } throw new ParsingException(String.format("The text '%s' should have a single character", s)); } private static int keyCodeFrom(@Nonnull String s) { try { Integer keyCode = field("VK_" + s).ofType(int.class).in(KeyEvent.class).get(); return checkNotNull(keyCode); } catch (ReflectionError e) { throw new ParsingException(concat("Unable to retrieve key code from text ", quote(s)), e.getCause()); } } private static int modifiersFrom(@Nonnull String s) { if ("NO_MASK".equals(s)) { return NO_MASK; } try { Integer modifiers = field(s).ofType(int.class).in(InputEvent.class).get(); return checkNotNull(modifiers); } catch (ReflectionError e) { throw new ParsingException(concat("Unable to retrieve modifiers from text ", quote(s)), e.getCause()); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy