/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 ro.nextreports.designer.grid.plaf; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.KeyAdapter; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.swing.*; import javax.swing.border.Border; import javax.swing.event.MouseInputListener; import javax.swing.plaf.ActionMapUIResource; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.UIResource; import ro.nextreports.designer.action.report.layout.cell.ClearCellAction; import ro.nextreports.designer.action.report.layout.cell.CopyAction; import ro.nextreports.designer.action.report.layout.cell.CutAction; import ro.nextreports.designer.action.report.layout.cell.PasteAction; import ro.nextreports.designer.grid.Cell; import ro.nextreports.designer.grid.CellSpan; import ro.nextreports.designer.grid.GridCellEditor; import ro.nextreports.designer.grid.GridCellRenderer; import ro.nextreports.designer.grid.JGrid; import ro.nextreports.designer.grid.SelectionModel; import ro.nextreports.designer.grid.SelectionRegion; import ro.nextreports.designer.grid.SpanModel; import ro.nextreports.engine.util.ObjectCloner; /** * @author Decebal Suiu */ public class BasicGridUI extends GridUI { private static boolean installed; protected CellRendererPane rendererPane; protected MouseInputListener mouseInputListener; private GridSelectionAlgorithm selectionAlgorithm; private static SelectionRegion shiftRegion; public static ComponentUI createUI(JComponent c) { return new BasicGridUI(); } public void paintEditor(Graphics g) { Component component = grid.getEditorComponent(); if (component == null) { return; } int editingRow = grid.getEditingRow(); int editingColumn = grid.getEditingColumn(); Rectangle cellBounds = grid.getCellBounds(editingRow, editingColumn); component.setBounds(cellBounds); component.validate(); component.requestFocus(); } public void paintSpans(Graphics g, int rowMin, int rowMax, int colMin, int colMax) { Iterator<?> cell = grid.getSpanModel().getSpanIterator(); while (cell.hasNext()) { CellSpan span = (CellSpan) cell.next(); Rectangle cellBounds = grid.getCellBounds(span.getRow(), span.getColumn()); // Only paint cell if visible if (span.getLastRow() >= rowMin && span.getLastColumn() >= colMin && span.getFirstRow() <= rowMax && span.getFirstColumn() <= colMax) { paintCell(g, cellBounds, span.getRow(), span.getColumn()); // Paint grid line around cell if (grid.getShowGrid()) { g.setColor(grid.getGridColor()); g.drawRect(cellBounds.x, cellBounds.y, cellBounds.width, cellBounds.height); } } } } public void paintGrid(Graphics g, int rowMin, int rowMax, int colMin, int colMax) { if (!grid.getShowGrid()) { return; // do nothing } int y1 = grid.getRowPosition(rowMin); int y2 = grid.getRowPosition(rowMax) + grid.getRowHeight(rowMax); int x1 = grid.getColumnPosition(colMin); int x2 = grid.getColumnPosition(colMax) + grid.getColumnWidth(colMax); g.setColor(grid.getGridColor()); // Draw the horizontal lines for (int row = rowMin; row <= rowMax; row++) { int rowY = grid.getRowPosition(row); g.drawLine(x1, rowY, x2, rowY); } g.drawLine(x1, y2, x2, y2); // Draw the vertical gridlines for (int col = colMin; col <= colMax; col++) { int colX = grid.getColumnPosition(col); g.drawLine(colX, y1, colX, y2); } g.drawLine(x2, y1, x2, y2); } public void paintCells(Graphics g, int rowMin, int rowMax, int colMin, int colMax) { for (int row = rowMin; row <= rowMax; row++) { for (int column = colMin; column <= colMax; column++) { /* Paint cell if it is atomic */ if (!grid.isCellSpan(row, column)) { Rectangle cellBounds = grid.getCellBounds(row, column); paintCell(g, cellBounds, row, column); } } } } public void paintSelection(Graphics g, int rowMin, int rowMax, int colMin, int colMax) { for (int row = rowMin; row <= rowMax; row++) { for (int column = colMin; column <= colMax; column++) { if (!grid.isCellSpan(row, column)) { Rectangle cellBounds = grid.getCellBounds(row, column); if (grid.getSelectionModel().isSelected(row, column)) { g.setColor(Color.RED); g.drawRect((int) cellBounds.getX() + 1, (int) cellBounds.getY() + 1, (int) cellBounds.getWidth() - 2, (int) cellBounds.getHeight() - 2); } } else { CellSpan span = grid.getSpanModel().getSpanOver(row, column); if (grid.getSelectionModel().isSelected(span.getRow(), span.getColumn())) { g.setColor(Color.RED); Rectangle cellBounds = grid.getCellBounds(span.getFirstRow(), span.getLastColumn()); g.drawRect((int) cellBounds.getX() + 1, (int) cellBounds.getY() + 1, (int) cellBounds.getWidth() - 2, (int) cellBounds.getHeight() - 2); } } } } } @Override public Dimension getPreferredSize(JComponent c) { return getMaximumSize(c); } @Override public Dimension getMinimumSize(JComponent c) { return getMaximumSize(c); } @Override public Dimension getMaximumSize(JComponent c) { int lastRow = grid.getRowCount() - 1; int lastCol = grid.getColumnCount() - 1; Rectangle cellBounds = grid.getCellBounds(lastRow, lastCol); int width = cellBounds.x + cellBounds.width; int height = cellBounds.y + cellBounds.height; return new Dimension(width, height); } @Override public void installUI(JComponent c) { grid = (JGrid) c; selectionAlgorithm = new GridSelectionAlgorithm(grid); rendererPane = new CellRendererPane(); grid.add(rendererPane); installDefaults(); installListeners(); installKeyboardActions(); } @Override public void uninstallUI(JComponent c) { grid.remove(rendererPane); // TODO unistall dropTargetListener si mouseInputListener } protected void installDefaults() { Color defaultGridColor = UIManager.getColor("Table.gridColor"); Color defaultForegroundColor = UIManager.getColor("Table.foreground"); Color defaultBackgroundColor = UIManager.getColor("Table.background"); Border defaultBorder = UIManager.getBorder("Table.scrollPaneBorder"); Color defaultSelectionForeground = UIManager .getColor("Table.selectionForeground"); Color defaultSelectionBackground = UIManager .getColor("Table.selectionBackground"); Color defaultFocusCellForeground = UIManager .getColor("Table.focusCellForeground"); Color defaultFocusCellBackground = new Color(153, 153, 204); Font defaultFont = UIManager.getFont("Table.font"); Border defaultGridBorder = UIManager.getBorder("Table.border"); InputMap inputMap = ObjectCloner.silenceDeepCopy((InputMap) UIManager.get("Table.ancestorInputMap")); if (!installed) { UIManager.getDefaults().put("Grid.gridColor", defaultGridColor); UIManager.getDefaults().put("Grid.foreground", defaultForegroundColor); UIManager.getDefaults().put("Grid.background", defaultBackgroundColor); UIManager.getDefaults().put("Grid.selectionForegroundColor", defaultSelectionForeground); UIManager.getDefaults().put("Grid.selectionBackgroundColor", defaultSelectionBackground); UIManager.getDefaults().put("Grid.focusForegroundColor", defaultFocusCellForeground); UIManager.getDefaults().put("Grid.focusBackgroundColor", defaultFocusCellBackground); UIManager.getDefaults().put("Grid.border", defaultGridBorder); UIManager.getDefaults().put("Grid.font", defaultFont); UIManager.getDefaults().put("Grid.scrollPaneBorder", defaultBorder); UIManager.getDefaults().put("Grid.ancestorInputMap", inputMap); installed = true; } Color foregroundColor = grid.getForeground(); Color backgroundColor = grid.getBackground(); Font font = grid.getFont(); Border border = grid.getBorder(); Color gridColor = grid.getGridColor(); if (foregroundColor == null || foregroundColor instanceof UIResource) { grid.setForeground(defaultForegroundColor); } if (backgroundColor == null || backgroundColor instanceof UIResource) { grid.setBackground(defaultBackgroundColor); } if (font == null || font instanceof UIResource) { grid.setFont(defaultFont); } if (gridColor == null || gridColor instanceof UIResource) { grid.setGridColor(defaultGridColor); } if (border == null || border instanceof UIResource) { grid.setBorder(defaultGridBorder); } } /** * Paint cell at (row, column). */ protected void paintCell(Graphics g, Rectangle cellBounds, int row, int column) { if ((grid.getEditingRow() == row) && (grid.getEditingColumn() == column)) { return; } GridCellRenderer renderer = grid.getCellRenderer(row, column); Component rendererComp = grid.prepareRenderer(renderer, row, column); rendererPane.paintComponent(g, rendererComp, grid, cellBounds.x, cellBounds.y, cellBounds.width, cellBounds.height, true); } /** * Attaches listeners to the JGrid */ protected void installListeners() { /* DropTargetListener dropTargetListener = createDropTargetListener(); DropTarget dropTarget = grid.getDropTarget(); if (dropTarget == null) { dropTarget = new DropTarget(grid, dropTargetListener); } else { try { dropTarget.addDropTargetListener(dropTargetListener); } catch (TooManyListenersException e) { // should not happen... swing drop target is multicast } } */ mouseInputListener = createMouseInputListener(); grid.addMouseListener(mouseInputListener); grid.addMouseMotionListener(mouseInputListener); grid.addKeyListener(new KeyAdapter() { public void keyReleased(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_SHIFT) { shiftRegion = null; } } }); } protected void installKeyboardActions() { ActionMap map = getActionMap(); SwingUtilities.replaceUIActionMap(grid, map); InputMap inputMap = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); SwingUtilities.replaceUIInputMap(grid, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap); } /** * Creates the mouse listener for the JGrid. */ protected MouseInputListener createMouseInputListener() { return new MouseInputHandler(); } /* protected DropTargetListener createDropTargetListener() { return new DropTargetHandler(); } */ private InputMap getInputMap(int condition) { if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) { InputMap inputMap = (InputMap) UIManager.get("Grid.ancestorInputMap"); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancel"); inputMap.put((KeyStroke) new ClearCellAction().getValue(Action.ACCELERATOR_KEY), "clearCell"); inputMap.put((KeyStroke) new CutAction().getValue(Action.ACCELERATOR_KEY), "cutCell"); inputMap.put((KeyStroke) new CopyAction().getValue(Action.ACCELERATOR_KEY), "copyCell"); inputMap.put((KeyStroke) new PasteAction().getValue(Action.ACCELERATOR_KEY), "pasteCell"); return inputMap; } else { return null; } } private ActionMap getActionMap() { ActionMap actionMap = (ActionMap) UIManager.get("Grid.actionMap"); if (actionMap == null) { actionMap = createActionMap(); if (actionMap != null) { UIManager.put("Grid.actionMap", actionMap); } } return actionMap; } private ActionMap createActionMap() { ActionMap map = new ActionMapUIResource(); map.put("selectNextColumn", new NavigationAction(1, 0)); map.put("selectPreviousColumn", new NavigationAction(-1, 0)); map.put("selectNextRow", new NavigationAction(0, 1)); map.put("selectPreviousRow", new NavigationAction(0, -1)); map.put("selectNextColumnExtendSelection", new NavigationAction(1, 0, true)); map.put("selectPreviousColumnExtendSelection", new NavigationAction(-1, 0, true)); map.put("selectNextRowExtendSelection", new NavigationAction(0, 1, true)); map.put("selectPreviousRowExtendSelection", new NavigationAction(0, -1, true)); map.put("startEditing", new StartEditingAction()); map.put("cancel", new CancelEditingAction()); map.put("clearCell", new ClearCellAction()); map.put("cutCell", new CutAction()); map.put("copyCell", new CopyAction()); map.put("pasteCell", new PasteAction()); return map; } /** * Instantiate it only within subclasses of BasicGridUI. */ protected class MouseInputHandler implements MouseInputListener { // Component recieving mouse events during editing. // May not be editorComponent. private Component dispatchComponent; private boolean selectedOnPress; private SelectionRegion selectionRegion; private Point startPoint = null; private Point previousPoint = null; public void mouseClicked(MouseEvent event) { } public void mousePressed(MouseEvent event) { startPoint = event.getPoint(); // System.out.println("MouseInputHandler.mousePressed()"); if (!event.isShiftDown()) { selectionRegion = null; } if (event.isConsumed()) { selectedOnPress = false; return; } selectedOnPress = true; adjustFocusAndSelection(event); } public void mouseReleased(MouseEvent event) { // System.out.println("MouseInputHandler.mouseReleased()"); startPoint = null; previousPoint = null; if (selectedOnPress) { if (shouldIgnore(event)) { return; } repostEvent(event); dispatchComponent = null; setValueIsAdjusting(false); } else { adjustFocusAndSelection(event); } } public void mouseEntered(MouseEvent event) { } public void mouseExited(MouseEvent event) { } public void mouseMoved(MouseEvent event) { } public void mouseDragged(MouseEvent event) { // System.out.println("MouseInputHandler.mouseDragged()"); if (shouldIgnore(event)) { return; } // if CTRL is pressed we are not interested in mouse drag events if (event.isControlDown()) { return; } repostEvent(event); CellEditor editor = grid.getCurrentCellEditor(); if (editor == null || editor.shouldSelectCell(event)) { Point p = event.getPoint(); if (startPoint == null) { startPoint = p; } if (previousPoint == null) { previousPoint = p; } int row = grid.rowAtPoint(p); int column = grid.columnAtPoint(p); // The autoscroller can generate drag events outside the Grid's range. if ((column == -1) || (row == -1)) { return; } // update selectionRegion if (selectionAlgorithm == null) { // for grid headers selectionAlgorithm = new GridSelectionAlgorithm(grid); } selectionAlgorithm.update(p, startPoint, previousPoint, selectionRegion); selectionRegionChanged(grid, selectionRegion, false); previousPoint = p; } } private void setDispatchComponent(MouseEvent event) { // Get location Point point = event.getPoint(); // Get editor component Component editorComponent = grid.getEditorComponent(); // Get dispatchComponent Point editorPoint = SwingUtilities.convertPoint(grid, point, editorComponent); dispatchComponent = SwingUtilities.getDeepestComponentAt(editorComponent, editorPoint.x, editorPoint.y); } /* Repost event to dispatchComponent */ private boolean repostEvent(MouseEvent event) { if (dispatchComponent == null) { return false; } MouseEvent editorMouseEvent = SwingUtilities.convertMouseEvent( grid, event, dispatchComponent); dispatchComponent.dispatchEvent(editorMouseEvent); return true; } private boolean shouldIgnore(MouseEvent event) { return event.isConsumed() || (!(SwingUtilities.isLeftMouseButton(event) && grid.isEnabled())); } private void setValueIsAdjusting(boolean flag) { grid.getSelectionModel().setValueIsAdjusting(flag); } private void adjustFocusAndSelection(MouseEvent event) { if (shouldIgnore(event)) { return; } Point point = event.getPoint(); int row = grid.rowAtPoint(point); int column = grid.columnAtPoint(point); // The autoscroller can generate drag events outside range. if ((column == -1) || (row == -1)) { System.err.println("Out of bounds"); return; } if (grid.editCellAt(row, column, event)) { setDispatchComponent(event); repostEvent(event); } else { grid.requestFocus(); } // System.out.println("^^^^^ "+selectionRegion); if (selectionRegion == null) { selectionRegion = new SelectionRegion(); selectionRegion.setFirstRow(row); selectionRegion.setFirstColumn(column); selectionRegion.setLastRow(row); selectionRegion.setLastColumn(column); } else { // for shift pressed if (row > selectionRegion.getFirstRow()) { selectionRegion.setLastRow(row); } if (row < selectionRegion.getFirstRow()) { selectionRegion.setLastRow(selectionRegion.getFirstRow()); selectionRegion.setFirstRow(row); } if (row == selectionRegion.getFirstRow()) { selectionRegion.setLastRow(row); } if (column > selectionRegion.getFirstColumn()) { selectionRegion.setLastColumn(column); } if (column < selectionRegion.getFirstColumn()) { selectionRegion.setLastColumn(selectionRegion.getFirstColumn()); selectionRegion.setFirstColumn(column); } if (column == selectionRegion.getFirstColumn()) { selectionRegion.setLastColumn(column); } } // System.out.println(">>>> " + selectionRegion); Iterator<CellSpan> it = grid.getSpanModel().getSpanIterator(); while (it.hasNext()) { CellSpan span = it.next(); if (span.getLastRow() >= selectionRegion.getFirstRow() && span.getFirstRow() <= selectionRegion.getLastRow() && span.getLastColumn() >= selectionRegion.getFirstColumn() && span.getFirstColumn() <= selectionRegion.getLastColumn()) { selectionRegion.setFirstRow(Math.min(selectionRegion.getFirstRow(), span.getFirstRow())); selectionRegion.setLastRow(Math.max(selectionRegion.getLastRow(), span.getLastRow())); selectionRegion.setFirstColumn(Math.min(selectionRegion.getFirstColumn(), span.getFirstColumn())); selectionRegion.setLastColumn(Math.max(selectionRegion.getLastColumn(), span.getLastColumn())); } } GridCellEditor editor = grid.getCurrentCellEditor(); if ((editor == null) || editor.shouldSelectCell(event)) { // Update selection model setValueIsAdjusting(true); if (event.isControlDown()) { if (grid.getSelectionModel().isSelected(row, column)) { Cell cell = new Cell(row, column); boolean isSpan = grid.getSpanModel().isCellSpan(row, column); if (isSpan) { // System.out.println("--isSpan"); CellSpan cellSpan = grid.getSpanModel().getSpanOver(row, column); for (int i = cellSpan.getFirstRow(); i <= cellSpan.getLastRow(); i++) { for (int j = cellSpan.getFirstColumn(); j <= cellSpan.getLastColumn(); j++) { grid.getSelectionModel().removeSelectionCell(new Cell(i, j)); } } } else { grid.getSelectionModel().removeSelectionCell(cell); } } else { selectionRegionChanged(grid, selectionRegion, true); } } else { selectionRegionChanged(grid, selectionRegion, false); } } } } /* protected class DropTargetHandler implements DropTargetListener { public void dragEnter(DropTargetDragEvent event) { if (canImport(event)) { event.acceptDrag(DnDConstants.ACTION_COPY); } else { event.rejectDrag(); } } public void dragExit(DropTargetEvent event) { } public void dragOver(DropTargetDragEvent event) { if (canImport(event)) { event.acceptDrag(DnDConstants.ACTION_COPY); } else { event.rejectDrag(); } } public void drop(DropTargetDropEvent event) { if (event.getDropAction() != DnDConstants.ACTION_COPY) { return; } event.acceptDrop(DnDConstants.ACTION_COPY); String data = null; try { data = (String) event.getTransferable().getTransferData(GridTransferable.GRID_FLAVOR); } catch (UnsupportedFlavorException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } Point point = event.getLocation(); int row = grid.rowAtPoint(point); // if (row < 0) { // System.out.println("row = " + row); // } int column = grid.columnAtPoint(point); // if (column < 0) { // System.out.println("column = " + column); // } Object value = null; try { // TODO // value = ReflectionUtil.createInstance(data, String.class, NameGenerator.getUniqueName("elem")); } catch (Exception e) { // TODO e.printStackTrace(); } // System.out.println("value = " + value); if (grid.getSpanModel().isCellSpan(row, column)) { // System.out.println("Cell span (" + row + ", " + column + ")"); CellSpan cellSpan = grid.getSpanModel().getSpanOver(row, column); grid.setValueAt(value, cellSpan.getRow(), cellSpan.getColumn()); } else { grid.setValueAt(value, row, column); } // TODO // grid.getSelectionModel().setSelectionRange(row, column, row, column); } public void dropActionChanged(DropTargetDragEvent event) { } private boolean canImport(DropTargetDragEvent event) { DataFlavor[] flavors = event.getCurrentDataFlavors(); for (DataFlavor flavor : flavors) { if (flavor == GridTransferable.GRID_FLAVOR) { // check for empty cell Point point = event.getLocation(); // System.out.println("point = " + point); int row = grid.rowAtPoint(point); // if (row < 0) { // System.out.println("row = " + row); // } int column = grid.columnAtPoint(point); // if (column < 0) { // System.out.println("column = " + column); // } Object value = grid.getValueAt(row, column); // System.out.println("value = " + value); return (value == null); } } return false; } } */ private static class NavigationAction extends AbstractAction { private int dx; private int dy; private boolean shiftPressed; private NavigationAction(int dx, int dy) { this(dx, dy, false); } private NavigationAction(int dx, int dy, boolean shiftPressed) { this.dx = dx; this.dy = dy; this.shiftPressed = shiftPressed; } public void actionPerformed(ActionEvent event) { JGrid grid = (JGrid) event.getSource(); if (grid.isEditing() && !grid.getCurrentCellEditor().stopCellEditing()) { return; } SelectionModel selectionModel = grid.getSelectionModel(); List<Cell> selectedCells = selectionModel.getSelectedCells(); int selectedCount = selectedCells.size(); if (selectedCount == 0) { return; } Cell firstSelectedCell = selectionModel.getSelectedCell(); Cell lastSelectedCell = selectionModel.getLastSelectedCell(); int row = lastSelectedCell.getRow(); int column = lastSelectedCell.getColumn(); if (shiftPressed) { if (shiftRegion == null) { shiftRegion = new SelectionRegion(); shiftRegion.setFirstRow(row); shiftRegion.setFirstColumn(column); shiftRegion.setLastRow(row); shiftRegion.setLastColumn(column); } boolean nextSelection = true; if ((dx == 1) && (column < grid.getColumnCount() - 1)) { column++; } else if ((dx == -1) && (column > 0)) { column--; } else if ((dy == 1) && (row < grid.getRowCount() - 1)) { row++; } else if ((dy == -1) && (row > 0)) { row--; } else { nextSelection = false; } if (nextSelection) { GridSelectionAlgorithm selectionAlgorithm = new GridSelectionAlgorithm(grid); selectionAlgorithm.update(row, column, firstSelectedCell.getRow(), firstSelectedCell.getColumn(), lastSelectedCell.getRow(), lastSelectedCell.getColumn(), shiftRegion); selectionRegionChanged(grid, shiftRegion, false); // because the selectionModel is cleared and made from scratch // keep a reference to first and last selected cells selectionModel.setFirstCell(firstSelectedCell); selectionModel.setLastCell(new Cell(row, column)); } } else { shiftRegion = null; SpanModel spanModel = grid.getSpanModel(); if (spanModel.isCellSpan(row, column)) { CellSpan span = spanModel.getSpanOver(row, column); row = span.getRow(); column = span.getColumn(); if ((dx > 0) && (span.getColumnCount() > 1)) { column = span.getLastColumn(); } if ((dy > 0) && (span.getRowCount() > 1)) { row = span.getLastRow(); } } row = clipToRange(row + dy, 0, grid.getRowCount()); column = clipToRange(column + dx, 0, grid.getColumnCount()); selectionModel.clearSelection(); if (!grid.isCellSpan(row, column)) { selectionModel.addSelectionCell(new Cell(row, column)); } else { CellSpan span = spanModel.getSpanOver(row, column); List<Cell> cells = new ArrayList<Cell>(); for (int i = 0; i < span.getRowCount(); i++) { for (int j = 0; j < span.getColumnCount(); j++) { cells.add(new Cell(span.getRow() + i, span.getColumn() + j)); } } selectionModel.addSelectionCells(cells); } } } private int clipToRange(int i, int a, int b) { return Math.min(Math.max(i, a), b - 1); } @Override public String toString() { return "NavigationAction: " + dx + ", " + dy; } } /** * Action to start editing, and pass focus to the editor. */ private static class StartEditingAction extends AbstractAction { public void actionPerformed(ActionEvent event) { JGrid grid = (JGrid) event.getSource(); if (!grid.hasFocus()) { CellEditor cellEditor = grid.getCurrentCellEditor(); if ((cellEditor != null) && !cellEditor.stopCellEditing()) { return; } grid.requestFocus(); } SelectionModel selectionModel = grid.getSelectionModel(); Cell selectedCell = selectionModel.getSelectedCell(); int row = selectedCell.getRow(); int column = selectedCell.getColumn(); grid.editCellAt(row, column, null); Component editorComponent = grid.getEditorComponent(); if (editorComponent != null) { editorComponent.requestFocus(); } } } private class CancelEditingAction extends AbstractAction { public void actionPerformed(ActionEvent event) { JGrid grid = (JGrid) event.getSource(); grid.removeEditor(); grid.requestFocus(); } @Override public boolean isEnabled() { return grid.isEditing(); } } private static void selectionRegionChanged(JGrid grid, SelectionRegion selectionRegion, boolean add) { if (!add) { grid.getSelectionModel().clearSelection(); } List<Cell> selectedCells = new ArrayList<Cell>(); for (int i = selectionRegion.getFirstRow(); i <= selectionRegion.getLastRow(); i++) { for (int j = selectionRegion.getFirstColumn(); j <= selectionRegion.getLastColumn(); j++) { boolean isSpan = grid.getSpanModel().isCellSpan(i, j); //if (!isSpan) { Cell cell = new Cell(i, j); // System.out.println("cell=" + cell); selectedCells.add(cell); // } else { // CellSpan cellSpan = grid.getSpanModel().getSpanOver(i, j); // if ((cellSpan.getRow() == i) && (cellSpan.getGroupColumn() == j)) { // Cell cell = new Cell(i, j); // System.out.println("cell=" + cell); // selectedCells.add(cell); // } // } } } grid.getSelectionModel().addSelectionCells(selectedCells); } }