com.gargoylesoftware.htmlunit.html.DoTypeProcessor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of htmlunit Show documentation
Show all versions of htmlunit Show documentation
A headless browser intended for use in testing web-based applications.
/*
* Copyright (c) 2002-2017 Gargoyle Software Inc.
*
* 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.
*/
package com.gargoylesoftware.htmlunit.html;
import static com.gargoylesoftware.htmlunit.javascript.host.event.KeyboardEvent.DOM_VK_ADD;
import static com.gargoylesoftware.htmlunit.javascript.host.event.KeyboardEvent.DOM_VK_BACK_SPACE;
import static com.gargoylesoftware.htmlunit.javascript.host.event.KeyboardEvent.DOM_VK_DECIMAL;
import static com.gargoylesoftware.htmlunit.javascript.host.event.KeyboardEvent.DOM_VK_DELETE;
import static com.gargoylesoftware.htmlunit.javascript.host.event.KeyboardEvent.DOM_VK_DIVIDE;
import static com.gargoylesoftware.htmlunit.javascript.host.event.KeyboardEvent.DOM_VK_END;
import static com.gargoylesoftware.htmlunit.javascript.host.event.KeyboardEvent.DOM_VK_EQUALS;
import static com.gargoylesoftware.htmlunit.javascript.host.event.KeyboardEvent.DOM_VK_HOME;
import static com.gargoylesoftware.htmlunit.javascript.host.event.KeyboardEvent.DOM_VK_LEFT;
import static com.gargoylesoftware.htmlunit.javascript.host.event.KeyboardEvent.DOM_VK_MULTIPLY;
import static com.gargoylesoftware.htmlunit.javascript.host.event.KeyboardEvent.DOM_VK_NUMPAD0;
import static com.gargoylesoftware.htmlunit.javascript.host.event.KeyboardEvent.DOM_VK_NUMPAD9;
import static com.gargoylesoftware.htmlunit.javascript.host.event.KeyboardEvent.DOM_VK_RIGHT;
import static com.gargoylesoftware.htmlunit.javascript.host.event.KeyboardEvent.DOM_VK_SEMICOLON;
import static com.gargoylesoftware.htmlunit.javascript.host.event.KeyboardEvent.DOM_VK_SEPARATOR;
import static com.gargoylesoftware.htmlunit.javascript.host.event.KeyboardEvent.DOM_VK_SPACE;
import static com.gargoylesoftware.htmlunit.javascript.host.event.KeyboardEvent.DOM_VK_SUBTRACT;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.ClipboardOwner;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import com.gargoylesoftware.htmlunit.html.impl.SelectionDelegate;
/**
* The process for {@link HtmlElement#doType(char, boolean, boolean)}.
*
* @author Marc Guillemot
* @author Ronald Brill
* @author Ahmed Ashour
*/
class DoTypeProcessor implements Serializable, ClipboardOwner {
private static Map SPECIAL_KEYS_MAP_ = new HashMap<>();
/**
* Either {@link HtmlElement} or {@link DomText}.
*/
private DomNode domNode_;
static {
SPECIAL_KEYS_MAP_.put(DOM_VK_ADD, '+');
SPECIAL_KEYS_MAP_.put(DOM_VK_DECIMAL, '.');
SPECIAL_KEYS_MAP_.put(DOM_VK_DIVIDE, '/');
SPECIAL_KEYS_MAP_.put(DOM_VK_EQUALS, '=');
SPECIAL_KEYS_MAP_.put(DOM_VK_MULTIPLY, '*');
SPECIAL_KEYS_MAP_.put(DOM_VK_SEMICOLON, ';');
SPECIAL_KEYS_MAP_.put(DOM_VK_SEPARATOR, ',');
SPECIAL_KEYS_MAP_.put(DOM_VK_SPACE, ' ');
SPECIAL_KEYS_MAP_.put(DOM_VK_SUBTRACT, '-');
for (int i = DOM_VK_NUMPAD0; i <= DOM_VK_NUMPAD9; i++) {
SPECIAL_KEYS_MAP_.put(i, (char) ('0' + (i - DOM_VK_NUMPAD0)));
}
}
DoTypeProcessor(final DomNode domNode) {
domNode_ = domNode;
}
void doType(final String currentValue, final SelectionDelegate selectionDelegate,
final char c, final HtmlElement element, final boolean lastType) {
int selectionStart = selectionDelegate.getSelectionStart();
int selectionEnd = selectionDelegate.getSelectionEnd();
final StringBuilder newValue = new StringBuilder(currentValue);
if (c == '\b') {
if (selectionStart > 0) {
newValue.deleteCharAt(selectionStart - 1);
selectionStart--;
selectionEnd--;
}
}
else if (acceptChar(c)) {
final boolean ctrlKey = element.isCtrlPressed();
if (ctrlKey && (c == 'C' || c == 'c')) {
final String content = newValue.substring(selectionStart, selectionEnd);
setClipboardContent(content);
}
else if (ctrlKey && (c == 'V' || c == 'v')) {
final String content = getClipboardContent();
add(newValue, content, selectionStart, selectionEnd);
selectionStart += content.length();
selectionEnd = selectionStart;
}
else if (ctrlKey && (c == 'X' || c == 'x')) {
final String content = newValue.substring(selectionStart, selectionEnd);
setClipboardContent(content);
newValue.delete(selectionStart, selectionEnd);
selectionEnd = selectionStart;
}
else if (ctrlKey && (c == 'A' || c == 'a')) {
selectionStart = 0;
selectionEnd = newValue.length();
}
else {
add(newValue, c, selectionStart, selectionEnd);
selectionStart++;
selectionEnd = selectionStart;
}
}
typeDone(newValue.toString(), lastType);
selectionDelegate.setSelectionStart(selectionStart);
selectionDelegate.setSelectionEnd(selectionEnd);
}
private static void add(final StringBuilder newValue, final char c, final int selectionStart,
final int selectionEnd) {
if (selectionStart != newValue.length()) {
newValue.replace(selectionStart, selectionEnd, Character.toString(c));
}
else {
newValue.append(c);
}
}
private static void add(final StringBuilder newValue, final String string, final int selectionStart,
final int selectionEnd) {
if (selectionStart != newValue.length()) {
newValue.replace(selectionStart, selectionEnd, string);
}
else {
newValue.append(string);
}
}
private static String getClipboardContent() {
String result = "";
final Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
final Transferable contents = clipboard.getContents(null);
if (contents != null && contents.isDataFlavorSupported(DataFlavor.stringFlavor)) {
try {
result = (String) contents.getTransferData(DataFlavor.stringFlavor);
}
catch (final UnsupportedFlavorException | IOException ex) {
}
}
return result;
}
private void setClipboardContent(final String string) {
final Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
final StringSelection stringSelection = new StringSelection(string);
clipboard.setContents(stringSelection, this);
}
private void typeDone(final String newValue, final boolean notifyAttributeChangeListeners) {
if (domNode_ instanceof DomText) {
((DomText) domNode_).setData(newValue);
}
else {
((HtmlElement) domNode_).typeDone(newValue, notifyAttributeChangeListeners);
}
}
private boolean acceptChar(final char ch) {
if (domNode_ instanceof DomText) {
return ((DomText) domNode_).acceptChar(ch);
}
return ((HtmlElement) domNode_).acceptChar(ch);
}
void doType(final String currentValue, final SelectionDelegate selectionDelegate,
final int keyCode, final HtmlElement element, final boolean lastType) {
final StringBuilder newValue = new StringBuilder(currentValue);
int selectionStart = selectionDelegate.getSelectionStart();
int selectionEnd = selectionDelegate.getSelectionEnd();
final Character ch = SPECIAL_KEYS_MAP_.get(keyCode);
if (ch != null) {
doType(currentValue, selectionDelegate, ch, element, lastType);
return;
}
switch (keyCode) {
case DOM_VK_BACK_SPACE:
if (selectionStart > 0) {
newValue.deleteCharAt(selectionStart - 1);
selectionStart--;
}
break;
case DOM_VK_LEFT:
if (element.isCtrlPressed()) {
while (selectionStart > 0 && newValue.charAt(selectionStart - 1) != ' ') {
selectionStart--;
}
}
else if (selectionStart > 0) {
selectionStart--;
}
break;
case DOM_VK_RIGHT:
if (element.isCtrlPressed()) {
if (selectionStart < newValue.length()) {
selectionStart++;
}
while (selectionStart < newValue.length() && newValue.charAt(selectionStart - 1) != ' ') {
selectionStart++;
}
}
else if (element.isShiftPressed()) {
selectionEnd++;
}
else if (selectionStart > 0) {
selectionStart++;
}
break;
case DOM_VK_HOME:
selectionStart = 0;
break;
case DOM_VK_END:
if (element.isShiftPressed()) {
selectionEnd = newValue.length();
}
else {
selectionStart = newValue.length();
}
break;
case DOM_VK_DELETE:
if (selectionEnd == selectionStart) {
selectionEnd++;
}
newValue.delete(selectionStart, selectionEnd);
selectionEnd = selectionStart;
break;
default:
return;
}
if (!element.isShiftPressed()) {
selectionEnd = selectionStart;
}
typeDone(newValue.toString(), lastType);
selectionDelegate.setSelectionStart(selectionStart);
selectionDelegate.setSelectionEnd(selectionEnd);
}
/**
* {@inheritDoc}
*/
@Override
public void lostOwnership(final Clipboard clipboard, final Transferable contents) {
}
}