Allow drag and drop reordering in project explorer

This commit is contained in:
Bane Stojkovic
2022-12-07 23:43:05 +01:00
parent a9c4f2807f
commit be996d6494
8 changed files with 247 additions and 26 deletions
@@ -342,16 +342,6 @@ public interface IPlugInPort extends ISelectionProcessor, IMouseProcessor, IKeyP
// */ // */
// Rectangle2D getSelectedAreaRect(); // Rectangle2D getSelectedAreaRect();
/**
* Sends each of the selected components one step back.
*/
void sendSelectionToBack();
/**
* Brings each of the selected components one step to front.
*/
void bringSelectionToFront();
/** /**
* Causes the display to refresh. * Causes the display to refresh.
*/ */
@@ -137,5 +137,21 @@ public interface ISelectionProcessor {
* *
* @param model * @param model
*/ */
void applyModelToSelection(String[] model); void applyModelToSelection(String[] model);
/**
* Sends each of the selected components one step back.
*/
void sendSelectionToBack();
/**
* Brings each of the selected components one step to front.
*/
void bringSelectionToFront();
/**
* Move selected components to z index starting from the provided value
* @param zIndex
*/
void moveSelectionToZIndex(int zIndex);
} }
@@ -1946,6 +1946,42 @@ public class Presenter implements IPlugInPort {
messageDispatcher.dispatchMessage(EventType.REPAINT); messageDispatcher.dispatchMessage(EventType.REPAINT);
} }
} }
@Override
public void moveSelectionToZIndex(int zIndex) {
LOG.info(String.format("moveSelectionToZIndex(%d)", zIndex));
Project oldProject = currentProject.clone();
// sort the selection in Z-order
List<IDIYComponent<?>> selection = new ArrayList<IDIYComponent<?>>(selectedComponents);
Collections.sort(selection, new Comparator<IDIYComponent<?>>() {
@Override
public int compare(IDIYComponent<?> o1, IDIYComponent<?> o2) {
return new Integer(currentProject.getComponents().indexOf(o1))
.compareTo(currentProject.getComponents().indexOf(o2));
}
});
for (IDIYComponent<?> component : selection) {
int index = currentProject.getComponents().indexOf(component);
if (index < 0) {
LOG.warn("Component not found in the project: " + component.getName());
} else {
if (index < zIndex)
zIndex--;
currentProject.getComponents().remove(index);
currentProject.getComponents().add(zIndex, component);
}
}
if (!oldProject.equals(currentProject)) {
messageDispatcher.dispatchMessage(EventType.PROJECT_MODIFIED, oldProject, currentProject,
"Change Z-order");
projectFileManager.notifyFileChange();
messageDispatcher.dispatchMessage(EventType.REPAINT);
}
}
@Override @Override
public void refresh() { public void refresh() {
+1
View File
@@ -55,6 +55,7 @@ Box
C-B-E BJT C-B-E BJT
Circle Circle
Coil(s) Coil(s)
Component reordering is possible only when Project Explorer is sorted by z-index
Configuration Configuration
Could not apply changes. Check the log for details. Could not apply changes. Check the log for details.
D-G-S JFET D-G-S JFET
@@ -0,0 +1,129 @@
/*
*
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
*
* This file is part of DIYLC.
*
* DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with DIYLC. If not, see
* <http://www.gnu.org/licenses/>.
*/
package org.diylc.swing.gui;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import javax.swing.DropMode;
import javax.swing.JList;
import javax.swing.TransferHandler;
public class DragDropList<T> extends JList<T> {
private static final long serialVersionUID = 1L;
public DragDropList(IDragDropListListener listener) {
super();
setDragEnabled(true);
setDropMode(DropMode.INSERT);
setTransferHandler(new MyListDropHandler(this, listener));
new MyDragListener(this);
}
}
class MyDragListener implements DragSourceListener, DragGestureListener {
DragDropList<?> list;
DragSource ds = new DragSource();
public MyDragListener(DragDropList<?> list) {
this.list = list;
ds.createDefaultDragGestureRecognizer(list, DnDConstants.ACTION_MOVE, this);
}
public void dragGestureRecognized(DragGestureEvent dge) {
StringSelection transferable = new StringSelection(Integer.toString(list.getSelectedIndex()));
ds.startDrag(dge, DragSource.DefaultMoveDrop, transferable, this);
}
public void dragEnter(DragSourceDragEvent dsde) {}
public void dragExit(DragSourceEvent dse) {}
public void dragOver(DragSourceDragEvent dsde) {}
public void dragDropEnd(DragSourceDropEvent dsde) {
// if (dsde.getDropSuccess()) {
// System.out.println("Succeeded");
// } else {
// System.out.println("Failed");
// }
}
public void dropActionChanged(DragSourceDragEvent dsde) {}
}
class MyListDropHandler extends TransferHandler {
private static final long serialVersionUID = 1L;
private DragDropList<?> dragDropList;
private IDragDropListListener listener;
public MyListDropHandler() {}
public MyListDropHandler(DragDropList<?> dragDropList, IDragDropListListener listener) {
this.dragDropList = dragDropList;
this.listener = listener;
}
public boolean canImport(TransferHandler.TransferSupport support) {
if (!support.isDataFlavorSupported(DataFlavor.stringFlavor)) {
return false;
}
if (support.getComponent() != dragDropList) {
return false;
}
JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
if (dl.getIndex() == -1) {
return false;
} else {
return true;
}
}
public boolean importData(TransferHandler.TransferSupport support) {
if (!canImport(support)) {
return false;
}
Transferable transferable = support.getTransferable();
String indexString;
try {
indexString = (String) transferable.getTransferData(DataFlavor.stringFlavor);
} catch (Exception e) {
return false;
}
int selectedIndex = Integer.parseInt(indexString);
JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
int dropTargetIndex = dl.getIndex();
return listener.dropComplete(selectedIndex, dropTargetIndex);
}
}
@@ -0,0 +1,22 @@
/*
*
* DIY Layout Creator (DIYLC). Copyright (c) 2009-2018 held jointly by the individual authors.
*
* This file is part of DIYLC.
*
* DIYLC is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* DIYLC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with DIYLC. If not, see
* <http://www.gnu.org/licenses/>.
*/
package org.diylc.swing.gui;
public interface IDragDropListListener {
boolean dropComplete(int selectedIndex, int dropTargetIndex);
}
@@ -10,6 +10,7 @@ import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashSet; import java.util.HashSet;
@@ -30,18 +31,26 @@ import org.apache.log4j.Logger;
import org.diylc.common.IPlugInPort; import org.diylc.common.IPlugInPort;
import org.diylc.core.IDIYComponent; import org.diylc.core.IDIYComponent;
import org.diylc.lang.LangUtil; import org.diylc.lang.LangUtil;
import org.diylc.swing.ISwingUI;
import org.diylc.swing.gui.ComponentPopupMenu; import org.diylc.swing.gui.ComponentPopupMenu;
import org.diylc.swing.gui.DragDropList;
import org.diylc.swing.gui.IDragDropListListener;
import org.diylc.swing.gui.SearchTextField; import org.diylc.swing.gui.SearchTextField;
public class ExplorerPane extends JPanel { public class ExplorerPane extends JPanel {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final String REORDERING_NOT_POSSIBLE = LangUtil.translate(
"Component reordering is possible only when Project Explorer is sorted by z-index.");
private static final Logger LOG = Logger.getLogger(ExplorerPane.class); private static final Logger LOG = Logger.getLogger(ExplorerPane.class);
public static Font DEFAULT_FONT = new Font("Square721 BT", Font.PLAIN, 12); public static Font DEFAULT_FONT = new Font("Square721 BT", Font.PLAIN, 12);
private ISwingUI swingUI;
private IPlugInPort plugInPort; private IPlugInPort plugInPort;
private JTextField searchField; private JTextField searchField;
private JScrollPane componentScrollPane; private JScrollPane componentScrollPane;
private ComponentListModel componentListModel; private ComponentListModel componentListModel;
@@ -49,8 +58,9 @@ public class ExplorerPane extends JPanel {
private ComponentPopupMenu popupMenu; private ComponentPopupMenu popupMenu;
private JComboBox<Sort> sortBox; private JComboBox<Sort> sortBox;
public ExplorerPane(IPlugInPort plugInPort) { public ExplorerPane(ISwingUI swingUI, IPlugInPort plugInPort) {
super(); super();
this.swingUI = swingUI;
this.plugInPort = plugInPort; this.plugInPort = plugInPort;
setName("Project Explorer"); setName("Project Explorer");
@@ -64,14 +74,6 @@ public class ExplorerPane extends JPanel {
gbc.gridwidth = 1; gbc.gridwidth = 1;
add(getSearchField(), gbc); add(getSearchField(), gbc);
gbc.gridy++;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 0;
gbc.weighty = 0;
add(getSortBox(), gbc);
gbc.gridy++; gbc.gridy++;
@@ -81,6 +83,14 @@ public class ExplorerPane extends JPanel {
add(getComponentScrollPane(), gbc); add(getComponentScrollPane(), gbc);
gbc.gridy++;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 0;
gbc.weighty = 0;
add(getSortBox(), gbc);
setPreferredSize(new Dimension(180, 200)); setPreferredSize(new Dimension(180, 200));
} }
@@ -117,7 +127,18 @@ public class ExplorerPane extends JPanel {
public JList<IDIYComponent<?>> getComponentList() { public JList<IDIYComponent<?>> getComponentList() {
if (componentList == null) { if (componentList == null) {
componentList = new JList<IDIYComponent<?>>(); componentList = new DragDropList<IDIYComponent<?>>(new IDragDropListListener() {
@Override
public boolean dropComplete(int selectedIndex, int dropTargetIndex) {
if (getComponentListModel().getSort() != Sort.Z_INDEX) {
swingUI.showMessage(REORDERING_NOT_POSSIBLE, "Error", ISwingUI.ERROR_MESSAGE);
return false;
}
plugInPort.moveSelectionToZIndex(getComponentListModel().getSize() - dropTargetIndex);
return true;
}
});
componentList.setModel(getComponentListModel()); componentList.setModel(getComponentListModel());
componentList.setFont(DEFAULT_FONT); componentList.setFont(DEFAULT_FONT);
componentList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); componentList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
@@ -183,8 +204,10 @@ public class ExplorerPane extends JPanel {
return popupMenu; return popupMenu;
} }
public void setComponents(List<IDIYComponent<?>> components) { public void setComponents(List<IDIYComponent<?>> components,
Collection<IDIYComponent<?>> selectedComponents) {
this.getComponentListModel().setComponents(components); this.getComponentListModel().setComponents(components);
setSelection(new HashSet<IDIYComponent<?>>(selectedComponents));
} }
public void setSelection(Set<IDIYComponent<?>> selectedComponents) { public void setSelection(Set<IDIYComponent<?>> selectedComponents) {
@@ -230,7 +253,7 @@ public class ExplorerPane extends JPanel {
private List<IDIYComponent<?>> components; private List<IDIYComponent<?>> components;
private String searchText; private String searchText;
private Sort sort; private Sort sort = Sort.Z_INDEX;
public void setComponents(List<IDIYComponent<?>> components) { public void setComponents(List<IDIYComponent<?>> components) {
this.componentsRaw = components; this.componentsRaw = components;
@@ -243,6 +266,10 @@ public class ExplorerPane extends JPanel {
return components; return components;
} }
public Sort getSort() {
return sort;
}
public void setSort(Sort sort) { public void setSort(Sort sort) {
this.sort = sort; this.sort = sort;
@@ -64,10 +64,10 @@ public class ExplorerPlugin implements IPlugIn {
public void processMessage(EventType eventType, Object... params) { public void processMessage(EventType eventType, Object... params) {
switch (eventType) { switch (eventType) {
case PROJECT_MODIFIED: case PROJECT_MODIFIED:
getExplorerPane().setComponents(((Project)params[1]).getComponents()); getExplorerPane().setComponents(((Project)params[1]).getComponents(), plugInPort.getSelectedComponents());
break; break;
case PROJECT_LOADED: case PROJECT_LOADED:
getExplorerPane().setComponents(((Project)params[0]).getComponents()); getExplorerPane().setComponents(((Project)params[0]).getComponents(), plugInPort.getSelectedComponents());
break; break;
case SELECTION_CHANGED: case SELECTION_CHANGED:
getExplorerPane().setSelection((Set<IDIYComponent<?>>)params[0]); getExplorerPane().setSelection((Set<IDIYComponent<?>>)params[0]);
@@ -103,7 +103,7 @@ public class ExplorerPlugin implements IPlugIn {
public ExplorerPane getExplorerPane() { public ExplorerPane getExplorerPane() {
if (explorerPane == null) { if (explorerPane == null) {
explorerPane = new ExplorerPane(plugInPort); explorerPane = new ExplorerPane(swingUI, plugInPort);
} }
return explorerPane; return explorerPane;
} }