content: /*
   * Created on Aug 25, 2007
   *
   * 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.
   *
   * Copyright @2007-2013 the original author or authors.
   */
  package org.fest.swing.test.swing;
  
  import static java.lang.String.valueOf;
  import static javax.swing.ListSelectionModel.SINGLE_SELECTION;
  import static org.fest.swing.edt.GuiActionRunner.execute;
  import static org.fest.util.Strings.concat;
  
  import javax.swing.JTable;
  import javax.swing.table.DefaultTableModel;
  
  import org.fest.swing.annotation.RunsInEDT;
  import org.fest.swing.edt.GuiTask;
  
  /**
   * <p>
   * {@code JTable} that requires a name and supports drag and drop.
   * </p>
   *
   * <p>
   * Adapted from the tutorial <a href="http://java.sun.com/docs/books/tutorial/uiswing/dnd/intro.html"
   * target="_blank">Introduction to Drag and Drop and Data Transfer</a>.
   * </p>
   *
   * @author Alex Ruiz
   * @author Yvonne Wang
   */
  public class TestTable extends JTable {
    private final CustomModel model;
  
    public TestTable(int rowCount, int columnCount) {
      this(null, rowData(rowCount, columnCount), columnNames(columnCount));
    }
  
    public TestTable(String name, int rowCount, int columnCount) {
      this(name, rowData(rowCount, columnCount), columnNames(columnCount));
    }
  
    public static Object[] columnNames(int columnCount) {
      Object[] columnNames = new Object[columnCount];
      for (int i = 0; i < columnCount; i++) {
        columnNames[i] = String.valueOf(i);
      }
      return columnNames;
    }
  
    public static Object[][] rowData(int rowCount, int columnCount) {
      Object[][] data = new Object[rowCount][columnCount];
      for (int i = 0; i < rowCount; i++) {
        for (int j = 0; j < columnCount; j++) {
          data[i][j] = createCellValueFrom(i, j);
        }
      }
      return data;
    }
  
    public static String createCellValueFrom(int row, int column) {
      return concat(valueOf(row), "-", valueOf(column));
    }
  
    public TestTable(Object[][] rowData, Object[] columnNames) {
      this(null, rowData, columnNames);
    }
  
    public TestTable(String name, Object[][] data, Object[] columnNames) {
      setDragEnabled(true);
      model = new CustomModel(data, columnNames);
      setModel(model);
      setName(name);
      setSelectionMode(SINGLE_SELECTION);
      setTransferHandler(new TableTransferHandler());
    }
  
    @RunsInEDT
    public void cellEditable(final int row, final int column, final boolean editable) {
      cellEditable(model, row, column, editable);
    }
  
    @RunsInEDT
    private static void cellEditable(final CustomModel model, final int row, final int column, final boolean editable) {
      execute(new GuiTask() {
        @Override
        protected void executeInEDT() {
          model.cellEditable(row, column, editable);
        }
      });
    }
  
    private static class CustomModel extends DefaultTableModel {
      private final boolean[][] editableCells;
  
      CustomModel(Object[][] data, Object[] columnNames) {
        super(data, columnNames);
        editableCells = new boolean[data.length][data[0].length];
      }
  
      @Override
      public boolean isCellEditable(int row, int column) {
        return editableCells[row][column];
      }
  
      void cellEditable(int row, int column, boolean editable) {
        editableCells[row][column] = editable;
      }
    }
  
    private static class TableTransferHandler extends StringTransferHandler<JTable> {
      TableTransferHandler() {
        super(JTable.class);
      }
  
      @Override
      protected String exportString(JTable table) {
        rows = table.getSelectedRows();
        int colCount = table.getColumnCount();
        StringBuilder b = new StringBuilder();
        for (int i = 0; i < rows.length; i++) {
          for (int j = 0; j < colCount; j++) {
            Object val = table.getValueAt(rows[i], j);
            b.append(val == null ? "" : val.toString());
            if (j != colCount - 1) {
              b.append(",");
            }
          }
          if (i != rows.length - 1) {
            b.append("\n");
          }
        }
        return b.toString();
      }
  
      @Override
      protected void importString(JTable target, String s) {
        DefaultTableModel model = (DefaultTableModel) target.getModel();
        int index = target.getSelectedRow();
        // Prevent the user from dropping data back on itself.
        if (rows != null && index >= rows[0] - 1 && index <= rows[rows.length - 1]) {
          rows = null;
          return;
        }
        int max = model.getRowCount();
        if (index < 0) {
          index = max;
        } else {
          index++;
          if (index > max) {
            index = max;
          }
        }
        addIndex = index;
        String[] values = s.split("\n");
        addCount = values.length;
        int colCount = target.getColumnCount();
        for (int i = 0; i < values.length && i < colCount; i++) {
          model.insertRow(index++, values[i].split(","));
        }
      }
  
      @Override
      protected void cleanup(JTable source, boolean remove) {
        if (remove && rows != null) {
          DefaultTableModel model = (DefaultTableModel) source.getModel();
          // If we are moving items around in the same table, we need to adjust the rows accordingly, since those after
          // the
          // insertion point have moved.
          if (addCount > 0) {
            for (int i = 0; i < rows.length; i++) {
              if (rows[i] > addIndex) {
                rows[i] += addCount;
              }
            }
          }
          for (int i = rows.length - 1; i >= 0; i--) {
            model.removeRow(rows[i]);
          }
        }
      }
    }
  }