blob: e2ec0ab3d6e278d8fd703d3786df61ce9c29312e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004 - 2006 University Of British Columbia 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:
* University Of British Columbia - initial API and implementation
*******************************************************************************/
package org.eclipse.mylar.internal.core;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import org.eclipse.mylar.internal.core.util.ITimerThreadListener;
import org.eclipse.mylar.internal.core.util.MylarStatusHandler;
import org.eclipse.mylar.internal.core.util.TimerThread;
import org.eclipse.mylar.provisional.core.AbstractRelationProvider;
import org.eclipse.mylar.provisional.core.IInteractionEventListener;
import org.eclipse.mylar.provisional.core.IMylarContext;
import org.eclipse.mylar.provisional.core.IMylarContextListener;
import org.eclipse.mylar.provisional.core.IMylarElement;
import org.eclipse.mylar.provisional.core.IMylarRelation;
import org.eclipse.mylar.provisional.core.IMylarStructureBridge;
import org.eclipse.mylar.provisional.core.InteractionEvent;
import org.eclipse.mylar.provisional.core.InterestComparator;
import org.eclipse.mylar.provisional.core.MylarPlugin;
/**
* This is the core class resposible for context management.
*
* @author Mik Kersten
*/
public class MylarContextManager {
// TODO: move constants
private static final String CONTEXT_FILENAME_ENCODING = "UTF-8";
public static final String ACTIVITY_DELTA_DEACTIVATED = "deactivated";
public static final String ACTIVITY_DELTA_ACTIVATED = "activated";
public static final String ACTIVITY_ORIGIN_ID = "org.eclipse.mylar.core";
public static final String ACTIVITY_HANDLE_ATTENTION = "attention";
public static final String ACTIVITY_HANDLE_LIFECYCLE = "lifecycle";
public static final String ACTIVITY_DELTA_STARTED = "started";
public static final String ACTIVITY_DELTA_STOPPED = "stopped";
public static final String ACTIVITY_STRUCTURE_KIND = "context";
private static final int TIMEOUT_INACTIVITY_MILLIS = 2 * 60 * 1000;
public static final String CONTEXT_HISTORY_FILE_NAME = "context-history";
public static final String SOURCE_ID_MODEL_PROPAGATION = "org.eclipse.mylar.core.model.interest.propagation";
public static final String SOURCE_ID_DECAY = "org.eclipse.mylar.core.model.interest.decay";
public static final String SOURCE_ID_DECAY_CORRECTION = "org.eclipse.mylar.core.model.interest.decay.correction";
public static final String SOURCE_ID_MODEL_ERROR = "org.eclipse.mylar.core.model.interest.propagation";
public static final String CONTAINMENT_PROPAGATION_ID = "org.eclipse.mylar.core.model.edges.containment";
public static final String CONTEXT_FILE_EXTENSION = ".xml";
private static final int MAX_PROPAGATION = 17; // TODO: parametrize this
private int numInterestingErrors = 0;
private List<String> errorElementHandles = new ArrayList<String>();
private boolean contextCapturePaused = false;
private CompositeContext currentContext = new CompositeContext();
private MylarContext activityMetaContext = null;
private ActivityListener activityListener;
private int inactivityTimeout = TIMEOUT_INACTIVITY_MILLIS;
private List<IMylarContextListener> activityMetaContextListeners = new ArrayList<IMylarContextListener>();
private List<IMylarContextListener> listeners = new ArrayList<IMylarContextListener>();
private List<IMylarContextListener> waitingListeners = new ArrayList<IMylarContextListener>();
private boolean suppressListenerNotification = false;
private MylarContextExternalizer externalizer = new MylarContextExternalizer();
private boolean activationHistorySuppressed = false;
public static final String CONTEXT_HANDLE_DELIM = "-";
private static ScalingFactors scalingFactors = new ScalingFactors();
private final ShellLifecycleListener shellLifecycleListener;
private class ActivityListener implements ITimerThreadListener, IInteractionEventListener, IMylarContextListener {
private TimerThread timer;
private int sleepPeriod = 60000;
private boolean isStalled;
public ActivityListener(int millis) {
timer = new TimerThread(millis);
timer.addListener(this);
timer.start();
sleepPeriod = millis;
MylarPlugin.getDefault().addInteractionListener(this);
}
public void fireTimedOut() {
if (!isStalled) {
handleActivityMetaContextEvent(new InteractionEvent(InteractionEvent.Kind.COMMAND, ACTIVITY_STRUCTURE_KIND,
ACTIVITY_HANDLE_ATTENTION, ACTIVITY_ORIGIN_ID, null, ACTIVITY_DELTA_DEACTIVATED, 1f));
}
isStalled = true;
}
public void intervalElapsed() {
// ignore
}
public void interactionObserved(InteractionEvent event) {
timer.resetTimer();
if (isStalled) {
handleActivityMetaContextEvent(new InteractionEvent(InteractionEvent.Kind.COMMAND, ACTIVITY_STRUCTURE_KIND,
ACTIVITY_HANDLE_ATTENTION, ACTIVITY_ORIGIN_ID, null, ACTIVITY_DELTA_ACTIVATED, 1f));
}
isStalled = false;
}
public void startObserving() {
}
public void stopTimer() {
timer.kill();
MylarPlugin.getDefault().removeInteractionListener(this);
}
public void stopObserving() {
}
public void setTimeout(int millis) {
timer.kill();
sleepPeriod = millis;
timer = new TimerThread(millis);
timer.addListener(this);
timer.start();
}
public void contextActivated(IMylarContext context) {
interactionObserved(null);
timer.kill();
timer = new TimerThread(sleepPeriod);
timer.addListener(this);
timer.start();
}
public void contextDeactivated(IMylarContext context) {
interactionObserved(null);
timer.kill();
}
public void presentationSettingsChanging(UpdateKind kind) {
// ignore
}
public void presentationSettingsChanged(UpdateKind kind) {
// ignore
}
public void interestChanged(List<IMylarElement> elements) {
// ignore
}
public void nodeDeleted(IMylarElement element) {
// ignore
}
public void landmarkAdded(IMylarElement element) {
// ignore
}
public void landmarkRemoved(IMylarElement element) {
// ignore
}
public void edgesChanged(IMylarElement element) {
// ignore
}
}
public MylarContextManager() {
File storeDir = new File(MylarPlugin.getDefault().getDataDirectory());
storeDir.mkdirs();
activityMetaContext = externalizer.readContextFromXML(CONTEXT_HISTORY_FILE_NAME,
getFileForContext(CONTEXT_HISTORY_FILE_NAME));
if (activityMetaContext == null) {
resetActivityHistory();
}
for (IMylarContextListener listener : activityMetaContextListeners) {
listener.contextActivated(activityMetaContext);
}
shellLifecycleListener = new ShellLifecycleListener(this);
activityListener = new ActivityListener(TIMEOUT_INACTIVITY_MILLIS);// INACTIVITY_TIMEOUT_MILLIS);
this.addListener(activityListener);
activityListener.startObserving();
}
public void handleActivityMetaContextEvent(InteractionEvent event) {
IMylarElement element = activityMetaContext.parseEvent(event);
for (IMylarContextListener listener : activityMetaContextListeners) {
try {
List<IMylarElement> changed = new ArrayList<IMylarElement>();
changed.add(element);
listener.interestChanged(changed);
} catch (Throwable t) {
MylarStatusHandler.fail(t, "context listener failed", false);
}
}
}
public void setInactivityTimeout(int millis) {
inactivityTimeout = millis;
activityListener.setTimeout(millis);
}
/**
* @return timeout in mililiseconds
*/
public int getInactivityTimeout() {
return inactivityTimeout;
}
public IMylarElement getActiveElement() {
if (currentContext != null) {
return currentContext.getActiveNode();
} else {
return null;
}
}
public void addErrorPredictedInterest(String handle, String kind, boolean notify) {
if (numInterestingErrors > scalingFactors.getMaxNumInterestingErrors()
|| currentContext.getContextMap().isEmpty())
return;
InteractionEvent errorEvent = new InteractionEvent(InteractionEvent.Kind.PROPAGATION, kind, handle,
SOURCE_ID_MODEL_ERROR, scalingFactors.getErrorInterest());
handleInteractionEvent(errorEvent, true);
errorElementHandles.add(handle);
numInterestingErrors++;
}
/**
* TODO: worry about decay-related change if predicted interest dacays
*/
public void removeErrorPredictedInterest(String handle, String kind, boolean notify) {
if (currentContext.getContextMap().isEmpty())
return;
if (handle == null)
return;
IMylarElement element = currentContext.get(handle);
if (element != null && element.getInterest().isInteresting() && errorElementHandles.contains(handle)) {
InteractionEvent errorEvent = new InteractionEvent(InteractionEvent.Kind.MANIPULATION, kind, handle,
SOURCE_ID_MODEL_ERROR, -scalingFactors.getErrorInterest());
handleInteractionEvent(errorEvent, true);
numInterestingErrors--;
errorElementHandles.remove(handle);
// TODO: this results in double-notification
if (notify)
for (IMylarContextListener listener : new ArrayList<IMylarContextListener>(listeners)) {
List<IMylarElement> changed = new ArrayList<IMylarElement>();
changed.add(element);
listener.interestChanged(changed);
}
}
}
public IMylarElement getElement(String elementHandle) {
if (currentContext != null && elementHandle != null) {
return currentContext.get(elementHandle);
} else {
return null;
}
}
public IMylarElement handleInteractionEvent(InteractionEvent event) {
return handleInteractionEvent(event, true);
}
public IMylarElement handleInteractionEvent(InteractionEvent event, boolean propagateToParents) {
return handleInteractionEvent(event, propagateToParents, true);
}
public void handleInteractionEvents(List<InteractionEvent> events, boolean propagateToParents) {
Set<IMylarElement> compositeDelta = new HashSet<IMylarElement>();
for (InteractionEvent event : events) {
compositeDelta.addAll(internalHandleInteractionEvent(event, propagateToParents));
}
notifyInterestDelta(new ArrayList<IMylarElement>(compositeDelta));
}
public IMylarElement handleInteractionEvent(InteractionEvent event, boolean propagateToParents,
boolean notifyListeners) {
List<IMylarElement> interestDelta = internalHandleInteractionEvent(event, propagateToParents);
if (notifyListeners) {
notifyInterestDelta(interestDelta);
}
return currentContext.get(event.getStructureHandle());
}
private List<IMylarElement> internalHandleInteractionEvent(InteractionEvent event, boolean propagateToParents) {
if (contextCapturePaused || InteractionEvent.Kind.COMMAND.equals(event.getKind()) || !isContextActive()
|| suppressListenerNotification) {
return Collections.emptyList();
}
IMylarElement previous = currentContext.get(event.getStructureHandle());
float previousInterest = 0;
boolean previouslyPredicted = false;
boolean previouslyPropagated = false;
float decayOffset = 0;
if (previous != null) {
previousInterest = previous.getInterest().getValue();
previouslyPredicted = previous.getInterest().isPredicted();
previouslyPropagated = previous.getInterest().isPropagated();
}
if (event.getKind().isUserEvent()) {
decayOffset = ensureIsInteresting(event.getStructureKind(), event.getStructureHandle(), previous, previousInterest);
}
IMylarElement element = currentContext.addEvent(event);
List<IMylarElement> interestDelta = new ArrayList<IMylarElement>();
if (propagateToParents && !event.getKind().equals(InteractionEvent.Kind.MANIPULATION)) {
propegateInterestToParents(event.getKind(), element, previousInterest, decayOffset, 1, interestDelta);
}
if (event.getKind().isUserEvent())
currentContext.setActiveElement(element);
if (isInterestDelta(previousInterest, previouslyPredicted, previouslyPropagated, element)) {
interestDelta.add(element);
}
checkForLandmarkDeltaAndNotify(previousInterest, element);
return interestDelta;
}
private float ensureIsInteresting(String contentType, String handle, IMylarElement previous, float previousInterest) {
float decayOffset = 0;
if (previousInterest < 0) { // reset interest if not interesting
decayOffset = (-1) * (previous.getInterest().getValue());
currentContext.addEvent(new InteractionEvent(InteractionEvent.Kind.MANIPULATION,
contentType, handle, SOURCE_ID_DECAY_CORRECTION, decayOffset));
}
return decayOffset;
}
private void notifyInterestDelta(List<IMylarElement> interestDelta) {
if (!interestDelta.isEmpty()) {
for (IMylarContextListener listener : new ArrayList<IMylarContextListener>(listeners)) {
listener.interestChanged(interestDelta);
}
}
}
protected boolean isInterestDelta(float previousInterest, boolean previouslyPredicted, boolean previouslyPropagated,
IMylarElement node) {
float currentInterest = node.getInterest().getValue();
if (previousInterest <= 0 && currentInterest > 0) {
return true;
} else if (previousInterest > 0 && currentInterest <= 0) {
return true;
} else if (currentInterest > 0 && previouslyPredicted && !node.getInterest().isPredicted()) {
return true;
} else if (currentInterest > 0 && previouslyPropagated && !node.getInterest().isPropagated()) {
return true;
} else {
return false;
}
}
protected void checkForLandmarkDeltaAndNotify(float previousInterest, IMylarElement node) {
// TODO: don't call interestChanged if it's a landmark?
IMylarStructureBridge bridge = MylarPlugin.getDefault().getStructureBridge(node.getContentType());
if (bridge.canBeLandmark(node.getHandleIdentifier())) {
if (previousInterest >= scalingFactors.getLandmark() && !node.getInterest().isLandmark()) {
for (IMylarContextListener listener : new ArrayList<IMylarContextListener>(listeners))
listener.landmarkRemoved(node);
} else if (previousInterest < scalingFactors.getLandmark() && node.getInterest().isLandmark()) {
for (IMylarContextListener listener : new ArrayList<IMylarContextListener>(listeners))
listener.landmarkAdded(node);
}
}
}
private void propegateInterestToParents(InteractionEvent.Kind kind, IMylarElement node, float previousInterest, float decayOffset, int level,
List<IMylarElement> interestDelta) {
if (level > MAX_PROPAGATION || node == null || node.getInterest().getValue() <= 0) {
return;
}
checkForLandmarkDeltaAndNotify(previousInterest, node);
level++; // original is 1st level
float propagatedIncrement = node.getInterest().getValue() - previousInterest + decayOffset;
IMylarStructureBridge bridge = MylarPlugin.getDefault().getStructureBridge(node.getContentType());
String parentHandle = bridge.getParentHandle(node.getHandleIdentifier());
if (parentHandle != null) {
InteractionEvent propagationEvent = new InteractionEvent(InteractionEvent.Kind.PROPAGATION, bridge
.getContentType(node.getHandleIdentifier()), bridge.getParentHandle(node.getHandleIdentifier()),
SOURCE_ID_MODEL_PROPAGATION, CONTAINMENT_PROPAGATION_ID, propagatedIncrement);
IMylarElement previous = currentContext.get(propagationEvent.getStructureHandle());
if (previous != null && previous.getInterest() != null) {
previousInterest = previous.getInterest().getValue();
}
CompositeContextElement parentNode = (CompositeContextElement) currentContext.addEvent(propagationEvent);
if (kind.isUserEvent() && parentNode.getInterest().getEncodedValue() < scalingFactors.getInteresting()) {
float parentOffset = ((-1) * parentNode.getInterest().getEncodedValue()) + 1;
currentContext.addEvent(new InteractionEvent(InteractionEvent.Kind.MANIPULATION,
parentNode.getContentType(), parentNode.getHandleIdentifier(), SOURCE_ID_DECAY_CORRECTION, parentOffset));
// ensureIsInteresting(parentNode.getContentType(), parentNode.getHandleIdentifier(), parentNode, parentNode.getInterest().getEncodedValue());
}
if (isInterestDelta(previousInterest, previous.getInterest().isPredicted(), previous.getInterest()
.isPropagated(), parentNode)) {
interestDelta.add(0, parentNode);
}
propegateInterestToParents(kind, parentNode, previousInterest, decayOffset, level, interestDelta);// adapter.getResourceExtension(),
}
}
public List<IMylarElement> findCompositesForNodes(List<MylarContextElement> nodes) {
List<IMylarElement> composites = new ArrayList<IMylarElement>();
for (MylarContextElement node : nodes) {
composites.add(currentContext.get(node.getHandleIdentifier()));
}
return composites;
}
public void addListener(IMylarContextListener listener) {
if (listener != null) {
if (suppressListenerNotification && !waitingListeners.contains(listener)) {
waitingListeners.add(listener);
} else {
if (!listeners.contains(listener))
listeners.add(listener);
}
} else {
MylarStatusHandler.log("attempted to add null lisetener", this);
}
}
public void removeListener(IMylarContextListener listener) {
listeners.remove(listener);
}
public void addActivityMetaContextListener(IMylarContextListener listener) {
activityMetaContextListeners.add(listener);
}
public void removeActivityMetaContextListener(IMylarContextListener listener) {
activityMetaContextListeners.remove(listener);
}
public void removeAllListeners() {
listeners.clear();
}
public void notifyPostPresentationSettingsChange(IMylarContextListener.UpdateKind kind) {
for (IMylarContextListener listener : listeners)
listener.presentationSettingsChanged(kind);
}
public void notifyActivePresentationSettingsChange(IMylarContextListener.UpdateKind kind) {
for (IMylarContextListener listener : listeners)
listener.presentationSettingsChanging(kind);
}
/**
* Public for testing, activiate via handle
*/
public void activateContext(MylarContext context) {
currentContext.getContextMap().put(context.getHandleIdentifier(), context);
if (!activationHistorySuppressed) {
handleActivityMetaContextEvent(new InteractionEvent(InteractionEvent.Kind.COMMAND, ACTIVITY_STRUCTURE_KIND, context
.getHandleIdentifier(), ACTIVITY_ORIGIN_ID, null, ACTIVITY_DELTA_ACTIVATED, 1f));
}
}
public List<MylarContext> getActiveContexts() {
return new ArrayList<MylarContext>(currentContext.getContextMap().values());
}
public void activateContext(String handleIdentifier) {
try {
suppressListenerNotification = true;
MylarContext context = currentContext.getContextMap().get(handleIdentifier);
if (context == null)
context = loadContext(handleIdentifier);
if (context != null) {
activateContext(context);
for (IMylarContextListener listener : new ArrayList<IMylarContextListener>(listeners)) {
try {
listener.contextActivated(context);
} catch (Exception e) {
MylarStatusHandler.fail(e, "context listener failed", false);
}
}
refreshRelatedElements();
} else {
MylarStatusHandler.log("Could not load context", this);
}
suppressListenerNotification = false;
listeners.addAll(waitingListeners);
waitingListeners.clear();
} catch (Throwable t) {
MylarStatusHandler.log(t, "Could not activate context");
}
}
/**
* Could load in the context and inspect it, but this is cheaper.
*/
public boolean hasContext(String path) {
File contextFile = getFileForContext(path);
return contextFile.exists() && contextFile.length() > 0;
}
void deactivateAllContexts() {
for (String handleIdentifier : currentContext.getContextMap().keySet()) {
deactivateContext(handleIdentifier);
}
}
public void deactivateContext(String handleIdentifier) {
try {
IMylarContext context = currentContext.getContextMap().get(handleIdentifier);
if (context != null) {
saveContext(handleIdentifier);
currentContext.getContextMap().remove(handleIdentifier);
setContextCapturePaused(true);
for (IMylarContextListener listener : new ArrayList<IMylarContextListener>(listeners)) {
try {
listener.contextDeactivated(context);
} catch (Exception e) {
MylarStatusHandler.fail(e, "context listener failed", false);
}
}
setContextCapturePaused(false);
}
if (!activationHistorySuppressed) {
handleActivityMetaContextEvent(new InteractionEvent(InteractionEvent.Kind.COMMAND, ACTIVITY_STRUCTURE_KIND,
handleIdentifier, ACTIVITY_ORIGIN_ID, null, ACTIVITY_DELTA_DEACTIVATED, 1f));
}
saveActivityHistoryContext();
} catch (Throwable t) {
MylarStatusHandler.log(t, "Could not deactivate context");
}
}
public void deleteContext(String handleIdentifier) {
IMylarContext context = currentContext.getContextMap().get(handleIdentifier);
eraseContext(handleIdentifier, false);
if (context != null) {
// TODO: this notification is redundant with eraseContext's
setContextCapturePaused(true);
for (IMylarContextListener listener : new ArrayList<IMylarContextListener>(listeners)) {
listener.contextDeactivated(context);
}
setContextCapturePaused(false);
}
try {
File file = getFileForContext(handleIdentifier);
if (file.exists()) {
file.delete();
}
} catch (SecurityException e) {
MylarStatusHandler.fail(e, "Could not delete context file", false);
}
}
private void eraseContext(String id, boolean notify) {
MylarContext context = currentContext.getContextMap().get(id);
if (context == null)
return;
currentContext.getContextMap().remove(context);
context.reset();
if (notify) {
for (IMylarContextListener listener : listeners)
listener.presentationSettingsChanging(IMylarContextListener.UpdateKind.UPDATE);
}
}
/**
* @return false if the map could not be read for any reason
*/
public MylarContext loadContext(String handleIdentifier) {
MylarContext loadedContext = externalizer.readContextFromXML(handleIdentifier,
getFileForContext(handleIdentifier));
if (loadedContext == null) {
return new MylarContext(handleIdentifier, MylarContextManager.getScalingFactors());
} else {
return loadedContext;
}
}
public void saveContext(String handleIdentifier) {
try {
setContextCapturePaused(true);
MylarContext context = currentContext.getContextMap().get(handleIdentifier);
if (context == null)
return;
context.collapse();
externalizer.writeContextToXML(context, getFileForContext(handleIdentifier));
} catch (Throwable t) {
MylarStatusHandler.fail(t, "could not save context", false);
} finally {
setContextCapturePaused(false);
}
}
public void saveActivityHistoryContext() {
try {
setContextCapturePaused(true);
externalizer.writeContextToXML(activityMetaContext, getFileForContext(CONTEXT_HISTORY_FILE_NAME));
} catch (Throwable t) {
MylarStatusHandler.fail(t, "could not save activity history", false);
} finally {
setContextCapturePaused(false);
}
}
public File getFileForContext(String handleIdentifier) {
String encoded;
try {
encoded = URLEncoder.encode(handleIdentifier, CONTEXT_FILENAME_ENCODING);
String dataDirectory = MylarPlugin.getDefault().getDataDirectory();
File contextFile = new File(dataDirectory + File.separator + encoded + CONTEXT_FILE_EXTENSION);
return contextFile;
} catch (UnsupportedEncodingException e) {
MylarStatusHandler.fail(e, "Could not determine path for context", false);
}
return null;
}
public IMylarContext getActiveContext() {
return currentContext;
}
/**
* @param kind
*/
public void resetLandmarkRelationshipsOfKind(String reltationKind) {
for (IMylarElement landmark : currentContext.getLandmarks()) {
for (IMylarRelation edge : landmark.getRelations()) {
if (edge.getRelationshipHandle().equals(reltationKind)) {
landmark.clearRelations();
}
}
}
for (IMylarContextListener listener : listeners)
listener.edgesChanged(null);
}
/**
* Copy the listener list in case it is modified during the notificiation.
*
* @param node
*/
public void notifyRelationshipsChanged(IMylarElement node) {
if (suppressListenerNotification)
return;
for (IMylarContextListener listener : new ArrayList<IMylarContextListener>(listeners)) {
listener.edgesChanged(node);
}
}
public void refreshRelatedElements() {
try {
for (IMylarStructureBridge bridge : MylarPlugin.getDefault().getStructureBridges().values()) {
if (bridge.getRelationshipProviders() != null) {
for (AbstractRelationProvider provider : bridge.getRelationshipProviders()) {
List<AbstractRelationProvider> providerList = new ArrayList<AbstractRelationProvider>();
providerList.add(provider);
updateDegreesOfSeparation(providerList, provider.getCurrentDegreeOfSeparation());
}
}
}
} catch (Throwable t) {
MylarStatusHandler.fail(t, "Could not refresn related elements", false);
}
}
public List<AbstractRelationProvider> getActiveRelationProviders() {
List<AbstractRelationProvider> providers = new ArrayList<AbstractRelationProvider>();
Map<String, IMylarStructureBridge> bridges = MylarPlugin.getDefault().getStructureBridges();
for (Entry<String, IMylarStructureBridge> entry : bridges.entrySet()) {
IMylarStructureBridge bridge = entry.getValue();// bridges.get(extension);
if (bridge.getRelationshipProviders() != null) {
providers.addAll(bridge.getRelationshipProviders());
}
}
return providers;
}
public void updateDegreeOfSeparation(AbstractRelationProvider provider, int degreeOfSeparation) {
MylarPlugin.getContextManager().resetLandmarkRelationshipsOfKind(provider.getId());
if (degreeOfSeparation <= 0) {
// provider.setEnabled(false);
provider.setDegreeOfSeparation(degreeOfSeparation);
} else {
// provider.setEnabled(true);
provider.setDegreeOfSeparation(degreeOfSeparation);
for (IMylarElement node : currentContext.getLandmarks())
provider.landmarkAdded(node);
}
}
public void updateDegreesOfSeparation(List<AbstractRelationProvider> providers, int degreeOfSeparation) {
for (AbstractRelationProvider provider : providers) {
updateDegreeOfSeparation(provider, degreeOfSeparation);
}
}
public static ScalingFactors getScalingFactors() {
return MylarContextManager.scalingFactors;
}
public boolean isContextActive() {
return !contextCapturePaused && currentContext.getContextMap().values().size() > 0;
}
public List<IMylarElement> getActiveLandmarks() {
List<IMylarElement> allLandmarks = currentContext.getLandmarks();
List<IMylarElement> acceptedLandmarks = new ArrayList<IMylarElement>();
for (IMylarElement node : allLandmarks) {
IMylarStructureBridge bridge = MylarPlugin.getDefault().getStructureBridge(node.getContentType());
if (bridge.canBeLandmark(node.getHandleIdentifier())) {
acceptedLandmarks.add(node);
}
}
return acceptedLandmarks;
}
/**
* Sorted in descending interest order.
*/
public List<IMylarElement> getInterestingDocuments(IMylarContext context) {
Set<IMylarElement> set = new HashSet<IMylarElement>();
List<IMylarElement> allIntersting = context.getInteresting();
for (IMylarElement node : allIntersting) {
if (MylarPlugin.getDefault().getStructureBridge(node.getContentType()).isDocument(
node.getHandleIdentifier())) {
set.add(node);
}
}
List<IMylarElement> list = new ArrayList<IMylarElement>(set);
Collections.sort(list, new InterestComparator<IMylarElement>());
return list;
}
/**
* Get the interesting resources for the active context.
*
* Sorted in descending interest order.
*/
public List<IMylarElement> getInterestingDocuments() {
return getInterestingDocuments(currentContext);
}
public MylarContext getActivityHistoryMetaContext() {
return activityMetaContext;
}
public void resetActivityHistory() {
activityMetaContext = new MylarContext(CONTEXT_HISTORY_FILE_NAME, MylarContextManager.getScalingFactors());
saveActivityHistoryContext();
}
public boolean isActivationHistorySuppressed() {
return activationHistorySuppressed;
}
public void setActivationHistorySuppressed(boolean activationHistorySuppressed) {
this.activationHistorySuppressed = activationHistorySuppressed;
}
/**
* @return true if interest was manipulated successfully
*/
public boolean manipulateInterestForElement(IMylarElement element, boolean increment, boolean forceLandmark,
String sourceId) {
if (element == null) {
return false;
}
float originalValue = element.getInterest().getValue();
float changeValue = 0;
IMylarStructureBridge bridge = MylarPlugin.getDefault().getStructureBridge(element.getContentType());
if (!increment) {
if (element.getInterest().isLandmark() && bridge.canBeLandmark(element.getHandleIdentifier())) {
// keep it interesting
changeValue = (-1 * originalValue) + 1;
} else {
// make uninteresting
if (originalValue >= 0) {
changeValue = (-1 * originalValue) - 1;
}
// reduce interest of children
for (String childHandle : bridge.getChildHandles(element.getHandleIdentifier())) {
IMylarElement childElement = getElement(childHandle);
if (childElement.getInterest().isInteresting() && !childElement.equals(element)) {
manipulateInterestForElement(childElement, increment, forceLandmark, sourceId);
}
}
}
} else {
if (!forceLandmark && (originalValue > MylarContextManager.getScalingFactors().getLandmark())) {
changeValue = 0;
} else {
// make it a landmark by setting interest to 2 x landmark interest
if (element != null && bridge.canBeLandmark(element.getHandleIdentifier())) {
changeValue = (2*MylarContextManager.getScalingFactors().getLandmark()) - originalValue + 1;
} else {
return false;
}
}
}
if (changeValue != 0) {
InteractionEvent interactionEvent = new InteractionEvent(InteractionEvent.Kind.MANIPULATION, element
.getContentType(), element.getHandleIdentifier(), sourceId, changeValue);
MylarPlugin.getContextManager().handleInteractionEvent(interactionEvent);
}
return true;
}
public void setActiveSearchEnabled(boolean enabled) {
for (AbstractRelationProvider provider : getActiveRelationProviders()) {
provider.setEnabled(enabled);
}
}
/**
* Retruns the highest interet context.
*
* TODO: refactor this into better multiple context support
*/
public String getDominantContextHandleForElement(IMylarElement node) {
IMylarElement dominantNode = null;
if (node instanceof CompositeContextElement) {
CompositeContextElement compositeNode = (CompositeContextElement) node;
if (compositeNode.getNodes().isEmpty())
return null;
dominantNode = (IMylarElement) compositeNode.getNodes().toArray()[0];
for (IMylarElement concreteNode : compositeNode.getNodes()) {
if (dominantNode != null
&& dominantNode.getInterest().getValue() < concreteNode.getInterest().getValue()) {
dominantNode = concreteNode;
}
}
} else if (node instanceof MylarContextElement) {
dominantNode = node;
}
if (node != null) {
return ((MylarContextElement) dominantNode).getContext().getHandleIdentifier();
} else {
return null;
}
}
public void updateHandle(IMylarElement element, String newHandle) {
if (element == null)
return;
getActiveContext().updateElementHandle(element, newHandle);
for (IMylarContextListener listener : new ArrayList<IMylarContextListener>(listeners)) {
List<IMylarElement> changed = new ArrayList<IMylarElement>();
changed.add(element);
listener.interestChanged(changed);
}
if (element.getInterest().isLandmark()) {
for (IMylarContextListener listener : new ArrayList<IMylarContextListener>(listeners)) {
listener.landmarkAdded(element);
}
}
}
public void delete(IMylarElement element) {
if (element == null)
return;
getActiveContext().delete(element);
for (IMylarContextListener listener : new ArrayList<IMylarContextListener>(listeners)) {
listener.nodeDeleted(element);
}
}
public void setContextCapturePaused(boolean paused) {
this.contextCapturePaused = paused;
}
/**
* For testing.
*/
public List<IMylarContextListener> getListeners() {
return Collections.unmodifiableList(listeners);
}
public ShellLifecycleListener getShellLifecycleListener() {
return shellLifecycleListener;
}
}