package org.archstudio.archipelago2;
import java.util.Arrays;
import java.util.List;
import org.archstudio.bna.IBNAModel;
import org.archstudio.bna.IBNAView;
import org.archstudio.bna.IThing;
import org.archstudio.bna.facets.IHasMutableSelected;
import org.archstudio.bna.logics.editing.SelectionLogic;
import org.archstudio.bna.utils.Assemblies;
import org.archstudio.bna.utils.BNAUtils;
import org.archstudio.bna.utils.BNAUtils2;
import org.archstudio.bna.utils.BNAUtils2.ThingReference;
import org.archstudio.sysutils.Finally;
import org.archstudio.sysutils.SystemUtils;
import org.archstudio.sysutils.WeakListener;
import org.archstudio.sysutils.WeakListener.RemoveListenerHandler;
import org.archstudio.xadl.bna.facets.IHasObjRef;
import org.archstudio.xarchadt.ObjRef;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.swt.graphics.Point;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
public class Archipelago2Utils {
/**
* Returns <code>true</code> if the last node objects in element match the node objects provided,
* <code>false</code> otherwise.
*
* @see IArchipelago2ContentProvider
* @param element The list of node objects in a Archipelago outline element.
* @param nodeObjects The node objects expected at the end of the path.
* @return <code>true</code> if the last node objects in element match the node objects provided,
* <code>false</code> otherwise.
*/
public static final boolean pathEndsWith(Object element, Object... nodeObjects) {
if (element instanceof List) {
@SuppressWarnings("unchecked")
List<Object> nodePath = (List<Object>) element;
if (nodePath.size() >= nodeObjects.length) {
if (nodePath.subList(nodePath.size() - nodeObjects.length, nodePath.size())
.equals(Arrays.asList(nodeObjects))) {
return true;
}
}
}
return false;
}
/**
* Returns the last node object if it is an ObjRef, or <code>null</code> otherwise.
*
* @see IArchipelago2ContentProvider
* @param element The list of node objects in a Archipelago outline element.
* @return The last node object if it is an ObjRef, or <code>null</code> otherwise.
*/
public static final ObjRef getLastObjRef(Object element) {
if (element instanceof List) {
@SuppressWarnings("unchecked")
List<Object> nodePath = (List<Object>) element;
if (nodePath.size() > 0) {
return SystemUtils.castOrNull(nodePath.get(nodePath.size() - 1), ObjRef.class);
}
}
return null;
}
/**
* Returns the ObjRef of the first thing with an {@link IHasObjRef#OBJREF_KEY an ObjRef value}, or
* <code>null</code> if no things have an ObjRef.
*
* @param model The model with the things.
* @param things The list of things to search for an ObjRef in.
* @return the ObjRef of the first thing with an {@link IHasObjRef#OBJREF_KEY an ObjRef value}, or
* <code>null</code> if no things have an ObjRef.
*/
public static final ObjRef getFirstObjRef(IBNAModel model, Iterable<IThing> things) {
for (IThing thing : things) {
IThing rootThing = Assemblies.getRoot(model, thing);
ObjRef objRef = rootThing.get(IHasObjRef.OBJREF_KEY);
if (objRef != null) {
return objRef;
}
}
return null;
}
/**
* Searches for, selects, and navigates to the last ObjRef in the element path.
*
* @param bnaView The view in which to make the selection.
* @param elementPath The {@link IArchipelago2ContentProvider element path} to use as a source of
* ObjRefs.
*/
public static final void focusOnObjRef(IBNAView bnaView, List<Object> elementPath) {
Preconditions.checkNotNull(bnaView);
Preconditions.checkNotNull(elementPath);
try (Finally lock = BNAUtils.lock()) {
// Find the last ObjRef.
ObjRef elementRef = null;
for (Object element : Lists.reverse(elementPath)) {
if (element instanceof ObjRef) {
elementRef = (ObjRef) element;
break;
}
}
if (elementRef != null) {
// Find a thing that represents that ObjRef.
final ObjRef finalElementRef = elementRef;
List<ThingReference> references = BNAUtils2.findThings(bnaView, new Predicate<IThing>() {
@Override
public boolean apply(IThing input) {
return input.has(IHasObjRef.OBJREF_KEY, finalElementRef);
}
});
if (references.size() > 0) {
ThingReference reference = references.get(0);
// Select the thing (and unselect everything else). But, only if it is user selectable.
IHasMutableSelected selectableThing =
Assemblies.getEditableThing(reference.getWorld().getBNAModel(), reference.getThing(),
IHasMutableSelected.class, IHasMutableSelected.USER_MAY_SELECT);
if (selectableThing != null) {
// Unselect everything else.
SelectionLogic.setWorldWithSelectionFocus(reference.getWorld());
SelectionLogic.unselectAllThings();
selectableThing.setSelected(true);
}
// Fly to the thing.
Point point =
BNAUtils2.getRepresentativePoint(reference.getWorld(), reference.getThing());
if (point != null) {
BNAUtils2.flyViewTo(bnaView, point, 1000);
}
// Pulse notify thing.
BNAUtils2.pulseNotify(reference.getWorld(), reference.getThing(), 4000);
// Finally focus on view.
bnaView.getBNAUI().getComposite().setFocus();
}
}
}
}
/**
* Returns a new list with the element added.
*
* @param list The original list to append to.
* @param newElement The element to add to the end.
* @return a new list with the element added.
*/
public static <T> List<T> append(List<T> list, T newElement) {
List<T> newList = Lists.newArrayListWithCapacity(list.size() + 1);
newList.addAll(list);
newList.add(newElement);
return newList;
}
/**
* Adds the listener to the preference store using a weak reference.
*
* @param preferenceStore The preference store to listen to.
* @param listener The listener to receive property change events.
*/
public static void weakListenToPropertyChanges(final IPreferenceStore preferenceStore,
IPropertyChangeListener listener) {
preferenceStore.addPropertyChangeListener(WeakListener.createWeakListener(listener,
IPropertyChangeListener.class, new RemoveListenerHandler<IPropertyChangeListener>() {
@Override
public void removeListener(IPropertyChangeListener proxyListener) {
preferenceStore.removePropertyChangeListener(proxyListener);
}
}));
}
}