diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgMqUnAppliedPatchesPanel.java b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgMqUnAppliedPatchesPanel.java index f8d44b0071ba..cadf613b6989 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgMqUnAppliedPatchesPanel.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgMqUnAppliedPatchesPanel.java @@ -30,17 +30,12 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.PopupHandler; -import com.intellij.ui.RowsDnDSupport; import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.TableSpeedSearch; import com.intellij.ui.table.JBTable; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.ui.EditableModel; -import org.jetbrains.annotations.CalledInAwt; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.*; import org.zmlx.hg4idea.HgUpdater; import org.zmlx.hg4idea.HgVcs; import org.zmlx.hg4idea.command.mq.HgQDeleteCommand; @@ -96,8 +91,10 @@ public class HgMqUnAppliedPatchesPanel extends JPanel implements DataProvider, H myPatchTable.setFillsViewportHeight(true); myPatchTable.getEmptyText().setText("Nothing to show"); myPatchTable.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0), START_EDITING); - RowsDnDSupport.install(myPatchTable, myPatchTable.getModel()); + myPatchTable.setDragEnabled(true); new TableSpeedSearch(myPatchTable); + myPatchTable.setDropMode(DropMode.INSERT_ROWS); + myPatchTable.setTransferHandler(new TableRowsTransferHandler(myPatchTable)); add(createToolbar(), BorderLayout.WEST); @@ -201,7 +198,13 @@ public class HgMqUnAppliedPatchesPanel extends JPanel implements DataProvider, H @NotNull @CalledInAwt public List getSelectedPatchNames() { - return ContainerUtil.map(Ints.asList(myPatchTable.getSelectedRows()), new Function() { + return getPatchNames(myPatchTable.getSelectedRows()); + } + + @NotNull + @CalledInAny + private List getPatchNames(int[] rows) { + return ContainerUtil.map(Ints.asList(rows), new Function() { @Override public String fun(Integer integer) { return getPatchName(integer); @@ -285,7 +288,7 @@ public class HgMqUnAppliedPatchesPanel extends JPanel implements DataProvider, H model.updatePatches(myRepository.getUnappliedPatchNames()); } - private class MyPatchModel extends AbstractTableModel implements EditableModel { + private class MyPatchModel extends AbstractTableModel implements MultiReorderedModel { @NotNull private final MqPatchDetails.MqPatchEnum[] myColumnNames = MqPatchDetails.MqPatchEnum.values(); @NotNull private final Map myPatchesWithDetails = ContainerUtil.newHashMap(); @@ -349,30 +352,6 @@ public class HgMqUnAppliedPatchesPanel extends JPanel implements DataProvider, H myPatches.set(rowIndex, newPatchName); } - @Override - public void addRow() { - throw new UnsupportedOperationException(); - } - - @Override - public void exchangeRows(int oldIndex, int newIndex) { - String tmp = myPatches.get(oldIndex); - myPatches.remove(oldIndex); - myPatches.add(newIndex, tmp); - myNeedToUpdateFileContent = true; - fireTableDataChanged(); - } - - @Override - public boolean canExchangeRows(int oldIndex, int newIndex) { - return true; - } - - @Override - public void removeRow(int idx) { - throw new UnsupportedOperationException(); - } - public void updatePatches(List newNames) { myPatches.clear(); myPatches.addAll(newNames); @@ -380,6 +359,25 @@ public class HgMqUnAppliedPatchesPanel extends JPanel implements DataProvider, H readMqPatchesDetails(); fireTableDataChanged(); } + + @Override + public boolean canMoveRows() { + return true; + } + + @Override + public int[] moveRows(int[] rowsIndexes, int destination) { + List names = getPatchNames(rowsIndexes); + myPatches.removeAll(ContainerUtil.newArrayList(names)); + int[] selection = new int[rowsIndexes.length]; + for (int i = 0; i < rowsIndexes.length; i++) { + selection[i] = destination; + myPatches.add(destination++, names.get(i)); + } + myNeedToUpdateFileContent = true; + fireTableDataChanged(); + return selection; + } } private class MyPatchTable extends JBTable { diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/MultiReorderedModel.java b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/MultiReorderedModel.java new file mode 100644 index 000000000000..0dd44b4b8f24 --- /dev/null +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/MultiReorderedModel.java @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2015 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 org.zmlx.hg4idea.ui; + +/** + * Interface for a Table components to allow multiSelection drag and drop + */ +public interface MultiReorderedModel { + + + /** + * @return is rows drag and drop possible + */ + boolean canMoveRows(); + + /** + * Reorder component rows + * + * @param rowsIndexes source array to drag + * @param destination destination index, already updated according to rowsToMove indexes before/after destination + * @return new rows indexes to select + */ + int[] moveRows(int[] rowsIndexes, int destination); +} diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/TableRowsTransferHandler.java b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/TableRowsTransferHandler.java new file mode 100644 index 000000000000..6830c77f5df1 --- /dev/null +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/TableRowsTransferHandler.java @@ -0,0 +1,98 @@ +/* + * Copyright 2000-2015 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 org.zmlx.hg4idea.ui; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.ui.TableUtil; + +import javax.activation.ActivationDataFlavor; +import javax.activation.DataHandler; +import javax.swing.*; +import javax.swing.table.TableModel; +import java.awt.*; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DragSource; + +public class TableRowsTransferHandler extends TransferHandler { + private static final Logger LOG = Logger.getInstance(TableRowsTransferHandler.class); + private final DataFlavor myDataFlavor = new ActivationDataFlavor(RowsDragInfo.class, DataFlavor.stringFlavor.getMimeType()); + private JTable myTable = null; + + public TableRowsTransferHandler(JTable table) { + myTable = table; + } + + @Override + protected Transferable createTransferable(JComponent c) { + assert (c == myTable); + return new DataHandler(new RowsDragInfo(myTable.getSelectedRows()), myDataFlavor.getMimeType()); + } + + @Override + public boolean canImport(TransferHandler.TransferSupport support) { + boolean canImport = support.getComponent() == myTable && support.isDrop(); + myTable.setCursor(canImport ? DragSource.DefaultMoveDrop : DragSource.DefaultMoveNoDrop); + return canImport; + } + + @Override + public int getSourceActions(JComponent c) { + return TransferHandler.COPY_OR_MOVE; + } + + @Override + public boolean importData(TransferHandler.TransferSupport support) { + TableModel tableModel = myTable.getModel(); + if (!(tableModel instanceof MultiReorderedModel) || !((MultiReorderedModel)tableModel).canMoveRows()) return false; + + JTable.DropLocation dl = (JTable.DropLocation)support.getDropLocation(); + int index = dl.getRow(); + int max = tableModel.getRowCount(); + if (index < 0 || index > max) { + index = max; + } + myTable.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + + try { + int[] rows = ((RowsDragInfo)support.getTransferable().getTransferData(myDataFlavor)).myRows; + if (rows != null && rows.length > 0) { + int dist = 0; + for (int row : rows) { + if (index > row) { + dist++; + } + } + index -= dist; + int[] newSelection = ((MultiReorderedModel)tableModel).moveRows(rows, index); + TableUtil.selectRows(myTable, newSelection); + return true; + } + } + catch (Exception e) { + LOG.error("Couldn't move transferred data."); + } + return false; + } + + private static class RowsDragInfo { + final int[] myRows; + + public RowsDragInfo(int[] rows) { + myRows = rows; + } + } +} \ No newline at end of file