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
EBTCalc (Android) Version 1.53 is now availableMay 19, 2024
Vault 3 Security EnhancementsOctober 24, 2023
Vault 3 is now available for Apple OSX M2 Mac Computers!September 18, 2023
Vault (for Desktop) Version 0.77 ReleasedMarch 26, 2023
EBTCalc (Android) Version 1.44 is now availableOctober 12, 2021
Vault (Desktop) Version 0.72 ReleasedOctober 6, 2021
EBT Compass is Now Available for Android DevicesJune 2, 2021