| /* |
| * Copyright 2000-2014 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.ui; |
| |
| import com.intellij.ide.ui.UISettings; |
| import com.intellij.openapi.actionSystem.AnAction; |
| import com.intellij.openapi.actionSystem.AnActionEvent; |
| import com.intellij.openapi.actionSystem.CustomShortcutSet; |
| import com.intellij.openapi.util.Couple; |
| import org.intellij.lang.annotations.JdkConstants; |
| import org.jetbrains.annotations.NotNull; |
| |
| import javax.swing.*; |
| import java.awt.*; |
| import java.awt.event.ActionEvent; |
| import java.awt.event.InputEvent; |
| import java.awt.event.KeyEvent; |
| |
| /** |
| * @author cdr |
| */ |
| public class TableScrollingUtil { |
| public static void ensureIndexIsVisible(JTable table, int index, int moveDirection) { |
| int visible = getVisibleRowCount(table); |
| int size = table.getModel().getRowCount(); |
| int top; |
| int bottom; |
| if (moveDirection == 0) { |
| top = index - (visible - 1) / ListScrollingUtil.ROW_PADDING; |
| bottom = top + visible - 1; |
| } |
| else if (moveDirection < 0) { |
| top = index - ListScrollingUtil.ROW_PADDING; |
| bottom = index; |
| } |
| else { |
| top = index; |
| bottom = index + ListScrollingUtil.ROW_PADDING; |
| } |
| if (top < 0) { |
| top = 0; |
| } |
| if (bottom >= size) { |
| bottom = size - 1; |
| } |
| Rectangle cellBounds = getCellBounds(table, top, bottom); |
| if (cellBounds != null) { |
| cellBounds.x = 0; |
| table.scrollRectToVisible(cellBounds); |
| } |
| } |
| |
| public static void ensureSelectionExists(@NotNull JTable list) { |
| int size = list.getModel().getRowCount(); |
| if (size == 0) { |
| list.clearSelection(); |
| return; |
| } |
| int selectedIndex = list.getSelectedRow(); |
| boolean reselect = false; |
| if (selectedIndex < 0 || selectedIndex >= size) { // fit index to [0, size-1] range |
| selectedIndex = 0; |
| reselect = true; |
| } |
| ensureIndexIsVisible(list, selectedIndex, 0); |
| if (reselect) { |
| list.getSelectionModel().setSelectionInterval(selectedIndex, selectedIndex); |
| } |
| } |
| |
| private static Rectangle getCellBounds(JTable table, int top, int bottom) { |
| return table.getCellRect(top, 0, true).union(table.getCellRect(bottom,0,true)); |
| } |
| |
| private static int getVisibleRowCount(JTable list) { |
| Rectangle visibleRect = list.getVisibleRect(); |
| return getTrailingRow(list, visibleRect) - getLeadingRow(list, visibleRect) + 1; |
| } |
| |
| public static Couple<Integer> getVisibleRows(JTable list) { |
| Rectangle visibleRect = list.getVisibleRect(); |
| return Couple.of(getLeadingRow(list, visibleRect) + 1, getTrailingRow(list, visibleRect)); |
| } |
| |
| private static int getLeadingRow(JTable table,Rectangle visibleRect) { |
| Point leadingPoint; |
| |
| if (table.getComponentOrientation().isLeftToRight()) { |
| leadingPoint = new Point(visibleRect.x, visibleRect.y); |
| } |
| else { |
| leadingPoint = new Point(visibleRect.x + visibleRect.width, |
| visibleRect.y); |
| } |
| return table.rowAtPoint(leadingPoint); |
| } |
| |
| private static int getTrailingRow(JTable table,Rectangle visibleRect) { |
| Point trailingPoint; |
| |
| if (table.getComponentOrientation().isLeftToRight()) { |
| trailingPoint = new Point(visibleRect.x, |
| visibleRect.y + visibleRect.height - 1); |
| } |
| else { |
| trailingPoint = new Point(visibleRect.x + visibleRect.width, |
| visibleRect.y + visibleRect.height - 1); |
| } |
| return table.rowAtPoint(trailingPoint); |
| } |
| |
| |
| public static void moveDown(JTable list, @JdkConstants.InputEventMask int modifiers, boolean cycleScrolling) { |
| int size = list.getModel().getRowCount(); |
| if (size == 0) { |
| return; |
| } |
| final ListSelectionModel selectionModel = list.getSelectionModel(); |
| int index = selectionModel.getLeadSelectionIndex(); |
| final int indexToSelect; |
| if (index < size - 1) { |
| indexToSelect = index + 1; |
| } |
| else if (cycleScrolling && index == size - 1) { |
| indexToSelect = 0; |
| } |
| else { |
| return; |
| } |
| ensureIndexIsVisible(list, indexToSelect, +1); |
| if (selectionModel.getSelectionMode() == ListSelectionModel.SINGLE_SELECTION) { |
| selectionModel.setSelectionInterval(indexToSelect,indexToSelect); |
| } |
| else { |
| if ((modifiers & InputEvent.SHIFT_DOWN_MASK) == 0) { |
| selectionModel.removeSelectionInterval(selectionModel.getMinSelectionIndex(), selectionModel.getMaxSelectionIndex()); |
| } |
| selectionModel.addSelectionInterval(indexToSelect, indexToSelect); |
| } |
| } |
| |
| public static void moveUp(JTable list, @JdkConstants.InputEventMask int modifiers, boolean cycleScrolling) { |
| int size = list.getModel().getRowCount(); |
| final ListSelectionModel selectionModel = list.getSelectionModel(); |
| int index = selectionModel.getMinSelectionIndex(); |
| int indexToSelect; |
| if (index > 0) { |
| indexToSelect = index - 1; |
| } |
| else if (cycleScrolling && index == 0) { |
| indexToSelect = size - 1; |
| } |
| else { |
| return; |
| } |
| ensureIndexIsVisible(list, indexToSelect, -1); |
| if (selectionModel.getSelectionMode() == ListSelectionModel.SINGLE_SELECTION) { |
| selectionModel.setSelectionInterval(indexToSelect, indexToSelect); |
| } |
| else { |
| if ((modifiers & InputEvent.SHIFT_DOWN_MASK) == 0) { |
| selectionModel.removeSelectionInterval(selectionModel.getMinSelectionIndex(), selectionModel.getMaxSelectionIndex()); |
| } |
| selectionModel.addSelectionInterval(indexToSelect, indexToSelect); |
| } |
| } |
| |
| public static void moveHome(JTable list) { |
| list.getSelectionModel().setSelectionInterval(0,0); |
| ensureIndexIsVisible(list, 0,0); |
| } |
| |
| public static void moveEnd(JTable list) { |
| int index = list.getModel().getRowCount() - 1; |
| list.getSelectionModel().setSelectionInterval(index, index); |
| ensureIndexIsVisible(list, index, 0); |
| } |
| |
| public static void movePageUp(JTable list) { |
| int visible = getVisibleRowCount(list); |
| if (visible <= 0) { |
| moveHome(list); |
| return; |
| } |
| int size = list.getModel().getRowCount(); |
| int decrement = visible - 1; |
| ListSelectionModel selectionModel = list.getSelectionModel(); |
| int index = Math.max(selectionModel.getMinSelectionIndex() - decrement, 0); |
| int visibleIndex = getLeadingRow(list, list.getVisibleRect()); |
| int top = visibleIndex - decrement; |
| if (top < 0) { |
| top = 0; |
| } |
| int bottom = top + visible - 1; |
| if (bottom >= size) { |
| bottom = size - 1; |
| } |
| |
| Rectangle cellBounds = getCellBounds(list, top, bottom); |
| if (cellBounds == null) { |
| moveHome(list); |
| return; |
| } |
| list.scrollRectToVisible(cellBounds); |
| |
| list.getSelectionModel().setSelectionInterval(index, index); |
| ensureIndexIsVisible(list, index, 0); |
| } |
| |
| public static void movePageDown(JTable list) { |
| int visible = getVisibleRowCount(list); |
| if (visible <= 0) { |
| moveEnd(list); |
| return; |
| } |
| ListSelectionModel selectionModel = list.getSelectionModel(); |
| int size = list.getModel().getRowCount(); |
| int increment = visible - 1; |
| int index = Math.min(selectionModel.getMinSelectionIndex() + increment, size - 1); |
| int fisrtVisibleRow = getLeadingRow(list, list.getVisibleRect()); |
| int top = fisrtVisibleRow + increment; |
| int bottom = top + visible - 1; |
| if (bottom >= size) { |
| bottom = size - 1; |
| } |
| Rectangle cellBounds = getCellBounds(list, top, bottom); |
| if (cellBounds == null) { |
| moveEnd(list); |
| return; |
| } |
| list.scrollRectToVisible(cellBounds); |
| list.getSelectionModel().setSelectionInterval(index, index); |
| ensureIndexIsVisible(list, index, 0); |
| } |
| |
| public static void installActions(final JTable list) { |
| installActions(list, UISettings.getInstance().CYCLE_SCROLLING); |
| } |
| |
| public static void installActions(final JTable list, final boolean cycleScrolling) { |
| ActionMap actionMap = list.getActionMap(); |
| actionMap.put(ListScrollingUtil.SCROLLUP_ACTION_ID, new AbstractAction() { |
| public void actionPerformed(ActionEvent e) { |
| movePageUp(list); |
| } |
| }); |
| actionMap.put(ListScrollingUtil.SCROLLDOWN_ACTION_ID, new AbstractAction() { |
| public void actionPerformed(ActionEvent e) { |
| movePageDown(list); |
| } |
| }); |
| actionMap.put(ListScrollingUtil.SELECT_PREVIOUS_ROW_ACTION_ID, new AbstractAction() { |
| public void actionPerformed(ActionEvent e) { |
| moveUp(list, e.getModifiers(), cycleScrolling); |
| } |
| }); |
| actionMap.put(ListScrollingUtil.SELECT_NEXT_ROW_ACTION_ID, new AbstractAction() { |
| public void actionPerformed(ActionEvent e) { |
| moveDown(list, e.getModifiers(), cycleScrolling); |
| } |
| }); |
| actionMap.put(ListScrollingUtil.SELECT_LAST_ROW_ACTION_ID, new AbstractAction() { |
| public void actionPerformed(ActionEvent e) { |
| moveEnd(list); |
| } |
| }); |
| actionMap.put(ListScrollingUtil.SELECT_FIRST_ROW_ACTION_ID, new AbstractAction() { |
| public void actionPerformed(ActionEvent e) { |
| moveHome(list); |
| } |
| }); |
| |
| ListScrollingUtil.maybeInstallDefaultShortcuts(list); |
| |
| new AnAction() { |
| public void actionPerformed(AnActionEvent e) { |
| moveHome(list); |
| } |
| }.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)), list); |
| new AnAction() { |
| public void actionPerformed(AnActionEvent e) { |
| moveEnd(list); |
| } |
| }.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0)), list); |
| |
| new AnAction() { |
| public void actionPerformed(AnActionEvent e) { |
| moveHome(list); |
| } |
| }.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0)), list); |
| new AnAction() { |
| public void actionPerformed(AnActionEvent e) { |
| moveEnd(list); |
| } |
| }.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0)), list); |
| } |
| |
| } |