blob: 8c648c3d15ed69e34e452540a50d7107d4baed9d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2020, 2021 Primetals Technologies Germany GmbH, Johannes Kepler University Linz
*
* 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:
* Alois Zoitl - initial implementation and/or documentation
* - implemented first version of gotoMarker for FB markers
* - extracted breadcrumb based editor to model.ui
* Michael Oberlehner, Alois Zoitl
* - implemented save and restore state
*******************************************************************************/
package org.eclipse.fordiac.ide.systemmanagement.ui.editors;
import java.util.Arrays;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
import org.eclipse.fordiac.ide.application.editors.ApplicationEditor;
import org.eclipse.fordiac.ide.application.editors.ApplicationEditorInput;
import org.eclipse.fordiac.ide.application.editors.FBNetworkEditor;
import org.eclipse.fordiac.ide.application.editors.SubAppNetworkEditor;
import org.eclipse.fordiac.ide.application.editors.SubApplicationEditorInput;
import org.eclipse.fordiac.ide.fbtypeeditor.network.viewer.CompositeAndSubAppInstanceViewerInput;
import org.eclipse.fordiac.ide.fbtypeeditor.network.viewer.CompositeInstanceViewer;
import org.eclipse.fordiac.ide.gef.DiagramEditorWithFlyoutPalette;
import org.eclipse.fordiac.ide.gef.DiagramOutlinePage;
import org.eclipse.fordiac.ide.model.libraryElement.Application;
import org.eclipse.fordiac.ide.model.libraryElement.AutomationSystem;
import org.eclipse.fordiac.ide.model.libraryElement.CompositeFBType;
import org.eclipse.fordiac.ide.model.libraryElement.Device;
import org.eclipse.fordiac.ide.model.libraryElement.FB;
import org.eclipse.fordiac.ide.model.libraryElement.FBNetwork;
import org.eclipse.fordiac.ide.model.libraryElement.FBNetworkElement;
import org.eclipse.fordiac.ide.model.libraryElement.Resource;
import org.eclipse.fordiac.ide.model.libraryElement.SubApp;
import org.eclipse.fordiac.ide.model.libraryElement.SystemConfiguration;
import org.eclipse.fordiac.ide.model.ui.actions.OpenListenerManager;
import org.eclipse.fordiac.ide.model.ui.editors.AbstractBreadCrumbEditor;
import org.eclipse.fordiac.ide.resourceediting.editors.ResourceDiagramEditor;
import org.eclipse.fordiac.ide.resourceediting.editors.ResourceEditorInput;
import org.eclipse.fordiac.ide.subapptypeeditor.viewer.SubappInstanceViewer;
import org.eclipse.fordiac.ide.systemconfiguration.editor.SystemConfigurationEditor;
import org.eclipse.fordiac.ide.systemconfiguration.editor.SystemConfigurationEditorInput;
import org.eclipse.fordiac.ide.systemmanagement.AutomationSystemListener;
import org.eclipse.fordiac.ide.systemmanagement.SystemManager;
import org.eclipse.fordiac.ide.systemmanagement.ui.Activator;
import org.eclipse.fordiac.ide.systemmanagement.ui.Messages;
import org.eclipse.fordiac.ide.systemmanagement.ui.providers.AutomationSystemProviderAdapterFactory;
import org.eclipse.fordiac.ide.systemmanagement.ui.systemexplorer.SystemLabelProvider;
import org.eclipse.fordiac.ide.ui.editors.EditorUtils;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.dialogs.SaveAsDialog;
import org.eclipse.ui.part.EditorPart;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import org.eclipse.ui.views.properties.IPropertySheetPage;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
public class AutomationSystemEditor extends AbstractBreadCrumbEditor implements AutomationSystemListener {
private static final int OVERWRITE_CHANGES = 0;
private static final int SAVE_CHANGES = 1;
private static final int DISCARD_CHANGES = 2;
private AutomationSystem system;
private DiagramOutlinePage outlinePage;
@Override
public void init(final IEditorSite site, final IEditorInput input) throws PartInitException {
super.init(site, input);
loadSystem();
SystemManager.INSTANCE.addAutomationSystemListener(this);
}
@Override
protected Composite createPageContainer(final Composite parent) {
final Composite pageContainer = new Composite(parent, SWT.NONE);
pageContainer.setLayoutData(new GridData(GridData.FILL_BOTH));
return pageContainer;
}
@Override
protected void createPages() {
try {
final int pagenum = addPage(new SystemEditor(), getEditorInput());
getModelToEditorNumMapping().put(system, Integer.valueOf(pagenum));
} catch (final PartInitException e) {
Activator.getDefault().logError(e.getMessage(), e);
}
}
private void loadSystem() {
if (getEditorInput() instanceof FileEditorInput) {
system = SystemManager.INSTANCE.getSystem(((FileEditorInput) getEditorInput()).getFile()); // register as
// listener and
// call this
// method
if (null != system) {
getCommandStack().addCommandStackEventListener(this);
setPartName(system.getName());
}
}
}
@Override
protected void pageChange(final int newPageIndex) {
super.pageChange(newPageIndex);
if ((-1 != newPageIndex) && (null != outlinePage)) {
final GraphicalViewer viewer = getActiveEditor().getAdapter(GraphicalViewer.class);
outlinePage.viewerChanged(viewer);
}
}
@Override
protected EditorPart createEditorPart(final Object model) {
if (model instanceof IFile) {
return new SystemEditor();
}
if (model instanceof FB && ((FB) model).getType() instanceof CompositeFBType) {
return new CompositeInstanceViewer();
}
if (model instanceof SubApp) {
if (((SubApp) model).getType() != null) {
return new SubappInstanceViewer();
}
return new SubAppNetworkEditor();
}
if (model instanceof Application) {
return new ApplicationEditor();
}
if (model instanceof SystemConfiguration) {
return new SystemConfigurationEditor();
}
if (model instanceof Device) {
return new SystemConfigurationEditor();
}
if (model instanceof Resource) {
return new ResourceDiagramEditor();
}
return null;
}
@Override
protected IEditorInput createEditorInput(final Object model) {
if (model instanceof IFile) {
return getEditorInput();
}
if (model instanceof SubApp) {
if (((SubApp) model).getType() != null) {
return createSubappInstanceViewer(model);
}
return new SubApplicationEditorInput((SubApp) model);
}
if (model instanceof FB && ((FB) model).getType() instanceof CompositeFBType) {
return createCompositeInstanceViewer(model);
}
if (model instanceof Application) {
return new ApplicationEditorInput((Application) model);
}
if (model instanceof SystemConfiguration) {
return new SystemConfigurationEditorInput((SystemConfiguration) model);
}
if (model instanceof Device) {
return new SystemConfigurationEditorInput(((Device) model).getSystemConfiguration());
}
if (model instanceof Resource) {
return new ResourceEditorInput((Resource) model);
}
return null;
}
private static IEditorInput createSubappInstanceViewer(final Object model) {
final EditPart createEditPart = new SubappInstanceViewer().getEditPartFactory().createEditPart(null, model);
return new CompositeAndSubAppInstanceViewerInput(createEditPart, model,
((FBNetworkElement) model).getType().getName());
}
private static IEditorInput createCompositeInstanceViewer(final Object model) {
final EditPart createEditPart = new CompositeInstanceViewer().getEditPartFactory().createEditPart(null, model);
return new CompositeAndSubAppInstanceViewerInput(createEditPart, model,
((FBNetworkElement) model).getType().getName());
}
@Override
public void doSave(final IProgressMonitor monitor) {
if (null != system) {
SystemManager.INSTANCE.removeAutomationSystemListener(this);
SystemManager.saveSystem(system);
getCommandStack().markSaveLocation();
firePropertyChange(IEditorPart.PROP_DIRTY);
SystemManager.INSTANCE.addAutomationSystemListener(this);
}
}
@Override
protected AdapterFactoryContentProvider createBreadcrumbContentProvider() {
return new AdapterFactoryContentProvider(new AutomationSystemProviderAdapterFactory());
}
@Override
protected AdapterFactoryLabelProvider createBreadcrumbLabelProvider() {
return new SystemLabelProvider();
}
@Override
protected Object getInitialModel(final String itemPath) {
if (null != itemPath) {
final String[] nameList = itemPath.split("\\."); //$NON-NLS-1$
if (nameList.length > 1) {
// we have a child of the system
final EObject targetmodel = getTargetModel(Arrays.copyOfRange(nameList, 1, nameList.length));
if (null != targetmodel) {
return targetmodel;
}
}
}
return system;
}
@Override
public void doSaveAs() {
if (system == null) {
return;
}
final SaveAsDialog saveAsDialog = new SaveAsDialog(getSite().getShell());
saveAsDialog.setOriginalName(system.getSystemFile().getName());
saveAsDialog.open();
final IPath path = saveAsDialog.getResult();
if (path == null) {
return;
}
final IPath fullPath = system.getSystemFile().getFullPath();
if (fullPath.equals(path)) {
doSave(null);
return;
}
SystemManager.INSTANCE.removeAutomationSystemListener(this);
final IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
SystemManager.saveSystem(system, file);
SystemManager.INSTANCE.addAutomationSystemListener(this);
}
@Override
public boolean isSaveAsAllowed() {
return true;
}
@Override
public <T> T getAdapter(final Class<T> adapter) {
if (adapter == IPropertySheetPage.class) {
return adapter.cast(new TabbedPropertySheetPage(this));
}
if (adapter == IContentOutlinePage.class) {
if (null == outlinePage) {
outlinePage = new DiagramOutlinePage(getActiveEditor().getAdapter(GraphicalViewer.class));
}
return adapter.cast(outlinePage);
}
return super.getAdapter(adapter);
}
@Override
public CommandStack getCommandStack() {
return (null != system) ? system.getCommandStack() : null;
}
@Override
public String getContributorId() {
return DiagramEditorWithFlyoutPalette.PROPERTY_CONTRIBUTOR_ID;
}
@Override
protected void gotoFBNetworkElement(final Object object) {
final String[] split = ((String) object).split("\\."); //$NON-NLS-1$
if (split.length >= 2) {
final EObject targetmodel = getTargetModel(Arrays.copyOf(split, split.length - 1));
if (null != targetmodel) {
getBreadcrumb().setInput(targetmodel);
final FBNetworkEditor fbEditor = getAdapter(FBNetworkEditor.class);
if (null != fbEditor) {
final FBNetworkElement elementToSelect = fbEditor.getModel()
.getElementNamed(split[split.length - 1]);
fbEditor.selectElement(elementToSelect);
}
}
}
}
private EObject getTargetModel(final String[] path) {
EObject retVal = system.getApplicationNamed(path[0]);
if (null != retVal) {
if (path.length > 1) {
// we are within a subapplication in the application
retVal = parseSubappPath(((Application) retVal).getFBNetwork(),
Arrays.copyOfRange(path, 1, path.length));
}
} else if (path.length > 2) {
// we need to have at least a device and a resource in the path
retVal = system.getDeviceNamed(path[0]);
if (null != retVal) {
retVal = ((Device) retVal).getResourceNamed(path[1]);
if ((null != retVal) && (path.length > 2)) {
// we are within a subapplication in the resource
retVal = parseSubappPath(((Resource) retVal).getFBNetwork(),
Arrays.copyOfRange(path, 2, path.length));
}
}
}
return retVal;
}
private static EObject parseSubappPath(FBNetwork network, final String[] path) {
EObject retVal = null;
for (final String element : path) {
retVal = network.getElementNamed(element);
if (retVal instanceof SubApp) {
network = ((SubApp) retVal).getSubAppNetwork();
} else {
return null;
}
}
return retVal;
}
@Override
public void dispose() {
SystemManager.INSTANCE.removeAutomationSystemListener(this);
super.dispose();
}
@Override
public void automationSystemChanged(final IFile file) {
if (file.equals(system.getSystemFile())) {
Display.getDefault().asyncExec(() -> openFileChangedDialog(file));
}
}
private void openFileChangedDialog(final IFile file) {
final String info = Messages.AutomationSystemEditor_Info.replace("{placeholder}", //$NON-NLS-1$
file.getFullPath().toOSString());
final MessageDialog dialog = new MessageDialog(getSite().getShell(), Messages.AutomationSystemEditor_Title,
null, info, MessageDialog.INFORMATION,
new String[] { Messages.AutomationSystemEditor_Overwrite_Changes,
Messages.AutomationSystemEditor_Save_Changes, Messages.AutomationSystemEditor_Discard_Changes },
0);
final int returnCode = dialog.open();
handleReturnCode(returnCode, file);
}
private void handleReturnCode(final int returnCode, final IFile file) {
switch (returnCode) {
case OVERWRITE_CHANGES:
doSave(new NullProgressMonitor());
break;
case SAVE_CHANGES:
doSaveAs();
replaceSystemFile(file);
break;
case DISCARD_CHANGES:
replaceSystemFile(file);
break;
default:
break;
}
}
private void replaceSystemFile(final IFile file) {
system = SystemManager.INSTANCE.replaceSystemFromFile(system, file);
if (!system.getApplication().isEmpty()) {
OpenListenerManager.openEditor(system.getApplication().get(0));
} else {
EditorUtils.CloseEditor.run(this);
}
}
}