Author: rwhitcomb Date: Thu Feb 14 17:55:00 2013 New Revision: 1446283 URL: http://svn.apache.org/r1446283 Log: Part of PIVOT-891: Implement double-click to select a word and triple-click to select the whole line.
Fix the Shift-LEFT and Shift-RIGHT to work "properly" in that case of first moving in one direction and then reversing direction -- this should reduce the selection that was just done instead of always expanding it. The same (or similar) changes for UP/DOWN are more difficult and are eluding me at the moment. Also implement Ctrl-HOME moves to the beginning of the document and Ctrl-END to the end of the document (and with Shift selects from cursor to the beginning/end). Modified: pivot/branches/2.0.x/wtk/src/org/apache/pivot/wtk/skin/TextAreaSkin.java Modified: pivot/branches/2.0.x/wtk/src/org/apache/pivot/wtk/skin/TextAreaSkin.java URL: http://svn.apache.org/viewvc/pivot/branches/2.0.x/wtk/src/org/apache/pivot/wtk/skin/TextAreaSkin.java?rev=1446283&r1=1446282&r2=1446283&view=diff ============================================================================== --- pivot/branches/2.0.x/wtk/src/org/apache/pivot/wtk/skin/TextAreaSkin.java (original) +++ pivot/branches/2.0.x/wtk/src/org/apache/pivot/wtk/skin/TextAreaSkin.java Thu Feb 14 17:55:00 2013 @@ -34,6 +34,7 @@ import org.apache.pivot.collections.Sequ import org.apache.pivot.wtk.ApplicationContext; import org.apache.pivot.wtk.Bounds; import org.apache.pivot.wtk.Component; +import org.apache.pivot.wtk.Cursor; import org.apache.pivot.wtk.Dimensions; import org.apache.pivot.wtk.GraphicsUtilities; import org.apache.pivot.wtk.Insets; @@ -166,6 +167,8 @@ public class TextAreaSkin extends Compon textArea.getTextAreaListeners().add(this); textArea.getTextAreaContentListeners().add(this); textArea.getTextAreaSelectionListeners().add(this); + + textArea.setCursor(Cursor.TEXT); } @Override @@ -944,13 +947,80 @@ public class TextAreaSkin extends Compon Mouse.release(); } - anchor = -1; scrollDirection = null; mouseX = -1; return consumed; } + private void selectSpan(TextArea textArea, int start) { + int rowStart = textArea.getRowOffset(start); + int rowLength = textArea.getRowLength(start); + if (start - rowStart >= rowLength) { + start = rowStart + rowLength - 1; + char ch = textArea.getCharacterAt(start); + if (ch == '\r' || ch == '\n') { + start--; + } + } + char ch = textArea.getCharacterAt(start); + int selectionStart = start; + int selectionLength = 1; + if (Character.isWhitespace(ch)) { + // Move backward to beginning of whitespace block + // but not before the beginning of the line. + do { + selectionStart--; + } while (selectionStart >= rowStart && + Character.isWhitespace(textArea.getCharacterAt(selectionStart))); + selectionStart++; + selectionLength = start - selectionStart; + // Move forward to end of whitespace block + // but not past the end of the text or the end of line + do { + selectionLength++; + } while (selectionStart + selectionLength - rowStart < rowLength && + Character.isWhitespace(textArea.getCharacterAt(selectionStart + selectionLength))); + } else if (Character.isJavaIdentifierPart(ch)) { + // Move backward to beginning of identifier block + do { + selectionStart--; + } while (selectionStart >= rowStart && + Character.isJavaIdentifierPart(textArea.getCharacterAt(selectionStart))); + selectionStart++; + selectionLength = start - selectionStart; + // Move forward to end of identifier block + // but not past end of text + do { + selectionLength++; + } while (selectionStart + selectionLength - rowStart < rowLength && + Character.isJavaIdentifierPart(textArea.getCharacterAt(selectionStart + selectionLength))); + } else { + return; + } + textArea.setSelection(selectionStart, selectionLength); + } + + @Override + public boolean mouseClick(Component component, Mouse.Button button, + int x, int y, int count) { + boolean consumed = super.mouseClick(component, button, x, y, count); + + TextArea textArea = (TextArea)component; + + if (button == Mouse.Button.LEFT) { + int index = getInsertionPoint(x, y); + if (index != -1) { + if (count == 2) { + selectSpan(textArea, index); + } else if (count == 3) { + textArea.setSelection(textArea.getRowOffset(index), textArea.getRowLength(index)); + } + } + } + return consumed; + } + @Override public boolean keyTyped(Component component, char character) { boolean consumed = super.keyTyped(component, character); @@ -988,12 +1058,15 @@ public class TextAreaSkin extends Compon if (paragraphViews.getLength() > 0) { TextArea textArea = (TextArea)getComponent(); - Keyboard.Modifier commandModifier = Platform.getCommandModifier(); - Keyboard.Modifier wordNavigationModifier = Platform.getWordNavigationModifier(); + boolean commandPressed = Keyboard.isPressed(Platform.getCommandModifier()); + boolean wordNavPressed = Keyboard.isPressed(Platform.getWordNavigationModifier()); + boolean shiftPressed = Keyboard.isPressed(Keyboard.Modifier.SHIFT); + boolean ctrlPressed = Keyboard.isPressed(Keyboard.Modifier.CTRL); + boolean metaPressed = Keyboard.isPressed(Keyboard.Modifier.META); + boolean isEditable = textArea.isEditable(); if (keyCode == Keyboard.KeyCode.ENTER - && acceptsEnter - && textArea.isEditable() + && acceptsEnter && isEditable && Keyboard.getModifiers() == 0) { int index = textArea.getSelectionStart(); textArea.removeText(index, textArea.getSelectionLength()); @@ -1001,7 +1074,7 @@ public class TextAreaSkin extends Compon consumed = true; } else if (keyCode == Keyboard.KeyCode.DELETE - && textArea.isEditable()) { + && isEditable) { int index = textArea.getSelectionStart(); if (index < textArea.getCharacterCount()) { @@ -1011,7 +1084,7 @@ public class TextAreaSkin extends Compon consumed = true; } } else if (keyCode == Keyboard.KeyCode.BACKSPACE - && textArea.isEditable()) { + && isEditable) { int index = textArea.getSelectionStart(); int count = textArea.getSelectionLength(); @@ -1024,19 +1097,21 @@ public class TextAreaSkin extends Compon consumed = true; } } else if (keyCode == Keyboard.KeyCode.TAB - && (acceptsTab != Keyboard.isPressed(Keyboard.Modifier.CTRL)) - && textArea.isEditable()) { + && (acceptsTab != ctrlPressed) + && isEditable) { + int selectionStart = textArea.getSelectionStart(); int selectionLength = textArea.getSelectionLength(); + int rowOffset = textArea.getRowOffset(selectionStart); + int linePos = selectionStart - rowOffset; StringBuilder tabBuilder = new StringBuilder(tabWidth); - for (int i = 0; i < tabWidth; i++) { + for (int i = 0; i < tabWidth - (linePos % tabWidth); i++) { tabBuilder.append(" "); } if (textArea.getCharacterCount() - selectionLength + tabWidth > textArea.getMaximumLength()) { Toolkit.getDefaultToolkit().beep(); } else { - int selectionStart = textArea.getSelectionStart(); textArea.removeText(selectionStart, selectionLength); textArea.insertText(tabBuilder, selectionStart); } @@ -1045,40 +1120,53 @@ public class TextAreaSkin extends Compon consumed = true; } else if (keyCode == Keyboard.KeyCode.HOME - || (keyCode == Keyboard.KeyCode.LEFT - && Keyboard.isPressed(Keyboard.Modifier.META))) { - // Move the caret to the beginning of the line + || (keyCode == Keyboard.KeyCode.LEFT && metaPressed)) { + int start; int selectionStart = textArea.getSelectionStart(); int selectionLength = textArea.getSelectionLength(); - int rowOffset = getRowOffset(selectionStart); + if (ctrlPressed) { + // Move the caret to the beginning of the text + start = 0; + } else { + // Move the caret to the beginning of the line + start = getRowOffset(selectionStart); + } - if (Keyboard.isPressed(Keyboard.Modifier.SHIFT)) { - selectionLength += selectionStart - rowOffset; + if (shiftPressed) { + selectionLength += selectionStart - start; + } else { + selectionLength = 0; } if (selectionStart >= 0) { - textArea.setSelection(rowOffset, selectionLength); - scrollCharacterToVisible(rowOffset); + textArea.setSelection(start, selectionLength); + scrollCharacterToVisible(start); caretX = caret.x; consumed = true; } } else if (keyCode == Keyboard.KeyCode.END - || (keyCode == Keyboard.KeyCode.RIGHT - && Keyboard.isPressed(Keyboard.Modifier.META))) { - // Move the caret to the end of the line + || (keyCode == Keyboard.KeyCode.RIGHT && metaPressed)) { + int end; int selectionStart = textArea.getSelectionStart(); int selectionLength = textArea.getSelectionLength(); - int index = selectionStart + selectionLength; - int rowOffset = getRowOffset(index); - int rowLength = getRowLength(index); - if (Keyboard.isPressed(Keyboard.Modifier.SHIFT)) { - selectionLength += (rowOffset + rowLength) - index; + if (ctrlPressed) { + // Move the caret to end of the text + end = textArea.getCharacterCount(); + } else { + // Move the caret to the end of the line + int rowOffset = getRowOffset(index); + int rowLength = getRowLength(index); + end = rowOffset + rowLength; + } + + if (shiftPressed) { + selectionLength += end - index; } else { - selectionStart = rowOffset + rowLength; + selectionStart = end; if (selectionStart < textArea.getCharacterCount() && textArea.getCharacterAt(selectionStart) != '\n') { selectionStart--; @@ -1102,7 +1190,7 @@ public class TextAreaSkin extends Compon int selectionStart = textArea.getSelectionStart(); int selectionLength = textArea.getSelectionLength(); - if (Keyboard.isPressed(wordNavigationModifier)) { + if (wordNavPressed) { // Move the caret to the start of the next word to the left if (selectionStart > 0) { // Skip over any space immediately to the left @@ -1118,7 +1206,7 @@ public class TextAreaSkin extends Compon index--; } - if (Keyboard.isPressed(Keyboard.Modifier.SHIFT)) { + if (shiftPressed) { selectionLength += selectionStart - index; } else { selectionLength = 0; @@ -1126,11 +1214,28 @@ public class TextAreaSkin extends Compon selectionStart = index; } - } else if (Keyboard.isPressed(Keyboard.Modifier.SHIFT)) { - // Add the previous character to the selection - if (selectionStart > 0) { - selectionStart--; - selectionLength++; + } else if (shiftPressed) { + if (anchor != -1) { + if (selectionStart < anchor) { + if (selectionStart > 0) { + selectionStart--; + selectionLength++; + } + } else { + if (selectionLength > 0) { + selectionLength--; + } else { + selectionStart--; + selectionLength++; + } + } + } else { + // Add the previous character to the selection + anchor = selectionStart; + if (selectionStart > 0) { + selectionStart--; + selectionLength++; + } } } else { // Move the caret back by one character @@ -1140,6 +1245,7 @@ public class TextAreaSkin extends Compon } // Clear the selection + anchor = -1; selectionLength = 0; } @@ -1155,7 +1261,7 @@ public class TextAreaSkin extends Compon int selectionStart = textArea.getSelectionStart(); int selectionLength = textArea.getSelectionLength(); - if (Keyboard.isPressed(wordNavigationModifier)) { + if (wordNavPressed) { // Move the caret to the start of the next word to the right if (selectionStart < textArea.getCharacterCount()) { int index = selectionStart + selectionLength; @@ -1172,16 +1278,26 @@ public class TextAreaSkin extends Compon index++; } - if (Keyboard.isPressed(Keyboard.Modifier.SHIFT)) { + if (shiftPressed) { selectionLength = index - selectionStart; } else { selectionStart = index; selectionLength = 0; } } - } else if (Keyboard.isPressed(Keyboard.Modifier.SHIFT)) { - // Add the next character to the selection - selectionLength++; + } else if (shiftPressed) { + if (anchor != -1) { + if (selectionStart < anchor) { + selectionStart++; + selectionLength--; + } else { + selectionLength++; + } + } else { + // Add the next character to the selection + anchor = selectionStart; + selectionLength++; + } } else { // Move the caret forward by one character if (selectionLength == 0) { @@ -1191,6 +1307,7 @@ public class TextAreaSkin extends Compon } // Clear the selection + anchor = -1; selectionLength = 0; } @@ -1207,14 +1324,13 @@ public class TextAreaSkin extends Compon } } else if (keyCode == Keyboard.KeyCode.UP) { int selectionStart = textArea.getSelectionStart(); + int selectionLength = textArea.getSelectionLength(); int index = getNextInsertionPoint(caretX, selectionStart, TextArea.ScrollDirection.UP); if (index != -1) { - int selectionLength; - if (Keyboard.isPressed(Keyboard.Modifier.SHIFT)) { - int selectionEnd = selectionStart + textArea.getSelectionLength() - 1; - selectionLength = selectionEnd - index + 1; + if (shiftPressed) { + selectionLength = selectionStart + selectionLength - index; } else { selectionLength = 0; } @@ -1228,7 +1344,7 @@ public class TextAreaSkin extends Compon int selectionStart = textArea.getSelectionStart(); int selectionLength = textArea.getSelectionLength(); - if (Keyboard.isPressed(Keyboard.Modifier.SHIFT)) { + if (shiftPressed) { int from; int x; if (selectionLength == 0) { @@ -1276,32 +1392,33 @@ public class TextAreaSkin extends Compon } consumed = true; - } else if (Keyboard.isPressed(commandModifier)) { + } else if (commandPressed) { if (keyCode == Keyboard.KeyCode.A) { textArea.setSelection(0, textArea.getCharacterCount()); consumed = true; } else if (keyCode == Keyboard.KeyCode.X - && textArea.isEditable()) { + && isEditable) { textArea.cut(); consumed = true; } else if (keyCode == Keyboard.KeyCode.C) { textArea.copy(); consumed = true; } else if (keyCode == Keyboard.KeyCode.V - && textArea.isEditable()) { + && isEditable) { textArea.paste(); consumed = true; } else if (keyCode == Keyboard.KeyCode.Z - && textArea.isEditable()) { - if (!Keyboard.isPressed(Keyboard.Modifier.SHIFT)) { + && isEditable) { + if (!shiftPressed) { textArea.undo(); } - consumed = true; + } else if (keyCode == Keyboard.KeyCode.TAB) { + // Only here if acceptsTab is false + consumed = super.keyPressed(component, keyCode, keyLocation); } } else if (keyCode == Keyboard.KeyCode.INSERT) { - if (Keyboard.isPressed(Keyboard.Modifier.SHIFT) - && textArea.isEditable()) { + if (shiftPressed && isEditable) { textArea.paste(); consumed = true; }