/* * Copyright (c) 2012 Sam Harwell, Tunnel Vision Laboratories LLC * All rights reserved. * * The source code of this document is proprietary work, and is not licensed for * distribution. For information about licensing, contact Sam Harwell at: * sam@tunnelvisionlabs.com */ package org.antlr.netbeans.editor; import java.util.ArrayList; import java.util.List; import javax.swing.JComponent; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.JTextComponent; import javax.swing.text.Position; import javax.swing.text.StyledDocument; /** * This class provides utility methods for working with rectangular selections. * * @author Sam Harwell */ public final class SelectionHelper { /** Boolean property defining whether selection is being rectangular in a particular text component. */ private static final String RECTANGULAR_SELECTION_PROPERTY = "rectangular-selection"; // NOI18N /** List of positions (with even size) defining regions of rectangular selection. Maintained by BaseCaret. */ private static final String RECTANGULAR_SELECTION_REGIONS_PROPERTY = "rectangular-selection-regions"; // NOI18N private SelectionHelper() { // static class } public static List<DocumentSpan> getSelection(JTextComponent target) { List<DocumentSpan> spans = new ArrayList<>(); Document document = target.getDocument(); if (!(document instanceof StyledDocument)) { return null; } if (isRectangularSelection(target)) { List<Position> positions = regionsCopy(target); for (int i = 0; i < positions.size(); i += 2) { Position start = positions.get(i); Position end = positions.get(i + 1); DocumentSpan selection = new DocumentSpan((StyledDocument)document, start, end); spans.add(selection); } } else { try { DocumentSpan selection = new DocumentSpan((StyledDocument)document, target.getSelectionStart(), target.getSelectionEnd()); spans.add(selection); } catch (BadLocationException ex) { throw new IllegalStateException("Shouldn't be reachable: the selection should be within valid bounds.", ex); } } return spans; } public static void setSelection(JTextComponent target, List<DocumentSpan> updatedSelection) throws BadLocationException { Document document = target.getDocument(); if (updatedSelection.size() > 1 && !isRectangularSelection(target)) { setRectangularSelection(target, true); } if (updatedSelection.size() > 1) { List<Position> positions = new ArrayList<>(); for (int i = 0; i < updatedSelection.size(); i++) { positions.add(document.createPosition(updatedSelection.get(i).getStart().getOffset())); positions.add(document.createPosition(updatedSelection.get(i).getEnd().getOffset())); } target.putClientProperty(RECTANGULAR_SELECTION_REGIONS_PROPERTY, positions); } else { target.select(updatedSelection.get(0).getStart().getOffset(), updatedSelection.get(0).getEnd().getOffset()); } } public static boolean isRectangularSelection(JComponent c) { return Boolean.TRUE.equals(c.getClientProperty(RECTANGULAR_SELECTION_PROPERTY)); } public static void setRectangularSelection(JComponent c, boolean value) { c.putClientProperty(RECTANGULAR_SELECTION_PROPERTY, value); } public static String getRectangularSelectionProperty() { return RECTANGULAR_SELECTION_PROPERTY; } public static List<Position> regionsCopy(JComponent c) { @SuppressWarnings("unchecked") List<Position> regions = (List<Position>) c.getClientProperty(RECTANGULAR_SELECTION_REGIONS_PROPERTY); List<Position> lRegions; if (regions != null) { synchronized (regions) { lRegions = new ArrayList<>(regions); } } else { lRegions = null; } return lRegions; } }