blob: c886e9d4ce3b8b170ee225ce27191cad580779c1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012 Rushan R. Gilmullin and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Rushan R. Gilmullin - initial API and implementation
*******************************************************************************/
package org.eclipse.osbp.e4extension.impl;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
import org.eclipse.core.runtime.Assert;
import org.eclipse.e4.core.contexts.ContextInjectionFactory;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.core.services.contributions.IContributionFactory;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.model.application.descriptor.basic.MPartDescriptor;
import org.eclipse.e4.ui.model.application.ui.MElementContainer;
import org.eclipse.e4.ui.model.application.ui.MUIElement;
import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
import org.eclipse.e4.ui.model.application.ui.advanced.MPerspectiveStack;
import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder;
import org.eclipse.e4.ui.model.application.ui.basic.MInputPart;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
import org.eclipse.e4.ui.model.application.ui.basic.impl.BasicFactoryImpl;
import org.eclipse.e4.ui.model.application.ui.menu.MToolBar;
import org.eclipse.e4.ui.workbench.modeling.EModelService;
import org.eclipse.e4.ui.workbench.modeling.EPartService;
import org.eclipse.e4.ui.workbench.modeling.EPartService.PartState;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.osbp.e4extension.service.EPartServiceExt;
import e4modelextension.EditorPartDescriptor;
import e4modelextension.VaaclipseApplication;
/**
* @author rushan
*
*/
public class PartServiceExtImpl implements EPartServiceExt {
@Inject
private IEclipseContext eclipseContext;
@Inject
private MApplication application;
@Inject
EPartService partService;
@Inject
EModelService modelService;
Map<String, Pattern> patterns = new HashMap<String, Pattern>();
private EPartService actualServiceImplementation;
@Override
public MInputPart createInputPart(String id) {
MPartDescriptor descriptor = findDescriptor(id);
return createInputPart(descriptor);
}
private MInputPart createInputPart(MPartDescriptor descriptor) {
if (descriptor == null) {
return null;
}
MInputPart part = BasicFactoryImpl.eINSTANCE.createInputPart();
part.setElementId(descriptor.getElementId());
part.getMenus().addAll(EcoreUtil.copyAll(descriptor.getMenus()));
if (descriptor.getToolbar() != null) {
part.setToolbar((MToolBar) EcoreUtil.copy((EObject) descriptor
.getToolbar()));
}
part.setContributorURI(descriptor.getContributorURI());
// part.setCloseable(descriptor.isCloseable());
part.setCloseable(true); // closable
part.setContributionURI(descriptor.getContributionURI());
part.setLabel(descriptor.getLabel());
part.setIconURI(descriptor.getIconURI());
part.setTooltip(descriptor.getTooltip());
part.getHandlers().addAll(EcoreUtil.copyAll(descriptor.getHandlers()));
part.getTags().addAll(descriptor.getTags());
part.getBindingContexts().addAll(descriptor.getBindingContexts());
part.getTags().add(EPartService.REMOVE_ON_HIDE_TAG);
return part;
}
@Override
public MPartDescriptor findDescriptor(String id) {
for (MPartDescriptor descriptor : application.getDescriptors()) {
if (descriptor.getElementId().equals(id)) {
return descriptor;
}
}
return null;
}
@Override
public EditorPartDescriptor findEditorPartDescriptorUsingId(String id) {
for (EditorPartDescriptor descriptor : ((VaaclipseApplication) application)
.getEditorDescriptors()) {
if (descriptor.getElementId().equals(id)) {
return descriptor;
}
}
return null;
}
@Override
public EditorPartDescriptor findEditorPartDescriptor(String inputUri) {
for (EditorPartDescriptor d : ((VaaclipseApplication) application)
.getEditorDescriptors()) {
if (d.getUriFilter() != null) {
String filter = d.getUriFilter().trim();
if (!filter.isEmpty()) {
if (!patterns.containsKey(filter)) {
patterns.put(filter, Pattern.compile(filter));
}
Pattern pattern = patterns.get(filter);
Matcher matcher = pattern.matcher(inputUri);
if (matcher.matches()) {
return d;
}
}
}
}
return null;
}
@Override
public MInputPart openUri(MElementContainer<?> area, String inputUri) {
EditorPartDescriptor editorPartDescriptor = findEditorPartDescriptor(inputUri);
return openUri(inputUri, editorPartDescriptor, area);
}
@Override
public MInputPart openUri(String inputUri,
EditorPartDescriptor editorPartDescriptor, MElementContainer<?> area) {
MInputPart part = ensurePartAdded(getWindow(), area,
editorPartDescriptor, inputUri);
// ATTENTION!!! We should use the EPartService showPart method ONLY if
// all contexts are crated (i.e. model is rendered)
// But this method (openURI) should be usable when model is not
// rendered. So we check the context and if it is created we use
// servive methods.
if (application.getContext() != null)
partService.showPart(part, PartState.ACTIVATE);
else // otherwise just select it in its container
{
MPlaceholder partPh = modelService.findPlaceholderFor(getWindow(),
part);
if (partPh != null) {
MElementContainer<MUIElement> parent = partPh.getParent();
parent.setSelectedElement(partPh);
} else {
MElementContainer<MUIElement> parent = part.getParent();
parent.setSelectedElement(part);
}
}
return part;
}
@Override
public MInputPart openUri(String inputUri) {
return this.openUri((MElementContainer<?>) null, inputUri);
}
@Override
public MInputPart openUri(String inputUri, EditorPartDescriptor descriptor) {
return this.openUri(inputUri, descriptor, null);
}
@Override
public MInputPart openUri(String inputUri, String editorDescriptorId) {
EditorPartDescriptor d = findEditorPartDescriptorUsingId(editorDescriptorId);
if (d != null) {
return openUri(inputUri, d);
} else
return null;
}
@Override
public void closeUri(String inputUri, boolean saveBeforeClose) {
MInputPart part = findPart(getWindow(), inputUri);
if (part == null)
return;
if (saveBeforeClose) {
IEclipseContext partContext = part.getContext();
if (partContext == null)
partContext = modelService.getContainingContext(part);
// Allow closes to be 'canceled'
EPartService partService = (EPartService) partContext
.get(EPartService.class.getName());
if (partService.savePart(part, true)) {
partService.hidePart(part, true);
}
} else {
partService.hidePart(part, true);
}
}
private MInputPart ensurePartAdded(MWindow window,
MElementContainer<?> area,
EditorPartDescriptor editorPartDescriptor, String inputUri) {
MInputPart part = findPart(window, inputUri);
if (part == null) {// else we create new part and add it with specified
// logic
// create part
part = addInputPart(window, area, editorPartDescriptor, inputUri);
// now part is added to window, so we all work is done
}
return part;
}
private MInputPart addInputPart(MWindow window, MElementContainer<?> area,
EditorPartDescriptor editorPartDescriptor, String inputUri) {
MInputPart part;
part = createInputPart(editorPartDescriptor);
part.setInputURI(inputUri);
// create context for add logic and set context info
IEclipseContext localContext = eclipseContext.createChild();
localContext.set(MPart.class, part);
localContext.set(MElementContainer.class, area);
localContext.set(MInputPart.class, part);
localContext.set(MWindow.class, window);
// obtain adding logic
IContributionFactory contributionFactory = (IContributionFactory) localContext
.get(IContributionFactory.class.getName());
Object addLogic = contributionFactory.create(
editorPartDescriptor.getPartAddingLogicUri(), localContext);
// execute adding logic
ContextInjectionFactory.invoke(addLogic, Execute.class, localContext);
return part;
}
@Override
public MInputPart openNewEditor(EditorPartDescriptor descriptor) {
return addInputPart(getWindow(), null, descriptor, null);
}
@Override
public MInputPart openNewEditor(String descriptorId) {
EditorPartDescriptor d = findEditorPartDescriptorUsingId(descriptorId);
if (d == null)
return null;
return openNewEditor(d);
}
private MInputPart findPart(MWindow window, String inputUri) {
MPerspectiveStack stack = null;
for (MUIElement e : window.getChildren()) {
if (e instanceof MPerspectiveStack) {
stack = (MPerspectiveStack) e;
break;
}
}
MPerspective persp = stack != null ? stack.getSelectedElement() : null;
MElementContainer<?> container = persp != null ? persp : window;
List<MPart> parts = modelService.findElements(container, null,
MPart.class, null, EModelService.OUTSIDE_PERSPECTIVE
| EModelService.IN_ACTIVE_PERSPECTIVE
| EModelService.IN_SHARED_AREA);
MInputPart part = null;
for (MPart p : parts) {
if (p instanceof MInputPart) {
String _inputUri = ((MInputPart) p).getInputURI();
if (inputUri.equals(_inputUri)) {
part = (MInputPart) p;
break;
}
}
}
return part;
}
private MWindow getWindow() {
if (application.getSelectedElement() != null)
return application.getSelectedElement();
List<MWindow> windows = application.getChildren();
if (windows.size() != 0)
return windows.get(0);
return null;
}
private EPartService getActualServiceImplementation() {
if (actualServiceImplementation != null)
return actualServiceImplementation;
try {
Method getActiveWindowService = partService.getClass()
.getDeclaredMethod("getActiveWindowService");
getActiveWindowService.setAccessible(true);
actualServiceImplementation = (EPartService) getActiveWindowService
.invoke(partService);
return actualServiceImplementation;
} catch (Exception e) {
return null;
}
}
public MPart showPart(String id, PartState partState) {
Assert.isNotNull(id);
Assert.isNotNull(partState);
MPart part = partService.findPart(id);
if (part == null) {
MPartDescriptor descriptor = findDescriptor(id);
try {
EPartService actualServiceImplementation = getActualServiceImplementation();
Method createPart = actualServiceImplementation.getClass()
.getDeclaredMethod("createPart", MPartDescriptor.class);
createPart.setAccessible(true);
part = (MPart) createPart.invoke(actualServiceImplementation,
descriptor);
} catch (Exception ex) {
return null;
}
if (part == null) {
return null;
}
}
// TODO - seems to work better that way!
return partService.showPart(part, partState);
}
public MPart addPart(MPart part) {
Assert.isNotNull(part);
MPart localPart = findPart(part.getElementId());
try {
EPartService actualServiceImplementation = getActualServiceImplementation();
Method addPart = actualServiceImplementation.getClass()
.getDeclaredMethod("addPart", MPart.class, MPart.class);
addPart.setAccessible(true);
return (MPart) addPart.invoke(actualServiceImplementation, part,
localPart == null ? part : localPart);
} catch (Exception ex) {
return null;
}
// return addPart(part, localPart == null ? part : localPart);
}
public MPart findPart(String id) {
List<MPart> parts = getParts(MPart.class, id);
return parts.size() > 0 ? parts.get(0) : null;
}
private <T> List<T> getParts(Class<T> cls, String id) {
return modelService.findElements(getWindow(), id, cls, null,
EModelService.OUTSIDE_PERSPECTIVE
| EModelService.IN_ANY_PERSPECTIVE
| EModelService.IN_SHARED_AREA);
}
}