# HG changeset patch # User Alex Henrie # Date 1408946690 21600 # Mon Aug 25 00:04:50 2014 -0600 # Node ID 3b870005c80d8f5835632679ba43c691cec46d48 # Parent 8ac7b2c816af95c82b4299d3f4b50ac89efd085a Issue #198885: Support back and forward mouse buttons diff --git a/editor.lib/src/org/netbeans/editor/BaseCaret.java b/editor.lib/src/org/netbeans/editor/BaseCaret.java --- a/editor.lib/src/org/netbeans/editor/BaseCaret.java +++ b/editor.lib/src/org/netbeans/editor/BaseCaret.java @@ -216,16 +216,18 @@ AtomicLockListener, FoldHierarchyListene /** Is the caret italic for italic fonts */ boolean italic; private int xPoints[] = new int[4]; private int yPoints[] = new int[4]; private Action selectWordAction; private Action selectLineAction; + private Action navigationHistoryBackAction; + private Action navigationHistoryForwardAction; /** Change event. Only one instance needed because it has only source property */ protected ChangeEvent changeEvent; /** Dot array of one character under caret */ protected char dotChar[] = {' '}; private boolean overwriteMode; @@ -1465,84 +1467,102 @@ AtomicLockListener, FoldHierarchyListene // MouseListener methods @Override public void mousePressed(MouseEvent evt) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("mousePressed: " + logMouseEvent(evt) + ", state=" + mouseState + '\n'); // NOI18N } JTextComponent c = component; - if (c != null && isLeftMouseButtonExt(evt)) { - // Expand fold if offset is in collapsed fold - int offset = mouse2Offset(evt); - switch (evt.getClickCount()) { - case 1: // Single press - if (c.isEnabled() && !c.hasFocus()) { - c.requestFocus(); - } - c.setDragEnabled(true); - if (evt.isShiftDown()) { // Select till offset - moveDot(offset); - adjustRectangularSelectionMouseX(evt.getX(), evt.getY()); // also fires state change - mouseState = MouseState.CHAR_SELECTION; - } else { // Regular press - // check whether selection drag is possible - if (isDragPossible(evt) && mapDragOperationFromModifiers(evt) != TransferHandler.NONE) { - mouseState = MouseState.DRAG_SELECTION_POSSIBLE; - } else { // Drag not possible + if (c != null) { + if (isLeftMouseButtonExt(evt)) { + // Expand fold if offset is in collapsed fold + int offset = mouse2Offset(evt); + switch (evt.getClickCount()) { + case 1: // Single press + if (c.isEnabled() && !c.hasFocus()) { + c.requestFocus(); + } + c.setDragEnabled(true); + if (evt.isShiftDown()) { // Select till offset + moveDot(offset); + adjustRectangularSelectionMouseX(evt.getX(), evt.getY()); // also fires state change mouseState = MouseState.CHAR_SELECTION; - setDot(offset); + } else { // Regular press + // check whether selection drag is possible + if (isDragPossible(evt) && mapDragOperationFromModifiers(evt) != TransferHandler.NONE) { + mouseState = MouseState.DRAG_SELECTION_POSSIBLE; + } else { // Drag not possible + mouseState = MouseState.CHAR_SELECTION; + setDot(offset); + } } - } - break; + break; - case 2: // double-click => word selection - mouseState = MouseState.WORD_SELECTION; - // Disable drag which would otherwise occur when mouse would be over text - c.setDragEnabled(false); - // Check possible fold expansion - try { - // hack, to get knowledge of possible expansion. Editor depends on Folding, so it's not really possible - // to have Folding depend on BaseCaret (= a cycle). If BaseCaret moves to editor.lib2, this contract - // can be formalized as an interface. - Callable cc = (Callable)c.getClientProperty("org.netbeans.api.fold.expander"); - if (cc == null || !cc.equals(this)) { - if (selectWordAction == null) { - selectWordAction = ((BaseKit) c.getUI().getEditorKit( - c)).getActionByName(BaseKit.selectWordAction); + case 2: // double-click => word selection + mouseState = MouseState.WORD_SELECTION; + // Disable drag which would otherwise occur when mouse would be over text + c.setDragEnabled(false); + // Check possible fold expansion + try { + // hack, to get knowledge of possible expansion. Editor depends on Folding, so it's not really possible + // to have Folding depend on BaseCaret (= a cycle). If BaseCaret moves to editor.lib2, this contract + // can be formalized as an interface. + Callable cc = (Callable)c.getClientProperty("org.netbeans.api.fold.expander"); + if (cc == null || !cc.equals(this)) { + if (selectWordAction == null) { + selectWordAction = ((BaseKit) c.getUI().getEditorKit( + c)).getActionByName(BaseKit.selectWordAction); + } + if (selectWordAction != null) { + selectWordAction.actionPerformed(null); + } + // Select word action selects forward i.e. dot > mark + minSelectionStartOffset = getMark(); + minSelectionEndOffset = getDot(); } - if (selectWordAction != null) { - selectWordAction.actionPerformed(null); - } + } catch (Exception ex) { + Exceptions.printStackTrace(ex); + } + break; + + case 3: // triple-click => line selection + mouseState = MouseState.LINE_SELECTION; + // Disable drag which would otherwise occur when mouse would be over text + c.setDragEnabled(false); + if (selectLineAction == null) { + selectLineAction = ((BaseKit) c.getUI().getEditorKit( + c)).getActionByName(BaseKit.selectLineAction); + } + if (selectLineAction != null) { + selectLineAction.actionPerformed(null); // Select word action selects forward i.e. dot > mark minSelectionStartOffset = getMark(); minSelectionEndOffset = getDot(); } - } catch (Exception ex) { - Exceptions.printStackTrace(ex); - } - break; - - case 3: // triple-click => line selection - mouseState = MouseState.LINE_SELECTION; - // Disable drag which would otherwise occur when mouse would be over text - c.setDragEnabled(false); - if (selectLineAction == null) { - selectLineAction = ((BaseKit) c.getUI().getEditorKit( - c)).getActionByName(BaseKit.selectLineAction); - } - if (selectLineAction != null) { - selectLineAction.actionPerformed(null); - // Select word action selects forward i.e. dot > mark - minSelectionStartOffset = getMark(); - minSelectionEndOffset = getDot(); - } - break; + break; - default: // multi-click + default: // multi-click + } + } else if (isBackMouseButtonExt(evt)) { + if (navigationHistoryBackAction == null) { + navigationHistoryBackAction = ((BaseKit) c.getUI().getEditorKit( + c)).getActionByName(BaseKit.jumpListPrevAction); + } + if (navigationHistoryBackAction != null) { + navigationHistoryBackAction.actionPerformed(null); + } + } else if (isForwardMouseButtonExt(evt)) { + if (navigationHistoryForwardAction == null) { + navigationHistoryForwardAction = ((BaseKit) c.getUI().getEditorKit( + c)).getActionByName(BaseKit.jumpListNextAction); + } + if (navigationHistoryForwardAction != null) { + navigationHistoryForwardAction.actionPerformed(null); + } } } } @Override public void mouseReleased(MouseEvent evt) { if (LOG.isLoggable(Level.FINE)) { LOG.fine("mouseReleased: " + logMouseEvent(evt) + ", state=" + mouseState + '\n'); // NOI18N @@ -1934,16 +1954,29 @@ AtomicLockListener, FoldHierarchyListene moveDot(Math.min(newDot, minSelectionStartOffset)); } else { // newDot > mark => swap mark and dot setDot(minSelectionStartOffset); moveDot(Math.max(newDot, minSelectionEndOffset)); } } } + + private boolean isBackMouseButtonExt(MouseEvent evt) { + return (evt.getButton() == 6 + && !(evt.isPopupTrigger()) + && (evt.getModifiers() & (InputEvent.META_MASK | InputEvent.ALT_MASK)) == 0); + } + + private boolean isForwardMouseButtonExt(MouseEvent evt) { + return (evt.getButton() == 7 + && !(evt.isPopupTrigger()) + && (evt.getModifiers() & (InputEvent.META_MASK | InputEvent.ALT_MASK)) == 0); + } + private boolean isLeftMouseButtonExt(MouseEvent evt) { return (SwingUtilities.isLeftMouseButton(evt) && !(evt.isPopupTrigger()) && (evt.getModifiers() & (InputEvent.META_MASK | InputEvent.ALT_MASK)) == 0); } private boolean isMiddleMouseButtonExt(MouseEvent evt) { return (evt.getButton() == MouseEvent.BUTTON2) &&