blob: f86a5ae6eb5a3fbecf1cc75016ba7fc276b77405 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2016 IBM Corporation and others.
*
* 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:
* IBM Corporation - initial API and implementation
* Jan-Hendrik Diederich, Bredex GmbH - bug 201052
* Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654
* Dirk Fauth <dirk.fauth@googlemail.com> - Bug 473063
* Patrik Suzzi <psuzzi@gmail.com> - Bug 500420
* Sopot Cela <scela@redhat.com> - Bug 502004
*******************************************************************************/
package org.eclipse.ui.internal.registry;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
import org.eclipse.e4.core.contexts.ContextInjectionFactory;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.services.log.Logger;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.model.application.ui.MSnippetContainer;
import org.eclipse.e4.ui.model.application.ui.MUIElement;
import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
import org.eclipse.e4.ui.workbench.modeling.EModelService;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.IPerspectiveDescriptor;
import org.eclipse.ui.IPerspectiveRegistry;
import org.eclipse.ui.IWorkbenchPreferenceConstants;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.activities.WorkbenchActivityHelper;
import org.eclipse.ui.internal.Workbench;
import org.eclipse.ui.internal.e4.compatibility.E4Util;
import org.eclipse.ui.internal.util.PrefUtil;
/**
* Perspective registry.
*/
public class PerspectiveRegistry implements IPerspectiveRegistry, IExtensionChangeHandler {
@Inject
private IExtensionRegistry extensionRegistry;
@Inject
EModelService modelService;
@Inject
MApplication application;
@Inject
IEclipseContext context;
private IEclipseContext impExpHandlerContext;
@Inject
Logger logger;
private Map<String, PerspectiveDescriptor> descriptors = new HashMap<>();
@PostConstruct
void postConstruct(MApplication application) {
IExtensionPoint point = extensionRegistry.getExtensionPoint("org.eclipse.ui.perspectives"); //$NON-NLS-1$
for (IConfigurationElement element : point.getConfigurationElements()) {
String id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
descriptors.put(id, new PerspectiveDescriptor(id, element));
}
List<MUIElement> snippets = application.getSnippets();
for (MUIElement snippet : snippets) {
if (snippet instanceof MPerspective) {
MPerspective perspective = (MPerspective) snippet;
String id = perspective.getElementId();
// See if the clone is customizing an a predefined perspective without changing
// its name
PerspectiveDescriptor existingDescriptor = descriptors.get(id);
if (existingDescriptor == null) {
// A custom perspective with its own name.
createDescriptor(perspective);
} else {
// A custom perspecitve with a name of a pre-defined perspective
existingDescriptor.setHasCustomDefinition(true);
}
}
}
impExpHandlerContext = context.createChild();
impExpHandlerContext.set(PerspectiveRegistry.class, this);
ContextInjectionFactory.make(ImportExportPespectiveHandler.class, impExpHandlerContext);
}
public void addPerspective(MPerspective perspective) {
application.getSnippets().add(perspective);
createDescriptor(perspective);
}
private void createDescriptor(MPerspective perspective) {
String label = perspective.getLocalizedLabel();
String originalId = getOriginalId(perspective);
PerspectiveDescriptor originalDescriptor = descriptors.get(originalId);
String id = perspective.getElementId();
PerspectiveDescriptor newDescriptor = new PerspectiveDescriptor(id, label, originalDescriptor);
if (perspective.getIconURI() != null) {
try {
ImageDescriptor img = ImageDescriptor.createFromURL(new URI(perspective.getIconURI()).toURL());
newDescriptor.setImageDescriptor(img);
} catch (MalformedURLException | URISyntaxException | IllegalArgumentException e) {
logger.warn(e, MessageFormat.format("Error on applying configured perspective icon: {0}", //$NON-NLS-1$
perspective.getIconURI()));
}
}
descriptors.put(id, newDescriptor);
}
/**
* Construct a new registry.
*/
public PerspectiveRegistry() {
IExtensionTracker tracker = PlatformUI.getWorkbench().getExtensionTracker();
tracker.registerHandler(this, null);
}
@Override
public IPerspectiveDescriptor clonePerspective(String id, String label, IPerspectiveDescriptor desc)
throws IllegalArgumentException {
// FIXME: compat clonePerspective. Not called in 3.8
E4Util.unsupported("clonePerspective"); //$NON-NLS-1$
return null;
}
@Override
public void deletePerspective(IPerspectiveDescriptor toDelete) {
PerspectiveDescriptor perspective = (PerspectiveDescriptor) toDelete;
if (perspective.isPredefined())
return;
descriptors.remove(perspective.getId());
removeSnippet(application, perspective.getId());
}
private MUIElement removeSnippet(MSnippetContainer snippetContainer, String id) {
MUIElement snippet = modelService.findSnippet(snippetContainer, id);
if (snippet != null)
snippetContainer.getSnippets().remove(snippet);
return snippet;
}
/**
* Deletes a list of perspectives
*
* @param perspToDelete
*/
public void deletePerspectives(ArrayList<IPerspectiveDescriptor> perspToDelete) {
for (IPerspectiveDescriptor descriptor : perspToDelete) {
deletePerspective(descriptor);
}
}
@Override
public IPerspectiveDescriptor findPerspectiveWithId(String perspectiveId) {
return findPerspectiveWithId(perspectiveId, true);
}
public IPerspectiveDescriptor findPerspectiveWithId(String perspectiveId, boolean considerRestrictRules) {
IPerspectiveDescriptor candidate = descriptors.get(perspectiveId);
if (considerRestrictRules && WorkbenchActivityHelper.restrictUseOf(candidate)) {
return null;
}
return candidate;
}
@Override
public IPerspectiveDescriptor findPerspectiveWithLabel(String label) {
for (IPerspectiveDescriptor descriptor : descriptors.values()) {
if (descriptor.getLabel().equals(label)) {
if (WorkbenchActivityHelper.restrictUseOf(descriptor)) {
return null;
}
return descriptor;
}
}
return null;
}
@Override
public String getDefaultPerspective() {
String defaultId = PrefUtil.getAPIPreferenceStore()
.getString(IWorkbenchPreferenceConstants.DEFAULT_PERSPECTIVE_ID);
// empty string may be returned but we want to return null if nothing
// found
if (defaultId.isEmpty() || findPerspectiveWithId(defaultId) == null) {
Workbench instance = Workbench.getInstance();
return instance == null ? null : instance.getDefaultPerspectiveId();
}
return defaultId;
}
@Override
public IPerspectiveDescriptor[] getPerspectives() {
Collection<?> descs = WorkbenchActivityHelper.restrictCollection(descriptors.values(), new ArrayList<>());
return descs.toArray(new IPerspectiveDescriptor[descs.size()]);
}
/**
* @see IPerspectiveRegistry#setDefaultPerspective(String)
*/
@Override
public void setDefaultPerspective(String id) {
IPerspectiveDescriptor desc = findPerspectiveWithId(id);
if (desc != null) {
PrefUtil.getAPIPreferenceStore().setValue(IWorkbenchPreferenceConstants.DEFAULT_PERSPECTIVE_ID, id);
}
}
/**
* Return <code>true</code> if a label is valid. This checks only the given
* label in isolation. It does not check whether the given label is used by any
* existing perspectives.
*
* @param label the label to test
* @return whether the label is valid
*/
public boolean validateLabel(String label) {
label = label.trim();
if (label.length() <= 0) {
return false;
}
return true;
}
@Override
public void revertPerspective(IPerspectiveDescriptor perspToRevert) {
PerspectiveDescriptor perspective = (PerspectiveDescriptor) perspToRevert;
if (!perspective.isPredefined())
return;
perspective.setHasCustomDefinition(false);
removeSnippet(application, perspective.getId());
}
/**
* Dispose the receiver.
*/
public void dispose() {
if (impExpHandlerContext != null) {
impExpHandlerContext.dispose();
}
PlatformUI.getWorkbench().getExtensionTracker().unregisterHandler(this);
// FIXME: what was this listener for?
// WorkbenchPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(
// preferenceListener);
}
@Override
public void removeExtension(IExtension source, Object[] objects) {
// TODO compat: what do we do about disappearing extensions
}
@Override
public void addExtension(IExtensionTracker tracker, IExtension addedExtension) {
// TODO compat: what do we do about appeaering extensions
}
/**
* Create a new perspective.
*
* @param label the name of the new descriptor
* @param originalDescriptor the descriptor on which to base the new descriptor
* @return a new perspective descriptor or <code>null</code> if the creation
* failed.
*/
public PerspectiveDescriptor createPerspective(String label, PerspectiveDescriptor originalDescriptor) {
String newID = createNewId(label, originalDescriptor);
PerspectiveDescriptor newDescriptor = new PerspectiveDescriptor(newID, label, originalDescriptor);
descriptors.put(newDescriptor.getId(), newDescriptor);
return newDescriptor;
}
/**
* Return an id for the new descriptor.
*
* The id must encode the original id. id is of the form &lt;originalId&gt;.label
*
* @param label
* @param originalDescriptor
* @return the new id
*/
private String createNewId(String label, PerspectiveDescriptor originalDescriptor) {
return originalDescriptor.getOriginalId() + '.' + label;
}
private String getOriginalId(MPerspective p) {
String id = p.getElementId();
String label = p.getLabel();
if (label == null) {
label = ""; //$NON-NLS-1$
logger.warn(String.format("Perspective %s has no label. Contributor is %s.", p.getElementId(), //$NON-NLS-1$
p.getContributorURI()));
}
int index = id.lastIndexOf('.');
// Custom perspectives store the user defined names in their labels
String trimE4 = label.trim();
String trimE3 = label.replace(' ', '_').trim();
if (id.endsWith(label)) {
index = id.lastIndexOf(label) - 1;
} else if (id.endsWith(trimE4)) {
index = id.lastIndexOf(trimE4) - 1;
} else if (id.endsWith(trimE3)) {
index = id.lastIndexOf(trimE3) - 1;
}
if (index >= 0 && index < id.length()) {
return id.substring(0, index);
}
return id;
}
}