Skip to content

Commit

Permalink
Cleanup selection
Browse files Browse the repository at this point in the history
  • Loading branch information
zapek committed Jan 18, 2025
1 parent 82071a5 commit dd38060
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,42 @@ else if (cellIndex >= virtualFlow.getLastVisibleIndex())
}
}

public void release(MouseEvent e)
{
if (e.getEventType() != MouseEvent.MOUSE_RELEASED)
{
throw new IllegalArgumentException("Event must be a MOUSE_RELEASED event");
}

var virtualFlow = getVirtualFlow(e);
virtualFlow.setCursor(Cursor.DEFAULT);

if (selectRange == null || !selectRange.isSelected())
{
clearSelection();
selectRange = null;
}

if (focusNode != null)
{
focusNode.requestFocus();
}
}

public void copy()
{
var text = getSelectionAsText();
if (StringUtils.isNotBlank(text))
{
ClipboardUtils.copyTextToClipboard(text);
}
}

public boolean isSelected()
{
return !textFlows.isEmpty();
}

private boolean handleMultilineSelect(VirtualFlow<ChatLine, ChatListCell> virtualFlow, VirtualFlowHit<ChatListCell> hitResult)
{
var cellIndex = hitResult.getCellIndex();
Expand Down Expand Up @@ -281,43 +317,6 @@ private void removeVisibleSelection(TextFlow textFlow)
textFlows.remove(textFlow);
}


public void release(MouseEvent e)
{
if (e.getEventType() != MouseEvent.MOUSE_RELEASED)
{
throw new IllegalArgumentException("Event must be a MOUSE_RELEASED event");
}

var virtualFlow = getVirtualFlow(e);
virtualFlow.setCursor(Cursor.DEFAULT);

if (selectRange == null || !selectRange.isSelected())
{
clearSelection();
selectRange = null;
}

if (focusNode != null)
{
focusNode.requestFocus();
}
}

public void copy()
{
var text = getSelectionAsText();
if (StringUtils.isNotBlank(text))
{
ClipboardUtils.copyTextToClipboard(text);
}
}

public boolean isSelected()
{
return !textFlows.isEmpty();
}

private void clearSelection()
{
while (!textFlows.isEmpty())
Expand Down
81 changes: 40 additions & 41 deletions ui/src/main/java/io/xeres/ui/support/util/TextFlowUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,12 @@
import javafx.scene.shape.Path;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Objects;

public final class TextFlowUtils
{
private static final Logger log = LoggerFactory.getLogger(TextFlowUtils.class);

private TextFlowUtils()
{
throw new UnsupportedOperationException("Utility class");
Expand All @@ -45,14 +41,9 @@ private TextFlowUtils()
* Returns a text flow as a string.
*
* @param textFlow the text flow, not null
* @param beginIndex the beginning index, inclusive
* @return the string, not null
*/
public static String getTextFlowAsText(TextFlow textFlow)
{
Objects.requireNonNull(textFlow);
return getTextFlowAsText(textFlow, 0, getTextFlowCount(textFlow));
}

public static String getTextFlowAsText(TextFlow textFlow, int beginIndex)
{
Objects.requireNonNull(textFlow);
Expand All @@ -73,6 +64,13 @@ public static String getTextFlowAsText(TextFlow textFlow, int beginIndex, int en
return context.getText();
}

/**
* Calculates the length of a textflow.
* <p>Note: only {@link Text} has a length equal to the characters it contains, the other nodes return 1.
*
* @param textFlow the textflow
* @return the length of the textflow
*/
public static int getTextFlowCount(TextFlow textFlow)
{
Objects.requireNonNull(textFlow);
Expand All @@ -82,18 +80,27 @@ public static int getTextFlowCount(TextFlow textFlow)

for (var node : children)
{
total += switch (node)
{
case Label ignored -> 1;
case Text text -> text.getText().length();
case Hyperlink ignored -> 1;
case ImageView ignored -> 1;
default -> 0;
};
total += getTotalSize(node);
}
return total;
}

private static int getTotalSize(Node node)
{
return switch (node)
{
case Label ignored -> 1;
case Text text -> text.getText().length();
case Hyperlink ignored -> 1;
case ImageView ignored -> 1;
case Path ignored -> 0; // We don't account for that one because it's for marking selected text, and it's always at the end
default -> throw new IllegalStateException("Unhandled node: " + node);
};
}

/**
* Little helper class to keep track of the context.
*/
private static class Context
{
private final List<Node> nodes;
Expand All @@ -110,6 +117,20 @@ public Context(List<Node> nodes, int beginIndex, int endIndex)
this.endIndex = endIndex;
}

public String getText()
{
var sb = new StringBuilder();
while (hasNextNode())
{
if (needsSpace() && !sb.isEmpty())
{
sb.append(" ");
}
sb.append(processNextNode());
}
return sb.toString();
}

private boolean hasNextNode()
{
return currentNode + 1 < nodes.size() && !(nodes.get(currentNode + 1) instanceof Path);
Expand All @@ -125,15 +146,7 @@ private String processNextNode()
currentNode++;
var node = nodes.get(currentNode);

var size = switch (node)
{
case Label ignored -> 1;
case Text text -> text.getText().length();
case Hyperlink ignored -> 1;
case ImageView ignored -> 1;
case Path ignored -> 0;
default -> throw new IllegalStateException("Unhandled node: " + node);
};
var size = getTotalSize(node);

if (currentIndex + size <= beginIndex)
{
Expand Down Expand Up @@ -186,19 +199,5 @@ private String processNextNode()
default -> throw new IllegalStateException("Unhandled node: " + node);
}
}

public String getText()
{
var sb = new StringBuilder();
while (hasNextNode())
{
if (needsSpace() && !sb.isEmpty())
{
sb.append(" ");
}
sb.append(processNextNode());
}
return sb.toString();
}
}
}

0 comments on commit dd38060

Please sign in to comment.