Eric Bergman-Terrell's Blog

Java Programming Tip: How to correctly position the cursor when a context menu is requested on a StyledText widget
January 28, 2009

Here's a snippet of code that will enable your context menus to work the way Open Office does. In other words, if the user right-clicks over selected text, the selection will not change. If the user right-clicks anywhere else, the cursor will move to the current mouse position if the mouse is over text. Otherwise the cursor will move to the end of the line to the left of the cursor.

This process is more complicated than it should be because StyledText.getOffsetAtLocation will throw an IllegalArgumentException when the specified point is not directly over actual text. To work around this issue, the below code will call getOffsetAtLocation a second time, with an x coordinate of 0. If that call succeeds, the offset is moved to the end of the current line.

getControl().getMenu().addMenuListener(new MenuListener() {
    @Override
    public void menuHidden(MenuEvent e) {
    }

    @Override
    public void menuShown(MenuEvent menuEvent) {
    // Move the cursor over a bit to avoid selecting the first menu item on Ubuntu.
    Point cursorLocation = menuEvent.display.getCursorLocation();

    Display.getCurrent().setCursorLocation(cursorLocation.x + 1, cursorLocation.y + 1);

    Point mappedPoint = Display.getCurrent().map(null, getTextWidget(), cursorLocation);

    // Try to move the cursor to the current mouse position.

    int offset = -1;

    try {
        offset = getTextWidget().getOffsetAtLocation(mappedPoint);
    }
    catch (Exception ex) {
        // The cursor was probably to the right of the text on a given line. Get the offset at the beginning
        // of the line by moving the point all the way to the left.
        Point newPoint = new Point(0, mappedPoint.y);

        try {
            // If we got the offset, move to the end of the line.
            offset = getTextWidget().getOffsetAtLocation(newPoint);
            int lineIndex = getTextWidget().getLineAtOffset(offset);
            offset += getTextWidget().getLine(lineIndex).length();
        }
        catch (Exception ex2) {
        // Otherwise, create an offset to the end of the entire text.
        offset = getTextWidget().getText().length();
        }
    }

    // Set the cursor if possible, but do not set the cursor if it's over selected text.
    if (offset != -1) {
        boolean overSelectedText = false;

        if (getTextWidget().getSelectionCount() < 0) {
            Point selectedPoint = getTextWidget().getSelection();

            overSelectedText = offset >= selectedPoint.x && offset < selectedPoint.y; 
        }

        if (!overSelectedText) {
            getTextWidget().setCaretOffset(offset);
        }
    }
}
});
Keywords: Java, SWT, JFace, Open Office, Context Menus, TextViewer, Eclipse, IllegalArgumentException

Reader Comments

Comment on this Blog Post

Recent Posts

TitleDate
How to decompile Java code with JetBrains IntelliJ IDEA (2018.2.3, Windows 10)October 5, 2018
Java Programming Tip: SWT Photo Frame ProgramOctober 31, 2016
Vault 3 (Desktop) Version 1.63 ReleasedSeptember 9, 2016
"Compliance with Court Orders Act of 2016"April 9, 2016
Disable "Visual Voicemail" on Android / T-MobileJanuary 17, 2016
IPv6 HumorDecember 10, 2015
Java Programming Tip: Specify the JVM time zoneDecember 7, 2015