blob: d2de02346fb5a8415fa071169190015fbbd5b66a [file] [log] [blame]
/**
********************************************************************************
* Copyright (c) 2015-2019 itemis AG and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* itemis AG - initial API and implementation
* Robert Bosch GmbH
* - added listener for refreshing the editor on resource change
* - added workaround for CSS styling bug
********************************************************************************
*/
package org.eclipse.app4mc.amalthea.sphinx.ui.editors.editor;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.app4mc.amalthea.sphinx.ui.editors.SphinxSupportPlugin;
import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.NotEnabledException;
import org.eclipse.core.commands.NotHandledException;
import org.eclipse.core.commands.common.NotDefinedException;
import org.eclipse.core.expressions.EvaluationContext;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProjectNature;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Platform;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.ui.css.swt.theme.IThemeEngine;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.util.URI;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.util.Util;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.osgi.util.NLS;
import org.eclipse.sphinx.emf.editors.forms.BasicTransactionalFormEditor;
import org.eclipse.sphinx.emf.metamodel.IMetaModelDescriptor;
import org.eclipse.sphinx.emf.metamodel.MetaModelDescriptorRegistry;
import org.eclipse.sphinx.emf.model.IModelDescriptor;
import org.eclipse.sphinx.emf.model.ModelDescriptorRegistry;
import org.eclipse.sphinx.emf.ui.util.EcoreUIUtil;
import org.eclipse.sphinx.emf.util.EcorePlatformUtil;
import org.eclipse.sphinx.platform.util.PlatformLogUtil;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.ISources;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.commands.ICommandService;
@SuppressWarnings("restriction")
public class ExtendedBasicTransactionalFormEditor extends BasicTransactionalFormEditor
implements IResourceChangeListener {
private static final String AMALTHEA_MODEL_ID = "org.eclipse.app4mc.amalthea.model";
private static final String SHOW_TYPES_OF_ELEMENTS = "show_types_of_elements"; //$NON-NLS-1$
/**
* @see org.eclipse.sphinx.emf.editors.forms.BasicTransactionalFormEditor#getCustomAdapterFactory()
*/
@Override
protected AdapterFactory getCustomAdapterFactory() {
return ExtendedItemProviderAdapterFactory.INSTANCE;
}
/**
* @see org.eclipse.sphinx.emf.editors.forms.BasicTransactionalFormEditor#getEditorInputName()
*/
@Override
protected String getEditorInputName() {
final IEditorInput editorInput = getEditorInput();
final URI editorURI = EcoreUIUtil.getURIFromEditorInput(editorInput);
if (null != editorURI) {
final String fileName = editorURI.lastSegment();
return fileName;
}
return super.getEditorInputName();
}
/**
* @see org.eclipse.sphinx.emf.editors.forms.BasicTransactionalFormEditor#addPages()
*/
@Override
protected void addPages() {
// super.addPages();
try {
addPage(new ExtendedContentsTreePage(this));
} catch (final PartInitException e) {
PlatformLogUtil.logAsError(SphinxSupportPlugin.getDefault(), e);
}
addResourceChangeListener();
}
/**
* @param showTypes true shows the type names after the element names, false is
* standard behavior
*/
public void setShowTypesOfElements(final boolean showTypes) {
SphinxSupportPlugin.getDefault().getDialogSettings().put(SHOW_TYPES_OF_ELEMENTS, showTypes);
}
/**
* @return true shows the type names after the element names, false is standard
* behavior
*/
public boolean isShowTypesOfElements() {
return SphinxSupportPlugin.getDefault().getDialogSettings().getBoolean(SHOW_TYPES_OF_ELEMENTS);
}
/*
* Register listener for Resource change: here the context is marker deletion
*/
public void addResourceChangeListener() {
ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE);
}
@Override
public void resourceChanged(final IResourceChangeEvent event) {
final IWorkbenchPartSite site = getSite();
if (site == null) return;
final IWorkbenchPage page = site.getPage();
if (page == null) return;
IEditorPart editorPart = page.getActiveEditor();
if (!(editorPart instanceof ExtendedBasicTransactionalFormEditor)) return;
final ExtendedBasicTransactionalFormEditor activeEditor = (ExtendedBasicTransactionalFormEditor) editorPart;
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
Viewer viewer = activeEditor.getViewer();
if (viewer != null) {
viewer.refresh();
}
}
});
}
/*
* Workaround for empty viewer after click on already selected item
*
* On Windows some SWT bug avoids repainting of non selected elements. Since the related SWT issue
* has been discussed for years and no real fix was found, we try to limit the negative effects.
* See Bugzilla entries: 491737, 458015, 433858.
*
* If (1) OS is Windows and (2) theming is enabled then an additional redraw is called explicitly.
* Users may notice a minor flickering on selection. However, that is surely preferable to not seeing
* unselected elements at all.
*/
@Override
public void setSelection(ISelection selection) {
super.setSelection(selection);
if (Util.isWindows() == false) return; // No Windows OS -> no workaround required
MApplication application = PlatformUI.getWorkbench().getService(MApplication.class);
if (application == null) return;
IEclipseContext context = application.getContext();
if (context == null) return;
IThemeEngine engine = context.get(IThemeEngine.class);
if (engine == null) return; // Theming is not enabled -> no workaround required
// System.out.println("Theme is " + engine.getActiveTheme().getLabel());
// *** Workaround: additional redraw ***
Viewer viewer = getViewer();
if (viewer != null) {
Control control = viewer.getControl();
if (control != null) {
control.redraw();
}
}
}
@Override
protected void createPages() {
// check model version
if (!isFileContainingValidModelNameSpace())
return;
super.createPages();
}
/**
* This method is used to check if the file contains valid AMALTHEA model namespace
* (which is compatible to the current MetaModel)
* <br>
* In case if the version of model (associated to the input file) and Meta-Model
* are different -> Message is shown and Editor is not opened
*
*/
private boolean isFileContainingValidModelNameSpace() {
if (getEditorInputObject() != null)
return true; // valid Amalthea resource found
// Get the IFile object editorInput
IEditorInput editorInput = getEditorInput();
IFile iFileObject = EcoreUIUtil.getFileFromEditorInput(editorInput);
// verify if amlt.no.load.nature is configured.. if so do not load Amalthea model file
try {
IProjectNature nature = iFileObject.getProject().getNature("amlt.no.load.nature");
if (nature != null) {
// This is the case, Amalthea model should not be loaded
MessageDialog dialog = new MessageDialog(getSite().getShell(), "AMALTHEA Model Editor", null,
"File is not loaded as Amalthea \"no load\" nature is configured", MessageDialog.WARNING, 0,
"OK", "Remove \"no load\" nature");
int open = dialog.open();
if (open == 1) {
// This is the case user has requested to remove the "Amalthea no.load nature"
ICommandService cmdService = getSite().getService(ICommandService.class);
Command sampleCommand = cmdService.getCommand("org.eclipse.app4mc.amalthea.noload.nature.remove");
Map<String, Object> params = new HashMap<>();
if (open == 1)
try {
StructuredSelection selection = new StructuredSelection(iFileObject.getProject());
EvaluationContext context = new EvaluationContext(null, selection);
context.addVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME, selection);
ExecutionEvent event = new ExecutionEvent(sampleCommand, params, null, context);
sampleCommand.executeWithChecks(event);
return true;
} catch (ExecutionException | NotDefinedException | NotEnabledException
| NotHandledException e) {
e.printStackTrace();
}
} else if (open == 0 || open ==-1) {
close(false);
return false;
}
}
} catch (CoreException e) {
// This is a case where nature might not be associated with IProject (or) nature
// plugin is missing in the product
}
// Verify if the Model descriptor can be fetched from the File
IModelDescriptor modelDescriptorContent = ModelDescriptorRegistry.INSTANCE.getModel(iFileObject);
if (modelDescriptorContent != null)
return true; // valid model descriptor found
// Get the Meta-Model descriptor belonging to the current version of AMALTHEA meta model plugin
IMetaModelDescriptor metaModelDescriptor = MetaModelDescriptorRegistry.INSTANCE.getDescriptor(AMALTHEA_MODEL_ID);
if (metaModelDescriptor == null)
return true; // undecidable -> delegate the check behaviour to Sphinx
// Extracting namespace from MetaModel
String nsURIFromMetaModel = metaModelDescriptor.getRootEPackage().getNsURI();
// Extracting namespace from Model file
String nsURIFromModel = EcorePlatformUtil.readModelNamespace(iFileObject);
if ((nsURIFromMetaModel == null) || (nsURIFromModel == null))
return true; // undecidable -> delegate the check behaviour to Sphinx
// *** Check for unsupported itea versions (legacy) ***
final String legacyAMALTHEANameSpacePrefix_1 = "http://www.amalthea.itea2.org/model/";
final String legacyAMALTHEANameSpacePrefix_2 = "http://amalthea.itea2.org/model/";
if (nsURIFromModel.startsWith(legacyAMALTHEANameSpacePrefix_1)
|| nsURIFromModel.startsWith(legacyAMALTHEANameSpacePrefix_2)) {
// legacy version detected -> do not open and show error
MessageDialog.openWarning(getSite().getShell(), "AMALTHEA Model Editor",
"Unsupported File ! \r\rEditor could not be opened because of a legacy model file that is no longer supported.");
close(false);
return false;
}
// Extracting AMALTHEA model version
String versionFromModel = nsURIFromModel.lastIndexOf("/") != -1
? nsURIFromModel.substring(nsURIFromModel.lastIndexOf("/") + 1)
: nsURIFromModel;
// Extracting AMALTHEA metamodel version
String versionFromMetaModel = nsURIFromMetaModel.lastIndexOf("/") != -1
? nsURIFromMetaModel.substring(nsURIFromMetaModel.lastIndexOf("/") + 1)
: nsURIFromMetaModel;
// *** Compare the versions obtained from MetaModel and Model ***
if (versionFromMetaModel.equals(versionFromModel)) {
// current version detected
return true;
}
String versionMismatchMessage = NLS.bind(
"Unsupported File ! \r\rEditor could not be opened because of a version mismatch. \r\rFound AMALTHEA model version : {0}\rCurrent editor supports only AMALTHEA model version : {1}",
new Object[] { versionFromModel, versionFromMetaModel });
if (Platform.getBundle("org.eclipse.app4mc.amalthea.converters.ui") == null) {
// migration plugins are not loaded -> show warning
MessageDialog.openWarning(
getSite().getShell(), "AMALTHEA Model Editor",
versionMismatchMessage + "\r\r** AMALTHEA Model Migration utility is not available");
} else {
// other APP4MC version detected -> do not open and show migration hint
MessageDialog dialog = new MessageDialog(
getSite().getShell(), "AMALTHEA Model Editor", null,
versionMismatchMessage + "\r\r** Start AMALTHEA Model Migration utility to convert the model",
MessageDialog.QUESTION_WITH_CANCEL, 0,
"Migrate to " + versionFromMetaModel, "Show Migration Dialog", "Cancel");
int open = dialog.open();
// If user chose Migrate option then the Model Migration command is executed to show the migration dialog
// IF Start Simple Migration is selected then return value is 0 & for Show Migration Dialog it is 1
if (open == MessageDialog.OK || open == MessageDialog.CANCEL) {
ICommandService cmdService = getSite().getService(ICommandService.class);
Command sampleCommand = cmdService.getCommand("org.eclipse.app4mc.amalthea.modelmigration.dialog.cmd");
Map<String, String> params = new HashMap<>();
if (open == MessageDialog.OK)
params.put("executioncontext", "simplemigration");
try {
sampleCommand.executeWithChecks(new ExecutionEvent(sampleCommand, params, null, null));
} catch (ExecutionException | NotDefinedException | NotEnabledException | NotHandledException e) {
e.printStackTrace();
}
}
}
close(false);
return false;
}
}