Group naming added

This commit is contained in:
Bane Stojkovic
2026-01-08 22:16:30 +01:00
parent a8e8e72458
commit a7bb1b02bf
7 changed files with 78 additions and 30 deletions
@@ -46,14 +46,16 @@ public class ComponentTransferable implements Transferable, Serializable {
private List<IDIYComponent<?>> components;
private Set<ComponentGroup> groups;
private String name;
public ComponentTransferable() {
super();
}
public ComponentTransferable(List<IDIYComponent<?>> components) {
public ComponentTransferable(List<IDIYComponent<?>> components, String name) {
super();
this.components = components;
this.name = name;
this.groups = null;
}
@@ -88,4 +90,8 @@ public class ComponentTransferable implements Transferable, Serializable {
public Set<ComponentGroup> getGroups() {
return groups;
}
public String getName() {
return name;
}
}
@@ -1,12 +1,13 @@
package org.diylc.core;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
public class ComponentGroup {
public class ComponentGroup implements Serializable {
private Set<UUID> componentIds;
private String name;
@@ -20,9 +21,9 @@ public class ComponentGroup {
this.name = name;
}
public static ComponentGroup from(Collection<IDIYComponent<?>> components) {
public static ComponentGroup from(Collection<IDIYComponent<?>> components, String name) {
return new ComponentGroup(components.stream()
.map(IDIYComponent::getId).collect(Collectors.toSet()));
.map(IDIYComponent::getId).collect(Collectors.toSet()), name);
}
public Set<UUID> getComponentIds() {
@@ -164,7 +164,7 @@ public class Project implements Serializable, Cloneable {
if (groups != null && !groups.isEmpty()) {
for (Set<IDIYComponent<?>> group : groups) {
ComponentGroup newGroup = ComponentGroup.from(group);
ComponentGroup newGroup = ComponentGroup.from(group, null);
groupsEx.add(newGroup);
}
groups.clear();
@@ -296,6 +296,11 @@ public class Project implements Serializable, Cloneable {
return false;
} else if (!groups.equals(other.groups))
return false;
if (groupsEx == null) {
if (other.groupsEx != null)
return false;
} else if (!groupsEx.equals(other.groupsEx))
return false;
if (lockedLayers == null) {
if (other.lockedLayers != null)
return false;
@@ -24,13 +24,7 @@ package org.diylc.presenter;
import java.awt.geom.Point2D;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
import org.apache.log4j.Logger;
import org.diylc.appframework.miscutils.ConfigurationManager;
@@ -68,9 +62,9 @@ public class InstantiationManager {
public static final ComponentType clipboardType = new ComponentType("Clipboard contents",
"Components from the clipboard", CreationMethod.SINGLE_CLICK, "Multi", "", "", null, null, 0, false, null,
false, null, KeywordPolicy.NEVER_SHOW, null, false, null, 0);
public static final ComponentType blockType = new ComponentType("Building block",
"Components from the building block", CreationMethod.SINGLE_CLICK, "Multi", "", "", null, null, 0, false, null,
false, null, KeywordPolicy.NEVER_SHOW, null, false, null, 0);
// public static final ComponentType blockType = new ComponentType("Building block",
// "Components from the building block", CreationMethod.SINGLE_CLICK, "Multi", "", "", null, null, 0, false, null,
// false, null, KeywordPolicy.NEVER_SHOW, null, false, null, 0);
public InstantiationManager() {}
@@ -213,7 +207,10 @@ public class InstantiationManager {
// Update the component type slot so the app knows that something's
// being instantiated.
this.componentTypeSlot = autoGroup ? blockType : clipboardType;
String slotName = Optional.ofNullable(componentTransferable.getName()).orElse("Building Block");
this.componentTypeSlot = autoGroup ? new ComponentType(slotName,
"Components from the building block", CreationMethod.SINGLE_CLICK, "Multi", "", "", null, null, 0, false, null,
false, null, KeywordPolicy.NEVER_SHOW, null, false, null, 0) : clipboardType;
if (snapToGrid) {
scaledPoint = new Point2D.Double(scaledPoint.getX(), scaledPoint.getY());
@@ -543,7 +543,7 @@ public class Presenter implements IPlugInPort {
// group components if there's more than one, e.g. building blocks, but not clipboard
// contents
if (componentSlot.size() > 1 && !componentTypeSlot.getName().toLowerCase().contains("clipboard")) {
this.currentProject.getGroupsEx().add(ComponentGroup.from(componentSlot));
this.currentProject.getGroupsEx().add(ComponentGroup.from(componentSlot, componentTypeSlot.getName()));
}
notifyProjectModifiedIfNeeded(oldProject, "Add " + componentTypeSlot.getName(), true, true);
@@ -1717,11 +1717,32 @@ public class Presenter implements IPlugInPort {
@Override
public void groupSelectedComponents() {
LOG.info("groupSelectedComponents()");
// Prompt user for group name
String groupName = view.showInputDialog("Enter group name:", "Group Components");
// If user cancelled, don't create the group
if (groupName == null) {
return;
}
Project oldProject = currentProject.clone();
// First remove the selected components from other groups.
// First break any existing groups that contain any of the selected components.
// This ensures that if components A and B are in a group, and the user selects
// A, B, and C to group together, the old group of A and B is deleted and replaced
// with a new group containing A, B, and C.
ungroupComponents(selectedComponents);
// Then group them together.
currentProject.getGroupsEx().add(ComponentGroup.from(selectedComponents));
// Then create a new group containing all selected components with the provided name.
// Filter out any null IDs to prevent creating groups with null component IDs.
Set<UUID> componentIds = selectedComponents.stream()
.map(IDIYComponent::getId)
.filter(id -> id != null)
.collect(Collectors.toSet());
// Only create the group if there are valid component IDs
if (!componentIds.isEmpty()) {
currentProject.getGroupsEx().add(new ComponentGroup(componentIds, groupName));
}
// Notify the listeners.
notifyProjectModifiedIfNeeded(oldProject, "Group", false, true);
}
@@ -2180,7 +2201,20 @@ public class Presenter implements IPlugInPort {
Iterator<ComponentGroup> groupIterator = currentProject.getGroupsEx().iterator();
while (groupIterator.hasNext()) {
ComponentGroup group = groupIterator.next();
if (group.getComponentIds().stream().anyMatch(id -> componentIds.contains(componentIds))) {
// Remove the group if it contains any of the specified components
if (group.getComponentIds() != null &&
group.getComponentIds().stream().anyMatch(id -> id != null && componentIds.contains(id))) {
groupIterator.remove();
}
}
// Clean up any groups with null or empty component IDs
groupIterator = currentProject.getGroupsEx().iterator();
while (groupIterator.hasNext()) {
ComponentGroup group = groupIterator.next();
if (group.getComponentIds() == null ||
group.getComponentIds().isEmpty() ||
group.getComponentIds().stream().anyMatch(id -> id == null)) {
groupIterator.remove();
}
}
@@ -2197,14 +2231,14 @@ public class Presenter implements IPlugInPort {
private Set<IDIYComponent<?>> findAllGroupedComponents(IDIYComponent<?> component) {
for (ComponentGroup group : currentProject.getGroupsEx()) {
if (group.getComponentIds().stream().anyMatch(id -> id.equals(component.getId()))) {
if (group.getComponentIds().stream().anyMatch(id -> Objects.equals(id, component.getId()))) {
return currentProject.getComponents().stream()
.filter(comp -> group.getComponentIds().contains(comp.getId()))
.collect(Collectors.toSet());
}
}
return new HashSet<>();
return new HashSet<>(Set.of(component));
}
@Override
@@ -2738,7 +2772,7 @@ public class Presenter implements IPlugInPort {
@Override
public void loadBlock(String blockName) throws InvalidBlockException {
List<IDIYComponent<?>> components = buildingBlockManager.loadBlock(blockName, currentProject.getComponents());
pasteComponents(new ComponentTransferable(components), true, true);
pasteComponents(new ComponentTransferable(components, blockName), true, true);
}
@Override
@@ -113,7 +113,7 @@ public class ImportNetlistAction extends AbstractAction {
if (!outputWarnings.isEmpty())
ActionFactory.LOG.warn("Component creation produced warnings:\n"
+ String.join("\n", outputWarnings));
plugInPort.pasteComponents(new ComponentTransferable(components), false, false);
plugInPort.pasteComponents(new ComponentTransferable(components, "Imported Netlist"), false, false);
}
} catch (Exception e) {
swingUI.showMessage("Could not import netlist file: " + e.getMessage(), "Error",
@@ -130,4 +130,4 @@ public class ImportNetlistAction extends AbstractAction {
}, true);
}
}
}
}
@@ -635,13 +635,18 @@ public class ExplorerPane extends JPanel {
}
}
String text = groupItem.getGroupName() != null && !groupItem.getGroupName().isEmpty()
// Format: name (component count), similar to regular components showing name (value)
String groupName = groupItem.getGroupName() != null && !groupItem.getGroupName().isEmpty()
? groupItem.getGroupName()
: "Group of " + groupItem.getComponentCount() + " components";
: "Group";
String componentCount = String.valueOf(groupItem.getComponentCount());
if (isSelected) {
renderer.setText(String.format("<html>[L%s] <b>%s</b></html>", maxLayerId, text));
renderer.setText(String.format("<html>[L%s] <b>%s</b> (<b>%s</b>)</html>", maxLayerId, groupName, componentCount));
} else {
renderer.setText(String.format("<html><font color='#c0c0c0'>[L%s]</font> %s</html>", maxLayerId, text));
renderer.setText(String.format(
"<html><font color='#c0c0c0'>[L%s]</font> %s (<font color='#666666'>%s</font>)</html>",
maxLayerId, groupName, componentCount));
}
}