Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plant Hierarchy inconsistency prevention when deleting subapp #1101

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ Require-Bundle: org.eclipse.core.resources,
org.eclipse.ui.ide,
org.eclipse.ui.views.properties.tabbed,
org.eclipse.fordiac.ide.model.commands,
org.eclipse.gef
org.eclipse.gef,
org.eclipse.ltk.core.refactoring
Bundle-Vendor: Eclipse 4diac Project
Automatic-Module-Name: org.eclipse.fordiac.ide.hierarchymanager.ui
Bundle-RequiredExecutionEnvironment: JavaSE-21
Expand Down
23 changes: 23 additions & 0 deletions plugins/org.eclipse.fordiac.ide.hierarchymanager.ui/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -278,4 +278,27 @@
point="org.eclipse.fordiac.ide.model.commands.QualNameChangeListener">
<listener class = "org.eclipse.fordiac.ide.hierarchymanager.ui.listeners.HierachyManagerUpdateListener"/>
</extension>
<extension
point="org.eclipse.ltk.core.refactoring.deleteParticipants">
<deleteParticipant
class="org.eclipse.fordiac.ide.hierarchymanager.ui.refactoring.DeleteLibraryElementParticipant"
id="org.eclipse.fordiac.ide.hierarchymanager.ui.deleteLibraryElementParticipant"
name="deletePlantElement">
<enablement>
<and>
<instanceof value="org.eclipse.core.resources.IFile"/>
<or>
<test
forcePluginActivation="true"
property="org.eclipse.core.resources.extension"
value="sys"/>
<test
forcePluginActivation="true"
property="org.eclipse.core.resources.extension"
value="sub"/>
</or>
</and>
</enablement>
</deleteParticipant>
</extension>
</plugin>
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,28 @@
import org.eclipse.emf.ecore.xmi.impl.XMLMapImpl;
import org.eclipse.fordiac.ide.hierarchymanager.model.hierarchy.HierarchyPackage;
import org.eclipse.fordiac.ide.hierarchymanager.model.hierarchy.Leaf;
import org.eclipse.fordiac.ide.hierarchymanager.model.hierarchy.Level;
import org.eclipse.fordiac.ide.hierarchymanager.model.hierarchy.RootLevel;
import org.eclipse.fordiac.ide.hierarchymanager.model.hierarchy.util.HierarchyResourceFactoryImpl;
import org.eclipse.fordiac.ide.hierarchymanager.ui.handlers.AbstractHierarchyHandler;
import org.eclipse.fordiac.ide.hierarchymanager.ui.operations.AbstractChangeHierarchyOperation;
import org.eclipse.fordiac.ide.hierarchymanager.ui.operations.AddLeafOperation;
import org.eclipse.fordiac.ide.hierarchymanager.ui.operations.DeleteNodeOperation;
import org.eclipse.fordiac.ide.hierarchymanager.ui.operations.UpdateLeafRefOperation;
import org.eclipse.fordiac.ide.hierarchymanager.ui.util.HierarchyManagerUtil;
import org.eclipse.fordiac.ide.hierarchymanager.ui.view.PlantHierarchyView;
import org.eclipse.fordiac.ide.model.commands.QualNameChange;
import org.eclipse.fordiac.ide.model.commands.QualNameChangeListener;
import org.eclipse.fordiac.ide.model.libraryElement.INamedElement;
import org.eclipse.fordiac.ide.model.libraryElement.SubApp;
import org.eclipse.fordiac.ide.model.libraryElement.UntypedSubApp;
import org.eclipse.fordiac.ide.model.typelibrary.TypeEntry;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;

