blob: 7af32a25feea0a4080fa36940bd3ae5eef5005c0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
******************************************************************************/
package org.eclipse.ui.internal.e4.compatibility;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.e4.core.services.events.IEventBroker;
import org.eclipse.e4.core.services.log.Logger;
import org.eclipse.e4.ui.di.Focus;
import org.eclipse.e4.ui.di.Persist;
import org.eclipse.e4.ui.internal.workbench.swt.AbstractPartRenderer;
import org.eclipse.e4.ui.model.application.ui.MDirtyable;
import org.eclipse.e4.ui.model.application.ui.MUIElement;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
import org.eclipse.e4.ui.widgets.CTabFolder;
import org.eclipse.e4.ui.widgets.CTabItem;
import org.eclipse.e4.ui.workbench.UIEvents;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IPropertyListener;
import org.eclipse.ui.ISaveablePart;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPart2;
import org.eclipse.ui.IWorkbenchPartConstants;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.internal.ErrorEditorPart;
import org.eclipse.ui.internal.ErrorViewPart;
import org.eclipse.ui.internal.PartSite;
import org.eclipse.ui.internal.SaveableHelper;
import org.eclipse.ui.internal.ViewSite;
import org.eclipse.ui.internal.WorkbenchPage;
import org.eclipse.ui.internal.WorkbenchPartReference;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.internal.util.Util;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;
public abstract class CompatibilityPart {
public static final String COMPATIBILITY_EDITOR_URI = "bundleclass://org.eclipse.ui.workbench/org.eclipse.ui.internal.e4.compatibility.CompatibilityEditor"; //$NON-NLS-1$
public static final String COMPATIBILITY_VIEW_URI = "bundleclass://org.eclipse.ui.workbench/org.eclipse.ui.internal.e4.compatibility.CompatibilityView"; //$NON-NLS-1$
@Inject
Composite composite;
@Inject
Logger logger;
IWorkbenchPart wrapped;
MPart part;
@Inject
private IEventBroker eventBroker;
private boolean beingDisposed = false;
private boolean alreadyDisposed = false;
/**
* This handler will be notified when the part's widget has been un/set.
*/
private EventHandler widgetSetHandler = new EventHandler() {
public void handleEvent(Event event) {
// check that we're looking at our own part and that the widget is
// being unset
if (event.getProperty(UIEvents.EventTags.ELEMENT) == part
&& event.getProperty(UIEvents.EventTags.NEW_VALUE) == null) {
Assert.isTrue(!composite.isDisposed(),
"The widget should not have been disposed at this point"); //$NON-NLS-1$
beingDisposed = true;
WorkbenchPartReference reference = getReference();
// notify the workbench we're being closed
((WorkbenchPage) reference.getPage()).firePartClosed(CompatibilityPart.this);
}
}
};
/**
* This handler will be notified when the part's client object has been
* un/set.
*/
private EventHandler objectSetHandler = new EventHandler() {
public void handleEvent(Event event) {
// check that we're looking at our own part and that the object is
// being set
if (event.getProperty(UIEvents.EventTags.ELEMENT) == part
&& event.getProperty(UIEvents.EventTags.NEW_VALUE) != null) {
WorkbenchPartReference reference = getReference();
// notify the workbench we've been opened
((WorkbenchPage) reference.getPage()).firePartOpened(CompatibilityPart.this);
}
}
};
CompatibilityPart(MPart part) {
this.part = part;
}
public abstract WorkbenchPartReference getReference();
protected boolean createPartControl(final IWorkbenchPart legacyPart, Composite parent) {
try {
legacyPart.createPartControl(parent);
} catch (RuntimeException e) {
logger.error(e);
try {
// couldn't create the part, dispose of it
legacyPart.dispose();
} catch (Exception ex) {
// client code may have errors so we need to catch it
logger.error(ex);
}
// dispose the site that was originally initialized for this part
internalDisposeSite();
// create a new error part notifying the user of the failure
IStatus status = new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH,
"Failed to create the part's controls", e); //$NON-NLS-1$
WorkbenchPartReference reference = getReference();
wrapped = reference.createErrorPart(status);
try {
reference.initialize(wrapped);
wrapped.createPartControl(parent);
} catch (RuntimeException ex) {
// failed to create the error part, log it
logger.error(ex);
} catch (PartInitException ex) {
WorkbenchPlugin.log("Unable to initialize error part", ex.getStatus()); //$NON-NLS-1$
}
}
return true;
}
@Focus
void delegateSetFocus() {
try {
wrapped.setFocus();
} catch (Exception e) {
if (logger != null) {
String msg = "Error setting focus to : " + part.getClass().getName(); //$NON-NLS-1$
msg += ' ' + part.getLocalizedLabel();
logger.error(e, msg);
}
}
}
private void invalidate() {
WorkbenchPartReference reference = getReference();
reference.invalidate();
if (wrapped != null) {
try {
wrapped.dispose();
} catch (Exception e) {
// client code may have errors so we need to catch it
logger.error(e);
}
}
internalDisposeSite();
alreadyDisposed = true;
}
private String computeLabel() {
if (wrapped instanceof ErrorEditorPart || wrapped instanceof ErrorViewPart) {
return getReference().getTitle();
}
if (wrapped instanceof IWorkbenchPart2) {
String label = ((IWorkbenchPart2) wrapped).getPartName();
return Util.safeString(label);
}
IWorkbenchPartSite site = wrapped.getSite();
if (site != null) {
return Util.safeString(site.getRegisteredName());
}
return Util.safeString(wrapped.getTitle());
}
/**
* Returns whether this part is being disposed. This is used for
* invalidating this part so that it is not returned when a method expects a
* "working" part.
* <p>
* See bug 308492.
* </p>
*
* @return if the part is currently being disposed
*/
public boolean isBeingDisposed() {
return beingDisposed;
}
IWorkbenchPart createPart(WorkbenchPartReference reference) throws PartInitException {
// ask our reference to instantiate the part through the registry
return reference.createPart();
}
boolean handlePartInitException(PartInitException e) {
WorkbenchPartReference reference = getReference();
reference.invalidate();
if (wrapped instanceof IEditorPart) {
try {
wrapped.dispose();
} catch (Exception ex) {
// client code may have errors so we need to catch it
logger.error(ex);
}
}
internalDisposeSite();
alreadyDisposed = false;
WorkbenchPlugin.log("Unable to create part", e.getStatus()); //$NON-NLS-1$
wrapped = reference.createErrorPart(e.getStatus());
try {
reference.initialize(wrapped);
} catch (PartInitException ex) {
WorkbenchPlugin.log("Unable to initialize error part", ex.getStatus()); //$NON-NLS-1$
return false;
}
return true;
}
@PostConstruct
public void create() {
eventBroker.subscribe(UIEvents.UIElement.TOPIC_WIDGET, widgetSetHandler);
eventBroker.subscribe(UIEvents.Contribution.TOPIC_OBJECT, objectSetHandler);
WorkbenchPartReference reference = getReference();
try {
wrapped = createPart(reference);
// invoke init methods
reference.initialize(wrapped);
} catch (PartInitException e) {
if (!handlePartInitException(e)) {
return;
}
}
// hook reference listeners to the part
// reference.hookPropertyListeners();
Composite parent = new Composite(composite, SWT.NONE);
parent.setLayout(new FillLayout());
if (!createPartControl(wrapped, parent)) {
return;
}
part.setLabel(computeLabel());
part.setTooltip(wrapped.getTitleToolTip());
updateImages(part);
if (wrapped instanceof ISaveablePart) {
part.setDirty(((ISaveablePart) wrapped).isDirty());
}
wrapped.addPropertyListener(new IPropertyListener() {
public void propertyChanged(Object source, int propId) {
switch (propId) {
case IWorkbenchPartConstants.PROP_TITLE:
part.setLabel(computeLabel());
part.setTooltip(wrapped.getTitleToolTip());
updateImages(part);
break;
case IWorkbenchPartConstants.PROP_DIRTY:
if (wrapped instanceof ISaveablePart) {
((MDirtyable) part).setDirty(((ISaveablePart) wrapped).isDirty());
}
break;
case IWorkbenchPartConstants.PROP_INPUT:
WorkbenchPartReference ref = getReference();
((WorkbenchPage) ref.getSite().getPage()).firePartInputChanged(ref);
break;
}
}
});
}
void updateTabImages(MUIElement element) {
// Try to update the image if we're using a CTF
MUIElement refParent = element.getParent();
if (!(refParent instanceof MPartStack)) {
return;
}
if (!(refParent.getWidget() instanceof CTabFolder)) {
return;
}
CTabFolder ctf = (CTabFolder) refParent.getWidget();
if (ctf.isDisposed()) {
return;
}
CTabItem[] items = ctf.getItems();
for (CTabItem item : items) {
if (item.getData(AbstractPartRenderer.OWNING_ME) == element) {
item.setImage(wrapped.getTitleImage());
}
}
}
abstract void updateImages(MPart part);
public void deactivateActionBars(boolean forceHide) {
PartSite site = getReference().getSite();
site.deactivateActionBars(forceHide);
}
@PreDestroy
void destroy() {
if (!alreadyDisposed) {
invalidate();
}
eventBroker.unsubscribe(widgetSetHandler);
eventBroker.unsubscribe(objectSetHandler);
}
/**
* Disposes of the 3.x part's site if it has one. Subclasses may override
* but must call <code>super.disposeSite()</code> in its implementation.
*/
private void internalDisposeSite() {
PartSite site = getReference().getSite();
if (site != null) {
disposeSite(site);
}
}
/**
* Disposes of the 3.x part's site if it has one. Subclasses may override
* but must call <code>super.disposeSite()</code> in its implementation.
*/
void disposeSite(PartSite site) {
deactivateActionBars(site instanceof ViewSite);
site.dispose();
}
@Persist
void doSave() {
if (wrapped instanceof ISaveablePart) {
SaveableHelper.savePart((ISaveablePart) wrapped, wrapped, getReference().getSite()
.getWorkbenchWindow(), false);
}
}
public IWorkbenchPart getPart() {
return wrapped;
}
public MPart getModel() {
return part;
}
}