fix copy paste groups

This commit is contained in:
Bane Stojkovic
2026-01-19 23:15:46 +01:00
parent 457f47782f
commit be16910767
6 changed files with 69 additions and 11 deletions
@@ -57,9 +57,16 @@ public class ComponentTransferableFactory {
.filter(Objects::nonNull)
.collect(Collectors.toList());
Set<ComponentGroup> clonedGroups = groups.stream().map(group ->
new ComponentGroup(group.getComponentIds().stream()
.map(idMap::get).collect(Collectors.toSet()), group.getName()))
Set<ComponentGroup> clonedGroups = groups.stream()
.map(group -> {
Set<UUID> newIds = group.getComponentIds().stream()
.map(idMap::get)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
// Only create group if it has at least one valid ID
return newIds.isEmpty() ? null : new ComponentGroup(newIds, group.getName());
})
.filter(Objects::nonNull)
.collect(Collectors.toSet());
return new ComponentTransferable(clonedComponents, clonedGroups);
@@ -22,8 +22,11 @@ public class ComponentGroup implements Serializable {
}
public static ComponentGroup from(Collection<IDIYComponent<?>> components, String name) {
return new ComponentGroup(components.stream()
.map(IDIYComponent::getId).collect(Collectors.toSet()), name);
Set<UUID> componentIds = components.stream()
.map(IDIYComponent::getId)
.filter(id -> id != null)
.collect(Collectors.toSet());
return new ComponentGroup(componentIds, name);
}
public Set<UUID> getComponentIds() {
@@ -366,7 +366,14 @@ public class Project implements Serializable, Cloneable {
}
for (ComponentGroup group : this.getGroupsEx()) {
project.getGroupsEx().add(new ComponentGroup(group.getComponentIds(), group.getName()));
// Filter out null IDs when cloning groups
Set<UUID> validIds = group.getComponentIds().stream()
.filter(id -> id != null)
.collect(Collectors.toSet());
// Only add group if it has valid component IDs
if (!validIds.isEmpty()) {
project.getGroupsEx().add(new ComponentGroup(validIds, group.getName()));
}
}
for (IDIYComponent<?> component : this.getLockedComponents()) {
@@ -34,6 +34,7 @@ import org.diylc.clipboard.ComponentTransferable;
import org.diylc.common.*;
import org.diylc.core.Angle;
import org.diylc.core.ComponentGroup;
import org.diylc.core.CreationMethod;
import org.diylc.core.IDIYComponent;
import org.diylc.core.Project;
@@ -219,9 +220,14 @@ public class InstantiationManager {
// Update the location according to mouse location
updateSingleClick(scaledPoint, snapToGrid, gridSpacing);
// copy group information if available
// copy group information if available, but filter out invalid groups
if (componentTransferable.getGroups() != null) {
currentProject.getGroupsEx().addAll(componentTransferable.getGroups());
for (ComponentGroup group : componentTransferable.getGroups()) {
if (group.getComponentIds() != null && !group.getComponentIds().isEmpty() &&
group.getComponentIds().stream().anyMatch(id -> id != null)) {
currentProject.getGroupsEx().add(group);
}
}
}
}
@@ -278,6 +278,8 @@ public class Presenter implements IPlugInPort {
drawingManager.clearContinuityArea();
DrawingCache.Instance.clear();
updateSelection(EMPTY_SELECTION);
// Clean up any invalid groups that may have been loaded
cleanupInvalidGroups();
messageDispatcher.dispatchMessage(EventType.PROJECT_LOADED, project, freshStart, filename);
messageDispatcher.dispatchMessage(EventType.REPAINT);
messageDispatcher.dispatchMessage(EventType.LAYER_STATE_CHANGED, currentProject.getLockedLayers());
@@ -543,7 +545,11 @@ 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, componentTypeSlot.getName()));
ComponentGroup group = ComponentGroup.from(componentSlot, componentTypeSlot.getName());
// Only add group if it has valid component IDs
if (group.getComponentIds() != null && !group.getComponentIds().isEmpty()) {
this.currentProject.getGroupsEx().add(group);
}
}
notifyProjectModifiedIfNeeded(oldProject, "Add " + componentTypeSlot.getName(), true, true);
@@ -1717,6 +1723,10 @@ public class Presenter implements IPlugInPort {
@Override
public void groupSelectedComponents() {
LOG.info("groupSelectedComponents()");
if (selectedComponents == null || selectedComponents.size() < 2) {
return;
}
// Prompt user for group name
String groupName = view.showInputDialog("Enter group name:", "Group Components");
@@ -1739,9 +1749,11 @@ public class Presenter implements IPlugInPort {
.filter(id -> id != null)
.collect(Collectors.toSet());
// Only create the group if there are valid component IDs
// Only create the group if there are valid component IDs
if (!componentIds.isEmpty()) {
currentProject.getGroupsEx().add(new ComponentGroup(componentIds, groupName));
} else {
LOG.warn("Cannot create group: all selected components have null IDs");
}
// Notify the listeners.
notifyProjectModifiedIfNeeded(oldProject, "Group", false, true);
@@ -2197,12 +2209,31 @@ public class Presenter implements IPlugInPort {
* @param components
*/
private void ungroupComponents(Collection<IDIYComponent<?>> components) {
Set<UUID> componentIds = components.stream().map(IDIYComponent::getId).collect(Collectors.toSet());
Set<UUID> componentIds = components.stream()
.map(IDIYComponent::getId)
.filter(id -> id != null)
.collect(Collectors.toSet());
// Remove the group if it contains any of the specified components
currentProject.getGroupsEx().removeIf(
group -> group.getComponentIds() != null && group.getComponentIds().stream()
.anyMatch(id -> id != null && componentIds.contains(id)));
}
/**
* Removes invalid groups (groups with null IDs or empty sets) from the project.
* This should be called periodically to clean up corrupted groups.
*/
private void cleanupInvalidGroups() {
int initialSize = currentProject.getGroupsEx().size();
currentProject.getGroupsEx().removeIf(group ->
group.getComponentIds() == null ||
group.getComponentIds().isEmpty() ||
group.getComponentIds().stream().allMatch(id -> id == null));
int removed = initialSize - currentProject.getGroupsEx().size();
if (removed > 0) {
LOG.warn("Removed " + removed + " invalid group(s) with null or empty component IDs");
}
}
/**
* Finds all components that are grouped with the specified component. This should be called any
@@ -573,6 +573,10 @@
<changeType>NEW_FEATURE</changeType>
<description>Added E-C-B BJT pinout to TO-92 transistor package</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>BUG_FIX</changeType>
<description>Fixed the performance issue that happens when groups of components are copy-pasted and the project size grows uncontrollably</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>BUG_FIX</changeType>
<description>'Tactile Micro Switch' editor doesn't show up on double click</description>