/** * * @param codeArea * @param suggestionProvider * @param replaceTextProvider * When a suggestion entered, which range of text should be replaced. */ public AutoCompletionCodeAreaBind(CodeArea codeArea, BiFunction<String, Integer, Collection<String>> suggestionProvider, BiFunction<String, Integer, IndexRange> replaceTextProvider) { this.codeArea = codeArea; this.suggestionProvider = suggestionProvider; this.replaceTextProvider = replaceTextProvider; this.popup = new AutoCompletePopup<>(); codeArea.textProperty().addListener(textChangeListener); codeArea.focusedProperty().addListener(focusChangedListener); codeArea.setPopupWindow(popup); codeArea.setPopupAlignment(PopupAlignment.CARET_BOTTOM); popup.setOnSuggestion(sce -> { completeUserInput(sce.getSuggestion()); hidePopup(); }); }
/** * Add Event Listener handler for the TextArea: * 1. detect double click on <> and obtain (RIC) text inside of <> * 2. subscribe to RIC */ @FXML private void clickedTextArea(MouseEvent event) { if (event.getClickCount() == 2) { // Get the range of the selected text IndexRange range = textArea.getSelection(); if ( findRegion(range, '<', '>') ) { // Check if region is embedded within < > brackets String ric = textArea.getSelectedText().trim(); if (m_debug) System.out.println("Selected text: [" + ric + "]"); m_consumer.subscribe(ric); } else { if ( findRegion(range, '[', ']') ) { // Check if region is embedded within [ ] brackets String news = textArea.getSelectedText().trim(); if (m_debug) System.out.println("Selected text: [" + news + "]"); updateStatus("Only text within < > supported.", StatusIndicator.RESPONSE_ERROR); } } // Unmark region textArea.selectRange(0,0); } }
private EventHandler<MouseEvent> makeOnButtonDownListener(){ return new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent event) { if(event.getButton() == MouseButton.PRIMARY){ HitInfo i = DnDTextInput.getHitInfo((TextInputControl) event.getSource(), event); IndexRange r = textInput.getSelection(); if(DnDTextInput.isInRange(i.getInsertionIndex(), r)){ currentSelection = r; } inClick = true; } } }; }
@Override public void handle(MouseEvent event) { if (event.getClickCount() == 1) { // codeArea.setStyleSpans(0, // groupBackgroundColor(codeArea.getText(), // codeArea.getCaretPosition())); } else if (event.getClickCount() == 2) { String selectedText = codeArea.getSelectedText(); if (ValueUtil.isNotEmpty(selectedText)) { IndexRange selection = codeArea.getSelection(); String ltrimText = selectedText.replaceAll("^\\s+", ""); String firstStr = ltrimText.substring(0, 1).replaceAll(CHARACTERS_MATCH, ""); int start = selection.getStart(); int end = selection.getEnd(); codeArea.selectRange(start + (selectedText.length() - ltrimText.length() + 1 - firstStr.length()), end); } } }
@Override public boolean deleteNextChar() { boolean success = false; // If there's a selection, delete it: final IndexRange selection = getSelection(); if (selection.getLength() > 0) { int selectionEnd = selection.getEnd(); this.deleteText(selection); this.positionCaret(selectionEnd); success = true; } else { // If the caret preceeds a digit, replace that digit with a zero and move the caret forward. Else just move the caret forward. int caret = this.getCaretPosition(); if (caret % 3 != 2) { // not preceeding a colon String currentText = this.getText(); setText(currentText.substring(0, caret) + "0" + currentText.substring(caret + 1)); success = true; } this.positionCaret(Math.min(caret + 1, this.getText().length())); } return success; }
@Override public boolean deletePreviousChar() { boolean success = false; // If there's a selection, delete it: final IndexRange selection = getSelection(); if (selection.getLength() > 0) { int selectionStart = selection.getStart(); this.deleteText(selection); this.positionCaret(selectionStart); success = true; } else { // If the caret is after a digit, replace that digit with a zero and move the caret backward. Else just move the caret back. int caret = this.getCaretPosition(); if (caret % 3 != 0) { // not following a colon String currentText = this.getText(); setText(currentText.substring(0, caret - 1) + "0" + currentText.substring(caret)); success = true; } this.positionCaret(Math.max(caret - 1, 0)); } return success; }
public MarkdownPreviewPane() { pane.getStyleClass().add("preview-pane"); previewContext = new PreviewContext() { @Override public Renderer getRenderer() { return activeRenderer; } @Override public String getMarkdownText() { return markdownText.get(); } @Override public Node getMarkdownAST() { return markdownAST.get(); } @Override public Path getPath() { return path.get(); } @Override public IndexRange getEditorSelection() { return editorSelection.get(); } }; path.addListener((observable, oldValue, newValue) -> update() ); markdownText.addListener((observable, oldValue, newValue) -> update() ); markdownAST.addListener((observable, oldValue, newValue) -> update() ); scrollY.addListener((observable, oldValue, newValue) -> scrollY()); editorSelection.addListener((observable, oldValue, newValue) -> editorSelectionChanged()); }
void replaceText(String text, StyleSpans<? extends Collection<String>> styleSpans) { // remember old selection range and scrollY IndexRange oldSelection = getSelection(); double oldScrollY = getEstimatedScrollY(); // replace text and styles doReplaceText(text); if (styleSpans != null) setStyleSpans(0, styleSpans); // restore old selection range and scrollY int newLength = getLength(); selectRange(Math.min(oldSelection.getStart(), newLength), Math.min(oldSelection.getEnd(), newLength)); Platform.runLater(() -> { estimatedScrollYProperty().setValue(oldScrollY); }); }
public void setMarkdown(String markdown) { // remember old selection range and scrollY IndexRange oldSelection = textArea.getSelection(); double oldScrollY = textArea.getEstimatedScrollY(); // replace text lineSeparator = determineLineSeparator(markdown); textArea.replaceText(markdown); // restore old selection range and scrollY int newLength = textArea.getLength(); textArea.selectRange(Math.min(oldSelection.getStart(), newLength), Math.min(oldSelection.getEnd(), newLength)); Platform.runLater(() -> { textArea.estimatedScrollYProperty().setValue(oldScrollY); }); }
private void moveLinesUp(KeyEvent e) { IndexRange selRange = getSelectedLinesRange(true); int selStart = selRange.getStart(); int selEnd = selRange.getEnd(); if (selStart == 0) return; int before = offsetToLine(selStart - 1); IndexRange beforeRange = linesToRange(before, before, true); int beforeStart = beforeRange.getStart(); int beforeEnd = beforeRange.getEnd(); String beforeText = textArea.getText(beforeStart, beforeEnd); String selText = textArea.getText(selStart, selEnd); if (!selText.endsWith("\n")) { selText += "\n"; if (beforeText.endsWith("\n")) beforeText = beforeText.substring(0, beforeText.length() - 1); } // Note: using single textArea.replaceText() to avoid multiple changes in undo history replaceText(textArea, beforeStart, selEnd, selText + beforeText); selectRange(textArea, beforeStart, beforeStart + selText.length() - 1); }
private void duplicateLines(boolean up) { IndexRange selRange = getSelectedLinesRange(true); int selStart = selRange.getStart(); int selEnd = selRange.getEnd(); String selText = textArea.getText(selStart, selEnd); if (!selText.endsWith("\n")) selText += "\n"; replaceText(textArea, selStart, selStart, selText); if (up) selectRange(textArea, selStart, selStart + selText.length() - 1); else { int newSelStart = selStart + selText.length(); int newSelEnd = newSelStart + selText.length(); if (selText.endsWith("\n")) newSelEnd--; selectRange(textArea, newSelStart, newSelEnd); } }
/** * Calculates the range of a value (background color, underline, etc.) that is shared between multiple * consecutive {@link TextExt} nodes */ private void updateSharedShapeRange(T value, int start, int end) { Runnable addNewValueRange = () -> ranges.add(Tuples.t(value, new IndexRange(start, end))); if (ranges.isEmpty()) { addNewValueRange.run();; } else { int lastIndex = ranges.size() - 1; Tuple2<T, IndexRange> lastShapeValueRange = ranges.get(lastIndex); T lastShapeValue = lastShapeValueRange._1; // calculate smallest possible position which is consecutive to the given start position final int prevEndNext = lastShapeValueRange.get2().getEnd() + 1; if (start <= prevEndNext && // Consecutive? lastShapeValue.equals(value)) { // Same style? IndexRange lastRange = lastShapeValueRange._2; IndexRange extendedRange = new IndexRange(lastRange.getStart(), end); ranges.set(lastIndex, Tuples.t(lastShapeValue, extendedRange)); } else { addNewValueRange.run(); } } }
@Override public IndexRange getParagraphSelection(Selection selection, int paragraph) { int startPar = selection.getStartParagraphIndex(); int endPar = selection.getEndParagraphIndex(); if(paragraph < startPar || paragraph > endPar) { return EMPTY_RANGE; } int start = paragraph == startPar ? selection.getStartColumnPosition() : 0; int end = paragraph == endPar ? selection.getEndColumnPosition() : getParagraphLength(paragraph) + 1; // force rangeProperty() to be valid selection.getRange(); return new IndexRange(start, end); }
final Optional<Bounds> getSelectionBoundsOnScreen(Selection selection) { if (selection.getLength() == 0) { return Optional.empty(); } List<Bounds> bounds = new ArrayList<>(selection.getParagraphSpan()); for (int i = selection.getStartParagraphIndex(); i <= selection.getEndParagraphIndex(); i++) { final int i0 = i; virtualFlow.getCellIfVisible(i).ifPresent(c -> { IndexRange rangeWithinPar = getParagraphSelection(selection, i0); Bounds b = c.getNode().getRangeBoundsOnScreen(rangeWithinPar); bounds.add(b); }); } if(bounds.size() == 0) { return Optional.empty(); } double minX = bounds.stream().mapToDouble(Bounds::getMinX).min().getAsDouble(); double maxX = bounds.stream().mapToDouble(Bounds::getMaxX).max().getAsDouble(); double minY = bounds.stream().mapToDouble(Bounds::getMinY).min().getAsDouble(); double maxY = bounds.stream().mapToDouble(Bounds::getMaxY).max().getAsDouble(); return Optional.of(new BoundingBox(minX, minY, maxX-minX, maxY-minY)); }
@Override public void moveTo(int pos, NavigationActions.SelectionPolicy selectionPolicy) { switch(selectionPolicy) { case CLEAR: selectRangeExpl(pos, pos); break; case ADJUST: selectRangeExpl(getAnchorPosition(), pos); break; case EXTEND: IndexRange sel = getRange(); int anchor; if (pos <= sel.getStart()) { anchor = sel.getEnd(); } else if(pos >= sel.getEnd()) { anchor = sel.getStart(); } else { anchor = getAnchorPosition(); } selectRangeExpl(anchor, pos); break; } }
private void moveBoundary(Direction direction, int amount, int oldBoundaryPosition, Function<Integer, IndexRange> updatedRange) { switch (direction) { case LEFT: moveBoundary( () -> oldBoundaryPosition - amount, (pos) -> 0 <= pos, updatedRange ); break; default: case RIGHT: moveBoundary( () -> oldBoundaryPosition + amount, (pos) -> pos <= area.getLength(), updatedRange ); } }
/** * Moves the caret to the position indicated by {@code pos}. * Based on the selection policy, the selection is either <em>cleared</em> * (i.e. anchor is set to the same position as caret), <em>adjusted</em> * (i.e. anchor is not moved at all), or <em>extended</em> * (i.e. {@code pos} becomes the new caret and, if {@code pos} points * outside the current selection, the far end of the current selection * becomes the anchor. */ default void moveTo(int pos, NavigationActions.SelectionPolicy selectionPolicy) { switch(selectionPolicy) { case CLEAR: selectRange(pos, pos); break; case ADJUST: selectRange(getAnchorPosition(), pos); break; case EXTEND: IndexRange sel = getRange(); int anchor; if(pos <= sel.getStart()) anchor = sel.getEnd(); else if(pos >= sel.getEnd()) anchor = sel.getStart(); else anchor = getAnchorPosition(); selectRangeExpl(anchor, pos); break; } }
/** * Transfers the currently selected text to the clipboard, * leaving the current selection. */ default void copy() { IndexRange selection = getSelection(); if(selection.getLength() > 0) { ClipboardContent content = new ClipboardContent(); content.putString(getSelectedText()); getStyleCodecs().ifPresent(codecs -> { Codec<StyledDocument<PS, SEG, S>> codec = ReadOnlyStyledDocument.codec(codecs._1, codecs._2, getSegOps()); DataFormat format = dataFormat(codec.getName()); StyledDocument<PS, SEG, S> doc = subDocument(selection.getStart(), selection.getEnd()); ByteArrayOutputStream os = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(os); try { codec.encode(dos, doc); content.put(format, os.toByteArray()); } catch (IOException e) { System.err.println("Codec error: Exception in encoding '" + codec.getName() + "':"); e.printStackTrace(); } }); Clipboard.getSystemClipboard().setContent(content); } }
/** * If something is currently selected and the given position is outside of the selection, moves the selected * rich-text document to the given position by deleting it from the area and re-inserting it at the given position. * If nothing is selected, moves the caret ot that position. */ default void moveSelectedText(int position) { IndexRange sel = getSelection(); if((position >= sel.getStart() && position <= sel.getEnd()) || sel.equals(GenericStyledArea.EMPTY_RANGE)) { // no move, just position the caret selectRange(position, position); } else { StyledDocument<PS, SEG, S> text = this.subDocument(sel.getStart(), sel.getEnd()); if(position > sel.getEnd()) position -= sel.getLength(); deleteText(sel); insert(position, text); // select moved text selectRange(position, position + text.length()); } }
private void handleFirstPrimaryPress(MouseEvent e) { // ensure focus view.requestFocus(); CharacterHit hit = view.hit(e.getX(), e.getY()); view.clearTargetCaretOffset(); IndexRange selection = view.getSelection(); if(view.isEditable() && selection.getLength() != 0 && hit.getCharacterIndex().isPresent() && hit.getCharacterIndex().getAsInt() >= selection.getStart() && hit.getCharacterIndex().getAsInt() < selection.getEnd()) { // press inside selection dragSelection = DragState.POTENTIAL_DRAG; dragNewSelection = DragState.NO_DRAG; } else { dragSelection = DragState.NO_DRAG; dragNewSelection = DragState.NO_DRAG; view.getOnOutsideSelectionMousePressed().handle(e); } }
@Test public void test() { LiveList<Integer> list = new LiveArrayList<>(1, 2, 4); Var<IndexRange> range = Var.newSimpleVar(new IndexRange(0, 0)); Val<Integer> rangeSum = list.reduceRange(range, (a, b) -> a + b); assertNull(rangeSum.getValue()); List<Integer> observed = new ArrayList<>(); rangeSum.values().subscribe(sum -> { observed.add(sum); if(sum == null) { range.setValue(new IndexRange(0, 2)); } else if(sum == 3) { list.addAll(1, Arrays.asList(8, 16)); } else if(sum == 9) { range.setValue(new IndexRange(2, 4)); } }); assertEquals(Arrays.asList(null, 3, 9, 18), observed); }
/** * Tests the case when both list and range have been modified and range * change notification arrived first. */ @Test public void testLateListNotifications() { SuspendableList<Integer> list = new LiveArrayList<Integer>(1, 2, 3).suspendable(); SuspendableVar<IndexRange> range = Var.newSimpleVar(new IndexRange(0, 3)).suspendable(); Val<Integer> rangeSum = list.reduceRange(range, (a, b) -> a + b); list.suspendWhile(() -> { range.suspendWhile(() -> { list.addAll(4, 5, 6); range.setValue(new IndexRange(3, 6)); }); }); assertEquals(15, rangeSum.getValue().intValue()); // most importantly, this test tests that no IndexOutOfBoundsException is thrown }
private boolean findRegion(IndexRange startingRange, int openToken, int closeToken) { if ( findStartPoint(startingRange, openToken, closeToken) ) { int start = textArea.getSelection().getStart(); if ( findEndPoint(startingRange, openToken, closeToken) ) { textArea.selectRange(start, textArea.getSelection().getEnd()); return(true); } } // Selected text not embedded with open/close tokens return(false); }
private boolean findStartPoint(IndexRange range, int openToken, int closeToken) { int start = range.getStart(); int end = range.getEnd(); while (true) { textArea.selectRange(start-10, end); IndexRange selection = textArea.getSelection(); // Determine if we've reached the start of the text area if ( selection.getStart() == start ) return(false); // Extract the text region of interest String region = textArea.getSelectedText(); // Determine if we've encountered a close token int cpos = region.lastIndexOf(closeToken); // Determine if we've encountered an Open token int opos = region.lastIndexOf(openToken); if (cpos > opos || opos >= 0) { textArea.selectRange(selection.getStart()+opos+1, end); return(true); } // We should not be on the previous line if ( region.indexOf('\n') >= 0 ) return(false); start = selection.getStart(); } }
private boolean findEndPoint(IndexRange range, int openToken, int closeToken) { int start = range.getStart(); int end = range.getEnd(); while (true) { textArea.selectRange(start, end+10); IndexRange selection = textArea.getSelection(); // Determine if we've reached the end of the text area if ( selection.getEnd() == end ) return(false); // Extract the text region of interest String region = textArea.getSelectedText(); // Determine if we've encountered a close token int cpos = region.indexOf(closeToken); // Determine if we've encountered an Open token int opos = region.indexOf(openToken); if (opos >= 0) { if ( cpos < 0 || opos < cpos ) return(false); } if (cpos >= 0) { textArea.selectRange(range.getStart(), start+cpos); return(true); } // We should not be on the previous line if ( region.indexOf('\n') >= 0 ) return(false); end = selection.getEnd(); } }
static void onSelectedPosition(TextInputControl textinput, Dragboard dragboard) { IndexRange selection = textinput.getSelection(); String t1 = textinput.getText().substring(0, selection.getStart()); String t2 = textinput.getText().substring(selection.getEnd(), textinput.getText().length()); textinput.setText(t1 + dragboard.getString() + t2); }
private static Collection<String> getSuggestionSimply(String text, int caretPos, CSSContext context) { String prePart = text.substring(0, caretPos); IndexRange replaceRange = getReplaceRange(text, caretPos); char c; int index = replaceRange.getStart(); while (true) { index--; c = text.charAt(index); if (c != ' ' && c != '\t') { break; } } String keyWord = text.substring(replaceRange.getStart(), caretPos); boolean inBrace = prePart.lastIndexOf('{') > prePart.lastIndexOf('}'); if (inBrace) { if (c == ':') { // XXX Can be smarter? // return filterSuggestion(CSSRepository.GLOBAL.getKeys(), keyWord); return Collections.emptyList(); } else if (c == ' ' || c == '\t' || c == '\n' | c == '{') { return filterSuggestion(context.getKeys(), keyWord); } else { return Collections.emptyList(); } } else { if (c == '.') { return filterSuggestion(context.getClasses(), keyWord); } else if (c == '#') { return filterSuggestion(context.getIds(), keyWord); } else if (c == ':') { return filterSuggestion(context.getStates(), keyWord); } else { return filterSuggestion(context.getJavaClasses(), keyWord); } } }
private static IndexRange getReplaceRangeSimply(String text, int caretPos) { int start = caretPos - 1; int end = caretPos; while (start > -1 && CSSConstants.LEGAL_CHARS.contains(text.charAt(start))) { start--; } while (end < text.length() && CSSConstants.LEGAL_CHARS.contains(text.charAt(end))) { end++; } return new IndexRange(start + 1, end); }
public void comment() { selectLines(codeArea); String selectedText = codeArea.getSelectedText(); IndexRange selection = codeArea.getSelection(); codeArea.getUndoManager().preventMerge(); codeArea.replaceSelection(CSSFormat.toggleComment(selectedText)); codeArea.getUndoManager().preventMerge(); codeArea.moveTo(selection.getStart(), SelectionPolicy.EXTEND); }
private static void selectLines(CodeArea area) { IndexRange origin = area.getSelection(); area.moveTo(origin.getStart()); area.lineStart(SelectionPolicy.CLEAR); int start = area.getCaretPosition(); area.moveTo(origin.getEnd()); area.lineEnd(SelectionPolicy.CLEAR); int end = area.getCaretPosition(); area.selectRange(start, end); }
@Override public void replaceSelection(String text) { IndexRange range = getSelection(); if (replaceValid(range.getStart(), range.getEnd(), text)) { super.replaceSelection(text); } }
protected static void unselect(final TextInputControlWrapInterface text_input) { new GetAction() { @Override public void run(Object... parameters) { IndexRange selection = text_input.getControl().getSelection(); text_input.getControl().selectRange(selection.getStart(), selection.getStart()); } }.dispatch(getEnvironment(text_input)); }
@Override public void replaceSelection(String replacement) { final IndexRange selection = this.getSelection(); if (selection.getLength() == 0) { this.insertText(selection.getStart(), replacement); } else { this.replaceText(selection.getStart(), selection.getEnd(), replacement); } }
/** * Handle the press of the tab key, with/without shift. * This either inserts getTabString() at the current caret position (if no text is selected, * or either indents or removes the indentation from all selected rows if a selection is made. * * @param component * @param shiftDown */ void handleTabPress(final ScriptEditorControl textArea, final boolean shiftDown) { String selected = textArea.getSelectedText(); int pos = textArea.getCaretPosition(); if (selected == null || selected.length() == 0) { textArea.insertText(pos, tabString); return; } String text = textArea.getText(); IndexRange range = textArea.getSelection(); int startRowPos = getRowStartPosition(text, range.getStart()); int endRowPos = getRowEndPosition(text, range.getEnd()); String textBetween = text.substring(startRowPos, endRowPos); String replaceText; if (shiftDown) { // Remove tabs at start of selected rows replaceText = textBetween.replace("\n"+tabString, "\n"); if (replaceText.startsWith(tabString)) replaceText = replaceText.substring(tabString.length()); } else { replaceText = tabString + textBetween.replace("\n", "\n"+tabString); } // System.out.println("LENGTH: " + textArea.getText().length() + ", POSITION: " + endRowPos); String newText = text.substring(0, startRowPos) + replaceText; if (endRowPos < text.length()) { newText = newText + text.substring(endRowPos); textArea.setText(newText); } else { // For reasons that aren't clear to me, I need to clear the text first to make this work (for now) // TODO: Check if this bug still applies textArea.deselect(); textArea.setText(newText); } // textArea.replaceText(startRowPos, endRowPos, replaceText); textArea.selectRange(startRowPos, startRowPos+replaceText.length()); }
@Override public void editorSelectionChanged(PreviewContext context, IndexRange range) { if (range.equals(lastEditorSelection)) return; lastEditorSelection = range; runWhenLoaded(() -> { webView.getEngine().executeScript(highlightNodesAt(range)); }); }