Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions src/main/java/com/googlecode/lanterna/gui2/TextBox.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@
import com.googlecode.lanterna.input.MouseAction;
import com.googlecode.lanterna.input.MouseActionType;

import com.googlecode.lanterna.gui2.textbox.TextBoxClipboard;
import com.googlecode.lanterna.gui2.textbox.TextBoxSelectionModel;
import com.googlecode.lanterna.gui2.textbox.TextBoxUndoStack;


/**
* This component keeps a text content that is editable by the user. A TextBox can be single line or multiline and lets
* the user navigate the cursor in the text area by using the arrow keys, page up, page down, home and end. For
Expand Down Expand Up @@ -70,6 +75,12 @@ public enum Style {
private Pattern validationPattern;
private TextChangeListener textChangeListener;


private final TextBoxSelectionModel selectionModel = new TextBoxSelectionModel();
private final TextBoxUndoStack undoStack = new TextBoxUndoStack(50);
private final TextBoxClipboard clipboard = new TextBoxClipboard();


/**
* Default constructor, this creates a single-line {@code TextBox} of size 10 which is initially empty
*/
Expand Down Expand Up @@ -1010,4 +1021,60 @@ public interface TextChangeListener {
*/
void onTextChanged(String newText, boolean changedByUserInteraction);
}


// ===== Phase 3 — Delegators to extracted collaborators =====

public void clearSelection() {
selectionModel.clearSelection();
}

public void setSelection(int start, int end) {
selectionModel.setSelection(start, end);
}

public boolean isSelectionActive() {
return selectionModel.isSelectionActive();
}

public int getSelectionStart() {
return selectionModel.getSelectionStart();
}

public int getSelectionEnd() {
return selectionModel.getSelectionEnd();
}

public String getSelectedText() {
return selectionModel.extractSelected(getText());
}

protected void recordUndoState(String previousState) {
undoStack.recordChange(previousState);
}

protected String performUndo() {
return undoStack.popUndo();
}

protected String performRedo() {
return undoStack.popRedo();
}

protected boolean canUndo() {
return undoStack.canUndo();
}

protected boolean canRedo() {
return undoStack.canRedo();
}

protected String readClipboard() {
return clipboard.read();
}

protected boolean writeClipboard(String text) {
return clipboard.write(text);
}

}
25 changes: 2 additions & 23 deletions src/main/java/com/googlecode/lanterna/gui2/table/Table.java
Original file line number Diff line number Diff line change
Expand Up @@ -214,16 +214,7 @@ public int getVisibleRows() {
return visibleRows;
}

/**
* Returns the index of the row that is currently the first row visible. This is always 0 unless scrolling has been
* enabled and either the user or the software (through {@code setViewTopRow(..)}) has scrolled down.
* @return Index of the row that is currently the first row visible
* @deprecated Use the table renderers method instead
*/
@Deprecated
public int getViewTopRow() {
return getRenderer().getViewTopRow();
}


/**
* Returns the index of the first row that is currently visible.
Expand All @@ -242,19 +233,7 @@ public int getLastViewedRowIndex() {
return Math.min(getRenderer().getViewTopRow() + visibleRows -1, tableModel.getRowCount() -1);
}

/**
* Sets the view row offset for the first row to display in the table. Calling this with 0 will make the first row
* in the model be the first visible row in the table.
*
* @param viewTopRow Index of the row that is currently the first row visible
* @return Itself
* @deprecated Use the table renderers method instead
*/
@Deprecated
public synchronized Table<V> setViewTopRow(int viewTopRow) {
getRenderer().setViewTopRow(viewTopRow);
return this;
}


/**
* Returns the index of the column that is currently the first column visible. This is always 0 unless scrolling has
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.googlecode.lanterna.gui2.textbox;

import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;

/**
* Extracted from TextBox (Phase 3 refactor — God Class).
* Encapsulates system-clipboard read/write.
*/
public class TextBoxClipboard {

public String read() {
try {
Transferable contents = Toolkit.getDefaultToolkit()
.getSystemClipboard()
.getContents(null);
if (contents == null || !contents.isDataFlavorSupported(DataFlavor.stringFlavor)) {
return "";
}
return (String) contents.getTransferData(DataFlavor.stringFlavor);
} catch (Exception e) {
return "";
}
}

public boolean write(String text) {
if (text == null) {
return false;
}
try {
Toolkit.getDefaultToolkit()
.getSystemClipboard()
.setContents(new StringSelection(text), null);
return true;
} catch (Exception e) {
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.googlecode.lanterna.gui2.textbox;

/**
* Extracted from TextBox (Phase 3 refactor — God Class).
* Manages text selection state: start, end, and querying the selection.
*/
public class TextBoxSelectionModel {
private int selectionStart = -1;
private int selectionEnd = -1;
private boolean selectionActive = false;

public void clearSelection() {
selectionStart = -1;
selectionEnd = -1;
selectionActive = false;
}

public void setSelection(int start, int end) {
this.selectionStart = Math.min(start, end);
this.selectionEnd = Math.max(start, end);
this.selectionActive = (selectionStart != selectionEnd);
}

public boolean isSelectionActive() {
return selectionActive;
}

public int getSelectionStart() {
return selectionStart;
}

public int getSelectionEnd() {
return selectionEnd;
}

public String extractSelected(String source) {
if (!selectionActive || source == null) {
return "";
}
int start = Math.max(0, Math.min(selectionStart, source.length()));
int end = Math.max(0, Math.min(selectionEnd, source.length()));
if (end <= start) {
return "";
}
return source.substring(start, end);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.googlecode.lanterna.gui2.textbox;

import java.util.ArrayDeque;
import java.util.Deque;

/**
* Extracted from TextBox (Phase 3 refactor — God Class).
* Bounded undo/redo history of text states.
*/
public class TextBoxUndoStack {
private final int limit;
private final Deque<String> undoStack = new ArrayDeque<>();
private final Deque<String> redoStack = new ArrayDeque<>();

public TextBoxUndoStack(int limit) {
this.limit = Math.max(1, limit);
}

public void recordChange(String previousState) {
if (previousState == null) {
return;
}
if (undoStack.size() >= limit) {
undoStack.removeFirst();
}
undoStack.push(previousState);
redoStack.clear();
}

public String popUndo() {
if (undoStack.isEmpty()) {
return null;
}
String state = undoStack.pop();
redoStack.push(state);
return state;
}

public String popRedo() {
if (redoStack.isEmpty()) {
return null;
}
String state = redoStack.pop();
undoStack.push(state);
return state;
}

public boolean canUndo() {
return !undoStack.isEmpty();
}

public boolean canRedo() {
return !redoStack.isEmpty();
}

public void clear() {
undoStack.clear();
redoStack.clear();
}
}