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);
         }
       }
     }
   }
 }
  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 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 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);
        }
      }
    }