diff --git a/plugins/org.eclipse.fordiac.ide.hierarchymanager.ui/META-INF/MANIFEST.MF b/plugins/org.eclipse.fordiac.ide.hierarchymanager.ui/META-INF/MANIFEST.MF index e6d8d34278..ae2264138e 100644 --- a/plugins/org.eclipse.fordiac.ide.hierarchymanager.ui/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.fordiac.ide.hierarchymanager.ui/META-INF/MANIFEST.MF @@ -19,7 +19,10 @@ Require-Bundle: org.eclipse.core.resources, org.eclipse.fordiac.ide.ui, org.eclipse.fordiac.ide.typemanagement, org.eclipse.ui.ide, - org.eclipse.ui.views.properties.tabbed + org.eclipse.emf.mwe.core, + org.eclipse.ui.views.properties.tabbed, + org.eclipse.fordiac.ide.model.commands, + org.eclipse.gef Bundle-Vendor: Eclipse 4diac Project Automatic-Module-Name: org.eclipse.fordiac.ide.hierarchymanager.ui Bundle-RequiredExecutionEnvironment: JavaSE-21 diff --git a/plugins/org.eclipse.fordiac.ide.hierarchymanager.ui/plugin.xml b/plugins/org.eclipse.fordiac.ide.hierarchymanager.ui/plugin.xml index 64db1fa231..85e00fef25 100644 --- a/plugins/org.eclipse.fordiac.ide.hierarchymanager.ui/plugin.xml +++ b/plugins/org.eclipse.fordiac.ide.hierarchymanager.ui/plugin.xml @@ -274,4 +274,8 @@ + + + diff --git a/plugins/org.eclipse.fordiac.ide.hierarchymanager.ui/src/org/eclipse/fordiac/ide/hierarchymanager/ui/listeners/HierachyManagerUpdateListener.java b/plugins/org.eclipse.fordiac.ide.hierarchymanager.ui/src/org/eclipse/fordiac/ide/hierarchymanager/ui/listeners/HierachyManagerUpdateListener.java new file mode 100644 index 0000000000..b2ee470f70 --- /dev/null +++ b/plugins/org.eclipse.fordiac.ide.hierarchymanager.ui/src/org/eclipse/fordiac/ide/hierarchymanager/ui/listeners/HierachyManagerUpdateListener.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright (c) 2024 Primetals Technology 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: + * Michael Oberlehner - initial API and implementation and/or initial documentation + *******************************************************************************/ +package org.eclipse.fordiac.ide.hierarchymanager.ui.listeners; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.commands.operations.AbstractOperation; +import org.eclipse.core.resources.IProject; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.emf.ecore.xmi.XMLResource; +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.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.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.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) { + final Map loadOptions = new HashMap<>(); + final ResourceSet hierarchyResouceSet = new ResourceSetImpl(); + hierarchyResouceSet.getResourceFactoryRegistry().getExtensionToFactoryMap() + .put(PlantHierarchyView.PLANT_HIERARCHY_FILE_NAME_EXTENSION, new HierarchyResourceFactoryImpl()); + loadOptions.put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE); + final XMLMapImpl map = new XMLMapImpl(); + map.setNoNamespacePackage(HierarchyPackage.eINSTANCE); + loadOptions.put(XMLResource.OPTION_XML_MAP, map); + hierarchyResouceSet.getLoadOptions().put(XMLResource.OPTION_XML_MAP, map); + return PlantHierarchyView.loadHierachyForProject(project, hierarchyResouceSet, loadOptions); + } + + @Override + public List constructExecutableUndoOperations(final QualNameChange change, final Object o) { + // TODO Auto-generated method stub + return null; + } + + @Override + protected List constructExecutableOperations(final QualNameChange qualNameChange, + final Object rootLevel) { + + final String identifier = qualNameChange.oldQualName(); + + final List result = new ArrayList<>(); + + final List leafs = HierarchyManagerUtil.searchLeaf((RootLevel) rootLevel, + leafRef -> leafRef.contains(identifier)); + if (leafs == null || leafs.isEmpty()) { + return null; // leaf may have been deleted in the meantime + } + + final String newRef = qualNameChange.newQualName(); + + for (final Leaf leaf : leafs) { + result.add(new UpdateLeafRefOperation(leaf, newRef)); + } + + return result; + } + + @Override + protected Object getReceiver(final TypeEntry key) { + return getPlantHierachy(key); + } + + @Override + protected void executeOperation(final AbstractOperation op) { + AbstractHierarchyHandler.executeOperation((AbstractChangeHierarchyOperation) op); + } + + private static RootLevel getPlantHierachy(final TypeEntry key) { + final IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + if (page != null) { + final PlantHierarchyView view = (PlantHierarchyView) page + .findView("org.eclipse.fordiac.ide.hierarchymanager.view"); //$NON-NLS-1$ + if (view != null) { + return (RootLevel) view.getCommonViewer().getInput(); + } + } + final IProject project = key.getFile().getProject(); + return (RootLevel) loadPlantHierachy(project); + } + + @Override + protected boolean isEnabled(final INamedElement element) { + return element instanceof UntypedSubApp; + } + +} diff --git a/plugins/org.eclipse.fordiac.ide.hierarchymanager.ui/src/org/eclipse/fordiac/ide/hierarchymanager/ui/operations/UpdateLeafRefOperation.java b/plugins/org.eclipse.fordiac.ide.hierarchymanager.ui/src/org/eclipse/fordiac/ide/hierarchymanager/ui/operations/UpdateLeafRefOperation.java new file mode 100644 index 0000000000..c125b32646 --- /dev/null +++ b/plugins/org.eclipse.fordiac.ide.hierarchymanager.ui/src/org/eclipse/fordiac/ide/hierarchymanager/ui/operations/UpdateLeafRefOperation.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2024 Primetals Technology 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: + * Michael Oberlehner - 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; + +public class UpdateLeafRefOperation extends AbstractChangeHierarchyOperation { + + private final Leaf leaf; + private final String newRef; + private final String oldRef; + + public UpdateLeafRefOperation(final Leaf level, final String newRef) { + super("Update Reference"); + this.leaf = level; + this.newRef = newRef; + this.oldRef = leaf.getRef(); + } + + @Override + public IStatus execute(final IProgressMonitor monitor, final IAdaptable info) throws ExecutionException { + final String replace = leaf.getRef().replace(oldRef, newRef); + + leaf.setRef(replace); + + saveHierarchy(leaf, monitor); + return Status.OK_STATUS; + } + + @Override + public IStatus redo(final IProgressMonitor monitor, final IAdaptable info) throws ExecutionException { + leaf.setRef(leaf.getRef().replace(oldRef, newRef)); + saveHierarchy(leaf, monitor); + return Status.OK_STATUS; + } + + @Override + public IStatus undo(final IProgressMonitor monitor, final IAdaptable info) throws ExecutionException { + leaf.setRef(leaf.getRef().replace(newRef, oldRef)); + saveHierarchy(leaf, monitor); + return Status.OK_STATUS; + } + +} diff --git a/plugins/org.eclipse.fordiac.ide.hierarchymanager.ui/src/org/eclipse/fordiac/ide/hierarchymanager/ui/util/HierarchyManagerUtil.java b/plugins/org.eclipse.fordiac.ide.hierarchymanager.ui/src/org/eclipse/fordiac/ide/hierarchymanager/ui/util/HierarchyManagerUtil.java index a58a77c696..4bc410bac7 100644 --- a/plugins/org.eclipse.fordiac.ide.hierarchymanager.ui/src/org/eclipse/fordiac/ide/hierarchymanager/ui/util/HierarchyManagerUtil.java +++ b/plugins/org.eclipse.fordiac.ide.hierarchymanager.ui/src/org/eclipse/fordiac/ide/hierarchymanager/ui/util/HierarchyManagerUtil.java @@ -13,12 +13,17 @@ *******************************************************************************/ package org.eclipse.fordiac.ide.hierarchymanager.ui.util; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.emf.ecore.EObject; 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.Node; +import org.eclipse.fordiac.ide.hierarchymanager.model.hierarchy.RootLevel; import org.eclipse.fordiac.ide.model.libraryElement.Application; import org.eclipse.fordiac.ide.model.libraryElement.AutomationSystem; import org.eclipse.fordiac.ide.model.libraryElement.Device; @@ -96,4 +101,31 @@ public static EObject parseSubappPath(FBNetwork network, final String[] path) { } return retVal; } + + @FunctionalInterface + public interface LeafMatcher { + boolean match(String s); + } + + public static List searchLeaf(final RootLevel rootLevel, final LeafMatcher matcher) { + final List result = new ArrayList<>(); + + for (final Level level : rootLevel.getLevels()) { + searchLeaf(level, result, matcher); + } + return result; + } + + public static List searchLeaf(final Level level, final List result, final LeafMatcher matcher) { + for (final Node node : level.getChildren()) { + if (node instanceof final Level l) { + searchLeaf(l, result, matcher); + } + if (node instanceof final Leaf leaf && matcher.match(leaf.getRef())) { + result.add(leaf); + } + } + return result; + } + } diff --git a/plugins/org.eclipse.fordiac.ide.hierarchymanager.ui/src/org/eclipse/fordiac/ide/hierarchymanager/ui/view/PlantHierarchyView.java b/plugins/org.eclipse.fordiac.ide.hierarchymanager.ui/src/org/eclipse/fordiac/ide/hierarchymanager/ui/view/PlantHierarchyView.java index 0425f1a7d4..4c26bb30a1 100644 --- a/plugins/org.eclipse.fordiac.ide.hierarchymanager.ui/src/org/eclipse/fordiac/ide/hierarchymanager/ui/view/PlantHierarchyView.java +++ b/plugins/org.eclipse.fordiac.ide.hierarchymanager.ui/src/org/eclipse/fordiac/ide/hierarchymanager/ui/view/PlantHierarchyView.java @@ -60,7 +60,7 @@ public class PlantHierarchyView extends CommonNavigator implements ITabbedProper private static final String PLANT_HIERARCHY_PROJECT = "PlantHierarchy.Project"; //$NON-NLS-1$ private static final String PLANT_HIERARCHY_FILE_NAME = ".plant.hier"; //$NON-NLS-1$ - private static final String PLANT_HIERARCHY_FILE_NAME_EXTENSION = "hier"; //$NON-NLS-1$ + public static final String PLANT_HIERARCHY_FILE_NAME_EXTENSION = "hier"; //$NON-NLS-1$ /** The PROPERTY_CONTRIBUTOR_ID. */ public static final String PROPERTY_CONTRIBUTOR_ID = "org.eclipse.fordiac.ide.hierarchymanager.ui.view"; //$NON-NLS-1$ @@ -117,7 +117,7 @@ protected Object getInitialInput() { // we can not use setInput here as getInitialInput is interacting with the // viewer in the base class currentProject = project; - return loadHierachyForProject(currentProject); + return loadHierachyForProject(currentProject, hierarchyResouceSet, loadOptions); } } } @@ -141,11 +141,11 @@ public IProject getCurrentProject() { return currentProject; } - private void setInput(final IProject proj) { + public void setInput(final IProject proj) { if (currentProject != proj) { // the new project is different set currentProject = proj; - getCommonViewer().setInput(loadHierachyForProject(proj)); + getCommonViewer().setInput(loadHierachyForProject(proj, hierarchyResouceSet, loadOptions)); setPartName(getConfigurationElement().getAttribute("name")); //$NON-NLS-1$ } } @@ -171,12 +171,13 @@ private static IProject getProjectFromEObject(final EObject eObj) { return null; } - private EObject loadHierachyForProject(final IProject proj) { + public static EObject loadHierachyForProject(final IProject proj, final ResourceSet hierarchyResouceSet, + final Map loadOptions) { final IFile file = proj.getFile(PLANT_HIERARCHY_FILE_NAME); final URI uri = URI.createPlatformResourceURI(file.getFullPath().toString(), true); if (!file.exists()) { // try to create a new file - return createNewHierarchyFile(file, uri); + return createNewHierarchyFile(file, uri, hierarchyResouceSet); } // we don't want to load the resource content as we can not give the mapping // options @@ -194,7 +195,8 @@ private EObject loadHierachyForProject(final IProject proj) { return null; } - public EObject createNewHierarchyFile(final IFile file, final URI uri) { + public static EObject createNewHierarchyFile(final IFile file, final URI uri, + final ResourceSet hierarchyResouceSet) { Resource resource = hierarchyResouceSet.getResource(uri, false); if (resource == null) { resource = new HierarchyResourceImpl(uri); diff --git a/plugins/org.eclipse.fordiac.ide.model.commands/plugin.xml b/plugins/org.eclipse.fordiac.ide.model.commands/plugin.xml new file mode 100644 index 0000000000..04b393c97e --- /dev/null +++ b/plugins/org.eclipse.fordiac.ide.model.commands/plugin.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/plugins/org.eclipse.fordiac.ide.model.commands/schema/QualNameChangeListener.exsd b/plugins/org.eclipse.fordiac.ide.model.commands/schema/QualNameChangeListener.exsd new file mode 100644 index 0000000000..6ecfb7c431 --- /dev/null +++ b/plugins/org.eclipse.fordiac.ide.model.commands/schema/QualNameChangeListener.exsd @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/org.eclipse.fordiac.ide.model.commands/src/org/eclipse/fordiac/ide/model/commands/QualNameAffectedCommand.java b/plugins/org.eclipse.fordiac.ide.model.commands/src/org/eclipse/fordiac/ide/model/commands/QualNameAffectedCommand.java new file mode 100644 index 0000000000..7e39bcd125 --- /dev/null +++ b/plugins/org.eclipse.fordiac.ide.model.commands/src/org/eclipse/fordiac/ide/model/commands/QualNameAffectedCommand.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2024 Primetals Technology 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: + * Michael Oberlehner - initial API and implementation and/or initial documentation + *******************************************************************************/ +package org.eclipse.fordiac.ide.model.commands; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.fordiac.ide.model.libraryElement.INamedElement; +import org.eclipse.fordiac.ide.model.libraryElement.LibraryElement; +import org.eclipse.fordiac.ide.model.typelibrary.TypeEntry; +import org.eclipse.gef.commands.Command; + +public abstract class QualNameAffectedCommand extends Command implements ScopedCommand { + + private final String oldQualName; + + protected QualNameAffectedCommand(final String oldQualName) { + this.oldQualName = oldQualName; + } + + protected String getOldQualName() { + return oldQualName; + } + + protected abstract String getNewQualName(); + + protected abstract INamedElement getNotifier(); + + /** + * encapsulate the change to not provide the command to the receiver + */ + public QualNameChange getQualNameChange() { + return new QualNameChange(getOldQualName(), getNewQualName(), getNotifier(), getTypeEntry(getNotifier())); + } + + protected static TypeEntry getTypeEntry(final INamedElement notifier) { + final EObject rootContainer = EcoreUtil.getRootContainer(notifier); + Assert.isTrue(rootContainer instanceof LibraryElement); + if (rootContainer instanceof final LibraryElement element) { + return element.getTypeEntry(); + } + return null; + } + +} diff --git a/plugins/org.eclipse.fordiac.ide.model.commands/src/org/eclipse/fordiac/ide/model/commands/QualNameChange.java b/plugins/org.eclipse.fordiac.ide.model.commands/src/org/eclipse/fordiac/ide/model/commands/QualNameChange.java new file mode 100644 index 0000000000..8c9c73254e --- /dev/null +++ b/plugins/org.eclipse.fordiac.ide.model.commands/src/org/eclipse/fordiac/ide/model/commands/QualNameChange.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2024 Primetals Technology 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: + * Michael Oberlehner - initial API and implementation and/or initial documentation + *******************************************************************************/ +package org.eclipse.fordiac.ide.model.commands; + +import org.eclipse.fordiac.ide.model.libraryElement.INamedElement; +import org.eclipse.fordiac.ide.model.typelibrary.TypeEntry; + +public record QualNameChange(String oldQualName, String newQualName, INamedElement notifier, TypeEntry key) { +} diff --git a/plugins/org.eclipse.fordiac.ide.model.commands/src/org/eclipse/fordiac/ide/model/commands/QualNameChangeListener.java b/plugins/org.eclipse.fordiac.ide.model.commands/src/org/eclipse/fordiac/ide/model/commands/QualNameChangeListener.java new file mode 100644 index 0000000000..772490b23f --- /dev/null +++ b/plugins/org.eclipse.fordiac.ide.model.commands/src/org/eclipse/fordiac/ide/model/commands/QualNameChangeListener.java @@ -0,0 +1,125 @@ +/******************************************************************************* + * Copyright (c) 2024 Primetals Technology 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: + * Michael Oberlehner - initial API and implementation and/or initial documentation + *******************************************************************************/ +package org.eclipse.fordiac.ide.model.commands; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.core.commands.operations.AbstractOperation; +import org.eclipse.fordiac.ide.model.libraryElement.INamedElement; +import org.eclipse.fordiac.ide.model.typelibrary.TypeEntry; + +public abstract class QualNameChangeListener { + + protected final HashMap> pendingChanges = new HashMap<>(); + protected final HashMap> executedOperations = new HashMap<>(); + + protected final Set undoSet = new HashSet<>(); + protected final Set redoSet = new HashSet<>(); + + protected abstract List constructExecutableOperations(final QualNameChange change, + Object receiver); + + protected abstract List constructExecutableUndoOperations(final QualNameChange change, + Object receiver); + + protected abstract void executeOperation(AbstractOperation op); + + protected abstract Object getReceiver(TypeEntry key); + + protected void onCommandExecuted(final QualNameChange qualNameChange) { + if (isEnabled(qualNameChange.notifier())) { + addToPendingList(qualNameChange); + } + } + + private void addToPendingList(final QualNameChange qualNameChange) { + final List changeList = pendingChanges.computeIfAbsent(qualNameChange.key(), + k -> new ArrayList<>()); + changeList.add(qualNameChange); + } + + protected void onCommandUndoExecuted(final QualNameChange qualNameChange) { + if (isEnabled(qualNameChange.notifier())) { + final List abstractOperation = executedOperations.get(qualNameChange); + if (abstractOperation != null) { + undoSet.addAll(abstractOperation); + abstractOperation.clear(); + } else { + // not yet executed, which means the editor has not been saved yet, so it needs + // to be in pending changes. + pendingChanges.remove(qualNameChange.key()); + } + } + + } + + void onCommandRedoExecuted(final QualNameChange qualNameChange) { + if (undoSet.remove(qualNameChange)) { + + } + } + + public void flush(final Object notifier) { + final List list = pendingChanges.get(notifier); + list.forEach(executedOperations::remove); + pendingChanges.remove(notifier); + } + + public void commitOperations(final Object notifier) { + + if (!(notifier instanceof final TypeEntry key)) { + return; + } + + final List list = pendingChanges.get(key); + if (list == null || list.isEmpty()) { + // we only want to reload if changes have been performed + return; + } + + for (final QualNameChange change : list) { + List operation = null; + + if (undoSet.contains(operation)) { + operation = constructExecutableUndoOperations(change, list); + } else { + + operation = constructExecutableOperations(change, getReceiver(key)); + } + + if (operation == null || operation.isEmpty()) { + continue; + // the receiving objrct might have change in the meantime + // TODO add to Plant hier a warning that we have umcomited change -> save all + // editors before editing plant hierachy + } + + operation.stream().forEach(op -> { + executeOperation(op); + }); + executedOperations.put(change, operation); + } + + pendingChanges.remove(key); + } + + @SuppressWarnings("static-method") + protected boolean isEnabled(final INamedElement element) { + return true; + } + +} diff --git a/plugins/org.eclipse.fordiac.ide.model.commands/src/org/eclipse/fordiac/ide/model/commands/QualNameChangeListenerManager.java b/plugins/org.eclipse.fordiac.ide.model.commands/src/org/eclipse/fordiac/ide/model/commands/QualNameChangeListenerManager.java new file mode 100644 index 0000000000..7c24010dac --- /dev/null +++ b/plugins/org.eclipse.fordiac.ide.model.commands/src/org/eclipse/fordiac/ide/model/commands/QualNameChangeListenerManager.java @@ -0,0 +1,133 @@ +/******************************************************************************* + * Copyright (c) 2024 Primetals Technology 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: + * Michael Oberlehner - initial API and implementation and/or initial documentation + *******************************************************************************/ +package org.eclipse.fordiac.ide.model.commands; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.Platform; +import org.eclipse.fordiac.ide.model.libraryElement.LibraryElement; +import org.eclipse.fordiac.ide.model.typelibrary.TypeEntry; +import org.eclipse.fordiac.ide.ui.editors.EditorUtils; +import org.eclipse.gef.commands.CommandStack; +import org.eclipse.gef.commands.CommandStackEvent; +import org.eclipse.gef.commands.CommandStackEventListener; +import org.eclipse.ui.IEditorPart; + +public enum QualNameChangeListenerManager implements CommandStackEventListener { + + INSTANCE; + + QualNameChangeListenerManager() { + initialize(); + } + + private static final String EXTENSION_POINT_ID = "org.eclipse.fordiac.ide.model.commands.QualNameChangeListener"; + private final List listeners = new ArrayList<>(); + + public void initialize() { + final IConfigurationElement[] config = Platform.getExtensionRegistry() + .getConfigurationElementsFor(EXTENSION_POINT_ID); + for (final IConfigurationElement element : config) { + try { + final Object obj = element.createExecutableExtension("class"); + if (obj instanceof QualNameChangeListener) { + listeners.add((QualNameChangeListener) obj); + } + } catch (final Exception e) { + e.printStackTrace(); + } + } + } + + public static void addCommandStackEventListener(final CommandStack commandStack) { + commandStack.addCommandStackEventListener(INSTANCE); + } + + public void removeCommandStackEventListener(final CommandStack commandStack, final Object notfier) { + listeners.forEach(l -> l.flush(notfier)); + commandStack.removeCommandStackEventListener(INSTANCE); + } + + @Override + public void stackChanged(final CommandStackEvent event) { + + if (event.getCommand() instanceof final QualNameAffectedCommand cmd) { + final QualNameChange qualNameChange = cmd.getQualNameChange(); + switch (event.getDetail()) { + case CommandStack.POST_EXECUTE: + notifyListenersExecute(qualNameChange); + break; + case CommandStack.POST_UNDO: + notifyListenersUndo(qualNameChange); + break; + case CommandStack.POST_REDO: + notifyListenersRedo(qualNameChange); + break; + + default: + break; + } + + } + + if (event.getDetail() == CommandStack.POST_MARK_SAVE && event.getSource() instanceof final CommandStack stack) { + + final TypeEntry typeEntry = getTypeEntryKeyFromCommandStack(stack); + if (typeEntry != null) { + notifiyCommit(typeEntry); + } + } + + } + + private static TypeEntry getTypeEntryKeyFromCommandStack(final CommandStack stack) { + final IEditorPart currentActiveEditor = EditorUtils.getCurrentActiveEditor(); + + if (currentActiveEditor.getAdapter(CommandStack.class) == stack) { + final LibraryElement libraryElement = currentActiveEditor.getAdapter(LibraryElement.class); + return libraryElement.getTypeEntry(); + + } + + return null; + + } + + public void notifyListenersExecute(final QualNameChange qualNameChange) { + for (final QualNameChangeListener listener : listeners) { + listener.onCommandExecuted(qualNameChange); + } + } + + public void notifyListenersUndo(final QualNameChange qualNameChange) { + for (final QualNameChangeListener listener : listeners) { + listener.onCommandUndoExecuted(qualNameChange); + } + } + + public void notifyListenersRedo(final QualNameChange qualNameChange) { + for (final QualNameChangeListener listener : listeners) { + listener.onCommandRedoExecuted(qualNameChange); + } + } + + void notifiyCommit(final Object notfier) { + for (final QualNameChangeListener listener : listeners) { + listener.commitOperations(notfier); + } + + } + +} \ No newline at end of file diff --git a/plugins/org.eclipse.fordiac.ide.model.commands/src/org/eclipse/fordiac/ide/model/commands/change/ChangeNameCommand.java b/plugins/org.eclipse.fordiac.ide.model.commands/src/org/eclipse/fordiac/ide/model/commands/change/ChangeNameCommand.java index c5720a637c..9c65c8d342 100644 --- a/plugins/org.eclipse.fordiac.ide.model.commands/src/org/eclipse/fordiac/ide/model/commands/change/ChangeNameCommand.java +++ b/plugins/org.eclipse.fordiac.ide.model.commands/src/org/eclipse/fordiac/ide/model/commands/change/ChangeNameCommand.java @@ -23,6 +23,7 @@ import org.eclipse.emf.ecore.EObject; import org.eclipse.fordiac.ide.model.ConnectionLayoutTagger; import org.eclipse.fordiac.ide.model.NameRepository; +import org.eclipse.fordiac.ide.model.commands.QualNameAffectedCommand; import org.eclipse.fordiac.ide.model.commands.ScopedCommand; import org.eclipse.fordiac.ide.model.libraryElement.AdapterDeclaration; import org.eclipse.fordiac.ide.model.libraryElement.AdapterFB; @@ -33,10 +34,9 @@ import org.eclipse.fordiac.ide.model.libraryElement.INamedElement; import org.eclipse.fordiac.ide.model.libraryElement.SubApp; import org.eclipse.fordiac.ide.model.libraryElement.VarDeclaration; -import org.eclipse.gef.commands.Command; import org.eclipse.gef.commands.CompoundCommand; -public class ChangeNameCommand extends Command implements ConnectionLayoutTagger, ScopedCommand { +public class ChangeNameCommand extends QualNameAffectedCommand implements ConnectionLayoutTagger, ScopedCommand { private final INamedElement element; private final String name; private String oldName; @@ -48,9 +48,11 @@ private ChangeNameCommand(final INamedElement element, final String name) { } private ChangeNameCommand(final INamedElement element, final String name, final boolean validateName) { + super(element.getQualifiedName()); this.element = Objects.requireNonNull(element); this.name = name; this.validateName = validateName; + this.oldName = element.getQualifiedName(); } public static ChangeNameCommand forName(final INamedElement element, final String name) { @@ -168,4 +170,18 @@ public Set getAffectedObjects() { } while (container != null); return Set.of(element); } + + @Override + public INamedElement getNotifier() { + return element; + } + + @Override + protected String getNewQualName() { + if (getElement().getQualifiedName().equals(getOldQualName())) { + return null; // TODO calc new name + } + return getElement().getQualifiedName(); + } + } diff --git a/plugins/org.eclipse.fordiac.ide.model.ui/META-INF/MANIFEST.MF b/plugins/org.eclipse.fordiac.ide.model.ui/META-INF/MANIFEST.MF index 282c98969a..2b584d6452 100644 --- a/plugins/org.eclipse.fordiac.ide.model.ui/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.fordiac.ide.model.ui/META-INF/MANIFEST.MF @@ -12,7 +12,8 @@ Require-Bundle: org.eclipse.emf.ecore.editor, org.eclipse.ui.editors, org.eclipse.ui.views.properties.tabbed, org.eclipse.ui.navigator, - org.eclipse.fordiac.ide.ui + org.eclipse.fordiac.ide.ui, + org.eclipse.fordiac.ide.model.commands Automatic-Module-Name: org.eclipse.fordiac.ide.model.ui Bundle-Vendor: Eclipse 4diac Export-Package: org.eclipse.fordiac.ide.model.ui, diff --git a/plugins/org.eclipse.fordiac.ide.model.ui/src/org/eclipse/fordiac/ide/model/ui/editors/AbstractBreadCrumbEditor.java b/plugins/org.eclipse.fordiac.ide.model.ui/src/org/eclipse/fordiac/ide/model/ui/editors/AbstractBreadCrumbEditor.java index 3e1efc081c..6380d64be3 100644 --- a/plugins/org.eclipse.fordiac.ide.model.ui/src/org/eclipse/fordiac/ide/model/ui/editors/AbstractBreadCrumbEditor.java +++ b/plugins/org.eclipse.fordiac.ide.model.ui/src/org/eclipse/fordiac/ide/model/ui/editors/AbstractBreadCrumbEditor.java @@ -34,6 +34,7 @@ import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider; import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider; import org.eclipse.fordiac.ide.model.ConnectionLayoutTagger; +import org.eclipse.fordiac.ide.model.commands.QualNameChangeListenerManager; import org.eclipse.fordiac.ide.model.errormarker.FordiacErrorMarker; import org.eclipse.fordiac.ide.model.libraryElement.Connection; import org.eclipse.fordiac.ide.model.libraryElement.FBNetwork; @@ -258,6 +259,7 @@ public void stackChanged(final CommandStackEvent event) { layoutCommand.undo(); } } + } private static boolean isTagged(final CommandStackEvent event) { @@ -269,6 +271,8 @@ private static boolean isTagged(final CommandStackEvent event) { @Override public void dispose() { if (null != getCommandStack()) { + QualNameChangeListenerManager.INSTANCE.removeCommandStackEventListener(getCommandStack(), + getAdapter(LibraryElement.class).getTypeEntry()); getCommandStack().removeCommandStackEventListener(this); } super.dispose(); diff --git a/plugins/org.eclipse.fordiac.ide.systemmanagement.ui/src/org/eclipse/fordiac/ide/systemmanagement/ui/editors/AutomationSystemEditor.java b/plugins/org.eclipse.fordiac.ide.systemmanagement.ui/src/org/eclipse/fordiac/ide/systemmanagement/ui/editors/AutomationSystemEditor.java index 4e2ea39852..b8d859399c 100644 --- a/plugins/org.eclipse.fordiac.ide.systemmanagement.ui/src/org/eclipse/fordiac/ide/systemmanagement/ui/editors/AutomationSystemEditor.java +++ b/plugins/org.eclipse.fordiac.ide.systemmanagement.ui/src/org/eclipse/fordiac/ide/systemmanagement/ui/editors/AutomationSystemEditor.java @@ -41,6 +41,7 @@ import org.eclipse.fordiac.ide.gef.annotation.FordiacMarkerGraphicalAnnotationModel; import org.eclipse.fordiac.ide.gef.annotation.GraphicalAnnotationModel; import org.eclipse.fordiac.ide.gef.validation.ValidationJob; +import org.eclipse.fordiac.ide.model.commands.QualNameChangeListenerManager; import org.eclipse.fordiac.ide.model.edit.ITypeEntryEditor; import org.eclipse.fordiac.ide.model.edit.TypeEntryAdapter; import org.eclipse.fordiac.ide.model.helpers.FBNetworkHelper; @@ -437,6 +438,7 @@ public void setInput(final IEditorInput input) { if (system != null) { getCommandStack().addCommandStackEventListener(this); getCommandStack().addCommandStackEventListener(subEditorCommandStackListener); + QualNameChangeListenerManager.INSTANCE.addCommandStackEventListener(getCommandStack()); system.getTypeEntry().eAdapters().add(adapter); } }