blob: b25bddef9c8673579128f6b4dbe97585857d7fac [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2008 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.equinox.internal.provisional.p2.ui.viewers;
import java.util.EventObject;
import org.eclipse.equinox.internal.p2.ui.BatchChangeBeginningEvent;
import org.eclipse.equinox.internal.p2.ui.BatchChangeCompleteEvent;
import org.eclipse.equinox.internal.provisional.p2.core.eventbus.ProvisioningListener;
import org.eclipse.equinox.internal.provisional.p2.core.repository.IRepository;
import org.eclipse.equinox.internal.provisional.p2.core.repository.RepositoryEvent;
import org.eclipse.equinox.internal.provisional.p2.engine.ProfileEvent;
import org.eclipse.equinox.internal.provisional.p2.ui.model.ProfileElement;
import org.eclipse.equinox.internal.provisional.p2.ui.policy.IQueryProvider;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PlatformUI;
/**
* ProvisioningListener which updates a structured viewer based on
* provisioning changes. Provides default behavior which refreshes particular
* model elements or the entire viewer based on the nature of the change and the
* changes that the client is interested in. Subclasses typically only need
* override when there is additional, specialized behavior required.
*
* @since 3.4
*/
public class StructuredViewerProvisioningListener implements ProvisioningListener {
public static final int PROV_EVENT_METADATA_REPOSITORY = 0x0001;
public static final int PROV_EVENT_IU = 0x0002;
public static final int PROV_EVENT_PROFILE = 0x0004;
public static final int PROV_EVENT_ARTIFACT_REPOSITORY = 0x0008;
int eventTypes = 0;
int batchCount = 0;
StructuredViewer viewer;
Display display;
IQueryProvider queryProvider;
public StructuredViewerProvisioningListener(StructuredViewer viewer, int eventTypes, IQueryProvider queryProvider) {
this.viewer = viewer;
this.eventTypes = eventTypes;
this.display = viewer.getControl().getDisplay();
this.queryProvider = queryProvider;
}
public void notify(EventObject o) {
if (o instanceof BatchChangeBeginningEvent) {
batchCount++;
} else if (o instanceof BatchChangeCompleteEvent) {
batchCount--;
if (batchCount <= 0)
asyncRefresh();
} else if (batchCount > 0) {
// We are in the middle of a batch operation
return;
} else if (o instanceof ProfileEvent && (((eventTypes & PROV_EVENT_IU) == PROV_EVENT_IU) || ((eventTypes & PROV_EVENT_PROFILE) == PROV_EVENT_PROFILE))) {
ProfileEvent event = (ProfileEvent) o;
if (event.getReason() == ProfileEvent.CHANGED) {
profileChanged(event.getProfileId());
} else if (event.getReason() == ProfileEvent.ADDED) {
profileAdded(event.getProfileId());
} else if (event.getReason() == ProfileEvent.REMOVED) {
profileRemoved(event.getProfileId());
}
} else if (o instanceof RepositoryEvent) {
RepositoryEvent event = (RepositoryEvent) o;
// Do not refresh unless this is the type of repo that we are interested in
if ((event.getRepositoryType() == IRepository.TYPE_METADATA && (eventTypes & PROV_EVENT_METADATA_REPOSITORY) == PROV_EVENT_METADATA_REPOSITORY) || (event.getRepositoryType() == IRepository.TYPE_ARTIFACT && (eventTypes & PROV_EVENT_ARTIFACT_REPOSITORY) == PROV_EVENT_ARTIFACT_REPOSITORY)) {
if (event.getKind() == RepositoryEvent.ADDED) {
repositoryAdded(event);
} else if (event.getKind() == RepositoryEvent.REMOVED) {
repositoryRemoved(event);
} else if (event.getKind() == RepositoryEvent.DISCOVERED) {
repositoryDiscovered(event);
} else if (event.getKind() == RepositoryEvent.CHANGED) {
repositoryChanged(event);
}
}
}
}
/**
* A repository has been added. The default behavior is to
* refresh the viewer. Subclasses may override. May be called
* from a non-UI thread.
*
* @param event the RepositoryEvent describing the details
*/
protected void repositoryAdded(RepositoryEvent event) {
asyncRefresh();
}
/**
* A repository has been removed. The default behavior is to
* refresh the viewer. Subclasses may override. May be called
* from a non-UI thread.
*
* @param event the RepositoryEvent describing the details
*/
protected void repositoryRemoved(RepositoryEvent event) {
asyncRefresh();
}
/**
* A repository has been discovered. Subclasses may override. May be called
* from a non-UI thread.
*
* @param event the RepositoryEvent describing the details
*/
protected void repositoryDiscovered(RepositoryEvent event) {
// Do nothing for now
}
/**
* A repository has changed. Subclasses may override. May be called
* from a non-UI thread.
*
* @param event the RepositoryEvent describing the details
*/
protected void repositoryChanged(RepositoryEvent event) {
// Do nothing for now. When this event is actually used in
// the core, we may want to refresh particular elements the way
// we currently refresh a profile element.
}
/**
* The specified profile has changed. The default behavior is to refresh the viewer
* with a profile element of the matching id. Subclasses may override. May be called
* from a non-UI thread.
*
* @param profileId the id of the profile that changed.
*/
protected void profileChanged(final String profileId) {
display.asyncExec(new Runnable() {
public void run() {
if (isClosing())
return;
// We want to refresh the affected profile, so we
// construct a profile element on this profile.
ProfileElement element = new ProfileElement(profileId);
element.setQueryProvider(queryProvider);
viewer.refresh(element);
}
});
}
/**
* The specified profile has been added. The default behavior is to fully
* refresh the associated viewer. Subclasses may override. May be called
* from a non-UI thread.
*
* @param profileId the id of the profile that has been added.
*/
protected void profileAdded(final String profileId) {
asyncRefresh();
}
/**
* The specified profile has been removed. The default behavior is to fully
* refresh the associated viewer. Subclasses may override. May be called
* from a non-UI thread.
*
* @param profileId the id of the profile that has been removed.
*/
protected void profileRemoved(final String profileId) {
asyncRefresh();
}
protected void asyncRefresh() {
display.asyncExec(new Runnable() {
public void run() {
if (isClosing())
return;
refreshAll();
}
});
}
/**
* Refresh the entire structure of the viewer. Subclasses may
* override to ensure that any caching done in content providers or
* model elements is refreshed before the viewer is refreshed. This will
* always be called from the UI thread.
*/
protected void refreshAll() {
viewer.refresh();
}
public int getEventTypes() {
return eventTypes;
}
/**
* Return whether the viewer is closing or shutting down.
* This method should be used in async execs to ensure that
* the viewer is still alive.
* @return a boolean indicating whether the viewer is closing
*/
protected boolean isClosing() {
IWorkbench workbench = PlatformUI.getWorkbench();
if (workbench.isClosing())
return true;
if (viewer.getControl().isDisposed())
return true;
return false;
}
}