blob: af45f01bb7921263da9daf2afc0049e53432ddeb [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2020 Johannes Kepler University, Linz
* 2021 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:
* Daniel Lindhuber, Bianca Wiesmayr
* - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.fordiac.ide.datatypeeditor.editors;
import java.util.ArrayList;
import java.util.List;
import javax.xml.stream.XMLStreamException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.fordiac.ide.datatypeeditor.Activator;
import org.eclipse.fordiac.ide.datatypeeditor.DataTypeListener;
import org.eclipse.fordiac.ide.datatypeeditor.Messages;
import org.eclipse.fordiac.ide.datatypeeditor.widgets.StructViewingComposite;
import org.eclipse.fordiac.ide.model.data.AnyDerivedType;
import org.eclipse.fordiac.ide.model.data.DataType;
import org.eclipse.fordiac.ide.model.data.StructuredType;
import org.eclipse.fordiac.ide.model.dataexport.DataTypeExporter;
import org.eclipse.fordiac.ide.model.dataimport.DataTypeImporter;
import org.eclipse.fordiac.ide.model.typelibrary.TypeLibrary;
import org.eclipse.fordiac.ide.ui.widget.TableWidgetFactory;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.gef.commands.CommandStackEvent;
import org.eclipse.gef.commands.CommandStackEventListener;
import org.eclipse.gef.ui.actions.ActionRegistry;
import org.eclipse.gef.ui.actions.RedoAction;
import org.eclipse.gef.ui.actions.UndoAction;
import org.eclipse.gef.ui.actions.UpdateAction;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.ide.FileStoreEditorInput;
import org.eclipse.ui.part.EditorPart;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
public class DataTypeEditor extends EditorPart
implements CommandStackEventListener, ITabbedPropertySheetPageContributor, ISelectionListener {
private DataType dataType;
private IFile file;
private final CommandStack commandStack = new CommandStack();
private StructViewingComposite editComposite;
private Composite errorComposite;
private boolean importFailed;
private boolean outsideWorkspace;
private DataTypeListener listener;
private ActionRegistry actionRegistry;
private final List<String> selectionActions = new ArrayList<>();
private final List<String> stackActions = new ArrayList<>();
private final List<String> propertyActions = new ArrayList<>();
@Override
public void stackChanged(final CommandStackEvent event) {
updateActions(stackActions);
firePropertyChange(IEditorPart.PROP_DIRTY);
editComposite.getViewer().refresh();
}
@Override
public String getContributorId() {
return "org.eclipse.fordiac.ide.datatypeeditor.editors.DataTypeEditor"; //$NON-NLS-1$
}
@Override
public void dispose() {
getCommandStack().removeCommandStackEventListener(this);
getSite().getWorkbenchWindow().getSelectionService().removeSelectionListener(this);
getActionRegistry().dispose();
ResourcesPlugin.getWorkspace().removeResourceChangeListener(listener);
super.dispose();
}
@Override
protected void firePropertyChange(final int property) {
super.firePropertyChange(property);
updateActions(propertyActions);
}
@Override
public void doSave(final IProgressMonitor monitor) {
final DataTypeExporter exporter = new DataTypeExporter((AnyDerivedType) dataType);
try {
exporter.saveType(file);
commandStack.markSaveLocation();
firePropertyChange(IEditorPart.PROP_DIRTY);
} catch (final XMLStreamException e) {
Activator.getDefault().logError(e.getMessage(), e);
MessageDialog.openError(getSite().getShell().getShell(), Messages.MessageDialogTitle_SaveError,
Messages.MessageDialogContent_SaveError);
}
}
@Override
public void doSaveAs() {
// TODO implement save as new data type method, update isSaveAsAllowed()
// accordingly
}
@Override
public void init(final IEditorSite site, final IEditorInput input) throws PartInitException {
importType(input);
setInput(input);
setSite(site);
site.getWorkbenchWindow().getSelectionService().addSelectionListener(this);
getCommandStack().addCommandStackEventListener(this);
initializeActionRegistry();
setActionHandlers(site);
}
private void importType(final IEditorInput input) throws PartInitException {
if (input instanceof FileEditorInput) {
file = ((FileEditorInput) input).getFile();
} else if (input instanceof FileStoreEditorInput) {
// is called when files are opened via File -> Open File
importFailed = true;
outsideWorkspace = true;
}
try {
if (null != file) {
setPartName(getDatatypeNameFromFile(file));
final DataTypeImporter importer = new DataTypeImporter(file);
importer.loadElement();
dataType = importer.getElement();
listener = new DataTypeListener(file, this);
final IWorkspace workspace = ResourcesPlugin.getWorkspace();
workspace.addResourceChangeListener(listener);
}
} catch (final Exception e) {
throw new PartInitException(e.getMessage(), e);
}
}
private static String getDatatypeNameFromFile(IFile file) {
return file.getName().substring(0, file.getName().lastIndexOf('.'));
}
private void setActionHandlers(final IEditorSite site) {
final ActionRegistry registry = getActionRegistry();
final IActionBars bars = site.getActionBars();
String id = ActionFactory.UNDO.getId();
bars.setGlobalActionHandler(id, registry.getAction(id));
id = ActionFactory.REDO.getId();
bars.setGlobalActionHandler(id, registry.getAction(id));
id = ActionFactory.DELETE.getId();
bars.setGlobalActionHandler(id, registry.getAction(id));
bars.updateActionBars();
}
@Override
public boolean isDirty() {
return getCommandStack().isDirty();
}
@Override
public boolean isSaveAsAllowed() {
return false;
}
@Override
public void createPartControl(final Composite parent) {
if ((dataType instanceof StructuredType) && (!importFailed)) {
editComposite = new StructViewingComposite(parent, 1, commandStack, (StructuredType) dataType,
TypeLibrary.getTypeLibrary(file.getProject()).getDataTypeLibrary(), this);
editComposite.createPartControl(parent);
TableWidgetFactory.enableCopyPasteCut(this);
} else if (importFailed) {
createErrorComposite(parent, Messages.ErrorCompositeMessage);
if (outsideWorkspace) {
MessageDialog.openError(getSite().getShell().getShell(),
Messages.MessageDialogTitle_OutsideWorkspaceError,
Messages.MessageDialogContent_OutsideWorkspaceError);
}
}
}
private void createErrorComposite(final Composite parent, final String errorText) {
errorComposite = new Composite(parent, SWT.NONE);
errorComposite.setLayout(new GridLayout(1, false));
final Label label = new Label(errorComposite, SWT.CENTER);
label.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.HEADER_FONT));
label.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
label.setText(errorText);
}
@Override
public void setFocus() {
if (null == editComposite) {
errorComposite.setFocus();
} else {
editComposite.setFocus();
}
}
public CommandStack getCommandStack() {
return commandStack;
}
@Override
public void selectionChanged(final IWorkbenchPart part, final ISelection selection) {
if (this.equals(getSite().getPage().getActiveEditor())) {
updateActions(selectionActions);
firePropertyChange(IEditorPart.PROP_DIRTY);
}
}
private void createActions() {
final ActionRegistry registry = getActionRegistry();
IAction action;
action = new UndoAction(this);
registry.registerAction(action);
getStackActions().add(action.getId());
action = new RedoAction(this);
registry.registerAction(action);
getStackActions().add(action.getId());
}
@Override
public <T> T getAdapter(final Class<T> key) {
if (key == org.eclipse.ui.views.properties.IPropertySheetPage.class) {
return key.cast(new TabbedPropertySheetPage(this));
}
if (key == CommandStack.class) {
return key.cast(getCommandStack());
}
if (key == ActionRegistry.class) {
return key.cast(getActionRegistry());
}
return super.getAdapter(key);
}
private List<String> getStackActions() {
return stackActions;
}
private void initializeActionRegistry() {
createActions();
updateActions(propertyActions);
updateActions(stackActions);
}
private void updateActions(final List<String> actionIds) {
final ActionRegistry registry = getActionRegistry();
actionIds.forEach(id -> {
final IAction action = registry.getAction(id);
if (action instanceof UpdateAction) {
((UpdateAction) action).update();
}
});
}
private ActionRegistry getActionRegistry() {
if (null == actionRegistry) {
actionRegistry = new ActionRegistry();
}
return actionRegistry;
}
public void updateDataType(IPath path) {
this.file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
final String name = getDatatypeNameFromFile(file);
dataType.setName(name);
setPartName(name);
setTitle(name);
setInput(new FileEditorInput(file));
}
}