/* ****************************************************************************** * Copyright (c) 2006-2012 XMind Ltd. and others. * * This file is a part of XMind 3. XMind releases 3 and * above are dual-licensed under the Eclipse Public License (EPL), * which is available at http://www.eclipse.org/legal/epl-v10.html * and the GNU Lesser General Public License (LGPL), * which is available at http://www.gnu.org/licenses/lgpl.html * See http://www.xmind.net/license.html for details. * * Contributors: * XMind Ltd. - initial API and implementation *******************************************************************************/ package org.xmind.gef.part; import static org.xmind.gef.GEF.PART_ACTIVE; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.jface.viewers.ViewerFilter; import org.xmind.gef.IViewer; import org.xmind.gef.Request; import org.xmind.gef.status.IStatusListener; import org.xmind.gef.status.StatusEvent; /** * @author Administrator */ public class Part implements IPart { private static final List<IPart> EMPTY_CHILDREN = Collections.emptyList(); private Object model = null; private IPart parent = null; private List<IPart> children = null; private IPartSite site = null; private IPartStatus status = null; private List<IPartListener> partListeners = null; public Part() { } /** * @see org.xmind.gef.part.IPart#getModel() */ public Object getModel() { return model; } public IPart getParent() { return parent; } /** * @param model * the model to set */ public void setModel(Object model) { if (model == this.model) return; this.model = model; } public void setParent(IPart parent) { if (parent == this) throw new IllegalArgumentException( "A part should NOT be set as its own parent."); //$NON-NLS-1$ this.parent = parent; } public List<IPart> getChildren() { if (children == null) return EMPTY_CHILDREN; return children; } public void addNotify() { register(); for (Object o : getChildren().toArray()) { ((IPart) o).addNotify(); } refresh(); } public void removeNotify() { getStatus().dePreSelect(); getStatus().deSelect(); getStatus().lostFocus(); for (Object o : getChildren().toArray()) { ((IPart) o).removeNotify(); } unregister(); } protected void addChild(IPart child, int index) { if (child == null) return; if (child == this) throw new IllegalArgumentException( "A part should NOT be added as its own child."); //$NON-NLS-1$ if (index == -1) index = getChildren().size(); if (children == null) { children = new ArrayList<IPart>(); } children.add(index, child); child.setParent(this); addChildView(child, index); child.addNotify(); if (getStatus().isActive()) child.getStatus().activate(); fireChildAdded(child, index); } protected void removeChild(IPart child) { if (child == null || child == this) return; int index = getChildren().indexOf(child); if (index < 0) return; fireRemovingChild(child, index); if (getStatus().isActive()) child.getStatus().deactivate(); child.removeNotify(); removeChildView(child); child.setParent(null); if (children != null && !children.isEmpty()) children.remove(child); } protected void addChildView(IPart child, int index) { } protected void removeChildView(IPart child) { } protected void register() { } protected void unregister() { } protected void unregisterModel(Object model) { PartRegistry partRegistry = getPartRegistry(); if (partRegistry != null) { partRegistry.unregister(model, this); } } protected void registerModel(Object model) { PartRegistry partRegistry = getPartRegistry(); if (partRegistry != null) { partRegistry.register(model, this); } } protected PartRegistry getPartRegistry() { return getSite().getPartRegistry(); } public void refresh() { updateView(); refreshChildren(); updateChildren(); } public void update() { updateView(); updateChildren(); } protected void updateView() { } protected void updateChildren() { } protected void refreshChildren() { Map<Object, IPart> modelToPart = new HashMap<Object, IPart>(); List<IPart> currentChildren = getChildren(); for (IPart p : currentChildren) { modelToPart.put(p.getModel(), p); } Object[] newModels = getModelChildren(getModel()); if (newModels.length > 0) { IViewer viewer = getSite().getViewer(); if (viewer != null) { newModels = getFilteredModelChildren(viewer, getModel(), newModels); newModels = getSortedModelChildren(viewer, getModel(), newModels); } } int i; IPartFactory factory = getSite().getPartFactory(); for (i = 0; i < newModels.length; i++) { Object model = newModels[i]; if (i < currentChildren.size()) { Object m = currentChildren.get(i).getModel(); if (model == m || model.equals(m)) continue; } IPart p = modelToPart.get(model); if (p != null) { reorderChild(p, i); } else { p = createChild(model, factory); addChild(p, i); } } Object[] toTrim = currentChildren.toArray(); for (; i < toTrim.length; i++) { removeChild((IPart) toTrim[i]); } } protected void reorderChild(IPart child, int index) { if (children == null) return; removeChildView(child); children.remove(child); children.add(index, child); addChildView(child, index); } protected IPart createChild(Object modelChild, IPartFactory factory) { return factory.createPart(this, modelChild); } protected Object[] getSortedModelChildren(IViewer viewer, Object model, Object[] modelChildren) { ViewerComparator sorter = viewer.getComparator(); if (sorter != null) { sorter.sort((Viewer) viewer, modelChildren); } return modelChildren; } protected Object[] getFilteredModelChildren(IViewer viewer, Object model, Object[] modelChildren) { ViewerFilter[] filters = viewer.getFilters(); if (filters != null && filters.length > 0) { for (ViewerFilter f : filters) { modelChildren = f.filter((Viewer) viewer, model, modelChildren); } } return modelChildren; } protected Object[] getModelChildren(Object model) { return new Object[0]; } /** * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) */ public <T> T getAdapter(Class<T> adapter) { if (adapter == IPartSite.class) return adapter.cast(getSite()); if (adapter == IPartStatus.class) return adapter.cast(getStatus()); if (getModel() instanceof IAdaptable) return ((IAdaptable) getModel()).getAdapter(adapter); return null; } public void addPartListener(IPartListener listener) { if (partListeners == null) { partListeners = new ArrayList<IPartListener>(); } partListeners.add(listener); } public void removePartListener(IPartListener listener) { if (partListeners != null) { partListeners.remove(listener); } } protected void fireChildAdded(IPart child, int index) { if (partListeners != null) { PartEvent event = new PartEvent(this, child); for (Object listener : partListeners.toArray()) { ((IPartListener) listener).childAdded(event); } } } protected void fireRemovingChild(IPart child, int index) { if (partListeners != null) { PartEvent event = new PartEvent(this, child); for (Object listener : partListeners.toArray()) { ((IPartListener) listener).childRemoving(event); } } } public IPartSite getSite() { if (site == null) { site = createSite(); } return site; } protected IPartSite createSite() { return new PartSite(this); } /** * @param site * the site to set */ protected void setSite(IPartSite site) { this.site = site; } /** * @see org.xmind.gef.part.IPart#getStatus() */ public IPartStatus getStatus() { if (status == null) { status = new PartStatus(this); status.addStatusListener(new IStatusListener() { public void statusChanged(StatusEvent event) { if (event.key == PART_ACTIVE) { if (event.newValue) { onActivated(); } else { onDeactivated(); } } else { handleStatusChanged(event); } } }); } return status; } protected void handleStatusChanged(StatusEvent event) { } protected void onActivated() { for (Object o : getChildren().toArray()) { ((IPart) o).getStatus().activate(); } } protected void onDeactivated() { for (Object p : getChildren().toArray()) { ((IPart) p).getStatus().deactivate(); } } @Override public String toString() { return getClass().getSimpleName() + "{" + getModel() + "}"; //$NON-NLS-1$ //$NON-NLS-2$ } /** * Default implementation of the abstract method indicating that this part * doesn't have any role. Subclasses may override to determine whether or * not this part has the specific role. */ public boolean hasRole(String role) { return false; } /** * Default implementation of the abstract method to do nothing. Subclasses * may override to provide this part with abilities to handle requests. */ public void handleRequest(Request request, String role) { // do nothing } }