public class HierachyManagerUpdateListener extends QualNameChangeListener {

private static EObject loadPlantHierachy(final IProject project) {
public static EObject loadPlantHierachy(final IProject project) {
final Map<String, Object> loadOptions = new HashMap<>();
final ResourceSet hierarchyResouceSet = new ResourceSetImpl();
hierarchyResouceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put( //
Expand All @@ -61,6 +65,8 @@ private static EObject loadPlantHierachy(final IProject project) {
return PlantHierarchyView.loadHierachyForProject(project, hierarchyResouceSet, loadOptions);
}

private final HashMap<String, List<AbstractOperation>> undoDeleteOperations = new HashMap<>();

@Override
public List<AbstractOperation> constructExecutableUndoOperations(final QualNameChange change, final Object o) {
return constructOperation(change, o, true);
Expand All @@ -73,22 +79,37 @@ protected List<AbstractOperation> constructExecutableOperations(final QualNameCh
return constructOperation(qualNameChange, rootLevel, false);
}

protected static List<AbstractOperation> constructOperation(final QualNameChange qualNameChange,
final Object rootLevel, final boolean isUndo) {
protected List<AbstractOperation> constructOperation(final QualNameChange qualNameChange, final Object rootLevel,
final boolean isUndo) {

if (qualNameChange.state() == QualNameChangeState.DELETE_UNDO
&& qualNameChange.notifier() instanceof final SubApp sub) {

return undoDeleteOperations.remove(qualNameChange.oldQualName());
}

final String identifier = isUndo ? qualNameChange.newQualName() : qualNameChange.oldQualName();

final List<AbstractOperation> result = new ArrayList<>();

final List<Leaf> leafs = HierarchyManagerUtil.searchLeaf((RootLevel) rootLevel,
leafRef -> leafRef.contains(identifier));
leaf -> leaf.getRef().contains(identifier));

if (leafs == null || leafs.isEmpty()) {
return Collections.emptyList(); // leaf may have been deleted in the meantime
}

final String newRef = isUndo ? qualNameChange.oldQualName() : qualNameChange.newQualName();

for (final Leaf leaf : leafs) {
result.add(new UpdateLeafRefOperation(leaf, newRef, identifier));
if (qualNameChange.state() == QualNameChangeState.DELETE
|| qualNameChange.state() == QualNameChangeState.DELETE_REDO) {

result.add(new DeleteNodeOperation(leaf));

storeUndoDeleteOperations(qualNameChange.oldQualName(), leaf);
} else {
result.add(new UpdateLeafRefOperation(leaf, newRef, identifier));
}
}

return result;
Expand All @@ -104,7 +125,7 @@ protected void executeOperation(final AbstractOperation op) {
AbstractHierarchyHandler.executeOperation((AbstractChangeHierarchyOperation) op);
}

private static RootLevel getPlantHierachy(final TypeEntry key) {
public static RootLevel getPlantHierachy(final TypeEntry key) {
final IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
if (page != null) {
final PlantHierarchyView view = (PlantHierarchyView) page
Expand All @@ -122,4 +143,10 @@ protected boolean isEnabled(final INamedElement element) {
return element instanceof UntypedSubApp;
}

protected void storeUndoDeleteOperations(final String qualName, final Leaf leaf) {
final AddLeafOperation op = new AddLeafOperation((Level) leaf.eContainer(), leaf);

undoDeleteOperations.computeIfAbsent(qualName, k -> new ArrayList<>()).add(op);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*******************************************************************************
* Copyright (c) 2025 Primetals Technologies Austria GmbH
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Qemal Alliu - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.fordiac.ide.hierarchymanager.ui.operations;

import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.fordiac.ide.hierarchymanager.model.hierarchy.Leaf;
import org.eclipse.fordiac.ide.hierarchymanager.model.hierarchy.Level;

public class AddLeafOperation extends AbstractChangeHierarchyOperation {

private final Level level;
private final Leaf leaf;

public AddLeafOperation(final Level level, final Leaf leaf) {
super("Add a leaf to a level");
this.level = level;
this.leaf = leaf;
}

@Override
public IStatus execute(final IProgressMonitor monitor, final IAdaptable info) throws ExecutionException {
level.getChildren().add(leaf);
saveHierarchy(level, monitor);

return Status.OK_STATUS;
}

@Override
public IStatus redo(final IProgressMonitor monitor, final IAdaptable info) throws ExecutionException {
level.getChildren().add(leaf);
saveHierarchy(level, monitor);

return Status.OK_STATUS;
}

@Override
public IStatus undo(final IProgressMonitor monitor, final IAdaptable info) throws ExecutionException {
level.getChildren().remove(leaf);
saveHierarchy(level, monitor);

return Status.OK_STATUS;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,18 @@ public IStatus execute(final IProgressMonitor monitor, final IAdaptable info) th
return Status.OK_STATUS;
}

private int getParentIndex() {
final EList<? extends Node> parentContainer = getParentContainer();
if (parentContainer != null) {
return parentContainer.indexOf(node);
@Override
public IStatus undo(final IProgressMonitor monitor, final IAdaptable info) throws ExecutionException {
// for adding we can not use getParentContainer as the root node has levels and
// not nodes
if (parent instanceof final RootLevel root) {
root.getLevels().add(index, (Level) node);
}
return -1;
if (parent instanceof final Level level) {
level.getChildren().add(index, node);
}
saveHierarchy(parent, monitor);
return Status.OK_STATUS;
}

@Override
Expand All @@ -58,24 +64,19 @@ public IStatus redo(final IProgressMonitor monitor, final IAdaptable info) throw
return Status.OK_STATUS;
}

private void removeFromParent() {
private int getParentIndex() {
final EList<? extends Node> parentContainer = getParentContainer();
if (parentContainer != null && index != -1) {
parentContainer.remove(index);
if (parentContainer != null) {
return parentContainer.indexOf(node);
}
return -1;
}

@Override
public IStatus undo(final IProgressMonitor monitor, final IAdaptable info) throws ExecutionException {
// for adding we can not use getParentContainer as the root node has levels and not nodes
if (parent instanceof final RootLevel root) {
root.getLevels().add(index, (Level) node);
}
if (parent instanceof final Level level) {
level.getChildren().add(index, node);
private void removeFromParent() {
final EList<? extends Node> parentContainer = getParentContainer();
if (parentContainer != null && index != -1) {
parentContainer.remove(index);
}
saveHierarchy(parent, monitor);
return Status.OK_STATUS;
}

private EList<? extends Node> getParentContainer() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*******************************************************************************
* Copyright (c) 2025 Primetals Technologies Austria GmbH
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Qemal Alliu - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.fordiac.ide.hierarchymanager.ui.refactoring;

import java.util.List;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.fordiac.ide.hierarchymanager.model.hierarchy.Leaf;
import org.eclipse.fordiac.ide.hierarchymanager.model.hierarchy.RootLevel;
import org.eclipse.fordiac.ide.hierarchymanager.ui.listeners.HierachyManagerUpdateListener;
import org.eclipse.fordiac.ide.hierarchymanager.ui.util.HierarchyManagerUtil;
import org.eclipse.fordiac.ide.hierarchymanager.ui.view.PlantHierarchyView;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
import org.eclipse.ltk.core.refactoring.participants.DeleteParticipant;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;

public class DeleteLibraryElementParticipant extends DeleteParticipant {

private RootLevel plantHierarchy;

private IFile file;

@Override
protected boolean initialize(final Object element) {

if (element instanceof final IFile file) {
this.file = file;
}

Display.getDefault().syncExec(() -> {
final IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
PlantHierarchyView view = null;

if (page != null) {
view = (PlantHierarchyView) page.findView("org.eclipse.fordiac.ide.hierarchymanager.view"); //$NON-NLS-1$

}

if (view != null) {
plantHierarchy = (RootLevel) view.getCommonViewer().getInput();
} else if (element instanceof final IFile file) {
plantHierarchy = (RootLevel) HierachyManagerUpdateListener.loadPlantHierachy(file.getProject());
}
});

return true;
}

@Override
public String getName() {
return "Delete element of plant hierarchy";
}

@Override
public RefactoringStatus checkConditions(final IProgressMonitor pm, final CheckConditionsContext context)
throws OperationCanceledException {

return new RefactoringStatus();
}

@Override
public Change createChange(final IProgressMonitor pm) throws CoreException, OperationCanceledException {
try {
pm.beginTask("Creating change...", 1); //$NON-NLS-1$

final List<Leaf> leaves = HierarchyManagerUtil.searchLeaf(plantHierarchy,
leaf -> leaf.getContainerFileName().contains(file.getName()));

if (!leaves.isEmpty()) {
return new SafePlantElementDeletionChange(plantHierarchy, leaves);
}

return null;
} finally {
pm.done();
}
}

}
Loading
Loading